diff options
Diffstat (limited to 'target/linux/lantiq')
113 files changed, 53803 insertions, 14453 deletions
diff --git a/target/linux/lantiq/Makefile b/target/linux/lantiq/Makefile index fa74e95..412b7b1 100644 --- a/target/linux/lantiq/Makefile +++ b/target/linux/lantiq/Makefile @@ -10,9 +10,10 @@ ARCH:=mips BOARD:=lantiq BOARDNAME:=Lantiq GPON/XWAY FEATURES:=squashfs jffs2 -SUBTARGETS:=falcon xway +SUBTARGETS:=falcon xway ase -LINUX_VERSION:=2.6.37.6 +LINUX_VERSION:=2.6.39 +#LINUX_VERSION:=2.6.32.33 CFLAGS=-Os -pipe -mips32r2 -mtune=mips32r2 -fno-caller-saves diff --git a/target/linux/lantiq/ase/config-2.6.32 b/target/linux/lantiq/ase/config-2.6.32 new file mode 100644 index 0000000..a3b8453 --- /dev/null +++ b/target/linux/lantiq/ase/config-2.6.32 @@ -0,0 +1,15 @@ +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_DM9000 is not set +CONFIG_INPUT=y +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_GPIO_BUTTONS is not set +CONFIG_INPUT_POLLDEV=y +# CONFIG_ISDN is not set +CONFIG_LANTIQ_ETOP=y +CONFIG_LANTIQ_MACH_EASY50601=y +CONFIG_SOC_AMAZON_SE=y +# CONFIG_SOC_FALCON is not set +CONFIG_SOC_TYPE_XWAY=y +# CONFIG_SOC_XWAY is not set +# CONFIG_I2C_DESIGNWARE is not set diff --git a/target/linux/lantiq/ase/config-default b/target/linux/lantiq/ase/config-default new file mode 100644 index 0000000..a1b6766 --- /dev/null +++ b/target/linux/lantiq/ase/config-default @@ -0,0 +1,39 @@ +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +# CONFIG_ATH79 is not set +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +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_INPUT=y +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_GPIO_BUTTONS is not set +CONFIG_INPUT_POLLDEV=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_SOC_AMAZON_SE=y +# CONFIG_SOC_FALCON is not set +CONFIG_SOC_TYPE_XWAY=y +# CONFIG_SOC_XWAY is not set +CONFIG_XZ_DEC=y diff --git a/target/linux/lantiq/ase/profiles/000-generic.mk b/target/linux/lantiq/ase/profiles/000-generic.mk new file mode 100644 index 0000000..787a74f --- /dev/null +++ b/target/linux/lantiq/ase/profiles/000-generic.mk @@ -0,0 +1,6 @@ +define Profile/Generic + NAME:=Generic - all boards + PACKAGES:=kmod-leds-gpio button-hotplug +endef + +$(eval $(call Profile,Generic)) diff --git a/target/linux/lantiq/ase/profiles/001-lantiq.mk b/target/linux/lantiq/ase/profiles/001-lantiq.mk new file mode 100644 index 0000000..dd763bd --- /dev/null +++ b/target/linux/lantiq/ase/profiles/001-lantiq.mk @@ -0,0 +1,10 @@ +define Profile/EASY50601 + NAME:=EASY50601 + PACKAGES:= kmod-usb-core kmod-usb-dwc-otg kmod-leds-gpio +endef + +define Profile/EASY50601/Description + Lantiq EASY50601 evalkit +endef + +$(eval $(call Profile,EASY50601)) diff --git a/target/linux/lantiq/ase/target.mk b/target/linux/lantiq/ase/target.mk new file mode 100644 index 0000000..343edf9 --- /dev/null +++ b/target/linux/lantiq/ase/target.mk @@ -0,0 +1,10 @@ +ARCH:=mips +SUBTARGET:=ase +BOARDNAME:=Amazon-SE +FEATURES:=squashfs jffs2 atm + +DEFAULT_PACKAGES+=kmod-pppoa ppp-mod-pppoa linux-atm atm-tools br2684ctl kmod-ltq-dsl ltq-dsl-app + +define Target/Description + Lantiq ASE +endef diff --git a/target/linux/lantiq/base-files/etc/inittab b/target/linux/lantiq/base-files/etc/inittab index 7989a7f..96afec9 100644 --- a/target/linux/lantiq/base-files/etc/inittab +++ b/target/linux/lantiq/base-files/etc/inittab @@ -1,4 +1,4 @@ ::sysinit:/etc/init.d/rcS S boot ::shutdown:/etc/init.d/rcS K stop -ttyS0::askfirst:/bin/ash --login -ttyS1::askfirst:/bin/ash --login +ttyLTQ0::askfirst:/bin/ash --login +ttyLTQ1::askfirst:/bin/ash --login diff --git a/target/linux/lantiq/config-2.6.32 b/target/linux/lantiq/config-2.6.32 new file mode 100644 index 0000000..ecaff7e --- /dev/null +++ b/target/linux/lantiq/config-2.6.32 @@ -0,0 +1,149 @@ +CONFIG_32BIT=y +# CONFIG_64BIT is not set +# CONFIG_ALCHEMY_GPIO_INDIRECT is not set +# CONFIG_AR7 is not set +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +# CONFIG_ARCH_SUPPORTS_MSI is not set +CONFIG_ARCH_SUPPORTS_OPROFILE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +# CONFIG_BCM47XX is not set +# CONFIG_BCM63XX is not set +CONFIG_BITREVERSE=y +CONFIG_BOOT_RAW=y +# CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set +# CONFIG_CAVIUM_OCTEON_SIMULATOR is not set +CONFIG_CEVT_R4K=y +CONFIG_CEVT_R4K_LIB=y +CONFIG_CFG80211_DEFAULT_PS_VALUE=0 +CONFIG_CPU_BIG_ENDIAN=y +# CONFIG_CPU_CAVIUM_OCTEON is not set +CONFIG_CPU_HAS_PREFETCH=y +CONFIG_CPU_HAS_SYNC=y +# CONFIG_CPU_LITTLE_ENDIAN is not set +# CONFIG_CPU_LOONGSON2E is not set +CONFIG_CPU_MIPS32=y +# CONFIG_CPU_MIPS32_R1 is not set +CONFIG_CPU_MIPS32_R2=y +# CONFIG_CPU_MIPS64_R1 is not set +# CONFIG_CPU_MIPS64_R2 is not set +CONFIG_CPU_MIPSR2=y +# CONFIG_CPU_NEVADA is not set +# CONFIG_CPU_R10000 is not set +# CONFIG_CPU_R3000 is not set +# CONFIG_CPU_R4300 is not set +# CONFIG_CPU_R4X00 is not set +# CONFIG_CPU_R5000 is not set +# CONFIG_CPU_R5432 is not set +# CONFIG_CPU_R5500 is not set +# CONFIG_CPU_R6000 is not set +# CONFIG_CPU_R8000 is not set +# CONFIG_CPU_RM7000 is not set +# CONFIG_CPU_RM9000 is not set +# CONFIG_CPU_SB1 is not set +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_HIGHMEM=y +# CONFIG_CPU_TX39XX is not set +# CONFIG_CPU_TX49XX is not set +# CONFIG_CPU_VR41XX is not set +CONFIG_CSRC_R4K=y +CONFIG_CSRC_R4K_LIB=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DMA_NEED_PCI_MAP_STATE=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_EARLY_PRINTK=y +# CONFIG_FSNOTIFY is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_FIND_LAST_BIT=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_HARDWARE_WATCHPOINTS=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HW_RANDOM=y +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +CONFIG_IFX_UDP_REDIRECT=y +CONFIG_IMAGE_CMDLINE_HACK=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_IRQ_CPU=y +CONFIG_LANTIQ=y +CONFIG_LANTIQ_WDT=y +CONFIG_LEDS_GPIO=y +# CONFIG_MACH_ALCHEMY is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_LOONGSON is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MIKROTIK_RB532 is not set +CONFIG_MIPS=y +# CONFIG_MIPS_COBALT is not set +CONFIG_MIPS_L1_CACHE_SHIFT=5 +CONFIG_MIPS_MACHINE=y +# CONFIG_MIPS_MALTA is not set +CONFIG_MIPS_MT_DISABLED=y +# CONFIG_MIPS_MT_SMP is not set +# CONFIG_MIPS_MT_SMTC is not set +# CONFIG_MIPS_SIM is not set +# CONFIG_MIPS_VPE_LOADER is not set +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_LANTIQ=y +CONFIG_MTD_UIMAGE_SPLIT=y +CONFIG_NLS=y +# CONFIG_NO_IOPORT is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_PHYLIB=y +# CONFIG_PMC_MSP is not set +# CONFIG_PMC_YOSEMITE is not set +# CONFIG_PNX8550_JBS is not set +# CONFIG_PNX8550_STB810 is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_SCSI_DMA is not set +# CONFIG_SERIAL_8250 is not set +CONFIG_SERIAL_LANTIQ=y +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_SWARM is not set +CONFIG_SWAP_IO_SPACE=y +CONFIG_SWCONFIG=y +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_SYS_HAS_CPU_MIPS32_R2=y +CONFIG_SYS_HAS_EARLY_PRINTK=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y +CONFIG_SYS_SUPPORTS_MULTITHREADING=y +CONFIG_TRAD_SIGNALS=y +# CONFIG_TREE_PREEMPT_RCU is not set +CONFIG_TREE_RCU=y +CONFIG_ZONE_DMA_FLAG=0 diff --git a/target/linux/lantiq/config-default b/target/linux/lantiq/config-default index ef3a4c5..ecaff7e 100644 --- a/target/linux/lantiq/config-default +++ b/target/linux/lantiq/config-default @@ -5,28 +5,26 @@ CONFIG_32BIT=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_ARCH_HIBERNATION_POSSIBLE=y -# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set CONFIG_ARCH_POPULATES_NODE_MAP=y CONFIG_ARCH_REQUIRE_GPIOLIB=y # CONFIG_ARCH_SUPPORTS_MSI is not set CONFIG_ARCH_SUPPORTS_OPROFILE=y CONFIG_ARCH_SUSPEND_POSSIBLE=y -# CONFIG_AUTO_IRQ_AFFINITY is not set # CONFIG_BCM47XX is not set # CONFIG_BCM63XX is not set CONFIG_BITREVERSE=y -CONFIG_BKL=y +CONFIG_BOOT_RAW=y # CONFIG_CAVIUM_OCTEON_REFERENCE_BOARD is not set # CONFIG_CAVIUM_OCTEON_SIMULATOR is not set CONFIG_CEVT_R4K=y CONFIG_CEVT_R4K_LIB=y +CONFIG_CFG80211_DEFAULT_PS_VALUE=0 CONFIG_CPU_BIG_ENDIAN=y # CONFIG_CPU_CAVIUM_OCTEON is not set CONFIG_CPU_HAS_PREFETCH=y CONFIG_CPU_HAS_SYNC=y # CONFIG_CPU_LITTLE_ENDIAN is not set # CONFIG_CPU_LOONGSON2E is not set -# CONFIG_CPU_LOONGSON2F is not set CONFIG_CPU_MIPS32=y # CONFIG_CPU_MIPS32_R1 is not set CONFIG_CPU_MIPS32_R2=y @@ -54,63 +52,43 @@ CONFIG_CPU_SUPPORTS_HIGHMEM=y CONFIG_CSRC_R4K=y CONFIG_CSRC_R4K_LIB=y CONFIG_DECOMPRESS_LZMA=y -CONFIG_DEVPORT=y -# CONFIG_DM9000 is not set CONFIG_DMA_NEED_PCI_MAP_STATE=y CONFIG_DMA_NONCOHERENT=y CONFIG_EARLY_PRINTK=y # CONFIG_FSNOTIFY is not set -CONFIG_GENERIC_ATOMIC64=y CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_CLOCKEVENTS_BUILD=y CONFIG_GENERIC_CMOS_UPDATE=y CONFIG_GENERIC_FIND_LAST_BIT=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_GPIO=y -# CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED is not set CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y -# CONFIG_GENERIC_PENDING_IRQ is not set CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y -# CONFIG_HARDIRQS_SW_RESEND is not set CONFIG_HARDWARE_WATCHPOINTS=y CONFIG_HAS_DMA=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y CONFIG_HAVE_ARCH_KGDB=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_CLK=y CONFIG_HAVE_GENERIC_DMA_COHERENT=y -CONFIG_HAVE_GENERIC_HARDIRQS=y -# CONFIG_HAVE_IDE is not set +CONFIG_HAVE_IDE=y CONFIG_HAVE_OPROFILE=y -CONFIG_HAVE_PERF_EVENTS=y -# CONFIG_HAVE_SPARSE_IRQ is not set CONFIG_HW_RANDOM=y CONFIG_HZ=250 # CONFIG_HZ_100 is not set CONFIG_HZ_250=y -# CONFIG_I2C_FALCON is not set CONFIG_IFX_UDP_REDIRECT=y CONFIG_IMAGE_CMDLINE_HACK=y CONFIG_INITRAMFS_SOURCE="" CONFIG_IRQ_CPU=y -# CONFIG_IRQ_PER_CPU is not set CONFIG_LANTIQ=y CONFIG_LANTIQ_WDT=y CONFIG_LEDS_GPIO=y -CONFIG_LOONGSON_UART_BASE=y # CONFIG_MACH_ALCHEMY is not set # CONFIG_MACH_DECSTATION is not set # CONFIG_MACH_JAZZ is not set # CONFIG_MACH_LOONGSON is not set -CONFIG_MACH_NO_WESTBRIDGE=y # CONFIG_MACH_TX39XX is not set # CONFIG_MACH_TX49XX is not set # CONFIG_MACH_VR41XX is not set @@ -130,28 +108,19 @@ CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_LANTIQ=y CONFIG_MTD_UIMAGE_SPLIT=y -CONFIG_NEED_DMA_MAP_STATE=y -CONFIG_NEED_PER_CPU_KM=y CONFIG_NLS=y # CONFIG_NO_IOPORT is not set # CONFIG_NXP_STB220 is not set # CONFIG_NXP_STB225 is not set CONFIG_PAGEFLAGS_EXTENDED=y -CONFIG_PCI=y -CONFIG_PCI_DOMAINS=y -CONFIG_PERF_USE_VMALLOC=y CONFIG_PHYLIB=y # CONFIG_PMC_MSP is not set # CONFIG_PMC_YOSEMITE is not set # CONFIG_PNX8550_JBS is not set # CONFIG_PNX8550_STB810 is not set -# CONFIG_POWERTV is not set -# CONFIG_PREEMPT_RCU is not set -# CONFIG_QUOTACTL is not set CONFIG_SCHED_OMIT_FRAME_POINTER=y # CONFIG_SCSI_DMA is not set # CONFIG_SERIAL_8250 is not set -# CONFIG_SERIAL_8250_EXTENDED is not set CONFIG_SERIAL_LANTIQ=y # CONFIG_SGI_IP22 is not set # CONFIG_SGI_IP27 is not set @@ -165,7 +134,6 @@ CONFIG_SERIAL_LANTIQ=y # CONFIG_SIBYTE_RHONE is not set # CONFIG_SIBYTE_SENTOSA is not set # CONFIG_SIBYTE_SWARM is not set -CONFIG_SOC_LANTIQ=y CONFIG_SWAP_IO_SPACE=y CONFIG_SWCONFIG=y CONFIG_SYS_HAS_CPU_MIPS32_R1=y @@ -175,8 +143,6 @@ CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y CONFIG_SYS_SUPPORTS_ARBIT_HZ=y CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y CONFIG_SYS_SUPPORTS_MULTITHREADING=y -# CONFIG_TC35815 is not set -CONFIG_TINY_RCU=y CONFIG_TRAD_SIGNALS=y # CONFIG_TREE_PREEMPT_RCU is not set CONFIG_TREE_RCU=y diff --git a/target/linux/lantiq/extract.py b/target/linux/lantiq/extract.py deleted file mode 100755 index 91b4a57..0000000 --- a/target/linux/lantiq/extract.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/python -from sys import stdin, stdout -while True: - c = stdin.read(2) - if len(c) < 2: - break - n1, n2 = ord(c[0]), ord(c[1]) - stdout.write(chr(((n2 & 15) << 4) + ((n2 & 240) >> 4))) - stdout.write(chr(((n1 & 15) << 4) + ((n1 & 240) >> 4))) diff --git a/target/linux/lantiq/extract.sh b/target/linux/lantiq/extract.sh deleted file mode 100755 index 98e413e..0000000 --- a/target/linux/lantiq/extract.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -DIR="$1/" -FILE="$1/$2" - -echo "This tool downloads the arcor a800 firmware release and extracts the voip firmware for the danube." -echo "Please only do so if it is legal in your country" - -[ ! -f ${FILE} ] && { - echo ${FILE} is missing - exit 1 -} - -[ -f ${DIR}/ifxmips_fw_decodev2.tar.bz2 -a ! -f ${DIR}voip_coef.bin ] && { - [ ! -f ${DIR}decode_ifx_fw && -f ${DIR}ifxmips_fw_decodev2.tar.bz2 ] && { - tar xjf ${DIR}ifxmips_fw_decodev2.tar.bz2 ifxmips_fw_decode/decode.c -O > ${DIR}decode.c - gcc -o ${DIR}decode_ifx_fw ${DIR}decode.c - } - [ ! -f ${DIR}decode_ifx_fw ] && { - [ ! -f ${DIR}voip_coef.lzma ] && { - ${DIR}decode_ifx_fw $FILE ${DIR}voip_coef.lzma - } - lzma d ${DIR}voip_coef.lzma ${DIR}voip_coef.bin - } -} -[ ! -f ${DIR}dsl_a.bin ] && { - dd if=${FILE} of=${DIR}dsl1.lzma bs=1 skip=2168832 count=150724 - lzma d ${DIR}dsl2.lzma ${DIR}dsl_a.bin -} - -[ ! -f ${DIR}dsl_b.bin ] && { - dd if=${FILE} of=${DIR}dsl2.lzma bs=1 skip=2320384 count=148343 - lzma d ${DIR}dsl1.lzma ${DIR}dsl_b.bin -} - -[ ! -f ${DIR}voip.bin ] && { - dd if=${FILE} of=${DIR}voip.lzma bs=1 skip=2468864 count=452105 - lzma d ${DIR}voip.lzma ${DIR}voip.bin -} -exit 0 - -# get lzma offsets -# hexdump -C arcor_A800_452CPW_FW_1.02.206\(20081201\).bin | grep "5d 00 00 80" -# hexdump -C arcor_A800_452CPW_FW_1.02.206\(20081201\).bin | grep "00 d5 08 00" diff --git a/target/linux/lantiq/falcon/config-2.6.32 b/target/linux/lantiq/falcon/config-2.6.32 new file mode 100644 index 0000000..5686536 --- /dev/null +++ b/target/linux/lantiq/falcon/config-2.6.32 @@ -0,0 +1,33 @@ +CONFIG_CPU_MIPSR2_IRQ_EI=y +CONFIG_CPU_MIPSR2_IRQ_VI=y +# CONFIG_CRYPTO is not set +CONFIG_DM9000=y +CONFIG_DM9000_DEBUGLEVEL=4 +CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_DESIGNWARE is not set +CONFIG_I2C_FALCON=y +CONFIG_IFX_VPE_CACHE_SPLIT=y +CONFIG_IFX_VPE_EXT=y +CONFIG_LANTIQ_MACH_95C3AM1=y +CONFIG_LANTIQ_MACH_EASY98000=y +CONFIG_LANTIQ_MACH_EASY98020=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_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_SPI=y +# CONFIG_SPI_BITBANG is not set +CONFIG_SPI_FALCON=y +# CONFIG_SPI_GPIO is not set +CONFIG_SPI_MASTER=y +# CONFIG_SPI_SPIDEV is not set diff --git a/target/linux/lantiq/falcon/config-default b/target/linux/lantiq/falcon/config-default index 2a06f87..ea89c73 100644 --- a/target/linux/lantiq/falcon/config-default +++ b/target/linux/lantiq/falcon/config-default @@ -1,31 +1,63 @@ +# CONFIG_ALTERA_STAPL is not set +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set +# CONFIG_ATH79 is not set CONFIG_CPU_MIPSR2_IRQ_EI=y CONFIG_CPU_MIPSR2_IRQ_VI=y # CONFIG_CRYPTO is not set CONFIG_DM9000=y CONFIG_DM9000_DEBUGLEVEL=4 CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL=y -CONFIG_HAVE_IDE=y -CONFIG_HW_HAS_PCI=y +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_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_FALCON=y +# CONFIG_I2C_PXA_PCI is not set CONFIG_IFX_VPE_CACHE_SPLIT=y CONFIG_IFX_VPE_EXT=y CONFIG_LANTIQ_MACH_95C3AM1=y CONFIG_LANTIQ_MACH_EASY98000=y CONFIG_LANTIQ_MACH_EASY98020=y -CONFIG_LANTIQ_PROM_ASC0=y -# CONFIG_LANTIQ_PROM_ASC1 is not set +# CONFIG_LEDS_LM3530 is not set CONFIG_M25PXX_USE_FAST_READ=y +CONFIG_MACH_NO_WESTBRIDGE=y +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set 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_LATCH_ADDR is not set CONFIG_MTD_M25P80=y CONFIG_MTSCHED=y -# CONFIG_PCI is not set +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_PER_CPU_KM=y # CONFIG_PERFCTRS is not set -CONFIG_SOC_LANTIQ_FALCON=y -# CONFIG_SOC_LANTIQ_XWAY is not set +CONFIG_PERF_USE_VMALLOC=y +# CONFIG_PREEMPT_RCU is not set +# CONFIG_QUOTACTL 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_SPI=y # CONFIG_SPI_BITBANG is not set CONFIG_SPI_FALCON=y # CONFIG_SPI_GPIO is not set CONFIG_SPI_MASTER=y +# CONFIG_TPS6105X is not set +CONFIG_XZ_DEC=y diff --git a/target/linux/lantiq/image/Makefile b/target/linux/lantiq/image/Makefile index bfd73f6..e73ee19 100644 --- a/target/linux/lantiq/image/Makefile +++ b/target/linux/lantiq/image/Makefile @@ -9,8 +9,9 @@ include $(INCLUDE_DIR)/image.mk JFFS2_BLOCKSIZE = 64k 128k 256k -xway_cmdline=-console=ttyS1,115200 rootfstype=squashfs,jffs2 -falcon_cmdline=-console=ttyS0,115200 rootfstype=squashfs,jffs2 +ase_cmdline=-console=ttyLTQ1,115200 rootfstype=squashfs,jffs2 +xway_cmdline=-console=ttyLTQ1,115200 rootfstype=squashfs,jffs2 +falcon_cmdline=-console=ttyLTQ0,115200 rootfstype=squashfs,jffs2 define CompressLzma $(STAGING_DIR_HOST)/bin/lzma e $(1) $(2) @@ -184,6 +185,27 @@ define Image/Build/Profile/Generic endef endif +ifeq ($(CONFIG_TARGET_lantiq_ase),y) +define Image/BuildKernel/Profile/EASY50601 + $(call Image/BuildKernel/Template,EASY50601,$(ase_cmdline)) +endef + +define Image/Build/Profile/EASY50601 + $(call Image/Build/$(1),$(1),EASY50601) +endef + +define Image/BuildKernel/Profile/Generic + $(call Image/BuildKernel/Template,EASY50601,$(ase_cmdline)) + $(call Image/BuildKernel/Template,NONE) +endef + +define Image/Build/Profile/Generic + $(call Image/Build/$(1),$(1),EASY50601) + $(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/patches-2.6.32/0001-MIPS-Lantiq-Add-initial-support-for-Lantiq-SoCs.patch b/target/linux/lantiq/patches-2.6.32/0001-MIPS-Lantiq-Add-initial-support-for-Lantiq-SoCs.patch new file mode 100644 index 0000000..6131577 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0001-MIPS-Lantiq-Add-initial-support-for-Lantiq-SoCs.patch @@ -0,0 +1,898 @@ +From 9e0235e97ea2617beaacaa16ab5f0b9e75f4680e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:47 +0200 +Subject: [PATCH 01/13] MIPS: Lantiq: Add initial support for Lantiq SoCs + +Add initial support for Mips based SoCs made by Lantiq. This series will add +support for the XWAY family. + +The series allows booting a minimal system using a initramfs or NOR. Missing +drivers and support for Amazon and GPON family will be provided in a later +series. + +[Ralf: Remove some cargo cult programming and fixed formatting.] + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Signed-off-by: David Daney <ddaney@caviumnetworks.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2252/ +Patchwork: https://patchwork.linux-mips.org/patch/2371/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/Kbuild.platforms | 1 + + arch/mips/Kconfig | 17 ++ + arch/mips/include/asm/mach-lantiq/lantiq.h | 63 ++++++ + arch/mips/include/asm/mach-lantiq/war.h | 24 ++ + arch/mips/lantiq/Makefile | 9 + + arch/mips/lantiq/Platform | 7 + + arch/mips/lantiq/clk.c | 140 ++++++++++++ + arch/mips/lantiq/clk.h | 18 ++ + arch/mips/lantiq/early_printk.c | 33 +++ + arch/mips/lantiq/irq.c | 326 ++++++++++++++++++++++++++++ + arch/mips/lantiq/prom.c | 71 ++++++ + arch/mips/lantiq/prom.h | 24 ++ + arch/mips/lantiq/setup.c | 41 ++++ + 13 files changed, 774 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq.h + create mode 100644 arch/mips/include/asm/mach-lantiq/war.h + create mode 100644 arch/mips/lantiq/Makefile + create mode 100644 arch/mips/lantiq/Platform + create mode 100644 arch/mips/lantiq/clk.c + create mode 100644 arch/mips/lantiq/clk.h + create mode 100644 arch/mips/lantiq/early_printk.c + create mode 100644 arch/mips/lantiq/irq.c + create mode 100644 arch/mips/lantiq/prom.c + create mode 100644 arch/mips/lantiq/prom.h + create mode 100644 arch/mips/lantiq/setup.c + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -174,6 +174,23 @@ + Members include the Acer PICA, MIPS Magnum 4000, MIPS Millennium and + Olivetti M700-10 workstations. + ++config LANTIQ ++ bool "Lantiq based platforms" ++ select DMA_NONCOHERENT ++ select IRQ_CPU ++ select CEVT_R4K ++ select CSRC_R4K ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_HAS_CPU_MIPS32_R2 ++ select SYS_SUPPORTS_BIG_ENDIAN ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_MULTITHREADING ++ select SYS_HAS_EARLY_PRINTK ++ select ARCH_REQUIRE_GPIOLIB ++ select SWAP_IO_SPACE ++ select BOOT_RAW ++ select HAVE_CLK ++ + config LASAT + bool "LASAT Networks platforms" + select CEVT_R4K +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/lantiq.h +@@ -0,0 +1,63 @@ ++/* ++ * 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> ++ */ ++#ifndef _LANTIQ_H__ ++#define _LANTIQ_H__ ++ ++#include <linux/irq.h> ++ ++/* generic reg access functions */ ++#define ltq_r32(reg) __raw_readl(reg) ++#define ltq_w32(val, reg) __raw_writel(val, reg) ++#define ltq_w32_mask(clear, set, reg) \ ++ ltq_w32((ltq_r32(reg) & ~(clear)) | (set), reg) ++#define ltq_r8(reg) __raw_readb(reg) ++#define ltq_w8(val, reg) __raw_writeb(val, reg) ++ ++/* 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_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) ++#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) ++ ++extern __iomem void *ltq_ebu_membase; ++extern __iomem void *ltq_cgu_membase; ++ ++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_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; ++ ++/* some irq helpers */ ++extern void ltq_disable_irq(unsigned int irq); ++extern void ltq_mask_and_ack_irq(unsigned int irq); ++extern void ltq_enable_irq(unsigned int irq); ++ ++/* find out what caused the last cpu reset */ ++extern int ltq_reset_cause(void); ++#define LTQ_RST_CAUSE_WDTRST 0x20 ++ ++#define IOPORT_RESOURCE_START 0x10000000 ++#define IOPORT_RESOURCE_END 0xffffffff ++#define IOMEM_RESOURCE_START 0x10000000 ++#define IOMEM_RESOURCE_END 0xffffffff ++#define LTQ_FLASH_START 0x10000000 ++#define LTQ_FLASH_MAX 0x04000000 ++ ++#endif +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/war.h +@@ -0,0 +1,24 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ */ ++#ifndef __ASM_MIPS_MACH_LANTIQ_WAR_H ++#define __ASM_MIPS_MACH_LANTIQ_WAR_H ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 0 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif +--- /dev/null ++++ b/arch/mips/lantiq/Makefile +@@ -0,0 +1,9 @@ ++# Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License version 2 as published ++# by the Free Software Foundation. ++ ++obj-y := irq.o setup.o clk.o prom.o ++ ++obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +--- /dev/null ++++ b/arch/mips/lantiq/Platform +@@ -0,0 +1,7 @@ ++# ++# Lantiq ++# ++ ++platform-$(CONFIG_LANTIQ) += lantiq/ ++cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq ++load-$(CONFIG_LANTIQ) = 0xffffffff80002000 +--- /dev/null ++++ b/arch/mips/lantiq/clk.c +@@ -0,0 +1,144 @@ ++/* ++ * 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 Thomas Langer <thomas.langer@lantiq.com> ++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++ */ ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/list.h> ++ ++#include <asm/time.h> ++#include <asm/irq.h> ++#include <asm/div64.h> ++ ++#include <lantiq_soc.h> ++ ++#include "clk.h" ++ ++struct clk { ++ const char *name; ++ unsigned long rate; ++ unsigned long (*get_rate) (void); ++}; ++ ++static struct clk *cpu_clk; ++static int cpu_clk_cnt; ++ ++/* 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, ++ }, ++}; ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++static struct resource ltq_cgu_resource = { ++ .name = "cgu", ++ .start = LTQ_CGU_BASE_ADDR, ++ .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++/* remapped clock register range */ ++void __iomem *ltq_cgu_membase; ++#endif ++ ++void clk_init(void) ++{ ++ cpu_clk = cpu_clk_generic; ++ cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic); ++} ++ ++static inline int clk_good(struct clk *clk) ++{ ++ return clk && !IS_ERR(clk); ++} ++ ++unsigned long clk_get_rate(struct clk *clk) ++{ ++ if (unlikely(!clk_good(clk))) ++ return 0; ++ ++ if (clk->rate != 0) ++ return clk->rate; ++ ++ if (clk->get_rate != NULL) ++ return clk->get_rate(); ++ ++ return 0; ++} ++EXPORT_SYMBOL(clk_get_rate); ++ ++struct clk *clk_get(struct device *dev, const char *id) ++{ ++ int i; ++ ++ for (i = 0; i < cpu_clk_cnt; i++) ++ if (!strcmp(id, cpu_clk[i].name)) ++ return &cpu_clk[i]; ++ BUG(); ++ return ERR_PTR(-ENOENT); ++} ++EXPORT_SYMBOL(clk_get); ++ ++void clk_put(struct clk *clk) ++{ ++ /* not used */ ++} ++EXPORT_SYMBOL(clk_put); ++ ++static inline u32 ltq_get_counter_resolution(void) ++{ ++ u32 res; ++ ++ __asm__ __volatile__( ++ ".set push\n" ++ ".set mips32r2\n" ++ "rdhwr %0, $3\n" ++ ".set pop\n" ++ : "=&r" (res) ++ : /* no input */ ++ : "memory"); ++ ++ return res; ++} ++ ++void __init plat_time_init(void) ++{ ++ struct clk *clk; ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++ if (insert_resource(&iomem_resource, <q_cgu_resource) < 0) ++ panic("Failed to insert cgu memory\n"); ++ ++ if (request_mem_region(ltq_cgu_resource.start, ++ resource_size(<q_cgu_resource), "cgu") < 0) ++ panic("Failed to request cgu memory\n"); ++ ++ ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start, ++ resource_size(<q_cgu_resource)); ++ if (!ltq_cgu_membase) { ++ pr_err("Failed to remap cgu memory\n"); ++ unreachable(); ++ } ++#endif ++ clk = clk_get(0, "cpu"); ++ mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution(); ++ write_c0_compare(read_c0_count()); ++ clk_put(clk); ++} +--- /dev/null ++++ b/arch/mips/lantiq/clk.h +@@ -0,0 +1,18 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_CLK_H__ ++#define _LTQ_CLK_H__ ++ ++extern void clk_init(void); ++ ++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); ++ ++#endif +--- /dev/null ++++ b/arch/mips/lantiq/early_printk.c +@@ -0,0 +1,37 @@ ++/* ++ * 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/cpu.h> ++ ++#include <lantiq.h> ++#include <lantiq_soc.h> ++ ++/* no ioremap possible at this early stage, lets use KSEG1 instead */ ++#ifdef CONFIG_SOC_FALCON ++#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC0_BASE_ADDR) ++#else ++#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR) ++#endif ++#define ASC_BUF 1024 ++#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048)) ++#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020)) ++#define TXMASK 0x3F00 ++#define TXOFFSET 8 ++ ++void prom_putchar(char c) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET); ++ if (c == '\n') ++ ltq_w32('\r', LTQ_ASC_TBUF); ++ ltq_w32(c, LTQ_ASC_TBUF); ++ local_irq_restore(flags); ++} +--- /dev/null ++++ b/arch/mips/lantiq/irq.c +@@ -0,0 +1,353 @@ ++/* ++ * 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> ++ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> ++ */ ++ ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <linux/module.h> ++ ++#include <asm/bootinfo.h> ++#include <asm/irq_cpu.h> ++ ++#include <lantiq_soc.h> ++#include <irq.h> ++ ++/* register definitions */ ++#define LTQ_ICU_IM0_ISR 0x0000 ++#define LTQ_ICU_IM0_IER 0x0008 ++#define LTQ_ICU_IM0_IOSR 0x0010 ++#define LTQ_ICU_IM0_IRSR 0x0018 ++#define LTQ_ICU_IM0_IMR 0x0020 ++#define LTQ_ICU_IM1_ISR 0x0028 ++#define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR) ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++ ++#define LTQ_EIU_EXIN_C 0x0000 ++#define LTQ_EIU_EXIN_INIC 0x0004 ++#define LTQ_EIU_EXIN_INEN 0x000C ++ ++/* irq numbers used by the external interrupt unit (EIU) */ ++#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30) ++#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31) ++#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26) ++#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0 ++#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1) ++#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2) ++#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30) ++ ++#define MAX_EIU 6 ++ ++/* irqs generated by device attached to the EBU need to be acked in ++ * a special manner ++ */ ++#define LTQ_ICU_EBU_IRQ 22 ++ ++#define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) ++#define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) ++ ++static unsigned short ltq_eiu_irq[MAX_EIU] = { ++ LTQ_EIU_IR0, ++ LTQ_EIU_IR1, ++ LTQ_EIU_IR2, ++ LTQ_EIU_IR3, ++ LTQ_EIU_IR4, ++ LTQ_EIU_IR5, ++}; ++ ++static void __iomem *ltq_eiu_membase; ++ ++static struct resource ltq_eiu_resource = { ++ .name = "eiu", ++ .start = LTQ_EIU_BASE_ADDR, ++ .end = LTQ_EIU_BASE_ADDR + LTQ_ICU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++#endif ++ ++static struct resource ltq_icu_resource = { ++ .name = "icu", ++ .start = LTQ_ICU_BASE_ADDR, ++ .end = LTQ_ICU_BASE_ADDR + LTQ_ICU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++#define ltq_icu_w32(x, y) ltq_w32((x), ltq_icu_membase + (y)) ++#define ltq_icu_r32(x) ltq_r32(ltq_icu_membase + (x)) ++ ++static void __iomem *ltq_icu_membase; ++ ++void ++ltq_disable_irq(unsigned int irq_nr) ++{ ++ u32 ier = LTQ_ICU_IM0_IER; ++ ++ irq_nr -= INT_NUM_IRQ0; ++ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); ++ irq_nr %= INT_NUM_IM_OFFSET; ++ ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); ++} ++ ++void ++ltq_mask_and_ack_irq(unsigned int irq_nr) ++{ ++ u32 ier = LTQ_ICU_IM0_IER; ++ u32 isr = LTQ_ICU_IM0_ISR; ++ ++ irq_nr -= INT_NUM_IRQ0; ++ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); ++ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); ++ irq_nr %= INT_NUM_IM_OFFSET; ++ ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); ++ ltq_icu_w32((1 << irq_nr), isr); ++} ++EXPORT_SYMBOL(ltq_mask_and_ack_irq); ++ ++static void ++ltq_ack_irq(unsigned int irq_nr) ++{ ++ u32 isr = LTQ_ICU_IM0_ISR; ++ ++ irq_nr -= INT_NUM_IRQ0; ++ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); ++ irq_nr %= INT_NUM_IM_OFFSET; ++ ltq_icu_w32((1 << irq_nr), isr); ++} ++ ++void ++ltq_enable_irq(unsigned int irq_nr) ++{ ++ u32 ier = LTQ_ICU_IM0_IER; ++ ++ irq_nr -= INT_NUM_IRQ0; ++ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); ++ irq_nr %= INT_NUM_IM_OFFSET; ++ ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier); ++} ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++static unsigned int ++ltq_startup_eiu_irq(unsigned int irq) ++{ ++ int i; ++ ++ ltq_enable_irq(irq); ++ for (i = 0; i < MAX_EIU; i++) { ++ if (irq == ltq_eiu_irq[i]) { ++ /* low level - we should really handle set_type */ ++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) | (0x6 << (i * 4)), ++ LTQ_EIU_EXIN_C); ++ /* clear all pending */ ++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~(1 << i), ++ LTQ_EIU_EXIN_INIC); ++ /* enable */ ++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | (1 << i), ++ LTQ_EIU_EXIN_INEN); ++ break; ++ } ++ } ++ return 0; ++} ++ ++static void ++ltq_shutdown_eiu_irq(unsigned int irq) ++{ ++ int i; ++ ++ ltq_disable_irq(irq); ++ for (i = 0; i < MAX_EIU; i++) { ++ if (irq == ltq_eiu_irq[i]) { ++ /* disable */ ++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i), ++ LTQ_EIU_EXIN_INEN); ++ break; ++ } ++ } ++} ++#endif ++ ++static void ++ltq_end_irq(unsigned int irq) ++{ ++ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) ++ ltq_enable_irq(irq); ++} ++ ++static struct irq_chip ++ltq_irq_type = { ++ "ltq_irq", ++ .enable = ltq_enable_irq, ++ .disable = ltq_disable_irq, ++ .unmask = ltq_enable_irq, ++ .ack = ltq_ack_irq, ++ .mask = ltq_disable_irq, ++ .mask_ack = ltq_mask_and_ack_irq, ++ .end = ltq_end_irq, ++}; ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++static struct irq_chip ++ltq_eiu_type = { ++ "ltq_eiu_irq", ++ .startup = ltq_startup_eiu_irq, ++ .shutdown = ltq_shutdown_eiu_irq, ++ .enable = ltq_enable_irq, ++ .disable = ltq_disable_irq, ++ .unmask = ltq_enable_irq, ++ .ack = ltq_ack_irq, ++ .mask = ltq_disable_irq, ++ .mask_ack = ltq_mask_and_ack_irq, ++ .end = ltq_end_irq, ++}; ++#endif ++ ++static void ltq_hw_irqdispatch(int module) ++{ ++ u32 irq; ++ ++ irq = ltq_icu_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET)); ++ if (irq == 0) ++ return; ++ ++ /* silicon bug causes only the msb set to 1 to be valid. all ++ * other bits might be bogus ++ */ ++ irq = __fls(irq); ++ do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module)); ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++ /* if this is a EBU irq, we need to ack it or get a deadlock */ ++ if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0)) ++ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10, ++ LTQ_EBU_PCC_ISTAT); ++#endif ++} ++ ++#define DEFINE_HWx_IRQDISPATCH(x) \ ++ static void ltq_hw ## x ## _irqdispatch(void) \ ++ { \ ++ ltq_hw_irqdispatch(x); \ ++ } ++DEFINE_HWx_IRQDISPATCH(0) ++DEFINE_HWx_IRQDISPATCH(1) ++DEFINE_HWx_IRQDISPATCH(2) ++DEFINE_HWx_IRQDISPATCH(3) ++DEFINE_HWx_IRQDISPATCH(4) ++ ++static void ltq_hw5_irqdispatch(void) ++{ ++ do_IRQ(MIPS_CPU_TIMER_IRQ); ++} ++ ++asmlinkage void plat_irq_dispatch(void) ++{ ++ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; ++ unsigned int i; ++ ++ if (pending & CAUSEF_IP7) { ++ do_IRQ(MIPS_CPU_TIMER_IRQ); ++ goto out; ++ } else { ++ for (i = 0; i < 5; i++) { ++ if (pending & (CAUSEF_IP2 << i)) { ++ ltq_hw_irqdispatch(i); ++ goto out; ++ } ++ } ++ } ++ pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status()); ++ ++out: ++ return; ++} ++ ++static struct irqaction cascade = { ++ .handler = no_action, ++ .flags = IRQF_DISABLED, ++ .name = "cascade", ++}; ++ ++void __init arch_init_irq(void) ++{ ++ int i; ++ ++ if (insert_resource(&iomem_resource, <q_icu_resource) < 0) ++ panic("Failed to insert icu memory\n"); ++ ++ if (request_mem_region(ltq_icu_resource.start, ++ resource_size(<q_icu_resource), "icu") < 0) ++ panic("Failed to request icu memory\n"); ++ ++ ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start, ++ resource_size(<q_icu_resource)); ++ if (!ltq_icu_membase) ++ panic("Failed to remap icu memory\n"); ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++ 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"); ++ ++ ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start, ++ resource_size(<q_eiu_resource)); ++ if (!ltq_eiu_membase) ++ panic("Failed to remap eiu memory\n"); ++#endif ++ /* make sure all irqs are turned off by default */ ++ for (i = 0; i < 5; i++) ++ 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)); ++ ++ mips_cpu_irq_init(); ++ ++ for (i = 2; i <= 6; i++) ++ setup_irq(i, &cascade); ++ ++ if (cpu_has_vint) { ++ pr_info("Setting up vectored interrupts\n"); ++ set_vi_handler(2, ltq_hw0_irqdispatch); ++ set_vi_handler(3, ltq_hw1_irqdispatch); ++ set_vi_handler(4, ltq_hw2_irqdispatch); ++ set_vi_handler(5, ltq_hw3_irqdispatch); ++ set_vi_handler(6, ltq_hw4_irqdispatch); ++ set_vi_handler(7, ltq_hw5_irqdispatch); ++ } ++ ++ for (i = INT_NUM_IRQ0; ++ i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++) ++#ifdef CONFIG_SOC_TYPE_XWAY ++ if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) || (i == LTQ_EIU_IR2)) ++ set_irq_chip_and_handler(i, <q_eiu_type, handle_level_irq); ++ /* EIU3-5 only exist on ar9 and vr9 */ ++ else if (((i == LTQ_EIU_IR3) || (i == LTQ_EIU_IR4) || ++ (i == LTQ_EIU_IR5)) && (ltq_is_ar9() || ltq_is_vr9())) ++ set_irq_chip_and_handler(i, <q_eiu_type, handle_level_irq); ++ else ++#endif ++ set_irq_chip_and_handler(i, <q_irq_type, handle_level_irq); ++ ++#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); ++#else ++ set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 | ++ IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); ++#endif ++ cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ; ++} ++ ++unsigned int __cpuinit get_c0_compare_int(void) ++{ ++ return CP0_LEGACY_COMPARE_IRQ; ++} +--- /dev/null ++++ b/arch/mips/lantiq/prom.c +@@ -0,0 +1,71 @@ ++/* ++ * 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.h> ++ ++#include "prom.h" ++#include "clk.h" ++ ++static struct ltq_soc_info soc_info; ++ ++unsigned int ltq_get_cpu_ver(void) ++{ ++ return soc_info.rev; ++} ++EXPORT_SYMBOL(ltq_get_cpu_ver); ++ ++unsigned int ltq_get_soc_type(void) ++{ ++ return soc_info.type; ++} ++EXPORT_SYMBOL(ltq_get_soc_type); ++ ++const char *get_system_type(void) ++{ ++ return soc_info.sys_type; ++} ++ ++void prom_free_prom_memory(void) ++{ ++} ++ ++static void __init prom_init_cmdline(void) ++{ ++ int argc = fw_arg0; ++ char **argv = (char **) KSEG1ADDR(fw_arg1); ++ int i; ++ ++ for (i = 0; i < argc; i++) { ++ char *p = (char *) KSEG1ADDR(argv[i]); ++ ++ if (p && *p) { ++ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); ++ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); ++ } ++ } ++} ++ ++void __init prom_init(void) ++{ ++ struct clk *clk; ++ ++ ltq_soc_detect(&soc_info); ++ clk_init(); ++ clk = clk_get(0, "cpu"); ++ snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d", ++ soc_info.name, soc_info.rev); ++ clk_put(clk); ++ soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; ++ pr_info("SoC: %s\n", soc_info.sys_type); ++ prom_init_cmdline(); ++} +--- /dev/null ++++ b/arch/mips/lantiq/prom.h +@@ -0,0 +1,24 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_PROM_H__ ++#define _LTQ_PROM_H__ ++ ++#define LTQ_SYS_TYPE_LEN 0x100 ++ ++struct ltq_soc_info { ++ unsigned char *name; ++ unsigned int rev; ++ unsigned int partnum; ++ unsigned int type; ++ unsigned char sys_type[LTQ_SYS_TYPE_LEN]; ++}; ++ ++extern void ltq_soc_detect(struct ltq_soc_info *i); ++ ++#endif +--- /dev/null ++++ b/arch/mips/lantiq/setup.c +@@ -0,0 +1,41 @@ ++/* ++ * 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/kernel.h> ++#include <linux/module.h> ++#include <linux/io.h> ++#include <linux/ioport.h> ++#include <asm/bootinfo.h> ++ ++#include <lantiq_soc.h> ++ ++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; ++ ioport_resource.end = IOPORT_RESOURCE_END; ++ iomem_resource.start = IOMEM_RESOURCE_START; ++ iomem_resource.end = IOMEM_RESOURCE_END; ++ ++ set_io_port_base((unsigned long) KSEG1); ++ ++ while (*envp) { ++ char *e = (char *)KSEG1ADDR(*envp); ++ if (!strncmp(e, "memsize=", 8)) { ++ e += 8; ++ if (strict_strtoul(e, 0, &memsize)) ++ pr_warn("bad memsize specified\n"); ++ } ++ envp++; ++ } ++ memsize *= 1024 * 1024; ++ add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); ++} diff --git a/target/linux/lantiq/patches-2.6.32/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch b/target/linux/lantiq/patches-2.6.32/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch new file mode 100644 index 0000000..cb0058c --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch @@ -0,0 +1,1151 @@ +From 36cc26a362c6ad64ba3d176809847ec60cc40859 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:48 +0200 +Subject: [PATCH 02/13] MIPS: Lantiq: add SoC specific code for XWAY family + +Add support for the Lantiq XWAY family of Mips24KEc SoCs. + +* Danube (PSB50702) +* Twinpass (PSB4000) +* AR9 (PSB50802) +* Amazon SE (PSB5061) + +The Amazon SE is a lightweight SoC and has no PCI as well as a different +clock. We split the code out into seperate files to handle this. + +The GPIO pins on the SoCs are multi function and there are several bits +we can use to configure the pins. To be as compatible as possible to +GPIOLIB we add a function + +int ltq_gpio_request(unsigned int pin, unsigned int alt0, + unsigned int alt1, unsigned int dir, const char *name); + +which lets you configure the 2 "alternate function" bits. This way drivers like +PCI can make use of GPIOLIB without a cubersome wrapper. + +The PLL code inside arch/mips/lantiq/xway/clk-xway.c is voodoo to me. It was +taken from a 2.4.20 source tree and was never really changed by me since then. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2249/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/Kconfig | 1 + + arch/mips/include/asm/mach-lantiq/xway/irq.h | 18 ++ + .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 66 ++++++ + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 140 ++++++++++++ + arch/mips/lantiq/Kconfig | 21 ++ + arch/mips/lantiq/Makefile | 2 + + arch/mips/lantiq/Platform | 1 + + arch/mips/lantiq/xway/Makefile | 4 + + arch/mips/lantiq/xway/clk-ase.c | 48 +++++ + arch/mips/lantiq/xway/clk-xway.c | 223 ++++++++++++++++++++ + arch/mips/lantiq/xway/ebu.c | 53 +++++ + arch/mips/lantiq/xway/gpio.c | 195 +++++++++++++++++ + arch/mips/lantiq/xway/pmu.c | 70 ++++++ + arch/mips/lantiq/xway/prom-ase.c | 39 ++++ + arch/mips/lantiq/xway/prom-xway.c | 54 +++++ + arch/mips/lantiq/xway/reset.c | 91 ++++++++ + 16 files changed, 1026 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/include/asm/mach-lantiq/xway/irq.h + create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h + create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h + create mode 100644 arch/mips/lantiq/Kconfig + create mode 100644 arch/mips/lantiq/xway/Makefile + create mode 100644 arch/mips/lantiq/xway/clk-ase.c + create mode 100644 arch/mips/lantiq/xway/clk-xway.c + create mode 100644 arch/mips/lantiq/xway/ebu.c + create mode 100644 arch/mips/lantiq/xway/gpio.c + create mode 100644 arch/mips/lantiq/xway/pmu.c + create mode 100644 arch/mips/lantiq/xway/prom-ase.c + create mode 100644 arch/mips/lantiq/xway/prom-xway.c + create mode 100644 arch/mips/lantiq/xway/reset.c + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -694,6 +694,7 @@ + source "arch/mips/basler/excite/Kconfig" + source "arch/mips/bcm63xx/Kconfig" + source "arch/mips/jazz/Kconfig" ++source "arch/mips/lantiq/Kconfig" + source "arch/mips/lasat/Kconfig" + source "arch/mips/pmc-sierra/Kconfig" + source "arch/mips/sgi-ip27/Kconfig" +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/xway/irq.h +@@ -0,0 +1,18 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef __LANTIQ_IRQ_H ++#define __LANTIQ_IRQ_H ++ ++#include <lantiq_irq.h> ++ ++#define NR_IRQS 256 ++ ++#include_next <irq.h> ++ ++#endif +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +@@ -0,0 +1,66 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LANTIQ_XWAY_IRQ_H__ ++#define _LANTIQ_XWAY_IRQ_H__ ++ ++#define INT_NUM_IRQ0 8 ++#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0) ++#define INT_NUM_IM1_IRL0 (INT_NUM_IRQ0 + 32) ++#define INT_NUM_IM2_IRL0 (INT_NUM_IRQ0 + 64) ++#define INT_NUM_IM3_IRL0 (INT_NUM_IRQ0 + 96) ++#define INT_NUM_IM4_IRL0 (INT_NUM_IRQ0 + 128) ++#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0) ++ ++#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8)) ++#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1) ++#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2) ++ ++#define LTQ_ASC_ASE_TIR INT_NUM_IM2_IRL0 ++#define LTQ_ASC_ASE_RIR (INT_NUM_IM2_IRL0 + 2) ++#define LTQ_ASC_ASE_EIR (INT_NUM_IM2_IRL0 + 3) ++ ++#define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15) ++#define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14) ++#define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16) ++ ++#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21) ++#define LTQ_MEI_INT (INT_NUM_IM1_IRL0 + 23) ++ ++#define LTQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23) ++#define LTQ_USB_INT (INT_NUM_IM1_IRL0 + 22) ++#define LTQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23) ++ ++#define MIPS_CPU_TIMER_IRQ 7 ++ ++#define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0) ++#define LTQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1) ++#define LTQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2) ++#define LTQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3) ++#define LTQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4) ++#define LTQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5) ++#define LTQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6) ++#define LTQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7) ++#define LTQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8) ++#define LTQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9) ++#define LTQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10) ++#define LTQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11) ++#define LTQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25) ++#define LTQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26) ++#define LTQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27) ++#define LTQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28) ++#define LTQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29) ++#define LTQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30) ++#define LTQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16) ++#define LTQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21) ++ ++#define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24) ++ ++#define INT_NUM_IM4_IRL14 (INT_NUM_IM4_IRL0 + 14) ++ ++#endif +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -0,0 +1,140 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_XWAY_H__ ++#define _LTQ_XWAY_H__ ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++ ++#include <lantiq.h> ++ ++/* Chip IDs */ ++#define SOC_ID_DANUBE1 0x129 ++#define SOC_ID_DANUBE2 0x12B ++#define SOC_ID_TWINPASS 0x12D ++#define SOC_ID_AMAZON_SE 0x152 ++#define SOC_ID_ARX188 0x16C ++#define SOC_ID_ARX168 0x16D ++#define SOC_ID_ARX182 0x16F ++ ++/* 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 ++ ++/* ASC0/1 - serial port */ ++#define LTQ_ASC0_BASE_ADDR 0x1E100400 ++#define LTQ_ASC1_BASE_ADDR 0x1E100C00 ++#define LTQ_ASC_SIZE 0x400 ++ ++/* RCU - reset control unit */ ++#define LTQ_RCU_BASE_ADDR 0x1F203000 ++#define LTQ_RCU_SIZE 0x1000 ++ ++/* GPTU - general purpose timer unit */ ++#define LTQ_GPTU_BASE_ADDR 0x18000300 ++#define LTQ_GPTU_SIZE 0x100 ++ ++/* EBU - external bus unit */ ++#define LTQ_EBU_GPIO_START 0x14000000 ++#define LTQ_EBU_GPIO_SIZE 0x1000 ++ ++#define LTQ_EBU_BASE_ADDR 0x1E105300 ++#define LTQ_EBU_SIZE 0x100 ++ ++#define LTQ_EBU_BUSCON0 0x0060 ++#define LTQ_EBU_PCC_CON 0x0090 ++#define LTQ_EBU_PCC_IEN 0x00A4 ++#define LTQ_EBU_PCC_ISTAT 0x00A0 ++#define LTQ_EBU_BUSCON1 0x0064 ++#define LTQ_EBU_ADDRSEL1 0x0024 ++#define EBU_WRDIS 0x80000000 ++ ++/* CGU - clock generation unit */ ++#define LTQ_CGU_BASE_ADDR 0x1F103000 ++#define LTQ_CGU_SIZE 0x1000 ++ ++/* ICU - interrupt control unit */ ++#define LTQ_ICU_BASE_ADDR 0x1F880200 ++#define LTQ_ICU_SIZE 0x100 ++ ++/* EIU - external interrupt unit */ ++#define LTQ_EIU_BASE_ADDR 0x1F101000 ++#define LTQ_EIU_SIZE 0x1000 ++ ++/* PMU - power management unit */ ++#define LTQ_PMU_BASE_ADDR 0x1F102000 ++#define LTQ_PMU_SIZE 0x1000 ++ ++#define PMU_DMA 0x0020 ++#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_PPE32_BASE_ADDR 0xBE180000 ++#define LTQ_PPE32_SIZE 0x40000 ++ ++/* DMA */ ++#define LTQ_DMA_BASE_ADDR 0xBE104100 ++ ++/* PCI */ ++#define PCI_CR_BASE_ADDR 0x1E105400 ++#define PCI_CR_SIZE 0x400 ++ ++/* WDT */ ++#define LTQ_WDT_BASE_ADDR 0x1F8803F0 ++#define LTQ_WDT_SIZE 0x10 ++ ++/* STP - serial to parallel conversion unit */ ++#define LTQ_STP_BASE_ADDR 0x1E100BB0 ++#define LTQ_STP_SIZE 0x40 ++ ++/* GPIO */ ++#define LTQ_GPIO0_BASE_ADDR 0x1E100B10 ++#define LTQ_GPIO1_BASE_ADDR 0x1E100B40 ++#define LTQ_GPIO2_BASE_ADDR 0x1E100B70 ++#define LTQ_GPIO_SIZE 0x30 ++ ++/* SSC */ ++#define LTQ_SSC_BASE_ADDR 0x1e100800 ++#define LTQ_SSC_SIZE 0x100 ++ ++/* MEI - dsl core */ ++#define LTQ_MEI_BASE_ADDR 0x1E116000 ++ ++/* DEU - data encryption unit */ ++#define LTQ_DEU_BASE_ADDR 0x1E103100 ++ ++/* MPS - multi processor unit (voice) */ ++#define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) ++#define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) ++ ++/* 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 void ltq_pmu_enable(unsigned int module); ++extern void ltq_pmu_disable(unsigned int module); ++ ++static inline int ltq_is_ar9(void) ++{ ++ return (ltq_get_soc_type() == SOC_TYPE_AR9); ++} ++ ++static inline int ltq_is_vr9(void) ++{ ++ return (ltq_get_soc_type() == SOC_TYPE_VR9); ++} ++ ++#endif /* CONFIG_SOC_TYPE_XWAY */ ++#endif /* _LTQ_XWAY_H__ */ +--- /dev/null ++++ b/arch/mips/lantiq/Kconfig +@@ -0,0 +1,21 @@ ++if LANTIQ ++ ++config SOC_TYPE_XWAY ++ bool ++ default n ++ ++choice ++ prompt "SoC Type" ++ default SOC_XWAY ++ ++config SOC_AMAZON_SE ++ bool "Amazon SE" ++ select SOC_TYPE_XWAY ++ ++config SOC_XWAY ++ bool "XWAY" ++ select SOC_TYPE_XWAY ++ select HW_HAS_PCI ++endchoice ++ ++endif +--- a/arch/mips/lantiq/Makefile ++++ b/arch/mips/lantiq/Makefile +@@ -7,3 +7,5 @@ + obj-y := irq.o setup.o clk.o prom.o + + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o ++ ++obj-$(CONFIG_SOC_TYPE_XWAY) += xway/ +--- a/arch/mips/lantiq/Platform ++++ b/arch/mips/lantiq/Platform +@@ -5,3 +5,4 @@ + 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 +--- /dev/null ++++ b/arch/mips/lantiq/xway/Makefile +@@ -0,0 +1,4 @@ ++obj-y := pmu.o ebu.o reset.o gpio.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/clk-ase.c +@@ -0,0 +1,48 @@ ++/* ++ * 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/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> ++ ++/* 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); +--- /dev/null ++++ b/arch/mips/lantiq/xway/clk-xway.c +@@ -0,0 +1,223 @@ ++/* ++ * 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> ++ ++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); +--- /dev/null ++++ b/arch/mips/lantiq/xway/ebu.c +@@ -0,0 +1,53 @@ ++/* ++ * 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. ++ * ++ * EBU - the external bus unit attaches PCI, NOR and NAND ++ * ++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/ioport.h> ++ ++#include <lantiq_soc.h> ++ ++/* all access to the ebu must be locked */ ++DEFINE_SPINLOCK(ebu_lock); ++EXPORT_SYMBOL_GPL(ebu_lock); ++ ++static struct resource ltq_ebu_resource = { ++ .name = "ebu", ++ .start = LTQ_EBU_BASE_ADDR, ++ .end = LTQ_EBU_BASE_ADDR + LTQ_EBU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++/* remapped base addr of the clock unit and external bus unit */ ++void __iomem *ltq_ebu_membase; ++ ++static int __init lantiq_ebu_init(void) ++{ ++ /* insert and request the memory region */ ++ if (insert_resource(&iomem_resource, <q_ebu_resource) < 0) ++ panic("Failed to insert ebu memory\n"); ++ ++ if (request_mem_region(ltq_ebu_resource.start, ++ resource_size(<q_ebu_resource), "ebu") < 0) ++ panic("Failed to request ebu memory\n"); ++ ++ /* remap ebu register range */ ++ ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start, ++ resource_size(<q_ebu_resource)); ++ if (!ltq_ebu_membase) ++ panic("Failed to remap ebu memory\n"); ++ ++ /* 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); ++ return 0; ++} ++ ++postcore_initcall(lantiq_ebu_init); +--- /dev/null ++++ b/arch/mips/lantiq/xway/gpio.c +@@ -0,0 +1,195 @@ ++/* ++ * 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/slab.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/gpio.h> ++#include <linux/ioport.h> ++#include <linux/io.h> ++ ++#include <lantiq_soc.h> ++ ++#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 PINS_PER_PORT 16 ++#define MAX_PORTS 3 ++ ++#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) ++#define ltq_gpio_clearbit(m, r, p) ltq_w32_mask((1 << p), 0, m + r) ++ ++struct ltq_gpio { ++ void __iomem *membase; ++ struct gpio_chip chip; ++}; ++ ++static struct ltq_gpio ltq_gpio_port[MAX_PORTS]; ++ ++int gpio_to_irq(unsigned int gpio) ++{ ++ return -EINVAL; ++} ++EXPORT_SYMBOL(gpio_to_irq); ++ ++int irq_to_gpio(unsigned int gpio) ++{ ++ return -EINVAL; ++} ++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 id = 0; ++ ++ if (pin >= (MAX_PORTS * PINS_PER_PORT)) ++ return -EINVAL; ++ if (gpio_request(pin, name)) { ++ pr_err("failed to setup lantiq gpio: %s\n", name); ++ return -EBUSY; ++ } ++ if (dir) ++ gpio_direction_output(pin, 1); ++ else ++ gpio_direction_input(pin); ++ while (pin >= PINS_PER_PORT) { ++ pin -= PINS_PER_PORT; ++ id++; ++ } ++ if (alt0) ++ 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) ++ 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); ++ return 0; ++} ++EXPORT_SYMBOL(ltq_gpio_request); ++ ++static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) ++{ ++ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); ++ ++ if (value) ++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset); ++ else ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset); ++} ++ ++static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset) ++{ ++ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); ++ ++ return ltq_gpio_getbit(ltq_gpio->membase, LTQ_GPIO_IN, offset); ++} ++ ++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); ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); ++ ++ return 0; ++} ++ ++static int ltq_gpio_direction_output(struct gpio_chip *chip, ++ unsigned int offset, int value) ++{ ++ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); ++ ++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); ++ ltq_gpio_set(chip, offset, value); ++ ++ return 0; ++} ++ ++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); ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset); ++ return 0; ++} ++ ++static int ltq_gpio_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ ++ if (pdev->id >= MAX_PORTS) { ++ dev_err(&pdev->dev, "invalid gpio port %d\n", ++ pdev->id); ++ return -EINVAL; ++ } ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get memory for gpio port %d\n", ++ pdev->id); ++ return -ENOENT; ++ } ++ 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 memory for gpio port %d\n", ++ pdev->id); ++ return -EBUSY; ++ } ++ ltq_gpio_port[pdev->id].membase = devm_ioremap_nocache(&pdev->dev, ++ res->start, resource_size(res)); ++ if (!ltq_gpio_port[pdev->id].membase) { ++ dev_err(&pdev->dev, "failed to remap memory for gpio port %d\n", ++ pdev->id); ++ return -ENOMEM; ++ } ++ ltq_gpio_port[pdev->id].chip.label = "ltq_gpio"; ++ ltq_gpio_port[pdev->id].chip.direction_input = ltq_gpio_direction_input; ++ ltq_gpio_port[pdev->id].chip.direction_output = ++ ltq_gpio_direction_output; ++ ltq_gpio_port[pdev->id].chip.get = ltq_gpio_get; ++ 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; ++ ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT; ++ platform_set_drvdata(pdev, <q_gpio_port[pdev->id]); ++ return gpiochip_add(<q_gpio_port[pdev->id].chip); ++} ++ ++static struct platform_driver ++ltq_gpio_driver = { ++ .probe = ltq_gpio_probe, ++ .driver = { ++ .name = "ltq_gpio", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init ltq_gpio_init(void) ++{ ++ int ret = platform_driver_register(<q_gpio_driver); ++ ++ if (ret) ++ pr_info("ltq_gpio : Error registering platfom driver!"); ++ return ret; ++} ++ ++postcore_initcall(ltq_gpio_init); +--- /dev/null ++++ b/arch/mips/lantiq/xway/pmu.c +@@ -0,0 +1,70 @@ ++/* ++ * 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/kernel.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/ioport.h> ++ ++#include <lantiq_soc.h> ++ ++/* PMU - the power management unit allows us to turn part of the core ++ * on and off ++ */ ++ ++/* the enable / disable registers */ ++#define LTQ_PMU_PWDCR 0x1C ++#define LTQ_PMU_PWDSR 0x20 ++ ++#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y)) ++#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x)) ++ ++static struct resource ltq_pmu_resource = { ++ .name = "pmu", ++ .start = LTQ_PMU_BASE_ADDR, ++ .end = LTQ_PMU_BASE_ADDR + LTQ_PMU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static void __iomem *ltq_pmu_membase; ++ ++void ltq_pmu_enable(unsigned int module) ++{ ++ 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)); ++ ++ if (!err) ++ panic("activating PMU module failed!\n"); ++} ++EXPORT_SYMBOL(ltq_pmu_enable); ++ ++void ltq_pmu_disable(unsigned int module) ++{ ++ ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR); ++} ++EXPORT_SYMBOL(ltq_pmu_disable); ++ ++int __init ltq_pmu_init(void) ++{ ++ if (insert_resource(&iomem_resource, <q_pmu_resource) < 0) ++ panic("Failed to insert pmu memory\n"); ++ ++ if (request_mem_region(ltq_pmu_resource.start, ++ resource_size(<q_pmu_resource), "pmu") < 0) ++ panic("Failed to request pmu memory\n"); ++ ++ ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start, ++ resource_size(<q_pmu_resource)); ++ if (!ltq_pmu_membase) ++ panic("Failed to remap pmu memory\n"); ++ return 0; ++} ++ ++core_initcall(ltq_pmu_init); +--- /dev/null ++++ b/arch/mips/lantiq/xway/prom-ase.c +@@ -0,0 +1,39 @@ ++/* ++ * 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 "../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; ++ switch (i->partnum) { ++ case SOC_ID_AMAZON_SE: ++ i->name = SOC_AMAZON_SE; ++ i->type = SOC_TYPE_AMAZON_SE; ++ break; ++ ++ default: ++ unreachable(); ++ break; ++ } ++} +--- /dev/null ++++ b/arch/mips/lantiq/xway/prom-xway.c +@@ -0,0 +1,54 @@ ++/* ++ * 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 "../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; ++ 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; ++ } ++} +--- /dev/null ++++ b/arch/mips/lantiq/xway/reset.c +@@ -0,0 +1,91 @@ ++/* ++ * 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/io.h> ++#include <linux/ioport.h> ++#include <linux/pm.h> ++#include <linux/module.h> ++#include <asm/reboot.h> ++ ++#include <lantiq_soc.h> ++ ++#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 ++ ++static struct resource ltq_rcu_resource = { ++ .name = "rcu", ++ .start = LTQ_RCU_BASE_ADDR, ++ .end = LTQ_RCU_BASE_ADDR + LTQ_RCU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++/* remapped base addr of the reset control unit */ ++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; ++} ++EXPORT_SYMBOL_GPL(ltq_reset_cause); ++ ++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); ++ unreachable(); ++} ++ ++static void ltq_machine_halt(void) ++{ ++ pr_notice("System halted.\n"); ++ local_irq_disable(); ++ unreachable(); ++} ++ ++static void ltq_machine_power_off(void) ++{ ++ pr_notice("Please turn off the power now.\n"); ++ local_irq_disable(); ++ unreachable(); ++} ++ ++static int __init mips_reboot_setup(void) ++{ ++ /* insert and request the memory region */ ++ if (insert_resource(&iomem_resource, <q_rcu_resource) < 0) ++ panic("Failed to insert rcu memory\n"); ++ ++ if (request_mem_region(ltq_rcu_resource.start, ++ resource_size(<q_rcu_resource), "rcu") < 0) ++ panic("Failed to request rcu memory\n"); ++ ++ /* remap rcu register range */ ++ ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start, ++ resource_size(<q_rcu_resource)); ++ if (!ltq_rcu_membase) ++ panic("Failed to remap rcu memory\n"); ++ ++ _machine_restart = ltq_machine_restart; ++ _machine_halt = ltq_machine_halt; ++ pm_power_off = ltq_machine_power_off; ++ ++ return 0; ++} ++ ++arch_initcall(mips_reboot_setup); diff --git a/target/linux/lantiq/patches-2.6.32/0003-MIPS-Lantiq-Add-PCI-controller-support.patch b/target/linux/lantiq/patches-2.6.32/0003-MIPS-Lantiq-Add-PCI-controller-support.patch new file mode 100644 index 0000000..1757266 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0003-MIPS-Lantiq-Add-PCI-controller-support.patch @@ -0,0 +1,546 @@ +From 08127ed36bad367903591bbf0f244179683ccb28 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:49 +0200 +Subject: [PATCH 03/13] MIPS: Lantiq: Add PCI controller support. + +The Lantiq family of SoCs have a EBU (External Bus Unit). This patch adds +the driver that allows us to use the EBU as a PCI controller. In order for +PCI to work the EBU is set to endianess swap all the data. In addition we +need to make use of SWAP_IO_SPACE for device->host DMA to work. + +The clock of the PCI works in several modes (internal/external). If this +is not configured correctly the SoC will hang. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2250/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + .../mips/include/asm/mach-lantiq/lantiq_platform.h | 46 +++ + arch/mips/pci/Makefile | 1 + + arch/mips/pci/ops-lantiq.c | 116 ++++++++ + arch/mips/pci/pci-lantiq.c | 297 ++++++++++++++++++++ + arch/mips/pci/pci-lantiq.h | 18 ++ + 5 files changed, 478 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_platform.h + create mode 100644 arch/mips/pci/ops-lantiq.c + create mode 100644 arch/mips/pci/pci-lantiq.c + create mode 100644 arch/mips/pci/pci-lantiq.h + +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +new file mode 100644 +index 0000000..1f1dba6 +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +@@ -0,0 +1,46 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LANTIQ_PLATFORM_H__ ++#define _LANTIQ_PLATFORM_H__ ++ ++#include <linux/mtd/partitions.h> ++ ++/* struct used to pass info to the pci core */ ++enum { ++ PCI_CLOCK_INT = 0, ++ PCI_CLOCK_EXT ++}; ++ ++#define PCI_EXIN0 0x0001 ++#define PCI_EXIN1 0x0002 ++#define PCI_EXIN2 0x0004 ++#define PCI_EXIN3 0x0008 ++#define PCI_EXIN4 0x0010 ++#define PCI_EXIN5 0x0020 ++#define PCI_EXIN_MAX 6 ++ ++#define PCI_GNT1 0x0040 ++#define PCI_GNT2 0x0080 ++#define PCI_GNT3 0x0100 ++#define PCI_GNT4 0x0200 ++ ++#define PCI_REQ1 0x0400 ++#define PCI_REQ2 0x0800 ++#define PCI_REQ3 0x1000 ++#define PCI_REQ4 0x2000 ++#define PCI_REQ_SHIFT 10 ++#define PCI_REQ_MASK 0xf ++ ++struct ltq_pci_data { ++ int clock; ++ int gpio; ++ int irq[16]; ++}; ++ ++#endif +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index f0d5329..4df8799 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -41,6 +41,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_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/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c +new file mode 100644 +index 0000000..1f2afb5 +--- /dev/null ++++ b/arch/mips/pci/ops-lantiq.c +@@ -0,0 +1,116 @@ ++/* ++ * 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/types.h> ++#include <linux/pci.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/mm.h> ++#include <asm/addrspace.h> ++#include <linux/vmalloc.h> ++ ++#include <lantiq_soc.h> ++ ++#include "pci-lantiq.h" ++ ++#define LTQ_PCI_CFG_BUSNUM_SHF 16 ++#define LTQ_PCI_CFG_DEVNUM_SHF 11 ++#define LTQ_PCI_CFG_FUNNUM_SHF 8 ++ ++#define PCI_ACCESS_READ 0 ++#define PCI_ACCESS_WRITE 1 ++ ++static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus, ++ unsigned int devfn, unsigned int where, u32 *data) ++{ ++ unsigned long cfg_base; ++ unsigned long flags; ++ u32 temp; ++ ++ /* we support slot from 0 to 15 dev_fn & 0x68 (AD29) is the ++ SoC itself */ ++ if ((bus->number != 0) || ((devfn & 0xf8) > 0x78) ++ || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68)) ++ return 1; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ ++ cfg_base = (unsigned long) ltq_pci_mapped_cfg; ++ cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn << ++ LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3); ++ ++ /* Perform access */ ++ if (access_type == PCI_ACCESS_WRITE) { ++ ltq_w32(swab32(*data), ((u32 *)cfg_base)); ++ } else { ++ *data = ltq_r32(((u32 *)(cfg_base))); ++ *data = swab32(*data); ++ } ++ wmb(); ++ ++ /* clean possible Master abort */ ++ cfg_base = (unsigned long) ltq_pci_mapped_cfg; ++ 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 |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; ++ ltq_w32(temp, ((u32 *)cfg_base)); ++ ++ spin_unlock_irqrestore(&ebu_lock, flags); ++ ++ if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ)) ++ return 1; ++ ++ return 0; ++} ++ ++int ltq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 *val) ++{ ++ u32 data = 0; ++ ++ if (ltq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ if (size == 1) ++ *val = (data >> ((where & 3) << 3)) & 0xff; ++ else if (size == 2) ++ *val = (data >> ((where & 3) << 3)) & 0xffff; ++ else ++ *val = data; ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++int ltq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 val) ++{ ++ u32 data = 0; ++ ++ if (size == 4) { ++ data = val; ++ } else { ++ if (ltq_pci_config_access(PCI_ACCESS_READ, bus, ++ devfn, where, &data)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ if (size == 1) ++ data = (data & ~(0xff << ((where & 3) << 3))) | ++ (val << ((where & 3) << 3)); ++ else if (size == 2) ++ data = (data & ~(0xffff << ((where & 3) << 3))) | ++ (val << ((where & 3) << 3)); ++ } ++ ++ if (ltq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ return PCIBIOS_SUCCESSFUL; ++} +diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c +new file mode 100644 +index 0000000..603d749 +--- /dev/null ++++ b/arch/mips/pci/pci-lantiq.c +@@ -0,0 +1,297 @@ ++/* ++ * 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/types.h> ++#include <linux/pci.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/mm.h> ++#include <linux/vmalloc.h> ++#include <linux/platform_device.h> ++ ++#include <asm/pci.h> ++#include <asm/gpio.h> ++#include <asm/addrspace.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_irq.h> ++#include <lantiq_platform.h> ++ ++#include "pci-lantiq.h" ++ ++#define LTQ_PCI_CFG_BASE 0x17000000 ++#define LTQ_PCI_CFG_SIZE 0x00008000 ++#define LTQ_PCI_MEM_BASE 0x18000000 ++#define LTQ_PCI_MEM_SIZE 0x02000000 ++#define LTQ_PCI_IO_BASE 0x1AE00000 ++#define LTQ_PCI_IO_SIZE 0x00200000 ++ ++#define PCI_CR_FCI_ADDR_MAP0 0x00C0 ++#define PCI_CR_FCI_ADDR_MAP1 0x00C4 ++#define PCI_CR_FCI_ADDR_MAP2 0x00C8 ++#define PCI_CR_FCI_ADDR_MAP3 0x00CC ++#define PCI_CR_FCI_ADDR_MAP4 0x00D0 ++#define PCI_CR_FCI_ADDR_MAP5 0x00D4 ++#define PCI_CR_FCI_ADDR_MAP6 0x00D8 ++#define PCI_CR_FCI_ADDR_MAP7 0x00DC ++#define PCI_CR_CLK_CTRL 0x0000 ++#define PCI_CR_PCI_MOD 0x0030 ++#define PCI_CR_PC_ARB 0x0080 ++#define PCI_CR_FCI_ADDR_MAP11hg 0x00E4 ++#define PCI_CR_BAR11MASK 0x0044 ++#define PCI_CR_BAR12MASK 0x0048 ++#define PCI_CR_BAR13MASK 0x004C ++#define PCI_CS_BASE_ADDR1 0x0010 ++#define PCI_CR_PCI_ADDR_MAP11 0x0064 ++#define PCI_CR_FCI_BURST_LENGTH 0x00E8 ++#define PCI_CR_PCI_EOI 0x002C ++#define PCI_CS_STS_CMD 0x0004 ++ ++#define PCI_MASTER0_REQ_MASK_2BITS 8 ++#define PCI_MASTER1_REQ_MASK_2BITS 10 ++#define PCI_MASTER2_REQ_MASK_2BITS 12 ++#define INTERNAL_ARB_ENABLE_BIT 0 ++ ++#define LTQ_CGU_IFCCR 0x0018 ++#define LTQ_CGU_PCICR 0x0034 ++ ++#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)) ++ ++struct ltq_pci_gpio_map { ++ int pin; ++ int alt0; ++ int alt1; ++ 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" }, ++}; ++ ++__iomem void *ltq_pci_mapped_cfg; ++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; ++ ++struct pci_ops ltq_pci_ops = { ++ .read = ltq_pci_read_config_dword, ++ .write = ltq_pci_write_config_dword ++}; ++ ++static struct resource pci_io_resource = { ++ .name = "pci io space", ++ .start = LTQ_PCI_IO_BASE, ++ .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1, ++ .flags = IORESOURCE_IO ++}; ++ ++static struct resource pci_mem_resource = { ++ .name = "pci memory space", ++ .start = LTQ_PCI_MEM_BASE, ++ .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1, ++ .flags = IORESOURCE_MEM ++}; ++ ++static struct pci_controller ltq_pci_controller = { ++ .pci_ops = <q_pci_ops, ++ .mem_resource = &pci_mem_resource, ++ .mem_offset = 0x00000000UL, ++ .io_resource = &pci_io_resource, ++ .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; ++ ++ /* BAR11MASK value depends on available memory on system. */ ++ mem = num_physpages * PAGE_SIZE; ++ bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8; ++ ++ return bar11mask; ++} ++ ++static void ltq_pci_setup_gpio(int gpio) ++{ ++ 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, ++ ltq_pci_gpio_map[i].alt0, ++ ltq_pci_gpio_map[i].alt1, ++ ltq_pci_gpio_map[i].dir, ++ ltq_pci_gpio_map[i].name); ++ } ++ } ++ ltq_gpio_request(21, 0, 0, 1, "pci-reset"); ++ ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; ++} ++ ++static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) ++{ ++ u32 temp_buffer; ++ ++ /* set clock to 33Mhz */ ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR); ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR); ++ ++ /* external or internal clock ? */ ++ if (conf->clock) { ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16), ++ LTQ_CGU_IFCCR); ++ ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR); ++ } else { ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16), ++ LTQ_CGU_IFCCR); ++ ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR); ++ } ++ ++ /* setup pci clock and gpis used by pci */ ++ ltq_pci_setup_gpio(conf->gpio); ++ ++ /* enable auto-switching between PCI and EBU */ ++ ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); ++ ++ /* busy, i.e. configuration is not done, PCI access has to be retried */ ++ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD); ++ wmb(); ++ /* BUS Master/IO/MEM access */ ++ ltq_pci_cfg_w32(ltq_pci_cfg_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD); ++ ++ /* enable external 2 PCI masters */ ++ temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB); ++ temp_buffer &= (~(ltq_pci_req_mask << 16)); ++ /* enable internal arbiter */ ++ temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT); ++ /* enable internal PCI master reqest */ ++ temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS)); ++ ++ /* enable EBU request */ ++ temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS)); ++ ++ /* enable all external masters request */ ++ temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS)); ++ ltq_pci_w32(temp_buffer, PCI_CR_PC_ARB); ++ wmb(); ++ ++ /* setup BAR memory regions */ ++ ltq_pci_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0); ++ ltq_pci_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1); ++ ltq_pci_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2); ++ ltq_pci_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3); ++ ltq_pci_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4); ++ ltq_pci_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5); ++ ltq_pci_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6); ++ ltq_pci_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7); ++ ltq_pci_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg); ++ ltq_pci_w32(ltq_calc_bar11mask(), PCI_CR_BAR11MASK); ++ ltq_pci_w32(0, PCI_CR_PCI_ADDR_MAP11); ++ ltq_pci_w32(0, PCI_CS_BASE_ADDR1); ++ /* both TX and RX endian swap are enabled */ ++ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI); ++ wmb(); ++ ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR12MASK) | 0x80000000, ++ PCI_CR_BAR12MASK); ++ ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR13MASK) | 0x80000000, ++ PCI_CR_BAR13MASK); ++ /*use 8 dw burst length */ ++ ltq_pci_w32(0x303, PCI_CR_FCI_BURST_LENGTH); ++ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD); ++ wmb(); ++ ++ /* setup irq line */ ++ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_CON) | 0xc, LTQ_EBU_PCC_CON); ++ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN); ++ ++ /* toggle reset pin */ ++ __gpio_set_value(21, 0); ++ wmb(); ++ mdelay(1); ++ __gpio_set_value(21, 1); ++ 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 "ltq_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 = ++ (struct ltq_pci_data *) pdev->dev.platform_data; ++ 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 = ++ 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); ++ register_pci_controller(<q_pci_controller); ++ ++ return 0; ++} ++ ++static struct platform_driver ++ltq_pci_driver = { ++ .probe = ltq_pci_probe, ++ .driver = { ++ .name = "ltq_pci", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init pcibios_init(void) ++{ ++ int ret = platform_driver_register(<q_pci_driver); ++ if (ret) ++ printk(KERN_INFO "ltq_pci: Error registering platfom driver!"); ++ return ret; ++} ++ ++arch_initcall(pcibios_init); +diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h +new file mode 100644 +index 0000000..66bf6cd +--- /dev/null ++++ b/arch/mips/pci/pci-lantiq.h +@@ -0,0 +1,18 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_PCI_H__ ++#define _LTQ_PCI_H__ ++ ++extern __iomem void *ltq_pci_mapped_cfg; ++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, ++ unsigned int devfn, int where, int size, u32 val); ++ ++#endif +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches-2.6.32/0004-MIPS-Lantiq-Add-NOR-flash-support.patch b/target/linux/lantiq/patches-2.6.32/0004-MIPS-Lantiq-Add-NOR-flash-support.patch new file mode 100644 index 0000000..03e86bb --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0004-MIPS-Lantiq-Add-NOR-flash-support.patch @@ -0,0 +1,301 @@ +From cd0d53b24ca744295d2cdf69bb2b659571091b75 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 12 Apr 2011 18:10:01 +0200 +Subject: [PATCH 04/13] MIPS: Lantiq: Add NOR flash support + +This patch adds the driver/map for NOR devices attached to the SoC via the +External Bus Unit (EBU). + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: David Woodhouse <dwmw2@infradead.org> +Cc: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +Cc: linux-mips@linux-mips.org +Cc: linux-mtd@lists.infradead.org +Acked-by: Artem Bityutskiy <dedekind1@gmail.com> +Patchwork: https://patchwork.linux-mips.org/patch/2285/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + drivers/mtd/maps/Kconfig | 7 + + drivers/mtd/maps/Makefile | 1 + + drivers/mtd/maps/lantiq-flash.c | 251 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 259 insertions(+), 0 deletions(-) + create mode 100644 drivers/mtd/maps/lantiq-flash.c + +--- a/drivers/mtd/maps/Kconfig ++++ b/drivers/mtd/maps/Kconfig +@@ -259,6 +259,13 @@ + help + Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards + ++config MTD_LANTIQ ++ tristate "Lantiq SoC NOR support" ++ depends on LANTIQ ++ select MTD_PARTITIONS ++ help ++ Support for NOR flash attached to the Lantiq SoC's External Bus Unit. ++ + config MTD_DILNETPC + tristate "CFI Flash device mapped on DIL/Net PC" + depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN +--- a/drivers/mtd/maps/Makefile ++++ b/drivers/mtd/maps/Makefile +@@ -61,3 +61,4 @@ + obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o + obj-$(CONFIG_MTD_VMU) += vmu-flash.o + obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o ++obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o +--- /dev/null ++++ b/drivers/mtd/maps/lantiq-flash.c +@@ -0,0 +1,251 @@ ++/* ++ * 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) 2004 Liu Peng Infineon IFAP DC COM CPE ++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/io.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++#include <linux/mtd/cfi.h> ++#include <linux/platform_device.h> ++#include <linux/mtd/physmap.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_platform.h> ++ ++/* ++ * The NOR flash is connected to the same external bus unit (EBU) as PCI. ++ * To make PCI work we need to enable the endianness swapping for the address ++ * written to the EBU. This endianness swapping works for PCI correctly but ++ * fails for attached NOR devices. To workaround this we need to use a complex ++ * map. The workaround involves swapping all addresses whilst probing the chip. ++ * Once probing is complete we stop swapping the addresses but swizzle the ++ * unlock addresses to ensure that access to the NOR device works correctly. ++ */ ++ ++enum { ++ LTQ_NOR_PROBING, ++ LTQ_NOR_NORMAL ++}; ++ ++struct ltq_mtd { ++ struct resource *res; ++ struct mtd_info *mtd; ++ struct map_info *map; ++}; ++ ++static char ltq_map_name[] = "ltq_nor"; ++ ++static map_word ++ltq_read16(struct map_info *map, unsigned long adr) ++{ ++ unsigned long flags; ++ map_word temp; ++ ++ if (map->map_priv_1 == LTQ_NOR_PROBING) ++ adr ^= 2; ++ spin_lock_irqsave(&ebu_lock, flags); ++ temp.x[0] = *(u16 *)(map->virt + adr); ++ spin_unlock_irqrestore(&ebu_lock, flags); ++ return temp; ++} ++ ++static void ++ltq_write16(struct map_info *map, map_word d, unsigned long adr) ++{ ++ unsigned long flags; ++ ++ if (map->map_priv_1 == LTQ_NOR_PROBING) ++ adr ^= 2; ++ spin_lock_irqsave(&ebu_lock, flags); ++ *(u16 *)(map->virt + adr) = d.x[0]; ++ spin_unlock_irqrestore(&ebu_lock, flags); ++} ++ ++/* ++ * The following 2 functions copy data between iomem and a cached memory ++ * section. As memcpy() makes use of pre-fetching we cannot use it here. ++ * The normal alternative of using memcpy_{to,from}io also makes use of ++ * memcpy() on MIPS so it is not applicable either. We are therefore stuck ++ * with having to use our own loop. ++ */ ++static void ++ltq_copy_from(struct map_info *map, void *to, ++ unsigned long from, ssize_t len) ++{ ++ unsigned char *f = (unsigned char *)map->virt + from; ++ unsigned char *t = (unsigned char *)to; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ while (len--) ++ *t++ = *f++; ++ spin_unlock_irqrestore(&ebu_lock, flags); ++} ++ ++static void ++ltq_copy_to(struct map_info *map, unsigned long to, ++ const void *from, ssize_t len) ++{ ++ unsigned char *f = (unsigned char *)from; ++ unsigned char *t = (unsigned char *)map->virt + to; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ while (len--) ++ *t++ = *f++; ++ spin_unlock_irqrestore(&ebu_lock, flags); ++} ++ ++static const char const *part_probe_types[] = { "cmdlinepart", NULL }; ++ ++static int __init ++ltq_mtd_probe(struct platform_device *pdev) ++{ ++ struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev); ++ struct ltq_mtd *ltq_mtd; ++ struct mtd_partition *parts; ++ struct resource *res; ++ int nr_parts = 0; ++ struct cfi_private *cfi; ++ int err; ++ ++ ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL); ++ platform_set_drvdata(pdev, ltq_mtd); ++ ++ ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!ltq_mtd->res) { ++ dev_err(&pdev->dev, "failed to get memory resource"); ++ err = -ENOENT; ++ goto err_out; ++ } ++ ++ res = devm_request_mem_region(&pdev->dev, ltq_mtd->res->start, ++ resource_size(ltq_mtd->res), dev_name(&pdev->dev)); ++ if (!ltq_mtd->res) { ++ dev_err(&pdev->dev, "failed to request mem resource"); ++ err = -EBUSY; ++ goto err_out; ++ } ++ ++ ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL); ++ ltq_mtd->map->phys = res->start; ++ ltq_mtd->map->size = resource_size(res); ++ ltq_mtd->map->virt = devm_ioremap_nocache(&pdev->dev, ++ ltq_mtd->map->phys, ltq_mtd->map->size); ++ if (!ltq_mtd->map->virt) { ++ dev_err(&pdev->dev, "failed to ioremap!\n"); ++ err = -ENOMEM; ++ goto err_free; ++ } ++ ++ ltq_mtd->map->name = ltq_map_name; ++ ltq_mtd->map->bankwidth = 2; ++ ltq_mtd->map->read = ltq_read16; ++ ltq_mtd->map->write = ltq_write16; ++ ltq_mtd->map->copy_from = ltq_copy_from; ++ ltq_mtd->map->copy_to = ltq_copy_to; ++ ++ ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING; ++ ltq_mtd->mtd = do_map_probe("cfi_probe", ltq_mtd->map); ++ ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL; ++ ++ if (!ltq_mtd->mtd) { ++ dev_err(&pdev->dev, "probing failed\n"); ++ err = -ENXIO; ++ goto err_unmap; ++ } ++ ++ ltq_mtd->mtd->owner = THIS_MODULE; ++ ++ cfi = ltq_mtd->map->fldrv_priv; ++ cfi->addr_unlock1 ^= 1; ++ cfi->addr_unlock2 ^= 1; ++ ++ nr_parts = parse_mtd_partitions(ltq_mtd->mtd, ++ part_probe_types, &parts, 0); ++ if (nr_parts > 0) { ++ dev_info(&pdev->dev, ++ "using %d partitions from cmdline", nr_parts); ++ } else { ++ nr_parts = ltq_mtd_data->nr_parts; ++ parts = ltq_mtd_data->parts; ++ } ++ ++ err = add_mtd_partitions(ltq_mtd->mtd, parts, nr_parts); ++ if (err) { ++ dev_err(&pdev->dev, "failed to add partitions\n"); ++ goto err_destroy; ++ } ++ ++ return 0; ++ ++err_destroy: ++ map_destroy(ltq_mtd->mtd); ++err_unmap: ++ iounmap(ltq_mtd->map->virt); ++err_free: ++ kfree(ltq_mtd->map); ++err_out: ++ kfree(ltq_mtd); ++ return err; ++} ++ ++static int __devexit ++ltq_mtd_remove(struct platform_device *pdev) ++{ ++ struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); ++ ++ if (ltq_mtd) { ++ if (ltq_mtd->mtd) { ++ del_mtd_partitions(ltq_mtd->mtd); ++ map_destroy(ltq_mtd->mtd); ++ } ++ if (ltq_mtd->map->virt) ++ iounmap(ltq_mtd->map->virt); ++ kfree(ltq_mtd->map); ++ kfree(ltq_mtd); ++ } ++ return 0; ++} ++ ++static struct platform_driver ltq_mtd_driver = { ++ .remove = __devexit_p(ltq_mtd_remove), ++ .driver = { ++ .name = "ltq_nor", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++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_LICENSE("GPL"); ++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); ++MODULE_DESCRIPTION("Lantiq SoC NOR"); diff --git a/target/linux/lantiq/patches-2.6.32/0005-MIPS-Lantiq-Add-platform-device-support.patch b/target/linux/lantiq/patches-2.6.32/0005-MIPS-Lantiq-Add-platform-device-support.patch new file mode 100644 index 0000000..917993f --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0005-MIPS-Lantiq-Add-platform-device-support.patch @@ -0,0 +1,338 @@ +From 09e57348261c1ae0ff89c68679126fc76a28b2a2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:53 +0200 +Subject: [PATCH 05/13] MIPS: Lantiq: Add platform device support + +This patch adds the wrappers for registering our platform devices. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2254/ +Patchwork: https://patchwork.linux-mips.org/patch/2360/ +Patchwork: https://patchwork.linux-mips.org/patch/2359/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/lantiq/Makefile | 2 +- + arch/mips/lantiq/devices.c | 122 +++++++++++++++++++++++++++++++++++++++ + arch/mips/lantiq/devices.h | 23 +++++++ + arch/mips/lantiq/xway/Makefile | 2 +- + arch/mips/lantiq/xway/devices.c | 98 +++++++++++++++++++++++++++++++ + arch/mips/lantiq/xway/devices.h | 18 ++++++ + 6 files changed, 263 insertions(+), 2 deletions(-) + create mode 100644 arch/mips/lantiq/devices.c + create mode 100644 arch/mips/lantiq/devices.h + create mode 100644 arch/mips/lantiq/xway/devices.c + create mode 100644 arch/mips/lantiq/xway/devices.h + +diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile +index a268391..e5dae0e 100644 +--- a/arch/mips/lantiq/Makefile ++++ b/arch/mips/lantiq/Makefile +@@ -4,7 +4,7 @@ + # under the terms of the GNU General Public License version 2 as published + # by the Free Software Foundation. + +-obj-y := irq.o setup.o clk.o prom.o ++obj-y := irq.o setup.o clk.o prom.o devices.o + + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + +diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c +new file mode 100644 +index 0000000..7b82c34 +--- /dev/null ++++ b/arch/mips/lantiq/devices.c +@@ -0,0 +1,122 @@ ++/* ++ * 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/module.h> ++#include <linux/types.h> ++#include <linux/string.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 "devices.h" ++ ++/* nor flash */ ++static struct resource ltq_nor_resource = { ++ .name = "nor", ++ .start = LTQ_FLASH_START, ++ .end = LTQ_FLASH_START + LTQ_FLASH_MAX - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static struct platform_device ltq_nor = { ++ .name = "ltq_nor", ++ .resource = <q_nor_resource, ++ .num_resources = 1, ++}; ++ ++void __init ltq_register_nor(struct physmap_flash_data *data) ++{ ++ ltq_nor.dev.platform_data = data; ++ platform_device_register(<q_nor); ++} ++ ++/* watchdog */ ++static struct resource ltq_wdt_resource = { ++ .name = "watchdog", ++ .start = LTQ_WDT_BASE_ADDR, ++ .end = LTQ_WDT_BASE_ADDR + LTQ_WDT_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++void __init ltq_register_wdt(void) ++{ ++ platform_device_register_simple("ltq_wdt", 0, <q_wdt_resource, 1); ++} ++ ++/* asc ports */ ++static struct resource ltq_asc0_resources[] = { ++ { ++ .name = "asc0", ++ .start = LTQ_ASC0_BASE_ADDR, ++ .end = LTQ_ASC0_BASE_ADDR + LTQ_ASC_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ IRQ_RES(tx, LTQ_ASC_TIR(0)), ++ IRQ_RES(rx, LTQ_ASC_RIR(0)), ++ IRQ_RES(err, LTQ_ASC_EIR(0)), ++}; ++ ++static struct resource ltq_asc1_resources[] = { ++ { ++ .name = "asc1", ++ .start = LTQ_ASC1_BASE_ADDR, ++ .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ IRQ_RES(tx, LTQ_ASC_TIR(1)), ++ IRQ_RES(rx, LTQ_ASC_RIR(1)), ++ IRQ_RES(err, LTQ_ASC_EIR(1)), ++}; ++ ++void __init ltq_register_asc(int port) ++{ ++ switch (port) { ++ case 0: ++ platform_device_register_simple("ltq_asc", 0, ++ ltq_asc0_resources, ARRAY_SIZE(ltq_asc0_resources)); ++ break; ++ case 1: ++ platform_device_register_simple("ltq_asc", 1, ++ ltq_asc1_resources, ARRAY_SIZE(ltq_asc1_resources)); ++ break; ++ default: ++ break; ++ } ++} ++ ++#ifdef CONFIG_PCI ++/* pci */ ++static struct platform_device ltq_pci = { ++ .name = "ltq_pci", ++ .num_resources = 0, ++}; ++ ++void __init ltq_register_pci(struct ltq_pci_data *data) ++{ ++ ltq_pci.dev.platform_data = data; ++ platform_device_register(<q_pci); ++} ++#else ++void __init ltq_register_pci(struct ltq_pci_data *data) ++{ ++ pr_err("kernel is compiled without PCI support\n"); ++} ++#endif +diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h +new file mode 100644 +index 0000000..2947bb1 +--- /dev/null ++++ b/arch/mips/lantiq/devices.h +@@ -0,0 +1,23 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_DEVICES_H__ ++#define _LTQ_DEVICES_H__ ++ ++#include <lantiq_platform.h> ++#include <linux/mtd/physmap.h> ++ ++#define IRQ_RES(resname, irq) \ ++ {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ} ++ ++extern void ltq_register_nor(struct physmap_flash_data *data); ++extern void ltq_register_wdt(void); ++extern void ltq_register_asc(int port); ++extern void ltq_register_pci(struct ltq_pci_data *data); ++ ++#endif +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 9c85ff9..74ce438 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := pmu.o ebu.o reset.o gpio.o ++obj-y := pmu.o ebu.o reset.o gpio.o devices.o + + obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o + obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +new file mode 100644 +index 0000000..a71b3b5 +--- /dev/null ++++ b/arch/mips/lantiq/xway/devices.c +@@ -0,0 +1,98 @@ ++/* ++ * 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/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> ++ ++#include "devices.h" ++ ++/* gpio */ ++static struct resource ltq_gpio_resource[] = { ++ { ++ .name = "gpio0", ++ .start = LTQ_GPIO0_BASE_ADDR, ++ .end = LTQ_GPIO0_BASE_ADDR + LTQ_GPIO_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .name = "gpio1", ++ .start = LTQ_GPIO1_BASE_ADDR, ++ .end = LTQ_GPIO1_BASE_ADDR + LTQ_GPIO_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .name = "gpio2", ++ .start = LTQ_GPIO2_BASE_ADDR, ++ .end = LTQ_GPIO2_BASE_ADDR + LTQ_GPIO_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ } ++}; ++ ++void __init ltq_register_gpio(void) ++{ ++ platform_device_register_simple("ltq_gpio", 0, ++ <q_gpio_resource[0], 1); ++ platform_device_register_simple("ltq_gpio", 1, ++ <q_gpio_resource[1], 1); ++ ++ /* AR9 and VR9 have an extra gpio block */ ++ if (ltq_is_ar9() || ltq_is_vr9()) { ++ platform_device_register_simple("ltq_gpio", 2, ++ <q_gpio_resource[2], 1); ++ } ++} ++ ++/* serial to parallel conversion */ ++static struct resource ltq_stp_resource = { ++ .name = "stp", ++ .start = LTQ_STP_BASE_ADDR, ++ .end = LTQ_STP_BASE_ADDR + LTQ_STP_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++void __init ltq_register_gpio_stp(void) ++{ ++ platform_device_register_simple("ltq_stp", 0, <q_stp_resource, 1); ++} ++ ++/* asc ports - amazon se has its own serial mapping */ ++static struct resource ltq_ase_asc_resources[] = { ++ { ++ .name = "asc0", ++ .start = LTQ_ASC1_BASE_ADDR, ++ .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ IRQ_RES(tx, LTQ_ASC_ASE_TIR), ++ IRQ_RES(rx, LTQ_ASC_ASE_RIR), ++ IRQ_RES(err, LTQ_ASC_ASE_EIR), ++}; ++ ++void __init ltq_register_ase_asc(void) ++{ ++ platform_device_register_simple("ltq_asc", 0, ++ ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources)); ++} +diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h +new file mode 100644 +index 0000000..51f56b5 +--- /dev/null ++++ b/arch/mips/lantiq/xway/devices.h +@@ -0,0 +1,18 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_DEVICES_XWAY_H__ ++#define _LTQ_DEVICES_XWAY_H__ ++ ++#include "../devices.h" ++ ++extern void ltq_register_gpio(void); ++extern void ltq_register_gpio_stp(void); ++extern void ltq_register_ase_asc(void); ++ ++#endif +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches-2.6.32/0006-MIPS-Lantiq-Add-mips_machine-support.patch b/target/linux/lantiq/patches-2.6.32/0006-MIPS-Lantiq-Add-mips_machine-support.patch new file mode 100644 index 0000000..9e02b6a --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0006-MIPS-Lantiq-Add-mips_machine-support.patch @@ -0,0 +1,170 @@ +From 52a5369d1067d4feddbfa7ff4486a77ac9a2971e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:54 +0200 +Subject: [PATCH 06/13] MIPS: Lantiq: Add mips_machine support + +This patch adds support for Gabor's mips_machine patch. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: Gabor Juhos <juhosg@openwrt.org> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2251/ +Patchwork: https://patchwork.linux-mips.org/patch/2358/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/Kconfig | 1 + + arch/mips/lantiq/machtypes.h | 18 ++++++++++++++++++ + arch/mips/lantiq/prom.h | 1 + + arch/mips/lantiq/setup.c | 25 +++++++++++++++++++++++++ + arch/mips/lantiq/xway/Makefile | 4 ++-- + arch/mips/lantiq/xway/setup-ase.c | 19 +++++++++++++++++++ + arch/mips/lantiq/xway/setup-xway.c | 20 ++++++++++++++++++++ + 7 files changed, 86 insertions(+), 2 deletions(-) + create mode 100644 arch/mips/lantiq/machtypes.h + create mode 100644 arch/mips/lantiq/xway/setup-ase.c + create mode 100644 arch/mips/lantiq/xway/setup-xway.c + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -190,6 +190,7 @@ + select SWAP_IO_SPACE + select BOOT_RAW + select HAVE_CLK ++ select MIPS_MACHINE + + config LASAT + bool "LASAT Networks platforms" +--- /dev/null ++++ b/arch/mips/lantiq/machtypes.h +@@ -0,0 +1,18 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LANTIQ_MACH_H__ ++#define _LANTIQ_MACH_H__ ++ ++#include <asm/mips_machine.h> ++ ++enum lantiq_mach_type { ++ LTQ_MACH_GENERIC = 0, ++}; ++ ++#endif +--- a/arch/mips/lantiq/prom.h ++++ b/arch/mips/lantiq/prom.h +@@ -20,5 +20,6 @@ + }; + + extern void ltq_soc_detect(struct ltq_soc_info *i); ++extern void ltq_soc_setup(void); + + #endif +--- a/arch/mips/lantiq/setup.c ++++ b/arch/mips/lantiq/setup.c +@@ -14,6 +14,12 @@ + + #include <lantiq_soc.h> + ++#include "machtypes.h" ++#include "devices.h" ++#include "prom.h" ++ ++unsigned long physical_memsize = 0L; ++ + void __init plat_mem_setup(void) + { + /* assume 16M as default incase uboot fails to pass proper ramsize */ +@@ -32,10 +38,32 @@ + if (!strncmp(e, "memsize=", 8)) { + e += 8; + if (strict_strtoul(e, 0, &memsize)) +- pr_warn("bad memsize specified\n"); ++ pr_warning("bad memsize specified\n"); + } + envp++; + } + memsize *= 1024 * 1024; + add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); ++ physical_memsize = memsize; ++} ++ ++static int __init ++lantiq_setup(void) ++{ ++ ltq_soc_setup(); ++ mips_machine_setup(); ++ return 0; + } ++ ++arch_initcall(lantiq_setup); ++ ++static void __init ++lantiq_generic_init(void) ++{ ++ /* Nothing to do */ ++} ++ ++MIPS_MACHINE(LTQ_MACH_GENERIC, ++ "Generic", ++ "Generic Lantiq based board", ++ lantiq_generic_init); +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ + obj-y := pmu.o ebu.o reset.o gpio.o devices.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) += clk-xway.o prom-xway.o setup-xway.o ++obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o +--- /dev/null ++++ b/arch/mips/lantiq/xway/setup-ase.c +@@ -0,0 +1,19 @@ ++/* ++ * 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 <lantiq_soc.h> ++ ++#include "../prom.h" ++#include "devices.h" ++ ++void __init ltq_soc_setup(void) ++{ ++ ltq_register_ase_asc(); ++ ltq_register_gpio(); ++ ltq_register_wdt(); ++} +--- /dev/null ++++ b/arch/mips/lantiq/xway/setup-xway.c +@@ -0,0 +1,20 @@ ++/* ++ * 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 <lantiq_soc.h> ++ ++#include "../prom.h" ++#include "devices.h" ++ ++void __init ltq_soc_setup(void) ++{ ++ ltq_register_asc(0); ++ ltq_register_asc(1); ++ ltq_register_gpio(); ++ ltq_register_wdt(); ++} diff --git a/target/linux/lantiq/patches-2.6.32/0007-MIPS-Lantiq-Add-machtypes-for-lantiq-eval-kits.patch b/target/linux/lantiq/patches-2.6.32/0007-MIPS-Lantiq-Add-machtypes-for-lantiq-eval-kits.patch new file mode 100644 index 0000000..e69558c --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0007-MIPS-Lantiq-Add-machtypes-for-lantiq-eval-kits.patch @@ -0,0 +1,230 @@ +From ab2182fc419548455d03979683eb0e92c372ed79 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:55 +0200 +Subject: [PATCH 07/13] MIPS: Lantiq: Add machtypes for lantiq eval kits + +This patch adds mach specific code for the Lantiq EASY50712/50601 evaluation +boards + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2255/ +Patchwork: https://patchwork.linux-mips.org/patch/2361/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/lantiq/Kconfig | 2 + + arch/mips/lantiq/machtypes.h | 2 + + arch/mips/lantiq/xway/Kconfig | 23 +++++++++++ + arch/mips/lantiq/xway/Makefile | 3 + + arch/mips/lantiq/xway/mach-easy50601.c | 57 ++++++++++++++++++++++++++ + arch/mips/lantiq/xway/mach-easy50712.c | 68 ++++++++++++++++++++++++++++++++ + 6 files changed, 155 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/lantiq/xway/Kconfig + create mode 100644 arch/mips/lantiq/xway/mach-easy50601.c + create mode 100644 arch/mips/lantiq/xway/mach-easy50712.c + +diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig +index 2780461..3fccf21 100644 +--- a/arch/mips/lantiq/Kconfig ++++ b/arch/mips/lantiq/Kconfig +@@ -18,4 +18,6 @@ config SOC_XWAY + select HW_HAS_PCI + endchoice + ++source "arch/mips/lantiq/xway/Kconfig" ++ + endif +diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h +index ffcacfc..7e01b8c 100644 +--- a/arch/mips/lantiq/machtypes.h ++++ b/arch/mips/lantiq/machtypes.h +@@ -13,6 +13,8 @@ + + enum lantiq_mach_type { + LTQ_MACH_GENERIC = 0, ++ LTQ_MACH_EASY50712, /* Danube evaluation board */ ++ LTQ_MACH_EASY50601, /* Amazon SE evaluation board */ + }; + + #endif +diff --git a/arch/mips/lantiq/xway/Kconfig b/arch/mips/lantiq/xway/Kconfig +new file mode 100644 +index 0000000..2b857de +--- /dev/null ++++ b/arch/mips/lantiq/xway/Kconfig +@@ -0,0 +1,23 @@ ++if SOC_XWAY ++ ++menu "MIPS Machine" ++ ++config LANTIQ_MACH_EASY50712 ++ bool "Easy50712 - Danube" ++ default y ++ ++endmenu ++ ++endif ++ ++if SOC_AMAZON_SE ++ ++menu "MIPS Machine" ++ ++config LANTIQ_MACH_EASY50601 ++ bool "Easy50601 - Amazon SE" ++ default y ++ ++endmenu ++ ++endif +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 8c06a97..b1d3640 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -2,3 +2,6 @@ obj-y := pmu.o ebu.o reset.o gpio.o devices.o + + obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o + obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-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/mach-easy50601.c b/arch/mips/lantiq/xway/mach-easy50601.c +new file mode 100644 +index 0000000..d5aaf63 +--- /dev/null ++++ b/arch/mips/lantiq/xway/mach-easy50601.c +@@ -0,0 +1,57 @@ ++/* ++ * 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 <lantiq.h> ++ ++#include "../machtypes.h" ++#include "devices.h" ++ ++static struct mtd_partition easy50601_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 easy50601_flash_data = { ++ .nr_parts = ARRAY_SIZE(easy50601_partitions), ++ .parts = easy50601_partitions, ++}; ++ ++static void __init easy50601_init(void) ++{ ++ ltq_register_nor(&easy50601_flash_data); ++} ++ ++MIPS_MACHINE(LTQ_MACH_EASY50601, ++ "EASY50601", ++ "EASY50601 Eval Board", ++ easy50601_init); +diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c +new file mode 100644 +index 0000000..e5e7e09 +--- /dev/null ++++ b/arch/mips/lantiq/xway/mach-easy50712.c +@@ -0,0 +1,68 @@ ++/* ++ * 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 <lantiq_soc.h> ++#include <irq.h> ++ ++#include "../machtypes.h" ++#include "devices.h" ++ ++static struct mtd_partition easy50712_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 easy50712_flash_data = { ++ .nr_parts = ARRAY_SIZE(easy50712_partitions), ++ .parts = easy50712_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 void __init easy50712_init(void) ++{ ++ ltq_register_gpio_stp(); ++ ltq_register_nor(&easy50712_flash_data); ++ ltq_register_pci(<q_pci_data); ++} ++ ++MIPS_MACHINE(LTQ_MACH_EASY50712, ++ "EASY50712", ++ "EASY50712 Eval Board", ++ easy50712_init); +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches-2.6.32/0008-MIPS-Lantiq-Add-more-gpio-drivers.patch b/target/linux/lantiq/patches-2.6.32/0008-MIPS-Lantiq-Add-more-gpio-drivers.patch new file mode 100644 index 0000000..2daa9e0 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0008-MIPS-Lantiq-Add-more-gpio-drivers.patch @@ -0,0 +1,330 @@ +From f9391211e47cdcc31f341d710efef4b3b46c333d Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:56 +0200 +Subject: [PATCH 08/13] MIPS: Lantiq: Add more gpio drivers + +The XWAY family allows to extend the number of gpios by using shift registers or latches. This patch adds the 2 drivers needed for this. The extended gpios are output only. + +[ralf@linux-mips.org: Fixed ltq_stp_probe section() attributes.] + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2258/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/lantiq/xway/Makefile | 2 +- + arch/mips/lantiq/xway/gpio_ebu.c | 126 ++++++++++++++++++++++++++++++ + arch/mips/lantiq/xway/gpio_stp.c | 157 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 284 insertions(+), 1 deletions(-) + create mode 100644 arch/mips/lantiq/xway/gpio_ebu.c + create mode 100644 arch/mips/lantiq/xway/gpio_stp.c + +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index b1d3640..6b5e07e 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := pmu.o ebu.o reset.o gpio.o devices.o ++obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o + + obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o + obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o +diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c +new file mode 100644 +index 0000000..a479355 +--- /dev/null ++++ b/arch/mips/lantiq/xway/gpio_ebu.c +@@ -0,0 +1,126 @@ ++/* ++ * 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/module.h> ++#include <linux/types.h> ++#include <linux/platform_device.h> ++#include <linux/mutex.h> ++#include <linux/gpio.h> ++#include <linux/io.h> ++ ++#include <lantiq_soc.h> ++ ++/* ++ * By attaching hardware latches to the EBU it is possible to create output ++ * only gpios. This driver configures a special memory address, which when ++ * written to outputs 16 bit to the latches. ++ */ ++ ++#define LTQ_EBU_BUSCON 0x1e7ff /* 16 bit access, slowest timing */ ++#define LTQ_EBU_WP 0x80000000 /* write protect bit */ ++ ++/* we keep a shadow value of the last value written to the ebu */ ++static int ltq_ebu_gpio_shadow = 0x0; ++static void __iomem *ltq_ebu_gpio_membase; ++ ++static void ltq_ebu_apply(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1); ++ *((__u16 *)ltq_ebu_gpio_membase) = ltq_ebu_gpio_shadow; ++ ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); ++ spin_unlock_irqrestore(&ebu_lock, flags); ++} ++ ++static void ltq_ebu_set(struct gpio_chip *chip, unsigned offset, int value) ++{ ++ if (value) ++ ltq_ebu_gpio_shadow |= (1 << offset); ++ else ++ ltq_ebu_gpio_shadow &= ~(1 << offset); ++ ltq_ebu_apply(); ++} ++ ++static int ltq_ebu_direction_output(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ ltq_ebu_set(chip, offset, value); ++ ++ return 0; ++} ++ ++static struct gpio_chip ltq_ebu_chip = { ++ .label = "ltq_ebu", ++ .direction_output = ltq_ebu_direction_output, ++ .set = ltq_ebu_set, ++ .base = 72, ++ .ngpio = 16, ++ .can_sleep = 1, ++ .owner = THIS_MODULE, ++}; ++ ++static int ltq_ebu_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get memory resource\n"); ++ return -ENOENT; ++ } ++ ++ 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 memory resource\n"); ++ return -EBUSY; ++ } ++ ++ ltq_ebu_gpio_membase = devm_ioremap_nocache(&pdev->dev, res->start, ++ resource_size(res)); ++ if (!ltq_ebu_gpio_membase) { ++ dev_err(&pdev->dev, "Failed to ioremap mem region\n"); ++ return -ENOMEM; ++ } ++ ++ /* grab the default shadow value passed form the platform code */ ++ ltq_ebu_gpio_shadow = (unsigned int) pdev->dev.platform_data; ++ ++ /* tell the ebu controller which memory address we will be using */ ++ ltq_ebu_w32(pdev->resource->start | 0x1, LTQ_EBU_ADDRSEL1); ++ ++ /* write protect the region */ ++ ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); ++ ++ ret = gpiochip_add(<q_ebu_chip); ++ if (!ret) ++ ltq_ebu_apply(); ++ return ret; ++} ++ ++static struct platform_driver ltq_ebu_driver = { ++ .probe = ltq_ebu_probe, ++ .driver = { ++ .name = "ltq_ebu", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init ltq_ebu_init(void) ++{ ++ int ret = platform_driver_register(<q_ebu_driver); ++ ++ if (ret) ++ pr_info("ltq_ebu : Error registering platfom driver!"); ++ return ret; ++} ++ ++postcore_initcall(ltq_ebu_init); +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +new file mode 100644 +index 0000000..67d59d6 +--- /dev/null ++++ b/arch/mips/lantiq/xway/gpio_stp.c +@@ -0,0 +1,157 @@ ++/* ++ * 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) 2007 John Crispin <blogic@openwrt.org> ++ * ++ */ ++ ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/platform_device.h> ++#include <linux/mutex.h> ++#include <linux/io.h> ++#include <linux/gpio.h> ++ ++#include <lantiq_soc.h> ++ ++#define LTQ_STP_CON0 0x00 ++#define LTQ_STP_CON1 0x04 ++#define LTQ_STP_CPU0 0x08 ++#define LTQ_STP_CPU1 0x0C ++#define LTQ_STP_AR 0x10 ++ ++#define LTQ_STP_CON_SWU (1 << 31) ++#define LTQ_STP_2HZ 0 ++#define LTQ_STP_4HZ (1 << 23) ++#define LTQ_STP_8HZ (2 << 23) ++#define LTQ_STP_10HZ (3 << 23) ++#define LTQ_STP_SPEED_MASK (0xf << 23) ++#define LTQ_STP_UPD_FPI (1 << 31) ++#define LTQ_STP_UPD_MASK (3 << 30) ++#define LTQ_STP_ADSL_SRC (3 << 24) ++ ++#define LTQ_STP_GROUP0 (1 << 0) ++ ++#define LTQ_STP_RISING 0 ++#define LTQ_STP_FALLING (1 << 26) ++#define LTQ_STP_EDGE_MASK (1 << 26) ++ ++#define ltq_stp_r32(reg) __raw_readl(ltq_stp_membase + reg) ++#define ltq_stp_w32(val, reg) __raw_writel(val, ltq_stp_membase + reg) ++#define ltq_stp_w32_mask(clear, set, reg) \ ++ ltq_w32((ltq_r32(ltq_stp_membase + reg) & ~(clear)) | (set), \ ++ ltq_stp_membase + (reg)) ++ ++static int ltq_stp_shadow = 0xffff; ++static void __iomem *ltq_stp_membase; ++ ++static void ltq_stp_set(struct gpio_chip *chip, unsigned offset, int value) ++{ ++ if (value) ++ ltq_stp_shadow |= (1 << offset); ++ else ++ ltq_stp_shadow &= ~(1 << offset); ++ ltq_stp_w32(ltq_stp_shadow, LTQ_STP_CPU0); ++} ++ ++static int ltq_stp_direction_output(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ ltq_stp_set(chip, offset, value); ++ ++ return 0; ++} ++ ++static struct gpio_chip ltq_stp_chip = { ++ .label = "ltq_stp", ++ .direction_output = ltq_stp_direction_output, ++ .set = ltq_stp_set, ++ .base = 48, ++ .ngpio = 24, ++ .can_sleep = 1, ++ .owner = THIS_MODULE, ++}; ++ ++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"); ++ ++ /* sane defaults */ ++ ltq_stp_w32(0, LTQ_STP_AR); ++ ltq_stp_w32(0, LTQ_STP_CPU0); ++ ltq_stp_w32(0, LTQ_STP_CPU1); ++ ltq_stp_w32(LTQ_STP_CON_SWU, LTQ_STP_CON0); ++ ltq_stp_w32(0, LTQ_STP_CON1); ++ ++ /* rising or falling edge */ ++ ltq_stp_w32_mask(LTQ_STP_EDGE_MASK, LTQ_STP_FALLING, LTQ_STP_CON0); ++ ++ /* per default stp 15-0 are set */ ++ ltq_stp_w32_mask(0, LTQ_STP_GROUP0, LTQ_STP_CON1); ++ ++ /* stp are update periodically by the FPI bus */ ++ ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1); ++ ++ /* set stp update speed */ ++ ltq_stp_w32_mask(LTQ_STP_SPEED_MASK, LTQ_STP_8HZ, LTQ_STP_CON1); ++ ++ /* tell the hardware that pin (led) 0 and 1 are controlled ++ * by the dsl arc ++ */ ++ ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0); ++ ++ ltq_pmu_enable(PMU_LED); ++ return 0; ++} ++ ++static int __devinit ltq_stp_probe(struct platform_device *pdev) ++{ ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ int ret = 0; ++ ++ if (!res) ++ return -ENOENT; ++ 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 STP memory\n"); ++ return -EBUSY; ++ } ++ ltq_stp_membase = devm_ioremap_nocache(&pdev->dev, res->start, ++ resource_size(res)); ++ if (!ltq_stp_membase) { ++ dev_err(&pdev->dev, "failed to remap STP memory\n"); ++ return -ENOMEM; ++ } ++ ret = gpiochip_add(<q_stp_chip); ++ if (!ret) ++ ret = ltq_stp_hw_init(); ++ ++ return ret; ++} ++ ++static struct platform_driver ltq_stp_driver = { ++ .probe = ltq_stp_probe, ++ .driver = { ++ .name = "ltq_stp", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init ltq_stp_init(void) ++{ ++ int ret = platform_driver_register(<q_stp_driver); ++ ++ if (ret) ++ pr_info("ltq_stp: error registering platfom driver"); ++ return ret; ++} ++ ++postcore_initcall(ltq_stp_init); +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches/200-serial.patch b/target/linux/lantiq/patches-2.6.32/0009-SERIAL-Lantiq-Add-driver-for-MIPS-Lantiq-SOCs.patch index 5f2df56..1d04aaa 100644 --- a/target/linux/lantiq/patches/200-serial.patch +++ b/target/linux/lantiq/patches-2.6.32/0009-SERIAL-Lantiq-Add-driver-for-MIPS-Lantiq-SOCs.patch @@ -1,30 +1,27 @@ ---- a/drivers/serial/Kconfig -+++ b/drivers/serial/Kconfig -@@ -1454,6 +1454,14 @@ - help - Support for Console on the NWP serial ports. - -+config SERIAL_LANTIQ -+ bool "Lantiq serial driver" -+ depends on LANTIQ -+ select SERIAL_CORE -+ select SERIAL_CORE_CONSOLE -+ help -+ Driver for the Lantiq SoC ASC hardware -+ - config SERIAL_QE - tristate "Freescale QUICC Engine serial port support" - depends on QUICC_ENGINE ---- a/drivers/serial/Makefile -+++ b/drivers/serial/Makefile -@@ -89,3 +89,4 @@ - obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o - obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o - obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o -+obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o +From 1d2b44b1afa3ef081cd817dbf947d48eb8f5d21a Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 5 Apr 2011 14:10:57 +0200 +Subject: [PATCH 09/13] SERIAL: Lantiq: Add driver for MIPS Lantiq SOCs. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +Cc: alan@lxorguk.ukuu.org.uk +Cc: linux-mips@linux-mips.org +Cc: linux-serial@vger.kernel.org +Patchwork: https://patchwork.linux-mips.org/patch/2269/ +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + drivers/tty/serial/Kconfig | 8 + + drivers/tty/serial/Makefile | 1 + + drivers/tty/serial/lantiq.c | 756 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 765 insertions(+), 0 deletions(-) + create mode 100644 drivers/tty/serial/lantiq.c + --- /dev/null +++ b/drivers/serial/lantiq.c -@@ -0,0 +1,772 @@ +@@ -0,0 +1,756 @@ +/* + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * @@ -44,7 +41,7 @@ + * Copyright (C) 2004 Infineon IFAP DC COM CPE + * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2007 John Crispin <blogic@openwrt.org> -+ * Copyright (C) 2010 Thomas Langer, Lantiq Deutschland ++ * Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com> + */ + +#include <linux/slab.h> @@ -62,112 +59,95 @@ +#include <linux/io.h> +#include <linux/clk.h> + -+#define lq_r32(reg) __raw_readl(reg) -+#define lq_r8(reg) __raw_readb(reg) -+#define lq_w32(val, reg) __raw_writel(val, reg) -+#define lq_w8(val, reg) __raw_writeb(val, reg) -+#define lq_w32_mask(clear, set, reg) lq_w32((lq_r32(reg) & ~(clear)) | (set), reg) ++#include <lantiq_soc.h> + -+#define PORT_IFXMIPSASC 111 ++#define PORT_LTQ_ASC 111 +#define MAXPORTS 2 -+ -+#define UART_DUMMY_UER_RX 1 -+ -+#define DRVNAME "lq_asc" -+ ++#define UART_DUMMY_UER_RX 1 ++#define DRVNAME "ltq_asc" +#ifdef __BIG_ENDIAN -+#define IFXMIPS_ASC_TBUF (0x0020 + 3) -+#define IFXMIPS_ASC_RBUF (0x0024 + 3) ++#define LTQ_ASC_TBUF (0x0020 + 3) ++#define LTQ_ASC_RBUF (0x0024 + 3) +#else -+#define IFXMIPS_ASC_TBUF 0x0020 -+#define IFXMIPS_ASC_RBUF 0x0024 ++#define LTQ_ASC_TBUF 0x0020 ++#define LTQ_ASC_RBUF 0x0024 +#endif -+ -+#define IFXMIPS_ASC_FSTAT 0x0048 -+#define IFXMIPS_ASC_WHBSTATE 0x0018 -+#define IFXMIPS_ASC_STATE 0x0014 -+#define IFXMIPS_ASC_IRNCR 0x00F8 -+#define IFXMIPS_ASC_CLC 0x0000 -+#define IFXMIPS_ASC_ID 0x0008 -+#define IFXMIPS_ASC_PISEL 0x0004 -+#define IFXMIPS_ASC_TXFCON 0x0044 -+#define IFXMIPS_ASC_RXFCON 0x0040 -+#define IFXMIPS_ASC_CON 0x0010 -+#define IFXMIPS_ASC_BG 0x0050 -+#define IFXMIPS_ASC_IRNREN 0x00F4 -+ -+#define ASC_IRNREN_TX 0x1 -+#define ASC_IRNREN_RX 0x2 -+#define ASC_IRNREN_ERR 0x4 -+#define ASC_IRNREN_TX_BUF 0x8 -+#define ASC_IRNCR_TIR 0x1 -+#define ASC_IRNCR_RIR 0x2 -+#define ASC_IRNCR_EIR 0x4 -+ -+#define ASCOPT_CSIZE 0x3 -+#define ASCOPT_CS7 0x1 -+#define ASCOPT_CS8 0x2 -+#define ASCOPT_PARENB 0x4 -+#define ASCOPT_STOPB 0x8 -+#define ASCOPT_PARODD 0x0 -+#define ASCOPT_CREAD 0x20 -+#define TXFIFO_FL 1 -+#define RXFIFO_FL 1 -+#define ASCCLC_DISS 0x2 -+#define ASCCLC_RMCMASK 0x0000FF00 -+#define ASCCLC_RMCOFFSET 8 -+#define ASCCON_M_8ASYNC 0x0 -+#define ASCCON_M_7ASYNC 0x2 -+#define ASCCON_ODD 0x00000020 -+#define ASCCON_STP 0x00000080 -+#define ASCCON_BRS 0x00000100 -+#define ASCCON_FDE 0x00000200 -+#define ASCCON_R 0x00008000 -+#define ASCCON_FEN 0x00020000 -+#define ASCCON_ROEN 0x00080000 -+#define ASCCON_TOEN 0x00100000 -+#define ASCSTATE_PE 0x00010000 -+#define ASCSTATE_FE 0x00020000 -+#define ASCSTATE_ROE 0x00080000 -+#define ASCSTATE_ANY (ASCSTATE_ROE|ASCSTATE_PE|ASCSTATE_FE) -+#define ASCWHBSTATE_CLRREN 0x00000001 -+#define ASCWHBSTATE_SETREN 0x00000002 -+#define ASCWHBSTATE_CLRPE 0x00000004 -+#define ASCWHBSTATE_CLRFE 0x00000008 -+#define ASCWHBSTATE_CLRROE 0x00000020 -+#define ASCTXFCON_TXFEN 0x0001 -+#define ASCTXFCON_TXFFLU 0x0002 -+#define ASCTXFCON_TXFITLMASK 0x3F00 -+#define ASCTXFCON_TXFITLOFF 8 -+#define ASCRXFCON_RXFEN 0x0001 -+#define ASCRXFCON_RXFFLU 0x0002 -+#define ASCRXFCON_RXFITLMASK 0x3F00 -+#define ASCRXFCON_RXFITLOFF 8 -+#define ASCFSTAT_RXFFLMASK 0x003F -+#define ASCFSTAT_TXFFLMASK 0x3F00 -+#define ASCFSTAT_TXFFLOFF 8 -+#define ASCFSTAT_RXFREEMASK 0x003F0000 -+#define ASCFSTAT_RXFREEOFF 16 -+#define ASCFSTAT_TXFREEMASK 0x3F000000 -+#define ASCFSTAT_TXFREEOFF 24 ++#define LTQ_ASC_FSTAT 0x0048 ++#define LTQ_ASC_WHBSTATE 0x0018 ++#define LTQ_ASC_STATE 0x0014 ++#define LTQ_ASC_IRNCR 0x00F8 ++#define LTQ_ASC_CLC 0x0000 ++#define LTQ_ASC_ID 0x0008 ++#define LTQ_ASC_PISEL 0x0004 ++#define LTQ_ASC_TXFCON 0x0044 ++#define LTQ_ASC_RXFCON 0x0040 ++#define LTQ_ASC_CON 0x0010 ++#define LTQ_ASC_BG 0x0050 ++#define LTQ_ASC_IRNREN 0x00F4 ++ ++#define ASC_IRNREN_TX 0x1 ++#define ASC_IRNREN_RX 0x2 ++#define ASC_IRNREN_ERR 0x4 ++#define ASC_IRNREN_TX_BUF 0x8 ++#define ASC_IRNCR_TIR 0x1 ++#define ASC_IRNCR_RIR 0x2 ++#define ASC_IRNCR_EIR 0x4 ++ ++#define ASCOPT_CSIZE 0x3 ++#define TXFIFO_FL 1 ++#define RXFIFO_FL 1 ++#define ASCCLC_DISS 0x2 ++#define ASCCLC_RMCMASK 0x0000FF00 ++#define ASCCLC_RMCOFFSET 8 ++#define ASCCON_M_8ASYNC 0x0 ++#define ASCCON_M_7ASYNC 0x2 ++#define ASCCON_ODD 0x00000020 ++#define ASCCON_STP 0x00000080 ++#define ASCCON_BRS 0x00000100 ++#define ASCCON_FDE 0x00000200 ++#define ASCCON_R 0x00008000 ++#define ASCCON_FEN 0x00020000 ++#define ASCCON_ROEN 0x00080000 ++#define ASCCON_TOEN 0x00100000 ++#define ASCSTATE_PE 0x00010000 ++#define ASCSTATE_FE 0x00020000 ++#define ASCSTATE_ROE 0x00080000 ++#define ASCSTATE_ANY (ASCSTATE_ROE|ASCSTATE_PE|ASCSTATE_FE) ++#define ASCWHBSTATE_CLRREN 0x00000001 ++#define ASCWHBSTATE_SETREN 0x00000002 ++#define ASCWHBSTATE_CLRPE 0x00000004 ++#define ASCWHBSTATE_CLRFE 0x00000008 ++#define ASCWHBSTATE_CLRROE 0x00000020 ++#define ASCTXFCON_TXFEN 0x0001 ++#define ASCTXFCON_TXFFLU 0x0002 ++#define ASCTXFCON_TXFITLMASK 0x3F00 ++#define ASCTXFCON_TXFITLOFF 8 ++#define ASCRXFCON_RXFEN 0x0001 ++#define ASCRXFCON_RXFFLU 0x0002 ++#define ASCRXFCON_RXFITLMASK 0x3F00 ++#define ASCRXFCON_RXFITLOFF 8 ++#define ASCFSTAT_RXFFLMASK 0x003F ++#define ASCFSTAT_TXFFLMASK 0x3F00 ++#define ASCFSTAT_TXFREEMASK 0x3F000000 ++#define ASCFSTAT_TXFREEOFF 24 + +static void lqasc_tx_chars(struct uart_port *port); -+extern void prom_printf(const char *fmt, ...); -+static struct lq_uart_port *lqasc_port[2]; ++static struct ltq_uart_port *lqasc_port[MAXPORTS]; +static struct uart_driver lqasc_reg; ++static DEFINE_SPINLOCK(ltq_asc_lock); + -+struct lq_uart_port { ++struct ltq_uart_port { + struct uart_port port; -+ struct clk *clk; ++ struct clk *clk; + unsigned int tx_irq; + unsigned int rx_irq; + unsigned int err_irq; +}; + +static inline struct -+lq_uart_port *to_lq_uart_port(struct uart_port *port) ++ltq_uart_port *to_ltq_uart_port(struct uart_port *port) +{ -+ return container_of(port, struct lq_uart_port, port); ++ return container_of(port, struct ltq_uart_port, port); +} + +static void @@ -180,16 +160,16 @@ +lqasc_start_tx(struct uart_port *port) +{ + unsigned long flags; -+ local_irq_save(flags); ++ spin_lock_irqsave(<q_asc_lock, flags); + lqasc_tx_chars(port); -+ local_irq_restore(flags); ++ spin_unlock_irqrestore(<q_asc_lock, flags); + return; +} + +static void +lqasc_stop_rx(struct uart_port *port) +{ -+ lq_w32(ASCWHBSTATE_CLRREN, port->membase + IFXMIPS_ASC_WHBSTATE); ++ ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE); +} + +static void @@ -197,17 +177,22 @@ +{ +} + -+static void ++static int +lqasc_rx_chars(struct uart_port *port) +{ -+ struct tty_struct *tty = port->state->port.tty; ++ struct tty_struct *tty = tty_port_tty_get(&port->state->port); + unsigned int ch = 0, rsr = 0, fifocnt; + -+ fifocnt = lq_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_RXFFLMASK; ++ if (!tty) { ++ dev_dbg(port->dev, "%s:tty is busy now", __func__); ++ return -EBUSY; ++ } ++ fifocnt = ++ ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK; + while (fifocnt--) { + u8 flag = TTY_NORMAL; -+ ch = lq_r8(port->membase + IFXMIPS_ASC_RBUF); -+ rsr = (lq_r32(port->membase + IFXMIPS_ASC_STATE) ++ ch = ltq_r8(port->membase + LTQ_ASC_RBUF); ++ rsr = (ltq_r32(port->membase + LTQ_ASC_STATE) + & ASCSTATE_ANY) | UART_DUMMY_UER_RX; + tty_flip_buffer_push(tty); + port->icount.rx++; @@ -219,17 +204,17 @@ + if (rsr & ASCSTATE_ANY) { + if (rsr & ASCSTATE_PE) { + port->icount.parity++; -+ lq_w32_mask(0, ASCWHBSTATE_CLRPE, -+ port->membase + IFXMIPS_ASC_WHBSTATE); ++ ltq_w32_mask(0, ASCWHBSTATE_CLRPE, ++ port->membase + LTQ_ASC_WHBSTATE); + } else if (rsr & ASCSTATE_FE) { + port->icount.frame++; -+ lq_w32_mask(0, ASCWHBSTATE_CLRFE, -+ port->membase + IFXMIPS_ASC_WHBSTATE); ++ ltq_w32_mask(0, ASCWHBSTATE_CLRFE, ++ port->membase + LTQ_ASC_WHBSTATE); + } + if (rsr & ASCSTATE_ROE) { + port->icount.overrun++; -+ lq_w32_mask(0, ASCWHBSTATE_CLRROE, -+ port->membase + IFXMIPS_ASC_WHBSTATE); ++ ltq_w32_mask(0, ASCWHBSTATE_CLRROE, ++ port->membase + LTQ_ASC_WHBSTATE); + } + + rsr &= port->read_status_mask; @@ -253,7 +238,8 @@ + } + if (ch != 0) + tty_flip_buffer_push(tty); -+ return; ++ tty_kref_put(tty); ++ return 0; +} + +static void @@ -265,10 +251,10 @@ + return; + } + -+ while (((lq_r32(port->membase + IFXMIPS_ASC_FSTAT) & ++ while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) & + ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) { + if (port->x_char) { -+ lq_w8(port->x_char, port->membase + IFXMIPS_ASC_TBUF); ++ ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF); + port->icount.tx++; + port->x_char = 0; + continue; @@ -277,8 +263,8 @@ + if (uart_circ_empty(xmit)) + break; + -+ lq_w8(port->state->xmit.buf[port->state->xmit.tail], -+ port->membase + IFXMIPS_ASC_TBUF); ++ ltq_w8(port->state->xmit.buf[port->state->xmit.tail], ++ port->membase + LTQ_ASC_TBUF); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } @@ -290,8 +276,11 @@ +static irqreturn_t +lqasc_tx_int(int irq, void *_port) +{ ++ unsigned long flags; + struct uart_port *port = (struct uart_port *)_port; -+ lq_w32(ASC_IRNCR_TIR, port->membase + IFXMIPS_ASC_IRNCR); ++ spin_lock_irqsave(<q_asc_lock, flags); ++ ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR); ++ spin_unlock_irqrestore(<q_asc_lock, flags); + lqasc_start_tx(port); + return IRQ_HANDLED; +} @@ -299,19 +288,25 @@ +static irqreturn_t +lqasc_err_int(int irq, void *_port) +{ ++ unsigned long flags; + struct uart_port *port = (struct uart_port *)_port; ++ spin_lock_irqsave(<q_asc_lock, flags); + /* clear any pending interrupts */ -+ lq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE | ASCWHBSTATE_CLRROE, -+ port->membase + IFXMIPS_ASC_WHBSTATE); ++ ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE | ++ ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE); ++ spin_unlock_irqrestore(<q_asc_lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t +lqasc_rx_int(int irq, void *_port) +{ ++ unsigned long flags; + struct uart_port *port = (struct uart_port *)_port; -+ lq_w32(ASC_IRNCR_RIR, port->membase + IFXMIPS_ASC_IRNCR); ++ spin_lock_irqsave(<q_asc_lock, flags); ++ ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR); + lqasc_rx_chars(port); ++ spin_unlock_irqrestore(<q_asc_lock, flags); + return IRQ_HANDLED; +} + @@ -319,7 +314,7 @@ +lqasc_tx_empty(struct uart_port *port) +{ + int status; -+ status = lq_r32(port->membase + IFXMIPS_ASC_FSTAT) & ASCFSTAT_TXFFLMASK; ++ status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK; + return status ? 0 : TIOCSER_TEMT; +} + @@ -342,73 +337,75 @@ +static int +lqasc_startup(struct uart_port *port) +{ -+ struct lq_uart_port *ifx_port = to_lq_uart_port(port); ++ struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); + int retval; + -+ port->uartclk = clk_get_rate(ifx_port->clk); ++ port->uartclk = clk_get_rate(ltq_port->clk); + -+ lq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), -+ port->membase + IFXMIPS_ASC_CLC); ++ ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), ++ port->membase + LTQ_ASC_CLC); + -+ lq_w32(0, port->membase + IFXMIPS_ASC_PISEL); -+ lq_w32( ++ ltq_w32(0, port->membase + LTQ_ASC_PISEL); ++ ltq_w32( + ((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) | + ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU, -+ port->membase + IFXMIPS_ASC_TXFCON); -+ lq_w32( ++ port->membase + LTQ_ASC_TXFCON); ++ ltq_w32( + ((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK) + | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU, -+ port->membase + IFXMIPS_ASC_RXFCON); -+ /* make sure other settings are written to hardware before setting enable bits */ ++ port->membase + LTQ_ASC_RXFCON); ++ /* make sure other settings are written to hardware before ++ * setting enable bits ++ */ + wmb(); -+ lq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | -+ ASCCON_ROEN, port->membase + IFXMIPS_ASC_CON); ++ ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | ++ ASCCON_ROEN, port->membase + LTQ_ASC_CON); + -+ retval = request_irq(ifx_port->tx_irq, lqasc_tx_int, ++ retval = request_irq(ltq_port->tx_irq, lqasc_tx_int, + IRQF_DISABLED, "asc_tx", port); + if (retval) { + pr_err("failed to request lqasc_tx_int\n"); + return retval; + } + -+ retval = request_irq(ifx_port->rx_irq, lqasc_rx_int, ++ retval = request_irq(ltq_port->rx_irq, lqasc_rx_int, + IRQF_DISABLED, "asc_rx", port); + if (retval) { + pr_err("failed to request lqasc_rx_int\n"); + goto err1; + } + -+ retval = request_irq(ifx_port->err_irq, lqasc_err_int, ++ retval = request_irq(ltq_port->err_irq, lqasc_err_int, + IRQF_DISABLED, "asc_err", port); + if (retval) { + pr_err("failed to request lqasc_err_int\n"); + goto err2; + } + -+ lq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX, -+ port->membase + IFXMIPS_ASC_IRNREN); ++ ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX, ++ port->membase + LTQ_ASC_IRNREN); + return 0; + +err2: -+ free_irq(ifx_port->rx_irq, port); ++ free_irq(ltq_port->rx_irq, port); +err1: -+ free_irq(ifx_port->tx_irq, port); ++ free_irq(ltq_port->tx_irq, port); + return retval; +} + +static void +lqasc_shutdown(struct uart_port *port) +{ -+ struct lq_uart_port *ifx_port = to_lq_uart_port(port); -+ free_irq(ifx_port->tx_irq, port); -+ free_irq(ifx_port->rx_irq, port); -+ free_irq(ifx_port->err_irq, port); -+ -+ lq_w32(0, port->membase + IFXMIPS_ASC_CON); -+ lq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU, -+ port->membase + IFXMIPS_ASC_RXFCON); -+ lq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU, -+ port->membase + IFXMIPS_ASC_TXFCON); ++ struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); ++ free_irq(ltq_port->tx_irq, port); ++ free_irq(ltq_port->rx_irq, port); ++ free_irq(ltq_port->err_irq, port); ++ ++ ltq_w32(0, port->membase + LTQ_ASC_CON); ++ ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU, ++ port->membase + LTQ_ASC_RXFCON); ++ ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU, ++ port->membase + LTQ_ASC_TXFCON); +} + +static void @@ -417,7 +414,7 @@ +{ + unsigned int cflag; + unsigned int iflag; -+ unsigned int quot; ++ unsigned int divisor; + unsigned int baud; + unsigned int con = 0; + unsigned long flags; @@ -433,10 +430,14 @@ + case CS5: + case CS6: + default: ++ new->c_cflag &= ~ CSIZE; ++ new->c_cflag |= CS8; + con = ASCCON_M_8ASYNC; + break; + } + ++ cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ ++ + if (cflag & CSTOPB) + con |= ASCCON_STP; + @@ -470,41 +471,45 @@ + /* set error signals - framing, parity and overrun, enable receiver */ + con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN; + -+ local_irq_save(flags); ++ spin_lock_irqsave(<q_asc_lock, flags); + + /* set up CON */ -+ lq_w32_mask(0, con, port->membase + IFXMIPS_ASC_CON); ++ ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON); + + /* Set baud rate - take a divider of 2 into account */ + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); -+ quot = uart_get_divisor(port, baud); -+ quot = quot / 2 - 1; ++ divisor = uart_get_divisor(port, baud); ++ divisor = divisor / 2 - 1; + + /* disable the baudrate generator */ -+ lq_w32_mask(ASCCON_R, 0, port->membase + IFXMIPS_ASC_CON); ++ ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON); + + /* make sure the fractional divider is off */ -+ lq_w32_mask(ASCCON_FDE, 0, port->membase + IFXMIPS_ASC_CON); ++ ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON); + + /* set up to use divisor of 2 */ -+ lq_w32_mask(ASCCON_BRS, 0, port->membase + IFXMIPS_ASC_CON); ++ ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON); + + /* now we can write the new baudrate into the register */ -+ lq_w32(quot, port->membase + IFXMIPS_ASC_BG); ++ ltq_w32(divisor, port->membase + LTQ_ASC_BG); + + /* turn the baudrate generator back on */ -+ lq_w32_mask(0, ASCCON_R, port->membase + IFXMIPS_ASC_CON); ++ ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON); + + /* enable rx */ -+ lq_w32(ASCWHBSTATE_SETREN, port->membase + IFXMIPS_ASC_WHBSTATE); ++ ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE); ++ ++ spin_unlock_irqrestore(<q_asc_lock, flags); + -+ local_irq_restore(flags); ++ /* Don't rewrite B0 */ ++ if (tty_termios_baud_rate(new)) ++ tty_termios_encode_baud_rate(new, baud, baud); +} + +static const char* +lqasc_type(struct uart_port *port) +{ -+ if (port->type == PORT_IFXMIPSASC) ++ if (port->type == PORT_LTQ_ASC) + return DRVNAME; + else + return NULL; @@ -523,16 +528,26 @@ +lqasc_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); -+ struct resource *mmres; ++ struct resource *res; + int size; + -+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!mmres) ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot obtain I/O memory region"); + return -ENODEV; -+ size = resource_size(mmres); ++ } ++ size = resource_size(res); ++ ++ res = devm_request_mem_region(&pdev->dev, res->start, ++ size, dev_name(&pdev->dev)); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot request I/O memory region"); ++ return -EBUSY; ++ } + + if (port->flags & UPF_IOREMAP) { -+ port->membase = ioremap_nocache(port->mapbase, size); ++ port->membase = devm_ioremap_nocache(&pdev->dev, ++ port->mapbase, size); + if (port->membase == NULL) + return -ENOMEM; + } @@ -543,7 +558,7 @@ +lqasc_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { -+ port->type = PORT_IFXMIPSASC; ++ port->type = PORT_LTQ_ASC; + lqasc_request_port(port); + } +} @@ -553,7 +568,7 @@ + struct serial_struct *ser) +{ + int ret = 0; -+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_IFXMIPSASC) ++ if (ser->type != PORT_UNKNOWN && ser->type != PORT_LTQ_ASC) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= NR_IRQS) + ret = -EINVAL; @@ -590,38 +605,38 @@ + return; + + do { -+ fifofree = (lq_r32(port->membase + IFXMIPS_ASC_FSTAT) ++ fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT) + & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF; + } while (fifofree == 0); -+ lq_w8(ch, port->membase + IFXMIPS_ASC_TBUF); ++ ltq_w8(ch, port->membase + LTQ_ASC_TBUF); +} + + +static void +lqasc_console_write(struct console *co, const char *s, u_int count) +{ -+ struct lq_uart_port *ifx_port; ++ struct ltq_uart_port *ltq_port; + struct uart_port *port; + unsigned long flags; + + if (co->index >= MAXPORTS) + return; + -+ ifx_port = lqasc_port[co->index]; -+ if (!ifx_port) ++ ltq_port = lqasc_port[co->index]; ++ if (!ltq_port) + return; + -+ port = &ifx_port->port; ++ port = <q_port->port; + -+ local_irq_save(flags); ++ spin_lock_irqsave(<q_asc_lock, flags); + uart_console_write(port, s, count, lqasc_console_putchar); -+ local_irq_restore(flags); ++ spin_unlock_irqrestore(<q_asc_lock, flags); +} + +static int __init +lqasc_console_setup(struct console *co, char *options) +{ -+ struct lq_uart_port *ifx_port; ++ struct ltq_uart_port *ltq_port; + struct uart_port *port; + int baud = 115200; + int bits = 8; @@ -631,13 +646,13 @@ + if (co->index >= MAXPORTS) + return -ENODEV; + -+ ifx_port = lqasc_port[co->index]; -+ if (!ifx_port) ++ ltq_port = lqasc_port[co->index]; ++ if (!ltq_port) + return -ENODEV; + -+ port = &ifx_port->port; ++ port = <q_port->port; + -+ port->uartclk = clk_get_rate(ifx_port->clk); ++ port->uartclk = clk_get_rate(ltq_port->clk); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -645,7 +660,7 @@ +} + +static struct console lqasc_console = { -+ .name = "ttyS", ++ .name = "ttyLTQ", + .write = lqasc_console_write, + .device = uart_console_device, + .setup = lqasc_console_setup, @@ -665,17 +680,17 @@ +static struct uart_driver lqasc_reg = { + .owner = THIS_MODULE, + .driver_name = DRVNAME, -+ .dev_name = "ttyS", -+ .major = TTY_MAJOR, -+ .minor = 64, ++ .dev_name = "ttyLTQ", ++ .major = 0, ++ .minor = 0, + .nr = MAXPORTS, + .cons = &lqasc_console, +}; + -+static int __devinit ++static int __init +lqasc_probe(struct platform_device *pdev) +{ -+ struct lq_uart_port *ifx_port; ++ struct ltq_uart_port *ltq_port; + struct uart_port *port; + struct resource *mmres, *irqres; + int tx_irq, rx_irq, err_irq; @@ -700,69 +715,43 @@ + } + + tx_irq = platform_get_irq_byname(pdev, "tx"); -+ if (tx_irq < 0) { -+ /* without named resources: assume standard irq scheme */ -+ tx_irq = irqres->start; -+ rx_irq = irqres->start+2; -+ err_irq = irqres->start+3; -+ } else { -+ /* other irqs must be named also! */ -+ rx_irq = platform_get_irq_byname(pdev, "rx"); -+ err_irq = platform_get_irq_byname(pdev, "err"); -+ if ((rx_irq < 0) | (err_irq < 0)) -+ return -ENODEV; -+ } ++ rx_irq = platform_get_irq_byname(pdev, "rx"); ++ err_irq = platform_get_irq_byname(pdev, "err"); ++ if ((tx_irq < 0) | (rx_irq < 0) | (err_irq < 0)) ++ return -ENODEV; + -+ ifx_port = kzalloc(sizeof(struct lq_uart_port), GFP_KERNEL); -+ if (!ifx_port) ++ ltq_port = kzalloc(sizeof(struct ltq_uart_port), GFP_KERNEL); ++ if (!ltq_port) + return -ENOMEM; + -+ port = &ifx_port->port; ++ port = <q_port->port; + + port->iotype = SERIAL_IO_MEM; + port->flags = ASYNC_BOOT_AUTOCONF | UPF_IOREMAP; + port->ops = &lqasc_pops; + port->fifosize = 16; -+ port->type = PORT_IFXMIPSASC, ++ port->type = PORT_LTQ_ASC, + port->line = pdev->id; + port->dev = &pdev->dev; + + port->irq = tx_irq; /* unused, just to be backward-compatibe */ + port->mapbase = mmres->start; + -+ ifx_port->clk = clk; ++ ltq_port->clk = clk; + -+ ifx_port->tx_irq = tx_irq; -+ ifx_port->rx_irq = rx_irq; -+ ifx_port->err_irq = err_irq; ++ ltq_port->tx_irq = tx_irq; ++ ltq_port->rx_irq = rx_irq; ++ ltq_port->err_irq = err_irq; + -+ lqasc_port[pdev->id] = ifx_port; -+ platform_set_drvdata(pdev, ifx_port); ++ lqasc_port[pdev->id] = ltq_port; ++ platform_set_drvdata(pdev, ltq_port); + + ret = uart_add_one_port(&lqasc_reg, port); + + return ret; +} + -+static int __devexit -+lqasc_remove(struct platform_device *pdev) -+{ -+ struct lq_uart_port *ifx_port = platform_get_drvdata(pdev); -+ int ret; -+ -+ clk_put(ifx_port->clk); -+ platform_set_drvdata(pdev, NULL); -+ lqasc_port[pdev->id] = NULL; -+ ret = uart_remove_one_port(&lqasc_reg, &ifx_port->port); -+ kfree(ifx_port); -+ -+ return 0; -+} -+ +static struct platform_driver lqasc_driver = { -+ .probe = lqasc_probe, -+ .remove = __devexit_p(lqasc_remove), -+ + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, @@ -778,22 +767,38 @@ + if (ret != 0) + return ret; + -+ ret = platform_driver_register(&lqasc_driver); ++ ret = platform_driver_probe(&lqasc_driver, lqasc_probe); + if (ret != 0) + uart_unregister_driver(&lqasc_reg); + + return ret; +} + -+void __exit -+exit_lqasc(void) -+{ -+ platform_driver_unregister(&lqasc_driver); -+ uart_unregister_driver(&lqasc_reg); -+} -+ +module_init(init_lqasc); -+module_exit(exit_lqasc); + +MODULE_DESCRIPTION("Lantiq serial port driver"); +MODULE_LICENSE("GPL"); +--- a/drivers/serial/Kconfig ++++ b/drivers/serial/Kconfig +@@ -1383,6 +1383,14 @@ + help + Support for Console on the NWP serial ports. + ++config SERIAL_LANTIQ ++ bool "Lantiq serial driver" ++ depends on LANTIQ ++ select SERIAL_CORE ++ select SERIAL_CORE_CONSOLE ++ help ++ Support for console and UART on Lantiq SoCs. ++ + config SERIAL_QE + tristate "Freescale QUICC Engine serial port support" + depends on QUICC_ENGINE +--- a/drivers/serial/Makefile ++++ b/drivers/serial/Makefile +@@ -81,3 +81,4 @@ + obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o + obj-$(CONFIG_SERIAL_QE) += ucc_uart.o + obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o ++obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o diff --git a/target/linux/lantiq/patches-2.6.32/0010-MIPS-Lantiq-Add-DMA-support.patch b/target/linux/lantiq/patches-2.6.32/0010-MIPS-Lantiq-Add-DMA-support.patch new file mode 100644 index 0000000..fd9981a --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0010-MIPS-Lantiq-Add-DMA-support.patch @@ -0,0 +1,387 @@ +From bd620ec1ca053bab8ce2562968700e6f80e4ff83 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 6 May 2011 00:10:00 +0200 +Subject: [PATCH 10/13] MIPS: Lantiq: Add DMA support + +This patch adds support for the DMA engine found inside the XWAY family of +SoCs. The engine has 5 ports and 20 channels. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2355/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 +- + arch/mips/include/asm/mach-lantiq/xway/xway_dma.h | 60 +++++ + arch/mips/lantiq/xway/Makefile | 2 +- + arch/mips/lantiq/xway/devices.h | 1 + + arch/mips/lantiq/xway/dma.c | 253 ++++++++++++++++++++ + 5 files changed, 317 insertions(+), 2 deletions(-) + create mode 100644 arch/mips/include/asm/mach-lantiq/xway/xway_dma.h + create mode 100644 arch/mips/lantiq/xway/dma.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 343e82c..4827afb 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -86,7 +86,8 @@ + #define LTQ_PPE32_SIZE 0x40000 + + /* DMA */ +-#define LTQ_DMA_BASE_ADDR 0xBE104100 ++#define LTQ_DMA_BASE_ADDR 0x1E104100 ++#define LTQ_DMA_SIZE 0x800 + + /* PCI */ + #define PCI_CR_BASE_ADDR 0x1E105400 +diff --git a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h +new file mode 100644 +index 0000000..872943a +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h +@@ -0,0 +1,60 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef LTQ_DMA_H__ ++#define LTQ_DMA_H__ ++ ++#define LTQ_DESC_SIZE 0x08 /* each descriptor is 64bit */ ++#define LTQ_DESC_NUM 0x40 /* 64 descriptors / channel */ ++ ++#define LTQ_DMA_OWN BIT(31) /* owner bit */ ++#define LTQ_DMA_C BIT(30) /* complete bit */ ++#define LTQ_DMA_SOP BIT(29) /* start of packet */ ++#define LTQ_DMA_EOP BIT(28) /* end of packet */ ++#define LTQ_DMA_TX_OFFSET(x) ((x & 0x1f) << 23) /* data bytes offset */ ++#define LTQ_DMA_RX_OFFSET(x) ((x & 0x7) << 23) /* data bytes offset */ ++#define LTQ_DMA_SIZE_MASK (0xffff) /* the size field is 16 bit */ ++ ++struct ltq_dma_desc { ++ u32 ctl; ++ u32 addr; ++}; ++ ++struct ltq_dma_channel { ++ int nr; /* the channel number */ ++ int irq; /* the mapped irq */ ++ int desc; /* the current descriptor */ ++ struct ltq_dma_desc *desc_base; /* the descriptor base */ ++ int phys; /* physical addr */ ++}; ++ ++enum { ++ DMA_PORT_ETOP = 0, ++ DMA_PORT_DEU, ++}; ++ ++extern void ltq_dma_enable_irq(struct ltq_dma_channel *ch); ++extern void ltq_dma_disable_irq(struct ltq_dma_channel *ch); ++extern void ltq_dma_ack_irq(struct ltq_dma_channel *ch); ++extern void ltq_dma_open(struct ltq_dma_channel *ch); ++extern void ltq_dma_close(struct ltq_dma_channel *ch); ++extern void ltq_dma_alloc_tx(struct ltq_dma_channel *ch); ++extern void ltq_dma_alloc_rx(struct ltq_dma_channel *ch); ++extern void ltq_dma_free(struct ltq_dma_channel *ch); ++extern void ltq_dma_init_port(int p); ++ ++#endif +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 6b5e07e..c517f2e 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o ++obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o + + obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o + obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o +diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h +index 51f56b5..d573084 100644 +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -10,6 +10,7 @@ + #define _LTQ_DEVICES_XWAY_H__ + + #include "../devices.h" ++#include <linux/phy.h> + + extern void ltq_register_gpio(void); + extern void ltq_register_gpio_stp(void); +diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c +new file mode 100644 +index 0000000..4278a45 +--- /dev/null ++++ b/arch/mips/lantiq/xway/dma.c +@@ -0,0 +1,253 @@ ++/* ++ * 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/init.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/dma-mapping.h> ++ ++#include <lantiq_soc.h> ++#include <xway_dma.h> ++ ++#define LTQ_DMA_CTRL 0x10 ++#define LTQ_DMA_CPOLL 0x14 ++#define LTQ_DMA_CS 0x18 ++#define LTQ_DMA_CCTRL 0x1C ++#define LTQ_DMA_CDBA 0x20 ++#define LTQ_DMA_CDLEN 0x24 ++#define LTQ_DMA_CIS 0x28 ++#define LTQ_DMA_CIE 0x2C ++#define LTQ_DMA_PS 0x40 ++#define LTQ_DMA_PCTRL 0x44 ++#define LTQ_DMA_IRNEN 0xf4 ++ ++#define DMA_DESCPT BIT(3) /* descriptor complete irq */ ++#define DMA_TX BIT(8) /* TX channel direction */ ++#define DMA_CHAN_ON BIT(0) /* channel on / off bit */ ++#define DMA_PDEN BIT(6) /* enable packet drop */ ++#define DMA_CHAN_RST BIT(1) /* channel on / off bit */ ++#define DMA_RESET BIT(0) /* channel on / off bit */ ++#define DMA_IRQ_ACK 0x7e /* IRQ status register */ ++#define DMA_POLL BIT(31) /* turn on channel polling */ ++#define DMA_CLK_DIV4 BIT(6) /* polling clock divider */ ++#define DMA_2W_BURST BIT(1) /* 2 word burst length */ ++#define DMA_MAX_CHANNEL 20 /* the soc has 20 channels */ ++#define DMA_ETOP_ENDIANESS (0xf << 8) /* endianess swap etop channels */ ++#define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */ ++ ++#define ltq_dma_r32(x) ltq_r32(ltq_dma_membase + (x)) ++#define ltq_dma_w32(x, y) ltq_w32(x, ltq_dma_membase + (y)) ++#define ltq_dma_w32_mask(x, y, z) ltq_w32_mask(x, y, \ ++ ltq_dma_membase + (z)) ++ ++static struct resource ltq_dma_resource = { ++ .name = "dma", ++ .start = LTQ_DMA_BASE_ADDR, ++ .end = LTQ_DMA_BASE_ADDR + LTQ_DMA_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static void __iomem *ltq_dma_membase; ++ ++void ++ltq_dma_enable_irq(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); ++ local_irq_restore(flags); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_enable_irq); ++ ++void ++ltq_dma_disable_irq(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN); ++ local_irq_restore(flags); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_disable_irq); ++ ++void ++ltq_dma_ack_irq(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32(DMA_IRQ_ACK, LTQ_DMA_CIS); ++ local_irq_restore(flags); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_ack_irq); ++ ++void ++ltq_dma_open(struct ltq_dma_channel *ch) ++{ ++ unsigned long flag; ++ ++ local_irq_save(flag); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL); ++ ltq_dma_enable_irq(ch); ++ local_irq_restore(flag); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_open); ++ ++void ++ltq_dma_close(struct ltq_dma_channel *ch) ++{ ++ unsigned long flag; ++ ++ local_irq_save(flag); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); ++ ltq_dma_disable_irq(ch); ++ local_irq_restore(flag); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_close); ++ ++static void ++ltq_dma_alloc(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ ch->desc = 0; ++ ch->desc_base = dma_alloc_coherent(NULL, ++ LTQ_DESC_NUM * LTQ_DESC_SIZE, ++ &ch->phys, GFP_ATOMIC); ++ memset(ch->desc_base, 0, LTQ_DESC_NUM * LTQ_DESC_SIZE); ++ ++ local_irq_save(flags); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32(ch->phys, LTQ_DMA_CDBA); ++ ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN); ++ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); ++ wmb(); ++ ltq_dma_w32_mask(0, DMA_CHAN_RST, LTQ_DMA_CCTRL); ++ while (ltq_dma_r32(LTQ_DMA_CCTRL) & DMA_CHAN_RST) ++ ; ++ local_irq_restore(flags); ++} ++ ++void ++ltq_dma_alloc_tx(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ ltq_dma_alloc(ch); ++ ++ local_irq_save(flags); ++ ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE); ++ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); ++ ltq_dma_w32(DMA_WEIGHT | DMA_TX, LTQ_DMA_CCTRL); ++ local_irq_restore(flags); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_alloc_tx); ++ ++void ++ltq_dma_alloc_rx(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ ltq_dma_alloc(ch); ++ ++ local_irq_save(flags); ++ ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE); ++ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); ++ ltq_dma_w32(DMA_WEIGHT, LTQ_DMA_CCTRL); ++ local_irq_restore(flags); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_alloc_rx); ++ ++void ++ltq_dma_free(struct ltq_dma_channel *ch) ++{ ++ if (!ch->desc_base) ++ return; ++ ltq_dma_close(ch); ++ dma_free_coherent(NULL, LTQ_DESC_NUM * LTQ_DESC_SIZE, ++ ch->desc_base, ch->phys); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_free); ++ ++void ++ltq_dma_init_port(int p) ++{ ++ ltq_dma_w32(p, LTQ_DMA_PS); ++ switch (p) { ++ case DMA_PORT_ETOP: ++ /* ++ * Tell the DMA engine to swap the endianess of data frames and ++ * drop packets if the channel arbitration fails. ++ */ ++ ltq_dma_w32_mask(0, DMA_ETOP_ENDIANESS | DMA_PDEN, ++ LTQ_DMA_PCTRL); ++ break; ++ ++ case DMA_PORT_DEU: ++ ltq_dma_w32((DMA_2W_BURST << 4) | (DMA_2W_BURST << 2), ++ LTQ_DMA_PCTRL); ++ break; ++ ++ default: ++ break; ++ } ++} ++EXPORT_SYMBOL_GPL(ltq_dma_init_port); ++ ++int __init ++ltq_dma_init(void) ++{ ++ int i; ++ ++ /* insert and request the memory region */ ++ if (insert_resource(&iomem_resource, <q_dma_resource) < 0) ++ panic("Failed to insert dma memory\n"); ++ ++ if (request_mem_region(ltq_dma_resource.start, ++ resource_size(<q_dma_resource), "dma") < 0) ++ panic("Failed to request dma memory\n"); ++ ++ /* remap dma register range */ ++ ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start, ++ resource_size(<q_dma_resource)); ++ if (!ltq_dma_membase) ++ panic("Failed to remap dma memory\n"); ++ ++ /* power up and reset the dma engine */ ++ ltq_pmu_enable(PMU_DMA); ++ ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL); ++ ++ /* disable all interrupts */ ++ ltq_dma_w32(0, LTQ_DMA_IRNEN); ++ ++ /* reset/configure each channel */ ++ for (i = 0; i < DMA_MAX_CHANNEL; i++) { ++ ltq_dma_w32(i, LTQ_DMA_CS); ++ ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL); ++ ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL); ++ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); ++ } ++ return 0; ++} ++ ++postcore_initcall(ltq_dma_init); +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches-2.6.32/0011-MIPS-Lantiq-Add-ethernet-driver.patch b/target/linux/lantiq/patches-2.6.32/0011-MIPS-Lantiq-Add-ethernet-driver.patch new file mode 100644 index 0000000..0d869de --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0011-MIPS-Lantiq-Add-ethernet-driver.patch @@ -0,0 +1,943 @@ +From 435de86088af82496bcba69165cd7422bb4622ec Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 6 May 2011 00:10:01 +0200 +Subject: [PATCH 11/13] MIPS: Lantiq: Add ethernet driver + +This patch adds the driver for the ETOP Packet Processing Engine (PPE32) +found inside the XWAY family of Lantiq MIPS SoCs. This driver makes 100MBit +ethernet work. Support for all 8 dma channels, gbit and the embedded switch +found on the ar9/vr9 still needs to be implemented. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Cc: netdev@vger.kernel.org +Patchwork: https://patchwork.linux-mips.org/patch/2357/ +Acked-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + .../mips/include/asm/mach-lantiq/lantiq_platform.h | 7 + + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 4 +- + arch/mips/lantiq/xway/devices.c | 23 + + arch/mips/lantiq/xway/devices.h | 1 + + drivers/net/Kconfig | 7 + + drivers/net/Makefile | 1 + + drivers/net/lantiq_etop.c | 805 ++++++++++++++++++++ + 7 files changed, 846 insertions(+), 2 deletions(-) + create mode 100644 drivers/net/lantiq_etop.c + +--- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h ++++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +@@ -10,6 +10,7 @@ + #define _LANTIQ_PLATFORM_H__ + + #include <linux/mtd/partitions.h> ++#include <linux/socket.h> + + /* struct used to pass info to the pci core */ + enum { +@@ -43,4 +44,10 @@ + int irq[16]; + }; + ++/* struct used to pass info to network drivers */ ++struct ltq_eth_data { ++ struct sockaddr mac; ++ int mii_mode; ++}; ++ + #endif +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -82,8 +82,8 @@ + #define PMU_SWITCH 0x10000000 + + /* ETOP - ethernet */ +-#define LTQ_PPE32_BASE_ADDR 0xBE180000 +-#define LTQ_PPE32_SIZE 0x40000 ++#define LTQ_ETOP_BASE_ADDR 0x1E180000 ++#define LTQ_ETOP_SIZE 0x40000 + + /* DMA */ + #define LTQ_DMA_BASE_ADDR 0x1E104100 +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -96,3 +96,26 @@ + platform_device_register_simple("ltq_asc", 0, + ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources)); + } ++ ++/* ethernet */ ++static struct resource ltq_etop_resources = { ++ .name = "etop", ++ .start = LTQ_ETOP_BASE_ADDR, ++ .end = LTQ_ETOP_BASE_ADDR + LTQ_ETOP_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static struct platform_device ltq_etop = { ++ .name = "ltq_etop", ++ .resource = <q_etop_resources, ++ .num_resources = 1, ++}; ++ ++void __init ++ltq_register_etop(struct ltq_eth_data *eth) ++{ ++ if (eth) { ++ ltq_etop.dev.platform_data = eth; ++ platform_device_register(<q_etop); ++ } ++} +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -15,5 +15,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); + + #endif +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -1951,6 +1951,13 @@ + This driver supports the ethernet MACs in the Broadcom 63xx + MIPS chipset family (BCM63XX). + ++config LANTIQ_ETOP ++ tristate "Lantiq SoC ETOP driver" ++ depends on SOC_TYPE_XWAY ++ help ++ Support for the MII0 inside the Lantiq SoC ++ ++ + source "drivers/net/fs_enet/Kconfig" + + endif # NET_ETHERNET +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -246,6 +246,7 @@ + obj-$(CONFIG_MLX4_CORE) += mlx4/ + obj-$(CONFIG_ENC28J60) += enc28j60.o + obj-$(CONFIG_ETHOC) += ethoc.o ++obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o + + obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o + +--- /dev/null ++++ b/drivers/net/lantiq_etop.c +@@ -0,0 +1,814 @@ ++/* ++ * 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 <asm/checksum.h> ++ ++#include <lantiq_soc.h> ++#include <xway_dma.h> ++#include <lantiq_platform.h> ++ ++#define LTQ_ETOP_MDIO 0x11804 ++#define MDIO_REQUEST 0x80000000 ++#define MDIO_READ 0x40000000 ++#define MDIO_ADDR_MASK 0x1f ++#define MDIO_ADDR_OFFSET 0x15 ++#define MDIO_REG_MASK 0x1f ++#define MDIO_REG_OFFSET 0x10 ++#define MDIO_VAL_MASK 0xffff ++ ++#define PPE32_CGEN 0x800 ++#define LTQ_PPE32_ENET_MAC_CFG 0x1840 ++ ++#define LTQ_ETOP_ENETS0 0x11850 ++#define LTQ_ETOP_MAC_DA0 0x1186C ++#define LTQ_ETOP_MAC_DA1 0x11870 ++#define LTQ_ETOP_CFG 0x16020 ++#define LTQ_ETOP_IGPLEN 0x16080 ++ ++#define MAX_DMA_CHAN 0x8 ++#define MAX_DMA_CRC_LEN 0x4 ++#define MAX_DMA_DATA_LEN 0x600 ++ ++#define ETOP_FTCU BIT(28) ++#define ETOP_MII_MASK 0xf ++#define ETOP_MII_NORMAL 0xd ++#define ETOP_MII_REVERSE 0xe ++#define ETOP_PLEN_UNDER 0x40 ++#define ETOP_CGEN 0x800 ++ ++/* use 2 static channels for TX/RX */ ++#define LTQ_ETOP_TX_CHANNEL 1 ++#define LTQ_ETOP_RX_CHANNEL 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) \ ++ ltq_w32_mask(x, y, ltq_etop_membase + (z)) ++ ++#define DRV_VERSION "1.0" ++ ++#ifndef netdev_err ++#define netdev_err(a, b, ...) printk(b, ##__VA_ARGS__) ++#endif ++ ++#ifndef pr_warn ++#define pr_warn pr_warning ++#endif ++ ++static void __iomem *ltq_etop_membase; ++ ++struct ltq_etop_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_etop_priv { ++ struct net_device *netdev; ++ struct ltq_eth_data *pldata; ++ struct resource *res; ++ ++ struct mii_bus *mii_bus; ++ struct phy_device *phydev; ++ ++ struct ltq_etop_chan ch[MAX_DMA_CHAN]; ++ int tx_free[MAX_DMA_CHAN >> 1]; ++ ++ spinlock_t lock; ++}; ++ ++static int ++ltq_etop_alloc_skb(struct ltq_etop_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_etop_hw_receive(struct ltq_etop_chan *ch) ++{ ++ struct ltq_etop_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_etop_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_etop_poll_rx(struct napi_struct *napi, int budget) ++{ ++ struct ltq_etop_chan *ch = container_of(napi, ++ struct ltq_etop_chan, napi); ++ int rx = 0; ++ int complete = 0; ++ ++ 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_etop_hw_receive(ch); ++ rx++; ++ } else { ++ complete = 1; ++ } ++ } ++ if (complete || !rx) { ++ napi_complete(&ch->napi); ++ ltq_dma_ack_irq(&ch->dma); ++ } ++ return rx; ++} ++ ++static int ++ltq_etop_poll_tx(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); ++ 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); ++ ltq_dma_ack_irq(&ch->dma); ++ return 1; ++} ++ ++static irqreturn_t ++ltq_etop_dma_irq(int irq, void *_priv) ++{ ++ struct ltq_etop_priv *priv = _priv; ++ int ch = irq - LTQ_DMA_CH0_INT; ++ ++ napi_schedule(&priv->ch[ch].napi); ++ return IRQ_HANDLED; ++} ++ ++static void ++ltq_etop_free_channel(struct net_device *dev, struct ltq_etop_chan *ch) ++{ ++ struct ltq_etop_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_etop_hw_exit(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ int i; ++ ++ ltq_pmu_disable(PMU_PPE); ++ for (i = 0; i < MAX_DMA_CHAN; i++) ++ if (IS_TX(i) || IS_RX(i)) ++ ltq_etop_free_channel(dev, &priv->ch[i]); ++} ++ ++static int ++ltq_etop_hw_init(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ int i; ++ ++ ltq_pmu_enable(PMU_PPE); ++ ++ switch (priv->pldata->mii_mode) { ++ case PHY_INTERFACE_MODE_RMII: ++ ltq_etop_w32_mask(ETOP_MII_MASK, ++ ETOP_MII_REVERSE, LTQ_ETOP_CFG); ++ break; ++ ++ case PHY_INTERFACE_MODE_MII: ++ ltq_etop_w32_mask(ETOP_MII_MASK, ++ ETOP_MII_NORMAL, LTQ_ETOP_CFG); ++ break; ++ ++ default: ++ netdev_err(dev, "unknown mii mode %d\n", ++ priv->pldata->mii_mode); ++ return -ENOTSUPP; ++ } ++ ++ /* enable crc generation */ ++ ltq_etop_w32(PPE32_CGEN, LTQ_PPE32_ENET_MAC_CFG); ++ ++ ltq_dma_init_port(DMA_PORT_ETOP); ++ ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ int irq = LTQ_DMA_CH0_INT + 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); ++ 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; ++ ch->dma.desc = 0; ++ request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, ++ "etop_rx", priv); ++ } ++ ch->dma.irq = irq; ++ } ++ return 0; ++} ++ ++static void ++ltq_etop_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_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); ++} ++ ++static int ++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); ++} ++ ++static int ++ltq_etop_nway_reset(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ ++ return phy_start_aneg(priv->phydev); ++} ++ ++static const struct ethtool_ops ltq_etop_ethtool_ops = { ++ .get_drvinfo = ltq_etop_get_drvinfo, ++ .get_settings = ltq_etop_get_settings, ++ .set_settings = ltq_etop_set_settings, ++ .nway_reset = ltq_etop_nway_reset, ++}; ++ ++static int ++ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data) ++{ ++ u32 val = MDIO_REQUEST | ++ ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) | ++ ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET) | ++ phy_data; ++ ++ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) ++ ; ++ ltq_etop_w32(val, LTQ_ETOP_MDIO); ++ return 0; ++} ++ ++static int ++ltq_etop_mdio_rd(struct mii_bus *bus, int phy_addr, int phy_reg) ++{ ++ u32 val = MDIO_REQUEST | MDIO_READ | ++ ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) | ++ ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET); ++ ++ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) ++ ; ++ ltq_etop_w32(val, LTQ_ETOP_MDIO); ++ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) ++ ; ++ val = ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_VAL_MASK; ++ return val; ++} ++ ++static void ++ltq_etop_mdio_link(struct net_device *dev) ++{ ++ /* nothing to do */ ++} ++ ++static int ++ltq_etop_mdio_probe(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ struct phy_device *phydev = NULL; ++ int phy_addr; ++ ++ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { ++ if (priv->mii_bus->phy_map[phy_addr]) { ++ phydev = priv->mii_bus->phy_map[phy_addr]; ++ break; ++ } ++ } ++ ++ if (!phydev) { ++ netdev_err(dev, "no PHY found\n"); ++ return -ENODEV; ++ } ++ ++ phydev = phy_connect(dev, dev_name(&phydev->dev), <q_etop_mdio_link, ++ 0, priv->pldata->mii_mode); ++ ++ 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_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); ++ ++ return 0; ++} ++ ++static int ++ltq_etop_mdio_init(struct net_device *dev) ++{ ++ struct ltq_etop_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_etop_mdio_rd; ++ priv->mii_bus->write = ltq_etop_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_etop_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_etop_mdio_cleanup(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ ++ phy_disconnect(priv->phydev); ++ mdiobus_unregister(priv->mii_bus); ++ kfree(priv->mii_bus->irq); ++ mdiobus_free(priv->mii_bus); ++} ++ ++static int ++ltq_etop_open(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ int i; ++ ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ struct ltq_etop_chan *ch = &priv->ch[i]; ++ ++ if (!IS_TX(i) && (!IS_RX(i))) ++ continue; ++ ltq_dma_open(&ch->dma); ++ napi_enable(&ch->napi); ++ } ++ phy_start(priv->phydev); ++ netif_tx_start_all_queues(dev); ++ return 0; ++} ++ ++static int ++ltq_etop_stop(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ int i; ++ ++ netif_tx_stop_all_queues(dev); ++ phy_stop(priv->phydev); ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ struct ltq_etop_chan *ch = &priv->ch[i]; ++ ++ if (!IS_RX(i) && !IS_TX(i)) ++ continue; ++ napi_disable(&ch->napi); ++ ltq_dma_close(&ch->dma); ++ } ++ return 0; ++} ++ ++static int ++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]; ++ int len; ++ unsigned long flags; ++ u32 byte_offset; ++ ++ 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); ++ 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_etop_change_mtu(struct net_device *dev, int new_mtu) ++{ ++ int ret = eth_change_mtu(dev, new_mtu); ++ ++ if (!ret) { ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_etop_w32((ETOP_PLEN_UNDER << 16) | new_mtu, ++ LTQ_ETOP_IGPLEN); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ return ret; ++} ++ ++static int ++ltq_etop_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ struct mii_ioctl_data *data = if_mii(rq); ++ ++ /* TODO: mii-toll reports "No MII transceiver present!." ?!*/ ++ return phy_mii_ioctl(priv->phydev, data, cmd); ++} ++ ++static int ++ltq_etop_set_mac_address(struct net_device *dev, void *p) ++{ ++ int ret = eth_mac_addr(dev, p); ++ ++ if (!ret) { ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ unsigned long flags; ++ ++ /* store the mac for the unicast filter */ ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_etop_w32(*((u32 *)dev->dev_addr), LTQ_ETOP_MAC_DA0); ++ ltq_etop_w32(*((u16 *)&dev->dev_addr[4]) << 16, ++ LTQ_ETOP_MAC_DA1); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ return ret; ++} ++ ++static void ++ltq_etop_set_multicast_list(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ unsigned long flags; ++ ++ /* ensure that the unicast filter is not enabled in promiscious mode */ ++ spin_lock_irqsave(&priv->lock, flags); ++ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI)) ++ ltq_etop_w32_mask(ETOP_FTCU, 0, LTQ_ETOP_ENETS0); ++ else ++ ltq_etop_w32_mask(0, ETOP_FTCU, LTQ_ETOP_ENETS0); ++ spin_unlock_irqrestore(&priv->lock, flags); ++} ++ ++static u16 ++ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb) ++{ ++ /* we are currently only using the first queue */ ++ return 0; ++} ++ ++static int ++ltq_etop_init(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ struct sockaddr mac; ++ int err; ++ ++ ether_setup(dev); ++ dev->watchdog_timeo = 10 * HZ; ++ err = ltq_etop_hw_init(dev); ++ if (err) ++ goto err_hw; ++ ltq_etop_change_mtu(dev, 1500); ++ ++ memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr)); ++ if (!is_valid_ether_addr(mac.sa_data)) { ++ pr_warn("etop: invalid MAC, using random\n"); ++ random_ether_addr(mac.sa_data); ++ } ++ ++ err = ltq_etop_set_mac_address(dev, &mac); ++ if (err) ++ goto err_netdev; ++ ltq_etop_set_multicast_list(dev); ++ err = ltq_etop_mdio_init(dev); ++ if (err) ++ goto err_netdev; ++ return 0; ++ ++err_netdev: ++ unregister_netdev(dev); ++ free_netdev(dev); ++err_hw: ++ ltq_etop_hw_exit(dev); ++ return err; ++} ++ ++static void ++ltq_etop_tx_timeout(struct net_device *dev) ++{ ++ int err; ++ ++ ltq_etop_hw_exit(dev); ++ err = ltq_etop_hw_init(dev); ++ if (err) ++ goto err_hw; ++ dev->trans_start = jiffies; ++ netif_wake_queue(dev); ++ return; ++ ++err_hw: ++ ltq_etop_hw_exit(dev); ++ netdev_err(dev, "failed to restart etop after TX timeout\n"); ++} ++ ++static const struct net_device_ops ltq_eth_netdev_ops = { ++ .ndo_open = ltq_etop_open, ++ .ndo_stop = ltq_etop_stop, ++ .ndo_start_xmit = ltq_etop_tx, ++ .ndo_change_mtu = ltq_etop_change_mtu, ++ .ndo_do_ioctl = ltq_etop_ioctl, ++ .ndo_set_mac_address = ltq_etop_set_mac_address, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_set_multicast_list = ltq_etop_set_multicast_list, ++ .ndo_select_queue = ltq_etop_select_queue, ++ .ndo_init = ltq_etop_init, ++ .ndo_tx_timeout = ltq_etop_tx_timeout, ++}; ++ ++static int __init ++ltq_etop_probe(struct platform_device *pdev) ++{ ++ struct net_device *dev; ++ struct ltq_etop_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 etop 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 etop resource\n"); ++ err = -EBUSY; ++ goto err_out; ++ } ++ ++ ltq_etop_membase = devm_ioremap_nocache(&pdev->dev, ++ res->start, resource_size(res)); ++ if (!ltq_etop_membase) { ++ dev_err(&pdev->dev, "failed to remap etop engine %d\n", ++ pdev->id); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ 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); ++ priv->netdev = dev; ++ 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; ++ } ++ ++ 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_etop_remove(struct platform_device *pdev) ++{ ++ struct net_device *dev = platform_get_drvdata(pdev); ++ ++ if (dev) { ++ netif_tx_stop_all_queues(dev); ++ ltq_etop_hw_exit(dev); ++ ltq_etop_mdio_cleanup(dev); ++ unregister_netdev(dev); ++ } ++ return 0; ++} ++ ++static struct platform_driver ltq_mii_driver = { ++ .remove = __devexit_p(ltq_etop_remove), ++ .driver = { ++ .name = "ltq_etop", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++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_AUTHOR("John Crispin <blogic@openwrt.org>"); ++MODULE_DESCRIPTION("Lantiq SoC ETOP"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/lantiq/patches-2.6.32/0012-MIPS-Lantiq-Add-etop-board-support.patch b/target/linux/lantiq/patches-2.6.32/0012-MIPS-Lantiq-Add-etop-board-support.patch new file mode 100644 index 0000000..2bc4abd --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0012-MIPS-Lantiq-Add-etop-board-support.patch @@ -0,0 +1,50 @@ +From 72a9b536ef81f06bb8042abee0410458f5df93d2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 6 May 2011 00:10:02 +0200 +Subject: [PATCH 12/13] MIPS: Lantiq: Add etop board support + +Register the etop platform device inside the machtype specific init code. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Signed-off-by: David Daney <ddaney@caviumnetworks.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2356/ +Patchwork: https://patchwork.linux-mips.org/patch/2370/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/lantiq/xway/mach-easy50712.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c +index e5e7e09..ea5027b 100644 +--- a/arch/mips/lantiq/xway/mach-easy50712.c ++++ b/arch/mips/lantiq/xway/mach-easy50712.c +@@ -12,6 +12,7 @@ + #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> +@@ -55,11 +56,16 @@ static struct ltq_pci_data ltq_pci_data = { + }, + }; + ++static struct ltq_eth_data ltq_eth_data = { ++ .mii_mode = PHY_INTERFACE_MODE_MII, ++}; ++ + static void __init easy50712_init(void) + { + ltq_register_gpio_stp(); + ltq_register_nor(&easy50712_flash_data); + ltq_register_pci(<q_pci_data); ++ ltq_register_etop(<q_eth_data); + } + + MIPS_MACHINE(LTQ_MACH_EASY50712, +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches-2.6.32/0013-MIPS-Lantiq-Add-watchdog-support.patch b/target/linux/lantiq/patches-2.6.32/0013-MIPS-Lantiq-Add-watchdog-support.patch new file mode 100644 index 0000000..903f674 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/0013-MIPS-Lantiq-Add-watchdog-support.patch @@ -0,0 +1,310 @@ +From 3466449c8f455da0cb646231602e6af16190f592 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 5 May 2011 23:00:23 +0200 +Subject: [PATCH 13/13] MIPS: Lantiq: Add watchdog support + +This patch adds the driver for the watchdog found inside the Lantiq SoC family. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: Wim Van Sebroeck <wim@iguana.be> +Cc: linux-mips@linux-mips.org +Cc: linux-watchdog@vger.kernel.org +Patchwork: https://patchwork.linux-mips.org/patch/2327/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + drivers/watchdog/Kconfig | 6 + + drivers/watchdog/Makefile | 1 + + drivers/watchdog/lantiq_wdt.c | 261 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 268 insertions(+), 0 deletions(-) + create mode 100644 drivers/watchdog/lantiq_wdt.c + +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -850,6 +850,12 @@ + help + Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs. + ++config LANTIQ_WDT ++ tristate "Lantiq SoC watchdog" ++ depends on LANTIQ ++ help ++ Hardware driver for the Lantiq SoC Watchdog Timer. ++ + # PARISC Architecture + + # POWERPC Architecture +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -113,6 +113,7 @@ + obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o + obj-$(CONFIG_AR7_WDT) += ar7_wdt.o + obj-$(CONFIG_TXX9_WDT) += txx9wdt.o ++obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o + + # PARISC Architecture + +--- /dev/null ++++ b/drivers/watchdog/lantiq_wdt.c +@@ -0,0 +1,261 @@ ++/* ++ * 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> ++ * Based on EP93xx wdt driver ++ */ ++ ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/watchdog.h> ++#include <linux/platform_device.h> ++#include <linux/uaccess.h> ++#include <linux/clk.h> ++#include <linux/io.h> ++ ++#include <lantiq.h> ++ ++/* Section 3.4 of the datasheet ++ * The password sequence protects the WDT control register from unintended ++ * write actions, which might cause malfunction of the WDT. ++ * ++ * essentially the following two magic passwords need to be written to allow ++ * IO access to the WDT core ++ */ ++#define LTQ_WDT_PW1 0x00BE0000 ++#define LTQ_WDT_PW2 0x00DC0000 ++ ++#define LTQ_WDT_CR 0x0 /* watchdog control register */ ++#define LTQ_WDT_SR 0x8 /* watchdog status register */ ++ ++#define LTQ_WDT_SR_EN (0x1 << 31) /* enable bit */ ++#define LTQ_WDT_SR_PWD (0x3 << 26) /* turn on power */ ++#define LTQ_WDT_SR_CLKDIV (0x3 << 24) /* turn on clock and set */ ++ /* divider to 0x40000 */ ++#define LTQ_WDT_DIVIDER 0x40000 ++#define LTQ_MAX_TIMEOUT ((1 << 16) - 1) /* the reload field is 16 bit */ ++ ++static int nowayout = WATCHDOG_NOWAYOUT; ++ ++static void __iomem *ltq_wdt_membase; ++static unsigned long ltq_io_region_clk_rate; ++ ++static unsigned long ltq_wdt_bootstatus; ++static unsigned long ltq_wdt_in_use; ++static int ltq_wdt_timeout = 30; ++static int ltq_wdt_ok_to_close; ++ ++static void ++ltq_wdt_enable(void) ++{ ++ ltq_wdt_timeout = ltq_wdt_timeout * ++ (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000; ++ if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT) ++ ltq_wdt_timeout = LTQ_MAX_TIMEOUT; ++ ++ /* write the first password magic */ ++ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); ++ /* write the second magic plus the configuration and new timeout */ ++ ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV | ++ LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR); ++} ++ ++static void ++ltq_wdt_disable(void) ++{ ++ /* write the first password magic */ ++ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); ++ /* write the second password magic with no config ++ * this turns the watchdog off ++ */ ++ ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR); ++} ++ ++static ssize_t ++ltq_wdt_write(struct file *file, const char __user *data, ++ size_t len, loff_t *ppos) ++{ ++ if (len) { ++ if (!nowayout) { ++ size_t i; ++ ++ ltq_wdt_ok_to_close = 0; ++ for (i = 0; i != len; i++) { ++ char c; ++ ++ if (get_user(c, data + i)) ++ return -EFAULT; ++ if (c == 'V') ++ ltq_wdt_ok_to_close = 1; ++ else ++ ltq_wdt_ok_to_close = 0; ++ } ++ } ++ ltq_wdt_enable(); ++ } ++ ++ return len; ++} ++ ++static struct watchdog_info ident = { ++ .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | ++ WDIOF_CARDRESET, ++ .identity = "ltq_wdt", ++}; ++ ++static long ++ltq_wdt_ioctl(struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret = -ENOTTY; ++ ++ switch (cmd) { ++ case WDIOC_GETSUPPORT: ++ ret = copy_to_user((struct watchdog_info __user *)arg, &ident, ++ sizeof(ident)) ? -EFAULT : 0; ++ break; ++ ++ case WDIOC_GETBOOTSTATUS: ++ ret = put_user(ltq_wdt_bootstatus, (int __user *)arg); ++ break; ++ ++ case WDIOC_GETSTATUS: ++ ret = put_user(0, (int __user *)arg); ++ break; ++ ++ case WDIOC_SETTIMEOUT: ++ ret = get_user(ltq_wdt_timeout, (int __user *)arg); ++ if (!ret) ++ ltq_wdt_enable(); ++ /* intentional drop through */ ++ case WDIOC_GETTIMEOUT: ++ ret = put_user(ltq_wdt_timeout, (int __user *)arg); ++ break; ++ ++ case WDIOC_KEEPALIVE: ++ ltq_wdt_enable(); ++ ret = 0; ++ break; ++ } ++ return ret; ++} ++ ++static int ++ltq_wdt_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(0, <q_wdt_in_use)) ++ return -EBUSY; ++ ltq_wdt_in_use = 1; ++ ltq_wdt_enable(); ++ ++ return nonseekable_open(inode, file); ++} ++ ++static int ++ltq_wdt_release(struct inode *inode, struct file *file) ++{ ++ if (ltq_wdt_ok_to_close) ++ ltq_wdt_disable(); ++ else ++ pr_err("ltq_wdt: watchdog closed without warning\n"); ++ ltq_wdt_ok_to_close = 0; ++ clear_bit(0, <q_wdt_in_use); ++ ++ return 0; ++} ++ ++static const struct file_operations ltq_wdt_fops = { ++ .owner = THIS_MODULE, ++ .write = ltq_wdt_write, ++ .unlocked_ioctl = ltq_wdt_ioctl, ++ .open = ltq_wdt_open, ++ .release = ltq_wdt_release, ++ .llseek = no_llseek, ++}; ++ ++static struct miscdevice ltq_wdt_miscdev = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = <q_wdt_fops, ++}; ++ ++static int __init ++ltq_wdt_probe(struct platform_device *pdev) ++{ ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ struct clk *clk; ++ ++ if (!res) { ++ dev_err(&pdev->dev, "cannot obtain I/O memory region"); ++ return -ENOENT; ++ } ++ res = devm_request_mem_region(&pdev->dev, res->start, ++ resource_size(res), dev_name(&pdev->dev)); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot request I/O memory region"); ++ return -EBUSY; ++ } ++ ltq_wdt_membase = devm_ioremap_nocache(&pdev->dev, res->start, ++ resource_size(res)); ++ if (!ltq_wdt_membase) { ++ dev_err(&pdev->dev, "cannot remap I/O memory region\n"); ++ return -ENOMEM; ++ } ++ ++ /* we do not need to enable the clock as it is always running */ ++ clk = clk_get(&pdev->dev, "io"); ++ WARN_ON(!clk); ++ ltq_io_region_clk_rate = clk_get_rate(clk); ++ clk_put(clk); ++ ++ if (ltq_reset_cause() == LTQ_RST_CAUSE_WDTRST) ++ ltq_wdt_bootstatus = WDIOF_CARDRESET; ++ ++ return misc_register(<q_wdt_miscdev); ++} ++ ++static int __devexit ++ltq_wdt_remove(struct platform_device *pdev) ++{ ++ misc_deregister(<q_wdt_miscdev); ++ ++ if (ltq_wdt_membase) ++ iounmap(ltq_wdt_membase); ++ ++ return 0; ++} ++ ++ ++static struct platform_driver ltq_wdt_driver = { ++ .remove = __devexit_p(ltq_wdt_remove), ++ .driver = { ++ .name = "ltq_wdt", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++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_param(nowayout, int, 0); ++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); ++ ++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); ++MODULE_DESCRIPTION("Lantiq SoC Watchdog"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/target/linux/lantiq/patches/900-header_falcon.patch b/target/linux/lantiq/patches-2.6.32/100-falcon_header.patch index f2e6870..f4da9ef 100644 --- a/target/linux/lantiq/patches/900-header_falcon.patch +++ b/target/linux/lantiq/patches-2.6.32/100-falcon_header.patch @@ -12406,18 +12406,6 @@ +extern int sys_gpe_hw_is_activated(u32 mask); + +#endif /* __FALCON_SYSCTRL_H */ ---- a/arch/mips/include/asm/mach-lantiq/lantiq_regs.h -+++ b/arch/mips/include/asm/mach-lantiq/lantiq_regs.h -@@ -12,6 +12,9 @@ - #ifdef CONFIG_SOC_LANTIQ_XWAY - #include <xway.h> - #include <xway_irq.h> -+#elif defined(CONFIG_SOC_LANTIQ_FALCON) -+#include <lantiq_falcon.h> -+#include <lantiq_falcon_irq.h> - #endif - - #endif --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/falcon/cpu-feature-overrides.h @@ -0,0 +1,58 @@ diff --git a/target/linux/lantiq/patches/901-board_falcon.patch b/target/linux/lantiq/patches-2.6.32/110-falcon_board.patch index 630ac10..9151463 100644 --- a/target/linux/lantiq/patches/901-board_falcon.patch +++ b/target/linux/lantiq/patches-2.6.32/110-falcon_board.patch @@ -1,7 +1,7 @@ --- /dev/null +++ b/arch/mips/lantiq/falcon/Kconfig @@ -0,0 +1,11 @@ -+if SOC_LANTIQ_FALCON ++if SOC_FALCON + +menu "Mips Machine" + @@ -20,7 +20,7 @@ +obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o --- /dev/null +++ b/arch/mips/lantiq/falcon/clk-falcon.c -@@ -0,0 +1,46 @@ +@@ -0,0 +1,48 @@ +/* + * 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 @@ -38,35 +38,37 @@ +#include <asm/irq.h> +#include <asm/div64.h> + -+#include <falcon.h> ++#include <lantiq_soc.h> + -+#include <falcon/sys1_reg.h> ++#include <falcon.h> ++#include <gpon_reg_base.h> ++#include <sys1_reg.h> + +static struct gpon_reg_sys1 * const pSYS1 = (struct gpon_reg_sys1 *)GPON_SYS1_BASE; + +unsigned int -+lq_get_io_region_clock(void) ++ltq_get_io_region_clock(void) +{ + return 200000000; /* 200 MHz */ +} -+EXPORT_SYMBOL(lq_get_io_region_clock); ++EXPORT_SYMBOL(ltq_get_io_region_clock); + +unsigned int -+lq_get_cpu_hz(void) ++ltq_get_cpu_hz(void) +{ -+ if ((lq_r32(&pSYS1->cpu0cc) & CPU0CC_CPUDIV) == CPU0CC_CPUDIV_SELFHALF) ++ if ((ltq_r32(&pSYS1->cpu0cc) & CPU0CC_CPUDIV) == CPU0CC_CPUDIV_SELFHALF) + return 200000000; /* 200 MHz */ + else + return 400000000; /* 400 MHz */ +} -+EXPORT_SYMBOL(lq_get_cpu_hz); ++EXPORT_SYMBOL(ltq_get_cpu_hz); + +unsigned int -+lq_get_fpi_hz(void) ++ltq_get_fpi_hz(void) +{ + return 100000000; +} -+EXPORT_SYMBOL(lq_get_fpi_hz); ++EXPORT_SYMBOL(ltq_get_fpi_hz); --- /dev/null +++ b/arch/mips/lantiq/falcon/devices.c @@ -0,0 +1,180 @@ @@ -101,15 +103,15 @@ + +#include "devices.h" + -+unsigned char lq_ethaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+EXPORT_SYMBOL(lq_ethaddr); ++unsigned char ltq_ethaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++EXPORT_SYMBOL(ltq_ethaddr); + +static int __init +falcon_set_ethaddr(char *str) +{ + sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", -+ &lq_ethaddr[0], &lq_ethaddr[1], &lq_ethaddr[2], -+ &lq_ethaddr[3], &lq_ethaddr[4], &lq_ethaddr[5]); ++ <q_ethaddr[0], <q_ethaddr[1], <q_ethaddr[2], ++ <q_ethaddr[3], <q_ethaddr[4], <q_ethaddr[5]); + return 0; +} +__setup("ethaddr=", falcon_set_ethaddr); @@ -135,11 +137,11 @@ +{ + switch (port) { + case 0: -+ platform_device_register_simple("lq_asc", 0, ++ platform_device_register_simple("ltq_asc", 0, + falcon_asc0_resources, ARRAY_SIZE(falcon_asc0_resources)); + break; + case 1: -+ platform_device_register_simple("lq_asc", 1, ++ platform_device_register_simple("ltq_asc", 1, + falcon_asc1_resources, ARRAY_SIZE(falcon_asc1_resources)); + break; + default: @@ -148,37 +150,37 @@ +} + +/* nor flash */ -+static struct resource lq_nor_resource = -+ MEM_RES("nor",LQ_FLASH_START,LQ_FLASH_START + LQ_FLASH_MAX - 1); ++static struct resource ltq_nor_resource = ++ MEM_RES("nor",LTQ_FLASH_START,LTQ_FLASH_START + LTQ_FLASH_MAX - 1); + -+static struct platform_device lq_nor = { -+ .name = "lq_nor", -+ .resource = &lq_nor_resource, ++static struct platform_device ltq_nor = { ++ .name = "ltq_nor", ++ .resource = <q_nor_resource, + .num_resources = 1, +}; + +void __init falcon_register_nor(struct physmap_flash_data *data) +{ -+ lq_nor.dev.platform_data = data; -+ platform_device_register(&lq_nor); ++ ltq_nor.dev.platform_data = data; ++ platform_device_register(<q_nor); +} + +/* spi flash */ -+static struct resource lq_spi_resources[] = { ++static struct resource ltq_spi_resources[] = { + MEM_RES("ebu", GPON_EBU_BASE, GPON_EBU_END), + MEM_RES("sys1", GPON_SYS1_BASE, GPON_SYS1_END) +}; + -+static struct platform_device lq_spi = { ++static struct platform_device ltq_spi = { + .name = "falcon_spi", -+ .resource = lq_spi_resources, -+ .num_resources = ARRAY_SIZE(lq_spi_resources) ++ .resource = ltq_spi_resources, ++ .num_resources = ARRAY_SIZE(ltq_spi_resources) +}; + +void __init falcon_register_spi_flash(struct spi_board_info *data) +{ + spi_register_board_info(data, 1); -+ platform_device_register(&lq_spi); ++ platform_device_register(<q_spi); +} + +/* watchdog */ @@ -187,7 +189,7 @@ + +void __init falcon_register_wdt(void) +{ -+ platform_device_register_simple("lq_wdt", 0, &falcon_wdt_resource, 1); ++ platform_device_register_simple("ltq_wdt", 0, &falcon_wdt_resource, 1); +} + +/* gpio */ @@ -248,7 +250,7 @@ + +void __init falcon_register_crypto(void) +{ -+ platform_device_register_simple("lq_falcon_deu", 0, NULL, 0); ++ platform_device_register_simple("ltq_falcon_deu", 0, NULL, 0); +} --- /dev/null +++ b/arch/mips/lantiq/falcon/devices.h @@ -276,7 +278,7 @@ +#endif --- /dev/null +++ b/arch/mips/lantiq/falcon/prom.c -@@ -0,0 +1,44 @@ +@@ -0,0 +1,52 @@ +/* + * 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 @@ -291,6 +293,8 @@ +#include <asm/bootinfo.h> +#include <asm/time.h> + ++#include <lantiq_soc.h> ++ +#include <falcon.h> + +#include <falcon/gpon_reg_base.h> @@ -304,10 +308,16 @@ +#define SOC_FALCON "Falcon" + +void __init -+lq_soc_detect(struct lq_soc_info *i) ++ltq_soc_setup(void) ++{ ++ /* not used */ ++} ++ ++void __init ++ltq_soc_detect(struct ltq_soc_info *i) +{ -+ i->partnum = (lq_r32(&pSTATUS->chipid) & STATUS_CHIPID_PARTNR_MASK) >> STATUS_CHIPID_PARTNR_OFFSET; -+ i->rev = (lq_r32(&pSTATUS->chipid) & STATUS_CHIPID_VERSION_MASK) >> STATUS_CHIPID_VERSION_OFFSET; ++ i->partnum = (ltq_r32(&pSTATUS->chipid) & STATUS_CHIPID_PARTNR_MASK) >> STATUS_CHIPID_PARTNR_OFFSET; ++ i->rev = (ltq_r32(&pSTATUS->chipid) & STATUS_CHIPID_VERSION_MASK) >> STATUS_CHIPID_VERSION_OFFSET; + switch (i->partnum) + { + case SOC_ID_FALCON: @@ -1173,7 +1183,7 @@ +module_exit(falcon_gpio_exit); --- /dev/null +++ b/arch/mips/include/asm/mach-lantiq/falcon/falcon.h -@@ -0,0 +1,30 @@ +@@ -0,0 +1,16 @@ +/* + * 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 @@ -1184,29 +1194,15 @@ + * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + */ + -+#ifdef CONFIG_SOC_LANTIQ_FALCON ++#ifdef CONFIG_SOC_FALCON + -+#ifndef _LQ_FALCON_H__ -+#define _LQ_FALCON_H__ -+ -+#include <lantiq.h> ++#include <lantiq_soc.h> +#include <falcon/gpon_reg_base.h> + -+/*------------ GENERAL */ -+#define BOARD_SYSTEM_TYPE "LANTIQ" -+ -+/*------------ Chip IDs */ -+#define SOC_ID_FALCON 0x01B8 -+ -+/*------------ SoC Types */ -+#define SOC_TYPE_FALCON 0x01 -+ -+#endif -+ +#endif --- /dev/null +++ b/arch/mips/lantiq/falcon/reset.c -@@ -0,0 +1,72 @@ +@@ -0,0 +1,80 @@ +/* + * 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 @@ -1220,6 +1216,7 @@ +#include <linux/io.h> +#include <linux/pm.h> +#include <asm/reboot.h> ++#include <linux/module.h> + +#include <falcon.h> +#include <falcon/gpon_reg_base.h> @@ -1232,18 +1229,25 @@ +#define WDT_PW2 0x00DC0000 +#define WDT_REG_BASE (KSEG1 | 0x1F8803F0) + ++/* This function is used by the watchdog driver */ ++int ltq_reset_cause(void) ++{ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ltq_reset_cause); ++ +static void -+lq_machine_restart(char *command) ++ltq_machine_restart(char *command) +{ + printk(KERN_NOTICE "System restart\n"); + local_irq_disable(); -+ lq_w32(0, (void*)0xBF200000); /* reset Bootreg RVEC */ ++ ltq_w32(0, (void*)0xBF200000); /* reset Bootreg RVEC */ +#if 0 -+ lq_w32(RBT_CPU_TRIG, &pSYS1->rbt); ++ ltq_w32(RBT_CPU_TRIG, &pSYS1->rbt); +#else + /* use workaround via watchdog timer */ -+ lq_w32(WDT_PW1, (void*)WDT_REG_BASE); -+ lq_w32(WDT_PW2 | ++ ltq_w32(WDT_PW1, (void*)WDT_REG_BASE); ++ ltq_w32(WDT_PW2 | + (0x3 << 26) | /* PWL */ + (0x2 << 24) | /* CLKDIV */ + (0x1 << 31) | /* enable */ @@ -1254,7 +1258,7 @@ +} + +static void -+lq_machine_halt(void) ++ltq_machine_halt(void) +{ + printk(KERN_NOTICE "System halted.\n"); + local_irq_disable(); @@ -1262,7 +1266,7 @@ +} + +static void -+lq_machine_power_off(void) ++ltq_machine_power_off(void) +{ + printk(KERN_NOTICE "Please turn off the power now.\n"); + local_irq_disable(); @@ -1272,16 +1276,16 @@ +static int __init +mips_reboot_setup(void) +{ -+ _machine_restart = lq_machine_restart; -+ _machine_halt = lq_machine_halt; -+ pm_power_off = lq_machine_power_off; ++ _machine_restart = ltq_machine_restart; ++ _machine_halt = ltq_machine_halt; ++ pm_power_off = ltq_machine_power_off; + return 0; +} + +arch_initcall(mips_reboot_setup); --- /dev/null +++ b/arch/mips/lantiq/falcon/mach-easy98000.c -@@ -0,0 +1,246 @@ +@@ -0,0 +1,247 @@ +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/leds.h> @@ -1299,7 +1303,8 @@ +#include <linux/spi/spi.h> +#include <linux/spi/spi_gpio.h> +#include <linux/spi/eeprom.h> -+#include <machine.h> ++ ++#include "../machtypes.h" + +#include "devices.h" +#include "dev-leds-gpio.h" @@ -1311,7 +1316,7 @@ +#define EASY98000_GPIO_LED_4 13 +#define EASY98000_GPIO_LED_5 14 + -+extern unsigned char lq_ethaddr[6]; ++extern unsigned char ltq_ethaddr[6]; + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition easy98000_nor_partitions[] = @@ -1420,10 +1425,10 @@ + +static void __init register_davicom(void) +{ -+ if (!is_valid_ether_addr(lq_ethaddr)) ++ if (!is_valid_ether_addr(ltq_ethaddr)) + random_ether_addr(dm9000_plat_data.dev_addr); + else { -+ memcpy(dm9000_plat_data.dev_addr, lq_ethaddr, 6); ++ memcpy(dm9000_plat_data.dev_addr, ltq_ethaddr, 6); + /* change to "Locally Administered Address" */ + dm9000_plat_data.dev_addr[0] |= 0x2; + } @@ -1500,7 +1505,7 @@ + falcon_register_i2c(); + platform_device_register(&easy98000_i2c_gpio_device); + register_davicom(); -+ lq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98000_leds_gpio), ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98000_leds_gpio), + easy98000_leds_gpio); + register_easy98000_cpld_led(); + falcon_register_crypto(); @@ -1689,49 +1694,44 @@ +#endif --- a/arch/mips/lantiq/Kconfig +++ b/arch/mips/lantiq/Kconfig -@@ -21,16 +21,16 @@ choice - prompt "SoC Type" - default SOC_LANTIQ_XWAY - --#config SOC_LANTIQ_FALCON --# bool "FALCON" --# select SOC_LANTIQ -+config SOC_LANTIQ_FALCON -+ bool "FALCON" -+ select SOC_LANTIQ - - config SOC_LANTIQ_XWAY +@@ -16,8 +16,12 @@ bool "XWAY" - select SOC_LANTIQ + select SOC_TYPE_XWAY + select HW_HAS_PCI ++ ++config SOC_FALCON ++ bool "FALCON" endchoice --#source "arch/mips/lantiq/falcon/Kconfig" -+source "arch/mips/lantiq/falcon/Kconfig" source "arch/mips/lantiq/xway/Kconfig" ++source "arch/mips/lantiq/falcon/Kconfig" - if EARLY_PRINTK ---- a/arch/mips/include/asm/mach-lantiq/machine.h -+++ b/arch/mips/include/asm/mach-lantiq/machine.h -@@ -5,6 +5,7 @@ enum lantiq_mach_type { - - /* FALCON */ - LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */ -+ LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */ - LANTIQ_MACH_EASY98020, /* Falcon Reference Board */ - - /* XWAY */ + endif --- a/arch/mips/lantiq/Makefile +++ b/arch/mips/lantiq/Makefile -@@ -1,3 +1,4 @@ - obj-y := dev-leds-gpio.o irq.o setup.o clk.o prom.o +@@ -9,3 +9,4 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -+obj-$(CONFIG_SOC_LANTIQ_FALCON) += falcon/ - obj-$(CONFIG_SOC_LANTIQ_XWAY) += xway/ + + obj-$(CONFIG_SOC_TYPE_XWAY) += xway/ ++obj-$(CONFIG_SOC_FALCON) += falcon/ --- a/arch/mips/lantiq/Platform +++ b/arch/mips/lantiq/Platform -@@ -5,4 +5,5 @@ - platform-$(CONFIG_LANTIQ) += lantiq/ - cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq - load-$(CONFIG_LANTIQ) = 0xffffffff80002000 -+cflags-$(CONFIG_SOC_LANTIQ_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon - cflags-$(CONFIG_SOC_LANTIQ_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway +@@ -6,3 +6,4 @@ + 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_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon +--- a/arch/mips/lantiq/machtypes.h ++++ b/arch/mips/lantiq/machtypes.h +@@ -15,6 +15,11 @@ + LTQ_MACH_GENERIC = 0, + LTQ_MACH_EASY50712, /* Danube evaluation board */ + LTQ_MACH_EASY50601, /* Amazon SE evaluation board */ ++ ++ /* FALCON */ ++ LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */ ++ LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */ ++ LANTIQ_MACH_EASY98020, /* Falcon Reference Board */ + }; + + #endif diff --git a/target/linux/lantiq/patches/910-falcon-i2c.patch b/target/linux/lantiq/patches-2.6.32/120-falcon-i2c.patch index 21d4125..3dd873b 100644 --- a/target/linux/lantiq/patches/910-falcon-i2c.patch +++ b/target/linux/lantiq/patches-2.6.32/120-falcon-i2c.patch @@ -1,15 +1,16 @@ --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile -@@ -76,5 +76,6 @@ +@@ -74,6 +74,7 @@ obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o +obj-$(CONFIG_I2C_FALCON) += i2c-falcon.o - ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG + ifeq ($(CONFIG_I2C_DEBUG_BUS),y) + EXTRA_CFLAGS += -DDEBUG --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig -@@ -281,6 +281,10 @@ +@@ -278,6 +278,10 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)" diff --git a/target/linux/lantiq/patches/915-falcon-spi-flash.patch b/target/linux/lantiq/patches-2.6.32/130-falcon-spi-flash.patch index d24183e..590d31f 100644 --- a/target/linux/lantiq/patches/915-falcon-spi-flash.patch +++ b/target/linux/lantiq/patches-2.6.32/130-falcon-spi-flash.patch @@ -1,9 +1,9 @@ --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile -@@ -22,6 +22,7 @@ obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi. - obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o - obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o - obj-$(CONFIG_SPI_EP93XX) += ep93xx_spi.o +@@ -16,6 +16,7 @@ + obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o + obj-$(CONFIG_SPI_AU1550) += au1550_spi.o + obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o +obj-$(CONFIG_SPI_FALCON) += spi_falcon.o obj-$(CONFIG_SPI_GPIO) += spi_gpio.o obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o @@ -484,14 +484,14 @@ +MODULE_DESCRIPTION("Lantiq Falcon SPI controller driver"); --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig -@@ -169,6 +169,10 @@ config SPI_LM70_LLP +@@ -142,6 +142,10 @@ which interfaces to an LM70 temperature sensor using a parallel port. +config SPI_FALCON + tristate "Falcon SPI controller support" -+ depends on SOC_LANTIQ_FALCON ++ depends on SOC_FALCON + - config SPI_MPC52xx - tristate "Freescale MPC52xx SPI (non-PSC) controller support" - depends on PPC_MPC52xx && SPI + config SPI_MPC52xx_PSC + tristate "Freescale MPC52xx PSC SPI controller" + depends on PPC_MPC52xx && EXPERIMENTAL diff --git a/target/linux/lantiq/patches/920-falcon-easy98000-cpld-led.patch b/target/linux/lantiq/patches-2.6.32/140-falcon-easy98000-cpld-led.patch index 6e8b302..f623b2e 100644 --- a/target/linux/lantiq/patches/920-falcon-easy98000-cpld-led.patch +++ b/target/linux/lantiq/patches-2.6.32/140-falcon-easy98000-cpld-led.patch @@ -44,8 +44,8 @@ +#define cpld_base7 ((u16 *)(KSEG1 | 0x17c0000c)) +#define cpld_base8 ((u16 *)(KSEG1 | 0x17c00012)) + -+#define lq_r16(reg) __raw_readw(reg) -+#define lq_w16(val, reg) __raw_writew(val, reg) ++#define ltq_r16(reg) __raw_readw(reg) ++#define ltq_w16(val, reg) __raw_writew(val, reg) + +struct cpld_led_dev { + struct led_classdev cdev; @@ -60,12 +60,12 @@ + +void led_set(u8 mask, u16 *base) +{ -+ lq_w16(lq_r16(base) | mask, base); ++ ltq_w16(ltq_r16(base) | mask, base); +} + +void led_clear(u8 mask, u16 *base) +{ -+ lq_w16(lq_r16(base) & (~mask), base); ++ ltq_w16(ltq_r16(base) & (~mask), base); +} + +void led_blink_clear(u8 mask, u16 *base) diff --git a/target/linux/lantiq/patches/920-falcon-easy98020.patch b/target/linux/lantiq/patches-2.6.32/150-falcon-easy98020.patch index 36a3b65..e9593c5 100644 --- a/target/linux/lantiq/patches/920-falcon-easy98020.patch +++ b/target/linux/lantiq/patches-2.6.32/150-falcon-easy98020.patch @@ -12,7 +12,7 @@ +#include <linux/interrupt.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> -+#include <machine.h> ++#include "../machtypes.h" + +#include "devices.h" +#include "dev-leds-gpio.h" @@ -22,7 +22,7 @@ +#define EASY98020_GPIO_LED_2 11 +#define EASY98020_GPIO_LED_3 12 + -+extern unsigned char lq_ethaddr[6]; ++extern unsigned char ltq_ethaddr[6]; + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition easy98020_spi_partitions[] = @@ -89,7 +89,7 @@ + falcon_register_wdt(); + falcon_register_i2c(); + falcon_register_spi_flash(&easy98020_spi_flash_data); -+ lq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98020_leds_gpio), ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98020_leds_gpio), + easy98020_leds_gpio); + falcon_register_crypto(); +} @@ -100,7 +100,7 @@ + easy98020_init); --- a/arch/mips/lantiq/falcon/Kconfig +++ b/arch/mips/lantiq/falcon/Kconfig -@@ -6,6 +6,10 @@ config LANTIQ_MACH_EASY98000 +@@ -6,6 +6,10 @@ bool "Easy98000" default y @@ -113,7 +113,7 @@ endif --- a/arch/mips/lantiq/falcon/Makefile +++ b/arch/mips/lantiq/falcon/Makefile -@@ -2,3 +2,4 @@ obj-y := clk-falcon.o devices.o gpio.o p +@@ -2,3 +2,4 @@ obj-y += softdog_vpe.o obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o diff --git a/target/linux/lantiq/patches/930-falcon-95C3AM1.patch b/target/linux/lantiq/patches-2.6.32/160-falcon-95C3AM1.patch index 618f8fb..0347037 100644 --- a/target/linux/lantiq/patches/930-falcon-95C3AM1.patch +++ b/target/linux/lantiq/patches-2.6.32/160-falcon-95C3AM1.patch @@ -4,7 +4,7 @@ +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c-gpio.h> -+#include <machine.h> ++#include "../machtypes.h" + +#include "devices.h" +#include "dev-leds-gpio.h" @@ -14,7 +14,7 @@ +#define BOARD_95C3AM1_GPIO_LED_2 12 +#define BOARD_95C3AM1_GPIO_LED_3 13 + -+extern unsigned char lq_ethaddr[6]; ++extern unsigned char ltq_ethaddr[6]; + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition board_95C3AM1_partitions[] = @@ -95,7 +95,7 @@ + falcon_register_i2c(); + falcon_register_spi_flash(&board_95C3AM1_flash_data); + platform_device_register(&board_95C3AM1_i2c_gpio_device); -+ lq_add_device_leds_gpio(-1, ARRAY_SIZE(board_95C3AM1_leds_gpio), ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(board_95C3AM1_leds_gpio), + board_95C3AM1_leds_gpio); + falcon_register_crypto(); +} @@ -104,19 +104,9 @@ + "95C3AM1", + "95C3AM1 Board", + board_95C3AM1_init); ---- a/arch/mips/include/asm/mach-lantiq/machine.h -+++ b/arch/mips/include/asm/mach-lantiq/machine.h -@@ -7,6 +7,7 @@ enum lantiq_mach_type { - LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */ - LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */ - LANTIQ_MACH_EASY98020, /* Falcon Reference Board */ -+ LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */ - - /* XWAY */ - LANTIQ_MACH_EASY4010, /* Twinpass evalkit */ --- a/arch/mips/lantiq/falcon/Kconfig +++ b/arch/mips/lantiq/falcon/Kconfig -@@ -10,6 +10,10 @@ config LANTIQ_MACH_EASY98020 +@@ -10,6 +10,10 @@ bool "Easy98020" default y @@ -129,8 +119,18 @@ endif --- a/arch/mips/lantiq/falcon/Makefile +++ b/arch/mips/lantiq/falcon/Makefile -@@ -3,3 +3,4 @@ obj-y += softdog_vpe.o +@@ -3,3 +3,4 @@ obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o obj-$(CONFIG_LANTIQ_MACH_EASY98020) += mach-easy98020.o +obj-$(CONFIG_LANTIQ_MACH_95C3AM1) += mach-95C3AM1.o +--- a/arch/mips/lantiq/machtypes.h ++++ b/arch/mips/lantiq/machtypes.h +@@ -20,6 +20,7 @@ + LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */ + LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */ + LANTIQ_MACH_EASY98020, /* Falcon Reference Board */ ++ LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */ + }; + + #endif diff --git a/target/linux/lantiq/patches/400-mach-arv45xx.patch b/target/linux/lantiq/patches-2.6.32/200-mach-arv45xx.patch index 4da4c98..26aa5fb 100644 --- a/target/linux/lantiq/patches/400-mach-arv45xx.patch +++ b/target/linux/lantiq/patches-2.6.32/200-mach-arv45xx.patch @@ -1,25 +1,7 @@ ---- a/arch/mips/include/asm/mach-lantiq/machine.h -+++ b/arch/mips/include/asm/mach-lantiq/machine.h -@@ -11,4 +11,15 @@ - LANTIQ_MACH_EASY4010, /* Twinpass evalkit */ - LANTIQ_MACH_EASY50712, /* Danube evalkit */ - LANTIQ_MACH_EASY50812, /* AR9 eval board */ -+ -+ /* Arcadyan */ -+ LANTIQ_MACH_ARV3527P, /* Arcor easybox a401 */ -+ LANTIQ_MACH_ARV4510PW, /* Wippies Homebox */ -+ LANTIQ_MACH_ARV4518PW, /* Airties WAV-221, SMC-7908A-ISP */ -+ LANTIQ_MACH_ARV4520PW, /* Airties WAV-281, Arcor EasyboxA800 */ -+ LANTIQ_MACH_ARV452CPW, /* Arcor EasyboxA801 */ -+ LANTIQ_MACH_ARV4525PW, /* Speedport W502V */ -+ LANTIQ_MACH_ARV752DPW, /* Arcor easybox a802 */ -+ LANTIQ_MACH_ARV752DPW22, /* Arcor easybox a803 */ -+ LANTIQ_MACH_ARV7518PW, /* ASTORIA */ - }; --- a/arch/mips/lantiq/xway/Kconfig +++ b/arch/mips/lantiq/xway/Kconfig -@@ -14,6 +14,10 @@ - bool "Easy4010" +@@ -6,6 +6,10 @@ + bool "Easy50712 - Danube" default y +config LANTIQ_MACH_ARV45XX @@ -31,14 +13,14 @@ endif --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile -@@ -3,3 +3,4 @@ - obj-$(CONFIG_LANTIQ_MACH_EASY50812) += mach-easy50812.o +@@ -5,3 +5,4 @@ + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o - obj-$(CONFIG_LANTIQ_MACH_EASY4010) += mach-easy4010.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o +obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o --- /dev/null +++ b/arch/mips/lantiq/xway/mach-arv45xx.c -@@ -0,0 +1,537 @@ +@@ -0,0 +1,504 @@ +/* + * 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 @@ -60,12 +42,12 @@ +#include <linux/ath5k_platform.h> +#include <linux/pci.h> + -+#include <machine.h> -+ -+#include <xway.h> ++#include <lantiq_soc.h> +#include <lantiq_platform.h> + ++#include "../machtypes.h" +#include "devices.h" ++#include "dev-leds-gpio.h" +#include "dev-dwc_otg.h" + +#ifdef CONFIG_MTD_PARTITIONS @@ -164,17 +146,16 @@ +#endif +}; + -+static struct lq_pci_data lq_pci_data = { -+ .clock = PCI_CLOCK_EXT, ++static struct ltq_pci_data ltq_pci_data = { ++ .clock = PCI_CLOCK_EXT, + .gpio = PCI_GNT1 | PCI_REQ1, + .irq = { + [14] = INT_NUM_IM0_IRL0 + 22, + }, +}; + -+static struct lq_eth_data lq_eth_data = { -+ .mii_mode = REV_MII_MODE, -+ .mac = "\xff\xff\xff\xff\xff\xff", ++static struct ltq_eth_data ltq_eth_data = { ++ .mii_mode = PHY_INTERFACE_MODE_RMII, +}; + +static struct gpio_led @@ -191,10 +172,10 @@ + { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:red:fail", .gpio = 8, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:green:usb", .gpio = 19, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:green:voip", .gpio = 32, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:green:fxs1", .gpio = 33, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:green:fxs2", .gpio = 34, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:green:fxo", .gpio = 35, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:voip", .gpio = 72, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:fxs1", .gpio = 73, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:fxs2", .gpio = 74, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" }, +}; + +static struct gpio_button @@ -212,13 +193,13 @@ + { .name = "soc:red:power", .gpio = 6, .active_low = 1, }, + { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, }, + { .name = "soc:red:wps", .gpio = 9, .active_low = 1, }, -+ { .name = "soc:blue:voip", .gpio = 32, .active_low = 1, }, -+ { .name = "soc:blue:fxs1", .gpio = 33, .active_low = 1, }, -+ { .name = "soc:blue:fxs2", .gpio = 34, .active_low = 1, }, -+ { .name = "soc:blue:fxo", .gpio = 35, .active_low = 1, }, -+ { .name = "soc:blue:voice", .gpio = 36, .active_low = 1, }, -+ { .name = "soc:blue:usb", .gpio = 37, .active_low = 1, }, -+ { .name = "soc:blue:wlan", .gpio = 38, .active_low = 1, }, ++ { .name = "soc:blue:voip", .gpio = 72, .active_low = 1, }, ++ { .name = "soc:blue:fxs1", .gpio = 73, .active_low = 1, }, ++ { .name = "soc:blue:fxs2", .gpio = 74, .active_low = 1, }, ++ { .name = "soc:blue:fxo", .gpio = 75, .active_low = 1, }, ++ { .name = "soc:blue:voice", .gpio = 76, .active_low = 1, }, ++ { .name = "soc:blue:usb", .gpio = 77, .active_low = 1, }, ++ { .name = "soc:blue:wlan", .gpio = 78, .active_low = 1, }, +}; + +static struct gpio_led @@ -229,15 +210,15 @@ + { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:red:wps", .gpio = 9, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:blue:fxs1", .gpio = 32, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:blue:fxs2", .gpio = 33, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:blue:wps", .gpio = 34, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:blue:fxo", .gpio = 35, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:blue:voice", .gpio = 36, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:blue:usb", .gpio = 37, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:blue:wlan", .gpio = 38, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:blue:internet", .gpio = 40, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:red:internet", .gpio = 41, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:fxs1", .gpio = 72, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:fxs2", .gpio = 73, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:wps", .gpio = 74, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:voice", .gpio = 76, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:usb", .gpio = 77, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:wlan", .gpio = 78, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:internet", .gpio = 80, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:red:internet", .gpio = 81, .active_low = 1, .default_trigger = "default-on" }, +}; + +static struct gpio_led @@ -255,17 +236,17 @@ + { .name = "soc:red:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" }, + { .name = "soc:red:wps", .gpio = 8, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:red:fxo", .gpio = 35, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:red:voice", .gpio = 36, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:green:usb", .gpio = 37, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:green:wlan", .gpio = 38, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:green:wlan1", .gpio = 39, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:blue:wlan", .gpio = 40, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:blue:wlan1", .gpio = 41, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:green:eth1", .gpio = 43, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:green:eth2", .gpio = 44, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:green:eth3", .gpio = 45, .active_low = 1, .default_trigger = "default-on" }, -+ { .name = "soc:green:eth4", .gpio = 46, .active_low = 1, .default_trigger = "default-on", }, ++ { .name = "soc:red:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:red:voice", .gpio = 76, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:usb", .gpio = 77, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:wlan", .gpio = 78, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:wlan1", .gpio = 79, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:wlan", .gpio = 80, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:wlan1", .gpio = 81, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:eth1", .gpio = 83, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:eth2", .gpio = 84, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:eth3", .gpio = 85, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:eth4", .gpio = 86, .active_low = 1, .default_trigger = "default-on", }, +}; + +static struct gpio_button @@ -295,27 +276,27 @@ +arv45xx_register_ethernet(void) +{ +#define ARV45XX_BRN_MAC 0x3f0016 -+ memcpy_fromio(lq_eth_data.mac, -+ (void *)KSEG1ADDR(LQ_FLASH_START + ARV45XX_BRN_MAC), 6); -+ lq_register_ethernet(&lq_eth_data); ++ memcpy_fromio(<q_eth_data.mac, ++ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6); ++ ltq_register_etop(<q_eth_data); +} + +static void +arv75xx_register_ethernet(void) +{ +#define ARV75XX_BRN_MAC 0x7f0016 -+ memcpy_fromio(lq_eth_data.mac, -+ (void *)KSEG1ADDR(LQ_FLASH_START + ARV75XX_BRN_MAC), 6); -+ lq_register_ethernet(&lq_eth_data); ++ memcpy_fromio(<q_eth_data.mac, ++ (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(lq_eth_data.mac, -+ (void *)KSEG1ADDR(LQ_FLASH_START + BEWAN_BRN_MAC), 6); -+ lq_register_ethernet(&lq_eth_data); ++ memcpy_fromio(<q_eth_data.mac, ++ (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]; @@ -337,10 +318,10 @@ + u32 *p = (u32*)arv45xx_ath5k_eeprom_data; + + memcpy_fromio(eeprom_mac, -+ (void *)KSEG1ADDR(LQ_FLASH_START + ARV45XX_BRN_MAC), 6); ++ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6); + eeprom_mac[5]++; + memcpy_fromio(arv45xx_ath5k_eeprom_data, -+ (void *)KSEG1ADDR(LQ_FLASH_START + ARV45XX_BRN_ATH), ATH5K_PLAT_EEP_MAX_WORDS); ++ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_ATH), 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); @@ -356,19 +337,15 @@ + } + arv45xx_ath5k_platform_data.eeprom_data = arv45xx_ath5k_eeprom_data; + arv45xx_ath5k_platform_data.macaddr = eeprom_mac; -+ lqpci_plat_dev_init = arv45xx_pci_plat_dev_init; ++ //lqpci_plat_dev_init = arv45xx_pci_plat_dev_init; +} + +static void __init +arv3527p_init(void) +{ -+ lq_register_gpio(); -+ lq_register_gpio_stp(); -+ //lq_register_gpio_leds(arv3527p_leds_gpio, ARRAY_SIZE(arv3527p_leds_gpio)); -+ lq_register_asc(0); -+ lq_register_asc(1); -+ lq_register_nor(&arv45xx_flash_data); -+ lq_register_wdt(); ++ ltq_register_gpio_stp(); ++ //ltq_add_device_leds_gpio(arv3527p_leds_gpio, ARRAY_SIZE(arv3527p_leds_gpio)); ++ ltq_register_nor(&arv45xx_flash_data); + arv45xx_register_ethernet(); +} + @@ -380,17 +357,13 @@ +static void __init +arv4510pw_init(void) +{ -+ lq_register_gpio(); -+ lq_register_gpio_stp(); -+ lq_register_gpio_leds(arv4510pw_leds_gpio, ARRAY_SIZE(arv4510pw_leds_gpio)); -+ lq_register_asc(0); -+ lq_register_asc(1); -+ lq_register_nor(&arv4510_flash_data); -+ lq_pci_data.irq[12] = (INT_NUM_IM2_IRL0 + 31); -+ lq_pci_data.irq[15] = (INT_NUM_IM0_IRL0 + 26); -+ lq_pci_data.gpio |= PCI_EXIN2 | PCI_REQ2; -+ lq_register_pci(&lq_pci_data); -+ lq_register_wdt(); ++ ltq_register_gpio_stp(); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4510pw_leds_gpio), arv4510pw_leds_gpio); ++ ltq_register_nor(&arv4510_flash_data); ++ 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(); +} + @@ -406,17 +379,13 @@ +#define ARV4518PW_USB 14 +#define ARV4518PW_SWITCH_RESET 13 + -+ lq_register_gpio(); -+ lq_register_gpio_ebu(ARV4518PW_EBU); -+ lq_register_gpio_leds(arv4518pw_leds_gpio, ARRAY_SIZE(arv4518pw_leds_gpio)); -+ lq_register_gpio_buttons(arv4518pw_gpio_buttons, ARRAY_SIZE(arv4518pw_gpio_buttons)); -+ lq_register_asc(0); -+ lq_register_asc(1); -+ lq_register_nor(&arv45xx_flash_data); -+ lq_pci_data.gpio = PCI_GNT2 | PCI_REQ2; -+ lq_register_pci(&lq_pci_data); -+ lq_register_wdt(); -+ lq_register_madwifi_eep(); ++ ltq_register_gpio_ebu(ARV4518PW_EBU); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4518pw_leds_gpio), arv4518pw_leds_gpio); ++ ltq_register_gpio_buttons(arv4518pw_gpio_buttons, ARRAY_SIZE(arv4518pw_gpio_buttons)); ++ ltq_register_nor(&arv45xx_flash_data); ++ ltq_pci_data.gpio = PCI_GNT2 | PCI_REQ2; ++ ltq_register_pci(<q_pci_data); ++ ltq_register_madwifi_eep(); + xway_register_dwc(ARV4518PW_USB); + arv45xx_register_ethernet(); + arv45xx_register_ath5k(); @@ -436,17 +405,13 @@ +{ +#define ARV4520PW_EBU 0x400 +#define ARV4520PW_USB 28 -+#define ARV4520PW_SWITCH_RESET 42 -+ -+ lq_register_gpio(); -+ lq_register_gpio_ebu(ARV4520PW_EBU); -+ lq_register_gpio_leds(arv4520pw_leds_gpio, ARRAY_SIZE(arv4520pw_leds_gpio)); -+ lq_register_asc(0); -+ lq_register_asc(1); -+ lq_register_nor(&arv45xx_flash_data); -+ lq_register_pci(&lq_pci_data); -+ lq_register_wdt(); -+ lq_register_tapi(); ++#define ARV4520PW_SWITCH_RESET 82 ++ ++ ltq_register_gpio_ebu(ARV4520PW_EBU); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4520pw_leds_gpio), arv4520pw_leds_gpio); ++ ltq_register_nor(&arv45xx_flash_data); ++ ltq_register_pci(<q_pci_data); ++ ltq_register_tapi(); + arv45xx_register_ethernet(); + xway_register_dwc(ARV4520PW_USB); + @@ -465,18 +430,14 @@ +#define ARV452CPW_EBU 0x77f +#define ARV452CPW_USB 28 +#define ARV452CPW_RELAY1 31 -+#define ARV452CPW_RELAY2 39 -+#define ARV452CPW_SWITCH_RESET 42 -+ -+ lq_register_gpio(); -+ lq_register_gpio_ebu(ARV452CPW_EBU); -+ lq_register_gpio_leds(arv452cpw_leds_gpio, ARRAY_SIZE(arv452cpw_leds_gpio)); -+ lq_register_asc(0); -+ lq_register_asc(1); -+ lq_register_nor(&arv45xx_flash_data); -+ lq_register_pci(&lq_pci_data); -+ lq_register_wdt(); -+ lq_register_madwifi_eep(); ++#define ARV452CPW_RELAY2 79 ++#define ARV452CPW_SWITCH_RESET 82 ++ ++ ltq_register_gpio_ebu(ARV452CPW_EBU); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv452cpw_leds_gpio), arv452cpw_leds_gpio); ++ ltq_register_nor(&arv45xx_flash_data); ++ ltq_register_pci(<q_pci_data); ++ ltq_register_madwifi_eep(); + xway_register_dwc(ARV452CPW_USB); + arv45xx_register_ethernet(); + arv45xx_register_ath5k(); @@ -502,16 +463,12 @@ +static void __init +arv4525pw_init(void) +{ -+ lq_register_gpio(); -+ lq_register_gpio_leds(arv4525pw_leds_gpio, ARRAY_SIZE(arv4525pw_leds_gpio)); -+ lq_register_asc(0); -+ lq_register_asc(1); -+ lq_register_nor(&arv45xx_flash_data); -+ lq_pci_data.clock = PCI_CLOCK_INT; -+ lq_register_pci(&lq_pci_data); -+ lq_register_wdt(); -+ lq_register_madwifi_eep(); -+ lq_eth_data.mii_mode = MII_MODE; ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4525pw_leds_gpio), arv4525pw_leds_gpio); ++ ltq_register_nor(&arv45xx_flash_data); ++ ltq_pci_data.clock = PCI_CLOCK_INT; ++ ltq_register_pci(<q_pci_data); ++ ltq_register_madwifi_eep(); ++ ltq_eth_data.mii_mode = PHY_INTERFACE_MODE_MII; + arv45xx_register_ethernet(); +} + @@ -526,16 +483,12 @@ +#define ARV7518PW_EBU 0x2 +#define ARV7518PW_USB 14 + -+ lq_register_gpio(); -+ lq_register_gpio_ebu(ARV7518PW_EBU); -+ lq_register_asc(0); -+ lq_register_asc(1); -+ lq_register_gpio_leds(arv7518pw_leds_gpio, ARRAY_SIZE(arv7518pw_leds_gpio)); -+ lq_register_gpio_buttons(arv7518pw_gpio_buttons, ARRAY_SIZE(arv7518pw_gpio_buttons)); -+ lq_register_nor(&arv75xx_flash_data); -+ lq_register_pci(&lq_pci_data); -+ lq_register_wdt(); -+ lq_register_tapi(); ++ ltq_register_gpio_ebu(ARV7518PW_EBU); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv7518pw_leds_gpio), arv7518pw_leds_gpio); ++ ltq_register_gpio_buttons(arv7518pw_gpio_buttons, ARRAY_SIZE(arv7518pw_gpio_buttons)); ++ 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); @@ -550,20 +503,16 @@ +arv752dpw22_init(void) +{ +#define ARV752DPW22_EBU 0x2 -+#define ARV752DPW22_USB 32 -+#define ARV752DPW22_RELAY 33 -+ -+ lq_register_gpio(); -+ lq_register_gpio_ebu(ARV752DPW22_EBU); -+ lq_register_asc(0); -+ lq_register_asc(1); -+ lq_register_gpio_leds(arv752dpw22_leds_gpio, ARRAY_SIZE(arv752dpw22_leds_gpio)); -+ lq_register_gpio_buttons(arv752dpw22_gpio_buttons, ARRAY_SIZE(arv752dpw22_gpio_buttons)); -+ lq_register_nor(&arv75xx_flash_data); -+ lq_pci_data.irq[15] = (INT_NUM_IM2_IRL0 + 31); -+ lq_pci_data.gpio |= PCI_EXIN1 | PCI_REQ2; -+ lq_register_pci(&lq_pci_data); -+ lq_register_wdt(); ++#define ARV752DPW22_USB 72 ++#define ARV752DPW22_RELAY 73 ++ ++ ltq_register_gpio_ebu(ARV752DPW22_EBU); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv752dpw22_leds_gpio), arv752dpw22_leds_gpio); ++ ltq_register_gpio_buttons(arv752dpw22_gpio_buttons, ARRAY_SIZE(arv752dpw22_gpio_buttons)); ++ ltq_register_nor(&arv75xx_flash_data); ++ ltq_pci_data.irq[15] = (INT_NUM_IM2_IRL0 + 31); ++ ltq_pci_data.gpio |= PCI_EXIN1 | PCI_REQ2; ++ ltq_register_pci(<q_pci_data); + xway_register_dwc(ARV752DPW22_USB); + arv75xx_register_ethernet(); + @@ -576,3 +525,23 @@ + "ARV752DPW22", + "ARV752DPW22 - Arcor A803", + arv752dpw22_init); +--- a/arch/mips/lantiq/machtypes.h ++++ b/arch/mips/lantiq/machtypes.h +@@ -21,6 +21,17 @@ + LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */ + LANTIQ_MACH_EASY98020, /* Falcon Reference Board */ + LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */ ++ ++ /* Arcadyan */ ++ LANTIQ_MACH_ARV3527P, /* Arcor easybox a401 */ ++ LANTIQ_MACH_ARV4510PW, /* Wippies Homebox */ ++ LANTIQ_MACH_ARV4518PW, /* Airties WAV-221, SMC-7908A-ISP */ ++ LANTIQ_MACH_ARV4520PW, /* Airties WAV-281, Arcor EasyboxA800 */ ++ LANTIQ_MACH_ARV452CPW, /* Arcor EasyboxA801 */ ++ LANTIQ_MACH_ARV4525PW, /* Speedport W502V */ ++ LANTIQ_MACH_ARV752DPW, /* Arcor easybox a802 */ ++ LANTIQ_MACH_ARV752DPW22, /* Arcor easybox a803 */ ++ LANTIQ_MACH_ARV7518PW, /* ASTORIA */ + }; + + #endif diff --git a/target/linux/lantiq/patches/220-mtd_uimage_split.patch b/target/linux/lantiq/patches-2.6.32/210-mtd_uimage_split.patch index 8509d58..bca51a8 100644 --- a/target/linux/lantiq/patches/220-mtd_uimage_split.patch +++ b/target/linux/lantiq/patches-2.6.32/210-mtd_uimage_split.patch @@ -1,6 +1,6 @@ --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig -@@ -63,6 +63,10 @@ config MTD_ROOTFS_SPLIT +@@ -63,6 +63,10 @@ depends on MTD_PARTITIONS default y @@ -13,7 +13,7 @@ depends on MTD_PARTITIONS --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c -@@ -722,6 +722,82 @@ static int refresh_rootfs_split(struct m +@@ -724,6 +724,82 @@ } #endif /* CONFIG_MTD_ROOTFS_SPLIT */ @@ -96,7 +96,7 @@ /* * 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 -@@ -746,6 +822,17 @@ int add_mtd_partitions(struct mtd_info * +@@ -748,6 +824,17 @@ if (!slave) return -ENOMEM; diff --git a/target/linux/lantiq/patches-2.6.32/220-atm_hack.patch b/target/linux/lantiq/patches-2.6.32/220-atm_hack.patch new file mode 100644 index 0000000..0270edd --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/220-atm_hack.patch @@ -0,0 +1,42 @@ +--- a/arch/mips/mm/cache.c ++++ b/arch/mips/mm/cache.c +@@ -52,6 +52,8 @@ + void (*_dma_cache_inv)(unsigned long start, unsigned long size); + + EXPORT_SYMBOL(_dma_cache_wback_inv); ++EXPORT_SYMBOL(_dma_cache_wback); ++EXPORT_SYMBOL(_dma_cache_inv); + + #endif /* CONFIG_DMA_NONCOHERENT */ + +--- a/net/atm/proc.c ++++ b/net/atm/proc.c +@@ -152,7 +152,7 @@ + static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc) + { + static const char *const class_name[] = +- {"off","UBR","CBR","VBR","ABR"}; ++ {"off","UBR","CBR","NTR-VBR","ABR","ANY","RT-VBR","UBR+","GFR"}; + 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 +@@ -57,11 +57,17 @@ + } + + ++struct sk_buff* (*ifx_atm_alloc_tx)(struct atm_vcc *, unsigned int) = NULL; ++EXPORT_SYMBOL(ifx_atm_alloc_tx); ++ + static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size) + { + struct sk_buff *skb; + struct sock *sk = sk_atm(vcc); + ++ if (ifx_atm_alloc_tx != NULL) ++ return ifx_atm_alloc_tx(vcc, size); ++ + if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) { + pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n", + sk_wmem_alloc_get(sk), size, diff --git a/target/linux/lantiq/patches-2.6.32/230-cmdline_hack.patch b/target/linux/lantiq/patches-2.6.32/230-cmdline_hack.patch new file mode 100644 index 0000000..df23286 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/230-cmdline_hack.patch @@ -0,0 +1,45 @@ +--- a/arch/mips/lantiq/prom.c ++++ b/arch/mips/lantiq/prom.c +@@ -39,6 +39,34 @@ + { + } + ++#ifdef CONFIG_IMAGE_CMDLINE_HACK ++extern char __image_cmdline[]; ++ ++static void __init ++prom_init_image_cmdline(void) ++{ ++ char *p = __image_cmdline; ++ int replace = 0; ++ ++ if (*p == '-') { ++ replace = 1; ++ p++; ++ } ++ ++ if (*p == '\0') ++ return; ++ ++ if (replace) { ++ strlcpy(arcs_cmdline, p, sizeof(arcs_cmdline)); ++ } else { ++ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); ++ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); ++ } ++} ++#else ++static void __init prom_init_image_cmdline(void) { return; } ++#endif ++ + static void __init prom_init_cmdline(void) + { + int argc = fw_arg0; +@@ -53,6 +81,7 @@ + strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); + } + } ++ prom_init_image_cmdline(); + } + + void __init prom_init(void) diff --git a/target/linux/lantiq/patches/300-udp_redirect.patch b/target/linux/lantiq/patches-2.6.32/240-udp_redirect.patch index a59f6cc..8002842 100644 --- a/target/linux/lantiq/patches/300-udp_redirect.patch +++ b/target/linux/lantiq/patches-2.6.32/240-udp_redirect.patch @@ -261,18 +261,19 @@ obj-$(CONFIG_PROC_FS) += proc.o --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c -@@ -107,6 +107,10 @@ +@@ -106,7 +106,11 @@ #include <net/xfrm.h> #include "udp_impl.h" +#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) +#include <linux/udp_redirect.h> +#endif + struct udp_table udp_table; + - struct udp_table udp_table __read_mostly; EXPORT_SYMBOL(udp_table); -@@ -784,7 +788,7 @@ + int sysctl_udp_mem[3] __read_mostly; +@@ -591,7 +595,7 @@ u8 tos; int err, is_udplite = IS_UDPLITE(sk); int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; @@ -281,7 +282,7 @@ if (len > 0xFFFF) return -EMSGSIZE; -@@ -946,6 +950,12 @@ +@@ -753,6 +757,12 @@ do_append_data: up->len += ulen; @@ -294,7 +295,7 @@ getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, sizeof(struct udphdr), &ipc, &rt, -@@ -1573,6 +1583,7 @@ +@@ -1283,6 +1293,7 @@ struct rtable *rt = skb_rtable(skb); __be32 saddr, daddr; struct net *net = dev_net(skb->dev); @@ -302,7 +303,7 @@ /* * Validate the packet. -@@ -1605,7 +1616,16 @@ +@@ -1315,7 +1326,16 @@ sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable); if (sk != NULL) { @@ -320,8 +321,8 @@ sock_put(sk); /* a return value > 0 means to resubmit the input, but -@@ -1902,7 +1922,7 @@ - .clear_sk = sk_prot_clear_portaddr_nulls, +@@ -1610,7 +1630,7 @@ + #endif }; EXPORT_SYMBOL(udp_prot); - diff --git a/target/linux/lantiq/patches-2.6.32/250-mt-vpe.patch b/target/linux/lantiq/patches-2.6.32/250-mt-vpe.patch new file mode 100644 index 0000000..2b46cb4 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/250-mt-vpe.patch @@ -0,0 +1,1174 @@ +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1646,6 +1646,28 @@ + Includes a loader for loading an elf relocatable object + onto another VPE and running it. + ++config IFX_VPE_EXT ++ bool "IFX APRP Extensions" ++ depends on MIPS_VPE_LOADER ++ default y ++ help ++ IFX included extensions in APRP ++ ++config PERFCTRS ++ bool "34K Performance counters" ++ depends on MIPS_MT && PROC_FS ++ default n ++ help ++ 34K Performance counter through /proc ++ ++config MTSCHED ++ bool "Support mtsched priority configuration for TCs" ++ depends on MIPS_MT && PROC_FS ++ default y ++ help ++ Support for mtsched priority configuration for TCs through ++ /proc/mips/mtsched ++ + config MIPS_MT_SMTC_IM_BACKSTOP + bool "Use per-TC register bits as backstop for inhibited IM bits" + depends on MIPS_MT_SMTC +--- a/arch/mips/include/asm/mipsmtregs.h ++++ b/arch/mips/include/asm/mipsmtregs.h +@@ -28,14 +28,34 @@ + #define read_c0_vpeconf0() __read_32bit_c0_register($1, 2) + #define write_c0_vpeconf0(val) __write_32bit_c0_register($1, 2, val) + ++#define read_c0_vpeconf1() __read_32bit_c0_register($1, 3) ++#define write_c0_vpeconf1(val) __write_32bit_c0_register($1, 3, val) ++ ++#define read_c0_vpeschedule() __read_32bit_c0_register($1, 5) ++#define write_c0_vpeschedule(val) __write_32bit_c0_register($1, 5, val) ++ ++#define read_c0_vpeschefback() __read_32bit_c0_register($1, 6) ++#define write_c0_vpeschefback(val) __write_32bit_c0_register($1, 6, val) ++ ++#define read_c0_vpeopt() __read_32bit_c0_register($1, 7) ++#define write_c0_vpeopt(val) __write_32bit_c0_register($1, 7, val) ++ + #define read_c0_tcstatus() __read_32bit_c0_register($2, 1) + #define write_c0_tcstatus(val) __write_32bit_c0_register($2, 1, val) + + #define read_c0_tcbind() __read_32bit_c0_register($2, 2) ++#define write_c0_tcbind(val) __write_32bit_c0_register($2, 2, val) + + #define read_c0_tccontext() __read_32bit_c0_register($2, 5) + #define write_c0_tccontext(val) __write_32bit_c0_register($2, 5, val) + ++#define read_c0_tcschedule() __read_32bit_c0_register($2, 6) ++#define write_c0_tcschedule(val) __write_32bit_c0_register($2, 6, val) ++ ++#define read_c0_tcschefback() __read_32bit_c0_register($2, 7) ++#define write_c0_tcschefback(val) __write_32bit_c0_register($2, 7, val) ++ ++ + #else /* Assembly */ + /* + * Macros for use in assembly language code +@@ -74,6 +94,8 @@ + #define MVPCONTROL_STLB_SHIFT 2 + #define MVPCONTROL_STLB (_ULCAST_(1) << MVPCONTROL_STLB_SHIFT) + ++#define MVPCONTROL_CPA_SHIFT 3 ++#define MVPCONTROL_CPA (_ULCAST_(1) << MVPCONTROL_CPA_SHIFT) + + /* MVPConf0 fields */ + #define MVPCONF0_PTC_SHIFT 0 +@@ -84,6 +106,8 @@ + #define MVPCONF0_TCA ( _ULCAST_(1) << MVPCONF0_TCA_SHIFT) + #define MVPCONF0_PTLBE_SHIFT 16 + #define MVPCONF0_PTLBE (_ULCAST_(0x3ff) << MVPCONF0_PTLBE_SHIFT) ++#define MVPCONF0_PCP_SHIFT 27 ++#define MVPCONF0_PCP (_ULCAST_(1) << MVPCONF0_PCP_SHIFT) + #define MVPCONF0_TLBS_SHIFT 29 + #define MVPCONF0_TLBS (_ULCAST_(1) << MVPCONF0_TLBS_SHIFT) + #define MVPCONF0_M_SHIFT 31 +@@ -121,9 +145,25 @@ + #define VPECONF0_VPA (_ULCAST_(1) << VPECONF0_VPA_SHIFT) + #define VPECONF0_MVP_SHIFT 1 + #define VPECONF0_MVP (_ULCAST_(1) << VPECONF0_MVP_SHIFT) ++#define VPECONF0_ICS_SHIFT 16 ++#define VPECONF0_ICS (_ULCAST_(1) << VPECONF0_ICS_SHIFT) ++#define VPECONF0_DCS_SHIFT 17 ++#define VPECONF0_DCS (_ULCAST_(1) << VPECONF0_DCS_SHIFT) + #define VPECONF0_XTC_SHIFT 21 + #define VPECONF0_XTC (_ULCAST_(0xff) << VPECONF0_XTC_SHIFT) + ++/* VPEOpt fields */ ++#define VPEOPT_DWX_SHIFT 0 ++#define VPEOPT_IWX_SHIFT 8 ++#define VPEOPT_IWX0 ( _ULCAST_(0x1) << VPEOPT_IWX_SHIFT) ++#define VPEOPT_IWX1 ( _ULCAST_(0x2) << VPEOPT_IWX_SHIFT) ++#define VPEOPT_IWX2 ( _ULCAST_(0x4) << VPEOPT_IWX_SHIFT) ++#define VPEOPT_IWX3 ( _ULCAST_(0x8) << VPEOPT_IWX_SHIFT) ++#define VPEOPT_DWX0 ( _ULCAST_(0x1) << VPEOPT_DWX_SHIFT) ++#define VPEOPT_DWX1 ( _ULCAST_(0x2) << VPEOPT_DWX_SHIFT) ++#define VPEOPT_DWX2 ( _ULCAST_(0x4) << VPEOPT_DWX_SHIFT) ++#define VPEOPT_DWX3 ( _ULCAST_(0x8) << VPEOPT_DWX_SHIFT) ++ + /* TCStatus fields (per TC) */ + #define TCSTATUS_TASID (_ULCAST_(0xff)) + #define TCSTATUS_IXMT_SHIFT 10 +@@ -350,6 +390,14 @@ + #define write_vpe_c0_vpecontrol(val) mttc0(1, 1, val) + #define read_vpe_c0_vpeconf0() mftc0(1, 2) + #define write_vpe_c0_vpeconf0(val) mttc0(1, 2, val) ++#define read_vpe_c0_vpeschedule() mftc0(1, 5) ++#define write_vpe_c0_vpeschedule(val) mttc0(1, 5, val) ++#define read_vpe_c0_vpeschefback() mftc0(1, 6) ++#define write_vpe_c0_vpeschefback(val) mttc0(1, 6, val) ++#define read_vpe_c0_vpeopt() mftc0(1, 7) ++#define write_vpe_c0_vpeopt(val) mttc0(1, 7, val) ++#define read_vpe_c0_wired() mftc0(6, 0) ++#define write_vpe_c0_wired(val) mttc0(6, 0, val) + #define read_vpe_c0_count() mftc0(9, 0) + #define write_vpe_c0_count(val) mttc0(9, 0, val) + #define read_vpe_c0_status() mftc0(12, 0) +@@ -381,6 +429,12 @@ + #define write_tc_c0_tchalt(val) mttc0(2, 4, val) + #define read_tc_c0_tccontext() mftc0(2, 5) + #define write_tc_c0_tccontext(val) mttc0(2, 5, val) ++#define read_tc_c0_tcschedule() mftc0(2, 6) ++#define write_tc_c0_tcschedule(val) mttc0(2, 6, val) ++#define read_tc_c0_tcschefback() mftc0(2, 7) ++#define write_tc_c0_tcschefback(val) mttc0(2, 7, val) ++#define read_tc_c0_entryhi() mftc0(10, 0) ++#define write_tc_c0_entryhi(val) mttc0(10, 0, val) + + /* GPR */ + #define read_tc_gpr_sp() mftgpr(29) +--- a/arch/mips/kernel/Makefile ++++ b/arch/mips/kernel/Makefile +@@ -78,7 +78,8 @@ + + obj-$(CONFIG_KGDB) += kgdb.o + obj-$(CONFIG_PROC_FS) += proc.o +- ++obj-$(CONFIG_MTSCHED) += mtsched_proc.o ++obj-$(CONFIG_PERFCTRS) += perf_proc.o + obj-$(CONFIG_64BIT) += cpu-bugs64.o + + obj-$(CONFIG_I8253) += i8253.o +--- a/arch/mips/kernel/mips-mt.c ++++ b/arch/mips/kernel/mips-mt.c +@@ -21,26 +21,96 @@ + #include <asm/cacheflush.h> + + int vpelimit; +- + static int __init maxvpes(char *str) + { + get_option(&str, &vpelimit); +- + return 1; + } +- + __setup("maxvpes=", maxvpes); + + int tclimit; +- + static int __init maxtcs(char *str) + { + get_option(&str, &tclimit); ++ return 1; ++} ++__setup("maxtcs=", maxtcs); + ++#ifdef CONFIG_IFX_VPE_EXT ++int stlb; ++static int __init istlbshared(char *str) ++{ ++ get_option(&str, &stlb); + return 1; + } ++__setup("vpe_tlb_shared=", istlbshared); + +-__setup("maxtcs=", maxtcs); ++int vpe0_wired; ++static int __init vpe0wired(char *str) ++{ ++ get_option(&str, &vpe0_wired); ++ return 1; ++} ++__setup("vpe0_wired_tlb_entries=", vpe0wired); ++ ++int vpe1_wired; ++static int __init vpe1wired(char *str) ++{ ++ get_option(&str, &vpe1_wired); ++ return 1; ++} ++__setup("vpe1_wired_tlb_entries=", vpe1wired); ++ ++#ifdef CONFIG_MIPS_MT_SMTC ++extern int nostlb; ++#endif ++void configure_tlb(void) ++{ ++ int vpeflags, tcflags, tlbsiz; ++ unsigned int config1val; ++ vpeflags = dvpe(); ++ tcflags = dmt(); ++ write_c0_vpeconf0((read_c0_vpeconf0() | VPECONF0_MVP)); ++ write_c0_mvpcontrol((read_c0_mvpcontrol() | MVPCONTROL_VPC)); ++ mips_ihb(); ++ //printk("stlb = %d, vpe0_wired = %d vpe1_wired=%d\n", stlb,vpe0_wired, vpe1_wired); ++ if (stlb) { ++ if (!(read_c0_mvpconf0() & MVPCONF0_TLBS)) { ++ emt(tcflags); ++ evpe(vpeflags); ++ return; ++ } ++ ++ write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_STLB); ++ write_c0_wired(vpe0_wired + vpe1_wired); ++ if (((read_vpe_c0_config() & MIPS_CONF_MT) >> 7) == 1) { ++ config1val = read_vpe_c0_config1(); ++ tlbsiz = (((config1val >> 25) & 0x3f) + 1); ++ if (tlbsiz > 64) ++ tlbsiz = 64; ++ cpu_data[0].tlbsize = tlbsiz; ++ current_cpu_data.tlbsize = tlbsiz; ++ } ++ ++ } ++ else { ++ write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_STLB); ++ write_c0_wired(vpe0_wired); ++ } ++ ++ ehb(); ++ write_c0_mvpcontrol((read_c0_mvpcontrol() & ~MVPCONTROL_VPC)); ++ ehb(); ++ local_flush_tlb_all(); ++ ++ printk("Wired TLB entries for Linux read_c0_wired() = %d\n", read_c0_wired()); ++#ifdef CONFIG_MIPS_MT_SMTC ++ nostlb = !stlb; ++#endif ++ emt(tcflags); ++ evpe(vpeflags); ++} ++#endif + + /* + * Dump new MIPS MT state for the core. Does not leave TCs halted. +@@ -78,18 +148,18 @@ + if ((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) { + printk(" VPE %d\n", i); + printk(" VPEControl : %08lx\n", +- read_vpe_c0_vpecontrol()); ++ read_vpe_c0_vpecontrol()); + printk(" VPEConf0 : %08lx\n", +- read_vpe_c0_vpeconf0()); ++ read_vpe_c0_vpeconf0()); + printk(" VPE%d.Status : %08lx\n", +- i, read_vpe_c0_status()); ++ i, read_vpe_c0_status()); + printk(" VPE%d.EPC : %08lx %pS\n", +- i, read_vpe_c0_epc(), +- (void *) read_vpe_c0_epc()); ++ i, read_vpe_c0_epc(), ++ (void *) read_vpe_c0_epc()); + printk(" VPE%d.Cause : %08lx\n", +- i, read_vpe_c0_cause()); ++ i, read_vpe_c0_cause()); + printk(" VPE%d.Config7 : %08lx\n", +- i, read_vpe_c0_config7()); ++ i, read_vpe_c0_config7()); + break; /* Next VPE */ + } + } +@@ -287,6 +357,9 @@ + printk("Mapped %ld ITC cells starting at 0x%08x\n", + ((itcblkgrn & 0x7fe00000) >> 20), itc_base); + } ++#ifdef CONFIG_IFX_VPE_EXT ++ configure_tlb(); ++#endif + } + + /* +--- a/arch/mips/kernel/proc.c ++++ b/arch/mips/kernel/proc.c +@@ -7,6 +7,7 @@ + #include <linux/kernel.h> + #include <linux/sched.h> + #include <linux/seq_file.h> ++#include <linux/proc_fs.h> + #include <asm/bootinfo.h> + #include <asm/cpu.h> + #include <asm/cpu-features.h> +@@ -108,3 +109,19 @@ + .stop = c_stop, + .show = show_cpuinfo, + }; ++ ++/* ++ * Support for MIPS/local /proc hooks in /proc/mips/ ++ */ ++ ++static struct proc_dir_entry *mips_proc = NULL; ++ ++struct proc_dir_entry *get_mips_proc_dir(void) ++{ ++ /* ++ * This ought not to be preemptable. ++ */ ++ if(mips_proc == NULL) ++ mips_proc = proc_mkdir("mips", NULL); ++ return(mips_proc); ++} +--- a/arch/mips/kernel/smtc.c ++++ b/arch/mips/kernel/smtc.c +@@ -1328,6 +1328,13 @@ + asid = asid_cache(cpu); + + do { ++#ifdef CONFIG_IFX_VPE_EXT ++ /* If TLB is shared between AP and RP (AP is running SMTC), ++ leave out max ASID i.e., ASID_MASK for RP ++ */ ++ if (!nostlb && ((asid & ASID_MASK) == (ASID_MASK - 1))) ++ asid++; ++#endif + if (!((asid += ASID_INC) & ASID_MASK) ) { + if (cpu_has_vtag_icache) + flush_icache_all(); +--- a/arch/mips/kernel/vpe.c ++++ b/arch/mips/kernel/vpe.c +@@ -77,6 +77,58 @@ + static int kspd_events_reqd; + #endif + ++#ifdef CONFIG_IFX_VPE_EXT ++static int is_sdepgm; ++extern int stlb; ++extern int vpe0_wired; ++extern int vpe1_wired; ++unsigned int vpe1_load_addr; ++ ++static int __init load_address(char *str) ++{ ++ get_option(&str, &vpe1_load_addr); ++ return 1; ++} ++__setup("vpe1_load_addr=", load_address); ++ ++#include <asm/mipsmtregs.h> ++#define write_vpe_c0_wired(val) mttc0(6, 0, val) ++ ++#ifndef COMMAND_LINE_SIZE ++# define COMMAND_LINE_SIZE 512 ++#endif ++ ++char command_line[COMMAND_LINE_SIZE * 2]; ++ ++static unsigned int vpe1_mem; ++static int __init vpe1mem(char *str) ++{ ++ vpe1_mem = memparse(str, &str); ++ return 1; ++} ++__setup("vpe1_mem=", vpe1mem); ++ ++uint32_t vpe1_wdog_ctr; ++static int __init wdog_ctr(char *str) ++{ ++ get_option(&str, &vpe1_wdog_ctr); ++ return 1; ++} ++ ++__setup("vpe1_wdog_ctr_addr=", wdog_ctr); ++EXPORT_SYMBOL(vpe1_wdog_ctr); ++ ++uint32_t vpe1_wdog_timeout; ++static int __init wdog_timeout(char *str) ++{ ++ get_option(&str, &vpe1_wdog_timeout); ++ return 1; ++} ++ ++__setup("vpe1_wdog_timeout=", wdog_timeout); ++EXPORT_SYMBOL(vpe1_wdog_timeout); ++ ++#endif + /* grab the likely amount of memory we will need. */ + #ifdef CONFIG_MIPS_VPE_LOADER_TOM + #define P_SIZE (2 * 1024 * 1024) +@@ -269,6 +321,13 @@ + void *addr; + + #ifdef CONFIG_MIPS_VPE_LOADER_TOM ++#ifdef CONFIG_IFX_VPE_EXT ++ if (vpe1_load_addr) { ++ memset((void *)vpe1_load_addr, 0, len); ++ return (void *)vpe1_load_addr; ++ } ++#endif ++ + /* + * This means you must tell Linux to use less memory than you + * physically have, for example by passing a mem= boot argument. +@@ -747,6 +806,12 @@ + } + + /* Write the address we want it to start running from in the TCPC register. */ ++#if defined(CONFIG_IFX_VPE_EXT) && 0 ++ if (stlb) ++ write_vpe_c0_wired(vpe0_wired + vpe1_wired); ++ else ++ write_vpe_c0_wired(vpe1_wired); ++#endif + write_tc_c0_tcrestart((unsigned long)v->__start); + write_tc_c0_tccontext((unsigned long)0); + +@@ -760,6 +825,20 @@ + + write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); + ++#if defined(CONFIG_IFX_VPE_EXT) && 0 ++ /* ++ * $a2 & $a3 are used to pass command line parameters to VPE1. $a2 ++ * points to the start of the command line string and $a3 points to ++ * the end of the string. This convention is identical to the Linux ++ * kernel boot parameter passing mechanism. Please note that $a3 is ++ * used to pass physical memory size or 0 in SDE tool kit. So, if you ++ * are passing comand line parameters through $a2 & $a3 SDE programs ++ * don't work as desired. ++ */ ++ mttgpr(6, command_line); ++ mttgpr(7, (command_line + strlen(command_line))); ++ if (is_sdepgm) ++#endif + /* + * The sde-kit passes 'memsize' to __start in $a3, so set something + * here... Or set $a3 to zero and define DFLT_STACK_SIZE and +@@ -834,6 +913,9 @@ + if ( (v->__start == 0) || (v->shared_ptr == NULL)) + return -1; + ++#ifdef CONFIG_IFX_VPE_EXT ++ is_sdepgm = 1; ++#endif + return 0; + } + +@@ -995,6 +1077,15 @@ + (unsigned long)v->load_addr + v->len); + + if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { ++#ifdef CONFIG_IFX_VPE_EXT ++ if (vpe1_load_addr) { ++ /* Conversion to KSEG1 is required ??? */ ++ v->__start = KSEG1ADDR(vpe1_load_addr); ++ is_sdepgm = 0; ++ return 0; ++ } ++#endif ++ + if (v->__start == 0) { + printk(KERN_WARNING "VPE loader: program does not contain " + "a __start symbol\n"); +@@ -1065,6 +1156,9 @@ + struct vpe_notifications *not; + struct vpe *v; + int ret; ++#ifdef CONFIG_IFX_VPE_EXT ++ int progsize; ++#endif + + if (minor != iminor(inode)) { + /* assume only 1 device at the moment. */ +@@ -1091,14 +1185,22 @@ + cleanup_tc(get_tc(tclimit)); + } + ++#ifdef CONFIG_IFX_VPE_EXT ++ progsize = (vpe1_mem != 0) ? vpe1_mem : P_SIZE; ++ //printk("progsize = %x\n", progsize); ++ v->pbuffer = vmalloc(progsize); ++ v->plen = progsize; ++#else + /* this of-course trashes what was there before... */ + v->pbuffer = vmalloc(P_SIZE); + v->plen = P_SIZE; ++#endif + v->load_addr = NULL; + v->len = 0; +- ++#if 0 + v->uid = filp->f_cred->fsuid; + v->gid = filp->f_cred->fsgid; ++#endif + + #ifdef CONFIG_MIPS_APSP_KSPD + /* get kspd to tell us when a syscall_exit happens */ +@@ -1351,6 +1453,133 @@ + cleanup_tc(get_tc(sp_id)); + } + #endif ++#ifdef CONFIG_IFX_VPE_EXT ++int32_t vpe1_sw_start(void* sw_start_addr, uint32_t tcmask, uint32_t flags) ++{ ++ enum vpe_state state; ++ struct vpe *v = get_vpe(tclimit); ++ struct vpe_notifications *not; ++ ++ if (tcmask || flags) { ++ printk(KERN_WARNING "Currently tcmask and flags should be 0.\ ++ other values not supported\n"); ++ return -1; ++ } ++ ++ state = xchg(&v->state, VPE_STATE_INUSE); ++ if (state != VPE_STATE_UNUSED) { ++ vpe_stop(v); ++ ++ list_for_each_entry(not, &v->notify, list) { ++ not->stop(tclimit); ++ } ++ } ++ ++ v->__start = (unsigned long)sw_start_addr; ++ is_sdepgm = 0; ++ ++ if (!vpe_run(v)) { ++ printk(KERN_DEBUG "VPE loader: VPE1 running successfully\n"); ++ return 0; ++ } ++ return -1; ++} ++ ++EXPORT_SYMBOL(vpe1_sw_start); ++ ++int32_t vpe1_sw_stop(uint32_t flags) ++{ ++ struct vpe *v = get_vpe(tclimit); ++ ++ if (!vpe_free(v)) { ++ printk(KERN_DEBUG "RP Stopped\n"); ++ return 0; ++ } ++ else ++ return -1; ++} ++ ++EXPORT_SYMBOL(vpe1_sw_stop); ++ ++uint32_t vpe1_get_load_addr (uint32_t flags) ++{ ++ return vpe1_load_addr; ++} ++ ++EXPORT_SYMBOL(vpe1_get_load_addr); ++ ++uint32_t vpe1_get_max_mem (uint32_t flags) ++{ ++ if (!vpe1_mem) ++ return P_SIZE; ++ else ++ return vpe1_mem; ++} ++ ++EXPORT_SYMBOL(vpe1_get_max_mem); ++ ++void* vpe1_get_cmdline_argument(void) ++{ ++ return saved_command_line; ++} ++ ++EXPORT_SYMBOL(vpe1_get_cmdline_argument); ++ ++int32_t vpe1_set_boot_param(char *field, char *value, char flags) ++{ ++ char *ptr, string[64]; ++ int start_off, end_off; ++ if (!field) ++ return -1; ++ strcpy(string, field); ++ if (value) { ++ strcat(string, "="); ++ strcat(string, value); ++ strcat(command_line, " "); ++ strcat(command_line, string); ++ } ++ else { ++ ptr = strstr(command_line, string); ++ if (ptr) { ++ start_off = ptr - command_line; ++ ptr += strlen(string); ++ while ((*ptr != ' ') && (*ptr != '\0')) ++ ptr++; ++ end_off = ptr - command_line; ++ command_line[start_off] = '\0'; ++ strcat (command_line, command_line+end_off); ++ } ++ } ++ return 0; ++} ++ ++EXPORT_SYMBOL(vpe1_set_boot_param); ++ ++int32_t vpe1_get_boot_param(char *field, char **value, char flags) ++{ ++ char *ptr, string[64]; ++ int i = 0; ++ if (!field) ++ return -1; ++ if ((ptr = strstr(command_line, field))) { ++ ptr += strlen(field) + 1; /* including = */ ++ while ((*ptr != ' ') && (*ptr != '\0')) ++ string[i++] = *ptr++; ++ string[i] = '\0'; ++ *value = kmalloc((strlen(string) + 1), GFP_KERNEL); ++ if (*value != NULL) ++ strcpy(*value, string); ++ } ++ else ++ *value = NULL; ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(vpe1_get_boot_param); ++ ++extern void configure_tlb(void); ++#endif + + static ssize_t store_kill(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +@@ -1432,6 +1661,18 @@ + printk("VPE loader: not a MIPS MT capable processor\n"); + return -ENODEV; + } ++#ifdef CONFIG_IFX_VPE_EXT ++#ifndef CONFIG_MIPS_MT_SMTC ++ configure_tlb(); ++#endif ++#endif ++ ++#ifndef CONFIG_MIPS_MT_SMTC ++ if (!vpelimit) ++ vpelimit = 1; ++ if (!tclimit) ++ tclimit = 1; ++#endif + + if (vpelimit == 0) { + printk(KERN_WARNING "No VPEs reserved for AP/SP, not " +@@ -1476,10 +1717,12 @@ + mtflags = dmt(); + vpflags = dvpe(); + ++ back_to_back_c0_hazard(); ++ + /* Put MVPE's into 'configuration state' */ + set_c0_mvpcontrol(MVPCONTROL_VPC); + +- /* dump_mtregs(); */ ++ dump_mtregs(); + + val = read_c0_mvpconf0(); + hw_tcs = (val & MVPCONF0_PTC) + 1; +@@ -1491,6 +1734,7 @@ + * reschedule send IPIs or similar we might hang. + */ + clear_c0_mvpcontrol(MVPCONTROL_VPC); ++ back_to_back_c0_hazard(); + evpe(vpflags); + emt(mtflags); + local_irq_restore(flags); +@@ -1516,6 +1760,7 @@ + } + + v->ntcs = hw_tcs - tclimit; ++ write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1); + + /* add the tc to the list of this vpe's tc's. */ + list_add(&t->tc, &v->tc); +@@ -1584,6 +1829,7 @@ + out_reenable: + /* release config state */ + clear_c0_mvpcontrol(MVPCONTROL_VPC); ++ back_to_back_c0_hazard(); + + evpe(vpflags); + emt(mtflags); +--- /dev/null ++++ b/arch/mips/kernel/mtsched_proc.c +@@ -0,0 +1,279 @@ ++/* ++ * /proc hooks for MIPS MT scheduling policy management for 34K cores ++ * ++ * This program is free software; you can distribute 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 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) 2006 Mips Technologies, Inc ++ */ ++ ++#include <linux/kernel.h> ++ ++#include <asm/cpu.h> ++#include <asm/processor.h> ++#include <asm/system.h> ++#include <asm/mipsregs.h> ++#include <asm/mipsmtregs.h> ++#include <asm/uaccess.h> ++#include <linux/proc_fs.h> ++ ++static struct proc_dir_entry *mtsched_proc; ++ ++#ifndef CONFIG_MIPS_MT_SMTC ++#define NTCS 2 ++#else ++#define NTCS NR_CPUS ++#endif ++#define NVPES 2 ++ ++int lastvpe = 1; ++int lasttc = 8; ++ ++static int proc_read_mtsched(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int totalen = 0; ++ int len; ++ ++ int i; ++ int vpe; ++ int mytc; ++ unsigned long flags; ++ unsigned int mtflags; ++ unsigned int haltstate; ++ unsigned int vpes_checked[NVPES]; ++ unsigned int vpeschedule[NVPES]; ++ unsigned int vpeschefback[NVPES]; ++ unsigned int tcschedule[NTCS]; ++ unsigned int tcschefback[NTCS]; ++ ++ /* Dump the state of the MIPS MT scheduling policy manager */ ++ /* Inititalize control state */ ++ for(i = 0; i < NVPES; i++) { ++ vpes_checked[i] = 0; ++ vpeschedule[i] = 0; ++ vpeschefback[i] = 0; ++ } ++ for(i = 0; i < NTCS; i++) { ++ tcschedule[i] = 0; ++ tcschefback[i] = 0; ++ } ++ ++ /* Disable interrupts and multithreaded issue */ ++ local_irq_save(flags); ++ mtflags = dvpe(); ++ ++ /* Then go through the TCs, halt 'em, and extract the values */ ++ mytc = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT; ++ for(i = 0; i < NTCS; i++) { ++ if(i == mytc) { ++ /* No need to halt ourselves! */ ++ tcschedule[i] = read_c0_tcschedule(); ++ tcschefback[i] = read_c0_tcschefback(); ++ /* If VPE bound to TC hasn't been checked, do it */ ++ vpe = read_c0_tcbind() & TCBIND_CURVPE; ++ if(!vpes_checked[vpe]) { ++ vpeschedule[vpe] = read_c0_vpeschedule(); ++ vpeschefback[vpe] = read_c0_vpeschefback(); ++ vpes_checked[vpe] = 1; ++ } ++ } else { ++ settc(i); ++ haltstate = read_tc_c0_tchalt(); ++ write_tc_c0_tchalt(TCHALT_H); ++ mips_ihb(); ++ tcschedule[i] = read_tc_c0_tcschedule(); ++ tcschefback[i] = read_tc_c0_tcschefback(); ++ /* If VPE bound to TC hasn't been checked, do it */ ++ vpe = read_tc_c0_tcbind() & TCBIND_CURVPE; ++ if(!vpes_checked[vpe]) { ++ vpeschedule[vpe] = read_vpe_c0_vpeschedule(); ++ vpeschefback[vpe] = read_vpe_c0_vpeschefback(); ++ vpes_checked[vpe] = 1; ++ } ++ if(!haltstate) write_tc_c0_tchalt(0); ++ } ++ } ++ /* Re-enable MT and interrupts */ ++ evpe(mtflags); ++ local_irq_restore(flags); ++ ++ for(vpe=0; vpe < NVPES; vpe++) { ++ len = sprintf(page, "VPE[%d].VPEschedule = 0x%08x\n", ++ vpe, vpeschedule[vpe]); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "VPE[%d].VPEschefback = 0x%08x\n", ++ vpe, vpeschefback[vpe]); ++ totalen += len; ++ page += len; ++ } ++ for(i=0; i < NTCS; i++) { ++ len = sprintf(page, "TC[%d].TCschedule = 0x%08x\n", ++ i, tcschedule[i]); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "TC[%d].TCschefback = 0x%08x\n", ++ i, tcschefback[i]); ++ totalen += len; ++ page += len; ++ } ++ return totalen; ++} ++ ++/* ++ * Write to perf counter registers based on text input ++ */ ++ ++#define TXTBUFSZ 100 ++ ++static int proc_write_mtsched(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ int len = 0; ++ char mybuf[TXTBUFSZ]; ++ /* At most, we will set up 9 TCs and 2 VPEs, 11 entries in all */ ++ char entity[1]; //, entity1[1]; ++ int number[1]; ++ unsigned long value[1]; ++ int nparsed = 0 , index = 0; ++ unsigned long flags; ++ unsigned int mtflags; ++ unsigned int haltstate; ++ unsigned int tcbindval; ++ ++ if(count >= TXTBUFSZ) len = TXTBUFSZ-1; ++ else len = count; ++ memset(mybuf,0,TXTBUFSZ); ++ if(copy_from_user(mybuf, buffer, len)) return -EFAULT; ++ ++ nparsed = sscanf(mybuf, "%c%d %lx", ++ &entity[0] ,&number[0], &value[0]); ++ ++ /* ++ * Having acquired the inputs, which might have ++ * generated exceptions and preemptions, ++ * program the registers. ++ */ ++ /* Disable interrupts and multithreaded issue */ ++ local_irq_save(flags); ++ mtflags = dvpe(); ++ ++ if(entity[index] == 't' ) { ++ /* Set TCSchedule or TCScheFBack of specified TC */ ++ if(number[index] > NTCS) goto skip; ++ /* If it's our own TC, do it direct */ ++ if(number[index] == ++ ((read_c0_tcbind() & TCBIND_CURTC) ++ >> TCBIND_CURTC_SHIFT)) { ++ if(entity[index] == 't') ++ write_c0_tcschedule(value[index]); ++ else ++ write_c0_tcschefback(value[index]); ++ } else { ++ /* Otherwise, we do it via MTTR */ ++ settc(number[index]); ++ haltstate = read_tc_c0_tchalt(); ++ write_tc_c0_tchalt(TCHALT_H); ++ mips_ihb(); ++ if(entity[index] == 't') ++ write_tc_c0_tcschedule(value[index]); ++ else ++ write_tc_c0_tcschefback(value[index]); ++ mips_ihb(); ++ if(!haltstate) write_tc_c0_tchalt(0); ++ } ++ } else if(entity[index] == 'v') { ++ /* Set VPESchedule of specified VPE */ ++ if(number[index] > NVPES) goto skip; ++ tcbindval = read_c0_tcbind(); ++ /* Are we doing this to our current VPE? */ ++ if((tcbindval & TCBIND_CURVPE) == number[index]) { ++ /* Then life is simple */ ++ write_c0_vpeschedule(value[index]); ++ } else { ++ /* ++ * Bind ourselves to the other VPE long enough ++ * to program the bind value. ++ */ ++ write_c0_tcbind((tcbindval & ~TCBIND_CURVPE) ++ | number[index]); ++ mips_ihb(); ++ write_c0_vpeschedule(value[index]); ++ mips_ihb(); ++ /* Restore previous binding */ ++ write_c0_tcbind(tcbindval); ++ mips_ihb(); ++ } ++ } ++ ++ else if(entity[index] == 'r') { ++ unsigned int vpes_checked[2], vpe ,i , mytc; ++ vpes_checked[0] = vpes_checked[1] = 0; ++ ++ /* Then go through the TCs, halt 'em, and extract the values */ ++ mytc = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT; ++ ++ for(i = 0; i < NTCS; i++) { ++ if(i == mytc) { ++ /* No need to halt ourselves! */ ++ write_c0_vpeschefback(0); ++ write_c0_tcschefback(0); ++ } else { ++ settc(i); ++ haltstate = read_tc_c0_tchalt(); ++ write_tc_c0_tchalt(TCHALT_H); ++ mips_ihb(); ++ write_tc_c0_tcschefback(0); ++ /* If VPE bound to TC hasn't been checked, do it */ ++ vpe = read_tc_c0_tcbind() & TCBIND_CURVPE; ++ if(!vpes_checked[vpe]) { ++ write_vpe_c0_vpeschefback(0); ++ vpes_checked[vpe] = 1; ++ } ++ if(!haltstate) write_tc_c0_tchalt(0); ++ } ++ } ++ } ++ else { ++ printk ("\n Usage : <t/v><0/1> <Hex Value>\n Example : t0 0x01\n"); ++ } ++ ++skip: ++ /* Re-enable MT and interrupts */ ++ evpe(mtflags); ++ local_irq_restore(flags); ++ return (len); ++} ++ ++static int __init init_mtsched_proc(void) ++{ ++ extern struct proc_dir_entry *get_mips_proc_dir(void); ++ struct proc_dir_entry *mips_proc_dir; ++ ++ if (!cpu_has_mipsmt) { ++ printk("mtsched: not a MIPS MT capable processor\n"); ++ return -ENODEV; ++ } ++ ++ mips_proc_dir = get_mips_proc_dir(); ++ ++ mtsched_proc = create_proc_entry("mtsched", 0644, mips_proc_dir); ++ mtsched_proc->read_proc = proc_read_mtsched; ++ mtsched_proc->write_proc = proc_write_mtsched; ++ ++ return 0; ++} ++ ++/* Automagically create the entry */ ++module_init(init_mtsched_proc); +--- /dev/null ++++ b/arch/mips/kernel/perf_proc.c +@@ -0,0 +1,191 @@ ++/* ++ * /proc hooks for CPU performance counter support for SMTC kernel ++ * (and ultimately others) ++ * Copyright (C) 2006 Mips Technologies, Inc ++ */ ++ ++#include <linux/kernel.h> ++ ++#include <asm/cpu.h> ++#include <asm/processor.h> ++#include <asm/system.h> ++#include <asm/mipsregs.h> ++#include <asm/uaccess.h> ++#include <linux/proc_fs.h> ++ ++/* ++ * /proc diagnostic and statistics hooks ++ */ ++ ++ ++/* Internal software-extended event counters */ ++ ++static unsigned long long extencount[4] = {0,0,0,0}; ++ ++static struct proc_dir_entry *perf_proc; ++ ++static int proc_read_perf(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int totalen = 0; ++ int len; ++ ++ len = sprintf(page, "PerfCnt[0].Ctl : 0x%08x\n", read_c0_perfctrl0()); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[0].Cnt : %Lu\n", ++ extencount[0] + (unsigned long long)((unsigned)read_c0_perfcntr0())); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[1].Ctl : 0x%08x\n", read_c0_perfctrl1()); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[1].Cnt : %Lu\n", ++ extencount[1] + (unsigned long long)((unsigned)read_c0_perfcntr1())); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[2].Ctl : 0x%08x\n", read_c0_perfctrl2()); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[2].Cnt : %Lu\n", ++ extencount[2] + (unsigned long long)((unsigned)read_c0_perfcntr2())); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[3].Ctl : 0x%08x\n", read_c0_perfctrl3()); ++ totalen += len; ++ page += len; ++ len = sprintf(page, "PerfCnt[3].Cnt : %Lu\n", ++ extencount[3] + (unsigned long long)((unsigned)read_c0_perfcntr3())); ++ totalen += len; ++ page += len; ++ ++ return totalen; ++} ++ ++/* ++ * Write to perf counter registers based on text input ++ */ ++ ++#define TXTBUFSZ 100 ++ ++static int proc_write_perf(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ int len; ++ int nparsed; ++ int index; ++ char mybuf[TXTBUFSZ]; ++ ++ int which[4]; ++ unsigned long control[4]; ++ long long ctrdata[4]; ++ ++ if(count >= TXTBUFSZ) len = TXTBUFSZ-1; ++ else len = count; ++ memset(mybuf,0,TXTBUFSZ); ++ if(copy_from_user(mybuf, buffer, len)) return -EFAULT; ++ ++ nparsed = sscanf(mybuf, ++ "%d %lx %Ld %d %lx %Ld %d %lx %Ld %d %lx %Ld", ++ &which[0], &control[0], &ctrdata[0], ++ &which[1], &control[1], &ctrdata[1], ++ &which[2], &control[2], &ctrdata[2], ++ &which[3], &control[3], &ctrdata[3]); ++ ++ for(index = 0; nparsed >= 3; index++) { ++ switch (which[index]) { ++ case 0: ++ write_c0_perfctrl0(control[index]); ++ if(ctrdata[index] != -1) { ++ extencount[0] = (unsigned long long)ctrdata[index]; ++ write_c0_perfcntr0((unsigned long)0); ++ } ++ break; ++ case 1: ++ write_c0_perfctrl1(control[index]); ++ if(ctrdata[index] != -1) { ++ extencount[1] = (unsigned long long)ctrdata[index]; ++ write_c0_perfcntr1((unsigned long)0); ++ } ++ break; ++ case 2: ++ write_c0_perfctrl2(control[index]); ++ if(ctrdata[index] != -1) { ++ extencount[2] = (unsigned long long)ctrdata[index]; ++ write_c0_perfcntr2((unsigned long)0); ++ } ++ break; ++ case 3: ++ write_c0_perfctrl3(control[index]); ++ if(ctrdata[index] != -1) { ++ extencount[3] = (unsigned long long)ctrdata[index]; ++ write_c0_perfcntr3((unsigned long)0); ++ } ++ break; ++ } ++ nparsed -= 3; ++ } ++ return (len); ++} ++ ++extern int (*perf_irq)(void); ++ ++/* ++ * Invoked when timer interrupt vector picks up a perf counter overflow ++ */ ++ ++static int perf_proc_irq(void) ++{ ++ unsigned long snapshot; ++ ++ /* ++ * It would be nice to do this as a loop, but we don't have ++ * indirect access to CP0 registers. ++ */ ++ snapshot = read_c0_perfcntr0(); ++ if ((long)snapshot < 0) { ++ extencount[0] += ++ (unsigned long long)((unsigned)read_c0_perfcntr0()); ++ write_c0_perfcntr0(0); ++ } ++ snapshot = read_c0_perfcntr1(); ++ if ((long)snapshot < 0) { ++ extencount[1] += ++ (unsigned long long)((unsigned)read_c0_perfcntr1()); ++ write_c0_perfcntr1(0); ++ } ++ snapshot = read_c0_perfcntr2(); ++ if ((long)snapshot < 0) { ++ extencount[2] += ++ (unsigned long long)((unsigned)read_c0_perfcntr2()); ++ write_c0_perfcntr2(0); ++ } ++ snapshot = read_c0_perfcntr3(); ++ if ((long)snapshot < 0) { ++ extencount[3] += ++ (unsigned long long)((unsigned)read_c0_perfcntr3()); ++ write_c0_perfcntr3(0); ++ } ++ return 0; ++} ++ ++static int __init init_perf_proc(void) ++{ ++ extern struct proc_dir_entry *get_mips_proc_dir(void); ++ ++ struct proc_dir_entry *mips_proc_dir = get_mips_proc_dir(); ++ ++ write_c0_perfcntr0(0); ++ write_c0_perfcntr1(0); ++ write_c0_perfcntr2(0); ++ write_c0_perfcntr3(0); ++ perf_proc = create_proc_entry("perf", 0644, mips_proc_dir); ++ perf_proc->read_proc = proc_read_perf; ++ perf_proc->write_proc = proc_write_perf; ++ perf_irq = perf_proc_irq; ++ ++ return 0; ++} ++ ++/* Automagically create the entry */ ++module_init(init_perf_proc); diff --git a/target/linux/lantiq/patches/810-ar9-cache-split.patch b/target/linux/lantiq/patches-2.6.32/260-ar9-cache-split.patch index d04f1e9..88d2a61 100644 --- a/target/linux/lantiq/patches/810-ar9-cache-split.patch +++ b/target/linux/lantiq/patches-2.6.32/260-ar9-cache-split.patch @@ -1,6 +1,6 @@ --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -1844,6 +1844,28 @@ +@@ -1653,6 +1653,28 @@ help IFX included extensions in APRP @@ -31,7 +31,7 @@ depends on MIPS_MT && PROC_FS --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c -@@ -128,6 +128,13 @@ +@@ -129,6 +129,13 @@ EXPORT_SYMBOL(vpe1_wdog_timeout); #endif @@ -45,7 +45,7 @@ /* 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 @@ +@@ -867,6 +874,65 @@ /* enable this VPE */ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); @@ -113,7 +113,7 @@ write_vpe_c0_cause(0); --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c -@@ -1347,6 +1347,106 @@ +@@ -1348,6 +1348,106 @@ __setup("coherentio", setcoherentio); #endif @@ -220,7 +220,7 @@ void __cpuinit r4k_cache_init(void) { extern void build_clear_page(void); -@@ -1366,6 +1466,78 @@ +@@ -1367,6 +1467,78 @@ break; } diff --git a/target/linux/lantiq/patches-2.6.32/270-m25p80-fast-read.patch b/target/linux/lantiq/patches-2.6.32/270-m25p80-fast-read.patch new file mode 100644 index 0000000..061ae1c --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/270-m25p80-fast-read.patch @@ -0,0 +1,8 @@ +--- a/drivers/mtd/devices/m25p80.c ++++ b/drivers/mtd/devices/m25p80.c +@@ -1,3 +1,5 @@ ++ ++ + /* + * MTD SPI driver for ST M25Pxx (and similar) serial flash chips + * diff --git a/target/linux/lantiq/patches/940-spi1.patch b/target/linux/lantiq/patches-2.6.32/400-spi1.patch index 343db3d..61bfa2e 100644 --- a/target/linux/lantiq/patches/940-spi1.patch +++ b/target/linux/lantiq/patches-2.6.32/400-spi1.patch @@ -10,35 +10,27 @@ Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> --- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h -@@ -48,4 +48,13 @@ - - extern int (*lqpci_plat_dev_init)(struct pci_dev *dev); +@@ -50,4 +50,13 @@ + int mii_mode; + }; + -+struct lq_spi_platform_data { ++struct ltq_spi_platform_data { + u16 num_chipselect; +}; + -+struct lq_spi_controller_data { ++struct ltq_spi_controller_data { + unsigned gpio; +}; + #endif ---- a/arch/mips/include/asm/mach-lantiq/xway/xway.h -+++ b/arch/mips/include/asm/mach-lantiq/xway/xway.h -@@ -72,6 +72,7 @@ - #define LQ_PMU_BASE_ADDR (KSEG1 + 0x1F102000) - - #define PMU_DMA 0x0020 -+#define PMU_SPI 0x0100 - #define PMU_USB 0x8041 - #define PMU_LED 0x0800 - #define PMU_GPT 0x1000 -@@ -105,6 +106,7 @@ - - /*------------ SSC */ - #define LQ_SSC_BASE_ADDR (KSEG1 + 0x1e100800) -+#define LQ_SSC_SIZE 0x100 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -75,6 +75,7 @@ - /*------------ MEI */ - #define LQ_MEI_BASE_ADDR (KSEG1 + 0x1E116000) + #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/target/linux/lantiq/patches-2.6.32/410-spi2.patch b/target/linux/lantiq/patches-2.6.32/410-spi2.patch new file mode 100644 index 0000000..d291e09 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/410-spi2.patch @@ -0,0 +1,1103 @@ +From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +Date: Thu, 3 Mar 2011 17:15:30 +0000 (+0100) +Subject: SPI: lantiq: Add driver for Lantiq SoC SPI controller +X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=653c95b8b9066c9c6ac08bd64d0ceee439e9fd90;hp=3d21b04682ae8eb1c1965aba39d1796e8c5ad84b + +SPI: lantiq: Add driver for Lantiq SoC SPI controller + +Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +--- + +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -133,6 +133,14 @@ + This enables using the Freescale i.MX SPI controllers in master + mode. + ++config SPI_LANTIQ ++ tristate "Lantiq SoC SPI controller" ++ depends on SOC_LANTIQ_XWAY ++ select SPI_BITBANG ++ help ++ This driver supports the Lantiq SoC SPI controller in master ++ mode. ++ + config SPI_LM70_LLP + tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)" + depends on PARPORT && EXPERIMENTAL +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -20,6 +20,7 @@ + obj-$(CONFIG_SPI_GPIO) += spi_gpio.o + obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o + obj-$(CONFIG_SPI_IMX) += spi_imx.o ++obj-$(CONFIG_SPI_LANTIQ) += spi_lantiq.o + obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o + obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o + obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o +--- /dev/null ++++ b/drivers/spi/spi_lantiq.c +@@ -0,0 +1,1063 @@ ++/* ++ * Lantiq SoC SPI controller ++ * ++ * Copyright (C) 2011 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/workqueue.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/completion.h> ++#include <linux/spinlock.h> ++#include <linux/err.h> ++#include <linux/clk.h> ++#include <linux/gpio.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/spi_bitbang.h> ++ ++#include <xway.h> ++#include <xway_irq.h> ++#include <lantiq_platform.h> ++ ++#define LTQ_SPI_CLC 0x00 /* Clock control */ ++#define LTQ_SPI_PISEL 0x04 /* Port input select */ ++#define LTQ_SPI_ID 0x08 /* Identification */ ++#define LTQ_SPI_CON 0x10 /* Control */ ++#define LTQ_SPI_STAT 0x14 /* Status */ ++#define LTQ_SPI_WHBSTATE 0x18 /* Write HW modified state */ ++#define LTQ_SPI_TB 0x20 /* Transmit buffer */ ++#define LTQ_SPI_RB 0x24 /* Receive buffer */ ++#define LTQ_SPI_RXFCON 0x30 /* Receive FIFO control */ ++#define LTQ_SPI_TXFCON 0x34 /* Transmit FIFO control */ ++#define LTQ_SPI_FSTAT 0x38 /* FIFO status */ ++#define LTQ_SPI_BRT 0x40 /* Baudrate timer */ ++#define LTQ_SPI_BRSTAT 0x44 /* Baudrate timer status */ ++#define LTQ_SPI_SFCON 0x60 /* Serial frame control */ ++#define LTQ_SPI_SFSTAT 0x64 /* Serial frame status */ ++#define LTQ_SPI_GPOCON 0x70 /* General purpose output control */ ++#define LTQ_SPI_GPOSTAT 0x74 /* General purpose output status */ ++#define LTQ_SPI_FGPO 0x78 /* Forced general purpose output */ ++#define LTQ_SPI_RXREQ 0x80 /* Receive request */ ++#define LTQ_SPI_RXCNT 0x84 /* Receive count */ ++#define LTQ_SPI_DMACON 0xEC /* DMA control */ ++#define LTQ_SPI_IRNEN 0xF4 /* Interrupt node enable */ ++#define LTQ_SPI_IRNICR 0xF8 /* Interrupt node interrupt capture */ ++#define LTQ_SPI_IRNCR 0xFC /* Interrupt node control */ ++ ++#define LTQ_SPI_CLC_SMC_SHIFT 16 /* Clock divider for sleep mode */ ++#define LTQ_SPI_CLC_SMC_MASK 0xFF ++#define LTQ_SPI_CLC_RMC_SHIFT 8 /* Clock divider for normal run mode */ ++#define LTQ_SPI_CLC_RMC_MASK 0xFF ++#define LTQ_SPI_CLC_DISS BIT(1) /* Disable status bit */ ++#define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */ ++ ++#define LTQ_SPI_ID_TXFS_SHIFT 24 /* Implemented TX FIFO size */ ++#define LTQ_SPI_ID_TXFS_MASK 0x3F ++#define LTQ_SPI_ID_RXFS_SHIFT 16 /* Implemented RX FIFO size */ ++#define LTQ_SPI_ID_RXFS_MASK 0x3F ++#define LTQ_SPI_ID_REV_MASK 0x1F /* Hardware revision number */ ++#define LTQ_SPI_ID_CFG BIT(5) /* DMA interface support */ ++ ++#define LTQ_SPI_CON_BM_SHIFT 16 /* Data width selection */ ++#define LTQ_SPI_CON_BM_MASK 0x1F ++#define LTQ_SPI_CON_EM BIT(24) /* Echo mode */ ++#define LTQ_SPI_CON_IDLE BIT(23) /* Idle bit value */ ++#define LTQ_SPI_CON_ENBV BIT(22) /* Enable byte valid control */ ++#define LTQ_SPI_CON_RUEN BIT(12) /* Receive underflow error enable */ ++#define LTQ_SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */ ++#define LTQ_SPI_CON_AEN BIT(10) /* Abort error enable */ ++#define LTQ_SPI_CON_REN BIT(9) /* Receive overflow error enable */ ++#define LTQ_SPI_CON_TEN BIT(8) /* Transmit overflow error enable */ ++#define LTQ_SPI_CON_LB BIT(7) /* Loopback control */ ++#define LTQ_SPI_CON_PO BIT(6) /* Clock polarity control */ ++#define LTQ_SPI_CON_PH BIT(5) /* Clock phase control */ ++#define LTQ_SPI_CON_HB BIT(4) /* Heading control */ ++#define LTQ_SPI_CON_RXOFF BIT(1) /* Switch receiver off */ ++#define LTQ_SPI_CON_TXOFF BIT(0) /* Switch transmitter off */ ++ ++#define LTQ_SPI_STAT_RXBV_MASK 0x7 ++#define LTQ_SPI_STAT_RXBV_SHIFT 28 ++#define LTQ_SPI_STAT_BSY BIT(13) /* Busy flag */ ++#define LTQ_SPI_STAT_RUE BIT(12) /* Receive underflow error flag */ ++#define LTQ_SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */ ++#define LTQ_SPI_STAT_AE BIT(10) /* Abort error flag */ ++#define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */ ++#define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */ ++#define LTQ_SPI_STAT_MS BIT(1) /* Master/slave select bit */ ++#define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */ ++ ++#define LTQ_SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */ ++#define LTQ_SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */ ++#define LTQ_SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */ ++#define LTQ_SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */ ++#define LTQ_SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */ ++#define LTQ_SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */ ++#define LTQ_SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */ ++#define LTQ_SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */ ++#define LTQ_SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */ ++#define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */ ++#define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */ ++#define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */ ++#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */ ++#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */ ++#define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */ ++#define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */ ++#define LTQ_SPI_WHBSTATE_CLR_ERRORS 0x0F50 ++ ++#define LTQ_SPI_RXFCON_RXFITL_SHIFT 8 /* FIFO interrupt trigger level */ ++#define LTQ_SPI_RXFCON_RXFITL_MASK 0x3F ++#define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */ ++#define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */ ++ ++#define LTQ_SPI_TXFCON_TXFITL_SHIFT 8 /* FIFO interrupt trigger level */ ++#define LTQ_SPI_TXFCON_TXFITL_MASK 0x3F ++#define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */ ++#define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */ ++ ++#define LTQ_SPI_FSTAT_RXFFL_MASK 0x3f ++#define LTQ_SPI_FSTAT_RXFFL_SHIFT 0 ++#define LTQ_SPI_FSTAT_TXFFL_MASK 0x3f ++#define LTQ_SPI_FSTAT_TXFFL_SHIFT 8 ++ ++#define LTQ_SPI_GPOCON_ISCSBN_SHIFT 8 ++#define LTQ_SPI_GPOCON_INVOUTN_SHIFT 0 ++ ++#define LTQ_SPI_FGPO_SETOUTN_SHIFT 8 ++#define LTQ_SPI_FGPO_CLROUTN_SHIFT 0 ++ ++#define LTQ_SPI_RXREQ_RXCNT_MASK 0xFFFF /* Receive count value */ ++#define LTQ_SPI_RXCNT_TODO_MASK 0xFFFF /* Recevie to-do value */ ++ ++#define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */ ++#define LTQ_SPI_IRNEN_E BIT(2) /* Error end interrupt request */ ++#define LTQ_SPI_IRNEN_T BIT(1) /* Transmit end interrupt request */ ++#define LTQ_SPI_IRNEN_R BIT(0) /* Receive end interrupt request */ ++#define LTQ_SPI_IRNEN_ALL 0xF ++ ++/* Hard-wired GPIOs used by SPI controller */ ++#define LTQ_SPI_GPIO_DI 16 ++#define LTQ_SPI_GPIO_DO 17 ++#define LTQ_SPI_GPIO_CLK 18 ++ ++struct ltq_spi { ++ struct spi_bitbang bitbang; ++ struct completion done; ++ spinlock_t lock; ++ ++ struct device *dev; ++ void __iomem *base; ++ struct clk *clk; ++ ++ int status; ++ int irq[3]; ++ ++ const u8 *tx; ++ u8 *rx; ++ u32 tx_cnt; ++ u32 rx_cnt; ++ u32 len; ++ struct spi_transfer *curr_transfer; ++ ++ u32 (*get_tx) (struct ltq_spi *); ++ ++ u16 txfs; ++ u16 rxfs; ++ unsigned dma_support:1; ++ unsigned cfg_mode:1; ++ ++}; ++ ++struct ltq_spi_controller_state { ++ void (*cs_activate) (struct spi_device *); ++ void (*cs_deactivate) (struct spi_device *); ++}; ++ ++struct ltq_spi_irq_map { ++ char *name; ++ irq_handler_t handler; ++}; ++ ++struct ltq_spi_cs_gpio_map { ++ unsigned gpio; ++ unsigned altsel0; ++ unsigned altsel1; ++}; ++ ++static inline struct ltq_spi *ltq_spi_to_hw(struct spi_device *spi) ++{ ++ return spi_master_get_devdata(spi->master); ++} ++ ++static inline u32 ltq_spi_reg_read(struct ltq_spi *hw, u32 reg) ++{ ++ return ioread32be(hw->base + reg); ++} ++ ++static inline void ltq_spi_reg_write(struct ltq_spi *hw, u32 val, u32 reg) ++{ ++ iowrite32be(val, hw->base + reg); ++} ++ ++static inline void ltq_spi_reg_setbit(struct ltq_spi *hw, u32 bits, u32 reg) ++{ ++ u32 val; ++ ++ val = ltq_spi_reg_read(hw, reg); ++ val |= bits; ++ ltq_spi_reg_write(hw, val, reg); ++} ++ ++static inline void ltq_spi_reg_clearbit(struct ltq_spi *hw, u32 bits, u32 reg) ++{ ++ u32 val; ++ ++ val = ltq_spi_reg_read(hw, reg); ++ val &= ~bits; ++ ltq_spi_reg_write(hw, val, reg); ++} ++ ++static void ltq_spi_hw_enable(struct ltq_spi *hw) ++{ ++ u32 clc; ++ ++ /* Power-up mdule */ ++ ltq_pmu_enable(PMU_SPI); ++ ++ /* ++ * Set clock divider for run mode to 1 to ++ * run at same frequency as FPI bus ++ */ ++ clc = (1 << LTQ_SPI_CLC_RMC_SHIFT); ++ ltq_spi_reg_write(hw, clc, LTQ_SPI_CLC); ++} ++ ++static void ltq_spi_hw_disable(struct ltq_spi *hw) ++{ ++ /* Set clock divider to 0 and set module disable bit */ ++ ltq_spi_reg_write(hw, LTQ_SPI_CLC_DISS, LTQ_SPI_CLC); ++ ++ /* Power-down mdule */ ++ ltq_pmu_disable(PMU_SPI); ++} ++ ++static void ltq_spi_reset_fifos(struct ltq_spi *hw) ++{ ++ u32 val; ++ ++ /* ++ * Enable and flush FIFOs. Set interrupt trigger level to ++ * half of FIFO count implemented in hardware. ++ */ ++ if (hw->txfs > 1) { ++ val = hw->txfs << (LTQ_SPI_TXFCON_TXFITL_SHIFT - 1); ++ val |= LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU; ++ ltq_spi_reg_write(hw, val, LTQ_SPI_TXFCON); ++ } ++ ++ if (hw->rxfs > 1) { ++ val = hw->rxfs << (LTQ_SPI_RXFCON_RXFITL_SHIFT - 1); ++ val |= LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU; ++ ltq_spi_reg_write(hw, val, LTQ_SPI_RXFCON); ++ } ++} ++ ++static inline int ltq_spi_wait_ready(struct ltq_spi *hw) ++{ ++ u32 stat; ++ unsigned long timeout; ++ ++ timeout = jiffies + msecs_to_jiffies(200); ++ ++ do { ++ stat = ltq_spi_reg_read(hw, LTQ_SPI_STAT); ++ if (!(stat & LTQ_SPI_STAT_BSY)) ++ return 0; ++ ++ cond_resched(); ++ } while (!time_after_eq(jiffies, timeout)); ++ ++ dev_err(hw->dev, "SPI wait ready timed out\n"); ++ ++ return -ETIMEDOUT; ++} ++ ++static void ltq_spi_config_mode_set(struct ltq_spi *hw) ++{ ++ if (hw->cfg_mode) ++ return; ++ ++ /* ++ * Putting the SPI module in config mode is only safe if no ++ * transfer is in progress as indicated by busy flag STATE.BSY. ++ */ ++ if (ltq_spi_wait_ready(hw)) { ++ ltq_spi_reset_fifos(hw); ++ hw->status = -ETIMEDOUT; ++ } ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLREN, LTQ_SPI_WHBSTATE); ++ ++ hw->cfg_mode = 1; ++} ++ ++static void ltq_spi_run_mode_set(struct ltq_spi *hw) ++{ ++ if (!hw->cfg_mode) ++ return; ++ ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETEN, LTQ_SPI_WHBSTATE); ++ ++ hw->cfg_mode = 0; ++} ++ ++static u32 ltq_spi_tx_word_u8(struct ltq_spi *hw) ++{ ++ const u8 *tx = hw->tx; ++ u32 data = *tx++; ++ ++ hw->tx_cnt++; ++ hw->tx++; ++ ++ return data; ++} ++ ++static u32 ltq_spi_tx_word_u16(struct ltq_spi *hw) ++{ ++ const u16 *tx = (u16 *) hw->tx; ++ u32 data = *tx++; ++ ++ hw->tx_cnt += 2; ++ hw->tx += 2; ++ ++ return data; ++} ++ ++static u32 ltq_spi_tx_word_u32(struct ltq_spi *hw) ++{ ++ const u32 *tx = (u32 *) hw->tx; ++ u32 data = *tx++; ++ ++ hw->tx_cnt += 4; ++ hw->tx += 4; ++ ++ return data; ++} ++ ++static void ltq_spi_bits_per_word_set(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 bm; ++ u8 bits_per_word = spi->bits_per_word; ++ ++ /* ++ * Use either default value of SPI device or value ++ * from current transfer. ++ */ ++ if (hw->curr_transfer && hw->curr_transfer->bits_per_word) ++ bits_per_word = hw->curr_transfer->bits_per_word; ++ ++ if (bits_per_word <= 8) ++ hw->get_tx = ltq_spi_tx_word_u8; ++ else if (bits_per_word <= 16) ++ hw->get_tx = ltq_spi_tx_word_u16; ++ else if (bits_per_word <= 32) ++ hw->get_tx = ltq_spi_tx_word_u32; ++ ++ /* CON.BM value = bits_per_word - 1 */ ++ bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_SHIFT; ++ ++ ltq_spi_reg_clearbit(hw, LTQ_SPI_CON_BM_MASK << ++ LTQ_SPI_CON_BM_SHIFT, LTQ_SPI_CON); ++ ltq_spi_reg_setbit(hw, bm, LTQ_SPI_CON); ++} ++ ++static void ltq_spi_speed_set(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 br, max_speed_hz, spi_clk; ++ u32 speed_hz = spi->max_speed_hz; ++ ++ /* ++ * Use either default value of SPI device or value ++ * from current transfer. ++ */ ++ if (hw->curr_transfer && hw->curr_transfer->speed_hz) ++ speed_hz = hw->curr_transfer->speed_hz; ++ ++ /* ++ * 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); ++ ++ /* ++ * Maximum SPI clock frequency in master mode is half of ++ * SPI module clock frequency. Maximum reload value of ++ * baudrate generator BR is 2^16. ++ */ ++ max_speed_hz = spi_clk / 2; ++ if (speed_hz >= max_speed_hz) ++ br = 0; ++ else ++ br = (max_speed_hz / speed_hz) - 1; ++ ++ if (br > 0xFFFF) ++ br = 0xFFFF; ++ ++ ltq_spi_reg_write(hw, br, LTQ_SPI_BRT); ++} ++ ++static void ltq_spi_clockmode_set(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 con; ++ ++ con = ltq_spi_reg_read(hw, LTQ_SPI_CON); ++ ++ /* ++ * SPI mode mapping in CON register: ++ * Mode CPOL CPHA CON.PO CON.PH ++ * 0 0 0 0 1 ++ * 1 0 1 0 0 ++ * 2 1 0 1 1 ++ * 3 1 1 1 0 ++ */ ++ if (spi->mode & SPI_CPHA) ++ con &= ~LTQ_SPI_CON_PH; ++ else ++ con |= LTQ_SPI_CON_PH; ++ ++ if (spi->mode & SPI_CPOL) ++ con |= LTQ_SPI_CON_PO; ++ else ++ con &= ~LTQ_SPI_CON_PO; ++ ++ /* Set heading control */ ++ if (spi->mode & SPI_LSB_FIRST) ++ con &= ~LTQ_SPI_CON_HB; ++ else ++ con |= LTQ_SPI_CON_HB; ++ ++ ltq_spi_reg_write(hw, con, LTQ_SPI_CON); ++} ++ ++static void ltq_spi_xmit_set(struct ltq_spi *hw, struct spi_transfer *t) ++{ ++ u32 con; ++ ++ con = ltq_spi_reg_read(hw, LTQ_SPI_CON); ++ ++ if (t) { ++ if (t->tx_buf && t->rx_buf) { ++ con &= ~(LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF); ++ } else if (t->rx_buf) { ++ con &= ~LTQ_SPI_CON_RXOFF; ++ con |= LTQ_SPI_CON_TXOFF; ++ } else if (t->tx_buf) { ++ con &= ~LTQ_SPI_CON_TXOFF; ++ con |= LTQ_SPI_CON_RXOFF; ++ } ++ } else ++ con |= (LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF); ++ ++ ltq_spi_reg_write(hw, con, LTQ_SPI_CON); ++} ++ ++static void ltq_spi_gpio_cs_activate(struct spi_device *spi) ++{ ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ int val = spi->mode & SPI_CS_HIGH ? 1 : 0; ++ ++ gpio_set_value(cdata->gpio, val); ++} ++ ++static void ltq_spi_gpio_cs_deactivate(struct spi_device *spi) ++{ ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ int val = spi->mode & SPI_CS_HIGH ? 0 : 1; ++ ++ gpio_set_value(cdata->gpio, val); ++} ++ ++static void ltq_spi_internal_cs_activate(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 fgpo; ++ ++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_CLROUTN_SHIFT)); ++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); ++} ++ ++static void ltq_spi_internal_cs_deactivate(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 fgpo; ++ ++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT)); ++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); ++} ++ ++static void ltq_spi_chipselect(struct spi_device *spi, int cs) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ struct ltq_spi_controller_state *cstate = spi->controller_state; ++ ++ switch (cs) { ++ case BITBANG_CS_ACTIVE: ++ ltq_spi_bits_per_word_set(spi); ++ ltq_spi_speed_set(spi); ++ ltq_spi_clockmode_set(spi); ++ ltq_spi_run_mode_set(hw); ++ ++ cstate->cs_activate(spi); ++ break; ++ ++ case BITBANG_CS_INACTIVE: ++ cstate->cs_deactivate(spi); ++ ++ ltq_spi_config_mode_set(hw); ++ ++ break; ++ } ++} ++ ++static int ltq_spi_setup_transfer(struct spi_device *spi, ++ struct spi_transfer *t) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u8 bits_per_word = spi->bits_per_word; ++ ++ hw->curr_transfer = t; ++ ++ if (t && t->bits_per_word) ++ bits_per_word = t->bits_per_word; ++ ++ if (bits_per_word > 32) ++ return -EINVAL; ++ ++ ltq_spi_config_mode_set(hw); ++ ++ return 0; ++} ++ ++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 }, ++}; ++ ++static int ltq_spi_setup(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ struct ltq_spi_controller_state *cstate; ++ u32 gpocon, fgpo; ++ int ret; ++ ++ /* Set default word length to 8 if not set */ ++ if (!spi->bits_per_word) ++ spi->bits_per_word = 8; ++ ++ if (spi->bits_per_word > 32) ++ return -EINVAL; ++ ++ if (!spi->controller_state) { ++ cstate = kzalloc(sizeof(struct ltq_spi_controller_state), ++ GFP_KERNEL); ++ if (!cstate) ++ return -ENOMEM; ++ ++ spi->controller_state = cstate; ++ } else ++ return 0; ++ ++ /* ++ * Up to six GPIOs can be connected to the SPI module ++ * via GPIO alternate function to control the chip select lines. ++ * For more flexibility in board layout this driver can also control ++ * the CS lines via GPIO API. If GPIOs should be used, board setup code ++ * have to register the SPI device with struct ltq_spi_controller_data ++ * attached. ++ */ ++ if (cdata && cdata->gpio) { ++ ret = gpio_request(cdata->gpio, "spi-cs"); ++ if (ret) ++ return -EBUSY; ++ ++ ret = spi->mode & SPI_CS_HIGH ? 0 : 1; ++ gpio_direction_output(cdata->gpio, ret); ++ ++ 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, ++ 1, "spi-cs"); ++ if (ret) ++ return -EBUSY; ++ ++ gpocon = (1 << (spi->chip_select + ++ LTQ_SPI_GPOCON_ISCSBN_SHIFT)); ++ ++ if (spi->mode & SPI_CS_HIGH) ++ gpocon |= (1 << spi->chip_select); ++ ++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT)); ++ ++ ltq_spi_reg_setbit(hw, gpocon, LTQ_SPI_GPOCON); ++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); ++ ++ cstate->cs_activate = ltq_spi_internal_cs_activate; ++ cstate->cs_deactivate = ltq_spi_internal_cs_deactivate; ++ } ++ ++ return 0; ++} ++ ++static void ltq_spi_cleanup(struct spi_device *spi) ++{ ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ struct ltq_spi_controller_state *cstate = spi->controller_state; ++ unsigned gpio; ++ ++ if (cdata && cdata->gpio) ++ gpio = cdata->gpio; ++ else ++ gpio = ltq_spi_cs[spi->chip_select].gpio; ++ ++ gpio_free(gpio); ++ kfree(cstate); ++} ++ ++static void ltq_spi_txfifo_write(struct ltq_spi *hw) ++{ ++ u32 fstat, data; ++ u16 fifo_space; ++ ++ /* Determine how much FIFOs are free for TX data */ ++ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT); ++ fifo_space = hw->txfs - ((fstat >> LTQ_SPI_FSTAT_TXFFL_SHIFT) & ++ LTQ_SPI_FSTAT_TXFFL_MASK); ++ ++ if (!fifo_space) ++ return; ++ ++ while (hw->tx_cnt < hw->len && fifo_space) { ++ data = hw->get_tx(hw); ++ ltq_spi_reg_write(hw, data, LTQ_SPI_TB); ++ fifo_space--; ++ } ++} ++ ++static void ltq_spi_rxfifo_read(struct ltq_spi *hw) ++{ ++ u32 fstat, data, *rx32; ++ u16 fifo_fill; ++ u8 rxbv, shift, *rx8; ++ ++ /* Determine how much FIFOs are filled with RX data */ ++ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT); ++ fifo_fill = ((fstat >> LTQ_SPI_FSTAT_RXFFL_SHIFT) ++ & LTQ_SPI_FSTAT_RXFFL_MASK); ++ ++ if (!fifo_fill) ++ return; ++ ++ /* ++ * The 32 bit FIFO is always used completely independent from the ++ * bits_per_word value. Thus four bytes have to be read at once ++ * per FIFO. ++ */ ++ rx32 = (u32 *) hw->rx; ++ while (hw->len - hw->rx_cnt >= 4 && fifo_fill) { ++ *rx32++ = ltq_spi_reg_read(hw, LTQ_SPI_RB); ++ hw->rx_cnt += 4; ++ hw->rx += 4; ++ fifo_fill--; ++ } ++ ++ /* ++ * If there are remaining bytes, read byte count from STAT.RXBV ++ * register and read the data byte-wise. ++ */ ++ while (fifo_fill && hw->rx_cnt < hw->len) { ++ rxbv = (ltq_spi_reg_read(hw, LTQ_SPI_STAT) >> ++ LTQ_SPI_STAT_RXBV_SHIFT) & LTQ_SPI_STAT_RXBV_MASK; ++ data = ltq_spi_reg_read(hw, LTQ_SPI_RB); ++ ++ shift = (rxbv - 1) * 8; ++ rx8 = hw->rx; ++ ++ while (rxbv) { ++ *rx8++ = (data >> shift) & 0xFF; ++ rxbv--; ++ shift -= 8; ++ hw->rx_cnt++; ++ hw->rx++; ++ } ++ ++ fifo_fill--; ++ } ++} ++ ++static void ltq_spi_rxreq_set(struct ltq_spi *hw) ++{ ++ u32 rxreq, rxreq_max, rxtodo; ++ ++ rxtodo = ltq_spi_reg_read(hw, LTQ_SPI_RXCNT) & LTQ_SPI_RXCNT_TODO_MASK; ++ ++ /* ++ * In RX-only mode the serial clock is activated only after writing ++ * the expected amount of RX bytes into RXREQ register. ++ * To avoid receive overflows at high clocks it is better to request ++ * only the amount of bytes that fits into all FIFOs. This value ++ * depends on the FIFO size implemented in hardware. ++ */ ++ rxreq = hw->len - hw->rx_cnt; ++ rxreq_max = hw->rxfs << 2; ++ rxreq = min(rxreq_max, rxreq); ++ ++ if (!rxtodo && rxreq) ++ ltq_spi_reg_write(hw, rxreq, LTQ_SPI_RXREQ); ++} ++ ++static inline void ltq_spi_complete(struct ltq_spi *hw) ++{ ++ complete(&hw->done); ++} ++ ++irqreturn_t ltq_spi_tx_irq(int irq, void *data) ++{ ++ struct ltq_spi *hw = data; ++ unsigned long flags; ++ int completed = 0; ++ ++ spin_lock_irqsave(&hw->lock, flags); ++ ++ if (hw->tx_cnt < hw->len) ++ ltq_spi_txfifo_write(hw); ++ ++ if (hw->tx_cnt == hw->len) ++ completed = 1; ++ ++ spin_unlock_irqrestore(&hw->lock, flags); ++ ++ if (completed) ++ ltq_spi_complete(hw); ++ ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t ltq_spi_rx_irq(int irq, void *data) ++{ ++ struct ltq_spi *hw = data; ++ unsigned long flags; ++ int completed = 0; ++ ++ spin_lock_irqsave(&hw->lock, flags); ++ ++ if (hw->rx_cnt < hw->len) { ++ ltq_spi_rxfifo_read(hw); ++ ++ if (hw->tx && hw->tx_cnt < hw->len) ++ ltq_spi_txfifo_write(hw); ++ } ++ ++ if (hw->rx_cnt == hw->len) ++ completed = 1; ++ else if (!hw->tx) ++ ltq_spi_rxreq_set(hw); ++ ++ spin_unlock_irqrestore(&hw->lock, flags); ++ ++ if (completed) ++ ltq_spi_complete(hw); ++ ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t ltq_spi_err_irq(int irq, void *data) ++{ ++ struct ltq_spi *hw = data; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&hw->lock, flags); ++ ++ /* Disable all interrupts */ ++ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN); ++ ++ /* Clear all error flags */ ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE); ++ ++ /* Flush FIFOs */ ++ ltq_spi_reg_setbit(hw, LTQ_SPI_RXFCON_RXFLU, LTQ_SPI_RXFCON); ++ ltq_spi_reg_setbit(hw, LTQ_SPI_TXFCON_TXFLU, LTQ_SPI_TXFCON); ++ ++ hw->status = -EIO; ++ spin_unlock_irqrestore(&hw->lock, flags); ++ ++ ltq_spi_complete(hw); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ltq_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 irq_flags = 0; ++ ++ hw->tx = t->tx_buf; ++ hw->rx = t->rx_buf; ++ hw->len = t->len; ++ hw->tx_cnt = 0; ++ hw->rx_cnt = 0; ++ hw->status = 0; ++ INIT_COMPLETION(hw->done); ++ ++ ltq_spi_xmit_set(hw, t); ++ ++ /* Enable error interrupts */ ++ ltq_spi_reg_setbit(hw, LTQ_SPI_IRNEN_E, LTQ_SPI_IRNEN); ++ ++ if (hw->tx) { ++ /* Initially fill TX FIFO with as much data as possible */ ++ ltq_spi_txfifo_write(hw); ++ irq_flags |= LTQ_SPI_IRNEN_T; ++ ++ /* Always enable RX interrupt in Full Duplex mode */ ++ if (hw->rx) ++ irq_flags |= LTQ_SPI_IRNEN_R; ++ } else if (hw->rx) { ++ /* Start RX clock */ ++ ltq_spi_rxreq_set(hw); ++ ++ /* Enable RX interrupt to receive data from RX FIFOs */ ++ irq_flags |= LTQ_SPI_IRNEN_R; ++ } ++ ++ /* Enable TX or RX interrupts */ ++ ltq_spi_reg_setbit(hw, irq_flags, LTQ_SPI_IRNEN); ++ wait_for_completion_interruptible(&hw->done); ++ ++ /* Disable all interrupts */ ++ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN); ++ ++ /* ++ * Return length of current transfer for bitbang utility code if ++ * no errors occured during transmission. ++ */ ++ if (!hw->status) ++ hw->status = hw->len; ++ ++ return hw->status; ++} ++ ++static const struct ltq_spi_irq_map ltq_spi_irqs[] = { ++ { "spi_tx", ltq_spi_tx_irq }, ++ { "spi_rx", ltq_spi_rx_irq }, ++ { "spi_err", ltq_spi_err_irq }, ++}; ++ ++static int __init ltq_spi_probe(struct platform_device *pdev) ++{ ++ struct spi_master *master; ++ struct resource *r; ++ struct ltq_spi *hw; ++ struct ltq_spi_platform_data *pdata = pdev->dev.platform_data; ++ int ret, i; ++ u32 data, id; ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(struct ltq_spi)); ++ if (!master) { ++ dev_err(&pdev->dev, "spi_alloc_master\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ hw = spi_master_get_devdata(master); ++ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (r == NULL) { ++ dev_err(&pdev->dev, "platform_get_resource\n"); ++ ret = -ENOENT; ++ goto err_master; ++ } ++ ++ r = devm_request_mem_region(&pdev->dev, r->start, resource_size(r), ++ pdev->name); ++ if (!r) { ++ dev_err(&pdev->dev, "devm_request_mem_region\n"); ++ ret = -ENXIO; ++ goto err_master; ++ } ++ ++ hw->base = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r)); ++ if (!hw->base) { ++ dev_err(&pdev->dev, "devm_ioremap_nocache\n"); ++ ret = -ENXIO; ++ goto err_master; ++ } ++ ++ hw->clk = clk_get(&pdev->dev, "fpi"); ++ if (IS_ERR(hw->clk)) { ++ dev_err(&pdev->dev, "clk_get\n"); ++ ret = PTR_ERR(hw->clk); ++ goto err_master; ++ } ++ ++ memset(hw->irq, 0, sizeof(hw->irq)); ++ for (i = 0; i < ARRAY_SIZE(ltq_spi_irqs); i++) { ++ ret = platform_get_irq_byname(pdev, ltq_spi_irqs[i].name); ++ if (0 > ret) { ++ dev_err(&pdev->dev, "platform_get_irq_byname\n"); ++ goto err_irq; ++ } ++ ++ hw->irq[i] = ret; ++ ret = request_irq(hw->irq[i], ltq_spi_irqs[i].handler, ++ 0, ltq_spi_irqs[i].name, hw); ++ if (ret) { ++ dev_err(&pdev->dev, "request_irq\n"); ++ goto err_irq; ++ } ++ } ++ ++ hw->bitbang.master = spi_master_get(master); ++ hw->bitbang.chipselect = ltq_spi_chipselect; ++ hw->bitbang.setup_transfer = ltq_spi_setup_transfer; ++ hw->bitbang.txrx_bufs = ltq_spi_txrx_bufs; ++ ++ master->bus_num = pdev->id; ++ master->num_chipselect = pdata->num_chipselect; ++ master->setup = ltq_spi_setup; ++ master->cleanup = ltq_spi_cleanup; ++ ++ hw->dev = &pdev->dev; ++ init_completion(&hw->done); ++ 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_spi_hw_enable(hw); ++ ++ /* Read module capabilities */ ++ id = ltq_spi_reg_read(hw, LTQ_SPI_ID); ++ hw->txfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK; ++ hw->rxfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK; ++ hw->dma_support = (id & LTQ_SPI_ID_CFG) ? 1 : 0; ++ ++ ltq_spi_config_mode_set(hw); ++ ++ /* Enable error checking, disable TX/RX, set idle value high */ ++ data = LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN | ++ LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN | ++ LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF | LTQ_SPI_CON_IDLE; ++ ltq_spi_reg_write(hw, data, LTQ_SPI_CON); ++ ++ /* Enable master mode and clear error flags */ ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETMS | ++ LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE); ++ ++ /* Reset GPIO/CS registers */ ++ ltq_spi_reg_write(hw, 0x0, LTQ_SPI_GPOCON); ++ ltq_spi_reg_write(hw, 0xFF00, LTQ_SPI_FGPO); ++ ++ /* Enable and flush FIFOs */ ++ ltq_spi_reset_fifos(hw); ++ ++ ret = spi_bitbang_start(&hw->bitbang); ++ if (ret) { ++ dev_err(&pdev->dev, "spi_bitbang_start\n"); ++ goto err_bitbang; ++ } ++ ++ platform_set_drvdata(pdev, hw); ++ ++ pr_info("Lantiq SoC SPI controller rev %u (TXFS %u, RXFS %u, DMA %u)\n", ++ id & LTQ_SPI_ID_REV_MASK, hw->txfs, hw->rxfs, hw->dma_support); ++ ++ return 0; ++ ++err_bitbang: ++ ltq_spi_hw_disable(hw); ++ ++err_irq: ++ clk_put(hw->clk); ++ ++ for (; i > 0; i--) ++ free_irq(hw->irq[i], hw); ++ ++err_master: ++ spi_master_put(master); ++ ++err: ++ return ret; ++} ++ ++static int __exit ltq_spi_remove(struct platform_device *pdev) ++{ ++ struct ltq_spi *hw = platform_get_drvdata(pdev); ++ int ret, i; ++ ++ ret = spi_bitbang_stop(&hw->bitbang); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ ltq_spi_config_mode_set(hw); ++ ltq_spi_hw_disable(hw); ++ ++ for (i = 0; i < ARRAY_SIZE(hw->irq); i++) ++ if (0 < hw->irq[i]) ++ free_irq(hw->irq[i], hw); ++ ++ gpio_free(LTQ_SPI_GPIO_DI); ++ gpio_free(LTQ_SPI_GPIO_DO); ++ gpio_free(LTQ_SPI_GPIO_CLK); ++ ++ clk_put(hw->clk); ++ spi_master_put(hw->bitbang.master); ++ ++ return 0; ++} ++ ++static struct platform_driver ltq_spi_driver = { ++ .driver = { ++ .name = "ltq-spi", ++ .owner = THIS_MODULE, ++ }, ++ .remove = __exit_p(ltq_spi_remove), ++}; ++ ++static int __init ltq_spi_init(void) ++{ ++ return platform_driver_probe(<q_spi_driver, ltq_spi_probe); ++} ++module_init(ltq_spi_init); ++ ++static void __exit ltq_spi_exit(void) ++{ ++ platform_driver_unregister(<q_spi_driver); ++} ++module_exit(ltq_spi_exit); ++ ++MODULE_DESCRIPTION("Lantiq SoC SPI controller driver"); ++MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ltq-spi"); diff --git a/target/linux/lantiq/patches-2.6.32/420-spi3.patch b/target/linux/lantiq/patches-2.6.32/420-spi3.patch new file mode 100644 index 0000000..31cf3c1 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/420-spi3.patch @@ -0,0 +1,49 @@ +From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +Date: Thu, 3 Mar 2011 20:42:26 +0000 (+0100) +Subject: MIPS: lantiq: Add device register helper for SPI controller and devices +X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=b35b07062b718ece9b9cb7b23b12d83a087eafb0;hp=653c95b8b9066c9c6ac08bd64d0ceee439e9fd90 + +MIPS: lantiq: Add device register helper for SPI controller and devices + +Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +--- + +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -21,6 +21,7 @@ + #include <linux/io.h> + #include <linux/gpio.h> + #include <linux/leds.h> ++#include <linux/spi/spi.h> + + #include <asm/bootinfo.h> + #include <asm/irq.h> +@@ -119,3 +120,28 @@ + platform_device_register(<q_etop); + } + } ++ ++static struct resource ltq_spi_resources[] = { ++ { ++ .start = LTQ_SSC_BASE_ADDR, ++ .end = LTQ_SSC_BASE_ADDR + LTQ_SSC_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ IRQ_RES(spi_tx, LTQ_SSC_TIR), ++ IRQ_RES(spi_rx, LTQ_SSC_RIR), ++ IRQ_RES(spi_err, LTQ_SSC_EIR), ++}; ++ ++static struct platform_device ltq_spi = { ++ .name = "ltq-spi", ++ .resource = ltq_spi_resources, ++ .num_resources = ARRAY_SIZE(ltq_spi_resources), ++}; ++ ++void __init ltq_register_spi(struct ltq_spi_platform_data *pdata, ++ struct spi_board_info const *info, unsigned n) ++{ ++ spi_register_board_info(info, n); ++ ltq_spi.dev.platform_data = pdata; ++ platform_device_register(<q_spi); ++} diff --git a/target/linux/lantiq/patches-2.6.32/500-register_ebu.patch b/target/linux/lantiq/patches-2.6.32/500-register_ebu.patch new file mode 100644 index 0000000..613cb69 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/500-register_ebu.patch @@ -0,0 +1,41 @@ +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -121,6 +121,29 @@ + } + } + ++/* ebu */ ++static struct resource ltq_ebu_resource = ++{ ++ .name = "gpio_ebu", ++ .start = LTQ_EBU_GPIO_START, ++ .end = LTQ_EBU_GPIO_START + LTQ_EBU_GPIO_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static struct platform_device ltq_ebu = ++{ ++ .name = "ltq_ebu", ++ .resource = <q_ebu_resource, ++ .num_resources = 1, ++}; ++ ++void __init ++ltq_register_gpio_ebu(unsigned int value) ++{ ++ ltq_ebu.dev.platform_data = (void*) value; ++ platform_device_register(<q_ebu); ++} ++ + static struct resource ltq_spi_resources[] = { + { + .start = LTQ_SSC_BASE_ADDR, +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -16,5 +16,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 ltq_register_gpio_ebu(unsigned int value); + + #endif diff --git a/target/linux/lantiq/patches-2.6.32/510-register_madwifi.patch b/target/linux/lantiq/patches-2.6.32/510-register_madwifi.patch new file mode 100644 index 0000000..678f0f5 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/510-register_madwifi.patch @@ -0,0 +1,28 @@ +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -144,6 +144,16 @@ + platform_device_register(<q_ebu); + } + ++/* madwifi */ ++int lantiq_emulate_madwifi_eep = 0; ++EXPORT_SYMBOL(lantiq_emulate_madwifi_eep); ++ ++void __init ++ltq_register_madwifi_eep(void) ++{ ++ lantiq_emulate_madwifi_eep = 1; ++} ++ + static struct resource ltq_spi_resources[] = { + { + .start = LTQ_SSC_BASE_ADDR, +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -17,5 +17,6 @@ + extern void ltq_register_ase_asc(void); + extern void ltq_register_etop(struct ltq_eth_data *eth); + extern void ltq_register_gpio_ebu(unsigned int value); ++extern void ltq_register_madwifi_eep(void); + + #endif diff --git a/target/linux/lantiq/patches-2.6.32/520-register_buttons.patch b/target/linux/lantiq/patches-2.6.32/520-register_buttons.patch new file mode 100644 index 0000000..0d8d58e --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/520-register_buttons.patch @@ -0,0 +1,46 @@ +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -154,6 +154,26 @@ + lantiq_emulate_madwifi_eep = 1; + } + ++/* gpio buttons */ ++static struct gpio_buttons_platform_data ltq_gpio_buttons_platform_data; ++ ++static struct platform_device ltq_gpio_buttons_platform_device = ++{ ++ .name = "gpio-buttons", ++ .id = 0, ++ .dev = { ++ .platform_data = (void *) <q_gpio_buttons_platform_data, ++ }, ++}; ++ ++void __init ++ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt) ++{ ++ ltq_gpio_buttons_platform_data.buttons = buttons; ++ ltq_gpio_buttons_platform_data.nbuttons = cnt; ++ platform_device_register(<q_gpio_buttons_platform_device); ++} ++ + static struct resource ltq_spi_resources[] = { + { + .start = LTQ_SSC_BASE_ADDR, +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -11,6 +11,7 @@ + + #include "../devices.h" + #include <linux/phy.h> ++#include <linux/gpio_buttons.h> + + extern void ltq_register_gpio(void); + extern void ltq_register_gpio_stp(void); +@@ -18,5 +19,6 @@ + extern void ltq_register_etop(struct ltq_eth_data *eth); + extern void ltq_register_gpio_ebu(unsigned int value); + extern void ltq_register_madwifi_eep(void); ++extern void ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt); + + #endif diff --git a/target/linux/lantiq/patches-2.6.32/530-register_tapi.patch b/target/linux/lantiq/patches-2.6.32/530-register_tapi.patch new file mode 100644 index 0000000..a581064 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/530-register_tapi.patch @@ -0,0 +1,42 @@ +--- a/arch/mips/lantiq/devices.c ++++ b/arch/mips/lantiq/devices.c +@@ -120,3 +120,20 @@ + pr_err("kernel is compiled without PCI support\n"); + } + #endif ++ ++static unsigned int *cp1_base = 0; ++unsigned int* ++ltq_get_cp1_base(void) ++{ ++ return cp1_base; ++} ++EXPORT_SYMBOL(ltq_get_cp1_base); ++ ++void __init ++ltq_register_tapi(void) ++{ ++#define CP1_SIZE (1 << 20) ++ dma_addr_t dma; ++ cp1_base = ++ (void*)CPHYSADDR(dma_alloc_coherent(NULL, CP1_SIZE, &dma, GFP_ATOMIC)); ++} +--- a/arch/mips/lantiq/devices.h ++++ b/arch/mips/lantiq/devices.h +@@ -19,5 +19,6 @@ + extern void ltq_register_wdt(void); + extern void ltq_register_asc(int port); + extern void ltq_register_pci(struct ltq_pci_data *data); ++extern void ltq_register_tapi(void); + + #endif +--- a/arch/mips/lantiq/xway/mach-easy50712.c ++++ b/arch/mips/lantiq/xway/mach-easy50712.c +@@ -66,6 +66,7 @@ + ltq_register_nor(&easy50712_flash_data); + ltq_register_pci(<q_pci_data); + ltq_register_etop(<q_eth_data); ++ ltq_register_tapi(); + } + + MIPS_MACHINE(LTQ_MACH_EASY50712, diff --git a/target/linux/lantiq/patches-2.6.32/540-gptu.patch b/target/linux/lantiq/patches-2.6.32/540-gptu.patch new file mode 100644 index 0000000..b7448e8 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/540-gptu.patch @@ -0,0 +1,999 @@ +--- /dev/null ++++ b/arch/mips/lantiq/xway/timer.c +@@ -0,0 +1,830 @@ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/init.h> ++#include <linux/uaccess.h> ++#include <linux/unistd.h> ++#include <linux/errno.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/irq.h> ++#include <asm/div64.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_irq.h> ++#include <lantiq_timer.h> ++ ++#define MAX_NUM_OF_32BIT_TIMER_BLOCKS 6 ++ ++#ifdef TIMER1A ++#define FIRST_TIMER TIMER1A ++#else ++#define FIRST_TIMER 2 ++#endif ++ ++/* ++ * GPTC divider is set or not. ++ */ ++#define GPTU_CLC_RMC_IS_SET 0 ++ ++/* ++ * Timer Interrupt (IRQ) ++ */ ++/* Must be adjusted when ICU driver is available */ ++#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22) ++ ++/* ++ * Bits Operation ++ */ ++#define GET_BITS(x, msb, lsb) \ ++ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) ++#define SET_BITS(x, msb, lsb, value) \ ++ (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | \ ++ (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb))) ++ ++/* ++ * GPTU Register Mapping ++ */ ++#define LQ_GPTU (KSEG1 + 0x1E100A00) ++#define LQ_GPTU_CLC ((volatile u32 *)(LQ_GPTU + 0x0000)) ++#define LQ_GPTU_ID ((volatile u32 *)(LQ_GPTU + 0x0008)) ++#define LQ_GPTU_CON(n, X) ((volatile u32 *)(LQ_GPTU + 0x0010 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_RUN(n, X) ((volatile u32 *)(LQ_GPTU + 0x0018 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_RELOAD(n, X) ((volatile u32 *)(LQ_GPTU + 0x0020 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_COUNT(n, X) ((volatile u32 *)(LQ_GPTU + 0x0028 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_IRNEN ((volatile u32 *)(LQ_GPTU + 0x00F4)) ++#define LQ_GPTU_IRNICR ((volatile u32 *)(LQ_GPTU + 0x00F8)) ++#define LQ_GPTU_IRNCR ((volatile u32 *)(LQ_GPTU + 0x00FC)) ++ ++/* ++ * Clock Control Register ++ */ ++#define GPTU_CLC_SMC GET_BITS(*LQ_GPTU_CLC, 23, 16) ++#define GPTU_CLC_RMC GET_BITS(*LQ_GPTU_CLC, 15, 8) ++#define GPTU_CLC_FSOE (*LQ_GPTU_CLC & (1 << 5)) ++#define GPTU_CLC_EDIS (*LQ_GPTU_CLC & (1 << 3)) ++#define GPTU_CLC_SPEN (*LQ_GPTU_CLC & (1 << 2)) ++#define GPTU_CLC_DISS (*LQ_GPTU_CLC & (1 << 1)) ++#define GPTU_CLC_DISR (*LQ_GPTU_CLC & (1 << 0)) ++ ++#define GPTU_CLC_SMC_SET(value) SET_BITS(0, 23, 16, (value)) ++#define GPTU_CLC_RMC_SET(value) SET_BITS(0, 15, 8, (value)) ++#define GPTU_CLC_FSOE_SET(value) ((value) ? (1 << 5) : 0) ++#define GPTU_CLC_SBWE_SET(value) ((value) ? (1 << 4) : 0) ++#define GPTU_CLC_EDIS_SET(value) ((value) ? (1 << 3) : 0) ++#define GPTU_CLC_SPEN_SET(value) ((value) ? (1 << 2) : 0) ++#define GPTU_CLC_DISR_SET(value) ((value) ? (1 << 0) : 0) ++ ++/* ++ * ID Register ++ */ ++#define GPTU_ID_ID GET_BITS(*LQ_GPTU_ID, 15, 8) ++#define GPTU_ID_CFG GET_BITS(*LQ_GPTU_ID, 7, 5) ++#define GPTU_ID_REV GET_BITS(*LQ_GPTU_ID, 4, 0) ++ ++/* ++ * Control Register of Timer/Counter nX ++ * n is the index of block (1 based index) ++ * X is either A or B ++ */ ++#define GPTU_CON_SRC_EG(n, X) (*LQ_GPTU_CON(n, X) & (1 << 10)) ++#define GPTU_CON_SRC_EXT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 9)) ++#define GPTU_CON_SYNC(n, X) (*LQ_GPTU_CON(n, X) & (1 << 8)) ++#define GPTU_CON_EDGE(n, X) GET_BITS(*LQ_GPTU_CON(n, X), 7, 6) ++#define GPTU_CON_INV(n, X) (*LQ_GPTU_CON(n, X) & (1 << 5)) ++#define GPTU_CON_EXT(n, X) (*LQ_GPTU_CON(n, A) & (1 << 4)) /* Timer/Counter B does not have this bit */ ++#define GPTU_CON_STP(n, X) (*LQ_GPTU_CON(n, X) & (1 << 3)) ++#define GPTU_CON_CNT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 2)) ++#define GPTU_CON_DIR(n, X) (*LQ_GPTU_CON(n, X) & (1 << 1)) ++#define GPTU_CON_EN(n, X) (*LQ_GPTU_CON(n, X) & (1 << 0)) ++ ++#define GPTU_CON_SRC_EG_SET(value) ((value) ? 0 : (1 << 10)) ++#define GPTU_CON_SRC_EXT_SET(value) ((value) ? (1 << 9) : 0) ++#define GPTU_CON_SYNC_SET(value) ((value) ? (1 << 8) : 0) ++#define GPTU_CON_EDGE_SET(value) SET_BITS(0, 7, 6, (value)) ++#define GPTU_CON_INV_SET(value) ((value) ? (1 << 5) : 0) ++#define GPTU_CON_EXT_SET(value) ((value) ? (1 << 4) : 0) ++#define GPTU_CON_STP_SET(value) ((value) ? (1 << 3) : 0) ++#define GPTU_CON_CNT_SET(value) ((value) ? (1 << 2) : 0) ++#define GPTU_CON_DIR_SET(value) ((value) ? (1 << 1) : 0) ++ ++#define GPTU_RUN_RL_SET(value) ((value) ? (1 << 2) : 0) ++#define GPTU_RUN_CEN_SET(value) ((value) ? (1 << 1) : 0) ++#define GPTU_RUN_SEN_SET(value) ((value) ? (1 << 0) : 0) ++ ++#define GPTU_IRNEN_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0) ++#define GPTU_IRNCR_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0) ++ ++#define TIMER_FLAG_MASK_SIZE(x) (x & 0x0001) ++#define TIMER_FLAG_MASK_TYPE(x) (x & 0x0002) ++#define TIMER_FLAG_MASK_STOP(x) (x & 0x0004) ++#define TIMER_FLAG_MASK_DIR(x) (x & 0x0008) ++#define TIMER_FLAG_NONE_EDGE 0x0000 ++#define TIMER_FLAG_MASK_EDGE(x) (x & 0x0030) ++#define TIMER_FLAG_REAL 0x0000 ++#define TIMER_FLAG_INVERT 0x0040 ++#define TIMER_FLAG_MASK_INVERT(x) (x & 0x0040) ++#define TIMER_FLAG_MASK_TRIGGER(x) (x & 0x0070) ++#define TIMER_FLAG_MASK_SYNC(x) (x & 0x0080) ++#define TIMER_FLAG_CALLBACK_IN_HB 0x0200 ++#define TIMER_FLAG_MASK_HANDLE(x) (x & 0x0300) ++#define TIMER_FLAG_MASK_SRC(x) (x & 0x1000) ++ ++struct timer_dev_timer { ++ unsigned int f_irq_on; ++ unsigned int irq; ++ unsigned int flag; ++ unsigned long arg1; ++ unsigned long arg2; ++}; ++ ++struct timer_dev { ++ struct mutex gptu_mutex; ++ unsigned int number_of_timers; ++ unsigned int occupation; ++ unsigned int f_gptu_on; ++ struct timer_dev_timer timer[MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2]; ++}; ++ ++unsigned int ltq_get_fpi_bus_clock(int fpi); ++ ++static long gptu_ioctl(struct file *, unsigned int, unsigned long); ++static int gptu_open(struct inode *, struct file *); ++static int gptu_release(struct inode *, struct file *); ++ ++static struct file_operations gptu_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = gptu_ioctl, ++ .open = gptu_open, ++ .release = gptu_release ++}; ++ ++static struct miscdevice gptu_miscdev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "gptu", ++ .fops = &gptu_fops, ++}; ++ ++static struct timer_dev timer_dev; ++ ++static irqreturn_t timer_irq_handler(int irq, void *p) ++{ ++ unsigned int timer; ++ unsigned int flag; ++ struct timer_dev_timer *dev_timer = (struct timer_dev_timer *)p; ++ ++ timer = irq - TIMER_INTERRUPT; ++ if (timer < timer_dev.number_of_timers ++ && dev_timer == &timer_dev.timer[timer]) { ++ /* Clear interrupt. */ ++ ltq_w32(1 << timer, LQ_GPTU_IRNCR); ++ ++ /* Call user hanler or signal. */ ++ flag = dev_timer->flag; ++ if (!(timer & 0x01) ++ || TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) { ++ /* 16-bit timer or timer A of 32-bit timer */ ++ switch (TIMER_FLAG_MASK_HANDLE(flag)) { ++ case TIMER_FLAG_CALLBACK_IN_IRQ: ++ case TIMER_FLAG_CALLBACK_IN_HB: ++ if (dev_timer->arg1) ++ (*(timer_callback)dev_timer->arg1)(dev_timer->arg2); ++ break; ++ case TIMER_FLAG_SIGNAL: ++ send_sig((int)dev_timer->arg2, (struct task_struct *)dev_timer->arg1, 0); ++ break; ++ } ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++static inline void lq_enable_gptu(void) ++{ ++ ltq_pmu_enable(PMU_GPT); ++ ++ /* Set divider as 1, disable write protection for SPEN, enable module. */ ++ *LQ_GPTU_CLC = ++ GPTU_CLC_SMC_SET(0x00) | ++ GPTU_CLC_RMC_SET(0x01) | ++ GPTU_CLC_FSOE_SET(0) | ++ GPTU_CLC_SBWE_SET(1) | ++ GPTU_CLC_EDIS_SET(0) | ++ GPTU_CLC_SPEN_SET(0) | ++ GPTU_CLC_DISR_SET(0); ++} ++ ++static inline void lq_disable_gptu(void) ++{ ++ ltq_w32(0x00, LQ_GPTU_IRNEN); ++ ltq_w32(0xfff, LQ_GPTU_IRNCR); ++ ++ /* Set divider as 0, enable write protection for SPEN, disable module. */ ++ *LQ_GPTU_CLC = ++ GPTU_CLC_SMC_SET(0x00) | ++ GPTU_CLC_RMC_SET(0x00) | ++ GPTU_CLC_FSOE_SET(0) | ++ GPTU_CLC_SBWE_SET(0) | ++ GPTU_CLC_EDIS_SET(0) | ++ GPTU_CLC_SPEN_SET(0) | ++ GPTU_CLC_DISR_SET(1); ++ ++ ltq_pmu_disable(PMU_GPT); ++} ++ ++int lq_request_timer(unsigned int timer, unsigned int flag, ++ unsigned long value, unsigned long arg1, unsigned long arg2) ++{ ++ int ret = 0; ++ unsigned int con_reg, irnen_reg; ++ int n, X; ++ ++ if (timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ printk(KERN_INFO "request_timer(%d, 0x%08X, %lu)...", ++ timer, flag, value); ++ ++ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) ++ value &= 0xFFFF; ++ else ++ timer &= ~0x01; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ /* ++ * Allocate timer. ++ */ ++ if (timer < FIRST_TIMER) { ++ unsigned int mask; ++ unsigned int shift; ++ /* This takes care of TIMER1B which is the only choice for Voice TAPI system */ ++ unsigned int offset = TIMER2A; ++ ++ /* ++ * Pick up a free timer. ++ */ ++ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) { ++ mask = 1 << offset; ++ shift = 1; ++ } else { ++ mask = 3 << offset; ++ shift = 2; ++ } ++ for (timer = offset; ++ timer < offset + timer_dev.number_of_timers; ++ timer += shift, mask <<= shift) ++ if (!(timer_dev.occupation & mask)) { ++ timer_dev.occupation |= mask; ++ break; ++ } ++ if (timer >= offset + timer_dev.number_of_timers) { ++ printk("failed![%d]\n", __LINE__); ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } else ++ ret = timer; ++ } else { ++ register unsigned int mask; ++ ++ /* ++ * Check if the requested timer is free. ++ */ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if ((timer_dev.occupation & mask)) { ++ printk("failed![%d] mask %#x, timer_dev.occupation %#x\n", ++ __LINE__, mask, timer_dev.occupation); ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EBUSY; ++ } else { ++ timer_dev.occupation |= mask; ++ ret = 0; ++ } ++ } ++ ++ /* ++ * Prepare control register value. ++ */ ++ switch (TIMER_FLAG_MASK_EDGE(flag)) { ++ default: ++ case TIMER_FLAG_NONE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x00); ++ break; ++ case TIMER_FLAG_RISE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x01); ++ break; ++ case TIMER_FLAG_FALL_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x02); ++ break; ++ case TIMER_FLAG_ANY_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x03); ++ break; ++ } ++ if (TIMER_FLAG_MASK_TYPE(flag) == TIMER_FLAG_TIMER) ++ con_reg |= ++ TIMER_FLAG_MASK_SRC(flag) == ++ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : ++ GPTU_CON_SRC_EXT_SET(0); ++ else ++ con_reg |= ++ TIMER_FLAG_MASK_SRC(flag) == ++ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : ++ GPTU_CON_SRC_EG_SET(0); ++ con_reg |= ++ TIMER_FLAG_MASK_SYNC(flag) == ++ TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : ++ GPTU_CON_SYNC_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_INVERT(flag) == ++ TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_SIZE(flag) == ++ TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : ++ GPTU_CON_EXT_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_STOP(flag) == ++ TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0); ++ con_reg |= ++ TIMER_FLAG_MASK_TYPE(flag) == ++ TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : ++ GPTU_CON_CNT_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_DIR(flag) == ++ TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0); ++ ++ /* ++ * Fill up running data. ++ */ ++ timer_dev.timer[timer - FIRST_TIMER].flag = flag; ++ timer_dev.timer[timer - FIRST_TIMER].arg1 = arg1; ++ timer_dev.timer[timer - FIRST_TIMER].arg2 = arg2; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flag; ++ ++ /* ++ * Enable GPTU module. ++ */ ++ if (!timer_dev.f_gptu_on) { ++ lq_enable_gptu(); ++ timer_dev.f_gptu_on = 1; ++ } ++ ++ /* ++ * Enable IRQ. ++ */ ++ if (TIMER_FLAG_MASK_HANDLE(flag) != TIMER_FLAG_NO_HANDLE) { ++ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL) ++ timer_dev.timer[timer - FIRST_TIMER].arg1 = ++ (unsigned long) find_task_by_vpid((int) arg1); ++ ++ irnen_reg = 1 << (timer - FIRST_TIMER); ++ ++ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL ++ || (TIMER_FLAG_MASK_HANDLE(flag) == ++ TIMER_FLAG_CALLBACK_IN_IRQ ++ && timer_dev.timer[timer - FIRST_TIMER].arg1)) { ++ enable_irq(timer_dev.timer[timer - FIRST_TIMER].irq); ++ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 1; ++ } ++ } else ++ irnen_reg = 0; ++ ++ /* ++ * Write config register, reload value and enable interrupt. ++ */ ++ n = timer >> 1; ++ X = timer & 0x01; ++ *LQ_GPTU_CON(n, X) = con_reg; ++ *LQ_GPTU_RELOAD(n, X) = value; ++ /* printk("reload value = %d\n", (u32)value); */ ++ *LQ_GPTU_IRNEN |= irnen_reg; ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ printk("successful!\n"); ++ return ret; ++} ++EXPORT_SYMBOL(lq_request_timer); ++ ++int lq_free_timer(unsigned int timer) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ if (GPTU_CON_EN(n, X)) ++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1); ++ ++ *LQ_GPTU_IRNEN &= ~GPTU_IRNEN_TC_SET(n, X, 1); ++ *LQ_GPTU_IRNCR |= GPTU_IRNCR_TC_SET(n, X, 1); ++ ++ if (timer_dev.timer[timer - FIRST_TIMER].f_irq_on) { ++ disable_irq(timer_dev.timer[timer - FIRST_TIMER].irq); ++ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 0; ++ } ++ ++ timer_dev.occupation &= ~mask; ++ if (!timer_dev.occupation && timer_dev.f_gptu_on) { ++ lq_disable_gptu(); ++ timer_dev.f_gptu_on = 0; ++ } ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_free_timer); ++ ++int lq_start_timer(unsigned int timer, int is_resume) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == ++ TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_RL_SET(!is_resume) | GPTU_RUN_SEN_SET(1); ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_start_timer); ++ ++int lq_stop_timer(unsigned int timer) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER ++ || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1); ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_stop_timer); ++ ++int lq_reset_counter_flags(u32 timer, u32 flags) ++{ ++ unsigned int oflag; ++ unsigned int mask, con_reg; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ oflag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(oflag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(oflag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ switch (TIMER_FLAG_MASK_EDGE(flags)) { ++ default: ++ case TIMER_FLAG_NONE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x00); ++ break; ++ case TIMER_FLAG_RISE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x01); ++ break; ++ case TIMER_FLAG_FALL_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x02); ++ break; ++ case TIMER_FLAG_ANY_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x03); ++ break; ++ } ++ if (TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER) ++ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : GPTU_CON_SRC_EXT_SET(0); ++ else ++ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : GPTU_CON_SRC_EG_SET(0); ++ con_reg |= TIMER_FLAG_MASK_SYNC(flags) == TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : GPTU_CON_SYNC_SET(1); ++ con_reg |= TIMER_FLAG_MASK_INVERT(flags) == TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1); ++ con_reg |= TIMER_FLAG_MASK_SIZE(flags) == TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : GPTU_CON_EXT_SET(1); ++ con_reg |= TIMER_FLAG_MASK_STOP(flags) == TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0); ++ con_reg |= TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : GPTU_CON_CNT_SET(1); ++ con_reg |= TIMER_FLAG_MASK_DIR(flags) == TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0); ++ ++ timer_dev.timer[timer - FIRST_TIMER].flag = flags; ++ if (TIMER_FLAG_MASK_SIZE(flags) != TIMER_FLAG_16BIT) ++ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flags; ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *LQ_GPTU_CON(n, X) = con_reg; ++ smp_wmb(); ++ printk(KERN_INFO "[%s]: counter%d oflags %#x, nflags %#x, GPTU_CON %#x\n", __func__, timer, oflag, flags, *LQ_GPTU_CON(n, X)); ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return 0; ++} ++EXPORT_SYMBOL(lq_reset_counter_flags); ++ ++int lq_get_count_value(unsigned int timer, unsigned long *value) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER ++ || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *value = *LQ_GPTU_COUNT(n, X); ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_get_count_value); ++ ++u32 lq_cal_divider(unsigned long freq) ++{ ++ u64 module_freq, fpi = ltq_get_fpi_bus_clock(2); ++ u32 clock_divider = 1; ++ module_freq = fpi * 1000; ++ do_div(module_freq, clock_divider * freq); ++ return module_freq; ++} ++EXPORT_SYMBOL(lq_cal_divider); ++ ++int lq_set_timer(unsigned int timer, unsigned int freq, int is_cyclic, ++ int is_ext_src, unsigned int handle_flag, unsigned long arg1, ++ unsigned long arg2) ++{ ++ unsigned long divider; ++ unsigned int flag; ++ ++ divider = lq_cal_divider(freq); ++ if (divider == 0) ++ return -EINVAL; ++ flag = ((divider & ~0xFFFF) ? TIMER_FLAG_32BIT : TIMER_FLAG_16BIT) ++ | (is_cyclic ? TIMER_FLAG_CYCLIC : TIMER_FLAG_ONCE) ++ | (is_ext_src ? TIMER_FLAG_EXT_SRC : TIMER_FLAG_INT_SRC) ++ | TIMER_FLAG_TIMER | TIMER_FLAG_DOWN ++ | TIMER_FLAG_MASK_HANDLE(handle_flag); ++ ++ printk(KERN_INFO "lq_set_timer(%d, %d), divider = %lu\n", ++ timer, freq, divider); ++ return lq_request_timer(timer, flag, divider, arg1, arg2); ++} ++EXPORT_SYMBOL(lq_set_timer); ++ ++int lq_set_counter(unsigned int timer, unsigned int flag, u32 reload, ++ unsigned long arg1, unsigned long arg2) ++{ ++ printk(KERN_INFO "lq_set_counter(%d, %#x, %d)\n", timer, flag, reload); ++ return lq_request_timer(timer, flag, reload, arg1, arg2); ++} ++EXPORT_SYMBOL(lq_set_counter); ++ ++static long gptu_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ int ret; ++ struct gptu_ioctl_param param; ++ ++ if (!access_ok(VERIFY_READ, arg, sizeof(struct gptu_ioctl_param))) ++ return -EFAULT; ++ copy_from_user(¶m, (void *) arg, sizeof(param)); ++ ++ if ((((cmd == GPTU_REQUEST_TIMER || cmd == GPTU_SET_TIMER ++ || GPTU_SET_COUNTER) && param.timer < 2) ++ || cmd == GPTU_GET_COUNT_VALUE || cmd == GPTU_CALCULATE_DIVIDER) ++ && !access_ok(VERIFY_WRITE, arg, ++ sizeof(struct gptu_ioctl_param))) ++ return -EFAULT; ++ ++ switch (cmd) { ++ case GPTU_REQUEST_TIMER: ++ ret = lq_request_timer(param.timer, param.flag, param.value, ++ (unsigned long) param.pid, ++ (unsigned long) param.sig); ++ if (ret > 0) { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ timer, &ret, sizeof(&ret)); ++ ret = 0; ++ } ++ break; ++ case GPTU_FREE_TIMER: ++ ret = lq_free_timer(param.timer); ++ break; ++ case GPTU_START_TIMER: ++ ret = lq_start_timer(param.timer, param.flag); ++ break; ++ case GPTU_STOP_TIMER: ++ ret = lq_stop_timer(param.timer); ++ break; ++ case GPTU_GET_COUNT_VALUE: ++ ret = lq_get_count_value(param.timer, ¶m.value); ++ if (!ret) ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ value, ¶m.value, ++ sizeof(param.value)); ++ break; ++ case GPTU_CALCULATE_DIVIDER: ++ param.value = lq_cal_divider(param.value); ++ if (param.value == 0) ++ ret = -EINVAL; ++ else { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ value, ¶m.value, ++ sizeof(param.value)); ++ ret = 0; ++ } ++ break; ++ case GPTU_SET_TIMER: ++ ret = lq_set_timer(param.timer, param.value, ++ TIMER_FLAG_MASK_STOP(param.flag) != ++ TIMER_FLAG_ONCE ? 1 : 0, ++ TIMER_FLAG_MASK_SRC(param.flag) == ++ TIMER_FLAG_EXT_SRC ? 1 : 0, ++ TIMER_FLAG_MASK_HANDLE(param.flag) == ++ TIMER_FLAG_SIGNAL ? TIMER_FLAG_SIGNAL : ++ TIMER_FLAG_NO_HANDLE, ++ (unsigned long) param.pid, ++ (unsigned long) param.sig); ++ if (ret > 0) { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ timer, &ret, sizeof(&ret)); ++ ret = 0; ++ } ++ break; ++ case GPTU_SET_COUNTER: ++ lq_set_counter(param.timer, param.flag, param.value, 0, 0); ++ if (ret > 0) { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ timer, &ret, sizeof(&ret)); ++ ret = 0; ++ } ++ break; ++ default: ++ ret = -ENOTTY; ++ } ++ ++ return ret; ++} ++ ++static int gptu_open(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++static int gptu_release(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++int __init lq_gptu_init(void) ++{ ++ int ret; ++ unsigned int i; ++ ++ ltq_w32(0, LQ_GPTU_IRNEN); ++ ltq_w32(0xfff, LQ_GPTU_IRNCR); ++ ++ memset(&timer_dev, 0, sizeof(timer_dev)); ++ mutex_init(&timer_dev.gptu_mutex); ++ ++ lq_enable_gptu(); ++ timer_dev.number_of_timers = GPTU_ID_CFG * 2; ++ lq_disable_gptu(); ++ if (timer_dev.number_of_timers > MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2) ++ timer_dev.number_of_timers = MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2; ++ printk(KERN_INFO "gptu: totally %d 16-bit timers/counters\n", timer_dev.number_of_timers); ++ ++ ret = misc_register(&gptu_miscdev); ++ if (ret) { ++ printk(KERN_ERR "gptu: can't misc_register, get error %d\n", -ret); ++ return ret; ++ } else { ++ printk(KERN_INFO "gptu: misc_register on minor %d\n", gptu_miscdev.minor); ++ } ++ ++ for (i = 0; i < timer_dev.number_of_timers; i++) { ++ ret = request_irq(TIMER_INTERRUPT + i, timer_irq_handler, IRQF_TIMER, gptu_miscdev.name, &timer_dev.timer[i]); ++ if (ret) { ++ for (; i >= 0; i--) ++ free_irq(TIMER_INTERRUPT + i, &timer_dev.timer[i]); ++ misc_deregister(&gptu_miscdev); ++ printk(KERN_ERR "gptu: failed in requesting irq (%d), get error %d\n", i, -ret); ++ return ret; ++ } else { ++ timer_dev.timer[i].irq = TIMER_INTERRUPT + i; ++ disable_irq(timer_dev.timer[i].irq); ++ printk(KERN_INFO "gptu: succeeded to request irq %d\n", timer_dev.timer[i].irq); ++ } ++ } ++ ++ return 0; ++} ++ ++void __exit lq_gptu_exit(void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < timer_dev.number_of_timers; i++) { ++ if (timer_dev.timer[i].f_irq_on) ++ disable_irq(timer_dev.timer[i].irq); ++ free_irq(timer_dev.timer[i].irq, &timer_dev.timer[i]); ++ } ++ lq_disable_gptu(); ++ misc_deregister(&gptu_miscdev); ++} ++ ++module_init(lq_gptu_init); ++module_exit(lq_gptu_exit); +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/lantiq_timer.h +@@ -0,0 +1,155 @@ ++#ifndef __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ ++#define __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ ++ ++ ++/****************************************************************************** ++ Copyright (c) 2002, Infineon Technologies. All rights reserved. ++ ++ No Warranty ++ Because the program is licensed free of charge, there is no warranty for ++ the program, to the extent permitted by applicable law. Except when ++ otherwise stated in writing the copyright holders and/or other parties ++ provide the program "as is" without warranty of any kind, either ++ expressed or implied, including, but not limited to, the implied ++ warranties of merchantability and fitness for a particular purpose. The ++ entire risk as to the quality and performance of the program is with ++ you. should the program prove defective, you assume the cost of all ++ necessary servicing, repair or correction. ++ ++ In no event unless required by applicable law or agreed to in writing ++ will any copyright holder, or any other party who may modify and/or ++ redistribute the program as permitted above, be liable to you for ++ damages, including any general, special, incidental or consequential ++ damages arising out of the use or inability to use the program ++ (including but not limited to loss of data or data being rendered ++ inaccurate or losses sustained by you or third parties or a failure of ++ the program to operate with any other programs), even if such holder or ++ other party has been advised of the possibility of such damages. ++******************************************************************************/ ++ ++ ++/* ++ * #################################### ++ * Definition ++ * #################################### ++ */ ++ ++/* ++ * Available Timer/Counter Index ++ */ ++#define TIMER(n, X) (n * 2 + (X ? 1 : 0)) ++#define TIMER_ANY 0x00 ++#define TIMER1A TIMER(1, 0) ++#define TIMER1B TIMER(1, 1) ++#define TIMER2A TIMER(2, 0) ++#define TIMER2B TIMER(2, 1) ++#define TIMER3A TIMER(3, 0) ++#define TIMER3B TIMER(3, 1) ++ ++/* ++ * Flag of Timer/Counter ++ * These flags specify the way in which timer is configured. ++ */ ++/* Bit size of timer/counter. */ ++#define TIMER_FLAG_16BIT 0x0000 ++#define TIMER_FLAG_32BIT 0x0001 ++/* Switch between timer and counter. */ ++#define TIMER_FLAG_TIMER 0x0000 ++#define TIMER_FLAG_COUNTER 0x0002 ++/* Stop or continue when overflowing/underflowing. */ ++#define TIMER_FLAG_ONCE 0x0000 ++#define TIMER_FLAG_CYCLIC 0x0004 ++/* Count up or counter down. */ ++#define TIMER_FLAG_UP 0x0000 ++#define TIMER_FLAG_DOWN 0x0008 ++/* Count on specific level or edge. */ ++#define TIMER_FLAG_HIGH_LEVEL_SENSITIVE 0x0000 ++#define TIMER_FLAG_LOW_LEVEL_SENSITIVE 0x0040 ++#define TIMER_FLAG_RISE_EDGE 0x0010 ++#define TIMER_FLAG_FALL_EDGE 0x0020 ++#define TIMER_FLAG_ANY_EDGE 0x0030 ++/* Signal is syncronous to module clock or not. */ ++#define TIMER_FLAG_UNSYNC 0x0000 ++#define TIMER_FLAG_SYNC 0x0080 ++/* Different interrupt handle type. */ ++#define TIMER_FLAG_NO_HANDLE 0x0000 ++#if defined(__KERNEL__) ++ #define TIMER_FLAG_CALLBACK_IN_IRQ 0x0100 ++#endif // defined(__KERNEL__) ++#define TIMER_FLAG_SIGNAL 0x0300 ++/* Internal clock source or external clock source */ ++#define TIMER_FLAG_INT_SRC 0x0000 ++#define TIMER_FLAG_EXT_SRC 0x1000 ++ ++ ++/* ++ * ioctl Command ++ */ ++#define GPTU_REQUEST_TIMER 0x01 /* General method to setup timer/counter. */ ++#define GPTU_FREE_TIMER 0x02 /* Free timer/counter. */ ++#define GPTU_START_TIMER 0x03 /* Start or resume timer/counter. */ ++#define GPTU_STOP_TIMER 0x04 /* Suspend timer/counter. */ ++#define GPTU_GET_COUNT_VALUE 0x05 /* Get current count value. */ ++#define GPTU_CALCULATE_DIVIDER 0x06 /* Calculate timer divider from given freq.*/ ++#define GPTU_SET_TIMER 0x07 /* Simplified method to setup timer. */ ++#define GPTU_SET_COUNTER 0x08 /* Simplified method to setup counter. */ ++ ++/* ++ * Data Type Used to Call ioctl ++ */ ++struct gptu_ioctl_param { ++ unsigned int timer; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * ++ * GPTU_SET_COUNTER, this field is ID of expected * ++ * timer/counter. If it's zero, a timer/counter would * ++ * be dynamically allocated and ID would be stored in * ++ * this field. * ++ * In command GPTU_GET_COUNT_VALUE, this field is * ++ * ignored. * ++ * In other command, this field is ID of timer/counter * ++ * allocated. */ ++ unsigned int flag; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * ++ * GPTU_SET_COUNTER, this field contains flags to * ++ * specify how to configure timer/counter. * ++ * In command GPTU_START_TIMER, zero indicate start * ++ * and non-zero indicate resume timer/counter. * ++ * In other command, this field is ignored. */ ++ unsigned long value; /* In command GPTU_REQUEST_TIMER, this field contains * ++ * init/reload value. * ++ * In command GPTU_SET_TIMER, this field contains * ++ * frequency (0.001Hz) of timer. * ++ * In command GPTU_GET_COUNT_VALUE, current count * ++ * value would be stored in this field. * ++ * In command GPTU_CALCULATE_DIVIDER, this field * ++ * contains frequency wanted, and after calculation, * ++ * divider would be stored in this field to overwrite * ++ * the frequency. * ++ * In other command, this field is ignored. */ ++ int pid; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * ++ * if signal is required, this field contains process * ++ * ID to which signal would be sent. * ++ * In other command, this field is ignored. */ ++ int sig; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * ++ * if signal is required, this field contains signal * ++ * number which would be sent. * ++ * In other command, this field is ignored. */ ++}; ++ ++/* ++ * #################################### ++ * Data Type ++ * #################################### ++ */ ++typedef void (*timer_callback)(unsigned long arg); ++ ++extern int lq_request_timer(unsigned int, unsigned int, unsigned long, unsigned long, unsigned long); ++extern int lq_free_timer(unsigned int); ++extern int lq_start_timer(unsigned int, int); ++extern int lq_stop_timer(unsigned int); ++extern int lq_reset_counter_flags(u32 timer, u32 flags); ++extern int lq_get_count_value(unsigned int, unsigned long *); ++extern u32 lq_cal_divider(unsigned long); ++extern int lq_set_timer(unsigned int, unsigned int, int, int, unsigned int, unsigned long, unsigned long); ++extern int lq_set_counter(unsigned int timer, unsigned int flag, ++ u32 reload, unsigned long arg1, unsigned long arg2); ++ ++#endif /* __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ */ +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o ++obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o timer.o + + obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o + obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o diff --git a/target/linux/lantiq/patches/700-dwc_otg.patch b/target/linux/lantiq/patches-2.6.32/550-dwc_otg.patch index 8188403..da13c71 100644 --- a/target/linux/lantiq/patches/700-dwc_otg.patch +++ b/target/linux/lantiq/patches-2.6.32/550-dwc_otg.patch @@ -1,6 +1,6 @@ --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig -@@ -113,6 +113,8 @@ +@@ -107,6 +107,8 @@ source "drivers/usb/host/Kconfig" @@ -11,7 +11,7 @@ source "drivers/usb/class/Kconfig" --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile -@@ -27,6 +27,8 @@ +@@ -26,6 +26,8 @@ obj-$(CONFIG_USB_WUSB) += wusbcore/ @@ -5776,7 +5776,7 @@ +const char dwc_driver_name[] = "dwc_otg"; + +static unsigned long dwc_iomem_base = IFX_USB_IOMEM_BASE; -+int dwc_irq = LQ_USB_INT; ++int dwc_irq = LTQ_USB_INT; +//int dwc_irq = 54; +//int dwc_irq = IFXMIPS_USB_OC_INT; + @@ -9930,7 +9930,7 @@ +#endif /* DWC_DEVICE_ONLY */ --- /dev/null +++ b/drivers/usb/dwc_otg/dwc_otg_hcd.h -@@ -0,0 +1,676 @@ +@@ -0,0 +1,677 @@ +/* ========================================================================== + * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd.h $ + * $Revision: 1.1.1.1 $ @@ -9969,7 +9969,8 @@ + +#include <linux/list.h> +#include <linux/usb.h> -+#include <linux/usb/hcd.h> ++//#include <linux/usb/hcd.h> ++#include "../core/hcd.h" + +struct lm_device; +struct dwc_otg_device; @@ -13283,7 +13284,7 @@ + +#include <asm/io.h> +//#include <asm/mach-ifxmips/ifxmips.h> -+#include <xway.h> ++#include <lantiq_soc.h> + +#define IFXMIPS_GPIO_BASE_ADDR (0xBE100B00) + @@ -13307,9 +13308,9 @@ +#define IFXMIPS_GPIO_P1_PUDEN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0060)) + + -+extern void lq_enable_irq(unsigned int irq_nr); -+#define writel lq_w32 -+#define readl lq_r32 ++extern void ltq_enable_irq(unsigned int irq_nr); ++#define writel ltq_w32 ++#define readl ltq_r32 +void dwc_otg_power_on (void) +{ + // clear power @@ -13398,7 +13399,7 @@ + * We could change this through module param. */ +#define IFX_USB_IOMEM_BASE 0x1e101000 +#define IFX_USB_IOMEM_SIZE SZ_256K -+#define IFX_USB_IRQ LQ_USB_INT ++#define IFX_USB_IRQ LTQ_USB_INT + +/** + * This function is called to set correct clock gating and power. @@ -13430,8 +13431,8 @@ +#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 + -+extern void lq_mask_and_ack_irq (unsigned int irq_nr); -+#define mask_and_ack_ifx_irq lq_mask_and_ack_irq ++extern void ltq_mask_and_ack_irq (unsigned int irq_nr); ++#define mask_and_ack_ifx_irq ltq_mask_and_ack_irq + +#endif //__DWC_OTG_IFX_H__ --- /dev/null @@ -13490,9 +13491,9 @@ +#error "The contents of this file is Linux specific!!!" +#endif +*/ -+#include <xway.h> -+#define writel lq_w32 -+#define readl lq_r32 ++#include <lantiq_soc.h> ++#define writel ltq_w32 ++#define readl ltq_r32 + +/** + * Reads the content of a register. @@ -15508,9 +15509,9 @@ +#endif --- a/arch/mips/lantiq/xway/Makefile +++ b/arch/mips/lantiq/xway/Makefile -@@ -4,3 +4,4 @@ +@@ -6,3 +6,4 @@ obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o - obj-$(CONFIG_LANTIQ_MACH_EASY4010) += mach-easy4010.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o +obj-y += dev-dwc_otg.o --- /dev/null @@ -15544,24 +15545,24 @@ +#include <asm/bootinfo.h> +#include <asm/irq.h> + -+#include <xway.h> -+#include <xway_irq.h> ++#include <lantiq_soc.h> ++#include <lantiq_irq.h> +#include <lantiq_platform.h> + -+#define LQ_USB_IOMEM_BASE 0x1e101000 -+#define LQ_USB_IOMEM_SIZE 0x00040000 ++#define LTQ_USB_IOMEM_BASE 0x1e101000 ++#define LTQ_USB_IOMEM_SIZE 0x00001000 + +static struct resource resources[] = +{ + [0] = { + .name = "dwc_otg_membase", -+ .start = LQ_USB_IOMEM_BASE, -+ .end = LQ_USB_IOMEM_BASE + LQ_USB_IOMEM_SIZE - 1, ++ .start = LTQ_USB_IOMEM_BASE, ++ .end = LTQ_USB_IOMEM_BASE + LTQ_USB_IOMEM_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .name = "dwc_otg_irq", -+ .start = LQ_USB_INT, ++ .start = LTQ_USB_INT, + .flags = IORESOURCE_IRQ, + }, +}; @@ -15580,7 +15581,7 @@ +int __init +xway_register_dwc(int pin) +{ -+ lq_enable_irq(resources[1].start); ++ ltq_enable_irq(resources[1].start); + platform_dev.dev.platform_data = (void*) pin; + return platform_device_register(&platform_dev); +} @@ -15596,11 +15597,27 @@ + * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + */ + -+#ifndef _LQ_DEV_DWC_H__ -+#define _LQ_DEV_DWC_H__ ++#ifndef _LTQ_DEV_DWC_H__ ++#define _LTQ_DEV_DWC_H__ + +#include <lantiq_platform.h> + +extern void __init xway_register_dwc(int pin); + +#endif +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -2704,11 +2704,11 @@ + udev->ttport = hdev->ttport; + } else if (udev->speed != USB_SPEED_HIGH + && hdev->speed == USB_SPEED_HIGH) { +- if (!hub->tt.hub) { ++/* if (!hub->tt.hub) { + dev_err(&udev->dev, "parent hub has no TT\n"); + retval = -EINVAL; + goto fail; +- } ++ }*/ + udev->tt = &hub->tt; + udev->ttport = port1; + } diff --git a/target/linux/lantiq/patches/150-dev-leds-gpio.patch b/target/linux/lantiq/patches-2.6.32/560-dev-leds-gpio.patch index 8ef996b..a66dc0d 100644 --- a/target/linux/lantiq/patches/150-dev-leds-gpio.patch +++ b/target/linux/lantiq/patches-2.6.32/560-dev-leds-gpio.patch @@ -17,7 +17,7 @@ + +#include <linux/leds.h> + -+void lq_add_device_leds_gpio(int id, ++void ltq_add_device_leds_gpio(int id, + unsigned num_leds, + struct gpio_led *leds) __init; + @@ -44,7 +44,7 @@ + +#include "dev-leds-gpio.h" + -+void __init lq_add_device_leds_gpio(int id, unsigned num_leds, ++void __init ltq_add_device_leds_gpio(int id, unsigned num_leds, + struct gpio_led *leds) +{ + struct platform_device *pdev; @@ -84,7 +84,12 @@ +} --- a/arch/mips/lantiq/Makefile +++ b/arch/mips/lantiq/Makefile -@@ -1,2 +1,2 @@ --obj-y := irq.o setup.o clk.o prom.o -+obj-y := dev-leds-gpio.o irq.o setup.o clk.o prom.o +@@ -4,7 +4,7 @@ + # under the terms of the GNU General Public License version 2 as published + # by the Free Software Foundation. + +-obj-y := irq.o setup.o clk.o prom.o devices.o ++obj-y := irq.o setup.o clk.o prom.o devices.o dev-leds-gpio.o + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + diff --git a/target/linux/lantiq/patches-2.6.32/990-fix_include.patch b/target/linux/lantiq/patches-2.6.32/990-fix_include.patch new file mode 100644 index 0000000..79c4a4a --- /dev/null +++ b/target/linux/lantiq/patches-2.6.32/990-fix_include.patch @@ -0,0 +1,76 @@ +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -179,6 +179,16 @@ + # + + # ++# Lantiq ++# ++ ++core-$(CONFIG_LANTIQ) += arch/mips/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_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon ++ ++# + # Texas Instruments AR7 + # + core-$(CONFIG_AR7) += arch/mips/ar7/ +--- a/include/linux/compiler.h ++++ b/include/linux/compiler.h +@@ -144,6 +144,11 @@ + # define barrier() __memory_barrier() + #endif + ++/* Unreachable code */ ++#ifndef unreachable ++# define unreachable() do { } while (1) ++#endif ++ + #ifndef RELOC_HIDE + # define RELOC_HIDE(ptr, off) \ + ({ unsigned long __ptr; \ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +@@ -0,0 +1,40 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_FALCON_H__ ++#define _LTQ_FALCON_H__ ++ ++#ifdef CONFIG_SOC_FALCON ++ ++#include <lantiq.h> ++ ++/* Chip IDs */ ++#define SOC_ID_FALCON 0x01B8 ++ ++/* SoC Types */ ++#define SOC_TYPE_FALCON 0x01 ++ ++/* ASC0/1 - serial port */ ++#define LTQ_ASC0_BASE_ADDR 0x1E100C00 ++#define LTQ_ASC1_BASE_ADDR 0x1E100B00 ++#define LTQ_ASC_SIZE 0x100 ++ ++#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8)) ++#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1) ++#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2) ++ ++/* ICU - interrupt control unit */ ++#define LTQ_ICU_BASE_ADDR 0x1F880200 ++#define LTQ_ICU_SIZE 0x100 ++ ++/* WDT */ ++#define LTQ_WDT_BASE_ADDR 0x1F8803F0 ++#define LTQ_WDT_SIZE 0x10 ++ ++#endif /* CONFIG_SOC_FALCON */ ++#endif /* _LTQ_XWAY_H__ */ diff --git a/target/linux/lantiq/patches-2.6.39/0001-MIPS-Lantiq-Add-initial-support-for-Lantiq-SoCs.patch b/target/linux/lantiq/patches-2.6.39/0001-MIPS-Lantiq-Add-initial-support-for-Lantiq-SoCs.patch new file mode 100644 index 0000000..c7f96cd --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0001-MIPS-Lantiq-Add-initial-support-for-Lantiq-SoCs.patch @@ -0,0 +1,894 @@ +From 9e0235e97ea2617beaacaa16ab5f0b9e75f4680e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:47 +0200 +Subject: [PATCH 01/13] MIPS: Lantiq: Add initial support for Lantiq SoCs + +Add initial support for Mips based SoCs made by Lantiq. This series will add +support for the XWAY family. + +The series allows booting a minimal system using a initramfs or NOR. Missing +drivers and support for Amazon and GPON family will be provided in a later +series. + +[Ralf: Remove some cargo cult programming and fixed formatting.] + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Signed-off-by: David Daney <ddaney@caviumnetworks.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2252/ +Patchwork: https://patchwork.linux-mips.org/patch/2371/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/Kbuild.platforms | 1 + + arch/mips/Kconfig | 17 ++ + arch/mips/include/asm/mach-lantiq/lantiq.h | 63 ++++++ + arch/mips/include/asm/mach-lantiq/war.h | 24 ++ + arch/mips/lantiq/Makefile | 9 + + arch/mips/lantiq/Platform | 7 + + arch/mips/lantiq/clk.c | 140 ++++++++++++ + arch/mips/lantiq/clk.h | 18 ++ + arch/mips/lantiq/early_printk.c | 33 +++ + arch/mips/lantiq/irq.c | 326 ++++++++++++++++++++++++++++ + arch/mips/lantiq/prom.c | 71 ++++++ + arch/mips/lantiq/prom.h | 24 ++ + arch/mips/lantiq/setup.c | 41 ++++ + 13 files changed, 774 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq.h + create mode 100644 arch/mips/include/asm/mach-lantiq/war.h + create mode 100644 arch/mips/lantiq/Makefile + create mode 100644 arch/mips/lantiq/Platform + create mode 100644 arch/mips/lantiq/clk.c + create mode 100644 arch/mips/lantiq/clk.h + create mode 100644 arch/mips/lantiq/early_printk.c + create mode 100644 arch/mips/lantiq/irq.c + create mode 100644 arch/mips/lantiq/prom.c + create mode 100644 arch/mips/lantiq/prom.h + create mode 100644 arch/mips/lantiq/setup.c + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -212,6 +212,23 @@ + select HAVE_PWM + select HAVE_CLK + ++config LANTIQ ++ bool "Lantiq based platforms" ++ select DMA_NONCOHERENT ++ select IRQ_CPU ++ select CEVT_R4K ++ select CSRC_R4K ++ select SYS_HAS_CPU_MIPS32_R1 ++ select SYS_HAS_CPU_MIPS32_R2 ++ select SYS_SUPPORTS_BIG_ENDIAN ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select SYS_SUPPORTS_MULTITHREADING ++ select SYS_HAS_EARLY_PRINTK ++ select ARCH_REQUIRE_GPIOLIB ++ select SWAP_IO_SPACE ++ select BOOT_RAW ++ select HAVE_CLK ++ + config LASAT + bool "LASAT Networks platforms" + select CEVT_R4K +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/lantiq.h +@@ -0,0 +1,63 @@ ++/* ++ * 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> ++ */ ++#ifndef _LANTIQ_H__ ++#define _LANTIQ_H__ ++ ++#include <linux/irq.h> ++ ++/* generic reg access functions */ ++#define ltq_r32(reg) __raw_readl(reg) ++#define ltq_w32(val, reg) __raw_writel(val, reg) ++#define ltq_w32_mask(clear, set, reg) \ ++ ltq_w32((ltq_r32(reg) & ~(clear)) | (set), reg) ++#define ltq_r8(reg) __raw_readb(reg) ++#define ltq_w8(val, reg) __raw_writeb(val, reg) ++ ++/* 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_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) ++#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) ++ ++extern __iomem void *ltq_ebu_membase; ++extern __iomem void *ltq_cgu_membase; ++ ++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_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; ++ ++/* some irq helpers */ ++extern void ltq_disable_irq(struct irq_data *d); ++extern void ltq_mask_and_ack_irq(struct irq_data *d); ++extern void ltq_enable_irq(struct irq_data *d); ++ ++/* find out what caused the last cpu reset */ ++extern int ltq_reset_cause(void); ++#define LTQ_RST_CAUSE_WDTRST 0x20 ++ ++#define IOPORT_RESOURCE_START 0x10000000 ++#define IOPORT_RESOURCE_END 0xffffffff ++#define IOMEM_RESOURCE_START 0x10000000 ++#define IOMEM_RESOURCE_END 0xffffffff ++#define LTQ_FLASH_START 0x10000000 ++#define LTQ_FLASH_MAX 0x04000000 ++ ++#endif +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/war.h +@@ -0,0 +1,24 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file "COPYING" in the main directory of this archive ++ * for more details. ++ * ++ */ ++#ifndef __ASM_MIPS_MACH_LANTIQ_WAR_H ++#define __ASM_MIPS_MACH_LANTIQ_WAR_H ++ ++#define R4600_V1_INDEX_ICACHEOP_WAR 0 ++#define R4600_V1_HIT_CACHEOP_WAR 0 ++#define R4600_V2_HIT_CACHEOP_WAR 0 ++#define R5432_CP0_INTERRUPT_WAR 0 ++#define BCM1250_M3_WAR 0 ++#define SIBYTE_1956_WAR 0 ++#define MIPS4K_ICACHE_REFILL_WAR 0 ++#define MIPS_CACHE_SYNC_WAR 0 ++#define TX49XX_ICACHE_INDEX_INV_WAR 0 ++#define RM9000_CDEX_SMP_WAR 0 ++#define ICACHE_REFILLS_WORKAROUND_WAR 0 ++#define R10000_LLSC_WAR 0 ++#define MIPS34K_MISSED_ITLB_WAR 0 ++ ++#endif +--- /dev/null ++++ b/arch/mips/lantiq/Makefile +@@ -0,0 +1,9 @@ ++# Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++# ++# This program is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License version 2 as published ++# by the Free Software Foundation. ++ ++obj-y := irq.o setup.o clk.o prom.o ++ ++obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +--- /dev/null ++++ b/arch/mips/lantiq/Platform +@@ -0,0 +1,7 @@ ++# ++# Lantiq ++# ++ ++platform-$(CONFIG_LANTIQ) += lantiq/ ++cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq ++load-$(CONFIG_LANTIQ) = 0xffffffff80002000 +--- /dev/null ++++ b/arch/mips/lantiq/clk.c +@@ -0,0 +1,144 @@ ++/* ++ * 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 Thomas Langer <thomas.langer@lantiq.com> ++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++ */ ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/list.h> ++ ++#include <asm/time.h> ++#include <asm/irq.h> ++#include <asm/div64.h> ++ ++#include <lantiq_soc.h> ++ ++#include "clk.h" ++ ++struct clk { ++ const char *name; ++ unsigned long rate; ++ unsigned long (*get_rate) (void); ++}; ++ ++static struct clk *cpu_clk; ++static int cpu_clk_cnt; ++ ++/* 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, ++ }, ++}; ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++static struct resource ltq_cgu_resource = { ++ .name = "cgu", ++ .start = LTQ_CGU_BASE_ADDR, ++ .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++/* remapped clock register range */ ++void __iomem *ltq_cgu_membase; ++#endif ++ ++void clk_init(void) ++{ ++ cpu_clk = cpu_clk_generic; ++ cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic); ++} ++ ++static inline int clk_good(struct clk *clk) ++{ ++ return clk && !IS_ERR(clk); ++} ++ ++unsigned long clk_get_rate(struct clk *clk) ++{ ++ if (unlikely(!clk_good(clk))) ++ return 0; ++ ++ if (clk->rate != 0) ++ return clk->rate; ++ ++ if (clk->get_rate != NULL) ++ return clk->get_rate(); ++ ++ return 0; ++} ++EXPORT_SYMBOL(clk_get_rate); ++ ++struct clk *clk_get(struct device *dev, const char *id) ++{ ++ int i; ++ ++ for (i = 0; i < cpu_clk_cnt; i++) ++ if (!strcmp(id, cpu_clk[i].name)) ++ return &cpu_clk[i]; ++ BUG(); ++ return ERR_PTR(-ENOENT); ++} ++EXPORT_SYMBOL(clk_get); ++ ++void clk_put(struct clk *clk) ++{ ++ /* not used */ ++} ++EXPORT_SYMBOL(clk_put); ++ ++static inline u32 ltq_get_counter_resolution(void) ++{ ++ u32 res; ++ ++ __asm__ __volatile__( ++ ".set push\n" ++ ".set mips32r2\n" ++ "rdhwr %0, $3\n" ++ ".set pop\n" ++ : "=&r" (res) ++ : /* no input */ ++ : "memory"); ++ ++ return res; ++} ++ ++void __init plat_time_init(void) ++{ ++ struct clk *clk; ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++ if (insert_resource(&iomem_resource, <q_cgu_resource) < 0) ++ panic("Failed to insert cgu memory\n"); ++ ++ if (request_mem_region(ltq_cgu_resource.start, ++ resource_size(<q_cgu_resource), "cgu") < 0) ++ panic("Failed to request cgu memory\n"); ++ ++ ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start, ++ resource_size(<q_cgu_resource)); ++ if (!ltq_cgu_membase) { ++ pr_err("Failed to remap cgu memory\n"); ++ unreachable(); ++ } ++#endif ++ clk = clk_get(0, "cpu"); ++ mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution(); ++ write_c0_compare(read_c0_count()); ++ clk_put(clk); ++} +--- /dev/null ++++ b/arch/mips/lantiq/clk.h +@@ -0,0 +1,18 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_CLK_H__ ++#define _LTQ_CLK_H__ ++ ++extern void clk_init(void); ++ ++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); ++ ++#endif +--- /dev/null ++++ b/arch/mips/lantiq/early_printk.c +@@ -0,0 +1,37 @@ ++/* ++ * 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/cpu.h> ++ ++#include <lantiq.h> ++#include <lantiq_soc.h> ++ ++/* no ioremap possible at this early stage, lets use KSEG1 instead */ ++#ifdef CONFIG_SOC_FALCON ++#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC0_BASE_ADDR) ++#else ++#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR) ++#endif ++#define ASC_BUF 1024 ++#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048)) ++#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020)) ++#define TXMASK 0x3F00 ++#define TXOFFSET 8 ++ ++void prom_putchar(char c) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET); ++ if (c == '\n') ++ ltq_w32('\r', LTQ_ASC_TBUF); ++ ltq_w32(c, LTQ_ASC_TBUF); ++ local_irq_restore(flags); ++} +--- /dev/null ++++ b/arch/mips/lantiq/irq.c +@@ -0,0 +1,339 @@ ++/* ++ * 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> ++ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> ++ */ ++ ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <linux/module.h> ++ ++#include <asm/bootinfo.h> ++#include <asm/irq_cpu.h> ++ ++#include <lantiq_soc.h> ++#include <irq.h> ++ ++/* register definitions */ ++#define LTQ_ICU_IM0_ISR 0x0000 ++#define LTQ_ICU_IM0_IER 0x0008 ++#define LTQ_ICU_IM0_IOSR 0x0010 ++#define LTQ_ICU_IM0_IRSR 0x0018 ++#define LTQ_ICU_IM0_IMR 0x0020 ++#define LTQ_ICU_IM1_ISR 0x0028 ++#define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR) ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++ ++#define LTQ_EIU_EXIN_C 0x0000 ++#define LTQ_EIU_EXIN_INIC 0x0004 ++#define LTQ_EIU_EXIN_INEN 0x000C ++ ++/* irq numbers used by the external interrupt unit (EIU) */ ++#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30) ++#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31) ++#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26) ++#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0 ++#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1) ++#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2) ++#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30) ++ ++#define MAX_EIU 6 ++ ++/* irqs generated by device attached to the EBU need to be acked in ++ * a special manner ++ */ ++#define LTQ_ICU_EBU_IRQ 22 ++ ++#define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) ++#define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) ++ ++static unsigned short ltq_eiu_irq[MAX_EIU] = { ++ LTQ_EIU_IR0, ++ LTQ_EIU_IR1, ++ LTQ_EIU_IR2, ++ LTQ_EIU_IR3, ++ LTQ_EIU_IR4, ++ LTQ_EIU_IR5, ++}; ++ ++static void __iomem *ltq_eiu_membase; ++ ++static struct resource ltq_eiu_resource = { ++ .name = "eiu", ++ .start = LTQ_EIU_BASE_ADDR, ++ .end = LTQ_EIU_BASE_ADDR + LTQ_ICU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++#endif ++ ++static struct resource ltq_icu_resource = { ++ .name = "icu", ++ .start = LTQ_ICU_BASE_ADDR, ++ .end = LTQ_ICU_BASE_ADDR + LTQ_ICU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++#define ltq_icu_w32(x, y) ltq_w32((x), ltq_icu_membase + (y)) ++#define ltq_icu_r32(x) ltq_r32(ltq_icu_membase + (x)) ++ ++static void __iomem *ltq_icu_membase; ++ ++ ++void ltq_disable_irq(struct irq_data *d) ++{ ++ u32 ier = LTQ_ICU_IM0_IER; ++ int irq_nr = d->irq - INT_NUM_IRQ0; ++ ++ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); ++ irq_nr %= INT_NUM_IM_OFFSET; ++ ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); ++} ++ ++void ltq_mask_and_ack_irq(struct irq_data *d) ++{ ++ u32 ier = LTQ_ICU_IM0_IER; ++ u32 isr = LTQ_ICU_IM0_ISR; ++ int irq_nr = d->irq - INT_NUM_IRQ0; ++ ++ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); ++ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); ++ irq_nr %= INT_NUM_IM_OFFSET; ++ ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier); ++ ltq_icu_w32((1 << irq_nr), isr); ++} ++EXPORT_SYMBOL(ltq_mask_and_ack_irq); ++ ++static void ltq_ack_irq(struct irq_data *d) ++{ ++ u32 isr = LTQ_ICU_IM0_ISR; ++ int irq_nr = d->irq - INT_NUM_IRQ0; ++ ++ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); ++ irq_nr %= INT_NUM_IM_OFFSET; ++ ltq_icu_w32((1 << irq_nr), isr); ++} ++ ++void ltq_enable_irq(struct irq_data *d) ++{ ++ u32 ier = LTQ_ICU_IM0_IER; ++ int irq_nr = d->irq - INT_NUM_IRQ0; ++ ++ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); ++ irq_nr %= INT_NUM_IM_OFFSET; ++ ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier); ++} ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++static unsigned int ltq_startup_eiu_irq(struct irq_data *d) ++{ ++ int i; ++ int irq_nr = d->irq - INT_NUM_IRQ0; ++ ++ ltq_enable_irq(d); ++ for (i = 0; i < MAX_EIU; i++) { ++ if (irq_nr == ltq_eiu_irq[i]) { ++ /* low level - we should really handle set_type */ ++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) | ++ (0x6 << (i * 4)), LTQ_EIU_EXIN_C); ++ /* clear all pending */ ++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~(1 << i), ++ LTQ_EIU_EXIN_INIC); ++ /* enable */ ++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | (1 << i), ++ LTQ_EIU_EXIN_INEN); ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++static void ltq_shutdown_eiu_irq(struct irq_data *d) ++{ ++ int i; ++ int irq_nr = d->irq - INT_NUM_IRQ0; ++ ++ ltq_disable_irq(d); ++ for (i = 0; i < MAX_EIU; i++) { ++ if (irq_nr == ltq_eiu_irq[i]) { ++ /* disable */ ++ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i), ++ LTQ_EIU_EXIN_INEN); ++ break; ++ } ++ } ++} ++#endif ++ ++static struct irq_chip ltq_irq_type = { ++ "icu", ++ .irq_enable = ltq_enable_irq, ++ .irq_disable = ltq_disable_irq, ++ .irq_unmask = ltq_enable_irq, ++ .irq_ack = ltq_ack_irq, ++ .irq_mask = ltq_disable_irq, ++ .irq_mask_ack = ltq_mask_and_ack_irq, ++}; ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++static struct irq_chip ltq_eiu_type = { ++ "eiu", ++ .irq_startup = ltq_startup_eiu_irq, ++ .irq_shutdown = ltq_shutdown_eiu_irq, ++ .irq_enable = ltq_enable_irq, ++ .irq_disable = ltq_disable_irq, ++ .irq_unmask = ltq_enable_irq, ++ .irq_ack = ltq_ack_irq, ++ .irq_mask = ltq_disable_irq, ++ .irq_mask_ack = ltq_mask_and_ack_irq, ++}; ++#endif ++ ++static void ltq_hw_irqdispatch(int module) ++{ ++ u32 irq; ++ ++ irq = ltq_icu_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET)); ++ if (irq == 0) ++ return; ++ ++ /* silicon bug causes only the msb set to 1 to be valid. all ++ * other bits might be bogus ++ */ ++ irq = __fls(irq); ++ do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module)); ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++ /* if this is a EBU irq, we need to ack it or get a deadlock */ ++ if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0)) ++ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10, ++ LTQ_EBU_PCC_ISTAT); ++#endif ++} ++ ++#define DEFINE_HWx_IRQDISPATCH(x) \ ++ static void ltq_hw ## x ## _irqdispatch(void) \ ++ { \ ++ ltq_hw_irqdispatch(x); \ ++ } ++DEFINE_HWx_IRQDISPATCH(0) ++DEFINE_HWx_IRQDISPATCH(1) ++DEFINE_HWx_IRQDISPATCH(2) ++DEFINE_HWx_IRQDISPATCH(3) ++DEFINE_HWx_IRQDISPATCH(4) ++ ++static void ltq_hw5_irqdispatch(void) ++{ ++ do_IRQ(MIPS_CPU_TIMER_IRQ); ++} ++ ++asmlinkage void plat_irq_dispatch(void) ++{ ++ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; ++ unsigned int i; ++ ++ if (pending & CAUSEF_IP7) { ++ do_IRQ(MIPS_CPU_TIMER_IRQ); ++ goto out; ++ } else { ++ for (i = 0; i < 5; i++) { ++ if (pending & (CAUSEF_IP2 << i)) { ++ ltq_hw_irqdispatch(i); ++ goto out; ++ } ++ } ++ } ++ pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status()); ++ ++out: ++ return; ++} ++ ++static struct irqaction cascade = { ++ .handler = no_action, ++ .flags = IRQF_DISABLED, ++ .name = "cascade", ++}; ++ ++void __init arch_init_irq(void) ++{ ++ int i; ++ ++ if (insert_resource(&iomem_resource, <q_icu_resource) < 0) ++ panic("Failed to insert icu memory\n"); ++ ++ if (request_mem_region(ltq_icu_resource.start, ++ resource_size(<q_icu_resource), "icu") < 0) ++ panic("Failed to request icu memory\n"); ++ ++ ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start, ++ resource_size(<q_icu_resource)); ++ if (!ltq_icu_membase) ++ panic("Failed to remap icu memory\n"); ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++ 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"); ++ ++ ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start, ++ resource_size(<q_eiu_resource)); ++ if (!ltq_eiu_membase) ++ panic("Failed to remap eiu memory\n"); ++#endif ++ /* make sure all irqs are turned off by default */ ++ for (i = 0; i < 5; i++) ++ 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)); ++ ++ mips_cpu_irq_init(); ++ ++ for (i = 2; i <= 6; i++) ++ setup_irq(i, &cascade); ++ ++ if (cpu_has_vint) { ++ pr_info("Setting up vectored interrupts\n"); ++ set_vi_handler(2, ltq_hw0_irqdispatch); ++ set_vi_handler(3, ltq_hw1_irqdispatch); ++ set_vi_handler(4, ltq_hw2_irqdispatch); ++ set_vi_handler(5, ltq_hw3_irqdispatch); ++ set_vi_handler(6, ltq_hw4_irqdispatch); ++ set_vi_handler(7, ltq_hw5_irqdispatch); ++ } ++ ++ for (i = INT_NUM_IRQ0; ++ i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++) ++#ifdef CONFIG_SOC_TYPE_XWAY ++ if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) || (i == LTQ_EIU_IR2)) ++ irq_set_chip_and_handler(i, <q_eiu_type, handle_level_irq); ++ /* EIU3-5 only exist on ar9 and vr9 */ ++ else if (((i == LTQ_EIU_IR3) || (i == LTQ_EIU_IR4) || ++ (i == LTQ_EIU_IR5)) && (ltq_is_ar9() || ltq_is_vr9())) ++ irq_set_chip_and_handler(i, <q_eiu_type, handle_level_irq); ++ else ++#endif ++ irq_set_chip_and_handler(i, <q_irq_type, handle_level_irq); ++ ++#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); ++#else ++ set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 | ++ IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); ++#endif ++} ++ ++unsigned int __cpuinit get_c0_compare_int(void) ++{ ++ return CP0_LEGACY_COMPARE_IRQ; ++} +--- /dev/null ++++ b/arch/mips/lantiq/prom.c +@@ -0,0 +1,71 @@ ++/* ++ * 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.h> ++ ++#include "prom.h" ++#include "clk.h" ++ ++static struct ltq_soc_info soc_info; ++ ++unsigned int ltq_get_cpu_ver(void) ++{ ++ return soc_info.rev; ++} ++EXPORT_SYMBOL(ltq_get_cpu_ver); ++ ++unsigned int ltq_get_soc_type(void) ++{ ++ return soc_info.type; ++} ++EXPORT_SYMBOL(ltq_get_soc_type); ++ ++const char *get_system_type(void) ++{ ++ return soc_info.sys_type; ++} ++ ++void prom_free_prom_memory(void) ++{ ++} ++ ++static void __init prom_init_cmdline(void) ++{ ++ int argc = fw_arg0; ++ char **argv = (char **) KSEG1ADDR(fw_arg1); ++ int i; ++ ++ for (i = 0; i < argc; i++) { ++ char *p = (char *) KSEG1ADDR(argv[i]); ++ ++ if (p && *p) { ++ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); ++ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); ++ } ++ } ++} ++ ++void __init prom_init(void) ++{ ++ struct clk *clk; ++ ++ ltq_soc_detect(&soc_info); ++ clk_init(); ++ clk = clk_get(0, "cpu"); ++ snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d", ++ soc_info.name, soc_info.rev); ++ clk_put(clk); ++ soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; ++ pr_info("SoC: %s\n", soc_info.sys_type); ++ prom_init_cmdline(); ++} +--- /dev/null ++++ b/arch/mips/lantiq/prom.h +@@ -0,0 +1,24 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_PROM_H__ ++#define _LTQ_PROM_H__ ++ ++#define LTQ_SYS_TYPE_LEN 0x100 ++ ++struct ltq_soc_info { ++ unsigned char *name; ++ unsigned int rev; ++ unsigned int partnum; ++ unsigned int type; ++ unsigned char sys_type[LTQ_SYS_TYPE_LEN]; ++}; ++ ++extern void ltq_soc_detect(struct ltq_soc_info *i); ++ ++#endif +--- /dev/null ++++ b/arch/mips/lantiq/setup.c +@@ -0,0 +1,41 @@ ++/* ++ * 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/kernel.h> ++#include <linux/module.h> ++#include <linux/io.h> ++#include <linux/ioport.h> ++#include <asm/bootinfo.h> ++ ++#include <lantiq_soc.h> ++ ++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; ++ ioport_resource.end = IOPORT_RESOURCE_END; ++ iomem_resource.start = IOMEM_RESOURCE_START; ++ iomem_resource.end = IOMEM_RESOURCE_END; ++ ++ set_io_port_base((unsigned long) KSEG1); ++ ++ while (*envp) { ++ char *e = (char *)KSEG1ADDR(*envp); ++ if (!strncmp(e, "memsize=", 8)) { ++ e += 8; ++ if (strict_strtoul(e, 0, &memsize)) ++ pr_warn("bad memsize specified\n"); ++ } ++ envp++; ++ } ++ memsize *= 1024 * 1024; ++ add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); ++} +--- a/arch/mips/Kbuild.platforms ++++ b/arch/mips/Kbuild.platforms +@@ -11,6 +11,7 @@ + platforms += emma + platforms += jazz + platforms += jz4740 ++platforms += lantiq + platforms += lasat + platforms += loongson + platforms += mipssim diff --git a/target/linux/lantiq/patches-2.6.39/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch b/target/linux/lantiq/patches-2.6.39/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch new file mode 100644 index 0000000..2f44b66 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch @@ -0,0 +1,1151 @@ +From 36cc26a362c6ad64ba3d176809847ec60cc40859 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:48 +0200 +Subject: [PATCH 02/13] MIPS: Lantiq: add SoC specific code for XWAY family + +Add support for the Lantiq XWAY family of Mips24KEc SoCs. + +* Danube (PSB50702) +* Twinpass (PSB4000) +* AR9 (PSB50802) +* Amazon SE (PSB5061) + +The Amazon SE is a lightweight SoC and has no PCI as well as a different +clock. We split the code out into seperate files to handle this. + +The GPIO pins on the SoCs are multi function and there are several bits +we can use to configure the pins. To be as compatible as possible to +GPIOLIB we add a function + +int ltq_gpio_request(unsigned int pin, unsigned int alt0, + unsigned int alt1, unsigned int dir, const char *name); + +which lets you configure the 2 "alternate function" bits. This way drivers like +PCI can make use of GPIOLIB without a cubersome wrapper. + +The PLL code inside arch/mips/lantiq/xway/clk-xway.c is voodoo to me. It was +taken from a 2.4.20 source tree and was never really changed by me since then. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2249/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/Kconfig | 1 + + arch/mips/include/asm/mach-lantiq/xway/irq.h | 18 ++ + .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 66 ++++++ + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 140 ++++++++++++ + arch/mips/lantiq/Kconfig | 21 ++ + arch/mips/lantiq/Makefile | 2 + + arch/mips/lantiq/Platform | 1 + + arch/mips/lantiq/xway/Makefile | 4 + + arch/mips/lantiq/xway/clk-ase.c | 48 +++++ + arch/mips/lantiq/xway/clk-xway.c | 223 ++++++++++++++++++++ + arch/mips/lantiq/xway/ebu.c | 53 +++++ + arch/mips/lantiq/xway/gpio.c | 195 +++++++++++++++++ + arch/mips/lantiq/xway/pmu.c | 70 ++++++ + arch/mips/lantiq/xway/prom-ase.c | 39 ++++ + arch/mips/lantiq/xway/prom-xway.c | 54 +++++ + arch/mips/lantiq/xway/reset.c | 91 ++++++++ + 16 files changed, 1026 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/include/asm/mach-lantiq/xway/irq.h + create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h + create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h + create mode 100644 arch/mips/lantiq/Kconfig + create mode 100644 arch/mips/lantiq/xway/Makefile + create mode 100644 arch/mips/lantiq/xway/clk-ase.c + create mode 100644 arch/mips/lantiq/xway/clk-xway.c + create mode 100644 arch/mips/lantiq/xway/ebu.c + create mode 100644 arch/mips/lantiq/xway/gpio.c + create mode 100644 arch/mips/lantiq/xway/pmu.c + create mode 100644 arch/mips/lantiq/xway/prom-ase.c + create mode 100644 arch/mips/lantiq/xway/prom-xway.c + create mode 100644 arch/mips/lantiq/xway/reset.c + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -760,6 +760,7 @@ + source "arch/mips/bcm63xx/Kconfig" + source "arch/mips/jazz/Kconfig" + source "arch/mips/jz4740/Kconfig" ++source "arch/mips/lantiq/Kconfig" + source "arch/mips/lasat/Kconfig" + source "arch/mips/pmc-sierra/Kconfig" + source "arch/mips/powertv/Kconfig" +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/xway/irq.h +@@ -0,0 +1,18 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef __LANTIQ_IRQ_H ++#define __LANTIQ_IRQ_H ++ ++#include <lantiq_irq.h> ++ ++#define NR_IRQS 256 ++ ++#include_next <irq.h> ++ ++#endif +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h +@@ -0,0 +1,66 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LANTIQ_XWAY_IRQ_H__ ++#define _LANTIQ_XWAY_IRQ_H__ ++ ++#define INT_NUM_IRQ0 8 ++#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0) ++#define INT_NUM_IM1_IRL0 (INT_NUM_IRQ0 + 32) ++#define INT_NUM_IM2_IRL0 (INT_NUM_IRQ0 + 64) ++#define INT_NUM_IM3_IRL0 (INT_NUM_IRQ0 + 96) ++#define INT_NUM_IM4_IRL0 (INT_NUM_IRQ0 + 128) ++#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0) ++ ++#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8)) ++#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1) ++#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2) ++ ++#define LTQ_ASC_ASE_TIR INT_NUM_IM2_IRL0 ++#define LTQ_ASC_ASE_RIR (INT_NUM_IM2_IRL0 + 2) ++#define LTQ_ASC_ASE_EIR (INT_NUM_IM2_IRL0 + 3) ++ ++#define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15) ++#define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14) ++#define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16) ++ ++#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21) ++#define LTQ_MEI_INT (INT_NUM_IM1_IRL0 + 23) ++ ++#define LTQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23) ++#define LTQ_USB_INT (INT_NUM_IM1_IRL0 + 22) ++#define LTQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23) ++ ++#define MIPS_CPU_TIMER_IRQ 7 ++ ++#define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0) ++#define LTQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1) ++#define LTQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2) ++#define LTQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3) ++#define LTQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4) ++#define LTQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5) ++#define LTQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6) ++#define LTQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7) ++#define LTQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8) ++#define LTQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9) ++#define LTQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10) ++#define LTQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11) ++#define LTQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25) ++#define LTQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26) ++#define LTQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27) ++#define LTQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28) ++#define LTQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29) ++#define LTQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30) ++#define LTQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16) ++#define LTQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21) ++ ++#define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24) ++ ++#define INT_NUM_IM4_IRL14 (INT_NUM_IM4_IRL0 + 14) ++ ++#endif +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -0,0 +1,140 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_XWAY_H__ ++#define _LTQ_XWAY_H__ ++ ++#ifdef CONFIG_SOC_TYPE_XWAY ++ ++#include <lantiq.h> ++ ++/* Chip IDs */ ++#define SOC_ID_DANUBE1 0x129 ++#define SOC_ID_DANUBE2 0x12B ++#define SOC_ID_TWINPASS 0x12D ++#define SOC_ID_AMAZON_SE 0x152 ++#define SOC_ID_ARX188 0x16C ++#define SOC_ID_ARX168 0x16D ++#define SOC_ID_ARX182 0x16F ++ ++/* 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 ++ ++/* ASC0/1 - serial port */ ++#define LTQ_ASC0_BASE_ADDR 0x1E100400 ++#define LTQ_ASC1_BASE_ADDR 0x1E100C00 ++#define LTQ_ASC_SIZE 0x400 ++ ++/* RCU - reset control unit */ ++#define LTQ_RCU_BASE_ADDR 0x1F203000 ++#define LTQ_RCU_SIZE 0x1000 ++ ++/* GPTU - general purpose timer unit */ ++#define LTQ_GPTU_BASE_ADDR 0x18000300 ++#define LTQ_GPTU_SIZE 0x100 ++ ++/* EBU - external bus unit */ ++#define LTQ_EBU_GPIO_START 0x14000000 ++#define LTQ_EBU_GPIO_SIZE 0x1000 ++ ++#define LTQ_EBU_BASE_ADDR 0x1E105300 ++#define LTQ_EBU_SIZE 0x100 ++ ++#define LTQ_EBU_BUSCON0 0x0060 ++#define LTQ_EBU_PCC_CON 0x0090 ++#define LTQ_EBU_PCC_IEN 0x00A4 ++#define LTQ_EBU_PCC_ISTAT 0x00A0 ++#define LTQ_EBU_BUSCON1 0x0064 ++#define LTQ_EBU_ADDRSEL1 0x0024 ++#define EBU_WRDIS 0x80000000 ++ ++/* CGU - clock generation unit */ ++#define LTQ_CGU_BASE_ADDR 0x1F103000 ++#define LTQ_CGU_SIZE 0x1000 ++ ++/* ICU - interrupt control unit */ ++#define LTQ_ICU_BASE_ADDR 0x1F880200 ++#define LTQ_ICU_SIZE 0x100 ++ ++/* EIU - external interrupt unit */ ++#define LTQ_EIU_BASE_ADDR 0x1F101000 ++#define LTQ_EIU_SIZE 0x1000 ++ ++/* PMU - power management unit */ ++#define LTQ_PMU_BASE_ADDR 0x1F102000 ++#define LTQ_PMU_SIZE 0x1000 ++ ++#define PMU_DMA 0x0020 ++#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_PPE32_BASE_ADDR 0xBE180000 ++#define LTQ_PPE32_SIZE 0x40000 ++ ++/* DMA */ ++#define LTQ_DMA_BASE_ADDR 0xBE104100 ++ ++/* PCI */ ++#define PCI_CR_BASE_ADDR 0x1E105400 ++#define PCI_CR_SIZE 0x400 ++ ++/* WDT */ ++#define LTQ_WDT_BASE_ADDR 0x1F8803F0 ++#define LTQ_WDT_SIZE 0x10 ++ ++/* STP - serial to parallel conversion unit */ ++#define LTQ_STP_BASE_ADDR 0x1E100BB0 ++#define LTQ_STP_SIZE 0x40 ++ ++/* GPIO */ ++#define LTQ_GPIO0_BASE_ADDR 0x1E100B10 ++#define LTQ_GPIO1_BASE_ADDR 0x1E100B40 ++#define LTQ_GPIO2_BASE_ADDR 0x1E100B70 ++#define LTQ_GPIO_SIZE 0x30 ++ ++/* SSC */ ++#define LTQ_SSC_BASE_ADDR 0x1e100800 ++#define LTQ_SSC_SIZE 0x100 ++ ++/* MEI - dsl core */ ++#define LTQ_MEI_BASE_ADDR 0x1E116000 ++ ++/* DEU - data encryption unit */ ++#define LTQ_DEU_BASE_ADDR 0x1E103100 ++ ++/* MPS - multi processor unit (voice) */ ++#define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) ++#define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344)) ++ ++/* 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 void ltq_pmu_enable(unsigned int module); ++extern void ltq_pmu_disable(unsigned int module); ++ ++static inline int ltq_is_ar9(void) ++{ ++ return (ltq_get_soc_type() == SOC_TYPE_AR9); ++} ++ ++static inline int ltq_is_vr9(void) ++{ ++ return (ltq_get_soc_type() == SOC_TYPE_VR9); ++} ++ ++#endif /* CONFIG_SOC_TYPE_XWAY */ ++#endif /* _LTQ_XWAY_H__ */ +--- /dev/null ++++ b/arch/mips/lantiq/Kconfig +@@ -0,0 +1,21 @@ ++if LANTIQ ++ ++config SOC_TYPE_XWAY ++ bool ++ default n ++ ++choice ++ prompt "SoC Type" ++ default SOC_XWAY ++ ++config SOC_AMAZON_SE ++ bool "Amazon SE" ++ select SOC_TYPE_XWAY ++ ++config SOC_XWAY ++ bool "XWAY" ++ select SOC_TYPE_XWAY ++ select HW_HAS_PCI ++endchoice ++ ++endif +--- a/arch/mips/lantiq/Makefile ++++ b/arch/mips/lantiq/Makefile +@@ -7,3 +7,5 @@ + obj-y := irq.o setup.o clk.o prom.o + + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o ++ ++obj-$(CONFIG_SOC_TYPE_XWAY) += xway/ +--- a/arch/mips/lantiq/Platform ++++ b/arch/mips/lantiq/Platform +@@ -5,3 +5,4 @@ + 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 +--- /dev/null ++++ b/arch/mips/lantiq/xway/Makefile +@@ -0,0 +1,4 @@ ++obj-y := pmu.o ebu.o reset.o gpio.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/clk-ase.c +@@ -0,0 +1,48 @@ ++/* ++ * 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/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> ++ ++/* 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); +--- /dev/null ++++ b/arch/mips/lantiq/xway/clk-xway.c +@@ -0,0 +1,223 @@ ++/* ++ * 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> ++ ++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); +--- /dev/null ++++ b/arch/mips/lantiq/xway/ebu.c +@@ -0,0 +1,53 @@ ++/* ++ * 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. ++ * ++ * EBU - the external bus unit attaches PCI, NOR and NAND ++ * ++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/ioport.h> ++ ++#include <lantiq_soc.h> ++ ++/* all access to the ebu must be locked */ ++DEFINE_SPINLOCK(ebu_lock); ++EXPORT_SYMBOL_GPL(ebu_lock); ++ ++static struct resource ltq_ebu_resource = { ++ .name = "ebu", ++ .start = LTQ_EBU_BASE_ADDR, ++ .end = LTQ_EBU_BASE_ADDR + LTQ_EBU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++/* remapped base addr of the clock unit and external bus unit */ ++void __iomem *ltq_ebu_membase; ++ ++static int __init lantiq_ebu_init(void) ++{ ++ /* insert and request the memory region */ ++ if (insert_resource(&iomem_resource, <q_ebu_resource) < 0) ++ panic("Failed to insert ebu memory\n"); ++ ++ if (request_mem_region(ltq_ebu_resource.start, ++ resource_size(<q_ebu_resource), "ebu") < 0) ++ panic("Failed to request ebu memory\n"); ++ ++ /* remap ebu register range */ ++ ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start, ++ resource_size(<q_ebu_resource)); ++ if (!ltq_ebu_membase) ++ panic("Failed to remap ebu memory\n"); ++ ++ /* 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); ++ return 0; ++} ++ ++postcore_initcall(lantiq_ebu_init); +--- /dev/null ++++ b/arch/mips/lantiq/xway/gpio.c +@@ -0,0 +1,195 @@ ++/* ++ * 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/slab.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/gpio.h> ++#include <linux/ioport.h> ++#include <linux/io.h> ++ ++#include <lantiq_soc.h> ++ ++#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 PINS_PER_PORT 16 ++#define MAX_PORTS 3 ++ ++#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) ++#define ltq_gpio_clearbit(m, r, p) ltq_w32_mask((1 << p), 0, m + r) ++ ++struct ltq_gpio { ++ void __iomem *membase; ++ struct gpio_chip chip; ++}; ++ ++static struct ltq_gpio ltq_gpio_port[MAX_PORTS]; ++ ++int gpio_to_irq(unsigned int gpio) ++{ ++ return -EINVAL; ++} ++EXPORT_SYMBOL(gpio_to_irq); ++ ++int irq_to_gpio(unsigned int gpio) ++{ ++ return -EINVAL; ++} ++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 id = 0; ++ ++ if (pin >= (MAX_PORTS * PINS_PER_PORT)) ++ return -EINVAL; ++ if (gpio_request(pin, name)) { ++ pr_err("failed to setup lantiq gpio: %s\n", name); ++ return -EBUSY; ++ } ++ if (dir) ++ gpio_direction_output(pin, 1); ++ else ++ gpio_direction_input(pin); ++ while (pin >= PINS_PER_PORT) { ++ pin -= PINS_PER_PORT; ++ id++; ++ } ++ if (alt0) ++ 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) ++ 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); ++ return 0; ++} ++EXPORT_SYMBOL(ltq_gpio_request); ++ ++static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) ++{ ++ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); ++ ++ if (value) ++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset); ++ else ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset); ++} ++ ++static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset) ++{ ++ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); ++ ++ return ltq_gpio_getbit(ltq_gpio->membase, LTQ_GPIO_IN, offset); ++} ++ ++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); ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); ++ ++ return 0; ++} ++ ++static int ltq_gpio_direction_output(struct gpio_chip *chip, ++ unsigned int offset, int value) ++{ ++ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip); ++ ++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset); ++ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset); ++ ltq_gpio_set(chip, offset, value); ++ ++ return 0; ++} ++ ++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); ++ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset); ++ return 0; ++} ++ ++static int ltq_gpio_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ ++ if (pdev->id >= MAX_PORTS) { ++ dev_err(&pdev->dev, "invalid gpio port %d\n", ++ pdev->id); ++ return -EINVAL; ++ } ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get memory for gpio port %d\n", ++ pdev->id); ++ return -ENOENT; ++ } ++ 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 memory for gpio port %d\n", ++ pdev->id); ++ return -EBUSY; ++ } ++ ltq_gpio_port[pdev->id].membase = devm_ioremap_nocache(&pdev->dev, ++ res->start, resource_size(res)); ++ if (!ltq_gpio_port[pdev->id].membase) { ++ dev_err(&pdev->dev, "failed to remap memory for gpio port %d\n", ++ pdev->id); ++ return -ENOMEM; ++ } ++ ltq_gpio_port[pdev->id].chip.label = "ltq_gpio"; ++ ltq_gpio_port[pdev->id].chip.direction_input = ltq_gpio_direction_input; ++ ltq_gpio_port[pdev->id].chip.direction_output = ++ ltq_gpio_direction_output; ++ ltq_gpio_port[pdev->id].chip.get = ltq_gpio_get; ++ 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; ++ ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT; ++ platform_set_drvdata(pdev, <q_gpio_port[pdev->id]); ++ return gpiochip_add(<q_gpio_port[pdev->id].chip); ++} ++ ++static struct platform_driver ++ltq_gpio_driver = { ++ .probe = ltq_gpio_probe, ++ .driver = { ++ .name = "ltq_gpio", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init ltq_gpio_init(void) ++{ ++ int ret = platform_driver_register(<q_gpio_driver); ++ ++ if (ret) ++ pr_info("ltq_gpio : Error registering platfom driver!"); ++ return ret; ++} ++ ++postcore_initcall(ltq_gpio_init); +--- /dev/null ++++ b/arch/mips/lantiq/xway/pmu.c +@@ -0,0 +1,70 @@ ++/* ++ * 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/kernel.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/ioport.h> ++ ++#include <lantiq_soc.h> ++ ++/* PMU - the power management unit allows us to turn part of the core ++ * on and off ++ */ ++ ++/* the enable / disable registers */ ++#define LTQ_PMU_PWDCR 0x1C ++#define LTQ_PMU_PWDSR 0x20 ++ ++#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y)) ++#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x)) ++ ++static struct resource ltq_pmu_resource = { ++ .name = "pmu", ++ .start = LTQ_PMU_BASE_ADDR, ++ .end = LTQ_PMU_BASE_ADDR + LTQ_PMU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static void __iomem *ltq_pmu_membase; ++ ++void ltq_pmu_enable(unsigned int module) ++{ ++ 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)); ++ ++ if (!err) ++ panic("activating PMU module failed!\n"); ++} ++EXPORT_SYMBOL(ltq_pmu_enable); ++ ++void ltq_pmu_disable(unsigned int module) ++{ ++ ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR); ++} ++EXPORT_SYMBOL(ltq_pmu_disable); ++ ++int __init ltq_pmu_init(void) ++{ ++ if (insert_resource(&iomem_resource, <q_pmu_resource) < 0) ++ panic("Failed to insert pmu memory\n"); ++ ++ if (request_mem_region(ltq_pmu_resource.start, ++ resource_size(<q_pmu_resource), "pmu") < 0) ++ panic("Failed to request pmu memory\n"); ++ ++ ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start, ++ resource_size(<q_pmu_resource)); ++ if (!ltq_pmu_membase) ++ panic("Failed to remap pmu memory\n"); ++ return 0; ++} ++ ++core_initcall(ltq_pmu_init); +--- /dev/null ++++ b/arch/mips/lantiq/xway/prom-ase.c +@@ -0,0 +1,39 @@ ++/* ++ * 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 "../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; ++ switch (i->partnum) { ++ case SOC_ID_AMAZON_SE: ++ i->name = SOC_AMAZON_SE; ++ i->type = SOC_TYPE_AMAZON_SE; ++ break; ++ ++ default: ++ unreachable(); ++ break; ++ } ++} +--- /dev/null ++++ b/arch/mips/lantiq/xway/prom-xway.c +@@ -0,0 +1,54 @@ ++/* ++ * 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 "../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; ++ 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; ++ } ++} +--- /dev/null ++++ b/arch/mips/lantiq/xway/reset.c +@@ -0,0 +1,91 @@ ++/* ++ * 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/io.h> ++#include <linux/ioport.h> ++#include <linux/pm.h> ++#include <linux/module.h> ++#include <asm/reboot.h> ++ ++#include <lantiq_soc.h> ++ ++#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 ++ ++static struct resource ltq_rcu_resource = { ++ .name = "rcu", ++ .start = LTQ_RCU_BASE_ADDR, ++ .end = LTQ_RCU_BASE_ADDR + LTQ_RCU_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++/* remapped base addr of the reset control unit */ ++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; ++} ++EXPORT_SYMBOL_GPL(ltq_reset_cause); ++ ++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); ++ unreachable(); ++} ++ ++static void ltq_machine_halt(void) ++{ ++ pr_notice("System halted.\n"); ++ local_irq_disable(); ++ unreachable(); ++} ++ ++static void ltq_machine_power_off(void) ++{ ++ pr_notice("Please turn off the power now.\n"); ++ local_irq_disable(); ++ unreachable(); ++} ++ ++static int __init mips_reboot_setup(void) ++{ ++ /* insert and request the memory region */ ++ if (insert_resource(&iomem_resource, <q_rcu_resource) < 0) ++ panic("Failed to insert rcu memory\n"); ++ ++ if (request_mem_region(ltq_rcu_resource.start, ++ resource_size(<q_rcu_resource), "rcu") < 0) ++ panic("Failed to request rcu memory\n"); ++ ++ /* remap rcu register range */ ++ ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start, ++ resource_size(<q_rcu_resource)); ++ if (!ltq_rcu_membase) ++ panic("Failed to remap rcu memory\n"); ++ ++ _machine_restart = ltq_machine_restart; ++ _machine_halt = ltq_machine_halt; ++ pm_power_off = ltq_machine_power_off; ++ ++ return 0; ++} ++ ++arch_initcall(mips_reboot_setup); diff --git a/target/linux/lantiq/patches-2.6.39/0003-MIPS-Lantiq-Add-PCI-controller-support.patch b/target/linux/lantiq/patches-2.6.39/0003-MIPS-Lantiq-Add-PCI-controller-support.patch new file mode 100644 index 0000000..1757266 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0003-MIPS-Lantiq-Add-PCI-controller-support.patch @@ -0,0 +1,546 @@ +From 08127ed36bad367903591bbf0f244179683ccb28 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:49 +0200 +Subject: [PATCH 03/13] MIPS: Lantiq: Add PCI controller support. + +The Lantiq family of SoCs have a EBU (External Bus Unit). This patch adds +the driver that allows us to use the EBU as a PCI controller. In order for +PCI to work the EBU is set to endianess swap all the data. In addition we +need to make use of SWAP_IO_SPACE for device->host DMA to work. + +The clock of the PCI works in several modes (internal/external). If this +is not configured correctly the SoC will hang. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2250/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + .../mips/include/asm/mach-lantiq/lantiq_platform.h | 46 +++ + arch/mips/pci/Makefile | 1 + + arch/mips/pci/ops-lantiq.c | 116 ++++++++ + arch/mips/pci/pci-lantiq.c | 297 ++++++++++++++++++++ + arch/mips/pci/pci-lantiq.h | 18 ++ + 5 files changed, 478 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_platform.h + create mode 100644 arch/mips/pci/ops-lantiq.c + create mode 100644 arch/mips/pci/pci-lantiq.c + create mode 100644 arch/mips/pci/pci-lantiq.h + +diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +new file mode 100644 +index 0000000..1f1dba6 +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +@@ -0,0 +1,46 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LANTIQ_PLATFORM_H__ ++#define _LANTIQ_PLATFORM_H__ ++ ++#include <linux/mtd/partitions.h> ++ ++/* struct used to pass info to the pci core */ ++enum { ++ PCI_CLOCK_INT = 0, ++ PCI_CLOCK_EXT ++}; ++ ++#define PCI_EXIN0 0x0001 ++#define PCI_EXIN1 0x0002 ++#define PCI_EXIN2 0x0004 ++#define PCI_EXIN3 0x0008 ++#define PCI_EXIN4 0x0010 ++#define PCI_EXIN5 0x0020 ++#define PCI_EXIN_MAX 6 ++ ++#define PCI_GNT1 0x0040 ++#define PCI_GNT2 0x0080 ++#define PCI_GNT3 0x0100 ++#define PCI_GNT4 0x0200 ++ ++#define PCI_REQ1 0x0400 ++#define PCI_REQ2 0x0800 ++#define PCI_REQ3 0x1000 ++#define PCI_REQ4 0x2000 ++#define PCI_REQ_SHIFT 10 ++#define PCI_REQ_MASK 0xf ++ ++struct ltq_pci_data { ++ int clock; ++ int gpio; ++ int irq[16]; ++}; ++ ++#endif +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index f0d5329..4df8799 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -41,6 +41,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_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/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c +new file mode 100644 +index 0000000..1f2afb5 +--- /dev/null ++++ b/arch/mips/pci/ops-lantiq.c +@@ -0,0 +1,116 @@ ++/* ++ * 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/types.h> ++#include <linux/pci.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/mm.h> ++#include <asm/addrspace.h> ++#include <linux/vmalloc.h> ++ ++#include <lantiq_soc.h> ++ ++#include "pci-lantiq.h" ++ ++#define LTQ_PCI_CFG_BUSNUM_SHF 16 ++#define LTQ_PCI_CFG_DEVNUM_SHF 11 ++#define LTQ_PCI_CFG_FUNNUM_SHF 8 ++ ++#define PCI_ACCESS_READ 0 ++#define PCI_ACCESS_WRITE 1 ++ ++static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus, ++ unsigned int devfn, unsigned int where, u32 *data) ++{ ++ unsigned long cfg_base; ++ unsigned long flags; ++ u32 temp; ++ ++ /* we support slot from 0 to 15 dev_fn & 0x68 (AD29) is the ++ SoC itself */ ++ if ((bus->number != 0) || ((devfn & 0xf8) > 0x78) ++ || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68)) ++ return 1; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ ++ cfg_base = (unsigned long) ltq_pci_mapped_cfg; ++ cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn << ++ LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3); ++ ++ /* Perform access */ ++ if (access_type == PCI_ACCESS_WRITE) { ++ ltq_w32(swab32(*data), ((u32 *)cfg_base)); ++ } else { ++ *data = ltq_r32(((u32 *)(cfg_base))); ++ *data = swab32(*data); ++ } ++ wmb(); ++ ++ /* clean possible Master abort */ ++ cfg_base = (unsigned long) ltq_pci_mapped_cfg; ++ 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 |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4; ++ ltq_w32(temp, ((u32 *)cfg_base)); ++ ++ spin_unlock_irqrestore(&ebu_lock, flags); ++ ++ if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ)) ++ return 1; ++ ++ return 0; ++} ++ ++int ltq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 *val) ++{ ++ u32 data = 0; ++ ++ if (ltq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ if (size == 1) ++ *val = (data >> ((where & 3) << 3)) & 0xff; ++ else if (size == 2) ++ *val = (data >> ((where & 3) << 3)) & 0xffff; ++ else ++ *val = data; ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++int ltq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 val) ++{ ++ u32 data = 0; ++ ++ if (size == 4) { ++ data = val; ++ } else { ++ if (ltq_pci_config_access(PCI_ACCESS_READ, bus, ++ devfn, where, &data)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ if (size == 1) ++ data = (data & ~(0xff << ((where & 3) << 3))) | ++ (val << ((where & 3) << 3)); ++ else if (size == 2) ++ data = (data & ~(0xffff << ((where & 3) << 3))) | ++ (val << ((where & 3) << 3)); ++ } ++ ++ if (ltq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ return PCIBIOS_SUCCESSFUL; ++} +diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c +new file mode 100644 +index 0000000..603d749 +--- /dev/null ++++ b/arch/mips/pci/pci-lantiq.c +@@ -0,0 +1,297 @@ ++/* ++ * 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/types.h> ++#include <linux/pci.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/mm.h> ++#include <linux/vmalloc.h> ++#include <linux/platform_device.h> ++ ++#include <asm/pci.h> ++#include <asm/gpio.h> ++#include <asm/addrspace.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_irq.h> ++#include <lantiq_platform.h> ++ ++#include "pci-lantiq.h" ++ ++#define LTQ_PCI_CFG_BASE 0x17000000 ++#define LTQ_PCI_CFG_SIZE 0x00008000 ++#define LTQ_PCI_MEM_BASE 0x18000000 ++#define LTQ_PCI_MEM_SIZE 0x02000000 ++#define LTQ_PCI_IO_BASE 0x1AE00000 ++#define LTQ_PCI_IO_SIZE 0x00200000 ++ ++#define PCI_CR_FCI_ADDR_MAP0 0x00C0 ++#define PCI_CR_FCI_ADDR_MAP1 0x00C4 ++#define PCI_CR_FCI_ADDR_MAP2 0x00C8 ++#define PCI_CR_FCI_ADDR_MAP3 0x00CC ++#define PCI_CR_FCI_ADDR_MAP4 0x00D0 ++#define PCI_CR_FCI_ADDR_MAP5 0x00D4 ++#define PCI_CR_FCI_ADDR_MAP6 0x00D8 ++#define PCI_CR_FCI_ADDR_MAP7 0x00DC ++#define PCI_CR_CLK_CTRL 0x0000 ++#define PCI_CR_PCI_MOD 0x0030 ++#define PCI_CR_PC_ARB 0x0080 ++#define PCI_CR_FCI_ADDR_MAP11hg 0x00E4 ++#define PCI_CR_BAR11MASK 0x0044 ++#define PCI_CR_BAR12MASK 0x0048 ++#define PCI_CR_BAR13MASK 0x004C ++#define PCI_CS_BASE_ADDR1 0x0010 ++#define PCI_CR_PCI_ADDR_MAP11 0x0064 ++#define PCI_CR_FCI_BURST_LENGTH 0x00E8 ++#define PCI_CR_PCI_EOI 0x002C ++#define PCI_CS_STS_CMD 0x0004 ++ ++#define PCI_MASTER0_REQ_MASK_2BITS 8 ++#define PCI_MASTER1_REQ_MASK_2BITS 10 ++#define PCI_MASTER2_REQ_MASK_2BITS 12 ++#define INTERNAL_ARB_ENABLE_BIT 0 ++ ++#define LTQ_CGU_IFCCR 0x0018 ++#define LTQ_CGU_PCICR 0x0034 ++ ++#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)) ++ ++struct ltq_pci_gpio_map { ++ int pin; ++ int alt0; ++ int alt1; ++ 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" }, ++}; ++ ++__iomem void *ltq_pci_mapped_cfg; ++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; ++ ++struct pci_ops ltq_pci_ops = { ++ .read = ltq_pci_read_config_dword, ++ .write = ltq_pci_write_config_dword ++}; ++ ++static struct resource pci_io_resource = { ++ .name = "pci io space", ++ .start = LTQ_PCI_IO_BASE, ++ .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1, ++ .flags = IORESOURCE_IO ++}; ++ ++static struct resource pci_mem_resource = { ++ .name = "pci memory space", ++ .start = LTQ_PCI_MEM_BASE, ++ .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1, ++ .flags = IORESOURCE_MEM ++}; ++ ++static struct pci_controller ltq_pci_controller = { ++ .pci_ops = <q_pci_ops, ++ .mem_resource = &pci_mem_resource, ++ .mem_offset = 0x00000000UL, ++ .io_resource = &pci_io_resource, ++ .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; ++ ++ /* BAR11MASK value depends on available memory on system. */ ++ mem = num_physpages * PAGE_SIZE; ++ bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8; ++ ++ return bar11mask; ++} ++ ++static void ltq_pci_setup_gpio(int gpio) ++{ ++ 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, ++ ltq_pci_gpio_map[i].alt0, ++ ltq_pci_gpio_map[i].alt1, ++ ltq_pci_gpio_map[i].dir, ++ ltq_pci_gpio_map[i].name); ++ } ++ } ++ ltq_gpio_request(21, 0, 0, 1, "pci-reset"); ++ ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK; ++} ++ ++static int __devinit ltq_pci_startup(struct ltq_pci_data *conf) ++{ ++ u32 temp_buffer; ++ ++ /* set clock to 33Mhz */ ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR); ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR); ++ ++ /* external or internal clock ? */ ++ if (conf->clock) { ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16), ++ LTQ_CGU_IFCCR); ++ ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR); ++ } else { ++ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16), ++ LTQ_CGU_IFCCR); ++ ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR); ++ } ++ ++ /* setup pci clock and gpis used by pci */ ++ ltq_pci_setup_gpio(conf->gpio); ++ ++ /* enable auto-switching between PCI and EBU */ ++ ltq_pci_w32(0xa, PCI_CR_CLK_CTRL); ++ ++ /* busy, i.e. configuration is not done, PCI access has to be retried */ ++ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD); ++ wmb(); ++ /* BUS Master/IO/MEM access */ ++ ltq_pci_cfg_w32(ltq_pci_cfg_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD); ++ ++ /* enable external 2 PCI masters */ ++ temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB); ++ temp_buffer &= (~(ltq_pci_req_mask << 16)); ++ /* enable internal arbiter */ ++ temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT); ++ /* enable internal PCI master reqest */ ++ temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS)); ++ ++ /* enable EBU request */ ++ temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS)); ++ ++ /* enable all external masters request */ ++ temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS)); ++ ltq_pci_w32(temp_buffer, PCI_CR_PC_ARB); ++ wmb(); ++ ++ /* setup BAR memory regions */ ++ ltq_pci_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0); ++ ltq_pci_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1); ++ ltq_pci_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2); ++ ltq_pci_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3); ++ ltq_pci_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4); ++ ltq_pci_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5); ++ ltq_pci_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6); ++ ltq_pci_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7); ++ ltq_pci_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg); ++ ltq_pci_w32(ltq_calc_bar11mask(), PCI_CR_BAR11MASK); ++ ltq_pci_w32(0, PCI_CR_PCI_ADDR_MAP11); ++ ltq_pci_w32(0, PCI_CS_BASE_ADDR1); ++ /* both TX and RX endian swap are enabled */ ++ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI); ++ wmb(); ++ ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR12MASK) | 0x80000000, ++ PCI_CR_BAR12MASK); ++ ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR13MASK) | 0x80000000, ++ PCI_CR_BAR13MASK); ++ /*use 8 dw burst length */ ++ ltq_pci_w32(0x303, PCI_CR_FCI_BURST_LENGTH); ++ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD); ++ wmb(); ++ ++ /* setup irq line */ ++ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_CON) | 0xc, LTQ_EBU_PCC_CON); ++ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN); ++ ++ /* toggle reset pin */ ++ __gpio_set_value(21, 0); ++ wmb(); ++ mdelay(1); ++ __gpio_set_value(21, 1); ++ 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 "ltq_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 = ++ (struct ltq_pci_data *) pdev->dev.platform_data; ++ 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 = ++ 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); ++ register_pci_controller(<q_pci_controller); ++ ++ return 0; ++} ++ ++static struct platform_driver ++ltq_pci_driver = { ++ .probe = ltq_pci_probe, ++ .driver = { ++ .name = "ltq_pci", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init pcibios_init(void) ++{ ++ int ret = platform_driver_register(<q_pci_driver); ++ if (ret) ++ printk(KERN_INFO "ltq_pci: Error registering platfom driver!"); ++ return ret; ++} ++ ++arch_initcall(pcibios_init); +diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h +new file mode 100644 +index 0000000..66bf6cd +--- /dev/null ++++ b/arch/mips/pci/pci-lantiq.h +@@ -0,0 +1,18 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_PCI_H__ ++#define _LTQ_PCI_H__ ++ ++extern __iomem void *ltq_pci_mapped_cfg; ++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, ++ unsigned int devfn, int where, int size, u32 val); ++ ++#endif +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches-2.6.39/0004-MIPS-Lantiq-Add-NOR-flash-support.patch b/target/linux/lantiq/patches-2.6.39/0004-MIPS-Lantiq-Add-NOR-flash-support.patch new file mode 100644 index 0000000..80efc1f --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0004-MIPS-Lantiq-Add-NOR-flash-support.patch @@ -0,0 +1,301 @@ +From cd0d53b24ca744295d2cdf69bb2b659571091b75 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 12 Apr 2011 18:10:01 +0200 +Subject: [PATCH 04/13] MIPS: Lantiq: Add NOR flash support + +This patch adds the driver/map for NOR devices attached to the SoC via the +External Bus Unit (EBU). + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: David Woodhouse <dwmw2@infradead.org> +Cc: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +Cc: linux-mips@linux-mips.org +Cc: linux-mtd@lists.infradead.org +Acked-by: Artem Bityutskiy <dedekind1@gmail.com> +Patchwork: https://patchwork.linux-mips.org/patch/2285/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + drivers/mtd/maps/Kconfig | 7 + + drivers/mtd/maps/Makefile | 1 + + drivers/mtd/maps/lantiq-flash.c | 251 +++++++++++++++++++++++++++++++++++++++ + 3 files changed, 259 insertions(+), 0 deletions(-) + create mode 100644 drivers/mtd/maps/lantiq-flash.c + +--- a/drivers/mtd/maps/Kconfig ++++ b/drivers/mtd/maps/Kconfig +@@ -260,6 +260,13 @@ + Support for parsing CFE image tag and creating MTD partitions on + Broadcom BCM63xx boards. + ++config MTD_LANTIQ ++ tristate "Lantiq SoC NOR support" ++ depends on LANTIQ ++ select MTD_PARTITIONS ++ help ++ Support for NOR flash attached to the Lantiq SoC's External Bus Unit. ++ + config MTD_DILNETPC + tristate "CFI Flash device mapped on DIL/Net PC" + depends on X86 && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN +--- a/drivers/mtd/maps/Makefile ++++ b/drivers/mtd/maps/Makefile +@@ -60,3 +60,4 @@ + obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o + obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o + obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o ++obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o +--- /dev/null ++++ b/drivers/mtd/maps/lantiq-flash.c +@@ -0,0 +1,251 @@ ++/* ++ * 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) 2004 Liu Peng Infineon IFAP DC COM CPE ++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/io.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++#include <linux/mtd/cfi.h> ++#include <linux/platform_device.h> ++#include <linux/mtd/physmap.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_platform.h> ++ ++/* ++ * The NOR flash is connected to the same external bus unit (EBU) as PCI. ++ * To make PCI work we need to enable the endianness swapping for the address ++ * written to the EBU. This endianness swapping works for PCI correctly but ++ * fails for attached NOR devices. To workaround this we need to use a complex ++ * map. The workaround involves swapping all addresses whilst probing the chip. ++ * Once probing is complete we stop swapping the addresses but swizzle the ++ * unlock addresses to ensure that access to the NOR device works correctly. ++ */ ++ ++enum { ++ LTQ_NOR_PROBING, ++ LTQ_NOR_NORMAL ++}; ++ ++struct ltq_mtd { ++ struct resource *res; ++ struct mtd_info *mtd; ++ struct map_info *map; ++}; ++ ++static char ltq_map_name[] = "ltq_nor"; ++ ++static map_word ++ltq_read16(struct map_info *map, unsigned long adr) ++{ ++ unsigned long flags; ++ map_word temp; ++ ++ if (map->map_priv_1 == LTQ_NOR_PROBING) ++ adr ^= 2; ++ spin_lock_irqsave(&ebu_lock, flags); ++ temp.x[0] = *(u16 *)(map->virt + adr); ++ spin_unlock_irqrestore(&ebu_lock, flags); ++ return temp; ++} ++ ++static void ++ltq_write16(struct map_info *map, map_word d, unsigned long adr) ++{ ++ unsigned long flags; ++ ++ if (map->map_priv_1 == LTQ_NOR_PROBING) ++ adr ^= 2; ++ spin_lock_irqsave(&ebu_lock, flags); ++ *(u16 *)(map->virt + adr) = d.x[0]; ++ spin_unlock_irqrestore(&ebu_lock, flags); ++} ++ ++/* ++ * The following 2 functions copy data between iomem and a cached memory ++ * section. As memcpy() makes use of pre-fetching we cannot use it here. ++ * The normal alternative of using memcpy_{to,from}io also makes use of ++ * memcpy() on MIPS so it is not applicable either. We are therefore stuck ++ * with having to use our own loop. ++ */ ++static void ++ltq_copy_from(struct map_info *map, void *to, ++ unsigned long from, ssize_t len) ++{ ++ unsigned char *f = (unsigned char *)map->virt + from; ++ unsigned char *t = (unsigned char *)to; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ while (len--) ++ *t++ = *f++; ++ spin_unlock_irqrestore(&ebu_lock, flags); ++} ++ ++static void ++ltq_copy_to(struct map_info *map, unsigned long to, ++ const void *from, ssize_t len) ++{ ++ unsigned char *f = (unsigned char *)from; ++ unsigned char *t = (unsigned char *)map->virt + to; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ while (len--) ++ *t++ = *f++; ++ spin_unlock_irqrestore(&ebu_lock, flags); ++} ++ ++static const char const *part_probe_types[] = { "cmdlinepart", NULL }; ++ ++static int __init ++ltq_mtd_probe(struct platform_device *pdev) ++{ ++ struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev); ++ struct ltq_mtd *ltq_mtd; ++ struct mtd_partition *parts; ++ struct resource *res; ++ int nr_parts = 0; ++ struct cfi_private *cfi; ++ int err; ++ ++ ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL); ++ platform_set_drvdata(pdev, ltq_mtd); ++ ++ ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!ltq_mtd->res) { ++ dev_err(&pdev->dev, "failed to get memory resource"); ++ err = -ENOENT; ++ goto err_out; ++ } ++ ++ res = devm_request_mem_region(&pdev->dev, ltq_mtd->res->start, ++ resource_size(ltq_mtd->res), dev_name(&pdev->dev)); ++ if (!ltq_mtd->res) { ++ dev_err(&pdev->dev, "failed to request mem resource"); ++ err = -EBUSY; ++ goto err_out; ++ } ++ ++ ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL); ++ ltq_mtd->map->phys = res->start; ++ ltq_mtd->map->size = resource_size(res); ++ ltq_mtd->map->virt = devm_ioremap_nocache(&pdev->dev, ++ ltq_mtd->map->phys, ltq_mtd->map->size); ++ if (!ltq_mtd->map->virt) { ++ dev_err(&pdev->dev, "failed to ioremap!\n"); ++ err = -ENOMEM; ++ goto err_free; ++ } ++ ++ ltq_mtd->map->name = ltq_map_name; ++ ltq_mtd->map->bankwidth = 2; ++ ltq_mtd->map->read = ltq_read16; ++ ltq_mtd->map->write = ltq_write16; ++ ltq_mtd->map->copy_from = ltq_copy_from; ++ ltq_mtd->map->copy_to = ltq_copy_to; ++ ++ ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING; ++ ltq_mtd->mtd = do_map_probe("cfi_probe", ltq_mtd->map); ++ ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL; ++ ++ if (!ltq_mtd->mtd) { ++ dev_err(&pdev->dev, "probing failed\n"); ++ err = -ENXIO; ++ goto err_unmap; ++ } ++ ++ ltq_mtd->mtd->owner = THIS_MODULE; ++ ++ cfi = ltq_mtd->map->fldrv_priv; ++ cfi->addr_unlock1 ^= 1; ++ cfi->addr_unlock2 ^= 1; ++ ++ nr_parts = parse_mtd_partitions(ltq_mtd->mtd, ++ part_probe_types, &parts, 0); ++ if (nr_parts > 0) { ++ dev_info(&pdev->dev, ++ "using %d partitions from cmdline", nr_parts); ++ } else { ++ nr_parts = ltq_mtd_data->nr_parts; ++ parts = ltq_mtd_data->parts; ++ } ++ ++ err = add_mtd_partitions(ltq_mtd->mtd, parts, nr_parts); ++ if (err) { ++ dev_err(&pdev->dev, "failed to add partitions\n"); ++ goto err_destroy; ++ } ++ ++ return 0; ++ ++err_destroy: ++ map_destroy(ltq_mtd->mtd); ++err_unmap: ++ iounmap(ltq_mtd->map->virt); ++err_free: ++ kfree(ltq_mtd->map); ++err_out: ++ kfree(ltq_mtd); ++ return err; ++} ++ ++static int __devexit ++ltq_mtd_remove(struct platform_device *pdev) ++{ ++ struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev); ++ ++ if (ltq_mtd) { ++ if (ltq_mtd->mtd) { ++ del_mtd_partitions(ltq_mtd->mtd); ++ map_destroy(ltq_mtd->mtd); ++ } ++ if (ltq_mtd->map->virt) ++ iounmap(ltq_mtd->map->virt); ++ kfree(ltq_mtd->map); ++ kfree(ltq_mtd); ++ } ++ return 0; ++} ++ ++static struct platform_driver ltq_mtd_driver = { ++ .remove = __devexit_p(ltq_mtd_remove), ++ .driver = { ++ .name = "ltq_nor", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++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_LICENSE("GPL"); ++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); ++MODULE_DESCRIPTION("Lantiq SoC NOR"); diff --git a/target/linux/lantiq/patches-2.6.39/0005-MIPS-Lantiq-Add-platform-device-support.patch b/target/linux/lantiq/patches-2.6.39/0005-MIPS-Lantiq-Add-platform-device-support.patch new file mode 100644 index 0000000..917993f --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0005-MIPS-Lantiq-Add-platform-device-support.patch @@ -0,0 +1,338 @@ +From 09e57348261c1ae0ff89c68679126fc76a28b2a2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:53 +0200 +Subject: [PATCH 05/13] MIPS: Lantiq: Add platform device support + +This patch adds the wrappers for registering our platform devices. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2254/ +Patchwork: https://patchwork.linux-mips.org/patch/2360/ +Patchwork: https://patchwork.linux-mips.org/patch/2359/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/lantiq/Makefile | 2 +- + arch/mips/lantiq/devices.c | 122 +++++++++++++++++++++++++++++++++++++++ + arch/mips/lantiq/devices.h | 23 +++++++ + arch/mips/lantiq/xway/Makefile | 2 +- + arch/mips/lantiq/xway/devices.c | 98 +++++++++++++++++++++++++++++++ + arch/mips/lantiq/xway/devices.h | 18 ++++++ + 6 files changed, 263 insertions(+), 2 deletions(-) + create mode 100644 arch/mips/lantiq/devices.c + create mode 100644 arch/mips/lantiq/devices.h + create mode 100644 arch/mips/lantiq/xway/devices.c + create mode 100644 arch/mips/lantiq/xway/devices.h + +diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile +index a268391..e5dae0e 100644 +--- a/arch/mips/lantiq/Makefile ++++ b/arch/mips/lantiq/Makefile +@@ -4,7 +4,7 @@ + # under the terms of the GNU General Public License version 2 as published + # by the Free Software Foundation. + +-obj-y := irq.o setup.o clk.o prom.o ++obj-y := irq.o setup.o clk.o prom.o devices.o + + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + +diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c +new file mode 100644 +index 0000000..7b82c34 +--- /dev/null ++++ b/arch/mips/lantiq/devices.c +@@ -0,0 +1,122 @@ ++/* ++ * 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/module.h> ++#include <linux/types.h> ++#include <linux/string.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 "devices.h" ++ ++/* nor flash */ ++static struct resource ltq_nor_resource = { ++ .name = "nor", ++ .start = LTQ_FLASH_START, ++ .end = LTQ_FLASH_START + LTQ_FLASH_MAX - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static struct platform_device ltq_nor = { ++ .name = "ltq_nor", ++ .resource = <q_nor_resource, ++ .num_resources = 1, ++}; ++ ++void __init ltq_register_nor(struct physmap_flash_data *data) ++{ ++ ltq_nor.dev.platform_data = data; ++ platform_device_register(<q_nor); ++} ++ ++/* watchdog */ ++static struct resource ltq_wdt_resource = { ++ .name = "watchdog", ++ .start = LTQ_WDT_BASE_ADDR, ++ .end = LTQ_WDT_BASE_ADDR + LTQ_WDT_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++void __init ltq_register_wdt(void) ++{ ++ platform_device_register_simple("ltq_wdt", 0, <q_wdt_resource, 1); ++} ++ ++/* asc ports */ ++static struct resource ltq_asc0_resources[] = { ++ { ++ .name = "asc0", ++ .start = LTQ_ASC0_BASE_ADDR, ++ .end = LTQ_ASC0_BASE_ADDR + LTQ_ASC_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ IRQ_RES(tx, LTQ_ASC_TIR(0)), ++ IRQ_RES(rx, LTQ_ASC_RIR(0)), ++ IRQ_RES(err, LTQ_ASC_EIR(0)), ++}; ++ ++static struct resource ltq_asc1_resources[] = { ++ { ++ .name = "asc1", ++ .start = LTQ_ASC1_BASE_ADDR, ++ .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ IRQ_RES(tx, LTQ_ASC_TIR(1)), ++ IRQ_RES(rx, LTQ_ASC_RIR(1)), ++ IRQ_RES(err, LTQ_ASC_EIR(1)), ++}; ++ ++void __init ltq_register_asc(int port) ++{ ++ switch (port) { ++ case 0: ++ platform_device_register_simple("ltq_asc", 0, ++ ltq_asc0_resources, ARRAY_SIZE(ltq_asc0_resources)); ++ break; ++ case 1: ++ platform_device_register_simple("ltq_asc", 1, ++ ltq_asc1_resources, ARRAY_SIZE(ltq_asc1_resources)); ++ break; ++ default: ++ break; ++ } ++} ++ ++#ifdef CONFIG_PCI ++/* pci */ ++static struct platform_device ltq_pci = { ++ .name = "ltq_pci", ++ .num_resources = 0, ++}; ++ ++void __init ltq_register_pci(struct ltq_pci_data *data) ++{ ++ ltq_pci.dev.platform_data = data; ++ platform_device_register(<q_pci); ++} ++#else ++void __init ltq_register_pci(struct ltq_pci_data *data) ++{ ++ pr_err("kernel is compiled without PCI support\n"); ++} ++#endif +diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h +new file mode 100644 +index 0000000..2947bb1 +--- /dev/null ++++ b/arch/mips/lantiq/devices.h +@@ -0,0 +1,23 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_DEVICES_H__ ++#define _LTQ_DEVICES_H__ ++ ++#include <lantiq_platform.h> ++#include <linux/mtd/physmap.h> ++ ++#define IRQ_RES(resname, irq) \ ++ {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ} ++ ++extern void ltq_register_nor(struct physmap_flash_data *data); ++extern void ltq_register_wdt(void); ++extern void ltq_register_asc(int port); ++extern void ltq_register_pci(struct ltq_pci_data *data); ++ ++#endif +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 9c85ff9..74ce438 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := pmu.o ebu.o reset.o gpio.o ++obj-y := pmu.o ebu.o reset.o gpio.o devices.o + + obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o + obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o +diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c +new file mode 100644 +index 0000000..a71b3b5 +--- /dev/null ++++ b/arch/mips/lantiq/xway/devices.c +@@ -0,0 +1,98 @@ ++/* ++ * 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/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> ++ ++#include "devices.h" ++ ++/* gpio */ ++static struct resource ltq_gpio_resource[] = { ++ { ++ .name = "gpio0", ++ .start = LTQ_GPIO0_BASE_ADDR, ++ .end = LTQ_GPIO0_BASE_ADDR + LTQ_GPIO_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .name = "gpio1", ++ .start = LTQ_GPIO1_BASE_ADDR, ++ .end = LTQ_GPIO1_BASE_ADDR + LTQ_GPIO_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, { ++ .name = "gpio2", ++ .start = LTQ_GPIO2_BASE_ADDR, ++ .end = LTQ_GPIO2_BASE_ADDR + LTQ_GPIO_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ } ++}; ++ ++void __init ltq_register_gpio(void) ++{ ++ platform_device_register_simple("ltq_gpio", 0, ++ <q_gpio_resource[0], 1); ++ platform_device_register_simple("ltq_gpio", 1, ++ <q_gpio_resource[1], 1); ++ ++ /* AR9 and VR9 have an extra gpio block */ ++ if (ltq_is_ar9() || ltq_is_vr9()) { ++ platform_device_register_simple("ltq_gpio", 2, ++ <q_gpio_resource[2], 1); ++ } ++} ++ ++/* serial to parallel conversion */ ++static struct resource ltq_stp_resource = { ++ .name = "stp", ++ .start = LTQ_STP_BASE_ADDR, ++ .end = LTQ_STP_BASE_ADDR + LTQ_STP_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++void __init ltq_register_gpio_stp(void) ++{ ++ platform_device_register_simple("ltq_stp", 0, <q_stp_resource, 1); ++} ++ ++/* asc ports - amazon se has its own serial mapping */ ++static struct resource ltq_ase_asc_resources[] = { ++ { ++ .name = "asc0", ++ .start = LTQ_ASC1_BASE_ADDR, ++ .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ IRQ_RES(tx, LTQ_ASC_ASE_TIR), ++ IRQ_RES(rx, LTQ_ASC_ASE_RIR), ++ IRQ_RES(err, LTQ_ASC_ASE_EIR), ++}; ++ ++void __init ltq_register_ase_asc(void) ++{ ++ platform_device_register_simple("ltq_asc", 0, ++ ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources)); ++} +diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h +new file mode 100644 +index 0000000..51f56b5 +--- /dev/null ++++ b/arch/mips/lantiq/xway/devices.h +@@ -0,0 +1,18 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_DEVICES_XWAY_H__ ++#define _LTQ_DEVICES_XWAY_H__ ++ ++#include "../devices.h" ++ ++extern void ltq_register_gpio(void); ++extern void ltq_register_gpio_stp(void); ++extern void ltq_register_ase_asc(void); ++ ++#endif +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches-2.6.39/0006-MIPS-Lantiq-Add-mips_machine-support.patch b/target/linux/lantiq/patches-2.6.39/0006-MIPS-Lantiq-Add-mips_machine-support.patch new file mode 100644 index 0000000..9e02b6a --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0006-MIPS-Lantiq-Add-mips_machine-support.patch @@ -0,0 +1,170 @@ +From 52a5369d1067d4feddbfa7ff4486a77ac9a2971e Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:54 +0200 +Subject: [PATCH 06/13] MIPS: Lantiq: Add mips_machine support + +This patch adds support for Gabor's mips_machine patch. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: Gabor Juhos <juhosg@openwrt.org> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2251/ +Patchwork: https://patchwork.linux-mips.org/patch/2358/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/Kconfig | 1 + + arch/mips/lantiq/machtypes.h | 18 ++++++++++++++++++ + arch/mips/lantiq/prom.h | 1 + + arch/mips/lantiq/setup.c | 25 +++++++++++++++++++++++++ + arch/mips/lantiq/xway/Makefile | 4 ++-- + arch/mips/lantiq/xway/setup-ase.c | 19 +++++++++++++++++++ + arch/mips/lantiq/xway/setup-xway.c | 20 ++++++++++++++++++++ + 7 files changed, 86 insertions(+), 2 deletions(-) + create mode 100644 arch/mips/lantiq/machtypes.h + create mode 100644 arch/mips/lantiq/xway/setup-ase.c + create mode 100644 arch/mips/lantiq/xway/setup-xway.c + +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -190,6 +190,7 @@ + select SWAP_IO_SPACE + select BOOT_RAW + select HAVE_CLK ++ select MIPS_MACHINE + + config LASAT + bool "LASAT Networks platforms" +--- /dev/null ++++ b/arch/mips/lantiq/machtypes.h +@@ -0,0 +1,18 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LANTIQ_MACH_H__ ++#define _LANTIQ_MACH_H__ ++ ++#include <asm/mips_machine.h> ++ ++enum lantiq_mach_type { ++ LTQ_MACH_GENERIC = 0, ++}; ++ ++#endif +--- a/arch/mips/lantiq/prom.h ++++ b/arch/mips/lantiq/prom.h +@@ -20,5 +20,6 @@ + }; + + extern void ltq_soc_detect(struct ltq_soc_info *i); ++extern void ltq_soc_setup(void); + + #endif +--- a/arch/mips/lantiq/setup.c ++++ b/arch/mips/lantiq/setup.c +@@ -14,6 +14,12 @@ + + #include <lantiq_soc.h> + ++#include "machtypes.h" ++#include "devices.h" ++#include "prom.h" ++ ++unsigned long physical_memsize = 0L; ++ + void __init plat_mem_setup(void) + { + /* assume 16M as default incase uboot fails to pass proper ramsize */ +@@ -32,10 +38,32 @@ + if (!strncmp(e, "memsize=", 8)) { + e += 8; + if (strict_strtoul(e, 0, &memsize)) +- pr_warn("bad memsize specified\n"); ++ pr_warning("bad memsize specified\n"); + } + envp++; + } + memsize *= 1024 * 1024; + add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); ++ physical_memsize = memsize; ++} ++ ++static int __init ++lantiq_setup(void) ++{ ++ ltq_soc_setup(); ++ mips_machine_setup(); ++ return 0; + } ++ ++arch_initcall(lantiq_setup); ++ ++static void __init ++lantiq_generic_init(void) ++{ ++ /* Nothing to do */ ++} ++ ++MIPS_MACHINE(LTQ_MACH_GENERIC, ++ "Generic", ++ "Generic Lantiq based board", ++ lantiq_generic_init); +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ + obj-y := pmu.o ebu.o reset.o gpio.o devices.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) += clk-xway.o prom-xway.o setup-xway.o ++obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o +--- /dev/null ++++ b/arch/mips/lantiq/xway/setup-ase.c +@@ -0,0 +1,19 @@ ++/* ++ * 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 <lantiq_soc.h> ++ ++#include "../prom.h" ++#include "devices.h" ++ ++void __init ltq_soc_setup(void) ++{ ++ ltq_register_ase_asc(); ++ ltq_register_gpio(); ++ ltq_register_wdt(); ++} +--- /dev/null ++++ b/arch/mips/lantiq/xway/setup-xway.c +@@ -0,0 +1,20 @@ ++/* ++ * 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 <lantiq_soc.h> ++ ++#include "../prom.h" ++#include "devices.h" ++ ++void __init ltq_soc_setup(void) ++{ ++ ltq_register_asc(0); ++ ltq_register_asc(1); ++ ltq_register_gpio(); ++ ltq_register_wdt(); ++} diff --git a/target/linux/lantiq/patches-2.6.39/0007-MIPS-Lantiq-Add-machtypes-for-lantiq-eval-kits.patch b/target/linux/lantiq/patches-2.6.39/0007-MIPS-Lantiq-Add-machtypes-for-lantiq-eval-kits.patch new file mode 100644 index 0000000..e69558c --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0007-MIPS-Lantiq-Add-machtypes-for-lantiq-eval-kits.patch @@ -0,0 +1,230 @@ +From ab2182fc419548455d03979683eb0e92c372ed79 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:55 +0200 +Subject: [PATCH 07/13] MIPS: Lantiq: Add machtypes for lantiq eval kits + +This patch adds mach specific code for the Lantiq EASY50712/50601 evaluation +boards + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2255/ +Patchwork: https://patchwork.linux-mips.org/patch/2361/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/lantiq/Kconfig | 2 + + arch/mips/lantiq/machtypes.h | 2 + + arch/mips/lantiq/xway/Kconfig | 23 +++++++++++ + arch/mips/lantiq/xway/Makefile | 3 + + arch/mips/lantiq/xway/mach-easy50601.c | 57 ++++++++++++++++++++++++++ + arch/mips/lantiq/xway/mach-easy50712.c | 68 ++++++++++++++++++++++++++++++++ + 6 files changed, 155 insertions(+), 0 deletions(-) + create mode 100644 arch/mips/lantiq/xway/Kconfig + create mode 100644 arch/mips/lantiq/xway/mach-easy50601.c + create mode 100644 arch/mips/lantiq/xway/mach-easy50712.c + +diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig +index 2780461..3fccf21 100644 +--- a/arch/mips/lantiq/Kconfig ++++ b/arch/mips/lantiq/Kconfig +@@ -18,4 +18,6 @@ config SOC_XWAY + select HW_HAS_PCI + endchoice + ++source "arch/mips/lantiq/xway/Kconfig" ++ + endif +diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h +index ffcacfc..7e01b8c 100644 +--- a/arch/mips/lantiq/machtypes.h ++++ b/arch/mips/lantiq/machtypes.h +@@ -13,6 +13,8 @@ + + enum lantiq_mach_type { + LTQ_MACH_GENERIC = 0, ++ LTQ_MACH_EASY50712, /* Danube evaluation board */ ++ LTQ_MACH_EASY50601, /* Amazon SE evaluation board */ + }; + + #endif +diff --git a/arch/mips/lantiq/xway/Kconfig b/arch/mips/lantiq/xway/Kconfig +new file mode 100644 +index 0000000..2b857de +--- /dev/null ++++ b/arch/mips/lantiq/xway/Kconfig +@@ -0,0 +1,23 @@ ++if SOC_XWAY ++ ++menu "MIPS Machine" ++ ++config LANTIQ_MACH_EASY50712 ++ bool "Easy50712 - Danube" ++ default y ++ ++endmenu ++ ++endif ++ ++if SOC_AMAZON_SE ++ ++menu "MIPS Machine" ++ ++config LANTIQ_MACH_EASY50601 ++ bool "Easy50601 - Amazon SE" ++ default y ++ ++endmenu ++ ++endif +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 8c06a97..b1d3640 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -2,3 +2,6 @@ obj-y := pmu.o ebu.o reset.o gpio.o devices.o + + obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o + obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-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/mach-easy50601.c b/arch/mips/lantiq/xway/mach-easy50601.c +new file mode 100644 +index 0000000..d5aaf63 +--- /dev/null ++++ b/arch/mips/lantiq/xway/mach-easy50601.c +@@ -0,0 +1,57 @@ ++/* ++ * 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 <lantiq.h> ++ ++#include "../machtypes.h" ++#include "devices.h" ++ ++static struct mtd_partition easy50601_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 easy50601_flash_data = { ++ .nr_parts = ARRAY_SIZE(easy50601_partitions), ++ .parts = easy50601_partitions, ++}; ++ ++static void __init easy50601_init(void) ++{ ++ ltq_register_nor(&easy50601_flash_data); ++} ++ ++MIPS_MACHINE(LTQ_MACH_EASY50601, ++ "EASY50601", ++ "EASY50601 Eval Board", ++ easy50601_init); +diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c +new file mode 100644 +index 0000000..e5e7e09 +--- /dev/null ++++ b/arch/mips/lantiq/xway/mach-easy50712.c +@@ -0,0 +1,68 @@ ++/* ++ * 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 <lantiq_soc.h> ++#include <irq.h> ++ ++#include "../machtypes.h" ++#include "devices.h" ++ ++static struct mtd_partition easy50712_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 easy50712_flash_data = { ++ .nr_parts = ARRAY_SIZE(easy50712_partitions), ++ .parts = easy50712_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 void __init easy50712_init(void) ++{ ++ ltq_register_gpio_stp(); ++ ltq_register_nor(&easy50712_flash_data); ++ ltq_register_pci(<q_pci_data); ++} ++ ++MIPS_MACHINE(LTQ_MACH_EASY50712, ++ "EASY50712", ++ "EASY50712 Eval Board", ++ easy50712_init); +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches-2.6.39/0008-MIPS-Lantiq-Add-more-gpio-drivers.patch b/target/linux/lantiq/patches-2.6.39/0008-MIPS-Lantiq-Add-more-gpio-drivers.patch new file mode 100644 index 0000000..2daa9e0 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0008-MIPS-Lantiq-Add-more-gpio-drivers.patch @@ -0,0 +1,330 @@ +From f9391211e47cdcc31f341d710efef4b3b46c333d Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Wed, 30 Mar 2011 09:27:56 +0200 +Subject: [PATCH 08/13] MIPS: Lantiq: Add more gpio drivers + +The XWAY family allows to extend the number of gpios by using shift registers or latches. This patch adds the 2 drivers needed for this. The extended gpios are output only. + +[ralf@linux-mips.org: Fixed ltq_stp_probe section() attributes.] + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2258/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/lantiq/xway/Makefile | 2 +- + arch/mips/lantiq/xway/gpio_ebu.c | 126 ++++++++++++++++++++++++++++++ + arch/mips/lantiq/xway/gpio_stp.c | 157 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 284 insertions(+), 1 deletions(-) + create mode 100644 arch/mips/lantiq/xway/gpio_ebu.c + create mode 100644 arch/mips/lantiq/xway/gpio_stp.c + +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index b1d3640..6b5e07e 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := pmu.o ebu.o reset.o gpio.o devices.o ++obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o + + obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o + obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o +diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c +new file mode 100644 +index 0000000..a479355 +--- /dev/null ++++ b/arch/mips/lantiq/xway/gpio_ebu.c +@@ -0,0 +1,126 @@ ++/* ++ * 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/module.h> ++#include <linux/types.h> ++#include <linux/platform_device.h> ++#include <linux/mutex.h> ++#include <linux/gpio.h> ++#include <linux/io.h> ++ ++#include <lantiq_soc.h> ++ ++/* ++ * By attaching hardware latches to the EBU it is possible to create output ++ * only gpios. This driver configures a special memory address, which when ++ * written to outputs 16 bit to the latches. ++ */ ++ ++#define LTQ_EBU_BUSCON 0x1e7ff /* 16 bit access, slowest timing */ ++#define LTQ_EBU_WP 0x80000000 /* write protect bit */ ++ ++/* we keep a shadow value of the last value written to the ebu */ ++static int ltq_ebu_gpio_shadow = 0x0; ++static void __iomem *ltq_ebu_gpio_membase; ++ ++static void ltq_ebu_apply(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1); ++ *((__u16 *)ltq_ebu_gpio_membase) = ltq_ebu_gpio_shadow; ++ ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); ++ spin_unlock_irqrestore(&ebu_lock, flags); ++} ++ ++static void ltq_ebu_set(struct gpio_chip *chip, unsigned offset, int value) ++{ ++ if (value) ++ ltq_ebu_gpio_shadow |= (1 << offset); ++ else ++ ltq_ebu_gpio_shadow &= ~(1 << offset); ++ ltq_ebu_apply(); ++} ++ ++static int ltq_ebu_direction_output(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ ltq_ebu_set(chip, offset, value); ++ ++ return 0; ++} ++ ++static struct gpio_chip ltq_ebu_chip = { ++ .label = "ltq_ebu", ++ .direction_output = ltq_ebu_direction_output, ++ .set = ltq_ebu_set, ++ .base = 72, ++ .ngpio = 16, ++ .can_sleep = 1, ++ .owner = THIS_MODULE, ++}; ++ ++static int ltq_ebu_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ ++ if (!res) { ++ dev_err(&pdev->dev, "failed to get memory resource\n"); ++ return -ENOENT; ++ } ++ ++ 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 memory resource\n"); ++ return -EBUSY; ++ } ++ ++ ltq_ebu_gpio_membase = devm_ioremap_nocache(&pdev->dev, res->start, ++ resource_size(res)); ++ if (!ltq_ebu_gpio_membase) { ++ dev_err(&pdev->dev, "Failed to ioremap mem region\n"); ++ return -ENOMEM; ++ } ++ ++ /* grab the default shadow value passed form the platform code */ ++ ltq_ebu_gpio_shadow = (unsigned int) pdev->dev.platform_data; ++ ++ /* tell the ebu controller which memory address we will be using */ ++ ltq_ebu_w32(pdev->resource->start | 0x1, LTQ_EBU_ADDRSEL1); ++ ++ /* write protect the region */ ++ ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1); ++ ++ ret = gpiochip_add(<q_ebu_chip); ++ if (!ret) ++ ltq_ebu_apply(); ++ return ret; ++} ++ ++static struct platform_driver ltq_ebu_driver = { ++ .probe = ltq_ebu_probe, ++ .driver = { ++ .name = "ltq_ebu", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init ltq_ebu_init(void) ++{ ++ int ret = platform_driver_register(<q_ebu_driver); ++ ++ if (ret) ++ pr_info("ltq_ebu : Error registering platfom driver!"); ++ return ret; ++} ++ ++postcore_initcall(ltq_ebu_init); +diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c +new file mode 100644 +index 0000000..67d59d6 +--- /dev/null ++++ b/arch/mips/lantiq/xway/gpio_stp.c +@@ -0,0 +1,157 @@ ++/* ++ * 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) 2007 John Crispin <blogic@openwrt.org> ++ * ++ */ ++ ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/platform_device.h> ++#include <linux/mutex.h> ++#include <linux/io.h> ++#include <linux/gpio.h> ++ ++#include <lantiq_soc.h> ++ ++#define LTQ_STP_CON0 0x00 ++#define LTQ_STP_CON1 0x04 ++#define LTQ_STP_CPU0 0x08 ++#define LTQ_STP_CPU1 0x0C ++#define LTQ_STP_AR 0x10 ++ ++#define LTQ_STP_CON_SWU (1 << 31) ++#define LTQ_STP_2HZ 0 ++#define LTQ_STP_4HZ (1 << 23) ++#define LTQ_STP_8HZ (2 << 23) ++#define LTQ_STP_10HZ (3 << 23) ++#define LTQ_STP_SPEED_MASK (0xf << 23) ++#define LTQ_STP_UPD_FPI (1 << 31) ++#define LTQ_STP_UPD_MASK (3 << 30) ++#define LTQ_STP_ADSL_SRC (3 << 24) ++ ++#define LTQ_STP_GROUP0 (1 << 0) ++ ++#define LTQ_STP_RISING 0 ++#define LTQ_STP_FALLING (1 << 26) ++#define LTQ_STP_EDGE_MASK (1 << 26) ++ ++#define ltq_stp_r32(reg) __raw_readl(ltq_stp_membase + reg) ++#define ltq_stp_w32(val, reg) __raw_writel(val, ltq_stp_membase + reg) ++#define ltq_stp_w32_mask(clear, set, reg) \ ++ ltq_w32((ltq_r32(ltq_stp_membase + reg) & ~(clear)) | (set), \ ++ ltq_stp_membase + (reg)) ++ ++static int ltq_stp_shadow = 0xffff; ++static void __iomem *ltq_stp_membase; ++ ++static void ltq_stp_set(struct gpio_chip *chip, unsigned offset, int value) ++{ ++ if (value) ++ ltq_stp_shadow |= (1 << offset); ++ else ++ ltq_stp_shadow &= ~(1 << offset); ++ ltq_stp_w32(ltq_stp_shadow, LTQ_STP_CPU0); ++} ++ ++static int ltq_stp_direction_output(struct gpio_chip *chip, unsigned offset, ++ int value) ++{ ++ ltq_stp_set(chip, offset, value); ++ ++ return 0; ++} ++ ++static struct gpio_chip ltq_stp_chip = { ++ .label = "ltq_stp", ++ .direction_output = ltq_stp_direction_output, ++ .set = ltq_stp_set, ++ .base = 48, ++ .ngpio = 24, ++ .can_sleep = 1, ++ .owner = THIS_MODULE, ++}; ++ ++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"); ++ ++ /* sane defaults */ ++ ltq_stp_w32(0, LTQ_STP_AR); ++ ltq_stp_w32(0, LTQ_STP_CPU0); ++ ltq_stp_w32(0, LTQ_STP_CPU1); ++ ltq_stp_w32(LTQ_STP_CON_SWU, LTQ_STP_CON0); ++ ltq_stp_w32(0, LTQ_STP_CON1); ++ ++ /* rising or falling edge */ ++ ltq_stp_w32_mask(LTQ_STP_EDGE_MASK, LTQ_STP_FALLING, LTQ_STP_CON0); ++ ++ /* per default stp 15-0 are set */ ++ ltq_stp_w32_mask(0, LTQ_STP_GROUP0, LTQ_STP_CON1); ++ ++ /* stp are update periodically by the FPI bus */ ++ ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1); ++ ++ /* set stp update speed */ ++ ltq_stp_w32_mask(LTQ_STP_SPEED_MASK, LTQ_STP_8HZ, LTQ_STP_CON1); ++ ++ /* tell the hardware that pin (led) 0 and 1 are controlled ++ * by the dsl arc ++ */ ++ ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0); ++ ++ ltq_pmu_enable(PMU_LED); ++ return 0; ++} ++ ++static int __devinit ltq_stp_probe(struct platform_device *pdev) ++{ ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ int ret = 0; ++ ++ if (!res) ++ return -ENOENT; ++ 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 STP memory\n"); ++ return -EBUSY; ++ } ++ ltq_stp_membase = devm_ioremap_nocache(&pdev->dev, res->start, ++ resource_size(res)); ++ if (!ltq_stp_membase) { ++ dev_err(&pdev->dev, "failed to remap STP memory\n"); ++ return -ENOMEM; ++ } ++ ret = gpiochip_add(<q_stp_chip); ++ if (!ret) ++ ret = ltq_stp_hw_init(); ++ ++ return ret; ++} ++ ++static struct platform_driver ltq_stp_driver = { ++ .probe = ltq_stp_probe, ++ .driver = { ++ .name = "ltq_stp", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init ltq_stp_init(void) ++{ ++ int ret = platform_driver_register(<q_stp_driver); ++ ++ if (ret) ++ pr_info("ltq_stp: error registering platfom driver"); ++ return ret; ++} ++ ++postcore_initcall(ltq_stp_init); +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches-2.6.39/0009-SERIAL-Lantiq-Add-driver-for-MIPS-Lantiq-SOCs.patch b/target/linux/lantiq/patches-2.6.39/0009-SERIAL-Lantiq-Add-driver-for-MIPS-Lantiq-SOCs.patch new file mode 100644 index 0000000..4877878 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0009-SERIAL-Lantiq-Add-driver-for-MIPS-Lantiq-SOCs.patch @@ -0,0 +1,804 @@ +From 1d2b44b1afa3ef081cd817dbf947d48eb8f5d21a Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Tue, 5 Apr 2011 14:10:57 +0200 +Subject: [PATCH 09/13] SERIAL: Lantiq: Add driver for MIPS Lantiq SOCs. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +Cc: alan@lxorguk.ukuu.org.uk +Cc: linux-mips@linux-mips.org +Cc: linux-serial@vger.kernel.org +Patchwork: https://patchwork.linux-mips.org/patch/2269/ +Acked-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + drivers/tty/serial/Kconfig | 8 + + drivers/tty/serial/Makefile | 1 + + drivers/tty/serial/lantiq.c | 756 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 765 insertions(+), 0 deletions(-) + create mode 100644 drivers/tty/serial/lantiq.c + +--- /dev/null ++++ b/drivers/tty/serial/lantiq.c +@@ -0,0 +1,756 @@ ++/* ++ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ * 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) 2004 Infineon IFAP DC COM CPE ++ * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> ++ * Copyright (C) 2007 John Crispin <blogic@openwrt.org> ++ * Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com> ++ */ ++ ++#include <linux/slab.h> ++#include <linux/module.h> ++#include <linux/ioport.h> ++#include <linux/init.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++#include <linux/device.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/serial_core.h> ++#include <linux/serial.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/clk.h> ++ ++#include <lantiq_soc.h> ++ ++#define PORT_LTQ_ASC 111 ++#define MAXPORTS 2 ++#define UART_DUMMY_UER_RX 1 ++#define DRVNAME "ltq_asc" ++#ifdef __BIG_ENDIAN ++#define LTQ_ASC_TBUF (0x0020 + 3) ++#define LTQ_ASC_RBUF (0x0024 + 3) ++#else ++#define LTQ_ASC_TBUF 0x0020 ++#define LTQ_ASC_RBUF 0x0024 ++#endif ++#define LTQ_ASC_FSTAT 0x0048 ++#define LTQ_ASC_WHBSTATE 0x0018 ++#define LTQ_ASC_STATE 0x0014 ++#define LTQ_ASC_IRNCR 0x00F8 ++#define LTQ_ASC_CLC 0x0000 ++#define LTQ_ASC_ID 0x0008 ++#define LTQ_ASC_PISEL 0x0004 ++#define LTQ_ASC_TXFCON 0x0044 ++#define LTQ_ASC_RXFCON 0x0040 ++#define LTQ_ASC_CON 0x0010 ++#define LTQ_ASC_BG 0x0050 ++#define LTQ_ASC_IRNREN 0x00F4 ++ ++#define ASC_IRNREN_TX 0x1 ++#define ASC_IRNREN_RX 0x2 ++#define ASC_IRNREN_ERR 0x4 ++#define ASC_IRNREN_TX_BUF 0x8 ++#define ASC_IRNCR_TIR 0x1 ++#define ASC_IRNCR_RIR 0x2 ++#define ASC_IRNCR_EIR 0x4 ++ ++#define ASCOPT_CSIZE 0x3 ++#define TXFIFO_FL 1 ++#define RXFIFO_FL 1 ++#define ASCCLC_DISS 0x2 ++#define ASCCLC_RMCMASK 0x0000FF00 ++#define ASCCLC_RMCOFFSET 8 ++#define ASCCON_M_8ASYNC 0x0 ++#define ASCCON_M_7ASYNC 0x2 ++#define ASCCON_ODD 0x00000020 ++#define ASCCON_STP 0x00000080 ++#define ASCCON_BRS 0x00000100 ++#define ASCCON_FDE 0x00000200 ++#define ASCCON_R 0x00008000 ++#define ASCCON_FEN 0x00020000 ++#define ASCCON_ROEN 0x00080000 ++#define ASCCON_TOEN 0x00100000 ++#define ASCSTATE_PE 0x00010000 ++#define ASCSTATE_FE 0x00020000 ++#define ASCSTATE_ROE 0x00080000 ++#define ASCSTATE_ANY (ASCSTATE_ROE|ASCSTATE_PE|ASCSTATE_FE) ++#define ASCWHBSTATE_CLRREN 0x00000001 ++#define ASCWHBSTATE_SETREN 0x00000002 ++#define ASCWHBSTATE_CLRPE 0x00000004 ++#define ASCWHBSTATE_CLRFE 0x00000008 ++#define ASCWHBSTATE_CLRROE 0x00000020 ++#define ASCTXFCON_TXFEN 0x0001 ++#define ASCTXFCON_TXFFLU 0x0002 ++#define ASCTXFCON_TXFITLMASK 0x3F00 ++#define ASCTXFCON_TXFITLOFF 8 ++#define ASCRXFCON_RXFEN 0x0001 ++#define ASCRXFCON_RXFFLU 0x0002 ++#define ASCRXFCON_RXFITLMASK 0x3F00 ++#define ASCRXFCON_RXFITLOFF 8 ++#define ASCFSTAT_RXFFLMASK 0x003F ++#define ASCFSTAT_TXFFLMASK 0x3F00 ++#define ASCFSTAT_TXFREEMASK 0x3F000000 ++#define ASCFSTAT_TXFREEOFF 24 ++ ++static void lqasc_tx_chars(struct uart_port *port); ++static struct ltq_uart_port *lqasc_port[MAXPORTS]; ++static struct uart_driver lqasc_reg; ++static DEFINE_SPINLOCK(ltq_asc_lock); ++ ++struct ltq_uart_port { ++ struct uart_port port; ++ struct clk *clk; ++ unsigned int tx_irq; ++ unsigned int rx_irq; ++ unsigned int err_irq; ++}; ++ ++static inline struct ++ltq_uart_port *to_ltq_uart_port(struct uart_port *port) ++{ ++ return container_of(port, struct ltq_uart_port, port); ++} ++ ++static void ++lqasc_stop_tx(struct uart_port *port) ++{ ++ return; ++} ++ ++static void ++lqasc_start_tx(struct uart_port *port) ++{ ++ unsigned long flags; ++ spin_lock_irqsave(<q_asc_lock, flags); ++ lqasc_tx_chars(port); ++ spin_unlock_irqrestore(<q_asc_lock, flags); ++ return; ++} ++ ++static void ++lqasc_stop_rx(struct uart_port *port) ++{ ++ ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE); ++} ++ ++static void ++lqasc_enable_ms(struct uart_port *port) ++{ ++} ++ ++static int ++lqasc_rx_chars(struct uart_port *port) ++{ ++ struct tty_struct *tty = tty_port_tty_get(&port->state->port); ++ unsigned int ch = 0, rsr = 0, fifocnt; ++ ++ if (!tty) { ++ dev_dbg(port->dev, "%s:tty is busy now", __func__); ++ return -EBUSY; ++ } ++ fifocnt = ++ ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK; ++ while (fifocnt--) { ++ u8 flag = TTY_NORMAL; ++ ch = ltq_r8(port->membase + LTQ_ASC_RBUF); ++ rsr = (ltq_r32(port->membase + LTQ_ASC_STATE) ++ & ASCSTATE_ANY) | UART_DUMMY_UER_RX; ++ tty_flip_buffer_push(tty); ++ port->icount.rx++; ++ ++ /* ++ * Note that the error handling code is ++ * out of the main execution path ++ */ ++ if (rsr & ASCSTATE_ANY) { ++ if (rsr & ASCSTATE_PE) { ++ port->icount.parity++; ++ ltq_w32_mask(0, ASCWHBSTATE_CLRPE, ++ port->membase + LTQ_ASC_WHBSTATE); ++ } else if (rsr & ASCSTATE_FE) { ++ port->icount.frame++; ++ ltq_w32_mask(0, ASCWHBSTATE_CLRFE, ++ port->membase + LTQ_ASC_WHBSTATE); ++ } ++ if (rsr & ASCSTATE_ROE) { ++ port->icount.overrun++; ++ ltq_w32_mask(0, ASCWHBSTATE_CLRROE, ++ port->membase + LTQ_ASC_WHBSTATE); ++ } ++ ++ rsr &= port->read_status_mask; ++ ++ if (rsr & ASCSTATE_PE) ++ flag = TTY_PARITY; ++ else if (rsr & ASCSTATE_FE) ++ flag = TTY_FRAME; ++ } ++ ++ if ((rsr & port->ignore_status_mask) == 0) ++ tty_insert_flip_char(tty, ch, flag); ++ ++ if (rsr & ASCSTATE_ROE) ++ /* ++ * Overrun is special, since it's reported ++ * immediately, and doesn't affect the current ++ * character ++ */ ++ tty_insert_flip_char(tty, 0, TTY_OVERRUN); ++ } ++ if (ch != 0) ++ tty_flip_buffer_push(tty); ++ tty_kref_put(tty); ++ return 0; ++} ++ ++static void ++lqasc_tx_chars(struct uart_port *port) ++{ ++ struct circ_buf *xmit = &port->state->xmit; ++ if (uart_tx_stopped(port)) { ++ lqasc_stop_tx(port); ++ return; ++ } ++ ++ while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) & ++ ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) { ++ if (port->x_char) { ++ ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF); ++ port->icount.tx++; ++ port->x_char = 0; ++ continue; ++ } ++ ++ if (uart_circ_empty(xmit)) ++ break; ++ ++ ltq_w8(port->state->xmit.buf[port->state->xmit.tail], ++ port->membase + LTQ_ASC_TBUF); ++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); ++ port->icount.tx++; ++ } ++ ++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) ++ uart_write_wakeup(port); ++} ++ ++static irqreturn_t ++lqasc_tx_int(int irq, void *_port) ++{ ++ unsigned long flags; ++ struct uart_port *port = (struct uart_port *)_port; ++ spin_lock_irqsave(<q_asc_lock, flags); ++ ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR); ++ spin_unlock_irqrestore(<q_asc_lock, flags); ++ lqasc_start_tx(port); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t ++lqasc_err_int(int irq, void *_port) ++{ ++ unsigned long flags; ++ struct uart_port *port = (struct uart_port *)_port; ++ spin_lock_irqsave(<q_asc_lock, flags); ++ /* clear any pending interrupts */ ++ ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE | ++ ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE); ++ spin_unlock_irqrestore(<q_asc_lock, flags); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t ++lqasc_rx_int(int irq, void *_port) ++{ ++ unsigned long flags; ++ struct uart_port *port = (struct uart_port *)_port; ++ spin_lock_irqsave(<q_asc_lock, flags); ++ ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR); ++ lqasc_rx_chars(port); ++ spin_unlock_irqrestore(<q_asc_lock, flags); ++ return IRQ_HANDLED; ++} ++ ++static unsigned int ++lqasc_tx_empty(struct uart_port *port) ++{ ++ int status; ++ status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK; ++ return status ? 0 : TIOCSER_TEMT; ++} ++ ++static unsigned int ++lqasc_get_mctrl(struct uart_port *port) ++{ ++ return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR; ++} ++ ++static void ++lqasc_set_mctrl(struct uart_port *port, u_int mctrl) ++{ ++} ++ ++static void ++lqasc_break_ctl(struct uart_port *port, int break_state) ++{ ++} ++ ++static int ++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); ++ ++ ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), ++ port->membase + LTQ_ASC_CLC); ++ ++ ltq_w32(0, port->membase + LTQ_ASC_PISEL); ++ ltq_w32( ++ ((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) | ++ ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU, ++ port->membase + LTQ_ASC_TXFCON); ++ ltq_w32( ++ ((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK) ++ | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU, ++ port->membase + LTQ_ASC_RXFCON); ++ /* make sure other settings are written to hardware before ++ * setting enable bits ++ */ ++ wmb(); ++ ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | ++ ASCCON_ROEN, port->membase + LTQ_ASC_CON); ++ ++ retval = request_irq(ltq_port->tx_irq, lqasc_tx_int, ++ IRQF_DISABLED, "asc_tx", port); ++ if (retval) { ++ pr_err("failed to request lqasc_tx_int\n"); ++ return retval; ++ } ++ ++ retval = request_irq(ltq_port->rx_irq, lqasc_rx_int, ++ IRQF_DISABLED, "asc_rx", port); ++ if (retval) { ++ pr_err("failed to request lqasc_rx_int\n"); ++ goto err1; ++ } ++ ++ retval = request_irq(ltq_port->err_irq, lqasc_err_int, ++ IRQF_DISABLED, "asc_err", port); ++ if (retval) { ++ pr_err("failed to request lqasc_err_int\n"); ++ goto err2; ++ } ++ ++ ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX, ++ port->membase + LTQ_ASC_IRNREN); ++ return 0; ++ ++err2: ++ free_irq(ltq_port->rx_irq, port); ++err1: ++ free_irq(ltq_port->tx_irq, port); ++ return retval; ++} ++ ++static void ++lqasc_shutdown(struct uart_port *port) ++{ ++ struct ltq_uart_port *ltq_port = to_ltq_uart_port(port); ++ free_irq(ltq_port->tx_irq, port); ++ free_irq(ltq_port->rx_irq, port); ++ free_irq(ltq_port->err_irq, port); ++ ++ ltq_w32(0, port->membase + LTQ_ASC_CON); ++ ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU, ++ port->membase + LTQ_ASC_RXFCON); ++ ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU, ++ port->membase + LTQ_ASC_TXFCON); ++} ++ ++static void ++lqasc_set_termios(struct uart_port *port, ++ struct ktermios *new, struct ktermios *old) ++{ ++ unsigned int cflag; ++ unsigned int iflag; ++ unsigned int divisor; ++ unsigned int baud; ++ unsigned int con = 0; ++ unsigned long flags; ++ ++ cflag = new->c_cflag; ++ iflag = new->c_iflag; ++ ++ switch (cflag & CSIZE) { ++ case CS7: ++ con = ASCCON_M_7ASYNC; ++ break; ++ ++ case CS5: ++ case CS6: ++ default: ++ new->c_cflag &= ~ CSIZE; ++ new->c_cflag |= CS8; ++ con = ASCCON_M_8ASYNC; ++ break; ++ } ++ ++ cflag &= ~CMSPAR; /* Mark/Space parity is not supported */ ++ ++ if (cflag & CSTOPB) ++ con |= ASCCON_STP; ++ ++ if (cflag & PARENB) { ++ if (!(cflag & PARODD)) ++ con &= ~ASCCON_ODD; ++ else ++ con |= ASCCON_ODD; ++ } ++ ++ port->read_status_mask = ASCSTATE_ROE; ++ if (iflag & INPCK) ++ port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE; ++ ++ port->ignore_status_mask = 0; ++ if (iflag & IGNPAR) ++ port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE; ++ ++ if (iflag & IGNBRK) { ++ /* ++ * If we're ignoring parity and break indicators, ++ * ignore overruns too (for real raw support). ++ */ ++ if (iflag & IGNPAR) ++ port->ignore_status_mask |= ASCSTATE_ROE; ++ } ++ ++ if ((cflag & CREAD) == 0) ++ port->ignore_status_mask |= UART_DUMMY_UER_RX; ++ ++ /* set error signals - framing, parity and overrun, enable receiver */ ++ con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN; ++ ++ spin_lock_irqsave(<q_asc_lock, flags); ++ ++ /* set up CON */ ++ ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON); ++ ++ /* Set baud rate - take a divider of 2 into account */ ++ baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); ++ divisor = uart_get_divisor(port, baud); ++ divisor = divisor / 2 - 1; ++ ++ /* disable the baudrate generator */ ++ ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON); ++ ++ /* make sure the fractional divider is off */ ++ ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON); ++ ++ /* set up to use divisor of 2 */ ++ ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON); ++ ++ /* now we can write the new baudrate into the register */ ++ ltq_w32(divisor, port->membase + LTQ_ASC_BG); ++ ++ /* turn the baudrate generator back on */ ++ ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON); ++ ++ /* enable rx */ ++ ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE); ++ ++ spin_unlock_irqrestore(<q_asc_lock, flags); ++ ++ /* Don't rewrite B0 */ ++ if (tty_termios_baud_rate(new)) ++ tty_termios_encode_baud_rate(new, baud, baud); ++} ++ ++static const char* ++lqasc_type(struct uart_port *port) ++{ ++ if (port->type == PORT_LTQ_ASC) ++ return DRVNAME; ++ else ++ return NULL; ++} ++ ++static void ++lqasc_release_port(struct uart_port *port) ++{ ++ if (port->flags & UPF_IOREMAP) { ++ iounmap(port->membase); ++ port->membase = NULL; ++ } ++} ++ ++static int ++lqasc_request_port(struct uart_port *port) ++{ ++ struct platform_device *pdev = to_platform_device(port->dev); ++ struct resource *res; ++ int size; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot obtain I/O memory region"); ++ return -ENODEV; ++ } ++ size = resource_size(res); ++ ++ res = devm_request_mem_region(&pdev->dev, res->start, ++ size, dev_name(&pdev->dev)); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot request I/O memory region"); ++ return -EBUSY; ++ } ++ ++ if (port->flags & UPF_IOREMAP) { ++ port->membase = devm_ioremap_nocache(&pdev->dev, ++ port->mapbase, size); ++ if (port->membase == NULL) ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++static void ++lqasc_config_port(struct uart_port *port, int flags) ++{ ++ if (flags & UART_CONFIG_TYPE) { ++ port->type = PORT_LTQ_ASC; ++ lqasc_request_port(port); ++ } ++} ++ ++static int ++lqasc_verify_port(struct uart_port *port, ++ struct serial_struct *ser) ++{ ++ int ret = 0; ++ if (ser->type != PORT_UNKNOWN && ser->type != PORT_LTQ_ASC) ++ ret = -EINVAL; ++ if (ser->irq < 0 || ser->irq >= NR_IRQS) ++ ret = -EINVAL; ++ if (ser->baud_base < 9600) ++ ret = -EINVAL; ++ return ret; ++} ++ ++static struct uart_ops lqasc_pops = { ++ .tx_empty = lqasc_tx_empty, ++ .set_mctrl = lqasc_set_mctrl, ++ .get_mctrl = lqasc_get_mctrl, ++ .stop_tx = lqasc_stop_tx, ++ .start_tx = lqasc_start_tx, ++ .stop_rx = lqasc_stop_rx, ++ .enable_ms = lqasc_enable_ms, ++ .break_ctl = lqasc_break_ctl, ++ .startup = lqasc_startup, ++ .shutdown = lqasc_shutdown, ++ .set_termios = lqasc_set_termios, ++ .type = lqasc_type, ++ .release_port = lqasc_release_port, ++ .request_port = lqasc_request_port, ++ .config_port = lqasc_config_port, ++ .verify_port = lqasc_verify_port, ++}; ++ ++static void ++lqasc_console_putchar(struct uart_port *port, int ch) ++{ ++ int fifofree; ++ ++ if (!port->membase) ++ return; ++ ++ do { ++ fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT) ++ & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF; ++ } while (fifofree == 0); ++ ltq_w8(ch, port->membase + LTQ_ASC_TBUF); ++} ++ ++ ++static void ++lqasc_console_write(struct console *co, const char *s, u_int count) ++{ ++ struct ltq_uart_port *ltq_port; ++ struct uart_port *port; ++ unsigned long flags; ++ ++ if (co->index >= MAXPORTS) ++ return; ++ ++ ltq_port = lqasc_port[co->index]; ++ if (!ltq_port) ++ return; ++ ++ port = <q_port->port; ++ ++ spin_lock_irqsave(<q_asc_lock, flags); ++ uart_console_write(port, s, count, lqasc_console_putchar); ++ spin_unlock_irqrestore(<q_asc_lock, flags); ++} ++ ++static int __init ++lqasc_console_setup(struct console *co, char *options) ++{ ++ struct ltq_uart_port *ltq_port; ++ struct uart_port *port; ++ int baud = 115200; ++ int bits = 8; ++ int parity = 'n'; ++ int flow = 'n'; ++ ++ if (co->index >= MAXPORTS) ++ return -ENODEV; ++ ++ ltq_port = lqasc_port[co->index]; ++ if (!ltq_port) ++ return -ENODEV; ++ ++ port = <q_port->port; ++ ++ port->uartclk = clk_get_rate(ltq_port->clk); ++ ++ if (options) ++ uart_parse_options(options, &baud, &parity, &bits, &flow); ++ return uart_set_options(port, co, baud, parity, bits, flow); ++} ++ ++static struct console lqasc_console = { ++ .name = "ttyLTQ", ++ .write = lqasc_console_write, ++ .device = uart_console_device, ++ .setup = lqasc_console_setup, ++ .flags = CON_PRINTBUFFER, ++ .index = -1, ++ .data = &lqasc_reg, ++}; ++ ++static int __init ++lqasc_console_init(void) ++{ ++ register_console(&lqasc_console); ++ return 0; ++} ++console_initcall(lqasc_console_init); ++ ++static struct uart_driver lqasc_reg = { ++ .owner = THIS_MODULE, ++ .driver_name = DRVNAME, ++ .dev_name = "ttyLTQ", ++ .major = 0, ++ .minor = 0, ++ .nr = MAXPORTS, ++ .cons = &lqasc_console, ++}; ++ ++static int __init ++lqasc_probe(struct platform_device *pdev) ++{ ++ struct ltq_uart_port *ltq_port; ++ struct uart_port *port; ++ struct resource *mmres, *irqres; ++ int tx_irq, rx_irq, err_irq; ++ struct clk *clk; ++ int ret; ++ ++ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (!mmres || !irqres) ++ return -ENODEV; ++ ++ if (pdev->id >= MAXPORTS) ++ return -EBUSY; ++ ++ if (lqasc_port[pdev->id] != NULL) ++ return -EBUSY; ++ ++ clk = clk_get(&pdev->dev, "fpi"); ++ if (IS_ERR(clk)) { ++ pr_err("failed to get fpi clk\n"); ++ return -ENOENT; ++ } ++ ++ tx_irq = platform_get_irq_byname(pdev, "tx"); ++ rx_irq = platform_get_irq_byname(pdev, "rx"); ++ err_irq = platform_get_irq_byname(pdev, "err"); ++ if ((tx_irq < 0) | (rx_irq < 0) | (err_irq < 0)) ++ return -ENODEV; ++ ++ ltq_port = kzalloc(sizeof(struct ltq_uart_port), GFP_KERNEL); ++ if (!ltq_port) ++ return -ENOMEM; ++ ++ port = <q_port->port; ++ ++ port->iotype = SERIAL_IO_MEM; ++ port->flags = ASYNC_BOOT_AUTOCONF | UPF_IOREMAP; ++ port->ops = &lqasc_pops; ++ port->fifosize = 16; ++ port->type = PORT_LTQ_ASC, ++ port->line = pdev->id; ++ port->dev = &pdev->dev; ++ ++ port->irq = tx_irq; /* unused, just to be backward-compatibe */ ++ port->mapbase = mmres->start; ++ ++ ltq_port->clk = clk; ++ ++ ltq_port->tx_irq = tx_irq; ++ ltq_port->rx_irq = rx_irq; ++ ltq_port->err_irq = err_irq; ++ ++ lqasc_port[pdev->id] = ltq_port; ++ platform_set_drvdata(pdev, ltq_port); ++ ++ ret = uart_add_one_port(&lqasc_reg, port); ++ ++ return ret; ++} ++ ++static struct platform_driver lqasc_driver = { ++ .driver = { ++ .name = DRVNAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init ++init_lqasc(void) ++{ ++ int ret; ++ ++ ret = uart_register_driver(&lqasc_reg); ++ if (ret != 0) ++ return ret; ++ ++ ret = platform_driver_probe(&lqasc_driver, lqasc_probe); ++ if (ret != 0) ++ uart_unregister_driver(&lqasc_reg); ++ ++ return ret; ++} ++ ++module_init(init_lqasc); ++ ++MODULE_DESCRIPTION("Lantiq serial port driver"); ++MODULE_LICENSE("GPL"); +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -1391,6 +1391,14 @@ + help + Support for Console on the NWP serial ports. + ++config SERIAL_LANTIQ ++ bool "Lantiq serial driver" ++ depends on LANTIQ ++ select SERIAL_CORE ++ select SERIAL_CORE_CONSOLE ++ help ++ Support for console and UART on Lantiq SoCs. ++ + config SERIAL_QE + tristate "Freescale QUICC Engine serial port support" + depends on QUICC_ENGINE +--- a/drivers/tty/serial/Makefile ++++ b/drivers/tty/serial/Makefile +@@ -94,3 +94,4 @@ + obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o + obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o + obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o ++obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o diff --git a/target/linux/lantiq/patches-2.6.39/0010-MIPS-Lantiq-Add-DMA-support.patch b/target/linux/lantiq/patches-2.6.39/0010-MIPS-Lantiq-Add-DMA-support.patch new file mode 100644 index 0000000..fd9981a --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0010-MIPS-Lantiq-Add-DMA-support.patch @@ -0,0 +1,387 @@ +From bd620ec1ca053bab8ce2562968700e6f80e4ff83 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 6 May 2011 00:10:00 +0200 +Subject: [PATCH 10/13] MIPS: Lantiq: Add DMA support + +This patch adds support for the DMA engine found inside the XWAY family of +SoCs. The engine has 5 ports and 20 channels. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2355/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 +- + arch/mips/include/asm/mach-lantiq/xway/xway_dma.h | 60 +++++ + arch/mips/lantiq/xway/Makefile | 2 +- + arch/mips/lantiq/xway/devices.h | 1 + + arch/mips/lantiq/xway/dma.c | 253 ++++++++++++++++++++ + 5 files changed, 317 insertions(+), 2 deletions(-) + create mode 100644 arch/mips/include/asm/mach-lantiq/xway/xway_dma.h + create mode 100644 arch/mips/lantiq/xway/dma.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 343e82c..4827afb 100644 +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -86,7 +86,8 @@ + #define LTQ_PPE32_SIZE 0x40000 + + /* DMA */ +-#define LTQ_DMA_BASE_ADDR 0xBE104100 ++#define LTQ_DMA_BASE_ADDR 0x1E104100 ++#define LTQ_DMA_SIZE 0x800 + + /* PCI */ + #define PCI_CR_BASE_ADDR 0x1E105400 +diff --git a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h +new file mode 100644 +index 0000000..872943a +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h +@@ -0,0 +1,60 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef LTQ_DMA_H__ ++#define LTQ_DMA_H__ ++ ++#define LTQ_DESC_SIZE 0x08 /* each descriptor is 64bit */ ++#define LTQ_DESC_NUM 0x40 /* 64 descriptors / channel */ ++ ++#define LTQ_DMA_OWN BIT(31) /* owner bit */ ++#define LTQ_DMA_C BIT(30) /* complete bit */ ++#define LTQ_DMA_SOP BIT(29) /* start of packet */ ++#define LTQ_DMA_EOP BIT(28) /* end of packet */ ++#define LTQ_DMA_TX_OFFSET(x) ((x & 0x1f) << 23) /* data bytes offset */ ++#define LTQ_DMA_RX_OFFSET(x) ((x & 0x7) << 23) /* data bytes offset */ ++#define LTQ_DMA_SIZE_MASK (0xffff) /* the size field is 16 bit */ ++ ++struct ltq_dma_desc { ++ u32 ctl; ++ u32 addr; ++}; ++ ++struct ltq_dma_channel { ++ int nr; /* the channel number */ ++ int irq; /* the mapped irq */ ++ int desc; /* the current descriptor */ ++ struct ltq_dma_desc *desc_base; /* the descriptor base */ ++ int phys; /* physical addr */ ++}; ++ ++enum { ++ DMA_PORT_ETOP = 0, ++ DMA_PORT_DEU, ++}; ++ ++extern void ltq_dma_enable_irq(struct ltq_dma_channel *ch); ++extern void ltq_dma_disable_irq(struct ltq_dma_channel *ch); ++extern void ltq_dma_ack_irq(struct ltq_dma_channel *ch); ++extern void ltq_dma_open(struct ltq_dma_channel *ch); ++extern void ltq_dma_close(struct ltq_dma_channel *ch); ++extern void ltq_dma_alloc_tx(struct ltq_dma_channel *ch); ++extern void ltq_dma_alloc_rx(struct ltq_dma_channel *ch); ++extern void ltq_dma_free(struct ltq_dma_channel *ch); ++extern void ltq_dma_init_port(int p); ++ ++#endif +diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile +index 6b5e07e..c517f2e 100644 +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o ++obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o + + obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o + obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o +diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h +index 51f56b5..d573084 100644 +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -10,6 +10,7 @@ + #define _LTQ_DEVICES_XWAY_H__ + + #include "../devices.h" ++#include <linux/phy.h> + + extern void ltq_register_gpio(void); + extern void ltq_register_gpio_stp(void); +diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c +new file mode 100644 +index 0000000..4278a45 +--- /dev/null ++++ b/arch/mips/lantiq/xway/dma.c +@@ -0,0 +1,253 @@ ++/* ++ * 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/init.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/dma-mapping.h> ++ ++#include <lantiq_soc.h> ++#include <xway_dma.h> ++ ++#define LTQ_DMA_CTRL 0x10 ++#define LTQ_DMA_CPOLL 0x14 ++#define LTQ_DMA_CS 0x18 ++#define LTQ_DMA_CCTRL 0x1C ++#define LTQ_DMA_CDBA 0x20 ++#define LTQ_DMA_CDLEN 0x24 ++#define LTQ_DMA_CIS 0x28 ++#define LTQ_DMA_CIE 0x2C ++#define LTQ_DMA_PS 0x40 ++#define LTQ_DMA_PCTRL 0x44 ++#define LTQ_DMA_IRNEN 0xf4 ++ ++#define DMA_DESCPT BIT(3) /* descriptor complete irq */ ++#define DMA_TX BIT(8) /* TX channel direction */ ++#define DMA_CHAN_ON BIT(0) /* channel on / off bit */ ++#define DMA_PDEN BIT(6) /* enable packet drop */ ++#define DMA_CHAN_RST BIT(1) /* channel on / off bit */ ++#define DMA_RESET BIT(0) /* channel on / off bit */ ++#define DMA_IRQ_ACK 0x7e /* IRQ status register */ ++#define DMA_POLL BIT(31) /* turn on channel polling */ ++#define DMA_CLK_DIV4 BIT(6) /* polling clock divider */ ++#define DMA_2W_BURST BIT(1) /* 2 word burst length */ ++#define DMA_MAX_CHANNEL 20 /* the soc has 20 channels */ ++#define DMA_ETOP_ENDIANESS (0xf << 8) /* endianess swap etop channels */ ++#define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */ ++ ++#define ltq_dma_r32(x) ltq_r32(ltq_dma_membase + (x)) ++#define ltq_dma_w32(x, y) ltq_w32(x, ltq_dma_membase + (y)) ++#define ltq_dma_w32_mask(x, y, z) ltq_w32_mask(x, y, \ ++ ltq_dma_membase + (z)) ++ ++static struct resource ltq_dma_resource = { ++ .name = "dma", ++ .start = LTQ_DMA_BASE_ADDR, ++ .end = LTQ_DMA_BASE_ADDR + LTQ_DMA_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static void __iomem *ltq_dma_membase; ++ ++void ++ltq_dma_enable_irq(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); ++ local_irq_restore(flags); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_enable_irq); ++ ++void ++ltq_dma_disable_irq(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN); ++ local_irq_restore(flags); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_disable_irq); ++ ++void ++ltq_dma_ack_irq(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32(DMA_IRQ_ACK, LTQ_DMA_CIS); ++ local_irq_restore(flags); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_ack_irq); ++ ++void ++ltq_dma_open(struct ltq_dma_channel *ch) ++{ ++ unsigned long flag; ++ ++ local_irq_save(flag); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL); ++ ltq_dma_enable_irq(ch); ++ local_irq_restore(flag); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_open); ++ ++void ++ltq_dma_close(struct ltq_dma_channel *ch) ++{ ++ unsigned long flag; ++ ++ local_irq_save(flag); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); ++ ltq_dma_disable_irq(ch); ++ local_irq_restore(flag); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_close); ++ ++static void ++ltq_dma_alloc(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ ch->desc = 0; ++ ch->desc_base = dma_alloc_coherent(NULL, ++ LTQ_DESC_NUM * LTQ_DESC_SIZE, ++ &ch->phys, GFP_ATOMIC); ++ memset(ch->desc_base, 0, LTQ_DESC_NUM * LTQ_DESC_SIZE); ++ ++ local_irq_save(flags); ++ ltq_dma_w32(ch->nr, LTQ_DMA_CS); ++ ltq_dma_w32(ch->phys, LTQ_DMA_CDBA); ++ ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN); ++ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); ++ wmb(); ++ ltq_dma_w32_mask(0, DMA_CHAN_RST, LTQ_DMA_CCTRL); ++ while (ltq_dma_r32(LTQ_DMA_CCTRL) & DMA_CHAN_RST) ++ ; ++ local_irq_restore(flags); ++} ++ ++void ++ltq_dma_alloc_tx(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ ltq_dma_alloc(ch); ++ ++ local_irq_save(flags); ++ ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE); ++ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); ++ ltq_dma_w32(DMA_WEIGHT | DMA_TX, LTQ_DMA_CCTRL); ++ local_irq_restore(flags); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_alloc_tx); ++ ++void ++ltq_dma_alloc_rx(struct ltq_dma_channel *ch) ++{ ++ unsigned long flags; ++ ++ ltq_dma_alloc(ch); ++ ++ local_irq_save(flags); ++ ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE); ++ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); ++ ltq_dma_w32(DMA_WEIGHT, LTQ_DMA_CCTRL); ++ local_irq_restore(flags); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_alloc_rx); ++ ++void ++ltq_dma_free(struct ltq_dma_channel *ch) ++{ ++ if (!ch->desc_base) ++ return; ++ ltq_dma_close(ch); ++ dma_free_coherent(NULL, LTQ_DESC_NUM * LTQ_DESC_SIZE, ++ ch->desc_base, ch->phys); ++} ++EXPORT_SYMBOL_GPL(ltq_dma_free); ++ ++void ++ltq_dma_init_port(int p) ++{ ++ ltq_dma_w32(p, LTQ_DMA_PS); ++ switch (p) { ++ case DMA_PORT_ETOP: ++ /* ++ * Tell the DMA engine to swap the endianess of data frames and ++ * drop packets if the channel arbitration fails. ++ */ ++ ltq_dma_w32_mask(0, DMA_ETOP_ENDIANESS | DMA_PDEN, ++ LTQ_DMA_PCTRL); ++ break; ++ ++ case DMA_PORT_DEU: ++ ltq_dma_w32((DMA_2W_BURST << 4) | (DMA_2W_BURST << 2), ++ LTQ_DMA_PCTRL); ++ break; ++ ++ default: ++ break; ++ } ++} ++EXPORT_SYMBOL_GPL(ltq_dma_init_port); ++ ++int __init ++ltq_dma_init(void) ++{ ++ int i; ++ ++ /* insert and request the memory region */ ++ if (insert_resource(&iomem_resource, <q_dma_resource) < 0) ++ panic("Failed to insert dma memory\n"); ++ ++ if (request_mem_region(ltq_dma_resource.start, ++ resource_size(<q_dma_resource), "dma") < 0) ++ panic("Failed to request dma memory\n"); ++ ++ /* remap dma register range */ ++ ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start, ++ resource_size(<q_dma_resource)); ++ if (!ltq_dma_membase) ++ panic("Failed to remap dma memory\n"); ++ ++ /* power up and reset the dma engine */ ++ ltq_pmu_enable(PMU_DMA); ++ ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL); ++ ++ /* disable all interrupts */ ++ ltq_dma_w32(0, LTQ_DMA_IRNEN); ++ ++ /* reset/configure each channel */ ++ for (i = 0; i < DMA_MAX_CHANNEL; i++) { ++ ltq_dma_w32(i, LTQ_DMA_CS); ++ ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL); ++ ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL); ++ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); ++ } ++ return 0; ++} ++ ++postcore_initcall(ltq_dma_init); +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches-2.6.39/0011-MIPS-Lantiq-Add-ethernet-driver.patch b/target/linux/lantiq/patches-2.6.39/0011-MIPS-Lantiq-Add-ethernet-driver.patch new file mode 100644 index 0000000..eac20d7 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0011-MIPS-Lantiq-Add-ethernet-driver.patch @@ -0,0 +1,942 @@ +From 435de86088af82496bcba69165cd7422bb4622ec Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 6 May 2011 00:10:01 +0200 +Subject: [PATCH 11/13] MIPS: Lantiq: Add ethernet driver + +This patch adds the driver for the ETOP Packet Processing Engine (PPE32) +found inside the XWAY family of Lantiq MIPS SoCs. This driver makes 100MBit +ethernet work. Support for all 8 dma channels, gbit and the embedded switch +found on the ar9/vr9 still needs to be implemented. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: linux-mips@linux-mips.org +Cc: netdev@vger.kernel.org +Patchwork: https://patchwork.linux-mips.org/patch/2357/ +Acked-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + .../mips/include/asm/mach-lantiq/lantiq_platform.h | 7 + + .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 4 +- + arch/mips/lantiq/xway/devices.c | 23 + + arch/mips/lantiq/xway/devices.h | 1 + + drivers/net/Kconfig | 7 + + drivers/net/Makefile | 1 + + drivers/net/lantiq_etop.c | 805 ++++++++++++++++++++ + 7 files changed, 846 insertions(+), 2 deletions(-) + create mode 100644 drivers/net/lantiq_etop.c + +--- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h ++++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +@@ -10,6 +10,7 @@ + #define _LANTIQ_PLATFORM_H__ + + #include <linux/mtd/partitions.h> ++#include <linux/socket.h> + + /* struct used to pass info to the pci core */ + enum { +@@ -43,4 +44,10 @@ + int irq[16]; + }; + ++/* struct used to pass info to network drivers */ ++struct ltq_eth_data { ++ struct sockaddr mac; ++ int mii_mode; ++}; ++ + #endif +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -82,8 +82,8 @@ + #define PMU_SWITCH 0x10000000 + + /* ETOP - ethernet */ +-#define LTQ_PPE32_BASE_ADDR 0xBE180000 +-#define LTQ_PPE32_SIZE 0x40000 ++#define LTQ_ETOP_BASE_ADDR 0x1E180000 ++#define LTQ_ETOP_SIZE 0x40000 + + /* DMA */ + #define LTQ_DMA_BASE_ADDR 0x1E104100 +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -96,3 +96,26 @@ + platform_device_register_simple("ltq_asc", 0, + ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources)); + } ++ ++/* ethernet */ ++static struct resource ltq_etop_resources = { ++ .name = "etop", ++ .start = LTQ_ETOP_BASE_ADDR, ++ .end = LTQ_ETOP_BASE_ADDR + LTQ_ETOP_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static struct platform_device ltq_etop = { ++ .name = "ltq_etop", ++ .resource = <q_etop_resources, ++ .num_resources = 1, ++}; ++ ++void __init ++ltq_register_etop(struct ltq_eth_data *eth) ++{ ++ if (eth) { ++ ltq_etop.dev.platform_data = eth; ++ platform_device_register(<q_etop); ++ } ++} +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -15,5 +15,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); + + #endif +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -2017,6 +2017,13 @@ + from Faraday. It is used on Faraday A320, Andes AG101 and some + other ARM/NDS32 SoC's. + ++config LANTIQ_ETOP ++ tristate "Lantiq SoC ETOP driver" ++ depends on SOC_TYPE_XWAY ++ help ++ Support for the MII0 inside the Lantiq SoC ++ ++ + source "drivers/net/fs_enet/Kconfig" + + source "drivers/net/octeon/Kconfig" +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -259,6 +259,7 @@ + obj-$(CONFIG_ENC28J60) += enc28j60.o + obj-$(CONFIG_ETHOC) += ethoc.o + obj-$(CONFIG_GRETH) += greth.o ++obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o + + obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o + +--- /dev/null ++++ b/drivers/net/lantiq_etop.c +@@ -0,0 +1,813 @@ ++/* ++ * 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 <asm/checksum.h> ++ ++#include <lantiq_soc.h> ++#include <xway_dma.h> ++#include <lantiq_platform.h> ++ ++#define LTQ_ETOP_MDIO 0x11804 ++#define MDIO_REQUEST 0x80000000 ++#define MDIO_READ 0x40000000 ++#define MDIO_ADDR_MASK 0x1f ++#define MDIO_ADDR_OFFSET 0x15 ++#define MDIO_REG_MASK 0x1f ++#define MDIO_REG_OFFSET 0x10 ++#define MDIO_VAL_MASK 0xffff ++ ++#define PPE32_CGEN 0x800 ++#define LTQ_PPE32_ENET_MAC_CFG 0x1840 ++ ++#define LTQ_ETOP_ENETS0 0x11850 ++#define LTQ_ETOP_MAC_DA0 0x1186C ++#define LTQ_ETOP_MAC_DA1 0x11870 ++#define LTQ_ETOP_CFG 0x16020 ++#define LTQ_ETOP_IGPLEN 0x16080 ++ ++#define MAX_DMA_CHAN 0x8 ++#define MAX_DMA_CRC_LEN 0x4 ++#define MAX_DMA_DATA_LEN 0x600 ++ ++#define ETOP_FTCU BIT(28) ++#define ETOP_MII_MASK 0xf ++#define ETOP_MII_NORMAL 0xd ++#define ETOP_MII_REVERSE 0xe ++#define ETOP_PLEN_UNDER 0x40 ++#define ETOP_CGEN 0x800 ++ ++/* use 2 static channels for TX/RX */ ++#define LTQ_ETOP_TX_CHANNEL 1 ++#define LTQ_ETOP_RX_CHANNEL 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) \ ++ ltq_w32_mask(x, y, ltq_etop_membase + (z)) ++ ++#define DRV_VERSION "1.0" ++ ++#ifndef netdev_err ++#define netdev_err(a, b, ...) printk(b, ##__VA_ARGS__) ++#endif ++ ++#ifndef pr_warn ++#define pr_warn pr_warning ++#endif ++ ++static void __iomem *ltq_etop_membase; ++ ++struct ltq_etop_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_etop_priv { ++ struct net_device *netdev; ++ struct ltq_eth_data *pldata; ++ struct resource *res; ++ ++ struct mii_bus *mii_bus; ++ struct phy_device *phydev; ++ ++ struct ltq_etop_chan ch[MAX_DMA_CHAN]; ++ int tx_free[MAX_DMA_CHAN >> 1]; ++ ++ spinlock_t lock; ++}; ++ ++static int ++ltq_etop_alloc_skb(struct ltq_etop_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_etop_hw_receive(struct ltq_etop_chan *ch) ++{ ++ struct ltq_etop_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_etop_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_etop_poll_rx(struct napi_struct *napi, int budget) ++{ ++ struct ltq_etop_chan *ch = container_of(napi, ++ struct ltq_etop_chan, napi); ++ int rx = 0; ++ int complete = 0; ++ ++ 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_etop_hw_receive(ch); ++ rx++; ++ } else { ++ complete = 1; ++ } ++ } ++ if (complete || !rx) { ++ napi_complete(&ch->napi); ++ ltq_dma_ack_irq(&ch->dma); ++ } ++ return rx; ++} ++ ++static int ++ltq_etop_poll_tx(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); ++ 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); ++ ltq_dma_ack_irq(&ch->dma); ++ return 1; ++} ++ ++static irqreturn_t ++ltq_etop_dma_irq(int irq, void *_priv) ++{ ++ struct ltq_etop_priv *priv = _priv; ++ int ch = irq - LTQ_DMA_CH0_INT; ++ ++ napi_schedule(&priv->ch[ch].napi); ++ return IRQ_HANDLED; ++} ++ ++static void ++ltq_etop_free_channel(struct net_device *dev, struct ltq_etop_chan *ch) ++{ ++ struct ltq_etop_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_etop_hw_exit(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ int i; ++ ++ ltq_pmu_disable(PMU_PPE); ++ for (i = 0; i < MAX_DMA_CHAN; i++) ++ if (IS_TX(i) || IS_RX(i)) ++ ltq_etop_free_channel(dev, &priv->ch[i]); ++} ++ ++static int ++ltq_etop_hw_init(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ int i; ++ ++ ltq_pmu_enable(PMU_PPE); ++ ++ switch (priv->pldata->mii_mode) { ++ case PHY_INTERFACE_MODE_RMII: ++ ltq_etop_w32_mask(ETOP_MII_MASK, ++ ETOP_MII_REVERSE, LTQ_ETOP_CFG); ++ break; ++ ++ case PHY_INTERFACE_MODE_MII: ++ ltq_etop_w32_mask(ETOP_MII_MASK, ++ ETOP_MII_NORMAL, LTQ_ETOP_CFG); ++ break; ++ ++ default: ++ netdev_err(dev, "unknown mii mode %d\n", ++ priv->pldata->mii_mode); ++ return -ENOTSUPP; ++ } ++ ++ /* enable crc generation */ ++ ltq_etop_w32(PPE32_CGEN, LTQ_PPE32_ENET_MAC_CFG); ++ ++ ltq_dma_init_port(DMA_PORT_ETOP); ++ ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ int irq = LTQ_DMA_CH0_INT + 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); ++ 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; ++ ch->dma.desc = 0; ++ request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED, ++ "etop_rx", priv); ++ } ++ ch->dma.irq = irq; ++ } ++ return 0; ++} ++ ++static void ++ltq_etop_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_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); ++} ++ ++static int ++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); ++} ++ ++static int ++ltq_etop_nway_reset(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ ++ return phy_start_aneg(priv->phydev); ++} ++ ++static const struct ethtool_ops ltq_etop_ethtool_ops = { ++ .get_drvinfo = ltq_etop_get_drvinfo, ++ .get_settings = ltq_etop_get_settings, ++ .set_settings = ltq_etop_set_settings, ++ .nway_reset = ltq_etop_nway_reset, ++}; ++ ++static int ++ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data) ++{ ++ u32 val = MDIO_REQUEST | ++ ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) | ++ ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET) | ++ phy_data; ++ ++ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) ++ ; ++ ltq_etop_w32(val, LTQ_ETOP_MDIO); ++ return 0; ++} ++ ++static int ++ltq_etop_mdio_rd(struct mii_bus *bus, int phy_addr, int phy_reg) ++{ ++ u32 val = MDIO_REQUEST | MDIO_READ | ++ ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) | ++ ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET); ++ ++ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) ++ ; ++ ltq_etop_w32(val, LTQ_ETOP_MDIO); ++ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST) ++ ; ++ val = ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_VAL_MASK; ++ return val; ++} ++ ++static void ++ltq_etop_mdio_link(struct net_device *dev) ++{ ++ /* nothing to do */ ++} ++ ++static int ++ltq_etop_mdio_probe(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ struct phy_device *phydev = NULL; ++ int phy_addr; ++ ++ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { ++ if (priv->mii_bus->phy_map[phy_addr]) { ++ phydev = priv->mii_bus->phy_map[phy_addr]; ++ break; ++ } ++ } ++ ++ if (!phydev) { ++ netdev_err(dev, "no PHY found\n"); ++ return -ENODEV; ++ } ++ ++ phydev = phy_connect(dev, dev_name(&phydev->dev), <q_etop_mdio_link, ++ 0, priv->pldata->mii_mode); ++ ++ 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_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); ++ ++ return 0; ++} ++ ++static int ++ltq_etop_mdio_init(struct net_device *dev) ++{ ++ struct ltq_etop_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_etop_mdio_rd; ++ priv->mii_bus->write = ltq_etop_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_etop_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_etop_mdio_cleanup(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ ++ phy_disconnect(priv->phydev); ++ mdiobus_unregister(priv->mii_bus); ++ kfree(priv->mii_bus->irq); ++ mdiobus_free(priv->mii_bus); ++} ++ ++static int ++ltq_etop_open(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ int i; ++ ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ struct ltq_etop_chan *ch = &priv->ch[i]; ++ ++ if (!IS_TX(i) && (!IS_RX(i))) ++ continue; ++ ltq_dma_open(&ch->dma); ++ napi_enable(&ch->napi); ++ } ++ phy_start(priv->phydev); ++ netif_tx_start_all_queues(dev); ++ return 0; ++} ++ ++static int ++ltq_etop_stop(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ int i; ++ ++ netif_tx_stop_all_queues(dev); ++ phy_stop(priv->phydev); ++ for (i = 0; i < MAX_DMA_CHAN; i++) { ++ struct ltq_etop_chan *ch = &priv->ch[i]; ++ ++ if (!IS_RX(i) && !IS_TX(i)) ++ continue; ++ napi_disable(&ch->napi); ++ ltq_dma_close(&ch->dma); ++ } ++ return 0; ++} ++ ++static int ++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]; ++ int len; ++ unsigned long flags; ++ u32 byte_offset; ++ ++ 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); ++ 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_etop_change_mtu(struct net_device *dev, int new_mtu) ++{ ++ int ret = eth_change_mtu(dev, new_mtu); ++ ++ if (!ret) { ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_etop_w32((ETOP_PLEN_UNDER << 16) | new_mtu, ++ LTQ_ETOP_IGPLEN); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ return ret; ++} ++ ++static int ++ltq_etop_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ ++ /* TODO: mii-toll reports "No MII transceiver present!." ?!*/ ++ return phy_mii_ioctl(priv->phydev, rq, cmd); ++} ++ ++static int ++ltq_etop_set_mac_address(struct net_device *dev, void *p) ++{ ++ int ret = eth_mac_addr(dev, p); ++ ++ if (!ret) { ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ unsigned long flags; ++ ++ /* store the mac for the unicast filter */ ++ spin_lock_irqsave(&priv->lock, flags); ++ ltq_etop_w32(*((u32 *)dev->dev_addr), LTQ_ETOP_MAC_DA0); ++ ltq_etop_w32(*((u16 *)&dev->dev_addr[4]) << 16, ++ LTQ_ETOP_MAC_DA1); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ } ++ return ret; ++} ++ ++static void ++ltq_etop_set_multicast_list(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ unsigned long flags; ++ ++ /* ensure that the unicast filter is not enabled in promiscious mode */ ++ spin_lock_irqsave(&priv->lock, flags); ++ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI)) ++ ltq_etop_w32_mask(ETOP_FTCU, 0, LTQ_ETOP_ENETS0); ++ else ++ ltq_etop_w32_mask(0, ETOP_FTCU, LTQ_ETOP_ENETS0); ++ spin_unlock_irqrestore(&priv->lock, flags); ++} ++ ++static u16 ++ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb) ++{ ++ /* we are currently only using the first queue */ ++ return 0; ++} ++ ++static int ++ltq_etop_init(struct net_device *dev) ++{ ++ struct ltq_etop_priv *priv = netdev_priv(dev); ++ struct sockaddr mac; ++ int err; ++ ++ ether_setup(dev); ++ dev->watchdog_timeo = 10 * HZ; ++ err = ltq_etop_hw_init(dev); ++ if (err) ++ goto err_hw; ++ ltq_etop_change_mtu(dev, 1500); ++ ++ memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr)); ++ if (!is_valid_ether_addr(mac.sa_data)) { ++ pr_warn("etop: invalid MAC, using random\n"); ++ random_ether_addr(mac.sa_data); ++ } ++ ++ err = ltq_etop_set_mac_address(dev, &mac); ++ if (err) ++ goto err_netdev; ++ ltq_etop_set_multicast_list(dev); ++ err = ltq_etop_mdio_init(dev); ++ if (err) ++ goto err_netdev; ++ return 0; ++ ++err_netdev: ++ unregister_netdev(dev); ++ free_netdev(dev); ++err_hw: ++ ltq_etop_hw_exit(dev); ++ return err; ++} ++ ++static void ++ltq_etop_tx_timeout(struct net_device *dev) ++{ ++ int err; ++ ++ ltq_etop_hw_exit(dev); ++ err = ltq_etop_hw_init(dev); ++ if (err) ++ goto err_hw; ++ dev->trans_start = jiffies; ++ netif_wake_queue(dev); ++ return; ++ ++err_hw: ++ ltq_etop_hw_exit(dev); ++ netdev_err(dev, "failed to restart etop after TX timeout\n"); ++} ++ ++static const struct net_device_ops ltq_eth_netdev_ops = { ++ .ndo_open = ltq_etop_open, ++ .ndo_stop = ltq_etop_stop, ++ .ndo_start_xmit = ltq_etop_tx, ++ .ndo_change_mtu = ltq_etop_change_mtu, ++ .ndo_do_ioctl = ltq_etop_ioctl, ++ .ndo_set_mac_address = ltq_etop_set_mac_address, ++ .ndo_validate_addr = eth_validate_addr, ++ .ndo_set_multicast_list = ltq_etop_set_multicast_list, ++ .ndo_select_queue = ltq_etop_select_queue, ++ .ndo_init = ltq_etop_init, ++ .ndo_tx_timeout = ltq_etop_tx_timeout, ++}; ++ ++static int __init ++ltq_etop_probe(struct platform_device *pdev) ++{ ++ struct net_device *dev; ++ struct ltq_etop_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 etop 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 etop resource\n"); ++ err = -EBUSY; ++ goto err_out; ++ } ++ ++ ltq_etop_membase = devm_ioremap_nocache(&pdev->dev, ++ res->start, resource_size(res)); ++ if (!ltq_etop_membase) { ++ dev_err(&pdev->dev, "failed to remap etop engine %d\n", ++ pdev->id); ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ 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); ++ priv->netdev = dev; ++ 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; ++ } ++ ++ 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_etop_remove(struct platform_device *pdev) ++{ ++ struct net_device *dev = platform_get_drvdata(pdev); ++ ++ if (dev) { ++ netif_tx_stop_all_queues(dev); ++ ltq_etop_hw_exit(dev); ++ ltq_etop_mdio_cleanup(dev); ++ unregister_netdev(dev); ++ } ++ return 0; ++} ++ ++static struct platform_driver ltq_mii_driver = { ++ .remove = __devexit_p(ltq_etop_remove), ++ .driver = { ++ .name = "ltq_etop", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++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_AUTHOR("John Crispin <blogic@openwrt.org>"); ++MODULE_DESCRIPTION("Lantiq SoC ETOP"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/lantiq/patches-2.6.39/0012-MIPS-Lantiq-Add-etop-board-support.patch b/target/linux/lantiq/patches-2.6.39/0012-MIPS-Lantiq-Add-etop-board-support.patch new file mode 100644 index 0000000..2bc4abd --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0012-MIPS-Lantiq-Add-etop-board-support.patch @@ -0,0 +1,50 @@ +From 72a9b536ef81f06bb8042abee0410458f5df93d2 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Fri, 6 May 2011 00:10:02 +0200 +Subject: [PATCH 12/13] MIPS: Lantiq: Add etop board support + +Register the etop platform device inside the machtype specific init code. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Signed-off-by: David Daney <ddaney@caviumnetworks.com> +Cc: linux-mips@linux-mips.org +Patchwork: https://patchwork.linux-mips.org/patch/2356/ +Patchwork: https://patchwork.linux-mips.org/patch/2370/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + arch/mips/lantiq/xway/mach-easy50712.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c +index e5e7e09..ea5027b 100644 +--- a/arch/mips/lantiq/xway/mach-easy50712.c ++++ b/arch/mips/lantiq/xway/mach-easy50712.c +@@ -12,6 +12,7 @@ + #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> +@@ -55,11 +56,16 @@ static struct ltq_pci_data ltq_pci_data = { + }, + }; + ++static struct ltq_eth_data ltq_eth_data = { ++ .mii_mode = PHY_INTERFACE_MODE_MII, ++}; ++ + static void __init easy50712_init(void) + { + ltq_register_gpio_stp(); + ltq_register_nor(&easy50712_flash_data); + ltq_register_pci(<q_pci_data); ++ ltq_register_etop(<q_eth_data); + } + + MIPS_MACHINE(LTQ_MACH_EASY50712, +-- +1.7.2.3 + diff --git a/target/linux/lantiq/patches-2.6.39/0013-MIPS-Lantiq-Add-watchdog-support.patch b/target/linux/lantiq/patches-2.6.39/0013-MIPS-Lantiq-Add-watchdog-support.patch new file mode 100644 index 0000000..5d07a63 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/0013-MIPS-Lantiq-Add-watchdog-support.patch @@ -0,0 +1,310 @@ +From 3466449c8f455da0cb646231602e6af16190f592 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 5 May 2011 23:00:23 +0200 +Subject: [PATCH 13/13] MIPS: Lantiq: Add watchdog support + +This patch adds the driver for the watchdog found inside the Lantiq SoC family. + +Signed-off-by: John Crispin <blogic@openwrt.org> +Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com> +Cc: Wim Van Sebroeck <wim@iguana.be> +Cc: linux-mips@linux-mips.org +Cc: linux-watchdog@vger.kernel.org +Patchwork: https://patchwork.linux-mips.org/patch/2327/ +Signed-off-by: Ralf Baechle <ralf@linux-mips.org> +--- + drivers/watchdog/Kconfig | 6 + + drivers/watchdog/Makefile | 1 + + drivers/watchdog/lantiq_wdt.c | 261 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 268 insertions(+), 0 deletions(-) + create mode 100644 drivers/watchdog/lantiq_wdt.c + +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -990,6 +990,12 @@ + To compile this driver as a loadable module, choose M here. + The module will be called bcm63xx_wdt. + ++config LANTIQ_WDT ++ tristate "Lantiq SoC watchdog" ++ depends on LANTIQ ++ help ++ Hardware driver for the Lantiq SoC Watchdog Timer. ++ + # PARISC Architecture + + # POWERPC Architecture +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -123,6 +123,7 @@ + obj-$(CONFIG_TXX9_WDT) += txx9wdt.o + obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o + octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o ++obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o + + # PARISC Architecture + +--- /dev/null ++++ b/drivers/watchdog/lantiq_wdt.c +@@ -0,0 +1,261 @@ ++/* ++ * 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> ++ * Based on EP93xx wdt driver ++ */ ++ ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/watchdog.h> ++#include <linux/platform_device.h> ++#include <linux/uaccess.h> ++#include <linux/clk.h> ++#include <linux/io.h> ++ ++#include <lantiq.h> ++ ++/* Section 3.4 of the datasheet ++ * The password sequence protects the WDT control register from unintended ++ * write actions, which might cause malfunction of the WDT. ++ * ++ * essentially the following two magic passwords need to be written to allow ++ * IO access to the WDT core ++ */ ++#define LTQ_WDT_PW1 0x00BE0000 ++#define LTQ_WDT_PW2 0x00DC0000 ++ ++#define LTQ_WDT_CR 0x0 /* watchdog control register */ ++#define LTQ_WDT_SR 0x8 /* watchdog status register */ ++ ++#define LTQ_WDT_SR_EN (0x1 << 31) /* enable bit */ ++#define LTQ_WDT_SR_PWD (0x3 << 26) /* turn on power */ ++#define LTQ_WDT_SR_CLKDIV (0x3 << 24) /* turn on clock and set */ ++ /* divider to 0x40000 */ ++#define LTQ_WDT_DIVIDER 0x40000 ++#define LTQ_MAX_TIMEOUT ((1 << 16) - 1) /* the reload field is 16 bit */ ++ ++static int nowayout = WATCHDOG_NOWAYOUT; ++ ++static void __iomem *ltq_wdt_membase; ++static unsigned long ltq_io_region_clk_rate; ++ ++static unsigned long ltq_wdt_bootstatus; ++static unsigned long ltq_wdt_in_use; ++static int ltq_wdt_timeout = 30; ++static int ltq_wdt_ok_to_close; ++ ++static void ++ltq_wdt_enable(void) ++{ ++ ltq_wdt_timeout = ltq_wdt_timeout * ++ (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000; ++ if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT) ++ ltq_wdt_timeout = LTQ_MAX_TIMEOUT; ++ ++ /* write the first password magic */ ++ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); ++ /* write the second magic plus the configuration and new timeout */ ++ ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV | ++ LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR); ++} ++ ++static void ++ltq_wdt_disable(void) ++{ ++ /* write the first password magic */ ++ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); ++ /* write the second password magic with no config ++ * this turns the watchdog off ++ */ ++ ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR); ++} ++ ++static ssize_t ++ltq_wdt_write(struct file *file, const char __user *data, ++ size_t len, loff_t *ppos) ++{ ++ if (len) { ++ if (!nowayout) { ++ size_t i; ++ ++ ltq_wdt_ok_to_close = 0; ++ for (i = 0; i != len; i++) { ++ char c; ++ ++ if (get_user(c, data + i)) ++ return -EFAULT; ++ if (c == 'V') ++ ltq_wdt_ok_to_close = 1; ++ else ++ ltq_wdt_ok_to_close = 0; ++ } ++ } ++ ltq_wdt_enable(); ++ } ++ ++ return len; ++} ++ ++static struct watchdog_info ident = { ++ .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | ++ WDIOF_CARDRESET, ++ .identity = "ltq_wdt", ++}; ++ ++static long ++ltq_wdt_ioctl(struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret = -ENOTTY; ++ ++ switch (cmd) { ++ case WDIOC_GETSUPPORT: ++ ret = copy_to_user((struct watchdog_info __user *)arg, &ident, ++ sizeof(ident)) ? -EFAULT : 0; ++ break; ++ ++ case WDIOC_GETBOOTSTATUS: ++ ret = put_user(ltq_wdt_bootstatus, (int __user *)arg); ++ break; ++ ++ case WDIOC_GETSTATUS: ++ ret = put_user(0, (int __user *)arg); ++ break; ++ ++ case WDIOC_SETTIMEOUT: ++ ret = get_user(ltq_wdt_timeout, (int __user *)arg); ++ if (!ret) ++ ltq_wdt_enable(); ++ /* intentional drop through */ ++ case WDIOC_GETTIMEOUT: ++ ret = put_user(ltq_wdt_timeout, (int __user *)arg); ++ break; ++ ++ case WDIOC_KEEPALIVE: ++ ltq_wdt_enable(); ++ ret = 0; ++ break; ++ } ++ return ret; ++} ++ ++static int ++ltq_wdt_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(0, <q_wdt_in_use)) ++ return -EBUSY; ++ ltq_wdt_in_use = 1; ++ ltq_wdt_enable(); ++ ++ return nonseekable_open(inode, file); ++} ++ ++static int ++ltq_wdt_release(struct inode *inode, struct file *file) ++{ ++ if (ltq_wdt_ok_to_close) ++ ltq_wdt_disable(); ++ else ++ pr_err("ltq_wdt: watchdog closed without warning\n"); ++ ltq_wdt_ok_to_close = 0; ++ clear_bit(0, <q_wdt_in_use); ++ ++ return 0; ++} ++ ++static const struct file_operations ltq_wdt_fops = { ++ .owner = THIS_MODULE, ++ .write = ltq_wdt_write, ++ .unlocked_ioctl = ltq_wdt_ioctl, ++ .open = ltq_wdt_open, ++ .release = ltq_wdt_release, ++ .llseek = no_llseek, ++}; ++ ++static struct miscdevice ltq_wdt_miscdev = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = <q_wdt_fops, ++}; ++ ++static int __init ++ltq_wdt_probe(struct platform_device *pdev) ++{ ++ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ struct clk *clk; ++ ++ if (!res) { ++ dev_err(&pdev->dev, "cannot obtain I/O memory region"); ++ return -ENOENT; ++ } ++ res = devm_request_mem_region(&pdev->dev, res->start, ++ resource_size(res), dev_name(&pdev->dev)); ++ if (!res) { ++ dev_err(&pdev->dev, "cannot request I/O memory region"); ++ return -EBUSY; ++ } ++ ltq_wdt_membase = devm_ioremap_nocache(&pdev->dev, res->start, ++ resource_size(res)); ++ if (!ltq_wdt_membase) { ++ dev_err(&pdev->dev, "cannot remap I/O memory region\n"); ++ return -ENOMEM; ++ } ++ ++ /* we do not need to enable the clock as it is always running */ ++ clk = clk_get(&pdev->dev, "io"); ++ WARN_ON(!clk); ++ ltq_io_region_clk_rate = clk_get_rate(clk); ++ clk_put(clk); ++ ++ if (ltq_reset_cause() == LTQ_RST_CAUSE_WDTRST) ++ ltq_wdt_bootstatus = WDIOF_CARDRESET; ++ ++ return misc_register(<q_wdt_miscdev); ++} ++ ++static int __devexit ++ltq_wdt_remove(struct platform_device *pdev) ++{ ++ misc_deregister(<q_wdt_miscdev); ++ ++ if (ltq_wdt_membase) ++ iounmap(ltq_wdt_membase); ++ ++ return 0; ++} ++ ++ ++static struct platform_driver ltq_wdt_driver = { ++ .remove = __devexit_p(ltq_wdt_remove), ++ .driver = { ++ .name = "ltq_wdt", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++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_param(nowayout, int, 0); ++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); ++ ++MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); ++MODULE_DESCRIPTION("Lantiq SoC Watchdog"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/target/linux/lantiq/patches-2.6.39/100-falcon_header.patch b/target/linux/lantiq/patches-2.6.39/100-falcon_header.patch new file mode 100644 index 0000000..f4da9ef --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/100-falcon_header.patch @@ -0,0 +1,13992 @@ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/falcon_irq.h +@@ -0,0 +1,277 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) 2010 Lantiq ++ */ ++#ifndef _FALCON_IRQ__ ++#define _FALCON_IRQ__ ++ ++#define INT_NUM_IRQ0 8 ++#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0) ++#define INT_NUM_IM1_IRL0 (INT_NUM_IM0_IRL0 + 32) ++#define INT_NUM_IM2_IRL0 (INT_NUM_IM1_IRL0 + 32) ++#define INT_NUM_IM3_IRL0 (INT_NUM_IM2_IRL0 + 32) ++#define INT_NUM_IM4_IRL0 (INT_NUM_IM3_IRL0 + 32) ++#define INT_NUM_EXTRA_START (INT_NUM_IM4_IRL0 + 32) ++#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0) ++ ++#define MIPS_CPU_TIMER_IRQ 7 ++ ++/* HOST IF Event Interrupt */ ++#define FALCON_IRQ_HOST (INT_NUM_IM0_IRL0 + 0) ++/* HOST IF Mailbox0 Receive Interrupt */ ++#define FALCON_IRQ_HOST_MB0_RX (INT_NUM_IM0_IRL0 + 1) ++/* HOST IF Mailbox0 Transmit Interrupt */ ++#define FALCON_IRQ_HOST_MB0_TX (INT_NUM_IM0_IRL0 + 2) ++/* HOST IF Mailbox1 Receive Interrupt */ ++#define FALCON_IRQ_HOST_MB1_RX (INT_NUM_IM0_IRL0 + 3) ++/* HOST IF Mailbox1 Transmit Interrupt */ ++#define FALCON_IRQ_HOST_MB1_TX (INT_NUM_IM0_IRL0 + 4) ++/* I2C Last Single Data Transfer Request */ ++#define FALCON_IRQ_I2C_LSREQ (INT_NUM_IM0_IRL0 + 8) ++/* I2C Single Data Transfer Request */ ++#define FALCON_IRQ_I2C_SREQ (INT_NUM_IM0_IRL0 + 9) ++/* I2C Last Burst Data Transfer Request */ ++#define FALCON_IRQ_I2C_LBREQ (INT_NUM_IM0_IRL0 + 10) ++/* I2C Burst Data Transfer Request */ ++#define FALCON_IRQ_I2C_BREQ (INT_NUM_IM0_IRL0 + 11) ++/* I2C Error Interrupt */ ++#define FALCON_IRQ_I2C_I2C_ERR (INT_NUM_IM0_IRL0 + 12) ++/* I2C Protocol Interrupt */ ++#define FALCON_IRQ_I2C_I2C_P (INT_NUM_IM0_IRL0 + 13) ++/* SSC Transmit Interrupt */ ++#define FALCON_IRQ_SSC_T (INT_NUM_IM0_IRL0 + 14) ++/* SSC Receive Interrupt */ ++#define FALCON_IRQ_SSC_R (INT_NUM_IM0_IRL0 + 15) ++/* SSC Error Interrupt */ ++#define FALCON_IRQ_SSC_E (INT_NUM_IM0_IRL0 + 16) ++/* SSC Frame Interrupt */ ++#define FALCON_IRQ_SSC_F (INT_NUM_IM0_IRL0 + 17) ++/* Advanced Encryption Standard Interrupt */ ++#define FALCON_IRQ_AES_AES (INT_NUM_IM0_IRL0 + 27) ++/* Secure Hash Algorithm Interrupt */ ++#define FALCON_IRQ_SHA_HASH (INT_NUM_IM0_IRL0 + 28) ++/* PCM Receive Interrupt */ ++#define FALCON_IRQ_PCM_RX (INT_NUM_IM0_IRL0 + 29) ++/* PCM Transmit Interrupt */ ++#define FALCON_IRQ_PCM_TX (INT_NUM_IM0_IRL0 + 30) ++/* PCM Transmit Crash Interrupt */ ++#define FALCON_IRQ_PCM_HW2_CRASH (INT_NUM_IM0_IRL0 + 31) ++ ++/* EBU Serial Flash Command Error */ ++#define FALCON_IRQ_EBU_SF_CMDERR (INT_NUM_IM1_IRL0 + 0) ++/* EBU Serial Flash Command Overwrite Error */ ++#define FALCON_IRQ_EBU_SF_COVERR (INT_NUM_IM1_IRL0 + 1) ++/* EBU Serial Flash Busy */ ++#define FALCON_IRQ_EBU_SF_BUSY (INT_NUM_IM1_IRL0 + 2) ++/* External Interrupt from GPIO P0 */ ++#define FALCON_IRQ_GPIO_P0 (INT_NUM_IM1_IRL0 + 4) ++/* External Interrupt from GPIO P1 */ ++#define FALCON_IRQ_GPIO_P1 (INT_NUM_IM1_IRL0 + 5) ++/* External Interrupt from GPIO P2 */ ++#define FALCON_IRQ_GPIO_P2 (INT_NUM_IM1_IRL0 + 6) ++/* External Interrupt from GPIO P3 */ ++#define FALCON_IRQ_GPIO_P3 (INT_NUM_IM1_IRL0 + 7) ++/* External Interrupt from GPIO P4 */ ++#define FALCON_IRQ_GPIO_P4 (INT_NUM_IM1_IRL0 + 8) ++/* 8kHz backup interrupt derived from core-PLL */ ++#define FALCON_IRQ_FSC_BKP (INT_NUM_IM1_IRL0 + 10) ++/* FSC Timer Interrupt 0 */ ++#define FALCON_IRQ_FSCT_CMP0 (INT_NUM_IM1_IRL0 + 11) ++/* FSC Timer Interrupt 1 */ ++#define FALCON_IRQ_FSCT_CMP1 (INT_NUM_IM1_IRL0 + 12) ++/* 8kHz root interrupt derived from GPON interface */ ++#define FALCON_IRQ_FSC_ROOT (INT_NUM_IM1_IRL0 + 13) ++/* Time of Day */ ++#define FALCON_IRQ_TOD (INT_NUM_IM1_IRL0 + 14) ++/* PMA Interrupt from IntNode of the 200MHz Domain */ ++#define FALCON_IRQ_PMA_200M (INT_NUM_IM1_IRL0 + 15) ++/* PMA Interrupt from IntNode of the TX Clk Domain */ ++#define FALCON_IRQ_PMA_TX (INT_NUM_IM1_IRL0 + 16) ++/* PMA Interrupt from IntNode of the RX Clk Domain */ ++#define FALCON_IRQ_PMA_RX (INT_NUM_IM1_IRL0 + 17) ++/* SYS1 Interrupt */ ++#define FALCON_IRQ_SYS1 (INT_NUM_IM1_IRL0 + 20) ++/* SYS GPE Interrupt */ ++#define FALCON_IRQ_SYS_GPE (INT_NUM_IM1_IRL0 + 21) ++/* Watchdog Access Error Interrupt */ ++#define FALCON_IRQ_WDT_AEIR (INT_NUM_IM1_IRL0 + 24) ++/* Watchdog Prewarning Interrupt */ ++#define FALCON_IRQ_WDT_PIR (INT_NUM_IM1_IRL0 + 25) ++/* SBIU interrupt */ ++#define FALCON_IRQ_SBIU0 (INT_NUM_IM1_IRL0 + 27) ++/* FPI Bus Control Unit Interrupt */ ++#define FALCON_IRQ_BCU0 (INT_NUM_IM1_IRL0 + 29) ++/* DDR Controller Interrupt */ ++#define FALCON_IRQ_DDR (INT_NUM_IM1_IRL0 + 30) ++/* Crossbar Error Interrupt */ ++#define FALCON_IRQ_XBAR_ERROR (INT_NUM_IM1_IRL0 + 31) ++ ++/* ICTRLL 0 Interrupt */ ++#define FALCON_IRQ_ICTRLL0 (INT_NUM_IM2_IRL0 + 0) ++/* ICTRLL 1 Interrupt */ ++#define FALCON_IRQ_ICTRLL1 (INT_NUM_IM2_IRL0 + 1) ++/* ICTRLL 2 Interrupt */ ++#define FALCON_IRQ_ICTRLL2 (INT_NUM_IM2_IRL0 + 2) ++/* ICTRLL 3 Interrupt */ ++#define FALCON_IRQ_ICTRLL3 (INT_NUM_IM2_IRL0 + 3) ++/* OCTRLL 0 Interrupt */ ++#define FALCON_IRQ_OCTRLL0 (INT_NUM_IM2_IRL0 + 4) ++/* OCTRLL 1 Interrupt */ ++#define FALCON_IRQ_OCTRLL1 (INT_NUM_IM2_IRL0 + 5) ++/* OCTRLL 2 Interrupt */ ++#define FALCON_IRQ_OCTRLL2 (INT_NUM_IM2_IRL0 + 6) ++/* OCTRLL 3 Interrupt */ ++#define FALCON_IRQ_OCTRLL3 (INT_NUM_IM2_IRL0 + 7) ++/* OCTRLG Interrupt */ ++#define FALCON_IRQ_OCTRLG (INT_NUM_IM2_IRL0 + 9) ++/* IQM Interrupt */ ++#define FALCON_IRQ_IQM (INT_NUM_IM2_IRL0 + 10) ++/* FSQM Interrupt */ ++#define FALCON_IRQ_FSQM (INT_NUM_IM2_IRL0 + 11) ++/* TMU Interrupt */ ++#define FALCON_IRQ_TMU (INT_NUM_IM2_IRL0 + 12) ++/* LINK1 Interrupt */ ++#define FALCON_IRQ_LINK1 (INT_NUM_IM2_IRL0 + 14) ++/* ICTRLC 0 Interrupt */ ++#define FALCON_IRQ_ICTRLC0 (INT_NUM_IM2_IRL0 + 16) ++/* ICTRLC 1 Interrupt */ ++#define FALCON_IRQ_ICTRLC1 (INT_NUM_IM2_IRL0 + 17) ++/* OCTRLC Interrupt */ ++#define FALCON_IRQ_OCTRLC (INT_NUM_IM2_IRL0 + 18) ++/* CONFIG Break Interrupt */ ++#define FALCON_IRQ_CONFIG_BREAK (INT_NUM_IM2_IRL0 + 19) ++/* CONFIG Interrupt */ ++#define FALCON_IRQ_CONFIG (INT_NUM_IM2_IRL0 + 20) ++/* Dispatcher Interrupt */ ++#define FALCON_IRQ_DISP (INT_NUM_IM2_IRL0 + 21) ++/* TBM Interrupt */ ++#define FALCON_IRQ_TBM (INT_NUM_IM2_IRL0 + 22) ++/* GTC Downstream Interrupt */ ++#define FALCON_IRQ_GTC_DS (INT_NUM_IM2_IRL0 + 29) ++/* GTC Upstream Interrupt */ ++#define FALCON_IRQ_GTC_US (INT_NUM_IM2_IRL0 + 30) ++/* EIM Interrupt */ ++#define FALCON_IRQ_EIM (INT_NUM_IM2_IRL0 + 31) ++ ++/* ASC0 Transmit Interrupt */ ++#define FALCON_IRQ_ASC0_T (INT_NUM_IM3_IRL0 + 0) ++/* ASC0 Receive Interrupt */ ++#define FALCON_IRQ_ASC0_R (INT_NUM_IM3_IRL0 + 1) ++/* ASC0 Error Interrupt */ ++#define FALCON_IRQ_ASC0_E (INT_NUM_IM3_IRL0 + 2) ++/* ASC0 Transmit Buffer Interrupt */ ++#define FALCON_IRQ_ASC0_TB (INT_NUM_IM3_IRL0 + 3) ++/* ASC0 Autobaud Start Interrupt */ ++#define FALCON_IRQ_ASC0_ABST (INT_NUM_IM3_IRL0 + 4) ++/* ASC0 Autobaud Detection Interrupt */ ++#define FALCON_IRQ_ASC0_ABDET (INT_NUM_IM3_IRL0 + 5) ++/* ASC1 Modem Status Interrupt */ ++#define FALCON_IRQ_ASC0_MS (INT_NUM_IM3_IRL0 + 6) ++/* ASC0 Soft Flow Control Interrupt */ ++#define FALCON_IRQ_ASC0_SFC (INT_NUM_IM3_IRL0 + 7) ++/* ASC1 Transmit Interrupt */ ++#define FALCON_IRQ_ASC1_T (INT_NUM_IM3_IRL0 + 8) ++/* ASC1 Receive Interrupt */ ++#define FALCON_IRQ_ASC1_R (INT_NUM_IM3_IRL0 + 9) ++/* ASC1 Error Interrupt */ ++#define FALCON_IRQ_ASC1_E (INT_NUM_IM3_IRL0 + 10) ++/* ASC1 Transmit Buffer Interrupt */ ++#define FALCON_IRQ_ASC1_TB (INT_NUM_IM3_IRL0 + 11) ++/* ASC1 Autobaud Start Interrupt */ ++#define FALCON_IRQ_ASC1_ABST (INT_NUM_IM3_IRL0 + 12) ++/* ASC1 Autobaud Detection Interrupt */ ++#define FALCON_IRQ_ASC1_ABDET (INT_NUM_IM3_IRL0 + 13) ++/* ASC1 Modem Status Interrupt */ ++#define FALCON_IRQ_ASC1_MS (INT_NUM_IM3_IRL0 + 14) ++/* ASC1 Soft Flow Control Interrupt */ ++#define FALCON_IRQ_ASC1_SFC (INT_NUM_IM3_IRL0 + 15) ++/* GPTC Timer/Counter 1A Interrupt */ ++#define FALCON_IRQ_GPTC_TC1A (INT_NUM_IM3_IRL0 + 16) ++/* GPTC Timer/Counter 1B Interrupt */ ++#define FALCON_IRQ_GPTC_TC1B (INT_NUM_IM3_IRL0 + 17) ++/* GPTC Timer/Counter 2A Interrupt */ ++#define FALCON_IRQ_GPTC_TC2A (INT_NUM_IM3_IRL0 + 18) ++/* GPTC Timer/Counter 2B Interrupt */ ++#define FALCON_IRQ_GPTC_TC2B (INT_NUM_IM3_IRL0 + 19) ++/* GPTC Timer/Counter 3A Interrupt */ ++#define FALCON_IRQ_GPTC_TC3A (INT_NUM_IM3_IRL0 + 20) ++/* GPTC Timer/Counter 3B Interrupt */ ++#define FALCON_IRQ_GPTC_TC3B (INT_NUM_IM3_IRL0 + 21) ++/* DFEV0, Channel 1 Transmit Interrupt */ ++#define FALCON_IRQ_DFEV0_2TX (INT_NUM_IM3_IRL0 + 26) ++/* DFEV0, Channel 1 Receive Interrupt */ ++#define FALCON_IRQ_DFEV0_2RX (INT_NUM_IM3_IRL0 + 27) ++/* DFEV0, Channel 1 General Purpose Interrupt */ ++#define FALCON_IRQ_DFEV0_2GP (INT_NUM_IM3_IRL0 + 28) ++/* DFEV0, Channel 0 Transmit Interrupt */ ++#define FALCON_IRQ_DFEV0_1TX (INT_NUM_IM3_IRL0 + 29) ++/* DFEV0, Channel 0 Receive Interrupt */ ++#define FALCON_IRQ_DFEV0_1RX (INT_NUM_IM3_IRL0 + 30) ++/* DFEV0, Channel 0 General Purpose Interrupt */ ++#define FALCON_IRQ_DFEV0_1GP (INT_NUM_IM3_IRL0 + 31) ++ ++/* ICTRLL 0 Error */ ++#define FALCON_IRQ_ICTRLL0_ERR (INT_NUM_IM4_IRL0 + 0) ++/* ICTRLL 1 Error */ ++#define FALCON_IRQ_ICTRLL1_ERR (INT_NUM_IM4_IRL0 + 1) ++/* ICTRLL 2 Error */ ++#define FALCON_IRQ_ICTRLL2_ERR (INT_NUM_IM4_IRL0 + 2) ++/* ICTRLL 3 Error */ ++#define FALCON_IRQ_ICTRLL3_ERR (INT_NUM_IM4_IRL0 + 3) ++/* OCTRLL 0 Error */ ++#define FALCON_IRQ_OCTRLL0_ERR (INT_NUM_IM4_IRL0 + 4) ++/* OCTRLL 1 Error */ ++#define FALCON_IRQ_OCTRLL1_ERR (INT_NUM_IM4_IRL0 + 5) ++/* OCTRLL 2 Error */ ++#define FALCON_IRQ_OCTRLL2_ERR (INT_NUM_IM4_IRL0 + 6) ++/* OCTRLL 3 Error */ ++#define FALCON_IRQ_OCTRLL3_ERR (INT_NUM_IM4_IRL0 + 7) ++/* ICTRLG Error */ ++#define FALCON_IRQ_ICTRLG_ERR (INT_NUM_IM4_IRL0 + 8) ++/* OCTRLG Error */ ++#define FALCON_IRQ_OCTRLG_ERR (INT_NUM_IM4_IRL0 + 9) ++/* IQM Error */ ++#define FALCON_IRQ_IQM_ERR (INT_NUM_IM4_IRL0 + 10) ++/* FSQM Error */ ++#define FALCON_IRQ_FSQM_ERR (INT_NUM_IM4_IRL0 + 11) ++/* TMU Error */ ++#define FALCON_IRQ_TMU_ERR (INT_NUM_IM4_IRL0 + 12) ++/* MPS Status Interrupt #0 (VPE1 to VPE0) */ ++#define FALCON_IRQ_MPS_IR0 (INT_NUM_IM4_IRL0 + 14) ++/* MPS Status Interrupt #1 (VPE1 to VPE0) */ ++#define FALCON_IRQ_MPS_IR1 (INT_NUM_IM4_IRL0 + 15) ++/* MPS Status Interrupt #2 (VPE1 to VPE0) */ ++#define FALCON_IRQ_MPS_IR2 (INT_NUM_IM4_IRL0 + 16) ++/* MPS Status Interrupt #3 (VPE1 to VPE0) */ ++#define FALCON_IRQ_MPS_IR3 (INT_NUM_IM4_IRL0 + 17) ++/* MPS Status Interrupt #4 (VPE1 to VPE0) */ ++#define FALCON_IRQ_MPS_IR4 (INT_NUM_IM4_IRL0 + 18) ++/* MPS Status Interrupt #5 (VPE1 to VPE0) */ ++#define FALCON_IRQ_MPS_IR5 (INT_NUM_IM4_IRL0 + 19) ++/* MPS Status Interrupt #6 (VPE1 to VPE0) */ ++#define FALCON_IRQ_MPS_IR6 (INT_NUM_IM4_IRL0 + 20) ++/* MPS Status Interrupt #7 (VPE1 to VPE0) */ ++#define FALCON_IRQ_MPS_IR7 (INT_NUM_IM4_IRL0 + 21) ++/* MPS Status Interrupt #8 (VPE1 to VPE0) */ ++#define FALCON_IRQ_MPS_IR8 (INT_NUM_IM4_IRL0 + 22) ++/* VPE0 Exception Level Flag Interrupt */ ++#define FALCON_IRQ_VPE0_EXL (INT_NUM_IM4_IRL0 + 29) ++/* VPE0 Error Level Flag Interrupt */ ++#define FALCON_IRQ_VPE0_ERL (INT_NUM_IM4_IRL0 + 30) ++/* VPE0 Performance Monitoring Counter Interrupt */ ++#define FALCON_IRQ_VPE0_PMCIR (INT_NUM_IM4_IRL0 + 31) ++ ++#endif /* _FALCON_IRQ__ */ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/gpon_reg_base.h +@@ -0,0 +1,376 @@ ++/****************************************************************************** ++ ++ Copyright (c) 2010 ++ Lantiq Deutschland GmbH ++ ++ For licensing information, see the file 'LICENSE' in the root folder of ++ this software module. ++ ++******************************************************************************/ ++ ++#ifndef _gpon_reg_base_h ++#define _gpon_reg_base_h ++ ++/** \addtogroup GPON_BASE ++ @{ ++*/ ++ ++#ifndef KSEG1 ++#define KSEG1 0xA0000000 ++#endif ++ ++/** address range for ebu ++ 0x18000000--0x180000FF */ ++#define GPON_EBU_BASE (KSEG1 | 0x18000000) ++#define GPON_EBU_END (KSEG1 | 0x180000FF) ++#define GPON_EBU_SIZE 0x00000100 ++/** address range for gpearb ++ 0x1D400100--0x1D4001FF */ ++#define GPON_GPEARB_BASE (KSEG1 | 0x1D400100) ++#define GPON_GPEARB_END (KSEG1 | 0x1D4001FF) ++#define GPON_GPEARB_SIZE 0x00000100 ++/** address range for tmu ++ 0x1D404000--0x1D404FFF */ ++#define GPON_TMU_BASE (KSEG1 | 0x1D404000) ++#define GPON_TMU_END (KSEG1 | 0x1D404FFF) ++#define GPON_TMU_SIZE 0x00001000 ++/** address range for iqm ++ 0x1D410000--0x1D41FFFF */ ++#define GPON_IQM_BASE (KSEG1 | 0x1D410000) ++#define GPON_IQM_END (KSEG1 | 0x1D41FFFF) ++#define GPON_IQM_SIZE 0x00010000 ++/** address range for octrlg ++ 0x1D420000--0x1D42FFFF */ ++#define GPON_OCTRLG_BASE (KSEG1 | 0x1D420000) ++#define GPON_OCTRLG_END (KSEG1 | 0x1D42FFFF) ++#define GPON_OCTRLG_SIZE 0x00010000 ++/** address range for octrll0 ++ 0x1D440000--0x1D4400FF */ ++#define GPON_OCTRLL0_BASE (KSEG1 | 0x1D440000) ++#define GPON_OCTRLL0_END (KSEG1 | 0x1D4400FF) ++#define GPON_OCTRLL0_SIZE 0x00000100 ++/** address range for octrll1 ++ 0x1D440100--0x1D4401FF */ ++#define GPON_OCTRLL1_BASE (KSEG1 | 0x1D440100) ++#define GPON_OCTRLL1_END (KSEG1 | 0x1D4401FF) ++#define GPON_OCTRLL1_SIZE 0x00000100 ++/** address range for octrll2 ++ 0x1D440200--0x1D4402FF */ ++#define GPON_OCTRLL2_BASE (KSEG1 | 0x1D440200) ++#define GPON_OCTRLL2_END (KSEG1 | 0x1D4402FF) ++#define GPON_OCTRLL2_SIZE 0x00000100 ++/** address range for octrll3 ++ 0x1D440300--0x1D4403FF */ ++#define GPON_OCTRLL3_BASE (KSEG1 | 0x1D440300) ++#define GPON_OCTRLL3_END (KSEG1 | 0x1D4403FF) ++#define GPON_OCTRLL3_SIZE 0x00000100 ++/** address range for octrlc ++ 0x1D441000--0x1D4410FF */ ++#define GPON_OCTRLC_BASE (KSEG1 | 0x1D441000) ++#define GPON_OCTRLC_END (KSEG1 | 0x1D4410FF) ++#define GPON_OCTRLC_SIZE 0x00000100 ++/** address range for ictrlg ++ 0x1D450000--0x1D45FFFF */ ++#define GPON_ICTRLG_BASE (KSEG1 | 0x1D450000) ++#define GPON_ICTRLG_END (KSEG1 | 0x1D45FFFF) ++#define GPON_ICTRLG_SIZE 0x00010000 ++/** address range for ictrll0 ++ 0x1D460000--0x1D4601FF */ ++#define GPON_ICTRLL0_BASE (KSEG1 | 0x1D460000) ++#define GPON_ICTRLL0_END (KSEG1 | 0x1D4601FF) ++#define GPON_ICTRLL0_SIZE 0x00000200 ++/** address range for ictrll1 ++ 0x1D460200--0x1D4603FF */ ++#define GPON_ICTRLL1_BASE (KSEG1 | 0x1D460200) ++#define GPON_ICTRLL1_END (KSEG1 | 0x1D4603FF) ++#define GPON_ICTRLL1_SIZE 0x00000200 ++/** address range for ictrll2 ++ 0x1D460400--0x1D4605FF */ ++#define GPON_ICTRLL2_BASE (KSEG1 | 0x1D460400) ++#define GPON_ICTRLL2_END (KSEG1 | 0x1D4605FF) ++#define GPON_ICTRLL2_SIZE 0x00000200 ++/** address range for ictrll3 ++ 0x1D460600--0x1D4607FF */ ++#define GPON_ICTRLL3_BASE (KSEG1 | 0x1D460600) ++#define GPON_ICTRLL3_END (KSEG1 | 0x1D4607FF) ++#define GPON_ICTRLL3_SIZE 0x00000200 ++/** address range for ictrlc0 ++ 0x1D461000--0x1D4610FF */ ++#define GPON_ICTRLC0_BASE (KSEG1 | 0x1D461000) ++#define GPON_ICTRLC0_END (KSEG1 | 0x1D4610FF) ++#define GPON_ICTRLC0_SIZE 0x00000100 ++/** address range for ictrlc1 ++ 0x1D461100--0x1D4611FF */ ++#define GPON_ICTRLC1_BASE (KSEG1 | 0x1D461100) ++#define GPON_ICTRLC1_END (KSEG1 | 0x1D4611FF) ++#define GPON_ICTRLC1_SIZE 0x00000100 ++/** address range for fsqm ++ 0x1D500000--0x1D5FFFFF */ ++#define GPON_FSQM_BASE (KSEG1 | 0x1D500000) ++#define GPON_FSQM_END (KSEG1 | 0x1D5FFFFF) ++#define GPON_FSQM_SIZE 0x00100000 ++/** address range for pctrl ++ 0x1D600000--0x1D6001FF */ ++#define GPON_PCTRL_BASE (KSEG1 | 0x1D600000) ++#define GPON_PCTRL_END (KSEG1 | 0x1D6001FF) ++#define GPON_PCTRL_SIZE 0x00000200 ++/** address range for link0 ++ 0x1D600200--0x1D6002FF */ ++#define GPON_LINK0_BASE (KSEG1 | 0x1D600200) ++#define GPON_LINK0_END (KSEG1 | 0x1D6002FF) ++#define GPON_LINK0_SIZE 0x00000100 ++/** address range for link1 ++ 0x1D600300--0x1D6003FF */ ++#define GPON_LINK1_BASE (KSEG1 | 0x1D600300) ++#define GPON_LINK1_END (KSEG1 | 0x1D6003FF) ++#define GPON_LINK1_SIZE 0x00000100 ++/** address range for link2 ++ 0x1D600400--0x1D6004FF */ ++#define GPON_LINK2_BASE (KSEG1 | 0x1D600400) ++#define GPON_LINK2_END (KSEG1 | 0x1D6004FF) ++#define GPON_LINK2_SIZE 0x00000100 ++/** address range for disp ++ 0x1D600500--0x1D6005FF */ ++#define GPON_DISP_BASE (KSEG1 | 0x1D600500) ++#define GPON_DISP_END (KSEG1 | 0x1D6005FF) ++#define GPON_DISP_SIZE 0x00000100 ++/** address range for merge ++ 0x1D600600--0x1D6006FF */ ++#define GPON_MERGE_BASE (KSEG1 | 0x1D600600) ++#define GPON_MERGE_END (KSEG1 | 0x1D6006FF) ++#define GPON_MERGE_SIZE 0x00000100 ++/** address range for tbm ++ 0x1D600700--0x1D6007FF */ ++#define GPON_TBM_BASE (KSEG1 | 0x1D600700) ++#define GPON_TBM_END (KSEG1 | 0x1D6007FF) ++#define GPON_TBM_SIZE 0x00000100 ++/** address range for pe0 ++ 0x1D610000--0x1D61FFFF */ ++#define GPON_PE0_BASE (KSEG1 | 0x1D610000) ++#define GPON_PE0_END (KSEG1 | 0x1D61FFFF) ++#define GPON_PE0_SIZE 0x00010000 ++/** address range for pe1 ++ 0x1D620000--0x1D62FFFF */ ++#define GPON_PE1_BASE (KSEG1 | 0x1D620000) ++#define GPON_PE1_END (KSEG1 | 0x1D62FFFF) ++#define GPON_PE1_SIZE 0x00010000 ++/** address range for pe2 ++ 0x1D630000--0x1D63FFFF */ ++#define GPON_PE2_BASE (KSEG1 | 0x1D630000) ++#define GPON_PE2_END (KSEG1 | 0x1D63FFFF) ++#define GPON_PE2_SIZE 0x00010000 ++/** address range for pe3 ++ 0x1D640000--0x1D64FFFF */ ++#define GPON_PE3_BASE (KSEG1 | 0x1D640000) ++#define GPON_PE3_END (KSEG1 | 0x1D64FFFF) ++#define GPON_PE3_SIZE 0x00010000 ++/** address range for pe4 ++ 0x1D650000--0x1D65FFFF */ ++#define GPON_PE4_BASE (KSEG1 | 0x1D650000) ++#define GPON_PE4_END (KSEG1 | 0x1D65FFFF) ++#define GPON_PE4_SIZE 0x00010000 ++/** address range for pe5 ++ 0x1D660000--0x1D66FFFF */ ++#define GPON_PE5_BASE (KSEG1 | 0x1D660000) ++#define GPON_PE5_END (KSEG1 | 0x1D66FFFF) ++#define GPON_PE5_SIZE 0x00010000 ++/** address range for sys_gpe ++ 0x1D700000--0x1D7000FF */ ++#define GPON_SYS_GPE_BASE (KSEG1 | 0x1D700000) ++#define GPON_SYS_GPE_END (KSEG1 | 0x1D7000FF) ++#define GPON_SYS_GPE_SIZE 0x00000100 ++/** address range for eim ++ 0x1D800000--0x1D800FFF */ ++#define GPON_EIM_BASE (KSEG1 | 0x1D800000) ++#define GPON_EIM_END (KSEG1 | 0x1D800FFF) ++#define GPON_EIM_SIZE 0x00001000 ++/** address range for sxgmii ++ 0x1D808800--0x1D8088FF */ ++#define GPON_SXGMII_BASE (KSEG1 | 0x1D808800) ++#define GPON_SXGMII_END (KSEG1 | 0x1D8088FF) ++#define GPON_SXGMII_SIZE 0x00000100 ++/** address range for sgmii ++ 0x1D808C00--0x1D808CFF */ ++#define GPON_SGMII_BASE (KSEG1 | 0x1D808C00) ++#define GPON_SGMII_END (KSEG1 | 0x1D808CFF) ++#define GPON_SGMII_SIZE 0x00000100 ++/** address range for gpio0 ++ 0x1D810000--0x1D81007F */ ++#define GPON_GPIO0_BASE (KSEG1 | 0x1D810000) ++#define GPON_GPIO0_END (KSEG1 | 0x1D81007F) ++#define GPON_GPIO0_SIZE 0x00000080 ++/** address range for gpio2 ++ 0x1D810100--0x1D81017F */ ++#define GPON_GPIO2_BASE (KSEG1 | 0x1D810100) ++#define GPON_GPIO2_END (KSEG1 | 0x1D81017F) ++#define GPON_GPIO2_SIZE 0x00000080 ++/** address range for sys_eth ++ 0x1DB00000--0x1DB000FF */ ++#define GPON_SYS_ETH_BASE (KSEG1 | 0x1DB00000) ++#define GPON_SYS_ETH_END (KSEG1 | 0x1DB000FF) ++#define GPON_SYS_ETH_SIZE 0x00000100 ++/** address range for padctrl0 ++ 0x1DB01000--0x1DB010FF */ ++#define GPON_PADCTRL0_BASE (KSEG1 | 0x1DB01000) ++#define GPON_PADCTRL0_END (KSEG1 | 0x1DB010FF) ++#define GPON_PADCTRL0_SIZE 0x00000100 ++/** address range for padctrl2 ++ 0x1DB02000--0x1DB020FF */ ++#define GPON_PADCTRL2_BASE (KSEG1 | 0x1DB02000) ++#define GPON_PADCTRL2_END (KSEG1 | 0x1DB020FF) ++#define GPON_PADCTRL2_SIZE 0x00000100 ++/** address range for gtc ++ 0x1DC05000--0x1DC052D4 */ ++#define GPON_GTC_BASE (KSEG1 | 0x1DC05000) ++#define GPON_GTC_END (KSEG1 | 0x1DC052D4) ++#define GPON_GTC_SIZE 0x000002D5 ++/** address range for pma ++ 0x1DD00000--0x1DD003FF */ ++#define GPON_PMA_BASE (KSEG1 | 0x1DD00000) ++#define GPON_PMA_END (KSEG1 | 0x1DD003FF) ++#define GPON_PMA_SIZE 0x00000400 ++/** address range for fcsic ++ 0x1DD00600--0x1DD0061F */ ++#define GPON_FCSIC_BASE (KSEG1 | 0x1DD00600) ++#define GPON_FCSIC_END (KSEG1 | 0x1DD0061F) ++#define GPON_FCSIC_SIZE 0x00000020 ++/** address range for pma_int200 ++ 0x1DD00700--0x1DD0070F */ ++#define GPON_PMA_INT200_BASE (KSEG1 | 0x1DD00700) ++#define GPON_PMA_INT200_END (KSEG1 | 0x1DD0070F) ++#define GPON_PMA_INT200_SIZE 0x00000010 ++/** address range for pma_inttx ++ 0x1DD00720--0x1DD0072F */ ++#define GPON_PMA_INTTX_BASE (KSEG1 | 0x1DD00720) ++#define GPON_PMA_INTTX_END (KSEG1 | 0x1DD0072F) ++#define GPON_PMA_INTTX_SIZE 0x00000010 ++/** address range for pma_intrx ++ 0x1DD00740--0x1DD0074F */ ++#define GPON_PMA_INTRX_BASE (KSEG1 | 0x1DD00740) ++#define GPON_PMA_INTRX_END (KSEG1 | 0x1DD0074F) ++#define GPON_PMA_INTRX_SIZE 0x00000010 ++/** address range for gtc_pma ++ 0x1DEFFF00--0x1DEFFFFF */ ++#define GPON_GTC_PMA_BASE (KSEG1 | 0x1DEFFF00) ++#define GPON_GTC_PMA_END (KSEG1 | 0x1DEFFFFF) ++#define GPON_GTC_PMA_SIZE 0x00000100 ++/** address range for sys ++ 0x1DF00000--0x1DF000FF */ ++#define GPON_SYS_BASE (KSEG1 | 0x1DF00000) ++#define GPON_SYS_END (KSEG1 | 0x1DF000FF) ++#define GPON_SYS_SIZE 0x00000100 ++/** address range for asc1 ++ 0x1E100B00--0x1E100BFF */ ++#define GPON_ASC1_BASE (KSEG1 | 0x1E100B00) ++#define GPON_ASC1_END (KSEG1 | 0x1E100BFF) ++#define GPON_ASC1_SIZE 0x00000100 ++/** address range for asc0 ++ 0x1E100C00--0x1E100CFF */ ++#define GPON_ASC0_BASE (KSEG1 | 0x1E100C00) ++#define GPON_ASC0_END (KSEG1 | 0x1E100CFF) ++#define GPON_ASC0_SIZE 0x00000100 ++/** address range for i2c ++ 0x1E200000--0x1E20FFFF */ ++#define GPON_I2C_BASE (KSEG1 | 0x1E200000) ++#define GPON_I2C_END (KSEG1 | 0x1E20FFFF) ++#define GPON_I2C_SIZE 0x00010000 ++/** address range for gpio1 ++ 0x1E800100--0x1E80017F */ ++#define GPON_GPIO1_BASE (KSEG1 | 0x1E800100) ++#define GPON_GPIO1_END (KSEG1 | 0x1E80017F) ++#define GPON_GPIO1_SIZE 0x00000080 ++/** address range for gpio3 ++ 0x1E800200--0x1E80027F */ ++#define GPON_GPIO3_BASE (KSEG1 | 0x1E800200) ++#define GPON_GPIO3_END (KSEG1 | 0x1E80027F) ++#define GPON_GPIO3_SIZE 0x00000080 ++/** address range for gpio4 ++ 0x1E800300--0x1E80037F */ ++#define GPON_GPIO4_BASE (KSEG1 | 0x1E800300) ++#define GPON_GPIO4_END (KSEG1 | 0x1E80037F) ++#define GPON_GPIO4_SIZE 0x00000080 ++/** address range for padctrl1 ++ 0x1E800400--0x1E8004FF */ ++#define GPON_PADCTRL1_BASE (KSEG1 | 0x1E800400) ++#define GPON_PADCTRL1_END (KSEG1 | 0x1E8004FF) ++#define GPON_PADCTRL1_SIZE 0x00000100 ++/** address range for padctrl3 ++ 0x1E800500--0x1E8005FF */ ++#define GPON_PADCTRL3_BASE (KSEG1 | 0x1E800500) ++#define GPON_PADCTRL3_END (KSEG1 | 0x1E8005FF) ++#define GPON_PADCTRL3_SIZE 0x00000100 ++/** address range for padctrl4 ++ 0x1E800600--0x1E8006FF */ ++#define GPON_PADCTRL4_BASE (KSEG1 | 0x1E800600) ++#define GPON_PADCTRL4_END (KSEG1 | 0x1E8006FF) ++#define GPON_PADCTRL4_SIZE 0x00000100 ++/** address range for status ++ 0x1E802000--0x1E80207F */ ++#define GPON_STATUS_BASE (KSEG1 | 0x1E802000) ++#define GPON_STATUS_END (KSEG1 | 0x1E80207F) ++#define GPON_STATUS_SIZE 0x00000080 ++/** address range for dcdc_1v0 ++ 0x1E803000--0x1E8033FF */ ++#define GPON_DCDC_1V0_BASE (KSEG1 | 0x1E803000) ++#define GPON_DCDC_1V0_END (KSEG1 | 0x1E8033FF) ++#define GPON_DCDC_1V0_SIZE 0x00000400 ++/** address range for dcdc_ddr ++ 0x1E804000--0x1E8043FF */ ++#define GPON_DCDC_DDR_BASE (KSEG1 | 0x1E804000) ++#define GPON_DCDC_DDR_END (KSEG1 | 0x1E8043FF) ++#define GPON_DCDC_DDR_SIZE 0x00000400 ++/** address range for dcdc_apd ++ 0x1E805000--0x1E8053FF */ ++#define GPON_DCDC_APD_BASE (KSEG1 | 0x1E805000) ++#define GPON_DCDC_APD_END (KSEG1 | 0x1E8053FF) ++#define GPON_DCDC_APD_SIZE 0x00000400 ++/** address range for sys1 ++ 0x1EF00000--0x1EF000FF */ ++#define GPON_SYS1_BASE (KSEG1 | 0x1EF00000) ++#define GPON_SYS1_END (KSEG1 | 0x1EF000FF) ++#define GPON_SYS1_SIZE 0x00000100 ++/** address range for sbs0ctrl ++ 0x1F080000--0x1F0801FF */ ++#define GPON_SBS0CTRL_BASE (KSEG1 | 0x1F080000) ++#define GPON_SBS0CTRL_END (KSEG1 | 0x1F0801FF) ++#define GPON_SBS0CTRL_SIZE 0x00000200 ++/** address range for sbs0red ++ 0x1F080200--0x1F08027F */ ++#define GPON_SBS0RED_BASE (KSEG1 | 0x1F080200) ++#define GPON_SBS0RED_END (KSEG1 | 0x1F08027F) ++#define GPON_SBS0RED_SIZE 0x00000080 ++/** address range for sbs0ram ++ 0x1F200000--0x1F32FFFF */ ++#define GPON_SBS0RAM_BASE (KSEG1 | 0x1F200000) ++#define GPON_SBS0RAM_END (KSEG1 | 0x1F32FFFF) ++#define GPON_SBS0RAM_SIZE 0x00130000 ++/** address range for ddrdb ++ 0x1F701000--0x1F701FFF */ ++#define GPON_DDRDB_BASE (KSEG1 | 0x1F701000) ++#define GPON_DDRDB_END (KSEG1 | 0x1F701FFF) ++#define GPON_DDRDB_SIZE 0x00001000 ++/** address range for sbiu ++ 0x1F880000--0x1F8800FF */ ++#define GPON_SBIU_BASE (KSEG1 | 0x1F880000) ++#define GPON_SBIU_END (KSEG1 | 0x1F8800FF) ++#define GPON_SBIU_SIZE 0x00000100 ++/** address range for icu0 ++ 0x1F880200--0x1F8802DF */ ++#define GPON_ICU0_BASE (KSEG1 | 0x1F880200) ++#define GPON_ICU0_END (KSEG1 | 0x1F8802DF) ++#define GPON_ICU0_SIZE 0x000000E0 ++/** address range for icu1 ++ 0x1F880300--0x1F8803DF */ ++#define GPON_ICU1_BASE (KSEG1 | 0x1F880300) ++#define GPON_ICU1_END (KSEG1 | 0x1F8803DF) ++#define GPON_ICU1_SIZE 0x000000E0 ++/** address range for wdt ++ 0x1F8803F0--0x1F8803FF */ ++#define GPON_WDT_BASE (KSEG1 | 0x1F8803F0) ++#define GPON_WDT_END (KSEG1 | 0x1F8803FF) ++#define GPON_WDT_SIZE 0x00000010 ++ ++/*! @} */ /* GPON_BASE */ ++ ++#endif /* _gpon_reg_base_h */ ++ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/i2c_reg.h +@@ -0,0 +1,830 @@ ++/****************************************************************************** ++ ++ Copyright (c) 2010 ++ Lantiq Deutschland GmbH ++ ++ For licensing information, see the file 'LICENSE' in the root folder of ++ this software module. ++ ++******************************************************************************/ ++ ++#ifndef _i2c_reg_h ++#define _i2c_reg_h ++ ++/** \addtogroup I2C_REGISTER ++ @{ ++*/ ++/* access macros */ ++#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 i2c_r32_table(reg, idx) reg_r32_table(i2c->reg, idx) ++#define i2c_w32_table(val, reg, idx) reg_w32_table(val, i2c->reg, idx) ++#define i2c_w32_table_mask(clear, set, reg, idx) reg_w32_table_mask(clear, set, i2c->reg, idx) ++#define i2c_adr_table(reg, idx) adr_table(i2c->reg, idx) ++ ++ ++/** 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 */ ++}; ++ ++ ++/* Fields of "I2C Kernel Clock Control Register" */ ++/** Clock Divider for Optional Run Mode (AHB peripherals) ++ Max 8-bit divider value. Note: As long as the new divider value ORMC is not valid, the register returns 0x0000 00xx on reading. */ ++#define I2C_CLC_ORMC_MASK 0x00FF0000 ++/** field offset */ ++#define I2C_CLC_ORMC_OFFSET 16 ++/** Clock Divider for Normal Run Mode ++ Max 8-bit divider value. IF RMC is 0 the module is disabled. Note: As long as the new divider value RMC is not valid, the register returns 0x0000 00xx on reading. */ ++#define I2C_CLC_RMC_MASK 0x0000FF00 ++/** field offset */ ++#define I2C_CLC_RMC_OFFSET 8 ++/** Fast Shut-Off Enable Bit */ ++#define I2C_CLC_FSOE 0x00000020 ++/* Disable ++#define I2C_CLC_FSOE_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_CLC_FSOE_EN 0x00000020 ++/** Suspend Bit Write Enable for OCDS */ ++#define I2C_CLC_SBWE 0x00000010 ++/* Disable ++#define I2C_CLC_SBWE_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_CLC_SBWE_EN 0x00000010 ++/** Disable External Request Disable */ ++#define I2C_CLC_EDIS 0x00000008 ++/* Enable ++#define I2C_CLC_EDIS_EN 0x00000000 */ ++/** Disable */ ++#define I2C_CLC_EDIS_DIS 0x00000008 ++/** Suspend Enable Bit for OCDS */ ++#define I2C_CLC_SPEN 0x00000004 ++/* Disable ++#define I2C_CLC_SPEN_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_CLC_SPEN_EN 0x00000004 ++/** Disable Status Bit ++ Bit DISS can be modified only by writing to bit DISR */ ++#define I2C_CLC_DISS 0x00000002 ++/* Enable ++#define I2C_CLC_DISS_EN 0x00000000 */ ++/** Disable */ ++#define I2C_CLC_DISS_DIS 0x00000002 ++/** Disable Request Bit */ ++#define I2C_CLC_DISR 0x00000001 ++/* Module disable not requested ++#define I2C_CLC_DISR_OFF 0x00000000 */ ++/** Module disable requested */ ++#define I2C_CLC_DISR_ON 0x00000001 ++ ++/* Fields of "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 ++ ++/* Fields of "I2C RUN Control Register" */ ++/** Enabling I2C Interface ++ Only when this bit is set to zero, the configuration registers of the I2C peripheral are writable by SW. */ ++#define I2C_RUN_CTRL_RUN 0x00000001 ++/* Disable ++#define I2C_RUN_CTRL_RUN_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_RUN_CTRL_RUN_EN 0x00000001 ++ ++/* Fields of "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 ++/* No-Operation ++#define I2C_ENDD_CTRL_SETEND_NOP 0x00000000 */ ++/** Master Receives Bytes */ ++#define I2C_ENDD_CTRL_SETEND_MRB 0x00000002 ++/** Set Restart Condition */ ++#define I2C_ENDD_CTRL_SETRSC 0x00000001 ++/* No-Operation ++#define I2C_ENDD_CTRL_SETRSC_NOP 0x00000000 */ ++/** Master Restart */ ++#define I2C_ENDD_CTRL_SETRSC_RESTART 0x00000001 ++ ++/* Fields of "I2C Fractional Divider Configuration Register" */ ++/** Decrement Value of fractional divider */ ++#define I2C_FDIV_CFG_INC_MASK 0x00FF0000 ++/** field offset */ ++#define I2C_FDIV_CFG_INC_OFFSET 16 ++/** Increment Value of fractional divider */ ++#define I2C_FDIV_CFG_DEC_MASK 0x000007FF ++/** field offset */ ++#define I2C_FDIV_CFG_DEC_OFFSET 0 ++ ++/* Fields of "I2C Fractional Divider (highspeed mode) Configuration Register" */ ++/** Decrement Value of fractional divider */ ++#define I2C_FDIV_HIGH_CFG_INC_MASK 0x00FF0000 ++/** field offset */ ++#define I2C_FDIV_HIGH_CFG_INC_OFFSET 16 ++/** Increment Value of fractional divider */ ++#define I2C_FDIV_HIGH_CFG_DEC_MASK 0x000007FF ++/** field offset */ ++#define I2C_FDIV_HIGH_CFG_DEC_OFFSET 0 ++ ++/* Fields of "I2C Address Configuration Register" */ ++/** Stop on Packet End ++ If device works as receiver a not acknowledge is generated in both cases. After successful transmission of a master code (during high speed mode) SOPE is not considered till a stop condition is manually generated by SETEND. */ ++#define I2C_ADDR_CFG_SOPE 0x00200000 ++/* Disable ++#define I2C_ADDR_CFG_SOPE_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_ADDR_CFG_SOPE_EN 0x00200000 ++/** Stop on Not Acknowledge ++ After successful transmission of a master code (during high speed mode) SONA is not considered till a stop condition is manually generated by SETEND. */ ++#define I2C_ADDR_CFG_SONA 0x00100000 ++/* Disable ++#define I2C_ADDR_CFG_SONA_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_ADDR_CFG_SONA_EN 0x00100000 ++/** Master Enable */ ++#define I2C_ADDR_CFG_MnS 0x00080000 ++/* Disable ++#define I2C_ADDR_CFG_MnS_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_ADDR_CFG_MnS_EN 0x00080000 ++/** Master Code Enable */ ++#define I2C_ADDR_CFG_MCE 0x00040000 ++/* Disable ++#define I2C_ADDR_CFG_MCE_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_ADDR_CFG_MCE_EN 0x00040000 ++/** General Call Enable */ ++#define I2C_ADDR_CFG_GCE 0x00020000 ++/* Disable ++#define I2C_ADDR_CFG_GCE_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_ADDR_CFG_GCE_EN 0x00020000 ++/** Ten Bit Address Mode */ ++#define I2C_ADDR_CFG_TBAM 0x00010000 ++/* 7-bit address mode enabled. ++#define I2C_ADDR_CFG_TBAM_7bit 0x00000000 */ ++/** 10-bit address mode enabled. */ ++#define I2C_ADDR_CFG_TBAM_10bit 0x00010000 ++/** I2C Bus device address ++ This is the address of this device. (Watch out for reserved addresses by referring to Phillips Spec V2.1) This could either be a 7bit- address (bits [7:1]) or a 10bit- address (bits [9:0]). Note:The validity of the bits are in accordance with the TBAM bit. Bit-1 (Bit-0) is the LSB of the device address. */ ++#define I2C_ADDR_CFG_ADR_MASK 0x000003FF ++/** field offset */ ++#define I2C_ADDR_CFG_ADR_OFFSET 0 ++ ++/* Fields of "I2C Bus Status Register" */ ++/** Read / not Write */ ++#define I2C_BUS_STAT_RNW 0x00000004 ++/* Write to I2C Bus. ++#define I2C_BUS_STAT_RNW_WRITE 0x00000000 */ ++/** Read from I2C Bus. */ ++#define I2C_BUS_STAT_RNW_READ 0x00000004 ++/** Bus Status */ ++#define I2C_BUS_STAT_BS_MASK 0x00000003 ++/** field offset */ ++#define I2C_BUS_STAT_BS_OFFSET 0 ++/** I2C Bus is free. */ ++#define I2C_BUS_STAT_BS_FREE 0x00000000 ++/** A start condition has been detected on the bus (bus busy). */ ++#define I2C_BUS_STAT_BS_SC 0x00000001 ++/** The device is working as master and has claimed the control on the I2C-bus (busy master). */ ++#define I2C_BUS_STAT_BS_BM 0x00000002 ++/** A remote master has accessed this device as slave. */ ++#define I2C_BUS_STAT_BS_RM 0x00000003 ++ ++/* Fields of "I2C FIFO Configuration Register" */ ++/** TX FIFO Flow Control */ ++#define I2C_FIFO_CFG_TXFC 0x00020000 ++/* TX FIFO not as Flow Controller ++#define I2C_FIFO_CFG_TXFC_TXNFC 0x00000000 */ ++/** RX FIFO Flow Control */ ++#define I2C_FIFO_CFG_RXFC 0x00010000 ++/* RX FIFO not as Flow Controller ++#define I2C_FIFO_CFG_RXFC_RXNFC 0x00000000 */ ++/** The reset value depends on the used character sizes of the peripheral. The maximum selectable alignment depends on the maximum number of characters per stage. */ ++#define I2C_FIFO_CFG_TXFA_MASK 0x00003000 ++/** field offset */ ++#define I2C_FIFO_CFG_TXFA_OFFSET 12 ++/** Byte aligned (character alignment) */ ++#define I2C_FIFO_CFG_TXFA_TXFA0 0x00000000 ++/** Half word aligned (character alignment of two characters) */ ++#define I2C_FIFO_CFG_TXFA_TXFA1 0x00001000 ++/** Word aligned (character alignment of four characters) */ ++#define I2C_FIFO_CFG_TXFA_TXFA2 0x00002000 ++/** Double word aligned (character alignment of eight */ ++#define I2C_FIFO_CFG_TXFA_TXFA3 0x00003000 ++/** The reset value depends on the used character sizes of the peripheral. The maximum selectable alignment depends on the maximum number of characters per stage. */ ++#define I2C_FIFO_CFG_RXFA_MASK 0x00000300 ++/** field offset */ ++#define I2C_FIFO_CFG_RXFA_OFFSET 8 ++/** Byte aligned (character alignment) */ ++#define I2C_FIFO_CFG_RXFA_RXFA0 0x00000000 ++/** Half word aligned (character alignment of two characters) */ ++#define I2C_FIFO_CFG_RXFA_RXFA1 0x00000100 ++/** Word aligned (character alignment of four characters) */ ++#define I2C_FIFO_CFG_RXFA_RXFA2 0x00000200 ++/** Double word aligned (character alignment of eight */ ++#define I2C_FIFO_CFG_RXFA_RXFA3 0x00000300 ++/** DMA controller does not support a burst size of 2 words. The reset value is the half of the FIFO size. The maximum selectable burst size is smaller than the FIFO size. */ ++#define I2C_FIFO_CFG_TXBS_MASK 0x00000030 ++/** field offset */ ++#define I2C_FIFO_CFG_TXBS_OFFSET 4 ++/** 1 word */ ++#define I2C_FIFO_CFG_TXBS_TXBS0 0x00000000 ++/** 2 words */ ++#define I2C_FIFO_CFG_TXBS_TXBS1 0x00000010 ++/** 4 words */ ++#define I2C_FIFO_CFG_TXBS_TXBS2 0x00000020 ++/** 8 words */ ++#define I2C_FIFO_CFG_TXBS_TXBS3 0x00000030 ++/** DMA controller does not support a burst size of 2 words. The reset value is the half of the FIFO size. The maximum selectable burst size is smaller than the FIFO size. */ ++#define I2C_FIFO_CFG_RXBS_MASK 0x00000003 ++/** field offset */ ++#define I2C_FIFO_CFG_RXBS_OFFSET 0 ++/** 1 word */ ++#define I2C_FIFO_CFG_RXBS_RXBS0 0x00000000 ++/** 2 words */ ++#define I2C_FIFO_CFG_RXBS_RXBS1 0x00000001 ++/** 4 words */ ++#define I2C_FIFO_CFG_RXBS_RXBS2 0x00000002 ++/** 8 words */ ++#define I2C_FIFO_CFG_RXBS_RXBS3 0x00000003 ++ ++/* Fields of "I2C Maximum Received Packet Size Register" */ ++/** MRPS */ ++#define I2C_MRPS_CTRL_MRPS_MASK 0x00003FFF ++/** field offset */ ++#define I2C_MRPS_CTRL_MRPS_OFFSET 0 ++ ++/* Fields of "I2C Received Packet Size Status Register" */ ++/** RPS */ ++#define I2C_RPS_STAT_RPS_MASK 0x00003FFF ++/** field offset */ ++#define I2C_RPS_STAT_RPS_OFFSET 0 ++ ++/* Fields of "I2C Transmit Packet Size Register" */ ++/** TPS */ ++#define I2C_TPS_CTRL_TPS_MASK 0x00003FFF ++/** field offset */ ++#define I2C_TPS_CTRL_TPS_OFFSET 0 ++ ++/* Fields of "I2C Filled FIFO Stages Status Register" */ ++/** FFS */ ++#define I2C_FFS_STAT_FFS_MASK 0x0000000F ++/** field offset */ ++#define I2C_FFS_STAT_FFS_OFFSET 0 ++ ++/* Fields of "I2C Timing Configuration Register" */ ++/** SDA Delay Stages for Start/Stop bit in High Speed Mode ++ The actual delay is calculated as the value of this field + 3 */ ++#define I2C_TIM_CFG_HS_SDA_DEL_MASK 0x00070000 ++/** field offset */ ++#define I2C_TIM_CFG_HS_SDA_DEL_OFFSET 16 ++/** Enable Fast Mode SCL Low period timing */ ++#define I2C_TIM_CFG_FS_SCL_LOW 0x00008000 ++/* Disable ++#define I2C_TIM_CFG_FS_SCL_LOW_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_TIM_CFG_FS_SCL_LOW_EN 0x00008000 ++/** SCL Delay Stages for Hold Time Start (Restart) Bit. ++ The actual delay is calculated as the value of this field + 2 */ ++#define I2C_TIM_CFG_SCL_DEL_HD_STA_MASK 0x00000E00 ++/** field offset */ ++#define I2C_TIM_CFG_SCL_DEL_HD_STA_OFFSET 9 ++/** SDA Delay Stages for Start/Stop bit in High Speed Mode ++ The actual delay is calculated as the value of this field + 3 */ ++#define I2C_TIM_CFG_HS_SDA_DEL_HD_DAT_MASK 0x000001C0 ++/** field offset */ ++#define I2C_TIM_CFG_HS_SDA_DEL_HD_DAT_OFFSET 6 ++/** SDA Delay Stages for Start/Stop bit in High Speed Mode ++ The actual delay is calculated as the value of this field + 3 */ ++#define I2C_TIM_CFG_SDA_DEL_HD_DAT_MASK 0x0000003F ++/** field offset */ ++#define I2C_TIM_CFG_SDA_DEL_HD_DAT_OFFSET 0 ++ ++/* Fields of "I2C Error Interrupt Request Source Mask Register" */ ++/** Enables the corresponding error interrupt. */ ++#define I2C_ERR_IRQSM_TXF_OFL 0x00000008 ++/* Disable ++#define I2C_ERR_IRQSM_TXF_OFL_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_ERR_IRQSM_TXF_OFL_EN 0x00000008 ++/** Enables the corresponding error interrupt. */ ++#define I2C_ERR_IRQSM_TXF_UFL 0x00000004 ++/* Disable ++#define I2C_ERR_IRQSM_TXF_UFL_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_ERR_IRQSM_TXF_UFL_EN 0x00000004 ++/** Enables the corresponding error interrupt. */ ++#define I2C_ERR_IRQSM_RXF_OFL 0x00000002 ++/* Disable ++#define I2C_ERR_IRQSM_RXF_OFL_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_ERR_IRQSM_RXF_OFL_EN 0x00000002 ++/** Enables the corresponding error interrupt. */ ++#define I2C_ERR_IRQSM_RXF_UFL 0x00000001 ++/* Disable ++#define I2C_ERR_IRQSM_RXF_UFL_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_ERR_IRQSM_RXF_UFL_EN 0x00000001 ++ ++/* Fields of "I2C Error Interrupt Request Source Status Register" */ ++/** TXF_OFL */ ++#define I2C_ERR_IRQSS_TXF_OFL 0x00000008 ++/* Nothing ++#define I2C_ERR_IRQSS_TXF_OFL_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_ERR_IRQSS_TXF_OFL_INTOCC 0x00000008 ++/** TXF_UFL */ ++#define I2C_ERR_IRQSS_TXF_UFL 0x00000004 ++/* Nothing ++#define I2C_ERR_IRQSS_TXF_UFL_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_ERR_IRQSS_TXF_UFL_INTOCC 0x00000004 ++/** RXF_OFL */ ++#define I2C_ERR_IRQSS_RXF_OFL 0x00000002 ++/* Nothing ++#define I2C_ERR_IRQSS_RXF_OFL_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_ERR_IRQSS_RXF_OFL_INTOCC 0x00000002 ++/** RXF_UFL */ ++#define I2C_ERR_IRQSS_RXF_UFL 0x00000001 ++/* Nothing ++#define I2C_ERR_IRQSS_RXF_UFL_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_ERR_IRQSS_RXF_UFL_INTOCC 0x00000001 ++ ++/* Fields of "I2C Error Interrupt Request Source Clear Register" */ ++/** TXF_OFL */ ++#define I2C_ERR_IRQSC_TXF_OFL 0x00000008 ++/* No-Operation ++#define I2C_ERR_IRQSC_TXF_OFL_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_ERR_IRQSC_TXF_OFL_CLR 0x00000008 ++/** TXF_UFL */ ++#define I2C_ERR_IRQSC_TXF_UFL 0x00000004 ++/* No-Operation ++#define I2C_ERR_IRQSC_TXF_UFL_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_ERR_IRQSC_TXF_UFL_CLR 0x00000004 ++/** RXF_OFL */ ++#define I2C_ERR_IRQSC_RXF_OFL 0x00000002 ++/* No-Operation ++#define I2C_ERR_IRQSC_RXF_OFL_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_ERR_IRQSC_RXF_OFL_CLR 0x00000002 ++/** RXF_UFL */ ++#define I2C_ERR_IRQSC_RXF_UFL 0x00000001 ++/* No-Operation ++#define I2C_ERR_IRQSC_RXF_UFL_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_ERR_IRQSC_RXF_UFL_CLR 0x00000001 ++ ++/* Fields of "I2C Protocol Interrupt Request Source Mask Register" */ ++/** Enables the corresponding interrupt. */ ++#define I2C_P_IRQSM_RX 0x00000040 ++/* Disable ++#define I2C_P_IRQSM_RX_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_P_IRQSM_RX_EN 0x00000040 ++/** Enables the corresponding interrupt. */ ++#define I2C_P_IRQSM_TX_END 0x00000020 ++/* Disable ++#define I2C_P_IRQSM_TX_END_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_P_IRQSM_TX_END_EN 0x00000020 ++/** Enables the corresponding interrupt. */ ++#define I2C_P_IRQSM_NACK 0x00000010 ++/* Disable ++#define I2C_P_IRQSM_NACK_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_P_IRQSM_NACK_EN 0x00000010 ++/** Enables the corresponding interrupt. */ ++#define I2C_P_IRQSM_AL 0x00000008 ++/* Disable ++#define I2C_P_IRQSM_AL_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_P_IRQSM_AL_EN 0x00000008 ++/** Enables the corresponding interrupt. */ ++#define I2C_P_IRQSM_MC 0x00000004 ++/* Disable ++#define I2C_P_IRQSM_MC_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_P_IRQSM_MC_EN 0x00000004 ++/** Enables the corresponding interrupt. */ ++#define I2C_P_IRQSM_GC 0x00000002 ++/* Disable ++#define I2C_P_IRQSM_GC_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_P_IRQSM_GC_EN 0x00000002 ++/** Enables the corresponding interrupt. */ ++#define I2C_P_IRQSM_AM 0x00000001 ++/* Disable ++#define I2C_P_IRQSM_AM_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_P_IRQSM_AM_EN 0x00000001 ++ ++/* Fields of "I2C Protocol Interrupt Request Source Status Register" */ ++/** RX */ ++#define I2C_P_IRQSS_RX 0x00000040 ++/* Nothing ++#define I2C_P_IRQSS_RX_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_P_IRQSS_RX_INTOCC 0x00000040 ++/** TX_END */ ++#define I2C_P_IRQSS_TX_END 0x00000020 ++/* Nothing ++#define I2C_P_IRQSS_TX_END_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_P_IRQSS_TX_END_INTOCC 0x00000020 ++/** NACK */ ++#define I2C_P_IRQSS_NACK 0x00000010 ++/* Nothing ++#define I2C_P_IRQSS_NACK_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_P_IRQSS_NACK_INTOCC 0x00000010 ++/** AL */ ++#define I2C_P_IRQSS_AL 0x00000008 ++/* Nothing ++#define I2C_P_IRQSS_AL_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_P_IRQSS_AL_INTOCC 0x00000008 ++/** MC */ ++#define I2C_P_IRQSS_MC 0x00000004 ++/* Nothing ++#define I2C_P_IRQSS_MC_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_P_IRQSS_MC_INTOCC 0x00000004 ++/** GC */ ++#define I2C_P_IRQSS_GC 0x00000002 ++/* Nothing ++#define I2C_P_IRQSS_GC_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_P_IRQSS_GC_INTOCC 0x00000002 ++/** AM */ ++#define I2C_P_IRQSS_AM 0x00000001 ++/* Nothing ++#define I2C_P_IRQSS_AM_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_P_IRQSS_AM_INTOCC 0x00000001 ++ ++/* Fields of "I2C Protocol Interrupt Request Source Clear Register" */ ++/** RX */ ++#define I2C_P_IRQSC_RX 0x00000040 ++/* No-Operation ++#define I2C_P_IRQSC_RX_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_P_IRQSC_RX_CLR 0x00000040 ++/** TX_END */ ++#define I2C_P_IRQSC_TX_END 0x00000020 ++/* No-Operation ++#define I2C_P_IRQSC_TX_END_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_P_IRQSC_TX_END_CLR 0x00000020 ++/** NACK */ ++#define I2C_P_IRQSC_NACK 0x00000010 ++/* No-Operation ++#define I2C_P_IRQSC_NACK_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_P_IRQSC_NACK_CLR 0x00000010 ++/** AL */ ++#define I2C_P_IRQSC_AL 0x00000008 ++/* No-Operation ++#define I2C_P_IRQSC_AL_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_P_IRQSC_AL_CLR 0x00000008 ++/** MC */ ++#define I2C_P_IRQSC_MC 0x00000004 ++/* No-Operation ++#define I2C_P_IRQSC_MC_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_P_IRQSC_MC_CLR 0x00000004 ++/** GC */ ++#define I2C_P_IRQSC_GC 0x00000002 ++/* No-Operation ++#define I2C_P_IRQSC_GC_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_P_IRQSC_GC_CLR 0x00000002 ++/** AM */ ++#define I2C_P_IRQSC_AM 0x00000001 ++/* No-Operation ++#define I2C_P_IRQSC_AM_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_P_IRQSC_AM_CLR 0x00000001 ++ ++/* Fields of "I2C Raw Interrupt Status Register" */ ++/** This is the combined interrupt bit for indication of an protocol event in the I2C kernel. */ ++#define I2C_RIS_I2C_P_INT 0x00000020 ++/* Nothing ++#define I2C_RIS_I2C_P_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_RIS_I2C_P_INT_INTOCC 0x00000020 ++/** This is the combined interrupt bit for indication of FIFO errors due to overflow and underrun. */ ++#define I2C_RIS_I2C_ERR_INT 0x00000010 ++/* Nothing ++#define I2C_RIS_I2C_ERR_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_RIS_I2C_ERR_INT_INTOCC 0x00000010 ++/** BREQ_INT */ ++#define I2C_RIS_BREQ_INT 0x00000008 ++/* Nothing ++#define I2C_RIS_BREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_RIS_BREQ_INT_INTOCC 0x00000008 ++/** LBREQ_INT */ ++#define I2C_RIS_LBREQ_INT 0x00000004 ++/* Nothing ++#define I2C_RIS_LBREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_RIS_LBREQ_INT_INTOCC 0x00000004 ++/** SREQ_INT */ ++#define I2C_RIS_SREQ_INT 0x00000002 ++/* Nothing ++#define I2C_RIS_SREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_RIS_SREQ_INT_INTOCC 0x00000002 ++/** LSREQ_INT */ ++#define I2C_RIS_LSREQ_INT 0x00000001 ++/* Nothing ++#define I2C_RIS_LSREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_RIS_LSREQ_INT_INTOCC 0x00000001 ++ ++/* Fields of "I2C Interrupt Mask Control Register" */ ++/** This is the combined interrupt bit for indication of an protocol event in the I2C kernel. */ ++#define I2C_IMSC_I2C_P_INT 0x00000020 ++/* Disable ++#define I2C_IMSC_I2C_P_INT_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_IMSC_I2C_P_INT_EN 0x00000020 ++/** This is the combined interrupt bit for indication of FIFO errors due to overflow and underrun. */ ++#define I2C_IMSC_I2C_ERR_INT 0x00000010 ++/* Disable ++#define I2C_IMSC_I2C_ERR_INT_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_IMSC_I2C_ERR_INT_EN 0x00000010 ++/** BREQ_INT */ ++#define I2C_IMSC_BREQ_INT 0x00000008 ++/* Disable ++#define I2C_IMSC_BREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_IMSC_BREQ_INT_EN 0x00000008 ++/** LBREQ_INT */ ++#define I2C_IMSC_LBREQ_INT 0x00000004 ++/* Disable ++#define I2C_IMSC_LBREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_IMSC_LBREQ_INT_EN 0x00000004 ++/** SREQ_INT */ ++#define I2C_IMSC_SREQ_INT 0x00000002 ++/* Disable ++#define I2C_IMSC_SREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_IMSC_SREQ_INT_EN 0x00000002 ++/** LSREQ_INT */ ++#define I2C_IMSC_LSREQ_INT 0x00000001 ++/* Disable ++#define I2C_IMSC_LSREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_IMSC_LSREQ_INT_EN 0x00000001 ++ ++/* Fields of "I2C Masked Interrupt Status Register" */ ++/** This is the combined interrupt bit for indication of an protocol event in the I2C kernel. */ ++#define I2C_MIS_I2C_P_INT 0x00000020 ++/* Nothing ++#define I2C_MIS_I2C_P_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_MIS_I2C_P_INT_INTOCC 0x00000020 ++/** This is the combined interrupt bit for indication of FIFO errors due to overflow and underrun. */ ++#define I2C_MIS_I2C_ERR_INT 0x00000010 ++/* Nothing ++#define I2C_MIS_I2C_ERR_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_MIS_I2C_ERR_INT_INTOCC 0x00000010 ++/** BREQ_INT */ ++#define I2C_MIS_BREQ_INT 0x00000008 ++/* Nothing ++#define I2C_MIS_BREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_MIS_BREQ_INT_INTOCC 0x00000008 ++/** LBREQ_INT */ ++#define I2C_MIS_LBREQ_INT 0x00000004 ++/* Nothing ++#define I2C_MIS_LBREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_MIS_LBREQ_INT_INTOCC 0x00000004 ++/** SREQ_INT */ ++#define I2C_MIS_SREQ_INT 0x00000002 ++/* Nothing ++#define I2C_MIS_SREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_MIS_SREQ_INT_INTOCC 0x00000002 ++/** LSREQ_INT */ ++#define I2C_MIS_LSREQ_INT 0x00000001 ++/* Nothing ++#define I2C_MIS_LSREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define I2C_MIS_LSREQ_INT_INTOCC 0x00000001 ++ ++/* Fields of "I2C Interrupt Clear Register" */ ++/** This is the combined interrupt bit for indication of an protocol event in the I2C kernel. */ ++#define I2C_ICR_I2C_P_INT 0x00000020 ++/* No-Operation ++#define I2C_ICR_I2C_P_INT_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_ICR_I2C_P_INT_CLR 0x00000020 ++/** This is the combined interrupt bit for indication of FIFO errors due to overflow and underrun. */ ++#define I2C_ICR_I2C_ERR_INT 0x00000010 ++/* No-Operation ++#define I2C_ICR_I2C_ERR_INT_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_ICR_I2C_ERR_INT_CLR 0x00000010 ++/** BREQ_INT */ ++#define I2C_ICR_BREQ_INT 0x00000008 ++/* No-Operation ++#define I2C_ICR_BREQ_INT_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_ICR_BREQ_INT_CLR 0x00000008 ++/** LBREQ_INT */ ++#define I2C_ICR_LBREQ_INT 0x00000004 ++/* No-Operation ++#define I2C_ICR_LBREQ_INT_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_ICR_LBREQ_INT_CLR 0x00000004 ++/** SREQ_INT */ ++#define I2C_ICR_SREQ_INT 0x00000002 ++/* No-Operation ++#define I2C_ICR_SREQ_INT_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_ICR_SREQ_INT_CLR 0x00000002 ++/** LSREQ_INT */ ++#define I2C_ICR_LSREQ_INT 0x00000001 ++/* No-Operation ++#define I2C_ICR_LSREQ_INT_NOP 0x00000000 */ ++/** Clear */ ++#define I2C_ICR_LSREQ_INT_CLR 0x00000001 ++ ++/* Fields of "I2C Interrupt Set Register" */ ++/** This is the combined interrupt bit for indication of an protocol event in the I2C kernel. */ ++#define I2C_ISR_I2C_P_INT 0x00000020 ++/* No-Operation ++#define I2C_ISR_I2C_P_INT_NOP 0x00000000 */ ++/** Set */ ++#define I2C_ISR_I2C_P_INT_SET 0x00000020 ++/** This is the combined interrupt bit for indication of FIFO errors due to overflow and underrun. */ ++#define I2C_ISR_I2C_ERR_INT 0x00000010 ++/* No-Operation ++#define I2C_ISR_I2C_ERR_INT_NOP 0x00000000 */ ++/** Set */ ++#define I2C_ISR_I2C_ERR_INT_SET 0x00000010 ++/** BREQ_INT */ ++#define I2C_ISR_BREQ_INT 0x00000008 ++/* No-Operation ++#define I2C_ISR_BREQ_INT_NOP 0x00000000 */ ++/** Set */ ++#define I2C_ISR_BREQ_INT_SET 0x00000008 ++/** LBREQ_INT */ ++#define I2C_ISR_LBREQ_INT 0x00000004 ++/* No-Operation ++#define I2C_ISR_LBREQ_INT_NOP 0x00000000 */ ++/** Set */ ++#define I2C_ISR_LBREQ_INT_SET 0x00000004 ++/** SREQ_INT */ ++#define I2C_ISR_SREQ_INT 0x00000002 ++/* No-Operation ++#define I2C_ISR_SREQ_INT_NOP 0x00000000 */ ++/** Set */ ++#define I2C_ISR_SREQ_INT_SET 0x00000002 ++/** LSREQ_INT */ ++#define I2C_ISR_LSREQ_INT 0x00000001 ++/* No-Operation ++#define I2C_ISR_LSREQ_INT_NOP 0x00000000 */ ++/** Set */ ++#define I2C_ISR_LSREQ_INT_SET 0x00000001 ++ ++/* Fields of "I2C DMA Enable Register" */ ++/** BREQ_INT */ ++#define I2C_DMAE_BREQ_INT 0x00000008 ++/* Disable ++#define I2C_DMAE_BREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_DMAE_BREQ_INT_EN 0x00000008 ++/** LBREQ_INT */ ++#define I2C_DMAE_LBREQ_INT 0x00000004 ++/* Disable ++#define I2C_DMAE_LBREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_DMAE_LBREQ_INT_EN 0x00000004 ++/** SREQ_INT */ ++#define I2C_DMAE_SREQ_INT 0x00000002 ++/* Disable ++#define I2C_DMAE_SREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_DMAE_SREQ_INT_EN 0x00000002 ++/** LSREQ_INT */ ++#define I2C_DMAE_LSREQ_INT 0x00000001 ++/* Disable ++#define I2C_DMAE_LSREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define I2C_DMAE_LSREQ_INT_EN 0x00000001 ++ ++/* Fields of "I2C Transmit Data Register" */ ++/** Characters to be transmitted */ ++#define I2C_TXD_TXD_MASK 0xFFFFFFFF ++/** field offset */ ++#define I2C_TXD_TXD_OFFSET 0 ++ ++/* Fields of "I2C Receive Data Register" */ ++/** Received characters */ ++#define I2C_RXD_RXD_MASK 0xFFFFFFFF ++/** field offset */ ++#define I2C_RXD_RXD_OFFSET 0 ++ ++/*! @} */ /* I2C_REGISTER */ ++ ++#endif /* _i2c_reg_h */ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/icu0_reg.h +@@ -0,0 +1,4324 @@ ++/****************************************************************************** ++ ++ Copyright (c) 2010 ++ Lantiq Deutschland GmbH ++ ++ For licensing information, see the file 'LICENSE' in the root folder of ++ this software module. ++ ++******************************************************************************/ ++ ++#ifndef _icu0_reg_h ++#define _icu0_reg_h ++ ++/** \addtogroup ICU0_REGISTER ++ @{ ++*/ ++/* access macros */ ++#define icu0_r32(reg) reg_r32(&icu0->reg) ++#define icu0_w32(val, reg) reg_w32(val, &icu0->reg) ++#define icu0_w32_mask(clear, set, reg) reg_w32_mask(clear, set, &icu0->reg) ++#define icu0_r32_table(reg, idx) reg_r32_table(icu0->reg, idx) ++#define icu0_w32_table(val, reg, idx) reg_w32_table(val, icu0->reg, idx) ++#define icu0_w32_table_mask(clear, set, reg, idx) reg_w32_table_mask(clear, set, icu0->reg, idx) ++#define icu0_adr_table(reg, idx) adr_table(icu0->reg, idx) ++ ++ ++/** ICU0 register structure */ ++struct gpon_reg_icu0 ++{ ++ /** IM0 Interrupt Status Register ++ A read action to this register delivers the unmasked captured status of the interrupt request lines. Each bit can be cleared by a write operation. */ ++ unsigned int im0_isr; /* 0x00000000 */ ++ /** Reserved */ ++ unsigned int res_0; /* 0x00000004 */ ++ /** IM0 Interrupt Enable Register ++ This register contains the enable (or mask) bits for the interrupts. Disabled interrupts are not visible in the IM0_IOSR register and are not signalled via the interrupt line towards the controller. */ ++ unsigned int im0_ier; /* 0x00000008 */ ++ /** Reserved */ ++ unsigned int res_1; /* 0x0000000C */ ++ /** IM0 Interrupt Output Status Register ++ This register shows the currently active interrupt requests masked with the corresponding enable bits of the IM0_IER register. */ ++ unsigned int im0_iosr; /* 0x00000010 */ ++ /** Reserved */ ++ unsigned int res_2; /* 0x00000014 */ ++ /** IM0 Interrupt Request Set Register ++ A write operation directly effects the interrupts. This can be used to trigger events under software control for testing purposes. A read operation returns the unmasked interrupt events. */ ++ unsigned int im0_irsr; /* 0x00000018 */ ++ /** Reserved */ ++ unsigned int res_3; /* 0x0000001C */ ++ /** IM0 Interrupt Mode Register ++ This register shows the type of interrupt for each bit. */ ++ unsigned int im0_imr; /* 0x00000020 */ ++ /** Reserved */ ++ unsigned int res_4; /* 0x00000024 */ ++ /** IM1 Interrupt Status Register ++ A read action to this register delivers the unmasked captured status of the interrupt request lines. Each bit can be cleared by a write operation. */ ++ unsigned int im1_isr; /* 0x00000028 */ ++ /** Reserved */ ++ unsigned int res_5; /* 0x0000002C */ ++ /** IM1 Interrupt Enable Register ++ This register contains the enable (or mask) bits for the interrupts. Disabled interrupts are not visible in the IM1_IOSR register and are not signalled via the interrupt line towards the controller. */ ++ unsigned int im1_ier; /* 0x00000030 */ ++ /** Reserved */ ++ unsigned int res_6; /* 0x00000034 */ ++ /** IM1 Interrupt Output Status Register ++ This register shows the currently active interrupt requests masked with the corresponding enable bits of the IM1_IER register. */ ++ unsigned int im1_iosr; /* 0x00000038 */ ++ /** Reserved */ ++ unsigned int res_7; /* 0x0000003C */ ++ /** IM1 Interrupt Request Set Register ++ A write operation directly effects the interrupts. This can be used to trigger events under software control for testing purposes. A read operation returns the unmasked interrupt events. */ ++ unsigned int im1_irsr; /* 0x00000040 */ ++ /** Reserved */ ++ unsigned int res_8; /* 0x00000044 */ ++ /** IM1 Interrupt Mode Register ++ This register shows the type of interrupt for each bit. */ ++ unsigned int im1_imr; /* 0x00000048 */ ++ /** Reserved */ ++ unsigned int res_9; /* 0x0000004C */ ++ /** IM2 Interrupt Status Register ++ A read action to this register delivers the unmasked captured status of the interrupt request lines. Each bit can be cleared by a write operation. */ ++ unsigned int im2_isr; /* 0x00000050 */ ++ /** Reserved */ ++ unsigned int res_10; /* 0x00000054 */ ++ /** IM2 Interrupt Enable Register ++ This register contains the enable (or mask) bits for the interrupts. Disabled interrupts are not visible in the IM2_IOSR register and are not signalled via the interrupt line towards the controller. */ ++ unsigned int im2_ier; /* 0x00000058 */ ++ /** Reserved */ ++ unsigned int res_11; /* 0x0000005C */ ++ /** IM2 Interrupt Output Status Register ++ This register shows the currently active interrupt requests masked with the corresponding enable bits of the IM2_IER register. */ ++ unsigned int im2_iosr; /* 0x00000060 */ ++ /** Reserved */ ++ unsigned int res_12; /* 0x00000064 */ ++ /** IM2 Interrupt Request Set Register ++ A write operation directly effects the interrupts. This can be used to trigger events under software control for testing purposes. A read operation returns the unmasked interrupt events. */ ++ unsigned int im2_irsr; /* 0x00000068 */ ++ /** Reserved */ ++ unsigned int res_13; /* 0x0000006C */ ++ /** IM2 Interrupt Mode Register ++ This register shows the type of interrupt for each bit. */ ++ unsigned int im2_imr; /* 0x00000070 */ ++ /** Reserved */ ++ unsigned int res_14; /* 0x00000074 */ ++ /** IM3 Interrupt Status Register ++ A read action to this register delivers the unmasked captured status of the interrupt request lines. Each bit can be cleared by a write operation. */ ++ unsigned int im3_isr; /* 0x00000078 */ ++ /** Reserved */ ++ unsigned int res_15; /* 0x0000007C */ ++ /** IM3 Interrupt Enable Register ++ This register contains the enable (or mask) bits for the interrupts. Disabled interrupts are not visible in the IM3_IOSR register and are not signalled via the interrupt line towards the controller. */ ++ unsigned int im3_ier; /* 0x00000080 */ ++ /** Reserved */ ++ unsigned int res_16; /* 0x00000084 */ ++ /** IM3 Interrupt Output Status Register ++ This register shows the currently active interrupt requests masked with the corresponding enable bits of the IM3_IER register. */ ++ unsigned int im3_iosr; /* 0x00000088 */ ++ /** Reserved */ ++ unsigned int res_17; /* 0x0000008C */ ++ /** IM3 Interrupt Request Set Register ++ A write operation directly effects the interrupts. This can be used to trigger events under software control for testing purposes. A read operation returns the unmasked interrupt events. */ ++ unsigned int im3_irsr; /* 0x00000090 */ ++ /** Reserved */ ++ unsigned int res_18; /* 0x00000094 */ ++ /** IM3 Interrupt Mode Register ++ This register shows the type of interrupt for each bit. */ ++ unsigned int im3_imr; /* 0x00000098 */ ++ /** Reserved */ ++ unsigned int res_19; /* 0x0000009C */ ++ /** IM4 Interrupt Status Register ++ A read action to this register delivers the unmasked captured status of the interrupt request lines. Each bit can be cleared by a write operation. */ ++ unsigned int im4_isr; /* 0x000000A0 */ ++ /** Reserved */ ++ unsigned int res_20; /* 0x000000A4 */ ++ /** IM4 Interrupt Enable Register ++ This register contains the enable (or mask) bits for the interrupts. Disabled interrupts are not visible in the IM4_IOSR register and are not signalled via the interrupt line towards the controller. */ ++ unsigned int im4_ier; /* 0x000000A8 */ ++ /** Reserved */ ++ unsigned int res_21; /* 0x000000AC */ ++ /** IM4 Interrupt Output Status Register ++ This register shows the currently active interrupt requests masked with the corresponding enable bits of the IM4_IER register. */ ++ unsigned int im4_iosr; /* 0x000000B0 */ ++ /** Reserved */ ++ unsigned int res_22; /* 0x000000B4 */ ++ /** IM4 Interrupt Request Set Register ++ A write operation directly effects the interrupts. This can be used to trigger events under software control for testing purposes. A read operation returns the unmasked interrupt events. */ ++ unsigned int im4_irsr; /* 0x000000B8 */ ++ /** Reserved */ ++ unsigned int res_23; /* 0x000000BC */ ++ /** IM4 Interrupt Mode Register ++ This register shows the type of interrupt for each bit. */ ++ unsigned int im4_imr; /* 0x000000C0 */ ++ /** Reserved */ ++ unsigned int res_24; /* 0x000000C4 */ ++ /** ICU Interrupt Vector Register (5 bit variant) ++ Shows the leftmost pending interrupt request. If e.g. bit 14 of the IOSR register is set, 15 is reported, because the 15th interrupt request is active. */ ++ unsigned int icu_ivec; /* 0x000000C8 */ ++ /** Reserved */ ++ unsigned int res_25; /* 0x000000CC */ ++ /** ICU Interrupt Vector Register (6 bit variant) ++ Shows the leftmost pending interrupt request. If e.g. bit 14 of the IOSR register is set, 15 is reported, because the 15th interrupt request is active. */ ++ unsigned int icu_ivec_6; /* 0x000000D0 */ ++ /** Reserved */ ++ unsigned int res_26[3]; /* 0x000000D4 */ ++}; ++ ++ ++/* Fields of "IM0 Interrupt Status Register" */ ++/** PCM Transmit Crash Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_PCM_HW2_CRASH 0x80000000 ++/* Nothing ++#define ICU0_IM0_ISR_PCM_HW2_CRASH_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_PCM_HW2_CRASH_INTACK 0x80000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_PCM_HW2_CRASH_INTOCC 0x80000000 ++/** PCM Transmit Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_PCM_TX 0x40000000 ++/* Nothing ++#define ICU0_IM0_ISR_PCM_TX_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_PCM_TX_INTACK 0x40000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_PCM_TX_INTOCC 0x40000000 ++/** PCM Receive Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_PCM_RX 0x20000000 ++/* Nothing ++#define ICU0_IM0_ISR_PCM_RX_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_PCM_RX_INTACK 0x20000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_PCM_RX_INTOCC 0x20000000 ++/** Secure Hash Algorithm Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM0_ISR_SHA1_HASH 0x10000000 ++/* Nothing ++#define ICU0_IM0_ISR_SHA1_HASH_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_SHA1_HASH_INTACK 0x10000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_SHA1_HASH_INTOCC 0x10000000 ++/** Advanced Encryption Standard Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM0_ISR_AES_AES 0x08000000 ++/* Nothing ++#define ICU0_IM0_ISR_AES_AES_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_AES_AES_INTACK 0x08000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_AES_AES_INTOCC 0x08000000 ++/** SSC Frame Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM0_ISR_SSC0_F 0x00020000 ++/* Nothing ++#define ICU0_IM0_ISR_SSC0_F_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_SSC0_F_INTACK 0x00020000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_SSC0_F_INTOCC 0x00020000 ++/** SSC Error Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM0_ISR_SSC0_E 0x00010000 ++/* Nothing ++#define ICU0_IM0_ISR_SSC0_E_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_SSC0_E_INTACK 0x00010000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_SSC0_E_INTOCC 0x00010000 ++/** SSC Receive Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM0_ISR_SSC0_R 0x00008000 ++/* Nothing ++#define ICU0_IM0_ISR_SSC0_R_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_SSC0_R_INTACK 0x00008000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_SSC0_R_INTOCC 0x00008000 ++/** SSC Transmit Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM0_ISR_SSC0_T 0x00004000 ++/* Nothing ++#define ICU0_IM0_ISR_SSC0_T_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_SSC0_T_INTACK 0x00004000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_SSC0_T_INTOCC 0x00004000 ++/** I2C Peripheral Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_I2C_I2C_P_INT 0x00002000 ++/* Nothing ++#define ICU0_IM0_ISR_I2C_I2C_P_INT_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_I2C_I2C_P_INT_INTACK 0x00002000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_I2C_I2C_P_INT_INTOCC 0x00002000 ++/** I2C Error Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_I2C_I2C_ERR_INT 0x00001000 ++/* Nothing ++#define ICU0_IM0_ISR_I2C_I2C_ERR_INT_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_I2C_I2C_ERR_INT_INTACK 0x00001000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_I2C_I2C_ERR_INT_INTOCC 0x00001000 ++/** I2C Burst Data Transfer Request ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_I2C_BREQ_INT 0x00000800 ++/* Nothing ++#define ICU0_IM0_ISR_I2C_BREQ_INT_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_I2C_BREQ_INT_INTACK 0x00000800 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_I2C_BREQ_INT_INTOCC 0x00000800 ++/** I2C Last Burst Data Transfer Request ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_I2C_LBREQ_INT 0x00000400 ++/* Nothing ++#define ICU0_IM0_ISR_I2C_LBREQ_INT_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_I2C_LBREQ_INT_INTACK 0x00000400 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_I2C_LBREQ_INT_INTOCC 0x00000400 ++/** I2C Single Data Transfer Request ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_I2C_SREQ_INT 0x00000200 ++/* Nothing ++#define ICU0_IM0_ISR_I2C_SREQ_INT_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_I2C_SREQ_INT_INTACK 0x00000200 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_I2C_SREQ_INT_INTOCC 0x00000200 ++/** I2C Last Single Data Transfer Request ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_I2C_LSREQ_INT 0x00000100 ++/* Nothing ++#define ICU0_IM0_ISR_I2C_LSREQ_INT_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_I2C_LSREQ_INT_INTACK 0x00000100 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_I2C_LSREQ_INT_INTOCC 0x00000100 ++/** HOST IF Mailbox1 Transmit Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_HOST_MB1_TIR 0x00000010 ++/* Nothing ++#define ICU0_IM0_ISR_HOST_MB1_TIR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_HOST_MB1_TIR_INTACK 0x00000010 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_HOST_MB1_TIR_INTOCC 0x00000010 ++/** HOST IF Mailbox1 Receive Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_HOST_MB1_RIR 0x00000008 ++/* Nothing ++#define ICU0_IM0_ISR_HOST_MB1_RIR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_HOST_MB1_RIR_INTACK 0x00000008 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_HOST_MB1_RIR_INTOCC 0x00000008 ++/** HOST IF Mailbox0 Transmit Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_HOST_MB0_TIR 0x00000004 ++/* Nothing ++#define ICU0_IM0_ISR_HOST_MB0_TIR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_HOST_MB0_TIR_INTACK 0x00000004 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_HOST_MB0_TIR_INTOCC 0x00000004 ++/** HOST IF Mailbox0 Receive Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_HOST_MB0_RIR 0x00000002 ++/* Nothing ++#define ICU0_IM0_ISR_HOST_MB0_RIR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_HOST_MB0_RIR_INTACK 0x00000002 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_HOST_MB0_RIR_INTOCC 0x00000002 ++/** HOST IF Event Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM0_ISR_HOST_EIR 0x00000001 ++/* Nothing ++#define ICU0_IM0_ISR_HOST_EIR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM0_ISR_HOST_EIR_INTACK 0x00000001 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_ISR_HOST_EIR_INTOCC 0x00000001 ++ ++/* Fields of "IM0 Interrupt Enable Register" */ ++/** PCM Transmit Crash Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_PCM_HW2_CRASH 0x80000000 ++/* Disable ++#define ICU0_IM0_IER_PCM_HW2_CRASH_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_PCM_HW2_CRASH_EN 0x80000000 ++/** PCM Transmit Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_PCM_TX 0x40000000 ++/* Disable ++#define ICU0_IM0_IER_PCM_TX_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_PCM_TX_EN 0x40000000 ++/** PCM Receive Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_PCM_RX 0x20000000 ++/* Disable ++#define ICU0_IM0_IER_PCM_RX_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_PCM_RX_EN 0x20000000 ++/** Secure Hash Algorithm Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_SHA1_HASH 0x10000000 ++/* Disable ++#define ICU0_IM0_IER_SHA1_HASH_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_SHA1_HASH_EN 0x10000000 ++/** Advanced Encryption Standard Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_AES_AES 0x08000000 ++/* Disable ++#define ICU0_IM0_IER_AES_AES_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_AES_AES_EN 0x08000000 ++/** SSC Frame Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_SSC0_F 0x00020000 ++/* Disable ++#define ICU0_IM0_IER_SSC0_F_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_SSC0_F_EN 0x00020000 ++/** SSC Error Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_SSC0_E 0x00010000 ++/* Disable ++#define ICU0_IM0_IER_SSC0_E_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_SSC0_E_EN 0x00010000 ++/** SSC Receive Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_SSC0_R 0x00008000 ++/* Disable ++#define ICU0_IM0_IER_SSC0_R_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_SSC0_R_EN 0x00008000 ++/** SSC Transmit Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_SSC0_T 0x00004000 ++/* Disable ++#define ICU0_IM0_IER_SSC0_T_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_SSC0_T_EN 0x00004000 ++/** I2C Peripheral Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_I2C_I2C_P_INT 0x00002000 ++/* Disable ++#define ICU0_IM0_IER_I2C_I2C_P_INT_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_I2C_I2C_P_INT_EN 0x00002000 ++/** I2C Error Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_I2C_I2C_ERR_INT 0x00001000 ++/* Disable ++#define ICU0_IM0_IER_I2C_I2C_ERR_INT_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_I2C_I2C_ERR_INT_EN 0x00001000 ++/** I2C Burst Data Transfer Request ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_I2C_BREQ_INT 0x00000800 ++/* Disable ++#define ICU0_IM0_IER_I2C_BREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_I2C_BREQ_INT_EN 0x00000800 ++/** I2C Last Burst Data Transfer Request ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_I2C_LBREQ_INT 0x00000400 ++/* Disable ++#define ICU0_IM0_IER_I2C_LBREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_I2C_LBREQ_INT_EN 0x00000400 ++/** I2C Single Data Transfer Request ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_I2C_SREQ_INT 0x00000200 ++/* Disable ++#define ICU0_IM0_IER_I2C_SREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_I2C_SREQ_INT_EN 0x00000200 ++/** I2C Last Single Data Transfer Request ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_I2C_LSREQ_INT 0x00000100 ++/* Disable ++#define ICU0_IM0_IER_I2C_LSREQ_INT_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_I2C_LSREQ_INT_EN 0x00000100 ++/** HOST IF Mailbox1 Transmit Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_HOST_MB1_TIR 0x00000010 ++/* Disable ++#define ICU0_IM0_IER_HOST_MB1_TIR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_HOST_MB1_TIR_EN 0x00000010 ++/** HOST IF Mailbox1 Receive Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_HOST_MB1_RIR 0x00000008 ++/* Disable ++#define ICU0_IM0_IER_HOST_MB1_RIR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_HOST_MB1_RIR_EN 0x00000008 ++/** HOST IF Mailbox0 Transmit Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_HOST_MB0_TIR 0x00000004 ++/* Disable ++#define ICU0_IM0_IER_HOST_MB0_TIR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_HOST_MB0_TIR_EN 0x00000004 ++/** HOST IF Mailbox0 Receive Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_HOST_MB0_RIR 0x00000002 ++/* Disable ++#define ICU0_IM0_IER_HOST_MB0_RIR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_HOST_MB0_RIR_EN 0x00000002 ++/** HOST IF Event Interrupt ++ Interrupt enable bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IER_HOST_EIR 0x00000001 ++/* Disable ++#define ICU0_IM0_IER_HOST_EIR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM0_IER_HOST_EIR_EN 0x00000001 ++ ++/* Fields of "IM0 Interrupt Output Status Register" */ ++/** PCM Transmit Crash Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_PCM_HW2_CRASH 0x80000000 ++/* Nothing ++#define ICU0_IM0_IOSR_PCM_HW2_CRASH_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_PCM_HW2_CRASH_INTOCC 0x80000000 ++/** PCM Transmit Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_PCM_TX 0x40000000 ++/* Nothing ++#define ICU0_IM0_IOSR_PCM_TX_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_PCM_TX_INTOCC 0x40000000 ++/** PCM Receive Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_PCM_RX 0x20000000 ++/* Nothing ++#define ICU0_IM0_IOSR_PCM_RX_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_PCM_RX_INTOCC 0x20000000 ++/** Secure Hash Algorithm Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_SHA1_HASH 0x10000000 ++/* Nothing ++#define ICU0_IM0_IOSR_SHA1_HASH_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_SHA1_HASH_INTOCC 0x10000000 ++/** Advanced Encryption Standard Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_AES_AES 0x08000000 ++/* Nothing ++#define ICU0_IM0_IOSR_AES_AES_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_AES_AES_INTOCC 0x08000000 ++/** SSC Frame Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_SSC0_F 0x00020000 ++/* Nothing ++#define ICU0_IM0_IOSR_SSC0_F_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_SSC0_F_INTOCC 0x00020000 ++/** SSC Error Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_SSC0_E 0x00010000 ++/* Nothing ++#define ICU0_IM0_IOSR_SSC0_E_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_SSC0_E_INTOCC 0x00010000 ++/** SSC Receive Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_SSC0_R 0x00008000 ++/* Nothing ++#define ICU0_IM0_IOSR_SSC0_R_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_SSC0_R_INTOCC 0x00008000 ++/** SSC Transmit Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_SSC0_T 0x00004000 ++/* Nothing ++#define ICU0_IM0_IOSR_SSC0_T_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_SSC0_T_INTOCC 0x00004000 ++/** I2C Peripheral Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_I2C_I2C_P_INT 0x00002000 ++/* Nothing ++#define ICU0_IM0_IOSR_I2C_I2C_P_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_I2C_I2C_P_INT_INTOCC 0x00002000 ++/** I2C Error Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_I2C_I2C_ERR_INT 0x00001000 ++/* Nothing ++#define ICU0_IM0_IOSR_I2C_I2C_ERR_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_I2C_I2C_ERR_INT_INTOCC 0x00001000 ++/** I2C Burst Data Transfer Request ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_I2C_BREQ_INT 0x00000800 ++/* Nothing ++#define ICU0_IM0_IOSR_I2C_BREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_I2C_BREQ_INT_INTOCC 0x00000800 ++/** I2C Last Burst Data Transfer Request ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_I2C_LBREQ_INT 0x00000400 ++/* Nothing ++#define ICU0_IM0_IOSR_I2C_LBREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_I2C_LBREQ_INT_INTOCC 0x00000400 ++/** I2C Single Data Transfer Request ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_I2C_SREQ_INT 0x00000200 ++/* Nothing ++#define ICU0_IM0_IOSR_I2C_SREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_I2C_SREQ_INT_INTOCC 0x00000200 ++/** I2C Last Single Data Transfer Request ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_I2C_LSREQ_INT 0x00000100 ++/* Nothing ++#define ICU0_IM0_IOSR_I2C_LSREQ_INT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_I2C_LSREQ_INT_INTOCC 0x00000100 ++/** HOST IF Mailbox1 Transmit Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_HOST_MB1_TIR 0x00000010 ++/* Nothing ++#define ICU0_IM0_IOSR_HOST_MB1_TIR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_HOST_MB1_TIR_INTOCC 0x00000010 ++/** HOST IF Mailbox1 Receive Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_HOST_MB1_RIR 0x00000008 ++/* Nothing ++#define ICU0_IM0_IOSR_HOST_MB1_RIR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_HOST_MB1_RIR_INTOCC 0x00000008 ++/** HOST IF Mailbox0 Transmit Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_HOST_MB0_TIR 0x00000004 ++/* Nothing ++#define ICU0_IM0_IOSR_HOST_MB0_TIR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_HOST_MB0_TIR_INTOCC 0x00000004 ++/** HOST IF Mailbox0 Receive Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_HOST_MB0_RIR 0x00000002 ++/* Nothing ++#define ICU0_IM0_IOSR_HOST_MB0_RIR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_HOST_MB0_RIR_INTOCC 0x00000002 ++/** HOST IF Event Interrupt ++ Masked interrupt bit for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IOSR_HOST_EIR 0x00000001 ++/* Nothing ++#define ICU0_IM0_IOSR_HOST_EIR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM0_IOSR_HOST_EIR_INTOCC 0x00000001 ++ ++/* Fields of "IM0 Interrupt Request Set Register" */ ++/** PCM Transmit Crash Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_PCM_HW2_CRASH 0x80000000 ++/** PCM Transmit Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_PCM_TX 0x40000000 ++/** PCM Receive Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_PCM_RX 0x20000000 ++/** Secure Hash Algorithm Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_SHA1_HASH 0x10000000 ++/** Advanced Encryption Standard Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_AES_AES 0x08000000 ++/** SSC Frame Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_SSC0_F 0x00020000 ++/** SSC Error Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_SSC0_E 0x00010000 ++/** SSC Receive Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_SSC0_R 0x00008000 ++/** SSC Transmit Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_SSC0_T 0x00004000 ++/** I2C Peripheral Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_I2C_I2C_P_INT 0x00002000 ++/** I2C Error Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_I2C_I2C_ERR_INT 0x00001000 ++/** I2C Burst Data Transfer Request ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_I2C_BREQ_INT 0x00000800 ++/** I2C Last Burst Data Transfer Request ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_I2C_LBREQ_INT 0x00000400 ++/** I2C Single Data Transfer Request ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_I2C_SREQ_INT 0x00000200 ++/** I2C Last Single Data Transfer Request ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_I2C_LSREQ_INT 0x00000100 ++/** HOST IF Mailbox1 Transmit Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_HOST_MB1_TIR 0x00000010 ++/** HOST IF Mailbox1 Receive Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_HOST_MB1_RIR 0x00000008 ++/** HOST IF Mailbox0 Transmit Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_HOST_MB0_TIR 0x00000004 ++/** HOST IF Mailbox0 Receive Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_HOST_MB0_RIR 0x00000002 ++/** HOST IF Event Interrupt ++ Software control for the corresponding bit in the IM0_ISR register. */ ++#define ICU0_IM0_IRSR_HOST_EIR 0x00000001 ++ ++/* Fields of "IM0 Interrupt Mode Register" */ ++/** PCM Transmit Crash Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_PCM_HW2_CRASH 0x80000000 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_PCM_HW2_CRASH_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_PCM_HW2_CRASH_DIR 0x80000000 ++/** PCM Transmit Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_PCM_TX 0x40000000 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_PCM_TX_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_PCM_TX_DIR 0x40000000 ++/** PCM Receive Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_PCM_RX 0x20000000 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_PCM_RX_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_PCM_RX_DIR 0x20000000 ++/** Secure Hash Algorithm Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_SHA1_HASH 0x10000000 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_SHA1_HASH_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_SHA1_HASH_DIR 0x10000000 ++/** Advanced Encryption Standard Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_AES_AES 0x08000000 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_AES_AES_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_AES_AES_DIR 0x08000000 ++/** SSC Frame Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_SSC0_F 0x00020000 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_SSC0_F_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_SSC0_F_DIR 0x00020000 ++/** SSC Error Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_SSC0_E 0x00010000 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_SSC0_E_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_SSC0_E_DIR 0x00010000 ++/** SSC Receive Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_SSC0_R 0x00008000 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_SSC0_R_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_SSC0_R_DIR 0x00008000 ++/** SSC Transmit Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_SSC0_T 0x00004000 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_SSC0_T_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_SSC0_T_DIR 0x00004000 ++/** I2C Peripheral Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_I2C_I2C_P_INT 0x00002000 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_I2C_I2C_P_INT_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_I2C_I2C_P_INT_DIR 0x00002000 ++/** I2C Error Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_I2C_I2C_ERR_INT 0x00001000 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_I2C_I2C_ERR_INT_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_I2C_I2C_ERR_INT_DIR 0x00001000 ++/** I2C Burst Data Transfer Request ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_I2C_BREQ_INT 0x00000800 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_I2C_BREQ_INT_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_I2C_BREQ_INT_DIR 0x00000800 ++/** I2C Last Burst Data Transfer Request ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_I2C_LBREQ_INT 0x00000400 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_I2C_LBREQ_INT_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_I2C_LBREQ_INT_DIR 0x00000400 ++/** I2C Single Data Transfer Request ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_I2C_SREQ_INT 0x00000200 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_I2C_SREQ_INT_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_I2C_SREQ_INT_DIR 0x00000200 ++/** I2C Last Single Data Transfer Request ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_I2C_LSREQ_INT 0x00000100 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_I2C_LSREQ_INT_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_I2C_LSREQ_INT_DIR 0x00000100 ++/** HOST IF Mailbox1 Transmit Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_HOST_MB1_TIR 0x00000010 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_HOST_MB1_TIR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_HOST_MB1_TIR_DIR 0x00000010 ++/** HOST IF Mailbox1 Receive Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_HOST_MB1_RIR 0x00000008 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_HOST_MB1_RIR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_HOST_MB1_RIR_DIR 0x00000008 ++/** HOST IF Mailbox0 Transmit Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_HOST_MB0_TIR 0x00000004 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_HOST_MB0_TIR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_HOST_MB0_TIR_DIR 0x00000004 ++/** HOST IF Mailbox0 Receive Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_HOST_MB0_RIR 0x00000002 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_HOST_MB0_RIR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_HOST_MB0_RIR_DIR 0x00000002 ++/** HOST IF Event Interrupt ++ Type of interrupt. */ ++#define ICU0_IM0_IMR_HOST_EIR 0x00000001 ++/* Indirect Interrupt. ++#define ICU0_IM0_IMR_HOST_EIR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM0_IMR_HOST_EIR_DIR 0x00000001 ++ ++/* Fields of "IM1 Interrupt Status Register" */ ++/** Crossbar Error Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_XBAR_ERROR 0x80000000 ++/* Nothing ++#define ICU0_IM1_ISR_XBAR_ERROR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_XBAR_ERROR_INTACK 0x80000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_XBAR_ERROR_INTOCC 0x80000000 ++/** DDR Controller Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_DDR 0x40000000 ++/* Nothing ++#define ICU0_IM1_ISR_DDR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_DDR_INTACK 0x40000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_DDR_INTOCC 0x40000000 ++/** FPI Bus Control Unit Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM1_ISR_BCU0 0x20000000 ++/* Nothing ++#define ICU0_IM1_ISR_BCU0_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_BCU0_INTACK 0x20000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_BCU0_INTOCC 0x20000000 ++/** SBIU interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_SBIU0 0x08000000 ++/* Nothing ++#define ICU0_IM1_ISR_SBIU0_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_SBIU0_INTACK 0x08000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_SBIU0_INTOCC 0x08000000 ++/** Watchdog Prewarning Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_WDT_PIR 0x02000000 ++/* Nothing ++#define ICU0_IM1_ISR_WDT_PIR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_WDT_PIR_INTACK 0x02000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_WDT_PIR_INTOCC 0x02000000 ++/** Watchdog Access Error Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_WDT_AEIR 0x01000000 ++/* Nothing ++#define ICU0_IM1_ISR_WDT_AEIR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_WDT_AEIR_INTACK 0x01000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_WDT_AEIR_INTOCC 0x01000000 ++/** SYS GPE Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_SYS_GPE 0x00200000 ++/* Nothing ++#define ICU0_IM1_ISR_SYS_GPE_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_SYS_GPE_INTACK 0x00200000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_SYS_GPE_INTOCC 0x00200000 ++/** SYS1 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_SYS1 0x00100000 ++/* Nothing ++#define ICU0_IM1_ISR_SYS1_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_SYS1_INTACK 0x00100000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_SYS1_INTOCC 0x00100000 ++/** PMA Interrupt from IntNode of the RX Clk Domain ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_PMA_RX 0x00020000 ++/* Nothing ++#define ICU0_IM1_ISR_PMA_RX_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_PMA_RX_INTACK 0x00020000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_PMA_RX_INTOCC 0x00020000 ++/** PMA Interrupt from IntNode of the TX Clk Domain ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_PMA_TX 0x00010000 ++/* Nothing ++#define ICU0_IM1_ISR_PMA_TX_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_PMA_TX_INTACK 0x00010000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_PMA_TX_INTOCC 0x00010000 ++/** PMA Interrupt from IntNode of the 200MHz Domain ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_PMA_200M 0x00008000 ++/* Nothing ++#define ICU0_IM1_ISR_PMA_200M_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_PMA_200M_INTACK 0x00008000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_PMA_200M_INTOCC 0x00008000 ++/** Time of Day ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_TOD 0x00004000 ++/* Nothing ++#define ICU0_IM1_ISR_TOD_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_TOD_INTACK 0x00004000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_TOD_INTOCC 0x00004000 ++/** 8kHz root interrupt derived from GPON interface ++ This bit is a direct interrupt. */ ++#define ICU0_IM1_ISR_FSC_ROOT 0x00002000 ++/* Nothing ++#define ICU0_IM1_ISR_FSC_ROOT_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_FSC_ROOT_INTACK 0x00002000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_FSC_ROOT_INTOCC 0x00002000 ++/** FSC Timer Interrupt 1 ++ Delayed version of FSCROOT. This bit is a direct interrupt. */ ++#define ICU0_IM1_ISR_FSCT_CMP1 0x00001000 ++/* Nothing ++#define ICU0_IM1_ISR_FSCT_CMP1_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_FSCT_CMP1_INTACK 0x00001000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_FSCT_CMP1_INTOCC 0x00001000 ++/** FSC Timer Interrupt 0 ++ Delayed version of FSCROOT. This bit is a direct interrupt. */ ++#define ICU0_IM1_ISR_FSCT_CMP0 0x00000800 ++/* Nothing ++#define ICU0_IM1_ISR_FSCT_CMP0_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_FSCT_CMP0_INTACK 0x00000800 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_FSCT_CMP0_INTOCC 0x00000800 ++/** 8kHz backup interrupt derived from core-PLL ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_FSC_BKP 0x00000400 ++/* Nothing ++#define ICU0_IM1_ISR_FSC_BKP_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_FSC_BKP_INTACK 0x00000400 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_FSC_BKP_INTOCC 0x00000400 ++/** External Interrupt from GPIO P4 ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_P4 0x00000100 ++/* Nothing ++#define ICU0_IM1_ISR_P4_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_P4_INTACK 0x00000100 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_P4_INTOCC 0x00000100 ++/** External Interrupt from GPIO P3 ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_P3 0x00000080 ++/* Nothing ++#define ICU0_IM1_ISR_P3_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_P3_INTACK 0x00000080 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_P3_INTOCC 0x00000080 ++/** External Interrupt from GPIO P2 ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_P2 0x00000040 ++/* Nothing ++#define ICU0_IM1_ISR_P2_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_P2_INTACK 0x00000040 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_P2_INTOCC 0x00000040 ++/** External Interrupt from GPIO P1 ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_P1 0x00000020 ++/* Nothing ++#define ICU0_IM1_ISR_P1_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_P1_INTACK 0x00000020 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_P1_INTOCC 0x00000020 ++/** External Interrupt from GPIO P0 ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_P0 0x00000010 ++/* Nothing ++#define ICU0_IM1_ISR_P0_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_P0_INTACK 0x00000010 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_P0_INTOCC 0x00000010 ++/** EBU Serial Flash Busy ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_EBU_SF_BUSY 0x00000004 ++/* Nothing ++#define ICU0_IM1_ISR_EBU_SF_BUSY_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_EBU_SF_BUSY_INTACK 0x00000004 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_EBU_SF_BUSY_INTOCC 0x00000004 ++/** EBU Serial Flash Command Overwrite Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_EBU_SF_COVERR 0x00000002 ++/* Nothing ++#define ICU0_IM1_ISR_EBU_SF_COVERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_EBU_SF_COVERR_INTACK 0x00000002 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_EBU_SF_COVERR_INTOCC 0x00000002 ++/** EBU Serial Flash Command Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM1_ISR_EBU_SF_CMDERR 0x00000001 ++/* Nothing ++#define ICU0_IM1_ISR_EBU_SF_CMDERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM1_ISR_EBU_SF_CMDERR_INTACK 0x00000001 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_ISR_EBU_SF_CMDERR_INTOCC 0x00000001 ++ ++/* Fields of "IM1 Interrupt Enable Register" */ ++/** Crossbar Error Interrupt ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_XBAR_ERROR 0x80000000 ++/* Disable ++#define ICU0_IM1_IER_XBAR_ERROR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_XBAR_ERROR_EN 0x80000000 ++/** DDR Controller Interrupt ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_DDR 0x40000000 ++/* Disable ++#define ICU0_IM1_IER_DDR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_DDR_EN 0x40000000 ++/** FPI Bus Control Unit Interrupt ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_BCU0 0x20000000 ++/* Disable ++#define ICU0_IM1_IER_BCU0_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_BCU0_EN 0x20000000 ++/** SBIU interrupt ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_SBIU0 0x08000000 ++/* Disable ++#define ICU0_IM1_IER_SBIU0_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_SBIU0_EN 0x08000000 ++/** Watchdog Prewarning Interrupt ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_WDT_PIR 0x02000000 ++/* Disable ++#define ICU0_IM1_IER_WDT_PIR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_WDT_PIR_EN 0x02000000 ++/** Watchdog Access Error Interrupt ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_WDT_AEIR 0x01000000 ++/* Disable ++#define ICU0_IM1_IER_WDT_AEIR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_WDT_AEIR_EN 0x01000000 ++/** SYS GPE Interrupt ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_SYS_GPE 0x00200000 ++/* Disable ++#define ICU0_IM1_IER_SYS_GPE_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_SYS_GPE_EN 0x00200000 ++/** SYS1 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_SYS1 0x00100000 ++/* Disable ++#define ICU0_IM1_IER_SYS1_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_SYS1_EN 0x00100000 ++/** PMA Interrupt from IntNode of the RX Clk Domain ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_PMA_RX 0x00020000 ++/* Disable ++#define ICU0_IM1_IER_PMA_RX_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_PMA_RX_EN 0x00020000 ++/** PMA Interrupt from IntNode of the TX Clk Domain ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_PMA_TX 0x00010000 ++/* Disable ++#define ICU0_IM1_IER_PMA_TX_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_PMA_TX_EN 0x00010000 ++/** PMA Interrupt from IntNode of the 200MHz Domain ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_PMA_200M 0x00008000 ++/* Disable ++#define ICU0_IM1_IER_PMA_200M_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_PMA_200M_EN 0x00008000 ++/** Time of Day ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_TOD 0x00004000 ++/* Disable ++#define ICU0_IM1_IER_TOD_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_TOD_EN 0x00004000 ++/** 8kHz root interrupt derived from GPON interface ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_FSC_ROOT 0x00002000 ++/* Disable ++#define ICU0_IM1_IER_FSC_ROOT_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_FSC_ROOT_EN 0x00002000 ++/** FSC Timer Interrupt 1 ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_FSCT_CMP1 0x00001000 ++/* Disable ++#define ICU0_IM1_IER_FSCT_CMP1_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_FSCT_CMP1_EN 0x00001000 ++/** FSC Timer Interrupt 0 ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_FSCT_CMP0 0x00000800 ++/* Disable ++#define ICU0_IM1_IER_FSCT_CMP0_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_FSCT_CMP0_EN 0x00000800 ++/** 8kHz backup interrupt derived from core-PLL ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_FSC_BKP 0x00000400 ++/* Disable ++#define ICU0_IM1_IER_FSC_BKP_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_FSC_BKP_EN 0x00000400 ++/** External Interrupt from GPIO P4 ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_P4 0x00000100 ++/* Disable ++#define ICU0_IM1_IER_P4_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_P4_EN 0x00000100 ++/** External Interrupt from GPIO P3 ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_P3 0x00000080 ++/* Disable ++#define ICU0_IM1_IER_P3_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_P3_EN 0x00000080 ++/** External Interrupt from GPIO P2 ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_P2 0x00000040 ++/* Disable ++#define ICU0_IM1_IER_P2_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_P2_EN 0x00000040 ++/** External Interrupt from GPIO P1 ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_P1 0x00000020 ++/* Disable ++#define ICU0_IM1_IER_P1_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_P1_EN 0x00000020 ++/** External Interrupt from GPIO P0 ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_P0 0x00000010 ++/* Disable ++#define ICU0_IM1_IER_P0_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_P0_EN 0x00000010 ++/** EBU Serial Flash Busy ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_EBU_SF_BUSY 0x00000004 ++/* Disable ++#define ICU0_IM1_IER_EBU_SF_BUSY_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_EBU_SF_BUSY_EN 0x00000004 ++/** EBU Serial Flash Command Overwrite Error ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_EBU_SF_COVERR 0x00000002 ++/* Disable ++#define ICU0_IM1_IER_EBU_SF_COVERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_EBU_SF_COVERR_EN 0x00000002 ++/** EBU Serial Flash Command Error ++ Interrupt enable bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IER_EBU_SF_CMDERR 0x00000001 ++/* Disable ++#define ICU0_IM1_IER_EBU_SF_CMDERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM1_IER_EBU_SF_CMDERR_EN 0x00000001 ++ ++/* Fields of "IM1 Interrupt Output Status Register" */ ++/** Crossbar Error Interrupt ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_XBAR_ERROR 0x80000000 ++/* Nothing ++#define ICU0_IM1_IOSR_XBAR_ERROR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_XBAR_ERROR_INTOCC 0x80000000 ++/** DDR Controller Interrupt ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_DDR 0x40000000 ++/* Nothing ++#define ICU0_IM1_IOSR_DDR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_DDR_INTOCC 0x40000000 ++/** FPI Bus Control Unit Interrupt ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_BCU0 0x20000000 ++/* Nothing ++#define ICU0_IM1_IOSR_BCU0_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_BCU0_INTOCC 0x20000000 ++/** SBIU interrupt ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_SBIU0 0x08000000 ++/* Nothing ++#define ICU0_IM1_IOSR_SBIU0_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_SBIU0_INTOCC 0x08000000 ++/** Watchdog Prewarning Interrupt ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_WDT_PIR 0x02000000 ++/* Nothing ++#define ICU0_IM1_IOSR_WDT_PIR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_WDT_PIR_INTOCC 0x02000000 ++/** Watchdog Access Error Interrupt ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_WDT_AEIR 0x01000000 ++/* Nothing ++#define ICU0_IM1_IOSR_WDT_AEIR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_WDT_AEIR_INTOCC 0x01000000 ++/** SYS GPE Interrupt ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_SYS_GPE 0x00200000 ++/* Nothing ++#define ICU0_IM1_IOSR_SYS_GPE_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_SYS_GPE_INTOCC 0x00200000 ++/** SYS1 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_SYS1 0x00100000 ++/* Nothing ++#define ICU0_IM1_IOSR_SYS1_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_SYS1_INTOCC 0x00100000 ++/** PMA Interrupt from IntNode of the RX Clk Domain ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_PMA_RX 0x00020000 ++/* Nothing ++#define ICU0_IM1_IOSR_PMA_RX_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_PMA_RX_INTOCC 0x00020000 ++/** PMA Interrupt from IntNode of the TX Clk Domain ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_PMA_TX 0x00010000 ++/* Nothing ++#define ICU0_IM1_IOSR_PMA_TX_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_PMA_TX_INTOCC 0x00010000 ++/** PMA Interrupt from IntNode of the 200MHz Domain ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_PMA_200M 0x00008000 ++/* Nothing ++#define ICU0_IM1_IOSR_PMA_200M_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_PMA_200M_INTOCC 0x00008000 ++/** Time of Day ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_TOD 0x00004000 ++/* Nothing ++#define ICU0_IM1_IOSR_TOD_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_TOD_INTOCC 0x00004000 ++/** 8kHz root interrupt derived from GPON interface ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_FSC_ROOT 0x00002000 ++/* Nothing ++#define ICU0_IM1_IOSR_FSC_ROOT_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_FSC_ROOT_INTOCC 0x00002000 ++/** FSC Timer Interrupt 1 ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_FSCT_CMP1 0x00001000 ++/* Nothing ++#define ICU0_IM1_IOSR_FSCT_CMP1_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_FSCT_CMP1_INTOCC 0x00001000 ++/** FSC Timer Interrupt 0 ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_FSCT_CMP0 0x00000800 ++/* Nothing ++#define ICU0_IM1_IOSR_FSCT_CMP0_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_FSCT_CMP0_INTOCC 0x00000800 ++/** 8kHz backup interrupt derived from core-PLL ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_FSC_BKP 0x00000400 ++/* Nothing ++#define ICU0_IM1_IOSR_FSC_BKP_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_FSC_BKP_INTOCC 0x00000400 ++/** External Interrupt from GPIO P4 ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_P4 0x00000100 ++/* Nothing ++#define ICU0_IM1_IOSR_P4_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_P4_INTOCC 0x00000100 ++/** External Interrupt from GPIO P3 ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_P3 0x00000080 ++/* Nothing ++#define ICU0_IM1_IOSR_P3_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_P3_INTOCC 0x00000080 ++/** External Interrupt from GPIO P2 ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_P2 0x00000040 ++/* Nothing ++#define ICU0_IM1_IOSR_P2_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_P2_INTOCC 0x00000040 ++/** External Interrupt from GPIO P1 ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_P1 0x00000020 ++/* Nothing ++#define ICU0_IM1_IOSR_P1_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_P1_INTOCC 0x00000020 ++/** External Interrupt from GPIO P0 ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_P0 0x00000010 ++/* Nothing ++#define ICU0_IM1_IOSR_P0_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_P0_INTOCC 0x00000010 ++/** EBU Serial Flash Busy ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_EBU_SF_BUSY 0x00000004 ++/* Nothing ++#define ICU0_IM1_IOSR_EBU_SF_BUSY_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_EBU_SF_BUSY_INTOCC 0x00000004 ++/** EBU Serial Flash Command Overwrite Error ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_EBU_SF_COVERR 0x00000002 ++/* Nothing ++#define ICU0_IM1_IOSR_EBU_SF_COVERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_EBU_SF_COVERR_INTOCC 0x00000002 ++/** EBU Serial Flash Command Error ++ Masked interrupt bit for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IOSR_EBU_SF_CMDERR 0x00000001 ++/* Nothing ++#define ICU0_IM1_IOSR_EBU_SF_CMDERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM1_IOSR_EBU_SF_CMDERR_INTOCC 0x00000001 ++ ++/* Fields of "IM1 Interrupt Request Set Register" */ ++/** Crossbar Error Interrupt ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_XBAR_ERROR 0x80000000 ++/** DDR Controller Interrupt ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_DDR 0x40000000 ++/** FPI Bus Control Unit Interrupt ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_BCU0 0x20000000 ++/** SBIU interrupt ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_SBIU0 0x08000000 ++/** Watchdog Prewarning Interrupt ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_WDT_PIR 0x02000000 ++/** Watchdog Access Error Interrupt ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_WDT_AEIR 0x01000000 ++/** SYS GPE Interrupt ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_SYS_GPE 0x00200000 ++/** SYS1 Interrupt ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_SYS1 0x00100000 ++/** PMA Interrupt from IntNode of the RX Clk Domain ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_PMA_RX 0x00020000 ++/** PMA Interrupt from IntNode of the TX Clk Domain ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_PMA_TX 0x00010000 ++/** PMA Interrupt from IntNode of the 200MHz Domain ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_PMA_200M 0x00008000 ++/** Time of Day ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_TOD 0x00004000 ++/** 8kHz root interrupt derived from GPON interface ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_FSC_ROOT 0x00002000 ++/** FSC Timer Interrupt 1 ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_FSCT_CMP1 0x00001000 ++/** FSC Timer Interrupt 0 ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_FSCT_CMP0 0x00000800 ++/** 8kHz backup interrupt derived from core-PLL ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_FSC_BKP 0x00000400 ++/** External Interrupt from GPIO P4 ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_P4 0x00000100 ++/** External Interrupt from GPIO P3 ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_P3 0x00000080 ++/** External Interrupt from GPIO P2 ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_P2 0x00000040 ++/** External Interrupt from GPIO P1 ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_P1 0x00000020 ++/** External Interrupt from GPIO P0 ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_P0 0x00000010 ++/** EBU Serial Flash Busy ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_EBU_SF_BUSY 0x00000004 ++/** EBU Serial Flash Command Overwrite Error ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_EBU_SF_COVERR 0x00000002 ++/** EBU Serial Flash Command Error ++ Software control for the corresponding bit in the IM1_ISR register. */ ++#define ICU0_IM1_IRSR_EBU_SF_CMDERR 0x00000001 ++ ++/* Fields of "IM1 Interrupt Mode Register" */ ++/** Crossbar Error Interrupt ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_XBAR_ERROR 0x80000000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_XBAR_ERROR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_XBAR_ERROR_DIR 0x80000000 ++/** DDR Controller Interrupt ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_DDR 0x40000000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_DDR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_DDR_DIR 0x40000000 ++/** FPI Bus Control Unit Interrupt ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_BCU0 0x20000000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_BCU0_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_BCU0_DIR 0x20000000 ++/** SBIU interrupt ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_SBIU0 0x08000000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_SBIU0_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_SBIU0_DIR 0x08000000 ++/** Watchdog Prewarning Interrupt ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_WDT_PIR 0x02000000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_WDT_PIR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_WDT_PIR_DIR 0x02000000 ++/** Watchdog Access Error Interrupt ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_WDT_AEIR 0x01000000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_WDT_AEIR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_WDT_AEIR_DIR 0x01000000 ++/** SYS GPE Interrupt ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_SYS_GPE 0x00200000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_SYS_GPE_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_SYS_GPE_DIR 0x00200000 ++/** SYS1 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_SYS1 0x00100000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_SYS1_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_SYS1_DIR 0x00100000 ++/** PMA Interrupt from IntNode of the RX Clk Domain ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_PMA_RX 0x00020000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_PMA_RX_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_PMA_RX_DIR 0x00020000 ++/** PMA Interrupt from IntNode of the TX Clk Domain ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_PMA_TX 0x00010000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_PMA_TX_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_PMA_TX_DIR 0x00010000 ++/** PMA Interrupt from IntNode of the 200MHz Domain ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_PMA_200M 0x00008000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_PMA_200M_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_PMA_200M_DIR 0x00008000 ++/** Time of Day ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_TOD 0x00004000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_TOD_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_TOD_DIR 0x00004000 ++/** 8kHz root interrupt derived from GPON interface ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_FSC_ROOT 0x00002000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_FSC_ROOT_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_FSC_ROOT_DIR 0x00002000 ++/** FSC Timer Interrupt 1 ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_FSCT_CMP1 0x00001000 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_FSCT_CMP1_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_FSCT_CMP1_DIR 0x00001000 ++/** FSC Timer Interrupt 0 ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_FSCT_CMP0 0x00000800 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_FSCT_CMP0_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_FSCT_CMP0_DIR 0x00000800 ++/** 8kHz backup interrupt derived from core-PLL ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_FSC_BKP 0x00000400 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_FSC_BKP_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_FSC_BKP_DIR 0x00000400 ++/** External Interrupt from GPIO P4 ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_P4 0x00000100 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_P4_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_P4_DIR 0x00000100 ++/** External Interrupt from GPIO P3 ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_P3 0x00000080 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_P3_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_P3_DIR 0x00000080 ++/** External Interrupt from GPIO P2 ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_P2 0x00000040 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_P2_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_P2_DIR 0x00000040 ++/** External Interrupt from GPIO P1 ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_P1 0x00000020 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_P1_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_P1_DIR 0x00000020 ++/** External Interrupt from GPIO P0 ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_P0 0x00000010 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_P0_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_P0_DIR 0x00000010 ++/** EBU Serial Flash Busy ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_EBU_SF_BUSY 0x00000004 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_EBU_SF_BUSY_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_EBU_SF_BUSY_DIR 0x00000004 ++/** EBU Serial Flash Command Overwrite Error ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_EBU_SF_COVERR 0x00000002 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_EBU_SF_COVERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_EBU_SF_COVERR_DIR 0x00000002 ++/** EBU Serial Flash Command Error ++ Type of interrupt. */ ++#define ICU0_IM1_IMR_EBU_SF_CMDERR 0x00000001 ++/* Indirect Interrupt. ++#define ICU0_IM1_IMR_EBU_SF_CMDERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM1_IMR_EBU_SF_CMDERR_DIR 0x00000001 ++ ++/* Fields of "IM2 Interrupt Status Register" */ ++/** EIM Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_EIM 0x80000000 ++/* Nothing ++#define ICU0_IM2_ISR_EIM_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_EIM_INTACK 0x80000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_EIM_INTOCC 0x80000000 ++/** GTC Upstream Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_GTC_US 0x40000000 ++/* Nothing ++#define ICU0_IM2_ISR_GTC_US_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_GTC_US_INTACK 0x40000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_GTC_US_INTOCC 0x40000000 ++/** GTC Downstream Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_GTC_DS 0x20000000 ++/* Nothing ++#define ICU0_IM2_ISR_GTC_DS_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_GTC_DS_INTACK 0x20000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_GTC_DS_INTOCC 0x20000000 ++/** TBM Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_TBM 0x00400000 ++/* Nothing ++#define ICU0_IM2_ISR_TBM_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_TBM_INTACK 0x00400000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_TBM_INTOCC 0x00400000 ++/** Dispatcher Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_DISP 0x00200000 ++/* Nothing ++#define ICU0_IM2_ISR_DISP_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_DISP_INTACK 0x00200000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_DISP_INTOCC 0x00200000 ++/** CONFIG Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_CONFIG 0x00100000 ++/* Nothing ++#define ICU0_IM2_ISR_CONFIG_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_CONFIG_INTACK 0x00100000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_CONFIG_INTOCC 0x00100000 ++/** CONFIG Break Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_CONFIG_BREAK 0x00080000 ++/* Nothing ++#define ICU0_IM2_ISR_CONFIG_BREAK_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_CONFIG_BREAK_INTACK 0x00080000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_CONFIG_BREAK_INTOCC 0x00080000 ++/** OCTRLC Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_OCTRLC 0x00040000 ++/* Nothing ++#define ICU0_IM2_ISR_OCTRLC_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_OCTRLC_INTACK 0x00040000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_OCTRLC_INTOCC 0x00040000 ++/** ICTRLC 1 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_ICTRLC1 0x00020000 ++/* Nothing ++#define ICU0_IM2_ISR_ICTRLC1_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_ICTRLC1_INTACK 0x00020000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_ICTRLC1_INTOCC 0x00020000 ++/** ICTRLC 0 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_ICTRLC0 0x00010000 ++/* Nothing ++#define ICU0_IM2_ISR_ICTRLC0_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_ICTRLC0_INTACK 0x00010000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_ICTRLC0_INTOCC 0x00010000 ++/** LINK 1 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_LINK1 0x00004000 ++/* Nothing ++#define ICU0_IM2_ISR_LINK1_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_LINK1_INTACK 0x00004000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_LINK1_INTOCC 0x00004000 ++/** TMU Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_TMU 0x00001000 ++/* Nothing ++#define ICU0_IM2_ISR_TMU_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_TMU_INTACK 0x00001000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_TMU_INTOCC 0x00001000 ++/** FSQM Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_FSQM 0x00000800 ++/* Nothing ++#define ICU0_IM2_ISR_FSQM_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_FSQM_INTACK 0x00000800 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_FSQM_INTOCC 0x00000800 ++/** IQM Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_IQM 0x00000400 ++/* Nothing ++#define ICU0_IM2_ISR_IQM_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_IQM_INTACK 0x00000400 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_IQM_INTOCC 0x00000400 ++/** OCTRLG Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_OCTRLG 0x00000200 ++/* Nothing ++#define ICU0_IM2_ISR_OCTRLG_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_OCTRLG_INTACK 0x00000200 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_OCTRLG_INTOCC 0x00000200 ++/** OCTRLL 3 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_OCTRLL3 0x00000080 ++/* Nothing ++#define ICU0_IM2_ISR_OCTRLL3_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_OCTRLL3_INTACK 0x00000080 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_OCTRLL3_INTOCC 0x00000080 ++/** OCTRLL 2 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_OCTRLL2 0x00000040 ++/* Nothing ++#define ICU0_IM2_ISR_OCTRLL2_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_OCTRLL2_INTACK 0x00000040 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_OCTRLL2_INTOCC 0x00000040 ++/** OCTRLL 1 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_OCTRLL1 0x00000020 ++/* Nothing ++#define ICU0_IM2_ISR_OCTRLL1_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_OCTRLL1_INTACK 0x00000020 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_OCTRLL1_INTOCC 0x00000020 ++/** OCTRLL 0 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_OCTRLL0 0x00000010 ++/* Nothing ++#define ICU0_IM2_ISR_OCTRLL0_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_OCTRLL0_INTACK 0x00000010 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_OCTRLL0_INTOCC 0x00000010 ++/** ICTRLL 3 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_ICTRLL3 0x00000008 ++/* Nothing ++#define ICU0_IM2_ISR_ICTRLL3_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_ICTRLL3_INTACK 0x00000008 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_ICTRLL3_INTOCC 0x00000008 ++/** ICTRLL 2 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_ICTRLL2 0x00000004 ++/* Nothing ++#define ICU0_IM2_ISR_ICTRLL2_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_ICTRLL2_INTACK 0x00000004 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_ICTRLL2_INTOCC 0x00000004 ++/** ICTRLL 1 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_ICTRLL1 0x00000002 ++/* Nothing ++#define ICU0_IM2_ISR_ICTRLL1_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_ICTRLL1_INTACK 0x00000002 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_ICTRLL1_INTOCC 0x00000002 ++/** ICTRLL 0 Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM2_ISR_ICTRLL0 0x00000001 ++/* Nothing ++#define ICU0_IM2_ISR_ICTRLL0_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM2_ISR_ICTRLL0_INTACK 0x00000001 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_ISR_ICTRLL0_INTOCC 0x00000001 ++ ++/* Fields of "IM2 Interrupt Enable Register" */ ++/** EIM Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_EIM 0x80000000 ++/* Disable ++#define ICU0_IM2_IER_EIM_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_EIM_EN 0x80000000 ++/** GTC Upstream Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_GTC_US 0x40000000 ++/* Disable ++#define ICU0_IM2_IER_GTC_US_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_GTC_US_EN 0x40000000 ++/** GTC Downstream Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_GTC_DS 0x20000000 ++/* Disable ++#define ICU0_IM2_IER_GTC_DS_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_GTC_DS_EN 0x20000000 ++/** TBM Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_TBM 0x00400000 ++/* Disable ++#define ICU0_IM2_IER_TBM_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_TBM_EN 0x00400000 ++/** Dispatcher Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_DISP 0x00200000 ++/* Disable ++#define ICU0_IM2_IER_DISP_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_DISP_EN 0x00200000 ++/** CONFIG Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_CONFIG 0x00100000 ++/* Disable ++#define ICU0_IM2_IER_CONFIG_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_CONFIG_EN 0x00100000 ++/** CONFIG Break Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_CONFIG_BREAK 0x00080000 ++/* Disable ++#define ICU0_IM2_IER_CONFIG_BREAK_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_CONFIG_BREAK_EN 0x00080000 ++/** OCTRLC Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_OCTRLC 0x00040000 ++/* Disable ++#define ICU0_IM2_IER_OCTRLC_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_OCTRLC_EN 0x00040000 ++/** ICTRLC 1 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_ICTRLC1 0x00020000 ++/* Disable ++#define ICU0_IM2_IER_ICTRLC1_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_ICTRLC1_EN 0x00020000 ++/** ICTRLC 0 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_ICTRLC0 0x00010000 ++/* Disable ++#define ICU0_IM2_IER_ICTRLC0_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_ICTRLC0_EN 0x00010000 ++/** LINK 1 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_LINK1 0x00004000 ++/* Disable ++#define ICU0_IM2_IER_LINK1_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_LINK1_EN 0x00004000 ++/** TMU Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_TMU 0x00001000 ++/* Disable ++#define ICU0_IM2_IER_TMU_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_TMU_EN 0x00001000 ++/** FSQM Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_FSQM 0x00000800 ++/* Disable ++#define ICU0_IM2_IER_FSQM_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_FSQM_EN 0x00000800 ++/** IQM Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_IQM 0x00000400 ++/* Disable ++#define ICU0_IM2_IER_IQM_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_IQM_EN 0x00000400 ++/** OCTRLG Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_OCTRLG 0x00000200 ++/* Disable ++#define ICU0_IM2_IER_OCTRLG_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_OCTRLG_EN 0x00000200 ++/** OCTRLL 3 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_OCTRLL3 0x00000080 ++/* Disable ++#define ICU0_IM2_IER_OCTRLL3_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_OCTRLL3_EN 0x00000080 ++/** OCTRLL 2 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_OCTRLL2 0x00000040 ++/* Disable ++#define ICU0_IM2_IER_OCTRLL2_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_OCTRLL2_EN 0x00000040 ++/** OCTRLL 1 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_OCTRLL1 0x00000020 ++/* Disable ++#define ICU0_IM2_IER_OCTRLL1_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_OCTRLL1_EN 0x00000020 ++/** OCTRLL 0 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_OCTRLL0 0x00000010 ++/* Disable ++#define ICU0_IM2_IER_OCTRLL0_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_OCTRLL0_EN 0x00000010 ++/** ICTRLL 3 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_ICTRLL3 0x00000008 ++/* Disable ++#define ICU0_IM2_IER_ICTRLL3_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_ICTRLL3_EN 0x00000008 ++/** ICTRLL 2 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_ICTRLL2 0x00000004 ++/* Disable ++#define ICU0_IM2_IER_ICTRLL2_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_ICTRLL2_EN 0x00000004 ++/** ICTRLL 1 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_ICTRLL1 0x00000002 ++/* Disable ++#define ICU0_IM2_IER_ICTRLL1_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_ICTRLL1_EN 0x00000002 ++/** ICTRLL 0 Interrupt ++ Interrupt enable bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IER_ICTRLL0 0x00000001 ++/* Disable ++#define ICU0_IM2_IER_ICTRLL0_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM2_IER_ICTRLL0_EN 0x00000001 ++ ++/* Fields of "IM2 Interrupt Output Status Register" */ ++/** EIM Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_EIM 0x80000000 ++/* Nothing ++#define ICU0_IM2_IOSR_EIM_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_EIM_INTOCC 0x80000000 ++/** GTC Upstream Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_GTC_US 0x40000000 ++/* Nothing ++#define ICU0_IM2_IOSR_GTC_US_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_GTC_US_INTOCC 0x40000000 ++/** GTC Downstream Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_GTC_DS 0x20000000 ++/* Nothing ++#define ICU0_IM2_IOSR_GTC_DS_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_GTC_DS_INTOCC 0x20000000 ++/** TBM Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_TBM 0x00400000 ++/* Nothing ++#define ICU0_IM2_IOSR_TBM_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_TBM_INTOCC 0x00400000 ++/** Dispatcher Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_DISP 0x00200000 ++/* Nothing ++#define ICU0_IM2_IOSR_DISP_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_DISP_INTOCC 0x00200000 ++/** CONFIG Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_CONFIG 0x00100000 ++/* Nothing ++#define ICU0_IM2_IOSR_CONFIG_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_CONFIG_INTOCC 0x00100000 ++/** CONFIG Break Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_CONFIG_BREAK 0x00080000 ++/* Nothing ++#define ICU0_IM2_IOSR_CONFIG_BREAK_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_CONFIG_BREAK_INTOCC 0x00080000 ++/** OCTRLC Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_OCTRLC 0x00040000 ++/* Nothing ++#define ICU0_IM2_IOSR_OCTRLC_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_OCTRLC_INTOCC 0x00040000 ++/** ICTRLC 1 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_ICTRLC1 0x00020000 ++/* Nothing ++#define ICU0_IM2_IOSR_ICTRLC1_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_ICTRLC1_INTOCC 0x00020000 ++/** ICTRLC 0 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_ICTRLC0 0x00010000 ++/* Nothing ++#define ICU0_IM2_IOSR_ICTRLC0_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_ICTRLC0_INTOCC 0x00010000 ++/** LINK 1 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_LINK1 0x00004000 ++/* Nothing ++#define ICU0_IM2_IOSR_LINK1_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_LINK1_INTOCC 0x00004000 ++/** TMU Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_TMU 0x00001000 ++/* Nothing ++#define ICU0_IM2_IOSR_TMU_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_TMU_INTOCC 0x00001000 ++/** FSQM Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_FSQM 0x00000800 ++/* Nothing ++#define ICU0_IM2_IOSR_FSQM_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_FSQM_INTOCC 0x00000800 ++/** IQM Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_IQM 0x00000400 ++/* Nothing ++#define ICU0_IM2_IOSR_IQM_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_IQM_INTOCC 0x00000400 ++/** OCTRLG Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_OCTRLG 0x00000200 ++/* Nothing ++#define ICU0_IM2_IOSR_OCTRLG_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_OCTRLG_INTOCC 0x00000200 ++/** OCTRLL 3 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_OCTRLL3 0x00000080 ++/* Nothing ++#define ICU0_IM2_IOSR_OCTRLL3_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_OCTRLL3_INTOCC 0x00000080 ++/** OCTRLL 2 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_OCTRLL2 0x00000040 ++/* Nothing ++#define ICU0_IM2_IOSR_OCTRLL2_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_OCTRLL2_INTOCC 0x00000040 ++/** OCTRLL 1 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_OCTRLL1 0x00000020 ++/* Nothing ++#define ICU0_IM2_IOSR_OCTRLL1_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_OCTRLL1_INTOCC 0x00000020 ++/** OCTRLL 0 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_OCTRLL0 0x00000010 ++/* Nothing ++#define ICU0_IM2_IOSR_OCTRLL0_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_OCTRLL0_INTOCC 0x00000010 ++/** ICTRLL 3 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_ICTRLL3 0x00000008 ++/* Nothing ++#define ICU0_IM2_IOSR_ICTRLL3_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_ICTRLL3_INTOCC 0x00000008 ++/** ICTRLL 2 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_ICTRLL2 0x00000004 ++/* Nothing ++#define ICU0_IM2_IOSR_ICTRLL2_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_ICTRLL2_INTOCC 0x00000004 ++/** ICTRLL 1 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_ICTRLL1 0x00000002 ++/* Nothing ++#define ICU0_IM2_IOSR_ICTRLL1_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_ICTRLL1_INTOCC 0x00000002 ++/** ICTRLL 0 Interrupt ++ Masked interrupt bit for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IOSR_ICTRLL0 0x00000001 ++/* Nothing ++#define ICU0_IM2_IOSR_ICTRLL0_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM2_IOSR_ICTRLL0_INTOCC 0x00000001 ++ ++/* Fields of "IM2 Interrupt Request Set Register" */ ++/** EIM Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_EIM 0x80000000 ++/** GTC Upstream Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_GTC_US 0x40000000 ++/** GTC Downstream Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_GTC_DS 0x20000000 ++/** TBM Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_TBM 0x00400000 ++/** Dispatcher Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_DISP 0x00200000 ++/** CONFIG Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_CONFIG 0x00100000 ++/** CONFIG Break Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_CONFIG_BREAK 0x00080000 ++/** OCTRLC Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_OCTRLC 0x00040000 ++/** ICTRLC 1 Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_ICTRLC1 0x00020000 ++/** ICTRLC 0 Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_ICTRLC0 0x00010000 ++/** LINK 1 Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_LINK1 0x00004000 ++/** TMU Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_TMU 0x00001000 ++/** FSQM Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_FSQM 0x00000800 ++/** IQM Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_IQM 0x00000400 ++/** OCTRLG Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_OCTRLG 0x00000200 ++/** OCTRLL 3 Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_OCTRLL3 0x00000080 ++/** OCTRLL 2 Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_OCTRLL2 0x00000040 ++/** OCTRLL 1 Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_OCTRLL1 0x00000020 ++/** OCTRLL 0 Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_OCTRLL0 0x00000010 ++/** ICTRLL 3 Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_ICTRLL3 0x00000008 ++/** ICTRLL 2 Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_ICTRLL2 0x00000004 ++/** ICTRLL 1 Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_ICTRLL1 0x00000002 ++/** ICTRLL 0 Interrupt ++ Software control for the corresponding bit in the IM2_ISR register. */ ++#define ICU0_IM2_IRSR_ICTRLL0 0x00000001 ++ ++/* Fields of "IM2 Interrupt Mode Register" */ ++/** EIM Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_EIM 0x80000000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_EIM_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_EIM_DIR 0x80000000 ++/** GTC Upstream Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_GTC_US 0x40000000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_GTC_US_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_GTC_US_DIR 0x40000000 ++/** GTC Downstream Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_GTC_DS 0x20000000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_GTC_DS_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_GTC_DS_DIR 0x20000000 ++/** TBM Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_TBM 0x00400000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_TBM_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_TBM_DIR 0x00400000 ++/** Dispatcher Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_DISP 0x00200000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_DISP_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_DISP_DIR 0x00200000 ++/** CONFIG Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_CONFIG 0x00100000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_CONFIG_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_CONFIG_DIR 0x00100000 ++/** CONFIG Break Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_CONFIG_BREAK 0x00080000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_CONFIG_BREAK_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_CONFIG_BREAK_DIR 0x00080000 ++/** OCTRLC Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_OCTRLC 0x00040000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_OCTRLC_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_OCTRLC_DIR 0x00040000 ++/** ICTRLC 1 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_ICTRLC1 0x00020000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_ICTRLC1_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_ICTRLC1_DIR 0x00020000 ++/** ICTRLC 0 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_ICTRLC0 0x00010000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_ICTRLC0_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_ICTRLC0_DIR 0x00010000 ++/** LINK 1 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_LINK1 0x00004000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_LINK1_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_LINK1_DIR 0x00004000 ++/** TMU Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_TMU 0x00001000 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_TMU_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_TMU_DIR 0x00001000 ++/** FSQM Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_FSQM 0x00000800 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_FSQM_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_FSQM_DIR 0x00000800 ++/** IQM Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_IQM 0x00000400 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_IQM_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_IQM_DIR 0x00000400 ++/** OCTRLG Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_OCTRLG 0x00000200 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_OCTRLG_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_OCTRLG_DIR 0x00000200 ++/** OCTRLL 3 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_OCTRLL3 0x00000080 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_OCTRLL3_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_OCTRLL3_DIR 0x00000080 ++/** OCTRLL 2 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_OCTRLL2 0x00000040 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_OCTRLL2_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_OCTRLL2_DIR 0x00000040 ++/** OCTRLL 1 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_OCTRLL1 0x00000020 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_OCTRLL1_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_OCTRLL1_DIR 0x00000020 ++/** OCTRLL 0 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_OCTRLL0 0x00000010 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_OCTRLL0_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_OCTRLL0_DIR 0x00000010 ++/** ICTRLL 3 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_ICTRLL3 0x00000008 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_ICTRLL3_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_ICTRLL3_DIR 0x00000008 ++/** ICTRLL 2 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_ICTRLL2 0x00000004 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_ICTRLL2_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_ICTRLL2_DIR 0x00000004 ++/** ICTRLL 1 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_ICTRLL1 0x00000002 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_ICTRLL1_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_ICTRLL1_DIR 0x00000002 ++/** ICTRLL 0 Interrupt ++ Type of interrupt. */ ++#define ICU0_IM2_IMR_ICTRLL0 0x00000001 ++/* Indirect Interrupt. ++#define ICU0_IM2_IMR_ICTRLL0_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM2_IMR_ICTRLL0_DIR 0x00000001 ++ ++/* Fields of "IM3 Interrupt Status Register" */ ++/** DFEV0, Channel 0 General Purpose Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_1GP 0x80000000 ++/* Nothing ++#define ICU0_IM3_ISR_DFEV0_1GP_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_1GP_INTACK 0x80000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_DFEV0_1GP_INTOCC 0x80000000 ++/** DFEV0, Channel 0 Receive Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_1RX 0x40000000 ++/* Nothing ++#define ICU0_IM3_ISR_DFEV0_1RX_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_1RX_INTACK 0x40000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_DFEV0_1RX_INTOCC 0x40000000 ++/** DFEV0, Channel 0 Transmit Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_1TX 0x20000000 ++/* Nothing ++#define ICU0_IM3_ISR_DFEV0_1TX_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_1TX_INTACK 0x20000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_DFEV0_1TX_INTOCC 0x20000000 ++/** DFEV0, Channel 1 General Purpose Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_2GP 0x10000000 ++/* Nothing ++#define ICU0_IM3_ISR_DFEV0_2GP_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_2GP_INTACK 0x10000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_DFEV0_2GP_INTOCC 0x10000000 ++/** DFEV0, Channel 1 Receive Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_2RX 0x08000000 ++/* Nothing ++#define ICU0_IM3_ISR_DFEV0_2RX_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_2RX_INTACK 0x08000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_DFEV0_2RX_INTOCC 0x08000000 ++/** DFEV0, Channel 1 Transmit Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_2TX 0x04000000 ++/* Nothing ++#define ICU0_IM3_ISR_DFEV0_2TX_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_DFEV0_2TX_INTACK 0x04000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_DFEV0_2TX_INTOCC 0x04000000 ++/** GPTC Timer/Counter 3B Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC3B 0x00200000 ++/* Nothing ++#define ICU0_IM3_ISR_GPTC_TC3B_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC3B_INTACK 0x00200000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_GPTC_TC3B_INTOCC 0x00200000 ++/** GPTC Timer/Counter 3A Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC3A 0x00100000 ++/* Nothing ++#define ICU0_IM3_ISR_GPTC_TC3A_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC3A_INTACK 0x00100000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_GPTC_TC3A_INTOCC 0x00100000 ++/** GPTC Timer/Counter 2B Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC2B 0x00080000 ++/* Nothing ++#define ICU0_IM3_ISR_GPTC_TC2B_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC2B_INTACK 0x00080000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_GPTC_TC2B_INTOCC 0x00080000 ++/** GPTC Timer/Counter 2A Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC2A 0x00040000 ++/* Nothing ++#define ICU0_IM3_ISR_GPTC_TC2A_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC2A_INTACK 0x00040000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_GPTC_TC2A_INTOCC 0x00040000 ++/** GPTC Timer/Counter 1B Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC1B 0x00020000 ++/* Nothing ++#define ICU0_IM3_ISR_GPTC_TC1B_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC1B_INTACK 0x00020000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_GPTC_TC1B_INTOCC 0x00020000 ++/** GPTC Timer/Counter 1A Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC1A 0x00010000 ++/* Nothing ++#define ICU0_IM3_ISR_GPTC_TC1A_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_GPTC_TC1A_INTACK 0x00010000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_GPTC_TC1A_INTOCC 0x00010000 ++/** ASC1 Soft Flow Control Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC1_SFC 0x00008000 ++/* Nothing ++#define ICU0_IM3_ISR_ASC1_SFC_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC1_SFC_INTACK 0x00008000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC1_SFC_INTOCC 0x00008000 ++/** ASC1 Modem Status Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC1_MS 0x00004000 ++/* Nothing ++#define ICU0_IM3_ISR_ASC1_MS_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC1_MS_INTACK 0x00004000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC1_MS_INTOCC 0x00004000 ++/** ASC1 Autobaud Detection Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC1_ABDET 0x00002000 ++/* Nothing ++#define ICU0_IM3_ISR_ASC1_ABDET_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC1_ABDET_INTACK 0x00002000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC1_ABDET_INTOCC 0x00002000 ++/** ASC1 Autobaud Start Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC1_ABST 0x00001000 ++/* Nothing ++#define ICU0_IM3_ISR_ASC1_ABST_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC1_ABST_INTACK 0x00001000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC1_ABST_INTOCC 0x00001000 ++/** ASC1 Transmit Buffer Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC1_TB 0x00000800 ++/* Nothing ++#define ICU0_IM3_ISR_ASC1_TB_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC1_TB_INTACK 0x00000800 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC1_TB_INTOCC 0x00000800 ++/** ASC1 Error Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC1_E 0x00000400 ++/* Nothing ++#define ICU0_IM3_ISR_ASC1_E_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC1_E_INTACK 0x00000400 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC1_E_INTOCC 0x00000400 ++/** ASC1 Receive Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC1_R 0x00000200 ++/* Nothing ++#define ICU0_IM3_ISR_ASC1_R_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC1_R_INTACK 0x00000200 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC1_R_INTOCC 0x00000200 ++/** ASC1 Transmit Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC1_T 0x00000100 ++/* Nothing ++#define ICU0_IM3_ISR_ASC1_T_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC1_T_INTACK 0x00000100 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC1_T_INTOCC 0x00000100 ++/** ASC0 Soft Flow Control Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC0_SFC 0x00000080 ++/* Nothing ++#define ICU0_IM3_ISR_ASC0_SFC_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC0_SFC_INTACK 0x00000080 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC0_SFC_INTOCC 0x00000080 ++/** ASC1 Modem Status Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC0_MS 0x00000040 ++/* Nothing ++#define ICU0_IM3_ISR_ASC0_MS_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC0_MS_INTACK 0x00000040 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC0_MS_INTOCC 0x00000040 ++/** ASC0 Autobaud Detection Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC0_ABDET 0x00000020 ++/* Nothing ++#define ICU0_IM3_ISR_ASC0_ABDET_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC0_ABDET_INTACK 0x00000020 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC0_ABDET_INTOCC 0x00000020 ++/** ASC0 Autobaud Start Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC0_ABST 0x00000010 ++/* Nothing ++#define ICU0_IM3_ISR_ASC0_ABST_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC0_ABST_INTACK 0x00000010 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC0_ABST_INTOCC 0x00000010 ++/** ASC0 Transmit Buffer Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC0_TB 0x00000008 ++/* Nothing ++#define ICU0_IM3_ISR_ASC0_TB_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC0_TB_INTACK 0x00000008 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC0_TB_INTOCC 0x00000008 ++/** ASC0 Error Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC0_E 0x00000004 ++/* Nothing ++#define ICU0_IM3_ISR_ASC0_E_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC0_E_INTACK 0x00000004 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC0_E_INTOCC 0x00000004 ++/** ASC0 Receive Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC0_R 0x00000002 ++/* Nothing ++#define ICU0_IM3_ISR_ASC0_R_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC0_R_INTACK 0x00000002 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC0_R_INTOCC 0x00000002 ++/** ASC0 Transmit Interrupt ++ This bit is a direct interrupt. */ ++#define ICU0_IM3_ISR_ASC0_T 0x00000001 ++/* Nothing ++#define ICU0_IM3_ISR_ASC0_T_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM3_ISR_ASC0_T_INTACK 0x00000001 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_ISR_ASC0_T_INTOCC 0x00000001 ++ ++/* Fields of "IM3 Interrupt Enable Register" */ ++/** DFEV0, Channel 0 General Purpose Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_DFEV0_1GP 0x80000000 ++/* Disable ++#define ICU0_IM3_IER_DFEV0_1GP_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_DFEV0_1GP_EN 0x80000000 ++/** DFEV0, Channel 0 Receive Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_DFEV0_1RX 0x40000000 ++/* Disable ++#define ICU0_IM3_IER_DFEV0_1RX_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_DFEV0_1RX_EN 0x40000000 ++/** DFEV0, Channel 0 Transmit Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_DFEV0_1TX 0x20000000 ++/* Disable ++#define ICU0_IM3_IER_DFEV0_1TX_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_DFEV0_1TX_EN 0x20000000 ++/** DFEV0, Channel 1 General Purpose Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_DFEV0_2GP 0x10000000 ++/* Disable ++#define ICU0_IM3_IER_DFEV0_2GP_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_DFEV0_2GP_EN 0x10000000 ++/** DFEV0, Channel 1 Receive Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_DFEV0_2RX 0x08000000 ++/* Disable ++#define ICU0_IM3_IER_DFEV0_2RX_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_DFEV0_2RX_EN 0x08000000 ++/** DFEV0, Channel 1 Transmit Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_DFEV0_2TX 0x04000000 ++/* Disable ++#define ICU0_IM3_IER_DFEV0_2TX_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_DFEV0_2TX_EN 0x04000000 ++/** GPTC Timer/Counter 3B Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_GPTC_TC3B 0x00200000 ++/* Disable ++#define ICU0_IM3_IER_GPTC_TC3B_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_GPTC_TC3B_EN 0x00200000 ++/** GPTC Timer/Counter 3A Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_GPTC_TC3A 0x00100000 ++/* Disable ++#define ICU0_IM3_IER_GPTC_TC3A_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_GPTC_TC3A_EN 0x00100000 ++/** GPTC Timer/Counter 2B Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_GPTC_TC2B 0x00080000 ++/* Disable ++#define ICU0_IM3_IER_GPTC_TC2B_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_GPTC_TC2B_EN 0x00080000 ++/** GPTC Timer/Counter 2A Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_GPTC_TC2A 0x00040000 ++/* Disable ++#define ICU0_IM3_IER_GPTC_TC2A_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_GPTC_TC2A_EN 0x00040000 ++/** GPTC Timer/Counter 1B Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_GPTC_TC1B 0x00020000 ++/* Disable ++#define ICU0_IM3_IER_GPTC_TC1B_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_GPTC_TC1B_EN 0x00020000 ++/** GPTC Timer/Counter 1A Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_GPTC_TC1A 0x00010000 ++/* Disable ++#define ICU0_IM3_IER_GPTC_TC1A_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_GPTC_TC1A_EN 0x00010000 ++/** ASC1 Soft Flow Control Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC1_SFC 0x00008000 ++/* Disable ++#define ICU0_IM3_IER_ASC1_SFC_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC1_SFC_EN 0x00008000 ++/** ASC1 Modem Status Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC1_MS 0x00004000 ++/* Disable ++#define ICU0_IM3_IER_ASC1_MS_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC1_MS_EN 0x00004000 ++/** ASC1 Autobaud Detection Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC1_ABDET 0x00002000 ++/* Disable ++#define ICU0_IM3_IER_ASC1_ABDET_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC1_ABDET_EN 0x00002000 ++/** ASC1 Autobaud Start Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC1_ABST 0x00001000 ++/* Disable ++#define ICU0_IM3_IER_ASC1_ABST_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC1_ABST_EN 0x00001000 ++/** ASC1 Transmit Buffer Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC1_TB 0x00000800 ++/* Disable ++#define ICU0_IM3_IER_ASC1_TB_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC1_TB_EN 0x00000800 ++/** ASC1 Error Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC1_E 0x00000400 ++/* Disable ++#define ICU0_IM3_IER_ASC1_E_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC1_E_EN 0x00000400 ++/** ASC1 Receive Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC1_R 0x00000200 ++/* Disable ++#define ICU0_IM3_IER_ASC1_R_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC1_R_EN 0x00000200 ++/** ASC1 Transmit Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC1_T 0x00000100 ++/* Disable ++#define ICU0_IM3_IER_ASC1_T_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC1_T_EN 0x00000100 ++/** ASC0 Soft Flow Control Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC0_SFC 0x00000080 ++/* Disable ++#define ICU0_IM3_IER_ASC0_SFC_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC0_SFC_EN 0x00000080 ++/** ASC1 Modem Status Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC0_MS 0x00000040 ++/* Disable ++#define ICU0_IM3_IER_ASC0_MS_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC0_MS_EN 0x00000040 ++/** ASC0 Autobaud Detection Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC0_ABDET 0x00000020 ++/* Disable ++#define ICU0_IM3_IER_ASC0_ABDET_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC0_ABDET_EN 0x00000020 ++/** ASC0 Autobaud Start Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC0_ABST 0x00000010 ++/* Disable ++#define ICU0_IM3_IER_ASC0_ABST_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC0_ABST_EN 0x00000010 ++/** ASC0 Transmit Buffer Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC0_TB 0x00000008 ++/* Disable ++#define ICU0_IM3_IER_ASC0_TB_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC0_TB_EN 0x00000008 ++/** ASC0 Error Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC0_E 0x00000004 ++/* Disable ++#define ICU0_IM3_IER_ASC0_E_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC0_E_EN 0x00000004 ++/** ASC0 Receive Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC0_R 0x00000002 ++/* Disable ++#define ICU0_IM3_IER_ASC0_R_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC0_R_EN 0x00000002 ++/** ASC0 Transmit Interrupt ++ Interrupt enable bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IER_ASC0_T 0x00000001 ++/* Disable ++#define ICU0_IM3_IER_ASC0_T_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM3_IER_ASC0_T_EN 0x00000001 ++ ++/* Fields of "IM3 Interrupt Output Status Register" */ ++/** DFEV0, Channel 0 General Purpose Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_DFEV0_1GP 0x80000000 ++/* Nothing ++#define ICU0_IM3_IOSR_DFEV0_1GP_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_DFEV0_1GP_INTOCC 0x80000000 ++/** DFEV0, Channel 0 Receive Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_DFEV0_1RX 0x40000000 ++/* Nothing ++#define ICU0_IM3_IOSR_DFEV0_1RX_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_DFEV0_1RX_INTOCC 0x40000000 ++/** DFEV0, Channel 0 Transmit Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_DFEV0_1TX 0x20000000 ++/* Nothing ++#define ICU0_IM3_IOSR_DFEV0_1TX_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_DFEV0_1TX_INTOCC 0x20000000 ++/** DFEV0, Channel 1 General Purpose Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_DFEV0_2GP 0x10000000 ++/* Nothing ++#define ICU0_IM3_IOSR_DFEV0_2GP_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_DFEV0_2GP_INTOCC 0x10000000 ++/** DFEV0, Channel 1 Receive Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_DFEV0_2RX 0x08000000 ++/* Nothing ++#define ICU0_IM3_IOSR_DFEV0_2RX_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_DFEV0_2RX_INTOCC 0x08000000 ++/** DFEV0, Channel 1 Transmit Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_DFEV0_2TX 0x04000000 ++/* Nothing ++#define ICU0_IM3_IOSR_DFEV0_2TX_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_DFEV0_2TX_INTOCC 0x04000000 ++/** GPTC Timer/Counter 3B Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_GPTC_TC3B 0x00200000 ++/* Nothing ++#define ICU0_IM3_IOSR_GPTC_TC3B_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_GPTC_TC3B_INTOCC 0x00200000 ++/** GPTC Timer/Counter 3A Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_GPTC_TC3A 0x00100000 ++/* Nothing ++#define ICU0_IM3_IOSR_GPTC_TC3A_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_GPTC_TC3A_INTOCC 0x00100000 ++/** GPTC Timer/Counter 2B Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_GPTC_TC2B 0x00080000 ++/* Nothing ++#define ICU0_IM3_IOSR_GPTC_TC2B_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_GPTC_TC2B_INTOCC 0x00080000 ++/** GPTC Timer/Counter 2A Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_GPTC_TC2A 0x00040000 ++/* Nothing ++#define ICU0_IM3_IOSR_GPTC_TC2A_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_GPTC_TC2A_INTOCC 0x00040000 ++/** GPTC Timer/Counter 1B Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_GPTC_TC1B 0x00020000 ++/* Nothing ++#define ICU0_IM3_IOSR_GPTC_TC1B_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_GPTC_TC1B_INTOCC 0x00020000 ++/** GPTC Timer/Counter 1A Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_GPTC_TC1A 0x00010000 ++/* Nothing ++#define ICU0_IM3_IOSR_GPTC_TC1A_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_GPTC_TC1A_INTOCC 0x00010000 ++/** ASC1 Soft Flow Control Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC1_SFC 0x00008000 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC1_SFC_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC1_SFC_INTOCC 0x00008000 ++/** ASC1 Modem Status Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC1_MS 0x00004000 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC1_MS_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC1_MS_INTOCC 0x00004000 ++/** ASC1 Autobaud Detection Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC1_ABDET 0x00002000 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC1_ABDET_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC1_ABDET_INTOCC 0x00002000 ++/** ASC1 Autobaud Start Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC1_ABST 0x00001000 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC1_ABST_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC1_ABST_INTOCC 0x00001000 ++/** ASC1 Transmit Buffer Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC1_TB 0x00000800 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC1_TB_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC1_TB_INTOCC 0x00000800 ++/** ASC1 Error Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC1_E 0x00000400 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC1_E_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC1_E_INTOCC 0x00000400 ++/** ASC1 Receive Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC1_R 0x00000200 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC1_R_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC1_R_INTOCC 0x00000200 ++/** ASC1 Transmit Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC1_T 0x00000100 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC1_T_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC1_T_INTOCC 0x00000100 ++/** ASC0 Soft Flow Control Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC0_SFC 0x00000080 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC0_SFC_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC0_SFC_INTOCC 0x00000080 ++/** ASC1 Modem Status Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC0_MS 0x00000040 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC0_MS_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC0_MS_INTOCC 0x00000040 ++/** ASC0 Autobaud Detection Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC0_ABDET 0x00000020 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC0_ABDET_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC0_ABDET_INTOCC 0x00000020 ++/** ASC0 Autobaud Start Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC0_ABST 0x00000010 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC0_ABST_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC0_ABST_INTOCC 0x00000010 ++/** ASC0 Transmit Buffer Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC0_TB 0x00000008 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC0_TB_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC0_TB_INTOCC 0x00000008 ++/** ASC0 Error Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC0_E 0x00000004 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC0_E_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC0_E_INTOCC 0x00000004 ++/** ASC0 Receive Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC0_R 0x00000002 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC0_R_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC0_R_INTOCC 0x00000002 ++/** ASC0 Transmit Interrupt ++ Masked interrupt bit for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IOSR_ASC0_T 0x00000001 ++/* Nothing ++#define ICU0_IM3_IOSR_ASC0_T_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM3_IOSR_ASC0_T_INTOCC 0x00000001 ++ ++/* Fields of "IM3 Interrupt Request Set Register" */ ++/** DFEV0, Channel 0 General Purpose Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_DFEV0_1GP 0x80000000 ++/** DFEV0, Channel 0 Receive Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_DFEV0_1RX 0x40000000 ++/** DFEV0, Channel 0 Transmit Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_DFEV0_1TX 0x20000000 ++/** DFEV0, Channel 1 General Purpose Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_DFEV0_2GP 0x10000000 ++/** DFEV0, Channel 1 Receive Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_DFEV0_2RX 0x08000000 ++/** DFEV0, Channel 1 Transmit Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_DFEV0_2TX 0x04000000 ++/** GPTC Timer/Counter 3B Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_GPTC_TC3B 0x00200000 ++/** GPTC Timer/Counter 3A Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_GPTC_TC3A 0x00100000 ++/** GPTC Timer/Counter 2B Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_GPTC_TC2B 0x00080000 ++/** GPTC Timer/Counter 2A Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_GPTC_TC2A 0x00040000 ++/** GPTC Timer/Counter 1B Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_GPTC_TC1B 0x00020000 ++/** GPTC Timer/Counter 1A Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_GPTC_TC1A 0x00010000 ++/** ASC1 Soft Flow Control Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC1_SFC 0x00008000 ++/** ASC1 Modem Status Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC1_MS 0x00004000 ++/** ASC1 Autobaud Detection Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC1_ABDET 0x00002000 ++/** ASC1 Autobaud Start Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC1_ABST 0x00001000 ++/** ASC1 Transmit Buffer Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC1_TB 0x00000800 ++/** ASC1 Error Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC1_E 0x00000400 ++/** ASC1 Receive Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC1_R 0x00000200 ++/** ASC1 Transmit Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC1_T 0x00000100 ++/** ASC0 Soft Flow Control Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC0_SFC 0x00000080 ++/** ASC1 Modem Status Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC0_MS 0x00000040 ++/** ASC0 Autobaud Detection Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC0_ABDET 0x00000020 ++/** ASC0 Autobaud Start Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC0_ABST 0x00000010 ++/** ASC0 Transmit Buffer Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC0_TB 0x00000008 ++/** ASC0 Error Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC0_E 0x00000004 ++/** ASC0 Receive Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC0_R 0x00000002 ++/** ASC0 Transmit Interrupt ++ Software control for the corresponding bit in the IM3_ISR register. */ ++#define ICU0_IM3_IRSR_ASC0_T 0x00000001 ++ ++/* Fields of "IM3 Interrupt Mode Register" */ ++/** DFEV0, Channel 0 General Purpose Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_1GP 0x80000000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_DFEV0_1GP_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_1GP_DIR 0x80000000 ++/** DFEV0, Channel 0 Receive Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_1RX 0x40000000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_DFEV0_1RX_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_1RX_DIR 0x40000000 ++/** DFEV0, Channel 0 Transmit Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_1TX 0x20000000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_DFEV0_1TX_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_1TX_DIR 0x20000000 ++/** DFEV0, Channel 1 General Purpose Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_2GP 0x10000000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_DFEV0_2GP_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_2GP_DIR 0x10000000 ++/** DFEV0, Channel 1 Receive Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_2RX 0x08000000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_DFEV0_2RX_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_2RX_DIR 0x08000000 ++/** DFEV0, Channel 1 Transmit Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_2TX 0x04000000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_DFEV0_2TX_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_DFEV0_2TX_DIR 0x04000000 ++/** GPTC Timer/Counter 3B Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC3B 0x00200000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_GPTC_TC3B_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC3B_DIR 0x00200000 ++/** GPTC Timer/Counter 3A Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC3A 0x00100000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_GPTC_TC3A_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC3A_DIR 0x00100000 ++/** GPTC Timer/Counter 2B Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC2B 0x00080000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_GPTC_TC2B_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC2B_DIR 0x00080000 ++/** GPTC Timer/Counter 2A Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC2A 0x00040000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_GPTC_TC2A_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC2A_DIR 0x00040000 ++/** GPTC Timer/Counter 1B Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC1B 0x00020000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_GPTC_TC1B_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC1B_DIR 0x00020000 ++/** GPTC Timer/Counter 1A Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC1A 0x00010000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_GPTC_TC1A_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_GPTC_TC1A_DIR 0x00010000 ++/** ASC1 Soft Flow Control Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC1_SFC 0x00008000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC1_SFC_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC1_SFC_DIR 0x00008000 ++/** ASC1 Modem Status Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC1_MS 0x00004000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC1_MS_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC1_MS_DIR 0x00004000 ++/** ASC1 Autobaud Detection Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC1_ABDET 0x00002000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC1_ABDET_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC1_ABDET_DIR 0x00002000 ++/** ASC1 Autobaud Start Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC1_ABST 0x00001000 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC1_ABST_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC1_ABST_DIR 0x00001000 ++/** ASC1 Transmit Buffer Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC1_TB 0x00000800 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC1_TB_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC1_TB_DIR 0x00000800 ++/** ASC1 Error Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC1_E 0x00000400 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC1_E_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC1_E_DIR 0x00000400 ++/** ASC1 Receive Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC1_R 0x00000200 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC1_R_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC1_R_DIR 0x00000200 ++/** ASC1 Transmit Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC1_T 0x00000100 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC1_T_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC1_T_DIR 0x00000100 ++/** ASC0 Soft Flow Control Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC0_SFC 0x00000080 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC0_SFC_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC0_SFC_DIR 0x00000080 ++/** ASC1 Modem Status Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC0_MS 0x00000040 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC0_MS_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC0_MS_DIR 0x00000040 ++/** ASC0 Autobaud Detection Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC0_ABDET 0x00000020 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC0_ABDET_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC0_ABDET_DIR 0x00000020 ++/** ASC0 Autobaud Start Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC0_ABST 0x00000010 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC0_ABST_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC0_ABST_DIR 0x00000010 ++/** ASC0 Transmit Buffer Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC0_TB 0x00000008 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC0_TB_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC0_TB_DIR 0x00000008 ++/** ASC0 Error Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC0_E 0x00000004 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC0_E_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC0_E_DIR 0x00000004 ++/** ASC0 Receive Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC0_R 0x00000002 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC0_R_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC0_R_DIR 0x00000002 ++/** ASC0 Transmit Interrupt ++ Type of interrupt. */ ++#define ICU0_IM3_IMR_ASC0_T 0x00000001 ++/* Indirect Interrupt. ++#define ICU0_IM3_IMR_ASC0_T_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM3_IMR_ASC0_T_DIR 0x00000001 ++ ++/* Fields of "IM4 Interrupt Status Register" */ ++/** VPE0 Performance Monitoring Counter Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_VPE0_PMCIR 0x80000000 ++/* Nothing ++#define ICU0_IM4_ISR_VPE0_PMCIR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_VPE0_PMCIR_INTACK 0x80000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_VPE0_PMCIR_INTOCC 0x80000000 ++/** VPE0 Error Level Flag Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_VPE0_ERL 0x40000000 ++/* Nothing ++#define ICU0_IM4_ISR_VPE0_ERL_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_VPE0_ERL_INTACK 0x40000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_VPE0_ERL_INTOCC 0x40000000 ++/** VPE0 Exception Level Flag Interrupt ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_VPE0_EXL 0x20000000 ++/* Nothing ++#define ICU0_IM4_ISR_VPE0_EXL_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_VPE0_EXL_INTACK 0x20000000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_VPE0_EXL_INTOCC 0x20000000 ++/** MPS Bin. Sem Interrupt to VPE0 ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR8 0x00400000 ++/* Nothing ++#define ICU0_IM4_ISR_MPS_IR8_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR8_INTACK 0x00400000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_MPS_IR8_INTOCC 0x00400000 ++/** MPS Global Interrupt to VPE0 ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR7 0x00200000 ++/* Nothing ++#define ICU0_IM4_ISR_MPS_IR7_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR7_INTACK 0x00200000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_MPS_IR7_INTOCC 0x00200000 ++/** MPS Status Interrupt #6 (VPE1 to VPE0) ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR6 0x00100000 ++/* Nothing ++#define ICU0_IM4_ISR_MPS_IR6_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR6_INTACK 0x00100000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_MPS_IR6_INTOCC 0x00100000 ++/** MPS Status Interrupt #5 (VPE1 to VPE0) ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR5 0x00080000 ++/* Nothing ++#define ICU0_IM4_ISR_MPS_IR5_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR5_INTACK 0x00080000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_MPS_IR5_INTOCC 0x00080000 ++/** MPS Status Interrupt #4 (VPE1 to VPE0) ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR4 0x00040000 ++/* Nothing ++#define ICU0_IM4_ISR_MPS_IR4_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR4_INTACK 0x00040000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_MPS_IR4_INTOCC 0x00040000 ++/** MPS Status Interrupt #3 (VPE1 to VPE0) ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR3 0x00020000 ++/* Nothing ++#define ICU0_IM4_ISR_MPS_IR3_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR3_INTACK 0x00020000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_MPS_IR3_INTOCC 0x00020000 ++/** MPS Status Interrupt #2 (VPE1 to VPE0) ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR2 0x00010000 ++/* Nothing ++#define ICU0_IM4_ISR_MPS_IR2_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR2_INTACK 0x00010000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_MPS_IR2_INTOCC 0x00010000 ++/** MPS Status Interrupt #1 (VPE1 to VPE0) ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR1 0x00008000 ++/* Nothing ++#define ICU0_IM4_ISR_MPS_IR1_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR1_INTACK 0x00008000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_MPS_IR1_INTOCC 0x00008000 ++/** MPS Status Interrupt #0 (VPE1 to VPE0) ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR0 0x00004000 ++/* Nothing ++#define ICU0_IM4_ISR_MPS_IR0_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_MPS_IR0_INTACK 0x00004000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_MPS_IR0_INTOCC 0x00004000 ++/** TMU Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_TMU_ERR 0x00001000 ++/* Nothing ++#define ICU0_IM4_ISR_TMU_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_TMU_ERR_INTACK 0x00001000 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_TMU_ERR_INTOCC 0x00001000 ++/** FSQM Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_FSQM_ERR 0x00000800 ++/* Nothing ++#define ICU0_IM4_ISR_FSQM_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_FSQM_ERR_INTACK 0x00000800 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_FSQM_ERR_INTOCC 0x00000800 ++/** IQM Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_IQM_ERR 0x00000400 ++/* Nothing ++#define ICU0_IM4_ISR_IQM_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_IQM_ERR_INTACK 0x00000400 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_IQM_ERR_INTOCC 0x00000400 ++/** OCTRLG Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_OCTRLG_ERR 0x00000200 ++/* Nothing ++#define ICU0_IM4_ISR_OCTRLG_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_OCTRLG_ERR_INTACK 0x00000200 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_OCTRLG_ERR_INTOCC 0x00000200 ++/** ICTRLG Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_ICTRLG_ERR 0x00000100 ++/* Nothing ++#define ICU0_IM4_ISR_ICTRLG_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_ICTRLG_ERR_INTACK 0x00000100 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_ICTRLG_ERR_INTOCC 0x00000100 ++/** OCTRLL 3 Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_OCTRLL3_ERR 0x00000080 ++/* Nothing ++#define ICU0_IM4_ISR_OCTRLL3_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_OCTRLL3_ERR_INTACK 0x00000080 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_OCTRLL3_ERR_INTOCC 0x00000080 ++/** OCTRLL 2 Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_OCTRLL2_ERR 0x00000040 ++/* Nothing ++#define ICU0_IM4_ISR_OCTRLL2_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_OCTRLL2_ERR_INTACK 0x00000040 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_OCTRLL2_ERR_INTOCC 0x00000040 ++/** OCTRLL 1 Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_OCTRLL1_ERR 0x00000020 ++/* Nothing ++#define ICU0_IM4_ISR_OCTRLL1_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_OCTRLL1_ERR_INTACK 0x00000020 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_OCTRLL1_ERR_INTOCC 0x00000020 ++/** OCTRLL 0 Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_OCTRLL0_ERR 0x00000010 ++/* Nothing ++#define ICU0_IM4_ISR_OCTRLL0_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_OCTRLL0_ERR_INTACK 0x00000010 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_OCTRLL0_ERR_INTOCC 0x00000010 ++/** ICTRLL 3 Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_ICTRLL3_ERR 0x00000008 ++/* Nothing ++#define ICU0_IM4_ISR_ICTRLL3_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_ICTRLL3_ERR_INTACK 0x00000008 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_ICTRLL3_ERR_INTOCC 0x00000008 ++/** ICTRLL 2 Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_ICTRLL2_ERR 0x00000004 ++/* Nothing ++#define ICU0_IM4_ISR_ICTRLL2_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_ICTRLL2_ERR_INTACK 0x00000004 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_ICTRLL2_ERR_INTOCC 0x00000004 ++/** ICTRLL 1 Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_ICTRLL1_ERR 0x00000002 ++/* Nothing ++#define ICU0_IM4_ISR_ICTRLL1_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_ICTRLL1_ERR_INTACK 0x00000002 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_ICTRLL1_ERR_INTOCC 0x00000002 ++/** ICTRLL 0 Error ++ This bit is an indirect interrupt. */ ++#define ICU0_IM4_ISR_ICTRLL0_ERR 0x00000001 ++/* Nothing ++#define ICU0_IM4_ISR_ICTRLL0_ERR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define ICU0_IM4_ISR_ICTRLL0_ERR_INTACK 0x00000001 ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_ISR_ICTRLL0_ERR_INTOCC 0x00000001 ++ ++/* Fields of "IM4 Interrupt Enable Register" */ ++/** VPE0 Performance Monitoring Counter Interrupt ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_VPE0_PMCIR 0x80000000 ++/* Disable ++#define ICU0_IM4_IER_VPE0_PMCIR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_VPE0_PMCIR_EN 0x80000000 ++/** VPE0 Error Level Flag Interrupt ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_VPE0_ERL 0x40000000 ++/* Disable ++#define ICU0_IM4_IER_VPE0_ERL_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_VPE0_ERL_EN 0x40000000 ++/** VPE0 Exception Level Flag Interrupt ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_VPE0_EXL 0x20000000 ++/* Disable ++#define ICU0_IM4_IER_VPE0_EXL_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_VPE0_EXL_EN 0x20000000 ++/** MPS Bin. Sem Interrupt to VPE0 ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_MPS_IR8 0x00400000 ++/* Disable ++#define ICU0_IM4_IER_MPS_IR8_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_MPS_IR8_EN 0x00400000 ++/** MPS Global Interrupt to VPE0 ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_MPS_IR7 0x00200000 ++/* Disable ++#define ICU0_IM4_IER_MPS_IR7_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_MPS_IR7_EN 0x00200000 ++/** MPS Status Interrupt #6 (VPE1 to VPE0) ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_MPS_IR6 0x00100000 ++/* Disable ++#define ICU0_IM4_IER_MPS_IR6_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_MPS_IR6_EN 0x00100000 ++/** MPS Status Interrupt #5 (VPE1 to VPE0) ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_MPS_IR5 0x00080000 ++/* Disable ++#define ICU0_IM4_IER_MPS_IR5_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_MPS_IR5_EN 0x00080000 ++/** MPS Status Interrupt #4 (VPE1 to VPE0) ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_MPS_IR4 0x00040000 ++/* Disable ++#define ICU0_IM4_IER_MPS_IR4_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_MPS_IR4_EN 0x00040000 ++/** MPS Status Interrupt #3 (VPE1 to VPE0) ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_MPS_IR3 0x00020000 ++/* Disable ++#define ICU0_IM4_IER_MPS_IR3_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_MPS_IR3_EN 0x00020000 ++/** MPS Status Interrupt #2 (VPE1 to VPE0) ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_MPS_IR2 0x00010000 ++/* Disable ++#define ICU0_IM4_IER_MPS_IR2_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_MPS_IR2_EN 0x00010000 ++/** MPS Status Interrupt #1 (VPE1 to VPE0) ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_MPS_IR1 0x00008000 ++/* Disable ++#define ICU0_IM4_IER_MPS_IR1_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_MPS_IR1_EN 0x00008000 ++/** MPS Status Interrupt #0 (VPE1 to VPE0) ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_MPS_IR0 0x00004000 ++/* Disable ++#define ICU0_IM4_IER_MPS_IR0_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_MPS_IR0_EN 0x00004000 ++/** TMU Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_TMU_ERR 0x00001000 ++/* Disable ++#define ICU0_IM4_IER_TMU_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_TMU_ERR_EN 0x00001000 ++/** FSQM Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_FSQM_ERR 0x00000800 ++/* Disable ++#define ICU0_IM4_IER_FSQM_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_FSQM_ERR_EN 0x00000800 ++/** IQM Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_IQM_ERR 0x00000400 ++/* Disable ++#define ICU0_IM4_IER_IQM_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_IQM_ERR_EN 0x00000400 ++/** OCTRLG Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_OCTRLG_ERR 0x00000200 ++/* Disable ++#define ICU0_IM4_IER_OCTRLG_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_OCTRLG_ERR_EN 0x00000200 ++/** ICTRLG Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_ICTRLG_ERR 0x00000100 ++/* Disable ++#define ICU0_IM4_IER_ICTRLG_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_ICTRLG_ERR_EN 0x00000100 ++/** OCTRLL 3 Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_OCTRLL3_ERR 0x00000080 ++/* Disable ++#define ICU0_IM4_IER_OCTRLL3_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_OCTRLL3_ERR_EN 0x00000080 ++/** OCTRLL 2 Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_OCTRLL2_ERR 0x00000040 ++/* Disable ++#define ICU0_IM4_IER_OCTRLL2_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_OCTRLL2_ERR_EN 0x00000040 ++/** OCTRLL 1 Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_OCTRLL1_ERR 0x00000020 ++/* Disable ++#define ICU0_IM4_IER_OCTRLL1_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_OCTRLL1_ERR_EN 0x00000020 ++/** OCTRLL 0 Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_OCTRLL0_ERR 0x00000010 ++/* Disable ++#define ICU0_IM4_IER_OCTRLL0_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_OCTRLL0_ERR_EN 0x00000010 ++/** ICTRLL 3 Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_ICTRLL3_ERR 0x00000008 ++/* Disable ++#define ICU0_IM4_IER_ICTRLL3_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_ICTRLL3_ERR_EN 0x00000008 ++/** ICTRLL 2 Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_ICTRLL2_ERR 0x00000004 ++/* Disable ++#define ICU0_IM4_IER_ICTRLL2_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_ICTRLL2_ERR_EN 0x00000004 ++/** ICTRLL 1 Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_ICTRLL1_ERR 0x00000002 ++/* Disable ++#define ICU0_IM4_IER_ICTRLL1_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_ICTRLL1_ERR_EN 0x00000002 ++/** ICTRLL 0 Error ++ Interrupt enable bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IER_ICTRLL0_ERR 0x00000001 ++/* Disable ++#define ICU0_IM4_IER_ICTRLL0_ERR_DIS 0x00000000 */ ++/** Enable */ ++#define ICU0_IM4_IER_ICTRLL0_ERR_EN 0x00000001 ++ ++/* Fields of "IM4 Interrupt Output Status Register" */ ++/** VPE0 Performance Monitoring Counter Interrupt ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_VPE0_PMCIR 0x80000000 ++/* Nothing ++#define ICU0_IM4_IOSR_VPE0_PMCIR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_VPE0_PMCIR_INTOCC 0x80000000 ++/** VPE0 Error Level Flag Interrupt ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_VPE0_ERL 0x40000000 ++/* Nothing ++#define ICU0_IM4_IOSR_VPE0_ERL_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_VPE0_ERL_INTOCC 0x40000000 ++/** VPE0 Exception Level Flag Interrupt ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_VPE0_EXL 0x20000000 ++/* Nothing ++#define ICU0_IM4_IOSR_VPE0_EXL_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_VPE0_EXL_INTOCC 0x20000000 ++/** MPS Bin. Sem Interrupt to VPE0 ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_MPS_IR8 0x00400000 ++/* Nothing ++#define ICU0_IM4_IOSR_MPS_IR8_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_MPS_IR8_INTOCC 0x00400000 ++/** MPS Global Interrupt to VPE0 ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_MPS_IR7 0x00200000 ++/* Nothing ++#define ICU0_IM4_IOSR_MPS_IR7_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_MPS_IR7_INTOCC 0x00200000 ++/** MPS Status Interrupt #6 (VPE1 to VPE0) ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_MPS_IR6 0x00100000 ++/* Nothing ++#define ICU0_IM4_IOSR_MPS_IR6_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_MPS_IR6_INTOCC 0x00100000 ++/** MPS Status Interrupt #5 (VPE1 to VPE0) ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_MPS_IR5 0x00080000 ++/* Nothing ++#define ICU0_IM4_IOSR_MPS_IR5_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_MPS_IR5_INTOCC 0x00080000 ++/** MPS Status Interrupt #4 (VPE1 to VPE0) ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_MPS_IR4 0x00040000 ++/* Nothing ++#define ICU0_IM4_IOSR_MPS_IR4_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_MPS_IR4_INTOCC 0x00040000 ++/** MPS Status Interrupt #3 (VPE1 to VPE0) ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_MPS_IR3 0x00020000 ++/* Nothing ++#define ICU0_IM4_IOSR_MPS_IR3_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_MPS_IR3_INTOCC 0x00020000 ++/** MPS Status Interrupt #2 (VPE1 to VPE0) ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_MPS_IR2 0x00010000 ++/* Nothing ++#define ICU0_IM4_IOSR_MPS_IR2_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_MPS_IR2_INTOCC 0x00010000 ++/** MPS Status Interrupt #1 (VPE1 to VPE0) ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_MPS_IR1 0x00008000 ++/* Nothing ++#define ICU0_IM4_IOSR_MPS_IR1_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_MPS_IR1_INTOCC 0x00008000 ++/** MPS Status Interrupt #0 (VPE1 to VPE0) ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_MPS_IR0 0x00004000 ++/* Nothing ++#define ICU0_IM4_IOSR_MPS_IR0_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_MPS_IR0_INTOCC 0x00004000 ++/** TMU Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_TMU_ERR 0x00001000 ++/* Nothing ++#define ICU0_IM4_IOSR_TMU_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_TMU_ERR_INTOCC 0x00001000 ++/** FSQM Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_FSQM_ERR 0x00000800 ++/* Nothing ++#define ICU0_IM4_IOSR_FSQM_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_FSQM_ERR_INTOCC 0x00000800 ++/** IQM Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_IQM_ERR 0x00000400 ++/* Nothing ++#define ICU0_IM4_IOSR_IQM_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_IQM_ERR_INTOCC 0x00000400 ++/** OCTRLG Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_OCTRLG_ERR 0x00000200 ++/* Nothing ++#define ICU0_IM4_IOSR_OCTRLG_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_OCTRLG_ERR_INTOCC 0x00000200 ++/** ICTRLG Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_ICTRLG_ERR 0x00000100 ++/* Nothing ++#define ICU0_IM4_IOSR_ICTRLG_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_ICTRLG_ERR_INTOCC 0x00000100 ++/** OCTRLL 3 Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_OCTRLL3_ERR 0x00000080 ++/* Nothing ++#define ICU0_IM4_IOSR_OCTRLL3_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_OCTRLL3_ERR_INTOCC 0x00000080 ++/** OCTRLL 2 Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_OCTRLL2_ERR 0x00000040 ++/* Nothing ++#define ICU0_IM4_IOSR_OCTRLL2_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_OCTRLL2_ERR_INTOCC 0x00000040 ++/** OCTRLL 1 Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_OCTRLL1_ERR 0x00000020 ++/* Nothing ++#define ICU0_IM4_IOSR_OCTRLL1_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_OCTRLL1_ERR_INTOCC 0x00000020 ++/** OCTRLL 0 Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_OCTRLL0_ERR 0x00000010 ++/* Nothing ++#define ICU0_IM4_IOSR_OCTRLL0_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_OCTRLL0_ERR_INTOCC 0x00000010 ++/** ICTRLL 3 Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_ICTRLL3_ERR 0x00000008 ++/* Nothing ++#define ICU0_IM4_IOSR_ICTRLL3_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_ICTRLL3_ERR_INTOCC 0x00000008 ++/** ICTRLL 2 Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_ICTRLL2_ERR 0x00000004 ++/* Nothing ++#define ICU0_IM4_IOSR_ICTRLL2_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_ICTRLL2_ERR_INTOCC 0x00000004 ++/** ICTRLL 1 Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_ICTRLL1_ERR 0x00000002 ++/* Nothing ++#define ICU0_IM4_IOSR_ICTRLL1_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_ICTRLL1_ERR_INTOCC 0x00000002 ++/** ICTRLL 0 Error ++ Masked interrupt bit for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IOSR_ICTRLL0_ERR 0x00000001 ++/* Nothing ++#define ICU0_IM4_IOSR_ICTRLL0_ERR_NULL 0x00000000 */ ++/** Read: Interrupt occurred. */ ++#define ICU0_IM4_IOSR_ICTRLL0_ERR_INTOCC 0x00000001 ++ ++/* Fields of "IM4 Interrupt Request Set Register" */ ++/** VPE0 Performance Monitoring Counter Interrupt ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_VPE0_PMCIR 0x80000000 ++/** VPE0 Error Level Flag Interrupt ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_VPE0_ERL 0x40000000 ++/** VPE0 Exception Level Flag Interrupt ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_VPE0_EXL 0x20000000 ++/** MPS Bin. Sem Interrupt to VPE0 ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_MPS_IR8 0x00400000 ++/** MPS Global Interrupt to VPE0 ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_MPS_IR7 0x00200000 ++/** MPS Status Interrupt #6 (VPE1 to VPE0) ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_MPS_IR6 0x00100000 ++/** MPS Status Interrupt #5 (VPE1 to VPE0) ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_MPS_IR5 0x00080000 ++/** MPS Status Interrupt #4 (VPE1 to VPE0) ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_MPS_IR4 0x00040000 ++/** MPS Status Interrupt #3 (VPE1 to VPE0) ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_MPS_IR3 0x00020000 ++/** MPS Status Interrupt #2 (VPE1 to VPE0) ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_MPS_IR2 0x00010000 ++/** MPS Status Interrupt #1 (VPE1 to VPE0) ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_MPS_IR1 0x00008000 ++/** MPS Status Interrupt #0 (VPE1 to VPE0) ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_MPS_IR0 0x00004000 ++/** TMU Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_TMU_ERR 0x00001000 ++/** FSQM Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_FSQM_ERR 0x00000800 ++/** IQM Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_IQM_ERR 0x00000400 ++/** OCTRLG Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_OCTRLG_ERR 0x00000200 ++/** ICTRLG Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_ICTRLG_ERR 0x00000100 ++/** OCTRLL 3 Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_OCTRLL3_ERR 0x00000080 ++/** OCTRLL 2 Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_OCTRLL2_ERR 0x00000040 ++/** OCTRLL 1 Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_OCTRLL1_ERR 0x00000020 ++/** OCTRLL 0 Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_OCTRLL0_ERR 0x00000010 ++/** ICTRLL 3 Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_ICTRLL3_ERR 0x00000008 ++/** ICTRLL 2 Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_ICTRLL2_ERR 0x00000004 ++/** ICTRLL 1 Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_ICTRLL1_ERR 0x00000002 ++/** ICTRLL 0 Error ++ Software control for the corresponding bit in the IM4_ISR register. */ ++#define ICU0_IM4_IRSR_ICTRLL0_ERR 0x00000001 ++ ++/* Fields of "IM4 Interrupt Mode Register" */ ++/** VPE0 Performance Monitoring Counter Interrupt ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_VPE0_PMCIR 0x80000000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_VPE0_PMCIR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_VPE0_PMCIR_DIR 0x80000000 ++/** VPE0 Error Level Flag Interrupt ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_VPE0_ERL 0x40000000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_VPE0_ERL_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_VPE0_ERL_DIR 0x40000000 ++/** VPE0 Exception Level Flag Interrupt ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_VPE0_EXL 0x20000000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_VPE0_EXL_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_VPE0_EXL_DIR 0x20000000 ++/** MPS Bin. Sem Interrupt to VPE0 ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR8 0x00400000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_MPS_IR8_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR8_DIR 0x00400000 ++/** MPS Global Interrupt to VPE0 ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR7 0x00200000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_MPS_IR7_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR7_DIR 0x00200000 ++/** MPS Status Interrupt #6 (VPE1 to VPE0) ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR6 0x00100000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_MPS_IR6_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR6_DIR 0x00100000 ++/** MPS Status Interrupt #5 (VPE1 to VPE0) ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR5 0x00080000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_MPS_IR5_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR5_DIR 0x00080000 ++/** MPS Status Interrupt #4 (VPE1 to VPE0) ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR4 0x00040000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_MPS_IR4_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR4_DIR 0x00040000 ++/** MPS Status Interrupt #3 (VPE1 to VPE0) ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR3 0x00020000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_MPS_IR3_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR3_DIR 0x00020000 ++/** MPS Status Interrupt #2 (VPE1 to VPE0) ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR2 0x00010000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_MPS_IR2_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR2_DIR 0x00010000 ++/** MPS Status Interrupt #1 (VPE1 to VPE0) ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR1 0x00008000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_MPS_IR1_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR1_DIR 0x00008000 ++/** MPS Status Interrupt #0 (VPE1 to VPE0) ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR0 0x00004000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_MPS_IR0_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_MPS_IR0_DIR 0x00004000 ++/** TMU Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_TMU_ERR 0x00001000 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_TMU_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_TMU_ERR_DIR 0x00001000 ++/** FSQM Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_FSQM_ERR 0x00000800 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_FSQM_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_FSQM_ERR_DIR 0x00000800 ++/** IQM Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_IQM_ERR 0x00000400 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_IQM_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_IQM_ERR_DIR 0x00000400 ++/** OCTRLG Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_OCTRLG_ERR 0x00000200 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_OCTRLG_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_OCTRLG_ERR_DIR 0x00000200 ++/** ICTRLG Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_ICTRLG_ERR 0x00000100 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_ICTRLG_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_ICTRLG_ERR_DIR 0x00000100 ++/** OCTRLL 3 Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_OCTRLL3_ERR 0x00000080 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_OCTRLL3_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_OCTRLL3_ERR_DIR 0x00000080 ++/** OCTRLL 2 Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_OCTRLL2_ERR 0x00000040 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_OCTRLL2_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_OCTRLL2_ERR_DIR 0x00000040 ++/** OCTRLL 1 Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_OCTRLL1_ERR 0x00000020 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_OCTRLL1_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_OCTRLL1_ERR_DIR 0x00000020 ++/** OCTRLL 0 Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_OCTRLL0_ERR 0x00000010 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_OCTRLL0_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_OCTRLL0_ERR_DIR 0x00000010 ++/** ICTRLL 3 Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_ICTRLL3_ERR 0x00000008 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_ICTRLL3_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_ICTRLL3_ERR_DIR 0x00000008 ++/** ICTRLL 2 Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_ICTRLL2_ERR 0x00000004 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_ICTRLL2_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_ICTRLL2_ERR_DIR 0x00000004 ++/** ICTRLL 1 Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_ICTRLL1_ERR 0x00000002 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_ICTRLL1_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_ICTRLL1_ERR_DIR 0x00000002 ++/** ICTRLL 0 Error ++ Type of interrupt. */ ++#define ICU0_IM4_IMR_ICTRLL0_ERR 0x00000001 ++/* Indirect Interrupt. ++#define ICU0_IM4_IMR_ICTRLL0_ERR_IND 0x00000000 */ ++/** Direct Interrupt. */ ++#define ICU0_IM4_IMR_ICTRLL0_ERR_DIR 0x00000001 ++ ++/* Fields of "ICU Interrupt Vector Register (5 bit variant)" */ ++/** IM4 Interrupt Vector Value ++ Returns the highest priority pending interrupt vector. */ ++#define ICU0_ICU_IVEC_IM4_vec_MASK 0x01F00000 ++/** field offset */ ++#define ICU0_ICU_IVEC_IM4_vec_OFFSET 20 ++/** Interrupt pending at bit 31 or no pending interrupt */ ++#define ICU0_ICU_IVEC_IM4_vec_NOINTorBit31 0x00000000 ++/** Interrupt pending at bit 0. */ ++#define ICU0_ICU_IVEC_IM4_vec_BIT0 0x00100000 ++/** Interrupt pending at bit 1. */ ++#define ICU0_ICU_IVEC_IM4_vec_BIT1 0x00200000 ++/** Interrupt pending at bit 30. */ ++#define ICU0_ICU_IVEC_IM4_vec_BIT30 0x01F00000 ++/** IM3 Interrupt Vector Value ++ Returns the highest priority pending interrupt vector. */ ++#define ICU0_ICU_IVEC_IM3_vec_MASK 0x000F8000 ++/** field offset */ ++#define ICU0_ICU_IVEC_IM3_vec_OFFSET 15 ++/** Interrupt pending at bit 31 or no pending interrupt */ ++#define ICU0_ICU_IVEC_IM3_vec_NOINTorBit31 0x00000000 ++/** Interrupt pending at bit 0. */ ++#define ICU0_ICU_IVEC_IM3_vec_BIT0 0x00008000 ++/** Interrupt pending at bit 1. */ ++#define ICU0_ICU_IVEC_IM3_vec_BIT1 0x00010000 ++/** Interrupt pending at bit 30. */ ++#define ICU0_ICU_IVEC_IM3_vec_BIT30 0x000F8000 ++/** IM2 Interrupt Vector Value ++ Returns the highest priority pending interrupt vector. */ ++#define ICU0_ICU_IVEC_IM2_vec_MASK 0x00007C00 ++/** field offset */ ++#define ICU0_ICU_IVEC_IM2_vec_OFFSET 10 ++/** Interrupt pending at bit 31 or no pending interrupt */ ++#define ICU0_ICU_IVEC_IM2_vec_NOINTorBit31 0x00000000 ++/** Interrupt pending at bit 0. */ ++#define ICU0_ICU_IVEC_IM2_vec_BIT0 0x00000400 ++/** Interrupt pending at bit 1. */ ++#define ICU0_ICU_IVEC_IM2_vec_BIT1 0x00000800 ++/** Interrupt pending at bit 30. */ ++#define ICU0_ICU_IVEC_IM2_vec_BIT30 0x00007C00 ++/** IM1 Interrupt Vector Value ++ Returns the highest priority pending interrupt vector. */ ++#define ICU0_ICU_IVEC_IM1_vec_MASK 0x000003E0 ++/** field offset */ ++#define ICU0_ICU_IVEC_IM1_vec_OFFSET 5 ++/** Interrupt pending at bit 31 or no pending interrupt */ ++#define ICU0_ICU_IVEC_IM1_vec_NOINTorBit31 0x00000000 ++/** Interrupt pending at bit 0. */ ++#define ICU0_ICU_IVEC_IM1_vec_BIT0 0x00000020 ++/** Interrupt pending at bit 1. */ ++#define ICU0_ICU_IVEC_IM1_vec_BIT1 0x00000040 ++/** Interrupt pending at bit 30. */ ++#define ICU0_ICU_IVEC_IM1_vec_BIT30 0x000003E0 ++/** IM0 Interrupt Vector Value ++ Returns the highest priority pending interrupt vector. */ ++#define ICU0_ICU_IVEC_IM0_vec_MASK 0x0000001F ++/** field offset */ ++#define ICU0_ICU_IVEC_IM0_vec_OFFSET 0 ++/** Interrupt pending at bit 31 or no pending interrupt */ ++#define ICU0_ICU_IVEC_IM0_vec_NOINTorBit31 0x00000000 ++/** Interrupt pending at bit 0. */ ++#define ICU0_ICU_IVEC_IM0_vec_BIT0 0x00000001 ++/** Interrupt pending at bit 1. */ ++#define ICU0_ICU_IVEC_IM0_vec_BIT1 0x00000002 ++/** Interrupt pending at bit 30. */ ++#define ICU0_ICU_IVEC_IM0_vec_BIT30 0x0000001F ++ ++/* Fields of "ICU Interrupt Vector Register (6 bit variant)" */ ++/** IM4 Interrupt Vector Value ++ Returns the highest priority pending interrupt vector. */ ++#define ICU0_ICU_IVEC_6_IM4_vec_MASK 0x3F000000 ++/** field offset */ ++#define ICU0_ICU_IVEC_6_IM4_vec_OFFSET 24 ++/** No pending interrupt */ ++#define ICU0_ICU_IVEC_6_IM4_vec_NOINT 0x00000000 ++/** Interrupt pending at bit 0. */ ++#define ICU0_ICU_IVEC_6_IM4_vec_BIT0 0x01000000 ++/** Interrupt pending at bit 1. */ ++#define ICU0_ICU_IVEC_6_IM4_vec_BIT1 0x02000000 ++/** Interrupt pending at bit 30. */ ++#define ICU0_ICU_IVEC_6_IM4_vec_BIT30 0x1F000000 ++/** Interrupt pending at bit 31. */ ++#define ICU0_ICU_IVEC_6_IM4_vec_BIT31 0x20000000 ++/** IM3 Interrupt Vector Value ++ Returns the highest priority pending interrupt vector. */ ++#define ICU0_ICU_IVEC_6_IM3_vec_MASK 0x00FC0000 ++/** field offset */ ++#define ICU0_ICU_IVEC_6_IM3_vec_OFFSET 18 ++/** No pending interrupt */ ++#define ICU0_ICU_IVEC_6_IM3_vec_NOINT 0x00000000 ++/** Interrupt pending at bit 0. */ ++#define ICU0_ICU_IVEC_6_IM3_vec_BIT0 0x00040000 ++/** Interrupt pending at bit 1. */ ++#define ICU0_ICU_IVEC_6_IM3_vec_BIT1 0x00080000 ++/** Interrupt pending at bit 30. */ ++#define ICU0_ICU_IVEC_6_IM3_vec_BIT30 0x007C0000 ++/** Interrupt pending at bit 31. */ ++#define ICU0_ICU_IVEC_6_IM3_vec_BIT31 0x00800000 ++/** IM2 Interrupt Vector Value ++ Returns the highest priority pending interrupt vector. */ ++#define ICU0_ICU_IVEC_6_IM2_vec_MASK 0x0003F000 ++/** field offset */ ++#define ICU0_ICU_IVEC_6_IM2_vec_OFFSET 12 ++/** No pending interrupt */ ++#define ICU0_ICU_IVEC_6_IM2_vec_NOINT 0x00000000 ++/** Interrupt pending at bit 0. */ ++#define ICU0_ICU_IVEC_6_IM2_vec_BIT0 0x00001000 ++/** Interrupt pending at bit 1. */ ++#define ICU0_ICU_IVEC_6_IM2_vec_BIT1 0x00002000 ++/** Interrupt pending at bit 30. */ ++#define ICU0_ICU_IVEC_6_IM2_vec_BIT30 0x0001F000 ++/** Interrupt pending at bit 31. */ ++#define ICU0_ICU_IVEC_6_IM2_vec_BIT31 0x00020000 ++/** IM1 Interrupt Vector Value ++ Returns the highest priority pending interrupt vector. */ ++#define ICU0_ICU_IVEC_6_IM1_vec_MASK 0x00000FC0 ++/** field offset */ ++#define ICU0_ICU_IVEC_6_IM1_vec_OFFSET 6 ++/** No pending interrupt */ ++#define ICU0_ICU_IVEC_6_IM1_vec_NOINT 0x00000000 ++/** Interrupt pending at bit 0. */ ++#define ICU0_ICU_IVEC_6_IM1_vec_BIT0 0x00000040 ++/** Interrupt pending at bit 1. */ ++#define ICU0_ICU_IVEC_6_IM1_vec_BIT1 0x00000080 ++/** Interrupt pending at bit 30. */ ++#define ICU0_ICU_IVEC_6_IM1_vec_BIT30 0x000007C0 ++/** Interrupt pending at bit 31. */ ++#define ICU0_ICU_IVEC_6_IM1_vec_BIT31 0x00000800 ++/** IM0 Interrupt Vector Value ++ Returns the highest priority pending interrupt vector. */ ++#define ICU0_ICU_IVEC_6_IM0_vec_MASK 0x0000003F ++/** field offset */ ++#define ICU0_ICU_IVEC_6_IM0_vec_OFFSET 0 ++/** No pending interrupt */ ++#define ICU0_ICU_IVEC_6_IM0_vec_NOINT 0x00000000 ++/** Interrupt pending at bit 0. */ ++#define ICU0_ICU_IVEC_6_IM0_vec_BIT0 0x00000001 ++/** Interrupt pending at bit 1. */ ++#define ICU0_ICU_IVEC_6_IM0_vec_BIT1 0x00000002 ++/** Interrupt pending at bit 30. */ ++#define ICU0_ICU_IVEC_6_IM0_vec_BIT30 0x0000001F ++/** Interrupt pending at bit 31. */ ++#define ICU0_ICU_IVEC_6_IM0_vec_BIT31 0x00000020 ++ ++/*! @} */ /* ICU0_REGISTER */ ++ ++#endif /* _icu0_reg_h */ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/irq.h +@@ -0,0 +1,31 @@ ++/* ++ * arch/mips/include/asm/mach-ifxmips/falcon/irq.h ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) 2010 Lantiq ++ * ++ */ ++ ++#ifndef __FALCON_IRQ_H ++#define __FALCON_IRQ_H ++ ++#include <falcon_irq.h> ++ ++#define NR_IRQS 264 ++ ++#include_next <irq.h> ++ ++#endif +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/status_reg.h +@@ -0,0 +1,529 @@ ++/****************************************************************************** ++ ++ Copyright (c) 2010 ++ Lantiq Deutschland GmbH ++ ++ For licensing information, see the file 'LICENSE' in the root folder of ++ this software module. ++ ++******************************************************************************/ ++ ++#ifndef _status_reg_h ++#define _status_reg_h ++ ++/** \addtogroup STATUS_REGISTER ++ @{ ++*/ ++/* access macros */ ++#define status_r32(reg) reg_r32(&status->reg) ++#define status_w32(val, reg) reg_w32(val, &status->reg) ++#define status_w32_mask(clear, set, reg) reg_w32_mask(clear, set, &status->reg) ++#define status_r32_table(reg, idx) reg_r32_table(status->reg, idx) ++#define status_w32_table(val, reg, idx) reg_w32_table(val, status->reg, idx) ++#define status_w32_table_mask(clear, set, reg, idx) reg_w32_table_mask(clear, set, status->reg, idx) ++#define status_adr_table(reg, idx) adr_table(status->reg, idx) ++ ++ ++/** STATUS register structure */ ++struct gpon_reg_status ++{ ++ /** Reserved */ ++ unsigned int res_0[3]; /* 0x00000000 */ ++ /** Chip Identification Register */ ++ unsigned int chipid; /* 0x0000000C */ ++ /** Chip Location Register ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int chiploc; /* 0x00000010 */ ++ /** Redundancy register ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int red0; /* 0x00000014 */ ++ /** Redundancy register ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int red1; /* 0x00000018 */ ++ /** Redundancy register ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int red2; /* 0x0000001C */ ++ /** Redundancy register ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int red3; /* 0x00000020 */ ++ /** Redundancy register ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int red4; /* 0x00000024 */ ++ /** Redundancy register ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int red5; /* 0x00000028 */ ++ /** Redundancy register ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int red6; /* 0x0000002C */ ++ /** Redundancy register ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int red7; /* 0x00000030 */ ++ /** Redundancy register ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int red8; /* 0x00000034 */ ++ /** SPARE fuse register 0 ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int fuse0; /* 0x00000038 */ ++ /** Fuses for Analog modules ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int analog; /* 0x0000003C */ ++ /** Configuration fuses for drivers and pll ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int config; /* 0x00000040 */ ++ /** SPARE fuse register 1 ++ Note: All fuse-bits have a default value of 0 that can be changed to 1 during production test (unfused = 0, fused = 1).The reset-values stated for these bits is 0 even though SW will never be able to read 0 if it was set to 1 during production test. */ ++ unsigned int fuse1; /* 0x00000044 */ ++ /** Configuration for sbs0 rambist */ ++ unsigned int mbcfg; /* 0x00000048 */ ++ /** sbs0 bist result and debug data */ ++ unsigned int mbdata; /* 0x0000004C */ ++ /** Reserved */ ++ unsigned int res_1[12]; /* 0x00000050 */ ++}; ++ ++ ++/* Fields of "Chip Identification Register" */ ++/** Chip Version Number ++ Version number */ ++#define STATUS_CHIPID_VERSION_MASK 0xF0000000 ++/** field offset */ ++#define STATUS_CHIPID_VERSION_OFFSET 28 ++/** Part Number, Constant Part ++ The Part Number is fixed to 016Bhex. */ ++#define STATUS_CHIPID_PARTNR_MASK 0x0FFFF000 ++/** field offset */ ++#define STATUS_CHIPID_PARTNR_OFFSET 12 ++/** Manufacturer ID ++ The value of bit field MANID is fixed to 41hex as configured in the JTAG ID register. The JEDEC normalized manufacturer code for Infineon Technologies is C1hex */ ++#define STATUS_CHIPID_MANID_MASK 0x00000FFE ++/** field offset */ ++#define STATUS_CHIPID_MANID_OFFSET 1 ++/** Constant bit ++ The value of bit field CONST1 is fixed to 1hex */ ++#define STATUS_CHIPID_CONST1 0x00000001 ++ ++/* Fields of "Chip Location Register" */ ++/** Chip Lot ID */ ++#define STATUS_CHIPLOC_CHIPLOT_MASK 0xFFFF0000 ++/** field offset */ ++#define STATUS_CHIPLOC_CHIPLOT_OFFSET 16 ++/** Chip X Coordinate */ ++#define STATUS_CHIPLOC_CHIPX_MASK 0x0000FF00 ++/** field offset */ ++#define STATUS_CHIPLOC_CHIPX_OFFSET 8 ++/** Chip Y Coordinate */ ++#define STATUS_CHIPLOC_CHIPY_MASK 0x000000FF ++/** field offset */ ++#define STATUS_CHIPLOC_CHIPY_OFFSET 0 ++ ++/* Fields of "Redundancy register" */ ++/** Redundancy ++ redundancy information stored in eFuses. MSB + MEM_ADDR - MSB = 1 defines a valid address */ ++#define STATUS_RED0_REDUNDANCY_MASK 0x0003FFFF ++/** field offset */ ++#define STATUS_RED0_REDUNDANCY_OFFSET 0 ++ ++/* Fields of "Redundancy register" */ ++/** Redundancy ++ redundancy information stored in eFuses. MSB + MEM_ADDR - MSB = 1 defines a valid address */ ++#define STATUS_RED1_REDUNDANCY_MASK 0x0003FFFF ++/** field offset */ ++#define STATUS_RED1_REDUNDANCY_OFFSET 0 ++ ++/* Fields of "Redundancy register" */ ++/** Redundancy ++ redundancy information stored in eFuses. MSB + MEM_ADDR - MSB = 1 defines a valid address */ ++#define STATUS_RED2_REDUNDANCY_MASK 0x0003FFFF ++/** field offset */ ++#define STATUS_RED2_REDUNDANCY_OFFSET 0 ++ ++/* Fields of "Redundancy register" */ ++/** Redundancy ++ redundancy information stored in eFuses. MSB + MEM_ADDR - MSB = 1 defines a valid address */ ++#define STATUS_RED3_REDUNDANCY_MASK 0x0003FFFF ++/** field offset */ ++#define STATUS_RED3_REDUNDANCY_OFFSET 0 ++ ++/* Fields of "Redundancy register" */ ++/** Redundancy ++ redundancy information stored in eFuses. MSB + MEM_ADDR - MSB = 1 defines a valid address */ ++#define STATUS_RED4_REDUNDANCY_MASK 0x0003FFFF ++/** field offset */ ++#define STATUS_RED4_REDUNDANCY_OFFSET 0 ++ ++/* Fields of "Redundancy register" */ ++/** Redundancy ++ redundancy information stored in eFuses. MSB + MEM_ADDR - MSB = 1 defines a valid address */ ++#define STATUS_RED5_REDUNDANCY_MASK 0x0003FFFF ++/** field offset */ ++#define STATUS_RED5_REDUNDANCY_OFFSET 0 ++ ++/* Fields of "Redundancy register" */ ++/** Redundancy ++ redundancy information stored in eFuses. MSB + MEM_ADDR - MSB = 1 defines a valid address */ ++#define STATUS_RED6_REDUNDANCY_MASK 0x0003FFFF ++/** field offset */ ++#define STATUS_RED6_REDUNDANCY_OFFSET 0 ++ ++/* Fields of "Redundancy register" */ ++/** Redundancy ++ redundancy information stored in eFuses. MSB + MEM_ADDR - MSB = 1 defines a valid address */ ++#define STATUS_RED7_REDUNDANCY_MASK 0x0003FFFF ++/** field offset */ ++#define STATUS_RED7_REDUNDANCY_OFFSET 0 ++ ++/* Fields of "Redundancy register" */ ++/** Redundancy ++ redundancy information stored in eFuses. MSB + MEM_ADDR - MSB = 1 defines a valid address */ ++#define STATUS_RED8_REDUNDANCY_MASK 0x0003FFFF ++/** field offset */ ++#define STATUS_RED8_REDUNDANCY_OFFSET 0 ++ ++/* Fields of "SPARE fuse register 0" */ ++/** Soft fuse control ++ Controls whether the status block is in its softfused state or not. In the softfused state the values written via software are active effective. */ ++#define STATUS_FUSE0_SFC 0x80000000 ++/* Not selected ++#define STATUS_FUSE0_SFC_NSEL 0x00000000 */ ++/** Selected */ ++#define STATUS_FUSE0_SFC_SEL 0x80000000 ++/** Soft control MBCFG ++ Controls whether mbist configuration can be overwritten or not from subsystem. If not selected jtag mbcfg register is source for software mbist configuration */ ++#define STATUS_FUSE0_SC_MBCFG 0x40000000 ++/* Not selected ++#define STATUS_FUSE0_SC_MBCFG_NSEL 0x00000000 */ ++/** Selected */ ++#define STATUS_FUSE0_SC_MBCFG_SEL 0x40000000 ++/** spare fuse0 ++ eFuses not assigned to hw/sw, can be used for future applications */ ++#define STATUS_FUSE0_F0_MASK 0x3C000000 ++/** field offset */ ++#define STATUS_FUSE0_F0_OFFSET 26 ++/** VCALMM20 Voltage Reference ++ Voltage Reference for calibration via R and constant current (20 uA) */ ++#define STATUS_FUSE0_VCALMM20_MASK 0x03F00000 ++/** field offset */ ++#define STATUS_FUSE0_VCALMM20_OFFSET 20 ++/** VCALMM100 Voltage Reference ++ Voltage Reference for calibration via R and constant current (100 uA) */ ++#define STATUS_FUSE0_VCALMM100_MASK 0x000FC000 ++/** field offset */ ++#define STATUS_FUSE0_VCALMM100_OFFSET 14 ++/** VCALMM400 Voltage Reference ++ Voltage Reference for calibration via R and constant current (400 uA) */ ++#define STATUS_FUSE0_VCALMM400_MASK 0x00003F00 ++/** field offset */ ++#define STATUS_FUSE0_VCALMM400_OFFSET 8 ++/** RCALMM R error correction ++ The resistance deviation from ideal R (1000 Ohm) */ ++#define STATUS_FUSE0_RCALMM_MASK 0x000000FF ++/** field offset */ ++#define STATUS_FUSE0_RCALMM_OFFSET 0 ++ ++/* Fields of "Fuses for Analog modules" */ ++/** reserved Analog eFuses ++ Reserved Register contains information stored in eFuses needed for the analog modules */ ++#define STATUS_ANALOG_A0_MASK 0xFF000000 ++/** field offset */ ++#define STATUS_ANALOG_A0_OFFSET 24 ++/** Absolut Temperature ++ Temperature ERROR */ ++#define STATUS_ANALOG_TEMPMM_MASK 0x00FC0000 ++/** field offset */ ++#define STATUS_ANALOG_TEMPMM_OFFSET 18 ++/** Bias Voltage Generation ++ temperature dependency */ ++#define STATUS_ANALOG_TBGP_MASK 0x00038000 ++/** field offset */ ++#define STATUS_ANALOG_TBGP_OFFSET 15 ++/** Bias Voltage Generation ++ voltage dependency */ ++#define STATUS_ANALOG_VBGP_MASK 0x00007000 ++/** field offset */ ++#define STATUS_ANALOG_VBGP_OFFSET 12 ++/** Bias Current Generation */ ++#define STATUS_ANALOG_IREFBGP_MASK 0x00000F00 ++/** field offset */ ++#define STATUS_ANALOG_IREFBGP_OFFSET 8 ++/** Drive DAC Gain */ ++#define STATUS_ANALOG_GAINDRIVEDAC_MASK 0x000000F0 ++/** field offset */ ++#define STATUS_ANALOG_GAINDRIVEDAC_OFFSET 4 ++/** BIAS DAC Gain */ ++#define STATUS_ANALOG_GAINBIASDAC_MASK 0x0000000F ++/** field offset */ ++#define STATUS_ANALOG_GAINBIASDAC_OFFSET 0 ++ ++/* Fields of "Configuration fuses for drivers and pll" */ ++/** ddr PU driver ++ ddr pullup driver strength adjustment */ ++#define STATUS_CONFIG_DDRPU_MASK 0xC0000000 ++/** field offset */ ++#define STATUS_CONFIG_DDRPU_OFFSET 30 ++/** ddr PD driver ++ ddr pulldown driver strength adjustment */ ++#define STATUS_CONFIG_DDRPD_MASK 0x30000000 ++/** field offset */ ++#define STATUS_CONFIG_DDRPD_OFFSET 28 ++/** Authentification Unit enable ++ This bit can only be set via eFuse and enables the authentification unit. */ ++#define STATUS_CONFIG_SHA1EN 0x08000000 ++/* Not selected ++#define STATUS_CONFIG_SHA1EN_NSEL 0x00000000 */ ++/** Selected */ ++#define STATUS_CONFIG_SHA1EN_SEL 0x08000000 ++/** Encryption Unit enable ++ This bit can only be set via eFuse and enables the encryption unit. */ ++#define STATUS_CONFIG_AESEN 0x04000000 ++/* Not selected ++#define STATUS_CONFIG_AESEN_NSEL 0x00000000 */ ++/** Selected */ ++#define STATUS_CONFIG_AESEN_SEL 0x04000000 ++/** Subversion Number ++ The subversion number has no direct effect on hardware functions. It is used to provide another chip version number that is fixed in hardware and can be read out by software. In this way different product packages consisting of GPON_MODEM and software can be defined for example */ ++#define STATUS_CONFIG_SUBVERS_MASK 0x03C00000 ++/** field offset */ ++#define STATUS_CONFIG_SUBVERS_OFFSET 22 ++/** PLL settings ++ PLL settings for infrastructure block */ ++#define STATUS_CONFIG_PLLINFRA_MASK 0x003FF000 ++/** field offset */ ++#define STATUS_CONFIG_PLLINFRA_OFFSET 12 ++/** GPE frequency selection ++ Scaling down the GPE frequency for debugging purpose */ ++#define STATUS_CONFIG_GPEFREQ_MASK 0x00000C00 ++/** field offset */ ++#define STATUS_CONFIG_GPEFREQ_OFFSET 10 ++/** RM enable ++ Activates the Read Margin Settings defined in the RM Field, for all VIRAGE Memories except GPE */ ++#define STATUS_CONFIG_RME 0x00000200 ++/* Not selected ++#define STATUS_CONFIG_RME_NSEL 0x00000000 */ ++/** Selected */ ++#define STATUS_CONFIG_RME_SEL 0x00000200 ++/** RM settings ++ Read Marging Settings for all VIRAGE Memories except GPE */ ++#define STATUS_CONFIG_RM_MASK 0x000001E0 ++/** field offset */ ++#define STATUS_CONFIG_RM_OFFSET 5 ++/** RM enable for GPE Memories ++ Activates the Read Margin Settings defined in the RM Field */ ++#define STATUS_CONFIG_RMEGPE 0x00000010 ++/* Not selected ++#define STATUS_CONFIG_RMEGPE_NSEL 0x00000000 */ ++/** Selected */ ++#define STATUS_CONFIG_RMEGPE_SEL 0x00000010 ++/** RM settings for GPE Memories ++ Read Marging Settings for VIRAGE Memories in GPE module */ ++#define STATUS_CONFIG_RMGPE_MASK 0x0000000F ++/** field offset */ ++#define STATUS_CONFIG_RMGPE_OFFSET 0 ++ ++/* Fields of "SPARE fuse register 1" */ ++/** spare fuse1 ++ eFuses not assigned to hw/sw, can be used for future applications */ ++#define STATUS_FUSE1_F1_MASK 0xFFF00000 ++/** field offset */ ++#define STATUS_FUSE1_F1_OFFSET 20 ++/** DCDC DDR OFFSET ++ offset error sense path */ ++#define STATUS_FUSE1_OFFSETDDRDCDC_MASK 0x000F0000 ++/** field offset */ ++#define STATUS_FUSE1_OFFSETDDRDCDC_OFFSET 16 ++/** DCDC DDR GAIN ++ gain error sense path */ ++#define STATUS_FUSE1_GAINDDRDCDC_MASK 0x0000FC00 ++/** field offset */ ++#define STATUS_FUSE1_GAINDDRDCDC_OFFSET 10 ++/** DCDC APD OFFSET ++ offset error sense path */ ++#define STATUS_FUSE1_OFFSETAPDDCDC_MASK 0x000003C0 ++/** field offset */ ++#define STATUS_FUSE1_OFFSETAPDDCDC_OFFSET 6 ++/** DCDC APD GAIN ++ gain error sense path */ ++#define STATUS_FUSE1_GAINAPDDCDC_MASK 0x0000003F ++/** field offset */ ++#define STATUS_FUSE1_GAINAPDDCDC_OFFSET 0 ++ ++/* Fields of "Configuration for sbs0 rambist" */ ++/** Disable asc monitoring during boot-up ++ Bit is used to avoid asc output for reducing pattern count on testsystem */ ++#define STATUS_MBCFG_ASC_DBGDIS 0x01000000 ++/* Disable ++#define STATUS_MBCFG_ASC_DBGDIS_DIS 0x00000000 */ ++/** Enable */ ++#define STATUS_MBCFG_ASC_DBGDIS_EN 0x01000000 ++/** Descrambling Enable/Disable ++ Enables Address and Data Descrambling for internal Memory Test */ ++#define STATUS_MBCFG_DSC 0x00800000 ++/* Disable ++#define STATUS_MBCFG_DSC_DIS 0x00000000 */ ++/** Enable */ ++#define STATUS_MBCFG_DSC_EN 0x00800000 ++/** Enable repair mode ++ When bit is set redundancy repair mode is activated */ ++#define STATUS_MBCFG_REPAIR 0x00400000 ++/* Disable ++#define STATUS_MBCFG_REPAIR_DIS 0x00000000 */ ++/** Enable */ ++#define STATUS_MBCFG_REPAIR_EN 0x00400000 ++/** DEBUG Mode */ ++#define STATUS_MBCFG_DBG 0x00200000 ++/* Disable ++#define STATUS_MBCFG_DBG_DIS 0x00000000 */ ++/** Enable */ ++#define STATUS_MBCFG_DBG_EN 0x00200000 ++/** Retention Time ++ Length oft the Retention Time */ ++#define STATUS_MBCFG_RTIME_MASK 0x001C0000 ++/** field offset */ ++#define STATUS_MBCFG_RTIME_OFFSET 18 ++/** retention mode is switched off */ ++#define STATUS_MBCFG_RTIME_RET0 0x00000000 ++/** Retention time 50 ms */ ++#define STATUS_MBCFG_RTIME_RET50 0x00040000 ++/** Retention time 60 ms */ ++#define STATUS_MBCFG_RTIME_RET60 0x00080000 ++/** Retention time 70 ms */ ++#define STATUS_MBCFG_RTIME_RET70 0x000C0000 ++/** Retention time 80 ms */ ++#define STATUS_MBCFG_RTIME_RET80 0x00100000 ++/** Retention time 90 ms */ ++#define STATUS_MBCFG_RTIME_RET90 0x00140000 ++/** Retention time 1000 ms */ ++#define STATUS_MBCFG_RTIME_RET1000 0x00180000 ++/** Test ID ++ Defines the test to execute. In which order the tests are executed can be defined via TID_n (TID_1 1st execution, TID_2 2nd execution ..) */ ++#define STATUS_MBCFG_TID_5_MASK 0x00038000 ++/** field offset */ ++#define STATUS_MBCFG_TID_5_OFFSET 15 ++/** No test is performed */ ++#define STATUS_MBCFG_TID_5_NONE 0x00000000 ++/** March test */ ++#define STATUS_MBCFG_TID_5_MARCH 0x00008000 ++/** Checkerboard test */ ++#define STATUS_MBCFG_TID_5_CHCK 0x00010000 ++/** Hammer test */ ++#define STATUS_MBCFG_TID_5_HAM 0x00018000 ++/** Address decoder test */ ++#define STATUS_MBCFG_TID_5_ADEC 0x00020000 ++/** Write mask byte test */ ++#define STATUS_MBCFG_TID_5_WMBYTE 0x00028000 ++/** Reserved */ ++#define STATUS_MBCFG_TID_5_RES 0x00030000 ++/** Test ID ++ Defines the test to execute. In which order the tests are executed can be defined via TID_n (TID_1 1st execution, TID_2 2nd execution ..) */ ++#define STATUS_MBCFG_TID_4_MASK 0x00007000 ++/** field offset */ ++#define STATUS_MBCFG_TID_4_OFFSET 12 ++/** No test is performed */ ++#define STATUS_MBCFG_TID_4_NONE 0x00000000 ++/** March test */ ++#define STATUS_MBCFG_TID_4_MARCH 0x00001000 ++/** Checkerboard test */ ++#define STATUS_MBCFG_TID_4_CHCK 0x00002000 ++/** Hammer test */ ++#define STATUS_MBCFG_TID_4_HAM 0x00003000 ++/** Address decoder test */ ++#define STATUS_MBCFG_TID_4_ADEC 0x00004000 ++/** Write mask byte test */ ++#define STATUS_MBCFG_TID_4_WMBYTE 0x00005000 ++/** Reserved */ ++#define STATUS_MBCFG_TID_4_RES 0x00006000 ++/** Test ID ++ Defines the test to execute. In which order the tests are executed can be defined via TID_n (TID_1 1st execution, TID_2 2nd execution ..) */ ++#define STATUS_MBCFG_TID_3_MASK 0x00000E00 ++/** field offset */ ++#define STATUS_MBCFG_TID_3_OFFSET 9 ++/** No test is performed */ ++#define STATUS_MBCFG_TID_3_NONE 0x00000000 ++/** March test */ ++#define STATUS_MBCFG_TID_3_MARCH 0x00000200 ++/** Checkerboard test */ ++#define STATUS_MBCFG_TID_3_CHCK 0x00000400 ++/** Hammer test */ ++#define STATUS_MBCFG_TID_3_HAM 0x00000600 ++/** Address decoder test */ ++#define STATUS_MBCFG_TID_3_ADEC 0x00000800 ++/** Write mask byte test */ ++#define STATUS_MBCFG_TID_3_WMBYTE 0x00000A00 ++/** Reserved */ ++#define STATUS_MBCFG_TID_3_RES 0x00000C00 ++/** Test ID ++ Defines the test to execute. In which order the tests are executed can be defined via TID_n (TID_1 1st execution, TID_2 2nd execution ..) */ ++#define STATUS_MBCFG_TID_2_MASK 0x000001C0 ++/** field offset */ ++#define STATUS_MBCFG_TID_2_OFFSET 6 ++/** No test is performed */ ++#define STATUS_MBCFG_TID_2_NONE 0x00000000 ++/** March test */ ++#define STATUS_MBCFG_TID_2_MARCH 0x00000040 ++/** Checkerboard test */ ++#define STATUS_MBCFG_TID_2_CHCK 0x00000080 ++/** Hammer test */ ++#define STATUS_MBCFG_TID_2_HAM 0x000000C0 ++/** Address decoder test */ ++#define STATUS_MBCFG_TID_2_ADEC 0x00000100 ++/** Write mask byte test */ ++#define STATUS_MBCFG_TID_2_WMBYTE 0x00000140 ++/** Reserved */ ++#define STATUS_MBCFG_TID_2_RES 0x00000180 ++/** Test ID ++ Defines the test to execute. In which order the tests are executed can be defined via TID_n (TID_1 1st execution, TID_2 2nd execution ..) */ ++#define STATUS_MBCFG_TID_1_MASK 0x00000038 ++/** field offset */ ++#define STATUS_MBCFG_TID_1_OFFSET 3 ++/** No test is performed */ ++#define STATUS_MBCFG_TID_1_NONE 0x00000000 ++/** March test */ ++#define STATUS_MBCFG_TID_1_MARCH 0x00000008 ++/** Checkerboard test */ ++#define STATUS_MBCFG_TID_1_CHCK 0x00000010 ++/** Hammer test */ ++#define STATUS_MBCFG_TID_1_HAM 0x00000018 ++/** Address decoder test */ ++#define STATUS_MBCFG_TID_1_ADEC 0x00000020 ++/** Write mask byte test */ ++#define STATUS_MBCFG_TID_1_WMBYTE 0x00000028 ++/** Reserved */ ++#define STATUS_MBCFG_TID_1_RES 0x00000030 ++/** Test ID ++ Defines the test to execute. In which order the tests are executed can be defined via TID_n (TID_1 1st execution, TID_2 2nd execution ..) */ ++#define STATUS_MBCFG_TID_0_MASK 0x00000007 ++/** field offset */ ++#define STATUS_MBCFG_TID_0_OFFSET 0 ++/** No test is performed */ ++#define STATUS_MBCFG_TID_0_NONE 0x00000000 ++/** March test */ ++#define STATUS_MBCFG_TID_0_MARCH 0x00000001 ++/** Checkerboard test */ ++#define STATUS_MBCFG_TID_0_CHCK 0x00000002 ++/** Hammer test */ ++#define STATUS_MBCFG_TID_0_HAM 0x00000003 ++/** Address decoder test */ ++#define STATUS_MBCFG_TID_0_ADEC 0x00000004 ++/** Write mask byte test */ ++#define STATUS_MBCFG_TID_0_WMBYTE 0x00000005 ++/** Reserved */ ++#define STATUS_MBCFG_TID_0_RES 0x00000006 ++ ++/* Fields of "sbs0 bist result and debug data" */ ++/** BIST result and debug data ++ Stores additional debug information */ ++#define STATUS_MBDATA_DATA_MASK 0xFFFFFFF8 ++/** field offset */ ++#define STATUS_MBDATA_DATA_OFFSET 3 ++/** MBIST NOGO ++ The BIST failed and cannot be repaired due to many failure locations */ ++#define STATUS_MBDATA_MBNOGO 0x00000004 ++/** MBIST FAILED ++ The BIST failed but can be repaired */ ++#define STATUS_MBDATA_MBFAIL 0x00000002 ++/** MBIST PASSED ++ The BIST passed without any Failures */ ++#define STATUS_MBDATA_MBPASS 0x00000001 ++ ++/*! @} */ /* STATUS_REGISTER */ ++ ++#endif /* _status_reg_h */ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/sys1_reg.h +@@ -0,0 +1,2008 @@ ++/****************************************************************************** ++ ++ Copyright (c) 2010 ++ Lantiq Deutschland GmbH ++ ++ For licensing information, see the file 'LICENSE' in the root folder of ++ this software module. ++ ++******************************************************************************/ ++ ++#ifndef _sys1_reg_h ++#define _sys1_reg_h ++ ++/** \addtogroup SYS1_REGISTER ++ @{ ++*/ ++/* access macros */ ++#define sys1_r32(reg) reg_r32(&sys1->reg) ++#define sys1_w32(val, reg) reg_w32(val, &sys1->reg) ++#define sys1_w32_mask(clear, set, reg) reg_w32_mask(clear, set, &sys1->reg) ++#define sys1_r32_table(reg, idx) reg_r32_table(sys1->reg, idx) ++#define sys1_w32_table(val, reg, idx) reg_w32_table(val, sys1->reg, idx) ++#define sys1_w32_table_mask(clear, set, reg, idx) reg_w32_table_mask(clear, set, sys1->reg, idx) ++#define sys1_adr_table(reg, idx) adr_table(sys1->reg, idx) ++ ++ ++/** SYS1 register structure */ ++struct gpon_reg_sys1 ++{ ++ /** Clock Status Register */ ++ unsigned int clks; /* 0x00000000 */ ++ /** Clock Enable Register ++ Via this register the clocks for the domains can be enabled. */ ++ unsigned int clken; /* 0x00000004 */ ++ /** Clock Clear Register ++ Via this register the clocks for the domains can be disabled. */ ++ unsigned int clkclr; /* 0x00000008 */ ++ /** Reserved */ ++ unsigned int res_0[5]; /* 0x0000000C */ ++ /** Activation Status Register */ ++ unsigned int acts; /* 0x00000020 */ ++ /** Activation Register ++ Via this register the domains can be activated. */ ++ unsigned int act; /* 0x00000024 */ ++ /** Deactivation Register ++ Via this register the domains can be deactivated. */ ++ unsigned int deact; /* 0x00000028 */ ++ /** Reboot Trigger Register ++ Via this register the domains can be rebooted (sent through reset). */ ++ unsigned int rbt; /* 0x0000002C */ ++ /** Reserved */ ++ unsigned int res_1[4]; /* 0x00000030 */ ++ /** CPU0 Clock Control Register ++ Clock control register for CPU0 */ ++ unsigned int cpu0cc; /* 0x00000040 */ ++ /** Reserved */ ++ unsigned int res_2[7]; /* 0x00000044 */ ++ /** CPU0 Reset Source Register ++ Via this register the CPU can find the the root cause for the boot it currently goes through, and take the appropriate measures. */ ++ unsigned int cpu0rs; /* 0x00000060 */ ++ /** Reserved */ ++ unsigned int res_3[7]; /* 0x00000064 */ ++ /** CPU0 Wakeup Configuration Register ++ Controls the wakeup condition for CPU0. Note: The upper 16 bit of this register have to be set to the same value as the mask bits within the yield-resume interface block. If the yield-resume interface is not used at all, set the upper 16 bit to 0. */ ++ unsigned int cpu0wcfg; /* 0x00000080 */ ++ /** Reserved */ ++ unsigned int res_4[7]; /* 0x00000084 */ ++ /** Bootmode Control Register ++ Reflects the bootmode for the CPU and provides means to manipulate it. */ ++ unsigned int bmc; /* 0x000000A0 */ ++ /** Reserved */ ++ unsigned int res_5[3]; /* 0x000000A4 */ ++ /** Sleep Configuration Register */ ++ unsigned int scfg; /* 0x000000B0 */ ++ /** Power Down Configuration Register ++ Via this register the configuration is done whether in case of deactivation the power supply of the domain shall be switched off. */ ++ unsigned int pdcfg; /* 0x000000B4 */ ++ /** CLKO Pad Control Register ++ Controls the behaviour of the CLKO pad/ball. */ ++ unsigned int clkoc; /* 0x000000B8 */ ++ /** Infrastructure Control Register ++ Controls the behaviour of the components of the infrastructure block. */ ++ unsigned int infrac; /* 0x000000BC */ ++ /** HRST_OUT_N Control Register ++ Controls the behaviour of the HRST_OUT_N pin. */ ++ unsigned int hrstoutc; /* 0x000000C0 */ ++ /** EBU Clock Control Register ++ Clock control register for the EBU. */ ++ unsigned int ebucc; /* 0x000000C4 */ ++ /** Reserved */ ++ unsigned int res_6[2]; /* 0x000000C8 */ ++ /** NMI Status Register ++ The Test NMI source is the GPTC counter 1A overflow bit. */ ++ unsigned int nmis; /* 0x000000D0 */ ++ /** NMI Set Register */ ++ unsigned int nmiset; /* 0x000000D4 */ ++ /** NMI Clear Register */ ++ unsigned int nmiclr; /* 0x000000D8 */ ++ /** NMI Test Configuration Register */ ++ unsigned int nmitcfg; /* 0x000000DC */ ++ /** NMI VPE1 Control Register */ ++ unsigned int nmivpe1c; /* 0x000000E0 */ ++ /** Reserved */ ++ unsigned int res_7[3]; /* 0x000000E4 */ ++ /** IRN Capture Register ++ This register shows the currently active interrupt events masked with the corresponding enable bits of the IRNEN register. The interrupts can be acknowledged by a write operation. */ ++ unsigned int irncr; /* 0x000000F0 */ ++ /** IRN Interrupt Control Register ++ A write operation directly effects the interrupts. This can be used to trigger events under software control for testing purposes. A read operation returns the unmasked interrupt events. */ ++ unsigned int irnicr; /* 0x000000F4 */ ++ /** IRN Interrupt Enable Register ++ This register contains the enable (or mask) bits for the interrupts. Disabled interrupts are not visible in the IRNCR register and are not signalled via the interrupt line towards the controller. */ ++ unsigned int irnen; /* 0x000000F8 */ ++ /** Reserved */ ++ unsigned int res_8; /* 0x000000FC */ ++}; ++ ++ ++/* Fields of "Clock Status Register" */ ++/** STATUS Clock Enable ++ Shows the clock enable bit for the STATUS domain. This domain contains the STATUS block. */ ++#define CLKS_STATUS 0x80000000 ++/* Disable ++#define CLKS_STATUS_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_STATUS_EN 0x80000000 ++/** SHA1 Clock Enable ++ Shows the clock enable bit for the SHA1 domain. This domain contains the SHA1 block. */ ++#define CLKS_SHA1 0x40000000 ++/* Disable ++#define CLKS_SHA1_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_SHA1_EN 0x40000000 ++/** AES Clock Enable ++ Shows the clock enable bit for the AES domain. This domain contains the AES block. */ ++#define CLKS_AES 0x20000000 ++/* Disable ++#define CLKS_AES_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_AES_EN 0x20000000 ++/** PCM Clock Enable ++ Shows the clock enable bit for the PCM domain. This domain contains the PCM interface block. */ ++#define CLKS_PCM 0x10000000 ++/* Disable ++#define CLKS_PCM_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_PCM_EN 0x10000000 ++/** FSCT Clock Enable ++ Shows the clock enable bit for the FSCT domain. This domain contains the FSCT block. */ ++#define CLKS_FSCT 0x08000000 ++/* Disable ++#define CLKS_FSCT_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_FSCT_EN 0x08000000 ++/** GPTC Clock Enable ++ Shows the clock enable bit for the GPTC domain. This domain contains the GPTC block. */ ++#define CLKS_GPTC 0x04000000 ++/* Disable ++#define CLKS_GPTC_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_GPTC_EN 0x04000000 ++/** MPS Clock Enable ++ Shows the clock enable bit for the MPS domain. This domain contains the MPS block. */ ++#define CLKS_MPS 0x02000000 ++/* Disable ++#define CLKS_MPS_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_MPS_EN 0x02000000 ++/** DFEV0 Clock Enable ++ Shows the clock enable bit for the DFEV0 domain. This domain contains the DFEV0 block. */ ++#define CLKS_DFEV0 0x01000000 ++/* Disable ++#define CLKS_DFEV0_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_DFEV0_EN 0x01000000 ++/** PADCTRL4 Clock Enable ++ Shows the clock enable bit for the PADCTRL4 domain. This domain contains the PADCTRL4 block. */ ++#define CLKS_PADCTRL4 0x00400000 ++/* Disable ++#define CLKS_PADCTRL4_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_PADCTRL4_EN 0x00400000 ++/** PADCTRL3 Clock Enable ++ Shows the clock enable bit for the PADCTRL3 domain. This domain contains the PADCTRL3 block. */ ++#define CLKS_PADCTRL3 0x00200000 ++/* Disable ++#define CLKS_PADCTRL3_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_PADCTRL3_EN 0x00200000 ++/** PADCTRL1 Clock Enable ++ Shows the clock enable bit for the PADCTRL1 domain. This domain contains the PADCTRL1 block. */ ++#define CLKS_PADCTRL1 0x00100000 ++/* Disable ++#define CLKS_PADCTRL1_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_PADCTRL1_EN 0x00100000 ++/** P4 Clock Enable ++ Shows the clock enable bit for the P4 domain. This domain contains the P4 instance of the GPIO block. */ ++#define CLKS_P4 0x00040000 ++/* Disable ++#define CLKS_P4_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_P4_EN 0x00040000 ++/** P3 Clock Enable ++ Shows the clock enable bit for the P3 domain. This domain contains the P3 instance of the GPIO block. */ ++#define CLKS_P3 0x00020000 ++/* Disable ++#define CLKS_P3_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_P3_EN 0x00020000 ++/** P1 Clock Enable ++ Shows the clock enable bit for the P1 domain. This domain contains the P1 instance of the GPIO block. */ ++#define CLKS_P1 0x00010000 ++/* Disable ++#define CLKS_P1_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_P1_EN 0x00010000 ++/** HOST Clock Enable ++ Shows the clock enable bit for the HOST domain. This domain contains the HOST interface block. */ ++#define CLKS_HOST 0x00008000 ++/* Disable ++#define CLKS_HOST_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_HOST_EN 0x00008000 ++/** I2C Clock Enable ++ Shows the clock enable bit for the I2C domain. This domain contains the I2C interface block. */ ++#define CLKS_I2C 0x00004000 ++/* Disable ++#define CLKS_I2C_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_I2C_EN 0x00004000 ++/** SSC0 Clock Enable ++ Shows the clock enable bit for the SSC0 domain. This domain contains the SSC0 interface block. */ ++#define CLKS_SSC0 0x00002000 ++/* Disable ++#define CLKS_SSC0_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_SSC0_EN 0x00002000 ++/** ASC0 Clock Enable ++ Shows the clock enable bit for the ASC0 domain. This domain contains the ASC0 interface block. */ ++#define CLKS_ASC0 0x00001000 ++/* Disable ++#define CLKS_ASC0_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_ASC0_EN 0x00001000 ++/** ASC1 Clock Enable ++ Shows the clock enable bit for the ASC1 domain. This domain contains the ASC1 block. */ ++#define CLKS_ASC1 0x00000800 ++/* Disable ++#define CLKS_ASC1_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_ASC1_EN 0x00000800 ++/** DCDCAPD Clock Enable ++ Shows the clock enable bit for the DCDCAPD domain. This domain contains the digital part of the 60 volts DCDC converter. */ ++#define CLKS_DCDCAPD 0x00000400 ++/* Disable ++#define CLKS_DCDCAPD_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_DCDCAPD_EN 0x00000400 ++/** DCDCDDR Clock Enable ++ Shows the clock enable bit for the DCDCDDR domain. This domain contains the digital part of the DCDC converter dedicated to the DDR interface. */ ++#define CLKS_DCDCDDR 0x00000200 ++/* Disable ++#define CLKS_DCDCDDR_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_DCDCDDR_EN 0x00000200 ++/** DCDC1V0 Clock Enable ++ Shows the clock enable bit for the DCDC1V0 domain. This domain contains the digital part of the 1.0 volts DCDC converter. */ ++#define CLKS_DCDC1V0 0x00000100 ++/* Disable ++#define CLKS_DCDC1V0_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_DCDC1V0_EN 0x00000100 ++/** TRC2MEM Clock Enable ++ Shows the clock enable bit for the TRC2MEM domain. This domain contains the TRC2MEM block. */ ++#define CLKS_TRC2MEM 0x00000040 ++/* Disable ++#define CLKS_TRC2MEM_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_TRC2MEM_EN 0x00000040 ++/** DDR Clock Enable ++ Shows the clock enable bit for the DDR domain. This domain contains the DDR interface block. */ ++#define CLKS_DDR 0x00000020 ++/* Disable ++#define CLKS_DDR_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_DDR_EN 0x00000020 ++/** EBU Clock Enable ++ Shows the clock enable bit for the EBU domain. This domain contains the EBU interface block. */ ++#define CLKS_EBU 0x00000010 ++/* Disable ++#define CLKS_EBU_DIS 0x00000000 */ ++/** Enable */ ++#define CLKS_EBU_EN 0x00000010 ++ ++/* Fields of "Clock Enable Register" */ ++/** Set Clock Enable STATUS ++ Sets the clock enable bit of the STATUS domain. This domain contains the STATUS block. */ ++#define CLKEN_STATUS 0x80000000 ++/* No-Operation ++#define CLKEN_STATUS_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_STATUS_SET 0x80000000 ++/** Set Clock Enable SHA1 ++ Sets the clock enable bit of the SHA1 domain. This domain contains the SHA1 block. */ ++#define CLKEN_SHA1 0x40000000 ++/* No-Operation ++#define CLKEN_SHA1_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_SHA1_SET 0x40000000 ++/** Set Clock Enable AES ++ Sets the clock enable bit of the AES domain. This domain contains the AES block. */ ++#define CLKEN_AES 0x20000000 ++/* No-Operation ++#define CLKEN_AES_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_AES_SET 0x20000000 ++/** Set Clock Enable PCM ++ Sets the clock enable bit of the PCM domain. This domain contains the PCM interface block. */ ++#define CLKEN_PCM 0x10000000 ++/* No-Operation ++#define CLKEN_PCM_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_PCM_SET 0x10000000 ++/** Set Clock Enable FSCT ++ Sets the clock enable bit of the FSCT domain. This domain contains the FSCT block. */ ++#define CLKEN_FSCT 0x08000000 ++/* No-Operation ++#define CLKEN_FSCT_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_FSCT_SET 0x08000000 ++/** Set Clock Enable GPTC ++ Sets the clock enable bit of the GPTC domain. This domain contains the GPTC block. */ ++#define CLKEN_GPTC 0x04000000 ++/* No-Operation ++#define CLKEN_GPTC_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_GPTC_SET 0x04000000 ++/** Set Clock Enable MPS ++ Sets the clock enable bit of the MPS domain. This domain contains the MPS block. */ ++#define CLKEN_MPS 0x02000000 ++/* No-Operation ++#define CLKEN_MPS_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_MPS_SET 0x02000000 ++/** Set Clock Enable DFEV0 ++ Sets the clock enable bit of the DFEV0 domain. This domain contains the DFEV0 block. */ ++#define CLKEN_DFEV0 0x01000000 ++/* No-Operation ++#define CLKEN_DFEV0_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_DFEV0_SET 0x01000000 ++/** Set Clock Enable PADCTRL4 ++ Sets the clock enable bit of the PADCTRL4 domain. This domain contains the PADCTRL4 block. */ ++#define CLKEN_PADCTRL4 0x00400000 ++/* No-Operation ++#define CLKEN_PADCTRL4_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_PADCTRL4_SET 0x00400000 ++/** Set Clock Enable PADCTRL3 ++ Sets the clock enable bit of the PADCTRL3 domain. This domain contains the PADCTRL3 block. */ ++#define CLKEN_PADCTRL3 0x00200000 ++/* No-Operation ++#define CLKEN_PADCTRL3_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_PADCTRL3_SET 0x00200000 ++/** Set Clock Enable PADCTRL1 ++ Sets the clock enable bit of the PADCTRL1 domain. This domain contains the PADCTRL1 block. */ ++#define CLKEN_PADCTRL1 0x00100000 ++/* No-Operation ++#define CLKEN_PADCTRL1_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_PADCTRL1_SET 0x00100000 ++/** Set Clock Enable P4 ++ Sets the clock enable bit of the P4 domain. This domain contains the P4 instance of the GPIO block. */ ++#define CLKEN_P4 0x00040000 ++/* No-Operation ++#define CLKEN_P4_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_P4_SET 0x00040000 ++/** Set Clock Enable P3 ++ Sets the clock enable bit of the P3 domain. This domain contains the P3 instance of the GPIO block. */ ++#define CLKEN_P3 0x00020000 ++/* No-Operation ++#define CLKEN_P3_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_P3_SET 0x00020000 ++/** Set Clock Enable P1 ++ Sets the clock enable bit of the P1 domain. This domain contains the P1 instance of the GPIO block. */ ++#define CLKEN_P1 0x00010000 ++/* No-Operation ++#define CLKEN_P1_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_P1_SET 0x00010000 ++/** Set Clock Enable HOST ++ Sets the clock enable bit of the HOST domain. This domain contains the HOST interface block. */ ++#define CLKEN_HOST 0x00008000 ++/* No-Operation ++#define CLKEN_HOST_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_HOST_SET 0x00008000 ++/** Set Clock Enable I2C ++ Sets the clock enable bit of the I2C domain. This domain contains the I2C interface block. */ ++#define CLKEN_I2C 0x00004000 ++/* No-Operation ++#define CLKEN_I2C_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_I2C_SET 0x00004000 ++/** Set Clock Enable SSC0 ++ Sets the clock enable bit of the SSC0 domain. This domain contains the SSC0 interface block. */ ++#define CLKEN_SSC0 0x00002000 ++/* No-Operation ++#define CLKEN_SSC0_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_SSC0_SET 0x00002000 ++/** Set Clock Enable ASC0 ++ Sets the clock enable bit of the ASC0 domain. This domain contains the ASC0 interface block. */ ++#define CLKEN_ASC0 0x00001000 ++/* No-Operation ++#define CLKEN_ASC0_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_ASC0_SET 0x00001000 ++/** Set Clock Enable ASC1 ++ Sets the clock enable bit of the ASC1 domain. This domain contains the ASC1 block. */ ++#define CLKEN_ASC1 0x00000800 ++/* No-Operation ++#define CLKEN_ASC1_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_ASC1_SET 0x00000800 ++/** Set Clock Enable DCDCAPD ++ Sets the clock enable bit of the DCDCAPD domain. This domain contains the digital part of the 60 volts DCDC converter. */ ++#define CLKEN_DCDCAPD 0x00000400 ++/* No-Operation ++#define CLKEN_DCDCAPD_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_DCDCAPD_SET 0x00000400 ++/** Set Clock Enable DCDCDDR ++ Sets the clock enable bit of the DCDCDDR domain. This domain contains the digital part of the DCDC converter dedicated to the DDR interface. */ ++#define CLKEN_DCDCDDR 0x00000200 ++/* No-Operation ++#define CLKEN_DCDCDDR_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_DCDCDDR_SET 0x00000200 ++/** Set Clock Enable DCDC1V0 ++ Sets the clock enable bit of the DCDC1V0 domain. This domain contains the digital part of the 1.0 volts DCDC converter. */ ++#define CLKEN_DCDC1V0 0x00000100 ++/* No-Operation ++#define CLKEN_DCDC1V0_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_DCDC1V0_SET 0x00000100 ++/** Set Clock Enable TRC2MEM ++ Sets the clock enable bit of the TRC2MEM domain. This domain contains the TRC2MEM block. */ ++#define CLKEN_TRC2MEM 0x00000040 ++/* No-Operation ++#define CLKEN_TRC2MEM_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_TRC2MEM_SET 0x00000040 ++/** Set Clock Enable DDR ++ Sets the clock enable bit of the DDR domain. This domain contains the DDR interface block. */ ++#define CLKEN_DDR 0x00000020 ++/* No-Operation ++#define CLKEN_DDR_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_DDR_SET 0x00000020 ++/** Set Clock Enable EBU ++ Sets the clock enable bit of the EBU domain. This domain contains the EBU interface block. */ ++#define CLKEN_EBU 0x00000010 ++/* No-Operation ++#define CLKEN_EBU_NOP 0x00000000 */ ++/** Set */ ++#define CLKEN_EBU_SET 0x00000010 ++ ++/* Fields of "Clock Clear Register" */ ++/** Clear Clock Enable STATUS ++ Clears the clock enable bit of the STATUS domain. This domain contains the STATUS block. */ ++#define CLKCLR_STATUS 0x80000000 ++/* No-Operation ++#define CLKCLR_STATUS_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_STATUS_CLR 0x80000000 ++/** Clear Clock Enable SHA1 ++ Clears the clock enable bit of the SHA1 domain. This domain contains the SHA1 block. */ ++#define CLKCLR_SHA1 0x40000000 ++/* No-Operation ++#define CLKCLR_SHA1_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_SHA1_CLR 0x40000000 ++/** Clear Clock Enable AES ++ Clears the clock enable bit of the AES domain. This domain contains the AES block. */ ++#define CLKCLR_AES 0x20000000 ++/* No-Operation ++#define CLKCLR_AES_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_AES_CLR 0x20000000 ++/** Clear Clock Enable PCM ++ Clears the clock enable bit of the PCM domain. This domain contains the PCM interface block. */ ++#define CLKCLR_PCM 0x10000000 ++/* No-Operation ++#define CLKCLR_PCM_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_PCM_CLR 0x10000000 ++/** Clear Clock Enable FSCT ++ Clears the clock enable bit of the FSCT domain. This domain contains the FSCT block. */ ++#define CLKCLR_FSCT 0x08000000 ++/* No-Operation ++#define CLKCLR_FSCT_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_FSCT_CLR 0x08000000 ++/** Clear Clock Enable GPTC ++ Clears the clock enable bit of the GPTC domain. This domain contains the GPTC block. */ ++#define CLKCLR_GPTC 0x04000000 ++/* No-Operation ++#define CLKCLR_GPTC_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_GPTC_CLR 0x04000000 ++/** Clear Clock Enable MPS ++ Clears the clock enable bit of the MPS domain. This domain contains the MPS block. */ ++#define CLKCLR_MPS 0x02000000 ++/* No-Operation ++#define CLKCLR_MPS_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_MPS_CLR 0x02000000 ++/** Clear Clock Enable DFEV0 ++ Clears the clock enable bit of the DFEV0 domain. This domain contains the DFEV0 block. */ ++#define CLKCLR_DFEV0 0x01000000 ++/* No-Operation ++#define CLKCLR_DFEV0_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_DFEV0_CLR 0x01000000 ++/** Clear Clock Enable PADCTRL4 ++ Clears the clock enable bit of the PADCTRL4 domain. This domain contains the PADCTRL4 block. */ ++#define CLKCLR_PADCTRL4 0x00400000 ++/* No-Operation ++#define CLKCLR_PADCTRL4_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_PADCTRL4_CLR 0x00400000 ++/** Clear Clock Enable PADCTRL3 ++ Clears the clock enable bit of the PADCTRL3 domain. This domain contains the PADCTRL3 block. */ ++#define CLKCLR_PADCTRL3 0x00200000 ++/* No-Operation ++#define CLKCLR_PADCTRL3_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_PADCTRL3_CLR 0x00200000 ++/** Clear Clock Enable PADCTRL1 ++ Clears the clock enable bit of the PADCTRL1 domain. This domain contains the PADCTRL1 block. */ ++#define CLKCLR_PADCTRL1 0x00100000 ++/* No-Operation ++#define CLKCLR_PADCTRL1_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_PADCTRL1_CLR 0x00100000 ++/** Clear Clock Enable P4 ++ Clears the clock enable bit of the P4 domain. This domain contains the P4 instance of the GPIO block. */ ++#define CLKCLR_P4 0x00040000 ++/* No-Operation ++#define CLKCLR_P4_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_P4_CLR 0x00040000 ++/** Clear Clock Enable P3 ++ Clears the clock enable bit of the P3 domain. This domain contains the P3 instance of the GPIO block. */ ++#define CLKCLR_P3 0x00020000 ++/* No-Operation ++#define CLKCLR_P3_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_P3_CLR 0x00020000 ++/** Clear Clock Enable P1 ++ Clears the clock enable bit of the P1 domain. This domain contains the P1 instance of the GPIO block. */ ++#define CLKCLR_P1 0x00010000 ++/* No-Operation ++#define CLKCLR_P1_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_P1_CLR 0x00010000 ++/** Clear Clock Enable HOST ++ Clears the clock enable bit of the HOST domain. This domain contains the HOST interface block. */ ++#define CLKCLR_HOST 0x00008000 ++/* No-Operation ++#define CLKCLR_HOST_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_HOST_CLR 0x00008000 ++/** Clear Clock Enable I2C ++ Clears the clock enable bit of the I2C domain. This domain contains the I2C interface block. */ ++#define CLKCLR_I2C 0x00004000 ++/* No-Operation ++#define CLKCLR_I2C_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_I2C_CLR 0x00004000 ++/** Clear Clock Enable SSC0 ++ Clears the clock enable bit of the SSC0 domain. This domain contains the SSC0 interface block. */ ++#define CLKCLR_SSC0 0x00002000 ++/* No-Operation ++#define CLKCLR_SSC0_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_SSC0_CLR 0x00002000 ++/** Clear Clock Enable ASC0 ++ Clears the clock enable bit of the ASC0 domain. This domain contains the ASC0 interface block. */ ++#define CLKCLR_ASC0 0x00001000 ++/* No-Operation ++#define CLKCLR_ASC0_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_ASC0_CLR 0x00001000 ++/** Clear Clock Enable ASC1 ++ Clears the clock enable bit of the ASC1 domain. This domain contains the ASC1 block. */ ++#define CLKCLR_ASC1 0x00000800 ++/* No-Operation ++#define CLKCLR_ASC1_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_ASC1_CLR 0x00000800 ++/** Clear Clock Enable DCDCAPD ++ Clears the clock enable bit of the DCDCAPD domain. This domain contains the digital part of the 60 volts DCDC converter. */ ++#define CLKCLR_DCDCAPD 0x00000400 ++/* No-Operation ++#define CLKCLR_DCDCAPD_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_DCDCAPD_CLR 0x00000400 ++/** Clear Clock Enable DCDCDDR ++ Clears the clock enable bit of the DCDCDDR domain. This domain contains the digital part of the DCDC converter dedicated to the DDR interface. */ ++#define CLKCLR_DCDCDDR 0x00000200 ++/* No-Operation ++#define CLKCLR_DCDCDDR_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_DCDCDDR_CLR 0x00000200 ++/** Clear Clock Enable DCDC1V0 ++ Clears the clock enable bit of the DCDC1V0 domain. This domain contains the digital part of the 1.0 volts DCDC converter. */ ++#define CLKCLR_DCDC1V0 0x00000100 ++/* No-Operation ++#define CLKCLR_DCDC1V0_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_DCDC1V0_CLR 0x00000100 ++/** Clear Clock Enable TRC2MEM ++ Clears the clock enable bit of the TRC2MEM domain. This domain contains the TRC2MEM block. */ ++#define CLKCLR_TRC2MEM 0x00000040 ++/* No-Operation ++#define CLKCLR_TRC2MEM_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_TRC2MEM_CLR 0x00000040 ++/** Clear Clock Enable DDR ++ Clears the clock enable bit of the DDR domain. This domain contains the DDR interface block. */ ++#define CLKCLR_DDR 0x00000020 ++/* No-Operation ++#define CLKCLR_DDR_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_DDR_CLR 0x00000020 ++/** Clear Clock Enable EBU ++ Clears the clock enable bit of the EBU domain. This domain contains the EBU interface block. */ ++#define CLKCLR_EBU 0x00000010 ++/* No-Operation ++#define CLKCLR_EBU_NOP 0x00000000 */ ++/** Clear */ ++#define CLKCLR_EBU_CLR 0x00000010 ++ ++/* Fields of "Activation Status Register" */ ++/** STATUS Status ++ Shows the activation status of the STATUS domain. This domain contains the STATUS block. */ ++#define ACTS_STATUS 0x80000000 ++/* The block is inactive. ++#define ACTS_STATUS_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_STATUS_ACT 0x80000000 ++/** SHA1 Status ++ Shows the activation status of the SHA1 domain. This domain contains the SHA1 block. */ ++#define ACTS_SHA1 0x40000000 ++/* The block is inactive. ++#define ACTS_SHA1_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_SHA1_ACT 0x40000000 ++/** AES Status ++ Shows the activation status of the AES domain. This domain contains the AES block. */ ++#define ACTS_AES 0x20000000 ++/* The block is inactive. ++#define ACTS_AES_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_AES_ACT 0x20000000 ++/** PCM Status ++ Shows the activation status of the PCM domain. This domain contains the PCM interface block. */ ++#define ACTS_PCM 0x10000000 ++/* The block is inactive. ++#define ACTS_PCM_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_PCM_ACT 0x10000000 ++/** FSCT Status ++ Shows the activation status of the FSCT domain. This domain contains the FSCT block. */ ++#define ACTS_FSCT 0x08000000 ++/* The block is inactive. ++#define ACTS_FSCT_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_FSCT_ACT 0x08000000 ++/** GPTC Status ++ Shows the activation status of the GPTC domain. This domain contains the GPTC block. */ ++#define ACTS_GPTC 0x04000000 ++/* The block is inactive. ++#define ACTS_GPTC_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_GPTC_ACT 0x04000000 ++/** MPS Status ++ Shows the activation status of the MPS domain. This domain contains the MPS block. */ ++#define ACTS_MPS 0x02000000 ++/* The block is inactive. ++#define ACTS_MPS_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_MPS_ACT 0x02000000 ++/** DFEV0 Status ++ Shows the activation status of the DFEV0 domain. This domain contains the DFEV0 block. */ ++#define ACTS_DFEV0 0x01000000 ++/* The block is inactive. ++#define ACTS_DFEV0_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_DFEV0_ACT 0x01000000 ++/** PADCTRL4 Status ++ Shows the activation status of the PADCTRL4 domain. This domain contains the PADCTRL4 block. */ ++#define ACTS_PADCTRL4 0x00400000 ++/* The block is inactive. ++#define ACTS_PADCTRL4_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_PADCTRL4_ACT 0x00400000 ++/** PADCTRL3 Status ++ Shows the activation status of the PADCTRL3 domain. This domain contains the PADCTRL3 block. */ ++#define ACTS_PADCTRL3 0x00200000 ++/* The block is inactive. ++#define ACTS_PADCTRL3_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_PADCTRL3_ACT 0x00200000 ++/** PADCTRL1 Status ++ Shows the activation status of the PADCTRL1 domain. This domain contains the PADCTRL1 block. */ ++#define ACTS_PADCTRL1 0x00100000 ++/* The block is inactive. ++#define ACTS_PADCTRL1_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_PADCTRL1_ACT 0x00100000 ++/** P4 Status ++ Shows the activation status of the P4 domain. This domain contains the P4 instance of the GPIO block. */ ++#define ACTS_P4 0x00040000 ++/* The block is inactive. ++#define ACTS_P4_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_P4_ACT 0x00040000 ++/** P3 Status ++ Shows the activation status of the P3 domain. This domain contains the P3 instance of the GPIO block. */ ++#define ACTS_P3 0x00020000 ++/* The block is inactive. ++#define ACTS_P3_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_P3_ACT 0x00020000 ++/** P1 Status ++ Shows the activation status of the P1 domain. This domain contains the P1 instance of the GPIO block. */ ++#define ACTS_P1 0x00010000 ++/* The block is inactive. ++#define ACTS_P1_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_P1_ACT 0x00010000 ++/** HOST Status ++ Shows the activation status of the HOST domain. This domain contains the HOST interface block. */ ++#define ACTS_HOST 0x00008000 ++/* The block is inactive. ++#define ACTS_HOST_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_HOST_ACT 0x00008000 ++/** I2C Status ++ Shows the activation status of the I2C domain. This domain contains the I2C interface block. */ ++#define ACTS_I2C 0x00004000 ++/* The block is inactive. ++#define ACTS_I2C_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_I2C_ACT 0x00004000 ++/** SSC0 Status ++ Shows the activation status of the SSC0 domain. This domain contains the SSC0 interface block. */ ++#define ACTS_SSC0 0x00002000 ++/* The block is inactive. ++#define ACTS_SSC0_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_SSC0_ACT 0x00002000 ++/** ASC0 Status ++ Shows the activation status of the ASC0 domain. This domain contains the ASC0 interface block. */ ++#define ACTS_ASC0 0x00001000 ++/* The block is inactive. ++#define ACTS_ASC0_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_ASC0_ACT 0x00001000 ++/** ASC1 Status ++ Shows the activation status of the ASC1 domain. This domain contains the ASC1 block. */ ++#define ACTS_ASC1 0x00000800 ++/* The block is inactive. ++#define ACTS_ASC1_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_ASC1_ACT 0x00000800 ++/** DCDCAPD Status ++ Shows the activation status of the DCDCAPD domain. This domain contains the digital part of the 60 volts DCDC converter. */ ++#define ACTS_DCDCAPD 0x00000400 ++/* The block is inactive. ++#define ACTS_DCDCAPD_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_DCDCAPD_ACT 0x00000400 ++/** DCDCDDR Status ++ Shows the activation status of the DCDCDDR domain. This domain contains the digital part of the DCDC converter dedicated to the DDR interface. */ ++#define ACTS_DCDCDDR 0x00000200 ++/* The block is inactive. ++#define ACTS_DCDCDDR_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_DCDCDDR_ACT 0x00000200 ++/** DCDC1V0 Status ++ Shows the activation status of the DCDC1V0 domain. This domain contains the digital part of the 1.0 volts DCDC converter. */ ++#define ACTS_DCDC1V0 0x00000100 ++/* The block is inactive. ++#define ACTS_DCDC1V0_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_DCDC1V0_ACT 0x00000100 ++/** TRC2MEM Status ++ Shows the activation status of the TRC2MEM domain. This domain contains the TRC2MEM block. */ ++#define ACTS_TRC2MEM 0x00000040 ++/* The block is inactive. ++#define ACTS_TRC2MEM_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_TRC2MEM_ACT 0x00000040 ++/** DDR Status ++ Shows the activation status of the DDR domain. This domain contains the DDR interface block. */ ++#define ACTS_DDR 0x00000020 ++/* The block is inactive. ++#define ACTS_DDR_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_DDR_ACT 0x00000020 ++/** EBU Status ++ Shows the activation status of the EBU domain. This domain contains the EBU interface block. */ ++#define ACTS_EBU 0x00000010 ++/* The block is inactive. ++#define ACTS_EBU_INACT 0x00000000 */ ++/** The block is active. */ ++#define ACTS_EBU_ACT 0x00000010 ++ ++/* Fields of "Activation Register" */ ++/** Activate STATUS ++ Sets the activation flag of the STATUS domain. This domain contains the STATUS block. */ ++#define ACT_STATUS 0x80000000 ++/* No-Operation ++#define ACT_STATUS_NOP 0x00000000 */ ++/** Set */ ++#define ACT_STATUS_SET 0x80000000 ++/** Activate SHA1 ++ Sets the activation flag of the SHA1 domain. This domain contains the SHA1 block. */ ++#define ACT_SHA1 0x40000000 ++/* No-Operation ++#define ACT_SHA1_NOP 0x00000000 */ ++/** Set */ ++#define ACT_SHA1_SET 0x40000000 ++/** Activate AES ++ Sets the activation flag of the AES domain. This domain contains the AES block. */ ++#define ACT_AES 0x20000000 ++/* No-Operation ++#define ACT_AES_NOP 0x00000000 */ ++/** Set */ ++#define ACT_AES_SET 0x20000000 ++/** Activate PCM ++ Sets the activation flag of the PCM domain. This domain contains the PCM interface block. */ ++#define ACT_PCM 0x10000000 ++/* No-Operation ++#define ACT_PCM_NOP 0x00000000 */ ++/** Set */ ++#define ACT_PCM_SET 0x10000000 ++/** Activate FSCT ++ Sets the activation flag of the FSCT domain. This domain contains the FSCT block. */ ++#define ACT_FSCT 0x08000000 ++/* No-Operation ++#define ACT_FSCT_NOP 0x00000000 */ ++/** Set */ ++#define ACT_FSCT_SET 0x08000000 ++/** Activate GPTC ++ Sets the activation flag of the GPTC domain. This domain contains the GPTC block. */ ++#define ACT_GPTC 0x04000000 ++/* No-Operation ++#define ACT_GPTC_NOP 0x00000000 */ ++/** Set */ ++#define ACT_GPTC_SET 0x04000000 ++/** Activate MPS ++ Sets the activation flag of the MPS domain. This domain contains the MPS block. */ ++#define ACT_MPS 0x02000000 ++/* No-Operation ++#define ACT_MPS_NOP 0x00000000 */ ++/** Set */ ++#define ACT_MPS_SET 0x02000000 ++/** Activate DFEV0 ++ Sets the activation flag of the DFEV0 domain. This domain contains the DFEV0 block. */ ++#define ACT_DFEV0 0x01000000 ++/* No-Operation ++#define ACT_DFEV0_NOP 0x00000000 */ ++/** Set */ ++#define ACT_DFEV0_SET 0x01000000 ++/** Activate PADCTRL4 ++ Sets the activation flag of the PADCTRL4 domain. This domain contains the PADCTRL4 block. */ ++#define ACT_PADCTRL4 0x00400000 ++/* No-Operation ++#define ACT_PADCTRL4_NOP 0x00000000 */ ++/** Set */ ++#define ACT_PADCTRL4_SET 0x00400000 ++/** Activate PADCTRL3 ++ Sets the activation flag of the PADCTRL3 domain. This domain contains the PADCTRL3 block. */ ++#define ACT_PADCTRL3 0x00200000 ++/* No-Operation ++#define ACT_PADCTRL3_NOP 0x00000000 */ ++/** Set */ ++#define ACT_PADCTRL3_SET 0x00200000 ++/** Activate PADCTRL1 ++ Sets the activation flag of the PADCTRL1 domain. This domain contains the PADCTRL1 block. */ ++#define ACT_PADCTRL1 0x00100000 ++/* No-Operation ++#define ACT_PADCTRL1_NOP 0x00000000 */ ++/** Set */ ++#define ACT_PADCTRL1_SET 0x00100000 ++/** Activate P4 ++ Sets the activation flag of the P4 domain. This domain contains the P4 instance of the GPIO block. */ ++#define ACT_P4 0x00040000 ++/* No-Operation ++#define ACT_P4_NOP 0x00000000 */ ++/** Set */ ++#define ACT_P4_SET 0x00040000 ++/** Activate P3 ++ Sets the activation flag of the P3 domain. This domain contains the P3 instance of the GPIO block. */ ++#define ACT_P3 0x00020000 ++/* No-Operation ++#define ACT_P3_NOP 0x00000000 */ ++/** Set */ ++#define ACT_P3_SET 0x00020000 ++/** Activate P1 ++ Sets the activation flag of the P1 domain. This domain contains the P1 instance of the GPIO block. */ ++#define ACT_P1 0x00010000 ++/* No-Operation ++#define ACT_P1_NOP 0x00000000 */ ++/** Set */ ++#define ACT_P1_SET 0x00010000 ++/** Activate HOST ++ Sets the activation flag of the HOST domain. This domain contains the HOST interface block. */ ++#define ACT_HOST 0x00008000 ++/* No-Operation ++#define ACT_HOST_NOP 0x00000000 */ ++/** Set */ ++#define ACT_HOST_SET 0x00008000 ++/** Activate I2C ++ Sets the activation flag of the I2C domain. This domain contains the I2C interface block. */ ++#define ACT_I2C 0x00004000 ++/* No-Operation ++#define ACT_I2C_NOP 0x00000000 */ ++/** Set */ ++#define ACT_I2C_SET 0x00004000 ++/** Activate SSC0 ++ Sets the activation flag of the SSC0 domain. This domain contains the SSC0 interface block. */ ++#define ACT_SSC0 0x00002000 ++/* No-Operation ++#define ACT_SSC0_NOP 0x00000000 */ ++/** Set */ ++#define ACT_SSC0_SET 0x00002000 ++/** Activate ASC0 ++ Sets the activation flag of the ASC0 domain. This domain contains the ASC0 interface block. */ ++#define ACT_ASC0 0x00001000 ++/* No-Operation ++#define ACT_ASC0_NOP 0x00000000 */ ++/** Set */ ++#define ACT_ASC0_SET 0x00001000 ++/** Activate ASC1 ++ Sets the activation flag of the ASC1 domain. This domain contains the ASC1 block. */ ++#define ACT_ASC1 0x00000800 ++/* No-Operation ++#define ACT_ASC1_NOP 0x00000000 */ ++/** Set */ ++#define ACT_ASC1_SET 0x00000800 ++/** Activate DCDCAPD ++ Sets the activation flag of the DCDCAPD domain. This domain contains the digital part of the 60 volts DCDC converter. */ ++#define ACT_DCDCAPD 0x00000400 ++/* No-Operation ++#define ACT_DCDCAPD_NOP 0x00000000 */ ++/** Set */ ++#define ACT_DCDCAPD_SET 0x00000400 ++/** Activate DCDCDDR ++ Sets the activation flag of the DCDCDDR domain. This domain contains the digital part of the DCDC converter dedicated to the DDR interface. */ ++#define ACT_DCDCDDR 0x00000200 ++/* No-Operation ++#define ACT_DCDCDDR_NOP 0x00000000 */ ++/** Set */ ++#define ACT_DCDCDDR_SET 0x00000200 ++/** Activate DCDC1V0 ++ Sets the activation flag of the DCDC1V0 domain. This domain contains the digital part of the 1.0 volts DCDC converter. */ ++#define ACT_DCDC1V0 0x00000100 ++/* No-Operation ++#define ACT_DCDC1V0_NOP 0x00000000 */ ++/** Set */ ++#define ACT_DCDC1V0_SET 0x00000100 ++/** Activate TRC2MEM ++ Sets the activation flag of the TRC2MEM domain. This domain contains the TRC2MEM block. */ ++#define ACT_TRC2MEM 0x00000040 ++/* No-Operation ++#define ACT_TRC2MEM_NOP 0x00000000 */ ++/** Set */ ++#define ACT_TRC2MEM_SET 0x00000040 ++/** Activate DDR ++ Sets the activation flag of the DDR domain. This domain contains the DDR interface block. */ ++#define ACT_DDR 0x00000020 ++/* No-Operation ++#define ACT_DDR_NOP 0x00000000 */ ++/** Set */ ++#define ACT_DDR_SET 0x00000020 ++/** Activate EBU ++ Sets the activation flag of the EBU domain. This domain contains the EBU interface block. */ ++#define ACT_EBU 0x00000010 ++/* No-Operation ++#define ACT_EBU_NOP 0x00000000 */ ++/** Set */ ++#define ACT_EBU_SET 0x00000010 ++ ++/* Fields of "Deactivation Register" */ ++/** Deactivate STATUS ++ Clears the activation flag of the STATUS domain. This domain contains the STATUS block. */ ++#define DEACT_STATUS 0x80000000 ++/* No-Operation ++#define DEACT_STATUS_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_STATUS_CLR 0x80000000 ++/** Deactivate SHA1 ++ Clears the activation flag of the SHA1 domain. This domain contains the SHA1 block. */ ++#define DEACT_SHA1 0x40000000 ++/* No-Operation ++#define DEACT_SHA1_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_SHA1_CLR 0x40000000 ++/** Deactivate AES ++ Clears the activation flag of the AES domain. This domain contains the AES block. */ ++#define DEACT_AES 0x20000000 ++/* No-Operation ++#define DEACT_AES_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_AES_CLR 0x20000000 ++/** Deactivate PCM ++ Clears the activation flag of the PCM domain. This domain contains the PCM interface block. */ ++#define DEACT_PCM 0x10000000 ++/* No-Operation ++#define DEACT_PCM_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_PCM_CLR 0x10000000 ++/** Deactivate FSCT ++ Clears the activation flag of the FSCT domain. This domain contains the FSCT block. */ ++#define DEACT_FSCT 0x08000000 ++/* No-Operation ++#define DEACT_FSCT_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_FSCT_CLR 0x08000000 ++/** Deactivate GPTC ++ Clears the activation flag of the GPTC domain. This domain contains the GPTC block. */ ++#define DEACT_GPTC 0x04000000 ++/* No-Operation ++#define DEACT_GPTC_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_GPTC_CLR 0x04000000 ++/** Deactivate MPS ++ Clears the activation flag of the MPS domain. This domain contains the MPS block. */ ++#define DEACT_MPS 0x02000000 ++/* No-Operation ++#define DEACT_MPS_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_MPS_CLR 0x02000000 ++/** Deactivate DFEV0 ++ Clears the activation flag of the DFEV0 domain. This domain contains the DFEV0 block. */ ++#define DEACT_DFEV0 0x01000000 ++/* No-Operation ++#define DEACT_DFEV0_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_DFEV0_CLR 0x01000000 ++/** Deactivate PADCTRL4 ++ Clears the activation flag of the PADCTRL4 domain. This domain contains the PADCTRL4 block. */ ++#define DEACT_PADCTRL4 0x00400000 ++/* No-Operation ++#define DEACT_PADCTRL4_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_PADCTRL4_CLR 0x00400000 ++/** Deactivate PADCTRL3 ++ Clears the activation flag of the PADCTRL3 domain. This domain contains the PADCTRL3 block. */ ++#define DEACT_PADCTRL3 0x00200000 ++/* No-Operation ++#define DEACT_PADCTRL3_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_PADCTRL3_CLR 0x00200000 ++/** Deactivate PADCTRL1 ++ Clears the activation flag of the PADCTRL1 domain. This domain contains the PADCTRL1 block. */ ++#define DEACT_PADCTRL1 0x00100000 ++/* No-Operation ++#define DEACT_PADCTRL1_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_PADCTRL1_CLR 0x00100000 ++/** Deactivate P4 ++ Clears the activation flag of the P4 domain. This domain contains the P4 instance of the GPIO block. */ ++#define DEACT_P4 0x00040000 ++/* No-Operation ++#define DEACT_P4_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_P4_CLR 0x00040000 ++/** Deactivate P3 ++ Clears the activation flag of the P3 domain. This domain contains the P3 instance of the GPIO block. */ ++#define DEACT_P3 0x00020000 ++/* No-Operation ++#define DEACT_P3_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_P3_CLR 0x00020000 ++/** Deactivate P1 ++ Clears the activation flag of the P1 domain. This domain contains the P1 instance of the GPIO block. */ ++#define DEACT_P1 0x00010000 ++/* No-Operation ++#define DEACT_P1_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_P1_CLR 0x00010000 ++/** Deactivate HOST ++ Clears the activation flag of the HOST domain. This domain contains the HOST interface block. */ ++#define DEACT_HOST 0x00008000 ++/* No-Operation ++#define DEACT_HOST_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_HOST_CLR 0x00008000 ++/** Deactivate I2C ++ Clears the activation flag of the I2C domain. This domain contains the I2C interface block. */ ++#define DEACT_I2C 0x00004000 ++/* No-Operation ++#define DEACT_I2C_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_I2C_CLR 0x00004000 ++/** Deactivate SSC0 ++ Clears the activation flag of the SSC0 domain. This domain contains the SSC0 interface block. */ ++#define DEACT_SSC0 0x00002000 ++/* No-Operation ++#define DEACT_SSC0_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_SSC0_CLR 0x00002000 ++/** Deactivate ASC0 ++ Clears the activation flag of the ASC0 domain. This domain contains the ASC0 interface block. */ ++#define DEACT_ASC0 0x00001000 ++/* No-Operation ++#define DEACT_ASC0_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_ASC0_CLR 0x00001000 ++/** Deactivate ASC1 ++ Clears the activation flag of the ASC1 domain. This domain contains the ASC1 block. */ ++#define DEACT_ASC1 0x00000800 ++/* No-Operation ++#define DEACT_ASC1_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_ASC1_CLR 0x00000800 ++/** Deactivate DCDCAPD ++ Clears the activation flag of the DCDCAPD domain. This domain contains the digital part of the 60 volts DCDC converter. */ ++#define DEACT_DCDCAPD 0x00000400 ++/* No-Operation ++#define DEACT_DCDCAPD_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_DCDCAPD_CLR 0x00000400 ++/** Deactivate DCDCDDR ++ Clears the activation flag of the DCDCDDR domain. This domain contains the digital part of the DCDC converter dedicated to the DDR interface. */ ++#define DEACT_DCDCDDR 0x00000200 ++/* No-Operation ++#define DEACT_DCDCDDR_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_DCDCDDR_CLR 0x00000200 ++/** Deactivate DCDC1V0 ++ Clears the activation flag of the DCDC1V0 domain. This domain contains the digital part of the 1.0 volts DCDC converter. */ ++#define DEACT_DCDC1V0 0x00000100 ++/* No-Operation ++#define DEACT_DCDC1V0_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_DCDC1V0_CLR 0x00000100 ++/** Deactivate TRC2MEM ++ Clears the activation flag of the TRC2MEM domain. This domain contains the TRC2MEM block. */ ++#define DEACT_TRC2MEM 0x00000040 ++/* No-Operation ++#define DEACT_TRC2MEM_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_TRC2MEM_CLR 0x00000040 ++/** Deactivate DDR ++ Clears the activation flag of the DDR domain. This domain contains the DDR interface block. */ ++#define DEACT_DDR 0x00000020 ++/* No-Operation ++#define DEACT_DDR_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_DDR_CLR 0x00000020 ++/** Deactivate EBU ++ Clears the activation flag of the EBU domain. This domain contains the EBU interface block. */ ++#define DEACT_EBU 0x00000010 ++/* No-Operation ++#define DEACT_EBU_NOP 0x00000000 */ ++/** Clear */ ++#define DEACT_EBU_CLR 0x00000010 ++ ++/* Fields of "Reboot Trigger Register" */ ++/** Reboot STATUS ++ Triggers a reboot of the STATUS domain. This domain contains the STATUS block. */ ++#define RBT_STATUS 0x80000000 ++/* No-Operation ++#define RBT_STATUS_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_STATUS_TRIG 0x80000000 ++/** Reboot SHA1 ++ Triggers a reboot of the SHA1 domain. This domain contains the SHA1 block. */ ++#define RBT_SHA1 0x40000000 ++/* No-Operation ++#define RBT_SHA1_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_SHA1_TRIG 0x40000000 ++/** Reboot AES ++ Triggers a reboot of the AES domain. This domain contains the AES block. */ ++#define RBT_AES 0x20000000 ++/* No-Operation ++#define RBT_AES_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_AES_TRIG 0x20000000 ++/** Reboot PCM ++ Triggers a reboot of the PCM domain. This domain contains the PCM interface block. */ ++#define RBT_PCM 0x10000000 ++/* No-Operation ++#define RBT_PCM_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_PCM_TRIG 0x10000000 ++/** Reboot FSCT ++ Triggers a reboot of the FSCT domain. This domain contains the FSCT block. */ ++#define RBT_FSCT 0x08000000 ++/* No-Operation ++#define RBT_FSCT_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_FSCT_TRIG 0x08000000 ++/** Reboot GPTC ++ Triggers a reboot of the GPTC domain. This domain contains the GPTC block. */ ++#define RBT_GPTC 0x04000000 ++/* No-Operation ++#define RBT_GPTC_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_GPTC_TRIG 0x04000000 ++/** Reboot MPS ++ Triggers a reboot of the MPS domain. This domain contains the MPS block. */ ++#define RBT_MPS 0x02000000 ++/* No-Operation ++#define RBT_MPS_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_MPS_TRIG 0x02000000 ++/** Reboot DFEV0 ++ Triggers a reboot of the DFEV0 domain. This domain contains the DFEV0 block. */ ++#define RBT_DFEV0 0x01000000 ++/* No-Operation ++#define RBT_DFEV0_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_DFEV0_TRIG 0x01000000 ++/** Reboot PADCTRL4 ++ Triggers a reboot of the PADCTRL4 domain. This domain contains the PADCTRL4 block. */ ++#define RBT_PADCTRL4 0x00400000 ++/* No-Operation ++#define RBT_PADCTRL4_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_PADCTRL4_TRIG 0x00400000 ++/** Reboot PADCTRL3 ++ Triggers a reboot of the PADCTRL3 domain. This domain contains the PADCTRL3 block. */ ++#define RBT_PADCTRL3 0x00200000 ++/* No-Operation ++#define RBT_PADCTRL3_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_PADCTRL3_TRIG 0x00200000 ++/** Reboot PADCTRL1 ++ Triggers a reboot of the PADCTRL1 domain. This domain contains the PADCTRL1 block. */ ++#define RBT_PADCTRL1 0x00100000 ++/* No-Operation ++#define RBT_PADCTRL1_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_PADCTRL1_TRIG 0x00100000 ++/** Reboot P4 ++ Triggers a reboot of the P4 domain. This domain contains the P4 instance of the GPIO block. */ ++#define RBT_P4 0x00040000 ++/* No-Operation ++#define RBT_P4_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_P4_TRIG 0x00040000 ++/** Reboot P3 ++ Triggers a reboot of the P3 domain. This domain contains the P3 instance of the GPIO block. */ ++#define RBT_P3 0x00020000 ++/* No-Operation ++#define RBT_P3_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_P3_TRIG 0x00020000 ++/** Reboot P1 ++ Triggers a reboot of the P1 domain. This domain contains the P1 instance of the GPIO block. */ ++#define RBT_P1 0x00010000 ++/* No-Operation ++#define RBT_P1_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_P1_TRIG 0x00010000 ++/** Reboot HOST ++ Triggers a reboot of the HOST domain. This domain contains the HOST interface block. */ ++#define RBT_HOST 0x00008000 ++/* No-Operation ++#define RBT_HOST_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_HOST_TRIG 0x00008000 ++/** Reboot I2C ++ Triggers a reboot of the I2C domain. This domain contains the I2C interface block. */ ++#define RBT_I2C 0x00004000 ++/* No-Operation ++#define RBT_I2C_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_I2C_TRIG 0x00004000 ++/** Reboot SSC0 ++ Triggers a reboot of the SSC0 domain. This domain contains the SSC0 interface block. */ ++#define RBT_SSC0 0x00002000 ++/* No-Operation ++#define RBT_SSC0_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_SSC0_TRIG 0x00002000 ++/** Reboot ASC0 ++ Triggers a reboot of the ASC0 domain. This domain contains the ASC0 interface block. */ ++#define RBT_ASC0 0x00001000 ++/* No-Operation ++#define RBT_ASC0_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_ASC0_TRIG 0x00001000 ++/** Reboot ASC1 ++ Triggers a reboot of the ASC1 domain. This domain contains the ASC1 block. */ ++#define RBT_ASC1 0x00000800 ++/* No-Operation ++#define RBT_ASC1_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_ASC1_TRIG 0x00000800 ++/** Reboot DCDCAPD ++ Triggers a reboot of the DCDCAPD domain. This domain contains the digital part of the 60 volts DCDC converter. */ ++#define RBT_DCDCAPD 0x00000400 ++/* No-Operation ++#define RBT_DCDCAPD_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_DCDCAPD_TRIG 0x00000400 ++/** Reboot DCDCDDR ++ Triggers a reboot of the DCDCDDR domain. This domain contains the digital part of the DCDC converter dedicated to the DDR interface. */ ++#define RBT_DCDCDDR 0x00000200 ++/* No-Operation ++#define RBT_DCDCDDR_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_DCDCDDR_TRIG 0x00000200 ++/** Reboot DCDC1V0 ++ Triggers a reboot of the DCDC1V0 domain. This domain contains the digital part of the 1.0 volts DCDC converter. */ ++#define RBT_DCDC1V0 0x00000100 ++/* No-Operation ++#define RBT_DCDC1V0_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_DCDC1V0_TRIG 0x00000100 ++/** Reboot TRC2MEM ++ Triggers a reboot of the TRC2MEM domain. This domain contains the TRC2MEM block. */ ++#define RBT_TRC2MEM 0x00000040 ++/* No-Operation ++#define RBT_TRC2MEM_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_TRC2MEM_TRIG 0x00000040 ++/** Reboot DDR ++ Triggers a reboot of the DDR domain. This domain contains the DDR interface block. */ ++#define RBT_DDR 0x00000020 ++/* No-Operation ++#define RBT_DDR_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_DDR_TRIG 0x00000020 ++/** Reboot EBU ++ Triggers a reboot of the EBU domain. This domain contains the EBU interface block. */ ++#define RBT_EBU 0x00000010 ++/* No-Operation ++#define RBT_EBU_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_EBU_TRIG 0x00000010 ++/** Reboot XBAR ++ Triggers a reboot of the XBAR. */ ++#define RBT_XBAR 0x00000002 ++/* No-Operation ++#define RBT_XBAR_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_XBAR_TRIG 0x00000002 ++/** Reboot CPU ++ Triggers a reboot of the CPU. */ ++#define RBT_CPU 0x00000001 ++/* No-Operation ++#define RBT_CPU_NOP 0x00000000 */ ++/** Trigger */ ++#define RBT_CPU_TRIG 0x00000001 ++ ++/* Fields of "CPU0 Clock Control Register" */ ++/** CPU Clock Divider ++ Via this bit the divider and therefore the frequency of the clock of CPU0 can be selected. */ ++#define CPU0CC_CPUDIV 0x00000001 ++/* Frequency set to the nominal value. ++#define CPU0CC_CPUDIV_SELFNOM 0x00000000 */ ++/** Frequency set to half of its nominal value. */ ++#define CPU0CC_CPUDIV_SELFHALF 0x00000001 ++ ++/* Fields of "CPU0 Reset Source Register" */ ++/** Software Reboot Request Occurred ++ This bit can be acknowledged by a write operation. */ ++#define CPU0RS_SWRRO 0x00000004 ++/* Nothing ++#define CPU0RS_SWRRO_NULL 0x00000000 */ ++/** Write: Acknowledge the event. */ ++#define CPU0RS_SWRRO_EVACK 0x00000004 ++/** Read: Event occurred. */ ++#define CPU0RS_SWRRO_EVOCC 0x00000004 ++/** Hardware Reset Source ++ Reflects the root cause for the last hardware reset. The infrastructure-block is only reset in case of POR. For all other blocks there is no difference between the three HW-reset sources. */ ++#define CPU0RS_HWRS_MASK 0x00000003 ++/** field offset */ ++#define CPU0RS_HWRS_OFFSET 0 ++/** Power-on reset. */ ++#define CPU0RS_HWRS_POR 0x00000000 ++/** RST pin. */ ++#define CPU0RS_HWRS_RST 0x00000001 ++/** Watchdog reset request. */ ++#define CPU0RS_HWRS_WDT 0x00000002 ++ ++/* Fields of "CPU0 Wakeup Configuration Register" */ ++/** Wakeup Request Source Yield Resume 15 ++ Select the signal connected to the yield/resume interface pin 15 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR15 0x80000000 ++/* Not selected ++#define CPU0WCFG_WRSYR15_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR15_SEL 0x80000000 ++/** Wakeup Request Source Yield Resume 14 ++ Select the signal connected to the yield/resume interface pin 14 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR14 0x40000000 ++/* Not selected ++#define CPU0WCFG_WRSYR14_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR14_SEL 0x40000000 ++/** Wakeup Request Source Yield Resume 13 ++ Select the signal connected to the yield/resume interface pin 13 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR13 0x20000000 ++/* Not selected ++#define CPU0WCFG_WRSYR13_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR13_SEL 0x20000000 ++/** Wakeup Request Source Yield Resume 12 ++ Select the signal connected to the yield/resume interface pin 12 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR12 0x10000000 ++/* Not selected ++#define CPU0WCFG_WRSYR12_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR12_SEL 0x10000000 ++/** Wakeup Request Source Yield Resume 11 ++ Select the signal connected to the yield/resume interface pin 11 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR11 0x08000000 ++/* Not selected ++#define CPU0WCFG_WRSYR11_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR11_SEL 0x08000000 ++/** Wakeup Request Source Yield Resume 10 ++ Select the signal connected to the yield/resume interface pin 10 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR10 0x04000000 ++/* Not selected ++#define CPU0WCFG_WRSYR10_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR10_SEL 0x04000000 ++/** Wakeup Request Source Yield Resume 9 ++ Select the signal connected to the yield/resume interface pin 9 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR9 0x02000000 ++/* Not selected ++#define CPU0WCFG_WRSYR9_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR9_SEL 0x02000000 ++/** Wakeup Request Source Yield Resume 8 ++ Select the signal connected to the yield/resume interface pin 8 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR8 0x01000000 ++/* Not selected ++#define CPU0WCFG_WRSYR8_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR8_SEL 0x01000000 ++/** Wakeup Request Source Yield Resume 7 ++ Select the signal connected to the yield/resume interface pin 7 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR7 0x00800000 ++/* Not selected ++#define CPU0WCFG_WRSYR7_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR7_SEL 0x00800000 ++/** Wakeup Request Source Yield Resume 6 ++ Select the signal connected to the yield/resume interface pin 6 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR6 0x00400000 ++/* Not selected ++#define CPU0WCFG_WRSYR6_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR6_SEL 0x00400000 ++/** Wakeup Request Source Yield Resume 5 ++ Select the signal connected to the yield/resume interface pin 5 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR5 0x00200000 ++/* Not selected ++#define CPU0WCFG_WRSYR5_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR5_SEL 0x00200000 ++/** Wakeup Request Source Yield Resume 4 ++ Select the signal connected to the yield/resume interface pin 4 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR4 0x00100000 ++/* Not selected ++#define CPU0WCFG_WRSYR4_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR4_SEL 0x00100000 ++/** Wakeup Request Source Yield Resume 3 ++ Select the signal connected to the yield/resume interface pin 3 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR3 0x00080000 ++/* Not selected ++#define CPU0WCFG_WRSYR3_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR3_SEL 0x00080000 ++/** Wakeup Request Source Yield Resume 2 ++ Select the signal connected to the yield/resume interface pin 2 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR2 0x00040000 ++/* Not selected ++#define CPU0WCFG_WRSYR2_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR2_SEL 0x00040000 ++/** Wakeup Request Source Yield Resume 1 ++ Select the signal connected to the yield/resume interface pin 1 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR1 0x00020000 ++/* Not selected ++#define CPU0WCFG_WRSYR1_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR1_SEL 0x00020000 ++/** Wakeup Request Source Yield Resume 0 ++ Select the signal connected to the yield/resume interface pin 0 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSYR0 0x00010000 ++/* Not selected ++#define CPU0WCFG_WRSYR0_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSYR0_SEL 0x00010000 ++/** Wakeup Request Source Debug ++ Select signal EJ_DINT as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSDBG 0x00000100 ++/* Not selected ++#define CPU0WCFG_WRSDBG_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSDBG_SEL 0x00000100 ++/** Wakeup Request Source ICU of VPE1 ++ Select signal ICU_IRQ of VPE1 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSICUVPE1 0x00000002 ++/* Not selected ++#define CPU0WCFG_WRSICUVPE1_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSICUVPE1_SEL 0x00000002 ++/** Wakeup Request Source ICU of VPE0 ++ Select signal ICU_IRQ of VPE0 as source for wakeup from sleep state. */ ++#define CPU0WCFG_WRSICUVPE0 0x00000001 ++/* Not selected ++#define CPU0WCFG_WRSICUVPE0_NSEL 0x00000000 */ ++/** Selected */ ++#define CPU0WCFG_WRSICUVPE0_SEL 0x00000001 ++ ++/* Fields of "Bootmode Control Register" */ ++/** Software Bootmode Select ++ Enables SW writing of Bootmode and shows whether or not the SW-programmed bootmode is reflected in field Bootmode instead of the hardware given value. */ ++#define BMC_BMSW 0x80000000 ++/* Disable ++#define BMC_BMSW_DIS 0x00000000 */ ++/** Enable */ ++#define BMC_BMSW_EN 0x80000000 ++/** Bootmode ++ Initially this field holds the value of the pinstraps LED_BMODEx on positions 5:0, and the value of the corresponding JTAG register bit on position 6. Writing is enabled by setting Software Bootmode Select to 1 during the write cycle. */ ++#define BMC_BM_MASK 0x0000007F ++/** field offset */ ++#define BMC_BM_OFFSET 0 ++ ++/* Fields of "Sleep Configuration Register" */ ++/** Enable XBAR Clockoff When All XBAR masters Clockoff ++ Enable XBAR clock shutdown in case all XBAR masters are in clockoff mode. This bit has no effect if bit CPU0 is not enabled. */ ++#define SCFG_XBAR 0x00010000 ++/* Disable ++#define SCFG_XBAR_DIS 0x00000000 */ ++/** Enable */ ++#define SCFG_XBAR_EN 0x00010000 ++/** CPU0 Clockoff On Sleep ++ Enable CPU0 clock shutdown in case its SI_SLEEP signal becomes active. */ ++#define SCFG_CPU0 0x00000001 ++/* Disable ++#define SCFG_CPU0_DIS 0x00000000 */ ++/** Enable */ ++#define SCFG_CPU0_EN 0x00000001 ++ ++/* Fields of "Power Down Configuration Register" */ ++/** Enable Power Down STATUS ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_STATUS 0x80000000 ++/* Disable ++#define PDCFG_STATUS_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_STATUS_EN 0x80000000 ++/** Enable Power Down SHA1 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_SHA1 0x40000000 ++/* Disable ++#define PDCFG_SHA1_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_SHA1_EN 0x40000000 ++/** Enable Power Down AES ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_AES 0x20000000 ++/* Disable ++#define PDCFG_AES_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_AES_EN 0x20000000 ++/** Enable Power Down PCM ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_PCM 0x10000000 ++/* Disable ++#define PDCFG_PCM_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_PCM_EN 0x10000000 ++/** Enable Power Down FSCT ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_FSCT 0x08000000 ++/* Disable ++#define PDCFG_FSCT_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_FSCT_EN 0x08000000 ++/** Enable Power Down GPTC ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_GPTC 0x04000000 ++/* Disable ++#define PDCFG_GPTC_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_GPTC_EN 0x04000000 ++/** Enable Power Down MPS ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_MPS 0x02000000 ++/* Disable ++#define PDCFG_MPS_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_MPS_EN 0x02000000 ++/** Enable Power Down DFEV0 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_DFEV0 0x01000000 ++/* Disable ++#define PDCFG_DFEV0_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_DFEV0_EN 0x01000000 ++/** Enable Power Down PADCTRL4 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_PADCTRL4 0x00400000 ++/* Disable ++#define PDCFG_PADCTRL4_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_PADCTRL4_EN 0x00400000 ++/** Enable Power Down PADCTRL3 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_PADCTRL3 0x00200000 ++/* Disable ++#define PDCFG_PADCTRL3_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_PADCTRL3_EN 0x00200000 ++/** Enable Power Down PADCTRL1 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_PADCTRL1 0x00100000 ++/* Disable ++#define PDCFG_PADCTRL1_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_PADCTRL1_EN 0x00100000 ++/** Enable Power Down P4 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_P4 0x00040000 ++/* Disable ++#define PDCFG_P4_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_P4_EN 0x00040000 ++/** Enable Power Down P3 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_P3 0x00020000 ++/* Disable ++#define PDCFG_P3_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_P3_EN 0x00020000 ++/** Enable Power Down P1 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_P1 0x00010000 ++/* Disable ++#define PDCFG_P1_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_P1_EN 0x00010000 ++/** Enable Power Down HOST ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_HOST 0x00008000 ++/* Disable ++#define PDCFG_HOST_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_HOST_EN 0x00008000 ++/** Enable Power Down I2C ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_I2C 0x00004000 ++/* Disable ++#define PDCFG_I2C_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_I2C_EN 0x00004000 ++/** Enable Power Down SSC0 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_SSC0 0x00002000 ++/* Disable ++#define PDCFG_SSC0_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_SSC0_EN 0x00002000 ++/** Enable Power Down ASC0 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_ASC0 0x00001000 ++/* Disable ++#define PDCFG_ASC0_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_ASC0_EN 0x00001000 ++/** Enable Power Down ASC1 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_ASC1 0x00000800 ++/* Disable ++#define PDCFG_ASC1_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_ASC1_EN 0x00000800 ++/** Enable Power Down DCDCAPD ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_DCDCAPD 0x00000400 ++/* Disable ++#define PDCFG_DCDCAPD_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_DCDCAPD_EN 0x00000400 ++/** Enable Power Down DCDCDDR ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_DCDCDDR 0x00000200 ++/* Disable ++#define PDCFG_DCDCDDR_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_DCDCDDR_EN 0x00000200 ++/** Enable Power Down DCDC1V0 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_DCDC1V0 0x00000100 ++/* Disable ++#define PDCFG_DCDC1V0_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_DCDC1V0_EN 0x00000100 ++/** Enable Power Down TRC2MEM ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_TRC2MEM 0x00000040 ++/* Disable ++#define PDCFG_TRC2MEM_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_TRC2MEM_EN 0x00000040 ++/** Enable Power Down DDR ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_DDR 0x00000020 ++/* Disable ++#define PDCFG_DDR_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_DDR_EN 0x00000020 ++/** Enable Power Down EBU ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define PDCFG_EBU 0x00000010 ++/* Disable ++#define PDCFG_EBU_DIS 0x00000000 */ ++/** Enable */ ++#define PDCFG_EBU_EN 0x00000010 ++ ++/* Fields of "CLKO Pad Control Register" */ ++/** Ethernet Reference Clock CLKO Select ++ Selects the CLKO pad's input as source for the GPHY, SGMII PLLs. */ ++#define CLKOC_ETHREF 0x00000002 ++/* Not selected ++#define CLKOC_ETHREF_NSEL 0x00000000 */ ++/** Selected */ ++#define CLKOC_ETHREF_SEL 0x00000002 ++/** Output Enable ++ Enables the output driver of the CLKO pad. */ ++#define CLKOC_OEN 0x00000001 ++/* Disable ++#define CLKOC_OEN_DIS 0x00000000 */ ++/** Enable */ ++#define CLKOC_OEN_EN 0x00000001 ++ ++/* Fields of "Infrastructure Control Register" */ ++/** General Purpose Control ++ Backup bits. Currently they are connected as: bit 0 : connected to the configmode_on pin of the pinstrapping block. bit 1 : clock enable of the GPE primary clock. bits 3:2 : frequency select of the GPE primary clock. 00 = 769.2MHz, 01 = 625MHz, 10 = 555.6MHz, 11 = 500MHz All other bits are unconnected. */ ++#define INFRAC_GP_MASK 0x1F000000 ++/** field offset */ ++#define INFRAC_GP_OFFSET 24 ++/** CMOS2CML Ethernet Control ++ CMOS2CML Ethernet Control. */ ++#define INFRAC_CMOS2CML_GPON_MASK 0x0000F000 ++/** field offset */ ++#define INFRAC_CMOS2CML_GPON_OFFSET 12 ++/** CMOS2CML Ethernet Control ++ CMOS2CML Ethernet Control. */ ++#define INFRAC_CMOS2CML_ETH_MASK 0x00000F00 ++/** field offset */ ++#define INFRAC_CMOS2CML_ETH_OFFSET 8 ++/** Dying Gasp Enable ++ Enables the dying gasp detector. */ ++#define INFRAC_DGASPEN 0x00000040 ++/* Disable ++#define INFRAC_DGASPEN_DIS 0x00000000 */ ++/** Enable */ ++#define INFRAC_DGASPEN_EN 0x00000040 ++/** Dying Gasp Hysteresis Control ++ Dying Gasp Hysteresis Control. */ ++#define INFRAC_DGASPHYS_MASK 0x00000030 ++/** field offset */ ++#define INFRAC_DGASPHYS_OFFSET 4 ++/** Linear Regulator 1.5V Enable ++ Enables 1.5V linear regulator. */ ++#define INFRAC_LIN1V5EN 0x00000008 ++/* Disable ++#define INFRAC_LIN1V5EN_DIS 0x00000000 */ ++/** Enable */ ++#define INFRAC_LIN1V5EN_EN 0x00000008 ++/** Linear Regulator 1.5V Control ++ Linear regulator 1.5V control. */ ++#define INFRAC_LIN1V5C_MASK 0x00000007 ++/** field offset */ ++#define INFRAC_LIN1V5C_OFFSET 0 ++ ++/* Fields of "HRST_OUT_N Control Register" */ ++/** HRST_OUT_N Pin Value ++ Controls the value of the HRST_OUT_N pin. */ ++#define HRSTOUTC_VALUE 0x00000001 ++ ++/* Fields of "EBU Clock Control Register" */ ++/** EBU Clock Divider ++ Via this bit the frequency of the clock of the EBU can be selected. */ ++#define EBUCC_EBUDIV 0x00000001 ++/* Frequency set to 50MHz. ++#define EBUCC_EBUDIV_SELF50 0x00000000 */ ++/** Frequency set to 100MHz. */ ++#define EBUCC_EBUDIV_SELF100 0x00000001 ++ ++/* Fields of "NMI Status Register" */ ++/** NMI Status Flag TEST ++ Shows whether the event NMI TEST occurred. */ ++#define NMIS_TEST 0x00000100 ++/* Nothing ++#define NMIS_TEST_NULL 0x00000000 */ ++/** Read: Event occurred. */ ++#define NMIS_TEST_EVOCC 0x00000100 ++/** NMI Status Flag DGASP ++ Shows whether the event NMI DGASP occurred. */ ++#define NMIS_DGASP 0x00000004 ++/* Nothing ++#define NMIS_DGASP_NULL 0x00000000 */ ++/** Read: Event occurred. */ ++#define NMIS_DGASP_EVOCC 0x00000004 ++/** NMI Status Flag HOST ++ Shows whether the event NMI HOST occurred. */ ++#define NMIS_HOST 0x00000002 ++/* Nothing ++#define NMIS_HOST_NULL 0x00000000 */ ++/** Read: Event occurred. */ ++#define NMIS_HOST_EVOCC 0x00000002 ++/** NMI Status Flag PIN ++ Shows whether the event NMI PIN occurred. */ ++#define NMIS_PIN 0x00000001 ++/* Nothing ++#define NMIS_PIN_NULL 0x00000000 */ ++/** Read: Event occurred. */ ++#define NMIS_PIN_EVOCC 0x00000001 ++ ++/* Fields of "NMI Set Register" */ ++/** Set NMI Status Flag TEST ++ Sets the corresponding NMI status flag. */ ++#define NMISET_TEST 0x00000100 ++/* Nothing ++#define NMISET_TEST_NULL 0x00000000 */ ++/** Set */ ++#define NMISET_TEST_SET 0x00000100 ++/** Set NMI Status Flag DGASP ++ Sets the corresponding NMI status flag. */ ++#define NMISET_DGASP 0x00000004 ++/* Nothing ++#define NMISET_DGASP_NULL 0x00000000 */ ++/** Set */ ++#define NMISET_DGASP_SET 0x00000004 ++/** Set NMI Status Flag HOST ++ Sets the corresponding NMI status flag. */ ++#define NMISET_HOST 0x00000002 ++/* Nothing ++#define NMISET_HOST_NULL 0x00000000 */ ++/** Set */ ++#define NMISET_HOST_SET 0x00000002 ++/** Set NMI Status Flag PIN ++ Sets the corresponding NMI status flag. */ ++#define NMISET_PIN 0x00000001 ++/* Nothing ++#define NMISET_PIN_NULL 0x00000000 */ ++/** Set */ ++#define NMISET_PIN_SET 0x00000001 ++ ++/* Fields of "NMI Clear Register" */ ++/** Clear NMI Status Flag TEST ++ Clears the corresponding NMI status flag. */ ++#define NMICLR_TEST 0x00000100 ++/* Nothing ++#define NMICLR_TEST_NULL 0x00000000 */ ++/** Clear */ ++#define NMICLR_TEST_CLR 0x00000100 ++/** Clear NMI Status Flag DGASP ++ Clears the corresponding NMI status flag. */ ++#define NMICLR_DGASP 0x00000004 ++/* Nothing ++#define NMICLR_DGASP_NULL 0x00000000 */ ++/** Clear */ ++#define NMICLR_DGASP_CLR 0x00000004 ++/** Clear NMI Status Flag HOST ++ Clears the corresponding NMI status flag. */ ++#define NMICLR_HOST 0x00000002 ++/* Nothing ++#define NMICLR_HOST_NULL 0x00000000 */ ++/** Clear */ ++#define NMICLR_HOST_CLR 0x00000002 ++/** Clear NMI Status Flag PIN ++ Clears the corresponding NMI status flag. */ ++#define NMICLR_PIN 0x00000001 ++/* Nothing ++#define NMICLR_PIN_NULL 0x00000000 */ ++/** Clear */ ++#define NMICLR_PIN_CLR 0x00000001 ++ ++/* Fields of "NMI Test Configuration Register" */ ++/** Enable NMI Test Feature ++ Enables the operation of the NMI TEST flag. This is the mask for the Non-Maskable-Interrupt dedicated to SW tests. All others cannot be masked. */ ++#define NMITCFG_TEN 0x00000100 ++/* Disable ++#define NMITCFG_TEN_DIS 0x00000000 */ ++/** Enable */ ++#define NMITCFG_TEN_EN 0x00000100 ++ ++/* Fields of "NMI VPE1 Control Register" */ ++/** NMI VPE1 State ++ Reflects the state of the NMI signal towards VPE1. This bit is controlled by software only, there is no hardware NMI source dedicated to VPE1. So VPE0 could trigger an NMI at VPE1 using this bit in its own NMI-routine. */ ++#define NMIVPE1C_NMI 0x00000001 ++/* False ++#define NMIVPE1C_NMI_FALSE 0x00000000 */ ++/** True */ ++#define NMIVPE1C_NMI_TRUE 0x00000001 ++ ++/* Fields of "IRN Capture Register" */ ++/** DCDCAPD Alarm ++ The DCDC Converter for the APD Supply submitted an alarm. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define IRNCR_DCDCAPD 0x00400000 ++/* Nothing ++#define IRNCR_DCDCAPD_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define IRNCR_DCDCAPD_INTACK 0x00400000 ++/** Read: Interrupt occurred. */ ++#define IRNCR_DCDCAPD_INTOCC 0x00400000 ++/** DCDCDDR Alarm ++ The DCDC Converter for the DDR Supply submitted an alarm. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define IRNCR_DCDCDDR 0x00200000 ++/* Nothing ++#define IRNCR_DCDCDDR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define IRNCR_DCDCDDR_INTACK 0x00200000 ++/** Read: Interrupt occurred. */ ++#define IRNCR_DCDCDDR_INTOCC 0x00200000 ++/** DCDC1V0 Alarm ++ The DCDC Converter for the 1.0 Volts submitted an alarm. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define IRNCR_DCDC1V0 0x00100000 ++/* Nothing ++#define IRNCR_DCDC1V0_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define IRNCR_DCDC1V0_INTACK 0x00100000 ++/** Read: Interrupt occurred. */ ++#define IRNCR_DCDC1V0_INTOCC 0x00100000 ++/** SIF0 wakeup request ++ SmartSlic Interface 0 submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define IRNCR_SIF0 0x00010000 ++/* Nothing ++#define IRNCR_SIF0_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define IRNCR_SIF0_INTACK 0x00010000 ++/** Read: Interrupt occurred. */ ++#define IRNCR_SIF0_INTOCC 0x00010000 ++ ++/* Fields of "IRN Interrupt Control Register" */ ++/** DCDCAPD Alarm ++ Interrupt control bit for the corresponding bit in the IRNCR register. */ ++#define IRNICR_DCDCAPD 0x00400000 ++/** DCDCDDR Alarm ++ Interrupt control bit for the corresponding bit in the IRNCR register. */ ++#define IRNICR_DCDCDDR 0x00200000 ++/** DCDC1V0 Alarm ++ Interrupt control bit for the corresponding bit in the IRNCR register. */ ++#define IRNICR_DCDC1V0 0x00100000 ++/** SIF0 wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCR register. */ ++#define IRNICR_SIF0 0x00010000 ++ ++/* Fields of "IRN Interrupt Enable Register" */ ++/** DCDCAPD Alarm ++ Interrupt enable bit for the corresponding bit in the IRNCR register. */ ++#define IRNEN_DCDCAPD 0x00400000 ++/* Disable ++#define IRNEN_DCDCAPD_DIS 0x00000000 */ ++/** Enable */ ++#define IRNEN_DCDCAPD_EN 0x00400000 ++/** DCDCDDR Alarm ++ Interrupt enable bit for the corresponding bit in the IRNCR register. */ ++#define IRNEN_DCDCDDR 0x00200000 ++/* Disable ++#define IRNEN_DCDCDDR_DIS 0x00000000 */ ++/** Enable */ ++#define IRNEN_DCDCDDR_EN 0x00200000 ++/** DCDC1V0 Alarm ++ Interrupt enable bit for the corresponding bit in the IRNCR register. */ ++#define IRNEN_DCDC1V0 0x00100000 ++/* Disable ++#define IRNEN_DCDC1V0_DIS 0x00000000 */ ++/** Enable */ ++#define IRNEN_DCDC1V0_EN 0x00100000 ++/** SIF0 wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCR register. */ ++#define IRNEN_SIF0 0x00010000 ++/* Disable ++#define IRNEN_SIF0_DIS 0x00000000 */ ++/** Enable */ ++#define IRNEN_SIF0_EN 0x00010000 ++ ++/*! @} */ /* SYS1_REGISTER */ ++ ++#endif /* _sys1_reg_h */ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/sys_eth_reg.h +@@ -0,0 +1,1132 @@ ++/****************************************************************************** ++ ++ Copyright (c) 2010 ++ Lantiq Deutschland GmbH ++ ++ For licensing information, see the file 'LICENSE' in the root folder of ++ this software module. ++ ++******************************************************************************/ ++ ++#ifndef _sys_eth_reg_h ++#define _sys_eth_reg_h ++ ++/** \addtogroup SYS_ETH_REGISTER ++ @{ ++*/ ++/* access macros */ ++#define sys_eth_r32(reg) reg_r32(&sys_eth->reg) ++#define sys_eth_w32(val, reg) reg_w32(val, &sys_eth->reg) ++#define sys_eth_w32_mask(clear, set, reg) reg_w32_mask(clear, set, &sys_eth->reg) ++#define sys_eth_r32_table(reg, idx) reg_r32_table(sys_eth->reg, idx) ++#define sys_eth_w32_table(val, reg, idx) reg_w32_table(val, sys_eth->reg, idx) ++#define sys_eth_w32_table_mask(clear, set, reg, idx) reg_w32_table_mask(clear, set, sys_eth->reg, idx) ++#define sys_eth_adr_table(reg, idx) adr_table(sys_eth->reg, idx) ++ ++ ++/** SYS_ETH register structure */ ++struct gpon_reg_sys_eth ++{ ++ /** Clock Status Register */ ++ unsigned int clks; /* 0x00000000 */ ++ /** Clock Enable Register ++ Via this register the clocks for the domains can be enabled. */ ++ unsigned int clken; /* 0x00000004 */ ++ /** Clock Clear Register ++ Via this register the clocks for the domains can be disabled. */ ++ unsigned int clkclr; /* 0x00000008 */ ++ /** Reserved */ ++ unsigned int res_0[5]; /* 0x0000000C */ ++ /** Activation Status Register */ ++ unsigned int acts; /* 0x00000020 */ ++ /** Activation Register ++ Via this register the domains can be activated. */ ++ unsigned int act; /* 0x00000024 */ ++ /** Deactivation Register ++ Via this register the domains can be deactivated. */ ++ unsigned int deact; /* 0x00000028 */ ++ /** Reboot Trigger Register ++ Via this register the domains can be rebooted (sent through reset). */ ++ unsigned int rbt; /* 0x0000002C */ ++ /** Reserved */ ++ unsigned int res_1[32]; /* 0x00000030 */ ++ /** External PHY Control Register */ ++ unsigned int extphyc; /* 0x000000B0 */ ++ /** Power Down Configuration Register ++ Via this register the configuration is done whether in case of deactivation the power supply of the domain shall be removed. */ ++ unsigned int pdcfg; /* 0x000000B4 */ ++ /** Datarate Control Register ++ Controls the datarate of the various physical layers. The contents of the writeable fields of this register shall not be changed during operation. */ ++ unsigned int drc; /* 0x000000B8 */ ++ /** GMAC Multiplexer Control Register ++ Controls the interconnect between GMACs and the various physical layers. All fields need to have a different content. If two GMACs are muxed to the same PHY unpredictable results may occur. The contents of this register shall not be changed during operation. */ ++ unsigned int gmuxc; /* 0x000000BC */ ++ /** Datarate Status Register ++ Shows the datarate of the GMACs. The datarate of a GMAC is derived from the datarate of the physical layer it is multiplexed to. This register is for debugging only. */ ++ unsigned int drs; /* 0x000000C0 */ ++ /** SGMII Control Register */ ++ unsigned int sgmiic; /* 0x000000C4 */ ++ /** Reserved */ ++ unsigned int res_2[14]; /* 0x000000C8 */ ++}; ++ ++ ++/* Fields of "Clock Status Register" */ ++/** GPHY1MII2 Clock Enable ++ Shows the clock enable bit for GPHY1MII2. */ ++#define SYS_ETH_CLKS_GPHY1MII2 0x02000000 ++/* Disable ++#define SYS_ETH_CLKS_GPHY1MII2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_GPHY1MII2_EN 0x02000000 ++/** GPHY0MII2 Clock Enable ++ Shows the clock enable bit for GPHY0MII2. */ ++#define SYS_ETH_CLKS_GPHY0MII2 0x01000000 ++/* Disable ++#define SYS_ETH_CLKS_GPHY0MII2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_GPHY0MII2_EN 0x01000000 ++/** PADCTRL2 Clock Enable ++ Shows the clock enable bit for the PADCTRL2 domain. This domain contains the PADCTRL2 block. */ ++#define SYS_ETH_CLKS_PADCTRL2 0x00200000 ++/* Disable ++#define SYS_ETH_CLKS_PADCTRL2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_PADCTRL2_EN 0x00200000 ++/** PADCTRL0 Clock Enable ++ Shows the clock enable bit for the PADCTRL0 domain. This domain contains the PADCTRL0 block. */ ++#define SYS_ETH_CLKS_PADCTRL0 0x00100000 ++/* Disable ++#define SYS_ETH_CLKS_PADCTRL0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_PADCTRL0_EN 0x00100000 ++/** P2 Clock Enable ++ Shows the clock enable bit for the P2 domain. This domain contains the P2 instance of the GPIO block. */ ++#define SYS_ETH_CLKS_P2 0x00020000 ++/* Disable ++#define SYS_ETH_CLKS_P2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_P2_EN 0x00020000 ++/** P0 Clock Enable ++ Shows the clock enable bit for the P0 domain. This domain contains the P0 instance of the GPIO block. */ ++#define SYS_ETH_CLKS_P0 0x00010000 ++/* Disable ++#define SYS_ETH_CLKS_P0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_P0_EN 0x00010000 ++/** xMII Clock Enable ++ Shows the clock enable bit for the xMII domain. This domain contains the XMII block. If any of the digital LAN interfaces shall be used, this domain has to be active. */ ++#define SYS_ETH_CLKS_xMII 0x00000800 ++/* Disable ++#define SYS_ETH_CLKS_xMII_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_xMII_EN 0x00000800 ++/** SGMII Clock Enable ++ Shows the clock enable bit for the SGMII domain. This domain contains all parts of the EIM related to the SGMII block. The SGMII block itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_CLKS_SGMII 0x00000400 ++/* Disable ++#define SYS_ETH_CLKS_SGMII_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_SGMII_EN 0x00000400 ++/** GPHY1 Clock Enable ++ Shows the clock enable bit for the GPHY1 domain. This domain contains all parts of the EIM related to GPHY1. The GPHY1 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_CLKS_GPHY1 0x00000200 ++/* Disable ++#define SYS_ETH_CLKS_GPHY1_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_GPHY1_EN 0x00000200 ++/** GPHY0 Clock Enable ++ Shows the clock enable bit for the GPHY0 domain. This domain contains all parts of the EIM related to GPHY0. The GPHY0 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_CLKS_GPHY0 0x00000100 ++/* Disable ++#define SYS_ETH_CLKS_GPHY0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_GPHY0_EN 0x00000100 ++/** MDIO Clock Enable ++ Shows the clock enable bit for the MDIO domain. This domain contains the MDIO block. */ ++#define SYS_ETH_CLKS_MDIO 0x00000080 ++/* Disable ++#define SYS_ETH_CLKS_MDIO_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_MDIO_EN 0x00000080 ++/** GMAC3 Clock Enable ++ Shows the clock enable bit for the GMAC3 domain. This domain contains the GMAC3 block. */ ++#define SYS_ETH_CLKS_GMAC3 0x00000008 ++/* Disable ++#define SYS_ETH_CLKS_GMAC3_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_GMAC3_EN 0x00000008 ++/** GMAC2 Clock Enable ++ Shows the clock enable bit for the GMAC2 domain. This domain contains the GMAC2 block. */ ++#define SYS_ETH_CLKS_GMAC2 0x00000004 ++/* Disable ++#define SYS_ETH_CLKS_GMAC2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_GMAC2_EN 0x00000004 ++/** GMAC1 Clock Enable ++ Shows the clock enable bit for the GMAC1 domain. This domain contains the GMAC1 block. */ ++#define SYS_ETH_CLKS_GMAC1 0x00000002 ++/* Disable ++#define SYS_ETH_CLKS_GMAC1_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_GMAC1_EN 0x00000002 ++/** GMAC0 Clock Enable ++ Shows the clock enable bit for the GMAC0 domain. This domain contains the GMAC0 block. */ ++#define SYS_ETH_CLKS_GMAC0 0x00000001 ++/* Disable ++#define SYS_ETH_CLKS_GMAC0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_CLKS_GMAC0_EN 0x00000001 ++ ++/* Fields of "Clock Enable Register" */ ++/** Set Clock Enable GPHY1MII2 ++ Sets the clock enable bit of the GPHY1MII2. */ ++#define SYS_ETH_CLKEN_GPHY1MII2 0x02000000 ++/* No-Operation ++#define SYS_ETH_CLKEN_GPHY1MII2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_GPHY1MII2_SET 0x02000000 ++/** Set Clock Enable GPHY0MII2 ++ Sets the clock enable bit of the GPHY0MII2. */ ++#define SYS_ETH_CLKEN_GPHY0MII2 0x01000000 ++/* No-Operation ++#define SYS_ETH_CLKEN_GPHY0MII2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_GPHY0MII2_SET 0x01000000 ++/** Set Clock Enable PADCTRL2 ++ Sets the clock enable bit of the PADCTRL2 domain. This domain contains the PADCTRL2 block. */ ++#define SYS_ETH_CLKEN_PADCTRL2 0x00200000 ++/* No-Operation ++#define SYS_ETH_CLKEN_PADCTRL2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_PADCTRL2_SET 0x00200000 ++/** Set Clock Enable PADCTRL0 ++ Sets the clock enable bit of the PADCTRL0 domain. This domain contains the PADCTRL0 block. */ ++#define SYS_ETH_CLKEN_PADCTRL0 0x00100000 ++/* No-Operation ++#define SYS_ETH_CLKEN_PADCTRL0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_PADCTRL0_SET 0x00100000 ++/** Set Clock Enable P2 ++ Sets the clock enable bit of the P2 domain. This domain contains the P2 instance of the GPIO block. */ ++#define SYS_ETH_CLKEN_P2 0x00020000 ++/* No-Operation ++#define SYS_ETH_CLKEN_P2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_P2_SET 0x00020000 ++/** Set Clock Enable P0 ++ Sets the clock enable bit of the P0 domain. This domain contains the P0 instance of the GPIO block. */ ++#define SYS_ETH_CLKEN_P0 0x00010000 ++/* No-Operation ++#define SYS_ETH_CLKEN_P0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_P0_SET 0x00010000 ++/** Set Clock Enable xMII ++ Sets the clock enable bit of the xMII domain. This domain contains the XMII block. If any of the digital LAN interfaces shall be used, this domain has to be active. */ ++#define SYS_ETH_CLKEN_xMII 0x00000800 ++/* No-Operation ++#define SYS_ETH_CLKEN_xMII_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_xMII_SET 0x00000800 ++/** Set Clock Enable SGMII ++ Sets the clock enable bit of the SGMII domain. This domain contains all parts of the EIM related to the SGMII block. The SGMII block itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_CLKEN_SGMII 0x00000400 ++/* No-Operation ++#define SYS_ETH_CLKEN_SGMII_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_SGMII_SET 0x00000400 ++/** Set Clock Enable GPHY1 ++ Sets the clock enable bit of the GPHY1 domain. This domain contains all parts of the EIM related to GPHY1. The GPHY1 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_CLKEN_GPHY1 0x00000200 ++/* No-Operation ++#define SYS_ETH_CLKEN_GPHY1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_GPHY1_SET 0x00000200 ++/** Set Clock Enable GPHY0 ++ Sets the clock enable bit of the GPHY0 domain. This domain contains all parts of the EIM related to GPHY0. The GPHY0 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_CLKEN_GPHY0 0x00000100 ++/* No-Operation ++#define SYS_ETH_CLKEN_GPHY0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_GPHY0_SET 0x00000100 ++/** Set Clock Enable MDIO ++ Sets the clock enable bit of the MDIO domain. This domain contains the MDIO block. */ ++#define SYS_ETH_CLKEN_MDIO 0x00000080 ++/* No-Operation ++#define SYS_ETH_CLKEN_MDIO_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_MDIO_SET 0x00000080 ++/** Set Clock Enable GMAC3 ++ Sets the clock enable bit of the GMAC3 domain. This domain contains the GMAC3 block. */ ++#define SYS_ETH_CLKEN_GMAC3 0x00000008 ++/* No-Operation ++#define SYS_ETH_CLKEN_GMAC3_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_GMAC3_SET 0x00000008 ++/** Set Clock Enable GMAC2 ++ Sets the clock enable bit of the GMAC2 domain. This domain contains the GMAC2 block. */ ++#define SYS_ETH_CLKEN_GMAC2 0x00000004 ++/* No-Operation ++#define SYS_ETH_CLKEN_GMAC2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_GMAC2_SET 0x00000004 ++/** Set Clock Enable GMAC1 ++ Sets the clock enable bit of the GMAC1 domain. This domain contains the GMAC1 block. */ ++#define SYS_ETH_CLKEN_GMAC1 0x00000002 ++/* No-Operation ++#define SYS_ETH_CLKEN_GMAC1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_GMAC1_SET 0x00000002 ++/** Set Clock Enable GMAC0 ++ Sets the clock enable bit of the GMAC0 domain. This domain contains the GMAC0 block. */ ++#define SYS_ETH_CLKEN_GMAC0 0x00000001 ++/* No-Operation ++#define SYS_ETH_CLKEN_GMAC0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_CLKEN_GMAC0_SET 0x00000001 ++ ++/* Fields of "Clock Clear Register" */ ++/** Clear Clock Enable GPHY1MII2 ++ Clears the clock enable bit of the GPHY1MII2. */ ++#define SYS_ETH_CLKCLR_GPHY1MII2 0x02000000 ++/* No-Operation ++#define SYS_ETH_CLKCLR_GPHY1MII2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_GPHY1MII2_CLR 0x02000000 ++/** Clear Clock Enable GPHY0MII2 ++ Clears the clock enable bit of the GPHY0MII2. */ ++#define SYS_ETH_CLKCLR_GPHY0MII2 0x01000000 ++/* No-Operation ++#define SYS_ETH_CLKCLR_GPHY0MII2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_GPHY0MII2_CLR 0x01000000 ++/** Clear Clock Enable PADCTRL2 ++ Clears the clock enable bit of the PADCTRL2 domain. This domain contains the PADCTRL2 block. */ ++#define SYS_ETH_CLKCLR_PADCTRL2 0x00200000 ++/* No-Operation ++#define SYS_ETH_CLKCLR_PADCTRL2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_PADCTRL2_CLR 0x00200000 ++/** Clear Clock Enable PADCTRL0 ++ Clears the clock enable bit of the PADCTRL0 domain. This domain contains the PADCTRL0 block. */ ++#define SYS_ETH_CLKCLR_PADCTRL0 0x00100000 ++/* No-Operation ++#define SYS_ETH_CLKCLR_PADCTRL0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_PADCTRL0_CLR 0x00100000 ++/** Clear Clock Enable P2 ++ Clears the clock enable bit of the P2 domain. This domain contains the P2 instance of the GPIO block. */ ++#define SYS_ETH_CLKCLR_P2 0x00020000 ++/* No-Operation ++#define SYS_ETH_CLKCLR_P2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_P2_CLR 0x00020000 ++/** Clear Clock Enable P0 ++ Clears the clock enable bit of the P0 domain. This domain contains the P0 instance of the GPIO block. */ ++#define SYS_ETH_CLKCLR_P0 0x00010000 ++/* No-Operation ++#define SYS_ETH_CLKCLR_P0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_P0_CLR 0x00010000 ++/** Clear Clock Enable xMII ++ Clears the clock enable bit of the xMII domain. This domain contains the XMII block. If any of the digital LAN interfaces shall be used, this domain has to be active. */ ++#define SYS_ETH_CLKCLR_xMII 0x00000800 ++/* No-Operation ++#define SYS_ETH_CLKCLR_xMII_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_xMII_CLR 0x00000800 ++/** Clear Clock Enable SGMII ++ Clears the clock enable bit of the SGMII domain. This domain contains all parts of the EIM related to the SGMII block. The SGMII block itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_CLKCLR_SGMII 0x00000400 ++/* No-Operation ++#define SYS_ETH_CLKCLR_SGMII_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_SGMII_CLR 0x00000400 ++/** Clear Clock Enable GPHY1 ++ Clears the clock enable bit of the GPHY1 domain. This domain contains all parts of the EIM related to GPHY1. The GPHY1 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_CLKCLR_GPHY1 0x00000200 ++/* No-Operation ++#define SYS_ETH_CLKCLR_GPHY1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_GPHY1_CLR 0x00000200 ++/** Clear Clock Enable GPHY0 ++ Clears the clock enable bit of the GPHY0 domain. This domain contains all parts of the EIM related to GPHY0. The GPHY0 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_CLKCLR_GPHY0 0x00000100 ++/* No-Operation ++#define SYS_ETH_CLKCLR_GPHY0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_GPHY0_CLR 0x00000100 ++/** Clear Clock Enable MDIO ++ Clears the clock enable bit of the MDIO domain. This domain contains the MDIO block. */ ++#define SYS_ETH_CLKCLR_MDIO 0x00000080 ++/* No-Operation ++#define SYS_ETH_CLKCLR_MDIO_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_MDIO_CLR 0x00000080 ++/** Clear Clock Enable GMAC3 ++ Clears the clock enable bit of the GMAC3 domain. This domain contains the GMAC3 block. */ ++#define SYS_ETH_CLKCLR_GMAC3 0x00000008 ++/* No-Operation ++#define SYS_ETH_CLKCLR_GMAC3_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_GMAC3_CLR 0x00000008 ++/** Clear Clock Enable GMAC2 ++ Clears the clock enable bit of the GMAC2 domain. This domain contains the GMAC2 block. */ ++#define SYS_ETH_CLKCLR_GMAC2 0x00000004 ++/* No-Operation ++#define SYS_ETH_CLKCLR_GMAC2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_GMAC2_CLR 0x00000004 ++/** Clear Clock Enable GMAC1 ++ Clears the clock enable bit of the GMAC1 domain. This domain contains the GMAC1 block. */ ++#define SYS_ETH_CLKCLR_GMAC1 0x00000002 ++/* No-Operation ++#define SYS_ETH_CLKCLR_GMAC1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_GMAC1_CLR 0x00000002 ++/** Clear Clock Enable GMAC0 ++ Clears the clock enable bit of the GMAC0 domain. This domain contains the GMAC0 block. */ ++#define SYS_ETH_CLKCLR_GMAC0 0x00000001 ++/* No-Operation ++#define SYS_ETH_CLKCLR_GMAC0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_CLKCLR_GMAC0_CLR 0x00000001 ++ ++/* Fields of "Activation Status Register" */ ++/** PADCTRL2 Status ++ Shows the activation status of the PADCTRL2 domain. This domain contains the PADCTRL2 block. */ ++#define SYS_ETH_ACTS_PADCTRL2 0x00200000 ++/* The block is inactive. ++#define SYS_ETH_ACTS_PADCTRL2_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_PADCTRL2_ACT 0x00200000 ++/** PADCTRL0 Status ++ Shows the activation status of the PADCTRL0 domain. This domain contains the PADCTRL0 block. */ ++#define SYS_ETH_ACTS_PADCTRL0 0x00100000 ++/* The block is inactive. ++#define SYS_ETH_ACTS_PADCTRL0_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_PADCTRL0_ACT 0x00100000 ++/** P2 Status ++ Shows the activation status of the P2 domain. This domain contains the P2 instance of the GPIO block. */ ++#define SYS_ETH_ACTS_P2 0x00020000 ++/* The block is inactive. ++#define SYS_ETH_ACTS_P2_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_P2_ACT 0x00020000 ++/** P0 Status ++ Shows the activation status of the P0 domain. This domain contains the P0 instance of the GPIO block. */ ++#define SYS_ETH_ACTS_P0 0x00010000 ++/* The block is inactive. ++#define SYS_ETH_ACTS_P0_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_P0_ACT 0x00010000 ++/** xMII Status ++ Shows the activation status of the xMII domain. This domain contains the XMII block. If any of the digital LAN interfaces shall be used, this domain has to be active. */ ++#define SYS_ETH_ACTS_xMII 0x00000800 ++/* The block is inactive. ++#define SYS_ETH_ACTS_xMII_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_xMII_ACT 0x00000800 ++/** SGMII Status ++ Shows the activation status of the SGMII domain. This domain contains all parts of the EIM related to the SGMII block. The SGMII block itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_ACTS_SGMII 0x00000400 ++/* The block is inactive. ++#define SYS_ETH_ACTS_SGMII_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_SGMII_ACT 0x00000400 ++/** GPHY1 Status ++ Shows the activation status of the GPHY1 domain. This domain contains all parts of the EIM related to GPHY1. The GPHY1 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_ACTS_GPHY1 0x00000200 ++/* The block is inactive. ++#define SYS_ETH_ACTS_GPHY1_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_GPHY1_ACT 0x00000200 ++/** GPHY0 Status ++ Shows the activation status of the GPHY0 domain. This domain contains all parts of the EIM related to GPHY0. The GPHY0 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_ACTS_GPHY0 0x00000100 ++/* The block is inactive. ++#define SYS_ETH_ACTS_GPHY0_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_GPHY0_ACT 0x00000100 ++/** MDIO Status ++ Shows the activation status of the MDIO domain. This domain contains the MDIO block. */ ++#define SYS_ETH_ACTS_MDIO 0x00000080 ++/* The block is inactive. ++#define SYS_ETH_ACTS_MDIO_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_MDIO_ACT 0x00000080 ++/** GMAC3 Status ++ Shows the activation status of the GMAC3 domain. This domain contains the GMAC3 block. */ ++#define SYS_ETH_ACTS_GMAC3 0x00000008 ++/* The block is inactive. ++#define SYS_ETH_ACTS_GMAC3_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_GMAC3_ACT 0x00000008 ++/** GMAC2 Status ++ Shows the activation status of the GMAC2 domain. This domain contains the GMAC2 block. */ ++#define SYS_ETH_ACTS_GMAC2 0x00000004 ++/* The block is inactive. ++#define SYS_ETH_ACTS_GMAC2_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_GMAC2_ACT 0x00000004 ++/** GMAC1 Status ++ Shows the activation status of the GMAC1 domain. This domain contains the GMAC1 block. */ ++#define SYS_ETH_ACTS_GMAC1 0x00000002 ++/* The block is inactive. ++#define SYS_ETH_ACTS_GMAC1_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_GMAC1_ACT 0x00000002 ++/** GMAC0 Status ++ Shows the activation status of the GMAC0 domain. This domain contains the GMAC0 block. */ ++#define SYS_ETH_ACTS_GMAC0 0x00000001 ++/* The block is inactive. ++#define SYS_ETH_ACTS_GMAC0_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_ETH_ACTS_GMAC0_ACT 0x00000001 ++ ++/* Fields of "Activation Register" */ ++/** Activate PADCTRL2 ++ Sets the activation flag of the PADCTRL2 domain. This domain contains the PADCTRL2 block. */ ++#define SYS_ETH_ACT_PADCTRL2 0x00200000 ++/* No-Operation ++#define SYS_ETH_ACT_PADCTRL2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_PADCTRL2_SET 0x00200000 ++/** Activate PADCTRL0 ++ Sets the activation flag of the PADCTRL0 domain. This domain contains the PADCTRL0 block. */ ++#define SYS_ETH_ACT_PADCTRL0 0x00100000 ++/* No-Operation ++#define SYS_ETH_ACT_PADCTRL0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_PADCTRL0_SET 0x00100000 ++/** Activate P2 ++ Sets the activation flag of the P2 domain. This domain contains the P2 instance of the GPIO block. */ ++#define SYS_ETH_ACT_P2 0x00020000 ++/* No-Operation ++#define SYS_ETH_ACT_P2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_P2_SET 0x00020000 ++/** Activate P0 ++ Sets the activation flag of the P0 domain. This domain contains the P0 instance of the GPIO block. */ ++#define SYS_ETH_ACT_P0 0x00010000 ++/* No-Operation ++#define SYS_ETH_ACT_P0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_P0_SET 0x00010000 ++/** Activate xMII ++ Sets the activation flag of the xMII domain. This domain contains the XMII block. If any of the digital LAN interfaces shall be used, this domain has to be active. */ ++#define SYS_ETH_ACT_xMII 0x00000800 ++/* No-Operation ++#define SYS_ETH_ACT_xMII_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_xMII_SET 0x00000800 ++/** Activate SGMII ++ Sets the activation flag of the SGMII domain. This domain contains all parts of the EIM related to the SGMII block. The SGMII block itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_ACT_SGMII 0x00000400 ++/* No-Operation ++#define SYS_ETH_ACT_SGMII_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_SGMII_SET 0x00000400 ++/** Activate GPHY1 ++ Sets the activation flag of the GPHY1 domain. This domain contains all parts of the EIM related to GPHY1. The GPHY1 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_ACT_GPHY1 0x00000200 ++/* No-Operation ++#define SYS_ETH_ACT_GPHY1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_GPHY1_SET 0x00000200 ++/** Activate GPHY0 ++ Sets the activation flag of the GPHY0 domain. This domain contains all parts of the EIM related to GPHY0. The GPHY0 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_ACT_GPHY0 0x00000100 ++/* No-Operation ++#define SYS_ETH_ACT_GPHY0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_GPHY0_SET 0x00000100 ++/** Activate MDIO ++ Sets the activation flag of the MDIO domain. This domain contains the MDIO block. */ ++#define SYS_ETH_ACT_MDIO 0x00000080 ++/* No-Operation ++#define SYS_ETH_ACT_MDIO_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_MDIO_SET 0x00000080 ++/** Activate GMAC3 ++ Sets the activation flag of the GMAC3 domain. This domain contains the GMAC3 block. */ ++#define SYS_ETH_ACT_GMAC3 0x00000008 ++/* No-Operation ++#define SYS_ETH_ACT_GMAC3_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_GMAC3_SET 0x00000008 ++/** Activate GMAC2 ++ Sets the activation flag of the GMAC2 domain. This domain contains the GMAC2 block. */ ++#define SYS_ETH_ACT_GMAC2 0x00000004 ++/* No-Operation ++#define SYS_ETH_ACT_GMAC2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_GMAC2_SET 0x00000004 ++/** Activate GMAC1 ++ Sets the activation flag of the GMAC1 domain. This domain contains the GMAC1 block. */ ++#define SYS_ETH_ACT_GMAC1 0x00000002 ++/* No-Operation ++#define SYS_ETH_ACT_GMAC1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_GMAC1_SET 0x00000002 ++/** Activate GMAC0 ++ Sets the activation flag of the GMAC0 domain. This domain contains the GMAC0 block. */ ++#define SYS_ETH_ACT_GMAC0 0x00000001 ++/* No-Operation ++#define SYS_ETH_ACT_GMAC0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_ETH_ACT_GMAC0_SET 0x00000001 ++ ++/* Fields of "Deactivation Register" */ ++/** Deactivate PADCTRL2 ++ Clears the activation flag of the PADCTRL2 domain. This domain contains the PADCTRL2 block. */ ++#define SYS_ETH_DEACT_PADCTRL2 0x00200000 ++/* No-Operation ++#define SYS_ETH_DEACT_PADCTRL2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_PADCTRL2_CLR 0x00200000 ++/** Deactivate PADCTRL0 ++ Clears the activation flag of the PADCTRL0 domain. This domain contains the PADCTRL0 block. */ ++#define SYS_ETH_DEACT_PADCTRL0 0x00100000 ++/* No-Operation ++#define SYS_ETH_DEACT_PADCTRL0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_PADCTRL0_CLR 0x00100000 ++/** Deactivate P2 ++ Clears the activation flag of the P2 domain. This domain contains the P2 instance of the GPIO block. */ ++#define SYS_ETH_DEACT_P2 0x00020000 ++/* No-Operation ++#define SYS_ETH_DEACT_P2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_P2_CLR 0x00020000 ++/** Deactivate P0 ++ Clears the activation flag of the P0 domain. This domain contains the P0 instance of the GPIO block. */ ++#define SYS_ETH_DEACT_P0 0x00010000 ++/* No-Operation ++#define SYS_ETH_DEACT_P0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_P0_CLR 0x00010000 ++/** Deactivate xMII ++ Clears the activation flag of the xMII domain. This domain contains the XMII block. If any of the digital LAN interfaces shall be used, this domain has to be active. */ ++#define SYS_ETH_DEACT_xMII 0x00000800 ++/* No-Operation ++#define SYS_ETH_DEACT_xMII_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_xMII_CLR 0x00000800 ++/** Deactivate SGMII ++ Clears the activation flag of the SGMII domain. This domain contains all parts of the EIM related to the SGMII block. The SGMII block itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_DEACT_SGMII 0x00000400 ++/* No-Operation ++#define SYS_ETH_DEACT_SGMII_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_SGMII_CLR 0x00000400 ++/** Deactivate GPHY1 ++ Clears the activation flag of the GPHY1 domain. This domain contains all parts of the EIM related to GPHY1. The GPHY1 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_DEACT_GPHY1 0x00000200 ++/* No-Operation ++#define SYS_ETH_DEACT_GPHY1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_GPHY1_CLR 0x00000200 ++/** Deactivate GPHY0 ++ Clears the activation flag of the GPHY0 domain. This domain contains all parts of the EIM related to GPHY0. The GPHY0 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_DEACT_GPHY0 0x00000100 ++/* No-Operation ++#define SYS_ETH_DEACT_GPHY0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_GPHY0_CLR 0x00000100 ++/** Deactivate MDIO ++ Clears the activation flag of the MDIO domain. This domain contains the MDIO block. */ ++#define SYS_ETH_DEACT_MDIO 0x00000080 ++/* No-Operation ++#define SYS_ETH_DEACT_MDIO_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_MDIO_CLR 0x00000080 ++/** Deactivate GMAC3 ++ Clears the activation flag of the GMAC3 domain. This domain contains the GMAC3 block. */ ++#define SYS_ETH_DEACT_GMAC3 0x00000008 ++/* No-Operation ++#define SYS_ETH_DEACT_GMAC3_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_GMAC3_CLR 0x00000008 ++/** Deactivate GMAC2 ++ Clears the activation flag of the GMAC2 domain. This domain contains the GMAC2 block. */ ++#define SYS_ETH_DEACT_GMAC2 0x00000004 ++/* No-Operation ++#define SYS_ETH_DEACT_GMAC2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_GMAC2_CLR 0x00000004 ++/** Deactivate GMAC1 ++ Clears the activation flag of the GMAC1 domain. This domain contains the GMAC1 block. */ ++#define SYS_ETH_DEACT_GMAC1 0x00000002 ++/* No-Operation ++#define SYS_ETH_DEACT_GMAC1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_GMAC1_CLR 0x00000002 ++/** Deactivate GMAC0 ++ Clears the activation flag of the GMAC0 domain. This domain contains the GMAC0 block. */ ++#define SYS_ETH_DEACT_GMAC0 0x00000001 ++/* No-Operation ++#define SYS_ETH_DEACT_GMAC0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_ETH_DEACT_GMAC0_CLR 0x00000001 ++ ++/* Fields of "Reboot Trigger Register" */ ++/** Reboot PADCTRL2 ++ Triggers a reboot of the PADCTRL2 domain. This domain contains the PADCTRL2 block. */ ++#define SYS_ETH_RBT_PADCTRL2 0x00200000 ++/* No-Operation ++#define SYS_ETH_RBT_PADCTRL2_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_PADCTRL2_TRIG 0x00200000 ++/** Reboot PADCTRL0 ++ Triggers a reboot of the PADCTRL0 domain. This domain contains the PADCTRL0 block. */ ++#define SYS_ETH_RBT_PADCTRL0 0x00100000 ++/* No-Operation ++#define SYS_ETH_RBT_PADCTRL0_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_PADCTRL0_TRIG 0x00100000 ++/** Reboot P2 ++ Triggers a reboot of the P2 domain. This domain contains the P2 instance of the GPIO block. */ ++#define SYS_ETH_RBT_P2 0x00020000 ++/* No-Operation ++#define SYS_ETH_RBT_P2_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_P2_TRIG 0x00020000 ++/** Reboot P0 ++ Triggers a reboot of the P0 domain. This domain contains the P0 instance of the GPIO block. */ ++#define SYS_ETH_RBT_P0 0x00010000 ++/* No-Operation ++#define SYS_ETH_RBT_P0_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_P0_TRIG 0x00010000 ++/** Reboot xMII ++ Triggers a reboot of the xMII domain. This domain contains the XMII block. If any of the digital LAN interfaces shall be used, this domain has to be active. */ ++#define SYS_ETH_RBT_xMII 0x00000800 ++/* No-Operation ++#define SYS_ETH_RBT_xMII_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_xMII_TRIG 0x00000800 ++/** Reboot SGMII ++ Triggers a reboot of the SGMII domain. This domain contains all parts of the EIM related to the SGMII block. The SGMII block itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_RBT_SGMII 0x00000400 ++/* No-Operation ++#define SYS_ETH_RBT_SGMII_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_SGMII_TRIG 0x00000400 ++/** Reboot GPHY1 ++ Triggers a reboot of the GPHY1 domain. This domain contains all parts of the EIM related to GPHY1. The GPHY1 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_RBT_GPHY1 0x00000200 ++/* No-Operation ++#define SYS_ETH_RBT_GPHY1_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_GPHY1_TRIG 0x00000200 ++/** Reboot GPHY0 ++ Triggers a reboot of the GPHY0 domain. This domain contains all parts of the EIM related to GPHY0. The GPHY0 itself is not contained, as it has its own clock/reset/power management. */ ++#define SYS_ETH_RBT_GPHY0 0x00000100 ++/* No-Operation ++#define SYS_ETH_RBT_GPHY0_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_GPHY0_TRIG 0x00000100 ++/** Reboot MDIO ++ Triggers a reboot of the MDIO domain. This domain contains the MDIO block. */ ++#define SYS_ETH_RBT_MDIO 0x00000080 ++/* No-Operation ++#define SYS_ETH_RBT_MDIO_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_MDIO_TRIG 0x00000080 ++/** Reboot GMAC3 ++ Triggers a reboot of the GMAC3 domain. This domain contains the GMAC3 block. */ ++#define SYS_ETH_RBT_GMAC3 0x00000008 ++/* No-Operation ++#define SYS_ETH_RBT_GMAC3_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_GMAC3_TRIG 0x00000008 ++/** Reboot GMAC2 ++ Triggers a reboot of the GMAC2 domain. This domain contains the GMAC2 block. */ ++#define SYS_ETH_RBT_GMAC2 0x00000004 ++/* No-Operation ++#define SYS_ETH_RBT_GMAC2_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_GMAC2_TRIG 0x00000004 ++/** Reboot GMAC1 ++ Triggers a reboot of the GMAC1 domain. This domain contains the GMAC1 block. */ ++#define SYS_ETH_RBT_GMAC1 0x00000002 ++/* No-Operation ++#define SYS_ETH_RBT_GMAC1_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_GMAC1_TRIG 0x00000002 ++/** Reboot GMAC0 ++ Triggers a reboot of the GMAC0 domain. This domain contains the GMAC0 block. */ ++#define SYS_ETH_RBT_GMAC0 0x00000001 ++/* No-Operation ++#define SYS_ETH_RBT_GMAC0_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_ETH_RBT_GMAC0_TRIG 0x00000001 ++ ++/* Fields of "External PHY Control Register" */ ++/** PHY_CLKO Output Enable ++ Enables the output driver of the PHY_CLKO pin. */ ++#define SYS_ETH_EXTPHYC_CLKEN 0x80000000 ++/* Disable ++#define SYS_ETH_EXTPHYC_CLKEN_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_EXTPHYC_CLKEN_EN 0x80000000 ++/** PHY_CLKO Frequency Select ++ Selects the frequency of the PHY_CLKO pin. */ ++#define SYS_ETH_EXTPHYC_CLKSEL_MASK 0x00000007 ++/** field offset */ ++#define SYS_ETH_EXTPHYC_CLKSEL_OFFSET 0 ++/** 25 MHz. */ ++#define SYS_ETH_EXTPHYC_CLKSEL_F25 0x00000001 ++/** 125 MHz. */ ++#define SYS_ETH_EXTPHYC_CLKSEL_F125 0x00000002 ++/** 50 MHz. */ ++#define SYS_ETH_EXTPHYC_CLKSEL_F50 0x00000005 ++ ++/* Fields of "Power Down Configuration Register" */ ++/** Enable Power Down PADCTRL2 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_PADCTRL2 0x00200000 ++/* Disable ++#define SYS_ETH_PDCFG_PADCTRL2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_PADCTRL2_EN 0x00200000 ++/** Enable Power Down PADCTRL0 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_PADCTRL0 0x00100000 ++/* Disable ++#define SYS_ETH_PDCFG_PADCTRL0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_PADCTRL0_EN 0x00100000 ++/** Enable Power Down P2 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_P2 0x00020000 ++/* Disable ++#define SYS_ETH_PDCFG_P2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_P2_EN 0x00020000 ++/** Enable Power Down P0 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_P0 0x00010000 ++/* Disable ++#define SYS_ETH_PDCFG_P0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_P0_EN 0x00010000 ++/** Enable Power Down xMII ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_xMII 0x00000800 ++/* Disable ++#define SYS_ETH_PDCFG_xMII_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_xMII_EN 0x00000800 ++/** Enable Power Down SGMII ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_SGMII 0x00000400 ++/* Disable ++#define SYS_ETH_PDCFG_SGMII_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_SGMII_EN 0x00000400 ++/** Enable Power Down GPHY1 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_GPHY1 0x00000200 ++/* Disable ++#define SYS_ETH_PDCFG_GPHY1_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_GPHY1_EN 0x00000200 ++/** Enable Power Down GPHY0 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_GPHY0 0x00000100 ++/* Disable ++#define SYS_ETH_PDCFG_GPHY0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_GPHY0_EN 0x00000100 ++/** Enable Power Down MDIO ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_MDIO 0x00000080 ++/* Disable ++#define SYS_ETH_PDCFG_MDIO_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_MDIO_EN 0x00000080 ++/** Enable Power Down GMAC3 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_GMAC3 0x00000008 ++/* Disable ++#define SYS_ETH_PDCFG_GMAC3_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_GMAC3_EN 0x00000008 ++/** Enable Power Down GMAC2 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_GMAC2 0x00000004 ++/* Disable ++#define SYS_ETH_PDCFG_GMAC2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_GMAC2_EN 0x00000004 ++/** Enable Power Down GMAC1 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_GMAC1 0x00000002 ++/* Disable ++#define SYS_ETH_PDCFG_GMAC1_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_GMAC1_EN 0x00000002 ++/** Enable Power Down GMAC0 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_ETH_PDCFG_GMAC0 0x00000001 ++/* Disable ++#define SYS_ETH_PDCFG_GMAC0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_ETH_PDCFG_GMAC0_EN 0x00000001 ++ ++/* Fields of "Datarate Control Register" */ ++/** MDC Clockrate ++ Selects the clockrate of the MDIO interface. */ ++#define SYS_ETH_DRC_MDC_MASK 0x30000000 ++/** field offset */ ++#define SYS_ETH_DRC_MDC_OFFSET 28 ++/** 312.5/128 = appr. 2.44 MHz. */ ++#define SYS_ETH_DRC_MDC_F2M44 0x00000000 ++/** 312.5/64 = appr. 4.88 MHz. */ ++#define SYS_ETH_DRC_MDC_F4M88 0x10000000 ++/** 312.5/32 = appr. 9.77 MHz. */ ++#define SYS_ETH_DRC_MDC_F9M77 0x20000000 ++/** 312.5/16 = appr. 19.5 MHz. */ ++#define SYS_ETH_DRC_MDC_F19M5 0x30000000 ++/** xMII1 Datarate ++ Selects the datarate of the xMII1 interface. */ ++#define SYS_ETH_DRC_xMII1_MASK 0x07000000 ++/** field offset */ ++#define SYS_ETH_DRC_xMII1_OFFSET 24 ++/** 10 MBit/s. */ ++#define SYS_ETH_DRC_xMII1_DR10 0x00000000 ++/** 100 MBit/s. */ ++#define SYS_ETH_DRC_xMII1_DR100 0x01000000 ++/** 1000 MBit/s. */ ++#define SYS_ETH_DRC_xMII1_DR1000 0x02000000 ++/** 200 MBit/s. */ ++#define SYS_ETH_DRC_xMII1_DR200 0x05000000 ++/** xMII0 Datarate ++ Selects the datarate of the xMII0 interface. */ ++#define SYS_ETH_DRC_xMII0_MASK 0x00700000 ++/** field offset */ ++#define SYS_ETH_DRC_xMII0_OFFSET 20 ++/** 10 MBit/s. */ ++#define SYS_ETH_DRC_xMII0_DR10 0x00000000 ++/** 100 MBit/s. */ ++#define SYS_ETH_DRC_xMII0_DR100 0x00100000 ++/** 1000 MBit/s. */ ++#define SYS_ETH_DRC_xMII0_DR1000 0x00200000 ++/** 200 MBit/s. */ ++#define SYS_ETH_DRC_xMII0_DR200 0x00500000 ++/** SGMII Datarate ++ Selects the datarate of the SGMII interface. */ ++#define SYS_ETH_DRC_SGMII_MASK 0x00070000 ++/** field offset */ ++#define SYS_ETH_DRC_SGMII_OFFSET 16 ++/** 10 MBit/s. */ ++#define SYS_ETH_DRC_SGMII_DR10 0x00000000 ++/** 100 MBit/s. */ ++#define SYS_ETH_DRC_SGMII_DR100 0x00010000 ++/** 1000 MBit/s. */ ++#define SYS_ETH_DRC_SGMII_DR1000 0x00020000 ++/** 2500 MBit/s. */ ++#define SYS_ETH_DRC_SGMII_DR2500 0x00040000 ++/** GPHY1_MII2 Datarate ++ Shows the datarate of the GPHY1_MII2 interface. */ ++#define SYS_ETH_DRC_GPHY1_MII2_MASK 0x00007000 ++/** field offset */ ++#define SYS_ETH_DRC_GPHY1_MII2_OFFSET 12 ++/** 10 MBit/s. */ ++#define SYS_ETH_DRC_GPHY1_MII2_DR10 0x00000000 ++/** 100 MBit/s. */ ++#define SYS_ETH_DRC_GPHY1_MII2_DR100 0x00001000 ++/** GPHY1_GMII Datarate ++ Shows the datarate of the GPHY1_GMII interface. */ ++#define SYS_ETH_DRC_GPHY1_GMII_MASK 0x00000700 ++/** field offset */ ++#define SYS_ETH_DRC_GPHY1_GMII_OFFSET 8 ++/** 10 MBit/s. */ ++#define SYS_ETH_DRC_GPHY1_GMII_DR10 0x00000000 ++/** 100 MBit/s. */ ++#define SYS_ETH_DRC_GPHY1_GMII_DR100 0x00000100 ++/** 1000 MBit/s. */ ++#define SYS_ETH_DRC_GPHY1_GMII_DR1000 0x00000200 ++/** GPHY0_MII2 Datarate ++ Shows the datarate of the GPHY0_MII2 interface. */ ++#define SYS_ETH_DRC_GPHY0_MII2_MASK 0x00000070 ++/** field offset */ ++#define SYS_ETH_DRC_GPHY0_MII2_OFFSET 4 ++/** 10 MBit/s. */ ++#define SYS_ETH_DRC_GPHY0_MII2_DR10 0x00000000 ++/** 100 MBit/s. */ ++#define SYS_ETH_DRC_GPHY0_MII2_DR100 0x00000010 ++/** GPHY0_GMII Datarate ++ Shows the datarate of the GPHY0_GMII interface. */ ++#define SYS_ETH_DRC_GPHY0_GMII_MASK 0x00000007 ++/** field offset */ ++#define SYS_ETH_DRC_GPHY0_GMII_OFFSET 0 ++/** 10 MBit/s. */ ++#define SYS_ETH_DRC_GPHY0_GMII_DR10 0x00000000 ++/** 100 MBit/s. */ ++#define SYS_ETH_DRC_GPHY0_GMII_DR100 0x00000001 ++/** 1000 MBit/s. */ ++#define SYS_ETH_DRC_GPHY0_GMII_DR1000 0x00000002 ++ ++/* Fields of "GMAC Multiplexer Control Register" */ ++/** GMAC 3 MUX setting ++ Selects the physical layer to be connected to GMAC3 */ ++#define SYS_ETH_GMUXC_GMAC3_MASK 0x00007000 ++/** field offset */ ++#define SYS_ETH_GMUXC_GMAC3_OFFSET 12 ++/** GMAC connects to GPHY0_GMII interface */ ++#define SYS_ETH_GMUXC_GMAC3_GPHY0_GMII 0x00000000 ++/** GMAC connects to GPHY0_MII2 interface */ ++#define SYS_ETH_GMUXC_GMAC3_GPHY0_MII2 0x00001000 ++/** GMAC connects to GPHY1_GMII interface */ ++#define SYS_ETH_GMUXC_GMAC3_GPHY1_GMII 0x00002000 ++/** GMAC connects to GPHY1_MII2 interface */ ++#define SYS_ETH_GMUXC_GMAC3_GPHY1_MII2 0x00003000 ++/** GMAC connects to SGMII interface */ ++#define SYS_ETH_GMUXC_GMAC3_SGMII 0x00004000 ++/** GMAC connects to xMII0 interface */ ++#define SYS_ETH_GMUXC_GMAC3_xMII0 0x00005000 ++/** GMAC connects to xMII1 interface */ ++#define SYS_ETH_GMUXC_GMAC3_xMII1 0x00006000 ++/** GMAC 2 MUX setting ++ Selects the physical layer to be connected to GMAC2 */ ++#define SYS_ETH_GMUXC_GMAC2_MASK 0x00000700 ++/** field offset */ ++#define SYS_ETH_GMUXC_GMAC2_OFFSET 8 ++/** GMAC connects to GPHY0_GMII interface */ ++#define SYS_ETH_GMUXC_GMAC2_GPHY0_GMII 0x00000000 ++/** GMAC connects to GPHY0_MII2 interface */ ++#define SYS_ETH_GMUXC_GMAC2_GPHY0_MII2 0x00000100 ++/** GMAC connects to GPHY1_GMII interface */ ++#define SYS_ETH_GMUXC_GMAC2_GPHY1_GMII 0x00000200 ++/** GMAC connects to GPHY1_MII2 interface */ ++#define SYS_ETH_GMUXC_GMAC2_GPHY1_MII2 0x00000300 ++/** GMAC connects to SGMII interface */ ++#define SYS_ETH_GMUXC_GMAC2_SGMII 0x00000400 ++/** GMAC connects to xMII0 interface */ ++#define SYS_ETH_GMUXC_GMAC2_xMII0 0x00000500 ++/** GMAC connects to xMII1 interface */ ++#define SYS_ETH_GMUXC_GMAC2_xMII1 0x00000600 ++/** GMAC 1 MUX setting ++ Selects the physical layer to be connected to GMAC1 */ ++#define SYS_ETH_GMUXC_GMAC1_MASK 0x00000070 ++/** field offset */ ++#define SYS_ETH_GMUXC_GMAC1_OFFSET 4 ++/** GMAC connects to GPHY0_GMII interface */ ++#define SYS_ETH_GMUXC_GMAC1_GPHY0_GMII 0x00000000 ++/** GMAC connects to GPHY0_MII2 interface */ ++#define SYS_ETH_GMUXC_GMAC1_GPHY0_MII2 0x00000010 ++/** GMAC connects to GPHY1_GMII interface */ ++#define SYS_ETH_GMUXC_GMAC1_GPHY1_GMII 0x00000020 ++/** GMAC connects to GPHY1_MII2 interface */ ++#define SYS_ETH_GMUXC_GMAC1_GPHY1_MII2 0x00000030 ++/** GMAC connects to SGMII interface */ ++#define SYS_ETH_GMUXC_GMAC1_SGMII 0x00000040 ++/** GMAC connects to xMII0 interface */ ++#define SYS_ETH_GMUXC_GMAC1_xMII0 0x00000050 ++/** GMAC connects to xMII1 interface */ ++#define SYS_ETH_GMUXC_GMAC1_xMII1 0x00000060 ++/** GMAC 0 MUX setting ++ Selects the physical layer to be connected to GMAC0 */ ++#define SYS_ETH_GMUXC_GMAC0_MASK 0x00000007 ++/** field offset */ ++#define SYS_ETH_GMUXC_GMAC0_OFFSET 0 ++/** GMAC connects to GPHY0_GMII interface */ ++#define SYS_ETH_GMUXC_GMAC0_GPHY0_GMII 0x00000000 ++/** GMAC connects to GPHY0_MII2 interface */ ++#define SYS_ETH_GMUXC_GMAC0_GPHY0_MII2 0x00000001 ++/** GMAC connects to GPHY1_GMII interface */ ++#define SYS_ETH_GMUXC_GMAC0_GPHY1_GMII 0x00000002 ++/** GMAC connects to GPHY1_MII2 interface */ ++#define SYS_ETH_GMUXC_GMAC0_GPHY1_MII2 0x00000003 ++/** GMAC connects to SGMII interface */ ++#define SYS_ETH_GMUXC_GMAC0_SGMII 0x00000004 ++/** GMAC connects to xMII0 interface */ ++#define SYS_ETH_GMUXC_GMAC0_xMII0 0x00000005 ++/** GMAC connects to xMII1 interface */ ++#define SYS_ETH_GMUXC_GMAC0_xMII1 0x00000006 ++ ++/* Fields of "Datarate Status Register" */ ++/** GMAC 3 datarate ++ Shows the datarate of GMAC3 */ ++#define SYS_ETH_DRS_GMAC3_MASK 0x00007000 ++/** field offset */ ++#define SYS_ETH_DRS_GMAC3_OFFSET 12 ++/** 10 MBit/s. */ ++#define SYS_ETH_DRS_GMAC3_DR10 0x00000000 ++/** 100 MBit/s. */ ++#define SYS_ETH_DRS_GMAC3_DR100 0x00001000 ++/** 1000 MBit/s. */ ++#define SYS_ETH_DRS_GMAC3_DR1000 0x00002000 ++/** 2500 MBit/s. */ ++#define SYS_ETH_DRS_GMAC3_DR2500 0x00004000 ++/** 200 MBit/s. */ ++#define SYS_ETH_DRS_GMAC3_DR200 0x00005000 ++/** GMAC 2 datarate ++ Shows the datarate of GMAC2 */ ++#define SYS_ETH_DRS_GMAC2_MASK 0x00000700 ++/** field offset */ ++#define SYS_ETH_DRS_GMAC2_OFFSET 8 ++/** 10 MBit/s. */ ++#define SYS_ETH_DRS_GMAC2_DR10 0x00000000 ++/** 100 MBit/s. */ ++#define SYS_ETH_DRS_GMAC2_DR100 0x00000100 ++/** 1000 MBit/s. */ ++#define SYS_ETH_DRS_GMAC2_DR1000 0x00000200 ++/** 2500 MBit/s. */ ++#define SYS_ETH_DRS_GMAC2_DR2500 0x00000400 ++/** 200 MBit/s. */ ++#define SYS_ETH_DRS_GMAC2_DR200 0x00000500 ++/** GMAC 1 datarate ++ Shows the datarate of GMAC1 */ ++#define SYS_ETH_DRS_GMAC1_MASK 0x00000070 ++/** field offset */ ++#define SYS_ETH_DRS_GMAC1_OFFSET 4 ++/** 10 MBit/s. */ ++#define SYS_ETH_DRS_GMAC1_DR10 0x00000000 ++/** 100 MBit/s. */ ++#define SYS_ETH_DRS_GMAC1_DR100 0x00000010 ++/** 1000 MBit/s. */ ++#define SYS_ETH_DRS_GMAC1_DR1000 0x00000020 ++/** 2500 MBit/s. */ ++#define SYS_ETH_DRS_GMAC1_DR2500 0x00000040 ++/** 200 MBit/s. */ ++#define SYS_ETH_DRS_GMAC1_DR200 0x00000050 ++/** GMAC 0 datarate ++ Shows the datarate of GMAC0 */ ++#define SYS_ETH_DRS_GMAC0_MASK 0x00000007 ++/** field offset */ ++#define SYS_ETH_DRS_GMAC0_OFFSET 0 ++/** 10 MBit/s. */ ++#define SYS_ETH_DRS_GMAC0_DR10 0x00000000 ++/** 100 MBit/s. */ ++#define SYS_ETH_DRS_GMAC0_DR100 0x00000001 ++/** 1000 MBit/s. */ ++#define SYS_ETH_DRS_GMAC0_DR1000 0x00000002 ++/** 2500 MBit/s. */ ++#define SYS_ETH_DRS_GMAC0_DR2500 0x00000004 ++/** 200 MBit/s. */ ++#define SYS_ETH_DRS_GMAC0_DR200 0x00000005 ++ ++/* Fields of "SGMII Control Register" */ ++/** Auto Negotiation Protocol ++ Selects the TBX/SGMII mode for the autonegotiation of the SGMII interface. */ ++#define SYS_ETH_SGMIIC_ANP 0x00000002 ++/* TBX Mode (IEEE 802.3 Clause 37 ANEG) ++#define SYS_ETH_SGMIIC_ANP_TBXM 0x00000000 */ ++/** SGMII Mode (Cisco Aneg) */ ++#define SYS_ETH_SGMIIC_ANP_SGMIIM 0x00000002 ++/** Auto Negotiation MAC/PHY ++ Selects the MAC/PHY mode for the autonegotiation of the SGMII interface. */ ++#define SYS_ETH_SGMIIC_ANMP 0x00000001 ++/* MAC Mode ++#define SYS_ETH_SGMIIC_ANMP_MAC 0x00000000 */ ++/** PHY Mode */ ++#define SYS_ETH_SGMIIC_ANMP_PHY 0x00000001 ++ ++/*! @} */ /* SYS_ETH_REGISTER */ ++ ++#endif /* _sys_eth_reg_h */ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/sys_gpe_reg.h +@@ -0,0 +1,2829 @@ ++/****************************************************************************** ++ ++ Copyright (c) 2010 ++ Lantiq Deutschland GmbH ++ ++ For licensing information, see the file 'LICENSE' in the root folder of ++ this software module. ++ ++******************************************************************************/ ++ ++#ifndef _sys_gpe_reg_h ++#define _sys_gpe_reg_h ++ ++/** \addtogroup SYS_GPE_REGISTER ++ @{ ++*/ ++/* access macros */ ++#define sys_gpe_r32(reg) reg_r32(&sys_gpe->reg) ++#define sys_gpe_w32(val, reg) reg_w32(val, &sys_gpe->reg) ++#define sys_gpe_w32_mask(clear, set, reg) reg_w32_mask(clear, set, &sys_gpe->reg) ++#define sys_gpe_r32_table(reg, idx) reg_r32_table(sys_gpe->reg, idx) ++#define sys_gpe_w32_table(val, reg, idx) reg_w32_table(val, sys_gpe->reg, idx) ++#define sys_gpe_w32_table_mask(clear, set, reg, idx) reg_w32_table_mask(clear, set, sys_gpe->reg, idx) ++#define sys_gpe_adr_table(reg, idx) adr_table(sys_gpe->reg, idx) ++ ++ ++/** SYS_GPE register structure */ ++struct gpon_reg_sys_gpe ++{ ++ /** Clock Status Register ++ The clock status reflects the actual clocking mode as a function of the SW settings and the hardware sleep mode. */ ++ unsigned int clks; /* 0x00000000 */ ++ /** Clock Enable Register ++ Via this register the clocks for the domains can be enabled. */ ++ unsigned int clken; /* 0x00000004 */ ++ /** Clock Clear Register ++ Via this register the clocks for the domains can be disabled. */ ++ unsigned int clkclr; /* 0x00000008 */ ++ /** Reserved */ ++ unsigned int res_0[5]; /* 0x0000000C */ ++ /** Activation Status Register */ ++ unsigned int acts; /* 0x00000020 */ ++ /** Activation Register ++ Via this register the domains can be activated. */ ++ unsigned int act; /* 0x00000024 */ ++ /** Deactivation Register ++ Via this register the domains can be deactivated. */ ++ unsigned int deact; /* 0x00000028 */ ++ /** Reboot Trigger Register ++ Via this register the domains can be rebooted (sent through reset). */ ++ unsigned int rbt; /* 0x0000002C */ ++ /** Reserved */ ++ unsigned int res_1[33]; /* 0x00000030 */ ++ /** Power Down Configuration Register ++ Via this register the configuration is done whether in case of deactivation the power supply of the domain shall be removed. */ ++ unsigned int pdcfg; /* 0x000000B4 */ ++ /** Sleep Source Configuration Register ++ All sleep/wakeup conditions selected in this register contribute to the generation of the hardware sleep/wakeup request. Unselected conditions are ignored for sleep and wakeup. If no bit is selected, HW sleep is disabled. */ ++ unsigned int sscfg; /* 0x000000B8 */ ++ /** Sleep Source Timer Register */ ++ unsigned int sst; /* 0x000000BC */ ++ /** Sleep Destination Status Register ++ Shows the status of the sleep destination vector. All clock domains selected in this register will be shutoff in case of a hardware sleep request. These clocks will be automatically reenabled in case of a hardware wakeup request. */ ++ unsigned int sds; /* 0x000000C0 */ ++ /** Sleep Destination Set Register ++ Via this register the the domains to be shutoff in case of a hardware sleep request can be selected. */ ++ unsigned int sdset; /* 0x000000C4 */ ++ /** Sleep Destination Clear Register ++ Via this register the the domains to be shutoff in case of a hardware sleep request can be deselected. */ ++ unsigned int sdclr; /* 0x000000C8 */ ++ /** Reserved */ ++ unsigned int res_2[9]; /* 0x000000CC */ ++ /** IRNCS Capture Register ++ This register shows the currently active interrupt events masked with the corresponding enable bits of the IRNCSEN register. The interrupts can be acknowledged by a write operation. */ ++ unsigned int irncscr; /* 0x000000F0 */ ++ /** IRNCS Interrupt Control Register ++ A write operation directly effects the interrupts. This can be used to trigger events under software control for testing purposes. A read operation returns the unmasked interrupt events. */ ++ unsigned int irncsicr; /* 0x000000F4 */ ++ /** IRNCS Interrupt Enable Register ++ This register contains the enable (or mask) bits for the interrupts. Disabled interrupts are not visible in the IRNCSCR register and are not signalled via the interrupt line towards the controller. */ ++ unsigned int irncsen; /* 0x000000F8 */ ++ /** Reserved */ ++ unsigned int res_3; /* 0x000000FC */ ++}; ++ ++ ++/* Fields of "Clock Status Register" */ ++/** COP7 Clock Enable ++ Shows the clock enable bit for the COP7 domain. This domain contains the Coprocessor 7 of the SCE. */ ++#define SYS_GPE_CLKS_COP7 0x80000000 ++/* Disable ++#define SYS_GPE_CLKS_COP7_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_COP7_EN 0x80000000 ++/** COP6 Clock Enable ++ Shows the clock enable bit for the COP6 domain. This domain contains the Coprocessor 6 of the SCE. */ ++#define SYS_GPE_CLKS_COP6 0x40000000 ++/* Disable ++#define SYS_GPE_CLKS_COP6_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_COP6_EN 0x40000000 ++/** COP5 Clock Enable ++ Shows the clock enable bit for the COP5 domain. This domain contains the Coprocessor 5 of the SCE. */ ++#define SYS_GPE_CLKS_COP5 0x20000000 ++/* Disable ++#define SYS_GPE_CLKS_COP5_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_COP5_EN 0x20000000 ++/** COP4 Clock Enable ++ Shows the clock enable bit for the COP4 domain. This domain contains the Coprocessor 4 of the SCE. */ ++#define SYS_GPE_CLKS_COP4 0x10000000 ++/* Disable ++#define SYS_GPE_CLKS_COP4_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_COP4_EN 0x10000000 ++/** COP3 Clock Enable ++ Shows the clock enable bit for the COP3 domain. This domain contains the Coprocessor 3 of the SCE. */ ++#define SYS_GPE_CLKS_COP3 0x08000000 ++/* Disable ++#define SYS_GPE_CLKS_COP3_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_COP3_EN 0x08000000 ++/** COP2 Clock Enable ++ Shows the clock enable bit for the COP2 domain. This domain contains the Coprocessor 2 of the SCE. */ ++#define SYS_GPE_CLKS_COP2 0x04000000 ++/* Disable ++#define SYS_GPE_CLKS_COP2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_COP2_EN 0x04000000 ++/** COP1 Clock Enable ++ Shows the clock enable bit for the COP1 domain. This domain contains the Coprocessor 1 of the SCE. */ ++#define SYS_GPE_CLKS_COP1 0x02000000 ++/* Disable ++#define SYS_GPE_CLKS_COP1_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_COP1_EN 0x02000000 ++/** COP0 Clock Enable ++ Shows the clock enable bit for the COP0 domain. This domain contains the Coprocessor 0 of the SCE. */ ++#define SYS_GPE_CLKS_COP0 0x01000000 ++/* Disable ++#define SYS_GPE_CLKS_COP0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_COP0_EN 0x01000000 ++/** PE5 Clock Enable ++ Shows the clock enable bit for the PE5 domain. This domain contains the Processing Element 5 of the SCE. */ ++#define SYS_GPE_CLKS_PE5 0x00200000 ++/* Disable ++#define SYS_GPE_CLKS_PE5_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_PE5_EN 0x00200000 ++/** PE4 Clock Enable ++ Shows the clock enable bit for the PE4 domain. This domain contains the Processing Element 4 of the SCE. */ ++#define SYS_GPE_CLKS_PE4 0x00100000 ++/* Disable ++#define SYS_GPE_CLKS_PE4_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_PE4_EN 0x00100000 ++/** PE3 Clock Enable ++ Shows the clock enable bit for the PE3 domain. This domain contains the Processing Element 3 of the SCE. */ ++#define SYS_GPE_CLKS_PE3 0x00080000 ++/* Disable ++#define SYS_GPE_CLKS_PE3_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_PE3_EN 0x00080000 ++/** PE2 Clock Enable ++ Shows the clock enable bit for the PE2 domain. This domain contains the Processing Element 2 of the SCE. */ ++#define SYS_GPE_CLKS_PE2 0x00040000 ++/* Disable ++#define SYS_GPE_CLKS_PE2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_PE2_EN 0x00040000 ++/** PE1 Clock Enable ++ Shows the clock enable bit for the PE1 domain. This domain contains the Processing Element 1 of the SCE. */ ++#define SYS_GPE_CLKS_PE1 0x00020000 ++/* Disable ++#define SYS_GPE_CLKS_PE1_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_PE1_EN 0x00020000 ++/** PE0 Clock Enable ++ Shows the clock enable bit for the PE0 domain. This domain contains the Processing Element 0 of the SCE. */ ++#define SYS_GPE_CLKS_PE0 0x00010000 ++/* Disable ++#define SYS_GPE_CLKS_PE0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_PE0_EN 0x00010000 ++/** ARB Clock Enable ++ Shows the clock enable bit for the ARB domain. This domain contains the Arbiter. */ ++#define SYS_GPE_CLKS_ARB 0x00002000 ++/* Disable ++#define SYS_GPE_CLKS_ARB_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_ARB_EN 0x00002000 ++/** FSQM Clock Enable ++ Shows the clock enable bit for the FSQM domain. This domain contains the FSQM. */ ++#define SYS_GPE_CLKS_FSQM 0x00001000 ++/* Disable ++#define SYS_GPE_CLKS_FSQM_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_FSQM_EN 0x00001000 ++/** TMU Clock Enable ++ Shows the clock enable bit for the TMU domain. This domain contains the TMU. */ ++#define SYS_GPE_CLKS_TMU 0x00000800 ++/* Disable ++#define SYS_GPE_CLKS_TMU_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_TMU_EN 0x00000800 ++/** MRG Clock Enable ++ Shows the clock enable bit for the MRG domain. This domain contains the Merger. */ ++#define SYS_GPE_CLKS_MRG 0x00000400 ++/* Disable ++#define SYS_GPE_CLKS_MRG_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_MRG_EN 0x00000400 ++/** DISP Clock Enable ++ Shows the clock enable bit for the DISP domain. This domain contains the Dispatcher. */ ++#define SYS_GPE_CLKS_DISP 0x00000200 ++/* Disable ++#define SYS_GPE_CLKS_DISP_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_DISP_EN 0x00000200 ++/** IQM Clock Enable ++ Shows the clock enable bit for the IQM domain. This domain contains the IQM. */ ++#define SYS_GPE_CLKS_IQM 0x00000100 ++/* Disable ++#define SYS_GPE_CLKS_IQM_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_IQM_EN 0x00000100 ++/** CPUE Clock Enable ++ Shows the clock enable bit for the CPUE domain. This domain contains all parts related to the CPU EGRESS interface. */ ++#define SYS_GPE_CLKS_CPUE 0x00000080 ++/* Disable ++#define SYS_GPE_CLKS_CPUE_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_CPUE_EN 0x00000080 ++/** CPUI Clock Enable ++ Shows the clock enable bit for the CPUI domain. This domain contains all parts related to the CPU INGRESS interface. */ ++#define SYS_GPE_CLKS_CPUI 0x00000040 ++/* Disable ++#define SYS_GPE_CLKS_CPUI_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_CPUI_EN 0x00000040 ++/** GPONE Clock Enable ++ Shows the clock enable bit for the GPONE domain. This domain contains all parts related to the GPON (GTC) EGRESS interface. */ ++#define SYS_GPE_CLKS_GPONE 0x00000020 ++/* Disable ++#define SYS_GPE_CLKS_GPONE_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_GPONE_EN 0x00000020 ++/** GPONI Clock Enable ++ Shows the clock enable bit for the GPONI domain. This domain contains all parts related to the GPON (GTC) INGRESS interface. */ ++#define SYS_GPE_CLKS_GPONI 0x00000010 ++/* Disable ++#define SYS_GPE_CLKS_GPONI_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_GPONI_EN 0x00000010 ++/** LAN3 Clock Enable ++ Shows the clock enable bit for the LAN3 domain. This domain contains all parts related to the LAN3 interface. */ ++#define SYS_GPE_CLKS_LAN3 0x00000008 ++/* Disable ++#define SYS_GPE_CLKS_LAN3_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_LAN3_EN 0x00000008 ++/** LAN2 Clock Enable ++ Shows the clock enable bit for the LAN2 domain. This domain contains all parts related to the LAN2 interface. */ ++#define SYS_GPE_CLKS_LAN2 0x00000004 ++/* Disable ++#define SYS_GPE_CLKS_LAN2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_LAN2_EN 0x00000004 ++/** LAN1 Clock Enable ++ Shows the clock enable bit for the LAN1 domain. This domain contains all parts related to the LAN1 interface. */ ++#define SYS_GPE_CLKS_LAN1 0x00000002 ++/* Disable ++#define SYS_GPE_CLKS_LAN1_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_LAN1_EN 0x00000002 ++/** LAN0 Clock Enable ++ Shows the clock enable bit for the LAN0 domain. This domain contains all parts related to the LAN0 interface. */ ++#define SYS_GPE_CLKS_LAN0 0x00000001 ++/* Disable ++#define SYS_GPE_CLKS_LAN0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_CLKS_LAN0_EN 0x00000001 ++ ++/* Fields of "Clock Enable Register" */ ++/** Set Clock Enable COP7 ++ Sets the clock enable bit of the COP7 domain. This domain contains the Coprocessor 7 of the SCE. */ ++#define SYS_GPE_CLKEN_COP7 0x80000000 ++/* No-Operation ++#define SYS_GPE_CLKEN_COP7_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_COP7_SET 0x80000000 ++/** Set Clock Enable COP6 ++ Sets the clock enable bit of the COP6 domain. This domain contains the Coprocessor 6 of the SCE. */ ++#define SYS_GPE_CLKEN_COP6 0x40000000 ++/* No-Operation ++#define SYS_GPE_CLKEN_COP6_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_COP6_SET 0x40000000 ++/** Set Clock Enable COP5 ++ Sets the clock enable bit of the COP5 domain. This domain contains the Coprocessor 5 of the SCE. */ ++#define SYS_GPE_CLKEN_COP5 0x20000000 ++/* No-Operation ++#define SYS_GPE_CLKEN_COP5_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_COP5_SET 0x20000000 ++/** Set Clock Enable COP4 ++ Sets the clock enable bit of the COP4 domain. This domain contains the Coprocessor 4 of the SCE. */ ++#define SYS_GPE_CLKEN_COP4 0x10000000 ++/* No-Operation ++#define SYS_GPE_CLKEN_COP4_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_COP4_SET 0x10000000 ++/** Set Clock Enable COP3 ++ Sets the clock enable bit of the COP3 domain. This domain contains the Coprocessor 3 of the SCE. */ ++#define SYS_GPE_CLKEN_COP3 0x08000000 ++/* No-Operation ++#define SYS_GPE_CLKEN_COP3_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_COP3_SET 0x08000000 ++/** Set Clock Enable COP2 ++ Sets the clock enable bit of the COP2 domain. This domain contains the Coprocessor 2 of the SCE. */ ++#define SYS_GPE_CLKEN_COP2 0x04000000 ++/* No-Operation ++#define SYS_GPE_CLKEN_COP2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_COP2_SET 0x04000000 ++/** Set Clock Enable COP1 ++ Sets the clock enable bit of the COP1 domain. This domain contains the Coprocessor 1 of the SCE. */ ++#define SYS_GPE_CLKEN_COP1 0x02000000 ++/* No-Operation ++#define SYS_GPE_CLKEN_COP1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_COP1_SET 0x02000000 ++/** Set Clock Enable COP0 ++ Sets the clock enable bit of the COP0 domain. This domain contains the Coprocessor 0 of the SCE. */ ++#define SYS_GPE_CLKEN_COP0 0x01000000 ++/* No-Operation ++#define SYS_GPE_CLKEN_COP0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_COP0_SET 0x01000000 ++/** Set Clock Enable PE5 ++ Sets the clock enable bit of the PE5 domain. This domain contains the Processing Element 5 of the SCE. */ ++#define SYS_GPE_CLKEN_PE5 0x00200000 ++/* No-Operation ++#define SYS_GPE_CLKEN_PE5_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_PE5_SET 0x00200000 ++/** Set Clock Enable PE4 ++ Sets the clock enable bit of the PE4 domain. This domain contains the Processing Element 4 of the SCE. */ ++#define SYS_GPE_CLKEN_PE4 0x00100000 ++/* No-Operation ++#define SYS_GPE_CLKEN_PE4_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_PE4_SET 0x00100000 ++/** Set Clock Enable PE3 ++ Sets the clock enable bit of the PE3 domain. This domain contains the Processing Element 3 of the SCE. */ ++#define SYS_GPE_CLKEN_PE3 0x00080000 ++/* No-Operation ++#define SYS_GPE_CLKEN_PE3_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_PE3_SET 0x00080000 ++/** Set Clock Enable PE2 ++ Sets the clock enable bit of the PE2 domain. This domain contains the Processing Element 2 of the SCE. */ ++#define SYS_GPE_CLKEN_PE2 0x00040000 ++/* No-Operation ++#define SYS_GPE_CLKEN_PE2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_PE2_SET 0x00040000 ++/** Set Clock Enable PE1 ++ Sets the clock enable bit of the PE1 domain. This domain contains the Processing Element 1 of the SCE. */ ++#define SYS_GPE_CLKEN_PE1 0x00020000 ++/* No-Operation ++#define SYS_GPE_CLKEN_PE1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_PE1_SET 0x00020000 ++/** Set Clock Enable PE0 ++ Sets the clock enable bit of the PE0 domain. This domain contains the Processing Element 0 of the SCE. */ ++#define SYS_GPE_CLKEN_PE0 0x00010000 ++/* No-Operation ++#define SYS_GPE_CLKEN_PE0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_PE0_SET 0x00010000 ++/** Set Clock Enable ARB ++ Sets the clock enable bit of the ARB domain. This domain contains the Arbiter. */ ++#define SYS_GPE_CLKEN_ARB 0x00002000 ++/* No-Operation ++#define SYS_GPE_CLKEN_ARB_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_ARB_SET 0x00002000 ++/** Set Clock Enable FSQM ++ Sets the clock enable bit of the FSQM domain. This domain contains the FSQM. */ ++#define SYS_GPE_CLKEN_FSQM 0x00001000 ++/* No-Operation ++#define SYS_GPE_CLKEN_FSQM_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_FSQM_SET 0x00001000 ++/** Set Clock Enable TMU ++ Sets the clock enable bit of the TMU domain. This domain contains the TMU. */ ++#define SYS_GPE_CLKEN_TMU 0x00000800 ++/* No-Operation ++#define SYS_GPE_CLKEN_TMU_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_TMU_SET 0x00000800 ++/** Set Clock Enable MRG ++ Sets the clock enable bit of the MRG domain. This domain contains the Merger. */ ++#define SYS_GPE_CLKEN_MRG 0x00000400 ++/* No-Operation ++#define SYS_GPE_CLKEN_MRG_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_MRG_SET 0x00000400 ++/** Set Clock Enable DISP ++ Sets the clock enable bit of the DISP domain. This domain contains the Dispatcher. */ ++#define SYS_GPE_CLKEN_DISP 0x00000200 ++/* No-Operation ++#define SYS_GPE_CLKEN_DISP_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_DISP_SET 0x00000200 ++/** Set Clock Enable IQM ++ Sets the clock enable bit of the IQM domain. This domain contains the IQM. */ ++#define SYS_GPE_CLKEN_IQM 0x00000100 ++/* No-Operation ++#define SYS_GPE_CLKEN_IQM_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_IQM_SET 0x00000100 ++/** Set Clock Enable CPUE ++ Sets the clock enable bit of the CPUE domain. This domain contains all parts related to the CPU EGRESS interface. */ ++#define SYS_GPE_CLKEN_CPUE 0x00000080 ++/* No-Operation ++#define SYS_GPE_CLKEN_CPUE_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_CPUE_SET 0x00000080 ++/** Set Clock Enable CPUI ++ Sets the clock enable bit of the CPUI domain. This domain contains all parts related to the CPU INGRESS interface. */ ++#define SYS_GPE_CLKEN_CPUI 0x00000040 ++/* No-Operation ++#define SYS_GPE_CLKEN_CPUI_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_CPUI_SET 0x00000040 ++/** Set Clock Enable GPONE ++ Sets the clock enable bit of the GPONE domain. This domain contains all parts related to the GPON (GTC) EGRESS interface. */ ++#define SYS_GPE_CLKEN_GPONE 0x00000020 ++/* No-Operation ++#define SYS_GPE_CLKEN_GPONE_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_GPONE_SET 0x00000020 ++/** Set Clock Enable GPONI ++ Sets the clock enable bit of the GPONI domain. This domain contains all parts related to the GPON (GTC) INGRESS interface. */ ++#define SYS_GPE_CLKEN_GPONI 0x00000010 ++/* No-Operation ++#define SYS_GPE_CLKEN_GPONI_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_GPONI_SET 0x00000010 ++/** Set Clock Enable LAN3 ++ Sets the clock enable bit of the LAN3 domain. This domain contains all parts related to the LAN3 interface. */ ++#define SYS_GPE_CLKEN_LAN3 0x00000008 ++/* No-Operation ++#define SYS_GPE_CLKEN_LAN3_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_LAN3_SET 0x00000008 ++/** Set Clock Enable LAN2 ++ Sets the clock enable bit of the LAN2 domain. This domain contains all parts related to the LAN2 interface. */ ++#define SYS_GPE_CLKEN_LAN2 0x00000004 ++/* No-Operation ++#define SYS_GPE_CLKEN_LAN2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_LAN2_SET 0x00000004 ++/** Set Clock Enable LAN1 ++ Sets the clock enable bit of the LAN1 domain. This domain contains all parts related to the LAN1 interface. */ ++#define SYS_GPE_CLKEN_LAN1 0x00000002 ++/* No-Operation ++#define SYS_GPE_CLKEN_LAN1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_LAN1_SET 0x00000002 ++/** Set Clock Enable LAN0 ++ Sets the clock enable bit of the LAN0 domain. This domain contains all parts related to the LAN0 interface. */ ++#define SYS_GPE_CLKEN_LAN0 0x00000001 ++/* No-Operation ++#define SYS_GPE_CLKEN_LAN0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_CLKEN_LAN0_SET 0x00000001 ++ ++/* Fields of "Clock Clear Register" */ ++/** Clear Clock Enable COP7 ++ Clears the clock enable bit of the COP7 domain. This domain contains the Coprocessor 7 of the SCE. */ ++#define SYS_GPE_CLKCLR_COP7 0x80000000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_COP7_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_COP7_CLR 0x80000000 ++/** Clear Clock Enable COP6 ++ Clears the clock enable bit of the COP6 domain. This domain contains the Coprocessor 6 of the SCE. */ ++#define SYS_GPE_CLKCLR_COP6 0x40000000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_COP6_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_COP6_CLR 0x40000000 ++/** Clear Clock Enable COP5 ++ Clears the clock enable bit of the COP5 domain. This domain contains the Coprocessor 5 of the SCE. */ ++#define SYS_GPE_CLKCLR_COP5 0x20000000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_COP5_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_COP5_CLR 0x20000000 ++/** Clear Clock Enable COP4 ++ Clears the clock enable bit of the COP4 domain. This domain contains the Coprocessor 4 of the SCE. */ ++#define SYS_GPE_CLKCLR_COP4 0x10000000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_COP4_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_COP4_CLR 0x10000000 ++/** Clear Clock Enable COP3 ++ Clears the clock enable bit of the COP3 domain. This domain contains the Coprocessor 3 of the SCE. */ ++#define SYS_GPE_CLKCLR_COP3 0x08000000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_COP3_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_COP3_CLR 0x08000000 ++/** Clear Clock Enable COP2 ++ Clears the clock enable bit of the COP2 domain. This domain contains the Coprocessor 2 of the SCE. */ ++#define SYS_GPE_CLKCLR_COP2 0x04000000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_COP2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_COP2_CLR 0x04000000 ++/** Clear Clock Enable COP1 ++ Clears the clock enable bit of the COP1 domain. This domain contains the Coprocessor 1 of the SCE. */ ++#define SYS_GPE_CLKCLR_COP1 0x02000000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_COP1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_COP1_CLR 0x02000000 ++/** Clear Clock Enable COP0 ++ Clears the clock enable bit of the COP0 domain. This domain contains the Coprocessor 0 of the SCE. */ ++#define SYS_GPE_CLKCLR_COP0 0x01000000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_COP0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_COP0_CLR 0x01000000 ++/** Clear Clock Enable PE5 ++ Clears the clock enable bit of the PE5 domain. This domain contains the Processing Element 5 of the SCE. */ ++#define SYS_GPE_CLKCLR_PE5 0x00200000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_PE5_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_PE5_CLR 0x00200000 ++/** Clear Clock Enable PE4 ++ Clears the clock enable bit of the PE4 domain. This domain contains the Processing Element 4 of the SCE. */ ++#define SYS_GPE_CLKCLR_PE4 0x00100000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_PE4_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_PE4_CLR 0x00100000 ++/** Clear Clock Enable PE3 ++ Clears the clock enable bit of the PE3 domain. This domain contains the Processing Element 3 of the SCE. */ ++#define SYS_GPE_CLKCLR_PE3 0x00080000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_PE3_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_PE3_CLR 0x00080000 ++/** Clear Clock Enable PE2 ++ Clears the clock enable bit of the PE2 domain. This domain contains the Processing Element 2 of the SCE. */ ++#define SYS_GPE_CLKCLR_PE2 0x00040000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_PE2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_PE2_CLR 0x00040000 ++/** Clear Clock Enable PE1 ++ Clears the clock enable bit of the PE1 domain. This domain contains the Processing Element 1 of the SCE. */ ++#define SYS_GPE_CLKCLR_PE1 0x00020000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_PE1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_PE1_CLR 0x00020000 ++/** Clear Clock Enable PE0 ++ Clears the clock enable bit of the PE0 domain. This domain contains the Processing Element 0 of the SCE. */ ++#define SYS_GPE_CLKCLR_PE0 0x00010000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_PE0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_PE0_CLR 0x00010000 ++/** Clear Clock Enable ARB ++ Clears the clock enable bit of the ARB domain. This domain contains the Arbiter. */ ++#define SYS_GPE_CLKCLR_ARB 0x00002000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_ARB_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_ARB_CLR 0x00002000 ++/** Clear Clock Enable FSQM ++ Clears the clock enable bit of the FSQM domain. This domain contains the FSQM. */ ++#define SYS_GPE_CLKCLR_FSQM 0x00001000 ++/* No-Operation ++#define SYS_GPE_CLKCLR_FSQM_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_FSQM_CLR 0x00001000 ++/** Clear Clock Enable TMU ++ Clears the clock enable bit of the TMU domain. This domain contains the TMU. */ ++#define SYS_GPE_CLKCLR_TMU 0x00000800 ++/* No-Operation ++#define SYS_GPE_CLKCLR_TMU_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_TMU_CLR 0x00000800 ++/** Clear Clock Enable MRG ++ Clears the clock enable bit of the MRG domain. This domain contains the Merger. */ ++#define SYS_GPE_CLKCLR_MRG 0x00000400 ++/* No-Operation ++#define SYS_GPE_CLKCLR_MRG_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_MRG_CLR 0x00000400 ++/** Clear Clock Enable DISP ++ Clears the clock enable bit of the DISP domain. This domain contains the Dispatcher. */ ++#define SYS_GPE_CLKCLR_DISP 0x00000200 ++/* No-Operation ++#define SYS_GPE_CLKCLR_DISP_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_DISP_CLR 0x00000200 ++/** Clear Clock Enable IQM ++ Clears the clock enable bit of the IQM domain. This domain contains the IQM. */ ++#define SYS_GPE_CLKCLR_IQM 0x00000100 ++/* No-Operation ++#define SYS_GPE_CLKCLR_IQM_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_IQM_CLR 0x00000100 ++/** Clear Clock Enable CPUE ++ Clears the clock enable bit of the CPUE domain. This domain contains all parts related to the CPU EGRESS interface. */ ++#define SYS_GPE_CLKCLR_CPUE 0x00000080 ++/* No-Operation ++#define SYS_GPE_CLKCLR_CPUE_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_CPUE_CLR 0x00000080 ++/** Clear Clock Enable CPUI ++ Clears the clock enable bit of the CPUI domain. This domain contains all parts related to the CPU INGRESS interface. */ ++#define SYS_GPE_CLKCLR_CPUI 0x00000040 ++/* No-Operation ++#define SYS_GPE_CLKCLR_CPUI_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_CPUI_CLR 0x00000040 ++/** Clear Clock Enable GPONE ++ Clears the clock enable bit of the GPONE domain. This domain contains all parts related to the GPON (GTC) EGRESS interface. */ ++#define SYS_GPE_CLKCLR_GPONE 0x00000020 ++/* No-Operation ++#define SYS_GPE_CLKCLR_GPONE_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_GPONE_CLR 0x00000020 ++/** Clear Clock Enable GPONI ++ Clears the clock enable bit of the GPONI domain. This domain contains all parts related to the GPON (GTC) INGRESS interface. */ ++#define SYS_GPE_CLKCLR_GPONI 0x00000010 ++/* No-Operation ++#define SYS_GPE_CLKCLR_GPONI_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_GPONI_CLR 0x00000010 ++/** Clear Clock Enable LAN3 ++ Clears the clock enable bit of the LAN3 domain. This domain contains all parts related to the LAN3 interface. */ ++#define SYS_GPE_CLKCLR_LAN3 0x00000008 ++/* No-Operation ++#define SYS_GPE_CLKCLR_LAN3_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_LAN3_CLR 0x00000008 ++/** Clear Clock Enable LAN2 ++ Clears the clock enable bit of the LAN2 domain. This domain contains all parts related to the LAN2 interface. */ ++#define SYS_GPE_CLKCLR_LAN2 0x00000004 ++/* No-Operation ++#define SYS_GPE_CLKCLR_LAN2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_LAN2_CLR 0x00000004 ++/** Clear Clock Enable LAN1 ++ Clears the clock enable bit of the LAN1 domain. This domain contains all parts related to the LAN1 interface. */ ++#define SYS_GPE_CLKCLR_LAN1 0x00000002 ++/* No-Operation ++#define SYS_GPE_CLKCLR_LAN1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_LAN1_CLR 0x00000002 ++/** Clear Clock Enable LAN0 ++ Clears the clock enable bit of the LAN0 domain. This domain contains all parts related to the LAN0 interface. */ ++#define SYS_GPE_CLKCLR_LAN0 0x00000001 ++/* No-Operation ++#define SYS_GPE_CLKCLR_LAN0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_CLKCLR_LAN0_CLR 0x00000001 ++ ++/* Fields of "Activation Status Register" */ ++/** COP7 Status ++ Shows the activation status of the COP7 domain. This domain contains the Coprocessor 7 of the SCE. */ ++#define SYS_GPE_ACTS_COP7 0x80000000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_COP7_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_COP7_ACT 0x80000000 ++/** COP6 Status ++ Shows the activation status of the COP6 domain. This domain contains the Coprocessor 6 of the SCE. */ ++#define SYS_GPE_ACTS_COP6 0x40000000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_COP6_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_COP6_ACT 0x40000000 ++/** COP5 Status ++ Shows the activation status of the COP5 domain. This domain contains the Coprocessor 5 of the SCE. */ ++#define SYS_GPE_ACTS_COP5 0x20000000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_COP5_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_COP5_ACT 0x20000000 ++/** COP4 Status ++ Shows the activation status of the COP4 domain. This domain contains the Coprocessor 4 of the SCE. */ ++#define SYS_GPE_ACTS_COP4 0x10000000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_COP4_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_COP4_ACT 0x10000000 ++/** COP3 Status ++ Shows the activation status of the COP3 domain. This domain contains the Coprocessor 3 of the SCE. */ ++#define SYS_GPE_ACTS_COP3 0x08000000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_COP3_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_COP3_ACT 0x08000000 ++/** COP2 Status ++ Shows the activation status of the COP2 domain. This domain contains the Coprocessor 2 of the SCE. */ ++#define SYS_GPE_ACTS_COP2 0x04000000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_COP2_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_COP2_ACT 0x04000000 ++/** COP1 Status ++ Shows the activation status of the COP1 domain. This domain contains the Coprocessor 1 of the SCE. */ ++#define SYS_GPE_ACTS_COP1 0x02000000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_COP1_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_COP1_ACT 0x02000000 ++/** COP0 Status ++ Shows the activation status of the COP0 domain. This domain contains the Coprocessor 0 of the SCE. */ ++#define SYS_GPE_ACTS_COP0 0x01000000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_COP0_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_COP0_ACT 0x01000000 ++/** PE5 Status ++ Shows the activation status of the PE5 domain. This domain contains the Processing Element 5 of the SCE. */ ++#define SYS_GPE_ACTS_PE5 0x00200000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_PE5_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_PE5_ACT 0x00200000 ++/** PE4 Status ++ Shows the activation status of the PE4 domain. This domain contains the Processing Element 4 of the SCE. */ ++#define SYS_GPE_ACTS_PE4 0x00100000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_PE4_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_PE4_ACT 0x00100000 ++/** PE3 Status ++ Shows the activation status of the PE3 domain. This domain contains the Processing Element 3 of the SCE. */ ++#define SYS_GPE_ACTS_PE3 0x00080000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_PE3_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_PE3_ACT 0x00080000 ++/** PE2 Status ++ Shows the activation status of the PE2 domain. This domain contains the Processing Element 2 of the SCE. */ ++#define SYS_GPE_ACTS_PE2 0x00040000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_PE2_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_PE2_ACT 0x00040000 ++/** PE1 Status ++ Shows the activation status of the PE1 domain. This domain contains the Processing Element 1 of the SCE. */ ++#define SYS_GPE_ACTS_PE1 0x00020000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_PE1_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_PE1_ACT 0x00020000 ++/** PE0 Status ++ Shows the activation status of the PE0 domain. This domain contains the Processing Element 0 of the SCE. */ ++#define SYS_GPE_ACTS_PE0 0x00010000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_PE0_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_PE0_ACT 0x00010000 ++/** ARB Status ++ Shows the activation status of the ARB domain. This domain contains the Arbiter. */ ++#define SYS_GPE_ACTS_ARB 0x00002000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_ARB_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_ARB_ACT 0x00002000 ++/** FSQM Status ++ Shows the activation status of the FSQM domain. This domain contains the FSQM. */ ++#define SYS_GPE_ACTS_FSQM 0x00001000 ++/* The block is inactive. ++#define SYS_GPE_ACTS_FSQM_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_FSQM_ACT 0x00001000 ++/** TMU Status ++ Shows the activation status of the TMU domain. This domain contains the TMU. */ ++#define SYS_GPE_ACTS_TMU 0x00000800 ++/* The block is inactive. ++#define SYS_GPE_ACTS_TMU_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_TMU_ACT 0x00000800 ++/** MRG Status ++ Shows the activation status of the MRG domain. This domain contains the Merger. */ ++#define SYS_GPE_ACTS_MRG 0x00000400 ++/* The block is inactive. ++#define SYS_GPE_ACTS_MRG_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_MRG_ACT 0x00000400 ++/** DISP Status ++ Shows the activation status of the DISP domain. This domain contains the Dispatcher. */ ++#define SYS_GPE_ACTS_DISP 0x00000200 ++/* The block is inactive. ++#define SYS_GPE_ACTS_DISP_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_DISP_ACT 0x00000200 ++/** IQM Status ++ Shows the activation status of the IQM domain. This domain contains the IQM. */ ++#define SYS_GPE_ACTS_IQM 0x00000100 ++/* The block is inactive. ++#define SYS_GPE_ACTS_IQM_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_IQM_ACT 0x00000100 ++/** CPUE Status ++ Shows the activation status of the CPUE domain. This domain contains all parts related to the CPU EGRESS interface. */ ++#define SYS_GPE_ACTS_CPUE 0x00000080 ++/* The block is inactive. ++#define SYS_GPE_ACTS_CPUE_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_CPUE_ACT 0x00000080 ++/** CPUI Status ++ Shows the activation status of the CPUI domain. This domain contains all parts related to the CPU INGRESS interface. */ ++#define SYS_GPE_ACTS_CPUI 0x00000040 ++/* The block is inactive. ++#define SYS_GPE_ACTS_CPUI_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_CPUI_ACT 0x00000040 ++/** GPONE Status ++ Shows the activation status of the GPONE domain. This domain contains all parts related to the GPON (GTC) EGRESS interface. */ ++#define SYS_GPE_ACTS_GPONE 0x00000020 ++/* The block is inactive. ++#define SYS_GPE_ACTS_GPONE_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_GPONE_ACT 0x00000020 ++/** GPONI Status ++ Shows the activation status of the GPONI domain. This domain contains all parts related to the GPON (GTC) INGRESS interface. */ ++#define SYS_GPE_ACTS_GPONI 0x00000010 ++/* The block is inactive. ++#define SYS_GPE_ACTS_GPONI_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_GPONI_ACT 0x00000010 ++/** LAN3 Status ++ Shows the activation status of the LAN3 domain. This domain contains all parts related to the LAN3 interface. */ ++#define SYS_GPE_ACTS_LAN3 0x00000008 ++/* The block is inactive. ++#define SYS_GPE_ACTS_LAN3_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_LAN3_ACT 0x00000008 ++/** LAN2 Status ++ Shows the activation status of the LAN2 domain. This domain contains all parts related to the LAN2 interface. */ ++#define SYS_GPE_ACTS_LAN2 0x00000004 ++/* The block is inactive. ++#define SYS_GPE_ACTS_LAN2_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_LAN2_ACT 0x00000004 ++/** LAN1 Status ++ Shows the activation status of the LAN1 domain. This domain contains all parts related to the LAN1 interface. */ ++#define SYS_GPE_ACTS_LAN1 0x00000002 ++/* The block is inactive. ++#define SYS_GPE_ACTS_LAN1_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_LAN1_ACT 0x00000002 ++/** LAN0 Status ++ Shows the activation status of the LAN0 domain. This domain contains all parts related to the LAN0 interface. */ ++#define SYS_GPE_ACTS_LAN0 0x00000001 ++/* The block is inactive. ++#define SYS_GPE_ACTS_LAN0_INACT 0x00000000 */ ++/** The block is active. */ ++#define SYS_GPE_ACTS_LAN0_ACT 0x00000001 ++ ++/* Fields of "Activation Register" */ ++/** Activate COP7 ++ Sets the activation flag of the COP7 domain. This domain contains the Coprocessor 7 of the SCE. */ ++#define SYS_GPE_ACT_COP7 0x80000000 ++/* No-Operation ++#define SYS_GPE_ACT_COP7_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_COP7_SET 0x80000000 ++/** Activate COP6 ++ Sets the activation flag of the COP6 domain. This domain contains the Coprocessor 6 of the SCE. */ ++#define SYS_GPE_ACT_COP6 0x40000000 ++/* No-Operation ++#define SYS_GPE_ACT_COP6_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_COP6_SET 0x40000000 ++/** Activate COP5 ++ Sets the activation flag of the COP5 domain. This domain contains the Coprocessor 5 of the SCE. */ ++#define SYS_GPE_ACT_COP5 0x20000000 ++/* No-Operation ++#define SYS_GPE_ACT_COP5_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_COP5_SET 0x20000000 ++/** Activate COP4 ++ Sets the activation flag of the COP4 domain. This domain contains the Coprocessor 4 of the SCE. */ ++#define SYS_GPE_ACT_COP4 0x10000000 ++/* No-Operation ++#define SYS_GPE_ACT_COP4_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_COP4_SET 0x10000000 ++/** Activate COP3 ++ Sets the activation flag of the COP3 domain. This domain contains the Coprocessor 3 of the SCE. */ ++#define SYS_GPE_ACT_COP3 0x08000000 ++/* No-Operation ++#define SYS_GPE_ACT_COP3_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_COP3_SET 0x08000000 ++/** Activate COP2 ++ Sets the activation flag of the COP2 domain. This domain contains the Coprocessor 2 of the SCE. */ ++#define SYS_GPE_ACT_COP2 0x04000000 ++/* No-Operation ++#define SYS_GPE_ACT_COP2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_COP2_SET 0x04000000 ++/** Activate COP1 ++ Sets the activation flag of the COP1 domain. This domain contains the Coprocessor 1 of the SCE. */ ++#define SYS_GPE_ACT_COP1 0x02000000 ++/* No-Operation ++#define SYS_GPE_ACT_COP1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_COP1_SET 0x02000000 ++/** Activate COP0 ++ Sets the activation flag of the COP0 domain. This domain contains the Coprocessor 0 of the SCE. */ ++#define SYS_GPE_ACT_COP0 0x01000000 ++/* No-Operation ++#define SYS_GPE_ACT_COP0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_COP0_SET 0x01000000 ++/** Activate PE5 ++ Sets the activation flag of the PE5 domain. This domain contains the Processing Element 5 of the SCE. */ ++#define SYS_GPE_ACT_PE5 0x00200000 ++/* No-Operation ++#define SYS_GPE_ACT_PE5_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_PE5_SET 0x00200000 ++/** Activate PE4 ++ Sets the activation flag of the PE4 domain. This domain contains the Processing Element 4 of the SCE. */ ++#define SYS_GPE_ACT_PE4 0x00100000 ++/* No-Operation ++#define SYS_GPE_ACT_PE4_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_PE4_SET 0x00100000 ++/** Activate PE3 ++ Sets the activation flag of the PE3 domain. This domain contains the Processing Element 3 of the SCE. */ ++#define SYS_GPE_ACT_PE3 0x00080000 ++/* No-Operation ++#define SYS_GPE_ACT_PE3_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_PE3_SET 0x00080000 ++/** Activate PE2 ++ Sets the activation flag of the PE2 domain. This domain contains the Processing Element 2 of the SCE. */ ++#define SYS_GPE_ACT_PE2 0x00040000 ++/* No-Operation ++#define SYS_GPE_ACT_PE2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_PE2_SET 0x00040000 ++/** Activate PE1 ++ Sets the activation flag of the PE1 domain. This domain contains the Processing Element 1 of the SCE. */ ++#define SYS_GPE_ACT_PE1 0x00020000 ++/* No-Operation ++#define SYS_GPE_ACT_PE1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_PE1_SET 0x00020000 ++/** Activate PE0 ++ Sets the activation flag of the PE0 domain. This domain contains the Processing Element 0 of the SCE. */ ++#define SYS_GPE_ACT_PE0 0x00010000 ++/* No-Operation ++#define SYS_GPE_ACT_PE0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_PE0_SET 0x00010000 ++/** Activate ARB ++ Sets the activation flag of the ARB domain. This domain contains the Arbiter. */ ++#define SYS_GPE_ACT_ARB 0x00002000 ++/* No-Operation ++#define SYS_GPE_ACT_ARB_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_ARB_SET 0x00002000 ++/** Activate FSQM ++ Sets the activation flag of the FSQM domain. This domain contains the FSQM. */ ++#define SYS_GPE_ACT_FSQM 0x00001000 ++/* No-Operation ++#define SYS_GPE_ACT_FSQM_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_FSQM_SET 0x00001000 ++/** Activate TMU ++ Sets the activation flag of the TMU domain. This domain contains the TMU. */ ++#define SYS_GPE_ACT_TMU 0x00000800 ++/* No-Operation ++#define SYS_GPE_ACT_TMU_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_TMU_SET 0x00000800 ++/** Activate MRG ++ Sets the activation flag of the MRG domain. This domain contains the Merger. */ ++#define SYS_GPE_ACT_MRG 0x00000400 ++/* No-Operation ++#define SYS_GPE_ACT_MRG_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_MRG_SET 0x00000400 ++/** Activate DISP ++ Sets the activation flag of the DISP domain. This domain contains the Dispatcher. */ ++#define SYS_GPE_ACT_DISP 0x00000200 ++/* No-Operation ++#define SYS_GPE_ACT_DISP_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_DISP_SET 0x00000200 ++/** Activate IQM ++ Sets the activation flag of the IQM domain. This domain contains the IQM. */ ++#define SYS_GPE_ACT_IQM 0x00000100 ++/* No-Operation ++#define SYS_GPE_ACT_IQM_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_IQM_SET 0x00000100 ++/** Activate CPUE ++ Sets the activation flag of the CPUE domain. This domain contains all parts related to the CPU EGRESS interface. */ ++#define SYS_GPE_ACT_CPUE 0x00000080 ++/* No-Operation ++#define SYS_GPE_ACT_CPUE_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_CPUE_SET 0x00000080 ++/** Activate CPUI ++ Sets the activation flag of the CPUI domain. This domain contains all parts related to the CPU INGRESS interface. */ ++#define SYS_GPE_ACT_CPUI 0x00000040 ++/* No-Operation ++#define SYS_GPE_ACT_CPUI_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_CPUI_SET 0x00000040 ++/** Activate GPONE ++ Sets the activation flag of the GPONE domain. This domain contains all parts related to the GPON (GTC) EGRESS interface. */ ++#define SYS_GPE_ACT_GPONE 0x00000020 ++/* No-Operation ++#define SYS_GPE_ACT_GPONE_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_GPONE_SET 0x00000020 ++/** Activate GPONI ++ Sets the activation flag of the GPONI domain. This domain contains all parts related to the GPON (GTC) INGRESS interface. */ ++#define SYS_GPE_ACT_GPONI 0x00000010 ++/* No-Operation ++#define SYS_GPE_ACT_GPONI_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_GPONI_SET 0x00000010 ++/** Activate LAN3 ++ Sets the activation flag of the LAN3 domain. This domain contains all parts related to the LAN3 interface. */ ++#define SYS_GPE_ACT_LAN3 0x00000008 ++/* No-Operation ++#define SYS_GPE_ACT_LAN3_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_LAN3_SET 0x00000008 ++/** Activate LAN2 ++ Sets the activation flag of the LAN2 domain. This domain contains all parts related to the LAN2 interface. */ ++#define SYS_GPE_ACT_LAN2 0x00000004 ++/* No-Operation ++#define SYS_GPE_ACT_LAN2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_LAN2_SET 0x00000004 ++/** Activate LAN1 ++ Sets the activation flag of the LAN1 domain. This domain contains all parts related to the LAN1 interface. */ ++#define SYS_GPE_ACT_LAN1 0x00000002 ++/* No-Operation ++#define SYS_GPE_ACT_LAN1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_LAN1_SET 0x00000002 ++/** Activate LAN0 ++ Sets the activation flag of the LAN0 domain. This domain contains all parts related to the LAN0 interface. */ ++#define SYS_GPE_ACT_LAN0 0x00000001 ++/* No-Operation ++#define SYS_GPE_ACT_LAN0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_ACT_LAN0_SET 0x00000001 ++ ++/* Fields of "Deactivation Register" */ ++/** Deactivate COP7 ++ Clears the activation flag of the COP7 domain. This domain contains the Coprocessor 7 of the SCE. */ ++#define SYS_GPE_DEACT_COP7 0x80000000 ++/* No-Operation ++#define SYS_GPE_DEACT_COP7_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_COP7_CLR 0x80000000 ++/** Deactivate COP6 ++ Clears the activation flag of the COP6 domain. This domain contains the Coprocessor 6 of the SCE. */ ++#define SYS_GPE_DEACT_COP6 0x40000000 ++/* No-Operation ++#define SYS_GPE_DEACT_COP6_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_COP6_CLR 0x40000000 ++/** Deactivate COP5 ++ Clears the activation flag of the COP5 domain. This domain contains the Coprocessor 5 of the SCE. */ ++#define SYS_GPE_DEACT_COP5 0x20000000 ++/* No-Operation ++#define SYS_GPE_DEACT_COP5_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_COP5_CLR 0x20000000 ++/** Deactivate COP4 ++ Clears the activation flag of the COP4 domain. This domain contains the Coprocessor 4 of the SCE. */ ++#define SYS_GPE_DEACT_COP4 0x10000000 ++/* No-Operation ++#define SYS_GPE_DEACT_COP4_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_COP4_CLR 0x10000000 ++/** Deactivate COP3 ++ Clears the activation flag of the COP3 domain. This domain contains the Coprocessor 3 of the SCE. */ ++#define SYS_GPE_DEACT_COP3 0x08000000 ++/* No-Operation ++#define SYS_GPE_DEACT_COP3_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_COP3_CLR 0x08000000 ++/** Deactivate COP2 ++ Clears the activation flag of the COP2 domain. This domain contains the Coprocessor 2 of the SCE. */ ++#define SYS_GPE_DEACT_COP2 0x04000000 ++/* No-Operation ++#define SYS_GPE_DEACT_COP2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_COP2_CLR 0x04000000 ++/** Deactivate COP1 ++ Clears the activation flag of the COP1 domain. This domain contains the Coprocessor 1 of the SCE. */ ++#define SYS_GPE_DEACT_COP1 0x02000000 ++/* No-Operation ++#define SYS_GPE_DEACT_COP1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_COP1_CLR 0x02000000 ++/** Deactivate COP0 ++ Clears the activation flag of the COP0 domain. This domain contains the Coprocessor 0 of the SCE. */ ++#define SYS_GPE_DEACT_COP0 0x01000000 ++/* No-Operation ++#define SYS_GPE_DEACT_COP0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_COP0_CLR 0x01000000 ++/** Deactivate PE5 ++ Clears the activation flag of the PE5 domain. This domain contains the Processing Element 5 of the SCE. */ ++#define SYS_GPE_DEACT_PE5 0x00200000 ++/* No-Operation ++#define SYS_GPE_DEACT_PE5_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_PE5_CLR 0x00200000 ++/** Deactivate PE4 ++ Clears the activation flag of the PE4 domain. This domain contains the Processing Element 4 of the SCE. */ ++#define SYS_GPE_DEACT_PE4 0x00100000 ++/* No-Operation ++#define SYS_GPE_DEACT_PE4_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_PE4_CLR 0x00100000 ++/** Deactivate PE3 ++ Clears the activation flag of the PE3 domain. This domain contains the Processing Element 3 of the SCE. */ ++#define SYS_GPE_DEACT_PE3 0x00080000 ++/* No-Operation ++#define SYS_GPE_DEACT_PE3_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_PE3_CLR 0x00080000 ++/** Deactivate PE2 ++ Clears the activation flag of the PE2 domain. This domain contains the Processing Element 2 of the SCE. */ ++#define SYS_GPE_DEACT_PE2 0x00040000 ++/* No-Operation ++#define SYS_GPE_DEACT_PE2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_PE2_CLR 0x00040000 ++/** Deactivate PE1 ++ Clears the activation flag of the PE1 domain. This domain contains the Processing Element 1 of the SCE. */ ++#define SYS_GPE_DEACT_PE1 0x00020000 ++/* No-Operation ++#define SYS_GPE_DEACT_PE1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_PE1_CLR 0x00020000 ++/** Deactivate PE0 ++ Clears the activation flag of the PE0 domain. This domain contains the Processing Element 0 of the SCE. */ ++#define SYS_GPE_DEACT_PE0 0x00010000 ++/* No-Operation ++#define SYS_GPE_DEACT_PE0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_PE0_CLR 0x00010000 ++/** Deactivate ARB ++ Clears the activation flag of the ARB domain. This domain contains the Arbiter. */ ++#define SYS_GPE_DEACT_ARB 0x00002000 ++/* No-Operation ++#define SYS_GPE_DEACT_ARB_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_ARB_CLR 0x00002000 ++/** Deactivate FSQM ++ Clears the activation flag of the FSQM domain. This domain contains the FSQM. */ ++#define SYS_GPE_DEACT_FSQM 0x00001000 ++/* No-Operation ++#define SYS_GPE_DEACT_FSQM_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_FSQM_CLR 0x00001000 ++/** Deactivate TMU ++ Clears the activation flag of the TMU domain. This domain contains the TMU. */ ++#define SYS_GPE_DEACT_TMU 0x00000800 ++/* No-Operation ++#define SYS_GPE_DEACT_TMU_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_TMU_CLR 0x00000800 ++/** Deactivate MRG ++ Clears the activation flag of the MRG domain. This domain contains the Merger. */ ++#define SYS_GPE_DEACT_MRG 0x00000400 ++/* No-Operation ++#define SYS_GPE_DEACT_MRG_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_MRG_CLR 0x00000400 ++/** Deactivate DISP ++ Clears the activation flag of the DISP domain. This domain contains the Dispatcher. */ ++#define SYS_GPE_DEACT_DISP 0x00000200 ++/* No-Operation ++#define SYS_GPE_DEACT_DISP_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_DISP_CLR 0x00000200 ++/** Deactivate IQM ++ Clears the activation flag of the IQM domain. This domain contains the IQM. */ ++#define SYS_GPE_DEACT_IQM 0x00000100 ++/* No-Operation ++#define SYS_GPE_DEACT_IQM_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_IQM_CLR 0x00000100 ++/** Deactivate CPUE ++ Clears the activation flag of the CPUE domain. This domain contains all parts related to the CPU EGRESS interface. */ ++#define SYS_GPE_DEACT_CPUE 0x00000080 ++/* No-Operation ++#define SYS_GPE_DEACT_CPUE_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_CPUE_CLR 0x00000080 ++/** Deactivate CPUI ++ Clears the activation flag of the CPUI domain. This domain contains all parts related to the CPU INGRESS interface. */ ++#define SYS_GPE_DEACT_CPUI 0x00000040 ++/* No-Operation ++#define SYS_GPE_DEACT_CPUI_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_CPUI_CLR 0x00000040 ++/** Deactivate GPONE ++ Clears the activation flag of the GPONE domain. This domain contains all parts related to the GPON (GTC) EGRESS interface. */ ++#define SYS_GPE_DEACT_GPONE 0x00000020 ++/* No-Operation ++#define SYS_GPE_DEACT_GPONE_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_GPONE_CLR 0x00000020 ++/** Deactivate GPONI ++ Clears the activation flag of the GPONI domain. This domain contains all parts related to the GPON (GTC) INGRESS interface. */ ++#define SYS_GPE_DEACT_GPONI 0x00000010 ++/* No-Operation ++#define SYS_GPE_DEACT_GPONI_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_GPONI_CLR 0x00000010 ++/** Deactivate LAN3 ++ Clears the activation flag of the LAN3 domain. This domain contains all parts related to the LAN3 interface. */ ++#define SYS_GPE_DEACT_LAN3 0x00000008 ++/* No-Operation ++#define SYS_GPE_DEACT_LAN3_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_LAN3_CLR 0x00000008 ++/** Deactivate LAN2 ++ Clears the activation flag of the LAN2 domain. This domain contains all parts related to the LAN2 interface. */ ++#define SYS_GPE_DEACT_LAN2 0x00000004 ++/* No-Operation ++#define SYS_GPE_DEACT_LAN2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_LAN2_CLR 0x00000004 ++/** Deactivate LAN1 ++ Clears the activation flag of the LAN1 domain. This domain contains all parts related to the LAN1 interface. */ ++#define SYS_GPE_DEACT_LAN1 0x00000002 ++/* No-Operation ++#define SYS_GPE_DEACT_LAN1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_LAN1_CLR 0x00000002 ++/** Deactivate LAN0 ++ Clears the activation flag of the LAN0 domain. This domain contains all parts related to the LAN0 interface. */ ++#define SYS_GPE_DEACT_LAN0 0x00000001 ++/* No-Operation ++#define SYS_GPE_DEACT_LAN0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_DEACT_LAN0_CLR 0x00000001 ++ ++/* Fields of "Reboot Trigger Register" */ ++/** Reboot COP7 ++ Triggers a reboot of the COP7 domain. This domain contains the Coprocessor 7 of the SCE. */ ++#define SYS_GPE_RBT_COP7 0x80000000 ++/* No-Operation ++#define SYS_GPE_RBT_COP7_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_COP7_TRIG 0x80000000 ++/** Reboot COP6 ++ Triggers a reboot of the COP6 domain. This domain contains the Coprocessor 6 of the SCE. */ ++#define SYS_GPE_RBT_COP6 0x40000000 ++/* No-Operation ++#define SYS_GPE_RBT_COP6_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_COP6_TRIG 0x40000000 ++/** Reboot COP5 ++ Triggers a reboot of the COP5 domain. This domain contains the Coprocessor 5 of the SCE. */ ++#define SYS_GPE_RBT_COP5 0x20000000 ++/* No-Operation ++#define SYS_GPE_RBT_COP5_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_COP5_TRIG 0x20000000 ++/** Reboot COP4 ++ Triggers a reboot of the COP4 domain. This domain contains the Coprocessor 4 of the SCE. */ ++#define SYS_GPE_RBT_COP4 0x10000000 ++/* No-Operation ++#define SYS_GPE_RBT_COP4_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_COP4_TRIG 0x10000000 ++/** Reboot COP3 ++ Triggers a reboot of the COP3 domain. This domain contains the Coprocessor 3 of the SCE. */ ++#define SYS_GPE_RBT_COP3 0x08000000 ++/* No-Operation ++#define SYS_GPE_RBT_COP3_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_COP3_TRIG 0x08000000 ++/** Reboot COP2 ++ Triggers a reboot of the COP2 domain. This domain contains the Coprocessor 2 of the SCE. */ ++#define SYS_GPE_RBT_COP2 0x04000000 ++/* No-Operation ++#define SYS_GPE_RBT_COP2_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_COP2_TRIG 0x04000000 ++/** Reboot COP1 ++ Triggers a reboot of the COP1 domain. This domain contains the Coprocessor 1 of the SCE. */ ++#define SYS_GPE_RBT_COP1 0x02000000 ++/* No-Operation ++#define SYS_GPE_RBT_COP1_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_COP1_TRIG 0x02000000 ++/** Reboot COP0 ++ Triggers a reboot of the COP0 domain. This domain contains the Coprocessor 0 of the SCE. */ ++#define SYS_GPE_RBT_COP0 0x01000000 ++/* No-Operation ++#define SYS_GPE_RBT_COP0_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_COP0_TRIG 0x01000000 ++/** Reboot PE5 ++ Triggers a reboot of the PE5 domain. This domain contains the Processing Element 5 of the SCE. */ ++#define SYS_GPE_RBT_PE5 0x00200000 ++/* No-Operation ++#define SYS_GPE_RBT_PE5_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_PE5_TRIG 0x00200000 ++/** Reboot PE4 ++ Triggers a reboot of the PE4 domain. This domain contains the Processing Element 4 of the SCE. */ ++#define SYS_GPE_RBT_PE4 0x00100000 ++/* No-Operation ++#define SYS_GPE_RBT_PE4_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_PE4_TRIG 0x00100000 ++/** Reboot PE3 ++ Triggers a reboot of the PE3 domain. This domain contains the Processing Element 3 of the SCE. */ ++#define SYS_GPE_RBT_PE3 0x00080000 ++/* No-Operation ++#define SYS_GPE_RBT_PE3_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_PE3_TRIG 0x00080000 ++/** Reboot PE2 ++ Triggers a reboot of the PE2 domain. This domain contains the Processing Element 2 of the SCE. */ ++#define SYS_GPE_RBT_PE2 0x00040000 ++/* No-Operation ++#define SYS_GPE_RBT_PE2_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_PE2_TRIG 0x00040000 ++/** Reboot PE1 ++ Triggers a reboot of the PE1 domain. This domain contains the Processing Element 1 of the SCE. */ ++#define SYS_GPE_RBT_PE1 0x00020000 ++/* No-Operation ++#define SYS_GPE_RBT_PE1_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_PE1_TRIG 0x00020000 ++/** Reboot PE0 ++ Triggers a reboot of the PE0 domain. This domain contains the Processing Element 0 of the SCE. */ ++#define SYS_GPE_RBT_PE0 0x00010000 ++/* No-Operation ++#define SYS_GPE_RBT_PE0_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_PE0_TRIG 0x00010000 ++/** Reboot ARB ++ Triggers a reboot of the ARB domain. This domain contains the Arbiter. */ ++#define SYS_GPE_RBT_ARB 0x00002000 ++/* No-Operation ++#define SYS_GPE_RBT_ARB_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_ARB_TRIG 0x00002000 ++/** Reboot FSQM ++ Triggers a reboot of the FSQM domain. This domain contains the FSQM. */ ++#define SYS_GPE_RBT_FSQM 0x00001000 ++/* No-Operation ++#define SYS_GPE_RBT_FSQM_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_FSQM_TRIG 0x00001000 ++/** Reboot TMU ++ Triggers a reboot of the TMU domain. This domain contains the TMU. */ ++#define SYS_GPE_RBT_TMU 0x00000800 ++/* No-Operation ++#define SYS_GPE_RBT_TMU_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_TMU_TRIG 0x00000800 ++/** Reboot MRG ++ Triggers a reboot of the MRG domain. This domain contains the Merger. */ ++#define SYS_GPE_RBT_MRG 0x00000400 ++/* No-Operation ++#define SYS_GPE_RBT_MRG_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_MRG_TRIG 0x00000400 ++/** Reboot DISP ++ Triggers a reboot of the DISP domain. This domain contains the Dispatcher. */ ++#define SYS_GPE_RBT_DISP 0x00000200 ++/* No-Operation ++#define SYS_GPE_RBT_DISP_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_DISP_TRIG 0x00000200 ++/** Reboot IQM ++ Triggers a reboot of the IQM domain. This domain contains the IQM. */ ++#define SYS_GPE_RBT_IQM 0x00000100 ++/* No-Operation ++#define SYS_GPE_RBT_IQM_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_IQM_TRIG 0x00000100 ++/** Reboot CPUE ++ Triggers a reboot of the CPUE domain. This domain contains all parts related to the CPU EGRESS interface. */ ++#define SYS_GPE_RBT_CPUE 0x00000080 ++/* No-Operation ++#define SYS_GPE_RBT_CPUE_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_CPUE_TRIG 0x00000080 ++/** Reboot CPUI ++ Triggers a reboot of the CPUI domain. This domain contains all parts related to the CPU INGRESS interface. */ ++#define SYS_GPE_RBT_CPUI 0x00000040 ++/* No-Operation ++#define SYS_GPE_RBT_CPUI_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_CPUI_TRIG 0x00000040 ++/** Reboot GPONE ++ Triggers a reboot of the GPONE domain. This domain contains all parts related to the GPON (GTC) EGRESS interface. */ ++#define SYS_GPE_RBT_GPONE 0x00000020 ++/* No-Operation ++#define SYS_GPE_RBT_GPONE_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_GPONE_TRIG 0x00000020 ++/** Reboot GPONI ++ Triggers a reboot of the GPONI domain. This domain contains all parts related to the GPON (GTC) INGRESS interface. */ ++#define SYS_GPE_RBT_GPONI 0x00000010 ++/* No-Operation ++#define SYS_GPE_RBT_GPONI_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_GPONI_TRIG 0x00000010 ++/** Reboot LAN3 ++ Triggers a reboot of the LAN3 domain. This domain contains all parts related to the LAN3 interface. */ ++#define SYS_GPE_RBT_LAN3 0x00000008 ++/* No-Operation ++#define SYS_GPE_RBT_LAN3_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_LAN3_TRIG 0x00000008 ++/** Reboot LAN2 ++ Triggers a reboot of the LAN2 domain. This domain contains all parts related to the LAN2 interface. */ ++#define SYS_GPE_RBT_LAN2 0x00000004 ++/* No-Operation ++#define SYS_GPE_RBT_LAN2_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_LAN2_TRIG 0x00000004 ++/** Reboot LAN1 ++ Triggers a reboot of the LAN1 domain. This domain contains all parts related to the LAN1 interface. */ ++#define SYS_GPE_RBT_LAN1 0x00000002 ++/* No-Operation ++#define SYS_GPE_RBT_LAN1_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_LAN1_TRIG 0x00000002 ++/** Reboot LAN0 ++ Triggers a reboot of the LAN0 domain. This domain contains all parts related to the LAN0 interface. */ ++#define SYS_GPE_RBT_LAN0 0x00000001 ++/* No-Operation ++#define SYS_GPE_RBT_LAN0_NOP 0x00000000 */ ++/** Trigger */ ++#define SYS_GPE_RBT_LAN0_TRIG 0x00000001 ++ ++/* Fields of "Power Down Configuration Register" */ ++/** Enable Power Down COP7 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_COP7 0x80000000 ++/* Disable ++#define SYS_GPE_PDCFG_COP7_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_COP7_EN 0x80000000 ++/** Enable Power Down COP6 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_COP6 0x40000000 ++/* Disable ++#define SYS_GPE_PDCFG_COP6_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_COP6_EN 0x40000000 ++/** Enable Power Down COP5 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_COP5 0x20000000 ++/* Disable ++#define SYS_GPE_PDCFG_COP5_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_COP5_EN 0x20000000 ++/** Enable Power Down COP4 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_COP4 0x10000000 ++/* Disable ++#define SYS_GPE_PDCFG_COP4_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_COP4_EN 0x10000000 ++/** Enable Power Down COP3 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_COP3 0x08000000 ++/* Disable ++#define SYS_GPE_PDCFG_COP3_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_COP3_EN 0x08000000 ++/** Enable Power Down COP2 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_COP2 0x04000000 ++/* Disable ++#define SYS_GPE_PDCFG_COP2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_COP2_EN 0x04000000 ++/** Enable Power Down COP1 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_COP1 0x02000000 ++/* Disable ++#define SYS_GPE_PDCFG_COP1_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_COP1_EN 0x02000000 ++/** Enable Power Down COP0 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_COP0 0x01000000 ++/* Disable ++#define SYS_GPE_PDCFG_COP0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_COP0_EN 0x01000000 ++/** Enable Power Down PE5 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_PE5 0x00200000 ++/* Disable ++#define SYS_GPE_PDCFG_PE5_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_PE5_EN 0x00200000 ++/** Enable Power Down PE4 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_PE4 0x00100000 ++/* Disable ++#define SYS_GPE_PDCFG_PE4_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_PE4_EN 0x00100000 ++/** Enable Power Down PE3 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_PE3 0x00080000 ++/* Disable ++#define SYS_GPE_PDCFG_PE3_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_PE3_EN 0x00080000 ++/** Enable Power Down PE2 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_PE2 0x00040000 ++/* Disable ++#define SYS_GPE_PDCFG_PE2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_PE2_EN 0x00040000 ++/** Enable Power Down PE1 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_PE1 0x00020000 ++/* Disable ++#define SYS_GPE_PDCFG_PE1_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_PE1_EN 0x00020000 ++/** Enable Power Down PE0 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_PE0 0x00010000 ++/* Disable ++#define SYS_GPE_PDCFG_PE0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_PE0_EN 0x00010000 ++/** Enable Power Down ARB ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_ARB 0x00002000 ++/* Disable ++#define SYS_GPE_PDCFG_ARB_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_ARB_EN 0x00002000 ++/** Enable Power Down FSQM ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_FSQM 0x00001000 ++/* Disable ++#define SYS_GPE_PDCFG_FSQM_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_FSQM_EN 0x00001000 ++/** Enable Power Down TMU ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_TMU 0x00000800 ++/* Disable ++#define SYS_GPE_PDCFG_TMU_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_TMU_EN 0x00000800 ++/** Enable Power Down MRG ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_MRG 0x00000400 ++/* Disable ++#define SYS_GPE_PDCFG_MRG_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_MRG_EN 0x00000400 ++/** Enable Power Down DISP ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_DISP 0x00000200 ++/* Disable ++#define SYS_GPE_PDCFG_DISP_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_DISP_EN 0x00000200 ++/** Enable Power Down IQM ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_IQM 0x00000100 ++/* Disable ++#define SYS_GPE_PDCFG_IQM_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_IQM_EN 0x00000100 ++/** Enable Power Down CPUE ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_CPUE 0x00000080 ++/* Disable ++#define SYS_GPE_PDCFG_CPUE_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_CPUE_EN 0x00000080 ++/** Enable Power Down CPUI ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_CPUI 0x00000040 ++/* Disable ++#define SYS_GPE_PDCFG_CPUI_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_CPUI_EN 0x00000040 ++/** Enable Power Down GPONE ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_GPONE 0x00000020 ++/* Disable ++#define SYS_GPE_PDCFG_GPONE_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_GPONE_EN 0x00000020 ++/** Enable Power Down GPONI ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_GPONI 0x00000010 ++/* Disable ++#define SYS_GPE_PDCFG_GPONI_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_GPONI_EN 0x00000010 ++/** Enable Power Down LAN3 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_LAN3 0x00000008 ++/* Disable ++#define SYS_GPE_PDCFG_LAN3_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_LAN3_EN 0x00000008 ++/** Enable Power Down LAN2 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_LAN2 0x00000004 ++/* Disable ++#define SYS_GPE_PDCFG_LAN2_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_LAN2_EN 0x00000004 ++/** Enable Power Down LAN1 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_LAN1 0x00000002 ++/* Disable ++#define SYS_GPE_PDCFG_LAN1_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_LAN1_EN 0x00000002 ++/** Enable Power Down LAN0 ++ Ignore this bit as power-gating is not supported for this chip. */ ++#define SYS_GPE_PDCFG_LAN0 0x00000001 ++/* Disable ++#define SYS_GPE_PDCFG_LAN0_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_PDCFG_LAN0_EN 0x00000001 ++ ++/* Fields of "Sleep Source Configuration Register" */ ++/** Sleep/Wakeup Source CPU ++ Selects the CPU access signal as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_CPU 0x00020000 ++/* Not selected ++#define SYS_GPE_SSCFG_CPU_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_CPU_SEL 0x00020000 ++/** Sleep/Wakeup Source FSQM ++ Selects the FSQM signal as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_FSQM 0x00008000 ++/* Not selected ++#define SYS_GPE_SSCFG_FSQM_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_FSQM_SEL 0x00008000 ++/** Sleep/Wakeup Source GPONT ++ Selects the FIFO empty signal of the TCONT Request FIFO of port GPON as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_GPONT 0x00002000 ++/* Not selected ++#define SYS_GPE_SSCFG_GPONT_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_GPONT_SEL 0x00002000 ++/** Sleep/Wakeup Source GPONE ++ Selects the FIFO empty signal of the EGRESS FIFO of port GPON as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_GPONE 0x00001000 ++/* Not selected ++#define SYS_GPE_SSCFG_GPONE_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_GPONE_SEL 0x00001000 ++/** Sleep/Wakeup Source LAN3E ++ Selects the FIFO empty signal of the EGRESS FIFO of port LAN3 as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_LAN3E 0x00000800 ++/* Not selected ++#define SYS_GPE_SSCFG_LAN3E_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_LAN3E_SEL 0x00000800 ++/** Sleep/Wakeup Source LAN2E ++ Selects the FIFO empty signal of the EGRESS FIFO of port LAN2 as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_LAN2E 0x00000400 ++/* Not selected ++#define SYS_GPE_SSCFG_LAN2E_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_LAN2E_SEL 0x00000400 ++/** Sleep/Wakeup Source LAN1E ++ Selects the FIFO empty signal of the EGRESS FIFO of port LAN1 as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_LAN1E 0x00000200 ++/* Not selected ++#define SYS_GPE_SSCFG_LAN1E_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_LAN1E_SEL 0x00000200 ++/** Sleep/Wakeup Source LAN0E ++ Selects the FIFO empty signal of the EGRESS FIFO of port LAN0 as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_LAN0E 0x00000100 ++/* Not selected ++#define SYS_GPE_SSCFG_LAN0E_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_LAN0E_SEL 0x00000100 ++/** Sleep/Wakeup Source GPONI ++ Selects the FIFO empty signal of the INGRESS FIFO of port GPON as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_GPONI 0x00000010 ++/* Not selected ++#define SYS_GPE_SSCFG_GPONI_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_GPONI_SEL 0x00000010 ++/** Sleep/Wakeup Source LAN3I ++ Selects the FIFO empty signal of the INGRESS FIFO of port LAN3 as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_LAN3I 0x00000008 ++/* Not selected ++#define SYS_GPE_SSCFG_LAN3I_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_LAN3I_SEL 0x00000008 ++/** Sleep/Wakeup Source LAN2I ++ Selects the FIFO empty signal of the INGRESS FIFO of port LAN2 as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_LAN2I 0x00000004 ++/* Not selected ++#define SYS_GPE_SSCFG_LAN2I_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_LAN2I_SEL 0x00000004 ++/** Sleep/Wakeup Source LAN1I ++ Selects the FIFO empty signal of the INGRESS FIFO of port LAN1 as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_LAN1I 0x00000002 ++/* Not selected ++#define SYS_GPE_SSCFG_LAN1I_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_LAN1I_SEL 0x00000002 ++/** Sleep/Wakeup Source LAN0I ++ Selects the FIFO empty signal of the INGRESS FIFO of port LAN0 as sleep/wakeup source. */ ++#define SYS_GPE_SSCFG_LAN0I 0x00000001 ++/* Not selected ++#define SYS_GPE_SSCFG_LAN0I_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SSCFG_LAN0I_SEL 0x00000001 ++ ++/* Fields of "Sleep Source Timer Register" */ ++/** Sleep Delay Value ++ A HW sleep request is delayed by this value multiplied by 3.2ns before it takes effect. A wakeup request is not delayed but takes effect immediately. Values lower than 256 are limited to 256. */ ++#define SYS_GPE_SST_SDV_MASK 0x7FFFFFFF ++/** field offset */ ++#define SYS_GPE_SST_SDV_OFFSET 0 ++ ++/* Fields of "Sleep Destination Status Register" */ ++/** Shutoff COP7 on HW Sleep ++ If selected the domain COP7 is shutoff on a hardware sleep request. This domain contains the Coprocessor 7 of the SCE. */ ++#define SYS_GPE_SDS_COP7 0x80000000 ++/* Not selected ++#define SYS_GPE_SDS_COP7_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_COP7_SEL 0x80000000 ++/** Shutoff COP6 on HW Sleep ++ If selected the domain COP6 is shutoff on a hardware sleep request. This domain contains the Coprocessor 6 of the SCE. */ ++#define SYS_GPE_SDS_COP6 0x40000000 ++/* Not selected ++#define SYS_GPE_SDS_COP6_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_COP6_SEL 0x40000000 ++/** Shutoff COP5 on HW Sleep ++ If selected the domain COP5 is shutoff on a hardware sleep request. This domain contains the Coprocessor 5 of the SCE. */ ++#define SYS_GPE_SDS_COP5 0x20000000 ++/* Not selected ++#define SYS_GPE_SDS_COP5_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_COP5_SEL 0x20000000 ++/** Shutoff COP4 on HW Sleep ++ If selected the domain COP4 is shutoff on a hardware sleep request. This domain contains the Coprocessor 4 of the SCE. */ ++#define SYS_GPE_SDS_COP4 0x10000000 ++/* Not selected ++#define SYS_GPE_SDS_COP4_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_COP4_SEL 0x10000000 ++/** Shutoff COP3 on HW Sleep ++ If selected the domain COP3 is shutoff on a hardware sleep request. This domain contains the Coprocessor 3 of the SCE. */ ++#define SYS_GPE_SDS_COP3 0x08000000 ++/* Not selected ++#define SYS_GPE_SDS_COP3_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_COP3_SEL 0x08000000 ++/** Shutoff COP2 on HW Sleep ++ If selected the domain COP2 is shutoff on a hardware sleep request. This domain contains the Coprocessor 2 of the SCE. */ ++#define SYS_GPE_SDS_COP2 0x04000000 ++/* Not selected ++#define SYS_GPE_SDS_COP2_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_COP2_SEL 0x04000000 ++/** Shutoff COP1 on HW Sleep ++ If selected the domain COP1 is shutoff on a hardware sleep request. This domain contains the Coprocessor 1 of the SCE. */ ++#define SYS_GPE_SDS_COP1 0x02000000 ++/* Not selected ++#define SYS_GPE_SDS_COP1_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_COP1_SEL 0x02000000 ++/** Shutoff COP0 on HW Sleep ++ If selected the domain COP0 is shutoff on a hardware sleep request. This domain contains the Coprocessor 0 of the SCE. */ ++#define SYS_GPE_SDS_COP0 0x01000000 ++/* Not selected ++#define SYS_GPE_SDS_COP0_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_COP0_SEL 0x01000000 ++/** Shutoff PE5 on HW Sleep ++ If selected the domain PE5 is shutoff on a hardware sleep request. This domain contains the Processing Element 5 of the SCE. */ ++#define SYS_GPE_SDS_PE5 0x00200000 ++/* Not selected ++#define SYS_GPE_SDS_PE5_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_PE5_SEL 0x00200000 ++/** Shutoff PE4 on HW Sleep ++ If selected the domain PE4 is shutoff on a hardware sleep request. This domain contains the Processing Element 4 of the SCE. */ ++#define SYS_GPE_SDS_PE4 0x00100000 ++/* Not selected ++#define SYS_GPE_SDS_PE4_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_PE4_SEL 0x00100000 ++/** Shutoff PE3 on HW Sleep ++ If selected the domain PE3 is shutoff on a hardware sleep request. This domain contains the Processing Element 3 of the SCE. */ ++#define SYS_GPE_SDS_PE3 0x00080000 ++/* Not selected ++#define SYS_GPE_SDS_PE3_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_PE3_SEL 0x00080000 ++/** Shutoff PE2 on HW Sleep ++ If selected the domain PE2 is shutoff on a hardware sleep request. This domain contains the Processing Element 2 of the SCE. */ ++#define SYS_GPE_SDS_PE2 0x00040000 ++/* Not selected ++#define SYS_GPE_SDS_PE2_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_PE2_SEL 0x00040000 ++/** Shutoff PE1 on HW Sleep ++ If selected the domain PE1 is shutoff on a hardware sleep request. This domain contains the Processing Element 1 of the SCE. */ ++#define SYS_GPE_SDS_PE1 0x00020000 ++/* Not selected ++#define SYS_GPE_SDS_PE1_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_PE1_SEL 0x00020000 ++/** Shutoff PE0 on HW Sleep ++ If selected the domain PE0 is shutoff on a hardware sleep request. This domain contains the Processing Element 0 of the SCE. */ ++#define SYS_GPE_SDS_PE0 0x00010000 ++/* Not selected ++#define SYS_GPE_SDS_PE0_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_PE0_SEL 0x00010000 ++/** Shutoff ARB on HW Sleep ++ If selected the domain ARB is shutoff on a hardware sleep request. This domain contains the Arbiter. */ ++#define SYS_GPE_SDS_ARB 0x00002000 ++/* Not selected ++#define SYS_GPE_SDS_ARB_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_ARB_SEL 0x00002000 ++/** Shutoff FSQM on HW Sleep ++ If selected the domain FSQM is shutoff on a hardware sleep request. This domain contains the FSQM. */ ++#define SYS_GPE_SDS_FSQM 0x00001000 ++/* Not selected ++#define SYS_GPE_SDS_FSQM_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_FSQM_SEL 0x00001000 ++/** Shutoff TMU on HW Sleep ++ If selected the domain TMU is shutoff on a hardware sleep request. This domain contains the TMU. */ ++#define SYS_GPE_SDS_TMU 0x00000800 ++/* Not selected ++#define SYS_GPE_SDS_TMU_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_TMU_SEL 0x00000800 ++/** Shutoff MRG on HW Sleep ++ If selected the domain MRG is shutoff on a hardware sleep request. This domain contains the Merger. */ ++#define SYS_GPE_SDS_MRG 0x00000400 ++/* Not selected ++#define SYS_GPE_SDS_MRG_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_MRG_SEL 0x00000400 ++/** Shutoff DISP on HW Sleep ++ If selected the domain DISP is shutoff on a hardware sleep request. This domain contains the Dispatcher. */ ++#define SYS_GPE_SDS_DISP 0x00000200 ++/* Not selected ++#define SYS_GPE_SDS_DISP_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_DISP_SEL 0x00000200 ++/** Shutoff IQM on HW Sleep ++ If selected the domain IQM is shutoff on a hardware sleep request. This domain contains the IQM. */ ++#define SYS_GPE_SDS_IQM 0x00000100 ++/* Not selected ++#define SYS_GPE_SDS_IQM_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_IQM_SEL 0x00000100 ++/** Shutoff CPUE on HW Sleep ++ If selected the domain CPUE is shutoff on a hardware sleep request. This domain contains all parts related to the CPU EGRESS interface. */ ++#define SYS_GPE_SDS_CPUE 0x00000080 ++/* Not selected ++#define SYS_GPE_SDS_CPUE_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_CPUE_SEL 0x00000080 ++/** Shutoff CPUI on HW Sleep ++ If selected the domain CPUI is shutoff on a hardware sleep request. This domain contains all parts related to the CPU INGRESS interface. */ ++#define SYS_GPE_SDS_CPUI 0x00000040 ++/* Not selected ++#define SYS_GPE_SDS_CPUI_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_CPUI_SEL 0x00000040 ++/** Shutoff GPONE on HW Sleep ++ If selected the domain GPONE is shutoff on a hardware sleep request. This domain contains all parts related to the GPON (GTC) EGRESS interface. */ ++#define SYS_GPE_SDS_GPONE 0x00000020 ++/* Not selected ++#define SYS_GPE_SDS_GPONE_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_GPONE_SEL 0x00000020 ++/** Shutoff GPONI on HW Sleep ++ If selected the domain GPONI is shutoff on a hardware sleep request. This domain contains all parts related to the GPON (GTC) INGRESS interface. */ ++#define SYS_GPE_SDS_GPONI 0x00000010 ++/* Not selected ++#define SYS_GPE_SDS_GPONI_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_GPONI_SEL 0x00000010 ++/** Shutoff LAN3 on HW Sleep ++ If selected the domain LAN3 is shutoff on a hardware sleep request. This domain contains all parts related to the LAN3 interface. */ ++#define SYS_GPE_SDS_LAN3 0x00000008 ++/* Not selected ++#define SYS_GPE_SDS_LAN3_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_LAN3_SEL 0x00000008 ++/** Shutoff LAN2 on HW Sleep ++ If selected the domain LAN2 is shutoff on a hardware sleep request. This domain contains all parts related to the LAN2 interface. */ ++#define SYS_GPE_SDS_LAN2 0x00000004 ++/* Not selected ++#define SYS_GPE_SDS_LAN2_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_LAN2_SEL 0x00000004 ++/** Shutoff LAN1 on HW Sleep ++ If selected the domain LAN1 is shutoff on a hardware sleep request. This domain contains all parts related to the LAN1 interface. */ ++#define SYS_GPE_SDS_LAN1 0x00000002 ++/* Not selected ++#define SYS_GPE_SDS_LAN1_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_LAN1_SEL 0x00000002 ++/** Shutoff LAN0 on HW Sleep ++ If selected the domain LAN0 is shutoff on a hardware sleep request. This domain contains all parts related to the LAN0 interface. */ ++#define SYS_GPE_SDS_LAN0 0x00000001 ++/* Not selected ++#define SYS_GPE_SDS_LAN0_NSEL 0x00000000 */ ++/** Selected */ ++#define SYS_GPE_SDS_LAN0_SEL 0x00000001 ++ ++/* Fields of "Sleep Destination Set Register" */ ++/** Set Sleep Selection COP7 ++ Sets the selection bit for domain COP7This domain contains the Coprocessor 7 of the SCE. */ ++#define SYS_GPE_SDSET_COP7 0x80000000 ++/* No-Operation ++#define SYS_GPE_SDSET_COP7_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_COP7_SET 0x80000000 ++/** Set Sleep Selection COP6 ++ Sets the selection bit for domain COP6This domain contains the Coprocessor 6 of the SCE. */ ++#define SYS_GPE_SDSET_COP6 0x40000000 ++/* No-Operation ++#define SYS_GPE_SDSET_COP6_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_COP6_SET 0x40000000 ++/** Set Sleep Selection COP5 ++ Sets the selection bit for domain COP5This domain contains the Coprocessor 5 of the SCE. */ ++#define SYS_GPE_SDSET_COP5 0x20000000 ++/* No-Operation ++#define SYS_GPE_SDSET_COP5_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_COP5_SET 0x20000000 ++/** Set Sleep Selection COP4 ++ Sets the selection bit for domain COP4This domain contains the Coprocessor 4 of the SCE. */ ++#define SYS_GPE_SDSET_COP4 0x10000000 ++/* No-Operation ++#define SYS_GPE_SDSET_COP4_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_COP4_SET 0x10000000 ++/** Set Sleep Selection COP3 ++ Sets the selection bit for domain COP3This domain contains the Coprocessor 3 of the SCE. */ ++#define SYS_GPE_SDSET_COP3 0x08000000 ++/* No-Operation ++#define SYS_GPE_SDSET_COP3_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_COP3_SET 0x08000000 ++/** Set Sleep Selection COP2 ++ Sets the selection bit for domain COP2This domain contains the Coprocessor 2 of the SCE. */ ++#define SYS_GPE_SDSET_COP2 0x04000000 ++/* No-Operation ++#define SYS_GPE_SDSET_COP2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_COP2_SET 0x04000000 ++/** Set Sleep Selection COP1 ++ Sets the selection bit for domain COP1This domain contains the Coprocessor 1 of the SCE. */ ++#define SYS_GPE_SDSET_COP1 0x02000000 ++/* No-Operation ++#define SYS_GPE_SDSET_COP1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_COP1_SET 0x02000000 ++/** Set Sleep Selection COP0 ++ Sets the selection bit for domain COP0This domain contains the Coprocessor 0 of the SCE. */ ++#define SYS_GPE_SDSET_COP0 0x01000000 ++/* No-Operation ++#define SYS_GPE_SDSET_COP0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_COP0_SET 0x01000000 ++/** Set Sleep Selection PE5 ++ Sets the selection bit for domain PE5This domain contains the Processing Element 5 of the SCE. */ ++#define SYS_GPE_SDSET_PE5 0x00200000 ++/* No-Operation ++#define SYS_GPE_SDSET_PE5_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_PE5_SET 0x00200000 ++/** Set Sleep Selection PE4 ++ Sets the selection bit for domain PE4This domain contains the Processing Element 4 of the SCE. */ ++#define SYS_GPE_SDSET_PE4 0x00100000 ++/* No-Operation ++#define SYS_GPE_SDSET_PE4_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_PE4_SET 0x00100000 ++/** Set Sleep Selection PE3 ++ Sets the selection bit for domain PE3This domain contains the Processing Element 3 of the SCE. */ ++#define SYS_GPE_SDSET_PE3 0x00080000 ++/* No-Operation ++#define SYS_GPE_SDSET_PE3_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_PE3_SET 0x00080000 ++/** Set Sleep Selection PE2 ++ Sets the selection bit for domain PE2This domain contains the Processing Element 2 of the SCE. */ ++#define SYS_GPE_SDSET_PE2 0x00040000 ++/* No-Operation ++#define SYS_GPE_SDSET_PE2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_PE2_SET 0x00040000 ++/** Set Sleep Selection PE1 ++ Sets the selection bit for domain PE1This domain contains the Processing Element 1 of the SCE. */ ++#define SYS_GPE_SDSET_PE1 0x00020000 ++/* No-Operation ++#define SYS_GPE_SDSET_PE1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_PE1_SET 0x00020000 ++/** Set Sleep Selection PE0 ++ Sets the selection bit for domain PE0This domain contains the Processing Element 0 of the SCE. */ ++#define SYS_GPE_SDSET_PE0 0x00010000 ++/* No-Operation ++#define SYS_GPE_SDSET_PE0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_PE0_SET 0x00010000 ++/** Set Sleep Selection ARB ++ Sets the selection bit for domain ARBThis domain contains the Arbiter. */ ++#define SYS_GPE_SDSET_ARB 0x00002000 ++/* No-Operation ++#define SYS_GPE_SDSET_ARB_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_ARB_SET 0x00002000 ++/** Set Sleep Selection FSQM ++ Sets the selection bit for domain FSQMThis domain contains the FSQM. */ ++#define SYS_GPE_SDSET_FSQM 0x00001000 ++/* No-Operation ++#define SYS_GPE_SDSET_FSQM_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_FSQM_SET 0x00001000 ++/** Set Sleep Selection TMU ++ Sets the selection bit for domain TMUThis domain contains the TMU. */ ++#define SYS_GPE_SDSET_TMU 0x00000800 ++/* No-Operation ++#define SYS_GPE_SDSET_TMU_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_TMU_SET 0x00000800 ++/** Set Sleep Selection MRG ++ Sets the selection bit for domain MRGThis domain contains the Merger. */ ++#define SYS_GPE_SDSET_MRG 0x00000400 ++/* No-Operation ++#define SYS_GPE_SDSET_MRG_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_MRG_SET 0x00000400 ++/** Set Sleep Selection DISP ++ Sets the selection bit for domain DISPThis domain contains the Dispatcher. */ ++#define SYS_GPE_SDSET_DISP 0x00000200 ++/* No-Operation ++#define SYS_GPE_SDSET_DISP_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_DISP_SET 0x00000200 ++/** Set Sleep Selection IQM ++ Sets the selection bit for domain IQMThis domain contains the IQM. */ ++#define SYS_GPE_SDSET_IQM 0x00000100 ++/* No-Operation ++#define SYS_GPE_SDSET_IQM_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_IQM_SET 0x00000100 ++/** Set Sleep Selection CPUE ++ Sets the selection bit for domain CPUEThis domain contains all parts related to the CPU EGRESS interface. */ ++#define SYS_GPE_SDSET_CPUE 0x00000080 ++/* No-Operation ++#define SYS_GPE_SDSET_CPUE_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_CPUE_SET 0x00000080 ++/** Set Sleep Selection CPUI ++ Sets the selection bit for domain CPUIThis domain contains all parts related to the CPU INGRESS interface. */ ++#define SYS_GPE_SDSET_CPUI 0x00000040 ++/* No-Operation ++#define SYS_GPE_SDSET_CPUI_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_CPUI_SET 0x00000040 ++/** Set Sleep Selection GPONE ++ Sets the selection bit for domain GPONEThis domain contains all parts related to the GPON (GTC) EGRESS interface. */ ++#define SYS_GPE_SDSET_GPONE 0x00000020 ++/* No-Operation ++#define SYS_GPE_SDSET_GPONE_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_GPONE_SET 0x00000020 ++/** Set Sleep Selection GPONI ++ Sets the selection bit for domain GPONIThis domain contains all parts related to the GPON (GTC) INGRESS interface. */ ++#define SYS_GPE_SDSET_GPONI 0x00000010 ++/* No-Operation ++#define SYS_GPE_SDSET_GPONI_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_GPONI_SET 0x00000010 ++/** Set Sleep Selection LAN3 ++ Sets the selection bit for domain LAN3This domain contains all parts related to the LAN3 interface. */ ++#define SYS_GPE_SDSET_LAN3 0x00000008 ++/* No-Operation ++#define SYS_GPE_SDSET_LAN3_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_LAN3_SET 0x00000008 ++/** Set Sleep Selection LAN2 ++ Sets the selection bit for domain LAN2This domain contains all parts related to the LAN2 interface. */ ++#define SYS_GPE_SDSET_LAN2 0x00000004 ++/* No-Operation ++#define SYS_GPE_SDSET_LAN2_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_LAN2_SET 0x00000004 ++/** Set Sleep Selection LAN1 ++ Sets the selection bit for domain LAN1This domain contains all parts related to the LAN1 interface. */ ++#define SYS_GPE_SDSET_LAN1 0x00000002 ++/* No-Operation ++#define SYS_GPE_SDSET_LAN1_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_LAN1_SET 0x00000002 ++/** Set Sleep Selection LAN0 ++ Sets the selection bit for domain LAN0This domain contains all parts related to the LAN0 interface. */ ++#define SYS_GPE_SDSET_LAN0 0x00000001 ++/* No-Operation ++#define SYS_GPE_SDSET_LAN0_NOP 0x00000000 */ ++/** Set */ ++#define SYS_GPE_SDSET_LAN0_SET 0x00000001 ++ ++/* Fields of "Sleep Destination Clear Register" */ ++/** Clear Sleep Selection COP7 ++ Clears the selection bit for domain COP7This domain contains the Coprocessor 7 of the SCE. */ ++#define SYS_GPE_SDCLR_COP7 0x80000000 ++/* No-Operation ++#define SYS_GPE_SDCLR_COP7_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_COP7_CLR 0x80000000 ++/** Clear Sleep Selection COP6 ++ Clears the selection bit for domain COP6This domain contains the Coprocessor 6 of the SCE. */ ++#define SYS_GPE_SDCLR_COP6 0x40000000 ++/* No-Operation ++#define SYS_GPE_SDCLR_COP6_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_COP6_CLR 0x40000000 ++/** Clear Sleep Selection COP5 ++ Clears the selection bit for domain COP5This domain contains the Coprocessor 5 of the SCE. */ ++#define SYS_GPE_SDCLR_COP5 0x20000000 ++/* No-Operation ++#define SYS_GPE_SDCLR_COP5_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_COP5_CLR 0x20000000 ++/** Clear Sleep Selection COP4 ++ Clears the selection bit for domain COP4This domain contains the Coprocessor 4 of the SCE. */ ++#define SYS_GPE_SDCLR_COP4 0x10000000 ++/* No-Operation ++#define SYS_GPE_SDCLR_COP4_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_COP4_CLR 0x10000000 ++/** Clear Sleep Selection COP3 ++ Clears the selection bit for domain COP3This domain contains the Coprocessor 3 of the SCE. */ ++#define SYS_GPE_SDCLR_COP3 0x08000000 ++/* No-Operation ++#define SYS_GPE_SDCLR_COP3_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_COP3_CLR 0x08000000 ++/** Clear Sleep Selection COP2 ++ Clears the selection bit for domain COP2This domain contains the Coprocessor 2 of the SCE. */ ++#define SYS_GPE_SDCLR_COP2 0x04000000 ++/* No-Operation ++#define SYS_GPE_SDCLR_COP2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_COP2_CLR 0x04000000 ++/** Clear Sleep Selection COP1 ++ Clears the selection bit for domain COP1This domain contains the Coprocessor 1 of the SCE. */ ++#define SYS_GPE_SDCLR_COP1 0x02000000 ++/* No-Operation ++#define SYS_GPE_SDCLR_COP1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_COP1_CLR 0x02000000 ++/** Clear Sleep Selection COP0 ++ Clears the selection bit for domain COP0This domain contains the Coprocessor 0 of the SCE. */ ++#define SYS_GPE_SDCLR_COP0 0x01000000 ++/* No-Operation ++#define SYS_GPE_SDCLR_COP0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_COP0_CLR 0x01000000 ++/** Clear Sleep Selection PE5 ++ Clears the selection bit for domain PE5This domain contains the Processing Element 5 of the SCE. */ ++#define SYS_GPE_SDCLR_PE5 0x00200000 ++/* No-Operation ++#define SYS_GPE_SDCLR_PE5_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_PE5_CLR 0x00200000 ++/** Clear Sleep Selection PE4 ++ Clears the selection bit for domain PE4This domain contains the Processing Element 4 of the SCE. */ ++#define SYS_GPE_SDCLR_PE4 0x00100000 ++/* No-Operation ++#define SYS_GPE_SDCLR_PE4_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_PE4_CLR 0x00100000 ++/** Clear Sleep Selection PE3 ++ Clears the selection bit for domain PE3This domain contains the Processing Element 3 of the SCE. */ ++#define SYS_GPE_SDCLR_PE3 0x00080000 ++/* No-Operation ++#define SYS_GPE_SDCLR_PE3_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_PE3_CLR 0x00080000 ++/** Clear Sleep Selection PE2 ++ Clears the selection bit for domain PE2This domain contains the Processing Element 2 of the SCE. */ ++#define SYS_GPE_SDCLR_PE2 0x00040000 ++/* No-Operation ++#define SYS_GPE_SDCLR_PE2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_PE2_CLR 0x00040000 ++/** Clear Sleep Selection PE1 ++ Clears the selection bit for domain PE1This domain contains the Processing Element 1 of the SCE. */ ++#define SYS_GPE_SDCLR_PE1 0x00020000 ++/* No-Operation ++#define SYS_GPE_SDCLR_PE1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_PE1_CLR 0x00020000 ++/** Clear Sleep Selection PE0 ++ Clears the selection bit for domain PE0This domain contains the Processing Element 0 of the SCE. */ ++#define SYS_GPE_SDCLR_PE0 0x00010000 ++/* No-Operation ++#define SYS_GPE_SDCLR_PE0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_PE0_CLR 0x00010000 ++/** Clear Sleep Selection ARB ++ Clears the selection bit for domain ARBThis domain contains the Arbiter. */ ++#define SYS_GPE_SDCLR_ARB 0x00002000 ++/* No-Operation ++#define SYS_GPE_SDCLR_ARB_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_ARB_CLR 0x00002000 ++/** Clear Sleep Selection FSQM ++ Clears the selection bit for domain FSQMThis domain contains the FSQM. */ ++#define SYS_GPE_SDCLR_FSQM 0x00001000 ++/* No-Operation ++#define SYS_GPE_SDCLR_FSQM_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_FSQM_CLR 0x00001000 ++/** Clear Sleep Selection TMU ++ Clears the selection bit for domain TMUThis domain contains the TMU. */ ++#define SYS_GPE_SDCLR_TMU 0x00000800 ++/* No-Operation ++#define SYS_GPE_SDCLR_TMU_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_TMU_CLR 0x00000800 ++/** Clear Sleep Selection MRG ++ Clears the selection bit for domain MRGThis domain contains the Merger. */ ++#define SYS_GPE_SDCLR_MRG 0x00000400 ++/* No-Operation ++#define SYS_GPE_SDCLR_MRG_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_MRG_CLR 0x00000400 ++/** Clear Sleep Selection DISP ++ Clears the selection bit for domain DISPThis domain contains the Dispatcher. */ ++#define SYS_GPE_SDCLR_DISP 0x00000200 ++/* No-Operation ++#define SYS_GPE_SDCLR_DISP_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_DISP_CLR 0x00000200 ++/** Clear Sleep Selection IQM ++ Clears the selection bit for domain IQMThis domain contains the IQM. */ ++#define SYS_GPE_SDCLR_IQM 0x00000100 ++/* No-Operation ++#define SYS_GPE_SDCLR_IQM_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_IQM_CLR 0x00000100 ++/** Clear Sleep Selection CPUE ++ Clears the selection bit for domain CPUEThis domain contains all parts related to the CPU EGRESS interface. */ ++#define SYS_GPE_SDCLR_CPUE 0x00000080 ++/* No-Operation ++#define SYS_GPE_SDCLR_CPUE_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_CPUE_CLR 0x00000080 ++/** Clear Sleep Selection CPUI ++ Clears the selection bit for domain CPUIThis domain contains all parts related to the CPU INGRESS interface. */ ++#define SYS_GPE_SDCLR_CPUI 0x00000040 ++/* No-Operation ++#define SYS_GPE_SDCLR_CPUI_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_CPUI_CLR 0x00000040 ++/** Clear Sleep Selection GPONE ++ Clears the selection bit for domain GPONEThis domain contains all parts related to the GPON (GTC) EGRESS interface. */ ++#define SYS_GPE_SDCLR_GPONE 0x00000020 ++/* No-Operation ++#define SYS_GPE_SDCLR_GPONE_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_GPONE_CLR 0x00000020 ++/** Clear Sleep Selection GPONI ++ Clears the selection bit for domain GPONIThis domain contains all parts related to the GPON (GTC) INGRESS interface. */ ++#define SYS_GPE_SDCLR_GPONI 0x00000010 ++/* No-Operation ++#define SYS_GPE_SDCLR_GPONI_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_GPONI_CLR 0x00000010 ++/** Clear Sleep Selection LAN3 ++ Clears the selection bit for domain LAN3This domain contains all parts related to the LAN3 interface. */ ++#define SYS_GPE_SDCLR_LAN3 0x00000008 ++/* No-Operation ++#define SYS_GPE_SDCLR_LAN3_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_LAN3_CLR 0x00000008 ++/** Clear Sleep Selection LAN2 ++ Clears the selection bit for domain LAN2This domain contains all parts related to the LAN2 interface. */ ++#define SYS_GPE_SDCLR_LAN2 0x00000004 ++/* No-Operation ++#define SYS_GPE_SDCLR_LAN2_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_LAN2_CLR 0x00000004 ++/** Clear Sleep Selection LAN1 ++ Clears the selection bit for domain LAN1This domain contains all parts related to the LAN1 interface. */ ++#define SYS_GPE_SDCLR_LAN1 0x00000002 ++/* No-Operation ++#define SYS_GPE_SDCLR_LAN1_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_LAN1_CLR 0x00000002 ++/** Clear Sleep Selection LAN0 ++ Clears the selection bit for domain LAN0This domain contains all parts related to the LAN0 interface. */ ++#define SYS_GPE_SDCLR_LAN0 0x00000001 ++/* No-Operation ++#define SYS_GPE_SDCLR_LAN0_NOP 0x00000000 */ ++/** Clear */ ++#define SYS_GPE_SDCLR_LAN0_CLR 0x00000001 ++ ++/* Fields of "IRNCS Capture Register" */ ++/** FSQM wakeup request ++ The FSQM submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_FSQMWR 0x80000000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_FSQMWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_FSQMWR_INTACK 0x80000000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_FSQMWR_INTOCC 0x80000000 ++/** GPONT wakeup request ++ The TCONT Request FIFO of port GPON submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONTWR 0x20000000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_GPONTWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONTWR_INTACK 0x20000000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_GPONTWR_INTOCC 0x20000000 ++/** GPONE wakeup request ++ The EGRESS FIFO of port GPON submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONEWR 0x10000000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_GPONEWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONEWR_INTACK 0x10000000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_GPONEWR_INTOCC 0x10000000 ++/** LAN3E wakeup request ++ The EGRESS FIFO of port LAN3 submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN3EWR 0x08000000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN3EWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN3EWR_INTACK 0x08000000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN3EWR_INTOCC 0x08000000 ++/** LAN2E wakeup requestThe ENGRESS FIFO of port LAN2 submitted a wakeup request. ++ This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN2EWR 0x04000000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN2EWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN2EWR_INTACK 0x04000000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN2EWR_INTOCC 0x04000000 ++/** LAN1E wakeup request ++ The EGRESS FIFO of port LAN1 submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN1EWR 0x02000000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN1EWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN1EWR_INTACK 0x02000000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN1EWR_INTOCC 0x02000000 ++/** LAN0E wakeup request ++ The EGRESS FIFO of port LAN0 submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN0EWR 0x01000000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN0EWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN0EWR_INTACK 0x01000000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN0EWR_INTOCC 0x01000000 ++/** GPONI wakeup request ++ The INGRESS FIFO of port GPON submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONIWR 0x00100000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_GPONIWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONIWR_INTACK 0x00100000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_GPONIWR_INTOCC 0x00100000 ++/** LAN3I wakeup request ++ The INGRESS FIFO of port LAN3 submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN3IWR 0x00080000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN3IWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN3IWR_INTACK 0x00080000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN3IWR_INTOCC 0x00080000 ++/** LAN2I wakeup request ++ The INGRESS FIFO of port LAN2 submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN2IWR 0x00040000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN2IWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN2IWR_INTACK 0x00040000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN2IWR_INTOCC 0x00040000 ++/** LAN1I wakeup request ++ The INGRESS FIFO of port LAN1 submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN1IWR 0x00020000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN1IWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN1IWR_INTACK 0x00020000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN1IWR_INTOCC 0x00020000 ++/** LAN0I wakeup request ++ The INGRESS FIFO of port LAN0 submitted a wakeup request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN0IWR 0x00010000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN0IWR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN0IWR_INTACK 0x00010000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN0IWR_INTOCC 0x00010000 ++/** FSQM sleep request ++ The FSQM submitted a sleep request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_FSQMSR 0x00008000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_FSQMSR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_FSQMSR_INTACK 0x00008000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_FSQMSR_INTOCC 0x00008000 ++/** GPONT sleep request ++ The TCONT Request FIFO of port GPON submitted a sleep request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONTSR 0x00002000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_GPONTSR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONTSR_INTACK 0x00002000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_GPONTSR_INTOCC 0x00002000 ++/** GPONE sleep request ++ The EGRESS FIFO of port GPON submitted a sleep request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONESR 0x00001000 ++/* Nothing ++#define SYS_GPE_IRNCSCR_GPONESR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONESR_INTACK 0x00001000 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_GPONESR_INTOCC 0x00001000 ++/** LAN3E sleep request ++ The EGRESS FIFO of port LAN3 submitted a sleep request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN3ESR 0x00000800 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN3ESR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN3ESR_INTACK 0x00000800 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN3ESR_INTOCC 0x00000800 ++/** LAN2E sleep requestThe ENGRESS FIFO of port LAN2 submitted a sleep request. ++ This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN2ESR 0x00000400 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN2ESR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN2ESR_INTACK 0x00000400 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN2ESR_INTOCC 0x00000400 ++/** LAN1E sleep request ++ The EGRESS FIFO of port LAN1 submitted a sleep request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN1ESR 0x00000200 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN1ESR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN1ESR_INTACK 0x00000200 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN1ESR_INTOCC 0x00000200 ++/** LAN0E sleep request ++ The EGRESS FIFO of port LAN0 submitted a sleep request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN0ESR 0x00000100 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN0ESR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN0ESR_INTACK 0x00000100 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN0ESR_INTOCC 0x00000100 ++/** GPONI sleep request ++ The INGRESS FIFO of port GPON submitted a sleep request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONISR 0x00000010 ++/* Nothing ++#define SYS_GPE_IRNCSCR_GPONISR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_GPONISR_INTACK 0x00000010 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_GPONISR_INTOCC 0x00000010 ++/** LAN3I sleep request ++ The INGRESS FIFO of port LAN3 submitted a sleep request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN3ISR 0x00000008 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN3ISR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN3ISR_INTACK 0x00000008 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN3ISR_INTOCC 0x00000008 ++/** LAN2I sleep request ++ The INGRESS FIFO of port LAN2 submitted a sleep request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN2ISR 0x00000004 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN2ISR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN2ISR_INTACK 0x00000004 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN2ISR_INTOCC 0x00000004 ++/** LAN1I sleep request ++ The INGRESS FIFO of port LAN1 submitted a sleep request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN1ISR 0x00000002 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN1ISR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN1ISR_INTACK 0x00000002 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN1ISR_INTOCC 0x00000002 ++/** LAN0I sleep request ++ The INGRESS FIFO of port LAN0 submitted a sleep request. This bit is edge-sensitive. This bit contributes to the indirect interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN0ISR 0x00000001 ++/* Nothing ++#define SYS_GPE_IRNCSCR_LAN0ISR_NULL 0x00000000 */ ++/** Write: Acknowledge the interrupt. */ ++#define SYS_GPE_IRNCSCR_LAN0ISR_INTACK 0x00000001 ++/** Read: Interrupt occurred. */ ++#define SYS_GPE_IRNCSCR_LAN0ISR_INTOCC 0x00000001 ++ ++/* Fields of "IRNCS Interrupt Control Register" */ ++/** FSQM wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_FSQMWR 0x80000000 ++/** GPONT wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_GPONTWR 0x20000000 ++/** GPONE wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_GPONEWR 0x10000000 ++/** LAN3E wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN3EWR 0x08000000 ++/** LAN2E wakeup requestThe ENGRESS FIFO of port LAN2 submitted a wakeup request. ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN2EWR 0x04000000 ++/** LAN1E wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN1EWR 0x02000000 ++/** LAN0E wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN0EWR 0x01000000 ++/** GPONI wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_GPONIWR 0x00100000 ++/** LAN3I wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN3IWR 0x00080000 ++/** LAN2I wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN2IWR 0x00040000 ++/** LAN1I wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN1IWR 0x00020000 ++/** LAN0I wakeup request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN0IWR 0x00010000 ++/** FSQM sleep request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_FSQMSR 0x00008000 ++/** GPONT sleep request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_GPONTSR 0x00002000 ++/** GPONE sleep request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_GPONESR 0x00001000 ++/** LAN3E sleep request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN3ESR 0x00000800 ++/** LAN2E sleep requestThe ENGRESS FIFO of port LAN2 submitted a sleep request. ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN2ESR 0x00000400 ++/** LAN1E sleep request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN1ESR 0x00000200 ++/** LAN0E sleep request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN0ESR 0x00000100 ++/** GPONI sleep request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_GPONISR 0x00000010 ++/** LAN3I sleep request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN3ISR 0x00000008 ++/** LAN2I sleep request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN2ISR 0x00000004 ++/** LAN1I sleep request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN1ISR 0x00000002 ++/** LAN0I sleep request ++ Interrupt control bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSICR_LAN0ISR 0x00000001 ++ ++/* Fields of "IRNCS Interrupt Enable Register" */ ++/** FSQM wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_FSQMWR 0x80000000 ++/* Disable ++#define SYS_GPE_IRNCSEN_FSQMWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_FSQMWR_EN 0x80000000 ++/** GPONT wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_GPONTWR 0x20000000 ++/* Disable ++#define SYS_GPE_IRNCSEN_GPONTWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_GPONTWR_EN 0x20000000 ++/** GPONE wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_GPONEWR 0x10000000 ++/* Disable ++#define SYS_GPE_IRNCSEN_GPONEWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_GPONEWR_EN 0x10000000 ++/** LAN3E wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN3EWR 0x08000000 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN3EWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN3EWR_EN 0x08000000 ++/** LAN2E wakeup requestThe ENGRESS FIFO of port LAN2 submitted a wakeup request. ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN2EWR 0x04000000 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN2EWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN2EWR_EN 0x04000000 ++/** LAN1E wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN1EWR 0x02000000 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN1EWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN1EWR_EN 0x02000000 ++/** LAN0E wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN0EWR 0x01000000 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN0EWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN0EWR_EN 0x01000000 ++/** GPONI wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_GPONIWR 0x00100000 ++/* Disable ++#define SYS_GPE_IRNCSEN_GPONIWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_GPONIWR_EN 0x00100000 ++/** LAN3I wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN3IWR 0x00080000 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN3IWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN3IWR_EN 0x00080000 ++/** LAN2I wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN2IWR 0x00040000 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN2IWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN2IWR_EN 0x00040000 ++/** LAN1I wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN1IWR 0x00020000 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN1IWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN1IWR_EN 0x00020000 ++/** LAN0I wakeup request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN0IWR 0x00010000 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN0IWR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN0IWR_EN 0x00010000 ++/** FSQM sleep request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_FSQMSR 0x00008000 ++/* Disable ++#define SYS_GPE_IRNCSEN_FSQMSR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_FSQMSR_EN 0x00008000 ++/** GPONT sleep request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_GPONTSR 0x00002000 ++/* Disable ++#define SYS_GPE_IRNCSEN_GPONTSR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_GPONTSR_EN 0x00002000 ++/** GPONE sleep request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_GPONESR 0x00001000 ++/* Disable ++#define SYS_GPE_IRNCSEN_GPONESR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_GPONESR_EN 0x00001000 ++/** LAN3E sleep request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN3ESR 0x00000800 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN3ESR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN3ESR_EN 0x00000800 ++/** LAN2E sleep requestThe ENGRESS FIFO of port LAN2 submitted a sleep request. ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN2ESR 0x00000400 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN2ESR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN2ESR_EN 0x00000400 ++/** LAN1E sleep request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN1ESR 0x00000200 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN1ESR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN1ESR_EN 0x00000200 ++/** LAN0E sleep request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN0ESR 0x00000100 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN0ESR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN0ESR_EN 0x00000100 ++/** GPONI sleep request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_GPONISR 0x00000010 ++/* Disable ++#define SYS_GPE_IRNCSEN_GPONISR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_GPONISR_EN 0x00000010 ++/** LAN3I sleep request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN3ISR 0x00000008 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN3ISR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN3ISR_EN 0x00000008 ++/** LAN2I sleep request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN2ISR 0x00000004 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN2ISR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN2ISR_EN 0x00000004 ++/** LAN1I sleep request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN1ISR 0x00000002 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN1ISR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN1ISR_EN 0x00000002 ++/** LAN0I sleep request ++ Interrupt enable bit for the corresponding bit in the IRNCSCR register. */ ++#define SYS_GPE_IRNCSEN_LAN0ISR 0x00000001 ++/* Disable ++#define SYS_GPE_IRNCSEN_LAN0ISR_DIS 0x00000000 */ ++/** Enable */ ++#define SYS_GPE_IRNCSEN_LAN0ISR_EN 0x00000001 ++ ++/*! @} */ /* SYS_GPE_REGISTER */ ++ ++#endif /* _sys_gpe_reg_h */ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/sysctrl.h +@@ -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 as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ * ++ * Copyright (C) 2010 Thomas Langer, Lantiq Deutschland ++ */ ++ ++#ifndef __FALCON_SYSCTRL_H ++#define __FALCON_SYSCTRL_H ++ ++extern void sys1_hw_activate(u32 mask); ++extern void sys1_hw_deactivate(u32 mask); ++extern void sys1_hw_clk_enable(u32 mask); ++extern void sys1_hw_clk_disable(u32 mask); ++extern void sys1_hw_activate_or_reboot(u32 mask); ++ ++extern void sys_eth_hw_activate(u32 mask); ++extern void sys_eth_hw_deactivate(u32 mask); ++extern void sys_eth_hw_clk_enable(u32 mask); ++extern void sys_eth_hw_clk_disable(u32 mask); ++extern void sys_eth_hw_activate_or_reboot(u32 mask); ++ ++extern void sys_gpe_hw_activate(u32 mask); ++extern void sys_gpe_hw_deactivate(u32 mask); ++extern void sys_gpe_hw_clk_enable(u32 mask); ++extern void sys_gpe_hw_clk_disable(u32 mask); ++extern void sys_gpe_hw_activate_or_reboot(u32 mask); ++extern int sys_gpe_hw_is_activated(u32 mask); ++ ++#endif /* __FALCON_SYSCTRL_H */ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/cpu-feature-overrides.h +@@ -0,0 +1,58 @@ ++/* ++ * Lantiq FALCON specific CPU feature overrides ++ * ++ * Copyright (C) 2010 Thomas Langer, Lantiq Deutschland ++ * ++ * This file was derived from: include/asm-mips/cpu-features.h ++ * Copyright (C) 2003, 2004 Ralf Baechle ++ * Copyright (C) 2004 Maciej W. Rozycki ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++#ifndef __ASM_MACH_FALCON_CPU_FEATURE_OVERRIDES_H ++#define __ASM_MACH_FALCON_CPU_FEATURE_OVERRIDES_H ++ ++#define cpu_has_tlb 1 ++#define cpu_has_4kex 1 ++#define cpu_has_3k_cache 0 ++#define cpu_has_4k_cache 1 ++#define cpu_has_tx39_cache 0 ++#define cpu_has_sb1_cache 0 ++#define cpu_has_fpu 0 ++#define cpu_has_32fpr 0 ++#define cpu_has_counter 1 ++#define cpu_has_watch 1 ++#define cpu_has_divec 1 ++ ++#define cpu_has_prefetch 1 ++#define cpu_has_ejtag 1 ++#define cpu_has_llsc 1 ++ ++#define cpu_has_mips16 1 ++#define cpu_has_mdmx 0 ++#define cpu_has_mips3d 0 ++#define cpu_has_smartmips 0 ++ ++#define cpu_has_mips32r1 1 ++#define cpu_has_mips32r2 1 ++#define cpu_has_mips64r1 0 ++#define cpu_has_mips64r2 0 ++ ++#define cpu_has_dsp 1 ++#define cpu_has_mipsmt 1 ++ ++#define cpu_has_vint 1 ++#define cpu_has_veic 1 ++ ++#define cpu_has_64bits 0 ++#define cpu_has_64bit_zero_reg 0 ++#define cpu_has_64bit_gp_regs 0 ++#define cpu_has_64bit_addresses 0 ++ ++#define cpu_dcache_line_size() 32 ++#define cpu_icache_line_size() 32 ++ ++#endif /* __ASM_MACH_FALCON_CPU_FEATURE_OVERRIDES_H */ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/ebu_reg.h +@@ -0,0 +1,1520 @@ ++/****************************************************************************** ++ ++ Copyright (c) 2010 ++ Lantiq Deutschland GmbH ++ ++ For licensing information, see the file 'LICENSE' in the root folder of ++ this software module. ++ ++******************************************************************************/ ++ ++#ifndef _ebu_reg_h ++#define _ebu_reg_h ++ ++/** \addtogroup EBU_REGISTER ++ @{ ++*/ ++/* access macros */ ++#define ebu_r32(reg) reg_r32(&ebu->reg) ++#define ebu_w32(val, reg) reg_w32(val, &ebu->reg) ++#define ebu_w32_mask(clear, set, reg) reg_w32_mask(clear, set, &ebu->reg) ++#define ebu_r32_table(reg, idx) reg_r32_table(ebu->reg, idx) ++#define ebu_w32_table(val, reg, idx) reg_w32_table(val, ebu->reg, idx) ++#define ebu_w32_table_mask(clear, set, reg, idx) reg_w32_table_mask(clear, set, ebu->reg, idx) ++#define ebu_adr_table(reg, idx) adr_table(ebu->reg, idx) ++ ++ ++/** EBU register structure */ ++struct gpon_reg_ebu ++{ ++ /** Reserved */ ++ unsigned int res_0[2]; /* 0x00000000 */ ++ /** Module ID Register ++ Module type and version identifier */ ++ unsigned int modid; /* 0x00000008 */ ++ /** Module Control Register ++ This register contains general configuration information observed for all CS regions or dealing with EBU functionality that is not directly related to external memory access. */ ++ unsigned int modcon; /* 0x0000000C */ ++ /** Bus Read Configuration Register0 ++ Note: The actual length of field enable depends on the number of bus ports connected to the EBU. For the GPON it is a single port (the bridge to the Asynchronous Xbar) so only bit 0 is implemented with all other bits tied to '0'. */ ++ unsigned int busrcon0; /* 0x00000010 */ ++ /** Bus Read Parameters Register0 */ ++ unsigned int busrp0; /* 0x00000014 */ ++ /** Bus Write Configuration Register0 ++ Note: The actual length of field enable depends on the number of bus ports connected to the EBU. For the GPON it is a single port (the bridge to the Asynchronous Xbar) so only bit 0 is implemented with all other bits tied to '0'. */ ++ unsigned int buswcon0; /* 0x00000018 */ ++ /** Bus Write Parameters Register0 */ ++ unsigned int buswp0; /* 0x0000001C */ ++ /** Bus Read Configuration Register1 ++ Note: The actual length of field enable depends on the number of bus ports connected to the EBU. For the GPON it is a single port (the bridge to the Asynchronous Xbar) so only bit 0 is implemented with all other bits tied to '0'. */ ++ unsigned int busrcon1; /* 0x00000020 */ ++ /** Bus Read Parameters Register1 */ ++ unsigned int busrp1; /* 0x00000024 */ ++ /** Bus Write Configuration Register1 ++ Note: The actual length of field enable depends on the number of bus ports connected to the EBU. For the GPON it is a single port (the bridge to the Asynchronous Xbar) so only bit 0 is implemented with all other bits tied to '0'. */ ++ unsigned int buswcon1; /* 0x00000028 */ ++ /** Bus Write Parameters Register1 */ ++ unsigned int buswp1; /* 0x0000002C */ ++ /** Reserved */ ++ unsigned int res_1[8]; /* 0x00000030 */ ++ /** Bus Protocol Configuration Extension Register 0 */ ++ unsigned int busconext0; /* 0x00000050 */ ++ /** Bus Protocol Configuration Extension Register 1 */ ++ unsigned int busconext1; /* 0x00000054 */ ++ /** Reserved */ ++ unsigned int res_2[10]; /* 0x00000058 */ ++ /** Serial Flash Configuration Register ++ The content of this register configures the EBU's Serial Flash protocol engine. */ ++ unsigned int sfcon; /* 0x00000080 */ ++ /** Serial Flash Timing Register ++ This register defines the signal timing for the Serial Flash Access. See Section 3.18.3 on page 112 for details. */ ++ unsigned int sftime; /* 0x00000084 */ ++ /** Serial Flash Status Register ++ This register holds status information on the Serial Flash device(s) attached and the EBU's Serial Flash protocol engine. */ ++ unsigned int sfstat; /* 0x00000088 */ ++ /** Serial Flash Command Register ++ When writing to this register's opcode field, a command is started in the EBU's Serial Flash controller. */ ++ unsigned int sfcmd; /* 0x0000008C */ ++ /** Serial Flash Address Register ++ This register holds the address to be sent (if any) with accesses to/from a Serial Flash started by writing to EBU_SFCMD (Indirect Access Mode, see Section 3.18.2.4.1 on page 103). */ ++ unsigned int sfaddr; /* 0x00000090 */ ++ /** Serial Flash Data Register ++ This register holds the data being transferred (if any) with accesses to/from a Serial Flash started by writing to EBU_SFCMD (Indirect Access Mode, see Section 4.18.2.4.1 on page 116). */ ++ unsigned int sfdata; /* 0x00000094 */ ++ /** Serial Flash I/O Control Register ++ This register provides additional configuration for controlling the IO pads of the Serial Flash interface. */ ++ unsigned int sfio; /* 0x00000098 */ ++ /** Reserved */ ++ unsigned int res_3[25]; /* 0x0000009C */ ++}; ++ ++ ++/* Fields of "Module ID Register" */ ++/** Feature Select ++ This field indicates the types of external devices/protocols supported by the GPON version of the EBU. */ ++#define MODID_FSEL_MASK 0xE0000000 ++/** field offset */ ++#define MODID_FSEL_OFFSET 29 ++/** Support for SRAM, NAND/NOR/OneNand Flash and Cellular RAM is implemented. */ ++#define MODID_FSEL_SRAM_FLASH_CRAM 0x00000000 ++/** Support for SRAM, NAND/NOR/OneNand Flash, Cellular RAM and SDR SDRAM is implemented. */ ++#define MODID_FSEL_SRAM_FLASH_CRAM_SDR 0x20000000 ++/** Support for SRAM, NAND/NOR/OneNand Flash, Cellular RAM and SDR/DDR SDRAM is implemented. */ ++#define MODID_FSEL_SRAM_FLASH_CRAM_DDR 0x40000000 ++/** Support for SRAM, NAND/NOR/OneNand Flash, Cellular RAM, SDR/DDR SDRAM 0nd LPDDR-Flash is implemented. */ ++#define MODID_FSEL_SRAM_FLASH_CRAM_DDR_LPNVM 0x60000000 ++/** Serial Flash Support ++ Indicates whether or not the support of Serial Flash devices is available. */ ++#define MODID_SF 0x10000000 ++/* Not Available ++#define MODID_SF_NAV 0x00000000 */ ++/** Available */ ++#define MODID_SF_AV 0x10000000 ++/** AAD-mux Support ++ Indicates whether or not the GPON EBU supports AAD-mux protocol for Burst Flash and Cellular RAM. */ ++#define MODID_AAD 0x08000000 ++/* Not Available ++#define MODID_AAD_NAV 0x00000000 */ ++/** Available */ ++#define MODID_AAD_AV 0x08000000 ++/** Indicates whether or not the GPON EBU implements a DLL which is e.g. used for 50% duty cycle external clock generation. Note that a DLL is always implemented if DDR-SDRAM support is selected. */ ++#define MODID_DLL 0x04000000 ++/* Not Available ++#define MODID_DLL_NAV 0x00000000 */ ++/** Available */ ++#define MODID_DLL_AV 0x04000000 ++/** Pad Multiplexing Scheme */ ++#define MODID_PMS_MASK 0x03000000 ++/** field offset */ ++#define MODID_PMS_OFFSET 24 ++/** The EBU comprises of dedicated address pins A[EXTAW-1=:16]. */ ++#define MODID_PMS_PMS_CLASSIC 0x00000000 ++/** Revision ++ Revision Number */ ++#define MODID_REV_MASK 0x000F0000 ++/** field offset */ ++#define MODID_REV_OFFSET 16 ++/** Module ID ++ This field contains the EBU's unique peripheral ID. */ ++#define MODID_ID_MASK 0x0000FF00 ++/** field offset */ ++#define MODID_ID_OFFSET 8 ++/** Version ++ This field gives the EBU version number. */ ++#define MODID_VERSION_MASK 0x000000FF ++/** field offset */ ++#define MODID_VERSION_OFFSET 0 ++ ++/* Fields of "Module Control Register" */ ++/** Reserved */ ++#define MODCON_DLLUPDINT_MASK 0xC0000000 ++/** field offset */ ++#define MODCON_DLLUPDINT_OFFSET 30 ++/** Access Inhibit Acknowledge ++ After suspension of all accesses to the External Bus has been requested by setting bit acc_inh, acc_inh_ack acknowledges the request and inidcates that access suspension is now in effect. The bit is cleared when acc_inh gets deasserted. */ ++#define MODCON_AIA 0x02000000 ++/* no access restriction are active in the EBU subsystem ++#define MODCON_AIA_NO_INHIBIT 0x00000000 */ ++/** accesses are restricted to selected (configuration) system bus port(s) */ ++#define MODCON_AIA_INHIBIT 0x02000000 ++/** Access Inhibit request ++ Setting this bit will suspend all non-CPU system bus ports and the EBU itself from accessing the External Bus. This feature is usually used when the CPU needs to reconfigure protocol parameters in the EBU in order to avoid external accesses with invalid settings. The EBU acknowledges that the access suspension is in effect by asserting acc_inh_ack. */ ++#define MODCON_AI 0x01000000 ++/* no access restriction are active in the EBU subsystem ++#define MODCON_AI_NO_INHIBIT 0x00000000 */ ++/** accesses are restricted to selected (configuration) system bus port(s) */ ++#define MODCON_AI_INHIBIT 0x01000000 ++/** Lock Timeout */ ++#define MODCON_LTO_MASK 0x00FF0000 ++/** field offset */ ++#define MODCON_LTO_OFFSET 16 ++/** Reserved */ ++#define MODCON_DDREN 0x00008000 ++/** Pad Drive Control ++ Intended to be used to control the EBU pad''s drive strength. Refer to the GPON chip specification to see which drive strnegth options are available and whether they are actually controlled by the EBU's register bit. The value stored in this register bit is directly connected to the corresponding output of the EBU module and takes no functional effect within the EBU itself. */ ++#define MODCON_PEXT 0x00004000 ++/* Normal drive ++#define MODCON_PEXT_NORMAL 0x00000000 */ ++/** Strong drive */ ++#define MODCON_PEXT_STRONG 0x00004000 ++/** Pad Slew Falling Edge Control ++ Intended to be used to trim the External Bus pad's falling edge slew rate. Refer to the GPON chip specification to see which slew rate options are available and whether they are actually controlled by the EBU's register bit. The value stored in this register bit is directly connected to the corresponding output of the EBU module and takes no functional effect within the EBU itself. */ ++#define MODCON_SLF 0x00002000 ++/* Slow slew rate ++#define MODCON_SLF_SLOW 0x00000000 */ ++/** Fast slew rate */ ++#define MODCON_SLF_FAST 0x00002000 ++/** Pad Slew Rising Edge Control ++ Intended to be used to trim the External Bus pad's rising edge slew rate. Refer to the GPON chip specification to see which slew rate options are available and whether they are actually controlled by the EBU's register bit. The value stored in this register bit is directly connected to the corresponding output of the EBU module and takes no functional effect within the EBU itself. */ ++#define MODCON_SLR 0x00001000 ++/* Slow slew rate ++#define MODCON_SLR_SLOW 0x00000000 */ ++/** Fast slew rate */ ++#define MODCON_SLR_FAST 0x00001000 ++/** Write Buffering Mode ++ This bit controls when the EBU starts a new write burst transaction from the Memport interface. */ ++#define MODCON_WBM 0x00000040 ++/* The EBU starts a write transaction on the External Bus as early as possible, expecting that the n beats of the write burst will be transferred within n or n+1 clock cycles over the EBU's Memport interface. Use this mode if the EBU is clocked at the same or a slower frequency than the system bus interconnect. ++#define MODCON_WBM_START_WRITE_EARLY 0x00000000 */ ++/** The EBU start a write transaction only after all data of a write burst have been received over the EBU's Memport interface. Use this mode if the EBU is clocked at a higher frequency than the system bus interrconnect. */ ++#define MODCON_WBM_START_WRITE_LATE 0x00000040 ++/** Reserved */ ++#define MODCON_SDCLKEN 0x00000020 ++/** Standby Mode Enable ++ When set allows the EBU subsystem to enter standby mode in response to a rising edge on input signal standby_req_i. See Section 3.9.3 for details. */ ++#define MODCON_STBYEN 0x00000010 ++/* Disable ++#define MODCON_STBYEN_DIS 0x00000000 */ ++/** Enable */ ++#define MODCON_STBYEN_EN 0x00000010 ++/** Enable BFCLK1 ++ This field will enables or disables mirroring the clock that is output on BFCLKO_0 also on pad BFCLKO_1 to double the drive strength. See also Section 3.17.3) */ ++#define MODCON_BFCLK1EN 0x00000008 ++/* Disable ++#define MODCON_BFCLK1EN_DIS 0x00000000 */ ++/** Enable */ ++#define MODCON_BFCLK1EN_EN 0x00000008 ++/** Ready/Busy Status Edge ++ This is a read-only bit which shows a change of the logic level shown in the sts field since last read. It is reset by a read access. */ ++#define MODCON_STSEDGE 0x00000004 ++/** Ready/Busy Status ++ This is a read-only bit which reflects the current logic level present on the RDY/BSY or STS input pin which is (optionally) fed-in from a General Purpose I/O pad which is not part of the EBU via the EBU's input pin signal gpio_nand_rdy_ */ ++#define MODCON_STS 0x00000002 ++/** External Bus Arbitration Mode ++ This bit allows to disconnect the EBU from the External Bus. While EBU_MODCON.acc_inh_ack is 0, the value of arb_mode is forced to OWN_BUS. */ ++#define MODCON_AM 0x00000001 ++/* The EBU does not own the bus (multi-master) ++#define MODCON_AM_SHAREDBUS 0x00000000 */ ++/** The EBU owns the external bus. */ ++#define MODCON_AM_OWNBUS 0x00000001 ++ ++/* Fields of "Bus Read Configuration Register0" */ ++/** Device Type For Region ++ After reset, the CS region is configured for a slow Asynchronous access protocol which is compatible with read access from an external multiplexed or demultiplexed 16-Bit Burst Flash in asynchronous mode. Reset: 0000B */ ++#define BUSRCON0_AGEN_MASK 0xF0000000 ++/** field offset */ ++#define BUSRCON0_AGEN_OFFSET 28 ++/** Muxed Asynchronous Type External Memory */ ++#define BUSRCON0_AGEN_MUXED_ASYNC_TYPE_EXT_MEM 0x00000000 ++/** Muxed Burst Type External Memory */ ++#define BUSRCON0_AGEN_MUXED_BURST_TYPE_EXT_MEM 0x10000000 ++/** NAND Flash (page optimised) */ ++#define BUSRCON0_AGEN_NAND_FLASH 0x20000000 ++/** Muxed Cellular RAM External Memory */ ++#define BUSRCON0_AGEN_MUXED_CELLULAR_RAM_EXT_MEM 0x30000000 ++/** Demuxed Asynchronous Type External Memory */ ++#define BUSRCON0_AGEN_DEMUXED_ASYNC_TYPE_EXT_MEM 0x40000000 ++/** Demuxed Burst Type External Memory */ ++#define BUSRCON0_AGEN_DEMUXED_BURST_TYPE_EXT_MEM 0x50000000 ++/** Demuxed Page Mode External Memory */ ++#define BUSRCON0_AGEN_DEMUXED_PAGE_MODE_EXT_MEM 0x60000000 ++/** Demuxed Cellular RAM External Memory */ ++#define BUSRCON0_AGEN_DEMUXED_CELLULAR_RAM_EXT_MEM 0x70000000 ++/** Serial Flash */ ++#define BUSRCON0_AGEN_SERIAL_FLASH 0xF0000000 ++/** Device Addressing Mode ++ t.b.d. */ ++#define BUSRCON0_PORTW_MASK 0x0C000000 ++/** field offset */ ++#define BUSRCON0_PORTW_OFFSET 26 ++/** 8-bit multiplexed */ ++#define BUSRCON0_PORTW_8_BIT_MUX 0x00000000 ++/** 16-bit multiplexed */ ++#define BUSRCON0_PORTW_16_BIT_MUX 0x04000000 ++/** Twin, 16-bit multiplexed */ ++#define BUSRCON0_PORTW_TWIN_16_BIT_MUX 0x08000000 ++/** 32-bit multiplexed */ ++#define BUSRCON0_PORTW_32_BIT_MUX 0x0C000000 ++/** External Wait Control ++ Function of the WAIT input. This is specific to the device type (i.e. the agen field). */ ++#define BUSRCON0_WAIT_MASK 0x03000000 ++/** field offset */ ++#define BUSRCON0_WAIT_OFFSET 24 ++/** WAIT is ignored (default after reset). */ ++#define BUSRCON0_WAIT_OFF 0x00000000 ++/** Synchronous Burst Devices: WAIT signal is provided one cycle ahead of the data cycle it applies to. */ ++#define BUSRCON0_WAIT_EARLY_WAIT 0x01000000 ++/** Asynchronous Devices: WAIT input passes through a two-stage synchronizer before being evaluated. */ ++#define BUSRCON0_WAIT_TWO_STAGE_SYNC 0x01000000 ++/** Synchronous Burst Devices: WAIT signal is provided in the same data cycle it applies to. */ ++#define BUSRCON0_WAIT_WAIT_WITH_DATA 0x02000000 ++/** Asynchronous Devices: WAIT input passes through a single-stage synchronizer before being evaluated. */ ++#define BUSRCON0_WAIT_SINGLE_STAGE_SYNC 0x02000000 ++/** Synchronous Burst Devices: Abort and retry access if WAIT asserted */ ++#define BUSRCON0_WAIT_ABORT_AND_RETRY 0x03000000 ++/** Disable Burst Address Wrapping */ ++#define BUSRCON0_DBA 0x00800000 ++/** Reversed polarity at wait */ ++#define BUSRCON0_WAITINV 0x00400000 ++/* Low active. ++#define BUSRCON0_WAITINV_ACTLOW 0x00000000 */ ++/** High active */ ++#define BUSRCON0_WAITINV_ACTHI 0x00400000 ++/** Early ADV Enable for Synchronous Bursts */ ++#define BUSRCON0_EBSE 0x00200000 ++/* Low active. ++#define BUSRCON0_EBSE_DELAYED 0x00000000 */ ++/** High active */ ++#define BUSRCON0_EBSE_NOT_DELAYED 0x00200000 ++/** Early Control Signals for Synchronous Bursts */ ++#define BUSRCON0_ECSE 0x00100000 ++/* Low active. ++#define BUSRCON0_ECSE_DELAYED 0x00000000 */ ++/** High active */ ++#define BUSRCON0_ECSE_NOT_DELAYED 0x00100000 ++/** Synchronous Burst Buffer Mode Select */ ++#define BUSRCON0_FBBMSEL 0x00080000 ++/* FIXED_LENGTH ++#define BUSRCON0_FBBMSEL_FIXED_LENGTH 0x00000000 */ ++/** CONTINUOUS */ ++#define BUSRCON0_FBBMSEL_CONTINUOUS 0x00080000 ++/** Burst Length for Synchronous Burst */ ++#define BUSRCON0_FETBLEN_MASK 0x00070000 ++/** field offset */ ++#define BUSRCON0_FETBLEN_OFFSET 16 ++/** Up to 1 data cycle (default after reset). */ ++#define BUSRCON0_FETBLEN_SINGLE 0x00000000 ++/** Up to 2 data cycles. */ ++#define BUSRCON0_FETBLEN_BURST2 0x00010000 ++/** Up to 4 data cycles. */ ++#define BUSRCON0_FETBLEN_BURST4 0x00020000 ++/** Up to 8 data cycles. */ ++#define BUSRCON0_FETBLEN_BURST8 0x00030000 ++/** Up to 16 data cycles. */ ++#define BUSRCON0_FETBLEN_BURST16 0x00040000 ++/** Reserved ++ This field allows to configure how the EBU generates the CLE and ALE signals for a NAND Flash device. The following options are available */ ++#define BUSRCON0_NANDAMAP_MASK 0x0000C000 ++/** field offset */ ++#define BUSRCON0_NANDAMAP_OFFSET 14 ++/** is taken from AMemport[18] and ALE from AMemport[17] and are output on pins A[17:16] on the External Bus (default after reset). */ ++#define BUSRCON0_NANDAMAP_NAND_A17_16 0x00000000 ++/** is taken from AMemport[18] and ALE from AMemport[17] and are output on pins A[17:16] on the External Bus (default after reset). */ ++#define BUSRCON0_NANDAMAP_NAND_WAIT_ADV 0x00004000 ++/** CLE is taken from AMemport[18] and ALE from AMemport[17] and are output on pins AD[9:8] and A[9:8] on the External Bus. This mode may only be used with a 8-Bit NAND-Flash device. */ ++#define BUSRCON0_NANDAMAP_NAND_AD9_8 0x00008000 ++/** Reserved for future use. Do not use or unpredictable results may occur. */ ++#define BUSRCON0_NANDAMAP_NAND_RFU 0x0000C000 ++/** AAD-mux Protocol ++ If this bit is set and the device is configured for a multiplexed access protocol in agen then the device is accessed in read mode using the AAD-mux protocol. If a non-multiplexed device type is selected in agen, field aadmux is ignored. */ ++#define BUSRCON0_AADMUX 0x00002000 ++/* Muxed device is write accessed in AD-mux mode. ++#define BUSRCON0_AADMUX_AD_MUX 0x00000000 */ ++/** Muxed device is write accessed in AAD-mux mode. */ ++#define BUSRCON0_AADMUX_AAD_MUX 0x00002000 ++/** Asynchronous Address Phase */ ++#define BUSRCON0_AAP 0x00001000 ++/* Clock is enabled at beginning of access. ++#define BUSRCON0_AAP_EARLY 0x00000000 */ ++/** Clock is enabled after address phase. */ ++#define BUSRCON0_AAP_LATE 0x00001000 ++/** Burst Flash Read Single Stage Synchronisation */ ++#define BUSRCON0_BFSSS 0x00000800 ++/* Two stages of synchronisation used. ++#define BUSRCON0_BFSSS_TWO_STAGE 0x00000000 */ ++/** Single stage of synchronisation used. */ ++#define BUSRCON0_BFSSS_SINGLE_STAGE 0x00000800 ++/** Burst Flash Clock Feedback Enable */ ++#define BUSRCON0_FDBKEN 0x00000400 ++/* Disable ++#define BUSRCON0_FDBKEN_DIS 0x00000000 */ ++/** Enable */ ++#define BUSRCON0_FDBKEN_EN 0x00000400 ++/** Auxiliary Chip Select Enable ++ Not supported in GPON-EBU, field must be set to 0. */ ++#define BUSRCON0_CSA 0x00000200 ++/* Disable ++#define BUSRCON0_CSA_DIS 0x00000000 */ ++/** Enable */ ++#define BUSRCON0_CSA_EN 0x00000200 ++/** Flash Non-Array Access Enable ++ Set to logic one to enable workaround when region is accessed with internal address bit 28 set. See Section 3.17.13 on page 90 for details. */ ++#define BUSRCON0_NAA 0x00000100 ++/* Disable ++#define BUSRCON0_NAA_DIS 0x00000000 */ ++/** Enable */ ++#define BUSRCON0_NAA_EN 0x00000100 ++/** Module Enable */ ++#define BUSRCON0_ENABLE 0x00000001 ++/* Disable ++#define BUSRCON0_ENABLE_DIS 0x00000000 */ ++/** Enable */ ++#define BUSRCON0_ENABLE_EN 0x00000001 ++ ++/* Fields of "Bus Read Parameters Register0" */ ++/** Address Cycles ++ Number of cycles for address phase. */ ++#define BUSRP0_ADDRC_MASK 0xF0000000 ++/** field offset */ ++#define BUSRP0_ADDRC_OFFSET 28 ++/** Address Hold Cycles For Multiplexed Address ++ Number of address hold cycles during multiplexed accesses. */ ++#define BUSRP0_ADHOLC_MASK 0x0F000000 ++/** field offset */ ++#define BUSRP0_ADHOLC_OFFSET 24 ++/** Programmed Command Delay Cycles ++ Number of delay cycles during command delay phase. */ ++#define BUSRP0_CMDDELAY_MASK 0x00F00000 ++/** field offset */ ++#define BUSRP0_CMDDELAY_OFFSET 20 ++/** Extended Data */ ++#define BUSRP0_EXTDATA_MASK 0x000C0000 ++/** field offset */ ++#define BUSRP0_EXTDATA_OFFSET 18 ++/** External device outputs data every BFCLK cycle */ ++#define BUSRP0_EXTDATA_ONE 0x00000000 ++/** External device outputs data every 2nd BFCLK cycles */ ++#define BUSRP0_EXTDATA_TWO 0x00040000 ++/** External device outputs data every 4th BFCLK cycles */ ++#define BUSRP0_EXTDATA_FOUR 0x00080000 ++/** External device outputs data every 8th BFCLK cycles */ ++#define BUSRP0_EXTDATA_EIGHT 0x000C0000 ++/** Frequency of external clock at pin BFCLKO */ ++#define BUSRP0_EXTCLOCK_MASK 0x00030000 ++/** field offset */ ++#define BUSRP0_EXTCLOCK_OFFSET 16 ++/** Equal to ebu_clk frequency. */ ++#define BUSRP0_EXTCLOCK_ONE_TO_ONE 0x00000000 ++/** 1/2 of ebu_clk frequency. */ ++#define BUSRP0_EXTCLOCK_ONE_TO_TWO 0x00010000 ++/** 1/3 of ebu_clk frequency. */ ++#define BUSRP0_EXTCLOCK_ONE_TO_THREE 0x00020000 ++/** 1/4 of ebu_clk frequency (default after reset). */ ++#define BUSRP0_EXTCLOCK_ONE_TO_FOUR 0x00030000 ++/** Data Hold Cycles For read Accesses ++ Number of data hold cycles during read accesses. Applies to spinner support only where the address is guaranteed stable for datac clocks after RD high */ ++#define BUSRP0_DATAC_MASK 0x0000F000 ++/** field offset */ ++#define BUSRP0_DATAC_OFFSET 12 ++/** Programmed Wait States for read accesses ++ Number of programmed wait states for read accesses. For synchronous accesses, this will always be adjusted so that the phase exits on a rising edge of the external clock. */ ++#define BUSRP0_WAITRDC_MASK 0x00000F80 ++/** field offset */ ++#define BUSRP0_WAITRDC_OFFSET 7 ++/** Recovery Cycles After read Accesses, same CS ++ Number of idle cycles after read accesses when the next access is to the same chip select. For synchronous accesses, this will always be adjusted so that the phase exits on a rising clock edge. Note that at least one recovery cycle must be programmed in case the region is configured for delayed control signals in field ecse of register EBU_BUSRCON. */ ++#define BUSRP0_RECOVC_MASK 0x00000070 ++/** field offset */ ++#define BUSRP0_RECOVC_OFFSET 4 ++/** Recovery Cycles After read Accesses, other CS ++ Number of idle cycles after read accesses when the next access is to a different chip select. For synchronous accesses, this will always be adjusted so that the phase exits on a rising clock edge. Note that at least one recovery cycle must be programmed in case the region is configured for delayed control signals in field ecse of register EBU_BUSRCON. */ ++#define BUSRP0_DTACS_MASK 0x0000000F ++/** field offset */ ++#define BUSRP0_DTACS_OFFSET 0 ++ ++/* Fields of "Bus Write Configuration Register0" */ ++/** Device Type For Region ++ After reset, the CS region is configured for a slow Asynchronous access protocol which is compatible with read access from an external multiplexed or demultiplexed 16-Bit Burst Flash in asynchronous mode. Reset: 0000B */ ++#define BUSWCON0_AGEN_MASK 0xF0000000 ++/** field offset */ ++#define BUSWCON0_AGEN_OFFSET 28 ++/** Muxed Asynchronous Type External Memory */ ++#define BUSWCON0_AGEN_MUXED_ASYNC_TYPE_EXT_MEM 0x00000000 ++/** Muxed Burst Type External Memory */ ++#define BUSWCON0_AGEN_MUXED_BURST_TYPE_EXT_MEM 0x10000000 ++/** NAND Flash (page optimised) */ ++#define BUSWCON0_AGEN_NAND_FLASH 0x20000000 ++/** Muxed Cellular RAM External Memory */ ++#define BUSWCON0_AGEN_MUXED_CELLULAR_RAM_EXT_MEM 0x30000000 ++/** Demuxed Asynchronous Type External Memory */ ++#define BUSWCON0_AGEN_DEMUXED_ASYNC_TYPE_EXT_MEM 0x40000000 ++/** Demuxed Burst Type External Memory */ ++#define BUSWCON0_AGEN_DEMUXED_BURST_TYPE_EXT_MEM 0x50000000 ++/** Demuxed Page Mode External Memory */ ++#define BUSWCON0_AGEN_DEMUXED_PAGE_MODE_EXT_MEM 0x60000000 ++/** Demuxed Cellular RAM External Memory */ ++#define BUSWCON0_AGEN_DEMUXED_CELLULAR_RAM_EXT_MEM 0x70000000 ++/** Serial Flash */ ++#define BUSWCON0_AGEN_SERIAL_FLASH 0xF0000000 ++/** Device Addressing Mode ++ t.b.d. */ ++#define BUSWCON0_PORTW_MASK 0x0C000000 ++/** field offset */ ++#define BUSWCON0_PORTW_OFFSET 26 ++/** External Wait Control ++ Function of the WAIT input. This is specific to the device type (i.e. the agen field). */ ++#define BUSWCON0_WAIT_MASK 0x03000000 ++/** field offset */ ++#define BUSWCON0_WAIT_OFFSET 24 ++/** WAIT is ignored (default after reset). */ ++#define BUSWCON0_WAIT_OFF 0x00000000 ++/** Synchronous Burst Devices: WAIT signal is provided one cycle ahead of the data cycle it applies to. */ ++#define BUSWCON0_WAIT_EARLY_WAIT 0x01000000 ++/** Asynchronous Devices: WAIT input passes through a two-stage synchronizer before being evaluated. */ ++#define BUSWCON0_WAIT_TWO_STAGE_SYNC 0x01000000 ++/** Synchronous Burst Devices: WAIT signal is provided in the same data cycle it applies to. */ ++#define BUSWCON0_WAIT_WAIT_WITH_DATA 0x02000000 ++/** Asynchronous Devices: WAIT input passes through a single-stage synchronizer before being evaluated. */ ++#define BUSWCON0_WAIT_SINGLE_STAGE_SYNC 0x02000000 ++/** Synchronous Burst Devices: Abort and retry access if WAIT asserted */ ++#define BUSWCON0_WAIT_ABORT_AND_RETRY 0x03000000 ++/** Reserved */ ++#define BUSWCON0_LOCKCS 0x00800000 ++/** Reversed polarity at wait */ ++#define BUSWCON0_WAITINV 0x00400000 ++/* Low active. ++#define BUSWCON0_WAITINV_ACTLOW 0x00000000 */ ++/** High active */ ++#define BUSWCON0_WAITINV_ACTHI 0x00400000 ++/** Early ADV Enable for Synchronous Bursts */ ++#define BUSWCON0_EBSE 0x00200000 ++/* Low active. ++#define BUSWCON0_EBSE_DELAYED 0x00000000 */ ++/** High active */ ++#define BUSWCON0_EBSE_NOT_DELAYED 0x00200000 ++/** Early Control Signals for Synchronous Bursts */ ++#define BUSWCON0_ECSE 0x00100000 ++/* Low active. ++#define BUSWCON0_ECSE_DELAYED 0x00000000 */ ++/** High active */ ++#define BUSWCON0_ECSE_NOT_DELAYED 0x00100000 ++/** Synchronous Burst Buffer Mode Select */ ++#define BUSWCON0_FBBMSEL 0x00080000 ++/* FIXED_LENGTH ++#define BUSWCON0_FBBMSEL_FIXED_LENGTH 0x00000000 */ ++/** CONTINUOUS */ ++#define BUSWCON0_FBBMSEL_CONTINUOUS 0x00080000 ++/** Burst Length for Synchronous Burst */ ++#define BUSWCON0_FETBLEN_MASK 0x00070000 ++/** field offset */ ++#define BUSWCON0_FETBLEN_OFFSET 16 ++/** Up to 1 data cycle (default after reset). */ ++#define BUSWCON0_FETBLEN_SINGLE 0x00000000 ++/** Up to 2 data cycles. */ ++#define BUSWCON0_FETBLEN_BURST2 0x00010000 ++/** Up to 4 data cycles. */ ++#define BUSWCON0_FETBLEN_BURST4 0x00020000 ++/** Up to 8 data cycles. */ ++#define BUSWCON0_FETBLEN_BURST8 0x00030000 ++/** Up to 16 data cycles. */ ++#define BUSWCON0_FETBLEN_BURST16 0x00040000 ++/** Reserved ++ This field allows to configure how the EBU generates the CLE and ALE signals for a NAND Flash device. The following options are available */ ++#define BUSWCON0_NANDAMAP_MASK 0x0000C000 ++/** field offset */ ++#define BUSWCON0_NANDAMAP_OFFSET 14 ++/** is taken from AMemport[18] and ALE from AMemport[17] and are output on pins A[17:16] on the External Bus (default after reset). */ ++#define BUSWCON0_NANDAMAP_NAND_A17_16 0x00000000 ++/** is taken from AMemport[18] and ALE from AMemport[17] and are output on pins A[17:16] on the External Bus (default after reset). */ ++#define BUSWCON0_NANDAMAP_NAND_WAIT_ADV 0x00004000 ++/** CLE is taken from AMemport[18] and ALE from AMemport[17] and are output on pins AD[9:8] and A[9:8] on the External Bus. This mode may only be used with a 8-Bit NAND-Flash device. */ ++#define BUSWCON0_NANDAMAP_NAND_AD9_8 0x00008000 ++/** Reserved for future use. Do not use or unpredictable results may occur. */ ++#define BUSWCON0_NANDAMAP_NAND_RFU 0x0000C000 ++/** AAD-mux Protocol ++ If this bit is set and the device is configured for a multiplexed access protocol in agen then the device is accessed in read mode using the AAD-mux protocol. If a non-multiplexed device type is selected in agen, field aadmux is ignored. */ ++#define BUSWCON0_AADMUX 0x00002000 ++/* Muxed device is write accessed in AD-mux mode. ++#define BUSWCON0_AADMUX_AD_MUX 0x00000000 */ ++/** Muxed device is write accessed in AAD-mux mode. */ ++#define BUSWCON0_AADMUX_AAD_MUX 0x00002000 ++/** Asynchronous Address Phase */ ++#define BUSWCON0_AAP 0x00001000 ++/* Clock is enabled at beginning of access. ++#define BUSWCON0_AAP_EARLY 0x00000000 */ ++/** Clock is enabled after address phase. */ ++#define BUSWCON0_AAP_LATE 0x00001000 ++/** Auxiliary Chip Select Enable ++ Not supported in GPON-EBU, field must be set to 0. */ ++#define BUSWCON0_CSA 0x00000200 ++/* Disable ++#define BUSWCON0_CSA_DIS 0x00000000 */ ++/** Enable */ ++#define BUSWCON0_CSA_EN 0x00000200 ++/** Flash Non-Array Access Enable ++ Set to logic one to enable workaround when region is accessed with internal address bit 28 set. See Section 3.17.13 on page 90 for details. */ ++#define BUSWCON0_NAA 0x00000100 ++/* Disable ++#define BUSWCON0_NAA_DIS 0x00000000 */ ++/** Enable */ ++#define BUSWCON0_NAA_EN 0x00000100 ++/** Module Enable */ ++#define BUSWCON0_ENABLE 0x00000001 ++/* Disable ++#define BUSWCON0_ENABLE_DIS 0x00000000 */ ++/** Enable */ ++#define BUSWCON0_ENABLE_EN 0x00000001 ++ ++/* Fields of "Bus Write Parameters Register0" */ ++/** Address Cycles ++ Number of cycles for address phase. */ ++#define BUSWP0_ADDRC_MASK 0xF0000000 ++/** field offset */ ++#define BUSWP0_ADDRC_OFFSET 28 ++/** Address Hold Cycles For Multiplexed Address ++ Number of address hold cycles during multiplexed accesses. */ ++#define BUSWP0_ADHOLC_MASK 0x0F000000 ++/** field offset */ ++#define BUSWP0_ADHOLC_OFFSET 24 ++/** Programmed Command Delay Cycles ++ Number of delay cycles during command delay phase. */ ++#define BUSWP0_CMDDELAY_MASK 0x00F00000 ++/** field offset */ ++#define BUSWP0_CMDDELAY_OFFSET 20 ++/** Extended Data */ ++#define BUSWP0_EXTDATA_MASK 0x000C0000 ++/** field offset */ ++#define BUSWP0_EXTDATA_OFFSET 18 ++/** External device outputs data every BFCLK cycle */ ++#define BUSWP0_EXTDATA_ONE 0x00000000 ++/** External device outputs data every 2nd BFCLK cycles */ ++#define BUSWP0_EXTDATA_TWO 0x00040000 ++/** External device outputs data every 4th BFCLK cycles */ ++#define BUSWP0_EXTDATA_FOUR 0x00080000 ++/** External device outputs data every 8th BFCLK cycles */ ++#define BUSWP0_EXTDATA_EIGHT 0x000C0000 ++/** Frequency of external clock at pin BFCLKO */ ++#define BUSWP0_EXTCLOCK_MASK 0x00030000 ++/** field offset */ ++#define BUSWP0_EXTCLOCK_OFFSET 16 ++/** Equal to ebu_clk frequency. */ ++#define BUSWP0_EXTCLOCK_ONE_TO_ONE 0x00000000 ++/** 1/2 of ebu_clk frequency. */ ++#define BUSWP0_EXTCLOCK_ONE_TO_TWO 0x00010000 ++/** 1/3 of ebu_clk frequency. */ ++#define BUSWP0_EXTCLOCK_ONE_TO_THREE 0x00020000 ++/** 1/4 of ebu_clk frequency (default after reset). */ ++#define BUSWP0_EXTCLOCK_ONE_TO_FOUR 0x00030000 ++/** Data Hold Cycles For write Accesses ++ Number of data hold cycles during write accesses. */ ++#define BUSWP0_DATAC_MASK 0x0000F000 ++/** field offset */ ++#define BUSWP0_DATAC_OFFSET 12 ++/** Programmed Wait States For write Accesses ++ Number of programmed wait states for write accesses. For synchronous accesses, this will always be adjusted so that the phase exits on a rising edge of the external clock. */ ++#define BUSWP0_WAITWDC_MASK 0x00000F80 ++/** field offset */ ++#define BUSWP0_WAITWDC_OFFSET 7 ++/** Recovery Cycles After write Accesses, same CS ++ Number of idle cycles after write accesses when following access is to the same chip select. For synchronous accesses, this will always be adjusted so that the phase exits on a rising clock edge. phase exits on a rising clock edge. Note that at least one recovery cycle must be programmed in case the region is configured for delayed control signals in field ecse of register EBU_BUSWCON. */ ++#define BUSWP0_RECOVC_MASK 0x00000070 ++/** field offset */ ++#define BUSWP0_RECOVC_OFFSET 4 ++/** Recovery Cycles After write Accesses, other CS ++ Number of idle cycles after write accesses when the following access is to a different chip select. For synchronous accesses, this will always be adjusted so that the phase exits on a rising clock edge. Note that at least one recovery cycle must be programmed in case the region is configured for delayed control signals in field ecse of register EBU_BUSWCON. */ ++#define BUSWP0_DTACS_MASK 0x0000000F ++/** field offset */ ++#define BUSWP0_DTACS_OFFSET 0 ++ ++/* Fields of "Bus Read Configuration Register1" */ ++/** Device Type For Region ++ After reset, the CS region is configured for a slow Asynchronous access protocol which is compatible with read access from an external multiplexed or demultiplexed 16-Bit Burst Flash in asynchronous mode. Reset: 0000B */ ++#define BUSRCON1_AGEN_MASK 0xF0000000 ++/** field offset */ ++#define BUSRCON1_AGEN_OFFSET 28 ++/** Muxed Asynchronous Type External Memory */ ++#define BUSRCON1_AGEN_MUXED_ASYNC_TYPE_EXT_MEM 0x00000000 ++/** Muxed Burst Type External Memory */ ++#define BUSRCON1_AGEN_MUXED_BURST_TYPE_EXT_MEM 0x10000000 ++/** NAND Flash (page optimised) */ ++#define BUSRCON1_AGEN_NAND_FLASH 0x20000000 ++/** Muxed Cellular RAM External Memory */ ++#define BUSRCON1_AGEN_MUXED_CELLULAR_RAM_EXT_MEM 0x30000000 ++/** Demuxed Asynchronous Type External Memory */ ++#define BUSRCON1_AGEN_DEMUXED_ASYNC_TYPE_EXT_MEM 0x40000000 ++/** Demuxed Burst Type External Memory */ ++#define BUSRCON1_AGEN_DEMUXED_BURST_TYPE_EXT_MEM 0x50000000 ++/** Demuxed Page Mode External Memory */ ++#define BUSRCON1_AGEN_DEMUXED_PAGE_MODE_EXT_MEM 0x60000000 ++/** Demuxed Cellular RAM External Memory */ ++#define BUSRCON1_AGEN_DEMUXED_CELLULAR_RAM_EXT_MEM 0x70000000 ++/** Serial Flash */ ++#define BUSRCON1_AGEN_SERIAL_FLASH 0xF0000000 ++/** Device Addressing Mode ++ t.b.d. */ ++#define BUSRCON1_PORTW_MASK 0x0C000000 ++/** field offset */ ++#define BUSRCON1_PORTW_OFFSET 26 ++/** 8-bit multiplexed */ ++#define BUSRCON1_PORTW_8_BIT_MUX 0x00000000 ++/** 16-bit multiplexed */ ++#define BUSRCON1_PORTW_16_BIT_MUX 0x04000000 ++/** Twin, 16-bit multiplexed */ ++#define BUSRCON1_PORTW_TWIN_16_BIT_MUX 0x08000000 ++/** 32-bit multiplexed */ ++#define BUSRCON1_PORTW_32_BIT_MUX 0x0C000000 ++/** External Wait Control ++ Function of the WAIT input. This is specific to the device type (i.e. the agen field). */ ++#define BUSRCON1_WAIT_MASK 0x03000000 ++/** field offset */ ++#define BUSRCON1_WAIT_OFFSET 24 ++/** WAIT is ignored (default after reset). */ ++#define BUSRCON1_WAIT_OFF 0x00000000 ++/** Synchronous Burst Devices: WAIT signal is provided one cycle ahead of the data cycle it applies to. */ ++#define BUSRCON1_WAIT_EARLY_WAIT 0x01000000 ++/** Asynchronous Devices: WAIT input passes through a two-stage synchronizer before being evaluated. */ ++#define BUSRCON1_WAIT_TWO_STAGE_SYNC 0x01000000 ++/** Synchronous Burst Devices: WAIT signal is provided in the same data cycle it applies to. */ ++#define BUSRCON1_WAIT_WAIT_WITH_DATA 0x02000000 ++/** Asynchronous Devices: WAIT input passes through a single-stage synchronizer before being evaluated. */ ++#define BUSRCON1_WAIT_SINGLE_STAGE_SYNC 0x02000000 ++/** Synchronous Burst Devices: Abort and retry access if WAIT asserted */ ++#define BUSRCON1_WAIT_ABORT_AND_RETRY 0x03000000 ++/** Disable Burst Address Wrapping */ ++#define BUSRCON1_DBA 0x00800000 ++/** Reversed polarity at wait */ ++#define BUSRCON1_WAITINV 0x00400000 ++/* Low active. ++#define BUSRCON1_WAITINV_ACTLOW 0x00000000 */ ++/** High active */ ++#define BUSRCON1_WAITINV_ACTHI 0x00400000 ++/** Early ADV Enable for Synchronous Bursts */ ++#define BUSRCON1_EBSE 0x00200000 ++/* Low active. ++#define BUSRCON1_EBSE_DELAYED 0x00000000 */ ++/** High active */ ++#define BUSRCON1_EBSE_NOT_DELAYED 0x00200000 ++/** Early Control Signals for Synchronous Bursts */ ++#define BUSRCON1_ECSE 0x00100000 ++/* Low active. ++#define BUSRCON1_ECSE_DELAYED 0x00000000 */ ++/** High active */ ++#define BUSRCON1_ECSE_NOT_DELAYED 0x00100000 ++/** Synchronous Burst Buffer Mode Select */ ++#define BUSRCON1_FBBMSEL 0x00080000 ++/* FIXED_LENGTH ++#define BUSRCON1_FBBMSEL_FIXED_LENGTH 0x00000000 */ ++/** CONTINUOUS */ ++#define BUSRCON1_FBBMSEL_CONTINUOUS 0x00080000 ++/** Burst Length for Synchronous Burst */ ++#define BUSRCON1_FETBLEN_MASK 0x00070000 ++/** field offset */ ++#define BUSRCON1_FETBLEN_OFFSET 16 ++/** Up to 1 data cycle (default after reset). */ ++#define BUSRCON1_FETBLEN_SINGLE 0x00000000 ++/** Up to 2 data cycles. */ ++#define BUSRCON1_FETBLEN_BURST2 0x00010000 ++/** Up to 4 data cycles. */ ++#define BUSRCON1_FETBLEN_BURST4 0x00020000 ++/** Up to 8 data cycles. */ ++#define BUSRCON1_FETBLEN_BURST8 0x00030000 ++/** Up to 16 data cycles. */ ++#define BUSRCON1_FETBLEN_BURST16 0x00040000 ++/** Reserved ++ This field allows to configure how the EBU generates the CLE and ALE signals for a NAND Flash device. The following options are available */ ++#define BUSRCON1_NANDAMAP_MASK 0x0000C000 ++/** field offset */ ++#define BUSRCON1_NANDAMAP_OFFSET 14 ++/** is taken from AMemport[18] and ALE from AMemport[17] and are output on pins A[17:16] on the External Bus (default after reset). */ ++#define BUSRCON1_NANDAMAP_NAND_A17_16 0x00000000 ++/** is taken from AMemport[18] and ALE from AMemport[17] and are output on pins A[17:16] on the External Bus (default after reset). */ ++#define BUSRCON1_NANDAMAP_NAND_WAIT_ADV 0x00004000 ++/** CLE is taken from AMemport[18] and ALE from AMemport[17] and are output on pins AD[9:8] and A[9:8] on the External Bus. This mode may only be used with a 8-Bit NAND-Flash device. */ ++#define BUSRCON1_NANDAMAP_NAND_AD9_8 0x00008000 ++/** Reserved for future use. Do not use or unpredictable results may occur. */ ++#define BUSRCON1_NANDAMAP_NAND_RFU 0x0000C000 ++/** AAD-mux Protocol ++ If this bit is set and the device is configured for a multiplexed access protocol in agen then the device is accessed in read mode using the AAD-mux protocol. If a non-multiplexed device type is selected in agen, field aadmux is ignored. */ ++#define BUSRCON1_AADMUX 0x00002000 ++/* Muxed device is write accessed in AD-mux mode. ++#define BUSRCON1_AADMUX_AD_MUX 0x00000000 */ ++/** Muxed device is write accessed in AAD-mux mode. */ ++#define BUSRCON1_AADMUX_AAD_MUX 0x00002000 ++/** Asynchronous Address Phase */ ++#define BUSRCON1_AAP 0x00001000 ++/* Clock is enabled at beginning of access. ++#define BUSRCON1_AAP_EARLY 0x00000000 */ ++/** Clock is enabled after address phase. */ ++#define BUSRCON1_AAP_LATE 0x00001000 ++/** Burst Flash Read Single Stage Synchronisation */ ++#define BUSRCON1_BFSSS 0x00000800 ++/* Two stages of synchronisation used. ++#define BUSRCON1_BFSSS_TWO_STAGE 0x00000000 */ ++/** Single stage of synchronisation used. */ ++#define BUSRCON1_BFSSS_SINGLE_STAGE 0x00000800 ++/** Burst Flash Clock Feedback Enable */ ++#define BUSRCON1_FDBKEN 0x00000400 ++/* Disable ++#define BUSRCON1_FDBKEN_DIS 0x00000000 */ ++/** Enable */ ++#define BUSRCON1_FDBKEN_EN 0x00000400 ++/** Auxiliary Chip Select Enable ++ Not supported in GPON-EBU, field must be set to 0. */ ++#define BUSRCON1_CSA 0x00000200 ++/* Disable ++#define BUSRCON1_CSA_DIS 0x00000000 */ ++/** Enable */ ++#define BUSRCON1_CSA_EN 0x00000200 ++/** Flash Non-Array Access Enable ++ Set to logic one to enable workaround when region is accessed with internal address bit 28 set. See Section 3.17.13 on page 90 for details. */ ++#define BUSRCON1_NAA 0x00000100 ++/* Disable ++#define BUSRCON1_NAA_DIS 0x00000000 */ ++/** Enable */ ++#define BUSRCON1_NAA_EN 0x00000100 ++/** Module Enable */ ++#define BUSRCON1_ENABLE 0x00000001 ++/* Disable ++#define BUSRCON1_ENABLE_DIS 0x00000000 */ ++/** Enable */ ++#define BUSRCON1_ENABLE_EN 0x00000001 ++ ++/* Fields of "Bus Read Parameters Register1" */ ++/** Address Cycles ++ Number of cycles for address phase. */ ++#define BUSRP1_ADDRC_MASK 0xF0000000 ++/** field offset */ ++#define BUSRP1_ADDRC_OFFSET 28 ++/** Address Hold Cycles For Multiplexed Address ++ Number of address hold cycles during multiplexed accesses. */ ++#define BUSRP1_ADHOLC_MASK 0x0F000000 ++/** field offset */ ++#define BUSRP1_ADHOLC_OFFSET 24 ++/** Programmed Command Delay Cycles ++ Number of delay cycles during command delay phase. */ ++#define BUSRP1_CMDDELAY_MASK 0x00F00000 ++/** field offset */ ++#define BUSRP1_CMDDELAY_OFFSET 20 ++/** Extended Data */ ++#define BUSRP1_EXTDATA_MASK 0x000C0000 ++/** field offset */ ++#define BUSRP1_EXTDATA_OFFSET 18 ++/** External device outputs data every BFCLK cycle */ ++#define BUSRP1_EXTDATA_ONE 0x00000000 ++/** External device outputs data every 2nd BFCLK cycles */ ++#define BUSRP1_EXTDATA_TWO 0x00040000 ++/** External device outputs data every 4th BFCLK cycles */ ++#define BUSRP1_EXTDATA_FOUR 0x00080000 ++/** External device outputs data every 8th BFCLK cycles */ ++#define BUSRP1_EXTDATA_EIGHT 0x000C0000 ++/** Frequency of external clock at pin BFCLKO */ ++#define BUSRP1_EXTCLOCK_MASK 0x00030000 ++/** field offset */ ++#define BUSRP1_EXTCLOCK_OFFSET 16 ++/** Equal to ebu_clk frequency. */ ++#define BUSRP1_EXTCLOCK_ONE_TO_ONE 0x00000000 ++/** 1/2 of ebu_clk frequency. */ ++#define BUSRP1_EXTCLOCK_ONE_TO_TWO 0x00010000 ++/** 1/3 of ebu_clk frequency. */ ++#define BUSRP1_EXTCLOCK_ONE_TO_THREE 0x00020000 ++/** 1/4 of ebu_clk frequency (default after reset). */ ++#define BUSRP1_EXTCLOCK_ONE_TO_FOUR 0x00030000 ++/** Data Hold Cycles For read Accesses ++ Number of data hold cycles during read accesses. Applies to spinner support only where the address is guaranteed stable for datac clocks after RD high */ ++#define BUSRP1_DATAC_MASK 0x0000F000 ++/** field offset */ ++#define BUSRP1_DATAC_OFFSET 12 ++/** Programmed Wait States for read accesses ++ Number of programmed wait states for read accesses. For synchronous accesses, this will always be adjusted so that the phase exits on a rising edge of the external clock. */ ++#define BUSRP1_WAITRDC_MASK 0x00000F80 ++/** field offset */ ++#define BUSRP1_WAITRDC_OFFSET 7 ++/** Recovery Cycles After read Accesses, same CS ++ Number of idle cycles after read accesses when the next access is to the same chip select. For synchronous accesses, this will always be adjusted so that the phase exits on a rising clock edge. Note that at least one recovery cycle must be programmed in case the region is configured for delayed control signals in field ecse of register EBU_BUSRCON. */ ++#define BUSRP1_RECOVC_MASK 0x00000070 ++/** field offset */ ++#define BUSRP1_RECOVC_OFFSET 4 ++/** Recovery Cycles After read Accesses, other CS ++ Number of idle cycles after read accesses when the next access is to a different chip select. For synchronous accesses, this will always be adjusted so that the phase exits on a rising clock edge. Note that at least one recovery cycle must be programmed in case the region is configured for delayed control signals in field ecse of register EBU_BUSRCON. */ ++#define BUSRP1_DTACS_MASK 0x0000000F ++/** field offset */ ++#define BUSRP1_DTACS_OFFSET 0 ++ ++/* Fields of "Bus Write Configuration Register1" */ ++/** Device Type For Region ++ After reset, the CS region is configured for a slow Asynchronous access protocol which is compatible with read access from an external multiplexed or demultiplexed 16-Bit Burst Flash in asynchronous mode. Reset: 0000B */ ++#define BUSWCON1_AGEN_MASK 0xF0000000 ++/** field offset */ ++#define BUSWCON1_AGEN_OFFSET 28 ++/** Muxed Asynchronous Type External Memory */ ++#define BUSWCON1_AGEN_MUXED_ASYNC_TYPE_EXT_MEM 0x00000000 ++/** Muxed Burst Type External Memory */ ++#define BUSWCON1_AGEN_MUXED_BURST_TYPE_EXT_MEM 0x10000000 ++/** NAND Flash (page optimised) */ ++#define BUSWCON1_AGEN_NAND_FLASH 0x20000000 ++/** Muxed Cellular RAM External Memory */ ++#define BUSWCON1_AGEN_MUXED_CELLULAR_RAM_EXT_MEM 0x30000000 ++/** Demuxed Asynchronous Type External Memory */ ++#define BUSWCON1_AGEN_DEMUXED_ASYNC_TYPE_EXT_MEM 0x40000000 ++/** Demuxed Burst Type External Memory */ ++#define BUSWCON1_AGEN_DEMUXED_BURST_TYPE_EXT_MEM 0x50000000 ++/** Demuxed Page Mode External Memory */ ++#define BUSWCON1_AGEN_DEMUXED_PAGE_MODE_EXT_MEM 0x60000000 ++/** Demuxed Cellular RAM External Memory */ ++#define BUSWCON1_AGEN_DEMUXED_CELLULAR_RAM_EXT_MEM 0x70000000 ++/** Serial Flash */ ++#define BUSWCON1_AGEN_SERIAL_FLASH 0xF0000000 ++/** Device Addressing Mode ++ t.b.d. */ ++#define BUSWCON1_PORTW_MASK 0x0C000000 ++/** field offset */ ++#define BUSWCON1_PORTW_OFFSET 26 ++/** External Wait Control ++ Function of the WAIT input. This is specific to the device type (i.e. the agen field). */ ++#define BUSWCON1_WAIT_MASK 0x03000000 ++/** field offset */ ++#define BUSWCON1_WAIT_OFFSET 24 ++/** WAIT is ignored (default after reset). */ ++#define BUSWCON1_WAIT_OFF 0x00000000 ++/** Synchronous Burst Devices: WAIT signal is provided one cycle ahead of the data cycle it applies to. */ ++#define BUSWCON1_WAIT_EARLY_WAIT 0x01000000 ++/** Asynchronous Devices: WAIT input passes through a two-stage synchronizer before being evaluated. */ ++#define BUSWCON1_WAIT_TWO_STAGE_SYNC 0x01000000 ++/** Synchronous Burst Devices: WAIT signal is provided in the same data cycle it applies to. */ ++#define BUSWCON1_WAIT_WAIT_WITH_DATA 0x02000000 ++/** Asynchronous Devices: WAIT input passes through a single-stage synchronizer before being evaluated. */ ++#define BUSWCON1_WAIT_SINGLE_STAGE_SYNC 0x02000000 ++/** Synchronous Burst Devices: Abort and retry access if WAIT asserted */ ++#define BUSWCON1_WAIT_ABORT_AND_RETRY 0x03000000 ++/** Reserved */ ++#define BUSWCON1_LOCKCS 0x00800000 ++/** Reversed polarity at wait */ ++#define BUSWCON1_WAITINV 0x00400000 ++/* Low active. ++#define BUSWCON1_WAITINV_ACTLOW 0x00000000 */ ++/** High active */ ++#define BUSWCON1_WAITINV_ACTHI 0x00400000 ++/** Early ADV Enable for Synchronous Bursts */ ++#define BUSWCON1_EBSE 0x00200000 ++/* Low active. ++#define BUSWCON1_EBSE_DELAYED 0x00000000 */ ++/** High active */ ++#define BUSWCON1_EBSE_NOT_DELAYED 0x00200000 ++/** Early Control Signals for Synchronous Bursts */ ++#define BUSWCON1_ECSE 0x00100000 ++/* Low active. ++#define BUSWCON1_ECSE_DELAYED 0x00000000 */ ++/** High active */ ++#define BUSWCON1_ECSE_NOT_DELAYED 0x00100000 ++/** Synchronous Burst Buffer Mode Select */ ++#define BUSWCON1_FBBMSEL 0x00080000 ++/* FIXED_LENGTH ++#define BUSWCON1_FBBMSEL_FIXED_LENGTH 0x00000000 */ ++/** CONTINUOUS */ ++#define BUSWCON1_FBBMSEL_CONTINUOUS 0x00080000 ++/** Burst Length for Synchronous Burst */ ++#define BUSWCON1_FETBLEN_MASK 0x00070000 ++/** field offset */ ++#define BUSWCON1_FETBLEN_OFFSET 16 ++/** Up to 1 data cycle (default after reset). */ ++#define BUSWCON1_FETBLEN_SINGLE 0x00000000 ++/** Up to 2 data cycles. */ ++#define BUSWCON1_FETBLEN_BURST2 0x00010000 ++/** Up to 4 data cycles. */ ++#define BUSWCON1_FETBLEN_BURST4 0x00020000 ++/** Up to 8 data cycles. */ ++#define BUSWCON1_FETBLEN_BURST8 0x00030000 ++/** Up to 16 data cycles. */ ++#define BUSWCON1_FETBLEN_BURST16 0x00040000 ++/** Reserved ++ This field allows to configure how the EBU generates the CLE and ALE signals for a NAND Flash device. The following options are available */ ++#define BUSWCON1_NANDAMAP_MASK 0x0000C000 ++/** field offset */ ++#define BUSWCON1_NANDAMAP_OFFSET 14 ++/** is taken from AMemport[18] and ALE from AMemport[17] and are output on pins A[17:16] on the External Bus (default after reset). */ ++#define BUSWCON1_NANDAMAP_NAND_A17_16 0x00000000 ++/** is taken from AMemport[18] and ALE from AMemport[17] and are output on pins A[17:16] on the External Bus (default after reset). */ ++#define BUSWCON1_NANDAMAP_NAND_WAIT_ADV 0x00004000 ++/** CLE is taken from AMemport[18] and ALE from AMemport[17] and are output on pins AD[9:8] and A[9:8] on the External Bus. This mode may only be used with a 8-Bit NAND-Flash device. */ ++#define BUSWCON1_NANDAMAP_NAND_AD9_8 0x00008000 ++/** Reserved for future use. Do not use or unpredictable results may occur. */ ++#define BUSWCON1_NANDAMAP_NAND_RFU 0x0000C000 ++/** AAD-mux Protocol ++ If this bit is set and the device is configured for a multiplexed access protocol in agen then the device is accessed in read mode using the AAD-mux protocol. If a non-multiplexed device type is selected in agen, field aadmux is ignored. */ ++#define BUSWCON1_AADMUX 0x00002000 ++/* Muxed device is write accessed in AD-mux mode. ++#define BUSWCON1_AADMUX_AD_MUX 0x00000000 */ ++/** Muxed device is write accessed in AAD-mux mode. */ ++#define BUSWCON1_AADMUX_AAD_MUX 0x00002000 ++/** Asynchronous Address Phase */ ++#define BUSWCON1_AAP 0x00001000 ++/* Clock is enabled at beginning of access. ++#define BUSWCON1_AAP_EARLY 0x00000000 */ ++/** Clock is enabled after address phase. */ ++#define BUSWCON1_AAP_LATE 0x00001000 ++/** Auxiliary Chip Select Enable ++ Not supported in GPON-EBU, field must be set to 0. */ ++#define BUSWCON1_CSA 0x00000200 ++/* Disable ++#define BUSWCON1_CSA_DIS 0x00000000 */ ++/** Enable */ ++#define BUSWCON1_CSA_EN 0x00000200 ++/** Flash Non-Array Access Enable ++ Set to logic one to enable workaround when region is accessed with internal address bit 28 set. See Section 3.17.13 on page 90 for details. */ ++#define BUSWCON1_NAA 0x00000100 ++/* Disable ++#define BUSWCON1_NAA_DIS 0x00000000 */ ++/** Enable */ ++#define BUSWCON1_NAA_EN 0x00000100 ++/** Module Enable */ ++#define BUSWCON1_ENABLE 0x00000001 ++/* Disable ++#define BUSWCON1_ENABLE_DIS 0x00000000 */ ++/** Enable */ ++#define BUSWCON1_ENABLE_EN 0x00000001 ++ ++/* Fields of "Bus Write Parameters Register1" */ ++/** Address Cycles ++ Number of cycles for address phase. */ ++#define BUSWP1_ADDRC_MASK 0xF0000000 ++/** field offset */ ++#define BUSWP1_ADDRC_OFFSET 28 ++/** Address Hold Cycles For Multiplexed Address ++ Number of address hold cycles during multiplexed accesses. */ ++#define BUSWP1_ADHOLC_MASK 0x0F000000 ++/** field offset */ ++#define BUSWP1_ADHOLC_OFFSET 24 ++/** Programmed Command Delay Cycles ++ Number of delay cycles during command delay phase. */ ++#define BUSWP1_CMDDELAY_MASK 0x00F00000 ++/** field offset */ ++#define BUSWP1_CMDDELAY_OFFSET 20 ++/** Extended Data */ ++#define BUSWP1_EXTDATA_MASK 0x000C0000 ++/** field offset */ ++#define BUSWP1_EXTDATA_OFFSET 18 ++/** External device outputs data every BFCLK cycle */ ++#define BUSWP1_EXTDATA_ONE 0x00000000 ++/** External device outputs data every 2nd BFCLK cycles */ ++#define BUSWP1_EXTDATA_TWO 0x00040000 ++/** External device outputs data every 4th BFCLK cycles */ ++#define BUSWP1_EXTDATA_FOUR 0x00080000 ++/** External device outputs data every 8th BFCLK cycles */ ++#define BUSWP1_EXTDATA_EIGHT 0x000C0000 ++/** Frequency of external clock at pin BFCLKO */ ++#define BUSWP1_EXTCLOCK_MASK 0x00030000 ++/** field offset */ ++#define BUSWP1_EXTCLOCK_OFFSET 16 ++/** Equal to ebu_clk frequency. */ ++#define BUSWP1_EXTCLOCK_ONE_TO_ONE 0x00000000 ++/** 1/2 of ebu_clk frequency. */ ++#define BUSWP1_EXTCLOCK_ONE_TO_TWO 0x00010000 ++/** 1/3 of ebu_clk frequency. */ ++#define BUSWP1_EXTCLOCK_ONE_TO_THREE 0x00020000 ++/** 1/4 of ebu_clk frequency (default after reset). */ ++#define BUSWP1_EXTCLOCK_ONE_TO_FOUR 0x00030000 ++/** Data Hold Cycles For write Accesses ++ Number of data hold cycles during write accesses. */ ++#define BUSWP1_DATAC_MASK 0x0000F000 ++/** field offset */ ++#define BUSWP1_DATAC_OFFSET 12 ++/** Programmed Wait States For write Accesses ++ Number of programmed wait states for write accesses. For synchronous accesses, this will always be adjusted so that the phase exits on a rising edge of the external clock. */ ++#define BUSWP1_WAITWDC_MASK 0x00000F80 ++/** field offset */ ++#define BUSWP1_WAITWDC_OFFSET 7 ++/** Recovery Cycles After write Accesses, same CS ++ Number of idle cycles after write accesses when following access is to the same chip select. For synchronous accesses, this will always be adjusted so that the phase exits on a rising clock edge. phase exits on a rising clock edge. Note that at least one recovery cycle must be programmed in case the region is configured for delayed control signals in field ecse of register EBU_BUSWCON. */ ++#define BUSWP1_RECOVC_MASK 0x00000070 ++/** field offset */ ++#define BUSWP1_RECOVC_OFFSET 4 ++/** Recovery Cycles After write Accesses, other CS ++ Number of idle cycles after write accesses when the following access is to a different chip select. For synchronous accesses, this will always be adjusted so that the phase exits on a rising clock edge. Note that at least one recovery cycle must be programmed in case the region is configured for delayed control signals in field ecse of register EBU_BUSWCON. */ ++#define BUSWP1_DTACS_MASK 0x0000000F ++/** field offset */ ++#define BUSWP1_DTACS_OFFSET 0 ++ ++/* Fields of "Bus Protocol Configuration Extension Register 0" */ ++/** Byte Control Mapping ++ Remapping of byte enable signals on address lines is not supported in the GPON-EBU. */ ++#define BUSCONEXT0_BCMAP_MASK 0x00030000 ++/** field offset */ ++#define BUSCONEXT0_BCMAP_OFFSET 16 ++/** No mirroring of byte enables. */ ++#define BUSCONEXT0_BCMAP_NOBCMAP 0x00000000 ++/** Asynchronous Early Write ++ This bit is obsolete and must be set to 0 or unpredictable results may result. */ ++#define BUSCONEXT0_AEW 0x00008000 ++/** AAD-mux Consecutive Address Cycles ++ This bit selects whether ADV gets deasserted between the high and the low address phase of a synchronous AAD-mux access or the two address cycles are consecutive. See Figure 32 for a waveform example that results when acac is set. acac only takes effect if the CS region is configured for synchronous AADmux access (agen = 1 or 3, aadmux = 1) and is ignored otherwise. */ ++#define BUSCONEXT0_ACAC 0x00004000 ++/* ADV is deasserted between high and low address phase. ++#define BUSCONEXT0_ACAC_SEPERATED 0x00000000 */ ++/** ADV is not deasserted between high and low address phase. */ ++#define BUSCONEXT0_ACAC_CONSECUTIVE 0x00004000 ++/** AAD-mux Write Address-to-Address Delay ++ Gives the length of the AA-Phase (in multiples of the ebu_clk cycle) to be used when writing to the CS region. The parameter is only observed if the CS region is configured for use of the AAD-mux protocol in register EBU_BUSWCON, fields agen and aadmux. */ ++#define BUSCONEXT0_WAAC_MASK 0x00003800 ++/** field offset */ ++#define BUSCONEXT0_WAAC_OFFSET 11 ++/** AAD-mux Read Address-to-Address Delay ++ Gives the length of the AA-Phase (in multiples of the ebu_clk cycle) to be used when reading from the CS region. The parameter is only observed if the CS region is configured for use of the AAD-mux protocol in register EBU_BUSRCON, fields agen and aadmux. */ ++#define BUSCONEXT0_RAAC_MASK 0x00000700 ++/** field offset */ ++#define BUSCONEXT0_RAAC_OFFSET 8 ++/** AAD-mux Paging Enable for CS0 ++ If the external device is configured for AAD-mux protocol in register EBU_BUSRCON, then this field selects whether or not to use paging. If paging is enabled, the EBU skips the high address cycle in case the upper address that would be sent are the same as in the most recent access to the device.configures how to set the AD[15:14] in the high address cycle of an access with the following encoding: */ ++#define BUSCONEXT0_PAGE_EN 0x00000080 ++/* Disable ++#define BUSCONEXT0_PAGE_EN_DIS 0x00000000 */ ++/** Enable */ ++#define BUSCONEXT0_PAGE_EN_EN 0x00000080 ++/** AAD-mux Address Extension Bit Generation Mode ++ If the external device is configured for AAD-mux protocol in register EBU_BUSRCON, then this field configures how to set the AD[15:14] in the high address cycle of an access with the following encoding: */ ++#define BUSCONEXT0_AEBM_MASK 0x00000070 ++/** field offset */ ++#define BUSCONEXT0_AEBM_OFFSET 4 ++/** A[15] in the high address cycle is set to AMemport[amsb+17], A[14] is set to 0 */ ++#define BUSCONEXT0_AEBM_AMAP_CRE_RFU0 0x00000000 ++/** A[15] in the high address cycle is set to AMemport[amsb+17], A[14] is set to 1 */ ++#define BUSCONEXT0_AEBM_AMAP_CRE_RFU1 0x00000010 ++/** A[15] in the high address cycle is set to AMemport[amsb+18], A[14] is set to AMemport[amsb+17] */ ++#define BUSCONEXT0_AEBM_AMAP_CRE_AND_RFU 0x00000020 ++/** Do not use */ ++#define BUSCONEXT0_AEBM_reserved 0x00000030 ++/** A[15:14] in the high address cycle is set to 00B. */ ++#define BUSCONEXT0_AEBM_DIRECT_00 0x00000040 ++/** A[15:14] in the high address cycle is set to 01B */ ++#define BUSCONEXT0_AEBM_DIRECT_01 0x00000050 ++/** A[15:14] in the high address cycle is set to 10B */ ++#define BUSCONEXT0_AEBM_DIRECT_10 0x00000060 ++/** A[15:14] in the high address cycle is set to 11B. */ ++#define BUSCONEXT0_AEBM_DIRECT_11 0x00000070 ++/** Most Significant Address Bit of External Device ++ If the external device is configured for AAD-mux protocol in register EBU_BUSRCON, then for amsb < 14 the EBU always sets A[13:amsb] = 0 in the high address cycle of an access. The value of A[15:14] is defined in field aebm. A value of amsb > 13 therefore has no effect. It is recommended to set amsb that it matches the addressable range of the external device according to the following formula: amsb = n - 16 for a device with 2n addressable words. */ ++#define BUSCONEXT0_AMSB_MASK 0x0000000F ++/** field offset */ ++#define BUSCONEXT0_AMSB_OFFSET 0 ++ ++/* Fields of "Bus Protocol Configuration Extension Register 1" */ ++/** Byte Control Mapping ++ Remapping of byte enable signals on address lines is not supported in the GPON-EBU. */ ++#define BUSCONEXT1_BCMAP_MASK 0x00030000 ++/** field offset */ ++#define BUSCONEXT1_BCMAP_OFFSET 16 ++/** No mirroring of byte enables. */ ++#define BUSCONEXT1_BCMAP_NOBCMAP 0x00000000 ++/** Asynchronous Early Write ++ This bit is obsolete and must be set to 0 or unpredictable results may result. */ ++#define BUSCONEXT1_AEW 0x00008000 ++/** AAD-mux Consecutive Address Cycles ++ This bit selects whether ADV gets deasserted between the high and the low address phase of a synchronous AAD-mux access or the two address cycles are consecutive. See Figure 32 for a waveform example that results when acac is set. acac only takes effect if the CS region is configured for synchronous AADmux access (agen = 1 or 3, aadmux = 1) and is ignored otherwise. */ ++#define BUSCONEXT1_ACAC 0x00004000 ++/* ADV is deasserted between high and low address phase. ++#define BUSCONEXT1_ACAC_SEPERATED 0x00000000 */ ++/** ADV is not deasserted between high and low address phase. */ ++#define BUSCONEXT1_ACAC_CONSECUTIVE 0x00004000 ++/** AAD-mux Write Address-to-Address Delay ++ Gives the length of the AA-Phase (in multiples of the ebu_clk cycle) to be used when writing to the CS region. The parameter is only observed if the CS region is configured for use of the AAD-mux protocol in register EBU_BUSWCON, fields agen and aadmux. */ ++#define BUSCONEXT1_WAAC_MASK 0x00003800 ++/** field offset */ ++#define BUSCONEXT1_WAAC_OFFSET 11 ++/** AAD-mux Read Address-to-Address Delay ++ Gives the length of the AA-Phase (in multiples of the ebu_clk cycle) to be used when reading from the CS region. The parameter is only observed if the CS region is configured for use of the AAD-mux protocol in register EBU_BUSRCON, fields agen and aadmux. */ ++#define BUSCONEXT1_RAAC_MASK 0x00000700 ++/** field offset */ ++#define BUSCONEXT1_RAAC_OFFSET 8 ++/** AAD-mux Paging Enable for CS0 ++ If the external device is configured for AAD-mux protocol in register EBU_BUSRCON, then this field selects whether or not to use paging. If paging is enabled, the EBU skips the high address cycle in case the upper address that would be sent are the same as in the most recent access to the device.configures how to set the AD[15:14] in the high address cycle of an access with the following encoding: */ ++#define BUSCONEXT1_PAGE_EN 0x00000080 ++/* Disable ++#define BUSCONEXT1_PAGE_EN_DIS 0x00000000 */ ++/** Enable */ ++#define BUSCONEXT1_PAGE_EN_EN 0x00000080 ++/** AAD-mux Address Extension Bit Generation Mode ++ If the external device is configured for AAD-mux protocol in register EBU_BUSRCON, then this field configures how to set the AD[15:14] in the high address cycle of an access with the following encoding: */ ++#define BUSCONEXT1_AEBM_MASK 0x00000070 ++/** field offset */ ++#define BUSCONEXT1_AEBM_OFFSET 4 ++/** A[15] in the high address cycle is set to AMemport[amsb+17], A[14] is set to 0 */ ++#define BUSCONEXT1_AEBM_AMAP_CRE_RFU0 0x00000000 ++/** A[15] in the high address cycle is set to AMemport[amsb+17], A[14] is set to 1 */ ++#define BUSCONEXT1_AEBM_AMAP_CRE_RFU1 0x00000010 ++/** A[15] in the high address cycle is set to AMemport[amsb+18], A[14] is set to AMemport[amsb+17] */ ++#define BUSCONEXT1_AEBM_AMAP_CRE_AND_RFU 0x00000020 ++/** Do not use */ ++#define BUSCONEXT1_AEBM_reserved 0x00000030 ++/** A[15:14] in the high address cycle is set to 00B. */ ++#define BUSCONEXT1_AEBM_DIRECT_00 0x00000040 ++/** A[15:14] in the high address cycle is set to 01B */ ++#define BUSCONEXT1_AEBM_DIRECT_01 0x00000050 ++/** A[15:14] in the high address cycle is set to 10B */ ++#define BUSCONEXT1_AEBM_DIRECT_10 0x00000060 ++/** A[15:14] in the high address cycle is set to 11B. */ ++#define BUSCONEXT1_AEBM_DIRECT_11 0x00000070 ++/** Most Significant Address Bit of External Device ++ If the external device is configured for AAD-mux protocol in register EBU_BUSRCON, then for amsb < 14 the EBU always sets A[13:amsb] = 0 in the high address cycle of an access. The value of A[15:14] is defined in field aebm. A value of amsb > 13 therefore has no effect. It is recommended to set amsb that it matches the addressable range of the external device according to the following formula: amsb = n - 16 for a device with 2n addressable words. */ ++#define BUSCONEXT1_AMSB_MASK 0x0000000F ++/** field offset */ ++#define BUSCONEXT1_AMSB_OFFSET 0 ++ ++/* Fields of "Serial Flash Configuration Register" */ ++/** Direct Access Device Port Width ++ DA_PORTW Defines the number of signal lines to be used with direct read access from a Serial Flash as defined for the command with opcode rd_opc. Depending on thedevice type and/or command, the number of used signal lines might differbetween command, address, and data phase of the transaction. */ ++#define SFCON_DA_PORTW_MASK 0xE0000000 ++/** field offset */ ++#define SFCON_DA_PORTW_OFFSET 29 ++/** One signal line used in all phases of the transaction. */ ++#define SFCON_DA_PORTW_WIDTH_1_1_1 0x00000000 ++/** One signal line used in the COMMAND and ADDRESS phase of the transaction and two signal lines used in the DATA phase. */ ++#define SFCON_DA_PORTW_WIDTH_1_1_2 0x20000000 ++/** One signal used in the COMMAND phase of the transaction and two signal lines used in the ADDRESS/DUMMY phase and the DATA phase. */ ++#define SFCON_DA_PORTW_WIDTH_1_2_2 0x40000000 ++/** Two signal lines used in all phases of the transaction. */ ++#define SFCON_DA_PORTW_WIDTH_2_2_2 0x60000000 ++/** One signal line used in the COMMAND and ADDRESS phase of the transaction and four signal lines used in the DATA phase. */ ++#define SFCON_DA_PORTW_WIDTH_1_1_4 0x80000000 ++/** One signal used in the COMMAND phase of the transaction and four signal lines used in the ADDRESS/DUMMY phase and the DATA phase. */ ++#define SFCON_DA_PORTW_WIDTH_1_4_4 0xA0000000 ++/** Four signal lines used in all phases of the transaction. */ ++#define SFCON_DA_PORTW_WIDTH_4_4_4 0xC0000000 ++/** for future use. */ ++#define SFCON_DA_PORTW_WIDTH_reserved 0xE0000000 ++/** Read Abort Enable ++ If set, a read access from the external device can be aborted via signal sf_rd_abort_i. See Section 3.18.2.9 for details. */ ++#define SFCON_RD_ABORT_EN 0x10000000 ++/** Device Size ++ Defines the number of significant address bits for the Serial Flash device(s). All address bits above the MSB are forced to 0. The configuration in this field also defines for the address auto-increment feature when to wrap around from the upper most address to 0. */ ++#define SFCON_DEV_SIZE_MASK 0x0F000000 ++/** field offset */ ++#define SFCON_DEV_SIZE_OFFSET 24 ++/** 16 MBit device */ ++#define SFCON_DEV_SIZE_A20_0 0x00000000 ++/** 32 MBit device */ ++#define SFCON_DEV_SIZE_A21_0 0x01000000 ++/** 64 MBit device */ ++#define SFCON_DEV_SIZE_A22_0 0x02000000 ++/** 128 MBit device */ ++#define SFCON_DEV_SIZE_A23_0 0x03000000 ++/** 256 MBit device */ ++#define SFCON_DEV_SIZE_A24_0 0x04000000 ++/** 512 MBit device */ ++#define SFCON_DEV_SIZE_A25_0 0x05000000 ++/** 1 GBit device */ ++#define SFCON_DEV_SIZE_A26_0 0x06000000 ++/** 2 GBit device */ ++#define SFCON_DEV_SIZE_A27_0 0x07000000 ++/** 4 GBit device */ ++#define SFCON_DEV_SIZE_A28_0 0x08000000 ++/** 8 GBit device */ ++#define SFCON_DEV_SIZE_A29_0 0x09000000 ++/** 16 GBit device */ ++#define SFCON_DEV_SIZE_A30_0 0x0A000000 ++/** 32 GBit device */ ++#define SFCON_DEV_SIZE_A31_0 0x0B000000 ++/** Device Page Size ++ Defines the page size employed by all connected Serial Flash devices. The device page size is used to determine the address wrap-around for the write address auto-increment feature. */ ++#define SFCON_DPS_MASK 0x00C00000 ++/** field offset */ ++#define SFCON_DPS_OFFSET 22 ++/** Device page size is 256 Bytes */ ++#define SFCON_DPS_DPS_256 0x00000000 ++/** Device page size is 512 Bytes */ ++#define SFCON_DPS_DPS_512 0x00400000 ++/** Page Buffer Size ++ Defines the size of the EBU's page buffer used in Buffered Access. Page buffer size configured here must be less than or equal to the maximum page buffer size which is a built option of the EBU (256 Bytes for GPON). */ ++#define SFCON_PB_SIZE_MASK 0x00300000 ++/** field offset */ ++#define SFCON_PB_SIZE_OFFSET 20 ++/** No read buffer is available/used. */ ++#define SFCON_PB_SIZE_NONE 0x00000000 ++/** 128 Bytes */ ++#define SFCON_PB_SIZE_SIZE_128 0x00100000 ++/** 256 Bytes */ ++#define SFCON_PB_SIZE_SIZE_256 0x00200000 ++/** Bidirectional Data Bus ++ Defines whether the Serial Flash uses a unidirectional or a bidirectional data bus. */ ++#define SFCON_BIDIR 0x00080000 ++/* The Serial Flash interface uses a pair of two unidirectional busses (one for write, one for read) ++#define SFCON_BIDIR_UNIDIRECTIONAL 0x00000000 */ ++/** The Serial Flash interface uses a bidirectional data bus. */ ++#define SFCON_BIDIR_BIDIRECTIONAL 0x00080000 ++/** No Busy Error termination ++ By default, the EBU error-terminates all direct access to a Serial Flash while EBU_SFSTAT.busy is set. By setting NO_BUSY_ERR, the EBU can be configured to permit direct accesses to proceed to the Serial Flash, e.g. for devices that support a read-while-write functionality. */ ++#define SFCON_NO_BUSY_ERR 0x00040000 ++/** End-of-Busy Detection Mode ++ Defines how the EBU detects the end of a busy phase in the Serial Flash device. The current version of the EBU requires the software to explicitly poll the device's status register and then inform the EBU on the end of the busy status by clearing the corresponding bit in register EBU_SF_STAT. */ ++#define SFCON_EOBDM_MASK 0x00030000 ++/** field offset */ ++#define SFCON_EOBDM_OFFSET 16 ++/** No read buffer is available/used. */ ++#define SFCON_EOBDM_SOFTWARE 0x00000000 ++/** Poll device status register (not supported yet) */ ++#define SFCON_EOBDM_POLL_SR 0x00010000 ++/** Poll devices busy/ready pin fed into EBU via WAIT pin (not supported yet). */ ++#define SFCON_EOBDM_POLL_RDY 0x00020000 ++/** Same as POLL_RDY, but CS must be asserted to have the device output its busy/ready status (not supported yet). */ ++#define SFCON_EOBDM_POLL_RDY_WITH_CS 0x00030000 ++/** Direct Access Keep Chip Select ++ Defines whether the Serial Flash remains selected after a direct access transaction has been finished. */ ++#define SFCON_DA_KEEP_CS 0x00008000 ++/* After a direct read access, the Serial Flash device is always deselected (CS deasserted). Follow-up read accesses always require sending command opcode and address. ++#define SFCON_DA_KEEP_CS_DESELECT 0x00000000 */ ++/** Chip Select of device is kept active after direct read access so that device is ready for follow-up read of next sequential byte without the need to send command and address. If the next command is to another Chip Select, is a different command or accesses a different address, the EBU first deactivates the kept Chip Select before it starts the new transaction with sending the command opcode and address. */ ++#define SFCON_DA_KEEP_CS_KEEP_SELECTED 0x00008000 ++/** Early Read Abort Enable ++ When aborting a Serial Flash Read is enabled in bit EBU_SFCON.rd_abort_en, bit early_abort selects at what point in the protocol an external access might be aborted. Datasheets of many Serial Flash devices are not explicit on what happens (and whether it is allowed) when a read access is cut-short by deselecting the device during the CMD, ADDR or DUMMY phase of the protocol. */ ++#define SFCON_EARLY_ABORT 0x00004000 ++/* DISABLE Early abortion is disabled (default after reset). Once the EBU has started the access on the External Bus (first bit time slot), the EBU continues the external transfer until the first data byte has been received. After a direct read access, the Serial Flash device is always deselected (CS deasserted). Follow-up read accesses always require sending command opcode and address. ++#define SFCON_EARLY_ABORT_DISABLE 0x00000000 */ ++/** Early abortion is not yet supported in the current version of the EBU. Do not use. The feature is a late improvement to the EBU and could not be verified completely before the final release. After proven to work, it should be made officially available to reduce access latency after aborted Serial Flash reads. Setting early_abort to ENABLE alters the read abort handling in the following way: Once the EBU has started the access on the External Bus, the transfer is cut-short after transferring the CMD byte, the three address bytes, any DUMMY bits or at the end of the next data byte - whatever comes first. */ ++#define SFCON_EARLY_ABORT_ENABLE 0x00004000 ++/** Direct Access Address Length ++ Defines the number of address bytes to be sent (MSB first) to the device with a direct read access transaction. Other values than listed below are not supported and have unpredictable results. */ ++#define SFCON_DA_ALEN_MASK 0x00003000 ++/** field offset */ ++#define SFCON_DA_ALEN_OFFSET 12 ++/** 3 address bytes (bits 23:0 of the internal address) */ ++#define SFCON_DA_ALEN_THREE 0x00000000 ++/** Read Access Dummy Bytes ++ This field defines the number of dummy bytes to send between the last address byte before the EBU starts capturing read data from the bus for a direct read access. The number of dummy bytes depends on the data access command being used (see field), the clock frequency and the type of device being used. */ ++#define SFCON_RD_DUMLEN_MASK 0x00000F00 ++/** field offset */ ++#define SFCON_RD_DUMLEN_OFFSET 8 ++/** Direct Read Access Command Opcode ++ This byte defines the command opcode to send when performing a data read from the Serial Flash in Direct Access Mode. Any value can be set (the EBU does not interpret the value, but directly uses the contents of this register field in the command phase of the transaction). Common opcodes to be used and understood by most devices are READ (03H) and FAST_READ (0BH), but some devices might provide additional opcodes, e.g. to support higher clock frequencies requiring additional dummy bytes or to define a wider interface bus. */ ++#define SFCON_RD_OPC_MASK 0x000000FF ++/** field offset */ ++#define SFCON_RD_OPC_OFFSET 0 ++/** READ */ ++#define SFCON_RD_OPC_READ 0x00000003 ++/** FAST_READ */ ++#define SFCON_RD_OPC_FAST_READ 0x0000000B ++ ++/* Fields of "Serial Flash Timing Register" */ ++/** CS Idle time ++ This field defines the minimum time the device's Chip Select has to be deasserted in between accesses. Most devices require a minimum deselect time between 50 and 100 ns. See Table 43 for the encoding used in this field. */ ++#define SFTIME_CS_IDLE_MASK 0xF0000000 ++/** field offset */ ++#define SFTIME_CS_IDLE_OFFSET 28 ++/** 1 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_0 0x00000000 ++/** 2 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_1 0x10000000 ++/** 3 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_2 0x20000000 ++/** 4 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_3 0x30000000 ++/** 6 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_4 0x40000000 ++/** 8 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_5 0x50000000 ++/** 10 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_6 0x60000000 ++/** 12 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_7 0x70000000 ++/** 14 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_8 0x80000000 ++/** 16 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_9 0x90000000 ++/** 20 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_10 0xA0000000 ++/** 24 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_11 0xB0000000 ++/** 32 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_12 0xC0000000 ++/** 40 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_13 0xD0000000 ++/** 48 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_14 0xE0000000 ++/** 64 EBU clock cycles */ ++#define SFTIME_CS_IDLE_CLKC_15 0xF0000000 ++/** CS Hold time ++ This field defines (in multiples of the EBU internal clock's period) the minimum time the device's Chip Select must remain asserted after transfer of the last bit of a write transaction. This CS hold time does not apply to read accesses */ ++#define SFTIME_CS_HOLD_MASK 0x0C000000 ++/** field offset */ ++#define SFTIME_CS_HOLD_OFFSET 26 ++/** CS Setup time ++ This field defines (in multiples of the EBU internal clock's period) when to assert the device's Chip Select before the first SCK clock period for transferring the command is started on the External Bus */ ++#define SFTIME_CS_SETUP_MASK 0x03000000 ++/** field offset */ ++#define SFTIME_CS_SETUP_OFFSET 24 ++/** Write-to-Read Pause ++ This field defines the length of the optional pause when switching from write to read direction in the transaction. During this pause, SCK is held stable. */ ++#define SFTIME_WR2RD_PAUSE_MASK 0x00300000 ++/** field offset */ ++#define SFTIME_WR2RD_PAUSE_OFFSET 20 ++/** Read Data Position ++ This field defines when to capture valid read data bit(s) (in multiples of half of the EBU internal clock's period) relative to the beginning of the SCK clock's period defined in EBU_SFTIME.sck_per. RD_POS must be less than or equal to EBU_SFTIME.sck_per (not checked in hardware) or unpredictable results may occur. */ ++#define SFTIME_RD_POS_MASK 0x000F0000 ++/** field offset */ ++#define SFTIME_RD_POS_OFFSET 16 ++/** SCK Fall-edge Position ++ This field defines the positioning of the SCK fall edge (in multiples of half of the EBU internal clock's period) with respect to the beginning of the SCK clock's period defined in EBU_SFTIME.sck_per. SCKF_POS must be less than or equal to SCK_PER (not checked in hardware) or unpredictable results may occur. If EBU_SFTIME.sck_inv is set, SCKF_POS defines the positioning of the falling instead of the rising edge of SCK. In the current version of the EBU, SCKF_POS must be set 0 or unpredictable results may occur. */ ++#define SFTIME_SCKF_POS_MASK 0x0000F000 ++/** field offset */ ++#define SFTIME_SCKF_POS_OFFSET 12 ++/** SCK Rise-edge Position ++ This field defines the positioning of the SCK rise edge (in multiples of half of the EBU internal clock's period) with respect to the beginning of the SCK clock's period defined in EBU_SFTIME.sck_per. SCKR_POS must be less than EBU_SFTIME.sck_per (not checked in hardware) or unpredictable results may occur. If EBU_SFTIME.sck_inv is set, SCKR_POS defines the positioning of the falling instead of the rising edge of SCK. */ ++#define SFTIME_SCKR_POS_MASK 0x00000F00 ++/** field offset */ ++#define SFTIME_SCKR_POS_OFFSET 8 ++/** SCK Feedback Clock Inversion ++ If set, read data gets captured with the falling instead of the rising edge of SCK if clock feedback is enabled in EBU_SFTIME.sck_fdbk_en. */ ++#define SFTIME_SCK_FDBK_INV 0x00000040 ++/** SCK Clock Feedback ++ If set, read data is captured using the external SCK clock feedback into the chip instead of the EBU's internal clock. Using the feedback clock compensate for the high delay over the pads and its use is required at higher frequencies. A penalty for synchronizing the read data from the SCK into the ebu_clk domain applies to the read access latency. */ ++#define SFTIME_SCK_FDBK_EN 0x00000020 ++/** Inverted SCK ++ If set, the clock to the Serial Flash devices is inverted. This also results in SCK high while a Serial Flash remains selected between transactions (keep_cs feature). In the current version of the EBU, clock inversion is not supported. SCK_INV must be set to 0 or unpredictable results may occur. */ ++#define SFTIME_SCK_INV 0x00000010 ++/** SCK Period ++ This field defines the period of the SCK clock in multiples of half of the EBU clock period. The EBU supports values between 2 and 14, corresponding to a frequency ratio range from 1:1. to 1:7 between SCK and the internal clock. Other values are prohibited and result in unpredictable behaviour. In the current version of the EBU, odd values for SCK_PER are not supported. */ ++#define SFTIME_SCK_PER_MASK 0x0000000F ++/** field offset */ ++#define SFTIME_SCK_PER_OFFSET 0 ++ ++/* Fields of "Serial Flash Status Register" */ ++/** Command Overwrite Error ++ This bit is set on an attempt to start an indirect access while a previous indirect access has not finished. The bit remains unaltered when the software writes a '0' and is toggled when a '1' is written. This toggle-by-write-1 behavior allows to also set the bit for testing purposes. In normal operation, the software is supposed to only write a '1' to this bit to clear after it has been set by the Serial Flash protocol engine. */ ++#define SFSTAT_CMD_OVWRT_ERR 0x40000000 ++/** Command Error ++ This bit is set when the EBU discards an indirect or direct access to/from a Serial Flash. The bit remains unaltered when the software writes a '0' and is toggled when a '1' is written. This toggle-by-write-1 behavior allows to also set the bit for testing purposes. In normal operation, the software is supposed to only write a '1' to this bit to clear after it has been set by the Serial Flash protocol engine. */ ++#define SFSTAT_CMD_ERR 0x20000000 ++/** Access Command Pending ++ If set, indicates that access from/to a Serial Flash device has not finished yet. */ ++#define SFSTAT_CMD_PEND 0x00400000 ++/** External Device Selected ++ If set, indicates that the Chip Select of a Serial Flash device is currently active on the External Bus. */ ++#define SFSTAT_SELECTED 0x00200000 ++/** Protocol Engine Active ++ If set, indicates that the EBU's Serial Flash protocol engine is active. */ ++#define SFSTAT_ACTIVE 0x00100000 ++/** Page Buffer Invalidate ++ When writing a one to this bit, bits PB_VALID and PB_UPDATE are both cleared, thereby invalidating the page buffer for access to/from the Serial Flash device. After invalidating the buffer, PB_INVALID is automatically cleared so that it always reads as 0. */ ++#define SFSTAT_PB_INVALID 0x00010000 ++/** Page Buffer Update ++ This bit is set when data in the page buffer gets modified. It is cleared when new data gets loaded to the page buffer, when it is written back to the device (WRITE_PAGE command) or when PB_VALID gets cleared. */ ++#define SFSTAT_PB_UPDATE 0x00002000 ++/** Page Buffer Valid ++ This bit is set after the last data byte of a LOAD_PAGE command has been stored in the page buffer or when the page buffer is explicitely validated via a VALIDATE_PAGE special command. It remains set until the page buffer gets invalidated by writing a 1 to PB_INVALID or any of the LOAD_PAGE special commands. While PB_VALID is set, all accesses to the buffered address range are diverted to the page buffer with no access being performed on the External Bus. */ ++#define SFSTAT_PB_VALID 0x00001000 ++/** Page Buffer Busy ++ The bit is set when the EBU starts executing a LOAD_PAGE or a WRITE_PAGE command and cleared when the last byte of the requested page has been transferred from/to the external device. The inverted value of PB_BUSY is output on the EBU interface and may trigger a system interrupt. */ ++#define SFSTAT_PB_BUSY 0x00000100 ++/** Device Busy ++ This bit is set by the Serial Flash protocol engine when an indirect access is performed via register EBU_SFCMD with SET_BUSY being set. While busy is set, access to the Serial Flash is very limited and all transactions are error-terminated except when explicitly marked to ignore the busy status. If the EBU is configured in EBU_SFCON.EOBDM to automatically poll the busy status of the device, busy is cleared as soon as the device is found to be idle again. On a software write, busy remains unaltered when written with a '0' and is toggled when written with a '1', respectively.This toggle-by-write-1 behaviour allows to also set the bit for testing purposes. In normal operation, the software is supposed to only write a '1' to this bit after it got set by the Serial Flash protocol engine and no automatic busy detection is configured in EBU_SFCON.EOBDM Then the software has to clear busy when it finds the device to be no longer busy by either polling the device's status register via the EBU or by waiting for the maximum busy time of the operation started in the device. */ ++#define SFSTAT_BUSY 0x00000001 ++ ++/* Fields of "Serial Flash Command Register" */ ++/** Command Type ++ This field is a qualifier of the command opcode in EBU_SFCMD.opc. Two types */ ++#define SFCMD_CMDTYPE 0x80000000 ++/* The opcode in EBU_SFCMD.opc is directly used in the command phase of a single transaction to the Serial Flash device. ++#define SFCMD_CMDTYPE_ACCESS_CMD 0x00000000 */ ++/** The opcode in EBU_SFCMD.opc is used to start a special command in the Serial Flash Controller which might include any number of external transactions to/from the Serial Flash device. */ ++#define SFCMD_CMDTYPE_SPECIAL_CMD 0x80000000 ++/** Device Port Width ++ Defines the number of signal lines to be used with direct read access from a Serial Flash as defined for the command with opcode opc. The encoding of this field is the same as forDA_PORTW. */ ++#define SFCMD_PORTW_MASK 0x70000000 ++/** field offset */ ++#define SFCMD_PORTW_OFFSET 28 ++/** Bidirectional Signal Lines ++ If set selects bidirectional signal lines to be used for the data transfer. */ ++#define SFCMD_BIDIR 0x08000000 ++/** Chip Select ++ This field selects which of the EBU's Chip Selects to activated for the command that is written to EBU_SFCMD.opc. A value between 0 and 3 selects one of the EBU's main CSs while 4 to 7 chooses one of the Auxiliary Chip Selects CSA[3:0], respectively. */ ++#define SFCMD_CS_MASK 0x07000000 ++/** field offset */ ++#define SFCMD_CS_OFFSET 24 ++/** Disable Auto Address Increment ++ By default, the address in register EBU_SFADDR is automatically incremented with each data byte being transferred. By setting this bit, the auto-increment can be disabled. */ ++#define SFCMD_DIS_AAI 0x00800000 ++/** Address Length ++ Defines the number of address bytes from register EBU_SFADDR to sent in the address phase of the transaction to/from the Serial Flash. Note: Address bytes are also sent when the command has no data. */ ++#define SFCMD_ALEN_MASK 0x00700000 ++/** field offset */ ++#define SFCMD_ALEN_OFFSET 20 ++/** Dummy Phase Length ++ Defines the number of dummy bytes to send to the device between the command/address phase and the data phase of a transaction. Note:Dummy bytes are also sent when the command has no address and/or no data. */ ++#define SFCMD_DUMLEN_MASK 0x000F0000 ++/** field offset */ ++#define SFCMD_DUMLEN_OFFSET 16 ++/** Keep Chip Select ++ Defines whether the Serial Flash remains selected after the indirect access transaction has been finished. */ ++#define SFCMD_KEEP_CS 0x00008000 ++/* After a direct read access, the Serial Flash device is always deselected (CS deasserted). Follow-up read accesses always require sending command opcode and address. ++#define SFCMD_KEEP_CS_DESELECT 0x00000000 */ ++/** Chip Select of device is kept active after direct read access so that device is ready for follow-up read of next sequential byte without the need to send command and address. If the next command is to another Chip Select, is a different command or accesses a different address, the EBU first deactivates the kept Chip Select before it starts the new transaction with sending the command opcode and address. */ ++#define SFCMD_KEEP_CS_KEEP_SELECTED 0x00008000 ++/** Set Busy Flag ++ If set, starting the command sets EBU_SFSTAT.busy. */ ++#define SFCMD_SET_BUSY 0x00004000 ++/** Ignore Busy ++ By default, the EBU error terminates all attempts to access a Serial Flash while EBU_SFSTAT.busy is set. Setting this bit overrules this error termination and permits the command written to EBU_SFCMD.opc to proceed to the External Bus. Normally, this bit is only set to execute a Read Status Register command to the Serial Flash, but may also be used for any other type of access the device is able to handle while it is busy. */ ++#define SFCMD_IGNORE_BUSY 0x00002000 ++/** Skip Opcode ++ If this bit is set, the opcode in field OPC is not sent to the External Bus, but the external transaction starts with sending the first address byte (if ALEN 0), the first dummy byte (if alen = 0 and DUMLEN 0), or directly with transferring the data bytes (if ALEN = DUMLEN = 0 and DLEN 0). Limiting the external transfer to just the data phase - together with the keep_cs feature - allow to transfer any number of data bytes for a device command sent via EBU_SFCMD by keeping the device selected between accesses and chaining multiple indirect access commands each transferring up to 4 data bytes from/to register EBU_SFDATA. */ ++#define SFCMD_SKIP_OPC 0x00001000 ++/** Data Length ++ This field defines the number of data bytes to transfer in the data phase of the command. For a read command, the data bytes are stored in register EBU_SFDATA, for a write transfer they are taken from that register. As the data register can hold at most 4 bytes, DLEN is restricted to the range [0..4]. */ ++#define SFCMD_DLEN_MASK 0x00000E00 ++/** field offset */ ++#define SFCMD_DLEN_OFFSET 9 ++/** Direction ++ Defines the direction of the data transfer (if any) in the data phase of the transaction to/from the serial bus. */ ++#define SFCMD_DIR 0x00000100 ++/* dlen bytes of data are read from the Serial Flash during the data phase of the transaction and stored in register EBU_SFDATA. ++#define SFCMD_DIR_READ 0x00000000 */ ++/** dlen bytes of data are read from register EBU_SFDATA and written to the Serial Flash during the data phase of the transactione */ ++#define SFCMD_DIR_WRITE 0x00000100 ++/** Command Opcode ++ A write access to this field starts an Indirect Access command in the EBU's Serial Flash controller. Two types of commands are supported (selected in EBU_SFCMD.cmdtype) and determine how the EBU interprets the opcode:- - For a ACCESS_CMD, a single transaction is executed to/from the Serial Flash device and the OPC is sent to the device in the command phase of the protocol. The number of address, dummy and data bytes to transfer with the command are given in fields ALEN, DUMLEN, and DLEN of register EBU_SFCMD, respectively. - For a SPECIAL_CMD, the EBU starts a complex operation that usually involves multiple transactions to/from the Serial Flash device. See Section 3.18.2.5 for an overview of the complex commands currently supported. */ ++#define SFCMD_OPC_MASK 0x000000FF ++/** field offset */ ++#define SFCMD_OPC_OFFSET 0 ++ ++/* Fields of "Serial Flash Address Register" */ ++/** Address ++ Before writing to register EBU_SFCMD to start a command that requires the transfer of an address, the address to use must be stored in this register. If not disabled in EBU_SFCMD.dis_aai, ADDR is incremented automatically with each data byte transferred between the EBU and the Serial Flash for an indirect access. Note:Register EBU_SFADDR is only used for access in Indirect Access Mode and is ignored/remains unaltered for all accesses in Direct Access Mode. */ ++#define SFADDR_ADDR_MASK 0xFFFFFFFF ++/** field offset */ ++#define SFADDR_ADDR_OFFSET 0 ++ ++/* Fields of "Serial Flash Data Register" */ ++/** Data Bytes ++ Before writing to register EBU_SFCMD to start a command that requires the transfer of data from the EBU to the Serial Flash device (write access), the data to send must be stored in this register. The data bytes have to be right-aligned in this register, that is, the last byte to send must be placed in bits DATA[7:0], the second-to-last byte in bits DATA[15:8], etc.. Similarly, for a read access with data being transferred from the Serial Flash to the EBU, this register collects the read data received from the device. The read data is right-aligned, that is, the last byte received gets placed in bits DATA[7:0], the second-to-last byte in bits DATA[15:8], etc... The number of data bytes to be transferred between EBU and the Serial Flash is defined in EBU_SFCMD.DLEN. Note:Register EBU_SFDATA is only used for accesses in Indirect Access Mode and is ignored/remains unaltered for all accesses in Direct Access Mode. */ ++#define SFDATA_DATA_MASK 0xFFFFFFFF ++/** field offset */ ++#define SFDATA_DATA_OFFSET 0 ++ ++/* Fields of "Serial Flash I/O Control Register" */ ++/** Start of Write Delay ++ By default, the EBU starts driving to AD[3:0] two EBU clock cycles before asserting the CS for an external Serial Flash access. For write accesses, this delay can be increased via field SOWD. */ ++#define SFIO_SOWD_MASK 0x0000F000 ++/** field offset */ ++#define SFIO_SOWD_OFFSET 12 ++/** End of Write Delay ++ This field defines the time (in number of EBU clock cycles) for which the EBU keeps driving the External Bus AD[3:0] after deassertion of the device's CS. */ ++#define SFIO_EOWD_MASK 0x00000F00 ++/** field offset */ ++#define SFIO_EOWD_OFFSET 8 ++/** Data Output ++ The EBU always controls the AD[3:0] pins while a CS for a Serial Flash device is asserted. Field UNUSED_WD defines the values being driven to these pins while the Serial Flash controller is not writing data to or is reading data from the device via the respective line. See Section 3.18.6 for details. */ ++#define SFIO_UNUSED_WD_MASK 0x0000000F ++/** field offset */ ++#define SFIO_UNUSED_WD_OFFSET 0 ++ ++/*! @} */ /* EBU_REGISTER */ ++ ++#endif /* _ebu_reg_h */ diff --git a/target/linux/lantiq/patches-2.6.39/110-falcon_board.patch b/target/linux/lantiq/patches-2.6.39/110-falcon_board.patch new file mode 100644 index 0000000..c6fb910 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/110-falcon_board.patch @@ -0,0 +1,1737 @@ +--- /dev/null ++++ b/arch/mips/lantiq/falcon/Kconfig +@@ -0,0 +1,11 @@ ++if SOC_FALCON ++ ++menu "Mips Machine" ++ ++config LANTIQ_MACH_EASY98000 ++ bool "Easy98000" ++ default y ++ ++endmenu ++ ++endif +--- /dev/null ++++ b/arch/mips/lantiq/falcon/Makefile +@@ -0,0 +1,3 @@ ++obj-y := clk-falcon.o devices.o gpio.o prom.o sysctrl.o reset.o ++obj-y += softdog_vpe.o ++obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o +--- /dev/null ++++ b/arch/mips/lantiq/falcon/clk-falcon.c +@@ -0,0 +1,48 @@ ++/* ++ * 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) 2010 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/io.h> ++#include <linux/module.h> ++#include <linux/init.h> ++ ++#include <asm/time.h> ++#include <asm/irq.h> ++#include <asm/div64.h> ++ ++#include <lantiq_soc.h> ++ ++#include <falcon.h> ++#include <gpon_reg_base.h> ++#include <sys1_reg.h> ++ ++static struct gpon_reg_sys1 * const pSYS1 = (struct gpon_reg_sys1 *)GPON_SYS1_BASE; ++ ++unsigned int ++ltq_get_io_region_clock(void) ++{ ++ return 200000000; /* 200 MHz */ ++} ++EXPORT_SYMBOL(ltq_get_io_region_clock); ++ ++unsigned int ++ltq_get_cpu_hz(void) ++{ ++ if ((ltq_r32(&pSYS1->cpu0cc) & CPU0CC_CPUDIV) == CPU0CC_CPUDIV_SELFHALF) ++ return 200000000; /* 200 MHz */ ++ else ++ return 400000000; /* 400 MHz */ ++} ++EXPORT_SYMBOL(ltq_get_cpu_hz); ++ ++unsigned int ++ltq_get_fpi_hz(void) ++{ ++ return 100000000; ++} ++EXPORT_SYMBOL(ltq_get_fpi_hz); +--- /dev/null ++++ b/arch/mips/lantiq/falcon/devices.c +@@ -0,0 +1,180 @@ ++#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 <linux/spi/spi.h> ++ ++#include <asm/bootinfo.h> ++#include <asm/irq.h> ++ ++#include <lantiq.h> ++ ++#include <falcon/falcon_irq.h> ++#include <falcon/gpon_reg_base.h> ++#include <falcon/sys1_reg.h> ++#include <falcon/sys_eth_reg.h> ++ ++#include <falcon/sysctrl.h> ++ ++#include "devices.h" ++ ++unsigned char ltq_ethaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ++EXPORT_SYMBOL(ltq_ethaddr); ++ ++static int __init ++falcon_set_ethaddr(char *str) ++{ ++ sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", ++ <q_ethaddr[0], <q_ethaddr[1], <q_ethaddr[2], ++ <q_ethaddr[3], <q_ethaddr[4], <q_ethaddr[5]); ++ return 0; ++} ++__setup("ethaddr=", falcon_set_ethaddr); ++ ++/* asc ports */ ++static struct resource falcon_asc0_resources[] = ++{ ++ MEM_RES("asc0",GPON_ASC0_BASE,GPON_ASC0_END), ++ IRQ_RES("tx",INT_NUM_IM3_IRL0), ++ IRQ_RES("rx",INT_NUM_IM3_IRL0+1), ++ IRQ_RES("err",INT_NUM_IM3_IRL0+2), ++}; ++ ++static struct resource falcon_asc1_resources[] = ++{ ++ MEM_RES("asc1",GPON_ASC1_BASE,GPON_ASC1_END), ++ IRQ_RES("tx",INT_NUM_IM3_IRL0+8), ++ IRQ_RES("rx",INT_NUM_IM3_IRL0+9), ++ IRQ_RES("err",INT_NUM_IM3_IRL0+10), ++}; ++ ++void __init falcon_register_asc(int port) ++{ ++ switch (port) { ++ case 0: ++ platform_device_register_simple("ltq_asc", 0, ++ falcon_asc0_resources, ARRAY_SIZE(falcon_asc0_resources)); ++ break; ++ case 1: ++ platform_device_register_simple("ltq_asc", 1, ++ falcon_asc1_resources, ARRAY_SIZE(falcon_asc1_resources)); ++ break; ++ default: ++ break; ++ } ++} ++ ++/* nor flash */ ++static struct resource ltq_nor_resource = ++ MEM_RES("nor",LTQ_FLASH_START,LTQ_FLASH_START + LTQ_FLASH_MAX - 1); ++ ++static struct platform_device ltq_nor = { ++ .name = "ltq_nor", ++ .resource = <q_nor_resource, ++ .num_resources = 1, ++}; ++ ++void __init falcon_register_nor(struct physmap_flash_data *data) ++{ ++ ltq_nor.dev.platform_data = data; ++ platform_device_register(<q_nor); ++} ++ ++/* spi flash */ ++static struct resource ltq_spi_resources[] = { ++ MEM_RES("ebu", GPON_EBU_BASE, GPON_EBU_END), ++ MEM_RES("sys1", GPON_SYS1_BASE, GPON_SYS1_END) ++}; ++ ++static struct platform_device ltq_spi = { ++ .name = "falcon_spi", ++ .resource = ltq_spi_resources, ++ .num_resources = ARRAY_SIZE(ltq_spi_resources) ++}; ++ ++void __init falcon_register_spi_flash(struct spi_board_info *data) ++{ ++ spi_register_board_info(data, 1); ++ platform_device_register(<q_spi); ++} ++ ++/* watchdog */ ++static struct resource falcon_wdt_resource = ++ MEM_RES("watchdog",GPON_WDT_BASE,GPON_WDT_END); ++ ++void __init falcon_register_wdt(void) ++{ ++ platform_device_register_simple("ltq_wdt", 0, &falcon_wdt_resource, 1); ++} ++ ++/* gpio */ ++#define DECLARE_GPIO_RES(port) \ ++static struct resource falcon_gpio ## port ## _resources[] = { \ ++ MEM_RES("gpio"#port,GPON_GPIO ## port ## _BASE,GPON_GPIO ## port ## _END), \ ++ MEM_RES("padctrl"#port,GPON_PADCTRL ## port ## _BASE,GPON_PADCTRL ## port ## _END), \ ++ IRQ_RES("gpio_mux"#port,FALCON_IRQ_GPIO_P ## port ) \ ++} ++DECLARE_GPIO_RES(0); ++DECLARE_GPIO_RES(1); ++DECLARE_GPIO_RES(2); ++#ifdef REGISTER_ALL_GPIO_PORTS ++#if NR_IRQS < 328 ++#error NR_IRQS to low for all gpio irqs ++#endif ++DECLARE_GPIO_RES(3); ++DECLARE_GPIO_RES(4); ++#endif ++ ++void __init falcon_register_gpio(void) ++{ ++ platform_device_register_simple("falcon_gpio", 0, ++ falcon_gpio0_resources, ARRAY_SIZE(falcon_gpio0_resources)); ++ platform_device_register_simple("falcon_gpio", 1, ++ falcon_gpio1_resources, ARRAY_SIZE(falcon_gpio1_resources)); ++ platform_device_register_simple("falcon_gpio", 2, ++ falcon_gpio2_resources, ARRAY_SIZE(falcon_gpio2_resources)); ++ sys1_hw_activate(ACTS_PADCTRL1 | ACTS_P1); ++ sys_eth_hw_activate(SYS_ETH_ACTS_PADCTRL0 | SYS_ETH_ACTS_PADCTRL2 | ++ SYS_ETH_ACTS_P0 | SYS_ETH_ACTS_P2); ++ ++#ifdef REGISTER_ALL_GPIO_PORTS ++ /* optional gpio ports: not registered, ++ as the pins are EBU specific and always used by linux */ ++ platform_device_register_simple("falcon_gpio", 3, ++ falcon_gpio3_resources, ARRAY_SIZE(falcon_gpio3_resources)); ++ platform_device_register_simple("falcon_gpio", 4, ++ falcon_gpio4_resources, ARRAY_SIZE(falcon_gpio4_resources)); ++ sys1_hw_activate(ACTS_PADCTRL3 | ACTS_PADCTRL4 | ACTS_P3 | ACTS_P4); ++#endif ++} ++ ++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), ++}; ++ ++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); ++} +--- /dev/null ++++ b/arch/mips/lantiq/falcon/devices.h +@@ -0,0 +1,21 @@ ++#ifndef _FALCON_DEVICES_H__ ++#define _FALCON_DEVICES_H__ ++ ++#include <linux/mtd/physmap.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/flash.h> ++ ++extern void __init falcon_register_asc(int port); ++extern void __init falcon_register_i2c(void); ++extern void __init falcon_register_spi_flash(struct spi_board_info *data); ++extern void __init falcon_register_gpio(void); ++extern void __init falcon_register_nor(struct physmap_flash_data *data); ++extern void __init falcon_register_wdt(void); ++extern void __init falcon_register_crypto(void); ++ ++#define IRQ_RES(resname,irq) {.name=resname,.start=(irq),.flags=IORESOURCE_IRQ} ++#define MEM_RES(resname,adr_start,adr_end) \ ++ { .name=resname, .flags=IORESOURCE_MEM, \ ++ .start=((adr_start)&~KSEG1),.end=((adr_end)&~KSEG1) } ++ ++#endif +--- /dev/null ++++ b/arch/mips/lantiq/falcon/prom.c +@@ -0,0 +1,52 @@ ++/* ++ * 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) 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 <falcon.h> ++ ++#include <falcon/gpon_reg_base.h> ++#include <falcon/status_reg.h> ++#include <falcon/sys1_reg.h> ++ ++#include "../prom.h" ++ ++static struct gpon_reg_status * const pSTATUS = (struct gpon_reg_status *)GPON_STATUS_BASE; ++ ++#define SOC_FALCON "Falcon" ++ ++void __init ++ltq_soc_setup(void) ++{ ++ /* not used */ ++} ++ ++void __init ++ltq_soc_detect(struct ltq_soc_info *i) ++{ ++ i->partnum = (ltq_r32(&pSTATUS->chipid) & STATUS_CHIPID_PARTNR_MASK) >> STATUS_CHIPID_PARTNR_OFFSET; ++ i->rev = (ltq_r32(&pSTATUS->chipid) & STATUS_CHIPID_VERSION_MASK) >> STATUS_CHIPID_VERSION_OFFSET; ++ switch (i->partnum) ++ { ++ case SOC_ID_FALCON: ++ i->name = SOC_FALCON; ++ i->type = SOC_TYPE_FALCON; ++ break; ++ ++ default: ++ printk(KERN_ERR "unknown partnum : 0x%08X\n", i->partnum); ++ while(1) { }; ++ break; ++ } ++} +--- /dev/null ++++ b/arch/mips/lantiq/falcon/sysctrl.c +@@ -0,0 +1,381 @@ ++/* ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of ++ * the License, or (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ * ++ * Copyright (C) 2010 Thomas Langer, Lantiq Deutschland ++ */ ++ ++#include <linux/cpu.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/pm.h> ++#include <linux/io.h> ++#include <linux/ioport.h> ++#include <linux/clk.h> ++#include <asm/reboot.h> ++ ++#include <falcon/gpon_reg_base.h> ++#include <falcon/status_reg.h> ++#include <falcon/sys1_reg.h> ++#include <falcon/sys_eth_reg.h> ++#include <falcon/sys_gpe_reg.h> ++ ++#include <falcon/sysctrl.h> ++ ++/* mapping to linux hw-accessor routines */ ++#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) ++ ++static struct gpon_reg_sys1 * const sys1 = (struct gpon_reg_sys1 *)GPON_SYS1_BASE; ++static struct gpon_reg_sys_eth * const sys_eth = (struct gpon_reg_sys_eth *)GPON_SYS_ETH_BASE; ++static struct gpon_reg_sys_gpe * const sys_gpe = (struct gpon_reg_sys_gpe *)GPON_SYS_GPE_BASE; ++static struct gpon_reg_status * const status = (struct gpon_reg_status *)GPON_STATUS_BASE; ++ ++/** ++ * Activate the selected module(s) ++ * Enables the clock of the module and activates the module itself. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS1.ACT ++ * \return void ++ */ ++void sys1_hw_activate(u32 mask) ++{ ++ sys1_w32(mask, clken); ++ sys1_w32(mask, act); ++ ++ while ( (sys1_r32(acts) & mask) != mask) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys1_hw_activate); ++ ++/** ++ * Deactivate the selected module(s) ++ * Disables the clock of the module and deactivates the module itself. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS1.DEACT ++ * \return void ++ */ ++void sys1_hw_deactivate(u32 mask) ++{ ++ sys1_w32(mask, clkclr); ++ sys1_w32(mask, deact); ++ ++ while ( (sys1_r32(acts) & mask) != 0) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys1_hw_deactivate); ++ ++/** ++ * Clock enable for the selected module(s) ++ * Enables the clock of the module. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS1.CLKEN ++ * \return void ++ */ ++void sys1_hw_clk_enable(u32 mask) ++{ ++ sys1_w32(mask, clken); ++ ++ while ( (sys1_r32(clks) & mask) != mask) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys1_hw_clk_enable); ++ ++/** ++ * Clock disable for the selected module(s) ++ * disables the clock of the module. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS1.CLKCLR ++ * \return void ++ */ ++void sys1_hw_clk_disable(u32 mask) ++{ ++ sys1_w32(mask, clkclr); ++ ++ while ( (sys1_r32(clks) & mask) != 0) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys1_hw_clk_disable); ++ ++/** ++ * Reboots the selected module(s) ++ * Triggers the reboot of the module. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS1.RBT ++ * \return void ++ */ ++void sys1_hw_activate_or_reboot(u32 mask) ++{ ++ u32 acts = sys1_r32(acts); ++ /* is not already active? */ ++ if ((~acts & mask) != 0) ++ sys1_hw_activate(~acts & mask); ++ sys1_w32(acts & mask, rbt); ++ while ( (sys1_r32(acts) & mask) != mask) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys1_hw_activate_or_reboot); ++ ++/** ++ * Activate the selected module(s) ++ * Enables the clock of the module and activates the module itself. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS_ETH.ACT ++ * \return void ++ */ ++void sys_eth_hw_activate(u32 mask) ++{ ++ sys_eth_w32(mask, clken); ++ sys_eth_w32(mask, act); ++ ++ while ( (sys_eth_r32(acts) & mask) != mask) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys_eth_hw_activate); ++ ++/** ++ * Deactivate the selected module(s) ++ * Disables the clock of the module and deactivates the module itself. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS_ETH.DEACT ++ * \return void ++ */ ++void sys_eth_hw_deactivate(u32 mask) ++{ ++ sys_eth_w32(mask, clkclr); ++ sys_eth_w32(mask, deact); ++ ++ while ( (sys_eth_r32(acts) & mask) != 0) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys_eth_hw_deactivate); ++ ++/** ++ * Clock enable for the selected module(s) ++ * Enables the clock of the module. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS_ETH.CLKEN ++ * \return void ++ */ ++void sys_eth_hw_clk_enable(u32 mask) ++{ ++ sys_eth_w32(mask, clken); ++ ++ while ( (sys_eth_r32(clks) & mask) != mask) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys_eth_hw_clk_enable); ++ ++/** ++ * Clock disable for the selected module(s) ++ * disables the clock of the module. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS_ETH.CLKCLR ++ * \return void ++ */ ++void sys_eth_hw_clk_disable(u32 mask) ++{ ++ sys_eth_w32(mask, clkclr); ++ ++ while ( (sys_eth_r32(clks) & mask) != 0) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys_eth_hw_clk_disable); ++ ++/** ++ * Reboots the selected module(s) ++ * Triggers the reboot of the module. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS_ETH.RBT ++ * \return void ++ */ ++void sys_eth_hw_activate_or_reboot(u32 mask) ++{ ++ u32 acts = sys_eth_r32(acts); ++ /* is not already active? */ ++ if ((~acts & mask) != 0) ++ sys_eth_hw_activate(~acts & mask); ++ sys_eth_w32(acts & mask, rbt); ++ while ( (sys_eth_r32(acts) & mask) != mask) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys_eth_hw_activate_or_reboot); ++ ++static int gpe_clk_is_enabled(void) ++{ ++ u32 rd_data; ++ ++ rd_data = sys1_r32(infrac); ++ if (rd_data & (1<<(INFRAC_GP_OFFSET+1))) ++ return 1; ++ return 0; ++} ++ ++static void enable_gpe_clk(void) ++{ ++ u32 aeFreq; ++ u32 rd_data; ++ u32 rd_data_to_keep; ++ int i; ++ ++ if (gpe_clk_is_enabled()) ++ /* clock already active, no need to change here */ ++ return; ++ ++ if (status_r32(config) == 0) ++ aeFreq = 1; /* use 625MHz on unfused chip */ ++ else ++ aeFreq = (status_r32(config) & STATUS_CONFIG_GPEFREQ_MASK) >> STATUS_CONFIG_GPEFREQ_OFFSET; ++ rd_data = sys1_r32(infrac); ++ /* clear gpe-fsel and enable bits */ ++ rd_data_to_keep = rd_data & ~(7<<(INFRAC_GP_OFFSET+1)); ++ ++ /* set new fsel */ ++ sys1_w32(rd_data_to_keep | (aeFreq<<(INFRAC_GP_OFFSET+2)), infrac); ++ ++ for (i = 0; i <10; i++) /* wait 10 cycles */ ++ {} ++ ++ /* keep new fsel and enable */ ++ sys1_w32(rd_data_to_keep | (aeFreq<<(INFRAC_GP_OFFSET+2)) | ++ (1<<(INFRAC_GP_OFFSET+1)), infrac); ++ for (i = 0; i <100; i++) /* wait 100 cycles */ ++ {} ++} ++ ++/** ++ * Activate the selected module(s) ++ * Enables the clock of the module and activates the module itself. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS_GPE.ACT ++ * \return void ++ */ ++void sys_gpe_hw_activate(u32 mask) ++{ ++ enable_gpe_clk(); ++ sys_gpe_w32(mask, clken); ++ sys_gpe_w32(mask, act); ++ ++ while ( (sys_gpe_r32(acts) & mask) != mask) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys_gpe_hw_activate); ++ ++/** ++ * Deactivate the selected module(s) ++ * Disables the clock of the module and deactivates the module itself. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS_GPE.DEACT ++ * \return void ++ */ ++void sys_gpe_hw_deactivate(u32 mask) ++{ ++ enable_gpe_clk(); ++ sys_gpe_w32(mask, clkclr); ++ sys_gpe_w32(mask, deact); ++ ++ while ( (sys_gpe_r32(acts) & mask) != 0) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys_gpe_hw_deactivate); ++ ++/** ++ * Clock enable for the selected module(s) ++ * Enables the clock of the module. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS_GPE.CLKEN ++ * \return void ++ */ ++void sys_gpe_hw_clk_enable(u32 mask) ++{ ++ enable_gpe_clk(); ++ sys_gpe_w32(mask, clken); ++ ++ while ( (sys_gpe_r32(clks) & mask) != mask) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys_gpe_hw_clk_enable); ++ ++/** ++ * Clock disable for the selected module(s) ++ * disables the clock of the module. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS_GPE.CLKCLR ++ * \return void ++ */ ++void sys_gpe_hw_clk_disable(u32 mask) ++{ ++ enable_gpe_clk(); ++ sys_gpe_w32(mask, clkclr); ++ ++ while ( (sys_gpe_r32(clks) & mask) != 0) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys_gpe_hw_clk_disable); ++ ++/** ++ * Reboots the selected module(s) ++ * Triggers the reboot of the module. ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS_GPE.RBT ++ * \return void ++ */ ++void sys_gpe_hw_activate_or_reboot(u32 mask) ++{ ++ u32 acts; ++ enable_gpe_clk(); ++ acts = sys_gpe_r32(acts); ++ /* is not already active? */ ++ if ((~acts & mask) != 0) ++ sys_gpe_hw_activate(~acts & mask); ++ sys_gpe_w32(acts & mask, rbt); ++ while ( (sys_gpe_r32(acts) & mask) != mask) { ++ /*NOP;*/ ++ }; ++} ++EXPORT_SYMBOL(sys_gpe_hw_activate_or_reboot); ++ ++/** ++ * Retrieve activation status of the selected hardware module(s) ++ * ++ * \param[in] mask bitmask of module(s), as for registers SYS_GPE.RBT ++ * \return int 1 - if hardware module(s) is activated (including clock) ++ */ ++ int sys_gpe_hw_is_activated(u32 mask) ++{ ++ if (gpe_clk_is_enabled() == 0) ++ return 0; ++ ++ if ((sys_gpe_r32(clks) & mask) != mask) ++ return 0; ++ ++ return ((sys_gpe_r32(acts) & mask) == mask); ++} ++EXPORT_SYMBOL(sys_gpe_hw_is_activated); +--- /dev/null ++++ b/arch/mips/lantiq/falcon/gpio.c +@@ -0,0 +1,463 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) 2010 Thomas Langer, Lantiq Deutschland ++ */ ++ ++/** ++ TODO: ++ - add locking? ++ - provide mask of available pins per platform_data ++*/ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/seq_file.h> ++#include <linux/platform_device.h> ++#include <linux/uaccess.h> ++#include <linux/gpio.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++ ++#include <falcon.h> ++#include <falcon/falcon_irq.h> ++ ++#include <linux/version.h> ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) ++#define for_each_set_bit for_each_bit ++#endif ++ ++#define gpio_r32(reg) __raw_readl(reg) ++#define gpio_w32(val, reg) __raw_writel(val, reg) ++#define gpio_w32_mask(clear, set, reg) gpio_w32((gpio_r32(reg) & ~(clear)) | (set), reg) ++ ++ ++/** register structure for padctrl ++ (mainly needed for mux control) */ ++typedef struct gpon_padctrl_s ++{ ++ /** Multiplexer Control Register ++ The value 0 (the reset-value) is always the default function corresponding to the pad's name. The value 1 selects always the GPIO functionality (if available). */ ++ unsigned int muxc[32]; ++ /** Pull Up Enable Register */ ++ unsigned int puen; /* 0x00000080 */ ++ /** Pull Down Enable Register */ ++ unsigned int pden; /* 0x00000084 */ ++ /** Slew Rate Control Register */ ++ unsigned int src; /* 0x00000088 */ ++ /** Drive Current Control Register */ ++ unsigned int dcc; /* 0x0000008C */ ++ /** Reserved */ ++ unsigned int res_0[24]; /* 0x00000090 */ ++ /** Pad Control Availability Register */ ++ unsigned int avail; /* 0x000000F0 */ ++} gpon_padctrl0_t; ++ ++/** register structure for gpio port */ ++typedef struct gpon_gpio_s ++{ ++ /** Data Output Register ++ Via this register the output values of the different bits can be set if they are switched as outputs. */ ++ unsigned int out; /* 0x00000000 */ ++ /** Data Input Register ++ Via this register the input values of the different bits can be observed. */ ++ unsigned int in; /* 0x00000004 */ ++ /** Direction Register ++ Via this register the input direction of the different bits can be determined. */ ++ unsigned int dir; /* 0x00000008 */ ++ /** Reserved */ ++ unsigned int res_0[3]; /* 0x0000000C */ ++ /** External Interrupt Control Register 0 */ ++ unsigned int exintcr0; /* 0x00000018 */ ++ /** External Interrupt Control Register 1 */ ++ unsigned int exintcr1; /* 0x0000001C */ ++ /** IRN Capture Register ++ This register shows the currently active interrupt events masked with the corresponding enable bits of the IRNEN register. The interrupts can be acknowledged by a write operation. */ ++ unsigned int irncr; /* 0x00000020 */ ++ /** IRN Interrupt Control Register ++ A write operation directly effects the interrupts. This can be used to trigger events under software control for testing purposes. A read operation returns the unmasked interrupt events. */ ++ unsigned int irnicr; /* 0x00000024 */ ++ /** IRN Interrupt Enable Register ++ This register contains the enable (or mask) bits for the interrupts. Disabled interrupts are not visible in the IRNCR register and are not signalled via the interrupt line towards the controller. */ ++ unsigned int irnen; /* 0x00000028 */ ++ /** IRN Interrupt Configuration Register ++ Configures the interrupts bitwise to be edge-senstivie or level-sensitive. */ ++ unsigned int irncfg; /* 0x0000002C */ ++ /** IRN Interrupt Enable Set Register ++ The corresponding bit in the IRNEN register can be set with an atomic access. */ ++ unsigned int irnenset; /* 0x00000030 */ ++ /** IRN Interrupt Enable Clear Register ++ The corresponding bit in the IRNEN register can be cleared with an atomic access. */ ++ unsigned int irnenclr; /* 0x00000034 */ ++ /** Reserved */ ++ unsigned int res_1[2]; /* 0x00000038 */ ++ /** Output Set Register ++ This register can be used to set certain bits within the OUT register without touching the other bits. */ ++ unsigned int outset; /* 0x00000040 */ ++ /** Output Clear Register ++ This register can be used to clear certain bits within the OUT register without touching the other bits. */ ++ unsigned int outclr; /* 0x00000044 */ ++ /** Direction Set Register ++ This register can be used to set certain bits within the DIR register without touching the other bits. */ ++ unsigned int dirset; /* 0x00000048 */ ++ /** Direction Clear Register ++ This register can be used to clear certain bits within the DIR register without touching the other bits. */ ++ unsigned int dirclr; /* 0x0000004C */ ++} gpon_gpio_t; ++ ++struct falcon_gpio_port { ++ struct gpio_chip gpio_chip; ++ gpon_padctrl0_t __iomem *pad; ++ gpon_gpio_t __iomem *port; ++ struct resource *pad_req; /* resources requested */ ++ struct resource *port_req; ++ unsigned int irq_base; ++ unsigned int chained_irq; ++}; ++ ++static int gpio_exported = 0; ++static int __init gpio_export_setup(char *str) ++{ ++ get_option(&str, &gpio_exported); ++ return 1; ++} ++__setup("gpio_exported=", gpio_export_setup); ++ ++static inline struct falcon_gpio_port *to_falcon_gpio_port(struct gpio_chip *chip) ++{ ++ return container_of(chip, struct falcon_gpio_port, gpio_chip); ++} ++ ++static int falcon_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) ++{ ++ struct falcon_gpio_port *gpio_port = to_falcon_gpio_port(chip); ++ gpio_w32(1<<offset, &gpio_port->port->dirclr); ++ return 0; ++} ++ ++static int falcon_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value) ++{ ++ struct falcon_gpio_port *gpio_port = to_falcon_gpio_port(chip); ++ gpio_w32(1<<offset, &gpio_port->port->dirset); ++ return 0; ++} ++ ++static void falcon_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) ++{ ++ struct falcon_gpio_port *gpio_port = to_falcon_gpio_port(chip); ++ if (value) ++ gpio_w32(1<<offset, &gpio_port->port->outset); ++ else ++ gpio_w32(1<<offset, &gpio_port->port->outclr); ++} ++ ++static int falcon_gpio_get(struct gpio_chip *chip, unsigned int offset) ++{ ++ struct falcon_gpio_port *gpio_port = to_falcon_gpio_port(chip); ++ if ((gpio_r32(&gpio_port->port->dir) >> offset) & 1) ++ return (gpio_r32(&gpio_port->port->out) >> offset) & 1; ++ else ++ return (gpio_r32(&gpio_port->port->in) >> offset) & 1; ++} ++ ++static int falcon_gpio_request(struct gpio_chip *chip, unsigned offset) ++{ ++ struct falcon_gpio_port *gpio_port = to_falcon_gpio_port(chip); ++ if ( (gpio_r32(&gpio_port->pad->avail) >> offset) & 1) { ++ if (gpio_r32(&gpio_port->pad->muxc[offset]) > 1) ++ return -EBUSY; ++ /* switch on gpio function */ ++ gpio_w32(1, &gpio_port->pad->muxc[offset]); ++ return 0; ++ } ++ ++ return -ENODEV; ++} ++ ++static void falcon_gpio_free(struct gpio_chip *chip, unsigned offset) ++{ ++ struct falcon_gpio_port *gpio_port = to_falcon_gpio_port(chip); ++ if ( (gpio_r32(&gpio_port->pad->avail) >> offset) & 1) { ++ if (gpio_r32(&gpio_port->pad->muxc[offset]) > 1) ++ return; ++ /* switch off gpio function */ ++ gpio_w32(0, &gpio_port->pad->muxc[offset]); ++ } ++} ++ ++static int falcon_gpio_to_irq(struct gpio_chip *chip, unsigned offset) ++{ ++ struct falcon_gpio_port *gpio_port = to_falcon_gpio_port(chip); ++ /* no checks: this functions is only registered with valid irq_base */ ++ return gpio_port->irq_base + offset; ++} ++ ++static void falcon_gpio_disable_irq(struct irq_data *d) ++{ ++ struct falcon_gpio_port *gpio_port = irq_get_chip_data(d->irq); ++ unsigned int offset = d->irq-gpio_port->irq_base; ++ gpio_w32(1<<offset, &gpio_port->port->irnenclr); ++} ++ ++static void falcon_gpio_enable_irq(struct irq_data *d) ++{ ++ struct falcon_gpio_port *gpio_port = irq_get_chip_data(d->irq); ++ unsigned int offset = d->irq-gpio_port->irq_base; ++ ++ if (gpio_r32(&gpio_port->pad->muxc[offset]) < 1) { ++ /* switch on gpio function */ ++ gpio_w32(1, &gpio_port->pad->muxc[offset]); ++ } ++ ++ gpio_w32(1<<offset, &gpio_port->port->irnenset); ++} ++ ++static void falcon_gpio_ack_irq(struct irq_data *d) ++{ ++ struct falcon_gpio_port *gpio_port = irq_get_chip_data(d->irq); ++ unsigned int offset = d->irq-gpio_port->irq_base; ++ gpio_w32(1<<offset, &gpio_port->port->irncr); ++} ++ ++static void falcon_gpio_mask_and_ack_irq(struct irq_data *d) ++{ ++ struct falcon_gpio_port *gpio_port = irq_get_chip_data(d->irq); ++ unsigned int offset = d->irq-gpio_port->irq_base; ++ gpio_w32(1<<offset, &gpio_port->port->irnenclr); ++ gpio_w32(1<<offset, &gpio_port->port->irncr); ++} ++ ++static struct irq_chip falcon_gpio_irq_chip; ++static int falcon_gpio_irq_type(struct irq_data *d, unsigned int type) ++{ ++ struct falcon_gpio_port *gpio_port = irq_get_chip_data(d->irq); ++ unsigned int offset = d->irq-gpio_port->irq_base; ++ unsigned int mask = 1 << offset; ++ ++ if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_NONE) ++ return 0; ++ ++ if ((type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) != 0) { ++ /* level triggered */ ++ gpio_w32_mask(0, mask, &gpio_port->port->irncfg); ++ irq_set_chip_and_handler_name(d->irq, ++ &falcon_gpio_irq_chip, handle_level_irq, "mux"); ++ } else { ++ /* edge triggered */ ++ gpio_w32_mask(mask, 0, &gpio_port->port->irncfg); ++ irq_set_chip_and_handler_name(d->irq, ++ &falcon_gpio_irq_chip, handle_simple_irq, "mux"); ++ } ++ ++ if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { ++ gpio_w32_mask(mask, 0, &gpio_port->port->exintcr0); ++ gpio_w32_mask(0, mask, &gpio_port->port->exintcr1); ++ } else { ++ if ((type & (IRQ_TYPE_EDGE_RISING |IRQ_TYPE_LEVEL_HIGH)) != 0) { ++ /* positive logic: rising edge, high level */ ++ gpio_w32_mask(mask, 0, &gpio_port->port->exintcr0); ++ } else { ++ /* negative logic: falling edge, low level */ ++ gpio_w32_mask(0, mask, &gpio_port->port->exintcr0); ++ } ++ gpio_w32_mask(mask, 0, &gpio_port->port->exintcr1); ++ } ++ ++ return gpio_direction_input(gpio_port->gpio_chip.base + offset); ++} ++ ++static void falcon_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ++{ ++ struct falcon_gpio_port *gpio_port = irq_desc_get_handler_data(desc); ++ unsigned long irncr; ++ int offset; ++ ++ irncr = gpio_r32(&gpio_port->port->irncr); ++ /* acknowledge interrupt */ ++ gpio_w32(irncr, &gpio_port->port->irncr); ++ ++ desc->irq_data.chip->irq_ack(&desc->irq_data); ++ ++ for_each_set_bit(offset, &irncr, gpio_port->gpio_chip.ngpio) ++ generic_handle_irq(gpio_port->irq_base + offset); ++} ++ ++static struct irq_chip falcon_gpio_irq_chip = { ++ .name = "gpio_irq_mux", ++ .irq_mask = falcon_gpio_disable_irq, ++ .irq_unmask = falcon_gpio_enable_irq, ++ .irq_ack = falcon_gpio_ack_irq, ++ .irq_mask_ack = falcon_gpio_mask_and_ack_irq, ++ .irq_set_type = falcon_gpio_irq_type, ++}; ++ ++static struct irqaction gpio_cascade = { ++ .handler = no_action, ++ .flags = IRQF_DISABLED, ++ .name = "gpio_cascade", ++}; ++ ++static int falcon_gpio_probe(struct platform_device *pdev) ++{ ++ struct falcon_gpio_port *gpio_port; ++ int ret, i; ++ struct resource *gpiores, *padres; ++ int irq; ++ ++ gpiores = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ padres = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ irq = platform_get_irq(pdev, 0); ++ if (!gpiores || !padres) ++ return -ENODEV; ++ ++ gpio_port = kzalloc(sizeof(*gpio_port), GFP_KERNEL); ++ if (gpio_port == NULL) ++ return -ENOMEM; ++ ++ gpio_port->gpio_chip.label = "falcon-gpio"; ++ gpio_port->gpio_chip.direction_input = falcon_gpio_direction_input; ++ gpio_port->gpio_chip.direction_output = falcon_gpio_direction_output; ++ gpio_port->gpio_chip.get = falcon_gpio_get; ++ gpio_port->gpio_chip.set = falcon_gpio_set; ++ gpio_port->gpio_chip.request = falcon_gpio_request; ++ gpio_port->gpio_chip.free = falcon_gpio_free; ++ gpio_port->gpio_chip.base = 100 * pdev->id; ++ gpio_port->gpio_chip.ngpio = 32; ++ gpio_port->gpio_chip.dev = &pdev->dev; ++ gpio_port->gpio_chip.exported = gpio_exported; ++ ++ gpio_port->port_req = request_mem_region(gpiores->start, ++ resource_size(gpiores), pdev->name); ++ gpio_port->pad_req = request_mem_region(padres->start, ++ resource_size(padres), pdev->name); ++ if (!gpio_port->port_req || !gpio_port->pad_req) { ++ dev_err(&pdev->dev, "cannot claim register area\n"); ++ ret = -EIO; ++ goto err; ++ } ++ ++ gpio_port->port = ioremap_nocache(gpiores->start, ++ resource_size(gpiores)); ++ gpio_port->pad = ioremap_nocache(padres->start, ++ resource_size(padres)); ++ if (!gpio_port->port || !gpio_port->pad) { ++ dev_err(&pdev->dev, "Could not map io ranges\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ if (irq>0) { ++ /* ++ * irq_chip support ++ */ ++ gpio_port->gpio_chip.to_irq = falcon_gpio_to_irq; ++ gpio_port->irq_base = INT_NUM_EXTRA_START + 32 * pdev->id; ++ ++ for (i = 0; i < 32; i++) { ++ irq_set_chip_and_handler_name(gpio_port->irq_base + i, ++ &falcon_gpio_irq_chip, handle_simple_irq, "mux"); ++ irq_set_chip_data(gpio_port->irq_base + i, gpio_port); ++ /* FIXME: set default cfg to level triggered */ ++ //gpio_w32_mask(0, 1<<i, &gpio_port->port->irncfg); ++ /* set to negative logic (falling edge, low level) */ ++ gpio_w32_mask(0, 1<<i, &gpio_port->port->exintcr0); ++ } ++ ++ gpio_port->chained_irq = irq; ++ setup_irq(irq, &gpio_cascade); ++ irq_set_handler_data(irq, gpio_port); ++ irq_set_chained_handler(irq, falcon_gpio_irq_handler); ++ } ++ ++ ret = gpiochip_add(&gpio_port->gpio_chip); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "Could not register gpiochip %d, %d\n", ++ pdev->id, ret); ++ goto err; ++ } ++ platform_set_drvdata(pdev, gpio_port); ++ return ret; ++ ++err: ++ dev_err(&pdev->dev, "Error in gpio_probe %d, %d\n", pdev->id, ret); ++ if (gpio_port->port_req) ++ release_resource(gpio_port->port_req); ++ if (gpio_port->pad_req) ++ release_resource(gpio_port->pad_req); ++ ++ if (gpio_port->port) ++ iounmap(gpio_port->port); ++ if (gpio_port->pad) ++ iounmap(gpio_port->pad); ++ kfree(gpio_port); ++ return ret; ++} ++ ++static int falcon_gpio_remove(struct platform_device *pdev) ++{ ++ struct falcon_gpio_port *gpio_port = platform_get_drvdata(pdev); ++ int ret; ++ ++ ret = gpiochip_remove(&gpio_port->gpio_chip); ++ if (gpio_port->port_req) ++ release_resource(gpio_port->port_req); ++ if (gpio_port->pad_req) ++ release_resource(gpio_port->pad_req); ++ if (gpio_port->port) ++ iounmap(gpio_port->port); ++ if (gpio_port->pad) ++ iounmap(gpio_port->pad); ++ if (ret == 0) ++ kfree(gpio_port); ++ ++ return ret; ++} ++ ++static struct platform_driver falcon_gpio_driver = { ++ .probe = falcon_gpio_probe, ++ .remove = __devexit_p(falcon_gpio_remove), ++ .driver = { ++ .name = "falcon_gpio", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init falcon_gpio_init(void) ++{ ++ int ret; ++ ++ printk(KERN_INFO "FALC(tm) ON GPIO Driver, (C) 2011 Lantiq Deutschland Gmbh\n"); ++ ret = platform_driver_register(&falcon_gpio_driver); ++ if (ret) ++ pr_err( "falcon_gpio: Error registering platform driver!"); ++ return ret; ++} ++ ++void __exit falcon_gpio_exit(void) ++{ ++ platform_driver_unregister(&falcon_gpio_driver); ++} ++ ++int gpio_to_irq(unsigned int gpio) ++{ ++ return __gpio_to_irq(gpio); ++} ++EXPORT_SYMBOL(gpio_to_irq); ++ ++module_init(falcon_gpio_init); ++module_exit(falcon_gpio_exit); +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/falcon.h +@@ -0,0 +1,16 @@ ++/* ++ * 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) 2005 infineon ++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> ++ */ ++ ++#ifdef CONFIG_SOC_FALCON ++ ++#include <lantiq_soc.h> ++#include <falcon/gpon_reg_base.h> ++ ++#endif +--- /dev/null ++++ b/arch/mips/lantiq/falcon/reset.c +@@ -0,0 +1,80 @@ ++/* ++ * 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) 2010 John Crispin <blogic@openwrt.org> ++ */ ++ ++#include <linux/init.h> ++#include <linux/io.h> ++#include <linux/pm.h> ++#include <asm/reboot.h> ++#include <linux/module.h> ++ ++#include <falcon.h> ++#include <falcon/gpon_reg_base.h> ++#include <falcon/status_reg.h> ++#include <falcon/sys1_reg.h> ++ ++static struct gpon_reg_sys1 * const pSYS1 = (struct gpon_reg_sys1 *)GPON_SYS1_BASE; ++ ++#define WDT_PW1 0x00BE0000 ++#define WDT_PW2 0x00DC0000 ++#define WDT_REG_BASE (KSEG1 | 0x1F8803F0) ++ ++/* This function is used by the watchdog driver */ ++int ltq_reset_cause(void) ++{ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ltq_reset_cause); ++ ++static void ++ltq_machine_restart(char *command) ++{ ++ printk(KERN_NOTICE "System restart\n"); ++ local_irq_disable(); ++ ltq_w32(0, (void*)0xBF200000); /* reset Bootreg RVEC */ ++#if 0 ++ ltq_w32(RBT_CPU_TRIG, &pSYS1->rbt); ++#else ++ /* use workaround via watchdog timer */ ++ ltq_w32(WDT_PW1, (void*)WDT_REG_BASE); ++ ltq_w32(WDT_PW2 | ++ (0x3 << 26) | /* PWL */ ++ (0x2 << 24) | /* CLKDIV */ ++ (0x1 << 31) | /* enable */ ++ (1), /* reload */ ++ (void*)WDT_REG_BASE); ++#endif ++ for(;;); ++} ++ ++static void ++ltq_machine_halt(void) ++{ ++ printk(KERN_NOTICE "System halted.\n"); ++ local_irq_disable(); ++ for(;;); ++} ++ ++static void ++ltq_machine_power_off(void) ++{ ++ printk(KERN_NOTICE "Please turn off the power now.\n"); ++ local_irq_disable(); ++ for(;;); ++} ++ ++static int __init ++mips_reboot_setup(void) ++{ ++ _machine_restart = ltq_machine_restart; ++ _machine_halt = ltq_machine_halt; ++ pm_power_off = ltq_machine_power_off; ++ return 0; ++} ++ ++arch_initcall(mips_reboot_setup); +--- /dev/null ++++ b/arch/mips/lantiq/falcon/mach-easy98000.c +@@ -0,0 +1,247 @@ ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/leds.h> ++#include <linux/gpio.h> ++#include <linux/gpio_buttons.h> ++#include <linux/etherdevice.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/mtd/physmap.h> ++#include <linux/input.h> ++#include <linux/interrupt.h> ++#include <linux/dm9000.h> ++#include <linux/i2c.h> ++#include <linux/i2c-gpio.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/spi_gpio.h> ++#include <linux/spi/eeprom.h> ++ ++#include "../machtypes.h" ++ ++#include "devices.h" ++#include "dev-leds-gpio.h" ++ ++#define EASY98000_GPIO_LED_0 9 ++#define EASY98000_GPIO_LED_1 10 ++#define EASY98000_GPIO_LED_2 11 ++#define EASY98000_GPIO_LED_3 12 ++#define EASY98000_GPIO_LED_4 13 ++#define EASY98000_GPIO_LED_5 14 ++ ++extern unsigned char ltq_ethaddr[6]; ++ ++#ifdef CONFIG_MTD_PARTITIONS ++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 */ ++ }, ++}; ++#endif ++ ++static struct physmap_flash_data easy98000_nor_flash_data = { ++#ifdef CONFIG_MTD_PARTITIONS ++ .nr_parts = ARRAY_SIZE(easy98000_nor_partitions), ++ .parts = easy98000_nor_partitions, ++#endif ++}; ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct flash_platform_data easy98000_spi_flash_platform_data = { ++ .name = "sflash", ++ .parts = easy98000_nor_partitions, ++ .nr_parts = ARRAY_SIZE(easy98000_nor_partitions) ++}; ++#endif ++ ++static struct spi_board_info easy98000_spi_flash_data __initdata = { ++ .modalias = "m25p80", ++ .bus_num = 0, ++ .chip_select = 0, ++ .max_speed_hz = 10 * 1000 * 1000, ++ .mode = SPI_MODE_3, ++#ifdef CONFIG_MTD_PARTITIONS ++ .platform_data = &easy98000_spi_flash_platform_data ++#endif ++}; ++ ++static struct gpio_led easy98000_leds_gpio[] __initdata = { ++ { ++ .name = "easy98000:green:0", ++ .gpio = EASY98000_GPIO_LED_0, ++ .active_low = 0, ++ }, { ++ .name = "easy98000:green:1", ++ .gpio = EASY98000_GPIO_LED_1, ++ .active_low = 0, ++ }, { ++ .name = "easy98000:green:2", ++ .gpio = EASY98000_GPIO_LED_2, ++ .active_low = 0, ++ }, { ++ .name = "easy98000:green:3", ++ .gpio = EASY98000_GPIO_LED_3, ++ .active_low = 0, ++ }, { ++ .name = "easy98000:green:4", ++ .gpio = EASY98000_GPIO_LED_4, ++ .active_low = 0, ++ }, { ++ .name = "easy98000:green:5", ++ .gpio = EASY98000_GPIO_LED_5, ++ .active_low = 0, ++ } ++}; ++ ++#define CONFIG_DM9000_BASE 0x14000000 ++#define DM9000_IO (CONFIG_DM9000_BASE + 3) ++#define DM9000_DATA (CONFIG_DM9000_BASE + 1) ++ ++static struct dm9000_plat_data dm9000_plat_data = { ++ .flags = DM9000_PLATF_8BITONLY, ++ //.dev_addr = { }, /* possibility to provide an ethernet address for the chip */ ++}; ++ ++static struct resource dm9000_resources[] = { ++ MEM_RES("dm9000_io", DM9000_IO, DM9000_IO), ++ MEM_RES("dm9000_data", DM9000_DATA, DM9000_DATA), ++ [2] = { ++ /* with irq (210 -> gpio 110) the driver is very unreliable */ ++ .start = -1, /* use polling */ ++ .end = -1, ++ .flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW, ++ }, ++}; ++ ++static struct platform_device dm9000_platform = { ++ .name = "dm9000", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(dm9000_resources), ++ .resource = dm9000_resources, ++ .dev = { ++ .platform_data = (void *) &dm9000_plat_data, ++ } ++}; ++ ++static void __init register_davicom(void) ++{ ++ if (!is_valid_ether_addr(ltq_ethaddr)) ++ random_ether_addr(dm9000_plat_data.dev_addr); ++ else { ++ memcpy(dm9000_plat_data.dev_addr, ltq_ethaddr, 6); ++ /* change to "Locally Administered Address" */ ++ dm9000_plat_data.dev_addr[0] |= 0x2; ++ } ++ platform_device_register(&dm9000_platform); ++} ++ ++static struct i2c_gpio_platform_data easy98000_i2c_gpio_data = { ++ .sda_pin = 107, ++ .scl_pin = 108, ++}; ++ ++static struct platform_device easy98000_i2c_gpio_device = { ++ .name = "i2c-gpio", ++ .id = 0, ++ .dev = { ++ .platform_data = &easy98000_i2c_gpio_data, ++ } ++}; ++ ++void __init register_easy98000_cpld_led(void) ++{ ++ platform_device_register_simple("easy98000_cpld_led", 0, NULL, 0); ++} ++ ++/* setup gpio based spi bus/device for access to the eeprom on the board */ ++#define SPI_GPIO_MRST 102 ++#define SPI_GPIO_MTSR 103 ++#define SPI_GPIO_CLK 104 ++#define SPI_GPIO_CS0 105 ++#define SPI_GPIO_CS1 106 ++#define SPI_GPIO_BUS_NUM 1 ++ ++static struct spi_gpio_platform_data easy98000_spi_gpio_data = { ++ .sck = SPI_GPIO_CLK, ++ .mosi = SPI_GPIO_MTSR, ++ .miso = SPI_GPIO_MRST, ++ .num_chipselect = 2, ++}; ++ ++static struct platform_device easy98000_spi_gpio_device = { ++ .name = "spi_gpio", ++ .id = SPI_GPIO_BUS_NUM, ++ .dev.platform_data = &easy98000_spi_gpio_data, ++}; ++ ++static struct spi_eeprom at25160n = { ++ .byte_len = 16 * 1024 / 8, ++ .name = "at25160n", ++ .page_size = 32, ++ .flags = EE_ADDR2, ++}; ++ ++static struct spi_board_info easy98000_spi_gpio_devices __initdata = { ++ .modalias = "at25", ++ .bus_num = SPI_GPIO_BUS_NUM, ++ .max_speed_hz = 1000 * 1000, ++ .mode = SPI_MODE_3, ++ .chip_select = 1, ++ .controller_data = (void *) SPI_GPIO_CS1, ++ .platform_data = &at25160n, ++}; ++ ++static void __init 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_common(void) ++{ ++ falcon_register_asc(0); ++ falcon_register_gpio(); ++ falcon_register_wdt(); ++ 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); ++ register_easy98000_cpld_led(); ++ falcon_register_crypto(); ++ easy98000_spi_gpio_init(); ++} ++ ++static void __init easy98000_init(void) ++{ ++ easy98000_init_common(); ++ falcon_register_nor(&easy98000_nor_flash_data); ++} ++ ++static void __init easy98000sf_init(void) ++{ ++ easy98000_init_common(); ++ falcon_register_spi_flash(&easy98000_spi_flash_data); ++} ++ ++MIPS_MACHINE(LANTIQ_MACH_EASY98000, ++ "EASY98000", ++ "EASY98000 Eval Board", ++ easy98000_init); ++ ++MIPS_MACHINE(LANTIQ_MACH_EASY98000SF, ++ "EASY98000SF", ++ "EASY98000 Eval Board (Serial Flash)", ++ easy98000sf_init); +--- /dev/null ++++ b/arch/mips/lantiq/falcon/softdog_vpe.c +@@ -0,0 +1,109 @@ ++/* ++** ============================================================================= ++** FILE NAME : softdog_vpe.c ++** MODULES : LXDB ++** DATE : 24-03-2008 ++** AUTHOR : LXDB Team ++** DESCRIPTION : This header file contains the code for the watchdog ++** implentation on vpe1 side. ++** REFERENCES : ++** COPYRIGHT : Copyright (c) 2008 ++** Am Campeon 1-12, 85579 Neubiberg, Germany ++** Any use of this software is subject to the conclusion of a respective ++** License agreement. Without such a License agreement no rights to the ++** software are granted ++** ++** HISTORY : ++** $Date $Author $Comment ++** 24-03-2008 LXDB Initial version ++** ============================================================================ ++*/ ++ ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/types.h> ++#include <linux/timer.h> ++#include <linux/reboot.h> ++#include <linux/init.h> ++#include <linux/jiffies.h> ++ ++#include <falcon/vpe.h> ++ ++static unsigned long last_wdog_value; ++static unsigned long vpe1_wdog_cleared; ++ ++static unsigned long vpe1_wdog_dead; ++static void watchdog_vpe0_fire(unsigned long); /* Called when vpe0 timer expires */ ++static void keep_alive_vpe0(unsigned long); ++VPE_SW_WDOG_RESET reset_local_fn; ++ ++ ++static struct timer_list watchdog_vpe0_ticktock = ++ TIMER_INITIALIZER(watchdog_vpe0_fire, 0, 0); ++ ++static void watchdog_vpe0_fire (unsigned long flags) ++{ ++ volatile unsigned long *wdog_ctr_value; ++ wdog_ctr_value = (void*)vpe1_wdog_ctr; ++ if (*wdog_ctr_value == last_wdog_value) { /* VPE1 watchdog expiry handling */ ++ vpe1_sw_wdog_stop(flags); ++ vpe1_wdog_dead++; ++ printk(KERN_DEBUG "VPE1 watchdog reset handler called\n"); ++ /* Call the reset handler function */ ++ reset_local_fn(flags); ++ } else { /* Everything is OK on vpe1 side. Continue. */ ++ last_wdog_value = *wdog_ctr_value; ++ vpe1_wdog_cleared++; ++ keep_alive_vpe0(flags); ++ } ++} ++ ++int32_t vpe1_sw_wdog_register_reset_handler (VPE_SW_WDOG_RESET reset_fn) ++{ ++ reset_local_fn = (VPE_SW_WDOG_RESET)reset_fn; ++ return 0; ++} ++ ++static void keep_alive_vpe0(unsigned long flags) ++{ ++ mod_timer(&watchdog_vpe0_ticktock, jiffies+ vpe1_wdog_timeout ); ++} ++ ++unsigned long vpe1_sw_wdog_start(unsigned long flags) ++{ ++ volatile unsigned long *wdog_ctr_value; ++ wdog_ctr_value = (void*)vpe1_wdog_ctr; ++ *wdog_ctr_value = 0; ++ last_wdog_value = 0; ++ keep_alive_vpe0(flags); ++ return 0; ++} ++ ++unsigned long vpe1_sw_wdog_stop(unsigned long flags) ++{ ++ del_timer(&watchdog_vpe0_ticktock); ++ return 0; ++} ++ ++static int __init watchdog_vpe1_init(void) ++{ ++ /* Nothing to be done here */ ++ return 0; ++} ++ ++static void __exit watchdog_vpe1_exit(void) ++{ ++ unsigned long flags=0; ++ vpe1_sw_wdog_stop(flags); ++} ++ ++module_init(watchdog_vpe1_init); ++module_exit(watchdog_vpe1_exit); ++ ++EXPORT_SYMBOL(vpe1_sw_wdog_register_reset_handler); ++EXPORT_SYMBOL(vpe1_sw_wdog_start); ++EXPORT_SYMBOL(vpe1_sw_wdog_stop); ++ ++MODULE_AUTHOR("LXDB"); ++MODULE_DESCRIPTION("Software Watchdog For VPE1"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/vpe.h +@@ -0,0 +1,44 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) 2005 infineon ++ * Copyright (C) 2007 John Crispin <blogic@openwrt.org> ++ * ++ */ ++#ifndef _IFXMIPS_VPE_H__ ++#define _IFXMIPS_VPE_H__ ++ ++/* For the explanation of the APIs please refer the section "MT APRP Kernel ++ * Programming" in AR9 SW Architecture Specification ++ */ ++int32_t vpe1_sw_start(void* sw_start_addr, uint32_t tcmask, uint32_t flags); ++int32_t vpe1_sw_stop(uint32_t flags); ++uint32_t vpe1_get_load_addr (uint32_t flags); ++uint32_t vpe1_get_max_mem (uint32_t flags); ++ ++int32_t vpe1_set_boot_param(char *field, char *value, char flags); ++int32_t vpe1_get_boot_param(char *field, char **value, char flags); ++ ++/* Watchdog APIs */ ++extern unsigned long vpe1_wdog_ctr; ++extern unsigned long vpe1_wdog_timeout; ++ ++unsigned long vpe1_sw_wdog_start(unsigned long); ++unsigned long vpe1_sw_wdog_stop(unsigned long); ++ ++typedef int (*VPE_SW_WDOG_RESET)(unsigned long wdog_cleared_ok_count); ++int32_t vpe1_sw_wdog_register_reset_handler(VPE_SW_WDOG_RESET reset_fn); ++ ++#endif +--- a/arch/mips/lantiq/Kconfig ++++ b/arch/mips/lantiq/Kconfig +@@ -16,8 +16,12 @@ + bool "XWAY" + select SOC_TYPE_XWAY + select HW_HAS_PCI ++ ++config SOC_FALCON ++ bool "FALCON" + endchoice + + source "arch/mips/lantiq/xway/Kconfig" ++source "arch/mips/lantiq/falcon/Kconfig" + + endif +--- a/arch/mips/lantiq/Makefile ++++ b/arch/mips/lantiq/Makefile +@@ -9,3 +9,4 @@ + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + + obj-$(CONFIG_SOC_TYPE_XWAY) += xway/ ++obj-$(CONFIG_SOC_FALCON) += falcon/ +--- a/arch/mips/lantiq/Platform ++++ b/arch/mips/lantiq/Platform +@@ -6,3 +6,4 @@ + 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_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon +--- a/arch/mips/lantiq/machtypes.h ++++ b/arch/mips/lantiq/machtypes.h +@@ -15,6 +15,11 @@ + LTQ_MACH_GENERIC = 0, + LTQ_MACH_EASY50712, /* Danube evaluation board */ + LTQ_MACH_EASY50601, /* Amazon SE evaluation board */ ++ ++ /* FALCON */ ++ LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */ ++ LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */ ++ LANTIQ_MACH_EASY98020, /* Falcon Reference Board */ + }; + + #endif diff --git a/target/linux/lantiq/patches-2.6.39/120-falcon-i2c.patch b/target/linux/lantiq/patches-2.6.39/120-falcon-i2c.patch new file mode 100644 index 0000000..3dd873b --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/120-falcon-i2c.patch @@ -0,0 +1,829 @@ +--- a/drivers/i2c/busses/Makefile ++++ b/drivers/i2c/busses/Makefile +@@ -74,6 +74,7 @@ + obj-$(CONFIG_I2C_STUB) += i2c-stub.o + obj-$(CONFIG_SCx200_ACB) += scx200_acb.o + obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o ++obj-$(CONFIG_I2C_FALCON) += i2c-falcon.o + + ifeq ($(CONFIG_I2C_DEBUG_BUS),y) + EXTRA_CFLAGS += -DDEBUG +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -278,6 +278,10 @@ + + comment "I2C system bus drivers (mostly embedded / system-on-chip)" + ++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 +--- /dev/null ++++ b/drivers/i2c/busses/i2c-falcon.c +@@ -0,0 +1,803 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++/* #define DEBUG */ ++ ++#include <linux/module.h> ++#include <linux/ioport.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/i2c.h> ++#include <linux/interrupt.h> ++#include <linux/spinlock.h> ++#include <linux/io.h> ++#include <linux/clk.h> ++#include <linux/err.h> ++#include <linux/slab.h> ++ ++/* CURRENT ISSUES: ++ * - no high speed support ++ * - rx issue with "address mode" & "tx end" interrupts ++ * - ten bit mode is not tested ++ */ ++ ++/* mapping for access macros */ ++#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> ++ ++/* enable hacks to overcome current issue */ ++#define FALCON_FIX_ME ++ ++#define FALCON_I2C_ADDR 0x00 ++#define FALCON_I2C_READY_TIMEOUT 1000 ++#define FALCON_I2C_WAIT_TIMEOUT 10 ++ ++#define DRV_NAME "i2c-falcon" ++ ++#if defined(DEBUG) ++#define static /* no static functions for better debugging */ ++#endif ++ ++#define FALCON_I2C_ARB_LOST (1 << 0) ++#define FALCON_I2C_NACK (1 << 1) ++#define FALCON_I2C_RX_UFL (1 << 2) ++#define FALCON_I2C_RX_OFL (1 << 3) ++#define FALCON_I2C_TX_UFL (1 << 4) ++#define FALCON_I2C_TX_OFL (1 << 5) ++#define FALCON_I2C_BURST_REQ (1 << 6) ++#define FALCON_I2C_RX (1 << 7) ++#define FALCON_I2C_TX_END (1 << 8) ++#define FALCON_I2C_ADDR_MATCH (1 << 9) /* doesn't trigger */ ++ ++struct falcon_i2c { ++ spinlock_t lock; ++ ++ enum { ++ FALCON_I2C_MODE_100 = 1, ++ FALCON_I2C_MODE_400 = 2, ++ FALCON_I2C_MODE_3400 = 3 ++ } mode; /* current speed mode */ ++ ++ int ten_bit; /* current address mode */ ++ unsigned long status; /* bus events holder */ ++ struct clk *clk; /* clock input for i2c hardware block */ ++ struct gpon_reg_i2c __iomem *membase; /* base of mapped registers */ ++ int irq_lb, irq_b, irq_err, irq_p; /* last burst, burst, error, ++ protocol IRQs */ ++ struct completion done; ++ struct i2c_adapter adap; ++ struct device *dev; ++}; ++ ++#define FALCON_I2C_ERROR_MASK (FALCON_I2C_NACK \ ++ | FALCON_I2C_ARB_LOST \ ++ | FALCON_I2C_RX_OFL \ ++ | FALCON_I2C_RX_UFL \ ++ | FALCON_I2C_TX_OFL \ ++ | FALCON_I2C_TX_UFL) ++ ++#define FALCON_I2C_ERROR(priv) (priv->status & FALCON_I2C_ERROR_MASK) ++#define FALCON_I2C_ERROR_CLEAR(priv) do { \ ++ priv->status &= \ ++ ~FALCON_I2C_ERROR_MASK; \ ++ } while (0) ++ ++static void falcon_addr_configure(struct falcon_i2c *priv, int ten_bit) ++{ ++ u32 ten_bit_mask = ten_bit ? I2C_ADDR_CFG_TBAM_10bit : 0; ++ ++ /* configure address */ ++ 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 */ ++ | ten_bit_mask ++ | FALCON_I2C_ADDR, /* our address */ ++ addr_cfg); ++} ++ ++static irqreturn_t falcon_i2c_isr(int irq, void *dev_id) ++{ ++ u32 i_raw, i_pro, i_err; ++ struct falcon_i2c *priv = dev_id; ++ unsigned long flags; ++ unsigned int old_status; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ old_status = (unsigned int)priv->status; ++ ++ i_raw = i2c_r32(mis); ++ ++ /* protocol interrupt */ ++ if (i_raw & I2C_RIS_I2C_P_INT_INTOCC) { ++ i_pro = i2c_r32(p_irqss); ++ ++ /* tx -> rx switch */ ++ if (i_pro & I2C_P_IRQSS_RX) ++ priv->status |= FALCON_I2C_RX; ++ ++ /* tx end */ ++ if (i_pro & I2C_P_IRQSS_TX_END) ++ priv->status |= FALCON_I2C_TX_END; ++ ++ /* not acknowledge */ ++ if (i_pro & I2C_P_IRQSS_NACK) ++ priv->status |= FALCON_I2C_NACK; ++ ++ /* arbitration lost */ ++ if (i_pro & I2C_P_IRQSS_AL) ++ priv->status |= FALCON_I2C_ARB_LOST; ++ ++ /* address match */ ++ if (i_pro & I2C_P_IRQSS_AM) ++ priv->status |= FALCON_I2C_ADDR_MATCH; ++ ++ i2c_w32(i_pro, p_irqsc); ++ } ++ ++ /* error interrupt */ ++ if (i_raw & I2C_RIS_I2C_ERR_INT_INTOCC) { ++ i_err = i2c_r32(err_irqss); ++ ++ /* tx fifo overflow */ ++ if (i_err & I2C_ERR_IRQSS_TXF_OFL) ++ priv->status |= FALCON_I2C_TX_OFL; ++ ++ /* tx fifo underflow */ ++ if (i_err & I2C_ERR_IRQSS_TXF_UFL) ++ priv->status |= FALCON_I2C_TX_UFL; ++ ++ /* rx fifo overflow */ ++ if (i_err & I2C_ERR_IRQSS_RXF_OFL) ++ priv->status |= FALCON_I2C_RX_OFL; ++ ++ /* rx fifo underflow */ ++ if (i_err & I2C_ERR_IRQSS_RXF_UFL) ++ priv->status |= FALCON_I2C_RX_UFL; ++ ++ i2c_w32(i_err, err_irqsc); ++ } ++ ++ /* burst request */ ++ if (i_raw & I2C_RIS_BREQ_INT_INTOCC) { ++ i2c_w32_mask(I2C_IMSC_BREQ_INT_EN, 0, imsc); ++ i2c_w32_mask(0, I2C_ICR_BREQ_INT_CLR, icr); ++ ++ priv->status |= FALCON_I2C_BURST_REQ; ++ } ++ ++ /* last burst request */ ++ if (i_raw & I2C_RIS_LBREQ_INT_INTOCC) { ++ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN, 0, imsc); ++ i2c_w32_mask(0, I2C_ICR_LBREQ_INT_CLR, icr); ++ ++ priv->status |= FALCON_I2C_BURST_REQ; ++ } ++ ++ if (old_status != (unsigned int)priv->status) ++ complete(&priv->done); ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ return IRQ_HANDLED; ++} ++ ++static int falcon_i2c_ready(struct falcon_i2c *priv) ++{ ++ int timeout; ++ u32 bus_stat; ++ unsigned long flags; ++ int ret; ++ ++ for (timeout = 0; timeout < FALCON_I2C_READY_TIMEOUT; timeout++) { ++ bus_stat = i2c_r32(bus_stat); ++ ++ if (bus_stat & I2C_BUS_STAT_BS_SC) { ++ cpu_relax(); ++ } else { ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ if (FALCON_I2C_ERROR(priv)) { ++ ret = priv->status; ++ ++ dev_dbg(priv->dev, "bus ready wait error 0x%08lx\n", priv->status); ++ ++ FALCON_I2C_ERROR_CLEAR(priv); ++ } else { ++ ret = 0; ++ } ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ return ret; ++ } ++ } ++ ++ dev_dbg(priv->dev, "bus ready wait timeout\n"); ++ ++ return -ETIME; ++} ++ ++static int falcon_i2c_wait(struct falcon_i2c *priv, unsigned long status) ++{ ++ int ret = 0; ++ unsigned long flags; ++ unsigned int timeout; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ priv->status &= FALCON_I2C_BURST_REQ; ++ ++ /* check if the event already occurred */ ++ if ((priv->status & status) == status) { ++ priv->status &= ~status; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ return 0; ++ } ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ /* unmask burst interrupts */ ++ i2c_w32_mask(0, I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, imsc); ++ ++ for (timeout = 0; timeout < FALCON_I2C_WAIT_TIMEOUT; timeout++) { ++ /* wait for the data request */ ++ wait_for_completion_timeout(&priv->done, HZ / 10); ++ ++ /* handle errors */ ++ spin_lock_irqsave(&priv->lock, flags); ++ ++ if (FALCON_I2C_ERROR(priv)) { ++ dev_dbg(priv->dev, "wait error 0x%08lx (waiting for 0x%08lx)\n", ++ priv->status, ++ status); ++ ++ if (priv->status & FALCON_I2C_NACK) ++ ret = -ENXIO; ++ else ++ ret = -EREMOTEIO; ++ ++ FALCON_I2C_ERROR_CLEAR(priv); ++ } else { ++ if ((priv->status & status) == status) { ++ priv->status &= ~status; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ return 0; ++ } ++ } ++ ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ if (ret) ++ return ret; ++ } ++ ++ dev_dbg(priv->dev, "wait timeout error 0x%08lx (waiting for 0x%08lx)\n", ++ priv->status, ++ status); ++ ++ return -ETIME; ++} ++ ++static int falcon_i2c_tx(struct falcon_i2c *priv, int ten_bit, u16 addr, ++ u8 *buf, int len) ++{ ++ int i; ++ int ret; ++ ++ dev_dbg(priv->dev, "%s\n", __func__); ++ ++ /* tell fifo the number of bytes we are going to send */ ++ i2c_w32(len + (ten_bit ? 2 : 1), tps_ctrl); ++ ++ /* wait for the data request */ ++ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ); ++ if (ret) ++ return ret; ++ ++ /* send slave address */ ++ if (ten_bit) { ++ i2c_w32(0x78 | ((addr >> 7) & 0x7), txd); ++ i2c_w32(0x78 | ((addr & 0x7f) << 1) | 0, txd); ++ } else { ++ i2c_w32((addr << 1) | 0, txd); ++ } ++ ++ /* fill fifo */ ++ for (i = 0; i < len; i++) { ++ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ); ++ if (ret) ++ return ret; ++ ++ i2c_w32(buf[i], txd); ++ } ++ ++ return falcon_i2c_wait(priv, FALCON_I2C_TX_END); ++} ++ ++static int falcon_i2c_rx(struct falcon_i2c *priv, int ten_bit, u16 addr, ++ u8 *buf, int len) ++{ ++ int i; ++ int ret; ++ ++ dev_dbg(priv->dev, "%s\n", __func__); ++ ++ /* we need to transmit address only */ ++ i2c_w32(ten_bit ? 2 : 1, tps_ctrl); ++ ++ /* set maximum received packet size */ ++ i2c_w32(len, mrps_ctrl); ++ ++ /* wait for the data request */ ++ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ); ++ if (ret) ++ return ret; ++ ++ /* write down the address */ ++ if (ten_bit) { ++ i2c_w32(0x78 | ((addr >> 7) & 0x7), txd); ++ i2c_w32(0x78 | ((addr & 0x7f) << 1) | 1, txd); ++ } else { ++ i2c_w32((addr << 1) | 1, txd); ++ } ++ ++ /* wait for the read request */ ++ ret = falcon_i2c_wait(priv, FALCON_I2C_TX_END ++#ifndef FALCON_FIX_ME ++ | FALCON_I2C_ADDR_MATCH ++#endif ++ | FALCON_I2C_RX); ++ ++ if (ret) ++ return ret; ++ ++ /* read bytes */ ++ for (i = 0; i < len; i++) { ++#ifdef FALCON_FIX_ME ++ while (i2c_r32(rps_stat) == 0) ++ cpu_relax(); ++#else ++ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ); ++ ++ if (ret) ++ return ret; ++#endif ++ ++ buf[i] = i2c_r32(rxd); ++ } ++ ++#ifndef FALCON_FIX_ME ++ /* wait for transmission end */ ++ return falcon_i2c_wait(priv, FALCON_I2C_TX_END); ++#else ++ return 0; ++#endif ++} ++ ++static int falcon_i2c_xfer_msg(struct falcon_i2c *priv, struct i2c_msg *msg) ++{ ++ int ret; ++ int ten_bit; ++ unsigned long flags; ++ ++ dev_dbg(priv->dev, "%s %u byte(s) %s 0x%02x\n", ++ (msg->flags & I2C_M_RD) ? "read" : "write", msg->len, ++ (msg->flags & I2C_M_RD) ? "from" : "to", msg->addr); ++ ++ if (msg->flags & I2C_M_TEN) ++ ten_bit = 1; ++ else ++ ten_bit = 0; ++ ++ /* reconfigure bus if need to send message in different address mode */ ++ spin_lock_irqsave(&priv->lock, flags); ++ if (ten_bit != priv->ten_bit) { ++ ++ /* disable bus */ ++ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl); ++ ++ /* reconfigure address */ ++ falcon_addr_configure(priv, ten_bit); ++ ++ /* enable bus */ ++ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl); ++ ++ priv->ten_bit = ten_bit; ++ } ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ /* read/write actual message */ ++ if (msg->flags & I2C_M_RD) ++ ret = falcon_i2c_rx(priv, ten_bit, msg->addr, msg->buf, ++ msg->len); ++ else ++ ret = falcon_i2c_tx(priv, ten_bit, msg->addr, msg->buf, ++ msg->len); ++ ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int falcon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, ++ int num) ++{ ++ int i; ++ int ret; ++ unsigned long flags; ++ struct falcon_i2c *priv = i2c_get_adapdata(adap); ++ ++ dev_dbg(priv->dev, "xfer %u messages\n", num); ++ ++ /* transfer each message */ ++ for (i = 0; i < num; i++) { ++#ifdef FALCON_FIX_ME ++ /* disable bus */ ++ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl); ++ /* enable bus */ ++ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl); ++#endif ++ ++ /* clear bus status */ ++ spin_lock_irqsave(&priv->lock, flags); ++ priv->status = 0; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ /* wait for the bus to become ready */ ++ ret = falcon_i2c_ready(priv); ++ if (ret) ++ return ret; ++ ++ /* transfer message */ ++ ret = falcon_i2c_xfer_msg(priv, &msg[i]); ++ ++ if (ret) ++ return ret; ++ ++ /* check for unhandled errors */ ++ spin_lock_irqsave(&priv->lock, flags); ++ if (FALCON_I2C_ERROR(priv)) ++ ret = priv->status; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ if (ret) { ++ dev_warn(priv->dev, "message %u unhandled error 0x%x\n", ++ i, ret); ++ ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static u32 falcon_i2c_func(struct i2c_adapter *adap) ++{ ++ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; ++} ++ ++static struct i2c_algorithm falcon_i2c_algorithm = { ++ .master_xfer = falcon_i2c_xfer, ++ .functionality = falcon_i2c_func, ++}; ++ ++static int falcon_i2c_hw_init(struct i2c_adapter *adap) ++{ ++ struct falcon_i2c *priv = i2c_get_adapdata(adap); ++ ++ /* disable bus */ ++ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl); ++ ++ /* set normal operation clock divider */ ++ i2c_w32(1 << I2C_CLC_RMC_OFFSET, clc); ++ ++ /* set frequency */ ++ if (priv->mode == FALCON_I2C_MODE_100) { ++ dev_dbg(priv->dev, "set standard mode (100 kHz)\n"); ++ ++ i2c_w32(0, fdiv_high_cfg); ++ ++ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET) ++ | (499 << I2C_FDIV_CFG_DEC_OFFSET), ++ fdiv_cfg); ++ } else if (priv->mode == FALCON_I2C_MODE_400) { ++ dev_dbg(priv->dev, "set fast mode (400 kHz)\n"); ++ ++ i2c_w32(0, fdiv_high_cfg); ++ ++ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET) ++ | (124 << I2C_FDIV_CFG_DEC_OFFSET), ++ fdiv_cfg); ++ } else if (priv->mode == FALCON_I2C_MODE_3400) { ++ dev_dbg(priv->dev, "set high mode (3.4 MHz)\n"); ++ ++ i2c_w32(0, fdiv_cfg); ++ ++ /* TODO recalculate value for 100MHz input */ ++ i2c_w32((41 << I2C_FDIV_CFG_INC_OFFSET) ++ | (152 << I2C_FDIV_CFG_DEC_OFFSET), ++ fdiv_high_cfg); ++ } else { ++ dev_warn(priv->dev, "unknown mode\n"); ++ ++ return -ENODEV; ++ } ++ ++ /* configure fifo */ ++ i2c_w32(I2C_FIFO_CFG_TXFC /* tx fifo as flow controller */ ++ | I2C_FIFO_CFG_RXFC /* rx fifo as flow controller */ ++ | I2C_FIFO_CFG_TXFA_TXFA2 /* tx fifo 4-byte aligned */ ++ | I2C_FIFO_CFG_RXFA_RXFA2 /* rx fifo 4-byte aligned */ ++ | I2C_FIFO_CFG_TXBS_TXBS0 /* tx fifo burst size is 1 word */ ++ | I2C_FIFO_CFG_RXBS_RXBS0, /* rx fifo burst size is 1 word */ ++ fifo_cfg); ++ ++ /* configure address */ ++ falcon_addr_configure(priv, priv->ten_bit); ++ ++ /* enable bus */ ++ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl); ++ ++ /* mask burst interrupts */ ++ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, 0, imsc); ++ ++ /* enable interrupts */ ++ i2c_w32(I2C_IMSC_LBREQ_INT_EN ++ | I2C_IMSC_BREQ_INT_EN ++ | I2C_IMSC_I2C_P_INT_EN ++ | I2C_IMSC_I2C_ERR_INT_EN, ++ imsc); ++ ++ return 0; ++} ++ ++static int __devinit falcon_i2c_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct falcon_i2c *priv; ++ struct i2c_adapter *adap; ++ struct resource *mmres, *ioarea, ++ *irqres_lb, *irqres_b, *irqres_err, *irqres_p; ++ struct clk *clk; ++ ++ dev_dbg(&pdev->dev, "probing\n"); ++ ++ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irqres_lb = platform_get_resource_byname(pdev, IORESOURCE_IRQ, ++ "i2c_lb"); ++ irqres_b = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_b"); ++ irqres_err = platform_get_resource_byname(pdev, IORESOURCE_IRQ, ++ "i2c_err"); ++ irqres_p = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_p"); ++ ++ if (!mmres || !irqres_lb || !irqres_b || !irqres_err || !irqres_p) { ++ dev_err(&pdev->dev, "no resources\n"); ++ return -ENODEV; ++ } ++ ++ clk = clk_get(&pdev->dev, "fpi"); ++ if (IS_ERR(clk)) { ++ dev_err(&pdev->dev, "failed to get fpi clk\n"); ++ return -ENOENT; ++ } ++ ++ if (clk_get_rate(clk) != 100000000) { ++ dev_err(&pdev->dev, "input clock is not 100MHz\n"); ++ return -ENOENT; ++ } ++ ++ /* allocate private data */ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) { ++ dev_err(&pdev->dev, "can't allocate private data\n"); ++ return -ENOMEM; ++ } ++ ++ adap = &priv->adap; ++ i2c_set_adapdata(adap, priv); ++ adap->owner = THIS_MODULE; ++ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; ++ strlcpy(adap->name, DRV_NAME "-adapter", sizeof(adap->name)); ++ adap->algo = &falcon_i2c_algorithm; ++ ++ priv->ten_bit = 0; ++ priv->mode = FALCON_I2C_MODE_100; ++ priv->clk = clk; ++ priv->dev = &pdev->dev; ++ ++ spin_lock_init(&priv->lock); ++ ++ ioarea = request_mem_region(mmres->start, resource_size(mmres), ++ pdev->name); ++ ++ if (ioarea == NULL) { ++ dev_err(&pdev->dev, "I2C region already claimed\n"); ++ ret = -ENXIO; ++ goto err_free_priv; ++ } ++ ++ /* map memory */ ++ priv->membase = ioremap_nocache(mmres->start & ~KSEG1, ++ resource_size(mmres)); ++ if (priv->membase == NULL) { ++ ret = -ENOMEM; ++ goto err_release_region; ++ } ++ ++ priv->irq_lb = irqres_lb->start; ++ ret = request_irq(priv->irq_lb, falcon_i2c_isr, IRQF_DISABLED, ++ irqres_lb->name, priv); ++ if (ret) { ++ dev_err(&pdev->dev, "can't get last burst IRQ %d\n", irqres_lb->start); ++ ret = -ENODEV; ++ goto err_unmap_mem; ++ } ++ ++ priv->irq_b = irqres_b->start; ++ ret = request_irq(priv->irq_b, falcon_i2c_isr, IRQF_DISABLED, ++ irqres_b->name, priv); ++ if (ret) { ++ dev_err(&pdev->dev, "can't get burst IRQ %d\n", irqres_b->start); ++ ret = -ENODEV; ++ goto err_free_lb_irq; ++ } ++ ++ priv->irq_err = irqres_err->start; ++ 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); ++ ret = -ENODEV; ++ goto err_free_b_irq; ++ } ++ ++ priv->irq_p = irqres_p->start; ++ 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); ++ ret = -ENODEV; ++ goto err_free_err_irq; ++ } ++ ++ dev_dbg(&pdev->dev, "mapped io-space to %p\n", priv->membase); ++ dev_dbg(&pdev->dev, "use IRQs %d, %d, %d, %d\n", irqres_lb->start, ++ irqres_b->start, irqres_err->start, irqres_p->start); ++ ++ /* add our adapter to the i2c stack */ ++ ret = i2c_add_numbered_adapter(adap); ++ if (ret) { ++ dev_err(&pdev->dev, "can't register I2C adapter\n"); ++ goto err_free_p_irq; ++ } ++ ++ platform_set_drvdata(pdev, priv); ++ i2c_set_adapdata(adap, priv); ++ ++ /* print module version information */ ++ dev_dbg(&pdev->dev, "module id=%u revision=%u\n", ++ (i2c_r32(id) & I2C_ID_ID_MASK) >> I2C_ID_ID_OFFSET, ++ (i2c_r32(id) & I2C_ID_REV_MASK) >> I2C_ID_REV_OFFSET); ++ ++ init_completion(&priv->done); ++ ++ /* initialize HW */ ++ ret = falcon_i2c_hw_init(adap); ++ if (ret) { ++ dev_err(&pdev->dev, "can't configure adapter\n"); ++ goto err_remove_adapter; ++ } ++ ++ return 0; ++ ++err_remove_adapter: ++ i2c_del_adapter(adap); ++ platform_set_drvdata(pdev, NULL); ++ ++err_free_p_irq: ++ free_irq(priv->irq_p, priv); ++ ++err_free_err_irq: ++ free_irq(priv->irq_err, priv); ++ ++err_free_b_irq: ++ free_irq(priv->irq_b, priv); ++ ++err_free_lb_irq: ++ free_irq(priv->irq_lb, priv); ++ ++err_unmap_mem: ++ iounmap(priv->membase); ++ ++err_release_region: ++ release_mem_region(mmres->start, resource_size(mmres)); ++ ++err_free_priv: ++ kfree(priv); ++ ++ return ret; ++} ++ ++static int __devexit falcon_i2c_remove(struct platform_device *pdev) ++{ ++ struct falcon_i2c *priv = platform_get_drvdata(pdev); ++ struct resource *mmres; ++ ++ /* disable bus */ ++ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl); ++ ++ /* remove driver */ ++ platform_set_drvdata(pdev, NULL); ++ i2c_del_adapter(&priv->adap); ++ ++ free_irq(priv->irq_lb, priv); ++ free_irq(priv->irq_b, priv); ++ free_irq(priv->irq_err, priv); ++ free_irq(priv->irq_p, priv); ++ ++ kfree(priv); ++ ++ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ release_mem_region(mmres->start, resource_size(mmres)); ++ ++ dev_dbg(&pdev->dev, "removed\n"); ++ ++ return 0; ++} ++ ++static struct platform_driver falcon_i2c_driver = { ++ .probe = falcon_i2c_probe, ++ .remove = __devexit_p(falcon_i2c_remove), ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init falcon_i2c_init(void) ++{ ++ int ret; ++ ++ ret = platform_driver_register(&falcon_i2c_driver); ++ ++ if (ret) ++ printk(KERN_DEBUG DRV_NAME ": can't register platform driver"); ++ ++ return ret; ++} ++ ++static void __exit falcon_i2c_exit(void) ++{ ++ platform_driver_unregister(&falcon_i2c_driver); ++} ++ ++module_init(falcon_i2c_init); ++module_exit(falcon_i2c_exit); ++ ++MODULE_DESCRIPTION("Lantiq FALC(tm) ON - I2C bus adapter"); ++MODULE_ALIAS("platform:i2c_falcon"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/lantiq/patches-2.6.39/130-falcon-spi-flash.patch b/target/linux/lantiq/patches-2.6.39/130-falcon-spi-flash.patch new file mode 100644 index 0000000..10ff605 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/130-falcon-spi-flash.patch @@ -0,0 +1,497 @@ +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -55,6 +55,7 @@ + obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o + obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o + obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o ++obj-$(CONFIG_SPI_FALCON) += spi_falcon.o + + # special build for s3c24xx spi driver with fiq support + spi_s3c24xx_hw-y := spi_s3c24xx.o +--- /dev/null ++++ b/drivers/spi/spi_falcon.c +@@ -0,0 +1,471 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++#include <linux/module.h> ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/spi/spi.h> ++#include <linux/delay.h> ++#include <linux/workqueue.h> ++ ++#include <lantiq.h> /* ebu_lock */ ++#include <falcon/ebu_reg.h> ++#include <falcon/sys1_reg.h> ++ ++#define DRV_NAME "falcon_spi" ++ ++#define FALCON_SPI_XFER_BEGIN (1 << 0) ++#define FALCON_SPI_XFER_END (1 << 1) ++ ++/* mapping for access macros */ ++#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 ebu (priv->ebu_membase) ++#define sys1 (priv->sys1_membase) ++ ++struct falcon_spi { ++ u32 sfcmd; /* for caching of opcode, direction, ... */ ++ ++ struct spi_master *master; ++ ++ struct gpon_reg_ebu __iomem *ebu_membase; ++ struct gpon_reg_sys1 __iomem *sys1_membase; ++}; ++ ++int falcon_spi_xfer(struct spi_device *spi, ++ struct spi_transfer *t, ++ unsigned long flags) ++{ ++ struct device *dev = &spi->dev; ++ struct falcon_spi *priv = spi_master_get_devdata(spi->master); ++ const u8 *txp = t->tx_buf; ++ u8 *rxp = t->rx_buf; ++ unsigned int bytelen = ((8 * t->len + 7) / 8); ++ unsigned int len, alen, dumlen; ++ u32 val; ++ enum { ++ state_init, ++ state_command_prepare, ++ state_write, ++ state_read, ++ state_disable_cs, ++ state_end ++ } state = state_init; ++ ++ do { ++ switch (state) { ++ case state_init: /* detect phase of upper layer sequence */ ++ { ++ /* initial write ? */ ++ if (flags & FALCON_SPI_XFER_BEGIN) { ++ if (!txp) { ++ dev_err(dev, ++ "BEGIN without tx data!\n"); ++ return -1; ++ } ++ /* ++ * Prepare the parts of the sfcmd register, ++ * which should not ++ * change during a sequence! ++ * Only exception are the length fields, ++ * especially alen and dumlen. ++ */ ++ ++ priv->sfcmd = ((spi->chip_select ++ << SFCMD_CS_OFFSET) ++ & SFCMD_CS_MASK); ++ priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED; ++ priv->sfcmd |= *txp; ++ txp++; ++ bytelen--; ++ if (bytelen) { ++ /* more data: ++ * maybe address and/or dummy */ ++ state = state_command_prepare; ++ break; ++ } else { ++ dev_dbg(dev, "write cmd %02X\n", ++ priv->sfcmd & SFCMD_OPC_MASK); ++ } ++ } ++ /* continued write ? */ ++ if (txp && bytelen) { ++ state = state_write; ++ break; ++ } ++ /* read data? */ ++ if (rxp && bytelen) { ++ state = state_read; ++ break; ++ } ++ /* end of sequence? */ ++ if (flags & FALCON_SPI_XFER_END) ++ state = state_disable_cs; ++ else ++ state = state_end; ++ break; ++ } ++ case state_command_prepare: /* collect tx data for ++ address and dummy phase */ ++ { ++ /* txp is valid, already checked */ ++ val = 0; ++ alen = 0; ++ dumlen = 0; ++ while (bytelen > 0) { ++ if (alen < 3) { ++ val = (val<<8)|(*txp++); ++ alen++; ++ } else if ((dumlen < 15) && (*txp == 0)) { ++ /* ++ * assume dummy bytes are set to 0 ++ * from upper layer ++ */ ++ dumlen++; ++ txp++; ++ } else ++ break; ++ bytelen--; ++ } ++ priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK); ++ priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) | ++ (dumlen << SFCMD_DUMLEN_OFFSET); ++ if (alen > 0) ++ ebu_w32(val, sfaddr); ++ ++ dev_dbg(dev, "write cmd %02X, alen=%d " ++ "(addr=%06X) dumlen=%d\n", ++ priv->sfcmd & SFCMD_OPC_MASK, ++ alen, val, dumlen); ++ ++ if (bytelen > 0) { ++ /* continue with write */ ++ state = state_write; ++ } else if (flags & FALCON_SPI_XFER_END) { ++ /* end of sequence? */ ++ state = state_disable_cs; ++ } else { ++ /* go to end and expect another ++ * call (read or write) */ ++ state = state_end; ++ } ++ break; ++ } ++ case state_write: ++ { ++ /* txp still valid */ ++ priv->sfcmd |= SFCMD_DIR_WRITE; ++ len = 0; ++ val = 0; ++ do { ++ if (bytelen--) ++ val |= (*txp++) << (8 * len++); ++ if ((flags & FALCON_SPI_XFER_END) ++ && (bytelen == 0)) { ++ priv->sfcmd &= ++ ~SFCMD_KEEP_CS_KEEP_SELECTED; ++ } ++ if ((len == 4) || (bytelen == 0)) { ++ ebu_w32(val, sfdata); ++ ebu_w32(priv->sfcmd ++ | (len<<SFCMD_DLEN_OFFSET), ++ sfcmd); ++ len = 0; ++ val = 0; ++ priv->sfcmd &= ~(SFCMD_ALEN_MASK ++ | SFCMD_DUMLEN_MASK); ++ } ++ } while (bytelen); ++ state = state_end; ++ break; ++ } ++ case state_read: ++ { ++ /* read data */ ++ priv->sfcmd &= ~SFCMD_DIR_WRITE; ++ do { ++ if ((flags & FALCON_SPI_XFER_END) ++ && (bytelen <= 4)) { ++ priv->sfcmd &= ++ ~SFCMD_KEEP_CS_KEEP_SELECTED; ++ } ++ len = (bytelen > 4) ? 4 : bytelen; ++ bytelen -= len; ++ ebu_w32(priv->sfcmd ++ |(len<<SFCMD_DLEN_OFFSET), sfcmd); ++ priv->sfcmd &= ~(SFCMD_ALEN_MASK ++ | SFCMD_DUMLEN_MASK); ++ do { ++ val = ebu_r32(sfstat); ++ if (val & SFSTAT_CMD_ERR) { ++ /* reset error status */ ++ dev_err(dev, "SFSTAT: CMD_ERR " ++ "(%x)\n", val); ++ ebu_w32(SFSTAT_CMD_ERR, sfstat); ++ return -1; ++ } ++ } while (val & SFSTAT_CMD_PEND); ++ val = ebu_r32(sfdata); ++ do { ++ *rxp = (val & 0xFF); ++ rxp++; ++ val >>= 8; ++ len--; ++ } while (len); ++ } while (bytelen); ++ state = state_end; ++ break; ++ } ++ case state_disable_cs: ++ { ++ priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED; ++ ebu_w32(priv->sfcmd | (0<<SFCMD_DLEN_OFFSET), sfcmd); ++ val = ebu_r32(sfstat); ++ if (val & SFSTAT_CMD_ERR) { ++ /* reset error status */ ++ dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val); ++ ebu_w32(SFSTAT_CMD_ERR, sfstat); ++ return -1; ++ } ++ state = state_end; ++ break; ++ } ++ case state_end: ++ break; ++ } ++ } while (state != state_end); ++ ++ return 0; ++} ++ ++static int falcon_spi_setup(struct spi_device *spi) ++{ ++ struct device *dev = &spi->dev; ++ struct falcon_spi *priv = spi_master_get_devdata(spi->master); ++ const u32 ebuclk = 100*1000*1000; ++ unsigned int i; ++ unsigned long flags; ++ ++ dev_dbg(dev, "setup\n"); ++ ++ if (spi->master->bus_num > 0 || spi->chip_select > 0) ++ return -ENODEV; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ ++ if (ebuclk < spi->max_speed_hz) { ++ /* set EBU clock to 100 MHz */ ++ sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, ebucc); ++ i = 1; /* divider */ ++ } else { ++ /* set EBU clock to 50 MHz */ ++ sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, ebucc); ++ ++ /* search for suitable divider */ ++ for (i = 1; i < 7; i++) { ++ if (ebuclk / i <= spi->max_speed_hz) ++ break; ++ } ++ } ++ ++ /* setup period of serial clock */ ++ ebu_w32_mask(SFTIME_SCKF_POS_MASK ++ | SFTIME_SCKR_POS_MASK ++ | SFTIME_SCK_PER_MASK, ++ (i << SFTIME_SCKR_POS_OFFSET) ++ | (i << (SFTIME_SCK_PER_OFFSET + 1)), ++ sftime); ++ ++ /* set some bits of unused_wd, to not trigger HOLD/WP ++ * signals on non QUAD flashes */ ++ ebu_w32((SFIO_UNUSED_WD_MASK & (0x8|0x4)), sfio); ++ ++ ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX, ++ busrcon0); ++ ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, buswcon0); ++ /* set address wrap around to maximum for 24-bit addresses */ ++ ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, sfcon); ++ ++ spin_unlock_irqrestore(&ebu_lock, flags); ++ ++ return 0; ++} ++ ++static int falcon_spi_transfer(struct spi_device *spi, struct spi_message *m) ++{ ++ struct falcon_spi *priv = spi_master_get_devdata(spi->master); ++ struct spi_transfer *t; ++ unsigned long spi_flags; ++ unsigned long flags; ++ int ret = 0; ++ ++ priv->sfcmd = 0; ++ m->actual_length = 0; ++ ++ spi_flags = FALCON_SPI_XFER_BEGIN; ++ list_for_each_entry(t, &m->transfers, transfer_list) { ++ if (list_is_last(&t->transfer_list, &m->transfers)) ++ spi_flags |= FALCON_SPI_XFER_END; ++ ++ spin_lock_irqsave(&ebu_lock, flags); ++ ret = falcon_spi_xfer(spi, t, spi_flags); ++ spin_unlock_irqrestore(&ebu_lock, flags); ++ ++ if (ret) ++ break; ++ ++ m->actual_length += t->len; ++ ++ if (t->delay_usecs || t->cs_change) ++ BUG(); ++ ++ spi_flags = 0; ++ } ++ ++ m->status = ret; ++ m->complete(m->context); ++ ++ return 0; ++} ++ ++static void falcon_spi_cleanup(struct spi_device *spi) ++{ ++ struct device *dev = &spi->dev; ++ ++ dev_dbg(dev, "cleanup\n"); ++} ++ ++static int __devinit falcon_spi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct falcon_spi *priv; ++ struct spi_master *master; ++ struct resource *memres_ebu, *memres_sys1; ++ int ret; ++ ++ dev_dbg(dev, "probing\n"); ++ ++ memres_ebu = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ebu"); ++ memres_sys1 = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ "sys1"); ++ ++ if (!memres_ebu || !memres_sys1) { ++ dev_err(dev, "no resources\n"); ++ return -ENODEV; ++ } ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(*priv)); ++ if (!master) { ++ dev_err(dev, "no memory for spi_master\n"); ++ return -ENOMEM; ++ } ++ ++ priv = spi_master_get_devdata(master); ++ ++ priv->ebu_membase = ioremap_nocache(memres_ebu->start & ~KSEG1, ++ resource_size(memres_ebu)); ++ ++ if (!priv->ebu_membase) { ++ dev_err(dev, "can't map ebu memory\n"); ++ ++ ret = -ENOMEM; ++ goto free_master; ++ } ++ ++ priv->sys1_membase = ioremap_nocache(memres_sys1->start & ~KSEG1, ++ resource_size(memres_sys1)); ++ ++ if (!priv->sys1_membase) { ++ dev_err(dev, "can't map sys1 memory\n"); ++ ++ ret = -ENOMEM; ++ goto unmap_ebu; ++ } ++ ++ priv->master = master; ++ ++ master->mode_bits = SPI_MODE_3; ++ master->num_chipselect = 1; ++ master->bus_num = 0; ++ ++ master->setup = falcon_spi_setup; ++ master->transfer = falcon_spi_transfer; ++ master->cleanup = falcon_spi_cleanup; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ ret = spi_register_master(master); ++ if (ret) ++ goto unmap_sys1; ++ ++ return 0; ++ ++unmap_sys1: ++ iounmap(priv->sys1_membase); ++ ++unmap_ebu: ++ iounmap(priv->ebu_membase); ++ ++free_master: ++ spi_master_put(master); ++ ++ return ret; ++} ++ ++static int __devexit falcon_spi_remove(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct falcon_spi *priv = platform_get_drvdata(pdev); ++ ++ dev_dbg(dev, "removed\n"); ++ ++ spi_unregister_master(priv->master); ++ ++ iounmap(priv->sys1_membase); ++ iounmap(priv->ebu_membase); ++ ++ return 0; ++} ++ ++static struct platform_driver falcon_spi_driver = { ++ .probe = falcon_spi_probe, ++ .remove = __devexit_p(falcon_spi_remove), ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE ++ } ++}; ++ ++static int __init falcon_spi_init(void) ++{ ++ return platform_driver_register(&falcon_spi_driver); ++} ++ ++static void __exit falcon_spi_exit(void) ++{ ++ platform_driver_unregister(&falcon_spi_driver); ++} ++ ++module_init(falcon_spi_init); ++module_exit(falcon_spi_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Lantiq Falcon SPI controller driver"); +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -210,6 +210,10 @@ + This drivers supports the MPC52xx SPI controller in master SPI + mode. + ++config SPI_FALCON ++ tristate "Falcon SPI controller support" ++ depends on SOC_FALCON ++ + config SPI_MPC52xx_PSC + tristate "Freescale MPC52xx PSC SPI controller" + depends on PPC_MPC52xx && EXPERIMENTAL diff --git a/target/linux/lantiq/patches-2.6.39/140-falcon-easy98000-cpld-led.patch b/target/linux/lantiq/patches-2.6.39/140-falcon-easy98000-cpld-led.patch new file mode 100644 index 0000000..f623b2e --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/140-falcon-easy98000-cpld-led.patch @@ -0,0 +1,193 @@ +--- a/arch/mips/lantiq/falcon/Makefile ++++ b/arch/mips/lantiq/falcon/Makefile +@@ -1,3 +1,4 @@ + obj-y := clk-falcon.o devices.o gpio.o prom.o sysctrl.o reset.o + obj-y += softdog_vpe.o + obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o ++obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o +--- /dev/null ++++ b/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.c +@@ -0,0 +1,160 @@ ++/* ++ * EASY98000 CPLD LED driver ++ * ++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/version.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/errno.h> ++#include <linux/leds.h> ++#include <linux/slab.h> ++ ++#include "dev-leds-easy98000-cpld.h" ++ ++const char *led_name[8] = { ++ "ge0_act", ++ "ge0_link", ++ "ge1_act", ++ "ge1_link", ++ "fe2_act", ++ "fe2_link", ++ "fe3_act", ++ "fe3_link" ++}; ++ ++#define cpld_base7 ((u16 *)(KSEG1 | 0x17c0000c)) ++#define cpld_base8 ((u16 *)(KSEG1 | 0x17c00012)) ++ ++#define ltq_r16(reg) __raw_readw(reg) ++#define ltq_w16(val, reg) __raw_writew(val, reg) ++ ++struct cpld_led_dev { ++ struct led_classdev cdev; ++ u8 mask; ++ u16 *base; ++}; ++ ++struct cpld_led_drvdata { ++ struct cpld_led_dev *led_devs; ++ int num_leds; ++}; ++ ++void led_set(u8 mask, u16 *base) ++{ ++ ltq_w16(ltq_r16(base) | mask, base); ++} ++ ++void led_clear(u8 mask, u16 *base) ++{ ++ ltq_w16(ltq_r16(base) & (~mask), base); ++} ++ ++void led_blink_clear(u8 mask, u16 *base) ++{ ++ led_clear(mask, base); ++} ++ ++static void led_brightness(struct led_classdev *led_cdev, ++ enum led_brightness value) ++{ ++ struct cpld_led_dev *led_dev = ++ container_of(led_cdev, struct cpld_led_dev, cdev); ++ ++ if (value) ++ led_set(led_dev->mask, led_dev->base); ++ else ++ led_clear(led_dev->mask, led_dev->base); ++} ++ ++static int led_probe(struct platform_device *pdev) ++{ ++ int i; ++ char name[32]; ++ struct cpld_led_drvdata *drvdata; ++ int ret = 0; ++ ++ drvdata = kzalloc(sizeof(struct cpld_led_drvdata) + ++ sizeof(struct cpld_led_dev) * MAX_LED, ++ GFP_KERNEL); ++ if (!drvdata) ++ return -ENOMEM; ++ ++ drvdata->led_devs = (struct cpld_led_dev *) &drvdata[1]; ++ ++ for (i = 0; i < MAX_LED; i++) { ++ struct cpld_led_dev *led_dev = &drvdata->led_devs[i]; ++ led_dev->cdev.brightness_set = led_brightness; ++ led_dev->cdev.default_trigger = NULL; ++ led_dev->mask = 1 << (i % 8); ++ if(i < 8) { ++ sprintf(name, "easy98000-cpld:%s", led_name[i]); ++ led_dev->base = cpld_base8; ++ } else { ++ sprintf(name, "easy98000-cpld:red:%d", i-8); ++ led_dev->base = cpld_base7; ++ } ++ led_dev->cdev.name = name; ++ ret = led_classdev_register(&pdev->dev, &led_dev->cdev); ++ if (ret) ++ goto err; ++ } ++ platform_set_drvdata(pdev, drvdata); ++ return 0; ++ ++err: ++ printk("led_probe: 3\n"); ++ for (i = i - 1; i >= 0; i--) ++ led_classdev_unregister(&drvdata->led_devs[i].cdev); ++ ++ kfree(drvdata); ++ return ret; ++} ++ ++static int led_remove(struct platform_device *pdev) ++{ ++ int i; ++ struct cpld_led_drvdata *drvdata = platform_get_drvdata(pdev); ++ for (i = 0; i < MAX_LED; i++) ++ led_classdev_unregister(&drvdata->led_devs[i].cdev); ++ kfree(drvdata); ++ return 0; ++} ++ ++static struct platform_driver led_driver = { ++ .probe = led_probe, ++ .remove = led_remove, ++ .driver = { ++ .name = LED_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++int __init easy98000_cpld_led_init(void) ++{ ++ pr_info(LED_DESC ", Version " LED_VERSION ++ " (c) Copyright 2011, Lantiq Deutschland GmbH\n"); ++ return platform_driver_register(&led_driver); ++} ++ ++void __exit easy98000_cpld_led_exit(void) ++{ ++ platform_driver_unregister(&led_driver); ++} ++ ++module_init(easy98000_cpld_led_init); ++module_exit(easy98000_cpld_led_exit); ++ ++MODULE_DESCRIPTION(LED_NAME); ++MODULE_DESCRIPTION(LED_DESC); ++MODULE_AUTHOR("Ralph Hempel <ralph.hempel@lantiq.com>"); ++MODULE_LICENSE("GPL v2"); ++ +--- /dev/null ++++ b/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.h +@@ -0,0 +1,20 @@ ++/* ++ * EASY98000 CPLD LED driver ++ * ++ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ * ++ */ ++#ifndef _INCLUDE_EASY98000_CPLD_LED_H_ ++#define _INCLUDE_EASY98000_CPLD_LED_H_ ++ ++#define LED_NAME "easy98000_cpld_led" ++#define LED_DESC "EASY98000 LED driver" ++#define LED_VERSION "1.0.0" ++ ++#define MAX_LED 16 ++ ++#endif /* _INCLUDE_EASY98000_CPLD_LED_H_ */ diff --git a/target/linux/lantiq/patches-2.6.39/150-falcon-easy98020.patch b/target/linux/lantiq/patches-2.6.39/150-falcon-easy98020.patch new file mode 100644 index 0000000..e9593c5 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/150-falcon-easy98020.patch @@ -0,0 +1,120 @@ +--- /dev/null ++++ b/arch/mips/lantiq/falcon/mach-easy98020.c +@@ -0,0 +1,97 @@ ++#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/input.h> ++#include <linux/interrupt.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/flash.h> ++#include "../machtypes.h" ++ ++#include "devices.h" ++#include "dev-leds-gpio.h" ++ ++#define EASY98020_GPIO_LED_0 9 ++#define EASY98020_GPIO_LED_1 10 ++#define EASY98020_GPIO_LED_2 11 ++#define EASY98020_GPIO_LED_3 12 ++ ++extern unsigned char ltq_ethaddr[6]; ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition easy98020_spi_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 easy98020_spi_flash_platform_data = { ++ .name = "sflash", ++ .parts = easy98020_spi_partitions, ++ .nr_parts = ARRAY_SIZE(easy98020_spi_partitions) ++}; ++#endif ++ ++static struct spi_board_info easy98020_spi_flash_data __initdata = { ++ .modalias = "m25p80", ++ .bus_num = 0, ++ .chip_select = 0, ++ .max_speed_hz = 10 * 1000 * 1000, ++ .mode = SPI_MODE_3, ++#ifdef CONFIG_MTD_PARTITIONS ++ .platform_data = &easy98020_spi_flash_platform_data ++#endif ++}; ++ ++static struct gpio_led easy98020_leds_gpio[] __initdata = { ++ { ++ .name = "easy98020:green:0", ++ .gpio = EASY98020_GPIO_LED_0, ++ .active_low = 0, ++ }, { ++ .name = "easy98020:green:1", ++ .gpio = EASY98020_GPIO_LED_1, ++ .active_low = 0, ++ }, { ++ .name = "easy98020:green:2", ++ .gpio = EASY98020_GPIO_LED_2, ++ .active_low = 0, ++ }, { ++ .name = "easy98020:green:3", ++ .gpio = EASY98020_GPIO_LED_3, ++ .active_low = 0, ++ } ++}; ++ ++static void __init easy98020_init(void) ++{ ++ falcon_register_asc(0); ++ falcon_register_gpio(); ++ falcon_register_wdt(); ++ falcon_register_i2c(); ++ falcon_register_spi_flash(&easy98020_spi_flash_data); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98020_leds_gpio), ++ easy98020_leds_gpio); ++ falcon_register_crypto(); ++} ++ ++MIPS_MACHINE(LANTIQ_MACH_EASY98020, ++ "EASY98020", ++ "EASY98020 Eval Board", ++ easy98020_init); +--- a/arch/mips/lantiq/falcon/Kconfig ++++ b/arch/mips/lantiq/falcon/Kconfig +@@ -6,6 +6,10 @@ + bool "Easy98000" + default y + ++config LANTIQ_MACH_EASY98020 ++ bool "Easy98020" ++ default y ++ + endmenu + + endif +--- a/arch/mips/lantiq/falcon/Makefile ++++ b/arch/mips/lantiq/falcon/Makefile +@@ -2,3 +2,4 @@ + obj-y += softdog_vpe.o + obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o + obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o ++obj-$(CONFIG_LANTIQ_MACH_EASY98020) += mach-easy98020.o diff --git a/target/linux/lantiq/patches-2.6.39/160-falcon-95C3AM1.patch b/target/linux/lantiq/patches-2.6.39/160-falcon-95C3AM1.patch new file mode 100644 index 0000000..0347037 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/160-falcon-95C3AM1.patch @@ -0,0 +1,136 @@ +--- /dev/null ++++ b/arch/mips/lantiq/falcon/mach-95C3AM1.c +@@ -0,0 +1,103 @@ ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/i2c-gpio.h> ++#include "../machtypes.h" ++ ++#include "devices.h" ++#include "dev-leds-gpio.h" ++ ++#define BOARD_95C3AM1_GPIO_LED_0 10 ++#define BOARD_95C3AM1_GPIO_LED_1 11 ++#define BOARD_95C3AM1_GPIO_LED_2 12 ++#define BOARD_95C3AM1_GPIO_LED_3 13 ++ ++extern unsigned char ltq_ethaddr[6]; ++ ++#ifdef CONFIG_MTD_PARTITIONS ++static struct mtd_partition board_95C3AM1_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 board_95C3AM1_flash_platform_data = { ++ .name = "sflash", ++ .parts = board_95C3AM1_partitions, ++ .nr_parts = ARRAY_SIZE(board_95C3AM1_partitions) ++}; ++#endif ++ ++static struct spi_board_info board_95C3AM1_flash_data __initdata = { ++ .modalias = "m25p80", ++ .bus_num = 0, ++ .chip_select = 0, ++ .max_speed_hz = 10 * 1000 * 1000, ++ .mode = SPI_MODE_3, ++#ifdef CONFIG_MTD_PARTITIONS ++ .platform_data = &board_95C3AM1_flash_platform_data ++#endif ++}; ++ ++static struct gpio_led board_95C3AM1_leds_gpio[] __initdata = { ++ { ++ .name = "power", ++ .gpio = BOARD_95C3AM1_GPIO_LED_0, ++ .active_low = 0, ++ }, { ++ .name = "optical", ++ .gpio = BOARD_95C3AM1_GPIO_LED_1, ++ .active_low = 0, ++ }, { ++ .name = "lan", ++ .gpio = BOARD_95C3AM1_GPIO_LED_2, ++ .active_low = 0, ++ }, { ++ .name = "update", ++ .gpio = BOARD_95C3AM1_GPIO_LED_3, ++ .active_low = 0, ++ } ++}; ++ ++static struct i2c_gpio_platform_data board_95C3AM1_i2c_gpio_data = { ++ .sda_pin = 107, ++ .scl_pin = 108, ++}; ++ ++static struct platform_device board_95C3AM1_i2c_gpio_device = { ++ .name = "i2c-gpio", ++ .id = 0, ++ .dev = { ++ .platform_data = &board_95C3AM1_i2c_gpio_data, ++ } ++}; ++ ++static void __init board_95C3AM1_init(void) ++{ ++ falcon_register_asc(0); ++ falcon_register_gpio(); ++ falcon_register_wdt(); ++ falcon_register_i2c(); ++ falcon_register_spi_flash(&board_95C3AM1_flash_data); ++ platform_device_register(&board_95C3AM1_i2c_gpio_device); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(board_95C3AM1_leds_gpio), ++ board_95C3AM1_leds_gpio); ++ falcon_register_crypto(); ++} ++ ++MIPS_MACHINE(LANTIQ_MACH_95C3AM1, ++ "95C3AM1", ++ "95C3AM1 Board", ++ board_95C3AM1_init); +--- a/arch/mips/lantiq/falcon/Kconfig ++++ b/arch/mips/lantiq/falcon/Kconfig +@@ -10,6 +10,10 @@ + bool "Easy98020" + default y + ++config LANTIQ_MACH_95C3AM1 ++ bool "95C3AM1" ++ default y ++ + endmenu + + endif +--- a/arch/mips/lantiq/falcon/Makefile ++++ b/arch/mips/lantiq/falcon/Makefile +@@ -3,3 +3,4 @@ + obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o + obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o + obj-$(CONFIG_LANTIQ_MACH_EASY98020) += mach-easy98020.o ++obj-$(CONFIG_LANTIQ_MACH_95C3AM1) += mach-95C3AM1.o +--- a/arch/mips/lantiq/machtypes.h ++++ b/arch/mips/lantiq/machtypes.h +@@ -20,6 +20,7 @@ + LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */ + LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */ + LANTIQ_MACH_EASY98020, /* Falcon Reference Board */ ++ LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */ + }; + + #endif diff --git a/target/linux/lantiq/patches-2.6.39/200-mach-arv45xx.patch b/target/linux/lantiq/patches-2.6.39/200-mach-arv45xx.patch new file mode 100644 index 0000000..b82dada --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/200-mach-arv45xx.patch @@ -0,0 +1,547 @@ +--- a/arch/mips/lantiq/xway/Kconfig ++++ b/arch/mips/lantiq/xway/Kconfig +@@ -6,6 +6,10 @@ + bool "Easy50712 - Danube" + default y + ++config LANTIQ_MACH_ARV45XX ++ bool "ARV45XX" ++ default y ++ + endmenu + + endif +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -5,3 +5,4 @@ + + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o ++obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o +--- /dev/null ++++ b/arch/mips/lantiq/xway/mach-arv45xx.c +@@ -0,0 +1,504 @@ ++/* ++ * 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/ath5k_platform.h> ++#include <linux/pci.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_platform.h> ++ ++#include "../machtypes.h" ++#include "devices.h" ++#include "dev-leds-gpio.h" ++#include "dev-dwc_otg.h" ++ ++#ifdef CONFIG_MTD_PARTITIONS ++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, ++ }, ++}; ++ ++static struct mtd_partition arv75xx_partitions[] = ++{ ++ { ++ .name = "uboot", ++ .offset = 0x0, ++ .size = 0x10000, ++ }, ++ { ++ .name = "uboot_env", ++ .offset = 0x10000, ++ .size = 0x10000, ++ }, ++ { ++ .name = "linux", ++ .offset = 0x20000, ++ .size = 0x7d0000, ++ }, ++ { ++ .name = "board_config", ++ .offset = 0x7f0000, ++ .size = 0x10000, ++ }, ++}; ++ ++#endif ++ ++static struct physmap_flash_data arv4510_flash_data = { ++#ifdef CONFIG_MTD_PARTITIONS ++ .nr_parts = ARRAY_SIZE(arv4510_partitions), ++ .parts = arv4510_partitions, ++#endif ++}; ++ ++static struct physmap_flash_data arv45xx_flash_data = { ++#ifdef CONFIG_MTD_PARTITIONS ++ .nr_parts = ARRAY_SIZE(arv45xx_partitions), ++ .parts = arv45xx_partitions, ++#endif ++}; ++ ++static struct physmap_flash_data arv75xx_flash_data = { ++#ifdef CONFIG_MTD_PARTITIONS ++ .nr_parts = ARRAY_SIZE(arv75xx_partitions), ++ .parts = arv75xx_partitions, ++#endif ++}; ++ ++static struct ltq_pci_data ltq_pci_data = { ++ .clock = PCI_CLOCK_EXT, ++ .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 struct gpio_led ++arv4510pw_leds_gpio[] __initdata = { ++ { .name = "soc:green:foo", .gpio = 4, .active_low = 1, }, ++}; ++ ++static struct gpio_led ++arv4518pw_leds_gpio[] __initdata = { ++ { .name = "soc:green:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:adsl", .gpio = 4, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:wlan", .gpio = 6, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:red:fail", .gpio = 8, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:usb", .gpio = 19, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:voip", .gpio = 72, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:fxs1", .gpio = 73, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:fxs2", .gpio = 74, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" }, ++}; ++ ++static struct gpio_button ++arv4518pw_gpio_buttons[] __initdata = { ++ { .desc = "wlan", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 28, .active_low = 1, }, ++ { .desc = "wps", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 29, .active_low = 1, }, ++ { .desc = "reset", .type = EV_KEY, .code = BTN_2, .threshold = 3, .gpio = 30, .active_low = 1, }, ++}; ++ ++static struct gpio_led ++arv4520pw_leds_gpio[] __initdata = { ++ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, }, ++ { .name = "soc:blue:adsl", .gpio = 4, .active_low = 1, }, ++ { .name = "soc:blue:internet", .gpio = 5, .active_low = 1, }, ++ { .name = "soc:red:power", .gpio = 6, .active_low = 1, }, ++ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, }, ++ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, }, ++ { .name = "soc:blue:voip", .gpio = 72, .active_low = 1, }, ++ { .name = "soc:blue:fxs1", .gpio = 73, .active_low = 1, }, ++ { .name = "soc:blue:fxs2", .gpio = 74, .active_low = 1, }, ++ { .name = "soc:blue:fxo", .gpio = 75, .active_low = 1, }, ++ { .name = "soc:blue:voice", .gpio = 76, .active_low = 1, }, ++ { .name = "soc:blue:usb", .gpio = 77, .active_low = 1, }, ++ { .name = "soc:blue:wlan", .gpio = 78, .active_low = 1, }, ++}; ++ ++static struct gpio_led ++arv452cpw_leds_gpio[] __initdata = { ++ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:adsl", .gpio = 4, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:isdn", .gpio = 5, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:fxs1", .gpio = 72, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:fxs2", .gpio = 73, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:wps", .gpio = 74, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:voice", .gpio = 76, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:usb", .gpio = 77, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:wlan", .gpio = 78, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:internet", .gpio = 80, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:red:internet", .gpio = 81, .active_low = 1, .default_trigger = "default-on" }, ++}; ++ ++static struct gpio_led ++arv4525pw_leds_gpio[] __initdata = { ++ { .name = "soc:green:festnetz", .gpio = 4, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:dsl", .gpio = 6, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:wlan", .gpio = 8, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:online", .gpio = 9, .active_low = 1, .default_trigger = "default-on" }, ++}; ++ ++static struct gpio_led ++arv752dpw22_leds_gpio[] __initdata = { ++ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:red:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:red:wps", .gpio = 8, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:red:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:red:voice", .gpio = 76, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:usb", .gpio = 77, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:wlan", .gpio = 78, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:wlan1", .gpio = 79, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:wlan", .gpio = 80, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:blue:wlan1", .gpio = 81, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:eth1", .gpio = 83, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:eth2", .gpio = 84, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:eth3", .gpio = 85, .active_low = 1, .default_trigger = "default-on" }, ++ { .name = "soc:green:eth4", .gpio = 86, .active_low = 1, .default_trigger = "default-on", }, ++}; ++ ++static struct gpio_button ++arv752dpw22_gpio_buttons[] __initdata = { ++ { .desc = "btn0", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 12, .active_low = 1, }, ++ { .desc = "btn1", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 13, .active_low = 1, }, ++ { .desc = "btn2", .type = EV_KEY, .code = BTN_2, .threshold = 3, .gpio = 28, .active_low = 1, }, ++}; ++ ++static struct gpio_led ++arv7518pw_leds_gpio[] __initdata = { ++ { .name = "soc:green:power", .gpio = 2, .active_low = 1, }, ++ { .name = "soc:green:adsl", .gpio = 4, .active_low = 1, }, ++ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, }, ++ { .name = "soc:green:wlan", .gpio = 6, .active_low = 1, }, ++ { .name = "soc:red:internet", .gpio = 8, .active_low = 1, }, ++ { .name = "soc:green:usb", .gpio = 19, .active_low = 1, }, ++}; ++ ++static struct gpio_button ++arv7518pw_gpio_buttons[] __initdata = { ++ { .desc = "reset", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 23, .active_low = 1, }, ++ { .desc = "wlan", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 25, .active_low = 1, }, ++}; ++ ++static void ++arv45xx_register_ethernet(void) ++{ ++#define ARV45XX_BRN_MAC 0x3f0016 ++ memcpy_fromio(<q_eth_data.mac, ++ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6); ++ ltq_register_etop(<q_eth_data); ++} ++ ++static void ++arv75xx_register_ethernet(void) ++{ ++#define ARV75XX_BRN_MAC 0x7f0016 ++ memcpy_fromio(<q_eth_data.mac, ++ (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, ++ (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 struct ath5k_platform_data arv45xx_ath5k_platform_data; ++ ++/*static int arv45xx_pci_plat_dev_init(struct pci_dev *dev) ++{ ++ dev->dev.platform_data = &arv45xx_ath5k_platform_data; ++ return 0; ++} ++*/ ++void __init ++arv45xx_register_ath5k(void) ++{ ++#define ARV45XX_BRN_ATH 0x3f0478 ++ int i; ++ unsigned char eeprom_mac[6]; ++ static u16 eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS]; ++ u32 *p = (u32*)arv45xx_ath5k_eeprom_data; ++ ++ memcpy_fromio(eeprom_mac, ++ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6); ++ eeprom_mac[5]++; ++ memcpy_fromio(arv45xx_ath5k_eeprom_data, ++ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_ATH), 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; ++ } ++ } ++ arv45xx_ath5k_platform_data.eeprom_data = arv45xx_ath5k_eeprom_data; ++ arv45xx_ath5k_platform_data.macaddr = eeprom_mac; ++ //lqpci_plat_dev_init = arv45xx_pci_plat_dev_init; ++} ++ ++static void __init ++arv3527p_init(void) ++{ ++ ltq_register_gpio_stp(); ++ //ltq_add_device_leds_gpio(arv3527p_leds_gpio, ARRAY_SIZE(arv3527p_leds_gpio)); ++ ltq_register_nor(&arv45xx_flash_data); ++ arv45xx_register_ethernet(); ++} ++ ++MIPS_MACHINE(LANTIQ_MACH_ARV3527P, ++ "ARV3527P", ++ "ARV3527P - Arcor Easybox 401", ++ arv3527p_init); ++ ++static void __init ++arv4510pw_init(void) ++{ ++ ltq_register_gpio_stp(); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4510pw_leds_gpio), arv4510pw_leds_gpio); ++ ltq_register_nor(&arv4510_flash_data); ++ 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(); ++} ++ ++MIPS_MACHINE(LANTIQ_MACH_ARV4510PW, ++ "ARV4510PW", ++ "ARV4510PW - Wippies Homebox", ++ arv4510pw_init); ++ ++static void __init ++arv4518pw_init(void) ++{ ++#define ARV4518PW_EBU 0 ++#define ARV4518PW_USB 14 ++#define ARV4518PW_SWITCH_RESET 13 ++ ++ ltq_register_gpio_ebu(ARV4518PW_EBU); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4518pw_leds_gpio), arv4518pw_leds_gpio); ++ ltq_register_gpio_buttons(arv4518pw_gpio_buttons, ARRAY_SIZE(arv4518pw_gpio_buttons)); ++ ltq_register_nor(&arv45xx_flash_data); ++ ltq_pci_data.gpio = PCI_GNT2 | PCI_REQ2; ++ ltq_register_pci(<q_pci_data); ++ ltq_register_madwifi_eep(); ++ xway_register_dwc(ARV4518PW_USB); ++ arv45xx_register_ethernet(); ++ arv45xx_register_ath5k(); ++ ++ gpio_request(ARV4518PW_SWITCH_RESET, "switch"); ++ gpio_direction_output(ARV4518PW_SWITCH_RESET, 1); ++ gpio_export(ARV4518PW_SWITCH_RESET, 0); ++} ++ ++MIPS_MACHINE(LANTIQ_MACH_ARV4518PW, ++ "ARV4518PW", ++ "ARV4518PW - SMC7908A-ISP, Airties WAV-221", ++ arv4518pw_init); ++ ++static void __init ++arv4520pw_init(void) ++{ ++#define ARV4520PW_EBU 0x400 ++#define ARV4520PW_USB 28 ++#define ARV4520PW_SWITCH_RESET 82 ++ ++ ltq_register_gpio_ebu(ARV4520PW_EBU); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4520pw_leds_gpio), arv4520pw_leds_gpio); ++ ltq_register_nor(&arv45xx_flash_data); ++ ltq_register_pci(<q_pci_data); ++ ltq_register_tapi(); ++ arv45xx_register_ethernet(); ++ xway_register_dwc(ARV4520PW_USB); ++ ++ gpio_request(ARV4520PW_SWITCH_RESET, "switch"); ++ gpio_set_value(ARV4520PW_SWITCH_RESET, 1); ++} ++ ++MIPS_MACHINE(LANTIQ_MACH_ARV4520PW, ++ "ARV4520PW", ++ "ARV4520PW - Airties WAV-281, Arcor A800", ++ arv4520pw_init); ++ ++static void __init ++arv452Cpw_init(void) ++{ ++#define ARV452CPW_EBU 0x77f ++#define ARV452CPW_USB 28 ++#define ARV452CPW_RELAY1 31 ++#define ARV452CPW_RELAY2 79 ++#define ARV452CPW_SWITCH_RESET 82 ++ ++ ltq_register_gpio_ebu(ARV452CPW_EBU); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv452cpw_leds_gpio), arv452cpw_leds_gpio); ++ ltq_register_nor(&arv45xx_flash_data); ++ ltq_register_pci(<q_pci_data); ++ ltq_register_madwifi_eep(); ++ xway_register_dwc(ARV452CPW_USB); ++ arv45xx_register_ethernet(); ++ arv45xx_register_ath5k(); ++ ++ gpio_request(ARV452CPW_SWITCH_RESET, "switch"); ++ gpio_set_value(ARV452CPW_SWITCH_RESET, 1); ++ gpio_export(ARV452CPW_SWITCH_RESET, 0); ++ ++ gpio_request(ARV452CPW_RELAY1, "relay1"); ++ gpio_direction_output(ARV452CPW_RELAY1, 1); ++ gpio_export(ARV452CPW_RELAY1, 0); ++ ++ gpio_request(ARV452CPW_RELAY2, "relay2"); ++ gpio_set_value(ARV452CPW_RELAY2, 1); ++ gpio_export(ARV452CPW_RELAY2, 0); ++} ++ ++MIPS_MACHINE(LANTIQ_MACH_ARV452CPW, ++ "ARV452CPW", ++ "ARV452CPW - Arcor A801", ++ arv452Cpw_init); ++ ++static void __init ++arv4525pw_init(void) ++{ ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4525pw_leds_gpio), arv4525pw_leds_gpio); ++ ltq_register_nor(&arv45xx_flash_data); ++ ltq_pci_data.clock = PCI_CLOCK_INT; ++ ltq_register_pci(<q_pci_data); ++ ltq_register_madwifi_eep(); ++ ltq_eth_data.mii_mode = PHY_INTERFACE_MODE_MII; ++ arv45xx_register_ethernet(); ++} ++ ++MIPS_MACHINE(LANTIQ_MACH_ARV4525PW, ++ "ARV4525PW", ++ "ARV4525PW - Speedport W502V", ++ arv4525pw_init); ++ ++static void __init ++arv7518pw_init(void) ++{ ++#define ARV7518PW_EBU 0x2 ++#define ARV7518PW_USB 14 ++ ++ ltq_register_gpio_ebu(ARV7518PW_EBU); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv7518pw_leds_gpio), arv7518pw_leds_gpio); ++ ltq_register_gpio_buttons(arv7518pw_gpio_buttons, ARRAY_SIZE(arv7518pw_gpio_buttons)); ++ 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); ++} ++ ++MIPS_MACHINE(LANTIQ_MACH_ARV7518PW, ++ "ARV7518PW", ++ "ARV7518PW - ASTORIA", ++ arv7518pw_init); ++ ++static void __init ++arv752dpw22_init(void) ++{ ++#define ARV752DPW22_EBU 0x2 ++#define ARV752DPW22_USB 72 ++#define ARV752DPW22_RELAY 73 ++ ++ ltq_register_gpio_ebu(ARV752DPW22_EBU); ++ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv752dpw22_leds_gpio), arv752dpw22_leds_gpio); ++ ltq_register_gpio_buttons(arv752dpw22_gpio_buttons, ARRAY_SIZE(arv752dpw22_gpio_buttons)); ++ ltq_register_nor(&arv75xx_flash_data); ++ ltq_pci_data.irq[15] = (INT_NUM_IM2_IRL0 + 31); ++ ltq_pci_data.gpio |= PCI_EXIN1 | PCI_REQ2; ++ ltq_register_pci(<q_pci_data); ++ xway_register_dwc(ARV752DPW22_USB); ++ arv75xx_register_ethernet(); ++ ++ gpio_request(ARV752DPW22_RELAY, "relay"); ++ gpio_set_value(ARV752DPW22_RELAY, 1); ++ gpio_export(ARV752DPW22_RELAY, 0); ++} ++ ++MIPS_MACHINE(LANTIQ_MACH_ARV752DPW22, ++ "ARV752DPW22", ++ "ARV752DPW22 - Arcor A803", ++ arv752dpw22_init); +--- a/arch/mips/lantiq/machtypes.h ++++ b/arch/mips/lantiq/machtypes.h +@@ -21,6 +21,17 @@ + LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */ + LANTIQ_MACH_EASY98020, /* Falcon Reference Board */ + LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */ ++ ++ /* Arcadyan */ ++ LANTIQ_MACH_ARV3527P, /* Arcor easybox a401 */ ++ LANTIQ_MACH_ARV4510PW, /* Wippies Homebox */ ++ LANTIQ_MACH_ARV4518PW, /* Airties WAV-221, SMC-7908A-ISP */ ++ LANTIQ_MACH_ARV4520PW, /* Airties WAV-281, Arcor EasyboxA800 */ ++ LANTIQ_MACH_ARV452CPW, /* Arcor EasyboxA801 */ ++ LANTIQ_MACH_ARV4525PW, /* Speedport W502V */ ++ LANTIQ_MACH_ARV752DPW, /* Arcor easybox a802 */ ++ LANTIQ_MACH_ARV752DPW22, /* Arcor easybox a803 */ ++ LANTIQ_MACH_ARV7518PW, /* ASTORIA */ + }; + + #endif diff --git a/target/linux/lantiq/patches-2.6.39/210-mtd_uimage_split.patch b/target/linux/lantiq/patches-2.6.39/210-mtd_uimage_split.patch new file mode 100644 index 0000000..bca51a8 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/210-mtd_uimage_split.patch @@ -0,0 +1,116 @@ +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -63,6 +63,10 @@ + depends on MTD_PARTITIONS + 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" + depends on MTD_PARTITIONS +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -724,6 +724,82 @@ + } + #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 +@@ -748,6 +824,17 @@ + if (!slave) + return -ENOMEM; + ++#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/310-atm_hack.patch b/target/linux/lantiq/patches-2.6.39/220-atm_hack.patch index ef19643..ef19643 100644 --- a/target/linux/lantiq/patches/310-atm_hack.patch +++ b/target/linux/lantiq/patches-2.6.39/220-atm_hack.patch diff --git a/target/linux/lantiq/patches-2.6.39/230-cmdline_hack.patch b/target/linux/lantiq/patches-2.6.39/230-cmdline_hack.patch new file mode 100644 index 0000000..df23286 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/230-cmdline_hack.patch @@ -0,0 +1,45 @@ +--- a/arch/mips/lantiq/prom.c ++++ b/arch/mips/lantiq/prom.c +@@ -39,6 +39,34 @@ + { + } + ++#ifdef CONFIG_IMAGE_CMDLINE_HACK ++extern char __image_cmdline[]; ++ ++static void __init ++prom_init_image_cmdline(void) ++{ ++ char *p = __image_cmdline; ++ int replace = 0; ++ ++ if (*p == '-') { ++ replace = 1; ++ p++; ++ } ++ ++ if (*p == '\0') ++ return; ++ ++ if (replace) { ++ strlcpy(arcs_cmdline, p, sizeof(arcs_cmdline)); ++ } else { ++ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); ++ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); ++ } ++} ++#else ++static void __init prom_init_image_cmdline(void) { return; } ++#endif ++ + static void __init prom_init_cmdline(void) + { + int argc = fw_arg0; +@@ -53,6 +81,7 @@ + strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); + } + } ++ prom_init_image_cmdline(); + } + + void __init prom_init(void) diff --git a/target/linux/lantiq/patches-2.6.39/240-udp_redirect.patch b/target/linux/lantiq/patches-2.6.39/240-udp_redirect.patch new file mode 100644 index 0000000..286dce8 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/240-udp_redirect.patch @@ -0,0 +1,348 @@ +--- /dev/null ++++ b/include/linux/udp_redirect.h +@@ -0,0 +1,57 @@ ++#ifndef _UDP_REDIRECT_H ++#define _UDP_REDIRECT_H ++ ++/****************************************************************************** ++ ++ Copyright (c) 2006 ++ Infineon Technologies AG ++ Am Campeon 1-12; 81726 Munich, Germany ++ ++ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE, ++ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS ++ SOFTWARE IS FREE OF CHARGE. ++ ++ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS ++ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING ++ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP, ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE ++ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD ++ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL ++ PROPERTY INFRINGEMENT. ++ ++ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT ++ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM ++ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ DEALINGS IN THE SOFTWARE. ++ ++******************************************************************************/ ++ ++/* ============================= */ ++/* Includes */ ++/* ============================= */ ++#ifndef _LINUX_TYPES_H ++#include <linux/types.h> ++#endif ++ ++ ++/* ============================= */ ++/* Definitions */ ++/* ============================= */ ++#define UDP_REDIRECT_MAGIC (void*)0x55445052L ++ ++ ++/* ============================= */ ++/* Global variable declaration */ ++/* ============================= */ ++extern int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb); ++extern int (*udpredirect_getfrag_fn)(void *p, char * to, ++ int offset, int fraglen, int odd, ++ struct sk_buff *skb); ++/* ============================= */ ++/* Global function declaration */ ++/* ============================= */ ++ ++extern int udpredirect_getfrag(void *p, char * to, int offset, ++ int fraglen, int odd, struct sk_buff *skb); ++#endif +--- /dev/null ++++ b/net/ipv4/udp_redirect_symb.c +@@ -0,0 +1,186 @@ ++/****************************************************************************** ++ ++ Copyright (c) 2006 ++ Infineon Technologies AG ++ Am Campeon 1-12; 81726 Munich, Germany ++ ++ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE, ++ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS ++ SOFTWARE IS FREE OF CHARGE. ++ ++ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS ++ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING ++ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP, ++ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE ++ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD ++ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL ++ PROPERTY INFRINGEMENT. ++ ++ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT ++ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM ++ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ DEALINGS IN THE SOFTWARE. ++ ++******************************************************************************/ ++#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) ++/* ============================= */ ++/* Includes */ ++/* ============================= */ ++#include <net/checksum.h> ++#include <net/udp.h> ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/udp_redirect.h> ++ ++/* ============================= */ ++/* Global variable definition */ ++/* ============================= */ ++int (*udpredirect_getfrag_fn) (void *p, char * to, int offset, ++ int fraglen, int odd, struct sk_buff *skb) = NULL; ++int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb) = NULL; ++ ++/* ============================= */ ++/* Local type definitions */ ++/* ============================= */ ++struct udpfakehdr ++{ ++ struct udphdr uh; ++ u32 saddr; ++ u32 daddr; ++ struct iovec *iov; ++ u32 wcheck; ++}; ++ ++/* ============================= */ ++/* Local function declaration */ ++/* ============================= */ ++static int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata, ++ struct iovec *iov, int offset, unsigned int len, __wsum *csump); ++ ++static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, ++ int len); ++ ++/* ============================= */ ++/* Global function definition */ ++/* ============================= */ ++ ++/* ++ Copy of udp_getfrag() from udp.c ++ This function exists because no copy_from_user() is needed for udpredirect. ++*/ ++ ++int ++udpredirect_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) ++{ ++ struct iovec *iov = from; ++ ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { ++ if (udpredirect_memcpy_fromiovecend(to, iov, offset, len) < 0) ++ return -EFAULT; ++ } else { ++ __wsum csum = 0; ++ if (udpredirect_csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0) ++ return -EFAULT; ++ skb->csum = csum_block_add(skb->csum, csum, odd); ++ } ++ return 0; ++} ++ ++static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, ++ int len) ++{ ++ /* Skip over the finished iovecs */ ++ while (offset >= iov->iov_len) { ++ offset -= iov->iov_len; ++ iov++; ++ } ++ ++ while (len > 0) { ++ u8 __user *base = iov->iov_base + offset; ++ int copy = min_t(unsigned int, len, iov->iov_len - offset); ++ ++ offset = 0; ++ memcpy(kdata, base, copy); ++ len -= copy; ++ kdata += copy; ++ iov++; ++ } ++ ++ return 0; ++} ++ ++/* ++ Copy of csum_partial_copy_fromiovecend() from iovec.c ++ This function exists because no copy_from_user() is needed for udpredirect. ++*/ ++ ++int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, ++ int offset, unsigned int len, __wsum *csump) ++{ ++ __wsum csum = *csump; ++ int partial_cnt = 0, err = 0; ++ ++ /* Skip over the finished iovecs */ ++ while (offset >= iov->iov_len) { ++ offset -= iov->iov_len; ++ iov++; ++ } ++ ++ while (len > 0) { ++ u8 __user *base = iov->iov_base + offset; ++ int copy = min_t(unsigned int, len, iov->iov_len - offset); ++ ++ offset = 0; ++ ++ /* There is a remnant from previous iov. */ ++ if (partial_cnt) { ++ int par_len = 4 - partial_cnt; ++ ++ /* iov component is too short ... */ ++ if (par_len > copy) { ++ memcpy(kdata, base, copy); ++ kdata += copy; ++ base += copy; ++ partial_cnt += copy; ++ len -= copy; ++ iov++; ++ if (len) ++ continue; ++ *csump = csum_partial(kdata - partial_cnt, ++ partial_cnt, csum); ++ goto out; ++ } ++ memcpy(kdata, base, par_len); ++ csum = csum_partial(kdata - partial_cnt, 4, csum); ++ kdata += par_len; ++ base += par_len; ++ copy -= par_len; ++ len -= par_len; ++ partial_cnt = 0; ++ } ++ ++ if (len > copy) { ++ partial_cnt = copy % 4; ++ if (partial_cnt) { ++ copy -= partial_cnt; ++ memcpy(kdata + copy, base + copy, partial_cnt); ++ } ++ } ++ ++ if (copy) { ++ csum = csum_partial_copy_nocheck(base, kdata, copy, csum); ++ } ++ len -= copy + partial_cnt; ++ kdata += copy + partial_cnt; ++ iov++; ++ } ++ *csump = csum; ++out: ++ return err; ++} ++ ++EXPORT_SYMBOL(udpredirect_getfrag); ++EXPORT_SYMBOL(udp_do_redirect_fn); ++EXPORT_SYMBOL(udpredirect_getfrag_fn); ++#endif /* CONFIG_IFX_UDP_REDIRECT* */ +--- a/net/ipv4/Makefile ++++ b/net/ipv4/Makefile +@@ -14,6 +14,9 @@ + inet_fragment.o + + obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o ++ifneq ($(CONFIG_IFX_UDP_REDIRECT),) ++obj-$(CONFIG_IFX_UDP_REDIRECT) += udp_redirect_symb.o ++endif + obj-$(CONFIG_PROC_FS) += proc.o + obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o + obj-$(CONFIG_IP_MROUTE) += ipmr.o +--- a/net/ipv4/udp.c ++++ b/net/ipv4/udp.c +@@ -107,6 +107,10 @@ + #include <net/xfrm.h> + #include "udp_impl.h" + ++#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) ++#include <linux/udp_redirect.h> ++#endif ++ + struct udp_table udp_table __read_mostly; + EXPORT_SYMBOL(udp_table); + +@@ -802,7 +806,7 @@ + u8 tos; + int err, is_udplite = IS_UDPLITE(sk); + int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; +- int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); ++ int (*getfrag)(void *, char *, int, int, int, struct sk_buff *) = NULL; + struct sk_buff *skb; + + if (len > 0xFFFF) +@@ -818,7 +822,13 @@ + ipc.opt = NULL; + ipc.tx_flags = 0; + +- getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; ++/* UDPREDIRECT */ ++#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) ++ if(udpredirect_getfrag_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC) ++ getfrag = udpredirect_getfrag_fn; ++ else ++#endif /* IFX_UDP_REDIRECT */ ++ getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + + if (up->pending) { + /* +@@ -1608,6 +1618,7 @@ + struct rtable *rt = skb_rtable(skb); + __be32 saddr, daddr; + struct net *net = dev_net(skb->dev); ++ int ret = 0; + + /* + * Validate the packet. +@@ -1640,7 +1651,16 @@ + sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable); + + if (sk != NULL) { +- int ret = udp_queue_rcv_skb(sk, skb); ++ /* UDPREDIRECT */ ++#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE) ++ if(udp_do_redirect_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC) ++ { ++ udp_do_redirect_fn(sk,skb); ++ kfree_skb(skb); ++ return(0); ++ } ++#endif ++ ret = udp_queue_rcv_skb(sk, skb); + sock_put(sk); + + /* a return value > 0 means to resubmit the input, but +@@ -1937,7 +1957,7 @@ + .clear_sk = sk_prot_clear_portaddr_nulls, + }; + EXPORT_SYMBOL(udp_prot); +- ++EXPORT_SYMBOL(udp_rcv); + /* ------------------------------------------------------------------------ */ + #ifdef CONFIG_PROC_FS + +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -72,6 +72,12 @@ + + Short answer: say Y. + ++config IFX_UDP_REDIRECT ++ bool "IFX Kernel Packet Interface for UDP redirection" ++ help ++ You can say Y here if you want to use hooks from kernel for ++ UDP redirection. ++ + if INET + source "net/ipv4/Kconfig" + source "net/ipv6/Kconfig" diff --git a/target/linux/lantiq/patches/809-mt-vpe.patch b/target/linux/lantiq/patches-2.6.39/250-mt-vpe.patch index ea50761..0a19289 100644 --- a/target/linux/lantiq/patches/809-mt-vpe.patch +++ b/target/linux/lantiq/patches-2.6.39/250-mt-vpe.patch @@ -1,6 +1,6 @@ --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -1837,6 +1837,28 @@ config MIPS_VPE_LOADER +@@ -1871,6 +1871,28 @@ Includes a loader for loading an elf relocatable object onto another VPE and running it. @@ -110,7 +110,7 @@ /* TCStatus fields (per TC) */ #define TCSTATUS_TASID (_ULCAST_(0xff)) #define TCSTATUS_IXMT_SHIFT 10 -@@ -350,6 +390,14 @@ do { \ +@@ -350,6 +390,14 @@ #define write_vpe_c0_vpecontrol(val) mttc0(1, 1, val) #define read_vpe_c0_vpeconf0() mftc0(1, 2) #define write_vpe_c0_vpeconf0(val) mttc0(1, 2, val) @@ -125,7 +125,7 @@ #define read_vpe_c0_count() mftc0(9, 0) #define write_vpe_c0_count(val) mttc0(9, 0, val) #define read_vpe_c0_status() mftc0(12, 0) -@@ -381,6 +429,12 @@ do { \ +@@ -381,6 +429,12 @@ #define write_tc_c0_tchalt(val) mttc0(2, 4, val) #define read_tc_c0_tccontext() mftc0(2, 5) #define write_tc_c0_tccontext(val) mttc0(2, 5, val) @@ -140,7 +140,7 @@ #define read_tc_gpr_sp() mftgpr(29) --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile -@@ -85,7 +85,8 @@ obj-$(CONFIG_MIPS32_O32) += binfmt_elfo3 +@@ -85,7 +85,8 @@ obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_PROC_FS) += proc.o @@ -254,7 +254,7 @@ /* * 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 @@ if ((read_tc_c0_tcbind() & TCBIND_CURVPE) == i) { printk(" VPE %d\n", i); printk(" VPEControl : %08lx\n", @@ -280,7 +280,7 @@ break; /* Next VPE */ } } -@@ -287,6 +357,9 @@ void mips_mt_set_cpuoptions(void) +@@ -287,6 +357,9 @@ printk("Mapped %ld ITC cells starting at 0x%08x\n", ((itcblkgrn & 0x7fe00000) >> 20), itc_base); } @@ -300,7 +300,7 @@ #include <asm/bootinfo.h> #include <asm/cpu.h> #include <asm/cpu-features.h> -@@ -108,3 +109,19 @@ const struct seq_operations cpuinfo_op = +@@ -110,3 +111,19 @@ .stop = c_stop, .show = show_cpuinfo, }; @@ -322,7 +322,7 @@ +} --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c -@@ -1335,6 +1335,13 @@ void smtc_get_new_mmu_context(struct mm_ +@@ -1334,6 +1334,13 @@ asid = asid_cache(cpu); do { @@ -338,7 +338,7 @@ flush_icache_all(); --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c -@@ -76,6 +76,58 @@ static struct kspd_notifications kspd_ev +@@ -76,6 +76,58 @@ static int kspd_events_reqd; #endif @@ -397,7 +397,7 @@ /* 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 +@@ -268,6 +320,13 @@ void *addr; #ifdef CONFIG_MIPS_VPE_LOADER_TOM @@ -411,7 +411,7 @@ /* * 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) +@@ -746,6 +805,12 @@ } /* Write the address we want it to start running from in the TCPC register. */ @@ -424,7 +424,7 @@ 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) +@@ -759,6 +824,20 @@ write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H); @@ -445,7 +445,7 @@ /* * 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 * +@@ -833,6 +912,9 @@ if ( (v->__start == 0) || (v->shared_ptr == NULL)) return -1; @@ -455,7 +455,7 @@ return 0; } -@@ -994,6 +1076,15 @@ static int vpe_elfload(struct vpe * v) +@@ -994,6 +1076,15 @@ (unsigned long)v->load_addr + v->len); if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) { @@ -471,7 +471,7 @@ 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, +@@ -1064,6 +1155,9 @@ struct vpe_notifications *not; struct vpe *v; int ret; @@ -481,10 +481,11 @@ if (minor != iminor(inode)) { /* assume only 1 device at the moment. */ -@@ -1090,6 +1184,12 @@ static int vpe_open(struct inode *inode, +@@ -1089,7 +1183,12 @@ + release_progmem(v->load_addr); cleanup_tc(get_tc(tclimit)); } - +- +#ifdef CONFIG_IFX_VPE_EXT + progsize = (vpe1_mem != 0) ? vpe1_mem : P_SIZE; + //printk("progsize = %x\n", progsize); @@ -494,14 +495,14 @@ /* this of-course trashes what was there before... */ v->pbuffer = vmalloc(P_SIZE); if (!v->pbuffer) { -@@ -1097,11 +1197,13 @@ static int vpe_open(struct inode *inode, +@@ -1097,11 +1196,14 @@ return -ENOMEM; } v->plen = P_SIZE; +#endif v->load_addr = NULL; v->len = 0; -- + +#if 0 v->uid = filp->f_cred->fsuid; v->gid = filp->f_cred->fsgid; @@ -509,7 +510,7 @@ #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) +@@ -1349,6 +1451,133 @@ cleanup_tc(get_tc(sp_id)); } #endif @@ -643,7 +644,7 @@ 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) +@@ -1430,6 +1659,18 @@ printk("VPE loader: not a MIPS MT capable processor\n"); return -ENODEV; } @@ -662,7 +663,7 @@ if (vpelimit == 0) { printk(KERN_WARNING "No VPEs reserved for AP/SP, not " -@@ -1474,10 +1715,12 @@ static int __init vpe_module_init(void) +@@ -1474,10 +1715,12 @@ mtflags = dmt(); vpflags = dvpe(); @@ -676,7 +677,7 @@ val = read_c0_mvpconf0(); hw_tcs = (val & MVPCONF0_PTC) + 1; -@@ -1489,6 +1732,7 @@ static int __init vpe_module_init(void) +@@ -1489,6 +1732,7 @@ * reschedule send IPIs or similar we might hang. */ clear_c0_mvpcontrol(MVPCONTROL_VPC); @@ -684,7 +685,7 @@ evpe(vpflags); emt(mtflags); local_irq_restore(flags); -@@ -1514,6 +1758,7 @@ static int __init vpe_module_init(void) +@@ -1514,6 +1758,7 @@ } v->ntcs = hw_tcs - tclimit; @@ -692,7 +693,7 @@ /* 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) +@@ -1582,6 +1827,7 @@ out_reenable: /* release config state */ clear_c0_mvpcontrol(MVPCONTROL_VPC); diff --git a/target/linux/lantiq/patches-2.6.39/260-ar9-cache-split.patch b/target/linux/lantiq/patches-2.6.39/260-ar9-cache-split.patch new file mode 100644 index 0000000..88d2a61 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/260-ar9-cache-split.patch @@ -0,0 +1,301 @@ +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1653,6 +1653,28 @@ + help + IFX included extensions in APRP + ++config IFX_VPE_CACHE_SPLIT ++ bool "IFX Cache Split Ways" ++ depends on IFX_VPE_EXT ++ help ++ IFX extension for reserving (splitting) cache ways among VPEs. You must ++ give kernel command line arguments vpe_icache_shared=0 or ++ vpe_dcache_shared=0 to enable splitting of icache or dcache ++ respectively. Then you can specify which cache ways should be ++ assigned to which VPE. There are total 8 cache ways, 4 each ++ for dcache and icache: dcache_way0, dcache_way1,dcache_way2, ++ dcache_way3 and icache_way0,icache_way1, icache_way2,icache_way3. ++ ++ For example, if you specify vpe_icache_shared=0 and icache_way2=1, ++ then the 3rd icache way will be assigned to VPE0 and denied in VPE1. ++ ++ For icache, software is required to make at least one cache way available ++ for a VPE at all times i.e., one can't assign all the icache ways to one ++ VPE. ++ ++ By default, vpe_dcache_shared and vpe_icache_shared are set to 1 ++ (i.e., both icache and dcache are shared among VPEs) ++ + config PERFCTRS + bool "34K Performance counters" + depends on MIPS_MT && PROC_FS +--- a/arch/mips/kernel/vpe.c ++++ b/arch/mips/kernel/vpe.c +@@ -129,6 +129,13 @@ + EXPORT_SYMBOL(vpe1_wdog_timeout); + + #endif ++ ++#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */ ++extern int vpe_icache_shared,vpe_dcache_shared; ++extern int icache_way0,icache_way1,icache_way2,icache_way3; ++extern int dcache_way0,dcache_way1,dcache_way2,dcache_way3; ++#endif ++ + /* grab the likely amount of memory we will need. */ + #ifdef CONFIG_MIPS_VPE_LOADER_TOM + #define P_SIZE (2 * 1024 * 1024) +@@ -867,6 +874,65 @@ + /* enable this VPE */ + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); + ++#ifdef CONFIG_IFX_VPE_CACHE_SPLIT ++ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ) { ++ ++ /* PCP bit must be 1 to split the cache */ ++ if(read_c0_mvpconf0() & MVPCONF0_PCP) { ++ ++ if ( !vpe_icache_shared ){ ++ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_ICS); ++ ++ /* ++ * If any cache way is 1, then that way is denied ++ * in VPE1. Otherwise assign that way to VPE1. ++ */ ++ if (!icache_way0) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX0 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX0 ); ++ if (!icache_way1) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX1 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX1 ); ++ if (!icache_way2) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX2 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX2 ); ++ if (!icache_way3) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX3 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX3 ); ++ } ++ ++ if ( !vpe_dcache_shared ) { ++ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_DCS); ++ ++ /* ++ * If any cache way is 1, then that way is denied ++ * in VPE1. Otherwise assign that way to VPE1. ++ */ ++ if (!dcache_way0) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX0 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX0 ); ++ if (!dcache_way1) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX1 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX1 ); ++ if (!dcache_way2) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX2 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX2 ); ++ if (!dcache_way3) ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX3 ); ++ else ++ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX3 ); ++ } ++ } ++ } ++#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */ ++ + /* clear out any left overs from a previous program */ + write_vpe_c0_status(0); + write_vpe_c0_cause(0); +--- a/arch/mips/mm/c-r4k.c ++++ b/arch/mips/mm/c-r4k.c +@@ -1348,6 +1348,106 @@ + __setup("coherentio", setcoherentio); + #endif + ++#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */ ++ ++#include <asm/mipsmtregs.h> ++ ++/* ++ * By default, vpe_icache_shared and vpe_dcache_shared ++ * values are 1 i.e., both icache and dcache are shared ++ * among the VPEs. ++ */ ++ ++int vpe_icache_shared = 1; ++static int __init vpe_icache_shared_val(char *str) ++{ ++ get_option(&str, &vpe_icache_shared); ++ return 1; ++} ++__setup("vpe_icache_shared=", vpe_icache_shared_val); ++EXPORT_SYMBOL(vpe_icache_shared); ++ ++int vpe_dcache_shared = 1; ++static int __init vpe_dcache_shared_val(char *str) ++{ ++ get_option(&str, &vpe_dcache_shared); ++ return 1; ++} ++__setup("vpe_dcache_shared=", vpe_dcache_shared_val); ++EXPORT_SYMBOL(vpe_dcache_shared); ++ ++/* ++ * Software is required to make atleast one icache ++ * way available for a VPE at all times i.e., one ++ * can't assign all the icache ways to one VPE. ++ */ ++ ++int icache_way0 = 0; ++static int __init icache_way0_val(char *str) ++{ ++ get_option(&str, &icache_way0); ++ return 1; ++} ++__setup("icache_way0=", icache_way0_val); ++ ++int icache_way1 = 0; ++static int __init icache_way1_val(char *str) ++{ ++ get_option(&str, &icache_way1); ++ return 1; ++} ++__setup("icache_way1=", icache_way1_val); ++ ++int icache_way2 = 0; ++static int __init icache_way2_val(char *str) ++{ ++ get_option(&str, &icache_way2); ++ return 1; ++} ++__setup("icache_way2=", icache_way2_val); ++ ++int icache_way3 = 0; ++static int __init icache_way3_val(char *str) ++{ ++ get_option(&str, &icache_way3); ++ return 1; ++} ++__setup("icache_way3=", icache_way3_val); ++ ++int dcache_way0 = 0; ++static int __init dcache_way0_val(char *str) ++{ ++ get_option(&str, &dcache_way0); ++ return 1; ++} ++__setup("dcache_way0=", dcache_way0_val); ++ ++int dcache_way1 = 0; ++static int __init dcache_way1_val(char *str) ++{ ++ get_option(&str, &dcache_way1); ++ return 1; ++} ++__setup("dcache_way1=", dcache_way1_val); ++ ++int dcache_way2 = 0; ++static int __init dcache_way2_val(char *str) ++{ ++ get_option(&str, &dcache_way2); ++ return 1; ++} ++__setup("dcache_way2=", dcache_way2_val); ++ ++int dcache_way3 = 0; ++static int __init dcache_way3_val(char *str) ++{ ++ get_option(&str, &dcache_way3); ++ return 1; ++} ++__setup("dcache_way3=", dcache_way3_val); ++ ++#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */ ++ + void __cpuinit r4k_cache_init(void) + { + extern void build_clear_page(void); +@@ -1367,6 +1467,78 @@ + break; + } + ++#ifdef CONFIG_IFX_VPE_CACHE_SPLIT ++ /* ++ * We split the cache ways appropriately among the VPEs ++ * based on cache ways values we received as command line ++ * arguments ++ */ ++ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ){ ++ ++ /* PCP bit must be 1 to split the cache */ ++ if(read_c0_mvpconf0() & MVPCONF0_PCP) { ++ ++ /* Set CPA bit which enables us to modify VPEOpt register */ ++ write_c0_mvpcontrol((read_c0_mvpcontrol()) | MVPCONTROL_CPA); ++ ++ if ( !vpe_icache_shared ){ ++ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_ICS); ++ /* ++ * If any cache way is 1, then that way is denied ++ * in VPE0. Otherwise assign that way to VPE0. ++ */ ++ printk(KERN_DEBUG "icache is split\n"); ++ printk(KERN_DEBUG "icache_way0=%d icache_way1=%d icache_way2=%d icache_way3=%d\n", ++ icache_way0, icache_way1,icache_way2, icache_way3); ++ if (icache_way0) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX0 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX0 ); ++ if (icache_way1) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX1 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX1 ); ++ if (icache_way2) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX2 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX2 ); ++ if (icache_way3) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX3 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX3 ); ++ } ++ ++ if ( !vpe_dcache_shared ) { ++ /* ++ * If any cache way is 1, then that way is denied ++ * in VPE0. Otherwise assign that way to VPE0. ++ */ ++ printk(KERN_DEBUG "dcache is split\n"); ++ printk(KERN_DEBUG "dcache_way0=%d dcache_way1=%d dcache_way2=%d dcache_way3=%d\n", ++ dcache_way0, dcache_way1, dcache_way2, dcache_way3); ++ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_DCS); ++ if (dcache_way0) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX0 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX0 ); ++ if (dcache_way1) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX1 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX1 ); ++ if (dcache_way2) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX2 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX2 ); ++ if (dcache_way3) ++ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX3 ); ++ else ++ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX3 ); ++ } ++ } ++ } ++ ++#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */ ++ + probe_pcache(); + setup_scache(); + diff --git a/target/linux/lantiq/patches-2.6.39/270-m25p80-fast-read.patch b/target/linux/lantiq/patches-2.6.39/270-m25p80-fast-read.patch new file mode 100644 index 0000000..061ae1c --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/270-m25p80-fast-read.patch @@ -0,0 +1,8 @@ +--- a/drivers/mtd/devices/m25p80.c ++++ b/drivers/mtd/devices/m25p80.c +@@ -1,3 +1,5 @@ ++ ++ + /* + * MTD SPI driver for ST M25Pxx (and similar) serial flash chips + * diff --git a/target/linux/lantiq/patches-2.6.39/400-spi1.patch b/target/linux/lantiq/patches-2.6.39/400-spi1.patch new file mode 100644 index 0000000..61bfa2e --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/400-spi1.patch @@ -0,0 +1,36 @@ +From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +Date: Thu, 3 Mar 2011 17:15:58 +0000 (+0100) +Subject: MIPS: lantiq: Add platform data for Lantiq SoC SPI controller driver +X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=3d21b04682ae8eb1c1965aba39d1796e8c5ad84b;hp=06b420500fe98e37662837e78d8e51aead8aea81 + +MIPS: lantiq: Add platform data for Lantiq SoC SPI controller driver + +Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +--- + +--- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h ++++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h +@@ -50,4 +50,13 @@ + int mii_mode; + }; + ++ ++struct ltq_spi_platform_data { ++ u16 num_chipselect; ++}; ++ ++struct ltq_spi_controller_data { ++ unsigned gpio; ++}; ++ + #endif +--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h ++++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +@@ -75,6 +75,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/target/linux/lantiq/patches-2.6.39/410-spi2.patch b/target/linux/lantiq/patches-2.6.39/410-spi2.patch new file mode 100644 index 0000000..d291e09 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/410-spi2.patch @@ -0,0 +1,1103 @@ +From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +Date: Thu, 3 Mar 2011 17:15:30 +0000 (+0100) +Subject: SPI: lantiq: Add driver for Lantiq SoC SPI controller +X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=653c95b8b9066c9c6ac08bd64d0ceee439e9fd90;hp=3d21b04682ae8eb1c1965aba39d1796e8c5ad84b + +SPI: lantiq: Add driver for Lantiq SoC SPI controller + +Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +--- + +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -133,6 +133,14 @@ + This enables using the Freescale i.MX SPI controllers in master + mode. + ++config SPI_LANTIQ ++ tristate "Lantiq SoC SPI controller" ++ depends on SOC_LANTIQ_XWAY ++ select SPI_BITBANG ++ help ++ This driver supports the Lantiq SoC SPI controller in master ++ mode. ++ + config SPI_LM70_LLP + tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)" + depends on PARPORT && EXPERIMENTAL +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -20,6 +20,7 @@ + obj-$(CONFIG_SPI_GPIO) += spi_gpio.o + obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o + obj-$(CONFIG_SPI_IMX) += spi_imx.o ++obj-$(CONFIG_SPI_LANTIQ) += spi_lantiq.o + obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o + obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o + obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o +--- /dev/null ++++ b/drivers/spi/spi_lantiq.c +@@ -0,0 +1,1063 @@ ++/* ++ * Lantiq SoC SPI controller ++ * ++ * Copyright (C) 2011 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/workqueue.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/completion.h> ++#include <linux/spinlock.h> ++#include <linux/err.h> ++#include <linux/clk.h> ++#include <linux/gpio.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/spi_bitbang.h> ++ ++#include <xway.h> ++#include <xway_irq.h> ++#include <lantiq_platform.h> ++ ++#define LTQ_SPI_CLC 0x00 /* Clock control */ ++#define LTQ_SPI_PISEL 0x04 /* Port input select */ ++#define LTQ_SPI_ID 0x08 /* Identification */ ++#define LTQ_SPI_CON 0x10 /* Control */ ++#define LTQ_SPI_STAT 0x14 /* Status */ ++#define LTQ_SPI_WHBSTATE 0x18 /* Write HW modified state */ ++#define LTQ_SPI_TB 0x20 /* Transmit buffer */ ++#define LTQ_SPI_RB 0x24 /* Receive buffer */ ++#define LTQ_SPI_RXFCON 0x30 /* Receive FIFO control */ ++#define LTQ_SPI_TXFCON 0x34 /* Transmit FIFO control */ ++#define LTQ_SPI_FSTAT 0x38 /* FIFO status */ ++#define LTQ_SPI_BRT 0x40 /* Baudrate timer */ ++#define LTQ_SPI_BRSTAT 0x44 /* Baudrate timer status */ ++#define LTQ_SPI_SFCON 0x60 /* Serial frame control */ ++#define LTQ_SPI_SFSTAT 0x64 /* Serial frame status */ ++#define LTQ_SPI_GPOCON 0x70 /* General purpose output control */ ++#define LTQ_SPI_GPOSTAT 0x74 /* General purpose output status */ ++#define LTQ_SPI_FGPO 0x78 /* Forced general purpose output */ ++#define LTQ_SPI_RXREQ 0x80 /* Receive request */ ++#define LTQ_SPI_RXCNT 0x84 /* Receive count */ ++#define LTQ_SPI_DMACON 0xEC /* DMA control */ ++#define LTQ_SPI_IRNEN 0xF4 /* Interrupt node enable */ ++#define LTQ_SPI_IRNICR 0xF8 /* Interrupt node interrupt capture */ ++#define LTQ_SPI_IRNCR 0xFC /* Interrupt node control */ ++ ++#define LTQ_SPI_CLC_SMC_SHIFT 16 /* Clock divider for sleep mode */ ++#define LTQ_SPI_CLC_SMC_MASK 0xFF ++#define LTQ_SPI_CLC_RMC_SHIFT 8 /* Clock divider for normal run mode */ ++#define LTQ_SPI_CLC_RMC_MASK 0xFF ++#define LTQ_SPI_CLC_DISS BIT(1) /* Disable status bit */ ++#define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */ ++ ++#define LTQ_SPI_ID_TXFS_SHIFT 24 /* Implemented TX FIFO size */ ++#define LTQ_SPI_ID_TXFS_MASK 0x3F ++#define LTQ_SPI_ID_RXFS_SHIFT 16 /* Implemented RX FIFO size */ ++#define LTQ_SPI_ID_RXFS_MASK 0x3F ++#define LTQ_SPI_ID_REV_MASK 0x1F /* Hardware revision number */ ++#define LTQ_SPI_ID_CFG BIT(5) /* DMA interface support */ ++ ++#define LTQ_SPI_CON_BM_SHIFT 16 /* Data width selection */ ++#define LTQ_SPI_CON_BM_MASK 0x1F ++#define LTQ_SPI_CON_EM BIT(24) /* Echo mode */ ++#define LTQ_SPI_CON_IDLE BIT(23) /* Idle bit value */ ++#define LTQ_SPI_CON_ENBV BIT(22) /* Enable byte valid control */ ++#define LTQ_SPI_CON_RUEN BIT(12) /* Receive underflow error enable */ ++#define LTQ_SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */ ++#define LTQ_SPI_CON_AEN BIT(10) /* Abort error enable */ ++#define LTQ_SPI_CON_REN BIT(9) /* Receive overflow error enable */ ++#define LTQ_SPI_CON_TEN BIT(8) /* Transmit overflow error enable */ ++#define LTQ_SPI_CON_LB BIT(7) /* Loopback control */ ++#define LTQ_SPI_CON_PO BIT(6) /* Clock polarity control */ ++#define LTQ_SPI_CON_PH BIT(5) /* Clock phase control */ ++#define LTQ_SPI_CON_HB BIT(4) /* Heading control */ ++#define LTQ_SPI_CON_RXOFF BIT(1) /* Switch receiver off */ ++#define LTQ_SPI_CON_TXOFF BIT(0) /* Switch transmitter off */ ++ ++#define LTQ_SPI_STAT_RXBV_MASK 0x7 ++#define LTQ_SPI_STAT_RXBV_SHIFT 28 ++#define LTQ_SPI_STAT_BSY BIT(13) /* Busy flag */ ++#define LTQ_SPI_STAT_RUE BIT(12) /* Receive underflow error flag */ ++#define LTQ_SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */ ++#define LTQ_SPI_STAT_AE BIT(10) /* Abort error flag */ ++#define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */ ++#define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */ ++#define LTQ_SPI_STAT_MS BIT(1) /* Master/slave select bit */ ++#define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */ ++ ++#define LTQ_SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */ ++#define LTQ_SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */ ++#define LTQ_SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */ ++#define LTQ_SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */ ++#define LTQ_SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */ ++#define LTQ_SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */ ++#define LTQ_SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */ ++#define LTQ_SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */ ++#define LTQ_SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */ ++#define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */ ++#define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */ ++#define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */ ++#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */ ++#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */ ++#define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */ ++#define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */ ++#define LTQ_SPI_WHBSTATE_CLR_ERRORS 0x0F50 ++ ++#define LTQ_SPI_RXFCON_RXFITL_SHIFT 8 /* FIFO interrupt trigger level */ ++#define LTQ_SPI_RXFCON_RXFITL_MASK 0x3F ++#define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */ ++#define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */ ++ ++#define LTQ_SPI_TXFCON_TXFITL_SHIFT 8 /* FIFO interrupt trigger level */ ++#define LTQ_SPI_TXFCON_TXFITL_MASK 0x3F ++#define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */ ++#define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */ ++ ++#define LTQ_SPI_FSTAT_RXFFL_MASK 0x3f ++#define LTQ_SPI_FSTAT_RXFFL_SHIFT 0 ++#define LTQ_SPI_FSTAT_TXFFL_MASK 0x3f ++#define LTQ_SPI_FSTAT_TXFFL_SHIFT 8 ++ ++#define LTQ_SPI_GPOCON_ISCSBN_SHIFT 8 ++#define LTQ_SPI_GPOCON_INVOUTN_SHIFT 0 ++ ++#define LTQ_SPI_FGPO_SETOUTN_SHIFT 8 ++#define LTQ_SPI_FGPO_CLROUTN_SHIFT 0 ++ ++#define LTQ_SPI_RXREQ_RXCNT_MASK 0xFFFF /* Receive count value */ ++#define LTQ_SPI_RXCNT_TODO_MASK 0xFFFF /* Recevie to-do value */ ++ ++#define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */ ++#define LTQ_SPI_IRNEN_E BIT(2) /* Error end interrupt request */ ++#define LTQ_SPI_IRNEN_T BIT(1) /* Transmit end interrupt request */ ++#define LTQ_SPI_IRNEN_R BIT(0) /* Receive end interrupt request */ ++#define LTQ_SPI_IRNEN_ALL 0xF ++ ++/* Hard-wired GPIOs used by SPI controller */ ++#define LTQ_SPI_GPIO_DI 16 ++#define LTQ_SPI_GPIO_DO 17 ++#define LTQ_SPI_GPIO_CLK 18 ++ ++struct ltq_spi { ++ struct spi_bitbang bitbang; ++ struct completion done; ++ spinlock_t lock; ++ ++ struct device *dev; ++ void __iomem *base; ++ struct clk *clk; ++ ++ int status; ++ int irq[3]; ++ ++ const u8 *tx; ++ u8 *rx; ++ u32 tx_cnt; ++ u32 rx_cnt; ++ u32 len; ++ struct spi_transfer *curr_transfer; ++ ++ u32 (*get_tx) (struct ltq_spi *); ++ ++ u16 txfs; ++ u16 rxfs; ++ unsigned dma_support:1; ++ unsigned cfg_mode:1; ++ ++}; ++ ++struct ltq_spi_controller_state { ++ void (*cs_activate) (struct spi_device *); ++ void (*cs_deactivate) (struct spi_device *); ++}; ++ ++struct ltq_spi_irq_map { ++ char *name; ++ irq_handler_t handler; ++}; ++ ++struct ltq_spi_cs_gpio_map { ++ unsigned gpio; ++ unsigned altsel0; ++ unsigned altsel1; ++}; ++ ++static inline struct ltq_spi *ltq_spi_to_hw(struct spi_device *spi) ++{ ++ return spi_master_get_devdata(spi->master); ++} ++ ++static inline u32 ltq_spi_reg_read(struct ltq_spi *hw, u32 reg) ++{ ++ return ioread32be(hw->base + reg); ++} ++ ++static inline void ltq_spi_reg_write(struct ltq_spi *hw, u32 val, u32 reg) ++{ ++ iowrite32be(val, hw->base + reg); ++} ++ ++static inline void ltq_spi_reg_setbit(struct ltq_spi *hw, u32 bits, u32 reg) ++{ ++ u32 val; ++ ++ val = ltq_spi_reg_read(hw, reg); ++ val |= bits; ++ ltq_spi_reg_write(hw, val, reg); ++} ++ ++static inline void ltq_spi_reg_clearbit(struct ltq_spi *hw, u32 bits, u32 reg) ++{ ++ u32 val; ++ ++ val = ltq_spi_reg_read(hw, reg); ++ val &= ~bits; ++ ltq_spi_reg_write(hw, val, reg); ++} ++ ++static void ltq_spi_hw_enable(struct ltq_spi *hw) ++{ ++ u32 clc; ++ ++ /* Power-up mdule */ ++ ltq_pmu_enable(PMU_SPI); ++ ++ /* ++ * Set clock divider for run mode to 1 to ++ * run at same frequency as FPI bus ++ */ ++ clc = (1 << LTQ_SPI_CLC_RMC_SHIFT); ++ ltq_spi_reg_write(hw, clc, LTQ_SPI_CLC); ++} ++ ++static void ltq_spi_hw_disable(struct ltq_spi *hw) ++{ ++ /* Set clock divider to 0 and set module disable bit */ ++ ltq_spi_reg_write(hw, LTQ_SPI_CLC_DISS, LTQ_SPI_CLC); ++ ++ /* Power-down mdule */ ++ ltq_pmu_disable(PMU_SPI); ++} ++ ++static void ltq_spi_reset_fifos(struct ltq_spi *hw) ++{ ++ u32 val; ++ ++ /* ++ * Enable and flush FIFOs. Set interrupt trigger level to ++ * half of FIFO count implemented in hardware. ++ */ ++ if (hw->txfs > 1) { ++ val = hw->txfs << (LTQ_SPI_TXFCON_TXFITL_SHIFT - 1); ++ val |= LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU; ++ ltq_spi_reg_write(hw, val, LTQ_SPI_TXFCON); ++ } ++ ++ if (hw->rxfs > 1) { ++ val = hw->rxfs << (LTQ_SPI_RXFCON_RXFITL_SHIFT - 1); ++ val |= LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU; ++ ltq_spi_reg_write(hw, val, LTQ_SPI_RXFCON); ++ } ++} ++ ++static inline int ltq_spi_wait_ready(struct ltq_spi *hw) ++{ ++ u32 stat; ++ unsigned long timeout; ++ ++ timeout = jiffies + msecs_to_jiffies(200); ++ ++ do { ++ stat = ltq_spi_reg_read(hw, LTQ_SPI_STAT); ++ if (!(stat & LTQ_SPI_STAT_BSY)) ++ return 0; ++ ++ cond_resched(); ++ } while (!time_after_eq(jiffies, timeout)); ++ ++ dev_err(hw->dev, "SPI wait ready timed out\n"); ++ ++ return -ETIMEDOUT; ++} ++ ++static void ltq_spi_config_mode_set(struct ltq_spi *hw) ++{ ++ if (hw->cfg_mode) ++ return; ++ ++ /* ++ * Putting the SPI module in config mode is only safe if no ++ * transfer is in progress as indicated by busy flag STATE.BSY. ++ */ ++ if (ltq_spi_wait_ready(hw)) { ++ ltq_spi_reset_fifos(hw); ++ hw->status = -ETIMEDOUT; ++ } ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLREN, LTQ_SPI_WHBSTATE); ++ ++ hw->cfg_mode = 1; ++} ++ ++static void ltq_spi_run_mode_set(struct ltq_spi *hw) ++{ ++ if (!hw->cfg_mode) ++ return; ++ ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETEN, LTQ_SPI_WHBSTATE); ++ ++ hw->cfg_mode = 0; ++} ++ ++static u32 ltq_spi_tx_word_u8(struct ltq_spi *hw) ++{ ++ const u8 *tx = hw->tx; ++ u32 data = *tx++; ++ ++ hw->tx_cnt++; ++ hw->tx++; ++ ++ return data; ++} ++ ++static u32 ltq_spi_tx_word_u16(struct ltq_spi *hw) ++{ ++ const u16 *tx = (u16 *) hw->tx; ++ u32 data = *tx++; ++ ++ hw->tx_cnt += 2; ++ hw->tx += 2; ++ ++ return data; ++} ++ ++static u32 ltq_spi_tx_word_u32(struct ltq_spi *hw) ++{ ++ const u32 *tx = (u32 *) hw->tx; ++ u32 data = *tx++; ++ ++ hw->tx_cnt += 4; ++ hw->tx += 4; ++ ++ return data; ++} ++ ++static void ltq_spi_bits_per_word_set(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 bm; ++ u8 bits_per_word = spi->bits_per_word; ++ ++ /* ++ * Use either default value of SPI device or value ++ * from current transfer. ++ */ ++ if (hw->curr_transfer && hw->curr_transfer->bits_per_word) ++ bits_per_word = hw->curr_transfer->bits_per_word; ++ ++ if (bits_per_word <= 8) ++ hw->get_tx = ltq_spi_tx_word_u8; ++ else if (bits_per_word <= 16) ++ hw->get_tx = ltq_spi_tx_word_u16; ++ else if (bits_per_word <= 32) ++ hw->get_tx = ltq_spi_tx_word_u32; ++ ++ /* CON.BM value = bits_per_word - 1 */ ++ bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_SHIFT; ++ ++ ltq_spi_reg_clearbit(hw, LTQ_SPI_CON_BM_MASK << ++ LTQ_SPI_CON_BM_SHIFT, LTQ_SPI_CON); ++ ltq_spi_reg_setbit(hw, bm, LTQ_SPI_CON); ++} ++ ++static void ltq_spi_speed_set(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 br, max_speed_hz, spi_clk; ++ u32 speed_hz = spi->max_speed_hz; ++ ++ /* ++ * Use either default value of SPI device or value ++ * from current transfer. ++ */ ++ if (hw->curr_transfer && hw->curr_transfer->speed_hz) ++ speed_hz = hw->curr_transfer->speed_hz; ++ ++ /* ++ * 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); ++ ++ /* ++ * Maximum SPI clock frequency in master mode is half of ++ * SPI module clock frequency. Maximum reload value of ++ * baudrate generator BR is 2^16. ++ */ ++ max_speed_hz = spi_clk / 2; ++ if (speed_hz >= max_speed_hz) ++ br = 0; ++ else ++ br = (max_speed_hz / speed_hz) - 1; ++ ++ if (br > 0xFFFF) ++ br = 0xFFFF; ++ ++ ltq_spi_reg_write(hw, br, LTQ_SPI_BRT); ++} ++ ++static void ltq_spi_clockmode_set(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 con; ++ ++ con = ltq_spi_reg_read(hw, LTQ_SPI_CON); ++ ++ /* ++ * SPI mode mapping in CON register: ++ * Mode CPOL CPHA CON.PO CON.PH ++ * 0 0 0 0 1 ++ * 1 0 1 0 0 ++ * 2 1 0 1 1 ++ * 3 1 1 1 0 ++ */ ++ if (spi->mode & SPI_CPHA) ++ con &= ~LTQ_SPI_CON_PH; ++ else ++ con |= LTQ_SPI_CON_PH; ++ ++ if (spi->mode & SPI_CPOL) ++ con |= LTQ_SPI_CON_PO; ++ else ++ con &= ~LTQ_SPI_CON_PO; ++ ++ /* Set heading control */ ++ if (spi->mode & SPI_LSB_FIRST) ++ con &= ~LTQ_SPI_CON_HB; ++ else ++ con |= LTQ_SPI_CON_HB; ++ ++ ltq_spi_reg_write(hw, con, LTQ_SPI_CON); ++} ++ ++static void ltq_spi_xmit_set(struct ltq_spi *hw, struct spi_transfer *t) ++{ ++ u32 con; ++ ++ con = ltq_spi_reg_read(hw, LTQ_SPI_CON); ++ ++ if (t) { ++ if (t->tx_buf && t->rx_buf) { ++ con &= ~(LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF); ++ } else if (t->rx_buf) { ++ con &= ~LTQ_SPI_CON_RXOFF; ++ con |= LTQ_SPI_CON_TXOFF; ++ } else if (t->tx_buf) { ++ con &= ~LTQ_SPI_CON_TXOFF; ++ con |= LTQ_SPI_CON_RXOFF; ++ } ++ } else ++ con |= (LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF); ++ ++ ltq_spi_reg_write(hw, con, LTQ_SPI_CON); ++} ++ ++static void ltq_spi_gpio_cs_activate(struct spi_device *spi) ++{ ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ int val = spi->mode & SPI_CS_HIGH ? 1 : 0; ++ ++ gpio_set_value(cdata->gpio, val); ++} ++ ++static void ltq_spi_gpio_cs_deactivate(struct spi_device *spi) ++{ ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ int val = spi->mode & SPI_CS_HIGH ? 0 : 1; ++ ++ gpio_set_value(cdata->gpio, val); ++} ++ ++static void ltq_spi_internal_cs_activate(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 fgpo; ++ ++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_CLROUTN_SHIFT)); ++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); ++} ++ ++static void ltq_spi_internal_cs_deactivate(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 fgpo; ++ ++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT)); ++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); ++} ++ ++static void ltq_spi_chipselect(struct spi_device *spi, int cs) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ struct ltq_spi_controller_state *cstate = spi->controller_state; ++ ++ switch (cs) { ++ case BITBANG_CS_ACTIVE: ++ ltq_spi_bits_per_word_set(spi); ++ ltq_spi_speed_set(spi); ++ ltq_spi_clockmode_set(spi); ++ ltq_spi_run_mode_set(hw); ++ ++ cstate->cs_activate(spi); ++ break; ++ ++ case BITBANG_CS_INACTIVE: ++ cstate->cs_deactivate(spi); ++ ++ ltq_spi_config_mode_set(hw); ++ ++ break; ++ } ++} ++ ++static int ltq_spi_setup_transfer(struct spi_device *spi, ++ struct spi_transfer *t) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u8 bits_per_word = spi->bits_per_word; ++ ++ hw->curr_transfer = t; ++ ++ if (t && t->bits_per_word) ++ bits_per_word = t->bits_per_word; ++ ++ if (bits_per_word > 32) ++ return -EINVAL; ++ ++ ltq_spi_config_mode_set(hw); ++ ++ return 0; ++} ++ ++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 }, ++}; ++ ++static int ltq_spi_setup(struct spi_device *spi) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ struct ltq_spi_controller_state *cstate; ++ u32 gpocon, fgpo; ++ int ret; ++ ++ /* Set default word length to 8 if not set */ ++ if (!spi->bits_per_word) ++ spi->bits_per_word = 8; ++ ++ if (spi->bits_per_word > 32) ++ return -EINVAL; ++ ++ if (!spi->controller_state) { ++ cstate = kzalloc(sizeof(struct ltq_spi_controller_state), ++ GFP_KERNEL); ++ if (!cstate) ++ return -ENOMEM; ++ ++ spi->controller_state = cstate; ++ } else ++ return 0; ++ ++ /* ++ * Up to six GPIOs can be connected to the SPI module ++ * via GPIO alternate function to control the chip select lines. ++ * For more flexibility in board layout this driver can also control ++ * the CS lines via GPIO API. If GPIOs should be used, board setup code ++ * have to register the SPI device with struct ltq_spi_controller_data ++ * attached. ++ */ ++ if (cdata && cdata->gpio) { ++ ret = gpio_request(cdata->gpio, "spi-cs"); ++ if (ret) ++ return -EBUSY; ++ ++ ret = spi->mode & SPI_CS_HIGH ? 0 : 1; ++ gpio_direction_output(cdata->gpio, ret); ++ ++ 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, ++ 1, "spi-cs"); ++ if (ret) ++ return -EBUSY; ++ ++ gpocon = (1 << (spi->chip_select + ++ LTQ_SPI_GPOCON_ISCSBN_SHIFT)); ++ ++ if (spi->mode & SPI_CS_HIGH) ++ gpocon |= (1 << spi->chip_select); ++ ++ fgpo = (1 << (spi->chip_select + LTQ_SPI_FGPO_SETOUTN_SHIFT)); ++ ++ ltq_spi_reg_setbit(hw, gpocon, LTQ_SPI_GPOCON); ++ ltq_spi_reg_setbit(hw, fgpo, LTQ_SPI_FGPO); ++ ++ cstate->cs_activate = ltq_spi_internal_cs_activate; ++ cstate->cs_deactivate = ltq_spi_internal_cs_deactivate; ++ } ++ ++ return 0; ++} ++ ++static void ltq_spi_cleanup(struct spi_device *spi) ++{ ++ struct ltq_spi_controller_data *cdata = spi->controller_data; ++ struct ltq_spi_controller_state *cstate = spi->controller_state; ++ unsigned gpio; ++ ++ if (cdata && cdata->gpio) ++ gpio = cdata->gpio; ++ else ++ gpio = ltq_spi_cs[spi->chip_select].gpio; ++ ++ gpio_free(gpio); ++ kfree(cstate); ++} ++ ++static void ltq_spi_txfifo_write(struct ltq_spi *hw) ++{ ++ u32 fstat, data; ++ u16 fifo_space; ++ ++ /* Determine how much FIFOs are free for TX data */ ++ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT); ++ fifo_space = hw->txfs - ((fstat >> LTQ_SPI_FSTAT_TXFFL_SHIFT) & ++ LTQ_SPI_FSTAT_TXFFL_MASK); ++ ++ if (!fifo_space) ++ return; ++ ++ while (hw->tx_cnt < hw->len && fifo_space) { ++ data = hw->get_tx(hw); ++ ltq_spi_reg_write(hw, data, LTQ_SPI_TB); ++ fifo_space--; ++ } ++} ++ ++static void ltq_spi_rxfifo_read(struct ltq_spi *hw) ++{ ++ u32 fstat, data, *rx32; ++ u16 fifo_fill; ++ u8 rxbv, shift, *rx8; ++ ++ /* Determine how much FIFOs are filled with RX data */ ++ fstat = ltq_spi_reg_read(hw, LTQ_SPI_FSTAT); ++ fifo_fill = ((fstat >> LTQ_SPI_FSTAT_RXFFL_SHIFT) ++ & LTQ_SPI_FSTAT_RXFFL_MASK); ++ ++ if (!fifo_fill) ++ return; ++ ++ /* ++ * The 32 bit FIFO is always used completely independent from the ++ * bits_per_word value. Thus four bytes have to be read at once ++ * per FIFO. ++ */ ++ rx32 = (u32 *) hw->rx; ++ while (hw->len - hw->rx_cnt >= 4 && fifo_fill) { ++ *rx32++ = ltq_spi_reg_read(hw, LTQ_SPI_RB); ++ hw->rx_cnt += 4; ++ hw->rx += 4; ++ fifo_fill--; ++ } ++ ++ /* ++ * If there are remaining bytes, read byte count from STAT.RXBV ++ * register and read the data byte-wise. ++ */ ++ while (fifo_fill && hw->rx_cnt < hw->len) { ++ rxbv = (ltq_spi_reg_read(hw, LTQ_SPI_STAT) >> ++ LTQ_SPI_STAT_RXBV_SHIFT) & LTQ_SPI_STAT_RXBV_MASK; ++ data = ltq_spi_reg_read(hw, LTQ_SPI_RB); ++ ++ shift = (rxbv - 1) * 8; ++ rx8 = hw->rx; ++ ++ while (rxbv) { ++ *rx8++ = (data >> shift) & 0xFF; ++ rxbv--; ++ shift -= 8; ++ hw->rx_cnt++; ++ hw->rx++; ++ } ++ ++ fifo_fill--; ++ } ++} ++ ++static void ltq_spi_rxreq_set(struct ltq_spi *hw) ++{ ++ u32 rxreq, rxreq_max, rxtodo; ++ ++ rxtodo = ltq_spi_reg_read(hw, LTQ_SPI_RXCNT) & LTQ_SPI_RXCNT_TODO_MASK; ++ ++ /* ++ * In RX-only mode the serial clock is activated only after writing ++ * the expected amount of RX bytes into RXREQ register. ++ * To avoid receive overflows at high clocks it is better to request ++ * only the amount of bytes that fits into all FIFOs. This value ++ * depends on the FIFO size implemented in hardware. ++ */ ++ rxreq = hw->len - hw->rx_cnt; ++ rxreq_max = hw->rxfs << 2; ++ rxreq = min(rxreq_max, rxreq); ++ ++ if (!rxtodo && rxreq) ++ ltq_spi_reg_write(hw, rxreq, LTQ_SPI_RXREQ); ++} ++ ++static inline void ltq_spi_complete(struct ltq_spi *hw) ++{ ++ complete(&hw->done); ++} ++ ++irqreturn_t ltq_spi_tx_irq(int irq, void *data) ++{ ++ struct ltq_spi *hw = data; ++ unsigned long flags; ++ int completed = 0; ++ ++ spin_lock_irqsave(&hw->lock, flags); ++ ++ if (hw->tx_cnt < hw->len) ++ ltq_spi_txfifo_write(hw); ++ ++ if (hw->tx_cnt == hw->len) ++ completed = 1; ++ ++ spin_unlock_irqrestore(&hw->lock, flags); ++ ++ if (completed) ++ ltq_spi_complete(hw); ++ ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t ltq_spi_rx_irq(int irq, void *data) ++{ ++ struct ltq_spi *hw = data; ++ unsigned long flags; ++ int completed = 0; ++ ++ spin_lock_irqsave(&hw->lock, flags); ++ ++ if (hw->rx_cnt < hw->len) { ++ ltq_spi_rxfifo_read(hw); ++ ++ if (hw->tx && hw->tx_cnt < hw->len) ++ ltq_spi_txfifo_write(hw); ++ } ++ ++ if (hw->rx_cnt == hw->len) ++ completed = 1; ++ else if (!hw->tx) ++ ltq_spi_rxreq_set(hw); ++ ++ spin_unlock_irqrestore(&hw->lock, flags); ++ ++ if (completed) ++ ltq_spi_complete(hw); ++ ++ return IRQ_HANDLED; ++} ++ ++irqreturn_t ltq_spi_err_irq(int irq, void *data) ++{ ++ struct ltq_spi *hw = data; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&hw->lock, flags); ++ ++ /* Disable all interrupts */ ++ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN); ++ ++ /* Clear all error flags */ ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE); ++ ++ /* Flush FIFOs */ ++ ltq_spi_reg_setbit(hw, LTQ_SPI_RXFCON_RXFLU, LTQ_SPI_RXFCON); ++ ltq_spi_reg_setbit(hw, LTQ_SPI_TXFCON_TXFLU, LTQ_SPI_TXFCON); ++ ++ hw->status = -EIO; ++ spin_unlock_irqrestore(&hw->lock, flags); ++ ++ ltq_spi_complete(hw); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ltq_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) ++{ ++ struct ltq_spi *hw = ltq_spi_to_hw(spi); ++ u32 irq_flags = 0; ++ ++ hw->tx = t->tx_buf; ++ hw->rx = t->rx_buf; ++ hw->len = t->len; ++ hw->tx_cnt = 0; ++ hw->rx_cnt = 0; ++ hw->status = 0; ++ INIT_COMPLETION(hw->done); ++ ++ ltq_spi_xmit_set(hw, t); ++ ++ /* Enable error interrupts */ ++ ltq_spi_reg_setbit(hw, LTQ_SPI_IRNEN_E, LTQ_SPI_IRNEN); ++ ++ if (hw->tx) { ++ /* Initially fill TX FIFO with as much data as possible */ ++ ltq_spi_txfifo_write(hw); ++ irq_flags |= LTQ_SPI_IRNEN_T; ++ ++ /* Always enable RX interrupt in Full Duplex mode */ ++ if (hw->rx) ++ irq_flags |= LTQ_SPI_IRNEN_R; ++ } else if (hw->rx) { ++ /* Start RX clock */ ++ ltq_spi_rxreq_set(hw); ++ ++ /* Enable RX interrupt to receive data from RX FIFOs */ ++ irq_flags |= LTQ_SPI_IRNEN_R; ++ } ++ ++ /* Enable TX or RX interrupts */ ++ ltq_spi_reg_setbit(hw, irq_flags, LTQ_SPI_IRNEN); ++ wait_for_completion_interruptible(&hw->done); ++ ++ /* Disable all interrupts */ ++ ltq_spi_reg_clearbit(hw, LTQ_SPI_IRNEN_ALL, LTQ_SPI_IRNEN); ++ ++ /* ++ * Return length of current transfer for bitbang utility code if ++ * no errors occured during transmission. ++ */ ++ if (!hw->status) ++ hw->status = hw->len; ++ ++ return hw->status; ++} ++ ++static const struct ltq_spi_irq_map ltq_spi_irqs[] = { ++ { "spi_tx", ltq_spi_tx_irq }, ++ { "spi_rx", ltq_spi_rx_irq }, ++ { "spi_err", ltq_spi_err_irq }, ++}; ++ ++static int __init ltq_spi_probe(struct platform_device *pdev) ++{ ++ struct spi_master *master; ++ struct resource *r; ++ struct ltq_spi *hw; ++ struct ltq_spi_platform_data *pdata = pdev->dev.platform_data; ++ int ret, i; ++ u32 data, id; ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(struct ltq_spi)); ++ if (!master) { ++ dev_err(&pdev->dev, "spi_alloc_master\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ hw = spi_master_get_devdata(master); ++ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (r == NULL) { ++ dev_err(&pdev->dev, "platform_get_resource\n"); ++ ret = -ENOENT; ++ goto err_master; ++ } ++ ++ r = devm_request_mem_region(&pdev->dev, r->start, resource_size(r), ++ pdev->name); ++ if (!r) { ++ dev_err(&pdev->dev, "devm_request_mem_region\n"); ++ ret = -ENXIO; ++ goto err_master; ++ } ++ ++ hw->base = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r)); ++ if (!hw->base) { ++ dev_err(&pdev->dev, "devm_ioremap_nocache\n"); ++ ret = -ENXIO; ++ goto err_master; ++ } ++ ++ hw->clk = clk_get(&pdev->dev, "fpi"); ++ if (IS_ERR(hw->clk)) { ++ dev_err(&pdev->dev, "clk_get\n"); ++ ret = PTR_ERR(hw->clk); ++ goto err_master; ++ } ++ ++ memset(hw->irq, 0, sizeof(hw->irq)); ++ for (i = 0; i < ARRAY_SIZE(ltq_spi_irqs); i++) { ++ ret = platform_get_irq_byname(pdev, ltq_spi_irqs[i].name); ++ if (0 > ret) { ++ dev_err(&pdev->dev, "platform_get_irq_byname\n"); ++ goto err_irq; ++ } ++ ++ hw->irq[i] = ret; ++ ret = request_irq(hw->irq[i], ltq_spi_irqs[i].handler, ++ 0, ltq_spi_irqs[i].name, hw); ++ if (ret) { ++ dev_err(&pdev->dev, "request_irq\n"); ++ goto err_irq; ++ } ++ } ++ ++ hw->bitbang.master = spi_master_get(master); ++ hw->bitbang.chipselect = ltq_spi_chipselect; ++ hw->bitbang.setup_transfer = ltq_spi_setup_transfer; ++ hw->bitbang.txrx_bufs = ltq_spi_txrx_bufs; ++ ++ master->bus_num = pdev->id; ++ master->num_chipselect = pdata->num_chipselect; ++ master->setup = ltq_spi_setup; ++ master->cleanup = ltq_spi_cleanup; ++ ++ hw->dev = &pdev->dev; ++ init_completion(&hw->done); ++ 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_spi_hw_enable(hw); ++ ++ /* Read module capabilities */ ++ id = ltq_spi_reg_read(hw, LTQ_SPI_ID); ++ hw->txfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK; ++ hw->rxfs = (id >> LTQ_SPI_ID_TXFS_SHIFT) & LTQ_SPI_ID_TXFS_MASK; ++ hw->dma_support = (id & LTQ_SPI_ID_CFG) ? 1 : 0; ++ ++ ltq_spi_config_mode_set(hw); ++ ++ /* Enable error checking, disable TX/RX, set idle value high */ ++ data = LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN | ++ LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN | ++ LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF | LTQ_SPI_CON_IDLE; ++ ltq_spi_reg_write(hw, data, LTQ_SPI_CON); ++ ++ /* Enable master mode and clear error flags */ ++ ltq_spi_reg_write(hw, LTQ_SPI_WHBSTATE_SETMS | ++ LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE); ++ ++ /* Reset GPIO/CS registers */ ++ ltq_spi_reg_write(hw, 0x0, LTQ_SPI_GPOCON); ++ ltq_spi_reg_write(hw, 0xFF00, LTQ_SPI_FGPO); ++ ++ /* Enable and flush FIFOs */ ++ ltq_spi_reset_fifos(hw); ++ ++ ret = spi_bitbang_start(&hw->bitbang); ++ if (ret) { ++ dev_err(&pdev->dev, "spi_bitbang_start\n"); ++ goto err_bitbang; ++ } ++ ++ platform_set_drvdata(pdev, hw); ++ ++ pr_info("Lantiq SoC SPI controller rev %u (TXFS %u, RXFS %u, DMA %u)\n", ++ id & LTQ_SPI_ID_REV_MASK, hw->txfs, hw->rxfs, hw->dma_support); ++ ++ return 0; ++ ++err_bitbang: ++ ltq_spi_hw_disable(hw); ++ ++err_irq: ++ clk_put(hw->clk); ++ ++ for (; i > 0; i--) ++ free_irq(hw->irq[i], hw); ++ ++err_master: ++ spi_master_put(master); ++ ++err: ++ return ret; ++} ++ ++static int __exit ltq_spi_remove(struct platform_device *pdev) ++{ ++ struct ltq_spi *hw = platform_get_drvdata(pdev); ++ int ret, i; ++ ++ ret = spi_bitbang_stop(&hw->bitbang); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ ltq_spi_config_mode_set(hw); ++ ltq_spi_hw_disable(hw); ++ ++ for (i = 0; i < ARRAY_SIZE(hw->irq); i++) ++ if (0 < hw->irq[i]) ++ free_irq(hw->irq[i], hw); ++ ++ gpio_free(LTQ_SPI_GPIO_DI); ++ gpio_free(LTQ_SPI_GPIO_DO); ++ gpio_free(LTQ_SPI_GPIO_CLK); ++ ++ clk_put(hw->clk); ++ spi_master_put(hw->bitbang.master); ++ ++ return 0; ++} ++ ++static struct platform_driver ltq_spi_driver = { ++ .driver = { ++ .name = "ltq-spi", ++ .owner = THIS_MODULE, ++ }, ++ .remove = __exit_p(ltq_spi_remove), ++}; ++ ++static int __init ltq_spi_init(void) ++{ ++ return platform_driver_probe(<q_spi_driver, ltq_spi_probe); ++} ++module_init(ltq_spi_init); ++ ++static void __exit ltq_spi_exit(void) ++{ ++ platform_driver_unregister(<q_spi_driver); ++} ++module_exit(ltq_spi_exit); ++ ++MODULE_DESCRIPTION("Lantiq SoC SPI controller driver"); ++MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:ltq-spi"); diff --git a/target/linux/lantiq/patches-2.6.39/420-spi3.patch b/target/linux/lantiq/patches-2.6.39/420-spi3.patch new file mode 100644 index 0000000..31cf3c1 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/420-spi3.patch @@ -0,0 +1,49 @@ +From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +Date: Thu, 3 Mar 2011 20:42:26 +0000 (+0100) +Subject: MIPS: lantiq: Add device register helper for SPI controller and devices +X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=b35b07062b718ece9b9cb7b23b12d83a087eafb0;hp=653c95b8b9066c9c6ac08bd64d0ceee439e9fd90 + +MIPS: lantiq: Add device register helper for SPI controller and devices + +Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> +--- + +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -21,6 +21,7 @@ + #include <linux/io.h> + #include <linux/gpio.h> + #include <linux/leds.h> ++#include <linux/spi/spi.h> + + #include <asm/bootinfo.h> + #include <asm/irq.h> +@@ -119,3 +120,28 @@ + platform_device_register(<q_etop); + } + } ++ ++static struct resource ltq_spi_resources[] = { ++ { ++ .start = LTQ_SSC_BASE_ADDR, ++ .end = LTQ_SSC_BASE_ADDR + LTQ_SSC_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ IRQ_RES(spi_tx, LTQ_SSC_TIR), ++ IRQ_RES(spi_rx, LTQ_SSC_RIR), ++ IRQ_RES(spi_err, LTQ_SSC_EIR), ++}; ++ ++static struct platform_device ltq_spi = { ++ .name = "ltq-spi", ++ .resource = ltq_spi_resources, ++ .num_resources = ARRAY_SIZE(ltq_spi_resources), ++}; ++ ++void __init ltq_register_spi(struct ltq_spi_platform_data *pdata, ++ struct spi_board_info const *info, unsigned n) ++{ ++ spi_register_board_info(info, n); ++ ltq_spi.dev.platform_data = pdata; ++ platform_device_register(<q_spi); ++} diff --git a/target/linux/lantiq/patches-2.6.39/500-register_ebu.patch b/target/linux/lantiq/patches-2.6.39/500-register_ebu.patch new file mode 100644 index 0000000..613cb69 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/500-register_ebu.patch @@ -0,0 +1,41 @@ +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -121,6 +121,29 @@ + } + } + ++/* ebu */ ++static struct resource ltq_ebu_resource = ++{ ++ .name = "gpio_ebu", ++ .start = LTQ_EBU_GPIO_START, ++ .end = LTQ_EBU_GPIO_START + LTQ_EBU_GPIO_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static struct platform_device ltq_ebu = ++{ ++ .name = "ltq_ebu", ++ .resource = <q_ebu_resource, ++ .num_resources = 1, ++}; ++ ++void __init ++ltq_register_gpio_ebu(unsigned int value) ++{ ++ ltq_ebu.dev.platform_data = (void*) value; ++ platform_device_register(<q_ebu); ++} ++ + static struct resource ltq_spi_resources[] = { + { + .start = LTQ_SSC_BASE_ADDR, +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -16,5 +16,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 ltq_register_gpio_ebu(unsigned int value); + + #endif diff --git a/target/linux/lantiq/patches-2.6.39/510-register_madwifi.patch b/target/linux/lantiq/patches-2.6.39/510-register_madwifi.patch new file mode 100644 index 0000000..678f0f5 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/510-register_madwifi.patch @@ -0,0 +1,28 @@ +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -144,6 +144,16 @@ + platform_device_register(<q_ebu); + } + ++/* madwifi */ ++int lantiq_emulate_madwifi_eep = 0; ++EXPORT_SYMBOL(lantiq_emulate_madwifi_eep); ++ ++void __init ++ltq_register_madwifi_eep(void) ++{ ++ lantiq_emulate_madwifi_eep = 1; ++} ++ + static struct resource ltq_spi_resources[] = { + { + .start = LTQ_SSC_BASE_ADDR, +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -17,5 +17,6 @@ + extern void ltq_register_ase_asc(void); + extern void ltq_register_etop(struct ltq_eth_data *eth); + extern void ltq_register_gpio_ebu(unsigned int value); ++extern void ltq_register_madwifi_eep(void); + + #endif diff --git a/target/linux/lantiq/patches-2.6.39/520-register_buttons.patch b/target/linux/lantiq/patches-2.6.39/520-register_buttons.patch new file mode 100644 index 0000000..0d8d58e --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/520-register_buttons.patch @@ -0,0 +1,46 @@ +--- a/arch/mips/lantiq/xway/devices.c ++++ b/arch/mips/lantiq/xway/devices.c +@@ -154,6 +154,26 @@ + lantiq_emulate_madwifi_eep = 1; + } + ++/* gpio buttons */ ++static struct gpio_buttons_platform_data ltq_gpio_buttons_platform_data; ++ ++static struct platform_device ltq_gpio_buttons_platform_device = ++{ ++ .name = "gpio-buttons", ++ .id = 0, ++ .dev = { ++ .platform_data = (void *) <q_gpio_buttons_platform_data, ++ }, ++}; ++ ++void __init ++ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt) ++{ ++ ltq_gpio_buttons_platform_data.buttons = buttons; ++ ltq_gpio_buttons_platform_data.nbuttons = cnt; ++ platform_device_register(<q_gpio_buttons_platform_device); ++} ++ + static struct resource ltq_spi_resources[] = { + { + .start = LTQ_SSC_BASE_ADDR, +--- a/arch/mips/lantiq/xway/devices.h ++++ b/arch/mips/lantiq/xway/devices.h +@@ -11,6 +11,7 @@ + + #include "../devices.h" + #include <linux/phy.h> ++#include <linux/gpio_buttons.h> + + extern void ltq_register_gpio(void); + extern void ltq_register_gpio_stp(void); +@@ -18,5 +19,6 @@ + extern void ltq_register_etop(struct ltq_eth_data *eth); + extern void ltq_register_gpio_ebu(unsigned int value); + extern void ltq_register_madwifi_eep(void); ++extern void ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt); + + #endif diff --git a/target/linux/lantiq/patches-2.6.39/530-register_tapi.patch b/target/linux/lantiq/patches-2.6.39/530-register_tapi.patch new file mode 100644 index 0000000..a581064 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/530-register_tapi.patch @@ -0,0 +1,42 @@ +--- a/arch/mips/lantiq/devices.c ++++ b/arch/mips/lantiq/devices.c +@@ -120,3 +120,20 @@ + pr_err("kernel is compiled without PCI support\n"); + } + #endif ++ ++static unsigned int *cp1_base = 0; ++unsigned int* ++ltq_get_cp1_base(void) ++{ ++ return cp1_base; ++} ++EXPORT_SYMBOL(ltq_get_cp1_base); ++ ++void __init ++ltq_register_tapi(void) ++{ ++#define CP1_SIZE (1 << 20) ++ dma_addr_t dma; ++ cp1_base = ++ (void*)CPHYSADDR(dma_alloc_coherent(NULL, CP1_SIZE, &dma, GFP_ATOMIC)); ++} +--- a/arch/mips/lantiq/devices.h ++++ b/arch/mips/lantiq/devices.h +@@ -19,5 +19,6 @@ + extern void ltq_register_wdt(void); + extern void ltq_register_asc(int port); + extern void ltq_register_pci(struct ltq_pci_data *data); ++extern void ltq_register_tapi(void); + + #endif +--- a/arch/mips/lantiq/xway/mach-easy50712.c ++++ b/arch/mips/lantiq/xway/mach-easy50712.c +@@ -66,6 +66,7 @@ + ltq_register_nor(&easy50712_flash_data); + ltq_register_pci(<q_pci_data); + ltq_register_etop(<q_eth_data); ++ ltq_register_tapi(); + } + + MIPS_MACHINE(LTQ_MACH_EASY50712, diff --git a/target/linux/lantiq/patches-2.6.39/540-gptu.patch b/target/linux/lantiq/patches-2.6.39/540-gptu.patch new file mode 100644 index 0000000..b7448e8 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/540-gptu.patch @@ -0,0 +1,999 @@ +--- /dev/null ++++ b/arch/mips/lantiq/xway/timer.c +@@ -0,0 +1,830 @@ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/version.h> ++#include <linux/types.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/init.h> ++#include <linux/uaccess.h> ++#include <linux/unistd.h> ++#include <linux/errno.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/irq.h> ++#include <asm/div64.h> ++ ++#include <lantiq_soc.h> ++#include <lantiq_irq.h> ++#include <lantiq_timer.h> ++ ++#define MAX_NUM_OF_32BIT_TIMER_BLOCKS 6 ++ ++#ifdef TIMER1A ++#define FIRST_TIMER TIMER1A ++#else ++#define FIRST_TIMER 2 ++#endif ++ ++/* ++ * GPTC divider is set or not. ++ */ ++#define GPTU_CLC_RMC_IS_SET 0 ++ ++/* ++ * Timer Interrupt (IRQ) ++ */ ++/* Must be adjusted when ICU driver is available */ ++#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22) ++ ++/* ++ * Bits Operation ++ */ ++#define GET_BITS(x, msb, lsb) \ ++ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) ++#define SET_BITS(x, msb, lsb, value) \ ++ (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | \ ++ (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb))) ++ ++/* ++ * GPTU Register Mapping ++ */ ++#define LQ_GPTU (KSEG1 + 0x1E100A00) ++#define LQ_GPTU_CLC ((volatile u32 *)(LQ_GPTU + 0x0000)) ++#define LQ_GPTU_ID ((volatile u32 *)(LQ_GPTU + 0x0008)) ++#define LQ_GPTU_CON(n, X) ((volatile u32 *)(LQ_GPTU + 0x0010 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_RUN(n, X) ((volatile u32 *)(LQ_GPTU + 0x0018 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_RELOAD(n, X) ((volatile u32 *)(LQ_GPTU + 0x0020 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_COUNT(n, X) ((volatile u32 *)(LQ_GPTU + 0x0028 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ ++#define LQ_GPTU_IRNEN ((volatile u32 *)(LQ_GPTU + 0x00F4)) ++#define LQ_GPTU_IRNICR ((volatile u32 *)(LQ_GPTU + 0x00F8)) ++#define LQ_GPTU_IRNCR ((volatile u32 *)(LQ_GPTU + 0x00FC)) ++ ++/* ++ * Clock Control Register ++ */ ++#define GPTU_CLC_SMC GET_BITS(*LQ_GPTU_CLC, 23, 16) ++#define GPTU_CLC_RMC GET_BITS(*LQ_GPTU_CLC, 15, 8) ++#define GPTU_CLC_FSOE (*LQ_GPTU_CLC & (1 << 5)) ++#define GPTU_CLC_EDIS (*LQ_GPTU_CLC & (1 << 3)) ++#define GPTU_CLC_SPEN (*LQ_GPTU_CLC & (1 << 2)) ++#define GPTU_CLC_DISS (*LQ_GPTU_CLC & (1 << 1)) ++#define GPTU_CLC_DISR (*LQ_GPTU_CLC & (1 << 0)) ++ ++#define GPTU_CLC_SMC_SET(value) SET_BITS(0, 23, 16, (value)) ++#define GPTU_CLC_RMC_SET(value) SET_BITS(0, 15, 8, (value)) ++#define GPTU_CLC_FSOE_SET(value) ((value) ? (1 << 5) : 0) ++#define GPTU_CLC_SBWE_SET(value) ((value) ? (1 << 4) : 0) ++#define GPTU_CLC_EDIS_SET(value) ((value) ? (1 << 3) : 0) ++#define GPTU_CLC_SPEN_SET(value) ((value) ? (1 << 2) : 0) ++#define GPTU_CLC_DISR_SET(value) ((value) ? (1 << 0) : 0) ++ ++/* ++ * ID Register ++ */ ++#define GPTU_ID_ID GET_BITS(*LQ_GPTU_ID, 15, 8) ++#define GPTU_ID_CFG GET_BITS(*LQ_GPTU_ID, 7, 5) ++#define GPTU_ID_REV GET_BITS(*LQ_GPTU_ID, 4, 0) ++ ++/* ++ * Control Register of Timer/Counter nX ++ * n is the index of block (1 based index) ++ * X is either A or B ++ */ ++#define GPTU_CON_SRC_EG(n, X) (*LQ_GPTU_CON(n, X) & (1 << 10)) ++#define GPTU_CON_SRC_EXT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 9)) ++#define GPTU_CON_SYNC(n, X) (*LQ_GPTU_CON(n, X) & (1 << 8)) ++#define GPTU_CON_EDGE(n, X) GET_BITS(*LQ_GPTU_CON(n, X), 7, 6) ++#define GPTU_CON_INV(n, X) (*LQ_GPTU_CON(n, X) & (1 << 5)) ++#define GPTU_CON_EXT(n, X) (*LQ_GPTU_CON(n, A) & (1 << 4)) /* Timer/Counter B does not have this bit */ ++#define GPTU_CON_STP(n, X) (*LQ_GPTU_CON(n, X) & (1 << 3)) ++#define GPTU_CON_CNT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 2)) ++#define GPTU_CON_DIR(n, X) (*LQ_GPTU_CON(n, X) & (1 << 1)) ++#define GPTU_CON_EN(n, X) (*LQ_GPTU_CON(n, X) & (1 << 0)) ++ ++#define GPTU_CON_SRC_EG_SET(value) ((value) ? 0 : (1 << 10)) ++#define GPTU_CON_SRC_EXT_SET(value) ((value) ? (1 << 9) : 0) ++#define GPTU_CON_SYNC_SET(value) ((value) ? (1 << 8) : 0) ++#define GPTU_CON_EDGE_SET(value) SET_BITS(0, 7, 6, (value)) ++#define GPTU_CON_INV_SET(value) ((value) ? (1 << 5) : 0) ++#define GPTU_CON_EXT_SET(value) ((value) ? (1 << 4) : 0) ++#define GPTU_CON_STP_SET(value) ((value) ? (1 << 3) : 0) ++#define GPTU_CON_CNT_SET(value) ((value) ? (1 << 2) : 0) ++#define GPTU_CON_DIR_SET(value) ((value) ? (1 << 1) : 0) ++ ++#define GPTU_RUN_RL_SET(value) ((value) ? (1 << 2) : 0) ++#define GPTU_RUN_CEN_SET(value) ((value) ? (1 << 1) : 0) ++#define GPTU_RUN_SEN_SET(value) ((value) ? (1 << 0) : 0) ++ ++#define GPTU_IRNEN_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0) ++#define GPTU_IRNCR_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0) ++ ++#define TIMER_FLAG_MASK_SIZE(x) (x & 0x0001) ++#define TIMER_FLAG_MASK_TYPE(x) (x & 0x0002) ++#define TIMER_FLAG_MASK_STOP(x) (x & 0x0004) ++#define TIMER_FLAG_MASK_DIR(x) (x & 0x0008) ++#define TIMER_FLAG_NONE_EDGE 0x0000 ++#define TIMER_FLAG_MASK_EDGE(x) (x & 0x0030) ++#define TIMER_FLAG_REAL 0x0000 ++#define TIMER_FLAG_INVERT 0x0040 ++#define TIMER_FLAG_MASK_INVERT(x) (x & 0x0040) ++#define TIMER_FLAG_MASK_TRIGGER(x) (x & 0x0070) ++#define TIMER_FLAG_MASK_SYNC(x) (x & 0x0080) ++#define TIMER_FLAG_CALLBACK_IN_HB 0x0200 ++#define TIMER_FLAG_MASK_HANDLE(x) (x & 0x0300) ++#define TIMER_FLAG_MASK_SRC(x) (x & 0x1000) ++ ++struct timer_dev_timer { ++ unsigned int f_irq_on; ++ unsigned int irq; ++ unsigned int flag; ++ unsigned long arg1; ++ unsigned long arg2; ++}; ++ ++struct timer_dev { ++ struct mutex gptu_mutex; ++ unsigned int number_of_timers; ++ unsigned int occupation; ++ unsigned int f_gptu_on; ++ struct timer_dev_timer timer[MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2]; ++}; ++ ++unsigned int ltq_get_fpi_bus_clock(int fpi); ++ ++static long gptu_ioctl(struct file *, unsigned int, unsigned long); ++static int gptu_open(struct inode *, struct file *); ++static int gptu_release(struct inode *, struct file *); ++ ++static struct file_operations gptu_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = gptu_ioctl, ++ .open = gptu_open, ++ .release = gptu_release ++}; ++ ++static struct miscdevice gptu_miscdev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "gptu", ++ .fops = &gptu_fops, ++}; ++ ++static struct timer_dev timer_dev; ++ ++static irqreturn_t timer_irq_handler(int irq, void *p) ++{ ++ unsigned int timer; ++ unsigned int flag; ++ struct timer_dev_timer *dev_timer = (struct timer_dev_timer *)p; ++ ++ timer = irq - TIMER_INTERRUPT; ++ if (timer < timer_dev.number_of_timers ++ && dev_timer == &timer_dev.timer[timer]) { ++ /* Clear interrupt. */ ++ ltq_w32(1 << timer, LQ_GPTU_IRNCR); ++ ++ /* Call user hanler or signal. */ ++ flag = dev_timer->flag; ++ if (!(timer & 0x01) ++ || TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) { ++ /* 16-bit timer or timer A of 32-bit timer */ ++ switch (TIMER_FLAG_MASK_HANDLE(flag)) { ++ case TIMER_FLAG_CALLBACK_IN_IRQ: ++ case TIMER_FLAG_CALLBACK_IN_HB: ++ if (dev_timer->arg1) ++ (*(timer_callback)dev_timer->arg1)(dev_timer->arg2); ++ break; ++ case TIMER_FLAG_SIGNAL: ++ send_sig((int)dev_timer->arg2, (struct task_struct *)dev_timer->arg1, 0); ++ break; ++ } ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++static inline void lq_enable_gptu(void) ++{ ++ ltq_pmu_enable(PMU_GPT); ++ ++ /* Set divider as 1, disable write protection for SPEN, enable module. */ ++ *LQ_GPTU_CLC = ++ GPTU_CLC_SMC_SET(0x00) | ++ GPTU_CLC_RMC_SET(0x01) | ++ GPTU_CLC_FSOE_SET(0) | ++ GPTU_CLC_SBWE_SET(1) | ++ GPTU_CLC_EDIS_SET(0) | ++ GPTU_CLC_SPEN_SET(0) | ++ GPTU_CLC_DISR_SET(0); ++} ++ ++static inline void lq_disable_gptu(void) ++{ ++ ltq_w32(0x00, LQ_GPTU_IRNEN); ++ ltq_w32(0xfff, LQ_GPTU_IRNCR); ++ ++ /* Set divider as 0, enable write protection for SPEN, disable module. */ ++ *LQ_GPTU_CLC = ++ GPTU_CLC_SMC_SET(0x00) | ++ GPTU_CLC_RMC_SET(0x00) | ++ GPTU_CLC_FSOE_SET(0) | ++ GPTU_CLC_SBWE_SET(0) | ++ GPTU_CLC_EDIS_SET(0) | ++ GPTU_CLC_SPEN_SET(0) | ++ GPTU_CLC_DISR_SET(1); ++ ++ ltq_pmu_disable(PMU_GPT); ++} ++ ++int lq_request_timer(unsigned int timer, unsigned int flag, ++ unsigned long value, unsigned long arg1, unsigned long arg2) ++{ ++ int ret = 0; ++ unsigned int con_reg, irnen_reg; ++ int n, X; ++ ++ if (timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ printk(KERN_INFO "request_timer(%d, 0x%08X, %lu)...", ++ timer, flag, value); ++ ++ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) ++ value &= 0xFFFF; ++ else ++ timer &= ~0x01; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ /* ++ * Allocate timer. ++ */ ++ if (timer < FIRST_TIMER) { ++ unsigned int mask; ++ unsigned int shift; ++ /* This takes care of TIMER1B which is the only choice for Voice TAPI system */ ++ unsigned int offset = TIMER2A; ++ ++ /* ++ * Pick up a free timer. ++ */ ++ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) { ++ mask = 1 << offset; ++ shift = 1; ++ } else { ++ mask = 3 << offset; ++ shift = 2; ++ } ++ for (timer = offset; ++ timer < offset + timer_dev.number_of_timers; ++ timer += shift, mask <<= shift) ++ if (!(timer_dev.occupation & mask)) { ++ timer_dev.occupation |= mask; ++ break; ++ } ++ if (timer >= offset + timer_dev.number_of_timers) { ++ printk("failed![%d]\n", __LINE__); ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } else ++ ret = timer; ++ } else { ++ register unsigned int mask; ++ ++ /* ++ * Check if the requested timer is free. ++ */ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if ((timer_dev.occupation & mask)) { ++ printk("failed![%d] mask %#x, timer_dev.occupation %#x\n", ++ __LINE__, mask, timer_dev.occupation); ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EBUSY; ++ } else { ++ timer_dev.occupation |= mask; ++ ret = 0; ++ } ++ } ++ ++ /* ++ * Prepare control register value. ++ */ ++ switch (TIMER_FLAG_MASK_EDGE(flag)) { ++ default: ++ case TIMER_FLAG_NONE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x00); ++ break; ++ case TIMER_FLAG_RISE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x01); ++ break; ++ case TIMER_FLAG_FALL_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x02); ++ break; ++ case TIMER_FLAG_ANY_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x03); ++ break; ++ } ++ if (TIMER_FLAG_MASK_TYPE(flag) == TIMER_FLAG_TIMER) ++ con_reg |= ++ TIMER_FLAG_MASK_SRC(flag) == ++ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : ++ GPTU_CON_SRC_EXT_SET(0); ++ else ++ con_reg |= ++ TIMER_FLAG_MASK_SRC(flag) == ++ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : ++ GPTU_CON_SRC_EG_SET(0); ++ con_reg |= ++ TIMER_FLAG_MASK_SYNC(flag) == ++ TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : ++ GPTU_CON_SYNC_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_INVERT(flag) == ++ TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_SIZE(flag) == ++ TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : ++ GPTU_CON_EXT_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_STOP(flag) == ++ TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0); ++ con_reg |= ++ TIMER_FLAG_MASK_TYPE(flag) == ++ TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : ++ GPTU_CON_CNT_SET(1); ++ con_reg |= ++ TIMER_FLAG_MASK_DIR(flag) == ++ TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0); ++ ++ /* ++ * Fill up running data. ++ */ ++ timer_dev.timer[timer - FIRST_TIMER].flag = flag; ++ timer_dev.timer[timer - FIRST_TIMER].arg1 = arg1; ++ timer_dev.timer[timer - FIRST_TIMER].arg2 = arg2; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flag; ++ ++ /* ++ * Enable GPTU module. ++ */ ++ if (!timer_dev.f_gptu_on) { ++ lq_enable_gptu(); ++ timer_dev.f_gptu_on = 1; ++ } ++ ++ /* ++ * Enable IRQ. ++ */ ++ if (TIMER_FLAG_MASK_HANDLE(flag) != TIMER_FLAG_NO_HANDLE) { ++ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL) ++ timer_dev.timer[timer - FIRST_TIMER].arg1 = ++ (unsigned long) find_task_by_vpid((int) arg1); ++ ++ irnen_reg = 1 << (timer - FIRST_TIMER); ++ ++ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL ++ || (TIMER_FLAG_MASK_HANDLE(flag) == ++ TIMER_FLAG_CALLBACK_IN_IRQ ++ && timer_dev.timer[timer - FIRST_TIMER].arg1)) { ++ enable_irq(timer_dev.timer[timer - FIRST_TIMER].irq); ++ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 1; ++ } ++ } else ++ irnen_reg = 0; ++ ++ /* ++ * Write config register, reload value and enable interrupt. ++ */ ++ n = timer >> 1; ++ X = timer & 0x01; ++ *LQ_GPTU_CON(n, X) = con_reg; ++ *LQ_GPTU_RELOAD(n, X) = value; ++ /* printk("reload value = %d\n", (u32)value); */ ++ *LQ_GPTU_IRNEN |= irnen_reg; ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ printk("successful!\n"); ++ return ret; ++} ++EXPORT_SYMBOL(lq_request_timer); ++ ++int lq_free_timer(unsigned int timer) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ if (GPTU_CON_EN(n, X)) ++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1); ++ ++ *LQ_GPTU_IRNEN &= ~GPTU_IRNEN_TC_SET(n, X, 1); ++ *LQ_GPTU_IRNCR |= GPTU_IRNCR_TC_SET(n, X, 1); ++ ++ if (timer_dev.timer[timer - FIRST_TIMER].f_irq_on) { ++ disable_irq(timer_dev.timer[timer - FIRST_TIMER].irq); ++ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 0; ++ } ++ ++ timer_dev.occupation &= ~mask; ++ if (!timer_dev.occupation && timer_dev.f_gptu_on) { ++ lq_disable_gptu(); ++ timer_dev.f_gptu_on = 0; ++ } ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_free_timer); ++ ++int lq_start_timer(unsigned int timer, int is_resume) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == ++ TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_RL_SET(!is_resume) | GPTU_RUN_SEN_SET(1); ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_start_timer); ++ ++int lq_stop_timer(unsigned int timer) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER ++ || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1); ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_stop_timer); ++ ++int lq_reset_counter_flags(u32 timer, u32 flags) ++{ ++ unsigned int oflag; ++ unsigned int mask, con_reg; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ oflag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(oflag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(oflag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ switch (TIMER_FLAG_MASK_EDGE(flags)) { ++ default: ++ case TIMER_FLAG_NONE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x00); ++ break; ++ case TIMER_FLAG_RISE_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x01); ++ break; ++ case TIMER_FLAG_FALL_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x02); ++ break; ++ case TIMER_FLAG_ANY_EDGE: ++ con_reg = GPTU_CON_EDGE_SET(0x03); ++ break; ++ } ++ if (TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER) ++ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : GPTU_CON_SRC_EXT_SET(0); ++ else ++ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : GPTU_CON_SRC_EG_SET(0); ++ con_reg |= TIMER_FLAG_MASK_SYNC(flags) == TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : GPTU_CON_SYNC_SET(1); ++ con_reg |= TIMER_FLAG_MASK_INVERT(flags) == TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1); ++ con_reg |= TIMER_FLAG_MASK_SIZE(flags) == TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : GPTU_CON_EXT_SET(1); ++ con_reg |= TIMER_FLAG_MASK_STOP(flags) == TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0); ++ con_reg |= TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : GPTU_CON_CNT_SET(1); ++ con_reg |= TIMER_FLAG_MASK_DIR(flags) == TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0); ++ ++ timer_dev.timer[timer - FIRST_TIMER].flag = flags; ++ if (TIMER_FLAG_MASK_SIZE(flags) != TIMER_FLAG_16BIT) ++ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flags; ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *LQ_GPTU_CON(n, X) = con_reg; ++ smp_wmb(); ++ printk(KERN_INFO "[%s]: counter%d oflags %#x, nflags %#x, GPTU_CON %#x\n", __func__, timer, oflag, flags, *LQ_GPTU_CON(n, X)); ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return 0; ++} ++EXPORT_SYMBOL(lq_reset_counter_flags); ++ ++int lq_get_count_value(unsigned int timer, unsigned long *value) ++{ ++ unsigned int flag; ++ unsigned int mask; ++ int n, X; ++ ++ if (!timer_dev.f_gptu_on) ++ return -EINVAL; ++ ++ if (timer < FIRST_TIMER ++ || timer >= FIRST_TIMER + timer_dev.number_of_timers) ++ return -EINVAL; ++ ++ mutex_lock(&timer_dev.gptu_mutex); ++ ++ flag = timer_dev.timer[timer - FIRST_TIMER].flag; ++ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) ++ timer &= ~0x01; ++ ++ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; ++ if (((timer_dev.occupation & mask) ^ mask)) { ++ mutex_unlock(&timer_dev.gptu_mutex); ++ return -EINVAL; ++ } ++ ++ n = timer >> 1; ++ X = timer & 0x01; ++ ++ *value = *LQ_GPTU_COUNT(n, X); ++ ++ mutex_unlock(&timer_dev.gptu_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL(lq_get_count_value); ++ ++u32 lq_cal_divider(unsigned long freq) ++{ ++ u64 module_freq, fpi = ltq_get_fpi_bus_clock(2); ++ u32 clock_divider = 1; ++ module_freq = fpi * 1000; ++ do_div(module_freq, clock_divider * freq); ++ return module_freq; ++} ++EXPORT_SYMBOL(lq_cal_divider); ++ ++int lq_set_timer(unsigned int timer, unsigned int freq, int is_cyclic, ++ int is_ext_src, unsigned int handle_flag, unsigned long arg1, ++ unsigned long arg2) ++{ ++ unsigned long divider; ++ unsigned int flag; ++ ++ divider = lq_cal_divider(freq); ++ if (divider == 0) ++ return -EINVAL; ++ flag = ((divider & ~0xFFFF) ? TIMER_FLAG_32BIT : TIMER_FLAG_16BIT) ++ | (is_cyclic ? TIMER_FLAG_CYCLIC : TIMER_FLAG_ONCE) ++ | (is_ext_src ? TIMER_FLAG_EXT_SRC : TIMER_FLAG_INT_SRC) ++ | TIMER_FLAG_TIMER | TIMER_FLAG_DOWN ++ | TIMER_FLAG_MASK_HANDLE(handle_flag); ++ ++ printk(KERN_INFO "lq_set_timer(%d, %d), divider = %lu\n", ++ timer, freq, divider); ++ return lq_request_timer(timer, flag, divider, arg1, arg2); ++} ++EXPORT_SYMBOL(lq_set_timer); ++ ++int lq_set_counter(unsigned int timer, unsigned int flag, u32 reload, ++ unsigned long arg1, unsigned long arg2) ++{ ++ printk(KERN_INFO "lq_set_counter(%d, %#x, %d)\n", timer, flag, reload); ++ return lq_request_timer(timer, flag, reload, arg1, arg2); ++} ++EXPORT_SYMBOL(lq_set_counter); ++ ++static long gptu_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ int ret; ++ struct gptu_ioctl_param param; ++ ++ if (!access_ok(VERIFY_READ, arg, sizeof(struct gptu_ioctl_param))) ++ return -EFAULT; ++ copy_from_user(¶m, (void *) arg, sizeof(param)); ++ ++ if ((((cmd == GPTU_REQUEST_TIMER || cmd == GPTU_SET_TIMER ++ || GPTU_SET_COUNTER) && param.timer < 2) ++ || cmd == GPTU_GET_COUNT_VALUE || cmd == GPTU_CALCULATE_DIVIDER) ++ && !access_ok(VERIFY_WRITE, arg, ++ sizeof(struct gptu_ioctl_param))) ++ return -EFAULT; ++ ++ switch (cmd) { ++ case GPTU_REQUEST_TIMER: ++ ret = lq_request_timer(param.timer, param.flag, param.value, ++ (unsigned long) param.pid, ++ (unsigned long) param.sig); ++ if (ret > 0) { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ timer, &ret, sizeof(&ret)); ++ ret = 0; ++ } ++ break; ++ case GPTU_FREE_TIMER: ++ ret = lq_free_timer(param.timer); ++ break; ++ case GPTU_START_TIMER: ++ ret = lq_start_timer(param.timer, param.flag); ++ break; ++ case GPTU_STOP_TIMER: ++ ret = lq_stop_timer(param.timer); ++ break; ++ case GPTU_GET_COUNT_VALUE: ++ ret = lq_get_count_value(param.timer, ¶m.value); ++ if (!ret) ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ value, ¶m.value, ++ sizeof(param.value)); ++ break; ++ case GPTU_CALCULATE_DIVIDER: ++ param.value = lq_cal_divider(param.value); ++ if (param.value == 0) ++ ret = -EINVAL; ++ else { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ value, ¶m.value, ++ sizeof(param.value)); ++ ret = 0; ++ } ++ break; ++ case GPTU_SET_TIMER: ++ ret = lq_set_timer(param.timer, param.value, ++ TIMER_FLAG_MASK_STOP(param.flag) != ++ TIMER_FLAG_ONCE ? 1 : 0, ++ TIMER_FLAG_MASK_SRC(param.flag) == ++ TIMER_FLAG_EXT_SRC ? 1 : 0, ++ TIMER_FLAG_MASK_HANDLE(param.flag) == ++ TIMER_FLAG_SIGNAL ? TIMER_FLAG_SIGNAL : ++ TIMER_FLAG_NO_HANDLE, ++ (unsigned long) param.pid, ++ (unsigned long) param.sig); ++ if (ret > 0) { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ timer, &ret, sizeof(&ret)); ++ ret = 0; ++ } ++ break; ++ case GPTU_SET_COUNTER: ++ lq_set_counter(param.timer, param.flag, param.value, 0, 0); ++ if (ret > 0) { ++ copy_to_user(&((struct gptu_ioctl_param *) arg)-> ++ timer, &ret, sizeof(&ret)); ++ ret = 0; ++ } ++ break; ++ default: ++ ret = -ENOTTY; ++ } ++ ++ return ret; ++} ++ ++static int gptu_open(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++static int gptu_release(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++int __init lq_gptu_init(void) ++{ ++ int ret; ++ unsigned int i; ++ ++ ltq_w32(0, LQ_GPTU_IRNEN); ++ ltq_w32(0xfff, LQ_GPTU_IRNCR); ++ ++ memset(&timer_dev, 0, sizeof(timer_dev)); ++ mutex_init(&timer_dev.gptu_mutex); ++ ++ lq_enable_gptu(); ++ timer_dev.number_of_timers = GPTU_ID_CFG * 2; ++ lq_disable_gptu(); ++ if (timer_dev.number_of_timers > MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2) ++ timer_dev.number_of_timers = MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2; ++ printk(KERN_INFO "gptu: totally %d 16-bit timers/counters\n", timer_dev.number_of_timers); ++ ++ ret = misc_register(&gptu_miscdev); ++ if (ret) { ++ printk(KERN_ERR "gptu: can't misc_register, get error %d\n", -ret); ++ return ret; ++ } else { ++ printk(KERN_INFO "gptu: misc_register on minor %d\n", gptu_miscdev.minor); ++ } ++ ++ for (i = 0; i < timer_dev.number_of_timers; i++) { ++ ret = request_irq(TIMER_INTERRUPT + i, timer_irq_handler, IRQF_TIMER, gptu_miscdev.name, &timer_dev.timer[i]); ++ if (ret) { ++ for (; i >= 0; i--) ++ free_irq(TIMER_INTERRUPT + i, &timer_dev.timer[i]); ++ misc_deregister(&gptu_miscdev); ++ printk(KERN_ERR "gptu: failed in requesting irq (%d), get error %d\n", i, -ret); ++ return ret; ++ } else { ++ timer_dev.timer[i].irq = TIMER_INTERRUPT + i; ++ disable_irq(timer_dev.timer[i].irq); ++ printk(KERN_INFO "gptu: succeeded to request irq %d\n", timer_dev.timer[i].irq); ++ } ++ } ++ ++ return 0; ++} ++ ++void __exit lq_gptu_exit(void) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < timer_dev.number_of_timers; i++) { ++ if (timer_dev.timer[i].f_irq_on) ++ disable_irq(timer_dev.timer[i].irq); ++ free_irq(timer_dev.timer[i].irq, &timer_dev.timer[i]); ++ } ++ lq_disable_gptu(); ++ misc_deregister(&gptu_miscdev); ++} ++ ++module_init(lq_gptu_init); ++module_exit(lq_gptu_exit); +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/lantiq_timer.h +@@ -0,0 +1,155 @@ ++#ifndef __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ ++#define __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ ++ ++ ++/****************************************************************************** ++ Copyright (c) 2002, Infineon Technologies. All rights reserved. ++ ++ No Warranty ++ Because the program is licensed free of charge, there is no warranty for ++ the program, to the extent permitted by applicable law. Except when ++ otherwise stated in writing the copyright holders and/or other parties ++ provide the program "as is" without warranty of any kind, either ++ expressed or implied, including, but not limited to, the implied ++ warranties of merchantability and fitness for a particular purpose. The ++ entire risk as to the quality and performance of the program is with ++ you. should the program prove defective, you assume the cost of all ++ necessary servicing, repair or correction. ++ ++ In no event unless required by applicable law or agreed to in writing ++ will any copyright holder, or any other party who may modify and/or ++ redistribute the program as permitted above, be liable to you for ++ damages, including any general, special, incidental or consequential ++ damages arising out of the use or inability to use the program ++ (including but not limited to loss of data or data being rendered ++ inaccurate or losses sustained by you or third parties or a failure of ++ the program to operate with any other programs), even if such holder or ++ other party has been advised of the possibility of such damages. ++******************************************************************************/ ++ ++ ++/* ++ * #################################### ++ * Definition ++ * #################################### ++ */ ++ ++/* ++ * Available Timer/Counter Index ++ */ ++#define TIMER(n, X) (n * 2 + (X ? 1 : 0)) ++#define TIMER_ANY 0x00 ++#define TIMER1A TIMER(1, 0) ++#define TIMER1B TIMER(1, 1) ++#define TIMER2A TIMER(2, 0) ++#define TIMER2B TIMER(2, 1) ++#define TIMER3A TIMER(3, 0) ++#define TIMER3B TIMER(3, 1) ++ ++/* ++ * Flag of Timer/Counter ++ * These flags specify the way in which timer is configured. ++ */ ++/* Bit size of timer/counter. */ ++#define TIMER_FLAG_16BIT 0x0000 ++#define TIMER_FLAG_32BIT 0x0001 ++/* Switch between timer and counter. */ ++#define TIMER_FLAG_TIMER 0x0000 ++#define TIMER_FLAG_COUNTER 0x0002 ++/* Stop or continue when overflowing/underflowing. */ ++#define TIMER_FLAG_ONCE 0x0000 ++#define TIMER_FLAG_CYCLIC 0x0004 ++/* Count up or counter down. */ ++#define TIMER_FLAG_UP 0x0000 ++#define TIMER_FLAG_DOWN 0x0008 ++/* Count on specific level or edge. */ ++#define TIMER_FLAG_HIGH_LEVEL_SENSITIVE 0x0000 ++#define TIMER_FLAG_LOW_LEVEL_SENSITIVE 0x0040 ++#define TIMER_FLAG_RISE_EDGE 0x0010 ++#define TIMER_FLAG_FALL_EDGE 0x0020 ++#define TIMER_FLAG_ANY_EDGE 0x0030 ++/* Signal is syncronous to module clock or not. */ ++#define TIMER_FLAG_UNSYNC 0x0000 ++#define TIMER_FLAG_SYNC 0x0080 ++/* Different interrupt handle type. */ ++#define TIMER_FLAG_NO_HANDLE 0x0000 ++#if defined(__KERNEL__) ++ #define TIMER_FLAG_CALLBACK_IN_IRQ 0x0100 ++#endif // defined(__KERNEL__) ++#define TIMER_FLAG_SIGNAL 0x0300 ++/* Internal clock source or external clock source */ ++#define TIMER_FLAG_INT_SRC 0x0000 ++#define TIMER_FLAG_EXT_SRC 0x1000 ++ ++ ++/* ++ * ioctl Command ++ */ ++#define GPTU_REQUEST_TIMER 0x01 /* General method to setup timer/counter. */ ++#define GPTU_FREE_TIMER 0x02 /* Free timer/counter. */ ++#define GPTU_START_TIMER 0x03 /* Start or resume timer/counter. */ ++#define GPTU_STOP_TIMER 0x04 /* Suspend timer/counter. */ ++#define GPTU_GET_COUNT_VALUE 0x05 /* Get current count value. */ ++#define GPTU_CALCULATE_DIVIDER 0x06 /* Calculate timer divider from given freq.*/ ++#define GPTU_SET_TIMER 0x07 /* Simplified method to setup timer. */ ++#define GPTU_SET_COUNTER 0x08 /* Simplified method to setup counter. */ ++ ++/* ++ * Data Type Used to Call ioctl ++ */ ++struct gptu_ioctl_param { ++ unsigned int timer; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * ++ * GPTU_SET_COUNTER, this field is ID of expected * ++ * timer/counter. If it's zero, a timer/counter would * ++ * be dynamically allocated and ID would be stored in * ++ * this field. * ++ * In command GPTU_GET_COUNT_VALUE, this field is * ++ * ignored. * ++ * In other command, this field is ID of timer/counter * ++ * allocated. */ ++ unsigned int flag; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * ++ * GPTU_SET_COUNTER, this field contains flags to * ++ * specify how to configure timer/counter. * ++ * In command GPTU_START_TIMER, zero indicate start * ++ * and non-zero indicate resume timer/counter. * ++ * In other command, this field is ignored. */ ++ unsigned long value; /* In command GPTU_REQUEST_TIMER, this field contains * ++ * init/reload value. * ++ * In command GPTU_SET_TIMER, this field contains * ++ * frequency (0.001Hz) of timer. * ++ * In command GPTU_GET_COUNT_VALUE, current count * ++ * value would be stored in this field. * ++ * In command GPTU_CALCULATE_DIVIDER, this field * ++ * contains frequency wanted, and after calculation, * ++ * divider would be stored in this field to overwrite * ++ * the frequency. * ++ * In other command, this field is ignored. */ ++ int pid; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * ++ * if signal is required, this field contains process * ++ * ID to which signal would be sent. * ++ * In other command, this field is ignored. */ ++ int sig; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * ++ * if signal is required, this field contains signal * ++ * number which would be sent. * ++ * In other command, this field is ignored. */ ++}; ++ ++/* ++ * #################################### ++ * Data Type ++ * #################################### ++ */ ++typedef void (*timer_callback)(unsigned long arg); ++ ++extern int lq_request_timer(unsigned int, unsigned int, unsigned long, unsigned long, unsigned long); ++extern int lq_free_timer(unsigned int); ++extern int lq_start_timer(unsigned int, int); ++extern int lq_stop_timer(unsigned int); ++extern int lq_reset_counter_flags(u32 timer, u32 flags); ++extern int lq_get_count_value(unsigned int, unsigned long *); ++extern u32 lq_cal_divider(unsigned long); ++extern int lq_set_timer(unsigned int, unsigned int, int, int, unsigned int, unsigned long, unsigned long); ++extern int lq_set_counter(unsigned int timer, unsigned int flag, ++ u32 reload, unsigned long arg1, unsigned long arg2); ++ ++#endif /* __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ */ +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -1,4 +1,4 @@ +-obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o ++obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o timer.o + + obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o + obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o diff --git a/target/linux/lantiq/patches-2.6.39/550-dwc_otg.patch b/target/linux/lantiq/patches-2.6.39/550-dwc_otg.patch new file mode 100644 index 0000000..7747b80 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/550-dwc_otg.patch @@ -0,0 +1,15629 @@ +--- a/drivers/usb/Kconfig ++++ b/drivers/usb/Kconfig +@@ -114,6 +114,8 @@ + + source "drivers/usb/host/Kconfig" + ++source "drivers/usb/dwc_otg/Kconfig" ++ + source "drivers/usb/musb/Kconfig" + + source "drivers/usb/class/Kconfig" +--- a/drivers/usb/Makefile ++++ b/drivers/usb/Makefile +@@ -27,6 +27,8 @@ + + obj-$(CONFIG_USB_WUSB) += wusbcore/ + ++obj-$(CONFIG_DWC_OTG) += dwc_otg/ ++ + obj-$(CONFIG_USB_ACM) += class/ + obj-$(CONFIG_USB_PRINTER) += class/ + obj-$(CONFIG_USB_WDM) += class/ +--- /dev/null ++++ b/drivers/usb/dwc_otg/Kconfig +@@ -0,0 +1,37 @@ ++config DWC_OTG ++ tristate "Synopsis DWC_OTG support" ++ depends on USB ++ help ++ This driver supports Synopsis DWC_OTG IP core ++ embebbed on many SOCs (ralink, infineon, etc) ++ ++choice ++ prompt "USB Operation Mode" ++ depends on DWC_OTG ++ default DWC_OTG_HOST_ONLY ++ ++config DWC_OTG_HOST_ONLY ++ bool "HOST ONLY MODE" ++ depends on DWC_OTG ++ ++#config DWC_OTG_DEVICE_ONLY ++# bool "DEVICE ONLY MODE" ++# depends on DWC_OTG ++endchoice ++ ++choice ++ prompt "Platform" ++ depends on DWC_OTG ++ default DWC_OTG_LANTIQ ++ ++config DWC_OTG_LANTIQ ++ bool "Lantiq" ++ depends on LANTIQ ++ help ++ Danube USB Host Controller ++ platform support ++endchoice ++ ++config DWC_OTG_DEBUG ++ bool "Enable debug mode" ++ depends on DWC_OTG +--- /dev/null ++++ b/drivers/usb/dwc_otg/Makefile +@@ -0,0 +1,39 @@ ++# ++# Makefile for DWC_otg Highspeed USB controller driver ++# ++ ++ifeq ($(CONFIG_DWC_OTG_DEBUG),y) ++EXTRA_CFLAGS += -DDEBUG ++endif ++ ++# Use one of the following flags to compile the software in host-only or ++# device-only mode based on the configuration selected by the user ++ifeq ($(CONFIG_DWC_OTG_HOST_ONLY),y) ++ EXTRA_CFLAGS += -DDWC_OTG_HOST_ONLY -DDWC_HOST_ONLY ++ EXTRA_CFLAGS += -DDWC_OTG_EN_ISOC -DDWC_EN_ISOC ++else ifeq ($(CONFIG_DWC_OTG_DEVICE_ONLY),y) ++ EXTRA_CFLAGS += -DDWC_OTG_DEVICE_ONLY ++else ++ EXTRA_CFLAGS += -DDWC_OTG_MODE ++endif ++ ++# EXTRA_CFLAGS += -DDWC_HS_ELECT_TST ++# EXTRA_CFLAGS += -DDWC_OTG_EXT_CHG_PUMP ++ ++ifeq ($(CONFIG_DWC_OTG_LANTIQ),y) ++ EXTRA_CFLAGS += -Dlinux -D__LINUX__ -DDWC_OTG_IFX -DDWC_OTG_HOST_ONLY -DDWC_HOST_ONLY -D__KERNEL__ ++endif ++ifeq ($(CONFIG_DWC_OTG_LANTIQ),m) ++ EXTRA_CFLAGS += -Dlinux -D__LINUX__ -DDWC_OTG_IFX -DDWC_HOST_ONLY -DMODULE -D__KERNEL__ -DDEBUG ++endif ++ ++obj-$(CONFIG_DWC_OTG) := dwc_otg.o ++dwc_otg-objs := dwc_otg_hcd.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o ++#dwc_otg-objs += dwc_otg_pcd.o dwc_otg_pcd_intr.o ++dwc_otg-objs += dwc_otg_attr.o ++dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o ++dwc_otg-objs += dwc_otg_ifx.o ++dwc_otg-objs += dwc_otg_driver.o ++ ++#obj-$(CONFIG_DWC_OTG_IFX) := dwc_otg_ifx.o ++#dwc_otg_ifx-objs := dwc_otg_ifx.o +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_attr.c +@@ -0,0 +1,802 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_attr.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 537387 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++/** @file ++ * ++ * The diagnostic interface will provide access to the controller for ++ * bringing up the hardware and testing. The Linux driver attributes ++ * feature will be used to provide the Linux Diagnostic ++ * Interface. These attributes are accessed through sysfs. ++ */ ++ ++/** @page "Linux Module Attributes" ++ * ++ * The Linux module attributes feature is used to provide the Linux ++ * Diagnostic Interface. These attributes are accessed through sysfs. ++ * The diagnostic interface will provide access to the controller for ++ * bringing up the hardware and testing. ++ ++ ++ The following table shows the attributes. ++ <table> ++ <tr> ++ <td><b> Name</b></td> ++ <td><b> Description</b></td> ++ <td><b> Access</b></td> ++ </tr> ++ ++ <tr> ++ <td> mode </td> ++ <td> Returns the current mode: 0 for device mode, 1 for host mode</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> hnpcapable </td> ++ <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register. ++ Read returns the current value.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> srpcapable </td> ++ <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register. ++ Read returns the current value.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> hnp </td> ++ <td> Initiates the Host Negotiation Protocol. Read returns the status.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> srp </td> ++ <td> Initiates the Session Request Protocol. Read returns the status.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> buspower </td> ++ <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> bussuspend </td> ++ <td> Suspends the USB bus.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> busconnected </td> ++ <td> Gets the connection status of the bus</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> gotgctl </td> ++ <td> Gets or sets the Core Control Status Register.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> gusbcfg </td> ++ <td> Gets or sets the Core USB Configuration Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> grxfsiz </td> ++ <td> Gets or sets the Receive FIFO Size Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> gnptxfsiz </td> ++ <td> Gets or sets the non-periodic Transmit Size Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> gpvndctl </td> ++ <td> Gets or sets the PHY Vendor Control Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> ggpio </td> ++ <td> Gets the value in the lower 16-bits of the General Purpose IO Register ++ or sets the upper 16 bits.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> guid </td> ++ <td> Gets or sets the value of the User ID Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> gsnpsid </td> ++ <td> Gets the value of the Synopsys ID Regester</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> devspeed </td> ++ <td> Gets or sets the device speed setting in the DCFG register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> enumspeed </td> ++ <td> Gets the device enumeration Speed.</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> hptxfsiz </td> ++ <td> Gets the value of the Host Periodic Transmit FIFO</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> hprt0 </td> ++ <td> Gets or sets the value in the Host Port Control and Status Register</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> regoffset </td> ++ <td> Sets the register offset for the next Register Access</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> regvalue </td> ++ <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> remote_wakeup </td> ++ <td> On read, shows the status of Remote Wakeup. On write, initiates a remote ++ wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote ++ Wakeup signalling bit in the Device Control Register is set for 1 ++ milli-second.</td> ++ <td> Read/Write</td> ++ </tr> ++ ++ <tr> ++ <td> regdump </td> ++ <td> Dumps the contents of core registers.</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> hcddump </td> ++ <td> Dumps the current HCD state.</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> hcd_frrem </td> ++ <td> Shows the average value of the Frame Remaining ++ field in the Host Frame Number/Frame Remaining register when an SOF interrupt ++ occurs. This can be used to determine the average interrupt latency. Also ++ shows the average Frame Remaining value for start_transfer and the "a" and ++ "b" sample points. The "a" and "b" sample points may be used during debugging ++ bto determine how long it takes to execute a section of the HCD code.</td> ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> rd_reg_test </td> ++ <td> Displays the time required to read the GNPTXFSIZ register many times ++ (the output shows the number of times the register is read). ++ <td> Read</td> ++ </tr> ++ ++ <tr> ++ <td> wr_reg_test </td> ++ <td> Displays the time required to write the GNPTXFSIZ register many times ++ (the output shows the number of times the register is written). ++ <td> Read</td> ++ </tr> ++ ++ </table> ++ ++ Example usage: ++ To get the current mode: ++ cat /sys/devices/lm0/mode ++ ++ To power down the USB: ++ echo 0 > /sys/devices/lm0/buspower ++ */ ++#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/types.h> ++#include <linux/stat.h> /* permission constants */ ++ ++#include <asm/io.h> ++ ++#include "dwc_otg_plat.h" ++#include "dwc_otg_attr.h" ++#include "dwc_otg_driver.h" ++// #include "dwc_otg_pcd.h" ++#include "dwc_otg_hcd.h" ++ ++// 20070316, winder added. ++#ifndef SZ_256K ++#define SZ_256K 0x00040000 ++#endif ++ ++/* ++ * MACROs for defining sysfs attribute ++ */ ++#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ ++{ \ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ ++ uint32_t val; \ ++ val = dwc_read_reg32 (_addr_); \ ++ val = (val & (_mask_)) >> _shift_; \ ++ return sprintf (buf, "%s = 0x%x\n", _string_, val); \ ++} ++#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count) \ ++{ \ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ ++ uint32_t set = simple_strtoul(buf, NULL, 16); \ ++ uint32_t clear = set; \ ++ clear = ((~clear) << _shift_) & _mask_; \ ++ set = (set << _shift_) & _mask_; \ ++ dev_dbg(_dev, "Storing Address=0x%08x Set=0x%08x Clear=0x%08x\n", (uint32_t)_addr_, set, clear); \ ++ dwc_modify_reg32(_addr_, clear, set); \ ++ return count; \ ++} ++ ++#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store); ++ ++#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,_addr_,_mask_,_shift_,_string_) \ ++DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL); ++ ++/* ++ * MACROs for defining sysfs attribute for 32-bit registers ++ */ ++#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \ ++static ssize_t _otg_attr_name_##_show (struct device *_dev, struct device_attribute *attr, char *buf) \ ++{ \ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ ++ uint32_t val; \ ++ val = dwc_read_reg32 (_addr_); \ ++ return sprintf (buf, "%s = 0x%08x\n", _string_, val); \ ++} ++#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_addr_,_string_) \ ++static ssize_t _otg_attr_name_##_store (struct device *_dev, struct device_attribute *attr, const char *buf, size_t count) \ ++{ \ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);\ ++ uint32_t val = simple_strtoul(buf, NULL, 16); \ ++ dev_dbg(_dev, "Storing Address=0x%08x Val=0x%08x\n", (uint32_t)_addr_, val); \ ++ dwc_write_reg32(_addr_, val); \ ++ return count; \ ++} ++ ++#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_,_addr_,_string_) \ ++DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \ ++DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_,_addr_,_string_) \ ++DEVICE_ATTR(_otg_attr_name_,0644,_otg_attr_name_##_show,_otg_attr_name_##_store); ++ ++#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_,_addr_,_string_) \ ++DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_,_addr_,_string_) \ ++DEVICE_ATTR(_otg_attr_name_,0444,_otg_attr_name_##_show,NULL); ++ ++ ++/** @name Functions for Show/Store of Attributes */ ++/**@{*/ ++ ++/** ++ * Show the register offset of the Register Access. ++ */ ++static ssize_t regoffset_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ return snprintf(buf, sizeof("0xFFFFFFFF\n")+1,"0x%08x\n", otg_dev->reg_offset); ++} ++ ++/** ++ * Set the register offset for the next Register Access Read/Write ++ */ ++static ssize_t regoffset_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t offset = simple_strtoul(buf, NULL, 16); ++ //dev_dbg(_dev, "Offset=0x%08x\n", offset); ++ if (offset < SZ_256K ) { ++ otg_dev->reg_offset = offset; ++ } ++ else { ++ dev_err( _dev, "invalid offset\n" ); ++ } ++ ++ return count; ++} ++DEVICE_ATTR(regoffset, S_IRUGO|S_IWUSR, regoffset_show, regoffset_store); ++ ++/** ++ * Show the value of the register at the offset in the reg_offset ++ * attribute. ++ */ ++static ssize_t regvalue_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t val; ++ volatile uint32_t *addr; ++ ++ if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) { ++ /* Calculate the address */ ++ addr = (uint32_t*)(otg_dev->reg_offset + ++ (uint8_t*)otg_dev->base); ++ //dev_dbg(_dev, "@0x%08x\n", (unsigned)addr); ++ val = dwc_read_reg32( addr ); ++ return snprintf(buf, sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n")+1, ++ "Reg@0x%06x = 0x%08x\n", ++ otg_dev->reg_offset, val); ++ } ++ else { ++ dev_err(_dev, "Invalid offset (0x%0x)\n", ++ otg_dev->reg_offset); ++ return sprintf(buf, "invalid offset\n" ); ++ } ++} ++ ++/** ++ * Store the value in the register at the offset in the reg_offset ++ * attribute. ++ * ++ */ ++static ssize_t regvalue_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ volatile uint32_t * addr; ++ uint32_t val = simple_strtoul(buf, NULL, 16); ++ //dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val); ++ if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) { ++ /* Calculate the address */ ++ addr = (uint32_t*)(otg_dev->reg_offset + ++ (uint8_t*)otg_dev->base); ++ //dev_dbg(_dev, "@0x%08x\n", (unsigned)addr); ++ dwc_write_reg32( addr, val ); ++ } ++ else { ++ dev_err(_dev, "Invalid Register Offset (0x%08x)\n", ++ otg_dev->reg_offset); ++ } ++ return count; ++} ++DEVICE_ATTR(regvalue, S_IRUGO|S_IWUSR, regvalue_show, regvalue_store); ++ ++/* ++ * Attributes ++ */ ++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<20),20,"Mode"); ++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable,&(otg_dev->core_if->core_global_regs->gusbcfg),(1<<9),9,"Mode"); ++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable,&(otg_dev->core_if->core_global_regs->gusbcfg),(1<<8),8,"Mode"); ++ ++//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); ++//DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); ++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected,otg_dev->core_if->host_if->hprt0,0x01,0,"Bus Connected"); ++ ++DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl,&(otg_dev->core_if->core_global_regs->gotgctl),"GOTGCTL"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,&(otg_dev->core_if->core_global_regs->gusbcfg),"GUSBCFG"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,&(otg_dev->core_if->core_global_regs->grxfsiz),"GRXFSIZ"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,&(otg_dev->core_if->core_global_regs->gnptxfsiz),"GNPTXFSIZ"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,&(otg_dev->core_if->core_global_regs->gpvndctl),"GPVNDCTL"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,&(otg_dev->core_if->core_global_regs->ggpio),"GGPIO"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(guid,&(otg_dev->core_if->core_global_regs->guid),"GUID"); ++DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,&(otg_dev->core_if->core_global_regs->gsnpsid),"GSNPSID"); ++DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed,&(otg_dev->core_if->dev_if->dev_global_regs->dcfg),0x3,0,"Device Speed"); ++DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed,&(otg_dev->core_if->dev_if->dev_global_regs->dsts),0x6,1,"Device Enumeration Speed"); ++ ++DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,&(otg_dev->core_if->core_global_regs->hptxfsiz),"HPTXFSIZ"); ++DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0,otg_dev->core_if->host_if->hprt0,"HPRT0"); ++ ++ ++/** ++ * @todo Add code to initiate the HNP. ++ */ ++/** ++ * Show the HNP status bit ++ */ ++static ssize_t hnp_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ gotgctl_data_t val; ++ val.d32 = dwc_read_reg32 (&(otg_dev->core_if->core_global_regs->gotgctl)); ++ return sprintf (buf, "HstNegScs = 0x%x\n", val.b.hstnegscs); ++} ++ ++/** ++ * Set the HNP Request bit ++ */ ++static ssize_t hnp_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t in = simple_strtoul(buf, NULL, 16); ++ uint32_t *addr = (uint32_t *)&(otg_dev->core_if->core_global_regs->gotgctl); ++ gotgctl_data_t mem; ++ mem.d32 = dwc_read_reg32(addr); ++ mem.b.hnpreq = in; ++ dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32); ++ dwc_write_reg32(addr, mem.d32); ++ return count; ++} ++DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store); ++ ++/** ++ * @todo Add code to initiate the SRP. ++ */ ++/** ++ * Show the SRP status bit ++ */ ++static ssize_t srp_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++#ifndef DWC_HOST_ONLY ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ gotgctl_data_t val; ++ val.d32 = dwc_read_reg32 (&(otg_dev->core_if->core_global_regs->gotgctl)); ++ return sprintf (buf, "SesReqScs = 0x%x\n", val.b.sesreqscs); ++#else ++ return sprintf(buf, "Host Only Mode!\n"); ++#endif ++} ++ ++/** ++ * Set the SRP Request bit ++ */ ++static ssize_t srp_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++#ifndef DWC_HOST_ONLY ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ dwc_otg_pcd_initiate_srp(otg_dev->pcd); ++#endif ++ return count; ++} ++DEVICE_ATTR(srp, 0644, srp_show, srp_store); ++ ++/** ++ * @todo Need to do more for power on/off? ++ */ ++/** ++ * Show the Bus Power status ++ */ ++static ssize_t buspower_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ hprt0_data_t val; ++ val.d32 = dwc_read_reg32 (otg_dev->core_if->host_if->hprt0); ++ return sprintf (buf, "Bus Power = 0x%x\n", val.b.prtpwr); ++} ++ ++ ++/** ++ * Set the Bus Power status ++ */ ++static ssize_t buspower_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t on = simple_strtoul(buf, NULL, 16); ++ uint32_t *addr = (uint32_t *)otg_dev->core_if->host_if->hprt0; ++ hprt0_data_t mem; ++ ++ mem.d32 = dwc_read_reg32(addr); ++ mem.b.prtpwr = on; ++ ++ //dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32); ++ dwc_write_reg32(addr, mem.d32); ++ ++ return count; ++} ++DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store); ++ ++/** ++ * @todo Need to do more for suspend? ++ */ ++/** ++ * Show the Bus Suspend status ++ */ ++static ssize_t bussuspend_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ hprt0_data_t val; ++ val.d32 = dwc_read_reg32 (otg_dev->core_if->host_if->hprt0); ++ return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); ++} ++ ++/** ++ * Set the Bus Suspend status ++ */ ++static ssize_t bussuspend_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t in = simple_strtoul(buf, NULL, 16); ++ uint32_t *addr = (uint32_t *)otg_dev->core_if->host_if->hprt0; ++ hprt0_data_t mem; ++ mem.d32 = dwc_read_reg32(addr); ++ mem.b.prtsusp = in; ++ dev_dbg(_dev, "Storing Address=0x%08x Data=0x%08x\n", (uint32_t)addr, mem.d32); ++ dwc_write_reg32(addr, mem.d32); ++ return count; ++} ++DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store); ++ ++/** ++ * Show the status of Remote Wakeup. ++ */ ++static ssize_t remote_wakeup_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++#ifndef DWC_HOST_ONLY ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ dctl_data_t val; ++ val.d32 = dwc_read_reg32( &otg_dev->core_if->dev_if->dev_global_regs->dctl); ++ return sprintf( buf, "Remote Wakeup = %d Enabled = %d\n", ++ val.b.rmtwkupsig, otg_dev->pcd->remote_wakeup_enable); ++#else ++ return sprintf(buf, "Host Only Mode!\n"); ++#endif ++} ++ ++/** ++ * Initiate a remote wakeup of the host. The Device control register ++ * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable ++ * flag is set. ++ * ++ */ ++static ssize_t remote_wakeup_store( struct device *_dev, struct device_attribute *attr, const char *buf, ++ size_t count ) ++{ ++#ifndef DWC_HOST_ONLY ++ uint32_t val = simple_strtoul(buf, NULL, 16); ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ if (val&1) { ++ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1); ++ } ++ else { ++ dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0); ++ } ++#endif ++ return count; ++} ++DEVICE_ATTR(remote_wakeup, S_IRUGO|S_IWUSR, remote_wakeup_show, ++ remote_wakeup_store); ++ ++/** ++ * Dump global registers and either host or device registers (depending on the ++ * current mode of the core). ++ */ ++static ssize_t regdump_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++#ifdef DEBUG ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ printk("%s otg_dev=0x%p\n", __FUNCTION__, otg_dev); ++ ++ dwc_otg_dump_global_registers( otg_dev->core_if); ++ if (dwc_otg_is_host_mode(otg_dev->core_if)) { ++ dwc_otg_dump_host_registers( otg_dev->core_if); ++ } else { ++ dwc_otg_dump_dev_registers( otg_dev->core_if); ++ } ++#endif ++ ++ return sprintf( buf, "Register Dump\n" ); ++} ++ ++DEVICE_ATTR(regdump, S_IRUGO|S_IWUSR, regdump_show, 0); ++ ++/** ++ * Dump the current hcd state. ++ */ ++static ssize_t hcddump_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++#ifndef DWC_DEVICE_ONLY ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ dwc_otg_hcd_dump_state(otg_dev->hcd); ++#endif ++ return sprintf( buf, "HCD Dump\n" ); ++} ++ ++DEVICE_ATTR(hcddump, S_IRUGO|S_IWUSR, hcddump_show, 0); ++ ++/** ++ * Dump the average frame remaining at SOF. This can be used to ++ * determine average interrupt latency. Frame remaining is also shown for ++ * start transfer and two additional sample points. ++ */ ++static ssize_t hcd_frrem_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++#ifndef DWC_DEVICE_ONLY ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ dwc_otg_hcd_dump_frrem(otg_dev->hcd); ++#endif ++ return sprintf( buf, "HCD Dump Frame Remaining\n" ); ++} ++ ++DEVICE_ATTR(hcd_frrem, S_IRUGO|S_IWUSR, hcd_frrem_show, 0); ++ ++/** ++ * Displays the time required to read the GNPTXFSIZ register many times (the ++ * output shows the number of times the register is read). ++ */ ++#define RW_REG_COUNT 10000000 ++#define MSEC_PER_JIFFIE 1000/HZ ++static ssize_t rd_reg_test_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ int i; ++ int time; ++ int start_jiffies; ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ ++ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n", ++ HZ, MSEC_PER_JIFFIE, loops_per_jiffy); ++ start_jiffies = jiffies; ++ for (i = 0; i < RW_REG_COUNT; i++) { ++ dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz); ++ } ++ time = jiffies - start_jiffies; ++ return sprintf( buf, "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n", ++ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time ); ++} ++ ++DEVICE_ATTR(rd_reg_test, S_IRUGO|S_IWUSR, rd_reg_test_show, 0); ++ ++/** ++ * Displays the time required to write the GNPTXFSIZ register many times (the ++ * output shows the number of times the register is written). ++ */ ++static ssize_t wr_reg_test_show( struct device *_dev, struct device_attribute *attr, char *buf) ++{ ++ int i; ++ int time; ++ int start_jiffies; ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ uint32_t reg_val; ++ ++ printk("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n", ++ HZ, MSEC_PER_JIFFIE, loops_per_jiffy); ++ reg_val = dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz); ++ start_jiffies = jiffies; ++ for (i = 0; i < RW_REG_COUNT; i++) { ++ dwc_write_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz, reg_val); ++ } ++ time = jiffies - start_jiffies; ++ return sprintf( buf, "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n", ++ RW_REG_COUNT, time * MSEC_PER_JIFFIE, time); ++} ++ ++DEVICE_ATTR(wr_reg_test, S_IRUGO|S_IWUSR, wr_reg_test_show, 0); ++/**@}*/ ++ ++/** ++ * Create the device files ++ */ ++void dwc_otg_attr_create (struct device *_dev) ++{ ++ int retval; ++ ++ retval = device_create_file(_dev, &dev_attr_regoffset); ++ retval += device_create_file(_dev, &dev_attr_regvalue); ++ retval += device_create_file(_dev, &dev_attr_mode); ++ retval += device_create_file(_dev, &dev_attr_hnpcapable); ++ retval += device_create_file(_dev, &dev_attr_srpcapable); ++ retval += device_create_file(_dev, &dev_attr_hnp); ++ retval += device_create_file(_dev, &dev_attr_srp); ++ retval += device_create_file(_dev, &dev_attr_buspower); ++ retval += device_create_file(_dev, &dev_attr_bussuspend); ++ retval += device_create_file(_dev, &dev_attr_busconnected); ++ retval += device_create_file(_dev, &dev_attr_gotgctl); ++ retval += device_create_file(_dev, &dev_attr_gusbcfg); ++ retval += device_create_file(_dev, &dev_attr_grxfsiz); ++ retval += device_create_file(_dev, &dev_attr_gnptxfsiz); ++ retval += device_create_file(_dev, &dev_attr_gpvndctl); ++ retval += device_create_file(_dev, &dev_attr_ggpio); ++ retval += device_create_file(_dev, &dev_attr_guid); ++ retval += device_create_file(_dev, &dev_attr_gsnpsid); ++ retval += device_create_file(_dev, &dev_attr_devspeed); ++ retval += device_create_file(_dev, &dev_attr_enumspeed); ++ retval += device_create_file(_dev, &dev_attr_hptxfsiz); ++ retval += device_create_file(_dev, &dev_attr_hprt0); ++ retval += device_create_file(_dev, &dev_attr_remote_wakeup); ++ retval += device_create_file(_dev, &dev_attr_regdump); ++ retval += device_create_file(_dev, &dev_attr_hcddump); ++ retval += device_create_file(_dev, &dev_attr_hcd_frrem); ++ retval += device_create_file(_dev, &dev_attr_rd_reg_test); ++ retval += device_create_file(_dev, &dev_attr_wr_reg_test); ++ ++ if(retval != 0) ++ { ++ DWC_PRINT("cannot create sysfs device files.\n"); ++ // DWC_PRINT("killing own sysfs device files!\n"); ++ dwc_otg_attr_remove(_dev); ++ } ++} ++ ++/** ++ * Remove the device files ++ */ ++void dwc_otg_attr_remove (struct device *_dev) ++{ ++ device_remove_file(_dev, &dev_attr_regoffset); ++ device_remove_file(_dev, &dev_attr_regvalue); ++ device_remove_file(_dev, &dev_attr_mode); ++ device_remove_file(_dev, &dev_attr_hnpcapable); ++ device_remove_file(_dev, &dev_attr_srpcapable); ++ device_remove_file(_dev, &dev_attr_hnp); ++ device_remove_file(_dev, &dev_attr_srp); ++ device_remove_file(_dev, &dev_attr_buspower); ++ device_remove_file(_dev, &dev_attr_bussuspend); ++ device_remove_file(_dev, &dev_attr_busconnected); ++ device_remove_file(_dev, &dev_attr_gotgctl); ++ device_remove_file(_dev, &dev_attr_gusbcfg); ++ device_remove_file(_dev, &dev_attr_grxfsiz); ++ device_remove_file(_dev, &dev_attr_gnptxfsiz); ++ device_remove_file(_dev, &dev_attr_gpvndctl); ++ device_remove_file(_dev, &dev_attr_ggpio); ++ device_remove_file(_dev, &dev_attr_guid); ++ device_remove_file(_dev, &dev_attr_gsnpsid); ++ device_remove_file(_dev, &dev_attr_devspeed); ++ device_remove_file(_dev, &dev_attr_enumspeed); ++ device_remove_file(_dev, &dev_attr_hptxfsiz); ++ device_remove_file(_dev, &dev_attr_hprt0); ++ device_remove_file(_dev, &dev_attr_remote_wakeup); ++ device_remove_file(_dev, &dev_attr_regdump); ++ device_remove_file(_dev, &dev_attr_hcddump); ++ device_remove_file(_dev, &dev_attr_hcd_frrem); ++ device_remove_file(_dev, &dev_attr_rd_reg_test); ++ device_remove_file(_dev, &dev_attr_wr_reg_test); ++} +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_attr.h +@@ -0,0 +1,67 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_attr.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 510275 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#if !defined(__DWC_OTG_ATTR_H__) ++#define __DWC_OTG_ATTR_H__ ++ ++/** @file ++ * This file contains the interface to the Linux device attributes. ++ */ ++extern struct device_attribute dev_attr_regoffset; ++extern struct device_attribute dev_attr_regvalue; ++ ++extern struct device_attribute dev_attr_mode; ++extern struct device_attribute dev_attr_hnpcapable; ++extern struct device_attribute dev_attr_srpcapable; ++extern struct device_attribute dev_attr_hnp; ++extern struct device_attribute dev_attr_srp; ++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_gotgctl; ++extern struct device_attribute dev_attr_gusbcfg; ++extern struct device_attribute dev_attr_grxfsiz; ++extern struct device_attribute dev_attr_gnptxfsiz; ++extern struct device_attribute dev_attr_gpvndctl; ++extern struct device_attribute dev_attr_ggpio; ++extern struct device_attribute dev_attr_guid; ++extern struct device_attribute dev_attr_gsnpsid; ++extern struct device_attribute dev_attr_devspeed; ++extern struct device_attribute dev_attr_enumspeed; ++extern struct device_attribute dev_attr_hptxfsiz; ++extern struct device_attribute dev_attr_hprt0; ++ ++void dwc_otg_attr_create (struct device *_dev); ++void dwc_otg_attr_remove (struct device *_dev); ++ ++#endif +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_cil.c +@@ -0,0 +1,3025 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 631780 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++/** @file ++ * ++ * The Core Interface Layer provides basic services for accessing and ++ * managing the DWC_otg hardware. These services are used by both the ++ * Host Controller Driver and the Peripheral Controller Driver. ++ * ++ * The CIL manages the memory map for the core so that the HCD and PCD ++ * don't have to do this separately. It also handles basic tasks like ++ * reading/writing the registers and data FIFOs in the controller. ++ * Some of the data access functions provide encapsulation of several ++ * operations required to perform a task, such as writing multiple ++ * registers to start a transfer. Finally, the CIL performs basic ++ * services that are not specific to either the host or device modes ++ * of operation. These services include management of the OTG Host ++ * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A ++ * Diagnostic API is also provided to allow testing of the controller ++ * hardware. ++ * ++ * The Core Interface Layer has the following requirements: ++ * - Provides basic controller operations. ++ * - Minimal use of OS services. ++ * - The OS services used will be abstracted by using inline functions ++ * or macros. ++ * ++ */ ++#include <asm/unaligned.h> ++ ++#ifdef DEBUG ++#include <linux/jiffies.h> ++#endif ++ ++#include "dwc_otg_plat.h" ++ ++#include "dwc_otg_regs.h" ++#include "dwc_otg_cil.h" ++ ++/** ++ * This function is called to initialize the DWC_otg 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 DWC_otg controller registers. The core_params ++ * argument holds the parameters that specify how the core should be ++ * configured. ++ * ++ * @param[in] _reg_base_addr Base address of DWC_otg core registers ++ * @param[in] _core_params Pointer to the core configuration parameters ++ * ++ */ ++dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t *_reg_base_addr, ++ dwc_otg_core_params_t *_core_params) ++{ ++ dwc_otg_core_if_t *core_if = 0; ++ dwc_otg_dev_if_t *dev_if = 0; ++ dwc_otg_host_if_t *host_if = 0; ++ uint8_t *reg_base = (uint8_t *)_reg_base_addr; ++ int i = 0; ++ ++ DWC_DEBUGPL(DBG_CILV, "%s(%p,%p)\n", __func__, _reg_base_addr, _core_params); ++ ++ core_if = kmalloc( sizeof(dwc_otg_core_if_t), GFP_KERNEL); ++ if (core_if == 0) { ++ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_core_if_t failed\n"); ++ return 0; ++ } ++ memset(core_if, 0, sizeof(dwc_otg_core_if_t)); ++ ++ core_if->core_params = _core_params; ++ core_if->core_global_regs = (dwc_otg_core_global_regs_t *)reg_base; ++ /* ++ * Allocate the Device Mode structures. ++ */ ++ dev_if = kmalloc( sizeof(dwc_otg_dev_if_t), GFP_KERNEL); ++ if (dev_if == 0) { ++ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_dev_if_t failed\n"); ++ kfree( core_if ); ++ return 0; ++ } ++ ++ dev_if->dev_global_regs = ++ (dwc_otg_device_global_regs_t *)(reg_base + DWC_DEV_GLOBAL_REG_OFFSET); ++ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) { ++ dev_if->in_ep_regs[i] = (dwc_otg_dev_in_ep_regs_t *) ++ (reg_base + DWC_DEV_IN_EP_REG_OFFSET + ++ (i * DWC_EP_REG_OFFSET)); ++ ++ dev_if->out_ep_regs[i] = (dwc_otg_dev_out_ep_regs_t *) ++ (reg_base + DWC_DEV_OUT_EP_REG_OFFSET + ++ (i * DWC_EP_REG_OFFSET)); ++ DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n", ++ i, &dev_if->in_ep_regs[i]->diepctl); ++ DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n", ++ i, &dev_if->out_ep_regs[i]->doepctl); ++ } ++ dev_if->speed = 0; // unknown ++ //dev_if->num_eps = MAX_EPS_CHANNELS; ++ //dev_if->num_perio_eps = 0; ++ ++ core_if->dev_if = dev_if; ++ /* ++ * Allocate the Host Mode structures. ++ */ ++ host_if = kmalloc( sizeof(dwc_otg_host_if_t), GFP_KERNEL); ++ if (host_if == 0) { ++ DWC_DEBUGPL(DBG_CIL, "Allocation of dwc_otg_host_if_t failed\n"); ++ kfree( dev_if ); ++ kfree( core_if ); ++ return 0; ++ } ++ ++ host_if->host_global_regs = (dwc_otg_host_global_regs_t *) ++ (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET); ++ host_if->hprt0 = (uint32_t*)(reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET); ++ for (i=0; i<MAX_EPS_CHANNELS; i++) { ++ host_if->hc_regs[i] = (dwc_otg_hc_regs_t *) ++ (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET + ++ (i * DWC_OTG_CHAN_REGS_OFFSET)); ++ DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n", ++ i, &host_if->hc_regs[i]->hcchar); ++ } ++ host_if->num_host_channels = MAX_EPS_CHANNELS; ++ core_if->host_if = host_if; ++ ++ for (i=0; i<MAX_EPS_CHANNELS; i++) { ++ core_if->data_fifo[i] = ++ (uint32_t *)(reg_base + DWC_OTG_DATA_FIFO_OFFSET + ++ (i * DWC_OTG_DATA_FIFO_SIZE)); ++ DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08x\n", ++ i, (unsigned)core_if->data_fifo[i]); ++ } // for loop. ++ ++ core_if->pcgcctl = (uint32_t*)(reg_base + DWC_OTG_PCGCCTL_OFFSET); ++ ++ /* ++ * Store the contents of the hardware configuration registers here for ++ * easy access later. ++ */ ++ core_if->hwcfg1.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg1); ++ core_if->hwcfg2.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg2); ++ core_if->hwcfg3.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg3); ++ core_if->hwcfg4.d32 = dwc_read_reg32(&core_if->core_global_regs->ghwcfg4); ++ ++ DWC_DEBUGPL(DBG_CILV,"hwcfg1=%08x\n",core_if->hwcfg1.d32); ++ DWC_DEBUGPL(DBG_CILV,"hwcfg2=%08x\n",core_if->hwcfg2.d32); ++ DWC_DEBUGPL(DBG_CILV,"hwcfg3=%08x\n",core_if->hwcfg3.d32); ++ DWC_DEBUGPL(DBG_CILV,"hwcfg4=%08x\n",core_if->hwcfg4.d32); ++ ++ ++ DWC_DEBUGPL(DBG_CILV,"op_mode=%0x\n",core_if->hwcfg2.b.op_mode); ++ DWC_DEBUGPL(DBG_CILV,"arch=%0x\n",core_if->hwcfg2.b.architecture); ++ DWC_DEBUGPL(DBG_CILV,"num_dev_ep=%d\n",core_if->hwcfg2.b.num_dev_ep); ++ DWC_DEBUGPL(DBG_CILV,"num_host_chan=%d\n",core_if->hwcfg2.b.num_host_chan); ++ DWC_DEBUGPL(DBG_CILV,"nonperio_tx_q_depth=0x%0x\n",core_if->hwcfg2.b.nonperio_tx_q_depth); ++ DWC_DEBUGPL(DBG_CILV,"host_perio_tx_q_depth=0x%0x\n",core_if->hwcfg2.b.host_perio_tx_q_depth); ++ DWC_DEBUGPL(DBG_CILV,"dev_token_q_depth=0x%0x\n",core_if->hwcfg2.b.dev_token_q_depth); ++ ++ DWC_DEBUGPL(DBG_CILV,"Total FIFO SZ=%d\n", core_if->hwcfg3.b.dfifo_depth); ++ DWC_DEBUGPL(DBG_CILV,"xfer_size_cntr_width=%0x\n", core_if->hwcfg3.b.xfer_size_cntr_width); ++ ++ /* ++ * Set the SRP sucess bit for FS-I2c ++ */ ++ core_if->srp_success = 0; ++ core_if->srp_timer_started = 0; ++ ++ return core_if; ++} ++/** ++ * This function frees the structures allocated by dwc_otg_cil_init(). ++ * ++ * @param[in] _core_if The core interface pointer returned from ++ * dwc_otg_cil_init(). ++ * ++ */ ++void dwc_otg_cil_remove( dwc_otg_core_if_t *_core_if ) ++{ ++ /* Disable all interrupts */ ++ dwc_modify_reg32( &_core_if->core_global_regs->gahbcfg, 1, 0); ++ dwc_write_reg32( &_core_if->core_global_regs->gintmsk, 0); ++ ++ if ( _core_if->dev_if ) { ++ kfree( _core_if->dev_if ); ++ } ++ if ( _core_if->host_if ) { ++ kfree( _core_if->host_if ); ++ } ++ kfree( _core_if ); ++} ++ ++/** ++ * This function enables the controller's Global Interrupt in the AHB Config ++ * register. ++ * ++ * @param[in] _core_if Programming view of DWC_otg controller. ++ */ ++extern void dwc_otg_enable_global_interrupts( dwc_otg_core_if_t *_core_if ) ++{ ++ gahbcfg_data_t ahbcfg = { .d32 = 0}; ++ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ ++ dwc_modify_reg32(&_core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32); ++} ++/** ++ * This function disables the controller's Global Interrupt in the AHB Config ++ * register. ++ * ++ * @param[in] _core_if Programming view of DWC_otg controller. ++ */ ++extern void dwc_otg_disable_global_interrupts( dwc_otg_core_if_t *_core_if ) ++{ ++ gahbcfg_data_t ahbcfg = { .d32 = 0}; ++ ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ ++ dwc_modify_reg32(&_core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0); ++} ++ ++/** ++ * This function initializes the commmon interrupts, used in both ++ * device and host modes. ++ * ++ * @param[in] _core_if Programming view of the DWC_otg controller ++ * ++ */ ++static void dwc_otg_enable_common_interrupts(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = ++ _core_if->core_global_regs; ++ gintmsk_data_t intr_mask = { .d32 = 0}; ++ /* Clear any pending OTG Interrupts */ ++ dwc_write_reg32( &global_regs->gotgint, 0xFFFFFFFF); ++ /* Clear any pending interrupts */ ++ dwc_write_reg32( &global_regs->gintsts, 0xFFFFFFFF); ++ /* ++ * Enable the interrupts in the GINTMSK. ++ */ ++ intr_mask.b.modemismatch = 1; ++ intr_mask.b.otgintr = 1; ++ if (!_core_if->dma_enable) { ++ 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; ++ intr_mask.b.sessreqintr = 1; ++ dwc_write_reg32( &global_regs->gintmsk, intr_mask.d32); ++} ++ ++/** ++ * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY ++ * type. ++ */ ++static void init_fslspclksel(dwc_otg_core_if_t *_core_if) ++{ ++ uint32_t val; ++ hcfg_data_t hcfg; ++ ++ if (((_core_if->hwcfg2.b.hs_phy_type == 2) && ++ (_core_if->hwcfg2.b.fs_phy_type == 1) && ++ (_core_if->core_params->ulpi_fs_ls)) || ++ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) ++ { ++ /* Full speed PHY */ ++ val = DWC_HCFG_48_MHZ; ++ } else { ++ /* High speed PHY running at full speed or high speed */ ++ val = DWC_HCFG_30_60_MHZ; ++ } ++ ++ DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val); ++ hcfg.d32 = dwc_read_reg32(&_core_if->host_if->host_global_regs->hcfg); ++ hcfg.b.fslspclksel = val; ++ dwc_write_reg32(&_core_if->host_if->host_global_regs->hcfg, hcfg.d32); ++} ++ ++/** ++ * Initializes the DevSpd field of the DCFG register depending on the PHY type ++ * and the enumeration speed of the device. ++ */ ++static void init_devspd(dwc_otg_core_if_t *_core_if) ++{ ++ uint32_t val; ++ dcfg_data_t dcfg; ++ ++ if (((_core_if->hwcfg2.b.hs_phy_type == 2) && ++ (_core_if->hwcfg2.b.fs_phy_type == 1) && ++ (_core_if->core_params->ulpi_fs_ls)) || ++ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) ++ { ++ /* Full speed PHY */ ++ val = 0x3; ++ } else if (_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) { ++ /* High speed PHY running at full speed */ ++ val = 0x1; ++ } else { ++ /* High speed PHY running at high speed */ ++ val = 0x0; ++ } ++ ++ DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val); ++ dcfg.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dcfg); ++ dcfg.b.devspd = val; ++ dwc_write_reg32(&_core_if->dev_if->dev_global_regs->dcfg, dcfg.d32); ++} ++ ++/** ++ * This function calculates the number of IN EPS ++ * using GHWCFG1 and GHWCFG2 registers values ++ * ++ * @param _pcd the pcd structure. ++ */ ++static uint32_t calc_num_in_eps(dwc_otg_core_if_t * _core_if) ++{ ++ uint32_t num_in_eps = 0; ++ uint32_t num_eps = _core_if->hwcfg2.b.num_dev_ep; ++ uint32_t hwcfg1 = _core_if->hwcfg1.d32 >> 2; ++ uint32_t num_tx_fifos = _core_if->hwcfg4.b.num_in_eps; ++ int i; ++ for (i = 0; i < num_eps; ++i) { ++ if (!(hwcfg1 & 0x1)) ++ num_in_eps++; ++ hwcfg1 >>= 2; ++ } ++ if (_core_if->hwcfg4.b.ded_fifo_en) { ++ num_in_eps = (num_in_eps > num_tx_fifos) ? num_tx_fifos : num_in_eps; ++ } ++ return num_in_eps; ++} ++ ++ ++/** ++ * This function calculates the number of OUT EPS ++ * using GHWCFG1 and GHWCFG2 registers values ++ * ++ * @param _pcd the pcd structure. ++ */ ++static uint32_t calc_num_out_eps(dwc_otg_core_if_t * _core_if) ++{ ++ uint32_t num_out_eps = 0; ++ uint32_t num_eps = _core_if->hwcfg2.b.num_dev_ep; ++ uint32_t hwcfg1 = _core_if->hwcfg1.d32 >> 2; ++ int i; ++ for (i = 0; i < num_eps; ++i) { ++ if (!(hwcfg1 & 0x2)) ++ num_out_eps++; ++ hwcfg1 >>= 2; ++ } ++ return num_out_eps; ++} ++/** ++ * This function initializes the DWC_otg controller registers and ++ * prepares the core for device mode or host mode operation. ++ * ++ * @param _core_if Programming view of the DWC_otg controller ++ * ++ */ ++void dwc_otg_core_init(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t * global_regs = _core_if->core_global_regs; ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ int i = 0; ++ gahbcfg_data_t ahbcfg = { .d32 = 0}; ++ gusbcfg_data_t usbcfg = { .d32 = 0 }; ++ gi2cctl_data_t i2cctl = {.d32 = 0}; ++ ++ DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p)\n",_core_if); ++ ++ /* Common Initialization */ ++ ++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); ++ DWC_DEBUGPL(DBG_CIL, "USB config register: 0x%08x\n", usbcfg.d32); ++ ++ /* Program the ULPI External VBUS bit if needed */ ++ //usbcfg.b.ulpi_ext_vbus_drv = 1; ++ //usbcfg.b.ulpi_ext_vbus_drv = 0; ++ usbcfg.b.ulpi_ext_vbus_drv = ++ (_core_if->core_params->phy_ulpi_ext_vbus == DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0; ++ ++ /* Set external TS Dline pulsing */ ++ usbcfg.b.term_sel_dl_pulse = (_core_if->core_params->ts_dline == 1) ? 1 : 0; ++ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Reset the Controller */ ++ dwc_otg_core_reset( _core_if ); ++ ++ /* Initialize parameters from Hardware configuration registers. */ ++#if 0 ++ dev_if->num_eps = _core_if->hwcfg2.b.num_dev_ep; ++ dev_if->num_perio_eps = _core_if->hwcfg4.b.num_dev_perio_in_ep; ++#else ++ dev_if->num_in_eps = calc_num_in_eps(_core_if); ++ dev_if->num_out_eps = calc_num_out_eps(_core_if); ++#endif ++ DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n", ++ _core_if->hwcfg4.b.num_dev_perio_in_ep); ++ DWC_DEBUGPL(DBG_CIL, "Is power optimization enabled? %s\n", ++ _core_if->hwcfg4.b.power_optimiz ? "Yes" : "No"); ++ DWC_DEBUGPL(DBG_CIL, "vbus_valid filter enabled? %s\n", ++ _core_if->hwcfg4.b.vbus_valid_filt_en ? "Yes" : "No"); ++ DWC_DEBUGPL(DBG_CIL, "iddig filter enabled? %s\n", ++ _core_if->hwcfg4.b.iddig_filt_en ? "Yes" : "No"); ++ ++ DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",_core_if->hwcfg4.b.num_dev_perio_in_ep); ++ for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) { ++ dev_if->perio_tx_fifo_size[i] = ++ dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16; ++ DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n", i, ++ dev_if->perio_tx_fifo_size[i]); ++ } ++ for (i = 0; i < _core_if->hwcfg4.b.num_in_eps; i++) { ++ dev_if->tx_fifo_size[i] = ++ dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i]) >> 16; ++ DWC_DEBUGPL(DBG_CIL, "Tx FIFO SZ #%d=0x%0x\n", i, ++ dev_if->perio_tx_fifo_size[i]); ++ } ++ ++ _core_if->total_fifo_size = _core_if->hwcfg3.b.dfifo_depth; ++ _core_if->rx_fifo_size = dwc_read_reg32(&global_regs->grxfsiz); ++ _core_if->nperio_tx_fifo_size = dwc_read_reg32(&global_regs->gnptxfsiz) >> 16; ++ ++ DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", _core_if->total_fifo_size); ++ DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", _core_if->rx_fifo_size); ++ DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n", _core_if->nperio_tx_fifo_size); ++ ++ /* This programming sequence needs to happen in FS mode before any other ++ * programming occurs */ ++ if ((_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) && ++ (_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) { ++ /* If FS mode with FS PHY */ ++ ++ /* core_init() is now called on every switch so only call the ++ * following for the first time through. */ ++ if (!_core_if->phy_init_done) { ++ _core_if->phy_init_done = 1; ++ DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n"); ++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); ++ usbcfg.b.physel = 1; ++ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Reset after a PHY select */ ++ dwc_otg_core_reset( _core_if ); ++ } ++ ++ /* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also ++ * do this on HNP Dev/Host mode switches (done in dev_init and ++ * host_init). */ ++ if (dwc_otg_is_host_mode(_core_if)) { ++ DWC_DEBUGPL(DBG_CIL, "host mode\n"); ++ init_fslspclksel(_core_if); ++ } else { ++ DWC_DEBUGPL(DBG_CIL, "device mode\n"); ++ init_devspd(_core_if); ++ } ++ ++ if (_core_if->core_params->i2c_enable) { ++ DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n"); ++ /* Program GUSBCFG.OtgUtmifsSel to I2C */ ++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); ++ usbcfg.b.otgutmifssel = 1; ++ dwc_write_reg32 (&global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Program GI2CCTL.I2CEn */ ++ i2cctl.d32 = dwc_read_reg32(&global_regs->gi2cctl); ++ i2cctl.b.i2cdevaddr = 1; ++ i2cctl.b.i2cen = 0; ++ dwc_write_reg32 (&global_regs->gi2cctl, i2cctl.d32); ++ i2cctl.b.i2cen = 1; ++ dwc_write_reg32 (&global_regs->gi2cctl, i2cctl.d32); ++ } ++ ++ } /* endif speed == DWC_SPEED_PARAM_FULL */ ++ else { ++ /* High speed PHY. */ ++ if (!_core_if->phy_init_done) { ++ _core_if->phy_init_done = 1; ++ DWC_DEBUGPL(DBG_CIL, "High spped PHY\n"); ++ /* 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 = _core_if->core_params->phy_type; ++ if (usbcfg.b.ulpi_utmi_sel == 2) { // winder ++ DWC_DEBUGPL(DBG_CIL, "ULPI\n"); ++ /* ULPI interface */ ++ usbcfg.b.phyif = 0; ++ usbcfg.b.ddrsel = _core_if->core_params->phy_ulpi_ddr; ++ } else { ++ /* UTMI+ interface */ ++ if (_core_if->core_params->phy_utmi_width == 16) { ++ usbcfg.b.phyif = 1; ++ DWC_DEBUGPL(DBG_CIL, "UTMI+ 16\n"); ++ } else { ++ DWC_DEBUGPL(DBG_CIL, "UTMI+ 8\n"); ++ usbcfg.b.phyif = 0; ++ } ++ } ++ dwc_write_reg32( &global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Reset after setting the PHY parameters */ ++ dwc_otg_core_reset( _core_if ); ++ } ++ } ++ ++ if ((_core_if->hwcfg2.b.hs_phy_type == 2) && ++ (_core_if->hwcfg2.b.fs_phy_type == 1) && ++ (_core_if->core_params->ulpi_fs_ls)) ++ { ++ DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n"); ++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); ++ usbcfg.b.ulpi_fsls = 1; ++ usbcfg.b.ulpi_clk_sus_m = 1; ++ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); ++ } else { ++ DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS=0\n"); ++ usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg); ++ usbcfg.b.ulpi_fsls = 0; ++ usbcfg.b.ulpi_clk_sus_m = 0; ++ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); ++ } ++ ++ /* Program the GAHBCFG Register.*/ ++ switch (_core_if->hwcfg2.b.architecture){ ++ ++ case DWC_SLAVE_ONLY_ARCH: ++ DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n"); ++ ahbcfg.b.nptxfemplvl_txfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY; ++ ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY; ++ _core_if->dma_enable = 0; ++ break; ++ ++ case DWC_EXT_DMA_ARCH: ++ DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n"); ++ ahbcfg.b.hburstlen = _core_if->core_params->dma_burst_size; ++ _core_if->dma_enable = (_core_if->core_params->dma_enable != 0); ++ break; ++ ++ case DWC_INT_DMA_ARCH: ++ DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n"); ++ //ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR; ++ ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR4; ++ _core_if->dma_enable = (_core_if->core_params->dma_enable != 0); ++ break; ++ } ++ ahbcfg.b.dmaenable = _core_if->dma_enable; ++ dwc_write_reg32(&global_regs->gahbcfg, ahbcfg.d32); ++ _core_if->en_multiple_tx_fifo = _core_if->hwcfg4.b.ded_fifo_en; ++ ++ /* ++ * Program the GUSBCFG register. ++ */ ++ usbcfg.d32 = dwc_read_reg32( &global_regs->gusbcfg ); ++ ++ switch (_core_if->hwcfg2.b.op_mode) { ++ case DWC_MODE_HNP_SRP_CAPABLE: ++ usbcfg.b.hnpcap = (_core_if->core_params->otg_cap == ++ DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE); ++ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != ++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); ++ break; ++ ++ case DWC_MODE_SRP_ONLY_CAPABLE: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != ++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); ++ break; ++ ++ case DWC_MODE_NO_HNP_SRP_CAPABLE: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = 0; ++ break; ++ ++ case DWC_MODE_SRP_CAPABLE_DEVICE: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != ++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); ++ break; ++ ++ case DWC_MODE_NO_SRP_CAPABLE_DEVICE: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = 0; ++ break; ++ ++ case DWC_MODE_SRP_CAPABLE_HOST: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = (_core_if->core_params->otg_cap != ++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE); ++ break; ++ ++ case DWC_MODE_NO_SRP_CAPABLE_HOST: ++ usbcfg.b.hnpcap = 0; ++ usbcfg.b.srpcap = 0; ++ break; ++ } ++ ++ dwc_write_reg32( &global_regs->gusbcfg, usbcfg.d32); ++ ++ /* Enable common interrupts */ ++ dwc_otg_enable_common_interrupts( _core_if ); ++ ++ /* Do device or host intialization based on mode during PCD ++ * and HCD initialization */ ++ if (dwc_otg_is_host_mode( _core_if )) { ++ DWC_DEBUGPL(DBG_ANY, "Host Mode\n" ); ++ _core_if->op_state = A_HOST; ++ } else { ++ DWC_DEBUGPL(DBG_ANY, "Device Mode\n" ); ++ _core_if->op_state = B_PERIPHERAL; ++#ifdef DWC_DEVICE_ONLY ++ dwc_otg_core_dev_init( _core_if ); ++#endif ++ } ++} ++ ++ ++/** ++ * This function enables the Device mode interrupts. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ */ ++void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t *_core_if) ++{ ++ gintmsk_data_t intr_mask = { .d32 = 0}; ++ dwc_otg_core_global_regs_t * global_regs = _core_if->core_global_regs; ++ ++ DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__); ++ ++ /* Disable all interrupts. */ ++ dwc_write_reg32( &global_regs->gintmsk, 0); ++ ++ /* Clear any pending interrupts */ ++ dwc_write_reg32( &global_regs->gintsts, 0xFFFFFFFF); ++ ++ /* Enable the common interrupts */ ++ dwc_otg_enable_common_interrupts( _core_if ); ++ ++ /* Enable interrupts */ ++ intr_mask.b.usbreset = 1; ++ intr_mask.b.enumdone = 1; ++ //intr_mask.b.epmismatch = 1; ++ intr_mask.b.inepintr = 1; ++ intr_mask.b.outepintr = 1; ++ intr_mask.b.erlysuspend = 1; ++ if (_core_if->en_multiple_tx_fifo == 0) { ++ intr_mask.b.epmismatch = 1; ++ } ++ ++ /** @todo NGS: Should this be a module parameter? */ ++ intr_mask.b.isooutdrop = 1; ++ intr_mask.b.eopframe = 1; ++ intr_mask.b.incomplisoin = 1; ++ intr_mask.b.incomplisoout = 1; ++ ++ dwc_modify_reg32( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); ++ ++ DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, ++ dwc_read_reg32( &global_regs->gintmsk)); ++} ++ ++/** ++ * This function initializes the DWC_otg controller registers for ++ * device mode. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ * ++ */ ++void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = ++ _core_if->core_global_regs; ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ dwc_otg_core_params_t *params = _core_if->core_params; ++ dcfg_data_t dcfg = {.d32 = 0}; ++ grstctl_t resetctl = { .d32=0 }; ++ int i; ++ uint32_t rx_fifo_size; ++ fifosize_data_t nptxfifosize; ++ fifosize_data_t txfifosize; ++ dthrctl_data_t dthrctl; ++ ++ fifosize_data_t ptxfifosize; ++ ++ /* Restart the Phy Clock */ ++ dwc_write_reg32(_core_if->pcgcctl, 0); ++ ++ /* Device configuration register */ ++ init_devspd(_core_if); ++ dcfg.d32 = dwc_read_reg32( &dev_if->dev_global_regs->dcfg); ++ dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80; ++ dwc_write_reg32( &dev_if->dev_global_regs->dcfg, dcfg.d32 ); ++ ++ /* Configure data FIFO sizes */ ++ if ( _core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo ) { ++ ++ DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n", _core_if->total_fifo_size); ++ DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n", params->dev_rx_fifo_size); ++ DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n", params->dev_nperio_tx_fifo_size); ++ ++ /* Rx FIFO */ ++ DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->grxfsiz)); ++ rx_fifo_size = params->dev_rx_fifo_size; ++ dwc_write_reg32( &global_regs->grxfsiz, rx_fifo_size ); ++ DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->grxfsiz)); ++ ++ /** Set Periodic Tx FIFO Mask all bits 0 */ ++ _core_if->p_tx_msk = 0; ++ ++ /** Set Tx FIFO Mask all bits 0 */ ++ _core_if->tx_msk = 0; ++ if (_core_if->en_multiple_tx_fifo == 0) { ++ /* Non-periodic Tx FIFO */ ++ DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->gnptxfsiz)); ++ nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size; ++ nptxfifosize.b.startaddr = params->dev_rx_fifo_size; ++ dwc_write_reg32( &global_regs->gnptxfsiz, nptxfifosize.d32 ); ++ DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->gnptxfsiz)); ++ ++ ++ /**@todo NGS: Fix Periodic FIFO Sizing! */ ++ /* ++ * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15. ++ * Indexes of the FIFO size module parameters in the ++ * dev_perio_tx_fifo_size array and the FIFO size registers in ++ * the dptxfsiz array run from 0 to 14. ++ */ ++ /** @todo Finish debug of this */ ++ ptxfifosize.b.startaddr = ++ nptxfifosize.b.startaddr + nptxfifosize.b.depth; ++ for (i = 0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep;i++) { ++ ptxfifosize.b.depth = params->dev_perio_tx_fifo_size[i]; ++ DWC_DEBUGPL(DBG_CIL,"initial dptxfsiz_dieptxf[%d]=%08x\n", ++ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])); ++ dwc_write_reg32(&global_regs->dptxfsiz_dieptxf[i],ptxfifosize.d32); ++ DWC_DEBUGPL(DBG_CIL,"new dptxfsiz_dieptxf[%d]=%08x\n", ++ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])); ++ ptxfifosize.b.startaddr += ptxfifosize.b.depth; ++ } ++ } else { ++ ++ /* ++ * Tx FIFOs These FIFOs are numbered from 1 to 15. ++ * Indexes of the FIFO size module parameters in the ++ * dev_tx_fifo_size array and the FIFO size registers in ++ * the dptxfsiz_dieptxf array run from 0 to 14. ++ */ ++ ++ /* Non-periodic Tx FIFO */ ++ DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->gnptxfsiz)); ++ nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size; ++ nptxfifosize.b.startaddr = params->dev_rx_fifo_size; ++ dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32); ++ DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n", ++ dwc_read_reg32(&global_regs->gnptxfsiz)); ++ txfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth; ++ for (i = 1;i < _core_if->hwcfg4.b.num_dev_perio_in_ep;i++) { ++ txfifosize.b.depth = params->dev_tx_fifo_size[i]; ++ DWC_DEBUGPL(DBG_CIL,"initial dptxfsiz_dieptxf[%d]=%08x\n", ++ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i])); ++ dwc_write_reg32(&global_regs->dptxfsiz_dieptxf[i - 1],txfifosize.d32); ++ DWC_DEBUGPL(DBG_CIL,"new dptxfsiz_dieptxf[%d]=%08x\n", ++ i,dwc_read_reg32(&global_regs->dptxfsiz_dieptxf[i-1])); ++ txfifosize.b.startaddr += txfifosize.b.depth; ++ } ++ } ++ } ++ /* Flush the FIFOs */ ++ dwc_otg_flush_tx_fifo(_core_if, 0x10); /* all Tx FIFOs */ ++ dwc_otg_flush_rx_fifo(_core_if); ++ ++ /* Flush the Learning Queue. */ ++ resetctl.b.intknqflsh = 1; ++ dwc_write_reg32( &_core_if->core_global_regs->grstctl, resetctl.d32); ++ ++ /* Clear all pending Device Interrupts */ ++ dwc_write_reg32( &dev_if->dev_global_regs->diepmsk, 0 ); ++ dwc_write_reg32( &dev_if->dev_global_regs->doepmsk, 0 ); ++ dwc_write_reg32( &dev_if->dev_global_regs->daint, 0xFFFFFFFF ); ++ dwc_write_reg32( &dev_if->dev_global_regs->daintmsk, 0 ); ++ ++ for (i = 0; i <= dev_if->num_in_eps; i++) { ++ depctl_data_t depctl; ++ depctl.d32 = dwc_read_reg32(&dev_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; ++ } ++ dwc_write_reg32( &dev_if->in_ep_regs[i]->diepctl, depctl.d32); ++ ++ dwc_write_reg32(&dev_if->in_ep_regs[i]->dieptsiz, 0); ++ dwc_write_reg32(&dev_if->in_ep_regs[i]->diepdma, 0); ++ dwc_write_reg32(&dev_if->in_ep_regs[i]->diepint, 0xFF); ++ } ++ for (i = 0; i <= dev_if->num_out_eps; i++) { ++ depctl_data_t depctl; ++ depctl.d32 = dwc_read_reg32(&dev_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; ++ } ++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepctl, depctl.d32); ++ ++ //dwc_write_reg32( &dev_if->in_ep_regs[i]->dieptsiz, 0); ++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doeptsiz, 0); ++ //dwc_write_reg32( &dev_if->in_ep_regs[i]->diepdma, 0); ++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepdma, 0); ++ //dwc_write_reg32( &dev_if->in_ep_regs[i]->diepint, 0xFF); ++ dwc_write_reg32( &dev_if->out_ep_regs[i]->doepint, 0xFF); ++ } ++ ++ if (_core_if->en_multiple_tx_fifo && _core_if->dma_enable) { ++ dev_if->non_iso_tx_thr_en = _core_if->core_params->thr_ctl & 0x1; ++ dev_if->iso_tx_thr_en = (_core_if->core_params->thr_ctl >> 1) & 0x1; ++ dev_if->rx_thr_en = (_core_if->core_params->thr_ctl >> 2) & 0x1; ++ dev_if->rx_thr_length = _core_if->core_params->rx_thr_length; ++ dev_if->tx_thr_length = _core_if->core_params->tx_thr_length; ++ dthrctl.d32 = 0; ++ dthrctl.b.non_iso_thr_en = dev_if->non_iso_tx_thr_en; ++ dthrctl.b.iso_thr_en = dev_if->iso_tx_thr_en; ++ dthrctl.b.tx_thr_len = dev_if->tx_thr_length; ++ dthrctl.b.rx_thr_en = dev_if->rx_thr_en; ++ dthrctl.b.rx_thr_len = dev_if->rx_thr_length; ++ dwc_write_reg32(&dev_if->dev_global_regs->dtknqr3_dthrctl,dthrctl.d32); ++ DWC_DEBUGPL(DBG_CIL, "Non ISO Tx Thr - %d\nISO Tx Thr - %d\n" ++ "Rx Thr - %d\nTx Thr Len - %d\nRx Thr Len - %d\n", ++ dthrctl.b.non_iso_thr_en, dthrctl.b.iso_thr_en, ++ dthrctl.b.rx_thr_en, dthrctl.b.tx_thr_len, ++ dthrctl.b.rx_thr_len); ++ } ++ dwc_otg_enable_device_interrupts( _core_if ); ++ { ++ diepmsk_data_t msk = {.d32 = 0}; ++ msk.b.txfifoundrn = 1; ++ dwc_modify_reg32(&dev_if->dev_global_regs->diepmsk, msk.d32,msk.d32); ++} ++} ++ ++/** ++ * This function enables the Host mode interrupts. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ */ ++void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ gintmsk_data_t intr_mask = {.d32 = 0}; ++ ++ DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__); ++ ++ /* Disable all interrupts. */ ++ dwc_write_reg32(&global_regs->gintmsk, 0); ++ ++ /* Clear any pending interrupts. */ ++ dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF); ++ ++ /* Enable the common interrupts */ ++ dwc_otg_enable_common_interrupts(_core_if); ++ ++ /* ++ * Enable host mode interrupts without disturbing common ++ * interrupts. ++ */ ++ intr_mask.b.sofintr = 1; ++ intr_mask.b.portintr = 1; ++ intr_mask.b.hcintr = 1; ++ ++ //dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32); ++ //dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32); ++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32); ++} ++ ++/** ++ * This function disables the Host Mode interrupts. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ */ ++void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = ++ _core_if->core_global_regs; ++ gintmsk_data_t intr_mask = {.d32 = 0}; ++ ++ DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__); ++ ++ /* ++ * Disable host mode interrupts without disturbing common ++ * 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; ++ ++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0); ++} ++ ++#if 0 ++/* currently not used, keep it here as if needed later */ ++static int phy_read(dwc_otg_core_if_t * _core_if, int addr) ++{ ++ u32 val; ++ int timeout = 10; ++ ++ dwc_write_reg32(&_core_if->core_global_regs->gpvndctl, ++ 0x02000000 | (addr << 16)); ++ val = dwc_read_reg32(&_core_if->core_global_regs->gpvndctl); ++ while (((val & 0x08000000) == 0) && (timeout--)) { ++ udelay(1000); ++ val = dwc_read_reg32(&_core_if->core_global_regs->gpvndctl); ++ } ++ val = dwc_read_reg32(&_core_if->core_global_regs->gpvndctl); ++ printk("%s: addr=%02x regval=%02x\n", __func__, addr, val & 0x000000ff); ++ ++ return 0; ++} ++#endif ++ ++/** ++ * This function initializes the DWC_otg controller registers for ++ * host mode. ++ * ++ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the ++ * request queues. Host channels are reset to ensure that they are ready for ++ * performing transfers. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ * ++ */ ++void dwc_otg_core_host_init(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ dwc_otg_host_if_t *host_if = _core_if->host_if; ++ dwc_otg_core_params_t *params = _core_if->core_params; ++ hprt0_data_t hprt0 = {.d32 = 0}; ++ fifosize_data_t nptxfifosize; ++ fifosize_data_t ptxfifosize; ++ int i; ++ hcchar_data_t hcchar; ++ hcfg_data_t hcfg; ++ dwc_otg_hc_regs_t *hc_regs; ++ int num_channels; ++ gotgctl_data_t gotgctl = {.d32 = 0}; ++ ++ DWC_DEBUGPL(DBG_CILV,"%s(%p)\n", __func__, _core_if); ++ ++ /* Restart the Phy Clock */ ++ dwc_write_reg32(_core_if->pcgcctl, 0); ++ ++ /* Initialize Host Configuration Register */ ++ init_fslspclksel(_core_if); ++ if (_core_if->core_params->speed == DWC_SPEED_PARAM_FULL) { ++ hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg); ++ hcfg.b.fslssupp = 1; ++ dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32); ++ } ++ ++ /* Configure data FIFO sizes */ ++ if (_core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) { ++ DWC_DEBUGPL(DBG_CIL,"Total FIFO Size=%d\n", _core_if->total_fifo_size); ++ DWC_DEBUGPL(DBG_CIL,"Rx FIFO Size=%d\n", params->host_rx_fifo_size); ++ DWC_DEBUGPL(DBG_CIL,"NP Tx FIFO Size=%d\n", params->host_nperio_tx_fifo_size); ++ DWC_DEBUGPL(DBG_CIL,"P Tx FIFO Size=%d\n", params->host_perio_tx_fifo_size); ++ ++ /* Rx FIFO */ ++ DWC_DEBUGPL(DBG_CIL,"initial grxfsiz=%08x\n", dwc_read_reg32(&global_regs->grxfsiz)); ++ dwc_write_reg32(&global_regs->grxfsiz, params->host_rx_fifo_size); ++ DWC_DEBUGPL(DBG_CIL,"new grxfsiz=%08x\n", dwc_read_reg32(&global_regs->grxfsiz)); ++ ++ /* Non-periodic Tx FIFO */ ++ DWC_DEBUGPL(DBG_CIL,"initial gnptxfsiz=%08x\n", dwc_read_reg32(&global_regs->gnptxfsiz)); ++ nptxfifosize.b.depth = params->host_nperio_tx_fifo_size; ++ nptxfifosize.b.startaddr = params->host_rx_fifo_size; ++ dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32); ++ DWC_DEBUGPL(DBG_CIL,"new gnptxfsiz=%08x\n", dwc_read_reg32(&global_regs->gnptxfsiz)); ++ ++ /* Periodic Tx FIFO */ ++ DWC_DEBUGPL(DBG_CIL,"initial hptxfsiz=%08x\n", dwc_read_reg32(&global_regs->hptxfsiz)); ++ ptxfifosize.b.depth = params->host_perio_tx_fifo_size; ++ ptxfifosize.b.startaddr = nptxfifosize.b.startaddr + nptxfifosize.b.depth; ++ dwc_write_reg32(&global_regs->hptxfsiz, ptxfifosize.d32); ++ DWC_DEBUGPL(DBG_CIL,"new hptxfsiz=%08x\n", dwc_read_reg32(&global_regs->hptxfsiz)); ++ } ++ ++ /* Clear Host Set HNP Enable in the OTG Control Register */ ++ gotgctl.b.hstsethnpen = 1; ++ dwc_modify_reg32( &global_regs->gotgctl, gotgctl.d32, 0); ++ ++ /* Make sure the FIFOs are flushed. */ ++ dwc_otg_flush_tx_fifo(_core_if, 0x10 /* all Tx FIFOs */); ++ dwc_otg_flush_rx_fifo(_core_if); ++ ++ /* Flush out any leftover queued requests. */ ++ num_channels = _core_if->core_params->host_channels; ++ for (i = 0; i < num_channels; i++) { ++ hc_regs = _core_if->host_if->hc_regs[i]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.chen = 0; ++ hcchar.b.chdis = 1; ++ hcchar.b.epdir = 0; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ } ++ ++ /* Halt all channels to put them into a known state. */ ++ for (i = 0; i < num_channels; i++) { ++ int count = 0; ++ hc_regs = _core_if->host_if->hc_regs[i]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 1; ++ hcchar.b.epdir = 0; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i); ++ do { ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (++count > 200) { ++ DWC_ERROR("%s: Unable to clear halt on channel %d\n", ++ __func__, i); ++ break; ++ } ++ udelay(100); ++ } while (hcchar.b.chen); ++ } ++ ++ /* Turn on the vbus power. */ ++ DWC_PRINT("Init: Port Power? op_state=%d\n", _core_if->op_state); ++ if (_core_if->op_state == A_HOST){ ++ hprt0.d32 = dwc_otg_read_hprt0(_core_if); ++ DWC_PRINT("Init: Power Port (%d)\n", hprt0.b.prtpwr); ++ if (hprt0.b.prtpwr == 0 ) { ++ hprt0.b.prtpwr = 1; ++ dwc_write_reg32(host_if->hprt0, hprt0.d32); ++ } ++ } ++ ++ dwc_otg_enable_host_interrupts( _core_if ); ++} ++ ++/** ++ * Prepares a host channel for transferring packets to/from a specific ++ * endpoint. The HCCHARn register is set up with the characteristics specified ++ * in _hc. Host channel interrupts that may need to be serviced while this ++ * transfer is in progress are enabled. ++ * ++ * @param _core_if Programming view of DWC_otg controller ++ * @param _hc Information needed to initialize the host channel ++ */ ++void dwc_otg_hc_init(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ uint32_t intr_enable; ++ hcintmsk_data_t hc_intr_mask; ++ gintmsk_data_t gintmsk = {.d32 = 0}; ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ ++ uint8_t hc_num = _hc->hc_num; ++ dwc_otg_host_if_t *host_if = _core_if->host_if; ++ dwc_otg_hc_regs_t *hc_regs = host_if->hc_regs[hc_num]; ++ ++ /* Clear old interrupt conditions for this host channel. */ ++ hc_intr_mask.d32 = 0xFFFFFFFF; ++ hc_intr_mask.b.reserved = 0; ++ dwc_write_reg32(&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; ++ if (_core_if->dma_enable) { ++ hc_intr_mask.b.ahberr = 1; ++ if (_hc->error_state && !_hc->do_split && ++ _hc->ep_type != DWC_OTG_EP_TYPE_ISOC) { ++ hc_intr_mask.b.ack = 1; ++ if (_hc->ep_is_in) { ++ hc_intr_mask.b.datatglerr = 1; ++ if (_hc->ep_type != DWC_OTG_EP_TYPE_INTR) { ++ hc_intr_mask.b.nak = 1; ++ } ++ } ++ } ++ } else { ++ switch (_hc->ep_type) { ++ case DWC_OTG_EP_TYPE_CONTROL: ++ case DWC_OTG_EP_TYPE_BULK: ++ hc_intr_mask.b.xfercompl = 1; ++ hc_intr_mask.b.stall = 1; ++ hc_intr_mask.b.xacterr = 1; ++ hc_intr_mask.b.datatglerr = 1; ++ if (_hc->ep_is_in) { ++ hc_intr_mask.b.bblerr = 1; ++ } else { ++ hc_intr_mask.b.nak = 1; ++ hc_intr_mask.b.nyet = 1; ++ if (_hc->do_ping) { ++ hc_intr_mask.b.ack = 1; ++ } ++ } ++ ++ if (_hc->do_split) { ++ hc_intr_mask.b.nak = 1; ++ if (_hc->complete_split) { ++ hc_intr_mask.b.nyet = 1; ++ } ++ else { ++ hc_intr_mask.b.ack = 1; ++ } ++ } ++ ++ if (_hc->error_state) { ++ hc_intr_mask.b.ack = 1; ++ } ++ break; ++ case DWC_OTG_EP_TYPE_INTR: ++ hc_intr_mask.b.xfercompl = 1; ++ hc_intr_mask.b.nak = 1; ++ hc_intr_mask.b.stall = 1; ++ hc_intr_mask.b.xacterr = 1; ++ hc_intr_mask.b.datatglerr = 1; ++ hc_intr_mask.b.frmovrun = 1; ++ ++ if (_hc->ep_is_in) { ++ hc_intr_mask.b.bblerr = 1; ++ } ++ if (_hc->error_state) { ++ hc_intr_mask.b.ack = 1; ++ } ++ if (_hc->do_split) { ++ if (_hc->complete_split) { ++ hc_intr_mask.b.nyet = 1; ++ } ++ else { ++ hc_intr_mask.b.ack = 1; ++ } ++ } ++ break; ++ case DWC_OTG_EP_TYPE_ISOC: ++ hc_intr_mask.b.xfercompl = 1; ++ hc_intr_mask.b.frmovrun = 1; ++ hc_intr_mask.b.ack = 1; ++ ++ if (_hc->ep_is_in) { ++ hc_intr_mask.b.xacterr = 1; ++ hc_intr_mask.b.bblerr = 1; ++ } ++ break; ++ } ++ } ++ dwc_write_reg32(&hc_regs->hcintmsk, hc_intr_mask.d32); ++ ++ /* Enable the top level host channel interrupt. */ ++ intr_enable = (1 << hc_num); ++ dwc_modify_reg32(&host_if->host_global_regs->haintmsk, 0, intr_enable); ++ ++ /* Make sure host channel interrupts are enabled. */ ++ gintmsk.b.hcintr = 1; ++ dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, 0, gintmsk.d32); ++ ++ /* ++ * Program the HCCHARn register with the endpoint characteristics for ++ * the current transfer. ++ */ ++ hcchar.d32 = 0; ++ hcchar.b.devaddr = _hc->dev_addr; ++ hcchar.b.epnum = _hc->ep_num; ++ hcchar.b.epdir = _hc->ep_is_in; ++ hcchar.b.lspddev = (_hc->speed == DWC_OTG_EP_SPEED_LOW); ++ hcchar.b.eptype = _hc->ep_type; ++ hcchar.b.mps = _hc->max_packet; ++ ++ dwc_write_reg32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32); ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " Dev Addr: %d\n", hcchar.b.devaddr); ++ DWC_DEBUGPL(DBG_HCDV, " Ep Num: %d\n", hcchar.b.epnum); ++ DWC_DEBUGPL(DBG_HCDV, " Is In: %d\n", hcchar.b.epdir); ++ DWC_DEBUGPL(DBG_HCDV, " Is Low Speed: %d\n", hcchar.b.lspddev); ++ DWC_DEBUGPL(DBG_HCDV, " Ep Type: %d\n", hcchar.b.eptype); ++ DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps); ++ DWC_DEBUGPL(DBG_HCDV, " Multi Cnt: %d\n", hcchar.b.multicnt); ++ ++ /* ++ * Program the HCSPLIT register for SPLITs ++ */ ++ hcsplt.d32 = 0; ++ if (_hc->do_split) { ++ DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n", _hc->hc_num, ++ _hc->complete_split ? "CSPLIT" : "SSPLIT"); ++ hcsplt.b.compsplt = _hc->complete_split; ++ hcsplt.b.xactpos = _hc->xact_pos; ++ hcsplt.b.hubaddr = _hc->hub_addr; ++ hcsplt.b.prtaddr = _hc->port_addr; ++ DWC_DEBUGPL(DBG_HCDV, " comp split %d\n", _hc->complete_split); ++ DWC_DEBUGPL(DBG_HCDV, " xact pos %d\n", _hc->xact_pos); ++ DWC_DEBUGPL(DBG_HCDV, " hub addr %d\n", _hc->hub_addr); ++ DWC_DEBUGPL(DBG_HCDV, " port addr %d\n", _hc->port_addr); ++ DWC_DEBUGPL(DBG_HCDV, " is_in %d\n", _hc->ep_is_in); ++ DWC_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n", hcchar.b.mps); ++ DWC_DEBUGPL(DBG_HCDV, " xferlen: %d\n", _hc->xfer_len); ++ } ++ dwc_write_reg32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32); ++ ++} ++ ++/** ++ * 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. ++ * ++ * @param _core_if Controller register interface. ++ * @param _hc Host channel to halt. ++ * @param _halt_status Reason for halting the channel. ++ */ ++void dwc_otg_hc_halt(dwc_otg_core_if_t *_core_if, ++ dwc_hc_t *_hc, ++ dwc_otg_halt_status_e _halt_status) ++{ ++ gnptxsts_data_t nptxsts; ++ hptxsts_data_t hptxsts; ++ hcchar_data_t hcchar; ++ dwc_otg_hc_regs_t *hc_regs; ++ dwc_otg_core_global_regs_t *global_regs; ++ dwc_otg_host_global_regs_t *host_global_regs; ++ ++ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ global_regs = _core_if->core_global_regs; ++ host_global_regs = _core_if->host_if->host_global_regs; ++ ++ WARN_ON(_halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS); ++ ++ if (_halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE || ++ _halt_status == DWC_OTG_HC_XFER_AHB_ERR) { ++ /* ++ * Disable all channel interrupts except Ch Halted. The QTD ++ * and QH 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. ++ */ ++ hcintmsk_data_t hcintmsk; ++ hcintmsk.d32 = 0; ++ hcintmsk.b.chhltd = 1; ++ dwc_write_reg32(&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 QTD and QH state. ++ */ ++ dwc_write_reg32(&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. ++ */ ++ _hc->halt_status = _halt_status; ++ ++ hcchar.d32 = dwc_read_reg32(&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 (_hc->halt_pending) { ++ /* ++ * 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 ++ DWC_PRINT("*** %s: Channel %d, _hc->halt_pending already set ***\n", ++ __func__, _hc->hc_num); ++ ++/* dwc_otg_dump_global_registers(_core_if); */ ++/* dwc_otg_dump_host_registers(_core_if); */ ++#endif ++ return; ++ } ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 1; ++ ++ if (!_core_if->dma_enable) { ++ /* Check for space in the request queue to issue the halt. */ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || ++ _hc->ep_type == DWC_OTG_EP_TYPE_BULK) { ++ nptxsts.d32 = dwc_read_reg32(&global_regs->gnptxsts); ++ if (nptxsts.b.nptxqspcavail == 0) { ++ hcchar.b.chen = 0; ++ } ++ } else { ++ hptxsts.d32 = dwc_read_reg32(&host_global_regs->hptxsts); ++ if ((hptxsts.b.ptxqspcavail == 0) || (_core_if->queuing_high_bandwidth)) { ++ hcchar.b.chen = 0; ++ } ++ } ++ } ++ ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ ++ _hc->halt_status = _halt_status; ++ ++ if (hcchar.b.chen) { ++ _hc->halt_pending = 1; ++ _hc->halt_on_queue = 0; ++ } else { ++ _hc->halt_on_queue = 1; ++ } ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n", hcchar.d32); ++ DWC_DEBUGPL(DBG_HCDV, " halt_pending: %d\n", _hc->halt_pending); ++ DWC_DEBUGPL(DBG_HCDV, " halt_on_queue: %d\n", _hc->halt_on_queue); ++ DWC_DEBUGPL(DBG_HCDV, " halt_status: %d\n", _hc->halt_status); ++ ++ return; ++} ++ ++/** ++ * 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. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _hc Identifies the host channel to clean up. ++ */ ++void dwc_otg_hc_cleanup(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ dwc_otg_hc_regs_t *hc_regs; ++ ++ _hc->xfer_started = 0; ++ ++ /* ++ * Clear channel interrupt enables and any unhandled channel interrupt ++ * conditions. ++ */ ++ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ dwc_write_reg32(&hc_regs->hcintmsk, 0); ++ dwc_write_reg32(&hc_regs->hcint, 0xFFFFFFFF); ++ ++#ifdef DEBUG ++ del_timer(&_core_if->hc_xfer_timer[_hc->hc_num]); ++ { ++ hcchar_data_t hcchar; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (hcchar.b.chdis) { ++ DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", ++ __func__, _hc->hc_num, hcchar.d32); ++ } ++ } ++#endif ++} ++ ++/** ++ * Sets the channel property that indicates in which frame a periodic transfer ++ * should occur. This is always set to the _next_ frame. This function has no ++ * effect on non-periodic transfers. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _hc Identifies the host channel to set up and its properties. ++ * @param _hcchar Current value of the HCCHAR register for the specified host ++ * channel. ++ */ ++static inline void hc_set_even_odd_frame(dwc_otg_core_if_t *_core_if, ++ dwc_hc_t *_hc, ++ hcchar_data_t *_hcchar) ++{ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ hfnum_data_t hfnum; ++ hfnum.d32 = dwc_read_reg32(&_core_if->host_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; ++#ifdef DEBUG ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR && _hc->do_split && !_hc->complete_split) { ++ switch (hfnum.b.frnum & 0x7) { ++ case 7: ++ _core_if->hfnum_7_samples++; ++ _core_if->hfnum_7_frrem_accum += hfnum.b.frrem; ++ break; ++ case 0: ++ _core_if->hfnum_0_samples++; ++ _core_if->hfnum_0_frrem_accum += hfnum.b.frrem; ++ break; ++ default: ++ _core_if->hfnum_other_samples++; ++ _core_if->hfnum_other_frrem_accum += hfnum.b.frrem; ++ break; ++ } ++ } ++#endif ++ } ++} ++ ++#ifdef DEBUG ++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; ++ DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num); ++ DWC_WARN(" start_hcchar_val 0x%08x\n", xfer_info->core_if->start_hcchar_val[hc_num]); ++} ++#endif ++ ++/* ++ * 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 _core_if Programming view of DWC_otg controller. ++ * @param _hc 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 dwc_otg_hc_start_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ hcchar_data_t hcchar; ++ hctsiz_data_t hctsiz; ++ uint16_t num_packets; ++ uint32_t max_hc_xfer_size = _core_if->core_params->max_transfer_size; ++ uint16_t max_hc_pkt_count = _core_if->core_params->max_packet_count; ++ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ ++ hctsiz.d32 = 0; ++ ++ if (_hc->do_ping) { ++ if (!_core_if->dma_enable) { ++ dwc_otg_hc_do_ping(_core_if, _hc); ++ _hc->xfer_started = 1; ++ return; ++ } else { ++ hctsiz.b.dopng = 1; ++ } ++ } ++ ++ if (_hc->do_split) { ++ num_packets = 1; ++ ++ if (_hc->complete_split && !_hc->ep_is_in) { ++ /* For CSPLIT OUT Transfer, set the size to 0 so the ++ * core doesn't expect any data written to the FIFO */ ++ _hc->xfer_len = 0; ++ } else if (_hc->ep_is_in || (_hc->xfer_len > _hc->max_packet)) { ++ _hc->xfer_len = _hc->max_packet; ++ } else if (!_hc->ep_is_in && (_hc->xfer_len > 188)) { ++ _hc->xfer_len = 188; ++ } ++ ++ hctsiz.b.xfersize = _hc->xfer_len; ++ } else { ++ /* ++ * Ensure that the transfer length and packet count will fit ++ * in the widths allocated for them in the HCTSIZn register. ++ */ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * Make sure the transfer size is no larger than one ++ * (micro)frame's worth of data. (A check was done ++ * when the periodic transfer was accepted to ensure ++ * that a (micro)frame's worth of data can be ++ * programmed into a channel.) ++ */ ++ uint32_t max_periodic_len = _hc->multi_count * _hc->max_packet; ++ if (_hc->xfer_len > max_periodic_len) { ++ _hc->xfer_len = max_periodic_len; ++ } else { ++ } ++ } else if (_hc->xfer_len > max_hc_xfer_size) { ++ /* Make sure that xfer_len is a multiple of max packet size. */ ++ _hc->xfer_len = max_hc_xfer_size - _hc->max_packet + 1; ++ } ++ ++ if (_hc->xfer_len > 0) { ++ num_packets = (_hc->xfer_len + _hc->max_packet - 1) / _hc->max_packet; ++ if (num_packets > max_hc_pkt_count) { ++ num_packets = max_hc_pkt_count; ++ _hc->xfer_len = num_packets * _hc->max_packet; ++ } ++ } else { ++ /* Need 1 packet for transfer length of 0. */ ++ num_packets = 1; ++ } ++ ++ if (_hc->ep_is_in) { ++ /* Always program an integral # of max packets for IN transfers. */ ++ _hc->xfer_len = num_packets * _hc->max_packet; ++ } ++ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * Make sure that the multi_count field matches the ++ * actual transfer length. ++ */ ++ _hc->multi_count = num_packets; ++ ++ } ++ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* Set up the initial PID for the transfer. */ ++ if (_hc->speed == DWC_OTG_EP_SPEED_HIGH) { ++ if (_hc->ep_is_in) { ++ if (_hc->multi_count == 1) { ++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0; ++ } else if (_hc->multi_count == 2) { ++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA1; ++ } else { ++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA2; ++ } ++ } else { ++ if (_hc->multi_count == 1) { ++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0; ++ } else { ++ _hc->data_pid_start = DWC_OTG_HC_PID_MDATA; ++ } ++ } ++ } else { ++ _hc->data_pid_start = DWC_OTG_HC_PID_DATA0; ++ } ++ } ++ ++ hctsiz.b.xfersize = _hc->xfer_len; ++ } ++ ++ _hc->start_pkt_count = num_packets; ++ hctsiz.b.pktcnt = num_packets; ++ hctsiz.b.pid = _hc->data_pid_start; ++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize); ++ DWC_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n", hctsiz.b.pktcnt); ++ DWC_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid); ++ ++ if (_core_if->dma_enable) { ++#ifdef DEBUG ++if(((uint32_t)_hc->xfer_buff)%4) ++printk("dwc_otg_hc_start_transfer _hc->xfer_buff not 4 byte alignment\n"); ++#endif ++ dwc_write_reg32(&hc_regs->hcdma, (uint32_t)_hc->xfer_buff); ++ } ++ ++ /* Start the split */ ++ if (_hc->do_split) { ++ hcsplt_data_t hcsplt; ++ hcsplt.d32 = dwc_read_reg32 (&hc_regs->hcsplt); ++ hcsplt.b.spltena = 1; ++ dwc_write_reg32(&hc_regs->hcsplt, hcsplt.d32); ++ } ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.multicnt = _hc->multi_count; ++ hc_set_even_odd_frame(_core_if, _hc, &hcchar); ++#ifdef DEBUG ++ _core_if->start_hcchar_val[_hc->hc_num] = hcchar.d32; ++ if (hcchar.b.chdis) { ++ DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", ++ __func__, _hc->hc_num, hcchar.d32); ++ } ++#endif ++ ++ /* Set host channel enable after all other setup is complete. */ ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 0; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ ++ _hc->xfer_started = 1; ++ _hc->requests++; ++ ++ if (!_core_if->dma_enable && !_hc->ep_is_in && _hc->xfer_len > 0) { ++ /* Load OUT packet into the appropriate Tx FIFO. */ ++ dwc_otg_hc_write_packet(_core_if, _hc); ++ } ++ ++#ifdef DEBUG ++ /* Start a timer for this transfer. */ ++ _core_if->hc_xfer_timer[_hc->hc_num].function = hc_xfer_timeout; ++ _core_if->hc_xfer_info[_hc->hc_num].core_if = _core_if; ++ _core_if->hc_xfer_info[_hc->hc_num].hc = _hc; ++ _core_if->hc_xfer_timer[_hc->hc_num].data = (unsigned long)(&_core_if->hc_xfer_info[_hc->hc_num]); ++ _core_if->hc_xfer_timer[_hc->hc_num].expires = jiffies + (HZ*10); ++ add_timer(&_core_if->hc_xfer_timer[_hc->hc_num]); ++#endif ++} ++ ++/** ++ * This function continues a data transfer that was started by previous call ++ * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is ++ * sufficient space in the request queue and Tx Data FIFO. This function ++ * should only be called in Slave mode. In DMA mode, the controller acts ++ * autonomously to complete transfers programmed to a host channel. ++ * ++ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO ++ * if there is any data remaining to be queued. For an IN transfer, another ++ * data packet is always requested. For the SETUP phase of a control transfer, ++ * this function does nothing. ++ * ++ * @return 1 if a new request is queued, 0 if no more requests are required ++ * for this transfer. ++ */ ++int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); ++ ++ if (_hc->do_split) { ++ /* SPLITs always queue just once per channel */ ++ return 0; ++ } else if (_hc->data_pid_start == DWC_OTG_HC_PID_SETUP) { ++ /* SETUPs are queued only once since they can't be NAKed. */ ++ return 0; ++ } else if (_hc->ep_is_in) { ++ /* ++ * Always queue another request for other IN transfers. If ++ * back-to-back INs are issued and NAKs are received for both, ++ * the driver may still be processing the first NAK when the ++ * second NAK is received. When the interrupt handler clears ++ * the NAK interrupt for the first NAK, the second NAK will ++ * not be seen. So we can't depend on the NAK interrupt ++ * handler to requeue a NAKed request. Instead, IN requests ++ * are issued each time this function is called. When the ++ * transfer completes, the extra requests for the channel will ++ * be flushed. ++ */ ++ hcchar_data_t hcchar; ++ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hc_set_even_odd_frame(_core_if, _hc, &hcchar); ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 0; ++ DWC_DEBUGPL(DBG_HCDV, " IN xfer: hcchar = 0x%08x\n", hcchar.d32); ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ _hc->requests++; ++ return 1; ++ } else { ++ /* OUT transfers. */ ++ if (_hc->xfer_count < _hc->xfer_len) { ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ hcchar_data_t hcchar; ++ dwc_otg_hc_regs_t *hc_regs; ++ hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hc_set_even_odd_frame(_core_if, _hc, &hcchar); ++ } ++ ++ /* Load OUT packet into the appropriate Tx FIFO. */ ++ dwc_otg_hc_write_packet(_core_if, _hc); ++ _hc->requests++; ++ return 1; ++ } else { ++ return 0; ++ } ++ } ++} ++ ++/** ++ * Starts a PING transfer. This function should only be called in Slave mode. ++ * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled. ++ */ ++void dwc_otg_hc_do_ping(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ hcchar_data_t hcchar; ++ hctsiz_data_t hctsiz; ++ dwc_otg_hc_regs_t *hc_regs = _core_if->host_if->hc_regs[_hc->hc_num]; ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _hc->hc_num); ++ ++ hctsiz.d32 = 0; ++ hctsiz.b.dopng = 1; ++ hctsiz.b.pktcnt = 1; ++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.chen = 1; ++ hcchar.b.chdis = 0; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++} ++ ++/* ++ * 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. ++ */ ++void dwc_otg_hc_write_packet(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ uint32_t i; ++ uint32_t remaining_count; ++ uint32_t byte_count; ++ uint32_t dword_count; ++ ++ uint32_t *data_buff = (uint32_t *)(_hc->xfer_buff); ++ uint32_t *data_fifo = _core_if->data_fifo[_hc->hc_num]; ++ ++ remaining_count = _hc->xfer_len - _hc->xfer_count; ++ if (remaining_count > _hc->max_packet) { ++ byte_count = _hc->max_packet; ++ } else { ++ byte_count = remaining_count; ++ } ++ ++ dword_count = (byte_count + 3) / 4; ++ ++ if ((((unsigned long)data_buff) & 0x3) == 0) { ++ /* xfer_buff is DWORD aligned. */ ++ for (i = 0; i < dword_count; i++, data_buff++) { ++ dwc_write_reg32(data_fifo, *data_buff); ++ } ++ } else { ++ /* xfer_buff is not DWORD aligned. */ ++ for (i = 0; i < dword_count; i++, data_buff++) { ++ dwc_write_reg32(data_fifo, get_unaligned(data_buff)); ++ } ++ } ++ ++ _hc->xfer_count += byte_count; ++ _hc->xfer_buff += byte_count; ++} ++ ++/** ++ * Gets the current USB frame number. This is the frame number from the last ++ * SOF packet. ++ */ ++uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t *_core_if) ++{ ++ dsts_data_t dsts; ++ dsts.d32 = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->dsts); ++ ++ /* read current frame/microfreme number from DSTS register */ ++ return dsts.b.soffn; ++} ++ ++/** ++ * This function reads a setup packet from the Rx FIFO into the destination ++ * buffer. This function is called from the Rx Status Queue Level (RxStsQLvl) ++ * Interrupt routine when a SETUP packet has been received in Slave mode. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _dest Destination buffer for packet data. ++ */ ++void dwc_otg_read_setup_packet(dwc_otg_core_if_t *_core_if, uint32_t *_dest) ++{ ++ /* Get the 8 bytes of a setup transaction data */ ++ ++ /* Pop 2 DWORDS off the receive data FIFO into memory */ ++ _dest[0] = dwc_read_reg32(_core_if->data_fifo[0]); ++ _dest[1] = dwc_read_reg32(_core_if->data_fifo[0]); ++ //_dest[0] = dwc_read_datafifo32(_core_if->data_fifo[0]); ++ //_dest[1] = dwc_read_datafifo32(_core_if->data_fifo[0]); ++} ++ ++ ++/** ++ * This function enables EP0 OUT to receive SETUP packets and configures EP0 ++ * IN for transmitting packets. It is normally called when the ++ * "Enumeration Done" interrupt occurs. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP0 data. ++ */ ++void dwc_otg_ep0_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ dsts_data_t dsts; ++ depctl_data_t diepctl; ++ depctl_data_t doepctl; ++ dctl_data_t dctl ={.d32=0}; ++ ++ /* Read the Device Status and Endpoint 0 Control registers */ ++ dsts.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dsts); ++ diepctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl); ++ doepctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl); ++ ++ /* Set the MPS of the IN EP based on the enumeration speed */ ++ switch (dsts.b.enumspd) { ++ case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: ++ case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: ++ case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ: ++ diepctl.b.mps = DWC_DEP0CTL_MPS_64; ++ break; ++ case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ: ++ diepctl.b.mps = DWC_DEP0CTL_MPS_8; ++ break; ++ } ++ ++ dwc_write_reg32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32); ++ ++ /* Enable OUT EP for receive */ ++ doepctl.b.epena = 1; ++ dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32); ++ ++#ifdef VERBOSE ++ DWC_DEBUGPL(DBG_PCDV,"doepctl0=%0x\n", ++ dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl)); ++ DWC_DEBUGPL(DBG_PCDV,"diepctl0=%0x\n", ++ dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl)); ++#endif ++ dctl.b.cgnpinnak = 1; ++ dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); ++ DWC_DEBUGPL(DBG_PCDV,"dctl=%0x\n", ++ dwc_read_reg32(&dev_if->dev_global_regs->dctl)); ++} ++ ++/** ++ * This function activates an EP. The Device EP control register for ++ * the EP is configured as defined in the ep structure. Note: This ++ * function is not used for EP0. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to activate. ++ */ ++void dwc_otg_ep_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ depctl_data_t depctl; ++ volatile uint32_t *addr; ++ daint_data_t daintmsk = {.d32=0}; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, _ep->num, ++ (_ep->is_in?"IN":"OUT")); ++ ++ /* Read DEPCTLn register */ ++ if (_ep->is_in == 1) { ++ addr = &dev_if->in_ep_regs[_ep->num]->diepctl; ++ daintmsk.ep.in = 1<<_ep->num; ++ } else { ++ addr = &dev_if->out_ep_regs[_ep->num]->doepctl; ++ daintmsk.ep.out = 1<<_ep->num; ++ } ++ ++ /* If the EP is already active don't change the EP Control ++ * register. */ ++ depctl.d32 = dwc_read_reg32(addr); ++ if (!depctl.b.usbactep) { ++ depctl.b.mps = _ep->maxpacket; ++ depctl.b.eptype = _ep->type; ++ depctl.b.txfnum = _ep->tx_fifo_num; ++ ++ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ depctl.b.setd0pid = 1; // ??? ++ } else { ++ depctl.b.setd0pid = 1; ++ } ++ depctl.b.usbactep = 1; ++ ++ dwc_write_reg32(addr, depctl.d32); ++ DWC_DEBUGPL(DBG_PCDV,"DEPCTL=%08x\n", dwc_read_reg32(addr)); ++ } ++ ++ ++ /* Enable the Interrupt for this EP */ ++ dwc_modify_reg32(&dev_if->dev_global_regs->daintmsk, ++ 0, daintmsk.d32); ++ DWC_DEBUGPL(DBG_PCDV,"DAINTMSK=%0x\n", ++ dwc_read_reg32(&dev_if->dev_global_regs->daintmsk)); ++ _ep->stall_clear_flag = 0; ++ return; ++} ++ ++/** ++ * This function deactivates an EP. This is done by clearing the USB Active ++ * EP bit in the Device EP control register. Note: This function is not used ++ * for EP0. EP0 cannot be deactivated. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to deactivate. ++ */ ++void dwc_otg_ep_deactivate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ depctl_data_t depctl ={.d32 = 0}; ++ volatile uint32_t *addr; ++ daint_data_t daintmsk = {.d32=0}; ++ ++ /* Read DEPCTLn register */ ++ if (_ep->is_in == 1) { ++ addr = &_core_if->dev_if->in_ep_regs[_ep->num]->diepctl; ++ daintmsk.ep.in = 1<<_ep->num; ++ } else { ++ addr = &_core_if->dev_if->out_ep_regs[_ep->num]->doepctl; ++ daintmsk.ep.out = 1<<_ep->num; ++ } ++ ++ depctl.b.usbactep = 0; ++ dwc_write_reg32(addr, depctl.d32); ++ ++ /* Disable the Interrupt for this EP */ ++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->daintmsk, ++ daintmsk.d32, 0); ++ ++ return; ++} ++ ++/** ++ * This function does the setup for a data transfer for an EP and ++ * starts the transfer. For an IN transfer, the packets will be ++ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, ++ * the packets are unloaded from the Rx FIFO in the ISR. the ISR. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to start the transfer on. ++ */ ++void dwc_otg_ep_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ /** @todo Refactor this funciton to check the transfer size ++ * count value does not execed the number bits in the Transfer ++ * count register. */ ++ depctl_data_t depctl; ++ deptsiz_data_t deptsiz; ++ gintmsk_data_t intr_mask = { .d32 = 0}; ++ ++#ifdef CHECK_PACKET_COUNTER_WIDTH ++ const uint32_t MAX_XFER_SIZE = ++ _core_if->core_params->max_transfer_size; ++ const uint32_t MAX_PKT_COUNT = ++ _core_if->core_params->max_packet_count; ++ uint32_t num_packets; ++ uint32_t transfer_len; ++ dwc_otg_dev_out_ep_regs_t *out_regs = ++ _core_if->dev_if->out_ep_regs[_ep->num]; ++ dwc_otg_dev_in_ep_regs_t *in_regs = ++ _core_if->dev_if->in_ep_regs[_ep->num]; ++ gnptxsts_data_t txstatus; ++ ++ int lvl = SET_DEBUG_LEVEL(DBG_PCD); ++ ++ ++ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d " ++ "xfer_buff=%p start_xfer_buff=%p\n", ++ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len, ++ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff); ++ ++ transfer_len = _ep->xfer_len - _ep->xfer_count; ++ if (transfer_len > MAX_XFER_SIZE) { ++ transfer_len = MAX_XFER_SIZE; ++ } ++ if (transfer_len == 0) { ++ num_packets = 1; ++ /* OUT EP to recieve Zero-length packet set transfer ++ * size to maxpacket size. */ ++ if (!_ep->is_in) { ++ transfer_len = _ep->maxpacket; ++ } ++ } else { ++ num_packets = ++ (transfer_len + _ep->maxpacket - 1) / _ep->maxpacket; ++ if (num_packets > MAX_PKT_COUNT) { ++ num_packets = MAX_PKT_COUNT; ++ } ++ } ++ DWC_DEBUGPL(DBG_PCD, "transfer_len=%d #pckt=%d\n", transfer_len, ++ num_packets); ++ ++ deptsiz.b.xfersize = transfer_len; ++ deptsiz.b.pktcnt = num_packets; ++ ++ /* IN endpoint */ ++ if (_ep->is_in == 1) { ++ depctl.d32 = dwc_read_reg32(&in_regs->diepctl); ++ } else {/* OUT endpoint */ ++ depctl.d32 = dwc_read_reg32(&out_regs->doepctl); ++ } ++ ++ /* EP enable, IN data in FIFO */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ /* IN endpoint */ ++ if (_ep->is_in == 1) { ++ txstatus.d32 = ++ dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); ++ if (txstatus.b.nptxqspcavail == 0) { ++ DWC_DEBUGPL(DBG_ANY, "TX Queue Full (0x%0x)\n", ++ txstatus.d32); ++ return; ++ } ++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); ++ dwc_write_reg32(&in_regs->diepctl, depctl.d32); ++ /** ++ * Enable the Non-Periodic Tx FIFO empty interrupt, the ++ * data will be written into the fifo by the ISR. ++ */ ++ if (_core_if->dma_enable) { ++ dwc_write_reg32(&in_regs->diepdma, (uint32_t) _ep->xfer_buff); ++ } else { ++ if (_core_if->en_multiple_tx_fifo == 0) { ++ intr_mask.b.nptxfempty = 1; ++ dwc_modify_reg32( &_core_if->core_global_regs->gintsts, ++ intr_mask.d32, 0); ++ dwc_modify_reg32( &_core_if->core_global_regs->gintmsk, ++ intr_mask.d32, intr_mask.d32); ++ } else { ++ /* Enable the Tx FIFO Empty Interrupt for this EP */ ++ if (_ep->xfer_len > 0 && ++ _ep->type != DWC_OTG_EP_TYPE_ISOC) { ++ uint32_t fifoemptymsk = 0; ++ fifoemptymsk = (0x1 << _ep->num); ++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs-> ++ dtknqr4_fifoemptymsk,0, fifoemptymsk); ++ } ++ } ++ } ++ } else { /* OUT endpoint */ ++ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); ++ dwc_write_reg32(&out_regs->doepctl, depctl.d32); ++ if (_core_if->dma_enable) { ++ dwc_write_reg32(&out_regs->doepdma,(uint32_t) _ep->xfer_buff); ++ } ++ } ++ DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n", ++ dwc_read_reg32(&out_regs->doepctl), ++ dwc_read_reg32(&out_regs->doeptsiz)); ++ DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n", ++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk), ++ dwc_read_reg32(&_core_if->core_global_regs->gintmsk)); ++ ++ SET_DEBUG_LEVEL(lvl); ++#endif ++ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__); ++ ++ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d " ++ "xfer_buff=%p start_xfer_buff=%p\n", ++ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len, ++ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff); ++ ++ /* IN endpoint */ ++ if (_ep->is_in == 1) { ++ dwc_otg_dev_in_ep_regs_t * in_regs = _core_if->dev_if->in_ep_regs[_ep->num]; ++ gnptxsts_data_t gtxstatus; ++ gtxstatus.d32 = dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); ++ if (_core_if->en_multiple_tx_fifo == 0 && ++ gtxstatus.b.nptxqspcavail == 0) { ++#ifdef DEBUG ++ DWC_PRINT("TX Queue Full (0x%0x)\n", gtxstatus.d32); ++#endif ++ //return; ++ MDELAY(100); //james ++ } ++ ++ depctl.d32 = dwc_read_reg32(&(in_regs->diepctl)); ++ deptsiz.d32 = dwc_read_reg32(&(in_regs->dieptsiz)); ++ ++ /* Zero Length Packet? */ ++ if (_ep->xfer_len == 0) { ++ deptsiz.b.xfersize = 0; ++ deptsiz.b.pktcnt = 1; ++ } else { ++ ++ /* Program the transfer size and packet count ++ * as follows: xfersize = N * maxpacket + ++ * short_packet pktcnt = N + (short_packet ++ * exist ? 1 : 0) ++ */ ++ deptsiz.b.xfersize = _ep->xfer_len; ++ deptsiz.b.pktcnt = (_ep->xfer_len - 1 + _ep->maxpacket) / _ep->maxpacket; ++ } ++ ++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); ++ ++ /* Write the DMA register */ ++ if (_core_if->dma_enable) { ++#if 1 // winder ++ dma_cache_wback_inv((unsigned long) _ep->xfer_buff, _ep->xfer_len); // winder ++ dwc_write_reg32 (&(in_regs->diepdma), ++ CPHYSADDR((uint32_t)_ep->xfer_buff)); // winder ++#else ++ dwc_write_reg32 (&(in_regs->diepdma), ++ (uint32_t)_ep->dma_addr); ++#endif ++ } else { ++ if (_ep->type != DWC_OTG_EP_TYPE_ISOC) { ++ /** ++ * Enable the Non-Periodic Tx FIFO empty interrupt, ++ * or the Tx FIFO epmty interrupt in dedicated Tx FIFO mode, ++ * the data will be written into the fifo by the ISR. ++ */ ++ if (_core_if->en_multiple_tx_fifo == 0) { ++ intr_mask.b.nptxfempty = 1; ++ dwc_modify_reg32( &_core_if->core_global_regs->gintsts, ++ intr_mask.d32, 0); ++ dwc_modify_reg32( &_core_if->core_global_regs->gintmsk, ++ intr_mask.d32, intr_mask.d32); ++ } else { ++ /* Enable the Tx FIFO Empty Interrupt for this EP */ ++ if (_ep->xfer_len > 0) { ++ uint32_t fifoemptymsk = 0; ++ fifoemptymsk = 1 << _ep->num; ++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs-> ++ dtknqr4_fifoemptymsk,0,fifoemptymsk); ++ } ++ } ++ } ++ } ++ ++ /* EP enable, IN data in FIFO */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ dwc_write_reg32(&in_regs->diepctl, depctl.d32); ++ ++ if (_core_if->dma_enable) { ++ depctl.d32 = dwc_read_reg32 (&_core_if->dev_if->in_ep_regs[0]->diepctl); ++ depctl.b.nextep = _ep->num; ++ dwc_write_reg32 (&_core_if->dev_if->in_ep_regs[0]->diepctl, depctl.d32); ++ ++ } ++ } else { ++ /* OUT endpoint */ ++ dwc_otg_dev_out_ep_regs_t * out_regs = _core_if->dev_if->out_ep_regs[_ep->num]; ++ ++ depctl.d32 = dwc_read_reg32(&(out_regs->doepctl)); ++ deptsiz.d32 = dwc_read_reg32(&(out_regs->doeptsiz)); ++ ++ /* Program the transfer size and packet count as follows: ++ * ++ * pktcnt = N ++ * xfersize = N * maxpacket ++ */ ++ if (_ep->xfer_len == 0) { ++ /* Zero Length Packet */ ++ deptsiz.b.xfersize = _ep->maxpacket; ++ deptsiz.b.pktcnt = 1; ++ } else { ++ deptsiz.b.pktcnt = (_ep->xfer_len + (_ep->maxpacket - 1)) / _ep->maxpacket; ++ deptsiz.b.xfersize = deptsiz.b.pktcnt * _ep->maxpacket; ++ } ++ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); ++ ++ DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n", ++ _ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt); ++ ++ if (_core_if->dma_enable) { ++#if 1 // winder ++ dwc_write_reg32 (&(out_regs->doepdma), ++ CPHYSADDR((uint32_t)_ep->xfer_buff)); // winder ++#else ++ dwc_write_reg32 (&(out_regs->doepdma), ++ (uint32_t)_ep->dma_addr); ++#endif ++ } ++ ++ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ /** @todo NGS: dpid is read-only. Use setd0pid ++ * or setd1pid. */ ++ if (_ep->even_odd_frame) { ++ depctl.b.setd1pid = 1; ++ } else { ++ depctl.b.setd0pid = 1; ++ } ++ } ++ ++ /* EP enable */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ ++ dwc_write_reg32(&out_regs->doepctl, depctl.d32); ++ ++ DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n", ++ dwc_read_reg32(&out_regs->doepctl), ++ dwc_read_reg32(&out_regs->doeptsiz)); ++ DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n", ++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk), ++ dwc_read_reg32(&_core_if->core_global_regs->gintmsk)); ++ } ++} ++ ++ ++/** ++ * This function does the setup for a data transfer for EP0 and starts ++ * the transfer. For an IN transfer, the packets will be loaded into ++ * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are ++ * unloaded from the Rx FIFO in the ISR. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP0 data. ++ */ ++void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ volatile depctl_data_t depctl; ++ volatile deptsiz0_data_t deptsiz; ++ gintmsk_data_t intr_mask = { .d32 = 0}; ++ ++ DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d " ++ "xfer_buff=%p start_xfer_buff=%p total_len=%d\n", ++ _ep->num, (_ep->is_in?"IN":"OUT"), _ep->xfer_len, ++ _ep->xfer_count, _ep->xfer_buff, _ep->start_xfer_buff, ++ _ep->total_len); ++ _ep->total_len = _ep->xfer_len; ++ ++ /* IN endpoint */ ++ if (_ep->is_in == 1) { ++ dwc_otg_dev_in_ep_regs_t * in_regs = _core_if->dev_if->in_ep_regs[0]; ++ gnptxsts_data_t gtxstatus; ++ gtxstatus.d32 = dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); ++ if (_core_if->en_multiple_tx_fifo == 0 && ++ gtxstatus.b.nptxqspcavail == 0) { ++#ifdef DEBUG ++ deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); ++ DWC_DEBUGPL(DBG_PCD,"DIEPCTL0=%0x\n", ++ dwc_read_reg32(&in_regs->diepctl)); ++ DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n", ++ deptsiz.d32, deptsiz.b.xfersize,deptsiz.b.pktcnt); ++ DWC_PRINT("TX Queue or FIFO Full (0x%0x)\n", gtxstatus.d32); ++#endif /* */ ++ printk("TX Queue or FIFO Full!!!!\n"); // test-only ++ //return; ++ MDELAY(100); //james ++ } ++ ++ depctl.d32 = dwc_read_reg32(&in_regs->diepctl); ++ deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); ++ ++ /* Zero Length Packet? */ ++ if (_ep->xfer_len == 0) { ++ deptsiz.b.xfersize = 0; ++ deptsiz.b.pktcnt = 1; ++ } else { ++ /* Program the transfer size and packet count ++ * as follows: xfersize = N * maxpacket + ++ * short_packet pktcnt = N + (short_packet ++ * exist ? 1 : 0) ++ */ ++ if (_ep->xfer_len > _ep->maxpacket) { ++ _ep->xfer_len = _ep->maxpacket; ++ deptsiz.b.xfersize = _ep->maxpacket; ++ } ++ else { ++ deptsiz.b.xfersize = _ep->xfer_len; ++ } ++ deptsiz.b.pktcnt = 1; ++ ++ } ++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); ++ DWC_DEBUGPL(DBG_PCDV, "IN len=%d xfersize=%d pktcnt=%d [%08x]\n", ++ _ep->xfer_len, deptsiz.b.xfersize,deptsiz.b.pktcnt, deptsiz.d32); ++ ++ /* Write the DMA register */ ++ if (_core_if->dma_enable) { ++ dwc_write_reg32(&(in_regs->diepdma), (uint32_t) _ep->dma_addr); ++ } ++ ++ /* EP enable, IN data in FIFO */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ dwc_write_reg32(&in_regs->diepctl, depctl.d32); ++ ++ /** ++ * Enable the Non-Periodic Tx FIFO empty interrupt, the ++ * data will be written into the fifo by the ISR. ++ */ ++ if (!_core_if->dma_enable) { ++ if (_core_if->en_multiple_tx_fifo == 0) { ++ intr_mask.b.nptxfempty = 1; ++ dwc_modify_reg32(&_core_if->core_global_regs->gintsts, intr_mask.d32, 0); ++ dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, intr_mask.d32, ++ intr_mask.d32); ++ } else { ++ /* Enable the Tx FIFO Empty Interrupt for this EP */ ++ if (_ep->xfer_len > 0) { ++ uint32_t fifoemptymsk = 0; ++ fifoemptymsk |= 1 << _ep->num; ++ dwc_modify_reg32(&_core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk, ++ 0, fifoemptymsk); ++ } ++ ++ } ++ } ++ } else { ++ /* OUT endpoint */ ++ dwc_otg_dev_out_ep_regs_t * out_regs = _core_if->dev_if->out_ep_regs[_ep->num]; ++ ++ depctl.d32 = dwc_read_reg32(&out_regs->doepctl); ++ deptsiz.d32 = dwc_read_reg32(&out_regs->doeptsiz); ++ ++ /* Program the transfer size and packet count as follows: ++ * xfersize = N * (maxpacket + 4 - (maxpacket % 4)) ++ * pktcnt = N */ ++ if (_ep->xfer_len == 0) { ++ /* Zero Length Packet */ ++ deptsiz.b.xfersize = _ep->maxpacket; ++ deptsiz.b.pktcnt = 1; ++ } else { ++ deptsiz.b.pktcnt = (_ep->xfer_len + (_ep->maxpacket - 1)) / _ep->maxpacket; ++ deptsiz.b.xfersize = deptsiz.b.pktcnt * _ep->maxpacket; ++ } ++ ++ dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32); ++ DWC_DEBUGPL(DBG_PCDV, "len=%d xfersize=%d pktcnt=%d\n", ++ _ep->xfer_len, deptsiz.b.xfersize,deptsiz.b.pktcnt); ++ ++ if (_core_if->dma_enable) { ++ dwc_write_reg32(&(out_regs->doepdma), (uint32_t) _ep->dma_addr); ++ } ++ ++ /* EP enable */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ dwc_write_reg32 (&(out_regs->doepctl), depctl.d32); ++ } ++} ++ ++/** ++ * This function continues control IN transfers started by ++ * dwc_otg_ep0_start_transfer, when the transfer does not fit in a ++ * single packet. NOTE: The DIEPCTL0/DOEPCTL0 registers only have one ++ * bit for the packet count. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP0 data. ++ */ ++void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ depctl_data_t depctl; ++ deptsiz0_data_t deptsiz; ++ gintmsk_data_t intr_mask = { .d32 = 0}; ++ ++ if (_ep->is_in == 1) { ++ dwc_otg_dev_in_ep_regs_t *in_regs = ++ _core_if->dev_if->in_ep_regs[0]; ++ gnptxsts_data_t tx_status = {.d32 = 0}; ++ ++ tx_status.d32 = dwc_read_reg32( &_core_if->core_global_regs->gnptxsts ); ++ /** @todo Should there be check for room in the Tx ++ * Status Queue. If not remove the code above this comment. */ ++ ++ depctl.d32 = dwc_read_reg32(&in_regs->diepctl); ++ deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz); ++ ++ /* Program the transfer size and packet count ++ * as follows: xfersize = N * maxpacket + ++ * short_packet pktcnt = N + (short_packet ++ * exist ? 1 : 0) ++ */ ++ deptsiz.b.xfersize = (_ep->total_len - _ep->xfer_count) > _ep->maxpacket ? _ep->maxpacket : ++ (_ep->total_len - _ep->xfer_count); ++ deptsiz.b.pktcnt = 1; ++ _ep->xfer_len += deptsiz.b.xfersize; ++ ++ dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32); ++ DWC_DEBUGPL(DBG_PCDV, "IN len=%d xfersize=%d pktcnt=%d [%08x]\n", ++ _ep->xfer_len, ++ deptsiz.b.xfersize, deptsiz.b.pktcnt, deptsiz.d32); ++ ++ /* Write the DMA register */ ++ if (_core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) { ++ dwc_write_reg32 (&(in_regs->diepdma), ++ CPHYSADDR((uint32_t)_ep->dma_addr)); // winder ++ } ++ ++ /* EP enable, IN data in FIFO */ ++ depctl.b.cnak = 1; ++ depctl.b.epena = 1; ++ dwc_write_reg32(&in_regs->diepctl, depctl.d32); ++ ++ /** ++ * Enable the Non-Periodic Tx FIFO empty interrupt, the ++ * data will be written into the fifo by the ISR. ++ */ ++ if (!_core_if->dma_enable) { ++ /* First clear it from GINTSTS */ ++ intr_mask.b.nptxfempty = 1; ++ dwc_write_reg32( &_core_if->core_global_regs->gintsts, ++ intr_mask.d32 ); ++ ++ dwc_modify_reg32( &_core_if->core_global_regs->gintmsk, ++ intr_mask.d32, intr_mask.d32); ++ } ++ ++ } ++ ++} ++ ++#ifdef DEBUG ++void dump_msg(const u8 *buf, unsigned int length) ++{ ++ 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; ++ DWC_PRINT( "%6x: %s\n", start, line); ++ buf += num; ++ start += num; ++ length -= num; ++ } ++} ++#else ++static inline void dump_msg(const u8 *buf, unsigned int length) ++{ ++} ++#endif ++ ++/** ++ * This function writes a packet into the Tx FIFO associated with the ++ * EP. For non-periodic EPs the non-periodic Tx FIFO is written. For ++ * periodic EPs the periodic Tx FIFO associated with the EP is written ++ * with all packets for the next micro-frame. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to write packet for. ++ * @param _dma Indicates if DMA is being used. ++ */ ++void dwc_otg_ep_write_packet(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep, int _dma) ++{ ++ /** ++ * The buffer is padded to DWORD on a per packet basis in ++ * slave/dma mode if the MPS is not DWORD aligned. The last ++ * packet, if short, is also padded to a multiple of DWORD. ++ * ++ * ep->xfer_buff always starts DWORD aligned in memory and is a ++ * multiple of DWORD in length ++ * ++ * ep->xfer_len can be any number of bytes ++ * ++ * ep->xfer_count is a multiple of ep->maxpacket until the last ++ * packet ++ * ++ * FIFO access is DWORD */ ++ ++ uint32_t i; ++ uint32_t byte_count; ++ uint32_t dword_count; ++ uint32_t *fifo; ++ uint32_t *data_buff = (uint32_t *)_ep->xfer_buff; ++ ++ //DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p)\n", __func__, _core_if, _ep); ++ if (_ep->xfer_count >= _ep->xfer_len) { ++ DWC_WARN("%s() No data for EP%d!!!\n", __func__, _ep->num); ++ return; ++ } ++ ++ /* Find the byte length of the packet either short packet or MPS */ ++ if ((_ep->xfer_len - _ep->xfer_count) < _ep->maxpacket) { ++ byte_count = _ep->xfer_len - _ep->xfer_count; ++ } ++ else { ++ byte_count = _ep->maxpacket; ++ } ++ ++ /* Find the DWORD length, padded by extra bytes as neccessary if MPS ++ * is not a multiple of DWORD */ ++ dword_count = (byte_count + 3) / 4; ++ ++#ifdef VERBOSE ++ dump_msg(_ep->xfer_buff, byte_count); ++#endif ++ if (_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ /**@todo NGS Where are the Periodic Tx FIFO addresses ++ * intialized? What should this be? */ ++ fifo = _core_if->data_fifo[_ep->tx_fifo_num]; ++ } else { ++ fifo = _core_if->data_fifo[_ep->num]; ++ } ++ ++ DWC_DEBUGPL((DBG_PCDV|DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n", ++ fifo, data_buff, *data_buff, byte_count); ++ ++ ++ if (!_dma) { ++ for (i=0; i<dword_count; i++, data_buff++) { ++ dwc_write_reg32( fifo, *data_buff ); ++ } ++ } ++ ++ _ep->xfer_count += byte_count; ++ _ep->xfer_buff += byte_count; ++#if 1 // winder, why do we need this?? ++ _ep->dma_addr += byte_count; ++#endif ++} ++ ++/** ++ * Set the EP STALL. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to set the stall on. ++ */ ++void dwc_otg_ep_set_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ depctl_data_t depctl; ++ volatile uint32_t *depctl_addr; ++ ++ DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _ep->num, ++ (_ep->is_in?"IN":"OUT")); ++ ++ if (_ep->is_in == 1) { ++ depctl_addr = &(_core_if->dev_if->in_ep_regs[_ep->num]->diepctl); ++ depctl.d32 = dwc_read_reg32(depctl_addr); ++ ++ /* set the disable and stall bits */ ++ if (depctl.b.epena) { ++ depctl.b.epdis = 1; ++ } ++ depctl.b.stall = 1; ++ dwc_write_reg32(depctl_addr, depctl.d32); ++ ++ } else { ++ depctl_addr = &(_core_if->dev_if->out_ep_regs[_ep->num]->doepctl); ++ depctl.d32 = dwc_read_reg32(depctl_addr); ++ ++ /* set the stall bit */ ++ depctl.b.stall = 1; ++ dwc_write_reg32(depctl_addr, depctl.d32); ++ } ++ DWC_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",dwc_read_reg32(depctl_addr)); ++ return; ++} ++ ++/** ++ * Clear the EP STALL. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _ep The EP to clear stall from. ++ */ ++void dwc_otg_ep_clear_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep) ++{ ++ depctl_data_t depctl; ++ volatile uint32_t *depctl_addr; ++ ++ DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _ep->num, ++ (_ep->is_in?"IN":"OUT")); ++ ++ if (_ep->is_in == 1) { ++ depctl_addr = &(_core_if->dev_if->in_ep_regs[_ep->num]->diepctl); ++ } else { ++ depctl_addr = &(_core_if->dev_if->out_ep_regs[_ep->num]->doepctl); ++ } ++ ++ depctl.d32 = dwc_read_reg32(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 == DWC_OTG_EP_TYPE_INTR || ++ _ep->type == DWC_OTG_EP_TYPE_BULK) { ++ depctl.b.setd0pid = 1; /* DATA0 */ ++ } ++ ++ dwc_write_reg32(depctl_addr, depctl.d32); ++ DWC_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",dwc_read_reg32(depctl_addr)); ++ return; ++} ++ ++/** ++ * This function reads a packet from the Rx FIFO into the destination ++ * buffer. To read SETUP data use dwc_otg_read_setup_packet. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _dest Destination buffer for the packet. ++ * @param _bytes Number of bytes to copy to the destination. ++ */ ++void dwc_otg_read_packet(dwc_otg_core_if_t *_core_if, ++ uint8_t *_dest, ++ uint16_t _bytes) ++{ ++ int i; ++ int word_count = (_bytes + 3) / 4; ++ ++ volatile uint32_t *fifo = _core_if->data_fifo[0]; ++ uint32_t *data_buff = (uint32_t *)_dest; ++ ++ /** ++ * @todo Account for the case where _dest is not dword aligned. This ++ * requires reading data from the FIFO into a uint32_t temp buffer, ++ * then moving it into the data buffer. ++ */ ++ ++ DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__, ++ _core_if, _dest, _bytes); ++ ++ for (i=0; i<word_count; i++, data_buff++) { ++ *data_buff = dwc_read_reg32(fifo); ++ } ++ ++ return; ++} ++ ++ ++#ifdef DEBUG ++/** ++ * This functions reads the device registers and prints them ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++void dwc_otg_dump_dev_registers(dwc_otg_core_if_t *_core_if) ++{ ++ int i; ++ volatile uint32_t *addr; ++ ++ DWC_PRINT("Device Global Registers\n"); ++ addr=&_core_if->dev_if->dev_global_regs->dcfg; ++ DWC_PRINT("DCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->dctl; ++ DWC_PRINT("DCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->dsts; ++ DWC_PRINT("DSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->diepmsk; ++ DWC_PRINT("DIEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->doepmsk; ++ DWC_PRINT("DOEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->daint; ++ DWC_PRINT("DAINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->dev_global_regs->dtknqr1; ++ DWC_PRINT("DTKNQR1 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 6) { ++ addr=&_core_if->dev_if->dev_global_regs->dtknqr2; ++ DWC_PRINT("DTKNQR2 @0x%08X : 0x%08X\n", ++ (uint32_t)addr,dwc_read_reg32(addr)); ++ } ++ ++ addr=&_core_if->dev_if->dev_global_regs->dvbusdis; ++ DWC_PRINT("DVBUSID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ ++ addr=&_core_if->dev_if->dev_global_regs->dvbuspulse; ++ DWC_PRINT("DVBUSPULSE @0x%08X : 0x%08X\n", ++ (uint32_t)addr,dwc_read_reg32(addr)); ++ ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 14) { ++ addr = &_core_if->dev_if->dev_global_regs->dtknqr3_dthrctl; ++ DWC_PRINT("DTKNQR3 @0x%08X : 0x%08X\n", ++ (uint32_t)addr, dwc_read_reg32(addr)); ++ } ++ ++ if (_core_if->hwcfg2.b.dev_token_q_depth > 22) { ++ addr = &_core_if->dev_if->dev_global_regs->dtknqr4_fifoemptymsk; ++ DWC_PRINT("DTKNQR4 @0x%08X : 0x%08X\n", (uint32_t) addr, ++ dwc_read_reg32(addr)); ++ } ++ for (i = 0; i <= _core_if->dev_if->num_in_eps; i++) { ++ DWC_PRINT("Device IN EP %d Registers\n", i); ++ addr=&_core_if->dev_if->in_ep_regs[i]->diepctl; ++ DWC_PRINT("DIEPCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->in_ep_regs[i]->diepint; ++ DWC_PRINT("DIEPINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->in_ep_regs[i]->dieptsiz; ++ DWC_PRINT("DIETSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->in_ep_regs[i]->diepdma; ++ DWC_PRINT("DIEPDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ ++addr = &_core_if->dev_if->in_ep_regs[i]->dtxfsts; ++ DWC_PRINT("DTXFSTS @0x%08X : 0x%08X\n", (uint32_t) addr, ++ dwc_read_reg32(addr)); ++ } ++ for (i = 0; i <= _core_if->dev_if->num_out_eps; i++) { ++ DWC_PRINT("Device OUT EP %d Registers\n", i); ++ addr=&_core_if->dev_if->out_ep_regs[i]->doepctl; ++ DWC_PRINT("DOEPCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->out_ep_regs[i]->doepfn; ++ DWC_PRINT("DOEPFN @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->out_ep_regs[i]->doepint; ++ DWC_PRINT("DOEPINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->out_ep_regs[i]->doeptsiz; ++ DWC_PRINT("DOETSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->dev_if->out_ep_regs[i]->doepdma; ++ DWC_PRINT("DOEPDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ } ++ return; ++} ++ ++/** ++ * This function reads the host registers and prints them ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++void dwc_otg_dump_host_registers(dwc_otg_core_if_t *_core_if) ++{ ++ int i; ++ volatile uint32_t *addr; ++ ++ DWC_PRINT("Host Global Registers\n"); ++ addr=&_core_if->host_if->host_global_regs->hcfg; ++ DWC_PRINT("HCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->host_global_regs->hfir; ++ DWC_PRINT("HFIR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->host_global_regs->hfnum; ++ DWC_PRINT("HFNUM @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->host_global_regs->hptxsts; ++ DWC_PRINT("HPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->host_global_regs->haint; ++ DWC_PRINT("HAINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->host_global_regs->haintmsk; ++ DWC_PRINT("HAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=_core_if->host_if->hprt0; ++ DWC_PRINT("HPRT0 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ ++ for (i=0; i<_core_if->core_params->host_channels; i++) { ++ DWC_PRINT("Host Channel %d Specific Registers\n", i); ++ addr=&_core_if->host_if->hc_regs[i]->hcchar; ++ DWC_PRINT("HCCHAR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->hc_regs[i]->hcsplt; ++ DWC_PRINT("HCSPLT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->hc_regs[i]->hcint; ++ DWC_PRINT("HCINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->hc_regs[i]->hcintmsk; ++ DWC_PRINT("HCINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->hc_regs[i]->hctsiz; ++ DWC_PRINT("HCTSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->host_if->hc_regs[i]->hcdma; ++ DWC_PRINT("HCDMA @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ ++ } ++ return; ++} ++ ++/** ++ * This function reads the core global registers and prints them ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++void dwc_otg_dump_global_registers(dwc_otg_core_if_t *_core_if) ++{ ++ int i; ++ volatile uint32_t *addr; ++ ++ DWC_PRINT("Core Global Registers\n"); ++ addr=&_core_if->core_global_regs->gotgctl; ++ DWC_PRINT("GOTGCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gotgint; ++ DWC_PRINT("GOTGINT @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gahbcfg; ++ DWC_PRINT("GAHBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gusbcfg; ++ DWC_PRINT("GUSBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->grstctl; ++ DWC_PRINT("GRSTCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gintsts; ++ DWC_PRINT("GINTSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gintmsk; ++ DWC_PRINT("GINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->grxstsr; ++ DWC_PRINT("GRXSTSR @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ //addr=&_core_if->core_global_regs->grxstsp; ++ //DWC_PRINT("GRXSTSP @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->grxfsiz; ++ DWC_PRINT("GRXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gnptxfsiz; ++ DWC_PRINT("GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gnptxsts; ++ DWC_PRINT("GNPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gi2cctl; ++ DWC_PRINT("GI2CCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gpvndctl; ++ DWC_PRINT("GPVNDCTL @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->ggpio; ++ DWC_PRINT("GGPIO @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->guid; ++ DWC_PRINT("GUID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->gsnpsid; ++ DWC_PRINT("GSNPSID @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg1; ++ DWC_PRINT("GHWCFG1 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg2; ++ DWC_PRINT("GHWCFG2 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg3; ++ DWC_PRINT("GHWCFG3 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->ghwcfg4; ++ DWC_PRINT("GHWCFG4 @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ addr=&_core_if->core_global_regs->hptxfsiz; ++ DWC_PRINT("HPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,dwc_read_reg32(addr)); ++ ++ for (i=0; i<_core_if->hwcfg4.b.num_dev_perio_in_ep; i++) { ++ addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i]; ++ DWC_PRINT("DPTXFSIZ[%d] @0x%08X : 0x%08X\n",i,(uint32_t)addr,dwc_read_reg32(addr)); ++ } ++ ++} ++#endif ++ ++/** ++ * Flush a Tx FIFO. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _num Tx FIFO to flush. ++ */ ++extern void dwc_otg_flush_tx_fifo( dwc_otg_core_if_t *_core_if, ++ const int _num ) ++{ ++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset = { .d32 = 0}; ++ int count = 0; ++ ++ DWC_DEBUGPL((DBG_CIL|DBG_PCDV), "Flush Tx FIFO %d\n", _num); ++ ++ greset.b.txfflsh = 1; ++ greset.b.txfnum = _num; ++ dwc_write_reg32( &global_regs->grstctl, greset.d32 ); ++ ++ do { ++ greset.d32 = dwc_read_reg32( &global_regs->grstctl); ++ if (++count > 10000){ ++ DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n", ++ __func__, greset.d32, ++ dwc_read_reg32( &global_regs->gnptxsts)); ++ break; ++ } ++ ++ udelay(1); ++ } while (greset.b.txfflsh == 1); ++ /* Wait for 3 PHY Clocks*/ ++ UDELAY(1); ++} ++ ++/** ++ * Flush Rx FIFO. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++extern void dwc_otg_flush_rx_fifo( dwc_otg_core_if_t *_core_if ) ++{ ++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset = { .d32 = 0}; ++ int count = 0; ++ ++ DWC_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__); ++ /* ++ * ++ */ ++ greset.b.rxfflsh = 1; ++ dwc_write_reg32( &global_regs->grstctl, greset.d32 ); ++ ++ do { ++ greset.d32 = dwc_read_reg32( &global_regs->grstctl); ++ if (++count > 10000){ ++ DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, ++ greset.d32); ++ break; ++ } ++ } while (greset.b.rxfflsh == 1); ++ /* Wait for 3 PHY Clocks*/ ++ UDELAY(1); ++} ++ ++/** ++ * Do core a soft reset of the core. Be careful with this because it ++ * resets all the internal state machines of the core. ++ */ ++ ++void dwc_otg_core_reset(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = _core_if->core_global_regs; ++ volatile grstctl_t greset = { .d32 = 0}; ++ int count = 0; ++ ++ DWC_DEBUGPL(DBG_CILV, "%s\n", __func__); ++ /* Wait for AHB master IDLE state. */ ++ do { ++ UDELAY(10); ++ greset.d32 = dwc_read_reg32( &global_regs->grstctl); ++ if (++count > 100000){ ++ DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x %x\n", __func__, ++ greset.d32, greset.b.ahbidle); ++ return; ++ } ++ } while (greset.b.ahbidle == 0); ++ ++// winder add. ++#if 1 ++ /* Note: Actually, I don't exactly why we need to put delay here. */ ++ MDELAY(100); ++#endif ++ /* Core Soft Reset */ ++ count = 0; ++ greset.b.csftrst = 1; ++ dwc_write_reg32( &global_regs->grstctl, greset.d32 ); ++// winder add. ++#if 1 ++ /* Note: Actually, I don't exactly why we need to put delay here. */ ++ MDELAY(100); ++#endif ++ do { ++ greset.d32 = dwc_read_reg32( &global_regs->grstctl); ++ if (++count > 10000){ ++ DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n", __func__, ++ greset.d32); ++ break; ++ } ++ udelay(1); ++ } while (greset.b.csftrst == 1); ++ /* Wait for 3 PHY Clocks*/ ++ //DWC_PRINT("100ms\n"); ++ MDELAY(100); ++} ++ ++ ++ ++/** ++ * Register HCD callbacks. The callbacks are used to start and stop ++ * the HCD for interrupt processing. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _cb the HCD callback structure. ++ * @param _p pointer to be passed to callback function (usb_hcd*). ++ */ ++extern void dwc_otg_cil_register_hcd_callbacks( dwc_otg_core_if_t *_core_if, ++ dwc_otg_cil_callbacks_t *_cb, ++ void *_p) ++{ ++ _core_if->hcd_cb = _cb; ++ _cb->p = _p; ++} ++ ++/** ++ * Register PCD callbacks. The callbacks are used to start and stop ++ * the PCD for interrupt processing. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ * @param _cb the PCD callback structure. ++ * @param _p pointer to be passed to callback function (pcd*). ++ */ ++extern void dwc_otg_cil_register_pcd_callbacks( dwc_otg_core_if_t *_core_if, ++ dwc_otg_cil_callbacks_t *_cb, ++ void *_p) ++{ ++ _core_if->pcd_cb = _cb; ++ _cb->p = _p; ++} ++ +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_cil.h +@@ -0,0 +1,911 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 631780 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#if !defined(__DWC_CIL_H__) ++#define __DWC_CIL_H__ ++ ++#include "dwc_otg_plat.h" ++ ++#include "dwc_otg_regs.h" ++#ifdef DEBUG ++#include "linux/timer.h" ++#endif ++ ++/* the OTG capabilities. */ ++#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0 ++#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1 ++#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 ++/* the maximum speed of operation in host and device mode. */ ++#define DWC_SPEED_PARAM_HIGH 0 ++#define DWC_SPEED_PARAM_FULL 1 ++/* the PHY clock rate in low power mode when connected to a ++ * Low Speed device in host mode. */ ++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0 ++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1 ++/* the type of PHY interface to use. */ ++#define DWC_PHY_TYPE_PARAM_FS 0 ++#define DWC_PHY_TYPE_PARAM_UTMI 1 ++#define DWC_PHY_TYPE_PARAM_ULPI 2 ++/* whether to use the internal or external supply to ++ * drive the vbus with a ULPI phy. */ ++#define DWC_PHY_ULPI_INTERNAL_VBUS 0 ++#define DWC_PHY_ULPI_EXTERNAL_VBUS 1 ++/* EP type. */ ++ ++/** ++ * @file ++ * This file contains the interface to the Core Interface Layer. ++ */ ++ ++/** ++ * The <code>dwc_ep</code> structure represents the state of a single ++ * endpoint when acting in device mode. It contains the data items ++ * needed for an endpoint to be activated and transfer packets. ++ */ ++typedef struct dwc_ep { ++ /** EP number used for register address lookup */ ++ uint8_t num; ++ /** EP direction 0 = OUT */ ++ unsigned is_in : 1; ++ /** EP active. */ ++ unsigned active : 1; ++ ++ /** Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use non-periodic Tx FIFO ++ If dedicated Tx FIFOs are enabled for all IN Eps - Tx FIFO # FOR IN EPs*/ ++ unsigned tx_fifo_num : 4; ++ /** EP type: 0 - Control, 1 - ISOC, 2 - BULK, 3 - INTR */ ++ unsigned type : 2; ++#define DWC_OTG_EP_TYPE_CONTROL 0 ++#define DWC_OTG_EP_TYPE_ISOC 1 ++#define DWC_OTG_EP_TYPE_BULK 2 ++#define DWC_OTG_EP_TYPE_INTR 3 ++ ++ /** DATA start PID for INTR and BULK EP */ ++ unsigned data_pid_start : 1; ++ /** Frame (even/odd) for ISOC EP */ ++ unsigned even_odd_frame : 1; ++ /** Max Packet bytes */ ++ unsigned maxpacket : 11; ++ ++ /** @name Transfer state */ ++ /** @{ */ ++ ++ /** ++ * Pointer to the beginning of the transfer buffer -- do not modify ++ * during transfer. ++ */ ++ ++ uint32_t dma_addr; ++ ++ uint8_t *start_xfer_buff; ++ /** pointer to the transfer buffer */ ++ uint8_t *xfer_buff; ++ /** Number of bytes to transfer */ ++ unsigned xfer_len : 19; ++ /** Number of bytes transferred. */ ++ unsigned xfer_count : 19; ++ /** Sent ZLP */ ++ unsigned sent_zlp : 1; ++ /** Total len for control transfer */ ++ unsigned total_len : 19; ++ ++ /** stall clear flag */ ++ unsigned stall_clear_flag : 1; ++ ++ /** @} */ ++} dwc_ep_t; ++ ++/* ++ * Reasons for halting a host channel. ++ */ ++typedef enum dwc_otg_halt_status { ++ DWC_OTG_HC_XFER_NO_HALT_STATUS, ++ DWC_OTG_HC_XFER_COMPLETE, ++ DWC_OTG_HC_XFER_URB_COMPLETE, ++ DWC_OTG_HC_XFER_ACK, ++ DWC_OTG_HC_XFER_NAK, ++ DWC_OTG_HC_XFER_NYET, ++ DWC_OTG_HC_XFER_STALL, ++ DWC_OTG_HC_XFER_XACT_ERR, ++ DWC_OTG_HC_XFER_FRAME_OVERRUN, ++ DWC_OTG_HC_XFER_BABBLE_ERR, ++ DWC_OTG_HC_XFER_DATA_TOGGLE_ERR, ++ DWC_OTG_HC_XFER_AHB_ERR, ++ DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE, ++ DWC_OTG_HC_XFER_URB_DEQUEUE ++} dwc_otg_halt_status_e; ++ ++/** ++ * 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 dwc_hc { ++ /** Host channel number used for register address lookup */ ++ uint8_t hc_num; ++ ++ /** Device to access */ ++ unsigned dev_addr : 7; ++ ++ /** EP to access */ ++ unsigned ep_num : 4; ++ ++ /** EP direction. 0: OUT, 1: IN */ ++ unsigned ep_is_in : 1; ++ ++ /** ++ * EP speed. ++ * One of the following values: ++ * - DWC_OTG_EP_SPEED_LOW ++ * - DWC_OTG_EP_SPEED_FULL ++ * - DWC_OTG_EP_SPEED_HIGH ++ */ ++ unsigned speed : 2; ++#define DWC_OTG_EP_SPEED_LOW 0 ++#define DWC_OTG_EP_SPEED_FULL 1 ++#define DWC_OTG_EP_SPEED_HIGH 2 ++ ++ /** ++ * Endpoint type. ++ * One of the following values: ++ * - DWC_OTG_EP_TYPE_CONTROL: 0 ++ * - DWC_OTG_EP_TYPE_ISOC: 1 ++ * - DWC_OTG_EP_TYPE_BULK: 2 ++ * - DWC_OTG_EP_TYPE_INTR: 3 ++ */ ++ unsigned ep_type : 2; ++ ++ /** Max packet size in bytes */ ++ unsigned max_packet : 11; ++ ++ /** ++ * PID for initial transaction. ++ * 0: DATA0,<br> ++ * 1: DATA2,<br> ++ * 2: DATA1,<br> ++ * 3: MDATA (non-Control EP), ++ * SETUP (Control EP) ++ */ ++ unsigned data_pid_start : 2; ++#define DWC_OTG_HC_PID_DATA0 0 ++#define DWC_OTG_HC_PID_DATA2 1 ++#define DWC_OTG_HC_PID_DATA1 2 ++#define DWC_OTG_HC_PID_MDATA 3 ++#define DWC_OTG_HC_PID_SETUP 3 ++ ++ /** Number of periodic transactions per (micro)frame */ ++ unsigned multi_count: 2; ++ ++ /** @name Transfer State */ ++ /** @{ */ ++ ++ /** Pointer to the current transfer buffer position. */ ++ uint8_t *xfer_buff; ++ /** Total number of bytes to transfer. */ ++ uint32_t xfer_len; ++ /** Number of bytes transferred so far. */ ++ uint32_t xfer_count; ++ /** Packet count at start of transfer.*/ ++ uint16_t start_pkt_count; ++ ++ /** ++ * Flag to indicate whether the transfer has been started. Set to 1 if ++ * it has been started, 0 otherwise. ++ */ ++ uint8_t xfer_started; ++ ++ /** ++ * Set to 1 to indicate that a PING request should be issued on this ++ * channel. If 0, process normally. ++ */ ++ uint8_t do_ping; ++ ++ /** ++ * Set to 1 to indicate that the error count for this transaction is ++ * non-zero. Set to 0 if the error count is 0. ++ */ ++ uint8_t error_state; ++ ++ /** ++ * Set to 1 to indicate that this channel should be halted the next ++ * time a request is queued for the channel. This is necessary in ++ * slave mode if no request queue space is available when an attempt ++ * is made to halt the channel. ++ */ ++ uint8_t halt_on_queue; ++ ++ /** ++ * Set to 1 if the host channel has been halted, but the core is not ++ * finished flushing queued requests. Otherwise 0. ++ */ ++ uint8_t halt_pending; ++ ++ /** ++ * Reason for halting the host channel. ++ */ ++ dwc_otg_halt_status_e halt_status; ++ ++ /* ++ * Split settings for the host channel ++ */ ++ uint8_t do_split; /**< Enable split for the channel */ ++ uint8_t complete_split; /**< Enable complete split */ ++ uint8_t hub_addr; /**< Address of high speed hub */ ++ ++ uint8_t port_addr; /**< Port of the low/full speed device */ ++ /** Split transaction position ++ * One of the following values: ++ * - DWC_HCSPLIT_XACTPOS_MID ++ * - DWC_HCSPLIT_XACTPOS_BEGIN ++ * - DWC_HCSPLIT_XACTPOS_END ++ * - DWC_HCSPLIT_XACTPOS_ALL */ ++ uint8_t xact_pos; ++ ++ /** Set when the host channel does a short read. */ ++ uint8_t short_read; ++ ++ /** ++ * Number of requests issued for this channel since it was assigned to ++ * the current transfer (not counting PINGs). ++ */ ++ uint8_t requests; ++ ++ /** ++ * Queue Head for the transfer being processed by this channel. ++ */ ++ struct dwc_otg_qh *qh; ++ ++ /** @} */ ++ ++ /** Entry in list of host channels. */ ++ struct list_head hc_list_entry; ++} dwc_hc_t; ++ ++/** ++ * The following parameters may be specified when starting the module. These ++ * parameters define how the DWC_otg controller should be configured. ++ * Parameter values are passed to the CIL initialization function ++ * dwc_otg_cil_init. ++ */ ++ ++typedef struct dwc_otg_core_params ++{ ++ int32_t opt; ++//#define dwc_param_opt_default 1 ++ /** ++ * Specifies the OTG capabilities. The driver will automatically ++ * detect the value for this parameter if none is specified. ++ * 0 - HNP and SRP capable (default) ++ * 1 - SRP Only capable ++ * 2 - No HNP/SRP capable ++ */ ++ int32_t otg_cap; ++#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0 ++#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1 ++#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 ++//#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE ++ /** ++ * Specifies whether to use slave or DMA mode for accessing the data ++ * FIFOs. The driver will automatically detect the value for this ++ * parameter if none is specified. ++ * 0 - Slave ++ * 1 - DMA (default, if available) ++ */ ++ int32_t dma_enable; ++//#define dwc_param_dma_enable_default 1 ++ /** The DMA Burst size (applicable only for External DMA ++ * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32) ++ */ ++ int32_t dma_burst_size; /* Translate this to GAHBCFG values */ ++//#define dwc_param_dma_burst_size_default 32 ++ /** ++ * 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 speed; ++//#define dwc_param_speed_default 0 ++#define DWC_SPEED_PARAM_HIGH 0 ++#define DWC_SPEED_PARAM_FULL 1 ++ ++ /** Specifies whether low power mode is supported when attached ++ * to a Full Speed or Low Speed device in host mode. ++ * 0 - Don't support low power mode (default) ++ * 1 - Support low power mode ++ */ ++ int32_t host_support_fs_ls_low_power; ++//#define dwc_param_host_support_fs_ls_low_power_default 0 ++ /** Specifies the PHY clock rate in low power mode when connected to a ++ * Low Speed device in host mode. This parameter is applicable only if ++ * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS ++ * then defaults to 6 MHZ otherwise 48 MHZ. ++ * ++ * 0 - 48 MHz ++ * 1 - 6 MHz ++ */ ++ int32_t host_ls_low_power_phy_clk; ++//#define dwc_param_host_ls_low_power_phy_clk_default 0 ++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0 ++#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1 ++ /** ++ * 0 - Use cC FIFO size parameters ++ * 1 - Allow dynamic FIFO sizing (default) ++ */ ++ int32_t enable_dynamic_fifo; ++//#define dwc_param_enable_dynamic_fifo_default 1 ++ /** Total number of 4-byte words in the data FIFO memory. This ++ * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic ++ * Tx FIFOs. ++ * 32 to 32768 (default 8192) ++ * Note: The total FIFO memory depth in the FPGA configuration is 8192. ++ */ ++ int32_t data_fifo_size; ++//#define dwc_param_data_fifo_size_default 8192 ++ /** Number of 4-byte words in the Rx FIFO in device mode when dynamic ++ * FIFO sizing is enabled. ++ * 16 to 32768 (default 1064) ++ */ ++ int32_t dev_rx_fifo_size; ++//#define dwc_param_dev_rx_fifo_size_default 1064 ++ /** Number of 4-byte words in the non-periodic Tx FIFO in device mode ++ * when dynamic FIFO sizing is enabled. ++ * 16 to 32768 (default 1024) ++ */ ++ int32_t dev_nperio_tx_fifo_size; ++//#define dwc_param_dev_nperio_tx_fifo_size_default 1024 ++ /** Number of 4-byte words in each of the periodic Tx FIFOs in device ++ * mode when dynamic FIFO sizing is enabled. ++ * 4 to 768 (default 256) ++ */ ++ uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS]; ++//#define dwc_param_dev_perio_tx_fifo_size_default 256 ++ /** Number of 4-byte words in the Rx FIFO in host mode when dynamic ++ * FIFO sizing is enabled. ++ * 16 to 32768 (default 1024) ++ */ ++ int32_t host_rx_fifo_size; ++//#define dwc_param_host_rx_fifo_size_default 1024 ++ /** Number of 4-byte words in the non-periodic Tx FIFO in host mode ++ * when Dynamic FIFO sizing is enabled in the core. ++ * 16 to 32768 (default 1024) ++ */ ++ int32_t host_nperio_tx_fifo_size; ++//#define dwc_param_host_nperio_tx_fifo_size_default 1024 ++ /** Number of 4-byte words in the host periodic Tx FIFO when dynamic ++ * FIFO sizing is enabled. ++ * 16 to 32768 (default 1024) ++ */ ++ int32_t host_perio_tx_fifo_size; ++//#define dwc_param_host_perio_tx_fifo_size_default 1024 ++ /** The maximum transfer size supported in bytes. ++ * 2047 to 65,535 (default 65,535) ++ */ ++ int32_t max_transfer_size; ++//#define dwc_param_max_transfer_size_default 65535 ++ /** The maximum number of packets in a transfer. ++ * 15 to 511 (default 511) ++ */ ++ int32_t max_packet_count; ++//#define dwc_param_max_packet_count_default 511 ++ /** The number of host channel registers to use. ++ * 1 to 16 (default 12) ++ * Note: The FPGA configuration supports a maximum of 12 host channels. ++ */ ++ int32_t host_channels; ++//#define dwc_param_host_channels_default 12 ++ /** The number of endpoints in addition to EP0 available for device ++ * mode operations. ++ * 1 to 15 (default 6 IN and OUT) ++ * Note: The FPGA configuration supports a maximum of 6 IN and OUT ++ * endpoints in addition to EP0. ++ */ ++ int32_t dev_endpoints; ++//#define dwc_param_dev_endpoints_default 6 ++ /** ++ * Specifies the type of PHY interface to use. By default, the driver ++ * will automatically detect the phy_type. ++ * ++ * 0 - Full Speed PHY ++ * 1 - UTMI+ (default) ++ * 2 - ULPI ++ */ ++ int32_t phy_type; ++#define DWC_PHY_TYPE_PARAM_FS 0 ++#define DWC_PHY_TYPE_PARAM_UTMI 1 ++#define DWC_PHY_TYPE_PARAM_ULPI 2 ++//#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI ++ /** ++ * Specifies the UTMI+ Data Width. This parameter is ++ * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI ++ * PHY_TYPE, this parameter indicates the data width between ++ * the MAC and the ULPI Wrapper.) Also, this parameter is ++ * applicable only if the OTG_HSPHY_WIDTH cC parameter was set ++ * to "8 and 16 bits", meaning that the core has been ++ * configured to work at either data path width. ++ * ++ * 8 or 16 bits (default 16) ++ */ ++ int32_t phy_utmi_width; ++//#define dwc_param_phy_utmi_width_default 16 ++ /** ++ * Specifies whether the ULPI operates at double or single ++ * data rate. This parameter is only applicable if PHY_TYPE is ++ * ULPI. ++ * ++ * 0 - single data rate ULPI interface with 8 bit wide data ++ * bus (default) ++ * 1 - double data rate ULPI interface with 4 bit wide data ++ * bus ++ */ ++ int32_t phy_ulpi_ddr; ++//#define dwc_param_phy_ulpi_ddr_default 0 ++ /** ++ * Specifies whether to use the internal or external supply to ++ * drive the vbus with a ULPI phy. ++ */ ++ int32_t phy_ulpi_ext_vbus; ++#define DWC_PHY_ULPI_INTERNAL_VBUS 0 ++#define DWC_PHY_ULPI_EXTERNAL_VBUS 1 ++//#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS ++ /** ++ * Specifies whether to use the I2Cinterface for full speed PHY. This ++ * parameter is only applicable if PHY_TYPE is FS. ++ * 0 - No (default) ++ * 1 - Yes ++ */ ++ int32_t i2c_enable; ++//#define dwc_param_i2c_enable_default 0 ++ ++ int32_t ulpi_fs_ls; ++//#define dwc_param_ulpi_fs_ls_default 0 ++ ++ int32_t ts_dline; ++//#define dwc_param_ts_dline_default 0 ++ ++ /** ++ * Specifies whether dedicated transmit FIFOs are ++ * enabled for non periodic IN endpoints in device mode ++ * 0 - No ++ * 1 - Yes ++ */ ++ int32_t en_multiple_tx_fifo; ++#define dwc_param_en_multiple_tx_fifo_default 1 ++ ++ /** Number of 4-byte words in each of the Tx FIFOs in device ++ * mode when dynamic FIFO sizing is enabled. ++ * 4 to 768 (default 256) ++ */ ++ uint32_t dev_tx_fifo_size[MAX_TX_FIFOS]; ++#define dwc_param_dev_tx_fifo_size_default 256 ++ ++ /** Thresholding enable flag- ++ * bit 0 - enable non-ISO Tx thresholding ++ * bit 1 - enable ISO Tx thresholding ++ * bit 2 - enable Rx thresholding ++ */ ++ uint32_t thr_ctl; ++#define dwc_param_thr_ctl_default 0 ++ ++ /** Thresholding length for Tx ++ * FIFOs in 32 bit DWORDs ++ */ ++ uint32_t tx_thr_length; ++#define dwc_param_tx_thr_length_default 64 ++ ++ /** Thresholding length for Rx ++ * FIFOs in 32 bit DWORDs ++ */ ++ uint32_t rx_thr_length; ++#define dwc_param_rx_thr_length_default 64 ++} dwc_otg_core_params_t; ++ ++#ifdef DEBUG ++struct dwc_otg_core_if; ++typedef struct hc_xfer_info ++{ ++ struct dwc_otg_core_if *core_if; ++ dwc_hc_t *hc; ++} hc_xfer_info_t; ++#endif ++ ++/** ++ * The <code>dwc_otg_core_if</code> structure contains information needed to manage ++ * the DWC_otg controller acting in either host or device mode. It ++ * represents the programming view of the controller as a whole. ++ */ ++typedef struct dwc_otg_core_if ++{ ++ /** Parameters that define how the core should be configured.*/ ++ dwc_otg_core_params_t *core_params; ++ ++ /** Core Global registers starting at offset 000h. */ ++ dwc_otg_core_global_regs_t *core_global_regs; ++ ++ /** Device-specific information */ ++ dwc_otg_dev_if_t *dev_if; ++ /** Host-specific information */ ++ dwc_otg_host_if_t *host_if; ++ ++ /* ++ * Set to 1 if the core PHY interface bits in USBCFG have been ++ * initialized. ++ */ ++ uint8_t phy_init_done; ++ ++ /* ++ * SRP Success flag, set by srp success interrupt in FS I2C mode ++ */ ++ uint8_t srp_success; ++ uint8_t srp_timer_started; ++ ++ /* Common configuration information */ ++ /** Power and Clock Gating Control Register */ ++ volatile uint32_t *pcgcctl; ++#define DWC_OTG_PCGCCTL_OFFSET 0xE00 ++ ++ /** Push/pop addresses for endpoints or host channels.*/ ++ uint32_t *data_fifo[MAX_EPS_CHANNELS]; ++#define DWC_OTG_DATA_FIFO_OFFSET 0x1000 ++#define DWC_OTG_DATA_FIFO_SIZE 0x1000 ++ ++ /** Total RAM for FIFOs (Bytes) */ ++ uint16_t total_fifo_size; ++ /** Size of Rx FIFO (Bytes) */ ++ uint16_t rx_fifo_size; ++ /** Size of Non-periodic Tx FIFO (Bytes) */ ++ uint16_t nperio_tx_fifo_size; ++ ++ /** 1 if DMA is enabled, 0 otherwise. */ ++ uint8_t dma_enable; ++ ++ /** 1 if dedicated Tx FIFOs are enabled, 0 otherwise. */ ++ uint8_t en_multiple_tx_fifo; ++ ++ /** Set to 1 if multiple packets of a high-bandwidth transfer is in ++ * process of being queued */ ++ uint8_t queuing_high_bandwidth; ++ ++ /** Hardware Configuration -- stored here for convenience.*/ ++ hwcfg1_data_t hwcfg1; ++ hwcfg2_data_t hwcfg2; ++ hwcfg3_data_t hwcfg3; ++ hwcfg4_data_t hwcfg4; ++ ++ /** The operational State, during transations ++ * (a_host>>a_peripherial and b_device=>b_host) this may not ++ * match the core but allows the software to determine ++ * transitions. ++ */ ++ uint8_t op_state; ++ ++ /** ++ * Set to 1 if the HCD needs to be restarted on a session request ++ * interrupt. This is required if no connector ID status change has ++ * occurred since the HCD was last disconnected. ++ */ ++ uint8_t restart_hcd_on_session_req; ++ ++ /** HCD callbacks */ ++ /** A-Device is a_host */ ++#define A_HOST (1) ++ /** A-Device is a_suspend */ ++#define A_SUSPEND (2) ++ /** A-Device is a_peripherial */ ++#define A_PERIPHERAL (3) ++ /** B-Device is operating as a Peripheral. */ ++#define B_PERIPHERAL (4) ++ /** B-Device is operating as a Host. */ ++#define B_HOST (5) ++ ++ /** HCD callbacks */ ++ struct dwc_otg_cil_callbacks *hcd_cb; ++ /** PCD callbacks */ ++ struct dwc_otg_cil_callbacks *pcd_cb; ++ ++ /** Device mode Periodic Tx FIFO Mask */ ++ uint32_t p_tx_msk; ++ /** Device mode Periodic Tx FIFO Mask */ ++ uint32_t tx_msk; ++ ++#ifdef DEBUG ++ uint32_t start_hcchar_val[MAX_EPS_CHANNELS]; ++ ++ hc_xfer_info_t hc_xfer_info[MAX_EPS_CHANNELS]; ++ struct timer_list hc_xfer_timer[MAX_EPS_CHANNELS]; ++ ++#if 1 // winder ++ uint32_t hfnum_7_samples; ++ uint32_t hfnum_7_frrem_accum; ++ uint32_t hfnum_0_samples; ++ uint32_t hfnum_0_frrem_accum; ++ uint32_t hfnum_other_samples; ++ uint32_t hfnum_other_frrem_accum; ++#else ++ uint32_t hfnum_7_samples; ++ uint64_t hfnum_7_frrem_accum; ++ uint32_t hfnum_0_samples; ++ uint64_t hfnum_0_frrem_accum; ++ uint32_t hfnum_other_samples; ++ uint64_t hfnum_other_frrem_accum; ++#endif ++ resource_size_t phys_addr; /* Added to support PLB DMA : phys-virt mapping */ ++#endif ++ ++} dwc_otg_core_if_t; ++ ++/* ++ * The following functions support initialization of the CIL driver component ++ * and the DWC_otg controller. ++ */ ++extern dwc_otg_core_if_t *dwc_otg_cil_init(const uint32_t *_reg_base_addr, ++ dwc_otg_core_params_t *_core_params); ++extern void dwc_otg_cil_remove(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_core_init(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_core_host_init(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_core_dev_init(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_enable_global_interrupts( dwc_otg_core_if_t *_core_if ); ++extern void dwc_otg_disable_global_interrupts( dwc_otg_core_if_t *_core_if ); ++ ++/** @name Device CIL Functions ++ * The following functions support managing the DWC_otg controller in device ++ * mode. ++ */ ++/**@{*/ ++extern void dwc_otg_wakeup(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_read_setup_packet (dwc_otg_core_if_t *_core_if, uint32_t *_dest); ++extern uint32_t dwc_otg_get_frame_number(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_ep0_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep_activate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep_deactivate(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep0_start_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep0_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep_write_packet(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep, int _dma); ++extern void dwc_otg_ep_set_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_ep_clear_stall(dwc_otg_core_if_t *_core_if, dwc_ep_t *_ep); ++extern void dwc_otg_enable_device_interrupts(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_dump_dev_registers(dwc_otg_core_if_t *_core_if); ++/**@}*/ ++ ++/** @name Host CIL Functions ++ * The following functions support managing the DWC_otg controller in host ++ * mode. ++ */ ++/**@{*/ ++extern void dwc_otg_hc_init(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern void dwc_otg_hc_halt(dwc_otg_core_if_t *_core_if, ++ dwc_hc_t *_hc, ++ dwc_otg_halt_status_e _halt_status); ++extern void dwc_otg_hc_cleanup(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern void dwc_otg_hc_start_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern int dwc_otg_hc_continue_transfer(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern void dwc_otg_hc_do_ping(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern void dwc_otg_hc_write_packet(dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc); ++extern void dwc_otg_enable_host_interrupts(dwc_otg_core_if_t *_core_if); ++extern void dwc_otg_disable_host_interrupts(dwc_otg_core_if_t *_core_if); ++ ++/** ++ * This function Reads HPRT0 in preparation to modify. It keeps the ++ * WC bits 0 so that if they are read as 1, they won't clear when you ++ * write it back ++ */ ++static inline uint32_t dwc_otg_read_hprt0(dwc_otg_core_if_t *_core_if) ++{ ++ hprt0_data_t hprt0; ++ hprt0.d32 = dwc_read_reg32(_core_if->host_if->hprt0); ++ hprt0.b.prtena = 0; ++ hprt0.b.prtconndet = 0; ++ hprt0.b.prtenchng = 0; ++ hprt0.b.prtovrcurrchng = 0; ++ return hprt0.d32; ++} ++ ++extern void dwc_otg_dump_host_registers(dwc_otg_core_if_t *_core_if); ++/**@}*/ ++ ++/** @name Common CIL Functions ++ * The following functions support managing the DWC_otg controller in either ++ * device or host mode. ++ */ ++/**@{*/ ++ ++extern void dwc_otg_read_packet(dwc_otg_core_if_t *core_if, ++ uint8_t *dest, ++ uint16_t bytes); ++ ++extern void dwc_otg_dump_global_registers(dwc_otg_core_if_t *_core_if); ++ ++extern void dwc_otg_flush_tx_fifo( dwc_otg_core_if_t *_core_if, ++ const int _num ); ++extern void dwc_otg_flush_rx_fifo( dwc_otg_core_if_t *_core_if ); ++extern void dwc_otg_core_reset( dwc_otg_core_if_t *_core_if ); ++ ++#define NP_TXFIFO_EMPTY -1 ++#define MAX_NP_TXREQUEST_Q_SLOTS 8 ++/** ++ * This function returns the endpoint number of the request at ++ * the top of non-periodic TX FIFO, or -1 if the request FIFO is ++ * empty. ++ */ ++static inline int dwc_otg_top_nptxfifo_epnum(dwc_otg_core_if_t *_core_if) { ++ gnptxsts_data_t txstatus = {.d32 = 0}; ++ ++ txstatus.d32 = dwc_read_reg32(&_core_if->core_global_regs->gnptxsts); ++ return (txstatus.b.nptxqspcavail == MAX_NP_TXREQUEST_Q_SLOTS ? ++ -1 : txstatus.b.nptxqtop_chnep); ++} ++/** ++ * This function returns the Core Interrupt register. ++ */ ++static inline uint32_t dwc_otg_read_core_intr(dwc_otg_core_if_t *_core_if) { ++ return (dwc_read_reg32(&_core_if->core_global_regs->gintsts) & ++ dwc_read_reg32(&_core_if->core_global_regs->gintmsk)); ++} ++ ++/** ++ * This function returns the OTG Interrupt register. ++ */ ++static inline uint32_t dwc_otg_read_otg_intr (dwc_otg_core_if_t *_core_if) { ++ return (dwc_read_reg32 (&_core_if->core_global_regs->gotgint)); ++} ++ ++/** ++ * This function reads the Device All Endpoints Interrupt register and ++ * returns the IN endpoint interrupt bits. ++ */ ++static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(dwc_otg_core_if_t *_core_if) { ++ uint32_t v; ++ v = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daint) & ++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk); ++ return (v & 0xffff); ++ ++} ++ ++/** ++ * This function reads the Device All Endpoints Interrupt register and ++ * returns the OUT endpoint interrupt bits. ++ */ ++static inline uint32_t dwc_otg_read_dev_all_out_ep_intr(dwc_otg_core_if_t *_core_if) { ++ uint32_t v; ++ v = dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daint) & ++ dwc_read_reg32(&_core_if->dev_if->dev_global_regs->daintmsk); ++ return ((v & 0xffff0000) >> 16); ++} ++ ++/** ++ * This function returns the Device IN EP Interrupt register ++ */ ++static inline uint32_t dwc_otg_read_dev_in_ep_intr(dwc_otg_core_if_t *_core_if, ++ dwc_ep_t *_ep) ++{ ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ uint32_t v, msk, emp; ++ msk = dwc_read_reg32(&dev_if->dev_global_regs->diepmsk); ++ emp = dwc_read_reg32(&dev_if->dev_global_regs->dtknqr4_fifoemptymsk); ++ msk |= ((emp >> _ep->num) & 0x1) << 7; ++ v = dwc_read_reg32(&dev_if->in_ep_regs[_ep->num]->diepint) & msk; ++/* ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ uint32_t v; ++ v = dwc_read_reg32(&dev_if->in_ep_regs[_ep->num]->diepint) & ++ dwc_read_reg32(&dev_if->dev_global_regs->diepmsk); ++*/ ++ return v; ++} ++/** ++ * This function returns the Device OUT EP Interrupt register ++ */ ++static inline uint32_t dwc_otg_read_dev_out_ep_intr(dwc_otg_core_if_t *_core_if, ++ dwc_ep_t *_ep) ++{ ++ dwc_otg_dev_if_t *dev_if = _core_if->dev_if; ++ uint32_t v; ++ v = dwc_read_reg32( &dev_if->out_ep_regs[_ep->num]->doepint) & ++ dwc_read_reg32(&dev_if->dev_global_regs->doepmsk); ++ return v; ++} ++ ++/** ++ * This function returns the Host All Channel Interrupt register ++ */ ++static inline uint32_t dwc_otg_read_host_all_channels_intr (dwc_otg_core_if_t *_core_if) ++{ ++ return (dwc_read_reg32 (&_core_if->host_if->host_global_regs->haint)); ++} ++ ++static inline uint32_t dwc_otg_read_host_channel_intr (dwc_otg_core_if_t *_core_if, dwc_hc_t *_hc) ++{ ++ return (dwc_read_reg32 (&_core_if->host_if->hc_regs[_hc->hc_num]->hcint)); ++} ++ ++ ++/** ++ * This function returns the mode of the operation, host or device. ++ * ++ * @return 0 - Device Mode, 1 - Host Mode ++ */ ++static inline uint32_t dwc_otg_mode(dwc_otg_core_if_t *_core_if) { ++ return (dwc_read_reg32( &_core_if->core_global_regs->gintsts ) & 0x1); ++} ++ ++static inline uint8_t dwc_otg_is_device_mode(dwc_otg_core_if_t *_core_if) ++{ ++ return (dwc_otg_mode(_core_if) != DWC_HOST_MODE); ++} ++static inline uint8_t dwc_otg_is_host_mode(dwc_otg_core_if_t *_core_if) ++{ ++ return (dwc_otg_mode(_core_if) == DWC_HOST_MODE); ++} ++ ++extern int32_t dwc_otg_handle_common_intr( dwc_otg_core_if_t *_core_if ); ++ ++ ++/**@}*/ ++ ++/** ++ * DWC_otg CIL callback structure. This structure allows the HCD and ++ * PCD to register functions used for starting and stopping the PCD ++ * and HCD for role change on for a DRD. ++ */ ++typedef struct dwc_otg_cil_callbacks ++{ ++ /** Start function for role change */ ++ int (*start) (void *_p); ++ /** Stop Function for role change */ ++ int (*stop) (void *_p); ++ /** Disconnect Function for role change */ ++ int (*disconnect) (void *_p); ++ /** Resume/Remote wakeup Function */ ++ int (*resume_wakeup) (void *_p); ++ /** Suspend function */ ++ int (*suspend) (void *_p); ++ /** Session Start (SRP) */ ++ int (*session_start) (void *_p); ++ /** Pointer passed to start() and stop() */ ++ void *p; ++} dwc_otg_cil_callbacks_t; ++ ++ ++ ++extern void dwc_otg_cil_register_pcd_callbacks( dwc_otg_core_if_t *_core_if, ++ dwc_otg_cil_callbacks_t *_cb, ++ void *_p); ++extern void dwc_otg_cil_register_hcd_callbacks( dwc_otg_core_if_t *_core_if, ++ dwc_otg_cil_callbacks_t *_cb, ++ void *_p); ++ ++ ++#endif +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_cil_ifx.h +@@ -0,0 +1,58 @@ ++/****************************************************************************** ++** ++** FILE NAME : dwc_otg_cil_ifx.h ++** PROJECT : Twinpass/Danube ++** MODULES : DWC OTG USB ++** ++** DATE : 07 Sep. 2007 ++** AUTHOR : Sung Winder ++** DESCRIPTION : Default param value. ++** COPYRIGHT : Copyright (c) 2007 ++** Infineon Technologies AG ++** 2F, No.2, Li-Hsin Rd., Hsinchu Science Park, ++** Hsin-chu City, 300 Taiwan. ++** ++** 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 ++** 12 April 2007 Sung Winder Initiate Version ++*******************************************************************************/ ++#if !defined(__DWC_OTG_CIL_IFX_H__) ++#define __DWC_OTG_CIL_IFX_H__ ++ ++/* ================ Default param value ================== */ ++#define dwc_param_opt_default 1 ++#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE ++#define dwc_param_dma_enable_default 1 ++#define dwc_param_dma_burst_size_default 32 ++#define dwc_param_speed_default DWC_SPEED_PARAM_HIGH ++#define dwc_param_host_support_fs_ls_low_power_default 0 ++#define dwc_param_host_ls_low_power_phy_clk_default DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ ++#define dwc_param_enable_dynamic_fifo_default 1 ++#define dwc_param_data_fifo_size_default 2048 ++#define dwc_param_dev_rx_fifo_size_default 1024 ++#define dwc_param_dev_nperio_tx_fifo_size_default 1024 ++#define dwc_param_dev_perio_tx_fifo_size_default 768 ++#define dwc_param_host_rx_fifo_size_default 640 ++#define dwc_param_host_nperio_tx_fifo_size_default 640 ++#define dwc_param_host_perio_tx_fifo_size_default 768 ++#define dwc_param_max_transfer_size_default 65535 ++#define dwc_param_max_packet_count_default 511 ++#define dwc_param_host_channels_default 16 ++#define dwc_param_dev_endpoints_default 6 ++#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI ++#define dwc_param_phy_utmi_width_default 16 ++#define dwc_param_phy_ulpi_ddr_default 0 ++#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS ++#define dwc_param_i2c_enable_default 0 ++#define dwc_param_ulpi_fs_ls_default 0 ++#define dwc_param_ts_dline_default 0 ++ ++/* ======================================================= */ ++ ++#endif // __DWC_OTG_CIL_IFX_H__ ++ +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_cil_intr.c +@@ -0,0 +1,708 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_cil_intr.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 553126 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++/** @file ++ * ++ * The Core Interface Layer provides basic services for accessing and ++ * managing the DWC_otg hardware. These services are used by both the ++ * Host Controller Driver and the Peripheral Controller Driver. ++ * ++ * This file contains the Common Interrupt handlers. ++ */ ++#include "dwc_otg_plat.h" ++#include "dwc_otg_regs.h" ++#include "dwc_otg_cil.h" ++ ++#ifdef DEBUG ++inline const char *op_state_str( dwc_otg_core_if_t *_core_if ) ++{ ++ return (_core_if->op_state==A_HOST?"a_host": ++ (_core_if->op_state==A_SUSPEND?"a_suspend": ++ (_core_if->op_state==A_PERIPHERAL?"a_peripheral": ++ (_core_if->op_state==B_PERIPHERAL?"b_peripheral": ++ (_core_if->op_state==B_HOST?"b_host": ++ "unknown"))))); ++} ++#endif ++ ++/** This function will log a debug message ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++int32_t dwc_otg_handle_mode_mismatch_intr (dwc_otg_core_if_t *_core_if) ++{ ++ gintsts_data_t gintsts; ++ DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n", ++ dwc_otg_mode(_core_if) ? "Host" : "Device"); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.modemismatch = 1; ++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++ ++/** Start the HCD. Helper function for using the HCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void hcd_start( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->hcd_cb && _core_if->hcd_cb->start) { ++ _core_if->hcd_cb->start( _core_if->hcd_cb->p ); ++ } ++} ++/** Stop the HCD. Helper function for using the HCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void hcd_stop( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->hcd_cb && _core_if->hcd_cb->stop) { ++ _core_if->hcd_cb->stop( _core_if->hcd_cb->p ); ++ } ++} ++/** Disconnect the HCD. Helper function for using the HCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void hcd_disconnect( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->hcd_cb && _core_if->hcd_cb->disconnect) { ++ _core_if->hcd_cb->disconnect( _core_if->hcd_cb->p ); ++ } ++} ++/** Inform the HCD the a New Session has begun. Helper function for ++ * using the HCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void hcd_session_start( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->hcd_cb && _core_if->hcd_cb->session_start) { ++ _core_if->hcd_cb->session_start( _core_if->hcd_cb->p ); ++ } ++} ++ ++/** Start the PCD. Helper function for using the PCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void pcd_start( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->pcd_cb && _core_if->pcd_cb->start ) { ++ _core_if->pcd_cb->start( _core_if->pcd_cb->p ); ++ } ++} ++/** Stop the PCD. Helper function for using the PCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void pcd_stop( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->pcd_cb && _core_if->pcd_cb->stop ) { ++ _core_if->pcd_cb->stop( _core_if->pcd_cb->p ); ++ } ++} ++/** Suspend the PCD. Helper function for using the PCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void pcd_suspend( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->pcd_cb && _core_if->pcd_cb->suspend ) { ++ _core_if->pcd_cb->suspend( _core_if->pcd_cb->p ); ++ } ++} ++/** Resume the PCD. Helper function for using the PCD callbacks. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++static inline void pcd_resume( dwc_otg_core_if_t *_core_if ) ++{ ++ if (_core_if->pcd_cb && _core_if->pcd_cb->resume_wakeup ) { ++ _core_if->pcd_cb->resume_wakeup( _core_if->pcd_cb->p ); ++ } ++} ++ ++/** ++ * This function handles the OTG Interrupts. It reads the OTG ++ * Interrupt Register (GOTGINT) to determine what interrupt has ++ * occurred. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++int32_t dwc_otg_handle_otg_intr(dwc_otg_core_if_t *_core_if) ++{ ++ dwc_otg_core_global_regs_t *global_regs = ++ _core_if->core_global_regs; ++ gotgint_data_t gotgint; ++ gotgctl_data_t gotgctl; ++ gintmsk_data_t gintmsk; ++ ++ gotgint.d32 = dwc_read_reg32( &global_regs->gotgint); ++ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl); ++ DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32, ++ op_state_str(_core_if)); ++ //DWC_DEBUGPL(DBG_CIL, "gotgctl=%08x\n", gotgctl.d32 ); ++ ++ if (gotgint.b.sesenddet) { ++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " ++ "Session End Detected++ (%s)\n", ++ op_state_str(_core_if)); ++ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl); ++ ++ if (_core_if->op_state == B_HOST) { ++ pcd_start( _core_if ); ++ _core_if->op_state = B_PERIPHERAL; ++ } else { ++ /* If not B_HOST and Device HNP still set. HNP ++ * Did not succeed!*/ ++ if (gotgctl.b.devhnpen) { ++ DWC_DEBUGPL(DBG_ANY, "Session End Detected\n"); ++ DWC_ERROR( "Device Not Connected/Responding!\n" ); ++ } ++ ++ /* If Session End Detected the B-Cable has ++ * been disconnected. */ ++ /* Reset PCD and Gadget driver to a ++ * clean state. */ ++ pcd_stop(_core_if); ++ } ++ gotgctl.d32 = 0; ++ gotgctl.b.devhnpen = 1; ++ dwc_modify_reg32( &global_regs->gotgctl, ++ gotgctl.d32, 0); ++ } ++ if (gotgint.b.sesreqsucstschng) { ++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " ++ "Session Reqeust Success Status Change++\n"); ++ gotgctl.d32 = dwc_read_reg32( &global_regs->gotgctl); ++ if (gotgctl.b.sesreqscs) { ++ if ((_core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) && ++ (_core_if->core_params->i2c_enable)) { ++ _core_if->srp_success = 1; ++ } ++ else { ++ pcd_resume( _core_if ); ++ /* Clear Session Request */ ++ gotgctl.d32 = 0; ++ gotgctl.b.sesreq = 1; ++ dwc_modify_reg32( &global_regs->gotgctl, ++ gotgctl.d32, 0); ++ } ++ } ++ } ++ if (gotgint.b.hstnegsucstschng) { ++ /* Print statements during the HNP interrupt handling ++ * can cause it to fail.*/ ++ gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl); ++ if (gotgctl.b.hstnegscs) { ++ if (dwc_otg_is_host_mode(_core_if) ) { ++ _core_if->op_state = B_HOST; ++ /* ++ * Need to disable SOF interrupt immediately. ++ * When switching from device to host, the PCD ++ * interrupt handler won't handle the ++ * interrupt if host mode is already set. The ++ * HCD interrupt handler won't get called if ++ * the HCD state is HALT. This means that the ++ * interrupt does not get handled and Linux ++ * complains loudly. ++ */ ++ gintmsk.d32 = 0; ++ gintmsk.b.sofintr = 1; ++ dwc_modify_reg32(&global_regs->gintmsk, ++ gintmsk.d32, 0); ++ pcd_stop(_core_if); ++ /* ++ * Initialize the Core for Host mode. ++ */ ++ hcd_start( _core_if ); ++ _core_if->op_state = B_HOST; ++ } ++ } else { ++ gotgctl.d32 = 0; ++ gotgctl.b.hnpreq = 1; ++ gotgctl.b.devhnpen = 1; ++ dwc_modify_reg32( &global_regs->gotgctl, ++ gotgctl.d32, 0); ++ DWC_DEBUGPL( DBG_ANY, "HNP Failed\n"); ++ DWC_ERROR( "Device Not Connected/Responding\n" ); ++ } ++ } ++ if (gotgint.b.hstnegdet) { ++ /* The disconnect interrupt is set at the same time as ++ * Host Negotiation Detected. During the mode ++ * switch all interrupts are cleared so the disconnect ++ * interrupt handler will not get executed. ++ */ ++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " ++ "Host Negotiation Detected++ (%s)\n", ++ (dwc_otg_is_host_mode(_core_if)?"Host":"Device")); ++ if (dwc_otg_is_device_mode(_core_if)){ ++ DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",_core_if->op_state); ++ hcd_disconnect( _core_if ); ++ pcd_start( _core_if ); ++ _core_if->op_state = A_PERIPHERAL; ++ } else { ++ /* ++ * Need to disable SOF interrupt immediately. When ++ * switching from device to host, the PCD interrupt ++ * handler won't handle the interrupt if host mode is ++ * already set. The HCD interrupt handler won't get ++ * called if the HCD state is HALT. This means that ++ * the interrupt does not get handled and Linux ++ * complains loudly. ++ */ ++ gintmsk.d32 = 0; ++ gintmsk.b.sofintr = 1; ++ dwc_modify_reg32(&global_regs->gintmsk, ++ gintmsk.d32, 0); ++ pcd_stop( _core_if ); ++ hcd_start( _core_if ); ++ _core_if->op_state = A_HOST; ++ } ++ } ++ if (gotgint.b.adevtoutchng) { ++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " ++ "A-Device Timeout Change++\n"); ++ } ++ if (gotgint.b.debdone) { ++ DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " ++ "Debounce Done++\n"); ++ } ++ ++ /* Clear GOTGINT */ ++ dwc_write_reg32 (&_core_if->core_global_regs->gotgint, gotgint.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. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *_core_if) ++{ ++ uint32_t count = 0; ++ ++ gintsts_data_t gintsts = { .d32 = 0 }; ++ gintmsk_data_t gintmsk = { .d32 = 0 }; ++ gotgctl_data_t gotgctl = { .d32 = 0 }; ++ ++ /* ++ * Need to disable SOF interrupt immediately. If switching from device ++ * to host, the PCD interrupt handler won't handle the interrupt if ++ * host mode is already set. The HCD interrupt handler won't get ++ * called if the HCD state is HALT. This means that the interrupt does ++ * not get handled and Linux complains loudly. ++ */ ++ gintmsk.b.sofintr = 1; ++ dwc_modify_reg32(&_core_if->core_global_regs->gintmsk, gintmsk.d32, 0); ++ ++ DWC_DEBUGPL(DBG_CIL, " ++Connector ID Status Change Interrupt++ (%s)\n", ++ (dwc_otg_is_host_mode(_core_if)?"Host":"Device")); ++ gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl); ++ DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32); ++ DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts); ++ ++ /* B-Device connector (Device Mode) */ ++ if (gotgctl.b.conidsts) { ++ /* Wait for switch to device mode. */ ++ while (!dwc_otg_is_device_mode(_core_if) ){ ++ DWC_PRINT("Waiting for Peripheral Mode, Mode=%s\n", ++ (dwc_otg_is_host_mode(_core_if)?"Host":"Peripheral")); ++ MDELAY(100); ++ if (++count > 10000) *(uint32_t*)NULL=0; ++ } ++ _core_if->op_state = B_PERIPHERAL; ++ dwc_otg_core_init(_core_if); ++ dwc_otg_enable_global_interrupts(_core_if); ++ pcd_start( _core_if ); ++ } else { ++ /* A-Device connector (Host Mode) */ ++ while (!dwc_otg_is_host_mode(_core_if) ) { ++ DWC_PRINT("Waiting for Host Mode, Mode=%s\n", ++ (dwc_otg_is_host_mode(_core_if)?"Host":"Peripheral")); ++ MDELAY(100); ++ if (++count > 10000) *(uint32_t*)NULL=0; ++ } ++ _core_if->op_state = A_HOST; ++ /* ++ * Initialize the Core for Host mode. ++ */ ++ dwc_otg_core_init(_core_if); ++ dwc_otg_enable_global_interrupts(_core_if); ++ hcd_start( _core_if ); ++ } ++ ++ /* Set flag and clear interrupt */ ++ gintsts.b.conidstschng = 1; ++ dwc_write_reg32 (&_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. ++ * ++ * @param _core_if Programming view of DWC_otg controller. ++ */ ++int32_t dwc_otg_handle_session_req_intr( dwc_otg_core_if_t *_core_if ) ++{ ++#ifndef DWC_HOST_ONLY // winder ++ hprt0_data_t hprt0; ++#endif ++ gintsts_data_t gintsts; ++ ++#ifndef DWC_HOST_ONLY ++ DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n"); ++ ++ if (dwc_otg_is_device_mode(_core_if) ) { ++ DWC_PRINT("SRP: Device mode\n"); ++ } else { ++ DWC_PRINT("SRP: Host mode\n"); ++ ++ /* Turn on the port power bit. */ ++ hprt0.d32 = dwc_otg_read_hprt0( _core_if ); ++ hprt0.b.prtpwr = 1; ++ dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32); ++ ++ /* Start the Connection timer. So a message can be displayed ++ * if connect does not occur within 10 seconds. */ ++ hcd_session_start( _core_if ); ++ } ++#endif ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.sessreqintr = 1; ++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * This interrupt indicates that the DWC_otg controller has detected a ++ * resume or remote wakeup sequence. If the DWC_otg 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. ++ */ ++int32_t dwc_otg_handle_wakeup_detected_intr( dwc_otg_core_if_t *_core_if ) ++{ ++ gintsts_data_t gintsts; ++ ++ DWC_DEBUGPL(DBG_ANY, "++Resume and Remote Wakeup Detected Interrupt++\n"); ++ ++ if (dwc_otg_is_device_mode(_core_if) ) { ++ dctl_data_t dctl = {.d32=0}; ++ DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", ++ dwc_read_reg32( &_core_if->dev_if->dev_global_regs->dsts)); ++#ifdef PARTIAL_POWER_DOWN ++ if (_core_if->hwcfg4.b.power_optimiz) { ++ pcgcctl_data_t power = {.d32=0}; ++ ++ power.d32 = dwc_read_reg32( _core_if->pcgcctl ); ++ DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n", power.d32); ++ ++ power.b.stoppclk = 0; ++ dwc_write_reg32( _core_if->pcgcctl, power.d32); ++ ++ power.b.pwrclmp = 0; ++ dwc_write_reg32( _core_if->pcgcctl, power.d32); ++ ++ power.b.rstpdwnmodule = 0; ++ dwc_write_reg32( _core_if->pcgcctl, power.d32); ++ } ++#endif ++ /* Clear the Remote Wakeup Signalling */ ++ dctl.b.rmtwkupsig = 1; ++ dwc_modify_reg32( &_core_if->dev_if->dev_global_regs->dctl, ++ dctl.d32, 0 ); ++ ++ if (_core_if->pcd_cb && _core_if->pcd_cb->resume_wakeup) { ++ _core_if->pcd_cb->resume_wakeup( _core_if->pcd_cb->p ); ++ } ++ ++ } else { ++ /* ++ * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms ++ * so that OPT tests pass with all PHYs). ++ */ ++ hprt0_data_t hprt0 = {.d32=0}; ++ pcgcctl_data_t pcgcctl = {.d32=0}; ++ /* Restart the Phy Clock */ ++ pcgcctl.b.stoppclk = 1; ++ dwc_modify_reg32(_core_if->pcgcctl, pcgcctl.d32, 0); ++ UDELAY(10); ++ ++ /* Now wait for 70 ms. */ ++ hprt0.d32 = dwc_otg_read_hprt0( _core_if ); ++ DWC_DEBUGPL(DBG_ANY,"Resume: HPRT0=%0x\n", hprt0.d32); ++ MDELAY(70); ++ hprt0.b.prtres = 0; /* Resume */ ++ dwc_write_reg32(_core_if->host_if->hprt0, hprt0.d32); ++ DWC_DEBUGPL(DBG_ANY,"Clear Resume: HPRT0=%0x\n", dwc_read_reg32(_core_if->host_if->hprt0)); ++ } ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.wkupintr = 1; ++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * This interrupt indicates that a device has been disconnected from ++ * the root port. ++ */ ++int32_t dwc_otg_handle_disconnect_intr( dwc_otg_core_if_t *_core_if) ++{ ++ gintsts_data_t gintsts; ++ ++ DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n", ++ (dwc_otg_is_host_mode(_core_if)?"Host":"Device"), ++ op_state_str(_core_if)); ++ ++/** @todo Consolidate this if statement. */ ++#ifndef DWC_HOST_ONLY ++ if (_core_if->op_state == B_HOST) { ++ /* If in device mode Disconnect and stop the HCD, then ++ * start the PCD. */ ++ hcd_disconnect( _core_if ); ++ pcd_start( _core_if ); ++ _core_if->op_state = B_PERIPHERAL; ++ } else if (dwc_otg_is_device_mode(_core_if)) { ++ gotgctl_data_t gotgctl = { .d32 = 0 }; ++ gotgctl.d32 = dwc_read_reg32(&_core_if->core_global_regs->gotgctl); ++ if (gotgctl.b.hstsethnpen==1) { ++ /* Do nothing, if HNP in process the OTG ++ * interrupt "Host Negotiation Detected" ++ * interrupt will do the mode switch. ++ */ ++ } else if (gotgctl.b.devhnpen == 0) { ++ /* If in device mode Disconnect and stop the HCD, then ++ * start the PCD. */ ++ hcd_disconnect( _core_if ); ++ pcd_start( _core_if ); ++ _core_if->op_state = B_PERIPHERAL; ++ } else { ++ DWC_DEBUGPL(DBG_ANY,"!a_peripheral && !devhnpen\n"); ++ } ++ } else { ++ if (_core_if->op_state == A_HOST) { ++ /* A-Cable still connected but device disconnected. */ ++ hcd_disconnect( _core_if ); ++ } ++ } ++#endif ++/* Without OTG, we should use the disconnect function!? winder added.*/ ++#if 1 // NO OTG, so host only!! ++ hcd_disconnect( _core_if ); ++#endif ++ ++ gintsts.d32 = 0; ++ gintsts.b.disconnect = 1; ++ dwc_write_reg32 (&_core_if->core_global_regs->gintsts, gintsts.d32); ++ return 1; ++} ++/** ++ * This interrupt indicates that SUSPEND state has been detected on ++ * the USB. ++ * ++ * For HNP the USB Suspend interrupt signals the change from ++ * "a_peripheral" to "a_host". ++ * ++ * When power management is enabled the core will be put in low power ++ * mode. ++ */ ++int32_t dwc_otg_handle_usb_suspend_intr(dwc_otg_core_if_t *_core_if ) ++{ ++ dsts_data_t dsts; ++ gintsts_data_t gintsts; ++ ++ //805141:<IFTW-fchang>.removed DWC_DEBUGPL(DBG_ANY,"USB SUSPEND\n"); ++ ++ if (dwc_otg_is_device_mode( _core_if ) ) { ++ /* Check the Device status register to determine if the Suspend ++ * state is active. */ ++ dsts.d32 = dwc_read_reg32( &_core_if->dev_if->dev_global_regs->dsts); ++ DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32); ++ DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d " ++ "HWCFG4.power Optimize=%d\n", ++ dsts.b.suspsts, _core_if->hwcfg4.b.power_optimiz); ++ ++ ++#ifdef PARTIAL_POWER_DOWN ++/** @todo Add a module parameter for power management. */ ++ ++ if (dsts.b.suspsts && _core_if->hwcfg4.b.power_optimiz) { ++ pcgcctl_data_t power = {.d32=0}; ++ DWC_DEBUGPL(DBG_CIL, "suspend\n"); ++ ++ power.b.pwrclmp = 1; ++ dwc_write_reg32( _core_if->pcgcctl, power.d32); ++ ++ power.b.rstpdwnmodule = 1; ++ dwc_modify_reg32( _core_if->pcgcctl, 0, power.d32); ++ ++ power.b.stoppclk = 1; ++ dwc_modify_reg32( _core_if->pcgcctl, 0, power.d32); ++ ++ } else { ++ DWC_DEBUGPL(DBG_ANY,"disconnect?\n"); ++ } ++#endif ++ /* PCD callback for suspend. */ ++ pcd_suspend(_core_if); ++ } else { ++ if (_core_if->op_state == A_PERIPHERAL) { ++ DWC_DEBUGPL(DBG_ANY,"a_peripheral->a_host\n"); ++ /* Clear the a_peripheral flag, back to a_host. */ ++ pcd_stop( _core_if ); ++ hcd_start( _core_if ); ++ _core_if->op_state = A_HOST; ++ } ++ } ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.usbsuspend = 1; ++ dwc_write_reg32( &_core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++ ++/** ++ * This function returns the Core Interrupt register. ++ */ ++static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t *_core_if) ++{ ++ gintsts_data_t gintsts; ++ gintmsk_data_t gintmsk; ++ gintmsk_data_t gintmsk_common = {.d32=0}; ++ gintmsk_common.b.wkupintr = 1; ++ gintmsk_common.b.sessreqintr = 1; ++ gintmsk_common.b.conidstschng = 1; ++ gintmsk_common.b.otgintr = 1; ++ gintmsk_common.b.modemismatch = 1; ++ gintmsk_common.b.disconnect = 1; ++ gintmsk_common.b.usbsuspend = 1; ++ /** @todo: The port interrupt occurs while in device ++ * mode. Added code to CIL to clear the interrupt for now! ++ */ ++ gintmsk_common.b.portintr = 1; ++ ++ gintsts.d32 = dwc_read_reg32(&_core_if->core_global_regs->gintsts); ++ gintmsk.d32 = dwc_read_reg32(&_core_if->core_global_regs->gintmsk); ++#ifdef DEBUG ++ /* if any common interrupts set */ ++ if (gintsts.d32 & gintmsk_common.d32) { ++ DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n", ++ gintsts.d32, gintmsk.d32); ++ } ++#endif ++ ++ return ((gintsts.d32 & gintmsk.d32 ) & gintmsk_common.d32); ++ ++} ++ ++/** ++ * Common interrupt handler. ++ * ++ * The common interrupts are those that occur in both Host and Device mode. ++ * This handler handles the following interrupts: ++ * - Mode Mismatch Interrupt ++ * - Disconnect Interrupt ++ * - OTG Interrupt ++ * - Connector ID Status Change Interrupt ++ * - Session Request Interrupt. ++ * - Resume / Remote Wakeup Detected Interrupt. ++ * ++ */ ++extern int32_t dwc_otg_handle_common_intr( dwc_otg_core_if_t *_core_if ) ++{ ++ int retval = 0; ++ gintsts_data_t gintsts; ++ ++ gintsts.d32 = dwc_otg_read_common_intr(_core_if); ++ ++ if (gintsts.b.modemismatch) { ++ retval |= dwc_otg_handle_mode_mismatch_intr( _core_if ); ++ } ++ if (gintsts.b.otgintr) { ++ retval |= dwc_otg_handle_otg_intr( _core_if ); ++ } ++ if (gintsts.b.conidstschng) { ++ retval |= dwc_otg_handle_conn_id_status_change_intr( _core_if ); ++ } ++ if (gintsts.b.disconnect) { ++ retval |= dwc_otg_handle_disconnect_intr( _core_if ); ++ } ++ if (gintsts.b.sessreqintr) { ++ retval |= dwc_otg_handle_session_req_intr( _core_if ); ++ } ++ if (gintsts.b.wkupintr) { ++ retval |= dwc_otg_handle_wakeup_detected_intr( _core_if ); ++ } ++ if (gintsts.b.usbsuspend) { ++ retval |= dwc_otg_handle_usb_suspend_intr( _core_if ); ++ } ++ if (gintsts.b.portintr && dwc_otg_is_device_mode(_core_if)) { ++ /* The port interrupt occurs while in device mode with HPRT0 ++ * Port Enable/Disable. ++ */ ++ gintsts.d32 = 0; ++ gintsts.b.portintr = 1; ++ dwc_write_reg32(&_core_if->core_global_regs->gintsts, ++ gintsts.d32); ++ retval |= 1; ++ ++ } ++ return retval; ++} +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_driver.c +@@ -0,0 +1,1274 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_driver.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 631780 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++/** @file ++ * The dwc_otg_driver module provides the initialization and cleanup entry ++ * points for the DWC_otg driver. This module will be dynamically installed ++ * after Linux is booted using the insmod command. When the module is ++ * installed, the dwc_otg_init function is called. When the module is ++ * removed (using rmmod), the dwc_otg_cleanup function is called. ++ * ++ * This module also defines a data structure for the dwc_otg_driver, which is ++ * used in conjunction with the standard ARM lm_device structure. These ++ * structures allow the OTG driver to comply with the standard Linux driver ++ * model in which devices and drivers are registered with a bus driver. This ++ * has the benefit that Linux can expose attributes of the driver and device ++ * in its special sysfs file system. Users can then read or write files in ++ * this file system to perform diagnostics on the driver components or the ++ * device. ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/moduleparam.h> ++#include <linux/init.h> ++#include <linux/gpio.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/irq.h> ++#include <asm/io.h> ++ ++#include "dwc_otg_plat.h" ++#include "dwc_otg_attr.h" ++#include "dwc_otg_driver.h" ++#include "dwc_otg_cil.h" ++#include "dwc_otg_cil_ifx.h" ++ ++// #include "dwc_otg_pcd.h" // device ++#include "dwc_otg_hcd.h" // host ++ ++#include "dwc_otg_ifx.h" // for Infineon platform specific. ++ ++#define DWC_DRIVER_VERSION "2.60a 22-NOV-2006" ++#define DWC_DRIVER_DESC "HS OTG USB Controller driver" ++ ++const char dwc_driver_name[] = "dwc_otg"; ++ ++static unsigned long dwc_iomem_base = IFX_USB_IOMEM_BASE; ++int dwc_irq = LTQ_USB_INT; ++//int dwc_irq = 54; ++//int dwc_irq = IFXMIPS_USB_OC_INT; ++ ++extern int ifx_usb_hc_init(unsigned long base_addr, int irq); ++extern void ifx_usb_hc_remove(void); ++ ++/*-------------------------------------------------------------------------*/ ++/* Encapsulate the module parameter settings */ ++ ++static dwc_otg_core_params_t dwc_otg_module_params = { ++ .opt = -1, ++ .otg_cap = -1, ++ .dma_enable = -1, ++ .dma_burst_size = -1, ++ .speed = -1, ++ .host_support_fs_ls_low_power = -1, ++ .host_ls_low_power_phy_clk = -1, ++ .enable_dynamic_fifo = -1, ++ .data_fifo_size = -1, ++ .dev_rx_fifo_size = -1, ++ .dev_nperio_tx_fifo_size = -1, ++ .dev_perio_tx_fifo_size = /* dev_perio_tx_fifo_size_1 */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, /* 15 */ ++ .host_rx_fifo_size = -1, ++ .host_nperio_tx_fifo_size = -1, ++ .host_perio_tx_fifo_size = -1, ++ .max_transfer_size = -1, ++ .max_packet_count = -1, ++ .host_channels = -1, ++ .dev_endpoints = -1, ++ .phy_type = -1, ++ .phy_utmi_width = -1, ++ .phy_ulpi_ddr = -1, ++ .phy_ulpi_ext_vbus = -1, ++ .i2c_enable = -1, ++ .ulpi_fs_ls = -1, ++ .ts_dline = -1, ++ .en_multiple_tx_fifo = -1, ++ .dev_tx_fifo_size = { /* dev_tx_fifo_size */ ++ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ++ }, /* 15 */ ++ .thr_ctl = -1, ++ .tx_thr_length = -1, ++ .rx_thr_length = -1, ++}; ++ ++/** ++ * This function shows the Driver Version. ++ */ ++static ssize_t version_show(struct device_driver *dev, char *buf) ++{ ++ return snprintf(buf, sizeof(DWC_DRIVER_VERSION)+2,"%s\n", ++ DWC_DRIVER_VERSION); ++} ++static DRIVER_ATTR(version, S_IRUGO, version_show, NULL); ++ ++/** ++ * Global Debug Level Mask. ++ */ ++uint32_t g_dbg_lvl = 0xff; /* OFF */ ++ ++/** ++ * This function shows the driver Debug Level. ++ */ ++static ssize_t dbg_level_show(struct device_driver *_drv, char *_buf) ++{ ++ return sprintf(_buf, "0x%0x\n", g_dbg_lvl); ++} ++/** ++ * This function stores the driver Debug Level. ++ */ ++static ssize_t dbg_level_store(struct device_driver *_drv, const char *_buf, ++ size_t _count) ++{ ++ g_dbg_lvl = simple_strtoul(_buf, NULL, 16); ++ return _count; ++} ++static DRIVER_ATTR(debuglevel, S_IRUGO|S_IWUSR, dbg_level_show, dbg_level_store); ++ ++/** ++ * This function is called during module intialization to verify that ++ * the module parameters are in a valid state. ++ */ ++static int check_parameters(dwc_otg_core_if_t *core_if) ++{ ++ int i; ++ int retval = 0; ++ ++/* Checks if the parameter is outside of its valid range of values */ ++#define DWC_OTG_PARAM_TEST(_param_,_low_,_high_) \ ++ ((dwc_otg_module_params._param_ < (_low_)) || \ ++ (dwc_otg_module_params._param_ > (_high_))) ++ ++/* If the parameter has been set by the user, check that the parameter value is ++ * within the value range of values. If not, report a module error. */ ++#define DWC_OTG_PARAM_ERR(_param_,_low_,_high_,_string_) \ ++ do { \ ++ if (dwc_otg_module_params._param_ != -1) { \ ++ if (DWC_OTG_PARAM_TEST(_param_,(_low_),(_high_))) { \ ++ DWC_ERROR("`%d' invalid for parameter `%s'\n", \ ++ dwc_otg_module_params._param_, _string_); \ ++ dwc_otg_module_params._param_ = dwc_param_##_param_##_default; \ ++ retval ++; \ ++ } \ ++ } \ ++ } while (0) ++ ++ DWC_OTG_PARAM_ERR(opt,0,1,"opt"); ++ DWC_OTG_PARAM_ERR(otg_cap,0,2,"otg_cap"); ++ DWC_OTG_PARAM_ERR(dma_enable,0,1,"dma_enable"); ++ DWC_OTG_PARAM_ERR(speed,0,1,"speed"); ++ DWC_OTG_PARAM_ERR(host_support_fs_ls_low_power,0,1,"host_support_fs_ls_low_power"); ++ DWC_OTG_PARAM_ERR(host_ls_low_power_phy_clk,0,1,"host_ls_low_power_phy_clk"); ++ DWC_OTG_PARAM_ERR(enable_dynamic_fifo,0,1,"enable_dynamic_fifo"); ++ DWC_OTG_PARAM_ERR(data_fifo_size,32,32768,"data_fifo_size"); ++ DWC_OTG_PARAM_ERR(dev_rx_fifo_size,16,32768,"dev_rx_fifo_size"); ++ DWC_OTG_PARAM_ERR(dev_nperio_tx_fifo_size,16,32768,"dev_nperio_tx_fifo_size"); ++ DWC_OTG_PARAM_ERR(host_rx_fifo_size,16,32768,"host_rx_fifo_size"); ++ DWC_OTG_PARAM_ERR(host_nperio_tx_fifo_size,16,32768,"host_nperio_tx_fifo_size"); ++ DWC_OTG_PARAM_ERR(host_perio_tx_fifo_size,16,32768,"host_perio_tx_fifo_size"); ++ DWC_OTG_PARAM_ERR(max_transfer_size,2047,524288,"max_transfer_size"); ++ DWC_OTG_PARAM_ERR(max_packet_count,15,511,"max_packet_count"); ++ DWC_OTG_PARAM_ERR(host_channels,1,16,"host_channels"); ++ DWC_OTG_PARAM_ERR(dev_endpoints,1,15,"dev_endpoints"); ++ DWC_OTG_PARAM_ERR(phy_type,0,2,"phy_type"); ++ DWC_OTG_PARAM_ERR(phy_ulpi_ddr,0,1,"phy_ulpi_ddr"); ++ DWC_OTG_PARAM_ERR(phy_ulpi_ext_vbus,0,1,"phy_ulpi_ext_vbus"); ++ DWC_OTG_PARAM_ERR(i2c_enable,0,1,"i2c_enable"); ++ DWC_OTG_PARAM_ERR(ulpi_fs_ls,0,1,"ulpi_fs_ls"); ++ DWC_OTG_PARAM_ERR(ts_dline,0,1,"ts_dline"); ++ ++ if (dwc_otg_module_params.dma_burst_size != -1) { ++ if (DWC_OTG_PARAM_TEST(dma_burst_size,1,1) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,4,4) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,8,8) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,16,16) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,32,32) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,64,64) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,128,128) && ++ DWC_OTG_PARAM_TEST(dma_burst_size,256,256)) ++ { ++ DWC_ERROR("`%d' invalid for parameter `dma_burst_size'\n", ++ dwc_otg_module_params.dma_burst_size); ++ dwc_otg_module_params.dma_burst_size = 32; ++ retval ++; ++ } ++ } ++ ++ if (dwc_otg_module_params.phy_utmi_width != -1) { ++ if (DWC_OTG_PARAM_TEST(phy_utmi_width,8,8) && ++ DWC_OTG_PARAM_TEST(phy_utmi_width,16,16)) ++ { ++ DWC_ERROR("`%d' invalid for parameter `phy_utmi_width'\n", ++ dwc_otg_module_params.phy_utmi_width); ++ //dwc_otg_module_params.phy_utmi_width = 16; ++ dwc_otg_module_params.phy_utmi_width = 8; ++ retval ++; ++ } ++ } ++ ++ for (i=0; i<15; i++) { ++ /** @todo should be like above */ ++ //DWC_OTG_PARAM_ERR(dev_perio_tx_fifo_size[i],4,768,"dev_perio_tx_fifo_size"); ++ if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) { ++ if (DWC_OTG_PARAM_TEST(dev_perio_tx_fifo_size[i],4,768)) { ++ DWC_ERROR("`%d' invalid for parameter `%s_%d'\n", ++ dwc_otg_module_params.dev_perio_tx_fifo_size[i], "dev_perio_tx_fifo_size", i); ++ dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_param_dev_perio_tx_fifo_size_default; ++ retval ++; ++ } ++ } ++ } ++ ++ DWC_OTG_PARAM_ERR(en_multiple_tx_fifo, 0, 1, "en_multiple_tx_fifo"); ++ for (i = 0; i < 15; i++) { ++ /** @todo should be like above */ ++ //DWC_OTG_PARAM_ERR(dev_tx_fifo_size[i],4,768,"dev_tx_fifo_size"); ++ if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) { ++ if (DWC_OTG_PARAM_TEST(dev_tx_fifo_size[i], 4, 768)) { ++ DWC_ERROR("`%d' invalid for parameter `%s_%d'\n", ++ dwc_otg_module_params.dev_tx_fifo_size[i], ++ "dev_tx_fifo_size", i); ++ dwc_otg_module_params.dev_tx_fifo_size[i] = ++ dwc_param_dev_tx_fifo_size_default; ++ retval++; ++ } ++ } ++ } ++ DWC_OTG_PARAM_ERR(thr_ctl, 0, 7, "thr_ctl"); ++ DWC_OTG_PARAM_ERR(tx_thr_length, 8, 128, "tx_thr_length"); ++ DWC_OTG_PARAM_ERR(rx_thr_length, 8, 128, "rx_thr_length"); ++ ++ /* At this point, all module parameters that have been set by the user ++ * are valid, and those that have not are left unset. Now set their ++ * default values and/or check the parameters against the hardware ++ * configurations of the OTG core. */ ++ ++ ++ ++/* This sets the parameter to the default value if it has not been set by the ++ * user */ ++#define DWC_OTG_PARAM_SET_DEFAULT(_param_) \ ++ ({ \ ++ int changed = 1; \ ++ if (dwc_otg_module_params._param_ == -1) { \ ++ changed = 0; \ ++ dwc_otg_module_params._param_ = dwc_param_##_param_##_default; \ ++ } \ ++ changed; \ ++ }) ++ ++/* This checks the macro agains the hardware configuration to see if it is ++ * valid. It is possible that the default value could be invalid. In this ++ * case, it will report a module error if the user touched the parameter. ++ * Otherwise it will adjust the value without any error. */ ++#define DWC_OTG_PARAM_CHECK_VALID(_param_,_str_,_is_valid_,_set_valid_) \ ++ ({ \ ++ int changed = DWC_OTG_PARAM_SET_DEFAULT(_param_); \ ++ int error = 0; \ ++ if (!(_is_valid_)) { \ ++ if (changed) { \ ++ DWC_ERROR("`%d' invalid for parameter `%s'. Check HW configuration.\n", dwc_otg_module_params._param_,_str_); \ ++ error = 1; \ ++ } \ ++ dwc_otg_module_params._param_ = (_set_valid_); \ ++ } \ ++ error; \ ++ }) ++ ++ /* OTG Cap */ ++ retval += DWC_OTG_PARAM_CHECK_VALID(otg_cap,"otg_cap", ++ ({ ++ int valid; ++ valid = 1; ++ switch (dwc_otg_module_params.otg_cap) { ++ case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE: ++ if (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) valid = 0; ++ break; ++ case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE: ++ if ((core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) && ++ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) && ++ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) && ++ (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ++ { ++ valid = 0; ++ } ++ break; ++ case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE: ++ /* always valid */ ++ break; ++ } ++ valid; ++ }), ++ (((core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG) || ++ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG) || ++ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || ++ (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST)) ? ++ DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE : ++ DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(dma_enable,"dma_enable", ++ ((dwc_otg_module_params.dma_enable == 1) && (core_if->hwcfg2.b.architecture == 0)) ? 0 : 1, ++ 0); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(opt,"opt", ++ 1, ++ 0); ++ ++ DWC_OTG_PARAM_SET_DEFAULT(dma_burst_size); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_support_fs_ls_low_power, ++ "host_support_fs_ls_low_power", ++ 1, 0); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(enable_dynamic_fifo, ++ "enable_dynamic_fifo", ++ ((dwc_otg_module_params.enable_dynamic_fifo == 0) || ++ (core_if->hwcfg2.b.dynamic_fifo == 1)), 0); ++ ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(data_fifo_size, ++ "data_fifo_size", ++ (dwc_otg_module_params.data_fifo_size <= core_if->hwcfg3.b.dfifo_depth), ++ core_if->hwcfg3.b.dfifo_depth); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(dev_rx_fifo_size, ++ "dev_rx_fifo_size", ++ (dwc_otg_module_params.dev_rx_fifo_size <= dwc_read_reg32(&core_if->core_global_regs->grxfsiz)), ++ dwc_read_reg32(&core_if->core_global_regs->grxfsiz)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(dev_nperio_tx_fifo_size, ++ "dev_nperio_tx_fifo_size", ++ (dwc_otg_module_params.dev_nperio_tx_fifo_size <= (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)), ++ (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_rx_fifo_size, ++ "host_rx_fifo_size", ++ (dwc_otg_module_params.host_rx_fifo_size <= dwc_read_reg32(&core_if->core_global_regs->grxfsiz)), ++ dwc_read_reg32(&core_if->core_global_regs->grxfsiz)); ++ ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_nperio_tx_fifo_size, ++ "host_nperio_tx_fifo_size", ++ (dwc_otg_module_params.host_nperio_tx_fifo_size <= (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)), ++ (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_perio_tx_fifo_size, ++ "host_perio_tx_fifo_size", ++ (dwc_otg_module_params.host_perio_tx_fifo_size <= ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))), ++ ((dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16))); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(max_transfer_size, ++ "max_transfer_size", ++ (dwc_otg_module_params.max_transfer_size < (1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11))), ++ ((1 << (core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(max_packet_count, ++ "max_packet_count", ++ (dwc_otg_module_params.max_packet_count < (1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4))), ++ ((1 << (core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_channels, ++ "host_channels", ++ (dwc_otg_module_params.host_channels <= (core_if->hwcfg2.b.num_host_chan + 1)), ++ (core_if->hwcfg2.b.num_host_chan + 1)); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(dev_endpoints, ++ "dev_endpoints", ++ (dwc_otg_module_params.dev_endpoints <= (core_if->hwcfg2.b.num_dev_ep)), ++ core_if->hwcfg2.b.num_dev_ep); ++ ++/* ++ * Define the following to disable the FS PHY Hardware checking. This is for ++ * internal testing only. ++ * ++ * #define NO_FS_PHY_HW_CHECKS ++ */ ++ ++#ifdef NO_FS_PHY_HW_CHECKS ++ retval += DWC_OTG_PARAM_CHECK_VALID(phy_type, ++ "phy_type", 1, 0); ++#else ++ retval += DWC_OTG_PARAM_CHECK_VALID(phy_type, ++ "phy_type", ++ ({ ++ int valid = 0; ++ if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_UTMI) && ++ ((core_if->hwcfg2.b.hs_phy_type == 1) || ++ (core_if->hwcfg2.b.hs_phy_type == 3))) ++ { ++ valid = 1; ++ } ++ else if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_ULPI) && ++ ((core_if->hwcfg2.b.hs_phy_type == 2) || ++ (core_if->hwcfg2.b.hs_phy_type == 3))) ++ { ++ valid = 1; ++ } ++ else if ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) && ++ (core_if->hwcfg2.b.fs_phy_type == 1)) ++ { ++ valid = 1; ++ } ++ valid; ++ }), ++ ({ ++ int set = DWC_PHY_TYPE_PARAM_FS; ++ if (core_if->hwcfg2.b.hs_phy_type) { ++ if ((core_if->hwcfg2.b.hs_phy_type == 3) || ++ (core_if->hwcfg2.b.hs_phy_type == 1)) { ++ set = DWC_PHY_TYPE_PARAM_UTMI; ++ } ++ else { ++ set = DWC_PHY_TYPE_PARAM_ULPI; ++ } ++ } ++ set; ++ })); ++#endif ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(speed,"speed", ++ (dwc_otg_module_params.speed == 0) && (dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? 0 : 1, ++ dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS ? 1 : 0); ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(host_ls_low_power_phy_clk, ++ "host_ls_low_power_phy_clk", ++ ((dwc_otg_module_params.host_ls_low_power_phy_clk == DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ) && (dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? 0 : 1), ++ ((dwc_otg_module_params.phy_type == DWC_PHY_TYPE_PARAM_FS) ? DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ : DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ)); ++ ++ DWC_OTG_PARAM_SET_DEFAULT(phy_ulpi_ddr); ++ DWC_OTG_PARAM_SET_DEFAULT(phy_ulpi_ext_vbus); ++ DWC_OTG_PARAM_SET_DEFAULT(phy_utmi_width); ++ DWC_OTG_PARAM_SET_DEFAULT(ulpi_fs_ls); ++ DWC_OTG_PARAM_SET_DEFAULT(ts_dline); ++ ++#ifdef NO_FS_PHY_HW_CHECKS ++ retval += DWC_OTG_PARAM_CHECK_VALID(i2c_enable, ++ "i2c_enable", 1, 0); ++#else ++ retval += DWC_OTG_PARAM_CHECK_VALID(i2c_enable, ++ "i2c_enable", ++ (dwc_otg_module_params.i2c_enable == 1) && (core_if->hwcfg3.b.i2c == 0) ? 0 : 1, ++ 0); ++#endif ++ ++ for (i=0; i<16; i++) { ++ ++ int changed = 1; ++ int error = 0; ++ ++ if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] == -1) { ++ changed = 0; ++ dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_param_dev_perio_tx_fifo_size_default; ++ } ++ if (!(dwc_otg_module_params.dev_perio_tx_fifo_size[i] <= (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i])))) { ++ if (changed) { ++ DWC_ERROR("`%d' invalid for parameter `dev_perio_fifo_size_%d'. Check HW configuration.\n", dwc_otg_module_params.dev_perio_tx_fifo_size[i],i); ++ error = 1; ++ } ++ dwc_otg_module_params.dev_perio_tx_fifo_size[i] = dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]); ++ } ++ retval += error; ++ } ++ ++ retval += DWC_OTG_PARAM_CHECK_VALID(en_multiple_tx_fifo, ++ "en_multiple_tx_fifo", ++ ((dwc_otg_module_params.en_multiple_tx_fifo == 1) && ++ (core_if->hwcfg4.b.ded_fifo_en == 0)) ? 0 : 1, 0); ++ ++ for (i = 0; i < 16; i++) { ++ int changed = 1; ++ int error = 0; ++ if (dwc_otg_module_params.dev_tx_fifo_size[i] == -1) { ++ changed = 0; ++ dwc_otg_module_params.dev_tx_fifo_size[i] = ++ dwc_param_dev_tx_fifo_size_default; ++ } ++ if (!(dwc_otg_module_params.dev_tx_fifo_size[i] <= ++ (dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i])))) { ++ if (changed) { ++ DWC_ERROR("%d' invalid for parameter `dev_perio_fifo_size_%d'." ++ "Check HW configuration.\n",dwc_otg_module_params.dev_tx_fifo_size[i],i); ++ error = 1; ++ } ++ dwc_otg_module_params.dev_tx_fifo_size[i] = ++ dwc_read_reg32(&core_if->core_global_regs->dptxfsiz_dieptxf[i]); ++ } ++ retval += error; ++ } ++ DWC_OTG_PARAM_SET_DEFAULT(thr_ctl); ++ DWC_OTG_PARAM_SET_DEFAULT(tx_thr_length); ++ DWC_OTG_PARAM_SET_DEFAULT(rx_thr_length); ++ return retval; ++} // check_parameters ++ ++ ++/** ++ * This function is the top level interrupt handler for the Common ++ * (Device and host modes) interrupts. ++ */ ++static irqreturn_t dwc_otg_common_irq(int _irq, void *_dev) ++{ ++ dwc_otg_device_t *otg_dev = _dev; ++ int32_t retval = IRQ_NONE; ++ ++ retval = dwc_otg_handle_common_intr( otg_dev->core_if ); ++ ++ mask_and_ack_ifx_irq (_irq); ++ ++ return IRQ_RETVAL(retval); ++} ++ ++ ++/** ++ * This function is called when a DWC_OTG device is unregistered with the ++ * dwc_otg_driver. This happens, for example, 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. ++ * ++ * @return ++ */ ++static int ++dwc_otg_driver_remove(struct platform_device *_dev) ++{ ++ //dwc_otg_device_t *otg_dev = dev_get_drvdata(&_dev->dev); ++ dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev); ++ ++ DWC_DEBUGPL(DBG_ANY, "%s(%p)\n", __func__, _dev); ++ ++ if (otg_dev == NULL) { ++ /* Memory allocation for the dwc_otg_device failed. */ ++ return 0; ++ } ++ ++ /* ++ * Free the IRQ ++ */ ++ if (otg_dev->common_irq_installed) { ++ free_irq( otg_dev->irq, otg_dev ); ++ } ++ ++#ifndef DWC_DEVICE_ONLY ++ if (otg_dev->hcd != NULL) { ++ dwc_otg_hcd_remove(&_dev->dev); ++ } ++#endif ++ printk("after removehcd\n"); ++ ++// Note: Integrate HOST and DEVICE(Gadget) is not planned yet. ++#ifndef DWC_HOST_ONLY ++ if (otg_dev->pcd != NULL) { ++ dwc_otg_pcd_remove(otg_dev); ++ } ++#endif ++ if (otg_dev->core_if != NULL) { ++ dwc_otg_cil_remove( otg_dev->core_if ); ++ } ++ printk("after removecil\n"); ++ ++ /* ++ * Remove the device attributes ++ */ ++ dwc_otg_attr_remove(&_dev->dev); ++ printk("after removeattr\n"); ++ ++ /* ++ * Return the memory. ++ */ ++ if (otg_dev->base != NULL) { ++ iounmap(otg_dev->base); ++ } ++ if (otg_dev->phys_addr != 0) { ++ release_mem_region(otg_dev->phys_addr, otg_dev->base_len); ++ } ++ kfree(otg_dev); ++ ++ /* ++ * Clear the drvdata pointer. ++ */ ++ //dev_set_drvdata(&_dev->dev, 0); ++ platform_set_drvdata(_dev, 0); ++ return 0; ++} ++ ++/** ++ * This function is called when an DWC_OTG device is bound to a ++ * dwc_otg_driver. It creates the driver components required to ++ * control the device (CIL, HCD, and PCD) and it initializes the ++ * device. The driver components are stored in a dwc_otg_device ++ * structure. A reference to the dwc_otg_device is saved in the ++ * lm_device. This allows the driver to access the dwc_otg_device ++ * structure on subsequent calls to driver methods for this device. ++ * ++ * @return ++ */ ++static int __devinit ++dwc_otg_driver_probe(struct platform_device *_dev) ++{ ++ int retval = 0; ++ dwc_otg_device_t *dwc_otg_device; ++ int pin = (int)_dev->dev.platform_data; ++ int32_t snpsid; ++ struct resource *res; ++ gusbcfg_data_t usbcfg = {.d32 = 0}; ++ ++ // GPIOs ++ if(pin >= 0) ++ { ++ gpio_request(pin, "usb_power"); ++ gpio_direction_output(pin, 1); ++ gpio_set_value(pin, 1); ++ gpio_export(pin, 0); ++ } ++ dev_dbg(&_dev->dev, "dwc_otg_driver_probe (%p)\n", _dev); ++ ++ dwc_otg_device = kmalloc(sizeof(dwc_otg_device_t), GFP_KERNEL); ++ if (dwc_otg_device == 0) { ++ dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n"); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ memset(dwc_otg_device, 0, sizeof(*dwc_otg_device)); ++ dwc_otg_device->reg_offset = 0xFFFFFFFF; ++ ++ /* ++ * Retrieve the memory and IRQ resources. ++ */ ++ dwc_otg_device->irq = platform_get_irq(_dev, 0); ++ if (dwc_otg_device->irq == 0) { ++ dev_err(&_dev->dev, "no device irq\n"); ++ retval = -ENODEV; ++ goto fail; ++ } ++ dev_dbg(&_dev->dev, "OTG - device irq: %d\n", dwc_otg_device->irq); ++ res = platform_get_resource(_dev, IORESOURCE_MEM, 0); ++ if (res == NULL) { ++ dev_err(&_dev->dev, "no CSR address\n"); ++ retval = -ENODEV; ++ goto fail; ++ } ++ dev_dbg(&_dev->dev, "OTG - ioresource_mem start0x%08x: end:0x%08x\n", ++ (unsigned)res->start, (unsigned)res->end); ++ dwc_otg_device->phys_addr = res->start; ++ dwc_otg_device->base_len = res->end - res->start + 1; ++ if (request_mem_region(dwc_otg_device->phys_addr, dwc_otg_device->base_len, ++ dwc_driver_name) == NULL) { ++ dev_err(&_dev->dev, "request_mem_region failed\n"); ++ retval = -EBUSY; ++ goto fail; ++ } ++ ++ /* ++ * Map the DWC_otg Core memory into virtual address space. ++ */ ++ dwc_otg_device->base = ioremap_nocache(dwc_otg_device->phys_addr, dwc_otg_device->base_len); ++ if (dwc_otg_device->base == NULL) { ++ dev_err(&_dev->dev, "ioremap() failed\n"); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ dev_dbg(&_dev->dev, "mapped base=0x%08x\n", (unsigned)dwc_otg_device->base); ++ ++ /* ++ * Attempt to ensure this device is really a DWC_otg Controller. ++ * Read and verify the SNPSID register contents. The value should be ++ * 0x45F42XXX, which corresponds to "OT2", as in "OTG version 2.XX". ++ */ ++ snpsid = dwc_read_reg32((uint32_t *)((uint8_t *)dwc_otg_device->base + 0x40)); ++ if ((snpsid & 0xFFFFF000) != 0x4F542000) { ++ dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n", snpsid); ++ retval = -EINVAL; ++ goto fail; ++ } ++ ++ /* ++ * Initialize driver data to point to the global DWC_otg ++ * Device structure. ++ */ ++ platform_set_drvdata(_dev, dwc_otg_device); ++ dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device); ++ dwc_otg_device->core_if = dwc_otg_cil_init( dwc_otg_device->base, &dwc_otg_module_params); ++ if (dwc_otg_device->core_if == 0) { ++ dev_err(&_dev->dev, "CIL initialization failed!\n"); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ++ /* ++ * Validate parameter values. ++ */ ++ if (check_parameters(dwc_otg_device->core_if) != 0) { ++ retval = -EINVAL; ++ goto fail; ++ } ++ ++ /* Added for PLB DMA phys virt mapping */ ++ //dwc_otg_device->core_if->phys_addr = dwc_otg_device->phys_addr; ++ /* ++ * Create Device Attributes in sysfs ++ */ ++ dwc_otg_attr_create (&_dev->dev); ++ ++ /* ++ * Disable the global interrupt until all the interrupt ++ * handlers are installed. ++ */ ++ dwc_otg_disable_global_interrupts( dwc_otg_device->core_if ); ++ /* ++ * Install the interrupt handler for the common interrupts before ++ * enabling common interrupts in core_init below. ++ */ ++ DWC_DEBUGPL( DBG_CIL, "registering (common) handler for irq%d\n", dwc_otg_device->irq); ++ ++ retval = request_irq((unsigned int)dwc_otg_device->irq, dwc_otg_common_irq, ++ //SA_INTERRUPT|SA_SHIRQ, "dwc_otg", (void *)dwc_otg_device ); ++ IRQF_SHARED, "dwc_otg", (void *)dwc_otg_device ); ++ //IRQF_DISABLED, "dwc_otg", (void *)dwc_otg_device ); ++ if (retval != 0) { ++ DWC_ERROR("request of irq%d failed retval: %d\n", dwc_otg_device->irq, retval); ++ retval = -EBUSY; ++ goto fail; ++ } else { ++ dwc_otg_device->common_irq_installed = 1; ++ } ++ ++ /* ++ * Initialize the DWC_otg core. ++ */ ++ dwc_otg_core_init( dwc_otg_device->core_if ); ++ ++ ++#ifndef DWC_HOST_ONLY // otg device mode. (gadget.) ++ /* ++ * Initialize the PCD ++ */ ++ retval = dwc_otg_pcd_init(dwc_otg_device); ++ if (retval != 0) { ++ DWC_ERROR("dwc_otg_pcd_init failed\n"); ++ dwc_otg_device->pcd = NULL; ++ goto fail; ++ } ++#endif // DWC_HOST_ONLY ++ ++#ifndef DWC_DEVICE_ONLY // otg host mode. (HCD) ++ /* ++ * Initialize the HCD ++ */ ++#if 1 /*fscz*/ ++ /* force_host_mode */ ++ usbcfg.d32 = dwc_read_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg); ++ usbcfg.b.force_host_mode = 1; ++ dwc_write_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg, usbcfg.d32); ++#endif ++ retval = dwc_otg_hcd_init(&_dev->dev, dwc_otg_device); ++ if (retval != 0) { ++ DWC_ERROR("dwc_otg_hcd_init failed\n"); ++ dwc_otg_device->hcd = NULL; ++ goto fail; ++ } ++#endif // DWC_DEVICE_ONLY ++ ++ /* ++ * Enable the global interrupt after all the interrupt ++ * handlers are installed. ++ */ ++ dwc_otg_enable_global_interrupts( dwc_otg_device->core_if ); ++#if 0 /*fscz*/ ++ usbcfg.d32 = dwc_read_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg); ++ usbcfg.b.force_host_mode = 0; ++ dwc_write_reg32(&dwc_otg_device->core_if->core_global_regs ->gusbcfg, usbcfg.d32); ++#endif ++ ++ ++ return 0; ++ ++fail: ++ dwc_otg_driver_remove(_dev); ++ return retval; ++} ++ ++/** ++ * This structure defines the methods to be called by a bus driver ++ * during the lifecycle of a device on that bus. Both drivers and ++ * devices are registered with a bus driver. The bus driver matches ++ * devices to drivers based on information in the device and driver ++ * structures. ++ * ++ * The probe function is called when the bus driver matches a device ++ * to this driver. The remove function is called when a device is ++ * unregistered with the bus driver. ++ */ ++struct platform_driver dwc_otg_driver = { ++ .probe = dwc_otg_driver_probe, ++ .remove = dwc_otg_driver_remove, ++// .suspend = dwc_otg_driver_suspend, ++// .resume = dwc_otg_driver_resume, ++ .driver = { ++ .name = dwc_driver_name, ++ .owner = THIS_MODULE, ++ }, ++}; ++EXPORT_SYMBOL(dwc_otg_driver); ++ ++/** ++ * This function is called when the dwc_otg_driver is installed with the ++ * insmod command. It registers the dwc_otg_driver structure with the ++ * appropriate bus driver. This will cause the dwc_otg_driver_probe function ++ * to be called. In addition, the bus driver will automatically expose ++ * attributes defined for the device and driver in the special sysfs file ++ * system. ++ * ++ * @return ++ */ ++static int __init dwc_otg_init(void) ++{ ++ int retval = 0; ++ ++ printk(KERN_INFO "%s: version %s\n", dwc_driver_name, DWC_DRIVER_VERSION); ++ ++ // ifxmips setup ++ retval = ifx_usb_hc_init(dwc_iomem_base, dwc_irq); ++ if (retval < 0) ++ { ++ printk(KERN_ERR "%s retval=%d\n", __func__, retval); ++ return retval; ++ } ++ dwc_otg_power_on(); // ifx only!! ++ ++ ++ retval = platform_driver_register(&dwc_otg_driver); ++ ++ if (retval < 0) { ++ printk(KERN_ERR "%s retval=%d\n", __func__, retval); ++ goto error1; ++ } ++ ++ retval = driver_create_file(&dwc_otg_driver.driver, &driver_attr_version); ++ if (retval < 0) ++ { ++ printk(KERN_ERR "%s retval=%d\n", __func__, retval); ++ goto error2; ++ } ++ retval = driver_create_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); ++ if (retval < 0) ++ { ++ printk(KERN_ERR "%s retval=%d\n", __func__, retval); ++ goto error3; ++ } ++ return retval; ++ ++ ++error3: ++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); ++error2: ++ driver_unregister(&dwc_otg_driver.driver); ++error1: ++ ifx_usb_hc_remove(); ++ return retval; ++} ++module_init(dwc_otg_init); ++ ++/** ++ * This function is called when the driver is removed from the kernel ++ * with the rmmod command. The driver unregisters itself with its bus ++ * driver. ++ * ++ */ ++static void __exit dwc_otg_cleanup(void) ++{ ++ printk(KERN_DEBUG "dwc_otg_cleanup()\n"); ++ ++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); ++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); ++ ++ platform_driver_unregister(&dwc_otg_driver); ++ ifx_usb_hc_remove(); ++ ++ printk(KERN_INFO "%s module removed\n", dwc_driver_name); ++} ++module_exit(dwc_otg_cleanup); ++ ++MODULE_DESCRIPTION(DWC_DRIVER_DESC); ++MODULE_AUTHOR("Synopsys Inc."); ++MODULE_LICENSE("GPL"); ++ ++module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444); ++MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None"); ++module_param_named(opt, dwc_otg_module_params.opt, int, 0444); ++MODULE_PARM_DESC(opt, "OPT Mode"); ++module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444); ++MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled"); ++module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int, 0444); ++MODULE_PARM_DESC(dma_burst_size, "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256"); ++module_param_named(speed, dwc_otg_module_params.speed, int, 0444); ++MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed"); ++module_param_named(host_support_fs_ls_low_power, dwc_otg_module_params.host_support_fs_ls_low_power, int, 0444); ++MODULE_PARM_DESC(host_support_fs_ls_low_power, "Support Low Power w/FS or LS 0=Support 1=Don't Support"); ++module_param_named(host_ls_low_power_phy_clk, dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444); ++MODULE_PARM_DESC(host_ls_low_power_phy_clk, "Low Speed Low Power Clock 0=48Mhz 1=6Mhz"); ++module_param_named(enable_dynamic_fifo, dwc_otg_module_params.enable_dynamic_fifo, int, 0444); ++MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing"); ++module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int, 0444); ++MODULE_PARM_DESC(data_fifo_size, "Total number of words in the data FIFO memory 32-32768"); ++module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size, int, 0444); ++MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); ++module_param_named(dev_nperio_tx_fifo_size, dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444); ++MODULE_PARM_DESC(dev_nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); ++module_param_named(dev_perio_tx_fifo_size_1, dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_1, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_2, dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_2, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_3, dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_3, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_4, dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_4, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_5, dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_5, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_6, dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_6, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_7, dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_7, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_8, dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_8, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_9, dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_9, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_10, dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_10, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_11, dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_11, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_12, dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_12, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_13, dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_13, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_14, dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_14, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_15, dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_15, "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size, int, 0444); ++MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); ++module_param_named(host_nperio_tx_fifo_size, dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444); ++MODULE_PARM_DESC(host_nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); ++module_param_named(host_perio_tx_fifo_size, dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444); ++MODULE_PARM_DESC(host_perio_tx_fifo_size, "Number of words in the host periodic Tx FIFO 16-32768"); ++module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size, int, 0444); ++/** @todo Set the max to 512K, modify checks */ ++MODULE_PARM_DESC(max_transfer_size, "The maximum transfer size supported in bytes 2047-65535"); ++module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count, int, 0444); ++MODULE_PARM_DESC(max_packet_count, "The maximum number of packets in a transfer 15-511"); ++module_param_named(host_channels, dwc_otg_module_params.host_channels, int, 0444); ++MODULE_PARM_DESC(host_channels, "The number of host channel registers to use 1-16"); ++module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int, 0444); ++MODULE_PARM_DESC(dev_endpoints, "The number of endpoints in addition to EP0 available for device mode 1-15"); ++module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444); ++MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI"); ++module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int, 0444); ++MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits"); ++module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444); ++MODULE_PARM_DESC(phy_ulpi_ddr, "ULPI at double or single data rate 0=Single 1=Double"); ++module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus, int, 0444); ++MODULE_PARM_DESC(phy_ulpi_ext_vbus, "ULPI PHY using internal or external vbus 0=Internal"); ++module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444); ++MODULE_PARM_DESC(i2c_enable, "FS PHY Interface"); ++module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444); ++MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only"); ++module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444); ++MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs"); ++module_param_named(debug, g_dbg_lvl, int, 0444); ++MODULE_PARM_DESC(debug, "0"); ++module_param_named(en_multiple_tx_fifo, ++ dwc_otg_module_params.en_multiple_tx_fifo, int, 0444); ++MODULE_PARM_DESC(en_multiple_tx_fifo, ++ "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled"); ++module_param_named(dev_tx_fifo_size_1, ++ dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_2, ++ dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_3, ++ dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_4, ++ dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_5, ++ dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_6, ++ dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_7, ++ dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_8, ++ dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_9, ++ dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_10, ++ dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_11, ++ dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_12, ++ dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_13, ++ dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_14, ++ dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_15, ++ dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768"); ++module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444); ++MODULE_PARM_DESC(thr_ctl, "Thresholding enable flag bit" ++ "0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled"); ++module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int, 0444); ++MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs"); ++module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int, 0444); ++MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs"); ++module_param_named (iomem_base, dwc_iomem_base, ulong, 0444); ++MODULE_PARM_DESC (dwc_iomem_base, "The base address of the DWC_OTG register."); ++module_param_named (irq, dwc_irq, int, 0444); ++MODULE_PARM_DESC (dwc_irq, "The interrupt number"); ++ ++/** @page "Module Parameters" ++ * ++ * The following parameters may be specified when starting the module. ++ * These parameters define how the DWC_otg controller should be ++ * configured. Parameter values are passed to the CIL initialization ++ * function dwc_otg_cil_init ++ * ++ * Example: <code>modprobe dwc_otg speed=1 otg_cap=1</code> ++ * ++ ++ <table> ++ <tr><td>Parameter Name</td><td>Meaning</td></tr> ++ ++ <tr> ++ <td>otg_cap</td> ++ <td>Specifies the OTG capabilities. The driver will automatically detect the ++ value for this parameter if none is specified. ++ - 0: HNP and SRP capable (default, if available) ++ - 1: SRP Only capable ++ - 2: No HNP/SRP capable ++ </td></tr> ++ ++ <tr> ++ <td>dma_enable</td> ++ <td>Specifies whether to use slave or DMA mode for accessing the data FIFOs. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: Slave ++ - 1: DMA (default, if available) ++ </td></tr> ++ ++ <tr> ++ <td>dma_burst_size</td> ++ <td>The DMA Burst size (applicable only for External DMA Mode). ++ - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32) ++ </td></tr> ++ ++ <tr> ++ <td>speed</td> ++ <td>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. ++ - 0: High Speed (default) ++ - 1: Full Speed ++ </td></tr> ++ ++ <tr> ++ <td>host_support_fs_ls_low_power</td> ++ <td>Specifies whether low power mode is supported when attached to a Full ++ Speed or Low Speed device in host mode. ++ - 0: Don't support low power mode (default) ++ - 1: Support low power mode ++ </td></tr> ++ ++ <tr> ++ <td>host_ls_low_power_phy_clk</td> ++ <td>Specifies the PHY clock rate in low power mode when connected to a Low ++ Speed device in host mode. This parameter is applicable only if ++ HOST_SUPPORT_FS_LS_LOW_POWER is enabled. ++ - 0: 48 MHz (default) ++ - 1: 6 MHz ++ </td></tr> ++ ++ <tr> ++ <td>enable_dynamic_fifo</td> ++ <td> Specifies whether FIFOs may be resized by the driver software. ++ - 0: Use cC FIFO size parameters ++ - 1: Allow dynamic FIFO sizing (default) ++ </td></tr> ++ ++ <tr> ++ <td>data_fifo_size</td> ++ <td>Total number of 4-byte words in the data FIFO memory. This memory ++ includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs. ++ - Values: 32 to 32768 (default 8192) ++ ++ Note: The total FIFO memory depth in the FPGA configuration is 8192. ++ </td></tr> ++ ++ <tr> ++ <td>dev_rx_fifo_size</td> ++ <td>Number of 4-byte words in the Rx FIFO in device mode when dynamic ++ FIFO sizing is enabled. ++ - Values: 16 to 32768 (default 1064) ++ </td></tr> ++ ++ <tr> ++ <td>dev_nperio_tx_fifo_size</td> ++ <td>Number of 4-byte words in the non-periodic Tx FIFO in device mode when ++ dynamic FIFO sizing is enabled. ++ - Values: 16 to 32768 (default 1024) ++ </td></tr> ++ ++ <tr> ++ <td>dev_perio_tx_fifo_size_n (n = 1 to 15)</td> ++ <td>Number of 4-byte words in each of the periodic Tx FIFOs in device mode ++ when dynamic FIFO sizing is enabled. ++ - Values: 4 to 768 (default 256) ++ </td></tr> ++ ++ <tr> ++ <td>host_rx_fifo_size</td> ++ <td>Number of 4-byte words in the Rx FIFO in host mode when dynamic FIFO ++ sizing is enabled. ++ - Values: 16 to 32768 (default 1024) ++ </td></tr> ++ ++ <tr> ++ <td>host_nperio_tx_fifo_size</td> ++ <td>Number of 4-byte words in the non-periodic Tx FIFO in host mode when ++ dynamic FIFO sizing is enabled in the core. ++ - Values: 16 to 32768 (default 1024) ++ </td></tr> ++ ++ <tr> ++ <td>host_perio_tx_fifo_size</td> ++ <td>Number of 4-byte words in the host periodic Tx FIFO when dynamic FIFO ++ sizing is enabled. ++ - Values: 16 to 32768 (default 1024) ++ </td></tr> ++ ++ <tr> ++ <td>max_transfer_size</td> ++ <td>The maximum transfer size supported in bytes. ++ - Values: 2047 to 65,535 (default 65,535) ++ </td></tr> ++ ++ <tr> ++ <td>max_packet_count</td> ++ <td>The maximum number of packets in a transfer. ++ - Values: 15 to 511 (default 511) ++ </td></tr> ++ ++ <tr> ++ <td>host_channels</td> ++ <td>The number of host channel registers to use. ++ - Values: 1 to 16 (default 12) ++ ++ Note: The FPGA configuration supports a maximum of 12 host channels. ++ </td></tr> ++ ++ <tr> ++ <td>dev_endpoints</td> ++ <td>The number of endpoints in addition to EP0 available for device mode ++ operations. ++ - Values: 1 to 15 (default 6 IN and OUT) ++ ++ Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in ++ addition to EP0. ++ </td></tr> ++ ++ <tr> ++ <td>phy_type</td> ++ <td>Specifies the type of PHY interface to use. By default, the driver will ++ automatically detect the phy_type. ++ - 0: Full Speed ++ - 1: UTMI+ (default, if available) ++ - 2: ULPI ++ </td></tr> ++ ++ <tr> ++ <td>phy_utmi_width</td> ++ <td>Specifies the UTMI+ Data Width. This parameter is applicable for a ++ phy_type of UTMI+. Also, this parameter is applicable only if the ++ OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the ++ core has been configured to work at either data path width. ++ - Values: 8 or 16 bits (default 16) ++ </td></tr> ++ ++ <tr> ++ <td>phy_ulpi_ddr</td> ++ <td>Specifies whether the ULPI operates at double or single data rate. This ++ parameter is only applicable if phy_type is ULPI. ++ - 0: single data rate ULPI interface with 8 bit wide data bus (default) ++ - 1: double data rate ULPI interface with 4 bit wide data bus ++ </td></tr> ++ ++ <tr> ++ <td>i2c_enable</td> ++ <td>Specifies whether to use the I2C interface for full speed PHY. This ++ parameter is only applicable if PHY_TYPE is FS. ++ - 0: Disabled (default) ++ - 1: Enabled ++ </td></tr> ++ ++ <tr> ++ <td>otg_en_multiple_tx_fifo</td> ++ <td>Specifies whether dedicatedto tx fifos are enabled for non periodic IN EPs. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: Disabled ++ - 1: Enabled (default, if available) ++ </td></tr> ++ ++ <tr> ++ <td>dev_tx_fifo_size_n (n = 1 to 15)</td> ++ <td>Number of 4-byte words in each of the Tx FIFOs in device mode ++ when dynamic FIFO sizing is enabled. ++ - Values: 4 to 768 (default 256) ++ </td></tr> ++ ++*/ +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_driver.h +@@ -0,0 +1,84 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_driver.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 510275 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#if !defined(__DWC_OTG_DRIVER_H__) ++#define __DWC_OTG_DRIVER_H__ ++ ++/** @file ++ * This file contains the interface to the Linux driver. ++ */ ++#include "dwc_otg_cil.h" ++ ++/* Type declarations */ ++struct dwc_otg_pcd; ++struct dwc_otg_hcd; ++ ++/** ++ * This structure is a wrapper that encapsulates the driver components used to ++ * manage a single DWC_otg controller. ++ */ ++typedef struct dwc_otg_device ++{ ++ /** Base address returned from ioremap() */ ++ void *base; ++ ++ /** Pointer to the core interface structure. */ ++ dwc_otg_core_if_t *core_if; ++ ++ /** Register offset for Diagnostic API.*/ ++ uint32_t reg_offset; ++ ++ /** Pointer to the PCD structure. */ ++ struct dwc_otg_pcd *pcd; ++ ++ /** Pointer to the HCD structure. */ ++ struct dwc_otg_hcd *hcd; ++ ++ /** Flag to indicate whether the common IRQ handler is installed. */ ++ uint8_t common_irq_installed; ++ ++ /** Interrupt request number. */ ++ unsigned int irq; ++ ++ /** Physical address of Control and Status registers, used by ++ * release_mem_region(). ++ */ ++ resource_size_t phys_addr; ++ ++ /** Length of memory region, used by release_mem_region(). */ ++ unsigned long base_len; ++} dwc_otg_device_t; ++ ++//#define dev_dbg(fake, format, arg...) printk(KERN_CRIT __FILE__ ":%d: " format "\n" , __LINE__, ## arg) ++ ++#endif +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_hcd.c +@@ -0,0 +1,2870 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 631780 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++ ++/** ++ * @file ++ * ++ * This file contains the implementation of the HCD. In Linux, the HCD ++ * implements the hc_driver API. ++ */ ++#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 "dwc_otg_driver.h" ++#include "dwc_otg_hcd.h" ++#include "dwc_otg_regs.h" ++ ++#include <asm/irq.h> ++#include "dwc_otg_ifx.h" // for Infineon platform specific. ++extern atomic_t release_later; ++ ++static u64 dma_mask = DMA_BIT_MASK(32); ++ ++static const char dwc_otg_hcd_name [] = "dwc_otg_hcd"; ++static const struct hc_driver dwc_otg_hc_driver = ++{ ++ .description = dwc_otg_hcd_name, ++ .product_desc = "DWC OTG Controller", ++ .hcd_priv_size = sizeof(dwc_otg_hcd_t), ++ .irq = dwc_otg_hcd_irq, ++ .flags = HCD_MEMORY | HCD_USB2, ++ //.reset = ++ .start = dwc_otg_hcd_start, ++ //.suspend = ++ //.resume = ++ .stop = dwc_otg_hcd_stop, ++ .urb_enqueue = dwc_otg_hcd_urb_enqueue, ++ .urb_dequeue = dwc_otg_hcd_urb_dequeue, ++ .endpoint_disable = dwc_otg_hcd_endpoint_disable, ++ .get_frame_number = dwc_otg_hcd_get_frame_number, ++ .hub_status_data = dwc_otg_hcd_hub_status_data, ++ .hub_control = dwc_otg_hcd_hub_control, ++ //.hub_suspend = ++ //.hub_resume = ++}; ++ ++ ++/** ++ * Work queue function for starting the HCD when A-Cable is connected. ++ * The dwc_otg_hcd_start() must be called in a process context. ++ */ ++static void hcd_start_func(struct work_struct *work) ++{ ++ struct dwc_otg_hcd *priv = ++ container_of(work, struct dwc_otg_hcd, start_work); ++ struct usb_hcd *usb_hcd = (struct usb_hcd *)priv->_p; ++ DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, usb_hcd); ++ if (usb_hcd) { ++ dwc_otg_hcd_start(usb_hcd); ++ } ++} ++ ++ ++/** ++ * HCD Callback function for starting the HCD when A-Cable is ++ * connected. ++ * ++ * @param _p void pointer to the <code>struct usb_hcd</code> ++ */ ++static int32_t dwc_otg_hcd_start_cb(void *_p) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_p); ++ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; ++ hprt0_data_t hprt0; ++ if (core_if->op_state == B_HOST) { ++ /* ++ * Reset the port. During a HNP mode switch the reset ++ * needs to occur within 1ms and have a duration of at ++ * least 50ms. ++ */ ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtrst = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ ((struct usb_hcd *)_p)->self.is_b_host = 1; ++ } else { ++ ((struct usb_hcd *)_p)->self.is_b_host = 0; ++ } ++ /* Need to start the HCD in a non-interrupt context. */ ++ INIT_WORK(&dwc_otg_hcd->start_work, hcd_start_func); ++ dwc_otg_hcd->_p = _p; ++ schedule_work(&dwc_otg_hcd->start_work); ++ return 1; ++} ++ ++ ++/** ++ * HCD Callback function for stopping the HCD. ++ * ++ * @param _p void pointer to the <code>struct usb_hcd</code> ++ */ ++static int32_t dwc_otg_hcd_stop_cb( void *_p ) ++{ ++ struct usb_hcd *usb_hcd = (struct usb_hcd *)_p; ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p); ++ dwc_otg_hcd_stop( usb_hcd ); ++ return 1; ++} ++static void del_xfer_timers(dwc_otg_hcd_t *_hcd) ++{ ++#ifdef DEBUG ++ int i; ++ int num_channels = _hcd->core_if->core_params->host_channels; ++ for (i = 0; i < num_channels; i++) { ++ del_timer(&_hcd->core_if->hc_xfer_timer[i]); ++ } ++#endif /* */ ++} ++ ++static void del_timers(dwc_otg_hcd_t *_hcd) ++{ ++ del_xfer_timers(_hcd); ++ del_timer(&_hcd->conn_timer); ++} ++ ++/** ++ * Processes all the URBs in a single list of QHs. Completes them with ++ * -ETIMEDOUT and frees the QTD. ++ */ ++static void kill_urbs_in_qh_list(dwc_otg_hcd_t * _hcd, ++ struct list_head *_qh_list) ++{ ++ struct list_head *qh_item; ++ dwc_otg_qh_t *qh; ++ struct list_head *qtd_item; ++ dwc_otg_qtd_t *qtd; ++ ++ list_for_each(qh_item, _qh_list) { ++ qh = list_entry(qh_item, dwc_otg_qh_t, qh_list_entry); ++ for (qtd_item = qh->qtd_list.next; qtd_item != &qh->qtd_list; ++ qtd_item = qh->qtd_list.next) { ++ qtd = list_entry(qtd_item, dwc_otg_qtd_t, qtd_list_entry); ++ if (qtd->urb != NULL) { ++ dwc_otg_hcd_complete_urb(_hcd, qtd->urb,-ETIMEDOUT); ++ } ++ dwc_otg_hcd_qtd_remove_and_free(qtd); ++ } ++ } ++} ++ ++/** ++ * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic ++ * and periodic schedules. The QTD associated with each URB is removed from ++ * the schedule and freed. This function may be called when a disconnect is ++ * detected or when the HCD is being stopped. ++ */ ++static void kill_all_urbs(dwc_otg_hcd_t *_hcd) ++{ ++ kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_deferred); ++ kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_inactive); ++ kill_urbs_in_qh_list(_hcd, &_hcd->non_periodic_sched_active); ++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_inactive); ++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_ready); ++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_assigned); ++ kill_urbs_in_qh_list(_hcd, &_hcd->periodic_sched_queued); ++} ++ ++/** ++ * HCD Callback function for disconnect of the HCD. ++ * ++ * @param _p void pointer to the <code>struct usb_hcd</code> ++ */ ++static int32_t dwc_otg_hcd_disconnect_cb( void *_p ) ++{ ++ gintsts_data_t intr; ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p); ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p); ++ ++ /* ++ * Set status flags for the hub driver. ++ */ ++ dwc_otg_hcd->flags.b.port_connect_status_change = 1; ++ dwc_otg_hcd->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. ++ */ ++ intr.d32 = 0; ++ intr.b.nptxfempty = 1; ++ intr.b.ptxfempty = 1; ++ intr.b.hcintr = 1; ++ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintmsk, intr.d32, 0); ++ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintsts, intr.d32, 0); ++ ++ del_timers(dwc_otg_hcd); ++ ++ /* ++ * Turn off the vbus power only if the core has transitioned to device ++ * mode. If still in host mode, need to keep power on to detect a ++ * reconnection. ++ */ ++ if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) { ++ if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) { ++ hprt0_data_t hprt0 = { .d32=0 }; ++ DWC_PRINT("Disconnect: PortPower off\n"); ++ hprt0.b.prtpwr = 0; ++ dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0.d32); ++ } ++ ++ dwc_otg_disable_host_interrupts( dwc_otg_hcd->core_if ); ++ } ++ ++ /* Respond with an error status to all URBs in the schedule. */ ++ kill_all_urbs(dwc_otg_hcd); ++ ++ if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) { ++ /* Clean up any host channels that were in use. */ ++ int num_channels; ++ int i; ++ dwc_hc_t *channel; ++ dwc_otg_hc_regs_t *hc_regs; ++ hcchar_data_t hcchar; ++ ++ num_channels = dwc_otg_hcd->core_if->core_params->host_channels; ++ ++ if (!dwc_otg_hcd->core_if->dma_enable) { ++ /* Flush out any channel requests in slave mode. */ ++ for (i = 0; i < num_channels; i++) { ++ channel = dwc_otg_hcd->hc_ptr_array[i]; ++ if (list_empty(&channel->hc_list_entry)) { ++ hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[i]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ hcchar.b.chen = 0; ++ hcchar.b.chdis = 1; ++ hcchar.b.epdir = 0; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ } ++ } ++ } ++ } ++ ++ for (i = 0; i < num_channels; i++) { ++ channel = dwc_otg_hcd->hc_ptr_array[i]; ++ if (list_empty(&channel->hc_list_entry)) { ++ hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[i]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ /* Halt the channel. */ ++ hcchar.b.chdis = 1; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ } ++ ++ dwc_otg_hc_cleanup(dwc_otg_hcd->core_if, channel); ++ list_add_tail(&channel->hc_list_entry, ++ &dwc_otg_hcd->free_hc_list); ++ } ++ } ++ } ++ ++ /* A disconnect will end the session so the B-Device is no ++ * longer a B-host. */ ++ ((struct usb_hcd *)_p)->self.is_b_host = 0; ++ ++ return 1; ++} ++ ++/** ++ * Connection timeout function. An OTG host is required to display a ++ * message if the device does not connect within 10 seconds. ++ */ ++void dwc_otg_hcd_connect_timeout( unsigned long _ptr ) ++{ ++ DWC_DEBUGPL(DBG_HCDV, "%s(%x)\n", __func__, (int)_ptr); ++ DWC_PRINT( "Connect Timeout\n"); ++ DWC_ERROR( "Device Not Connected/Responding\n" ); ++} ++ ++/** ++ * Start the connection timer. An OTG host is required to display a ++ * message if the device does not connect within 10 seconds. The ++ * timer is deleted if a port connect interrupt occurs before the ++ * timer expires. ++ */ ++static void dwc_otg_hcd_start_connect_timer( dwc_otg_hcd_t *_hcd) ++{ ++ init_timer( &_hcd->conn_timer ); ++ _hcd->conn_timer.function = dwc_otg_hcd_connect_timeout; ++ _hcd->conn_timer.data = (unsigned long)0; ++ _hcd->conn_timer.expires = jiffies + (HZ*10); ++ add_timer( &_hcd->conn_timer ); ++} ++ ++/** ++ * HCD Callback function for disconnect of the HCD. ++ * ++ * @param _p void pointer to the <code>struct usb_hcd</code> ++ */ ++static int32_t dwc_otg_hcd_session_start_cb( void *_p ) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_p); ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p); ++ dwc_otg_hcd_start_connect_timer( dwc_otg_hcd ); ++ return 1; ++} ++ ++/** ++ * HCD Callback structure for handling mode switching. ++ */ ++static dwc_otg_cil_callbacks_t hcd_cil_callbacks = { ++ .start = dwc_otg_hcd_start_cb, ++ .stop = dwc_otg_hcd_stop_cb, ++ .disconnect = dwc_otg_hcd_disconnect_cb, ++ .session_start = dwc_otg_hcd_session_start_cb, ++ .p = 0, ++}; ++ ++ ++/** ++ * Reset tasklet function ++ */ ++static void reset_tasklet_func (unsigned long data) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t*)data; ++ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; ++ hprt0_data_t hprt0; ++ ++ DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n"); ++ ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtrst = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ mdelay (60); ++ ++ hprt0.b.prtrst = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ dwc_otg_hcd->flags.b.port_reset_change = 1; ++ ++ return; ++} ++ ++static struct tasklet_struct reset_tasklet = { ++ .next = NULL, ++ .state = 0, ++ .count = ATOMIC_INIT(0), ++ .func = reset_tasklet_func, ++ .data = 0, ++}; ++ ++/** ++ * Initializes the HCD. This function allocates memory for and initializes the ++ * static parts of the usb_hcd and dwc_otg_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 init_hcd_usecs(dwc_otg_hcd_t *_hcd); ++ ++int __devinit dwc_otg_hcd_init(struct device *_dev, dwc_otg_device_t * dwc_otg_device) ++{ ++ struct usb_hcd *hcd = NULL; ++ dwc_otg_hcd_t *dwc_otg_hcd = NULL; ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ ++ int num_channels; ++ int i; ++ dwc_hc_t *channel; ++ ++ int retval = 0; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n"); ++ ++ /* ++ * Allocate memory for the base HCD plus the DWC OTG HCD. ++ * Initialize the base HCD. ++ */ ++ hcd = usb_create_hcd(&dwc_otg_hc_driver, _dev, dev_name(_dev)); ++ if (hcd == NULL) { ++ retval = -ENOMEM; ++ goto error1; ++ } ++ dev_set_drvdata(_dev, dwc_otg_device); /* fscz restore */ ++ hcd->regs = otg_dev->base; ++ hcd->rsrc_start = (int)otg_dev->base; ++ ++ hcd->self.otg_port = 1; ++ ++ /* Initialize the DWC OTG HCD. */ ++ dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); ++ dwc_otg_hcd->core_if = otg_dev->core_if; ++ otg_dev->hcd = dwc_otg_hcd; ++ ++ /* Register the HCD CIL Callbacks */ ++ dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if, ++ &hcd_cil_callbacks, hcd); ++ ++ /* Initialize the non-periodic schedule. */ ++ INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_inactive); ++ INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_active); ++ INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_deferred); ++ ++ /* Initialize the periodic schedule. */ ++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_inactive); ++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready); ++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned); ++ INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued); ++ ++ /* ++ * Create a host channel descriptor for each host channel implemented ++ * in the controller. Initialize the channel descriptor array. ++ */ ++ INIT_LIST_HEAD(&dwc_otg_hcd->free_hc_list); ++ num_channels = dwc_otg_hcd->core_if->core_params->host_channels; ++ for (i = 0; i < num_channels; i++) { ++ channel = kmalloc(sizeof(dwc_hc_t), GFP_KERNEL); ++ if (channel == NULL) { ++ retval = -ENOMEM; ++ DWC_ERROR("%s: host channel allocation failed\n", __func__); ++ goto error2; ++ } ++ memset(channel, 0, sizeof(dwc_hc_t)); ++ channel->hc_num = i; ++ dwc_otg_hcd->hc_ptr_array[i] = channel; ++#ifdef DEBUG ++ init_timer(&dwc_otg_hcd->core_if->hc_xfer_timer[i]); ++#endif ++ ++ DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i, channel); ++ } ++ ++ /* Initialize the Connection timeout timer. */ ++ init_timer( &dwc_otg_hcd->conn_timer ); ++ ++ /* Initialize reset tasklet. */ ++ reset_tasklet.data = (unsigned long) dwc_otg_hcd; ++ dwc_otg_hcd->reset_tasklet = &reset_tasklet; ++ ++ /* Set device flags indicating whether the HCD supports DMA. */ ++ if (otg_dev->core_if->dma_enable) { ++ DWC_PRINT("Using DMA mode\n"); ++ //_dev->dma_mask = (void *)~0; ++ //_dev->coherent_dma_mask = ~0; ++ _dev->dma_mask = &dma_mask; ++ _dev->coherent_dma_mask = DMA_BIT_MASK(32); ++ } else { ++ DWC_PRINT("Using Slave mode\n"); ++ _dev->dma_mask = (void *)0; ++ _dev->coherent_dma_mask = 0; ++ } ++ ++ init_hcd_usecs(dwc_otg_hcd); ++ /* ++ * 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 dwc_otg_hcd_start method. ++ */ ++ retval = usb_add_hcd(hcd, otg_dev->irq, 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. ++ */ ++ if (otg_dev->core_if->dma_enable) { ++ dwc_otg_hcd->status_buf = ++ dma_alloc_coherent(_dev, ++ DWC_OTG_HCD_STATUS_BUF_SIZE, ++ &dwc_otg_hcd->status_buf_dma, ++ GFP_KERNEL | GFP_DMA); ++ } else { ++ dwc_otg_hcd->status_buf = kmalloc(DWC_OTG_HCD_STATUS_BUF_SIZE, ++ GFP_KERNEL); ++ } ++ if (dwc_otg_hcd->status_buf == NULL) { ++ retval = -ENOMEM; ++ DWC_ERROR("%s: status_buf allocation failed\n", __func__); ++ goto error3; ++ } ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Initialized HCD, bus=%s, usbbus=%d\n", ++ dev_name(_dev), hcd->self.busnum); ++ ++ return 0; ++ ++ /* Error conditions */ ++error3: ++ usb_remove_hcd(hcd); ++error2: ++ dwc_otg_hcd_free(hcd); ++ usb_put_hcd(hcd); ++error1: ++ return retval; ++} ++ ++/** ++ * Removes the HCD. ++ * Frees memory and resources associated with the HCD and deregisters the bus. ++ */ ++void dwc_otg_hcd_remove(struct device *_dev) ++{ ++ dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev); ++ dwc_otg_hcd_t *dwc_otg_hcd = otg_dev->hcd; ++ struct usb_hcd *hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd); ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE\n"); ++ ++ /* Turn off all interrupts */ ++ dwc_write_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gintmsk, 0); ++ dwc_modify_reg32 (&dwc_otg_hcd->core_if->core_global_regs->gahbcfg, 1, 0); ++ ++ usb_remove_hcd(hcd); ++ ++ dwc_otg_hcd_free(hcd); ++ ++ usb_put_hcd(hcd); ++ ++ return; ++} ++ ++ ++/* ========================================================================= ++ * Linux HC Driver Functions ++ * ========================================================================= */ ++ ++/** ++ * Initializes dynamic portions of the DWC_otg HCD state. ++ */ ++static void hcd_reinit(dwc_otg_hcd_t *_hcd) ++{ ++ struct list_head *item; ++ int num_channels; ++ int i; ++ dwc_hc_t *channel; ++ ++ _hcd->flags.d32 = 0; ++ ++ _hcd->non_periodic_qh_ptr = &_hcd->non_periodic_sched_active; ++ _hcd->available_host_channels = _hcd->core_if->core_params->host_channels; ++ ++ /* ++ * Put all channels in the free channel list and clean up channel ++ * states. ++ */ ++ item = _hcd->free_hc_list.next; ++ while (item != &_hcd->free_hc_list) { ++ list_del(item); ++ item = _hcd->free_hc_list.next; ++ } ++ num_channels = _hcd->core_if->core_params->host_channels; ++ for (i = 0; i < num_channels; i++) { ++ channel = _hcd->hc_ptr_array[i]; ++ list_add_tail(&channel->hc_list_entry, &_hcd->free_hc_list); ++ dwc_otg_hc_cleanup(_hcd->core_if, channel); ++ } ++ ++ /* Initialize the DWC core for host mode operation. */ ++ dwc_otg_core_host_init(_hcd->core_if); ++} ++ ++/** Initializes the DWC_otg 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. */ ++int dwc_otg_hcd_start(struct usb_hcd *_hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ dwc_otg_core_if_t * core_if = dwc_otg_hcd->core_if; ++ struct usb_bus *bus; ++ ++ // int retval; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n"); ++ ++ bus = hcd_to_bus(_hcd); ++ ++ /* Initialize the bus state. If the core is in Device Mode ++ * HALT the USB bus and return. */ ++ if (dwc_otg_is_device_mode (core_if)) { ++ _hcd->state = HC_STATE_HALT; ++ return 0; ++ } ++ _hcd->state = HC_STATE_RUNNING; ++ ++ /* Initialize and connect root hub if one is not already attached */ ++ if (bus->root_hub) { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n"); ++ /* Inform the HUB driver to resume. */ ++ usb_hcd_resume_root_hub(_hcd); ++ } ++ else { ++#if 0 ++ struct usb_device *udev; ++ udev = usb_alloc_dev(NULL, bus, 0); ++ if (!udev) { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Error udev alloc\n"); ++ return -ENODEV; ++ } ++ udev->speed = USB_SPEED_HIGH; ++ /* Not needed - VJ ++ if ((retval = usb_hcd_register_root_hub(udev, _hcd)) != 0) { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Error registering %d\n", retval); ++ return -ENODEV; ++ } ++ */ ++#else ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Error udev alloc\n"); ++#endif ++ } ++ ++ hcd_reinit(dwc_otg_hcd); ++ ++ return 0; ++} ++ ++static void qh_list_free(dwc_otg_hcd_t *_hcd, struct list_head *_qh_list) ++{ ++ struct list_head *item; ++ dwc_otg_qh_t *qh; ++ ++ if (_qh_list->next == NULL) { ++ /* The list hasn't been initialized yet. */ ++ return; ++ } ++ ++ /* Ensure there are no QTDs or URBs left. */ ++ kill_urbs_in_qh_list(_hcd, _qh_list); ++ ++ for (item = _qh_list->next; item != _qh_list; item = _qh_list->next) { ++ qh = list_entry(item, dwc_otg_qh_t, qh_list_entry); ++ dwc_otg_hcd_qh_remove_and_free(_hcd, qh); ++ } ++} ++ ++/** ++ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are ++ * stopped. ++ */ ++void dwc_otg_hcd_stop(struct usb_hcd *_hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ hprt0_data_t hprt0 = { .d32=0 }; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n"); ++ ++ /* Turn off all host-specific interrupts. */ ++ dwc_otg_disable_host_interrupts( dwc_otg_hcd->core_if ); ++ ++ /* ++ * The root hub should be disconnected before this function is called. ++ * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue) ++ * and the QH lists (via ..._hcd_endpoint_disable). ++ */ ++ ++ /* Turn off the vbus power */ ++ DWC_PRINT("PortPower off\n"); ++ hprt0.b.prtpwr = 0; ++ dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0.d32); ++ ++ return; ++} ++ ++ ++/** Returns the current frame number. */ ++int dwc_otg_hcd_get_frame_number(struct usb_hcd *_hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); ++ hfnum_data_t hfnum; ++ ++ hfnum.d32 = dwc_read_reg32(&dwc_otg_hcd->core_if-> ++ host_if->host_global_regs->hfnum); ++ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n", hfnum.b.frnum); ++#endif ++ return hfnum.b.frnum; ++} ++ ++/** ++ * Frees secondary storage associated with the dwc_otg_hcd structure contained ++ * in the struct usb_hcd field. ++ */ ++void dwc_otg_hcd_free(struct usb_hcd *_hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); ++ int i; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n"); ++ ++ del_timers(dwc_otg_hcd); ++ ++ /* Free memory for QH/QTD lists */ ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_deferred); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued); ++ ++ /* Free memory for the host channels. */ ++ for (i = 0; i < MAX_EPS_CHANNELS; i++) { ++ dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i]; ++ if (hc != NULL) { ++ DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n", i, hc); ++ kfree(hc); ++ } ++ } ++ ++ if (dwc_otg_hcd->core_if->dma_enable) { ++ if (dwc_otg_hcd->status_buf_dma) { ++ dma_free_coherent(_hcd->self.controller, ++ DWC_OTG_HCD_STATUS_BUF_SIZE, ++ dwc_otg_hcd->status_buf, ++ dwc_otg_hcd->status_buf_dma); ++ } ++ } else if (dwc_otg_hcd->status_buf != NULL) { ++ kfree(dwc_otg_hcd->status_buf); ++ } ++ ++ return; ++} ++ ++ ++#ifdef DEBUG ++static void dump_urb_info(struct urb *_urb, char* _fn_name) ++{ ++ DWC_PRINT("%s, urb %p\n", _fn_name, _urb); ++ DWC_PRINT(" Device address: %d\n", usb_pipedevice(_urb->pipe)); ++ DWC_PRINT(" Endpoint: %d, %s\n", usb_pipeendpoint(_urb->pipe), ++ (usb_pipein(_urb->pipe) ? "IN" : "OUT")); ++ DWC_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;})); ++ DWC_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;})); ++ DWC_PRINT(" Max packet size: %d\n", ++ usb_maxpacket(_urb->dev, _urb->pipe, usb_pipeout(_urb->pipe))); ++ DWC_PRINT(" Data buffer length: %d\n", _urb->transfer_buffer_length); ++ DWC_PRINT(" Transfer buffer: %p, Transfer DMA: %p\n", ++ _urb->transfer_buffer, (void *)_urb->transfer_dma); ++ DWC_PRINT(" Setup buffer: %p, Setup DMA: %p\n", ++ _urb->setup_packet, (void *)_urb->setup_dma); ++ DWC_PRINT(" Interval: %d\n", _urb->interval); ++ if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) { ++ int i; ++ for (i = 0; i < _urb->number_of_packets; i++) { ++ DWC_PRINT(" ISO Desc %d:\n", i); ++ DWC_PRINT(" offset: %d, length %d\n", ++ _urb->iso_frame_desc[i].offset, ++ _urb->iso_frame_desc[i].length); ++ } ++ } ++} ++ ++static void dump_channel_info(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *qh) ++{ ++ if (qh->channel != NULL) { ++ dwc_hc_t *hc = qh->channel; ++ struct list_head *item; ++ dwc_otg_qh_t *qh_item; ++ int num_channels = _hcd->core_if->core_params->host_channels; ++ int i; ++ ++ dwc_otg_hc_regs_t *hc_regs; ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ hctsiz_data_t hctsiz; ++ uint32_t hcdma; ++ ++ hc_regs = _hcd->core_if->host_if->hc_regs[hc->hc_num]; ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt); ++ hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz); ++ hcdma = dwc_read_reg32(&hc_regs->hcdma); ++ ++ DWC_PRINT(" Assigned to channel %p:\n", hc); ++ DWC_PRINT(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); ++ DWC_PRINT(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); ++ DWC_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", ++ hc->dev_addr, hc->ep_num, hc->ep_is_in); ++ DWC_PRINT(" ep_type: %d\n", hc->ep_type); ++ DWC_PRINT(" max_packet: %d\n", hc->max_packet); ++ DWC_PRINT(" data_pid_start: %d\n", hc->data_pid_start); ++ DWC_PRINT(" xfer_started: %d\n", hc->xfer_started); ++ DWC_PRINT(" halt_status: %d\n", hc->halt_status); ++ DWC_PRINT(" xfer_buff: %p\n", hc->xfer_buff); ++ DWC_PRINT(" xfer_len: %d\n", hc->xfer_len); ++ DWC_PRINT(" qh: %p\n", hc->qh); ++ DWC_PRINT(" NP inactive sched:\n"); ++ list_for_each(item, &_hcd->non_periodic_sched_inactive) { ++ qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry); ++ DWC_PRINT(" %p\n", qh_item); ++ } DWC_PRINT(" NP active sched:\n"); ++ list_for_each(item, &_hcd->non_periodic_sched_deferred) { ++ qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry); ++ DWC_PRINT(" %p\n", qh_item); ++ } DWC_PRINT(" NP deferred sched:\n"); ++ list_for_each(item, &_hcd->non_periodic_sched_active) { ++ qh_item = list_entry(item, dwc_otg_qh_t, qh_list_entry); ++ DWC_PRINT(" %p\n", qh_item); ++ } DWC_PRINT(" Channels: \n"); ++ for (i = 0; i < num_channels; i++) { ++ dwc_hc_t *hc = _hcd->hc_ptr_array[i]; ++ DWC_PRINT(" %2d: %p\n", i, hc); ++ } ++ } ++} ++#endif // DEBUG ++ ++/** 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 dwc_otg_hcd_urb_enqueue(struct usb_hcd *_hcd, ++ struct urb *_urb, ++ gfp_t _mem_flags) ++{ ++ unsigned long flags; ++ int retval; ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ dwc_otg_qtd_t *qtd; ++ ++ local_irq_save(flags); ++ retval = usb_hcd_link_urb_to_ep(_hcd, _urb); ++ if (retval) { ++ local_irq_restore(flags); ++ return retval; ++ } ++#ifdef DEBUG ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ dump_urb_info(_urb, "dwc_otg_hcd_urb_enqueue"); ++ } ++#endif // DEBUG ++ if (!dwc_otg_hcd->flags.b.port_connect_status) { ++ /* No longer connected. */ ++ local_irq_restore(flags); ++ return -ENODEV; ++ } ++ ++ qtd = dwc_otg_hcd_qtd_create (_urb); ++ if (qtd == NULL) { ++ local_irq_restore(flags); ++ DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n"); ++ return -ENOMEM; ++ } ++ ++ retval = dwc_otg_hcd_qtd_add (qtd, dwc_otg_hcd); ++ if (retval < 0) { ++ DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. " ++ "Error status %d\n", retval); ++ dwc_otg_hcd_qtd_free(qtd); ++ } ++ ++ local_irq_restore (flags); ++ return retval; ++} ++ ++/** Aborts/cancels a USB transfer request. Always returns 0 to indicate ++ * success. */ ++int dwc_otg_hcd_urb_dequeue(struct usb_hcd *_hcd, struct urb *_urb, int _status) ++{ ++ unsigned long flags; ++ dwc_otg_hcd_t *dwc_otg_hcd; ++ dwc_otg_qtd_t *urb_qtd; ++ dwc_otg_qh_t *qh; ++ int retval; ++ //struct usb_host_endpoint *_ep = NULL; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n"); ++ ++ local_irq_save(flags); ++ ++ retval = usb_hcd_check_unlink_urb(_hcd, _urb, _status); ++ if (retval) { ++ local_irq_restore(flags); ++ return retval; ++ } ++ ++ dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); ++ urb_qtd = (dwc_otg_qtd_t *)_urb->hcpriv; ++ if (urb_qtd == NULL) { ++ printk("urb_qtd is NULL for _urb %08x\n",(unsigned)_urb); ++ goto done; ++ } ++ qh = (dwc_otg_qh_t *) urb_qtd->qtd_qh_ptr; ++ if (qh == NULL) { ++ goto done; ++ } ++ ++#ifdef DEBUG ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ dump_urb_info(_urb, "dwc_otg_hcd_urb_dequeue"); ++ if (urb_qtd == qh->qtd_in_process) { ++ dump_channel_info(dwc_otg_hcd, qh); ++ } ++ } ++#endif // DEBUG ++ ++ if (urb_qtd == qh->qtd_in_process) { ++ /* The QTD is in process (it has been assigned to a channel). */ ++ ++ if (dwc_otg_hcd->flags.b.port_connect_status) { ++ /* ++ * 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. ++ */ ++ dwc_otg_hc_halt(dwc_otg_hcd->core_if, qh->channel, ++ DWC_OTG_HC_XFER_URB_DEQUEUE); ++ } ++ } ++ ++ /* ++ * Free the QTD and clean up the associated QH. Leave the QH in the ++ * schedule if it has any remaining QTDs. ++ */ ++ dwc_otg_hcd_qtd_remove_and_free(urb_qtd); ++ if (urb_qtd == qh->qtd_in_process) { ++ dwc_otg_hcd_qh_deactivate(dwc_otg_hcd, qh, 0); ++ qh->channel = NULL; ++ qh->qtd_in_process = NULL; ++ } else if (list_empty(&qh->qtd_list)) { ++ dwc_otg_hcd_qh_remove(dwc_otg_hcd, qh); ++ } ++ ++done: ++ local_irq_restore(flags); ++ _urb->hcpriv = NULL; ++ ++ /* Higher layer software sets URB status. */ ++ usb_hcd_unlink_urb_from_ep(_hcd, _urb); ++ usb_hcd_giveback_urb(_hcd, _urb, _status); ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ DWC_PRINT("Called usb_hcd_giveback_urb()\n"); ++ DWC_PRINT(" urb->status = %d\n", _urb->status); ++ } ++ ++ return 0; ++} ++ ++ ++/** Frees resources in the DWC_otg 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 dwc_otg_hcd_endpoint_disable(struct usb_hcd *_hcd, ++ struct usb_host_endpoint *_ep) ++ ++{ ++ dwc_otg_qh_t *qh; ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd); ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, " ++ "endpoint=%d\n", _ep->desc.bEndpointAddress, ++ dwc_ep_addr_to_endpoint(_ep->desc.bEndpointAddress)); ++ ++ qh = (dwc_otg_qh_t *)(_ep->hcpriv); ++ if (qh != NULL) { ++#ifdef DEBUG ++ /** Check that the QTD list is really empty */ ++ if (!list_empty(&qh->qtd_list)) { ++ DWC_WARN("DWC OTG HCD EP DISABLE:" ++ " QTD List for this endpoint is not empty\n"); ++ } ++#endif // DEBUG ++ ++ dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd, qh); ++ _ep->hcpriv = NULL; ++ } ++ ++ return; ++} ++extern int dwc_irq; ++/** Handles host mode interrupts for the DWC_otg 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 dwc_otg_hcd_irq(struct usb_hcd *_hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ ++ mask_and_ack_ifx_irq (dwc_irq); ++ return IRQ_RETVAL(dwc_otg_hcd_handle_intr(dwc_otg_hcd)); ++} ++ ++/** 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 dwc_otg_hcd_hub_status_data(struct usb_hcd *_hcd, char *_buf) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ ++ _buf[0] = 0; ++ _buf[0] |= (dwc_otg_hcd->flags.b.port_connect_status_change || ++ dwc_otg_hcd->flags.b.port_reset_change || ++ dwc_otg_hcd->flags.b.port_enable_change || ++ dwc_otg_hcd->flags.b.port_suspend_change || ++ dwc_otg_hcd->flags.b.port_over_current_change) << 1; ++ ++#ifdef DEBUG ++ if (_buf[0]) { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:" ++ " Root port status changed\n"); ++ DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n", ++ dwc_otg_hcd->flags.b.port_connect_status_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n", ++ dwc_otg_hcd->flags.b.port_reset_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n", ++ dwc_otg_hcd->flags.b.port_enable_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n", ++ dwc_otg_hcd->flags.b.port_suspend_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n", ++ dwc_otg_hcd->flags.b.port_over_current_change); ++ } ++#endif // DEBUG ++ return (_buf[0] != 0); ++} ++ ++#ifdef DWC_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. ++ */ ++ ++dwc_otg_core_global_regs_t *global_regs; ++dwc_otg_host_global_regs_t *hc_global_regs; ++dwc_otg_hc_regs_t *hc_regs; ++uint32_t *data_fifo; ++ ++static void do_setup(void) ++{ ++ gintsts_data_t gintsts; ++ hctsiz_data_t hctsiz; ++ hcchar_data_t hcchar; ++ haint_data_t haint; ++ hcint_data_t hcint; ++ ++ /* Enable HAINTs */ ++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001); ++ ++ /* Enable HCINTs */ ++ dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* ++ * Send Setup packet (Get Device Descriptor) ++ */ ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = dwc_read_reg32(&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; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ MDELAY(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = dwc_read_reg32(&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 = DWC_OTG_HC_PID_SETUP; ++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; ++ hcchar.b.epdir = 0; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ ++ /* Fill FIFO with Setup data for Get Device Descriptor */ ++ data_fifo = (uint32_t *)((char *)global_regs + 0x1000); ++ dwc_write_reg32(data_fifo++, 0x01000680); ++ dwc_write_reg32(data_fifo++, 0x00080000); ++ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Disable HCINTs */ ++ dwc_write_reg32(&hc_regs->hcintmsk, 0x0000); ++ ++ /* Disable HAINTs */ ++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++} ++ ++static void do_in_ack(void) ++{ ++ gintsts_data_t gintsts; ++ hctsiz_data_t hctsiz; ++ hcchar_data_t hcchar; ++ haint_data_t haint; ++ hcint_data_t hcint; ++ host_grxsts_data_t grxsts; ++ ++ /* Enable HAINTs */ ++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001); ++ ++ /* Enable HCINTs */ ++ dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* ++ * Receive Control In packet ++ */ ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = dwc_read_reg32(&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; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ MDELAY(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = dwc_read_reg32(&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 = DWC_OTG_HC_PID_DATA1; ++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; ++ hcchar.b.epdir = 1; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for receive status queue interrupt */ ++ do { ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ } while (gintsts.b.rxstsqlvl == 0); ++ ++ //fprintf(stderr, "Got RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read RXSTS */ ++ grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp); ++ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); ++ ++ /* Clear RXSTSQLVL in GINTSTS */ ++ gintsts.d32 = 0; ++ gintsts.b.rxstsqlvl = 1; ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ switch (grxsts.b.pktsts) { ++ case DWC_GRXSTS_PKTSTS_IN: ++ /* Read the data into the host buffer */ ++ if (grxsts.b.bcnt > 0) { ++ int i; ++ int word_count = (grxsts.b.bcnt + 3) / 4; ++ ++ data_fifo = (uint32_t *)((char *)global_regs + 0x1000); ++ ++ for (i = 0; i < word_count; i++) { ++ (void)dwc_read_reg32(data_fifo++); ++ } ++ } ++ ++ //fprintf(stderr, "Received %u bytes\n", (unsigned)grxsts.b.bcnt); ++ break; ++ ++ default: ++ //fprintf(stderr, "** Unexpected GRXSTS packet status 1 **\n"); ++ break; ++ } ++ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for receive status queue interrupt */ ++ do { ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ } while (gintsts.b.rxstsqlvl == 0); ++ ++ //fprintf(stderr, "Got RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read RXSTS */ ++ grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp); ++ //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); ++ ++ /* Clear RXSTSQLVL in GINTSTS */ ++ gintsts.d32 = 0; ++ gintsts.b.rxstsqlvl = 1; ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ switch (grxsts.b.pktsts) { ++ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: ++ break; ++ ++ default: ++ //fprintf(stderr, "** Unexpected GRXSTS packet status 2 **\n"); ++ break; ++ } ++ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ // usleep(100000); ++ // mdelay(100); ++ MDELAY(1); ++ ++ /* ++ * Send handshake packet ++ */ ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = dwc_read_reg32(&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; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ MDELAY(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = dwc_read_reg32(&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 = DWC_OTG_HC_PID_DATA1; ++ dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; ++ hcchar.b.epdir = 0; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ dwc_write_reg32(&hc_regs->hcchar, hcchar.d32); ++ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "Waiting for HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ //fprintf(stderr, "Got HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); ++ ++ /* Disable HCINTs */ ++ dwc_write_reg32(&hc_regs->hcintmsk, 0x0000); ++ ++ /* Disable HAINTs */ ++ dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000); ++ ++ /* Read HAINT */ ++ haint.d32 = dwc_read_reg32(&hc_global_regs->haint); ++ //fprintf(stderr, "HAINT: %08x\n", haint.d32); ++ ++ /* Read HCINT */ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ //fprintf(stderr, "HCINT: %08x\n", hcint.d32); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar); ++ //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); ++ ++ /* Clear HCINT */ ++ dwc_write_reg32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ dwc_write_reg32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ dwc_write_reg32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = dwc_read_reg32(&global_regs->gintsts); ++ //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); ++} ++#endif /* DWC_HS_ELECT_TST */ ++ ++/** Handles hub class-specific requests.*/ ++int dwc_otg_hcd_hub_control(struct usb_hcd *_hcd, ++ u16 _typeReq, ++ u16 _wValue, ++ u16 _wIndex, ++ char *_buf, ++ u16 _wLength) ++{ ++ int retval = 0; ++ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd (_hcd); ++ dwc_otg_core_if_t *core_if = hcd_to_dwc_otg_hcd (_hcd)->core_if; ++ struct usb_hub_descriptor *desc; ++ hprt0_data_t hprt0 = {.d32 = 0}; ++ ++ uint32_t port_status; ++ ++ switch (_typeReq) { ++ case ClearHubFeature: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG 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; ++ DWC_ERROR ("DWC OTG HCD - " ++ "ClearHubFeature request %xh unknown\n", _wValue); ++ } ++ break; ++ case ClearPortFeature: ++ if (!_wIndex || _wIndex > 1) ++ goto error; ++ ++ switch (_wValue) { ++ case USB_PORT_FEAT_ENABLE: ++ DWC_DEBUGPL (DBG_ANY, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_ENABLE\n"); ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtena = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_SUSPEND: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtres = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ /* Clear Resume bit */ ++ mdelay (100); ++ hprt0.b.prtres = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_POWER: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_POWER\n"); ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtpwr = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_INDICATOR: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG 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 */ ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n"); ++ dwc_otg_hcd->flags.b.port_connect_status_change = 0; ++ break; ++ case USB_PORT_FEAT_C_RESET: ++ /* Clears the driver's internal Port Reset Change ++ * flag */ ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_RESET\n"); ++ dwc_otg_hcd->flags.b.port_reset_change = 0; ++ break; ++ case USB_PORT_FEAT_C_ENABLE: ++ /* Clears the driver's internal Port ++ * Enable/Disable Change flag */ ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n"); ++ dwc_otg_hcd->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 */ ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n"); ++ dwc_otg_hcd->flags.b.port_suspend_change = 0; ++ break; ++ case USB_PORT_FEAT_C_OVER_CURRENT: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n"); ++ dwc_otg_hcd->flags.b.port_over_current_change = 0; ++ break; ++ default: ++ retval = -EINVAL; ++ DWC_ERROR ("DWC OTG HCD - " ++ "ClearPortFeature request %xh " ++ "unknown or unsupported\n", _wValue); ++ } ++ break; ++ case GetHubDescriptor: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG 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->u.hs.DeviceRemovable[0] = 0; ++ desc->u.hs.DeviceRemovable[1] = 0xff; ++ break; ++ case GetHubStatus: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "GetHubStatus\n"); ++ memset (_buf, 0, 4); ++ break; ++ case GetPortStatus: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "GetPortStatus\n"); ++ ++ if (!_wIndex || _wIndex > 1) ++ goto error; ++ ++ port_status = 0; ++ ++ if (dwc_otg_hcd->flags.b.port_connect_status_change) ++ port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); ++ ++ if (dwc_otg_hcd->flags.b.port_enable_change) ++ port_status |= (1 << USB_PORT_FEAT_C_ENABLE); ++ ++ if (dwc_otg_hcd->flags.b.port_suspend_change) ++ port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); ++ ++ if (dwc_otg_hcd->flags.b.port_reset_change) ++ port_status |= (1 << USB_PORT_FEAT_C_RESET); ++ ++ if (dwc_otg_hcd->flags.b.port_over_current_change) { ++ DWC_ERROR("Device Not Supported\n"); ++ port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT); ++ } ++ ++ if (!dwc_otg_hcd->flags.b.port_connect_status) { ++ printk("DISCONNECTED PORT\n"); ++ /* ++ * 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. ++ */ ++#if 1 // winder. ++ *((u32 *) _buf) = cpu_to_le32(port_status); ++#else ++ *((__le32 *) _buf) = cpu_to_le32(port_status); ++#endif ++ break; ++ } ++ ++ hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0); ++ DWC_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 == DWC_HPRT0_PRTSPD_HIGH_SPEED) ++ port_status |= USB_PORT_STAT_HIGH_SPEED; ++ ++ else if (hprt0.b.prtspd == DWC_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 */ ++#if 1 // winder. ++ *((u32 *) _buf) = cpu_to_le32(port_status); ++#else ++ *((__le32 *) _buf) = cpu_to_le32(port_status); ++#endif ++ ++ break; ++ case SetHubFeature: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetHubFeature\n"); ++ /* No HUB features supported */ ++ break; ++ case SetPortFeature: ++ if (_wValue != USB_PORT_FEAT_TEST && (!_wIndex || _wIndex > 1)) ++ goto error; ++ ++ if (!dwc_otg_hcd->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 without doing anything since the port ++ * register can't be written if the core is in device ++ * mode. ++ */ ++ break; ++ } ++ ++ switch (_wValue) { ++ case USB_PORT_FEAT_SUSPEND: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); ++ if (_hcd->self.otg_port == _wIndex ++ && _hcd->self.b_hnp_enable) { ++ gotgctl_data_t gotgctl = {.d32=0}; ++ gotgctl.b.hstsethnpen = 1; ++ dwc_modify_reg32(&core_if->core_global_regs-> ++ gotgctl, 0, gotgctl.d32); ++ core_if->op_state = A_SUSPEND; ++ } ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ //DWC_PRINT( "SUSPEND: HPRT0=%0x\n", hprt0.d32); ++ /* Suspend the Phy Clock */ ++ { ++ pcgcctl_data_t pcgcctl = {.d32=0}; ++ pcgcctl.b.stoppclk = 1; ++ dwc_write_reg32(core_if->pcgcctl, pcgcctl.d32); ++ } ++ ++ /* For HNP the bus must be suspended for at least 200ms.*/ ++ if (_hcd->self.b_hnp_enable) { ++ mdelay(200); ++ //DWC_PRINT( "SUSPEND: wait complete! (%d)\n", _hcd->state); ++ } ++ break; ++ case USB_PORT_FEAT_POWER: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_POWER\n"); ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtpwr = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ case USB_PORT_FEAT_RESET: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_RESET\n"); ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ /* TODO: Is this for OTG protocol?? ++ * We shoudl remove OTG totally for Danube system. ++ * But, in the future, maybe we need this. ++ */ ++#if 1 // winder ++ hprt0.b.prtrst = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++#else ++ /* When B-Host the Port reset bit is set in ++ * the Start HCD Callback function, so that ++ * the reset is started within 1ms of the HNP ++ * success interrupt. */ ++ if (!_hcd->self.is_b_host) { ++ hprt0.b.prtrst = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ } ++#endif ++ /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ ++ MDELAY (60); ++ hprt0.b.prtrst = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ ++#ifdef DWC_HS_ELECT_TST ++ case USB_PORT_FEAT_TEST: ++ { ++ uint32_t t; ++ gintmsk_data_t gintmsk; ++ ++ t = (_wIndex >> 8); /* MSB wIndex USB */ ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_TEST %d\n", t); ++ printk("USB_PORT_FEAT_TEST %d\n", t); ++ if (t < 6) { ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prttstctl = t; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ } else { ++ /* Setup global vars with reg addresses (quick and ++ * dirty hack, should be cleaned up) ++ */ ++ global_regs = core_if->core_global_regs; ++ hc_global_regs = core_if->host_if->host_global_regs; ++ hc_regs = (dwc_otg_hc_regs_t *)((char *)global_regs + 0x500); ++ data_fifo = (uint32_t *)((char *)global_regs + 0x1000); ++ ++ if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */ ++ /* Save current interrupt mask */ ++ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ dwc_write_reg32(&global_regs->gintmsk, 0); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Drive suspend on the root port */ ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 1; ++ hprt0.b.prtres = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Drive resume on the root port */ ++ hprt0.d32 = dwc_otg_read_hprt0 (core_if); ++ hprt0.b.prtsusp = 0; ++ hprt0.b.prtres = 1; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ mdelay(100); ++ ++ /* Clear the resume bit */ ++ hprt0.b.prtres = 0; ++ dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32); ++ ++ /* Restore interrupts */ ++ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32); ++ } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */ ++ /* Save current interrupt mask */ ++ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ dwc_write_reg32(&global_regs->gintmsk, 0); ++ ++ /* 15 second delay per the test spec */ ++ mdelay(15000); ++ ++ /* Send the Setup packet */ ++ do_setup(); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Restore interrupts */ ++ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32); ++ } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */ ++ /* Save current interrupt mask */ ++ gintmsk.d32 = dwc_read_reg32(&global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ dwc_write_reg32(&global_regs->gintmsk, 0); ++ ++ /* Send the Setup packet */ ++ do_setup(); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Send the In and Ack packets */ ++ do_in_ack(); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ mdelay(15000); ++ ++ /* Restore interrupts */ ++ dwc_write_reg32(&global_regs->gintmsk, gintmsk.d32); ++ } ++ } ++ break; ++ } ++#endif /* DWC_HS_ELECT_TST */ ++ ++ case USB_PORT_FEAT_INDICATOR: ++ DWC_DEBUGPL (DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_INDICATOR\n"); ++ /* Not supported */ ++ break; ++ default: ++ retval = -EINVAL; ++ DWC_ERROR ("DWC OTG HCD - " ++ "SetPortFeature request %xh " ++ "unknown or unsupported\n", _wValue); ++ break; ++ } ++ break; ++ default: ++error: ++ retval = -EINVAL; ++ DWC_WARN ("DWC OTG HCD - " ++ "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n", ++ _typeReq, _wIndex, _wValue); ++ break; ++ } ++ ++ return retval; ++} ++ ++ ++/** ++ * Assigns transactions from a QTD to a free host channel and initializes the ++ * host channel to perform the transactions. The host channel is removed from ++ * the free list. ++ * ++ * @param _hcd The HCD state structure. ++ * @param _qh Transactions from the first QTD for this QH are selected and ++ * assigned to a free host channel. ++ */ ++static void assign_and_init_hc(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ dwc_hc_t *hc; ++ dwc_otg_qtd_t *qtd; ++ struct urb *urb; ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, _hcd, _qh); ++ ++ hc = list_entry(_hcd->free_hc_list.next, dwc_hc_t, hc_list_entry); ++ ++ /* Remove the host channel from the free list. */ ++ list_del_init(&hc->hc_list_entry); ++ ++ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); ++ urb = qtd->urb; ++ _qh->channel = hc; ++ _qh->qtd_in_process = qtd; ++ ++ /* ++ * Use usb_pipedevice to determine device address. This address is ++ * 0 before the SET_ADDRESS command and the correct address afterward. ++ */ ++ hc->dev_addr = usb_pipedevice(urb->pipe); ++ hc->ep_num = usb_pipeendpoint(urb->pipe); ++ ++ if (urb->dev->speed == USB_SPEED_LOW) { ++ hc->speed = DWC_OTG_EP_SPEED_LOW; ++ } else if (urb->dev->speed == USB_SPEED_FULL) { ++ hc->speed = DWC_OTG_EP_SPEED_FULL; ++ } else { ++ hc->speed = DWC_OTG_EP_SPEED_HIGH; ++ } ++ hc->max_packet = dwc_max_packet(_qh->maxp); ++ ++ hc->xfer_started = 0; ++ hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS; ++ hc->error_state = (qtd->error_count > 0); ++ hc->halt_on_queue = 0; ++ hc->halt_pending = 0; ++ hc->requests = 0; ++ ++ /* ++ * The following values may be modified in the transfer type section ++ * below. The xfer_len value may be reduced when the transfer is ++ * started to accommodate the max widths of the XferSize and PktCnt ++ * fields in the HCTSIZn register. ++ */ ++ hc->do_ping = _qh->ping_state; ++ hc->ep_is_in = (usb_pipein(urb->pipe) != 0); ++ hc->data_pid_start = _qh->data_toggle; ++ hc->multi_count = 1; ++ ++ if (_hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *)(u32)urb->transfer_dma + urb->actual_length; ++ } else { ++ hc->xfer_buff = (uint8_t *)urb->transfer_buffer + urb->actual_length; ++ } ++ hc->xfer_len = urb->transfer_buffer_length - urb->actual_length; ++ hc->xfer_count = 0; ++ ++ /* ++ * Set the split attributes ++ */ ++ hc->do_split = 0; ++ if (_qh->do_split) { ++ hc->do_split = 1; ++ hc->xact_pos = qtd->isoc_split_pos; ++ hc->complete_split = qtd->complete_split; ++ hc->hub_addr = urb->dev->tt->hub->devnum; ++ hc->port_addr = urb->dev->ttport; ++ } ++ ++ switch (usb_pipetype(urb->pipe)) { ++ case PIPE_CONTROL: ++ hc->ep_type = DWC_OTG_EP_TYPE_CONTROL; ++ switch (qtd->control_phase) { ++ case DWC_OTG_CONTROL_SETUP: ++ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n"); ++ hc->do_ping = 0; ++ hc->ep_is_in = 0; ++ hc->data_pid_start = DWC_OTG_HC_PID_SETUP; ++ if (_hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *)(u32)urb->setup_dma; ++ } else { ++ hc->xfer_buff = (uint8_t *)urb->setup_packet; ++ } ++ hc->xfer_len = 8; ++ break; ++ case DWC_OTG_CONTROL_DATA: ++ DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n"); ++ hc->data_pid_start = qtd->data_toggle; ++ break; ++ case DWC_OTG_CONTROL_STATUS: ++ /* ++ * Direction is opposite of data direction or IN if no ++ * data. ++ */ ++ DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n"); ++ if (urb->transfer_buffer_length == 0) { ++ hc->ep_is_in = 1; ++ } else { ++ hc->ep_is_in = (usb_pipein(urb->pipe) != USB_DIR_IN); ++ } ++ if (hc->ep_is_in) { ++ hc->do_ping = 0; ++ } ++ hc->data_pid_start = DWC_OTG_HC_PID_DATA1; ++ hc->xfer_len = 0; ++ if (_hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *)_hcd->status_buf_dma; ++ } else { ++ hc->xfer_buff = (uint8_t *)_hcd->status_buf; ++ } ++ break; ++ } ++ break; ++ case PIPE_BULK: ++ hc->ep_type = DWC_OTG_EP_TYPE_BULK; ++ break; ++ case PIPE_INTERRUPT: ++ hc->ep_type = DWC_OTG_EP_TYPE_INTR; ++ break; ++ case PIPE_ISOCHRONOUS: ++ { ++ struct usb_iso_packet_descriptor *frame_desc; ++ frame_desc = &urb->iso_frame_desc[qtd->isoc_frame_index]; ++ hc->ep_type = DWC_OTG_EP_TYPE_ISOC; ++ if (_hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *)(u32)urb->transfer_dma; ++ } else { ++ hc->xfer_buff = (uint8_t *)urb->transfer_buffer; ++ } ++ hc->xfer_buff += frame_desc->offset + qtd->isoc_split_offset; ++ hc->xfer_len = frame_desc->length - qtd->isoc_split_offset; ++ ++ if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) { ++ if (hc->xfer_len <= 188) { ++ hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL; ++ } ++ else { ++ hc->xact_pos = DWC_HCSPLIT_XACTPOS_BEGIN; ++ } ++ } ++ } ++ break; ++ } ++ ++ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * This value may be modified when the transfer is started to ++ * reflect the actual transfer length. ++ */ ++ hc->multi_count = dwc_hb_mult(_qh->maxp); ++ } ++ ++ dwc_otg_hc_init(_hcd->core_if, hc); ++ hc->qh = _qh; ++} ++#define DEBUG_HOST_CHANNELS ++#ifdef DEBUG_HOST_CHANNELS ++static int last_sel_trans_num_per_scheduled = 0; ++module_param(last_sel_trans_num_per_scheduled, int, 0444); ++ ++static int last_sel_trans_num_nonper_scheduled = 0; ++module_param(last_sel_trans_num_nonper_scheduled, int, 0444); ++ ++static int last_sel_trans_num_avail_hc_at_start = 0; ++module_param(last_sel_trans_num_avail_hc_at_start, int, 0444); ++ ++static int last_sel_trans_num_avail_hc_at_end = 0; ++module_param(last_sel_trans_num_avail_hc_at_end, int, 0444); ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++/** ++ * This function selects transactions from the HCD transfer schedule and ++ * assigns them to available host channels. It is called from HCD interrupt ++ * handler functions. ++ * ++ * @param _hcd The HCD state structure. ++ * ++ * @return The types of new transactions that were assigned to host channels. ++ */ ++dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd) ++{ ++ struct list_head *qh_ptr; ++ dwc_otg_qh_t *qh; ++ int num_channels; ++ unsigned long flags; ++ dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE; ++ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCD, " Select Transactions\n"); ++#endif /* */ ++ ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_per_scheduled = 0; ++ last_sel_trans_num_nonper_scheduled = 0; ++ last_sel_trans_num_avail_hc_at_start = _hcd->available_host_channels; ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++ /* Process entries in the periodic ready list. */ ++ num_channels = _hcd->core_if->core_params->host_channels; ++ qh_ptr = _hcd->periodic_sched_ready.next; ++ while (qh_ptr != &_hcd->periodic_sched_ready ++ && !list_empty(&_hcd->free_hc_list)) { ++ ++ // Make sure we leave one channel for non periodic transactions. ++ local_irq_save(flags); ++ if (_hcd->available_host_channels <= 1) { ++ local_irq_restore(flags); ++ break; ++ } ++ _hcd->available_host_channels--; ++ local_irq_restore(flags); ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_per_scheduled++; ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ assign_and_init_hc(_hcd, qh); ++ ++ /* ++ * Move the QH from the periodic ready schedule to the ++ * periodic assigned schedule. ++ */ ++ qh_ptr = qh_ptr->next; ++ local_irq_save(flags); ++ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_assigned); ++ local_irq_restore(flags); ++ ret_val = DWC_OTG_TRANSACTION_PERIODIC; ++ } ++ ++ /* ++ * Process entries in the deferred portion of the non-periodic list. ++ * A NAK put them here and, at the right time, they need to be ++ * placed on the sched_inactive list. ++ */ ++ qh_ptr = _hcd->non_periodic_sched_deferred.next; ++ while (qh_ptr != &_hcd->non_periodic_sched_deferred) { ++ uint16_t frame_number = ++ dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd)); ++ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ qh_ptr = qh_ptr->next; ++ ++ if (dwc_frame_num_le(qh->sched_frame, frame_number)) { ++ // NAK did this ++ /* ++ * Move the QH from the non periodic deferred schedule to ++ * the non periodic inactive schedule. ++ */ ++ local_irq_save(flags); ++ list_move(&qh->qh_list_entry, ++ &_hcd->non_periodic_sched_inactive); ++ local_irq_restore(flags); ++ } ++ } ++ ++ /* ++ * Process entries in the inactive portion of the non-periodic ++ * schedule. Some free host channels may not be used if they are ++ * reserved for periodic transfers. ++ */ ++ qh_ptr = _hcd->non_periodic_sched_inactive.next; ++ num_channels = _hcd->core_if->core_params->host_channels; ++ while (qh_ptr != &_hcd->non_periodic_sched_inactive ++ && !list_empty(&_hcd->free_hc_list)) { ++ ++ local_irq_save(flags); ++ if (_hcd->available_host_channels < 1) { ++ local_irq_restore(flags); ++ break; ++ } ++ _hcd->available_host_channels--; ++ local_irq_restore(flags); ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_nonper_scheduled++; ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ assign_and_init_hc(_hcd, qh); ++ ++ /* ++ * Move the QH from the non-periodic inactive schedule to the ++ * non-periodic active schedule. ++ */ ++ qh_ptr = qh_ptr->next; ++ local_irq_save(flags); ++ list_move(&qh->qh_list_entry, &_hcd->non_periodic_sched_active); ++ local_irq_restore(flags); ++ ++ if (ret_val == DWC_OTG_TRANSACTION_NONE) { ++ ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC; ++ } else { ++ ret_val = DWC_OTG_TRANSACTION_ALL; ++ } ++ ++ } ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_avail_hc_at_end = _hcd->available_host_channels; ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++ return ret_val; ++} ++ ++/** ++ * Attempts to queue a single transaction request for a host channel ++ * associated with either a periodic or non-periodic transfer. This function ++ * assumes that there is space available in the appropriate request queue. For ++ * an OUT transfer or SETUP transaction in Slave mode, it checks whether space ++ * is available in the appropriate Tx FIFO. ++ * ++ * @param _hcd The HCD state structure. ++ * @param _hc Host channel descriptor associated with either a periodic or ++ * non-periodic transfer. ++ * @param _fifo_dwords_avail Number of DWORDs available in the periodic Tx ++ * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic ++ * transfers. ++ * ++ * @return 1 if a request is queued and more requests may be needed to ++ * complete the transfer, 0 if no more requests are required for this ++ * transfer, -1 if there is insufficient space in the Tx FIFO. ++ */ ++static int queue_transaction(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ uint16_t _fifo_dwords_avail) ++{ ++ int retval; ++ ++ if (_hcd->core_if->dma_enable) { ++ if (!_hc->xfer_started) { ++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); ++ _hc->qh->ping_state = 0; ++ } ++ retval = 0; ++ } else if (_hc->halt_pending) { ++ /* Don't queue a request if the channel has been halted. */ ++ retval = 0; ++ } else if (_hc->halt_on_queue) { ++ dwc_otg_hc_halt(_hcd->core_if, _hc, _hc->halt_status); ++ retval = 0; ++ } else if (_hc->do_ping) { ++ if (!_hc->xfer_started) { ++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); ++ } ++ retval = 0; ++ } else if (!_hc->ep_is_in || ++ _hc->data_pid_start == DWC_OTG_HC_PID_SETUP) { ++ if ((_fifo_dwords_avail * 4) >= _hc->max_packet) { ++ if (!_hc->xfer_started) { ++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); ++ retval = 1; ++ } else { ++ retval = dwc_otg_hc_continue_transfer(_hcd->core_if, _hc); ++ } ++ } else { ++ retval = -1; ++ } ++ } else { ++ if (!_hc->xfer_started) { ++ dwc_otg_hc_start_transfer(_hcd->core_if, _hc); ++ retval = 1; ++ } else { ++ retval = dwc_otg_hc_continue_transfer(_hcd->core_if, _hc); ++ } ++ } ++ ++ return retval; ++} ++ ++/** ++ * Processes active non-periodic channels and queues transactions for these ++ * channels to the DWC_otg controller. After queueing transactions, the NP Tx ++ * FIFO Empty interrupt is enabled if there are more transactions to queue as ++ * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx ++ * FIFO Empty interrupt is disabled. ++ */ ++static void process_non_periodic_channels(dwc_otg_hcd_t *_hcd) ++{ ++ gnptxsts_data_t tx_status; ++ struct list_head *orig_qh_ptr; ++ dwc_otg_qh_t *qh; ++ int status; ++ int no_queue_space = 0; ++ int no_fifo_space = 0; ++ int more_to_do = 0; ++ ++ dwc_otg_core_global_regs_t *global_regs = _hcd->core_if->core_global_regs; ++ ++ DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n"); ++#ifdef DEBUG ++ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); ++ DWC_DEBUGPL(DBG_HCDV, " NP Tx Req Queue Space Avail (before queue): %d\n", ++ tx_status.b.nptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n", ++ tx_status.b.nptxfspcavail); ++#endif ++ /* ++ * Keep track of the starting point. Skip over the start-of-list ++ * entry. ++ */ ++ if (_hcd->non_periodic_qh_ptr == &_hcd->non_periodic_sched_active) { ++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; ++ } ++ orig_qh_ptr = _hcd->non_periodic_qh_ptr; ++ ++ /* ++ * Process once through the active list or until no more space is ++ * available in the request queue or the Tx FIFO. ++ */ ++ do { ++ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); ++ if (!_hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) { ++ no_queue_space = 1; ++ break; ++ } ++ ++ qh = list_entry(_hcd->non_periodic_qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ status = queue_transaction(_hcd, qh->channel, tx_status.b.nptxfspcavail); ++ ++ if (status > 0) { ++ more_to_do = 1; ++ } else if (status < 0) { ++ no_fifo_space = 1; ++ break; ++ } ++ ++ /* Advance to next QH, skipping start-of-list entry. */ ++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; ++ if (_hcd->non_periodic_qh_ptr == &_hcd->non_periodic_sched_active) { ++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; ++ } ++ ++ } while (_hcd->non_periodic_qh_ptr != orig_qh_ptr); ++ ++ if (!_hcd->core_if->dma_enable) { ++ gintmsk_data_t intr_mask = {.d32 = 0}; ++ intr_mask.b.nptxfempty = 1; ++ ++#ifdef DEBUG ++ tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts); ++ DWC_DEBUGPL(DBG_HCDV, " NP Tx Req Queue Space Avail (after queue): %d\n", ++ tx_status.b.nptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (after queue): %d\n", ++ tx_status.b.nptxfspcavail); ++#endif ++ if (more_to_do || no_queue_space || no_fifo_space) { ++ /* ++ * May need to queue more transactions as the request ++ * queue or Tx FIFO empties. Enable the non-periodic ++ * Tx FIFO empty interrupt. (Always use the half-empty ++ * level to ensure that new requests are loaded as ++ * soon as possible.) ++ */ ++ dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32); ++ } else { ++ /* ++ * Disable the Tx FIFO empty interrupt since there are ++ * no more transactions that need to be queued right ++ * now. This function is called from interrupt ++ * handlers to queue more transactions as transfer ++ * states change. ++ */ ++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0); ++ } ++ } ++} ++ ++/** ++ * Processes periodic channels for the next frame and queues transactions for ++ * these channels to the DWC_otg controller. After queueing transactions, the ++ * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions ++ * to queue as Periodic Tx FIFO or request queue space becomes available. ++ * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled. ++ */ ++static void process_periodic_channels(dwc_otg_hcd_t *_hcd) ++{ ++ hptxsts_data_t tx_status; ++ struct list_head *qh_ptr; ++ dwc_otg_qh_t *qh; ++ int status; ++ int no_queue_space = 0; ++ int no_fifo_space = 0; ++ ++ dwc_otg_host_global_regs_t *host_regs; ++ host_regs = _hcd->core_if->host_if->host_global_regs; ++ ++ DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n"); ++#ifdef DEBUG ++ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); ++ DWC_DEBUGPL(DBG_HCDV, " P Tx Req Queue Space Avail (before queue): %d\n", ++ tx_status.b.ptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n", ++ tx_status.b.ptxfspcavail); ++#endif ++ ++ qh_ptr = _hcd->periodic_sched_assigned.next; ++ while (qh_ptr != &_hcd->periodic_sched_assigned) { ++ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); ++ if (tx_status.b.ptxqspcavail == 0) { ++ no_queue_space = 1; ++ break; ++ } ++ ++ qh = list_entry(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ ++ /* ++ * Set a flag if we're queuing high-bandwidth in slave mode. ++ * The flag prevents any halts to get into the request queue in ++ * the middle of multiple high-bandwidth packets getting queued. ++ */ ++ if ((!_hcd->core_if->dma_enable) && ++ (qh->channel->multi_count > 1)) ++ { ++ _hcd->core_if->queuing_high_bandwidth = 1; ++ } ++ ++ status = queue_transaction(_hcd, qh->channel, tx_status.b.ptxfspcavail); ++ if (status < 0) { ++ no_fifo_space = 1; ++ break; ++ } ++ ++ /* ++ * In Slave mode, stay on the current transfer until there is ++ * nothing more to do or the high-bandwidth request count is ++ * reached. In DMA mode, only need to queue one request. The ++ * controller automatically handles multiple packets for ++ * high-bandwidth transfers. ++ */ ++ if (_hcd->core_if->dma_enable || ++ (status == 0 || ++ qh->channel->requests == qh->channel->multi_count)) { ++ qh_ptr = qh_ptr->next; ++ /* ++ * Move the QH from the periodic assigned schedule to ++ * the periodic queued schedule. ++ */ ++ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_queued); ++ ++ /* done queuing high bandwidth */ ++ _hcd->core_if->queuing_high_bandwidth = 0; ++ } ++ } ++ ++ if (!_hcd->core_if->dma_enable) { ++ dwc_otg_core_global_regs_t *global_regs; ++ gintmsk_data_t intr_mask = {.d32 = 0}; ++ ++ global_regs = _hcd->core_if->core_global_regs; ++ intr_mask.b.ptxfempty = 1; ++#ifdef DEBUG ++ tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts); ++ DWC_DEBUGPL(DBG_HCDV, " P Tx Req Queue Space Avail (after queue): %d\n", ++ tx_status.b.ptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (after queue): %d\n", ++ tx_status.b.ptxfspcavail); ++#endif ++ if (!(list_empty(&_hcd->periodic_sched_assigned)) || ++ no_queue_space || no_fifo_space) { ++ /* ++ * May need to queue more transactions as the request ++ * queue or Tx FIFO empties. Enable the periodic Tx ++ * FIFO empty interrupt. (Always use the half-empty ++ * level to ensure that new requests are loaded as ++ * soon as possible.) ++ */ ++ dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32); ++ } else { ++ /* ++ * Disable the Tx FIFO empty interrupt since there are ++ * no more transactions that need to be queued right ++ * now. This function is called from interrupt ++ * handlers to queue more transactions as transfer ++ * states change. ++ */ ++ dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0); ++ } ++ } ++} ++ ++/** ++ * This function processes the currently active host channels and queues ++ * transactions for these channels to the DWC_otg controller. It is called ++ * from HCD interrupt handler functions. ++ * ++ * @param _hcd The HCD state structure. ++ * @param _tr_type The type(s) of transactions to queue (non-periodic, ++ * periodic, or both). ++ */ ++void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t *_hcd, ++ dwc_otg_transaction_type_e _tr_type) ++{ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n"); ++#endif ++ /* Process host channels associated with periodic transfers. */ ++ if ((_tr_type == DWC_OTG_TRANSACTION_PERIODIC || ++ _tr_type == DWC_OTG_TRANSACTION_ALL) && ++ !list_empty(&_hcd->periodic_sched_assigned)) { ++ ++ process_periodic_channels(_hcd); ++ } ++ ++ /* Process host channels associated with non-periodic transfers. */ ++ if ((_tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC || ++ _tr_type == DWC_OTG_TRANSACTION_ALL)) { ++ if (!list_empty(&_hcd->non_periodic_sched_active)) { ++ process_non_periodic_channels(_hcd); ++ } else { ++ /* ++ * Ensure NP Tx FIFO empty interrupt is disabled when ++ * there are no non-periodic transfers to process. ++ */ ++ gintmsk_data_t gintmsk = {.d32 = 0}; ++ gintmsk.b.nptxfempty = 1; ++ dwc_modify_reg32(&_hcd->core_if->core_global_regs->gintmsk, gintmsk.d32, 0); ++ } ++ } ++} ++ ++/** ++ * Sets the final status of an URB and returns it to the device driver. Any ++ * required cleanup of the URB is performed. ++ */ ++void dwc_otg_hcd_complete_urb(dwc_otg_hcd_t * _hcd, struct urb *_urb, ++ int _status) ++ __releases(_hcd->lock) ++__acquires(_hcd->lock) ++{ ++#ifdef DEBUG ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ DWC_PRINT("%s: urb %p, device %d, ep %d %s, status=%d\n", ++ __func__, _urb, usb_pipedevice(_urb->pipe), ++ usb_pipeendpoint(_urb->pipe), ++ usb_pipein(_urb->pipe) ? "IN" : "OUT", _status); ++ if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) { ++ int i; ++ for (i = 0; i < _urb->number_of_packets; i++) { ++ DWC_PRINT(" ISO Desc %d status: %d\n", ++ i, _urb->iso_frame_desc[i].status); ++ } ++ } ++ } ++#endif ++ ++ _urb->status = _status; ++ _urb->hcpriv = NULL; ++ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(_hcd), _urb); ++ spin_unlock(&_hcd->lock); ++ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(_hcd), _urb, _status); ++ spin_lock(&_hcd->lock); ++} ++ ++/* ++ * Returns the Queue Head for an URB. ++ */ ++dwc_otg_qh_t *dwc_urb_to_qh(struct urb *_urb) ++{ ++ struct usb_host_endpoint *ep = dwc_urb_to_endpoint(_urb); ++ return (dwc_otg_qh_t *)ep->hcpriv; ++} ++ ++#ifdef DEBUG ++void dwc_print_setup_data (uint8_t *setup) ++{ ++ int i; ++ if (CHK_DEBUG_LEVEL(DBG_HCD)){ ++ DWC_PRINT("Setup Data = MSB "); ++ for (i=7; i>=0; i--) DWC_PRINT ("%02x ", setup[i]); ++ DWC_PRINT("\n"); ++ DWC_PRINT(" bmRequestType Tranfer = %s\n", (setup[0]&0x80) ? "Device-to-Host" : "Host-to-Device"); ++ DWC_PRINT(" bmRequestType Type = "); ++ switch ((setup[0]&0x60) >> 5) { ++ case 0: DWC_PRINT("Standard\n"); break; ++ case 1: DWC_PRINT("Class\n"); break; ++ case 2: DWC_PRINT("Vendor\n"); break; ++ case 3: DWC_PRINT("Reserved\n"); break; ++ } ++ DWC_PRINT(" bmRequestType Recipient = "); ++ switch (setup[0]&0x1f) { ++ case 0: DWC_PRINT("Device\n"); break; ++ case 1: DWC_PRINT("Interface\n"); break; ++ case 2: DWC_PRINT("Endpoint\n"); break; ++ case 3: DWC_PRINT("Other\n"); break; ++ default: DWC_PRINT("Reserved\n"); break; ++ } ++ DWC_PRINT(" bRequest = 0x%0x\n", setup[1]); ++ DWC_PRINT(" wValue = 0x%0x\n", *((uint16_t *)&setup[2])); ++ DWC_PRINT(" wIndex = 0x%0x\n", *((uint16_t *)&setup[4])); ++ DWC_PRINT(" wLength = 0x%0x\n\n", *((uint16_t *)&setup[6])); ++ } ++} ++#endif ++ ++void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t *_hcd) { ++#ifdef DEBUG ++#if 0 ++ DWC_PRINT("Frame remaining at SOF:\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->frrem_samples, _hcd->frrem_accum, ++ (_hcd->frrem_samples > 0) ? ++ _hcd->frrem_accum/_hcd->frrem_samples : 0); ++ ++ DWC_PRINT("\n"); ++ DWC_PRINT("Frame remaining at start_transfer (uframe 7):\n"); ++ DWC_PRINT(" samples %u, accum %u, avg %u\n", ++ _hcd->core_if->hfnum_7_samples, _hcd->core_if->hfnum_7_frrem_accum, ++ (_hcd->core_if->hfnum_7_samples > 0) ? ++ _hcd->core_if->hfnum_7_frrem_accum/_hcd->core_if->hfnum_7_samples : 0); ++ DWC_PRINT("Frame remaining at start_transfer (uframe 0):\n"); ++ DWC_PRINT(" samples %u, accum %u, avg %u\n", ++ _hcd->core_if->hfnum_0_samples, _hcd->core_if->hfnum_0_frrem_accum, ++ (_hcd->core_if->hfnum_0_samples > 0) ? ++ _hcd->core_if->hfnum_0_frrem_accum/_hcd->core_if->hfnum_0_samples : 0); ++ DWC_PRINT("Frame remaining at start_transfer (uframe 1-6):\n"); ++ DWC_PRINT(" samples %u, accum %u, avg %u\n", ++ _hcd->core_if->hfnum_other_samples, _hcd->core_if->hfnum_other_frrem_accum, ++ (_hcd->core_if->hfnum_other_samples > 0) ? ++ _hcd->core_if->hfnum_other_frrem_accum/_hcd->core_if->hfnum_other_samples : 0); ++ ++ DWC_PRINT("\n"); ++ DWC_PRINT("Frame remaining at sample point A (uframe 7):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_7_samples_a, _hcd->hfnum_7_frrem_accum_a, ++ (_hcd->hfnum_7_samples_a > 0) ? ++ _hcd->hfnum_7_frrem_accum_a/_hcd->hfnum_7_samples_a : 0); ++ DWC_PRINT("Frame remaining at sample point A (uframe 0):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_0_samples_a, _hcd->hfnum_0_frrem_accum_a, ++ (_hcd->hfnum_0_samples_a > 0) ? ++ _hcd->hfnum_0_frrem_accum_a/_hcd->hfnum_0_samples_a : 0); ++ DWC_PRINT("Frame remaining at sample point A (uframe 1-6):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_other_samples_a, _hcd->hfnum_other_frrem_accum_a, ++ (_hcd->hfnum_other_samples_a > 0) ? ++ _hcd->hfnum_other_frrem_accum_a/_hcd->hfnum_other_samples_a : 0); ++ ++ DWC_PRINT("\n"); ++ DWC_PRINT("Frame remaining at sample point B (uframe 7):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_7_samples_b, _hcd->hfnum_7_frrem_accum_b, ++ (_hcd->hfnum_7_samples_b > 0) ? ++ _hcd->hfnum_7_frrem_accum_b/_hcd->hfnum_7_samples_b : 0); ++ DWC_PRINT("Frame remaining at sample point B (uframe 0):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_0_samples_b, _hcd->hfnum_0_frrem_accum_b, ++ (_hcd->hfnum_0_samples_b > 0) ? ++ _hcd->hfnum_0_frrem_accum_b/_hcd->hfnum_0_samples_b : 0); ++ DWC_PRINT("Frame remaining at sample point B (uframe 1-6):\n"); ++ DWC_PRINT(" samples %u, accum %llu, avg %llu\n", ++ _hcd->hfnum_other_samples_b, _hcd->hfnum_other_frrem_accum_b, ++ (_hcd->hfnum_other_samples_b > 0) ? ++ _hcd->hfnum_other_frrem_accum_b/_hcd->hfnum_other_samples_b : 0); ++#endif ++#endif ++} ++ ++void dwc_otg_hcd_dump_state(dwc_otg_hcd_t *_hcd) ++{ ++#ifdef DEBUG ++ int num_channels; ++ int i; ++ gnptxsts_data_t np_tx_status; ++ hptxsts_data_t p_tx_status; ++ ++ num_channels = _hcd->core_if->core_params->host_channels; ++ DWC_PRINT("\n"); ++ DWC_PRINT("************************************************************\n"); ++ DWC_PRINT("HCD State:\n"); ++ DWC_PRINT(" Num channels: %d\n", num_channels); ++ for (i = 0; i < num_channels; i++) { ++ dwc_hc_t *hc = _hcd->hc_ptr_array[i]; ++ DWC_PRINT(" Channel %d:\n", i); ++ DWC_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", ++ hc->dev_addr, hc->ep_num, hc->ep_is_in); ++ DWC_PRINT(" speed: %d\n", hc->speed); ++ DWC_PRINT(" ep_type: %d\n", hc->ep_type); ++ DWC_PRINT(" max_packet: %d\n", hc->max_packet); ++ DWC_PRINT(" data_pid_start: %d\n", hc->data_pid_start); ++ DWC_PRINT(" multi_count: %d\n", hc->multi_count); ++ DWC_PRINT(" xfer_started: %d\n", hc->xfer_started); ++ DWC_PRINT(" xfer_buff: %p\n", hc->xfer_buff); ++ DWC_PRINT(" xfer_len: %d\n", hc->xfer_len); ++ DWC_PRINT(" xfer_count: %d\n", hc->xfer_count); ++ DWC_PRINT(" halt_on_queue: %d\n", hc->halt_on_queue); ++ DWC_PRINT(" halt_pending: %d\n", hc->halt_pending); ++ DWC_PRINT(" halt_status: %d\n", hc->halt_status); ++ DWC_PRINT(" do_split: %d\n", hc->do_split); ++ DWC_PRINT(" complete_split: %d\n", hc->complete_split); ++ DWC_PRINT(" hub_addr: %d\n", hc->hub_addr); ++ DWC_PRINT(" port_addr: %d\n", hc->port_addr); ++ DWC_PRINT(" xact_pos: %d\n", hc->xact_pos); ++ DWC_PRINT(" requests: %d\n", hc->requests); ++ DWC_PRINT(" qh: %p\n", hc->qh); ++ if (hc->xfer_started) { ++ hfnum_data_t hfnum; ++ hcchar_data_t hcchar; ++ hctsiz_data_t hctsiz; ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; ++ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); ++ hcchar.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcchar); ++ hctsiz.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hctsiz); ++ hcint.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcint); ++ hcintmsk.d32 = dwc_read_reg32(&_hcd->core_if->host_if->hc_regs[i]->hcintmsk); ++ DWC_PRINT(" hfnum: 0x%08x\n", hfnum.d32); ++ DWC_PRINT(" hcchar: 0x%08x\n", hcchar.d32); ++ DWC_PRINT(" hctsiz: 0x%08x\n", hctsiz.d32); ++ DWC_PRINT(" hcint: 0x%08x\n", hcint.d32); ++ DWC_PRINT(" hcintmsk: 0x%08x\n", hcintmsk.d32); ++ } ++ if (hc->xfer_started && (hc->qh != NULL) && (hc->qh->qtd_in_process != NULL)) { ++ dwc_otg_qtd_t *qtd; ++ struct urb *urb; ++ qtd = hc->qh->qtd_in_process; ++ urb = qtd->urb; ++ DWC_PRINT(" URB Info:\n"); ++ DWC_PRINT(" qtd: %p, urb: %p\n", qtd, urb); ++ if (urb != NULL) { ++ DWC_PRINT(" Dev: %d, EP: %d %s\n", ++ usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe), ++ usb_pipein(urb->pipe) ? "IN" : "OUT"); ++ DWC_PRINT(" Max packet size: %d\n", ++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); ++ DWC_PRINT(" transfer_buffer: %p\n", urb->transfer_buffer); ++ DWC_PRINT(" transfer_dma: %p\n", (void *)urb->transfer_dma); ++ DWC_PRINT(" transfer_buffer_length: %d\n", urb->transfer_buffer_length); ++ DWC_PRINT(" actual_length: %d\n", urb->actual_length); ++ } ++ } ++ } ++ //DWC_PRINT(" non_periodic_channels: %d\n", _hcd->non_periodic_channels); ++ //DWC_PRINT(" periodic_channels: %d\n", _hcd->periodic_channels); ++ DWC_PRINT(" available_channels: %d\n", _hcd->available_host_channels); ++ DWC_PRINT(" periodic_usecs: %d\n", _hcd->periodic_usecs); ++ np_tx_status.d32 = dwc_read_reg32(&_hcd->core_if->core_global_regs->gnptxsts); ++ DWC_PRINT(" NP Tx Req Queue Space Avail: %d\n", np_tx_status.b.nptxqspcavail); ++ DWC_PRINT(" NP Tx FIFO Space Avail: %d\n", np_tx_status.b.nptxfspcavail); ++ p_tx_status.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hptxsts); ++ DWC_PRINT(" P Tx Req Queue Space Avail: %d\n", p_tx_status.b.ptxqspcavail); ++ DWC_PRINT(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail); ++ dwc_otg_hcd_dump_frrem(_hcd); ++ dwc_otg_dump_global_registers(_hcd->core_if); ++ dwc_otg_dump_host_registers(_hcd->core_if); ++ DWC_PRINT("************************************************************\n"); ++ DWC_PRINT("\n"); ++#endif ++} ++#endif /* DWC_DEVICE_ONLY */ +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_hcd.h +@@ -0,0 +1,676 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 537387 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++#if !defined(__DWC_HCD_H__) ++#define __DWC_HCD_H__ ++ ++#include <linux/list.h> ++#include <linux/usb.h> ++#include <linux/usb/hcd.h> ++ ++struct lm_device; ++struct dwc_otg_device; ++ ++#include "dwc_otg_cil.h" ++//#include "dwc_otg_ifx.h" // winder ++ ++ ++/** ++ * @file ++ * ++ * 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 DWC_otg controller. ++ * It isolates the USBD from the specifics of the controller by providing an ++ * API to the USBD. ++ */ ++ ++/** ++ * Phases for control transfers. ++ */ ++typedef enum dwc_otg_control_phase { ++ DWC_OTG_CONTROL_SETUP, ++ DWC_OTG_CONTROL_DATA, ++ DWC_OTG_CONTROL_STATUS ++} dwc_otg_control_phase_e; ++ ++/** Transaction types. */ ++typedef enum dwc_otg_transaction_type { ++ DWC_OTG_TRANSACTION_NONE, ++ DWC_OTG_TRANSACTION_PERIODIC, ++ DWC_OTG_TRANSACTION_NON_PERIODIC, ++ DWC_OTG_TRANSACTION_ALL ++} dwc_otg_transaction_type_e; ++ ++/** ++ * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, ++ * interrupt, or isochronous transfer. A single QTD is created for each URB ++ * (of one of these types) submitted to the HCD. The transfer associated with ++ * a QTD may require one or multiple transactions. ++ * ++ * A QTD is linked to a Queue Head, which is entered in either the ++ * non-periodic or periodic schedule for execution. When a QTD is chosen for ++ * execution, some or all of its transactions may be executed. After ++ * execution, the state of the QTD is updated. The QTD 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. ++ */ ++struct dwc_otg_qh; ++typedef struct dwc_otg_qtd { ++ /** ++ * Determines the PID of the next data packet for the data phase of ++ * control transfers. Ignored for other transfer types.<br> ++ * One of the following values: ++ * - DWC_OTG_HC_PID_DATA0 ++ * - DWC_OTG_HC_PID_DATA1 ++ */ ++ uint8_t data_toggle; ++ ++ /** Current phase for control transfers (Setup, Data, or Status). */ ++ dwc_otg_control_phase_e control_phase; ++ ++ /** Keep track of the current split type ++ * for FS/LS endpoints on a HS Hub */ ++ uint8_t complete_split; ++ ++ /** How many bytes transferred during SSPLIT OUT */ ++ uint32_t ssplit_out_xfer_count; ++ ++ /** ++ * Holds the number of bus errors that have occurred for a transaction ++ * within this transfer. ++ */ ++ uint8_t error_count; ++ ++ /** ++ * 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. ++ */ ++ int isoc_frame_index; ++ ++ /** Position of the ISOC split on full/low speed */ ++ uint8_t isoc_split_pos; ++ ++ /** Position of the ISOC split in the buffer for the current frame */ ++ uint16_t isoc_split_offset; ++ ++ /** URB for this transfer */ ++ struct urb *urb; ++ ++ /** This list of QTDs */ ++ struct list_head qtd_list_entry; ++ ++ /* Field to track the qh pointer */ ++ struct dwc_otg_qh *qtd_qh_ptr; ++} dwc_otg_qtd_t; ++ ++/** ++ * A Queue Head (QH) holds the static characteristics of an endpoint and ++ * maintains a list of transfers (QTDs) for that endpoint. A QH structure may ++ * be entered in either the non-periodic or periodic schedule. ++ */ ++typedef struct dwc_otg_qh { ++ /** ++ * Endpoint type. ++ * One of the following values: ++ * - USB_ENDPOINT_XFER_CONTROL ++ * - USB_ENDPOINT_XFER_ISOC ++ * - USB_ENDPOINT_XFER_BULK ++ * - USB_ENDPOINT_XFER_INT ++ */ ++ uint8_t ep_type; ++ uint8_t ep_is_in; ++ ++ /** wMaxPacketSize Field of Endpoint Descriptor. */ ++ uint16_t maxp; ++ ++ /** ++ * Determines the PID of the next data packet for non-control ++ * transfers. Ignored for control transfers.<br> ++ * One of the following values: ++ * - DWC_OTG_HC_PID_DATA0 ++ * - DWC_OTG_HC_PID_DATA1 ++ */ ++ uint8_t data_toggle; ++ ++ /** Ping state if 1. */ ++ uint8_t ping_state; ++ ++ /** ++ * List of QTDs for this QH. ++ */ ++ struct list_head qtd_list; ++ ++ /** Host channel currently processing transfers for this QH. */ ++ dwc_hc_t *channel; ++ ++ /** QTD currently assigned to a host channel for this QH. */ ++ dwc_otg_qtd_t *qtd_in_process; ++ ++ /** Full/low speed endpoint on high-speed hub requires split. */ ++ uint8_t do_split; ++ ++ /** @name Periodic schedule information */ ++ /** @{ */ ++ ++ /** Bandwidth in microseconds per (micro)frame. */ ++ uint8_t usecs; ++ ++ /** Interval between transfers in (micro)frames. */ ++ uint16_t interval; ++ ++ /** ++ * (micro)frame to initialize a periodic transfer. The transfer ++ * executes in the following (micro)frame. ++ */ ++ uint16_t sched_frame; ++ ++ /** (micro)frame at which last start split was initialized. */ ++ uint16_t start_split_frame; ++ ++ /** @} */ ++ ++ uint16_t speed; ++ uint16_t frame_usecs[8]; ++ /** Entry for QH in either the periodic or non-periodic schedule. */ ++ struct list_head qh_list_entry; ++} dwc_otg_qh_t; ++ ++/** ++ * This structure holds the state of the HCD, including the non-periodic and ++ * periodic schedules. ++ */ ++typedef struct dwc_otg_hcd { ++ spinlock_t lock; ++ ++ /** DWC OTG Core Interface Layer */ ++ dwc_otg_core_if_t *core_if; ++ ++ /** Internal DWC HCD Flags */ ++ volatile union dwc_otg_hcd_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; ++ ++ /** ++ * Inactive items in the non-periodic schedule. This is a list of ++ * Queue Heads. Transfers associated with these Queue Heads are not ++ * currently assigned to a host channel. ++ */ ++ struct list_head non_periodic_sched_inactive; ++ ++ /** ++ * Deferred items in the non-periodic schedule. This is a list of ++ * Queue Heads. Transfers associated with these Queue Heads are not ++ * currently assigned to a host channel. ++ * When we get an NAK, the QH goes here. ++ */ ++ struct list_head non_periodic_sched_deferred; ++ ++ /** ++ * Active items in the non-periodic schedule. This is a list of ++ * Queue Heads. Transfers associated with these Queue Heads are ++ * currently assigned to a host channel. ++ */ ++ struct list_head non_periodic_sched_active; ++ ++ /** ++ * Pointer to the next Queue Head to process in the active ++ * non-periodic schedule. ++ */ ++ struct list_head *non_periodic_qh_ptr; ++ ++ /** ++ * Inactive items in the periodic schedule. This is a list of QHs for ++ * periodic transfers that are _not_ scheduled for the next frame. ++ * Each QH in the list has an interval counter that determines when it ++ * needs to be scheduled for execution. This scheduling mechanism ++ * allows only a simple calculation for periodic bandwidth used (i.e. ++ * must assume that all periodic transfers may need to execute in the ++ * same frame). However, it greatly simplifies scheduling and should ++ * be sufficient for the vast majority of OTG hosts, which need to ++ * connect to a small number of peripherals at one time. ++ * ++ * Items move from this list to periodic_sched_ready when the QH ++ * interval counter is 0 at SOF. ++ */ ++ struct list_head periodic_sched_inactive; ++ ++ /** ++ * List of periodic QHs that are ready for execution in the next ++ * frame, but have not yet been assigned to host channels. ++ * ++ * Items move from this list to periodic_sched_assigned as host ++ * channels become available during the current frame. ++ */ ++ struct list_head periodic_sched_ready; ++ ++ /** ++ * List of periodic QHs to be executed in the next frame that are ++ * assigned to host channels. ++ * ++ * Items move from this list to periodic_sched_queued as the ++ * transactions for the QH are queued to the DWC_otg controller. ++ */ ++ struct list_head periodic_sched_assigned; ++ ++ /** ++ * List of periodic QHs that have been queued for execution. ++ * ++ * Items move from this list to either periodic_sched_inactive or ++ * periodic_sched_ready when the channel associated with the transfer ++ * is released. If the interval for the QH is 1, the item moves to ++ * periodic_sched_ready because it must be rescheduled for the next ++ * frame. Otherwise, the item moves to periodic_sched_inactive. ++ */ ++ struct list_head periodic_sched_queued; ++ ++ /** ++ * Total bandwidth claimed so far for periodic transfers. This value ++ * is in microseconds per (micro)frame. The assumption is that all ++ * periodic transfers may occur in the same (micro)frame. ++ */ ++ uint16_t periodic_usecs; ++ ++ /** ++ * Total bandwidth claimed so far for all periodic transfers ++ * in a frame. ++ * This will include a mixture of HS and FS transfers. ++ * Units are microseconds per (micro)frame. ++ * We have a budget per frame and have to schedule ++ * transactions accordingly. ++ * Watch out for the fact that things are actually scheduled for the ++ * "next frame". ++ */ ++ uint16_t frame_usecs[8]; ++ ++ /** ++ * Frame number read from the core at SOF. The value ranges from 0 to ++ * DWC_HFNUM_MAX_FRNUM. ++ */ ++ uint16_t frame_number; ++ ++ /** ++ * Free host channels in the controller. This is a list of ++ * dwc_hc_t items. ++ */ ++ struct list_head free_hc_list; ++ ++ /** ++ * Number of available host channels. ++ */ ++ int available_host_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. ++ */ ++ dwc_hc_t *hc_ptr_array[MAX_EPS_CHANNELS]; ++ ++ /** ++ * 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. ++ */ ++ uint8_t *status_buf; ++ ++ /** ++ * DMA address for status_buf. ++ */ ++ dma_addr_t status_buf_dma; ++#define DWC_OTG_HCD_STATUS_BUF_SIZE 64 ++ ++ /** ++ * Structure to allow starting the HCD in a non-interrupt context ++ * during an OTG role change. ++ */ ++ struct work_struct start_work; ++ struct usb_hcd *_p; ++ ++ /** ++ * Connection timer. An OTG host must display a message if the device ++ * does not connect. Started when the VBus power is turned on via ++ * sysfs attribute "buspower". ++ */ ++ struct timer_list conn_timer; ++ ++ /* Tasket to do a reset */ ++ struct tasklet_struct *reset_tasklet; ++ ++#ifdef DEBUG ++ uint32_t frrem_samples; ++ uint64_t frrem_accum; ++ ++ uint32_t hfnum_7_samples_a; ++ uint64_t hfnum_7_frrem_accum_a; ++ uint32_t hfnum_0_samples_a; ++ uint64_t hfnum_0_frrem_accum_a; ++ uint32_t hfnum_other_samples_a; ++ uint64_t hfnum_other_frrem_accum_a; ++ ++ uint32_t hfnum_7_samples_b; ++ uint64_t hfnum_7_frrem_accum_b; ++ uint32_t hfnum_0_samples_b; ++ uint64_t hfnum_0_frrem_accum_b; ++ uint32_t hfnum_other_samples_b; ++ uint64_t hfnum_other_frrem_accum_b; ++#endif ++ ++} dwc_otg_hcd_t; ++ ++/** Gets the dwc_otg_hcd from a struct usb_hcd */ ++static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd) ++{ ++ return (dwc_otg_hcd_t *)(hcd->hcd_priv); ++} ++ ++/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */ ++static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t *dwc_otg_hcd) ++{ ++ return container_of((void *)dwc_otg_hcd, struct usb_hcd, hcd_priv); ++} ++ ++/** @name HCD Create/Destroy Functions */ ++/** @{ */ ++extern int __devinit dwc_otg_hcd_init(struct device *_dev, dwc_otg_device_t * dwc_otg_device); ++extern void dwc_otg_hcd_remove(struct device *_dev); ++/** @} */ ++ ++/** @name Linux HC Driver API Functions */ ++/** @{ */ ++ ++extern int dwc_otg_hcd_start(struct usb_hcd *hcd); ++extern void dwc_otg_hcd_stop(struct usb_hcd *hcd); ++extern int dwc_otg_hcd_get_frame_number(struct usb_hcd *hcd); ++extern void dwc_otg_hcd_free(struct usb_hcd *hcd); ++ ++extern int dwc_otg_hcd_urb_enqueue(struct usb_hcd *hcd, ++ struct urb *urb, ++ gfp_t mem_flags); ++extern int dwc_otg_hcd_urb_dequeue(struct usb_hcd *hcd, ++ struct urb *urb, ++ int status); ++extern irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd); ++ ++extern void dwc_otg_hcd_endpoint_disable(struct usb_hcd *hcd, ++ struct usb_host_endpoint *ep); ++ ++extern int dwc_otg_hcd_hub_status_data(struct usb_hcd *hcd, ++ char *buf); ++extern int dwc_otg_hcd_hub_control(struct usb_hcd *hcd, ++ u16 typeReq, ++ u16 wValue, ++ u16 wIndex, ++ char *buf, ++ u16 wLength); ++ ++/** @} */ ++ ++/** @name Transaction Execution Functions */ ++/** @{ */ ++extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t *_hcd); ++extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t *_hcd, ++ dwc_otg_transaction_type_e _tr_type); ++extern void dwc_otg_hcd_complete_urb(dwc_otg_hcd_t *_hcd, struct urb *_urb, ++ int _status); ++/** @} */ ++ ++/** @name Interrupt Handler Functions */ ++/** @{ */ ++extern int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_disconnect_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_hc_n_intr (dwc_otg_hcd_t *_dwc_otg_hcd, uint32_t _num); ++extern int32_t dwc_otg_hcd_handle_session_req_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr (dwc_otg_hcd_t *_dwc_otg_hcd); ++/** @} */ ++ ++ ++/** @name Schedule Queue Functions */ ++/** @{ */ ++ ++/* Implemented in dwc_otg_hcd_queue.c */ ++extern dwc_otg_qh_t *dwc_otg_hcd_qh_create (dwc_otg_hcd_t *_hcd, struct urb *_urb); ++extern void dwc_otg_hcd_qh_init (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, struct urb *_urb); ++extern void dwc_otg_hcd_qh_free (dwc_otg_qh_t *_qh); ++extern int dwc_otg_hcd_qh_add (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh); ++extern void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh); ++extern void dwc_otg_hcd_qh_deactivate (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int sched_csplit); ++extern int dwc_otg_hcd_qh_deferr (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int delay); ++ ++/** Remove and free a QH */ ++static inline void dwc_otg_hcd_qh_remove_and_free (dwc_otg_hcd_t *_hcd, ++ dwc_otg_qh_t *_qh) ++{ ++ dwc_otg_hcd_qh_remove (_hcd, _qh); ++ dwc_otg_hcd_qh_free (_qh); ++} ++ ++/** Allocates memory for a QH structure. ++ * @return Returns the memory allocate or NULL on error. */ ++static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc (void) ++{ ++#ifdef _SC_BUILD_ ++ return (dwc_otg_qh_t *) kmalloc (sizeof(dwc_otg_qh_t), GFP_ATOMIC); ++#else ++ return (dwc_otg_qh_t *) kmalloc (sizeof(dwc_otg_qh_t), GFP_KERNEL); ++#endif ++} ++ ++extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create (struct urb *urb); ++extern void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t *qtd, struct urb *urb); ++extern int dwc_otg_hcd_qtd_add (dwc_otg_qtd_t *qtd, dwc_otg_hcd_t *dwc_otg_hcd); ++ ++/** Allocates memory for a QTD structure. ++ * @return Returns the memory allocate or NULL on error. */ ++static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc (void) ++{ ++#ifdef _SC_BUILD_ ++ return (dwc_otg_qtd_t *) kmalloc (sizeof(dwc_otg_qtd_t), GFP_ATOMIC); ++#else ++ return (dwc_otg_qtd_t *) kmalloc (sizeof(dwc_otg_qtd_t), GFP_KERNEL); ++#endif ++} ++ ++/** Frees the memory for a QTD structure. QTD should already be removed from ++ * list. ++ * @param[in] _qtd QTD to free.*/ ++static inline void dwc_otg_hcd_qtd_free (dwc_otg_qtd_t *_qtd) ++{ ++ kfree (_qtd); ++} ++ ++/** Removes a QTD from list. ++ * @param[in] _qtd QTD to remove from list. */ ++static inline void dwc_otg_hcd_qtd_remove (dwc_otg_qtd_t *_qtd) ++{ ++ unsigned long flags; ++ local_irq_save (flags); ++ list_del (&_qtd->qtd_list_entry); ++ local_irq_restore (flags); ++} ++ ++/** Remove and free a QTD */ ++static inline void dwc_otg_hcd_qtd_remove_and_free (dwc_otg_qtd_t *_qtd) ++{ ++ dwc_otg_hcd_qtd_remove (_qtd); ++ dwc_otg_hcd_qtd_free (_qtd); ++} ++ ++/** @} */ ++ ++ ++/** @name Internal Functions */ ++/** @{ */ ++dwc_otg_qh_t *dwc_urb_to_qh(struct urb *_urb); ++void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t *_hcd); ++void dwc_otg_hcd_dump_state(dwc_otg_hcd_t *_hcd); ++/** @} */ ++ ++ ++/** Gets the usb_host_endpoint associated with an URB. */ ++static inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *_urb) ++{ ++ struct usb_device *dev = _urb->dev; ++ int ep_num = usb_pipeendpoint(_urb->pipe); ++ if (usb_pipein(_urb->pipe)) ++ return dev->ep_in[ep_num]; ++ else ++ return dev->ep_out[ep_num]; ++} ++ ++/** ++ * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is ++ * qualified with its direction (possible 32 endpoints per device). ++ */ ++#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) \ ++ ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \ ++ ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4) ++ ++/** Gets the QH that contains the list_head */ ++#define dwc_list_to_qh(_list_head_ptr_) (container_of(_list_head_ptr_,dwc_otg_qh_t,qh_list_entry)) ++ ++/** Gets the QTD that contains the list_head */ ++#define dwc_list_to_qtd(_list_head_ptr_) (container_of(_list_head_ptr_,dwc_otg_qtd_t,qtd_list_entry)) ++ ++/** Check if QH is non-periodic */ ++#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == USB_ENDPOINT_XFER_BULK) || \ ++ (_qh_ptr_->ep_type == USB_ENDPOINT_XFER_CONTROL)) ++ ++/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */ ++#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) ++ ++/** Packet size for any kind of endpoint descriptor */ ++#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) ++ ++/** ++ * Returns true if _frame1 is less than or equal to _frame2. The comparison is ++ * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the ++ * frame number when the max frame number is reached. ++ */ ++static inline int dwc_frame_num_le(uint16_t _frame1, uint16_t _frame2) ++{ ++ return ((_frame2 - _frame1) & DWC_HFNUM_MAX_FRNUM) <= ++ (DWC_HFNUM_MAX_FRNUM >> 1); ++} ++ ++/** ++ * Returns true if _frame1 is greater than _frame2. The comparison is done ++ * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame ++ * number when the max frame number is reached. ++ */ ++static inline int dwc_frame_num_gt(uint16_t _frame1, uint16_t _frame2) ++{ ++ return (_frame1 != _frame2) && ++ (((_frame1 - _frame2) & DWC_HFNUM_MAX_FRNUM) < ++ (DWC_HFNUM_MAX_FRNUM >> 1)); ++} ++ ++/** ++ * Increments _frame by the amount specified by _inc. The addition is done ++ * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value. ++ */ ++static inline uint16_t dwc_frame_num_inc(uint16_t _frame, uint16_t _inc) ++{ ++ return (_frame + _inc) & DWC_HFNUM_MAX_FRNUM; ++} ++ ++static inline uint16_t dwc_full_frame_num (uint16_t _frame) ++{ ++ return ((_frame) & DWC_HFNUM_MAX_FRNUM) >> 3; ++} ++ ++static inline uint16_t dwc_micro_frame_num (uint16_t _frame) ++{ ++ return (_frame) & 0x7; ++} ++ ++#ifdef DEBUG ++/** ++ * Macro to sample the remaining PHY clocks left in the current frame. This ++ * may be used during debugging to determine the average time it takes to ++ * execute sections of code. There are two possible sample points, "a" and ++ * "b", so the _letter argument must be one of these values. ++ * ++ * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For ++ * example, "cat /sys/devices/lm0/hcd_frrem". ++ */ ++#define dwc_sample_frrem(_hcd, _qh, _letter) \ ++{ \ ++ hfnum_data_t hfnum; \ ++ dwc_otg_qtd_t *qtd; \ ++ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \ ++ if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \ ++ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); \ ++ switch (hfnum.b.frnum & 0x7) { \ ++ case 7: \ ++ _hcd->hfnum_7_samples_##_letter++; \ ++ _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \ ++ break; \ ++ case 0: \ ++ _hcd->hfnum_0_samples_##_letter++; \ ++ _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \ ++ break; \ ++ default: \ ++ _hcd->hfnum_other_samples_##_letter++; \ ++ _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \ ++ break; \ ++ } \ ++ } \ ++} ++#else // DEBUG ++#define dwc_sample_frrem(_hcd, _qh, _letter) ++#endif // DEBUG ++#endif // __DWC_HCD_H__ ++#endif /* DWC_DEVICE_ONLY */ +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_hcd_intr.c +@@ -0,0 +1,1841 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd_intr.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 553126 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++ ++#include "dwc_otg_driver.h" ++#include "dwc_otg_hcd.h" ++#include "dwc_otg_regs.h" ++ ++const int erratum_usb09_patched = 0; ++const int deferral_on = 1; ++const int nak_deferral_delay = 8; ++const int nyet_deferral_delay = 1; ++/** @file ++ * This file contains the implementation of the HCD Interrupt handlers. ++ */ ++ ++/** This function handles interrupts for the HCD. */ ++int32_t dwc_otg_hcd_handle_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ int retval = 0; ++ ++ dwc_otg_core_if_t *core_if = _dwc_otg_hcd->core_if; ++ gintsts_data_t gintsts; ++#ifdef DEBUG ++ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; ++#endif ++ ++ /* Check if HOST Mode */ ++ if (dwc_otg_is_host_mode(core_if)) { ++ gintsts.d32 = dwc_otg_read_core_intr(core_if); ++ if (!gintsts.d32) { ++ return 0; ++ } ++ ++#ifdef DEBUG ++ /* Don't print debug message in the interrupt handler on SOF */ ++# ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++# endif ++ DWC_DEBUGPL (DBG_HCD, "\n"); ++#endif ++ ++#ifdef DEBUG ++# ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++# endif ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n", gintsts.d32); ++#endif ++ ++ if (gintsts.b.sofintr) { ++ retval |= dwc_otg_hcd_handle_sof_intr (_dwc_otg_hcd); ++ } ++ if (gintsts.b.rxstsqlvl) { ++ retval |= dwc_otg_hcd_handle_rx_status_q_level_intr (_dwc_otg_hcd); ++ } ++ if (gintsts.b.nptxfempty) { ++ retval |= dwc_otg_hcd_handle_np_tx_fifo_empty_intr (_dwc_otg_hcd); ++ } ++ if (gintsts.b.i2cintr) { ++ /** @todo Implement i2cintr handler. */ ++ } ++ if (gintsts.b.portintr) { ++ retval |= dwc_otg_hcd_handle_port_intr (_dwc_otg_hcd); ++ } ++ if (gintsts.b.hcintr) { ++ retval |= dwc_otg_hcd_handle_hc_intr (_dwc_otg_hcd); ++ } ++ if (gintsts.b.ptxfempty) { ++ retval |= dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (_dwc_otg_hcd); ++ } ++#ifdef DEBUG ++# ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++# endif ++ { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Finished Servicing Interrupts\n"); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n", ++ dwc_read_reg32(&global_regs->gintsts)); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n", ++ dwc_read_reg32(&global_regs->gintmsk)); ++ } ++#endif ++ ++#ifdef DEBUG ++# ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++# endif ++ DWC_DEBUGPL (DBG_HCD, "\n"); ++#endif ++ ++ } ++ ++ return retval; ++} ++ ++#ifdef DWC_TRACK_MISSED_SOFS ++#warning Compiling code to track missed SOFs ++#define FRAME_NUM_ARRAY_SIZE 1000 ++/** ++ * This function is for debug only. ++ */ ++static inline void track_missed_sofs(uint16_t _curr_frame_number) { ++ static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE]; ++ static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE]; ++ static int frame_num_idx = 0; ++ static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM; ++ static int dumped_frame_num_array = 0; ++ ++ if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) { ++ if ((((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) != _curr_frame_number)) { ++ frame_num_array[frame_num_idx] = _curr_frame_number; ++ last_frame_num_array[frame_num_idx++] = last_frame_num; ++ } ++ } else if (!dumped_frame_num_array) { ++ int i; ++ printk(KERN_EMERG USB_DWC "Frame Last Frame\n"); ++ printk(KERN_EMERG USB_DWC "----- ----------\n"); ++ for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) { ++ printk(KERN_EMERG USB_DWC "0x%04x 0x%04x\n", ++ frame_num_array[i], last_frame_num_array[i]); ++ } ++ dumped_frame_num_array = 1; ++ } ++ last_frame_num = _curr_frame_number; ++} ++#endif ++ ++/** ++ * 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. ++ */ ++int32_t dwc_otg_hcd_handle_sof_intr (dwc_otg_hcd_t *_hcd) ++{ ++ hfnum_data_t hfnum; ++ struct list_head *qh_entry; ++ dwc_otg_qh_t *qh; ++ dwc_otg_transaction_type_e tr_type; ++ gintsts_data_t gintsts = {.d32 = 0}; ++ ++ hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); ++ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n"); ++#endif ++ ++ _hcd->frame_number = hfnum.b.frnum; ++ ++#ifdef DEBUG ++ _hcd->frrem_accum += hfnum.b.frrem; ++ _hcd->frrem_samples++; ++#endif ++ ++#ifdef DWC_TRACK_MISSED_SOFS ++ track_missed_sofs(_hcd->frame_number); ++#endif ++ ++ /* Determine whether any periodic QHs should be executed. */ ++ qh_entry = _hcd->periodic_sched_inactive.next; ++ while (qh_entry != &_hcd->periodic_sched_inactive) { ++ qh = list_entry(qh_entry, dwc_otg_qh_t, qh_list_entry); ++ qh_entry = qh_entry->next; ++ if (dwc_frame_num_le(qh->sched_frame, _hcd->frame_number)) { ++ /* ++ * Move QH to the ready list to be executed next ++ * (micro)frame. ++ */ ++ list_move(&qh->qh_list_entry, &_hcd->periodic_sched_ready); ++ } ++ } ++ ++ tr_type = dwc_otg_hcd_select_transactions(_hcd); ++ if (tr_type != DWC_OTG_TRANSACTION_NONE) { ++ dwc_otg_hcd_queue_transactions(_hcd, tr_type); ++ } ++ ++ /* Clear interrupt */ ++ gintsts.b.sofintr = 1; ++ dwc_write_reg32(&_hcd->core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at ++ * least one packet in the Rx FIFO. The packets are moved from the FIFO to ++ * memory if the DWC_otg controller is operating in Slave mode. */ ++int32_t dwc_otg_hcd_handle_rx_status_q_level_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ host_grxsts_data_t grxsts; ++ dwc_hc_t *hc = NULL; ++ ++ DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n"); ++ ++ grxsts.d32 = dwc_read_reg32(&_dwc_otg_hcd->core_if->core_global_regs->grxstsp); ++ ++ hc = _dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum]; ++ ++ /* Packet Status */ ++ DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum); ++ DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt); ++ DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid, hc->data_pid_start); ++ DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts); ++ ++ switch (grxsts.b.pktsts) { ++ case DWC_GRXSTS_PKTSTS_IN: ++ /* Read the data into the host buffer. */ ++ if (grxsts.b.bcnt > 0) { ++ dwc_otg_read_packet(_dwc_otg_hcd->core_if, ++ hc->xfer_buff, ++ grxsts.b.bcnt); ++ ++ /* Update the HC fields for the next packet received. */ ++ hc->xfer_count += grxsts.b.bcnt; ++ hc->xfer_buff += grxsts.b.bcnt; ++ } ++ ++ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: ++ case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR: ++ case DWC_GRXSTS_PKTSTS_CH_HALTED: ++ /* Handled in interrupt, just ignore data */ ++ break; ++ default: ++ DWC_ERROR ("RX_STS_Q Interrupt: Unknown status %d\n", grxsts.b.pktsts); ++ break; ++ } ++ ++ return 1; ++} ++ ++/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More ++ * data packets may be written to the FIFO for OUT transfers. More requests ++ * may be written to the non-periodic request queue for IN transfers. This ++ * interrupt is enabled only in Slave mode. */ ++int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n"); ++ dwc_otg_hcd_queue_transactions(_dwc_otg_hcd, ++ DWC_OTG_TRANSACTION_NON_PERIODIC); ++ return 1; ++} ++ ++/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data ++ * packets may be written to the FIFO for OUT transfers. More requests may be ++ * written to the periodic request queue for IN transfers. This interrupt is ++ * enabled only in Slave mode. */ ++int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n"); ++ dwc_otg_hcd_queue_transactions(_dwc_otg_hcd, ++ DWC_OTG_TRANSACTION_PERIODIC); ++ return 1; ++} ++ ++/** There are multiple conditions that can cause a port interrupt. This function ++ * determines which interrupt conditions have occurred and handles them ++ * appropriately. */ ++int32_t dwc_otg_hcd_handle_port_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ int retval = 0; ++ hprt0_data_t hprt0; ++ hprt0_data_t hprt0_modify; ++ ++ hprt0.d32 = dwc_read_reg32(_dwc_otg_hcd->core_if->host_if->hprt0); ++ hprt0_modify.d32 = dwc_read_reg32(_dwc_otg_hcd->core_if->host_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) { ++ DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x " ++ "Port Connect Detected--\n", hprt0.d32); ++ _dwc_otg_hcd->flags.b.port_connect_status_change = 1; ++ _dwc_otg_hcd->flags.b.port_connect_status = 1; ++ hprt0_modify.b.prtconndet = 1; ++ ++ /* B-Device has connected, Delete the connection timer. */ ++ del_timer( &_dwc_otg_hcd->conn_timer ); ++ ++ /* 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) { ++ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " ++ "Port Enable Changed--\n", hprt0.d32); ++ hprt0_modify.b.prtenchng = 1; ++ if (hprt0.b.prtena == 1) { ++ int do_reset = 0; ++ dwc_otg_core_params_t *params = _dwc_otg_hcd->core_if->core_params; ++ dwc_otg_core_global_regs_t *global_regs = _dwc_otg_hcd->core_if->core_global_regs; ++ dwc_otg_host_if_t *host_if = _dwc_otg_hcd->core_if->host_if; ++ ++ /* Check if we need to adjust the PHY clock speed for ++ * low power and adjust it */ ++ if (params->host_support_fs_ls_low_power) ++ { ++ gusbcfg_data_t usbcfg; ++ ++ usbcfg.d32 = dwc_read_reg32 (&global_regs->gusbcfg); ++ ++ if ((hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) || ++ (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_FULL_SPEED)) ++ { ++ /* ++ * Low power ++ */ ++ hcfg_data_t hcfg; ++ if (usbcfg.b.phylpwrclksel == 0) { ++ /* Set PHY low power clock select for FS/LS devices */ ++ usbcfg.b.phylpwrclksel = 1; ++ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); ++ do_reset = 1; ++ } ++ ++ hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg); ++ ++ if ((hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) && ++ (params->host_ls_low_power_phy_clk == ++ DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)) ++ { ++ /* 6 MHZ */ ++ DWC_DEBUGPL(DBG_CIL, "FS_PHY programming HCFG to 6 MHz (Low Power)\n"); ++ if (hcfg.b.fslspclksel != DWC_HCFG_6_MHZ) { ++ hcfg.b.fslspclksel = DWC_HCFG_6_MHZ; ++ dwc_write_reg32(&host_if->host_global_regs->hcfg, ++ hcfg.d32); ++ do_reset = 1; ++ } ++ } ++ else { ++ /* 48 MHZ */ ++ DWC_DEBUGPL(DBG_CIL, "FS_PHY programming HCFG to 48 MHz ()\n"); ++ if (hcfg.b.fslspclksel != DWC_HCFG_48_MHZ) { ++ hcfg.b.fslspclksel = DWC_HCFG_48_MHZ; ++ dwc_write_reg32(&host_if->host_global_regs->hcfg, ++ hcfg.d32); ++ do_reset = 1; ++ } ++ } ++ } ++ else { ++ /* ++ * Not low power ++ */ ++ if (usbcfg.b.phylpwrclksel == 1) { ++ usbcfg.b.phylpwrclksel = 0; ++ dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32); ++ do_reset = 1; ++ } ++ } ++ ++ if (do_reset) { ++ tasklet_schedule(_dwc_otg_hcd->reset_tasklet); ++ } ++ } ++ ++ if (!do_reset) { ++ /* Port has been enabled set the reset change flag */ ++ _dwc_otg_hcd->flags.b.port_reset_change = 1; ++ } ++ ++ } else { ++ _dwc_otg_hcd->flags.b.port_enable_change = 1; ++ } ++ retval |= 1; ++ } ++ ++ /** Overcurrent Change Interrupt */ ++ if (hprt0.b.prtovrcurrchng) { ++ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " ++ "Port Overcurrent Changed--\n", hprt0.d32); ++ _dwc_otg_hcd->flags.b.port_over_current_change = 1; ++ hprt0_modify.b.prtovrcurrchng = 1; ++ retval |= 1; ++ } ++ ++ /* Clear Port Interrupts */ ++ dwc_write_reg32(_dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32); ++ ++ return retval; ++} ++ ++ ++/** This interrupt indicates that one or more 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 each ++ * host channel interrupt and handles them appropriately. */ ++int32_t dwc_otg_hcd_handle_hc_intr (dwc_otg_hcd_t *_dwc_otg_hcd) ++{ ++ int i; ++ int retval = 0; ++ haint_data_t haint; ++ ++ /* Clear appropriate bits in HCINTn to clear the interrupt bit in ++ * GINTSTS */ ++ ++ haint.d32 = dwc_otg_read_host_all_channels_intr(_dwc_otg_hcd->core_if); ++ ++ for (i=0; i<_dwc_otg_hcd->core_if->core_params->host_channels; i++) { ++ if (haint.b2.chint & (1 << i)) { ++ retval |= dwc_otg_hcd_handle_hc_n_intr (_dwc_otg_hcd, i); ++ } ++ } ++ ++ return retval; ++} ++ ++/* 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; \ ++ dwc_write_reg32(&((_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 { \ ++ hcintmsk_data_t hcintmsk = {.d32 = 0}; \ ++ hcintmsk.b._intr_ = 1; \ ++ dwc_modify_reg32(&((_hc_regs_)->hcintmsk), hcintmsk.d32, 0); \ ++} while (0) ++ ++/** ++ * Gets the actual length of a transfer after the transfer halts. _halt_status ++ * holds the reason for the halt. ++ * ++ * For IN transfers where _halt_status is DWC_OTG_HC_XFER_COMPLETE, ++ * *_short_read is set to 1 upon return if less than the requested ++ * number of bytes were transferred. Otherwise, *_short_read is set to 0 upon ++ * return. _short_read may also be NULL on entry, in which case it remains ++ * unchanged. ++ */ ++static uint32_t get_actual_xfer_length(dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status, ++ int *_short_read) ++{ ++ hctsiz_data_t hctsiz; ++ uint32_t length; ++ ++ if (_short_read != NULL) { ++ *_short_read = 0; ++ } ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ ++ if (_halt_status == DWC_OTG_HC_XFER_COMPLETE) { ++ if (_hc->ep_is_in) { ++ length = _hc->xfer_len - hctsiz.b.xfersize; ++ if (_short_read != NULL) { ++ *_short_read = (hctsiz.b.xfersize != 0); ++ } ++ } else if (_hc->qh->do_split) { ++ length = _qtd->ssplit_out_xfer_count; ++ } else { ++ length = _hc->xfer_len; ++ } ++ } else { ++ /* ++ * Must use the hctsiz.pktcnt field to determine how much data ++ * has been transferred. This field reflects the number of ++ * packets that have been transferred via the USB. This is ++ * always an integral number of packets if the transfer was ++ * halted before its normal completion. (Can't use the ++ * hctsiz.xfersize field because that reflects the number of ++ * bytes transferred via the AHB, not the USB). ++ */ ++ length = (_hc->start_pkt_count - hctsiz.b.pktcnt) * _hc->max_packet; ++ } ++ ++ return length; ++} ++ ++/** ++ * 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(dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t * _hc_regs, struct urb *_urb, ++ dwc_otg_qtd_t * _qtd, int *status) ++{ ++ int xfer_done = 0; ++ int short_read = 0; ++ ++ _urb->actual_length += get_actual_xfer_length(_hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_COMPLETE, ++ &short_read); ++ ++ if (short_read || (_urb->actual_length == _urb->transfer_buffer_length)) { ++ xfer_done = 1; ++ if (short_read && (_urb->transfer_flags & URB_SHORT_NOT_OK)) { ++ *status = -EREMOTEIO; ++ } else { ++ *status = 0; ++ } ++ } ++ ++#ifdef DEBUG ++ { ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n", ++ __func__, (_hc->ep_is_in ? "IN" : "OUT"), _hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", _hc->xfer_len); ++ DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n", hctsiz.b.xfersize); ++ DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", ++ _urb->transfer_buffer_length); ++ DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", _urb->actual_length); ++ DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n", ++ short_read, xfer_done); ++ } ++#endif ++ ++ return xfer_done; ++} ++ ++/* ++ * 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. ++ */ ++static void save_data_toggle(dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd) ++{ ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ ++ if (_hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) { ++ dwc_otg_qh_t *qh = _hc->qh; ++ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) { ++ qh->data_toggle = DWC_OTG_HC_PID_DATA0; ++ } else { ++ qh->data_toggle = DWC_OTG_HC_PID_DATA1; ++ } ++ } else { ++ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) { ++ _qtd->data_toggle = DWC_OTG_HC_PID_DATA0; ++ } else { ++ _qtd->data_toggle = DWC_OTG_HC_PID_DATA1; ++ } ++ } ++} ++ ++/** ++ * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic ++ * QHs, removes the QH from the active non-periodic schedule. If any QTDs are ++ * still linked to the QH, the QH is added to the end of the inactive ++ * non-periodic schedule. For periodic QHs, removes the QH from the periodic ++ * schedule if no more QTDs are linked to the QH. ++ */ ++static void deactivate_qh(dwc_otg_hcd_t *_hcd, ++ dwc_otg_qh_t *_qh, ++ int free_qtd) ++{ ++ int continue_split = 0; ++ dwc_otg_qtd_t *qtd; ++ ++ DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, _hcd, _qh, free_qtd); ++ ++ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); ++ ++ if (qtd->complete_split) { ++ continue_split = 1; ++ } ++ else if ((qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID) || ++ (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END)) ++ { ++ continue_split = 1; ++ } ++ ++ if (free_qtd) { ++ /* ++ * Note that this was previously a call to ++ * dwc_otg_hcd_qtd_remove_and_free(qtd), which frees the qtd. ++ * However, that call frees the qtd memory, and we continue in the ++ * interrupt logic to access it many more times, including writing ++ * to it. With slub debugging on, it is clear that we were writing ++ * to memory we had freed. ++ * Call this instead, and now I have moved the freeing of the memory to ++ * the end of processing this interrupt. ++ */ ++ //dwc_otg_hcd_qtd_remove_and_free(qtd); ++ dwc_otg_hcd_qtd_remove(qtd); ++ ++ continue_split = 0; ++ } ++ ++ _qh->channel = NULL; ++ _qh->qtd_in_process = NULL; ++ dwc_otg_hcd_qh_deactivate(_hcd, _qh, continue_split); ++} ++ ++/** ++ * Updates the state of an Isochronous URB when the transfer is stopped for ++ * any reason. The fields of the current entry in the frame descriptor array ++ * are set based on the transfer state and the input _halt_status. Completes ++ * the Isochronous URB if all the URB frames have been completed. ++ * ++ * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be ++ * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE. ++ */ ++static dwc_otg_halt_status_e ++update_isoc_urb_state(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status) ++{ ++ struct urb *urb = _qtd->urb; ++ dwc_otg_halt_status_e ret_val = _halt_status; ++ struct usb_iso_packet_descriptor *frame_desc; ++ ++ frame_desc = &urb->iso_frame_desc[_qtd->isoc_frame_index]; ++ switch (_halt_status) { ++ case DWC_OTG_HC_XFER_COMPLETE: ++ frame_desc->status = 0; ++ frame_desc->actual_length = ++ get_actual_xfer_length(_hc, _hc_regs, _qtd, ++ _halt_status, NULL); ++ break; ++ case DWC_OTG_HC_XFER_FRAME_OVERRUN: ++ urb->error_count++; ++ if (_hc->ep_is_in) { ++ frame_desc->status = -ENOSR; ++ } else { ++ frame_desc->status = -ECOMM; ++ } ++ frame_desc->actual_length = 0; ++ break; ++ case DWC_OTG_HC_XFER_BABBLE_ERR: ++ urb->error_count++; ++ frame_desc->status = -EOVERFLOW; ++ /* Don't need to update actual_length in this case. */ ++ break; ++ case DWC_OTG_HC_XFER_XACT_ERR: ++ urb->error_count++; ++ frame_desc->status = -EPROTO; ++ frame_desc->actual_length = ++ get_actual_xfer_length(_hc, _hc_regs, _qtd, ++ _halt_status, NULL); ++ default: ++ DWC_ERROR("%s: Unhandled _halt_status (%d)\n", __func__, ++ _halt_status); ++ BUG(); ++ break; ++ } ++ ++ if (++_qtd->isoc_frame_index == urb->number_of_packets) { ++ /* ++ * urb->status is not used for isoc transfers. ++ * The individual frame_desc statuses are used instead. ++ */ ++ dwc_otg_hcd_complete_urb(_hcd, urb, 0); ++ ret_val = DWC_OTG_HC_XFER_URB_COMPLETE; ++ } else { ++ ret_val = DWC_OTG_HC_XFER_COMPLETE; ++ } ++ ++ return ret_val; ++} ++ ++/** ++ * Releases a host channel for use by other transfers. Attempts to select and ++ * queue more transactions since at least one host channel is available. ++ * ++ * @param _hcd The HCD state structure. ++ * @param _hc The host channel to release. ++ * @param _qtd The QTD associated with the host channel. This QTD may be freed ++ * if the transfer is complete or an error has occurred. ++ * @param _halt_status Reason the channel is being released. This status ++ * determines the actions taken by this function. ++ */ ++static void release_channel(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status, ++ int *must_free) ++{ ++ dwc_otg_transaction_type_e tr_type; ++ int free_qtd; ++ dwc_otg_qh_t * _qh; ++ int deact = 1; ++ int retry_delay = 1; ++ unsigned long flags; ++ ++ DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n", __func__, ++ _hc->hc_num, _halt_status); ++ ++ switch (_halt_status) { ++ case DWC_OTG_HC_XFER_NYET: ++ case DWC_OTG_HC_XFER_NAK: ++ if (_halt_status == DWC_OTG_HC_XFER_NYET) { ++ retry_delay = nyet_deferral_delay; ++ } else { ++ retry_delay = nak_deferral_delay; ++ } ++ free_qtd = 0; ++ if (deferral_on && _hc->do_split) { ++ _qh = _hc->qh; ++ if (_qh) { ++ deact = dwc_otg_hcd_qh_deferr(_hcd, _qh , retry_delay); ++ } ++ } ++ break; ++ case DWC_OTG_HC_XFER_URB_COMPLETE: ++ free_qtd = 1; ++ break; ++ case DWC_OTG_HC_XFER_AHB_ERR: ++ case DWC_OTG_HC_XFER_STALL: ++ case DWC_OTG_HC_XFER_BABBLE_ERR: ++ free_qtd = 1; ++ break; ++ case DWC_OTG_HC_XFER_XACT_ERR: ++ if (_qtd->error_count >= 3) { ++ DWC_DEBUGPL(DBG_HCDV, " Complete URB with transaction error\n"); ++ free_qtd = 1; ++ //_qtd->urb->status = -EPROTO; ++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPROTO); ++ } else { ++ free_qtd = 0; ++ } ++ break; ++ case DWC_OTG_HC_XFER_URB_DEQUEUE: ++ /* ++ * The QTD has already been removed and the QH has been ++ * deactivated. Don't want to do anything except release the ++ * host channel and try to queue more transfers. ++ */ ++ goto cleanup; ++ case DWC_OTG_HC_XFER_NO_HALT_STATUS: ++ DWC_ERROR("%s: No halt_status, channel %d\n", __func__, _hc->hc_num); ++ free_qtd = 0; ++ break; ++ default: ++ free_qtd = 0; ++ break; ++ } ++ if (free_qtd) { ++ /* Only change must_free to true (do not set to zero here -- it is ++ * pre-initialized to zero). ++ */ ++ *must_free = 1; ++ } ++ if (deact) { ++ deactivate_qh(_hcd, _hc->qh, free_qtd); ++ } ++ cleanup: ++ /* ++ * Release the host channel for use by other transfers. The cleanup ++ * function clears the channel interrupt enables and conditions, so ++ * there's no need to clear the Channel Halted interrupt separately. ++ */ ++ dwc_otg_hc_cleanup(_hcd->core_if, _hc); ++ list_add_tail(&_hc->hc_list_entry, &_hcd->free_hc_list); ++ ++ local_irq_save(flags); ++ _hcd->available_host_channels++; ++ local_irq_restore(flags); ++ /* Try to queue more transfers now that there's a free channel, */ ++ /* unless erratum_usb09_patched is set */ ++ if (!erratum_usb09_patched) { ++ tr_type = dwc_otg_hcd_select_transactions(_hcd); ++ if (tr_type != DWC_OTG_TRANSACTION_NONE) { ++ dwc_otg_hcd_queue_transactions(_hcd, tr_type); ++ } ++ } ++} ++ ++/** ++ * Halts a host channel. If the channel cannot be halted immediately because ++ * the request queue is full, this function ensures that the FIFO empty ++ * interrupt for the appropriate queue is enabled so that the halt request can ++ * be queued when there is space in the request queue. ++ * ++ * This function may also be called in DMA mode. In that case, the channel is ++ * simply released since the core always halts the channel automatically in ++ * DMA mode. ++ */ ++static void halt_channel(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status, int *must_free) ++{ ++ if (_hcd->core_if->dma_enable) { ++ release_channel(_hcd, _hc, _qtd, _halt_status, must_free); ++ return; ++ } ++ ++ /* Slave mode processing... */ ++ dwc_otg_hc_halt(_hcd->core_if, _hc, _halt_status); ++ ++ if (_hc->halt_on_queue) { ++ gintmsk_data_t gintmsk = {.d32 = 0}; ++ dwc_otg_core_global_regs_t *global_regs; ++ global_regs = _hcd->core_if->core_global_regs; ++ ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || ++ _hc->ep_type == DWC_OTG_EP_TYPE_BULK) { ++ /* ++ * Make sure the Non-periodic Tx FIFO empty interrupt ++ * is enabled so that the non-periodic schedule will ++ * be processed. ++ */ ++ gintmsk.b.nptxfempty = 1; ++ dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32); ++ } else { ++ /* ++ * Move the QH from the periodic queued schedule to ++ * the periodic assigned schedule. This allows the ++ * halt to be queued when the periodic schedule is ++ * processed. ++ */ ++ list_move(&_hc->qh->qh_list_entry, ++ &_hcd->periodic_sched_assigned); ++ ++ /* ++ * Make sure the Periodic Tx FIFO Empty interrupt is ++ * enabled so that the periodic schedule will be ++ * processed. ++ */ ++ gintmsk.b.ptxfempty = 1; ++ dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32); ++ } ++ } ++} ++ ++/** ++ * Performs common cleanup for non-periodic transfers after a Transfer ++ * Complete interrupt. This function should be called after any endpoint type ++ * specific handling is finished to release the host channel. ++ */ ++static void complete_non_periodic_xfer(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status, int *must_free) ++{ ++ hcint_data_t hcint; ++ ++ _qtd->error_count = 0; ++ ++ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint); ++ if (hcint.b.nyet) { ++ /* ++ * Got a NYET on the last transaction of the transfer. This ++ * means that the endpoint should be in the PING state at the ++ * beginning of the next transfer. ++ */ ++ _hc->qh->ping_state = 1; ++ clear_hc_int(_hc_regs,nyet); ++ } ++ ++ /* ++ * Always halt and release the host channel to make it available for ++ * more transfers. There may still be more phases for a control ++ * transfer or more data packets for a bulk transfer at this point, ++ * but the host channel is still halted. A channel will be reassigned ++ * to the transfer when the non-periodic schedule is processed after ++ * the channel is released. This allows transactions to be queued ++ * properly via dwc_otg_hcd_queue_transactions, which also enables the ++ * Tx FIFO Empty interrupt if necessary. ++ */ ++ if (_hc->ep_is_in) { ++ /* ++ * IN transfers in Slave mode require an explicit disable to ++ * halt the channel. (In DMA mode, this call simply releases ++ * the channel.) ++ */ ++ halt_channel(_hcd, _hc, _qtd, _halt_status, must_free); ++ } else { ++ /* ++ * The channel is automatically disabled by the core for OUT ++ * transfers in Slave mode. ++ */ ++ release_channel(_hcd, _hc, _qtd, _halt_status, must_free); ++ } ++} ++ ++/** ++ * Performs common cleanup for periodic transfers after a Transfer Complete ++ * interrupt. This function should be called after any endpoint type specific ++ * handling is finished to release the host channel. ++ */ ++static void complete_periodic_xfer(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status, int *must_free) ++{ ++ hctsiz_data_t hctsiz; ++ _qtd->error_count = 0; ++ ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ if (!_hc->ep_is_in || hctsiz.b.pktcnt == 0) { ++ /* Core halts channel in these cases. */ ++ release_channel(_hcd, _hc, _qtd, _halt_status, must_free); ++ } else { ++ /* Flush any outstanding requests from the Tx queue. */ ++ halt_channel(_hcd, _hc, _qtd, _halt_status, must_free); ++ } ++} ++ ++/** ++ * Handles a host channel Transfer Complete interrupt. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, int *must_free) ++{ ++ int urb_xfer_done; ++ dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ struct urb *urb = _qtd->urb; ++ int pipe_type = usb_pipetype(urb->pipe); ++ int status = -EINPROGRESS; ++ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Transfer Complete--\n", _hc->hc_num); ++ ++ /* ++ * Handle xfer complete on CSPLIT. ++ */ ++ if (_hc->qh->do_split) { ++ _qtd->complete_split = 0; ++ } ++ ++ /* Update the QTD and URB states. */ ++ switch (pipe_type) { ++ case PIPE_CONTROL: ++ switch (_qtd->control_phase) { ++ case DWC_OTG_CONTROL_SETUP: ++ if (urb->transfer_buffer_length > 0) { ++ _qtd->control_phase = DWC_OTG_CONTROL_DATA; ++ } else { ++ _qtd->control_phase = DWC_OTG_CONTROL_STATUS; ++ } ++ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n"); ++ halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ break; ++ case DWC_OTG_CONTROL_DATA: { ++ urb_xfer_done = update_urb_state_xfer_comp(_hc, _hc_regs,urb, _qtd, &status); ++ if (urb_xfer_done) { ++ _qtd->control_phase = DWC_OTG_CONTROL_STATUS; ++ DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n"); ++ } else { ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ } ++ halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ break; ++ } ++ case DWC_OTG_CONTROL_STATUS: ++ DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n"); ++ if (status == -EINPROGRESS) { ++ status = 0; ++ } ++ dwc_otg_hcd_complete_urb(_hcd, urb, status); ++ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE; ++ break; ++ } ++ ++ complete_non_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, ++ halt_status, must_free); ++ break; ++ case PIPE_BULK: ++ DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n"); ++ urb_xfer_done = update_urb_state_xfer_comp(_hc, _hc_regs, urb, _qtd, &status); ++ if (urb_xfer_done) { ++ dwc_otg_hcd_complete_urb(_hcd, urb, status); ++ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE; ++ } else { ++ halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ } ++ ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ complete_non_periodic_xfer(_hcd, _hc, _hc_regs, _qtd,halt_status, must_free); ++ break; ++ case PIPE_INTERRUPT: ++ DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n"); ++ update_urb_state_xfer_comp(_hc, _hc_regs, urb, _qtd, &status); ++ ++ /* ++ * Interrupt URB is done on the first transfer complete ++ * interrupt. ++ */ ++ dwc_otg_hcd_complete_urb(_hcd, urb, status); ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ complete_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_URB_COMPLETE, must_free); ++ break; ++ case PIPE_ISOCHRONOUS: ++ DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n"); ++ if (_qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) ++ { ++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_COMPLETE); ++ } ++ complete_periodic_xfer(_hcd, _hc, _hc_regs, _qtd, halt_status, must_free); ++ break; ++ } ++ ++ disable_hc_int(_hc_regs,xfercompl); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel STALL interrupt. This handler may be called in ++ * either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_stall_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, int *must_free) ++{ ++ struct urb *urb = _qtd->urb; ++ int pipe_type = usb_pipetype(urb->pipe); ++ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "STALL Received--\n", _hc->hc_num); ++ ++ if (pipe_type == PIPE_CONTROL) { ++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPIPE); ++ } ++ ++ if (pipe_type == PIPE_BULK || pipe_type == PIPE_INTERRUPT) { ++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPIPE); ++ /* ++ * USB protocol requires resetting the data toggle for bulk ++ * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT) ++ * setup command is issued to the endpoint. Anticipate the ++ * CLEAR_FEATURE command since a STALL has occurred and reset ++ * the data toggle now. ++ */ ++ _hc->qh->data_toggle = 0; ++ } ++ ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_STALL, must_free); ++ disable_hc_int(_hc_regs,stall); ++ ++ return 1; ++} ++ ++/* ++ * Updates the state of the URB when a transfer has been stopped due to an ++ * abnormal condition before the transfer completes. Modifies the ++ * actual_length field of the URB to reflect the number of bytes that have ++ * actually been transferred via the host channel. ++ */ ++static void update_urb_state_xfer_intr(dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ struct urb *_urb, ++ dwc_otg_qtd_t *_qtd, ++ dwc_otg_halt_status_e _halt_status) ++{ ++ uint32_t bytes_transferred = get_actual_xfer_length(_hc, _hc_regs, _qtd, ++ _halt_status, NULL); ++ _urb->actual_length += bytes_transferred; ++ ++#ifdef DEBUG ++ { ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n", ++ __func__, (_hc->ep_is_in ? "IN" : "OUT"), _hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " _hc->start_pkt_count %d\n", _hc->start_pkt_count); ++ DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt); ++ DWC_DEBUGPL(DBG_HCDV, " _hc->max_packet %d\n", _hc->max_packet); ++ DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n", bytes_transferred); ++ DWC_DEBUGPL(DBG_HCDV, " _urb->actual_length %d\n", _urb->actual_length); ++ DWC_DEBUGPL(DBG_HCDV, " _urb->transfer_buffer_length %d\n", ++ _urb->transfer_buffer_length); ++ } ++#endif ++} ++ ++/** ++ * Handles a host channel NAK interrupt. This handler may be called in either ++ * DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_nak_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "NAK Received--\n", _hc->hc_num); ++ ++ /* ++ * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and ++ * interrupt. Re-start the SSPLIT transfer. ++ */ ++ if (_hc->do_split) { ++ if (_hc->complete_split) { ++ _qtd->error_count = 0; ++ } ++ _qtd->complete_split = 0; ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK, must_free); ++ goto handle_nak_done; ++ } ++ ++ switch (usb_pipetype(_qtd->urb->pipe)) { ++ case PIPE_CONTROL: ++ case PIPE_BULK: ++ if (_hcd->core_if->dma_enable && _hc->ep_is_in) { ++ /* ++ * NAK interrupts are enabled on bulk/control IN ++ * transfers in DMA mode for the sole purpose of ++ * resetting the error count after a transaction error ++ * occurs. The core will continue transferring data. ++ */ ++ _qtd->error_count = 0; ++ goto handle_nak_done; ++ } ++ ++ /* ++ * NAK interrupts normally occur during OUT transfers in DMA ++ * or Slave mode. For IN transfers, more requests will be ++ * queued as request queue space is available. ++ */ ++ _qtd->error_count = 0; ++ ++ if (!_hc->qh->ping_state) { ++ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb, ++ _qtd, DWC_OTG_HC_XFER_NAK); ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ if (_qtd->urb->dev->speed == USB_SPEED_HIGH) { ++ _hc->qh->ping_state = 1; ++ } ++ } ++ ++ /* ++ * Halt the channel so the transfer can be re-started from ++ * the appropriate point or the PING protocol will ++ * start/continue. ++ */ ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK, must_free); ++ break; ++ case PIPE_INTERRUPT: ++ _qtd->error_count = 0; ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NAK, must_free); ++ break; ++ case PIPE_ISOCHRONOUS: ++ /* Should never get called for isochronous transfers. */ ++ BUG(); ++ break; ++ } ++ ++ handle_nak_done: ++ disable_hc_int(_hc_regs,nak); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel ACK interrupt. This interrupt is enabled when ++ * performing the PING protocol in Slave mode, when errors occur during ++ * either Slave mode or DMA mode, and during Start Split transactions. ++ */ ++static int32_t handle_hc_ack_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "ACK Received--\n", _hc->hc_num); ++ ++ if (_hc->do_split) { ++ /* ++ * Handle ACK on SSPLIT. ++ * ACK should not occur in CSPLIT. ++ */ ++ if ((!_hc->ep_is_in) && (_hc->data_pid_start != DWC_OTG_HC_PID_SETUP)) { ++ _qtd->ssplit_out_xfer_count = _hc->xfer_len; ++ } ++ if (!(_hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !_hc->ep_is_in)) { ++ /* Don't need complete for isochronous out transfers. */ ++ _qtd->complete_split = 1; ++ } ++ ++ /* ISOC OUT */ ++ if ((_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && !_hc->ep_is_in) { ++ switch (_hc->xact_pos) { ++ case DWC_HCSPLIT_XACTPOS_ALL: ++ break; ++ case DWC_HCSPLIT_XACTPOS_END: ++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL; ++ _qtd->isoc_split_offset = 0; ++ break; ++ case DWC_HCSPLIT_XACTPOS_BEGIN: ++ case DWC_HCSPLIT_XACTPOS_MID: ++ /* ++ * For BEGIN or MID, calculate the length for ++ * the next microframe to determine the correct ++ * SSPLIT token, either MID or END. ++ */ ++ do { ++ struct usb_iso_packet_descriptor *frame_desc; ++ ++ frame_desc = &_qtd->urb->iso_frame_desc[_qtd->isoc_frame_index]; ++ _qtd->isoc_split_offset += 188; ++ ++ if ((frame_desc->length - _qtd->isoc_split_offset) <= 188) { ++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_END; ++ } ++ else { ++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_MID; ++ } ++ ++ } while(0); ++ break; ++ } ++ } else { ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK, must_free); ++ } ++ } else { ++ _qtd->error_count = 0; ++ ++ if (_hc->qh->ping_state) { ++ _hc->qh->ping_state = 0; ++ /* ++ * Halt the channel so the transfer can be re-started ++ * from the appropriate point. This only happens in ++ * Slave mode. In DMA mode, the ping_state is cleared ++ * when the transfer is started because the core ++ * 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); ++ } ++ } ++ ++ /* ++ * If the ACK occurred when _not_ in the PING state, let the channel ++ * continue transferring data after clearing the error count. ++ */ ++ ++ disable_hc_int(_hc_regs,ack); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel NYET interrupt. This interrupt should only occur on ++ * Bulk and Control OUT endpoints and for complete split transactions. If a ++ * NYET occurs at the same time as a Transfer Complete interrupt, it is ++ * handled in the xfercomp interrupt handler, not here. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "NYET Received--\n", _hc->hc_num); ++ ++ /* ++ * NYET on CSPLIT ++ * re-do the CSPLIT immediately on non-periodic ++ */ ++ if ((_hc->do_split) && (_hc->complete_split)) { ++ if ((_hc->ep_type == DWC_OTG_EP_TYPE_INTR) || ++ (_hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) { ++ int frnum = dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd)); ++ ++ if (dwc_full_frame_num(frnum) != ++ dwc_full_frame_num(_hc->qh->sched_frame)) { ++ /* ++ * No longer in the same full speed frame. ++ * Treat this as a transaction error. ++ */ ++#if 0 ++ /** @todo Fix system performance so this can ++ * be treated as an error. Right now complete ++ * splits cannot be scheduled precisely enough ++ * due to other system activity, so this error ++ * occurs regularly in Slave mode. ++ */ ++ _qtd->error_count++; ++#endif ++ _qtd->complete_split = 0; ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR, must_free); ++ /** @todo add support for isoc release */ ++ goto handle_nyet_done; ++ } ++ } ++ ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NYET, must_free); ++ goto handle_nyet_done; ++ } ++ ++ _hc->qh->ping_state = 1; ++ _qtd->error_count = 0; ++ ++ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb, _qtd, ++ DWC_OTG_HC_XFER_NYET); ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ ++ /* ++ * Halt the channel and re-start the transfer so the PING ++ * protocol will start. ++ */ ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NYET, must_free); ++ ++handle_nyet_done: ++ disable_hc_int(_hc_regs,nyet); ++ clear_hc_int(_hc_regs, nyet); ++ return 1; ++} ++ ++/** ++ * Handles a host channel babble interrupt. This handler may be called in ++ * either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_babble_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Babble Error--\n", _hc->hc_num); ++ if (_hc->ep_type != DWC_OTG_EP_TYPE_ISOC) { ++ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EOVERFLOW); ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_BABBLE_ERR, must_free); ++ } else { ++ dwc_otg_halt_status_e halt_status; ++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_BABBLE_ERR); ++ halt_channel(_hcd, _hc, _qtd, halt_status, must_free); ++ } ++ disable_hc_int(_hc_regs,bblerr); ++ return 1; ++} ++ ++/** ++ * Handles a host channel AHB error interrupt. This handler is only called in ++ * DMA mode. ++ */ ++static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t *_hc, ++ dwc_otg_hc_regs_t *_hc_regs, ++ dwc_otg_qtd_t *_qtd) ++{ ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ hctsiz_data_t hctsiz; ++ uint32_t hcdma; ++ struct urb *urb = _qtd->urb; ++ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "AHB Error--\n", _hc->hc_num); ++ ++ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar); ++ hcsplt.d32 = dwc_read_reg32(&_hc_regs->hcsplt); ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ hcdma = dwc_read_reg32(&_hc_regs->hcdma); ++ ++ DWC_ERROR("AHB ERROR, Channel %d\n", _hc->hc_num); ++ DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); ++ DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n"); ++ DWC_ERROR(" Device address: %d\n", usb_pipedevice(urb->pipe)); ++ DWC_ERROR(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), ++ (usb_pipein(urb->pipe) ? "IN" : "OUT")); ++ DWC_ERROR(" 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;})); ++ DWC_ERROR(" 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;})); ++ DWC_ERROR(" Max packet size: %d\n", ++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); ++ DWC_ERROR(" Data buffer length: %d\n", urb->transfer_buffer_length); ++ DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n", ++ urb->transfer_buffer, (void *)(u32)urb->transfer_dma); ++ DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n", ++ urb->setup_packet, (void *)(u32)urb->setup_dma); ++ DWC_ERROR(" Interval: %d\n", urb->interval); ++ ++ dwc_otg_hcd_complete_urb(_hcd, urb, -EIO); ++ ++ /* ++ * Force a channel halt. Don't call halt_channel because that won't ++ * write to the HCCHARn register in DMA mode to force the halt. ++ */ ++ dwc_otg_hc_halt(_hcd->core_if, _hc, DWC_OTG_HC_XFER_AHB_ERR); ++ ++ disable_hc_int(_hc_regs,ahberr); ++ return 1; ++} ++ ++/** ++ * Handles a host channel transaction error interrupt. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Transaction Error--\n", _hc->hc_num); ++ ++ switch (usb_pipetype(_qtd->urb->pipe)) { ++ case PIPE_CONTROL: ++ case PIPE_BULK: ++ _qtd->error_count++; ++ if (!_hc->qh->ping_state) { ++ update_urb_state_xfer_intr(_hc, _hc_regs, _qtd->urb, ++ _qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ save_data_toggle(_hc, _hc_regs, _qtd); ++ if (!_hc->ep_is_in && _qtd->urb->dev->speed == USB_SPEED_HIGH) { ++ _hc->qh->ping_state = 1; ++ } ++ } ++ ++ /* ++ * Halt the channel so the transfer can be re-started from ++ * the appropriate point or the PING protocol will start. ++ */ ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR, must_free); ++ break; ++ case PIPE_INTERRUPT: ++ _qtd->error_count++; ++ if ((_hc->do_split) && (_hc->complete_split)) { ++ _qtd->complete_split = 0; ++ } ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_XACT_ERR, must_free); ++ break; ++ case PIPE_ISOCHRONOUS: ++ { ++ dwc_otg_halt_status_e halt_status; ++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_XACT_ERR); ++ ++ halt_channel(_hcd, _hc, _qtd, halt_status, must_free); ++ } ++ break; ++ } ++ ++ ++ disable_hc_int(_hc_regs,xacterr); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel frame overrun interrupt. This handler may be called ++ * in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Frame Overrun--\n", _hc->hc_num); ++ ++ switch (usb_pipetype(_qtd->urb->pipe)) { ++ case PIPE_CONTROL: ++ case PIPE_BULK: ++ break; ++ case PIPE_INTERRUPT: ++ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN, must_free); ++ break; ++ case PIPE_ISOCHRONOUS: ++ { ++ dwc_otg_halt_status_e halt_status; ++ halt_status = update_isoc_urb_state(_hcd, _hc, _hc_regs, _qtd, ++ DWC_OTG_HC_XFER_FRAME_OVERRUN); ++ ++ halt_channel(_hcd, _hc, _qtd, halt_status, must_free); ++ } ++ break; ++ } ++ ++ disable_hc_int(_hc_regs,frmovrun); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel data toggle error interrupt. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Data Toggle Error--\n", _hc->hc_num); ++ ++ if (_hc->ep_is_in) { ++ _qtd->error_count = 0; ++ } else { ++ DWC_ERROR("Data Toggle Error on OUT transfer," ++ "channel %d\n", _hc->hc_num); ++ } ++ ++ disable_hc_int(_hc_regs,datatglerr); ++ ++ return 1; ++} ++ ++#ifdef DEBUG ++/** ++ * This function is for debug only. It checks that a valid halt status is set ++ * and that HCCHARn.chdis is clear. If there's a problem, corrective action is ++ * taken and a warning is issued. ++ * @return 1 if halt status is ok, 0 otherwise. ++ */ ++static inline int halt_status_ok(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ hcchar_data_t hcchar; ++ hctsiz_data_t hctsiz; ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; ++ hcsplt_data_t hcsplt; ++ ++ if (_hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) { ++ /* ++ * This code is here only as a check. This condition should ++ * never happen. Ignore the halt if it does occur. ++ */ ++ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar); ++ hctsiz.d32 = dwc_read_reg32(&_hc_regs->hctsiz); ++ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint); ++ hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk); ++ hcsplt.d32 = dwc_read_reg32(&_hc_regs->hcsplt); ++ DWC_WARN("%s: _hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, " ++ "channel %d, hcchar 0x%08x, hctsiz 0x%08x, " ++ "hcint 0x%08x, hcintmsk 0x%08x, " ++ "hcsplt 0x%08x, qtd->complete_split %d\n", ++ __func__, _hc->hc_num, hcchar.d32, hctsiz.d32, ++ hcint.d32, hcintmsk.d32, ++ hcsplt.d32, _qtd->complete_split); ++ ++ DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n", ++ __func__, _hc->hc_num); ++ DWC_WARN("\n"); ++ clear_hc_int(_hc_regs,chhltd); ++ return 0; ++ } ++ ++ /* ++ * This code is here only as a check. hcchar.chdis should ++ * never be set when the halt interrupt occurs. Halt the ++ * channel again if it does occur. ++ */ ++ hcchar.d32 = dwc_read_reg32(&_hc_regs->hcchar); ++ if (hcchar.b.chdis) { ++ DWC_WARN("%s: hcchar.chdis set unexpectedly, " ++ "hcchar 0x%08x, trying to halt again\n", ++ __func__, hcchar.d32); ++ clear_hc_int(_hc_regs,chhltd); ++ _hc->halt_pending = 0; ++ halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); ++ return 0; ++ } ++ ++ return 1; ++} ++#endif ++ ++/** ++ * Handles a host Channel Halted interrupt in DMA mode. This handler ++ * determines the reason the channel halted and proceeds accordingly. ++ */ ++static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; ++ ++ if (_hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE || ++ _hc->halt_status == DWC_OTG_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(_hcd, _hc, _qtd, _hc->halt_status, must_free); ++ return; ++ } ++ ++ /* Read the HCINTn register to determine the cause for the halt. */ ++ hcint.d32 = dwc_read_reg32(&_hc_regs->hcint); ++ hcintmsk.d32 = dwc_read_reg32(&_hc_regs->hcintmsk); ++ ++ if (hcint.b.xfercomp) { ++ /** @todo This is here because of a possible hardware bug. Spec ++ * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT ++ * interrupt w/ACK bit set should occur, but I only see the ++ * XFERCOMP bit, even with it masked out. This is a workaround ++ * for that behavior. Should fix this when hardware is fixed. ++ */ ++ if ((_hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && (!_hc->ep_is_in)) { ++ handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } ++ handle_hc_xfercomp_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.stall) { ++ handle_hc_stall_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.xacterr) { ++ /* ++ * Must handle xacterr before nak or ack. Could get a xacterr ++ * at the same time as either of these on a BULK/CONTROL OUT ++ * that started with a PING. The xacterr takes precedence. ++ */ ++ handle_hc_xacterr_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.nyet) { ++ /* ++ * Must handle nyet before nak or ack. Could get a nyet at the ++ * same time as either of those on a BULK/CONTROL OUT that ++ * started with a PING. The nyet takes precedence. ++ */ ++ handle_hc_nyet_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.bblerr) { ++ handle_hc_babble_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.frmovrun) { ++ handle_hc_frmovrun_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.datatglerr) { ++ handle_hc_datatglerr_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ _hc->qh->data_toggle = 0; ++ halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); ++ } else if (hcint.b.nak && !hcintmsk.b.nak) { ++ /* ++ * If nak is not masked, it's because a non-split IN transfer ++ * is in an error state. In that case, the nak is handled by ++ * the nak interrupt handler, not here. Handle nak here for ++ * BULK/CONTROL OUT transfers, which halt on a NAK to allow ++ * rewinding the buffer pointer. ++ */ ++ handle_hc_nak_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else if (hcint.b.ack && !hcintmsk.b.ack) { ++ /* ++ * If ack is not masked, it's because a non-split IN transfer ++ * is in an error state. In that case, the ack is handled by ++ * the ack interrupt handler, not here. Handle ack here for ++ * split transfers. Start splits halt on ACK. ++ */ ++ handle_hc_ack_intr(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else { ++ if (_hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ _hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * A periodic transfer halted with no other channel ++ * interrupts set. Assume it was halted by the core ++ * because it could not be completed in its scheduled ++ * (micro)frame. ++ */ ++#ifdef DEBUG ++ DWC_PRINT("%s: Halt channel %d (assume incomplete periodic transfer)\n", ++ __func__, _hc->hc_num); ++#endif /* */ ++ halt_channel(_hcd, _hc, _qtd, ++ DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE, must_free); ++ } else { ++#ifdef DEBUG ++ DWC_ERROR("%s: Channel %d, DMA Mode -- ChHltd set, but reason " ++ "for halting is unknown, nyet %d, hcint 0x%08x, intsts 0x%08x\n", ++ __func__, _hc->hc_num, hcint.b.nyet, hcint.d32, ++ dwc_read_reg32(&_hcd->core_if->core_global_regs->gintsts)); ++#endif ++ halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); ++ } ++ } ++} ++ ++/** ++ * Handles a host channel Channel Halted interrupt. ++ * ++ * In slave mode, this handler is called only when the driver specifically ++ * requests a halt. This occurs during handling other host channel interrupts ++ * (e.g. nak, xacterr, stall, nyet, etc.). ++ * ++ * In DMA mode, this is the interrupt that occurs when the core has finished ++ * processing a transfer on a channel. Other host channel interrupts (except ++ * ahberr) are disabled in DMA mode. ++ */ ++static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t *_hcd, ++ dwc_hc_t * _hc, dwc_otg_hc_regs_t * _hc_regs, dwc_otg_qtd_t * _qtd, int *must_free) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "Channel Halted--\n", _hc->hc_num); ++ ++ if (_hcd->core_if->dma_enable) { ++ handle_hc_chhltd_intr_dma(_hcd, _hc, _hc_regs, _qtd, must_free); ++ } else { ++#ifdef DEBUG ++ if (!halt_status_ok(_hcd, _hc, _hc_regs, _qtd, must_free)) { ++ return 1; ++ } ++#endif /* */ ++ release_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free); ++ } ++ ++ return 1; ++} ++ ++/** Handles interrupt for a specific Host Channel */ ++int32_t dwc_otg_hcd_handle_hc_n_intr (dwc_otg_hcd_t *_dwc_otg_hcd, uint32_t _num) ++{ ++ int must_free = 0; ++ int retval = 0; ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; ++ dwc_hc_t *hc; ++ dwc_otg_hc_regs_t *hc_regs; ++ dwc_otg_qtd_t *qtd; ++ ++ DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", _num); ++ ++ hc = _dwc_otg_hcd->hc_ptr_array[_num]; ++ hc_regs = _dwc_otg_hcd->core_if->host_if->hc_regs[_num]; ++ qtd = list_entry(hc->qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); ++ ++ hcint.d32 = dwc_read_reg32(&hc_regs->hcint); ++ hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk); ++ DWC_DEBUGPL(DBG_HCDV, " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", ++ hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32)); ++ hcint.d32 = hcint.d32 & hcintmsk.d32; ++ ++ if (!_dwc_otg_hcd->core_if->dma_enable) { ++ if ((hcint.b.chhltd) && (hcint.d32 != 0x2)) { ++ hcint.b.chhltd = 0; ++ } ++ } ++ ++ if (hcint.b.xfercomp) { ++ retval |= handle_hc_xfercomp_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ /* ++ * If NYET occurred at same time as Xfer Complete, the NYET is ++ * handled by the Xfer Complete interrupt handler. Don't want ++ * to call the NYET interrupt handler in this case. ++ */ ++ hcint.b.nyet = 0; ++ } ++ if (hcint.b.chhltd) { ++ retval |= handle_hc_chhltd_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.ahberr) { ++ retval |= handle_hc_ahberr_intr(_dwc_otg_hcd, hc, hc_regs, qtd); ++ } ++ if (hcint.b.stall) { ++ retval |= handle_hc_stall_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.nak) { ++ retval |= handle_hc_nak_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.ack) { ++ retval |= handle_hc_ack_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.nyet) { ++ retval |= handle_hc_nyet_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.xacterr) { ++ retval |= handle_hc_xacterr_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.bblerr) { ++ retval |= handle_hc_babble_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.frmovrun) { ++ retval |= handle_hc_frmovrun_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ if (hcint.b.datatglerr) { ++ retval |= handle_hc_datatglerr_intr(_dwc_otg_hcd, hc, hc_regs, qtd, &must_free); ++ } ++ ++ /* ++ * Logic to free the qtd here, at the end of the hc intr ++ * processing, if the handling of this interrupt determined ++ * that it needs to be freed. ++ */ ++ if (must_free) { ++ /* Free the qtd here now that we are done using it. */ ++ dwc_otg_hcd_qtd_free(qtd); ++ } ++ return retval; ++} ++ ++#endif /* DWC_DEVICE_ONLY */ +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_hcd_queue.c +@@ -0,0 +1,794 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_hcd_queue.c $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 537387 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++ ++/** ++ * @file ++ * ++ * This file contains the functions to manage Queue Heads and Queue ++ * Transfer Descriptors. ++ */ ++#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 "dwc_otg_driver.h" ++#include "dwc_otg_hcd.h" ++#include "dwc_otg_regs.h" ++ ++/** ++ * This function allocates and initializes a QH. ++ * ++ * @param _hcd The HCD state structure for the DWC OTG controller. ++ * @param[in] _urb Holds the information about the device/endpoint that we need ++ * to initialize the QH. ++ * ++ * @return Returns pointer to the newly allocated QH, or NULL on error. */ ++dwc_otg_qh_t *dwc_otg_hcd_qh_create (dwc_otg_hcd_t *_hcd, struct urb *_urb) ++{ ++ dwc_otg_qh_t *qh; ++ ++ /* Allocate memory */ ++ /** @todo add memflags argument */ ++ qh = dwc_otg_hcd_qh_alloc (); ++ if (qh == NULL) { ++ return NULL; ++ } ++ ++ dwc_otg_hcd_qh_init (_hcd, qh, _urb); ++ return qh; ++} ++ ++/** Free each QTD in the QH's QTD-list then free the QH. QH should already be ++ * removed from a list. QTD list should already be empty if called from URB ++ * Dequeue. ++ * ++ * @param[in] _qh The QH to free. ++ */ ++void dwc_otg_hcd_qh_free (dwc_otg_qh_t *_qh) ++{ ++ dwc_otg_qtd_t *qtd; ++ struct list_head *pos; ++ unsigned long flags; ++ ++ /* Free each QTD in the QTD list */ ++ local_irq_save (flags); ++ for (pos = _qh->qtd_list.next; ++ pos != &_qh->qtd_list; ++ pos = _qh->qtd_list.next) ++ { ++ list_del (pos); ++ qtd = dwc_list_to_qtd (pos); ++ dwc_otg_hcd_qtd_free (qtd); ++ } ++ local_irq_restore (flags); ++ ++ kfree (_qh); ++ return; ++} ++ ++/** Initializes a QH structure. ++ * ++ * @param[in] _hcd The HCD state structure for the DWC OTG controller. ++ * @param[in] _qh The QH to init. ++ * @param[in] _urb Holds the information about the device/endpoint that we need ++ * to initialize the QH. */ ++#define SCHEDULE_SLOP 10 ++void dwc_otg_hcd_qh_init(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, struct urb *_urb) ++{ ++ memset (_qh, 0, sizeof (dwc_otg_qh_t)); ++ ++ /* Initialize QH */ ++ switch (usb_pipetype(_urb->pipe)) { ++ case PIPE_CONTROL: ++ _qh->ep_type = USB_ENDPOINT_XFER_CONTROL; ++ break; ++ case PIPE_BULK: ++ _qh->ep_type = USB_ENDPOINT_XFER_BULK; ++ break; ++ case PIPE_ISOCHRONOUS: ++ _qh->ep_type = USB_ENDPOINT_XFER_ISOC; ++ break; ++ case PIPE_INTERRUPT: ++ _qh->ep_type = USB_ENDPOINT_XFER_INT; ++ break; ++ } ++ ++ _qh->ep_is_in = usb_pipein(_urb->pipe) ? 1 : 0; ++ ++ _qh->data_toggle = DWC_OTG_HC_PID_DATA0; ++ _qh->maxp = usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe))); ++ INIT_LIST_HEAD(&_qh->qtd_list); ++ INIT_LIST_HEAD(&_qh->qh_list_entry); ++ _qh->channel = NULL; ++ ++ /* FS/LS Enpoint on HS Hub ++ * NOT virtual root hub */ ++ _qh->do_split = 0; ++ _qh->speed = _urb->dev->speed; ++ if (((_urb->dev->speed == USB_SPEED_LOW) || ++ (_urb->dev->speed == USB_SPEED_FULL)) && ++ (_urb->dev->tt) && (_urb->dev->tt->hub) && (_urb->dev->tt->hub->devnum != 1)) { ++ DWC_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); ++ _qh->do_split = 1; ++ } ++ ++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT || ++ _qh->ep_type == USB_ENDPOINT_XFER_ISOC) { ++ /* Compute scheduling parameters once and save them. */ ++ hprt0_data_t hprt; ++ ++ /** @todo Account for split transfers in the bus time. */ ++ int bytecount = dwc_hb_mult(_qh->maxp) * dwc_max_packet(_qh->maxp); ++ _qh->usecs = NS_TO_US(usb_calc_bus_time(_urb->dev->speed, ++ usb_pipein(_urb->pipe), ++ (_qh->ep_type == USB_ENDPOINT_XFER_ISOC),bytecount)); ++ ++ /* Start in a slightly future (micro)frame. */ ++ _qh->sched_frame = dwc_frame_num_inc(_hcd->frame_number, SCHEDULE_SLOP); ++ _qh->interval = _urb->interval; ++#if 0 ++ /* Increase interrupt polling rate for debugging. */ ++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { ++ _qh->interval = 8; ++ } ++#endif ++ hprt.d32 = dwc_read_reg32(_hcd->core_if->host_if->hprt0); ++ if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) && ++ ((_urb->dev->speed == USB_SPEED_LOW) || ++ (_urb->dev->speed == USB_SPEED_FULL))) ++ { ++ _qh->interval *= 8; ++ _qh->sched_frame |= 0x7; ++ _qh->start_split_frame = _qh->sched_frame; ++ } ++ } ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n"); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", _qh); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n", ++ _urb->dev->devnum); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n", ++ usb_pipeendpoint(_urb->pipe), ++ usb_pipein(_urb->pipe) == USB_DIR_IN ? "IN" : "OUT"); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - 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;})); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", ++ ({ char *type; switch (_qh->ep_type) { ++ case USB_ENDPOINT_XFER_ISOC: type = "isochronous"; break; ++ case USB_ENDPOINT_XFER_INT: type = "interrupt"; break; ++ case USB_ENDPOINT_XFER_CONTROL: type = "control"; break; ++ case USB_ENDPOINT_XFER_BULK: type = "bulk"; break; ++ default: type = "?"; break; ++ }; type;})); ++#ifdef DEBUG ++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n", ++ _qh->usecs); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n", ++ _qh->interval); ++ } ++#endif ++ ++ return; ++} ++ ++/** ++ * Microframe scheduler ++ * track the total use in hcd->frame_usecs ++ * keep each qh use in qh->frame_usecs ++ * when surrendering the qh then donate the time back ++ */ ++const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 }; ++ ++/* ++ * called from dwc_otg_hcd.c:dwc_otg_hcd_init ++ */ ++int init_hcd_usecs(dwc_otg_hcd_t *_hcd) ++{ ++ int i; ++ for (i=0; i<8; i++) { ++ _hcd->frame_usecs[i] = max_uframe_usecs[i]; ++ } ++ return 0; ++} ++ ++static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) ++{ ++ int i; ++ unsigned short utime; ++ int t_left; ++ int ret; ++ int done; ++ ++ ret = -1; ++ utime = _qh->usecs; ++ t_left = utime; ++ i = 0; ++ done = 0; ++ while (done == 0) { ++ /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */ ++ if (utime <= _hcd->frame_usecs[i]) { ++ _hcd->frame_usecs[i] -= utime; ++ _qh->frame_usecs[i] += utime; ++ t_left -= utime; ++ ret = i; ++ done = 1; ++ return ret; ++ } else { ++ i++; ++ if (i == 8) { ++ done = 1; ++ ret = -1; ++ } ++ } ++ } ++ return ret; ++} ++ ++/* ++ * use this for FS apps that can span multiple uframes ++ */ ++static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) ++{ ++ int i; ++ int j; ++ unsigned short utime; ++ int t_left; ++ int ret; ++ int done; ++ unsigned short xtime; ++ ++ ret = -1; ++ utime = _qh->usecs; ++ t_left = utime; ++ i = 0; ++ done = 0; ++loop: ++ while (done == 0) { ++ if(_hcd->frame_usecs[i] <= 0) { ++ i++; ++ if (i == 8) { ++ done = 1; ++ ret = -1; ++ } ++ goto loop; ++ } ++ ++ /* ++ * we need n consequtive slots ++ * so use j as a start slot j plus j+1 must be enough time (for now) ++ */ ++ xtime= _hcd->frame_usecs[i]; ++ for (j = i+1 ; j < 8 ; j++ ) { ++ /* ++ * if we add this frame remaining time to xtime we may ++ * be OK, if not we need to test j for a complete frame ++ */ ++ if ((xtime+_hcd->frame_usecs[j]) < utime) { ++ if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) { ++ j = 8; ++ ret = -1; ++ continue; ++ } ++ } ++ if (xtime >= utime) { ++ ret = i; ++ j = 8; /* stop loop with a good value ret */ ++ continue; ++ } ++ /* add the frame time to x time */ ++ xtime += _hcd->frame_usecs[j]; ++ /* we must have a fully available next frame or break */ ++ if ((xtime < utime) ++ && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) { ++ ret = -1; ++ j = 8; /* stop loop with a bad value ret */ ++ continue; ++ } ++ } ++ if (ret >= 0) { ++ t_left = utime; ++ for (j = i; (t_left>0) && (j < 8); j++ ) { ++ t_left -= _hcd->frame_usecs[j]; ++ if ( t_left <= 0 ) { ++ _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left; ++ _hcd->frame_usecs[j]= -t_left; ++ ret = i; ++ done = 1; ++ } else { ++ _qh->frame_usecs[j] += _hcd->frame_usecs[j]; ++ _hcd->frame_usecs[j] = 0; ++ } ++ } ++ } else { ++ i++; ++ if (i == 8) { ++ done = 1; ++ ret = -1; ++ } ++ } ++ } ++ return ret; ++} ++ ++static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) ++{ ++ int ret; ++ ret = -1; ++ ++ if (_qh->speed == USB_SPEED_HIGH) { ++ /* if this is a hs transaction we need a full frame */ ++ ret = find_single_uframe(_hcd, _qh); ++ } else { ++ /* if this is a fs transaction we may need a sequence of frames */ ++ ret = find_multi_uframe(_hcd, _qh); ++ } ++ return ret; ++} ++ ++/** ++ * Checks that the max transfer size allowed in a host channel is large enough ++ * to handle the maximum data transfer in a single (micro)frame for a periodic ++ * transfer. ++ * ++ * @param _hcd The HCD state structure for the DWC OTG controller. ++ * @param _qh QH for a periodic endpoint. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++static int check_max_xfer_size(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ int status; ++ uint32_t max_xfer_size; ++ uint32_t max_channel_xfer_size; ++ ++ status = 0; ++ ++ max_xfer_size = dwc_max_packet(_qh->maxp) * dwc_hb_mult(_qh->maxp); ++ max_channel_xfer_size = _hcd->core_if->core_params->max_transfer_size; ++ ++ if (max_xfer_size > max_channel_xfer_size) { ++ DWC_NOTICE("%s: Periodic xfer length %d > " ++ "max xfer length for channel %d\n", ++ __func__, max_xfer_size, max_channel_xfer_size); ++ status = -ENOSPC; ++ } ++ ++ return status; ++} ++ ++/** ++ * Schedules an interrupt or isochronous transfer in the periodic schedule. ++ * ++ * @param _hcd The HCD state structure for the DWC OTG controller. ++ * @param _qh QH for the periodic transfer. The QH should already contain the ++ * scheduling information. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++static int schedule_periodic(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ int status = 0; ++ ++ int frame; ++ status = find_uframe(_hcd, _qh); ++ frame = -1; ++ if (status == 0) { ++ frame = 7; ++ } else { ++ if (status > 0 ) ++ frame = status-1; ++ } ++ ++ /* Set the new frame up */ ++ if (frame > -1) { ++ _qh->sched_frame &= ~0x7; ++ _qh->sched_frame |= (frame & 7); ++ } ++ ++ if (status != -1 ) ++ status = 0; ++ if (status) { ++ DWC_NOTICE("%s: Insufficient periodic bandwidth for " ++ "periodic transfer.\n", __func__); ++ return status; ++ } ++ ++ status = check_max_xfer_size(_hcd, _qh); ++ if (status) { ++ DWC_NOTICE("%s: Channel max transfer size too small " ++ "for periodic transfer.\n", __func__); ++ return status; ++ } ++ ++ /* Always start in the inactive schedule. */ ++ list_add_tail(&_qh->qh_list_entry, &_hcd->periodic_sched_inactive); ++ ++ ++ /* Update claimed usecs per (micro)frame. */ ++ _hcd->periodic_usecs += _qh->usecs; ++ ++ /* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */ ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_allocated += _qh->usecs / _qh->interval; ++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_int_reqs++; ++ DWC_DEBUGPL(DBG_HCD, "Scheduled intr: qh %p, usecs %d, period %d\n", ++ _qh, _qh->usecs, _qh->interval); ++ } else { ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_isoc_reqs++; ++ DWC_DEBUGPL(DBG_HCD, "Scheduled isoc: qh %p, usecs %d, period %d\n", ++ _qh, _qh->usecs, _qh->interval); ++ } ++ ++ return status; ++} ++ ++/** ++ * This function adds a QH to either the non periodic or periodic schedule if ++ * it is not already in the schedule. If the QH is already in the schedule, no ++ * action is taken. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++int dwc_otg_hcd_qh_add (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ unsigned long flags; ++ int status = 0; ++ ++ local_irq_save(flags); ++ ++ if (!list_empty(&_qh->qh_list_entry)) { ++ /* QH already in a schedule. */ ++ goto done; ++ } ++ ++ /* Add the new QH to the appropriate schedule */ ++ if (dwc_qh_is_non_per(_qh)) { ++ /* Always start in the inactive schedule. */ ++ list_add_tail(&_qh->qh_list_entry, &_hcd->non_periodic_sched_inactive); ++ } else { ++ status = schedule_periodic(_hcd, _qh); ++ } ++ ++ done: ++ local_irq_restore(flags); ++ ++ return status; ++} ++ ++/** ++ * This function adds a QH to the non periodic deferred schedule. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++int dwc_otg_hcd_qh_add_deferred(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ if (!list_empty(&_qh->qh_list_entry)) { ++ /* QH already in a schedule. */ ++ goto done; ++ } ++ ++ /* Add the new QH to the non periodic deferred schedule */ ++ if (dwc_qh_is_non_per(_qh)) { ++ list_add_tail(&_qh->qh_list_entry, ++ &_hcd->non_periodic_sched_deferred); ++ } ++done: ++ local_irq_restore(flags); ++ return 0; ++} ++ ++/** ++ * Removes an interrupt or isochronous transfer from the periodic schedule. ++ * ++ * @param _hcd The HCD state structure for the DWC OTG controller. ++ * @param _qh QH for the periodic transfer. ++ */ ++static void deschedule_periodic(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ int i; ++ list_del_init(&_qh->qh_list_entry); ++ ++ ++ /* Update claimed usecs per (micro)frame. */ ++ _hcd->periodic_usecs -= _qh->usecs; ++ ++ for (i = 0; i < 8; i++) { ++ _hcd->frame_usecs[i] += _qh->frame_usecs[i]; ++ _qh->frame_usecs[i] = 0; ++ } ++ /* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */ ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_allocated -= _qh->usecs / _qh->interval; ++ ++ if (_qh->ep_type == USB_ENDPOINT_XFER_INT) { ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_int_reqs--; ++ DWC_DEBUGPL(DBG_HCD, "Descheduled intr: qh %p, usecs %d, period %d\n", ++ _qh, _qh->usecs, _qh->interval); ++ } else { ++ hcd_to_bus(dwc_otg_hcd_to_hcd(_hcd))->bandwidth_isoc_reqs--; ++ DWC_DEBUGPL(DBG_HCD, "Descheduled isoc: qh %p, usecs %d, period %d\n", ++ _qh, _qh->usecs, _qh->interval); ++ } ++} ++ ++/** ++ * Removes a QH from either the non-periodic or periodic schedule. Memory is ++ * not freed. ++ * ++ * @param[in] _hcd The HCD state structure. ++ * @param[in] _qh QH to remove from schedule. */ ++void dwc_otg_hcd_qh_remove (dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ if (list_empty(&_qh->qh_list_entry)) { ++ /* QH is not in a schedule. */ ++ goto done; ++ } ++ ++ if (dwc_qh_is_non_per(_qh)) { ++ if (_hcd->non_periodic_qh_ptr == &_qh->qh_list_entry) { ++ _hcd->non_periodic_qh_ptr = _hcd->non_periodic_qh_ptr->next; ++ } ++ list_del_init(&_qh->qh_list_entry); ++ } else { ++ deschedule_periodic(_hcd, _qh); ++ } ++ ++ done: ++ local_irq_restore(flags); ++} ++ ++/** ++ * Defers a QH. For non-periodic QHs, removes the QH from the active ++ * non-periodic schedule. The QH is added to the deferred non-periodic ++ * schedule if any QTDs are still attached to the QH. ++ */ ++int dwc_otg_hcd_qh_deferr(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh, int delay) ++{ ++ int deact = 1; ++ unsigned long flags; ++ local_irq_save(flags); ++ if (dwc_qh_is_non_per(_qh)) { ++ _qh->sched_frame = ++ dwc_frame_num_inc(_hcd->frame_number, ++ delay); ++ _qh->channel = NULL; ++ _qh->qtd_in_process = NULL; ++ deact = 0; ++ dwc_otg_hcd_qh_remove(_hcd, _qh); ++ if (!list_empty(&_qh->qtd_list)) { ++ /* Add back to deferred non-periodic schedule. */ ++ dwc_otg_hcd_qh_add_deferred(_hcd, _qh); ++ } ++ } ++ local_irq_restore(flags); ++ return deact; ++} ++ ++/** ++ * Deactivates a QH. For non-periodic QHs, removes the QH from the active ++ * non-periodic schedule. The QH is added to the inactive non-periodic ++ * schedule if any QTDs are still attached to the QH. ++ * ++ * For periodic QHs, the QH is removed from the periodic queued schedule. If ++ * there are any QTDs still attached to the QH, the QH is added to either the ++ * periodic inactive schedule or the periodic ready schedule and its next ++ * scheduled frame is calculated. The QH is placed in the ready schedule if ++ * the scheduled frame has been reached already. Otherwise it's placed in the ++ * inactive schedule. If there are no QTDs attached to the QH, the QH is ++ * completely removed from the periodic schedule. ++ */ ++void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t *_hcd, dwc_otg_qh_t *_qh, int sched_next_periodic_split) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ ++ if (dwc_qh_is_non_per(_qh)) { ++ dwc_otg_hcd_qh_remove(_hcd, _qh); ++ if (!list_empty(&_qh->qtd_list)) { ++ /* Add back to inactive non-periodic schedule. */ ++ dwc_otg_hcd_qh_add(_hcd, _qh); ++ } ++ } else { ++ uint16_t frame_number = dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(_hcd)); ++ ++ if (_qh->do_split) { ++ /* Schedule the next continuing periodic split transfer */ ++ if (sched_next_periodic_split) { ++ ++ _qh->sched_frame = frame_number; ++ if (dwc_frame_num_le(frame_number, ++ dwc_frame_num_inc(_qh->start_split_frame, 1))) { ++ /* ++ * Allow one frame to elapse after start ++ * split microframe before scheduling ++ * complete split, but DONT if we are ++ * doing the next start split in the ++ * same frame for an ISOC out. ++ */ ++ if ((_qh->ep_type != USB_ENDPOINT_XFER_ISOC) || (_qh->ep_is_in != 0)) { ++ _qh->sched_frame = dwc_frame_num_inc(_qh->sched_frame, 1); ++ } ++ } ++ } else { ++ _qh->sched_frame = dwc_frame_num_inc(_qh->start_split_frame, ++ _qh->interval); ++ if (dwc_frame_num_le(_qh->sched_frame, frame_number)) { ++ _qh->sched_frame = frame_number; ++ } ++ _qh->sched_frame |= 0x7; ++ _qh->start_split_frame = _qh->sched_frame; ++ } ++ } else { ++ _qh->sched_frame = dwc_frame_num_inc(_qh->sched_frame, _qh->interval); ++ if (dwc_frame_num_le(_qh->sched_frame, frame_number)) { ++ _qh->sched_frame = frame_number; ++ } ++ } ++ ++ if (list_empty(&_qh->qtd_list)) { ++ dwc_otg_hcd_qh_remove(_hcd, _qh); ++ } else { ++ /* ++ * Remove from periodic_sched_queued and move to ++ * appropriate queue. ++ */ ++ if (dwc_frame_num_le(_qh->sched_frame, frame_number)) { ++ list_move(&_qh->qh_list_entry, ++ &_hcd->periodic_sched_ready); ++ } else { ++ list_move(&_qh->qh_list_entry, ++ &_hcd->periodic_sched_inactive); ++ } ++ } ++ } ++ ++ local_irq_restore(flags); ++} ++ ++/** ++ * This function allocates and initializes a QTD. ++ * ++ * @param[in] _urb The URB to create a QTD from. Each URB-QTD pair will end up ++ * pointing to each other so each pair should have a unique correlation. ++ * ++ * @return Returns pointer to the newly allocated QTD, or NULL on error. */ ++dwc_otg_qtd_t *dwc_otg_hcd_qtd_create (struct urb *_urb) ++{ ++ dwc_otg_qtd_t *qtd; ++ ++ qtd = dwc_otg_hcd_qtd_alloc (); ++ if (qtd == NULL) { ++ return NULL; ++ } ++ ++ dwc_otg_hcd_qtd_init (qtd, _urb); ++ return qtd; ++} ++ ++/** ++ * Initializes a QTD structure. ++ * ++ * @param[in] _qtd The QTD to initialize. ++ * @param[in] _urb The URB to use for initialization. */ ++void dwc_otg_hcd_qtd_init (dwc_otg_qtd_t *_qtd, struct urb *_urb) ++{ ++ memset (_qtd, 0, sizeof (dwc_otg_qtd_t)); ++ _qtd->urb = _urb; ++ if (usb_pipecontrol(_urb->pipe)) { ++ /* ++ * The only time the QTD data toggle is used is on the data ++ * phase of control transfers. This phase always starts with ++ * DATA1. ++ */ ++ _qtd->data_toggle = DWC_OTG_HC_PID_DATA1; ++ _qtd->control_phase = DWC_OTG_CONTROL_SETUP; ++ } ++ ++ /* start split */ ++ _qtd->complete_split = 0; ++ _qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL; ++ _qtd->isoc_split_offset = 0; ++ ++ /* Store the qtd ptr in the urb to reference what QTD. */ ++ _urb->hcpriv = _qtd; ++ return; ++} ++ ++/** ++ * This function adds a QTD to the QTD-list of a QH. It will find the correct ++ * QH to place the QTD into. If it does not find a QH, then it will create a ++ * new QH. If the QH to which the QTD is added is not currently scheduled, it ++ * is placed into the proper schedule based on its EP type. ++ * ++ * @param[in] _qtd The QTD to add ++ * @param[in] _dwc_otg_hcd The DWC HCD structure ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * _qtd, dwc_otg_hcd_t * _dwc_otg_hcd) ++{ ++ struct usb_host_endpoint *ep; ++ dwc_otg_qh_t *qh; ++ unsigned long flags; ++ int retval = 0; ++ struct urb *urb = _qtd->urb; ++ ++ local_irq_save(flags); ++ ++ /* ++ * Get the QH which holds the QTD-list to insert to. Create QH if it ++ * doesn't exist. ++ */ ++ ep = dwc_urb_to_endpoint(urb); ++ qh = (dwc_otg_qh_t *)ep->hcpriv; ++ if (qh == NULL) { ++ qh = dwc_otg_hcd_qh_create (_dwc_otg_hcd, urb); ++ if (qh == NULL) { ++ retval = -1; ++ goto done; ++ } ++ ep->hcpriv = qh; ++ } ++ ++ _qtd->qtd_qh_ptr = qh; ++ retval = dwc_otg_hcd_qh_add(_dwc_otg_hcd, qh); ++ if (retval == 0) { ++ list_add_tail(&_qtd->qtd_list_entry, &qh->qtd_list); ++ } ++ ++ done: ++ local_irq_restore(flags); ++ return retval; ++} ++ ++#endif /* DWC_DEVICE_ONLY */ +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_ifx.c +@@ -0,0 +1,100 @@ ++/****************************************************************************** ++** ++** FILE NAME : dwc_otg_ifx.c ++** PROJECT : Twinpass/Danube ++** MODULES : DWC OTG USB ++** ++** DATE : 12 Auguest 2007 ++** AUTHOR : Sung Winder ++** DESCRIPTION : Platform specific initialization. ++** COPYRIGHT : Copyright (c) 2007 ++** Infineon Technologies AG ++** 2F, No.2, Li-Hsin Rd., Hsinchu Science Park, ++** Hsin-chu City, 300 Taiwan. ++** ++** 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 ++** 12 Auguest 2007 Sung Winder Initiate Version ++*******************************************************************************/ ++#include "dwc_otg_ifx.h" ++ ++#include <linux/platform_device.h> ++#include <linux/kernel.h> ++#include <linux/ioport.h> ++#include <linux/gpio.h> ++ ++#include <asm/io.h> ++//#include <asm/mach-ifxmips/ifxmips.h> ++#include <lantiq_soc.h> ++ ++#define IFXMIPS_GPIO_BASE_ADDR (0xBE100B00) ++ ++#define IFXMIPS_GPIO_P0_OUT ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0010)) ++#define IFXMIPS_GPIO_P1_OUT ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0040)) ++#define IFXMIPS_GPIO_P0_IN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0014)) ++#define IFXMIPS_GPIO_P1_IN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0044)) ++#define IFXMIPS_GPIO_P0_DIR ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0018)) ++#define IFXMIPS_GPIO_P1_DIR ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0048)) ++#define IFXMIPS_GPIO_P0_ALTSEL0 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x001C)) ++#define IFXMIPS_GPIO_P1_ALTSEL0 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x004C)) ++#define IFXMIPS_GPIO_P0_ALTSEL1 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0020)) ++#define IFXMIPS_GPIO_P1_ALTSEL1 ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0050)) ++#define IFXMIPS_GPIO_P0_OD ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0024)) ++#define IFXMIPS_GPIO_P1_OD ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0054)) ++#define IFXMIPS_GPIO_P0_STOFF ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0028)) ++#define IFXMIPS_GPIO_P1_STOFF ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0058)) ++#define IFXMIPS_GPIO_P0_PUDSEL ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x002C)) ++#define IFXMIPS_GPIO_P1_PUDSEL ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x005C)) ++#define IFXMIPS_GPIO_P0_PUDEN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0030)) ++#define IFXMIPS_GPIO_P1_PUDEN ((u32 *)(IFXMIPS_GPIO_BASE_ADDR + 0x0060)) ++ ++ ++#define writel ltq_w32 ++#define readl ltq_r32 ++void dwc_otg_power_on (void) ++{ ++ // clear power ++ writel(readl(DANUBE_PMU_PWDCR) | 0x41, DANUBE_PMU_PWDCR); ++ // set clock gating ++ writel(readl(DANUBE_CGU_IFCCR) | 0x30, DANUBE_CGU_IFCCR); ++ // set power ++ writel(readl(DANUBE_PMU_PWDCR) & ~0x1, DANUBE_PMU_PWDCR); ++ writel(readl(DANUBE_PMU_PWDCR) & ~0x40, DANUBE_PMU_PWDCR); ++ writel(readl(DANUBE_PMU_PWDCR) & ~0x8000, DANUBE_PMU_PWDCR); ++ ++#if 1//defined (DWC_HOST_ONLY) ++ // make the hardware be a host controller (default) ++ //clear_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); ++ writel(readl(DANUBE_RCU_UBSCFG) & ~(1<<DANUBE_USBCFG_HDSEL_BIT), DANUBE_RCU_UBSCFG); ++ ++ //#elif defined (DWC_DEVICE_ONLY) ++ /* set the controller to the device mode */ ++ // set_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); ++#else ++#error "For Danube/Twinpass, it should be HOST or Device Only." ++#endif ++ ++ // set the HC's byte-order to big-endian ++ //set_bit (DANUBE_USBCFG_HOST_END_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); ++ writel(readl(DANUBE_RCU_UBSCFG) | (1<<DANUBE_USBCFG_HOST_END_BIT), DANUBE_RCU_UBSCFG); ++ //clear_bit (DANUBE_USBCFG_SLV_END_BIT, (volatile unsigned long *)DANUBE_RCU_UBSCFG); ++ writel(readl(DANUBE_RCU_UBSCFG) & ~(1<<DANUBE_USBCFG_SLV_END_BIT), DANUBE_RCU_UBSCFG); ++ //writel(0x400, DANUBE_RCU_UBSCFG); ++ ++ // PHY configurations. ++ writel (0x14014, (volatile unsigned long *)0xbe10103c); ++} ++ ++int ifx_usb_hc_init(unsigned long base_addr, int irq) ++{ ++ return 0; ++} ++ ++void ifx_usb_hc_remove(void) ++{ ++} +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_ifx.h +@@ -0,0 +1,85 @@ ++/****************************************************************************** ++** ++** FILE NAME : dwc_otg_ifx.h ++** PROJECT : Twinpass/Danube ++** MODULES : DWC OTG USB ++** ++** DATE : 12 April 2007 ++** AUTHOR : Sung Winder ++** DESCRIPTION : Platform specific initialization. ++** COPYRIGHT : Copyright (c) 2007 ++** Infineon Technologies AG ++** 2F, No.2, Li-Hsin Rd., Hsinchu Science Park, ++** Hsin-chu City, 300 Taiwan. ++** ++** 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 ++** 12 April 2007 Sung Winder Initiate Version ++*******************************************************************************/ ++#if !defined(__DWC_OTG_IFX_H__) ++#define __DWC_OTG_IFX_H__ ++ ++#include <linux/irq.h> ++#include <irq.h> ++ ++// 20070316, winder added. ++#ifndef SZ_256K ++#define SZ_256K 0x00040000 ++#endif ++ ++extern void dwc_otg_power_on (void); ++ ++/* FIXME: The current Linux-2.6 do not have these header files, but anyway, we need these. */ ++// #include <asm/danube/danube.h> ++// #include <asm/ifx/irq.h> ++ ++/* winder, I used the Danube parameter as default. * ++ * We could change this through module param. */ ++#define IFX_USB_IOMEM_BASE 0x1e101000 ++#define IFX_USB_IOMEM_SIZE SZ_256K ++#define IFX_USB_IRQ LTQ_USB_INT ++ ++/** ++ * This function is called to set correct clock gating and power. ++ * For Twinpass/Danube board. ++ */ ++#ifndef DANUBE_RCU_BASE_ADDR ++#define DANUBE_RCU_BASE_ADDR (0xBF203000) ++#endif ++ ++#ifndef DANUBE_CGU ++#define DANUBE_CGU (0xBF103000) ++#endif ++#ifndef DANUBE_CGU_IFCCR ++/***CGU Interface Clock Control Register***/ ++#define DANUBE_CGU_IFCCR ((volatile u32*)(DANUBE_CGU+ 0x0018)) ++#endif ++ ++#ifndef DANUBE_PMU ++#define DANUBE_PMU (KSEG1+0x1F102000) ++#endif ++#ifndef DANUBE_PMU_PWDCR ++/* PMU Power down Control Register */ ++#define DANUBE_PMU_PWDCR ((volatile u32*)(DANUBE_PMU+0x001C)) ++#endif ++ ++ ++#define DANUBE_RCU_UBSCFG ((volatile u32*)(DANUBE_RCU_BASE_ADDR + 0x18)) ++#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 ++ ++extern void ltq_mask_and_ack_irq(struct irq_data *d); ++ ++static void inline mask_and_ack_ifx_irq(int x) ++{ ++ struct irq_data d; ++ d.irq = x; ++ ltq_mask_and_ack_irq(&d); ++} ++#endif //__DWC_OTG_IFX_H__ +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_plat.h +@@ -0,0 +1,269 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/platform/dwc_otg_plat.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 510301 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#if !defined(__DWC_OTG_PLAT_H__) ++#define __DWC_OTG_PLAT_H__ ++ ++#include <linux/types.h> ++#include <linux/slab.h> ++#include <linux/list.h> ++#include <linux/delay.h> ++#include <asm/io.h> ++ ++/** ++ * @file ++ * ++ * This file contains the Platform Specific constants, interfaces ++ * (functions and macros) for Linux. ++ * ++ */ ++/*#if !defined(__LINUX__) ++#error "The contents of this file is Linux specific!!!" ++#endif ++*/ ++#include <lantiq_soc.h> ++#define writel ltq_w32 ++#define readl ltq_r32 ++ ++/** ++ * Reads the content of a register. ++ * ++ * @param _reg address of register to read. ++ * @return contents of the register. ++ * ++ ++ * Usage:<br> ++ * <code>uint32_t dev_ctl = dwc_read_reg32(&dev_regs->dctl);</code> ++ */ ++static __inline__ uint32_t dwc_read_reg32( volatile uint32_t *_reg) ++{ ++ return readl(_reg); ++}; ++ ++/** ++ * Writes a register with a 32 bit value. ++ * ++ * @param _reg address of register to read. ++ * @param _value to write to _reg. ++ * ++ * Usage:<br> ++ * <code>dwc_write_reg32(&dev_regs->dctl, 0); </code> ++ */ ++static __inline__ void dwc_write_reg32( volatile uint32_t *_reg, const uint32_t _value) ++{ ++ writel( _value, _reg ); ++}; ++ ++/** ++ * This function modifies bit values in a register. Using the ++ * algorithm: (reg_contents & ~clear_mask) | set_mask. ++ * ++ * @param _reg address of register to read. ++ * @param _clear_mask bit mask to be cleared. ++ * @param _set_mask bit mask to be set. ++ * ++ * Usage:<br> ++ * <code> // Clear the SOF Interrupt Mask bit and <br> ++ * // set the OTG Interrupt mask bit, leaving all others as they were. ++ * dwc_modify_reg32(&dev_regs->gintmsk, DWC_SOF_INT, DWC_OTG_INT);</code> ++ */ ++static __inline__ ++ void dwc_modify_reg32( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) ++{ ++ writel( (readl(_reg) & ~_clear_mask) | _set_mask, _reg ); ++}; ++ ++ ++/** ++ * Wrapper for the OS micro-second delay function. ++ * @param[in] _usecs Microseconds of delay ++ */ ++static __inline__ void UDELAY( const uint32_t _usecs ) ++{ ++ udelay( _usecs ); ++} ++ ++/** ++ * Wrapper for the OS milli-second delay function. ++ * @param[in] _msecs milliseconds of delay ++ */ ++static __inline__ void MDELAY( const uint32_t _msecs ) ++{ ++ mdelay( _msecs ); ++} ++ ++/** ++ * Wrapper for the Linux spin_lock. On the ARM (Integrator) ++ * spin_lock() is a nop. ++ * ++ * @param _lock Pointer to the spinlock. ++ */ ++static __inline__ void SPIN_LOCK( spinlock_t *_lock ) ++{ ++ spin_lock(_lock); ++} ++ ++/** ++ * Wrapper for the Linux spin_unlock. On the ARM (Integrator) ++ * spin_lock() is a nop. ++ * ++ * @param _lock Pointer to the spinlock. ++ */ ++static __inline__ void SPIN_UNLOCK( spinlock_t *_lock ) ++{ ++ spin_unlock(_lock); ++} ++ ++/** ++ * Wrapper (macro) for the Linux spin_lock_irqsave. On the ARM ++ * (Integrator) spin_lock() is a nop. ++ * ++ * @param _l Pointer to the spinlock. ++ * @param _f unsigned long for irq flags storage. ++ */ ++#define SPIN_LOCK_IRQSAVE( _l, _f ) { \ ++ spin_lock_irqsave(_l,_f); \ ++ } ++ ++/** ++ * Wrapper (macro) for the Linux spin_unlock_irqrestore. On the ARM ++ * (Integrator) spin_lock() is a nop. ++ * ++ * @param _l Pointer to the spinlock. ++ * @param _f unsigned long for irq flags storage. ++ */ ++#define SPIN_UNLOCK_IRQRESTORE( _l,_f ) {\ ++ spin_unlock_irqrestore(_l,_f); \ ++ } ++ ++ ++/* ++ * Debugging support vanishes in non-debug builds. ++ */ ++ ++ ++/** ++ * The Debug Level bit-mask variable. ++ */ ++extern uint32_t g_dbg_lvl; ++/** ++ * Set the Debug Level variable. ++ */ ++static inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new ) ++{ ++ uint32_t old = g_dbg_lvl; ++ g_dbg_lvl = _new; ++ return old; ++} ++ ++/** When debug level has the DBG_CIL bit set, display CIL Debug messages. */ ++#define DBG_CIL (0x2) ++/** When debug level has the DBG_CILV bit set, display CIL Verbose debug ++ * messages */ ++#define DBG_CILV (0x20) ++/** When debug level has the DBG_PCD bit set, display PCD (Device) debug ++ * messages */ ++#define DBG_PCD (0x4) ++/** When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug ++ * messages */ ++#define DBG_PCDV (0x40) ++/** When debug level has the DBG_HCD bit set, display Host debug messages */ ++#define DBG_HCD (0x8) ++/** When debug level has the DBG_HCDV bit set, display Verbose Host debug ++ * messages */ ++#define DBG_HCDV (0x80) ++/** When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host ++ * mode. */ ++#define DBG_HCD_URB (0x800) ++ ++/** When debug level has any bit set, display debug messages */ ++#define DBG_ANY (0xFF) ++ ++/** All debug messages off */ ++#define DBG_OFF 0 ++ ++/** Prefix string for DWC_DEBUG print macros. */ ++#define USB_DWC "DWC_otg: " ++ ++/** ++ * Print a debug message when the Global debug level variable contains ++ * the bit defined in <code>lvl</code>. ++ * ++ * @param[in] lvl - Debug level, use one of the DBG_ constants above. ++ * @param[in] x - like printf ++ * ++ * Example:<p> ++ * <code> ++ * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr); ++ * </code> ++ * <br> ++ * results in:<br> ++ * <code> ++ * usb-DWC_otg: dwc_otg_cil_init(ca867000) ++ * </code> ++ */ ++#ifdef DEBUG ++ ++# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)printk( KERN_DEBUG USB_DWC x ); }while(0) ++# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x ) ++ ++# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl) ++ ++#else ++ ++# define DWC_DEBUGPL(lvl, x...) do{}while(0) ++# define DWC_DEBUGP(x...) ++ ++# define CHK_DEBUG_LEVEL(level) (0) ++ ++#endif /*DEBUG*/ ++ ++/** ++ * Print an Error message. ++ */ ++#define DWC_ERROR(x...) printk( KERN_ERR USB_DWC x ) ++/** ++ * Print a Warning message. ++ */ ++#define DWC_WARN(x...) printk( KERN_WARNING USB_DWC x ) ++/** ++ * Print a notice (normal but significant message). ++ */ ++#define DWC_NOTICE(x...) printk( KERN_NOTICE USB_DWC x ) ++/** ++ * Basic message printing. ++ */ ++#define DWC_PRINT(x...) printk( KERN_INFO USB_DWC x ) ++ ++#endif ++ +--- /dev/null ++++ b/drivers/usb/dwc_otg/dwc_otg_regs.h +@@ -0,0 +1,1797 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg_ipmate/linux/drivers/dwc_otg_regs.h $ ++ * $Revision: 1.1.1.1 $ ++ * $Date: 2009-04-17 06:15:34 $ ++ * $Change: 631780 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#ifndef __DWC_OTG_REGS_H__ ++#define __DWC_OTG_REGS_H__ ++ ++/** ++ * @file ++ * ++ * This file contains the data structures for accessing the DWC_otg core registers. ++ * ++ * The application interfaces with the HS OTG 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 HS OTG 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. ++ */ ++ ++/****************************************************************************/ ++/** DWC_otg Core registers . ++ * The dwc_otg_core_global_regs structure defines the size ++ * and relative field offsets for the Core Global registers. ++ */ ++typedef struct dwc_otg_core_global_regs ++{ ++ /** OTG Control and Status Register. <i>Offset: 000h</i> */ ++ volatile uint32_t gotgctl; ++ /** OTG Interrupt Register. <i>Offset: 004h</i> */ ++ volatile uint32_t gotgint; ++ /**Core AHB Configuration Register. <i>Offset: 008h</i> */ ++ volatile uint32_t gahbcfg; ++#define DWC_GLBINTRMASK 0x0001 ++#define DWC_DMAENABLE 0x0020 ++#define DWC_NPTXEMPTYLVL_EMPTY 0x0080 ++#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000 ++#define DWC_PTXEMPTYLVL_EMPTY 0x0100 ++#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000 ++ ++ ++ /**Core USB Configuration Register. <i>Offset: 00Ch</i> */ ++ volatile uint32_t gusbcfg; ++ /**Core Reset Register. <i>Offset: 010h</i> */ ++ volatile uint32_t grstctl; ++ /**Core Interrupt Register. <i>Offset: 014h</i> */ ++ volatile uint32_t gintsts; ++ /**Core Interrupt Mask Register. <i>Offset: 018h</i> */ ++ volatile uint32_t gintmsk; ++ /**Receive Status Queue Read Register (Read Only). <i>Offset: 01Ch</i> */ ++ volatile uint32_t grxstsr; ++ /**Receive Status Queue Read & POP Register (Read Only). <i>Offset: 020h</i>*/ ++ volatile uint32_t grxstsp; ++ /**Receive FIFO Size Register. <i>Offset: 024h</i> */ ++ volatile uint32_t grxfsiz; ++ /**Non Periodic Transmit FIFO Size Register. <i>Offset: 028h</i> */ ++ volatile uint32_t gnptxfsiz; ++ /**Non Periodic Transmit FIFO/Queue Status Register (Read ++ * Only). <i>Offset: 02Ch</i> */ ++ volatile uint32_t gnptxsts; ++ /**I2C Access Register. <i>Offset: 030h</i> */ ++ volatile uint32_t gi2cctl; ++ /**PHY Vendor Control Register. <i>Offset: 034h</i> */ ++ volatile uint32_t gpvndctl; ++ /**General Purpose Input/Output Register. <i>Offset: 038h</i> */ ++ volatile uint32_t ggpio; ++ /**User ID Register. <i>Offset: 03Ch</i> */ ++ volatile uint32_t guid; ++ /**Synopsys ID Register (Read Only). <i>Offset: 040h</i> */ ++ volatile uint32_t gsnpsid; ++ /**User HW Config1 Register (Read Only). <i>Offset: 044h</i> */ ++ volatile uint32_t ghwcfg1; ++ /**User HW Config2 Register (Read Only). <i>Offset: 048h</i> */ ++ volatile uint32_t ghwcfg2; ++#define DWC_SLAVE_ONLY_ARCH 0 ++#define DWC_EXT_DMA_ARCH 1 ++#define DWC_INT_DMA_ARCH 2 ++ ++#define DWC_MODE_HNP_SRP_CAPABLE 0 ++#define DWC_MODE_SRP_ONLY_CAPABLE 1 ++#define DWC_MODE_NO_HNP_SRP_CAPABLE 2 ++#define DWC_MODE_SRP_CAPABLE_DEVICE 3 ++#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4 ++#define DWC_MODE_SRP_CAPABLE_HOST 5 ++#define DWC_MODE_NO_SRP_CAPABLE_HOST 6 ++ ++ /**User HW Config3 Register (Read Only). <i>Offset: 04Ch</i> */ ++ volatile uint32_t ghwcfg3; ++ /**User HW Config4 Register (Read Only). <i>Offset: 050h</i>*/ ++ volatile uint32_t ghwcfg4; ++ /** Reserved <i>Offset: 054h-0FFh</i> */ ++ uint32_t reserved[43]; ++ /** Host Periodic Transmit FIFO Size Register. <i>Offset: 100h</i> */ ++ volatile uint32_t hptxfsiz; ++ /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled, ++ otherwise Device Transmit FIFO#n Register. ++ * <i>Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15).</i> */ ++ //volatile uint32_t dptxfsiz[15]; ++ volatile uint32_t dptxfsiz_dieptxf[15]; ++} dwc_otg_core_global_regs_t; ++ ++/** ++ * This union represents the bit fields of the Core OTG Control ++ * and Status Register (GOTGCTL). Set the bits using the bit ++ * fields then write the <i>d32</i> value to the register. ++ */ ++typedef union gotgctl_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++ unsigned reserved31_21 : 11; ++ unsigned currmod : 1; ++ unsigned bsesvld : 1; ++ unsigned asesvld : 1; ++ unsigned reserved17 : 1; ++ unsigned conidsts : 1; ++ unsigned reserved15_12 : 4; ++ unsigned devhnpen : 1; ++ unsigned hstsethnpen : 1; ++ unsigned hnpreq : 1; ++ unsigned hstnegscs : 1; ++ unsigned reserved7_2 : 6; ++ unsigned sesreq : 1; ++ unsigned sesreqscs : 1; ++ } b; ++} gotgctl_data_t; ++ ++/** ++ * This union represents the bit fields of the Core OTG Interrupt Register ++ * (GOTGINT). Set/clear the bits using the bit fields then write the <i>d32</i> ++ * value to the register. ++ */ ++typedef union gotgint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++ /** Current Mode */ ++ unsigned reserved31_20 : 12; ++ /** Debounce Done */ ++ unsigned debdone : 1; ++ /** A-Device Timeout Change */ ++ unsigned adevtoutchng : 1; ++ /** Host Negotiation Detected */ ++ unsigned hstnegdet : 1; ++ unsigned reserver16_10 : 7; ++ /** Host Negotiation Success Status Change */ ++ unsigned hstnegsucstschng : 1; ++ /** Session Request Success Status Change */ ++ unsigned sesreqsucstschng : 1; ++ unsigned reserved3_7 : 5; ++ /** Session End Detected */ ++ unsigned sesenddet : 1; ++ /** Current Mode */ ++ unsigned reserved1_0 : 2; ++ } b; ++} gotgint_data_t; ++ ++ ++/** ++ * This union represents the bit fields of the Core AHB Configuration ++ * Register (GAHBCFG). Set/clear the bits using the bit fields then ++ * write the <i>d32</i> value to the register. ++ */ ++typedef union gahbcfg_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1 ++#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 ++ unsigned reserved9_31 : 23; ++ unsigned ptxfemplvl : 1; ++ unsigned nptxfemplvl_txfemplvl : 1; ++#define DWC_GAHBCFG_DMAENABLE 1 ++ unsigned reserved : 1; ++ unsigned dmaenable : 1; ++#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7 ++ unsigned hburstlen : 4; ++ unsigned glblintrmsk : 1; ++#define DWC_GAHBCFG_GLBINT_ENABLE 1 ++ ++ } b; ++} gahbcfg_data_t; ++ ++/** ++ * This union represents the bit fields of the Core USB Configuration ++ * Register (GUSBCFG). Set the bits using the bit fields then write ++ * the <i>d32</i> value to the register. ++ */ ++typedef union gusbcfg_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++ unsigned corrupt_tx_packet: 1; /*fscz*/ ++ unsigned force_device_mode: 1; ++ unsigned force_host_mode: 1; ++ unsigned reserved23_28 : 6; ++ unsigned term_sel_dl_pulse : 1; ++ unsigned ulpi_int_vbus_indicator : 1; ++ unsigned ulpi_ext_vbus_drv : 1; ++ unsigned ulpi_clk_sus_m : 1; ++ unsigned ulpi_auto_res : 1; ++ unsigned ulpi_fsls : 1; ++ unsigned otgutmifssel : 1; ++ unsigned phylpwrclksel : 1; ++ unsigned nptxfrwnden : 1; ++ unsigned usbtrdtim : 4; ++ unsigned hnpcap : 1; ++ unsigned srpcap : 1; ++ unsigned ddrsel : 1; ++ unsigned physel : 1; ++ unsigned fsintf : 1; ++ unsigned ulpi_utmi_sel : 1; ++ unsigned phyif : 1; ++ unsigned toutcal : 3; ++ } b; ++} gusbcfg_data_t; ++ ++/** ++ * This union represents the bit fields of the Core Reset Register ++ * (GRSTCTL). Set/clear the bits using the bit fields then write the ++ * <i>d32</i> value to the register. ++ */ ++typedef union grstctl_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++ /** AHB Master Idle. Indicates the AHB Master State ++ * Machine is in IDLE condition. */ ++ unsigned ahbidle : 1; ++ /** DMA Request Signal. Indicated DMA request is in ++ * probress. Used for debug purpose. */ ++ unsigned dmareq : 1; ++ /** Reserved */ ++ unsigned reserved29_11 : 19; ++ /** TxFIFO Number (TxFNum) (Device and Host). ++ * ++ * This is the FIFO number which needs to be flushed, ++ * using the TxFIFO Flush bit. This field should not ++ * be changed until the TxFIFO Flush bit is cleared by ++ * the core. ++ * - 0x0 : Non Periodic TxFIFO Flush ++ * - 0x1 : Periodic TxFIFO #1 Flush in device mode ++ * or Periodic TxFIFO in host mode ++ * - 0x2 : Periodic TxFIFO #2 Flush in device mode. ++ * - ... ++ * - 0xF : Periodic TxFIFO #15 Flush in device mode ++ * - 0x10: Flush all the Transmit NonPeriodic and ++ * Transmit Periodic FIFOs in the core ++ */ ++ unsigned txfnum : 5; ++ /** TxFIFO Flush (TxFFlsh) (Device and Host). ++ * ++ * This bit is used to selectively flush a single or ++ * all transmit FIFOs. The application must first ++ * ensure that the core is not in the middle of a ++ * transaction. <p>The application should write into ++ * this bit, only after making sure that neither the ++ * DMA engine is writing into the TxFIFO nor the MAC ++ * is reading the data out of the FIFO. <p>The ++ * application should wait until the core clears this ++ * bit, before performing any operations. This bit ++ * will takes 8 clocks (slowest of PHY or AHB clock) ++ * to clear. ++ */ ++ unsigned txfflsh : 1; ++ /** RxFIFO Flush (RxFFlsh) (Device and Host) ++ * ++ * The application can flush the entire Receive FIFO ++ * using this bit. <p>The application must first ++ * ensure that the core is not in the middle of a ++ * transaction. <p>The application should write into ++ * this bit, only after making sure that neither the ++ * DMA engine is reading from the RxFIFO nor the MAC ++ * is writing the data in to the FIFO. <p>The ++ * application should wait until the bit is cleared ++ * before performing any other operations. This bit ++ * will takes 8 clocks (slowest of PHY or AHB clock) ++ * to clear. ++ */ ++ unsigned rxfflsh : 1; ++ /** In Token Sequence Learning Queue Flush ++ * (INTknQFlsh) (Device Only) ++ */ ++ unsigned intknqflsh : 1; ++ /** Host Frame Counter Reset (Host Only)<br> ++ * ++ * The application can reset the (micro)frame number ++ * counter inside the core, using this bit. When the ++ * (micro)frame counter is reset, the subsequent SOF ++ * sent out by the core, will have a (micro)frame ++ * number of 0. ++ */ ++ unsigned hstfrm : 1; ++ /** Hclk Soft Reset ++ * ++ * The application uses this bit to reset the control logic in ++ * the AHB clock domain. Only AHB clock domain pipelines are ++ * reset. ++ */ ++ unsigned hsftrst : 1; ++ /** Core Soft Reset (CSftRst) (Device and Host) ++ * ++ * 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. ++ */ ++ unsigned csftrst : 1; ++ } b; ++} grstctl_t; ++ ++ ++/** ++ * This union represents the bit fields of the Core Interrupt Mask ++ * Register (GINTMSK). Set/clear the bits using the bit fields then ++ * write the <i>d32</i> value to the register. ++ */ ++typedef union gintmsk_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct ++ { ++ unsigned wkupintr : 1; ++ unsigned sessreqintr : 1; ++ unsigned disconnect : 1; ++ unsigned conidstschng : 1; ++ unsigned reserved27 : 1; ++ unsigned ptxfempty : 1; ++ unsigned hcintr : 1; ++ unsigned portintr : 1; ++ unsigned reserved22_23 : 2; ++ unsigned incomplisoout : 1; ++ unsigned incomplisoin : 1; ++ unsigned outepintr : 1; ++ unsigned inepintr : 1; ++ unsigned epmismatch : 1; ++ unsigned reserved16 : 1; ++ unsigned eopframe : 1; ++ unsigned isooutdrop : 1; ++ unsigned enumdone : 1; ++ unsigned usbreset : 1; ++ unsigned usbsuspend : 1; ++ unsigned erlysuspend : 1; ++ unsigned i2cintr : 1; ++ unsigned reserved8 : 1; ++ unsigned goutnakeff : 1; ++ unsigned ginnakeff : 1; ++ unsigned nptxfempty : 1; ++ unsigned rxstsqlvl : 1; ++ unsigned sofintr : 1; ++ unsigned otgintr : 1; ++ unsigned modemismatch : 1; ++ unsigned reserved0 : 1; ++ } b; ++} gintmsk_data_t; ++/** ++ * This union represents the bit fields of the Core Interrupt Register ++ * (GINTSTS). Set/clear the bits using the bit fields then write the ++ * <i>d32</i> value to the register. ++ */ ++typedef union gintsts_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++#define DWC_SOF_INTR_MASK 0x0008 ++ /** register bits */ ++ struct ++ { ++#define DWC_HOST_MODE 1 ++ unsigned wkupintr : 1; ++ unsigned sessreqintr : 1; ++ unsigned disconnect : 1; ++ unsigned conidstschng : 1; ++ unsigned reserved27 : 1; ++ unsigned ptxfempty : 1; ++ unsigned hcintr : 1; ++ unsigned portintr : 1; ++ unsigned reserved22_23 : 2; ++ unsigned incomplisoout : 1; ++ unsigned incomplisoin : 1; ++ unsigned outepintr : 1; ++ unsigned inepint: 1; ++ unsigned epmismatch : 1; ++ unsigned intokenrx : 1; ++ unsigned eopframe : 1; ++ unsigned isooutdrop : 1; ++ unsigned enumdone : 1; ++ unsigned usbreset : 1; ++ unsigned usbsuspend : 1; ++ unsigned erlysuspend : 1; ++ unsigned i2cintr : 1; ++ unsigned reserved8 : 1; ++ unsigned goutnakeff : 1; ++ unsigned ginnakeff : 1; ++ unsigned nptxfempty : 1; ++ unsigned rxstsqlvl : 1; ++ unsigned sofintr : 1; ++ unsigned otgintr : 1; ++ unsigned modemismatch : 1; ++ unsigned curmode : 1; ++ } b; ++} gintsts_data_t; ++ ++ ++/** ++ * This union represents the bit fields in the Device Receive Status Read and ++ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i> ++ * element then read out the bits using the <i>b</i>it elements. ++ */ ++typedef union device_grxsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 7; ++ unsigned fn : 4; ++#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet ++#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete ++ ++#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK ++#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete ++#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet ++ unsigned pktsts : 4; ++ unsigned dpid : 2; ++ unsigned bcnt : 11; ++ unsigned epnum : 4; ++ } b; ++} device_grxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Receive Status Read and ++ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the <i>d32</i> ++ * element then read out the bits using the <i>b</i>it elements. ++ */ ++typedef union host_grxsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved31_21 : 11; ++#define DWC_GRXSTS_PKTSTS_IN 0x2 ++#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3 ++#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5 ++#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7 ++ unsigned pktsts : 4; ++ unsigned dpid : 2; ++ unsigned bcnt : 11; ++ unsigned chnum : 4; ++ } b; ++} host_grxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, ++ * GNPTXFSIZ, DPTXFSIZn). Read the register into the <i>d32</i> element then ++ * read out the bits using the <i>b</i>it elements. ++ */ ++typedef union fifosize_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned depth : 16; ++ unsigned startaddr : 16; ++ } b; ++} fifosize_data_t; ++ ++/** ++ * This union represents the bit fields in the Non-Periodic Transmit ++ * FIFO/Queue Status Register (GNPTXSTS). Read the register into the ++ * <i>d32</i> element then read out the bits using the <i>b</i>it ++ * elements. ++ */ ++typedef union gnptxsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 1; ++ /** Top of the Non-Periodic Transmit Request Queue ++ * - bits 30:27 - Channel/EP Number ++ * - bits 26:25 - Token Type ++ * - bit 24 - Terminate (Last entry for the selected ++ * channel/EP) ++ * - 2'b00 - IN/OUT ++ * - 2'b01 - Zero Length OUT ++ * - 2'b10 - PING/Complete Split ++ * - 2'b11 - Channel Halt ++ ++ */ ++ unsigned nptxqtop_chnep : 4; ++ unsigned nptxqtop_token : 2; ++ unsigned nptxqtop_terminate : 1; ++ unsigned nptxqspcavail : 8; ++ unsigned nptxfspcavail : 16; ++ } b; ++} gnptxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the Transmit ++ * FIFO Status Register (DTXFSTS). Read the register into the ++ * <i>d32</i> element then read out the bits using the <i>b</i>it ++ * elements. ++ */ ++typedef union dtxfsts_data /* fscz */ //* ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 16; ++ unsigned txfspcavail : 16; ++ } b; ++} dtxfsts_data_t; ++ ++/** ++ * This union represents the bit fields in the I2C Control Register ++ * (I2CCTL). Read the register into the <i>d32</i> element then read out the ++ * bits using the <i>b</i>it elements. ++ */ ++typedef union gi2cctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned bsydne : 1; ++ unsigned rw : 1; ++ unsigned reserved : 2; ++ unsigned i2cdevaddr : 2; ++ unsigned i2csuspctl : 1; ++ unsigned ack : 1; ++ unsigned i2cen : 1; ++ unsigned addr : 7; ++ unsigned regaddr : 8; ++ unsigned rwdata : 8; ++ } b; ++} gi2cctl_data_t; ++ ++/** ++ * This union represents the bit fields in the User HW Config1 ++ * Register. Read the register into the <i>d32</i> element then read ++ * out the bits using the <i>b</i>it elements. ++ */ ++typedef union hwcfg1_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned ep_dir15 : 2; ++ unsigned ep_dir14 : 2; ++ unsigned ep_dir13 : 2; ++ unsigned ep_dir12 : 2; ++ unsigned ep_dir11 : 2; ++ unsigned ep_dir10 : 2; ++ unsigned ep_dir9 : 2; ++ unsigned ep_dir8 : 2; ++ unsigned ep_dir7 : 2; ++ unsigned ep_dir6 : 2; ++ unsigned ep_dir5 : 2; ++ unsigned ep_dir4 : 2; ++ unsigned ep_dir3 : 2; ++ unsigned ep_dir2 : 2; ++ unsigned ep_dir1 : 2; ++ unsigned ep_dir0 : 2; ++ } b; ++} hwcfg1_data_t; ++ ++/** ++ * This union represents the bit fields in the User HW Config2 ++ * Register. Read the register into the <i>d32</i> element then read ++ * out the bits using the <i>b</i>it elements. ++ */ ++typedef union hwcfg2_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /* GHWCFG2 */ ++ unsigned reserved31 : 1; ++ unsigned dev_token_q_depth : 5; ++ unsigned host_perio_tx_q_depth : 2; ++ unsigned nonperio_tx_q_depth : 2; ++ unsigned rx_status_q_depth : 2; ++ unsigned dynamic_fifo : 1; ++ unsigned perio_ep_supported : 1; ++ unsigned num_host_chan : 4; ++ unsigned num_dev_ep : 4; ++ unsigned fs_phy_type : 2; ++#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 ++#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1 ++#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2 ++#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 ++ unsigned hs_phy_type : 2; ++ unsigned point2point : 1; ++ unsigned architecture : 2; ++#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 ++#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 ++#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 ++#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 ++#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 ++#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 ++#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 ++ unsigned op_mode : 3; ++ } b; ++} hwcfg2_data_t; ++ ++/** ++ * This union represents the bit fields in the User HW Config3 ++ * Register. Read the register into the <i>d32</i> element then read ++ * out the bits using the <i>b</i>it elements. ++ */ ++typedef union hwcfg3_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /* GHWCFG3 */ ++ unsigned dfifo_depth : 16; ++ unsigned reserved15_13 : 3; ++ unsigned ahb_phy_clock_synch : 1; ++ unsigned synch_reset_type : 1; ++ unsigned optional_features : 1; ++ unsigned vendor_ctrl_if : 1; ++ unsigned i2c : 1; ++ unsigned otg_func : 1; ++ unsigned packet_size_cntr_width : 3; ++ unsigned xfer_size_cntr_width : 4; ++ } b; ++} hwcfg3_data_t; ++ ++/** ++ * This union represents the 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 ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++unsigned reserved31_30 : 2; /* fscz */ ++ unsigned num_in_eps : 4; ++ unsigned ded_fifo_en : 1; ++ ++ unsigned session_end_filt_en : 1; ++ unsigned b_valid_filt_en : 1; ++ unsigned a_valid_filt_en : 1; ++ unsigned vbus_valid_filt_en : 1; ++ unsigned iddig_filt_en : 1; ++ unsigned num_dev_mode_ctrl_ep : 4; ++ unsigned utmi_phy_data_width : 2; ++ unsigned min_ahb_freq : 9; ++ unsigned power_optimiz : 1; ++ unsigned num_dev_perio_in_ep : 4; ++ } b; ++} hwcfg4_data_t; ++ ++//////////////////////////////////////////// ++// Device Registers ++/** ++ * Device Global Registers. <i>Offsets 800h-BFFh</i> ++ * ++ * The following structures define the size and relative field offsets ++ * for the Device Mode Registers. ++ * ++ * <i>These registers are visible only in Device mode and must not be ++ * accessed in Host mode, as the results are unknown.</i> ++ */ ++typedef struct dwc_otg_dev_global_regs ++{ ++ /** Device Configuration Register. <i>Offset 800h</i> */ ++ volatile uint32_t dcfg; ++ /** Device Control Register. <i>Offset: 804h</i> */ ++ volatile uint32_t dctl; ++ /** Device Status Register (Read Only). <i>Offset: 808h</i> */ ++ volatile uint32_t dsts; ++ /** Reserved. <i>Offset: 80Ch</i> */ ++ uint32_t unused; ++ /** Device IN Endpoint Common Interrupt Mask ++ * Register. <i>Offset: 810h</i> */ ++ volatile uint32_t diepmsk; ++ /** Device OUT Endpoint Common Interrupt Mask ++ * Register. <i>Offset: 814h</i> */ ++ volatile uint32_t doepmsk; ++ /** Device All Endpoints Interrupt Register. <i>Offset: 818h</i> */ ++ volatile uint32_t daint; ++ /** Device All Endpoints Interrupt Mask Register. <i>Offset: ++ * 81Ch</i> */ ++ volatile uint32_t daintmsk; ++ /** Device IN Token Queue Read Register-1 (Read Only). ++ * <i>Offset: 820h</i> */ ++ volatile uint32_t dtknqr1; ++ /** Device IN Token Queue Read Register-2 (Read Only). ++ * <i>Offset: 824h</i> */ ++ volatile uint32_t dtknqr2; ++ /** Device VBUS discharge Register. <i>Offset: 828h</i> */ ++ volatile uint32_t dvbusdis; ++ /** Device VBUS Pulse Register. <i>Offset: 82Ch</i> */ ++ volatile uint32_t dvbuspulse; ++ /** Device IN Token Queue Read Register-3 (Read Only). ++ * Device Thresholding control register (Read/Write) ++ * <i>Offset: 830h</i> */ ++ volatile uint32_t dtknqr3_dthrctl; ++ /** Device IN Token Queue Read Register-4 (Read Only). / ++ * Device IN EPs empty Inr. Mask Register (Read/Write) ++ * <i>Offset: 834h</i> */ ++ volatile uint32_t dtknqr4_fifoemptymsk; ++} dwc_otg_device_global_regs_t; ++ ++/** ++ * This union represents the bit fields in the Device Configuration ++ * Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. Write the ++ * <i>d32</i> member to the dcfg register. ++ */ ++typedef union dcfg_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved31_23 : 9; ++ /** In Endpoint Mis-match count */ ++ unsigned epmscnt : 5; ++ unsigned reserved13_17 : 5; ++ /** Periodic Frame Interval */ ++#define DWC_DCFG_FRAME_INTERVAL_80 0 ++#define DWC_DCFG_FRAME_INTERVAL_85 1 ++#define DWC_DCFG_FRAME_INTERVAL_90 2 ++#define DWC_DCFG_FRAME_INTERVAL_95 3 ++ unsigned perfrint : 2; ++ /** Device Addresses */ ++ unsigned devaddr : 7; ++ unsigned reserved3 : 1; ++ /** Non Zero Length Status OUT Handshake */ ++#define DWC_DCFG_SEND_STALL 1 ++ unsigned nzstsouthshk : 1; ++ /** Device Speed */ ++ unsigned devspd : 2; ++ } b; ++} dcfg_data_t; ++ ++/** ++ * This union represents the bit fields in the Device Control ++ * Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. ++ */ ++typedef union dctl_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 20; ++ /** Power-On Programming Done */ ++ unsigned pwronprgdone : 1; ++ /** Clear Global OUT NAK */ ++ unsigned cgoutnak : 1; ++ /** Set Global OUT NAK */ ++ unsigned sgoutnak : 1; ++ /** Clear Global Non-Periodic IN NAK */ ++ unsigned cgnpinnak : 1; ++ /** Set Global Non-Periodic IN NAK */ ++ unsigned sgnpinnak : 1; ++ /** Test Control */ ++ unsigned tstctl : 3; ++ /** Global OUT NAK Status */ ++ unsigned goutnaksts : 1; ++ /** Global Non-Periodic IN NAK Status */ ++ unsigned gnpinnaksts : 1; ++ /** Soft Disconnect */ ++ unsigned sftdiscon : 1; ++ /** Remote Wakeup */ ++ unsigned rmtwkupsig : 1; ++ } b; ++} dctl_data_t; ++ ++/** ++ * This union represents the bit fields in the Device Status ++ * Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. ++ */ ++typedef union dsts_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved22_31 : 10; ++ /** Frame or Microframe Number of the received SOF */ ++ unsigned soffn : 14; ++ unsigned reserved4_7: 4; ++ /** Erratic Error */ ++ unsigned errticerr : 1; ++ /** Enumerated Speed */ ++#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 ++#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 ++#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2 ++#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3 ++ unsigned enumspd : 2; ++ /** Suspend Status */ ++ unsigned suspsts : 1; ++ } b; ++} dsts_data_t; ++ ++ ++/** ++ * This union represents the bit fields in the Device IN EP Interrupt ++ * Register and the Device IN EP Common Mask Register. ++ * ++ * - Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. ++ */ ++typedef union diepint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved07_31 : 23; ++ unsigned txfifoundrn : 1; ++ /** IN Endpoint HAK Effective mask */ ++ unsigned emptyintr : 1; ++ /** IN Endpoint NAK Effective mask */ ++ unsigned inepnakeff : 1; ++ /** IN Token Received with EP mismatch mask */ ++ unsigned intknepmis : 1; ++ /** IN Token received with TxF Empty mask */ ++ unsigned intktxfemp : 1; ++ /** TimeOUT Handshake mask (non-ISOC EPs) */ ++ unsigned timeout : 1; ++ /** AHB Error mask */ ++ unsigned ahberr : 1; ++ /** Endpoint disable mask */ ++ unsigned epdisabled : 1; ++ /** Transfer complete mask */ ++ unsigned xfercompl : 1; ++ } b; ++} diepint_data_t; ++/** ++ * This union represents the bit fields in the Device IN EP Common ++ * Interrupt Mask Register. ++ */ ++typedef union diepint_data diepmsk_data_t; ++ ++/** ++ * This union represents the bit fields in the Device OUT EP Interrupt ++ * Registerand Device OUT EP Common Interrupt Mask Register. ++ * ++ * - Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. ++ */ ++typedef union doepint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved04_31 : 27; ++ /** OUT Token Received when Endpoint Disabled */ ++ unsigned outtknepdis : 1; ++ /** Setup Phase Done (contorl EPs) */ ++ unsigned setup : 1; ++ /** AHB Error */ ++ unsigned ahberr : 1; ++ /** Endpoint disable */ ++ unsigned epdisabled : 1; ++ /** Transfer complete */ ++ unsigned xfercompl : 1; ++ } b; ++} doepint_data_t; ++/** ++ * This union represents the bit fields in the Device OUT EP Common ++ * Interrupt Mask Register. ++ */ ++typedef union doepint_data doepmsk_data_t; ++ ++ ++/** ++ * This union represents the bit fields in the Device All EP Interrupt ++ * and Mask Registers. ++ * - Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. ++ */ ++typedef union daint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** OUT Endpoint bits */ ++ unsigned out : 16; ++ /** IN Endpoint bits */ ++ unsigned in : 16; ++ } ep; ++ struct { ++ /** OUT Endpoint bits */ ++ unsigned outep15 : 1; ++ unsigned outep14 : 1; ++ unsigned outep13 : 1; ++ unsigned outep12 : 1; ++ unsigned outep11 : 1; ++ unsigned outep10 : 1; ++ unsigned outep9 : 1; ++ unsigned outep8 : 1; ++ unsigned outep7 : 1; ++ unsigned outep6 : 1; ++ unsigned outep5 : 1; ++ unsigned outep4 : 1; ++ unsigned outep3 : 1; ++ unsigned outep2 : 1; ++ unsigned outep1 : 1; ++ unsigned outep0 : 1; ++ /** IN Endpoint bits */ ++ unsigned inep15 : 1; ++ unsigned inep14 : 1; ++ unsigned inep13 : 1; ++ unsigned inep12 : 1; ++ unsigned inep11 : 1; ++ unsigned inep10 : 1; ++ unsigned inep9 : 1; ++ unsigned inep8 : 1; ++ unsigned inep7 : 1; ++ unsigned inep6 : 1; ++ unsigned inep5 : 1; ++ unsigned inep4 : 1; ++ unsigned inep3 : 1; ++ unsigned inep2 : 1; ++ unsigned inep1 : 1; ++ unsigned inep0 : 1; ++ } b; ++} daint_data_t; ++ ++/** ++ * This union represents the bit fields in the Device IN Token Queue ++ * Read Registers. ++ * - Read the register into the <i>d32</i> member. ++ * - READ-ONLY Register ++ */ ++typedef union dtknq1_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** EP Numbers of IN Tokens 0 ... 4 */ ++ unsigned epnums0_5 : 24; ++ /** write pointer has wrapped. */ ++ unsigned wrap_bit : 1; ++ /** Reserved */ ++ unsigned reserved05_06 : 2; ++ /** In Token Queue Write Pointer */ ++ unsigned intknwptr : 5; ++ }b; ++} dtknq1_data_t; ++ ++/** ++ * This union represents Threshold control Register ++ * - Read and write the register into the <i>d32</i> member. ++ * - READ-WRITABLE Register ++ */ ++typedef union dthrctl_data //* /*fscz */ ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Reserved */ ++ unsigned reserved26_31 : 6; ++ /** Rx Thr. Length */ ++ unsigned rx_thr_len : 9; ++ /** Rx Thr. Enable */ ++ unsigned rx_thr_en : 1; ++ /** Reserved */ ++ unsigned reserved11_15 : 5; ++ /** Tx Thr. Length */ ++ unsigned tx_thr_len : 9; ++ /** ISO Tx Thr. Enable */ ++ unsigned iso_thr_en : 1; ++ /** non ISO Tx Thr. Enable */ ++ unsigned non_iso_thr_en : 1; ++ ++ }b; ++} dthrctl_data_t; ++ ++/** ++ * Device Logical IN Endpoint-Specific Registers. <i>Offsets ++ * 900h-AFCh</i> ++ * ++ * There will be one set of endpoint registers per logical endpoint ++ * implemented. ++ * ++ * <i>These registers are visible only in Device mode and must not be ++ * accessed in Host mode, as the results are unknown.</i> ++ */ ++typedef struct dwc_otg_dev_in_ep_regs ++{ ++ /** Device IN Endpoint Control Register. <i>Offset:900h + ++ * (ep_num * 20h) + 00h</i> */ ++ volatile uint32_t diepctl; ++ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 04h</i> */ ++ uint32_t reserved04; ++ /** Device IN Endpoint Interrupt Register. <i>Offset:900h + ++ * (ep_num * 20h) + 08h</i> */ ++ volatile uint32_t diepint; ++ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 0Ch</i> */ ++ uint32_t reserved0C; ++ /** Device IN Endpoint Transfer Size ++ * Register. <i>Offset:900h + (ep_num * 20h) + 10h</i> */ ++ volatile uint32_t dieptsiz; ++ /** Device IN Endpoint DMA Address Register. <i>Offset:900h + ++ * (ep_num * 20h) + 14h</i> */ ++ volatile uint32_t diepdma; ++ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 18h - 900h + ++ * (ep_num * 20h) + 1Ch</i>*/ ++ volatile uint32_t dtxfsts; ++ /** Reserved. <i>Offset:900h + (ep_num * 20h) + 1Ch - 900h + ++ * (ep_num * 20h) + 1Ch</i>*/ ++ uint32_t reserved18; ++} dwc_otg_dev_in_ep_regs_t; ++ ++/** ++ * Device Logical OUT Endpoint-Specific Registers. <i>Offsets: ++ * B00h-CFCh</i> ++ * ++ * There will be one set of endpoint registers per logical endpoint ++ * implemented. ++ * ++ * <i>These registers are visible only in Device mode and must not be ++ * accessed in Host mode, as the results are unknown.</i> ++ */ ++typedef struct dwc_otg_dev_out_ep_regs ++{ ++ /** Device OUT Endpoint Control Register. <i>Offset:B00h + ++ * (ep_num * 20h) + 00h</i> */ ++ volatile uint32_t doepctl; ++ /** Device OUT Endpoint Frame number Register. <i>Offset: ++ * B00h + (ep_num * 20h) + 04h</i> */ ++ volatile uint32_t doepfn; ++ /** Device OUT Endpoint Interrupt Register. <i>Offset:B00h + ++ * (ep_num * 20h) + 08h</i> */ ++ volatile uint32_t doepint; ++ /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 0Ch</i> */ ++ uint32_t reserved0C; ++ /** Device OUT Endpoint Transfer Size Register. <i>Offset: ++ * B00h + (ep_num * 20h) + 10h</i> */ ++ volatile uint32_t doeptsiz; ++ /** Device OUT Endpoint DMA Address Register. <i>Offset:B00h ++ * + (ep_num * 20h) + 14h</i> */ ++ volatile uint32_t doepdma; ++ /** Reserved. <i>Offset:B00h + (ep_num * 20h) + 18h - B00h + ++ * (ep_num * 20h) + 1Ch</i> */ ++ uint32_t unused[2]; ++} dwc_otg_dev_out_ep_regs_t; ++ ++/** ++ * This union represents the bit fields in the Device EP Control ++ * Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. ++ */ ++typedef union depctl_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Endpoint Enable */ ++ unsigned epena : 1; ++ /** Endpoint Disable */ ++ unsigned epdis : 1; ++ /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints) ++ * Writing to this field sets the Endpoint DPID (DPID) ++ * field in this register to DATA1 Set Odd ++ * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints) ++ * Writing to this field sets the Even/Odd ++ * (micro)frame (EO_FrNum) field to odd (micro) frame. ++ */ ++ unsigned setd1pid : 1; ++ /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints) ++ * Writing to this field sets the Endpoint DPID (DPID) ++ * field in this register to DATA0. Set Even ++ * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints) ++ * Writing to this field sets the Even/Odd ++ * (micro)frame (EO_FrNum) field to even (micro) ++ * frame. ++ */ ++ unsigned setd0pid : 1; ++ /** Set NAK */ ++ unsigned snak : 1; ++ /** Clear NAK */ ++ unsigned cnak : 1; ++ /** Tx Fifo Number ++ * IN EPn/IN EP0 ++ * OUT EPn/OUT EP0 - reserved */ ++ unsigned txfnum : 4; ++ /** Stall Handshake */ ++ unsigned stall : 1; ++ /** Snoop Mode ++ * OUT EPn/OUT EP0 ++ * IN EPn/IN EP0 - reserved */ ++ unsigned snp : 1; ++ /** Endpoint Type ++ * 2'b00: Control ++ * 2'b01: Isochronous ++ * 2'b10: Bulk ++ * 2'b11: Interrupt */ ++ unsigned eptype : 2; ++ /** NAK Status */ ++ unsigned naksts : 1; ++ /** Endpoint DPID (INTR/Bulk IN and OUT endpoints) ++ * This field contains the PID of the packet going to ++ * be received or transmitted on this endpoint. The ++ * application should program the PID of the first ++ * packet going to be received or transmitted on this ++ * endpoint , after the endpoint is ++ * activated. Application use the SetD1PID and ++ * SetD0PID fields of this register to program either ++ * D0 or D1 PID. ++ * ++ * The encoding for this field is ++ * - 0: D0 ++ * - 1: D1 ++ */ ++ unsigned dpid : 1; ++ /** USB Active Endpoint */ ++ unsigned usbactep : 1; ++ /** Next Endpoint ++ * IN EPn/IN EP0 ++ * OUT EPn/OUT EP0 - reserved */ ++ unsigned nextep : 4; ++ /** Maximum Packet Size ++ * IN/OUT EPn ++ * IN/OUT EP0 - 2 bits ++ * 2'b00: 64 Bytes ++ * 2'b01: 32 ++ * 2'b10: 16 ++ * 2'b11: 8 */ ++#define DWC_DEP0CTL_MPS_64 0 ++#define DWC_DEP0CTL_MPS_32 1 ++#define DWC_DEP0CTL_MPS_16 2 ++#define DWC_DEP0CTL_MPS_8 3 ++ unsigned mps : 11; ++ } b; ++} depctl_data_t; ++ ++/** ++ * This union represents the bit fields in the Device EP Transfer ++ * Size Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. ++ */ ++typedef union deptsiz_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 1; ++ /** Multi Count - Periodic IN endpoints */ ++ unsigned mc : 2; ++ /** Packet Count */ ++ unsigned pktcnt : 10; ++ /** Transfer size */ ++ unsigned xfersize : 19; ++ } b; ++} deptsiz_data_t; ++ ++/** ++ * This union represents the bit fields in the Device EP 0 Transfer ++ * Size Register. Read the register into the <i>d32</i> member then ++ * set/clear the bits using the <i>b</i>it elements. ++ */ ++typedef union deptsiz0_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved31 : 1; ++ /**Setup Packet Count (DOEPTSIZ0 Only) */ ++ unsigned supcnt : 2; ++ /** Reserved */ ++ unsigned reserved28_20 : 9; ++ /** Packet Count */ ++ unsigned pktcnt : 1; ++ /** Reserved */ ++ unsigned reserved18_7 : 12; ++ /** Transfer size */ ++ unsigned xfersize : 7; ++ } b; ++} deptsiz0_data_t; ++ ++ ++/** Maximum number of Periodic FIFOs */ ++#define MAX_PERIO_FIFOS 15 ++/** Maximum number of TX FIFOs */ ++#define MAX_TX_FIFOS 15 ++/** Maximum number of Endpoints/HostChannels */ ++#define MAX_EPS_CHANNELS 16 ++//#define MAX_EPS_CHANNELS 4 ++ ++/** ++ * The dwc_otg_dev_if structure contains information needed to manage ++ * the DWC_otg controller acting in device mode. It represents the ++ * programming view of the device-specific aspects of the controller. ++ */ ++typedef struct dwc_otg_dev_if { ++ /** Pointer to device Global registers. ++ * Device Global Registers starting at offset 800h ++ */ ++ dwc_otg_device_global_regs_t *dev_global_regs; ++#define DWC_DEV_GLOBAL_REG_OFFSET 0x800 ++ ++ /** ++ * Device Logical IN Endpoint-Specific Registers 900h-AFCh ++ */ ++ dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS]; ++#define DWC_DEV_IN_EP_REG_OFFSET 0x900 ++#define DWC_EP_REG_OFFSET 0x20 ++ ++ /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */ ++ dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS]; ++#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00 ++ ++ /* Device configuration information*/ ++ uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */ ++ //uint8_t num_eps; /**< Number of EPs range: 0-16 (includes EP0) */ ++ //uint8_t num_perio_eps; /**< # of Periodic EP range: 0-15 */ ++ /*fscz */ ++ uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */ ++ uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/ ++ ++ /** Size of periodic FIFOs (Bytes) */ ++ uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS]; ++ ++ /** Size of Tx FIFOs (Bytes) */ ++ uint16_t tx_fifo_size[MAX_TX_FIFOS]; ++ ++ /** Thresholding enable flags and length varaiables **/ ++ uint16_t rx_thr_en; ++ uint16_t iso_tx_thr_en; ++ uint16_t non_iso_tx_thr_en; ++ ++ uint16_t rx_thr_length; ++ uint16_t tx_thr_length; ++} dwc_otg_dev_if_t; ++ ++/** ++ * This union represents the bit fields in the Power and Clock Gating Control ++ * Register. Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. ++ */ ++typedef union pcgcctl_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned reserved31_05 : 27; ++ /** PHY Suspended */ ++ unsigned physuspended : 1; ++ /** Reset Power Down Modules */ ++ unsigned rstpdwnmodule : 1; ++ /** Power Clamp */ ++ unsigned pwrclmp : 1; ++ /** Gate Hclk */ ++ unsigned gatehclk : 1; ++ /** Stop Pclk */ ++ unsigned stoppclk : 1; ++ } b; ++} pcgcctl_data_t; ++ ++///////////////////////////////////////////////// ++// Host Mode Register Structures ++// ++/** ++ * The Host Global Registers structure defines the size and relative ++ * field offsets for the Host Mode Global Registers. Host Global ++ * Registers offsets 400h-7FFh. ++*/ ++typedef struct dwc_otg_host_global_regs ++{ ++ /** Host Configuration Register. <i>Offset: 400h</i> */ ++ volatile uint32_t hcfg; ++ /** Host Frame Interval Register. <i>Offset: 404h</i> */ ++ volatile uint32_t hfir; ++ /** Host Frame Number / Frame Remaining Register. <i>Offset: 408h</i> */ ++ volatile uint32_t hfnum; ++ /** Reserved. <i>Offset: 40Ch</i> */ ++ uint32_t reserved40C; ++ /** Host Periodic Transmit FIFO/ Queue Status Register. <i>Offset: 410h</i> */ ++ volatile uint32_t hptxsts; ++ /** Host All Channels Interrupt Register. <i>Offset: 414h</i> */ ++ volatile uint32_t haint; ++ /** Host All Channels Interrupt Mask Register. <i>Offset: 418h</i> */ ++ volatile uint32_t haintmsk; ++} dwc_otg_host_global_regs_t; ++ ++/** ++ * This union represents the bit fields in the Host Configuration Register. ++ * Read the register into the <i>d32</i> member then set/clear the bits using ++ * the <i>b</i>it elements. Write the <i>d32</i> member to the hcfg register. ++ */ ++typedef union hcfg_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Reserved */ ++ //unsigned reserved31_03 : 29; ++ /** FS/LS Only Support */ ++ unsigned fslssupp : 1; ++ /** FS/LS Phy Clock Select */ ++#define DWC_HCFG_30_60_MHZ 0 ++#define DWC_HCFG_48_MHZ 1 ++#define DWC_HCFG_6_MHZ 2 ++ unsigned fslspclksel : 2; ++ } b; ++} hcfg_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Frame Remaing/Number ++ * Register. ++ */ ++typedef union hfir_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned reserved : 16; ++ unsigned frint : 16; ++ } b; ++} hfir_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Frame Remaing/Number ++ * Register. ++ */ ++typedef union hfnum_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned frrem : 16; ++#define DWC_HFNUM_MAX_FRNUM 0x3FFF ++ unsigned frnum : 16; ++ } b; ++} hfnum_data_t; ++ ++typedef union hptxsts_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Top of the Periodic Transmit Request Queue ++ * - bit 24 - Terminate (last entry for the selected channel) ++ * - bits 26:25 - Token Type ++ * - 2'b00 - Zero length ++ * - 2'b01 - Ping ++ * - 2'b10 - Disable ++ * - bits 30:27 - Channel Number ++ * - bit 31 - Odd/even microframe ++ */ ++ unsigned ptxqtop_odd : 1; ++ unsigned ptxqtop_chnum : 4; ++ unsigned ptxqtop_token : 2; ++ unsigned ptxqtop_terminate : 1; ++ unsigned ptxqspcavail : 8; ++ unsigned ptxfspcavail : 16; ++ } b; ++} hptxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Port Control and Status ++ * Register. Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the ++ * hprt0 register. ++ */ ++typedef union hprt0_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved19_31 : 13; ++#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0 ++#define DWC_HPRT0_PRTSPD_FULL_SPEED 1 ++#define DWC_HPRT0_PRTSPD_LOW_SPEED 2 ++ unsigned prtspd : 2; ++ unsigned prttstctl : 4; ++ unsigned prtpwr : 1; ++ unsigned prtlnsts : 2; ++ unsigned reserved9 : 1; ++ unsigned prtrst : 1; ++ unsigned prtsusp : 1; ++ unsigned prtres : 1; ++ unsigned prtovrcurrchng : 1; ++ unsigned prtovrcurract : 1; ++ unsigned prtenchng : 1; ++ unsigned prtena : 1; ++ unsigned prtconndet : 1; ++ unsigned prtconnsts : 1; ++ } b; ++} hprt0_data_t; ++ ++/** ++ * This union represents the bit fields in the Host All Interrupt ++ * Register. ++ */ ++typedef union haint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 16; ++ unsigned ch15 : 1; ++ unsigned ch14 : 1; ++ unsigned ch13 : 1; ++ unsigned ch12 : 1; ++ unsigned ch11 : 1; ++ unsigned ch10 : 1; ++ unsigned ch9 : 1; ++ unsigned ch8 : 1; ++ unsigned ch7 : 1; ++ unsigned ch6 : 1; ++ unsigned ch5 : 1; ++ unsigned ch4 : 1; ++ unsigned ch3 : 1; ++ unsigned ch2 : 1; ++ unsigned ch1 : 1; ++ unsigned ch0 : 1; ++ } b; ++ struct { ++ unsigned reserved : 16; ++ unsigned chint : 16; ++ } b2; ++} haint_data_t; ++ ++/** ++ * This union represents the bit fields in the Host All Interrupt ++ * Register. ++ */ ++typedef union haintmsk_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved : 16; ++ unsigned ch15 : 1; ++ unsigned ch14 : 1; ++ unsigned ch13 : 1; ++ unsigned ch12 : 1; ++ unsigned ch11 : 1; ++ unsigned ch10 : 1; ++ unsigned ch9 : 1; ++ unsigned ch8 : 1; ++ unsigned ch7 : 1; ++ unsigned ch6 : 1; ++ unsigned ch5 : 1; ++ unsigned ch4 : 1; ++ unsigned ch3 : 1; ++ unsigned ch2 : 1; ++ unsigned ch1 : 1; ++ unsigned ch0 : 1; ++ } b; ++ struct { ++ unsigned reserved : 16; ++ unsigned chint : 16; ++ } b2; ++} haintmsk_data_t; ++ ++/** ++ * Host Channel Specific Registers. <i>500h-5FCh</i> ++ */ ++typedef struct dwc_otg_hc_regs ++{ ++ /** Host Channel 0 Characteristic Register. <i>Offset: 500h + (chan_num * 20h) + 00h</i> */ ++ volatile uint32_t hcchar; ++ /** Host Channel 0 Split Control Register. <i>Offset: 500h + (chan_num * 20h) + 04h</i> */ ++ volatile uint32_t hcsplt; ++ /** Host Channel 0 Interrupt Register. <i>Offset: 500h + (chan_num * 20h) + 08h</i> */ ++ volatile uint32_t hcint; ++ /** Host Channel 0 Interrupt Mask Register. <i>Offset: 500h + (chan_num * 20h) + 0Ch</i> */ ++ volatile uint32_t hcintmsk; ++ /** Host Channel 0 Transfer Size Register. <i>Offset: 500h + (chan_num * 20h) + 10h</i> */ ++ volatile uint32_t hctsiz; ++ /** Host Channel 0 DMA Address Register. <i>Offset: 500h + (chan_num * 20h) + 14h</i> */ ++ volatile uint32_t hcdma; ++ /** Reserved. <i>Offset: 500h + (chan_num * 20h) + 18h - 500h + (chan_num * 20h) + 1Ch</i> */ ++ uint32_t reserved[2]; ++} dwc_otg_hc_regs_t; ++ ++/** ++ * This union represents the bit fields in the Host Channel Characteristics ++ * Register. Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the ++ * hcchar register. ++ */ ++typedef union hcchar_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Channel enable */ ++ unsigned chen : 1; ++ /** Channel disable */ ++ unsigned chdis : 1; ++ /** ++ * Frame to transmit periodic transaction. ++ * 0: even, 1: odd ++ */ ++ unsigned oddfrm : 1; ++ /** Device address */ ++ unsigned devaddr : 7; ++ /** Packets per frame for periodic transfers. 0 is reserved. */ ++ unsigned multicnt : 2; ++ /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */ ++ unsigned eptype : 2; ++ /** 0: Full/high speed device, 1: Low speed device */ ++ unsigned lspddev : 1; ++ unsigned reserved : 1; ++ /** 0: OUT, 1: IN */ ++ unsigned epdir : 1; ++ /** Endpoint number */ ++ unsigned epnum : 4; ++ /** Maximum packet size in bytes */ ++ unsigned mps : 11; ++ } b; ++} hcchar_data_t; ++ ++typedef union hcsplt_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Split Enble */ ++ unsigned spltena : 1; ++ /** Reserved */ ++ unsigned reserved : 14; ++ /** Do Complete Split */ ++ unsigned compsplt : 1; ++ /** Transaction Position */ ++#define DWC_HCSPLIT_XACTPOS_MID 0 ++#define DWC_HCSPLIT_XACTPOS_END 1 ++#define DWC_HCSPLIT_XACTPOS_BEGIN 2 ++#define DWC_HCSPLIT_XACTPOS_ALL 3 ++ unsigned xactpos : 2; ++ /** Hub Address */ ++ unsigned hubaddr : 7; ++ /** Port Address */ ++ unsigned prtaddr : 7; ++ } b; ++} hcsplt_data_t; ++ ++ ++/** ++ * This union represents the bit fields in the Host All Interrupt ++ * Register. ++ */ ++typedef union hcint_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Reserved */ ++ unsigned reserved : 21; ++ /** Data Toggle Error */ ++ unsigned datatglerr : 1; ++ /** Frame Overrun */ ++ unsigned frmovrun : 1; ++ /** Babble Error */ ++ unsigned bblerr : 1; ++ /** Transaction Err */ ++ unsigned xacterr : 1; ++ /** NYET Response Received */ ++ unsigned nyet : 1; ++ /** ACK Response Received */ ++ unsigned ack : 1; ++ /** NAK Response Received */ ++ unsigned nak : 1; ++ /** STALL Response Received */ ++ unsigned stall : 1; ++ /** AHB Error */ ++ unsigned ahberr : 1; ++ /** Channel Halted */ ++ unsigned chhltd : 1; ++ /** Transfer Complete */ ++ unsigned xfercomp : 1; ++ } b; ++} hcint_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Channel Transfer Size ++ * Register. Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the ++ * hcchar register. ++ */ ++typedef union hctsiz_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Do PING protocol when 1 */ ++ unsigned dopng : 1; ++ /** ++ * Packet ID for next data packet ++ * 0: DATA0 ++ * 1: DATA2 ++ * 2: DATA1 ++ * 3: MDATA (non-Control), SETUP (Control) ++ */ ++#define DWC_HCTSIZ_DATA0 0 ++#define DWC_HCTSIZ_DATA1 2 ++#define DWC_HCTSIZ_DATA2 1 ++#define DWC_HCTSIZ_MDATA 3 ++#define DWC_HCTSIZ_SETUP 3 ++ unsigned pid : 2; ++ /** Data packets to transfer */ ++ unsigned pktcnt : 10; ++ /** Total transfer size in bytes */ ++ unsigned xfersize : 19; ++ } b; ++} hctsiz_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Channel Interrupt Mask ++ * Register. Read the register into the <i>d32</i> member then set/clear the ++ * bits using the <i>b</i>it elements. Write the <i>d32</i> member to the ++ * hcintmsk register. ++ */ ++typedef union hcintmsk_data ++{ ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned reserved : 21; ++ unsigned datatglerr : 1; ++ unsigned frmovrun : 1; ++ unsigned bblerr : 1; ++ unsigned xacterr : 1; ++ unsigned nyet : 1; ++ unsigned ack : 1; ++ unsigned nak : 1; ++ unsigned stall : 1; ++ unsigned ahberr : 1; ++ unsigned chhltd : 1; ++ unsigned xfercompl : 1; ++ } b; ++} hcintmsk_data_t; ++ ++/** OTG Host Interface Structure. ++ * ++ * The OTG Host Interface Structure structure contains information ++ * needed to manage the DWC_otg controller acting in host mode. It ++ * represents the programming view of the host-specific aspects of the ++ * controller. ++ */ ++typedef struct dwc_otg_host_if { ++ /** Host Global Registers starting at offset 400h.*/ ++ dwc_otg_host_global_regs_t *host_global_regs; ++#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400 ++ ++ /** Host Port 0 Control and Status Register */ ++ volatile uint32_t *hprt0; ++#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440 ++ ++ ++ /** Host Channel Specific Registers at offsets 500h-5FCh. */ ++ dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS]; ++#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500 ++#define DWC_OTG_CHAN_REGS_OFFSET 0x20 ++ ++ ++ /* Host configuration information */ ++ /** Number of Host Channels (range: 1-16) */ ++ uint8_t num_host_channels; ++ /** Periodic EPs supported (0: no, 1: yes) */ ++ uint8_t perio_eps_supported; ++ /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */ ++ uint16_t perio_tx_fifo_size; ++ ++} dwc_otg_host_if_t; ++ ++#endif +--- a/arch/mips/lantiq/xway/Makefile ++++ b/arch/mips/lantiq/xway/Makefile +@@ -6,3 +6,4 @@ + obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o + obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o + obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o ++obj-y += dev-dwc_otg.o +--- /dev/null ++++ b/arch/mips/lantiq/xway/dev-dwc_otg.c +@@ -0,0 +1,70 @@ ++/* ++ * 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) 2010 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> ++ ++#define LTQ_USB_IOMEM_BASE 0x1e101000 ++#define LTQ_USB_IOMEM_SIZE 0x00001000 ++ ++static struct resource resources[] = ++{ ++ [0] = { ++ .name = "dwc_otg_membase", ++ .start = LTQ_USB_IOMEM_BASE, ++ .end = LTQ_USB_IOMEM_BASE + LTQ_USB_IOMEM_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .name = "dwc_otg_irq", ++ .start = LTQ_USB_INT, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static u64 dwc_dmamask = (u32)0x1fffffff; ++ ++static struct platform_device platform_dev = { ++ .name = "dwc_otg", ++ .dev = { ++ .dma_mask = &dwc_dmamask, ++ }, ++ .resource = resources, ++ .num_resources = ARRAY_SIZE(resources), ++}; ++ ++int __init ++xway_register_dwc(int pin) ++{ ++ struct irq_data d; ++ d.irq = resources[1].start; ++ ltq_enable_irq(&d); ++ platform_dev.dev.platform_data = (void*) pin; ++ return platform_device_register(&platform_dev); ++} +--- /dev/null ++++ b/arch/mips/lantiq/xway/dev-dwc_otg.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) 2010 John Crispin <blogic@openwrt.org> ++ */ ++ ++#ifndef _LTQ_DEV_DWC_H__ ++#define _LTQ_DEV_DWC_H__ ++ ++#include <lantiq_platform.h> ++ ++extern void __init xway_register_dwc(int pin); ++ ++#endif +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -2812,11 +2812,11 @@ + udev->ttport = hdev->ttport; + } else if (udev->speed != USB_SPEED_HIGH + && hdev->speed == USB_SPEED_HIGH) { +- if (!hub->tt.hub) { ++/* if (!hub->tt.hub) { + dev_err(&udev->dev, "parent hub has no TT\n"); + retval = -EINVAL; + goto fail; +- } ++ }*/ + udev->tt = &hub->tt; + udev->ttport = port1; + } diff --git a/target/linux/lantiq/patches-2.6.39/560-dev-leds-gpio.patch b/target/linux/lantiq/patches-2.6.39/560-dev-leds-gpio.patch new file mode 100644 index 0000000..a66dc0d --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/560-dev-leds-gpio.patch @@ -0,0 +1,95 @@ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/dev-leds-gpio.h +@@ -0,0 +1,21 @@ ++/* ++ * Lantiq GPIO LED device support ++ * ++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#ifndef _LANTIQ_DEV_LEDS_GPIO_H ++#define _LANTIQ_DEV_LEDS_GPIO_H ++ ++#include <linux/leds.h> ++ ++void ltq_add_device_leds_gpio(int id, ++ unsigned num_leds, ++ struct gpio_led *leds) __init; ++ ++#endif /* _LANTIQ_DEV_LEDS_GPIO_H */ +--- /dev/null ++++ b/arch/mips/lantiq/dev-leds-gpio.c +@@ -0,0 +1,57 @@ ++/* ++ * Lantiq GPIO LED device support ++ * ++ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> ++ * ++ * Parts of this file are based on Atheros' 2.6.15 BSP ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/platform_device.h> ++ ++#include "dev-leds-gpio.h" ++ ++void __init ltq_add_device_leds_gpio(int id, unsigned num_leds, ++ struct gpio_led *leds) ++{ ++ struct platform_device *pdev; ++ struct gpio_led_platform_data pdata; ++ struct gpio_led *p; ++ int err; ++ ++ p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL); ++ if (!p) ++ return; ++ ++ memcpy(p, leds, num_leds * sizeof(*p)); ++ ++ pdev = platform_device_alloc("leds-gpio", id); ++ if (!pdev) ++ goto err_free_leds; ++ ++ memset(&pdata, 0, sizeof(pdata)); ++ pdata.num_leds = num_leds; ++ pdata.leds = p; ++ ++ err = platform_device_add_data(pdev, &pdata, sizeof(pdata)); ++ if (err) ++ goto err_put_pdev; ++ ++ err = platform_device_add(pdev); ++ if (err) ++ goto err_put_pdev; ++ ++ return; ++ ++err_put_pdev: ++ platform_device_put(pdev); ++ ++err_free_leds: ++ kfree(p); ++} +--- a/arch/mips/lantiq/Makefile ++++ b/arch/mips/lantiq/Makefile +@@ -4,7 +4,7 @@ + # under the terms of the GNU General Public License version 2 as published + # by the Free Software Foundation. + +-obj-y := irq.o setup.o clk.o prom.o devices.o ++obj-y := irq.o setup.o clk.o prom.o devices.o dev-leds-gpio.o + + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + diff --git a/target/linux/lantiq/patches-2.6.39/570-gpio_fix.patch b/target/linux/lantiq/patches-2.6.39/570-gpio_fix.patch new file mode 100644 index 0000000..a058355 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/570-gpio_fix.patch @@ -0,0 +1,20 @@ +--- a/arch/mips/lantiq/xway/gpio_ebu.c ++++ b/arch/mips/lantiq/xway/gpio_ebu.c +@@ -63,7 +63,6 @@ + .set = ltq_ebu_set, + .base = 72, + .ngpio = 16, +- .can_sleep = 1, + .owner = THIS_MODULE, + }; + +--- a/arch/mips/lantiq/xway/gpio_stp.c ++++ b/arch/mips/lantiq/xway/gpio_stp.c +@@ -72,7 +72,6 @@ + .set = ltq_stp_set, + .base = 48, + .ngpio = 24, +- .can_sleep = 1, + .owner = THIS_MODULE, + }; + diff --git a/target/linux/lantiq/patches-2.6.39/990-fix_include.patch b/target/linux/lantiq/patches-2.6.39/990-fix_include.patch new file mode 100644 index 0000000..332ba93 --- /dev/null +++ b/target/linux/lantiq/patches-2.6.39/990-fix_include.patch @@ -0,0 +1,43 @@ +--- /dev/null ++++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +@@ -0,0 +1,40 @@ ++/* ++ * 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> ++ */ ++ ++#ifndef _LTQ_FALCON_H__ ++#define _LTQ_FALCON_H__ ++ ++#ifdef CONFIG_SOC_FALCON ++ ++#include <lantiq.h> ++ ++/* Chip IDs */ ++#define SOC_ID_FALCON 0x01B8 ++ ++/* SoC Types */ ++#define SOC_TYPE_FALCON 0x01 ++ ++/* ASC0/1 - serial port */ ++#define LTQ_ASC0_BASE_ADDR 0x1E100C00 ++#define LTQ_ASC1_BASE_ADDR 0x1E100B00 ++#define LTQ_ASC_SIZE 0x100 ++ ++#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8)) ++#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1) ++#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2) ++ ++/* ICU - interrupt control unit */ ++#define LTQ_ICU_BASE_ADDR 0x1F880200 ++#define LTQ_ICU_SIZE 0x100 ++ ++/* WDT */ ++#define LTQ_WDT_BASE_ADDR 0x1F8803F0 ++#define LTQ_WDT_SIZE 0x10 ++ ++#endif /* CONFIG_SOC_FALCON */ ++#endif /* _LTQ_XWAY_H__ */ diff --git a/target/linux/lantiq/patches/000-mips-bad-intctl.patch b/target/linux/lantiq/patches/000-mips-bad-intctl.patch deleted file mode 100644 index 7c0f52d..0000000 --- a/target/linux/lantiq/patches/000-mips-bad-intctl.patch +++ /dev/null @@ -1,35 +0,0 @@ ---- a/arch/mips/kernel/traps.c -+++ b/arch/mips/kernel/traps.c -@@ -1496,7 +1496,18 @@ void __cpuinit per_cpu_trap_init(void) - if (cpu_has_mips_r2) { - cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP; - cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7; -+ -+ if (!cp0_compare_irq) -+ cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ; -+ - cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7; -+ -+ if (!cp0_perfcount_irq) -+ cp0_perfcount_irq = CP0_LEGACY_PERFCNT_IRQ; -+ -+ if (arch_fixup_c0_irqs) -+ arch_fixup_c0_irqs(); -+ - if (cp0_perfcount_irq == cp0_compare_irq) - cp0_perfcount_irq = -1; - } else { ---- a/arch/mips/include/asm/irq.h -+++ b/arch/mips/include/asm/irq.h -@@ -133,9 +133,11 @@ extern void free_irqno(unsigned int irq) - * IE7. Since R2 their number has to be read from the c0_intctl register. - */ - #define CP0_LEGACY_COMPARE_IRQ 7 -+#define CP0_LEGACY_PERFCNT_IRQ 7 - - extern int cp0_compare_irq; - extern int cp0_compare_irq_shift; - extern int cp0_perfcount_irq; -+extern void __weak arch_fixup_c0_irqs(void); - - #endif /* _ASM_IRQ_H */ diff --git a/target/linux/lantiq/patches/010-mips_clocksource_init_war.patch b/target/linux/lantiq/patches/010-mips_clocksource_init_war.patch deleted file mode 100644 index 1670ccb..0000000 --- a/target/linux/lantiq/patches/010-mips_clocksource_init_war.patch +++ /dev/null @@ -1,33 +0,0 @@ ---- a/arch/mips/kernel/cevt-r4k.c -+++ b/arch/mips/kernel/cevt-r4k.c -@@ -23,6 +23,22 @@ - - #ifndef CONFIG_MIPS_MT_SMTC - -+/* -+ * Compare interrupt can be routed and latched outside the core, -+ * so a single execution hazard barrier may not be enough to give -+ * it time to clear as seen in the Cause register. 4 time the -+ * pipeline depth seems reasonably conservative, and empirically -+ * works better in configurations with high CPU/bus clock ratios. -+ */ -+ -+#define compare_change_hazard() \ -+ do { \ -+ irq_disable_hazard(); \ -+ irq_disable_hazard(); \ -+ irq_disable_hazard(); \ -+ irq_disable_hazard(); \ -+ } while (0) -+ - static int mips_next_event(unsigned long delta, - struct clock_event_device *evt) - { -@@ -32,6 +48,7 @@ - cnt = read_c0_count(); - cnt += delta; - write_c0_compare(cnt); -+ compare_change_hazard(); - res = ((int)(read_c0_count() - cnt) >= 0) ? -ETIME : 0; - return res; - } diff --git a/target/linux/lantiq/patches/020-genirq_fix.patch b/target/linux/lantiq/patches/020-genirq_fix.patch deleted file mode 100644 index ebb369f..0000000 --- a/target/linux/lantiq/patches/020-genirq_fix.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- a/kernel/irq/chip.c -+++ b/kernel/irq/chip.c -@@ -678,6 +678,9 @@ - - kstat_incr_irqs_this_cpu(irq, desc); - -+ if (unlikely(!desc->action || (desc->status & IRQ_DISABLED))) -+ return; -+ - if (desc->irq_data.chip->irq_ack) - desc->irq_data.chip->irq_ack(&desc->irq_data); - diff --git a/target/linux/lantiq/patches/100-board.patch b/target/linux/lantiq/patches/100-board.patch deleted file mode 100644 index d22f586..0000000 --- a/target/linux/lantiq/patches/100-board.patch +++ /dev/null @@ -1,649 +0,0 @@ ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -157,6 +157,9 @@ - - otherwise choose R3000. - -+config LANTIQ -+ bool "Lantiq MIPS" -+ - config MACH_JAZZ - bool "Jazz family of machines" - select ARC -@@ -729,6 +732,7 @@ - source "arch/mips/vr41xx/Kconfig" - source "arch/mips/cavium-octeon/Kconfig" - source "arch/mips/loongson/Kconfig" -+source "arch/mips/lantiq/Kconfig" - - endmenu - ---- /dev/null -+++ b/arch/mips/lantiq/Kconfig -@@ -0,0 +1,36 @@ -+if LANTIQ -+ -+config SOC_LANTIQ -+ bool -+ select DMA_NONCOHERENT -+ select IRQ_CPU -+ select CEVT_R4K -+ select CSRC_R4K -+ select SYS_HAS_CPU_MIPS32_R1 -+ select SYS_HAS_CPU_MIPS32_R2 -+ select SYS_SUPPORTS_BIG_ENDIAN -+ select SYS_SUPPORTS_32BIT_KERNEL -+ select SYS_SUPPORTS_MULTITHREADING -+ select SYS_HAS_EARLY_PRINTK -+ select HW_HAS_PCI -+ select ARCH_REQUIRE_GPIOLIB -+ select SWAP_IO_SPACE -+ select MIPS_MACHINE -+ -+choice -+ prompt "SoC Type" -+ default SOC_LANTIQ_XWAY -+ -+#config SOC_LANTIQ_FALCON -+# bool "FALCON" -+# select SOC_LANTIQ -+ -+config SOC_LANTIQ_XWAY -+ bool "XWAY" -+ select SOC_LANTIQ -+endchoice -+ -+#source "arch/mips/lantiq/falcon/Kconfig" -+source "arch/mips/lantiq/xway/Kconfig" -+ -+endif ---- /dev/null -+++ b/arch/mips/lantiq/Makefile -@@ -0,0 +1,3 @@ -+obj-y := irq.o setup.o clk.o prom.o -+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -+obj-$(CONFIG_SOC_LANTIQ_XWAY) += xway/ ---- /dev/null -+++ b/arch/mips/lantiq/irq.c -@@ -0,0 +1,218 @@ -+/* -+ * 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/interrupt.h> -+ -+#include <asm/bootinfo.h> -+#include <asm/irq_cpu.h> -+ -+#include <lantiq.h> -+#include <irq.h> -+ -+#define LQ_ICU_BASE_ADDR (KSEG1 | 0x1F880200) -+ -+#define LQ_ICU_IM0_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0000)) -+#define LQ_ICU_IM0_IER ((u32 *)(LQ_ICU_BASE_ADDR + 0x0008)) -+#define LQ_ICU_IM0_IOSR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0010)) -+#define LQ_ICU_IM0_IRSR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0018)) -+#define LQ_ICU_IM0_IMR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0020)) -+ -+#define LQ_ICU_IM1_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0028)) -+#define LQ_ICU_IM2_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0050)) -+#define LQ_ICU_IM3_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x0078)) -+#define LQ_ICU_IM4_ISR ((u32 *)(LQ_ICU_BASE_ADDR + 0x00A0)) -+ -+#define LQ_ICU_OFFSET (LQ_ICU_IM1_ISR - LQ_ICU_IM0_ISR) -+ -+#define LQ_EBU_BASE_ADDR 0xBE105300 -+#define LQ_EBU_PCC_ISTAT ((u32 *)(LQ_EBU_BASE_ADDR + 0x00A0)) -+ -+void -+lq_disable_irq(unsigned int irq_nr) -+{ -+ u32 *ier = LQ_ICU_IM0_IER; -+ irq_nr -= INT_NUM_IRQ0; -+ ier += LQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); -+ irq_nr %= INT_NUM_IM_OFFSET; -+ lq_w32(lq_r32(ier) & ~(1 << irq_nr), ier); -+} -+EXPORT_SYMBOL(lq_disable_irq); -+ -+void -+lq_mask_and_ack_irq(unsigned int irq_nr) -+{ -+ u32 *ier = LQ_ICU_IM0_IER; -+ u32 *isr = LQ_ICU_IM0_ISR; -+ irq_nr -= INT_NUM_IRQ0; -+ ier += LQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); -+ isr += LQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); -+ irq_nr %= INT_NUM_IM_OFFSET; -+ lq_w32(lq_r32(ier) & ~(1 << irq_nr), ier); -+ lq_w32((1 << irq_nr), isr); -+} -+EXPORT_SYMBOL(lq_mask_and_ack_irq); -+ -+static void -+lq_ack_irq(unsigned int irq_nr) -+{ -+ u32 *isr = LQ_ICU_IM0_ISR; -+ irq_nr -= INT_NUM_IRQ0; -+ isr += LQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); -+ irq_nr %= INT_NUM_IM_OFFSET; -+ lq_w32((1 << irq_nr), isr); -+} -+ -+void -+lq_enable_irq(unsigned int irq_nr) -+{ -+ u32 *ier = LQ_ICU_IM0_IER; -+ irq_nr -= INT_NUM_IRQ0; -+ ier += LQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET); -+ irq_nr %= INT_NUM_IM_OFFSET; -+ lq_w32(lq_r32(ier) | (1 << irq_nr), ier); -+} -+EXPORT_SYMBOL(lq_enable_irq); -+ -+static unsigned int -+lq_startup_irq(unsigned int irq) -+{ -+ lq_enable_irq(irq); -+ return 0; -+} -+ -+static void -+lq_end_irq(unsigned int irq) -+{ -+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) -+ lq_enable_irq(irq); -+} -+ -+static struct irq_chip -+lq_irq_type = { -+ "lq_irq", -+ .startup = lq_startup_irq, -+ .enable = lq_enable_irq, -+ .disable = lq_disable_irq, -+ .unmask = lq_enable_irq, -+ .ack = lq_ack_irq, -+ .mask = lq_disable_irq, -+ .mask_ack = lq_mask_and_ack_irq, -+ .end = lq_end_irq, -+}; -+ -+static void -+lq_hw_irqdispatch(int module) -+{ -+ u32 irq; -+ -+ irq = lq_r32(LQ_ICU_IM0_IOSR + (module * LQ_ICU_OFFSET)); -+ if (irq == 0) -+ return; -+ -+ /* silicon bug causes only the msb set to 1 to be valid. all -+ other bits might be bogus */ -+ irq = __fls(irq); -+ do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module)); -+ if ((irq == 22) && (module == 0)) -+ lq_w32(lq_r32(LQ_EBU_PCC_ISTAT) | 0x10, -+ LQ_EBU_PCC_ISTAT); -+} -+ -+#define DEFINE_HWx_IRQDISPATCH(x) \ -+static void lq_hw ## x ## _irqdispatch(void)\ -+{\ -+ lq_hw_irqdispatch(x); \ -+} -+static void lq_hw5_irqdispatch(void) -+{ -+ do_IRQ(MIPS_CPU_TIMER_IRQ); -+} -+DEFINE_HWx_IRQDISPATCH(0) -+DEFINE_HWx_IRQDISPATCH(1) -+DEFINE_HWx_IRQDISPATCH(2) -+DEFINE_HWx_IRQDISPATCH(3) -+DEFINE_HWx_IRQDISPATCH(4) -+/*DEFINE_HWx_IRQDISPATCH(5)*/ -+ -+asmlinkage void -+plat_irq_dispatch(void) -+{ -+ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; -+ unsigned int i; -+ -+ if (pending & CAUSEF_IP7) -+ { -+ do_IRQ(MIPS_CPU_TIMER_IRQ); -+ goto out; -+ } else { -+ for (i = 0; i < 5; i++) -+ { -+ if (pending & (CAUSEF_IP2 << i)) -+ { -+ lq_hw_irqdispatch(i); -+ goto out; -+ } -+ } -+ } -+ printk(KERN_ALERT "Spurious IRQ: CAUSE=0x%08x\n", read_c0_status()); -+ -+out: -+ return; -+} -+ -+static struct irqaction -+cascade = { -+ .handler = no_action, -+ .flags = IRQF_DISABLED, -+ .name = "cascade", -+}; -+ -+void __init -+arch_init_irq(void) -+{ -+ int i; -+ -+ for (i = 0; i < 5; i++) -+ lq_w32(0, LQ_ICU_IM0_IER + (i * LQ_ICU_OFFSET)); -+ -+ mips_cpu_irq_init(); -+ -+ for (i = 2; i <= 6; i++) -+ setup_irq(i, &cascade); -+ -+ if (cpu_has_vint) { -+ printk(KERN_INFO "Setting up vectored interrupts\n"); -+ set_vi_handler(2, lq_hw0_irqdispatch); -+ set_vi_handler(3, lq_hw1_irqdispatch); -+ set_vi_handler(4, lq_hw2_irqdispatch); -+ set_vi_handler(5, lq_hw3_irqdispatch); -+ set_vi_handler(6, lq_hw4_irqdispatch); -+ set_vi_handler(7, lq_hw5_irqdispatch); -+ } -+ -+ for (i = INT_NUM_IRQ0; i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++) -+ set_irq_chip_and_handler(i, &lq_irq_type, -+ handle_level_irq); -+ -+ #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); -+ #else -+ set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 | -+ IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5); -+ #endif -+} -+ -+void __cpuinit -+arch_fixup_c0_irqs(void) -+{ -+ /* FIXME: check for CPUID and only do fix for specific chips/versions */ -+ cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ; -+ cp0_perfcount_irq = CP0_LEGACY_PERFCNT_IRQ; -+} ---- /dev/null -+++ b/arch/mips/lantiq/setup.c -@@ -0,0 +1,47 @@ -+/* -+ * 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/kernel.h> -+#include <linux/module.h> -+#include <linux/io.h> -+#include <linux/ioport.h> -+ -+#include <lantiq.h> -+#include <lantiq_regs.h> -+ -+void __init -+plat_mem_setup(void) -+{ -+ /* assume 16M as default */ -+ int memsize = 16; -+ char **envp = (char **) KSEG1ADDR(fw_arg2); -+ u32 status; -+ -+ /* make sure to have no "reverse endian" for user mode! */ -+ status = read_c0_status(); -+ status &= (~(1<<25)); -+ write_c0_status(status); -+ -+ ioport_resource.start = IOPORT_RESOURCE_START; -+ ioport_resource.end = IOPORT_RESOURCE_END; -+ iomem_resource.start = IOMEM_RESOURCE_START; -+ iomem_resource.end = IOMEM_RESOURCE_END; -+ -+ while (*envp) -+ { -+ char *e = (char *)KSEG1ADDR(*envp); -+ if (!strncmp(e, "memsize=", 8)) -+ { -+ e += 8; -+ memsize = simple_strtoul(e, NULL, 10); -+ } -+ envp++; -+ } -+ memsize *= 1024 * 1024; -+ add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); -+} ---- /dev/null -+++ b/arch/mips/lantiq/clk.c -@@ -0,0 +1,141 @@ -+/* -+ * 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 Thomas Langer, Lantiq Deutschland -+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/io.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/types.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/list.h> -+ -+#include <asm/time.h> -+#include <asm/irq.h> -+#include <asm/div64.h> -+ -+#include <lantiq.h> -+#ifdef CONFIG_SOC_LANTIQ_XWAY -+#include <xway.h> -+#endif -+ -+extern unsigned long lq_get_cpu_hz(void); -+extern unsigned long lq_get_fpi_hz(void); -+extern unsigned long lq_get_io_region_clock(void); -+ -+struct clk { -+ const char *name; -+ unsigned long rate; -+ unsigned long (*get_rate) (void); -+}; -+ -+static struct clk *cpu_clk = 0; -+static int cpu_clk_cnt = 0; -+ -+static unsigned int r4k_offset; -+static unsigned int r4k_cur; -+ -+static struct clk cpu_clk_generic[] = { -+ { -+ .name = "cpu", -+ .get_rate = lq_get_cpu_hz, -+ }, { -+ .name = "fpi", -+ .get_rate = lq_get_fpi_hz, -+ }, { -+ .name = "io", -+ .get_rate = lq_get_io_region_clock, -+ }, -+}; -+ -+void -+clk_init(void) -+{ -+ int i; -+ cpu_clk = cpu_clk_generic; -+ cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic); -+ for(i = 0; i < cpu_clk_cnt; i++) -+ printk("%s: %ld\n", cpu_clk[i].name, clk_get_rate(&cpu_clk[i])); -+} -+ -+static inline int -+clk_good(struct clk *clk) -+{ -+ return clk && !IS_ERR(clk); -+} -+ -+unsigned long -+clk_get_rate(struct clk *clk) -+{ -+ if (unlikely(!clk_good(clk))) -+ return 0; -+ -+ if (clk->rate != 0) -+ return clk->rate; -+ -+ if (clk->get_rate != NULL) -+ return clk->get_rate(); -+ -+ return 0; -+} -+EXPORT_SYMBOL(clk_get_rate); -+ -+struct clk* -+clk_get(struct device *dev, const char *id) -+{ -+ int i; -+ for(i = 0; i < cpu_clk_cnt; i++) -+ if (!strcmp(id, cpu_clk[i].name)) -+ return &cpu_clk[i]; -+ BUG(); -+ return ERR_PTR(-ENOENT); -+} -+EXPORT_SYMBOL(clk_get); -+ -+void -+clk_put(struct clk *clk) -+{ -+ /* not used */ -+} -+EXPORT_SYMBOL(clk_put); -+ -+static inline u32 -+lq_get_counter_resolution(void) -+{ -+ u32 res; -+ __asm__ __volatile__( -+ ".set push\n" -+ ".set mips32r2\n" -+ ".set noreorder\n" -+ "rdhwr %0, $3\n" -+ "ehb\n" -+ ".set pop\n" -+ : "=&r" (res) -+ : /* no input */ -+ : "memory"); -+ instruction_hazard(); -+ return res; -+} -+ -+void __init -+plat_time_init(void) -+{ -+ struct clk *clk = clk_get(0, "cpu"); -+ mips_hpt_frequency = clk_get_rate(clk) / lq_get_counter_resolution(); -+ r4k_cur = (read_c0_count() + r4k_offset); -+ write_c0_compare(r4k_cur); -+ -+#ifdef CONFIG_SOC_LANTIQ_XWAY -+#define LQ_GPTU_GPT_CLC ((u32 *)(LQ_GPTU_BASE_ADDR + 0x0000)) -+ lq_pmu_enable(PMU_GPT); -+ lq_pmu_enable(PMU_FPI); -+ -+ lq_w32(0x100, LQ_GPTU_GPT_CLC); -+#endif -+} ---- /dev/null -+++ b/arch/mips/lantiq/prom.c -@@ -0,0 +1,118 @@ -+/* -+ * 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.h> -+ -+#include "prom.h" -+ -+static struct lq_soc_info soc_info; -+ -+/* for Multithreading (APRP) on MIPS34K */ -+unsigned long physical_memsize; -+ -+/* all access to the ebu must be locked */ -+DEFINE_SPINLOCK(ebu_lock); -+EXPORT_SYMBOL_GPL(ebu_lock); -+ -+extern void clk_init(void); -+ -+unsigned int -+lq_get_cpu_ver(void) -+{ -+ return soc_info.rev; -+} -+EXPORT_SYMBOL(lq_get_cpu_ver); -+ -+unsigned int -+lq_get_soc_type(void) -+{ -+ return soc_info.type; -+} -+EXPORT_SYMBOL(lq_get_soc_type); -+ -+const char* -+get_system_type(void) -+{ -+ return soc_info.sys_type; -+} -+ -+void -+prom_free_prom_memory(void) -+{ -+} -+ -+#ifdef CONFIG_IMAGE_CMDLINE_HACK -+extern char __image_cmdline[]; -+ -+static void __init -+prom_init_image_cmdline(void) -+{ -+ char *p = __image_cmdline; -+ int replace = 0; -+ -+ if (*p == '-') { -+ replace = 1; -+ p++; -+ } -+ -+ if (*p == '\0') -+ return; -+ -+ if (replace) { -+ strlcpy(arcs_cmdline, p, sizeof(arcs_cmdline)); -+ } else { -+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); -+ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); -+ } -+} -+#else -+static void __init prom_init_image_cmdline(void) { return; } -+#endif -+ -+static void __init -+prom_init_cmdline(void) -+{ -+ int argc = fw_arg0; -+ char **argv = (char**)KSEG1ADDR(fw_arg1); -+ int i; -+ -+ arcs_cmdline[0] = '\0'; -+ if(argc) -+ for (i = 1; i < argc; i++) -+ { -+ strlcat(arcs_cmdline, (char*)KSEG1ADDR(argv[i]), COMMAND_LINE_SIZE); -+ if(i + 1 != argc) -+ strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE); -+ } -+ -+ if (!*arcs_cmdline) -+ strcpy(&(arcs_cmdline[0]), -+ "console=ttyS1,115200 rootfstype=squashfs,jffs2"); -+ prom_init_image_cmdline(); -+} -+ -+void __init -+prom_init(void) -+{ -+ struct clk *clk; -+ lq_soc_detect(&soc_info); -+ -+ clk_init(); -+ clk = clk_get(0, "cpu"); -+ snprintf(soc_info.sys_type, LQ_SYS_TYPE_LEN - 1, "%s rev1.%d %ldMhz", -+ soc_info.name, soc_info.rev, clk_get_rate(clk) / 1000000); -+ soc_info.sys_type[LQ_SYS_TYPE_LEN - 1] = '\0'; -+ printk("SoC: %s\n", soc_info.sys_type); -+ -+ prom_init_cmdline(); -+} ---- /dev/null -+++ b/arch/mips/lantiq/prom.h -@@ -0,0 +1,24 @@ -+/* -+ * 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> -+ */ -+ -+#ifndef _LQ_PROM_H__ -+#define _LQ_PROM_H__ -+ -+#define LQ_SYS_TYPE_LEN 0x100 -+ -+struct lq_soc_info { -+ unsigned char *name; -+ unsigned int rev; -+ unsigned int partnum; -+ unsigned int type; -+ unsigned char sys_type[LQ_SYS_TYPE_LEN]; -+}; -+ -+void lq_soc_detect(struct lq_soc_info *i); -+ -+#endif ---- a/arch/mips/Kbuild.platforms -+++ b/arch/mips/Kbuild.platforms -@@ -11,6 +11,7 @@ - platforms += jazz - platforms += jz4740 - platforms += lasat -+platforms += lantiq - platforms += loongson - platforms += mipssim - platforms += mti-malta ---- /dev/null -+++ b/arch/mips/lantiq/Platform -@@ -0,0 +1,8 @@ -+# -+# Lantiq -+# -+ -+platform-$(CONFIG_LANTIQ) += lantiq/ -+cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq -+load-$(CONFIG_LANTIQ) = 0xffffffff80002000 -+cflags-$(CONFIG_SOC_LANTIQ_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway diff --git a/target/linux/lantiq/patches/101-header.patch b/target/linux/lantiq/patches/101-header.patch deleted file mode 100644 index 454ed3e..0000000 --- a/target/linux/lantiq/patches/101-header.patch +++ /dev/null @@ -1,151 +0,0 @@ ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/war.h -@@ -0,0 +1,24 @@ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ */ -+#ifndef __ASM_MIPS_MACH_LANTIQ_WAR_H -+#define __ASM_MIPS_MACH_LANTIQ_WAR_H -+ -+#define R4600_V1_INDEX_ICACHEOP_WAR 0 -+#define R4600_V1_HIT_CACHEOP_WAR 0 -+#define R4600_V2_HIT_CACHEOP_WAR 0 -+#define R5432_CP0_INTERRUPT_WAR 0 -+#define BCM1250_M3_WAR 0 -+#define SIBYTE_1956_WAR 0 -+#define MIPS4K_ICACHE_REFILL_WAR 0 -+#define MIPS_CACHE_SYNC_WAR 0 -+#define TX49XX_ICACHE_INDEX_INV_WAR 0 -+#define RM9000_CDEX_SMP_WAR 0 -+#define ICACHE_REFILLS_WORKAROUND_WAR 0 -+#define R10000_LLSC_WAR 0 -+#define MIPS34K_MISSED_ITLB_WAR 0 -+ -+#endif ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/lantiq.h -@@ -0,0 +1,47 @@ -+/* -+ * 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> -+ */ -+ -+#ifndef _LANTIQ_H__ -+#define _LANTIQ_H__ -+ -+/* generic reg access functions */ -+#define lq_r32(reg) __raw_readl(reg) -+#define lq_w32(val, reg) __raw_writel(val, reg) -+#define lq_w32_mask(clear, set, reg) lq_w32((lq_r32(reg) & ~clear) | set, reg) -+ -+extern unsigned int lq_get_cpu_ver(void); -+extern unsigned int lq_get_soc_type(void); -+ -+/* clock speeds */ -+#define CLOCK_60M 60000000 -+#define CLOCK_83M 83333333 -+#define CLOCK_111M 111111111 -+#define CLOCK_111M 111111111 -+#define CLOCK_133M 133333333 -+#define CLOCK_167M 166666667 -+#define CLOCK_200M 200000000 -+#define CLOCK_333M 333333333 -+#define CLOCK_400M 400000000 -+ -+/* spinlock all ebu i/o */ -+extern spinlock_t ebu_lock; -+ -+/* some irq helpers */ -+extern void lq_disable_irq(unsigned int irq_nr); -+extern void lq_mask_and_ack_irq(unsigned int irq_nr); -+extern void lq_enable_irq(unsigned int irq_nr); -+ -+#define IOPORT_RESOURCE_START 0x10000000 -+#define IOPORT_RESOURCE_END 0xffffffff -+#define IOMEM_RESOURCE_START 0x10000000 -+#define IOMEM_RESOURCE_END 0xffffffff -+ -+#define LQ_FLASH_START 0x10000000 -+#define LQ_FLASH_MAX 0x04000000 -+ -+#endif ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/lantiq_regs.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 version 2 as published -+ * by the Free Software Foundation. -+ * -+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> -+ */ -+ -+#ifndef _LANTIQ_REGS_H__ -+#define _LANTIQ_REGS_H__ -+ -+#ifdef CONFIG_SOC_LANTIQ_XWAY -+#include <xway.h> -+#include <xway_irq.h> -+#endif -+ -+#endif ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h -@@ -0,0 +1,51 @@ -+/* -+ * 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> -+ */ -+ -+#ifndef _LANTIQ_PLATFORM_H__ -+#define _LANTIQ_PLATFORM_H__ -+ -+#include <linux/mtd/partitions.h> -+ -+/* struct used to pass info to network drivers */ -+enum { -+ MII_MODE, -+ REV_MII_MODE, -+}; -+ -+struct lq_eth_data { -+ unsigned char *mac; -+ int mii_mode; -+}; -+ -+#define PCI_EXIN0 0x0001 -+#define PCI_EXIN1 0x0002 -+#define PCI_EXIN2 0x0004 -+#define PCI_EXIN_SHIFT 0 -+ -+#define PCI_GNT1 0x0008 -+#define PCI_GNT2 0x0010 -+#define PCI_GNT3 0x0020 -+#define PCI_GNT_SHIFT 3 -+ -+#define PCI_REQ1 0x0040 -+#define PCI_REQ2 0x0080 -+#define PCI_REQ3 0x0100 -+#define PCI_REQ_SHIFT 6 -+ -+#define PCI_CLOCK_INT 0 -+#define PCI_CLOCK_EXT 1 -+ -+struct lq_pci_data { -+ int clock; -+ int gpio; -+ int irq[16]; -+}; -+ -+extern int (*lqpci_plat_dev_init)(struct pci_dev *dev); -+ -+#endif diff --git a/target/linux/lantiq/patches/104-board_xway.patch b/target/linux/lantiq/patches/104-board_xway.patch deleted file mode 100644 index 297fbd3..0000000 --- a/target/linux/lantiq/patches/104-board_xway.patch +++ /dev/null @@ -1,3212 +0,0 @@ - ---- /dev/null -+++ b/arch/mips/lantiq/xway/Kconfig -@@ -0,0 +1,19 @@ -+if SOC_LANTIQ_XWAY -+ -+menu "Mips Machine" -+ -+config LANTIQ_MACH_EASY50812 -+ bool "Easy50812" -+ default y -+ -+config LANTIQ_MACH_EASY50712 -+ bool "Easy50712" -+ default y -+ -+config LANTIQ_MACH_EASY4010 -+ bool "Easy4010" -+ default y -+ -+endmenu -+ -+endif ---- /dev/null -+++ b/arch/mips/lantiq/xway/gpio_ebu.c -@@ -0,0 +1,116 @@ -+/* -+ * 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/module.h> -+#include <linux/types.h> -+#include <linux/platform_device.h> -+#include <linux/mutex.h> -+#include <linux/gpio.h> -+ -+#include <xway.h> -+ -+#define LQ_EBU_BUSCON 0x1e7ff -+#define LQ_EBU_WP 0x80000000 -+ -+static int shadow = 0x0000; -+static void __iomem *virt; -+ -+static int -+lq_ebu_direction_output(struct gpio_chip *chip, unsigned offset, int value) -+{ -+ return 0; -+} -+ -+static void -+lq_ebu_apply(void) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&ebu_lock, flags); -+ lq_w32(LQ_EBU_BUSCON, LQ_EBU_BUSCON1); -+ *((__u16*)virt) = shadow; -+ lq_w32(LQ_EBU_BUSCON | LQ_EBU_WP, LQ_EBU_BUSCON1); -+ spin_unlock_irqrestore(&ebu_lock, flags); -+} -+ -+static void -+lq_ebu_set(struct gpio_chip *chip, unsigned offset, int value) -+{ -+ if(value) -+ shadow |= (1 << offset); -+ else -+ shadow &= ~(1 << offset); -+ lq_ebu_apply(); -+} -+ -+static struct gpio_chip -+lq_ebu_chip = -+{ -+ .label = "lq_ebu", -+ .direction_output = lq_ebu_direction_output, -+ .set = lq_ebu_set, -+ .base = 32, -+ .ngpio = 16, -+ .can_sleep = 0, -+ .owner = THIS_MODULE, -+}; -+ -+static int __devinit -+lq_ebu_probe(struct platform_device *pdev) -+{ -+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ int ret = 0; -+ if (!res) -+ return -ENOENT; -+ res = request_mem_region(res->start, resource_size(res), -+ dev_name(&pdev->dev)); -+ if (!res) -+ return -EBUSY; -+ -+ /* tell the ebu controller which mem addr we will be using */ -+ lq_w32(pdev->resource->start | 0x1, LQ_EBU_ADDRSEL1); -+ lq_w32(LQ_EBU_BUSCON | LQ_EBU_WP, LQ_EBU_BUSCON1); -+ -+ virt = ioremap_nocache(res->start, resource_size(res)); -+ if (!virt) -+ { -+ dev_err(&pdev->dev, "Failed to ioremap mem region\n"); -+ ret = -ENOMEM; -+ goto err_release_mem_region; -+ } -+ /* grab the default settings passed form the platform code */ -+ shadow = (unsigned int) pdev->dev.platform_data; -+ -+ ret = gpiochip_add(&lq_ebu_chip); -+ if (!ret) -+ { -+ lq_ebu_apply(); -+ return 0; -+ } -+ -+err_release_mem_region: -+ release_mem_region(res->start, resource_size(res)); -+ return ret; -+} -+ -+static struct platform_driver -+lq_ebu_driver = { -+ .probe = lq_ebu_probe, -+ .driver = { -+ .name = "lq_ebu", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init -+init_lq_ebu(void) -+{ -+ return platform_driver_register(&lq_ebu_driver); -+} -+ -+postcore_initcall(init_lq_ebu); ---- /dev/null -+++ b/arch/mips/lantiq/xway/gpio_leds.c -@@ -0,0 +1,161 @@ -+/* -+ * 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) 2007 John Crispin <blogic@openwrt.org> -+ * -+ */ -+ -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/platform_device.h> -+#include <linux/mutex.h> -+#include <linux/gpio.h> -+ -+#include <xway.h> -+ -+#define LQ_STP_BASE 0x1E100BB0 -+#define LQ_STP_SIZE 0x40 -+ -+#define LQ_STP_CON0 0x00 -+#define LQ_STP_CON1 0x04 -+#define LQ_STP_CPU0 0x08 -+#define LQ_STP_CPU1 0x0C -+#define LQ_STP_AR 0x10 -+ -+#define STP_CON0_SWU (1 << 31) -+ -+#define LQ_STP_2HZ (0) -+#define LQ_STP_4HZ (1 << 23) -+#define LQ_STP_8HZ (2 << 23) -+#define LQ_STP_10HZ (3 << 23) -+#define LQ_STP_MASK (0xf << 23) -+ -+#define LQ_STP_UPD_SRC_FPI (1 << 31) -+#define LQ_STP_UPD_MASK (3 << 30) -+#define LQ_STP_ADSL_SRC (3 << 24) -+ -+#define LQ_STP_GROUP0 (1 << 0) -+ -+#define LQ_STP_RISING 0 -+#define LQ_STP_FALLING (1 << 26) -+#define LQ_STP_EDGE_MASK (1 << 26) -+ -+#define lq_stp_r32(reg) __raw_readl(virt + reg) -+#define lq_stp_w32(val, reg) __raw_writel(val, virt + reg) -+#define lq_stp_w32_mask(clear, set, reg) \ -+ lq_w32((lq_r32(virt + reg) & ~clear) | set, virt + reg) -+ -+static int shadow = 0xffff; -+static void __iomem *virt; -+ -+static int -+lq_stp_direction_output(struct gpio_chip *chip, unsigned offset, int value) -+{ -+ return 0; -+} -+ -+static void -+lq_stp_set(struct gpio_chip *chip, unsigned offset, int value) -+{ -+ if(value) -+ shadow |= (1 << offset); -+ else -+ shadow &= ~(1 << offset); -+ lq_stp_w32(shadow, LQ_STP_CPU0); -+} -+ -+static struct gpio_chip lq_stp_chip = -+{ -+ .label = "lq_stp", -+ .direction_output = lq_stp_direction_output, -+ .set = lq_stp_set, -+ .base = 48, -+ .ngpio = 24, -+ .can_sleep = 0, -+ .owner = THIS_MODULE, -+}; -+ -+static int -+lq_stp_hw_init(void) -+{ -+ /* the 3 pins used to control the external stp */ -+ lq_gpio_request(4, 1, 0, 1, "stp-st"); -+ lq_gpio_request(5, 1, 0, 1, "stp-d"); -+ lq_gpio_request(6, 1, 0, 1, "stp-sh"); -+ -+ /* sane defaults */ -+ lq_stp_w32(0, LQ_STP_AR); -+ lq_stp_w32(0, LQ_STP_CPU0); -+ lq_stp_w32(0, LQ_STP_CPU1); -+ lq_stp_w32(STP_CON0_SWU, LQ_STP_CON0); -+ lq_stp_w32(0, LQ_STP_CON1); -+ -+ /* rising or falling edge */ -+ lq_stp_w32_mask(LQ_STP_EDGE_MASK, LQ_STP_FALLING, LQ_STP_CON0); -+ -+ /* per default stp 15-0 are set */ -+ lq_stp_w32_mask(0, LQ_STP_GROUP0, LQ_STP_CON1); -+ -+ /* stp are update periodically by the FPID */ -+ lq_stp_w32_mask(LQ_STP_UPD_MASK, LQ_STP_UPD_SRC_FPI, LQ_STP_CON1); -+ -+ /* set stp update speed */ -+ lq_stp_w32_mask(LQ_STP_MASK, LQ_STP_8HZ, LQ_STP_CON1); -+ -+ /* adsl 0 and 1 stp are updated by the arc */ -+ lq_stp_w32_mask(0, LQ_STP_ADSL_SRC, LQ_STP_CON0); -+ -+ lq_pmu_enable(PMU_LED); -+ return 0; -+} -+ -+static int -+lq_stp_probe(struct platform_device *pdev) -+{ -+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ int ret = 0; -+ if (!res) -+ return -ENOENT; -+ res = request_mem_region(res->start, resource_size(res), -+ dev_name(&pdev->dev)); -+ if (!res) -+ return -EBUSY; -+ virt = ioremap_nocache(res->start, resource_size(res)); -+ if(!virt) -+ { -+ ret = -ENOMEM; -+ goto err_release_mem_region; -+ } -+ ret = gpiochip_add(&lq_stp_chip); -+ if(!ret) -+ return lq_stp_hw_init(); -+ -+ iounmap(virt); -+err_release_mem_region: -+ release_mem_region(res->start, resource_size(res)); -+ return ret; -+} -+ -+static struct platform_driver lq_stp_driver = { -+ .probe = lq_stp_probe, -+ .driver = { -+ .name = "lq_stp", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+int __init -+init_lq_stp(void) -+{ -+ int ret = platform_driver_register(&lq_stp_driver); -+ if (ret) -+ printk(KERN_INFO -+ "lq_stp: error registering platfom driver"); -+ return ret; -+} -+ -+postcore_initcall(init_lq_stp); ---- /dev/null -+++ b/arch/mips/lantiq/xway/mach-easy4010.c -@@ -0,0 +1,82 @@ -+/* -+ * 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 <machine.h> -+ -+#include <xway.h> -+#include <lantiq_platform.h> -+ -+#include "devices.h" -+ -+#ifdef CONFIG_MTD_PARTITIONS -+static struct mtd_partition easy4010_partitions[] = -+{ -+ { -+ .name = "uboot", -+ .offset = 0x0, -+ .size = 0x20000, -+ }, -+ { -+ .name = "uboot_env", -+ .offset = 0x20000, -+ .size = 0x10000, -+ }, -+ { -+ .name = "linux", -+ .offset = 0x30000, -+ .size = 0x3D0000, -+ }, -+}; -+#endif -+ -+static struct physmap_flash_data easy4010_flash_data = { -+#ifdef CONFIG_MTD_PARTITIONS -+ .nr_parts = ARRAY_SIZE(easy4010_partitions), -+ .parts = easy4010_partitions, -+#endif -+}; -+ -+static struct lq_pci_data lq_pci_data = { -+ .clock = PCI_CLOCK_INT, -+ .gpio = PCI_GNT1 | PCI_REQ1, -+ .irq = { -+ [14] = INT_NUM_IM0_IRL0 + 22, -+ }, -+}; -+ -+static struct lq_eth_data lq_eth_data = { -+ .mii_mode = REV_MII_MODE, -+}; -+ -+static void __init -+easy4010_init(void) -+{ -+ lq_register_gpio(); -+ lq_register_gpio_stp(); -+ lq_register_asc(0); -+ lq_register_asc(1); -+ lq_register_nor(&easy4010_flash_data); -+ lq_register_wdt(); -+ lq_register_pci(&lq_pci_data); -+ lq_register_ethernet(&lq_eth_data); -+} -+ -+MIPS_MACHINE(LANTIQ_MACH_EASY4010, -+ "EASY4010", -+ "EASY4010 Eval Board", -+ easy4010_init); ---- /dev/null -+++ b/arch/mips/lantiq/xway/mach-easy50712.c -@@ -0,0 +1,82 @@ -+/* -+ * 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 <machine.h> -+ -+#include <xway.h> -+#include <lantiq_platform.h> -+ -+#include "devices.h" -+ -+#ifdef CONFIG_MTD_PARTITIONS -+static struct mtd_partition easy50712_partitions[] = -+{ -+ { -+ .name = "uboot", -+ .offset = 0x0, -+ .size = 0x20000, -+ }, -+ { -+ .name = "uboot_env", -+ .offset = 0x20000, -+ .size = 0x10000, -+ }, -+ { -+ .name = "linux", -+ .offset = 0x30000, -+ .size = 0x3D0000, -+ }, -+}; -+#endif -+ -+static struct physmap_flash_data easy50712_flash_data = { -+#ifdef CONFIG_MTD_PARTITIONS -+ .nr_parts = ARRAY_SIZE(easy50712_partitions), -+ .parts = easy50712_partitions, -+#endif -+}; -+ -+static struct lq_pci_data lq_pci_data = { -+ .clock = PCI_CLOCK_INT, -+ .gpio = PCI_GNT1 | PCI_REQ1, -+ .irq = { -+ [14] = INT_NUM_IM0_IRL0 + 22, -+ }, -+}; -+ -+static struct lq_eth_data lq_eth_data = { -+ .mii_mode = REV_MII_MODE, -+}; -+ -+static void __init -+easy50712_init(void) -+{ -+ lq_register_asc(0); -+ lq_register_asc(1); -+ lq_register_gpio(); -+ lq_register_gpio_stp(); -+ lq_register_nor(&easy50712_flash_data); -+ lq_register_wdt(); -+ lq_register_pci(&lq_pci_data); -+ lq_register_ethernet(&lq_eth_data); -+} -+ -+MIPS_MACHINE(LANTIQ_MACH_EASY50712, -+ "EASY50712", -+ "EASY50712 Eval Board", -+ easy50712_init); ---- /dev/null -+++ b/arch/mips/lantiq/xway/mach-easy50812.c -@@ -0,0 +1,81 @@ -+/* -+ * 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 <machine.h> -+ -+#include <xway.h> -+#include <lantiq_platform.h> -+ -+#include "devices.h" -+ -+#ifdef CONFIG_MTD_PARTITIONS -+static struct mtd_partition easy50812_partitions[] = -+{ -+ { -+ .name = "uboot", -+ .offset = 0x0, -+ .size = 0x40000, -+ }, -+ { -+ .name = "uboot_env", -+ .offset = 0x40000, -+ .size = 0x10000, -+ }, -+ { -+ .name = "linux", -+ .offset = 0x50000, -+ .size = 0x3B0000, -+ }, -+}; -+#endif -+ -+static struct physmap_flash_data easy50812_flash_data = { -+#ifdef CONFIG_MTD_PARTITIONS -+ .nr_parts = ARRAY_SIZE(easy50812_partitions), -+ .parts = easy50812_partitions, -+#endif -+}; -+ -+static struct lq_pci_data lq_pci_data = { -+ .clock = PCI_CLOCK_INT, -+ .gpio = PCI_GNT1 | PCI_REQ1, -+ .irq = { -+ [14] = INT_NUM_IM0_IRL0 + 22, -+ }, -+}; -+ -+static struct lq_eth_data lq_eth_data = { -+ .mii_mode = REV_MII_MODE, -+}; -+ -+static void __init -+easy50812_init(void) -+{ -+ lq_register_gpio(); -+ lq_register_asc(0); -+ lq_register_asc(1); -+ lq_register_nor(&easy50812_flash_data); -+ lq_register_wdt(); -+ lq_register_pci(&lq_pci_data); -+ lq_register_ethernet(&lq_eth_data); -+} -+ -+MIPS_MACHINE(LANTIQ_MACH_EASY50812, -+ "EASY50812", -+ "EASY50812 Eval Board", -+ easy50812_init); ---- /dev/null -+++ b/arch/mips/lantiq/xway/prom.c -@@ -0,0 +1,52 @@ -+/* -+ * 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 <xway.h> -+ -+#include "../prom.h" -+ -+#define SOC_DANUBE "Danube" -+#define SOC_TWINPASS "Twinpass" -+#define SOC_AR9 "AR9" -+ -+void __init -+lq_soc_detect(struct lq_soc_info *i) -+{ -+ i->partnum = (lq_r32(LQ_MPS_CHIPID) & 0x0FFFFFFF) >> 12; -+ i->rev = (lq_r32(LQ_MPS_CHIPID) & 0xF0000000) >> 28; -+ 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: -+ printk(KERN_ERR "unknown chiprev : 0x%08X\n", i->partnum); -+ while(1) { }; -+ break; -+ } -+} ---- /dev/null -+++ b/arch/mips/lantiq/xway/devices.c -@@ -0,0 +1,336 @@ -+/* -+ * 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/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/gpio_buttons.h> -+#include <linux/leds.h> -+ -+#include <asm/bootinfo.h> -+#include <asm/irq.h> -+ -+#include <xway.h> -+#include <xway_irq.h> -+#include <lantiq_platform.h> -+ -+#define IRQ_RES(resname,irq) {.name=#resname,.start=(irq),.flags=IORESOURCE_IRQ} -+ -+/* gpio leds */ -+static struct gpio_led_platform_data lq_gpio_led_data; -+ -+static struct platform_device lq_gpio_leds = -+{ -+ .name = "leds-gpio", -+ .dev = { -+ .platform_data = (void *) &lq_gpio_led_data, -+ } -+}; -+ -+void __init -+lq_register_gpio_leds(struct gpio_led *leds, int cnt) -+{ -+ lq_gpio_led_data.leds = leds; -+ lq_gpio_led_data.num_leds = cnt; -+ platform_device_register(&lq_gpio_leds); -+} -+ -+/* gpio buttons */ -+static struct gpio_buttons_platform_data lq_gpio_buttons_platform_data; -+ -+static struct platform_device lq_gpio_buttons_platform_device = -+{ -+ .name = "gpio-buttons", -+ .id = 0, -+ .dev = { -+ .platform_data = (void *) &lq_gpio_buttons_platform_data, -+ }, -+}; -+ -+void __init -+lq_register_gpio_buttons(struct gpio_button *buttons, int cnt) -+{ -+ lq_gpio_buttons_platform_data.buttons = buttons; -+ lq_gpio_buttons_platform_data.nbuttons = cnt; -+ platform_device_register(&lq_gpio_buttons_platform_device); -+} -+ -+/* serial to parallel conversion */ -+static struct resource lq_stp_resource = -+{ -+ .name = "stp", -+ .start = LQ_STP_BASE, -+ .end = LQ_STP_BASE + LQ_STP_SIZE - 1, -+ .flags = IORESOURCE_MEM, -+}; -+ -+void __init -+lq_register_gpio_stp(void) -+{ -+ platform_device_register_simple("lq_stp", 0, &lq_stp_resource, 1); -+} -+ -+/* nor flash */ -+static struct resource lq_nor_resource = -+{ -+ .name = "nor", -+ .start = LQ_FLASH_START, -+ .end = LQ_FLASH_START + LQ_FLASH_MAX - 1, -+ .flags = IORESOURCE_MEM, -+}; -+ -+static struct platform_device lq_nor = -+{ -+ .name = "lq_nor", -+ .resource = &lq_nor_resource, -+ .num_resources = 1, -+}; -+ -+void __init -+lq_register_nor(struct physmap_flash_data *data) -+{ -+ lq_nor.dev.platform_data = data; -+ platform_device_register(&lq_nor); -+} -+ -+/* watchdog */ -+static struct resource lq_wdt_resource = -+{ -+ .name = "watchdog", -+ .start = LQ_WDT_BASE, -+ .end = LQ_WDT_BASE + LQ_WDT_SIZE - 1, -+ .flags = IORESOURCE_MEM, -+}; -+ -+void __init -+lq_register_wdt(void) -+{ -+ platform_device_register_simple("lq_wdt", 0, &lq_wdt_resource, 1); -+} -+ -+/* gpio */ -+static struct resource lq_gpio_resource[] = { -+ { -+ .name = "gpio0", -+ .start = LQ_GPIO0_BASE_ADDR, -+ .end = LQ_GPIO0_BASE_ADDR + LQ_GPIO_SIZE - 1, -+ .flags = IORESOURCE_MEM, -+ }, { -+ .name = "gpio1", -+ .start = LQ_GPIO1_BASE_ADDR, -+ .end = LQ_GPIO1_BASE_ADDR + LQ_GPIO_SIZE - 1, -+ .flags = IORESOURCE_MEM, -+ } -+}; -+ -+void __init -+lq_register_gpio(void) -+{ -+ platform_device_register_simple("lq_gpio", 0, &lq_gpio_resource[0], 1); -+ platform_device_register_simple("lq_gpio", 1, &lq_gpio_resource[1], 1); -+} -+ -+/* pci */ -+static struct platform_device lq_pci = -+{ -+ .name = "lq_pci", -+ .num_resources = 0, -+}; -+ -+void __init -+lq_register_pci(struct lq_pci_data *data) -+{ -+ lq_pci.dev.platform_data = data; -+ platform_device_register(&lq_pci); -+} -+ -+/* ebu */ -+static struct resource lq_ebu_resource = -+{ -+ .name = "gpio_ebu", -+ .start = LQ_EBU_GPIO_START, -+ .end = LQ_EBU_GPIO_START + LQ_EBU_GPIO_SIZE - 1, -+ .flags = IORESOURCE_MEM, -+}; -+ -+static struct platform_device lq_ebu = -+{ -+ .name = "lq_ebu", -+ .resource = &lq_ebu_resource, -+ .num_resources = 1, -+}; -+ -+void __init -+lq_register_gpio_ebu(unsigned int value) -+{ -+ lq_ebu.dev.platform_data = (void*) value; -+ platform_device_register(&lq_ebu); -+} -+ -+/* ethernet */ -+unsigned char lq_ethaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -+ -+static int __init -+lq_set_ethaddr(char *str) -+{ -+ sscanf(&str[8], "0%02hhx:0%02hhx:0%02hhx:0%02hhx:0%02hhx:0%02hhx", -+ &lq_ethaddr[0], &lq_ethaddr[1], &lq_ethaddr[2], -+ &lq_ethaddr[3], &lq_ethaddr[4], &lq_ethaddr[5]); -+ return 0; -+} -+__setup("ethaddr=", lq_set_ethaddr); -+ -+static struct resource lq_ethernet_resources = -+{ -+ .name = "etop", -+ .start = LQ_PPE32_BASE_ADDR, -+ .end = LQ_PPE32_BASE_ADDR + LQ_PPE32_SIZE - 1, -+ .flags = IORESOURCE_MEM, -+}; -+ -+static struct platform_device lq_ethernet = -+{ -+ .name = "lq_etop", -+ .resource = &lq_ethernet_resources, -+ .num_resources = 1, -+}; -+ -+void __init -+lq_register_ethernet(struct lq_eth_data *eth) -+{ -+ if(!eth) -+ return; -+ if(!eth->mac) -+ eth->mac = lq_ethaddr; -+ if(!is_valid_ether_addr(eth->mac)) -+ random_ether_addr(eth->mac); -+ lq_ethernet.dev.platform_data = eth; -+ platform_device_register(&lq_ethernet); -+} -+ -+/* tapi */ -+static struct resource mps_resources[] = { -+ { -+ .name = "voice-mem", -+ .flags = IORESOURCE_MEM, -+ .start = 0x1f107000, -+ .end = 0x1f1073ff, -+ }, -+ { -+ .name = "voice-mailbox", -+ .flags = IORESOURCE_MEM, -+ .start = 0x1f200000, -+ .end = 0x1f2007ff, -+ }, -+}; -+ -+static struct platform_device mps_device = { -+ .name = "mps", -+ .resource = mps_resources, -+ .num_resources = ARRAY_SIZE(mps_resources), -+}; -+ -+static struct platform_device vmmc_device = { -+ .name = "vmmc", -+ .dev = { -+ .parent = &mps_device.dev, -+ }, -+}; -+ -+static unsigned int *cp1_base; -+unsigned int* -+lq_get_cp1_base(void) -+{ -+ return cp1_base; -+} -+EXPORT_SYMBOL(lq_get_cp1_base); -+ -+void __init -+lq_register_tapi(void) -+{ -+#define CP1_SIZE (1 << 20) -+ dma_addr_t dma; -+ mps_device.dev.platform_data = -+ cp1_base = -+ (void*)CPHYSADDR(dma_alloc_coherent(NULL, CP1_SIZE, &dma, GFP_ATOMIC)); -+ mps_device.dev.platform_data = cp1_base; -+ platform_device_register(&mps_device); -+ platform_device_register(&vmmc_device); -+} -+ -+/* asc ports */ -+static struct resource lq_asc0_resources[] = -+{ -+ { -+ .start = LQ_ASC0_BASE, -+ .end = LQ_ASC0_BASE + LQ_ASC_SIZE - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ IRQ_RES(tx, INT_NUM_IM3_IRL0), -+ IRQ_RES(rx, INT_NUM_IM3_IRL0 + 1), -+ IRQ_RES(err, INT_NUM_IM3_IRL0 + 2), -+}; -+ -+static struct resource lq_asc1_resources[] = -+{ -+ { -+ .start = LQ_ASC1_BASE, -+ .end = LQ_ASC1_BASE + LQ_ASC_SIZE - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ IRQ_RES(tx, INT_NUM_IM3_IRL0 + 8), -+ IRQ_RES(rx, INT_NUM_IM3_IRL0 + 9), -+ IRQ_RES(err, INT_NUM_IM3_IRL0 + 10), -+}; -+ -+void __init -+lq_register_asc(int port) -+{ -+ switch (port) { -+ case 0: -+ platform_device_register_simple("lq_asc", 0, -+ lq_asc0_resources, ARRAY_SIZE(lq_asc0_resources)); -+ break; -+ case 1: -+ platform_device_register_simple("lq_asc", 1, -+ lq_asc1_resources, ARRAY_SIZE(lq_asc1_resources)); -+ break; -+ default: -+ break; -+ } -+} -+ -+void __init -+lq_register_crypto(const char *name) -+{ -+ platform_device_register_simple(name, 0, 0, 0); -+} -+ -+/* madwifi */ -+int lantiq_emulate_madwifi_eep = 0; -+EXPORT_SYMBOL(lantiq_emulate_madwifi_eep); -+ -+void __init -+lq_register_madwifi_eep(void) -+{ -+ lantiq_emulate_madwifi_eep = 1; -+} -+ -+ -+ ---- /dev/null -+++ b/arch/mips/lantiq/xway/devices.h -@@ -0,0 +1,28 @@ -+/* -+ * 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> -+ */ -+ -+#ifndef _LQ_DEVICES_H__ -+#define _LQ_DEVICES_H__ -+ -+#include <lantiq_platform.h> -+#include <xway_irq.h> -+ -+extern void __init lq_register_gpio(void); -+extern void __init lq_register_gpio_stp(void); -+extern void __init lq_register_gpio_ebu(unsigned int value); -+extern void __init lq_register_gpio_leds(struct gpio_led *leds, int cnt); -+extern void __init lq_register_pci(struct lq_pci_data *data); -+extern void __init lq_register_nor(struct physmap_flash_data *data); -+extern void __init lq_register_tapi(void); -+extern void __init lq_register_madwifi_eep(void); -+extern void __init lq_register_wdt(void); -+extern void __init lq_register_ethernet(struct lq_eth_data *eth); -+extern void __init lq_register_asc(int port); -+extern void __init lq_register_gpio_buttons(struct gpio_button *buttons, int cnt); -+ -+#endif ---- /dev/null -+++ b/arch/mips/lantiq/xway/dma.c -@@ -0,0 +1,701 @@ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/sched.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/string.h> -+#include <linux/timer.h> -+#include <linux/fs.h> -+#include <linux/errno.h> -+#include <linux/stat.h> -+#include <linux/mm.h> -+#include <linux/tty.h> -+#include <linux/selection.h> -+#include <linux/kmod.h> -+#include <linux/vmalloc.h> -+#include <linux/interrupt.h> -+#include <linux/delay.h> -+#include <linux/uaccess.h> -+#include <linux/errno.h> -+#include <linux/io.h> -+ -+#include <xway.h> -+#include <xway_irq.h> -+#include <xway_dma.h> -+ -+#define LQ_DMA_CS ((u32 *)(LQ_DMA_BASE_ADDR + 0x18)) -+#define LQ_DMA_CIE ((u32 *)(LQ_DMA_BASE_ADDR + 0x2C)) -+#define LQ_DMA_IRNEN ((u32 *)(LQ_DMA_BASE_ADDR + 0xf4)) -+#define LQ_DMA_CCTRL ((u32 *)(LQ_DMA_BASE_ADDR + 0x1C)) -+#define LQ_DMA_CIS ((u32 *)(LQ_DMA_BASE_ADDR + 0x28)) -+#define LQ_DMA_CDLEN ((u32 *)(LQ_DMA_BASE_ADDR + 0x24)) -+#define LQ_DMA_PS ((u32 *)(LQ_DMA_BASE_ADDR + 0x40)) -+#define LQ_DMA_PCTRL ((u32 *)(LQ_DMA_BASE_ADDR + 0x44)) -+#define LQ_DMA_CTRL ((u32 *)(LQ_DMA_BASE_ADDR + 0x10)) -+#define LQ_DMA_CPOLL ((u32 *)(LQ_DMA_BASE_ADDR + 0x14)) -+#define LQ_DMA_CDBA ((u32 *)(LQ_DMA_BASE_ADDR + 0x20)) -+ -+/*25 descriptors for each dma channel,4096/8/20=25.xx*/ -+#define LQ_DMA_DESCRIPTOR_OFFSET 25 -+ -+#define MAX_DMA_DEVICE_NUM 6 /*max ports connecting to dma */ -+#define MAX_DMA_CHANNEL_NUM 20 /*max dma channels */ -+#define DMA_INT_BUDGET 100 /*budget for interrupt handling */ -+#define DMA_POLL_COUNTER 4 /*fix me, set the correct counter value here! */ -+ -+extern void lq_mask_and_ack_irq(unsigned int irq_nr); -+extern void lq_enable_irq(unsigned int irq_nr); -+extern void lq_disable_irq(unsigned int irq_nr); -+ -+u64 *g_desc_list; -+struct dma_device_info dma_devs[MAX_DMA_DEVICE_NUM]; -+struct dma_channel_info dma_chan[MAX_DMA_CHANNEL_NUM]; -+ -+static const char *global_device_name[MAX_DMA_DEVICE_NUM] = -+ { "PPE", "DEU", "SPI", "SDIO", "MCTRL0", "MCTRL1" }; -+ -+struct dma_chan_map default_dma_map[MAX_DMA_CHANNEL_NUM] = { -+ {"PPE", LQ_DMA_RX, 0, LQ_DMA_CH0_INT, 0}, -+ {"PPE", LQ_DMA_TX, 0, LQ_DMA_CH1_INT, 0}, -+ {"PPE", LQ_DMA_RX, 1, LQ_DMA_CH2_INT, 1}, -+ {"PPE", LQ_DMA_TX, 1, LQ_DMA_CH3_INT, 1}, -+ {"PPE", LQ_DMA_RX, 2, LQ_DMA_CH4_INT, 2}, -+ {"PPE", LQ_DMA_TX, 2, LQ_DMA_CH5_INT, 2}, -+ {"PPE", LQ_DMA_RX, 3, LQ_DMA_CH6_INT, 3}, -+ {"PPE", LQ_DMA_TX, 3, LQ_DMA_CH7_INT, 3}, -+ {"DEU", LQ_DMA_RX, 0, LQ_DMA_CH8_INT, 0}, -+ {"DEU", LQ_DMA_TX, 0, LQ_DMA_CH9_INT, 0}, -+ {"DEU", LQ_DMA_RX, 1, LQ_DMA_CH10_INT, 1}, -+ {"DEU", LQ_DMA_TX, 1, LQ_DMA_CH11_INT, 1}, -+ {"SPI", LQ_DMA_RX, 0, LQ_DMA_CH12_INT, 0}, -+ {"SPI", LQ_DMA_TX, 0, LQ_DMA_CH13_INT, 0}, -+ {"SDIO", LQ_DMA_RX, 0, LQ_DMA_CH14_INT, 0}, -+ {"SDIO", LQ_DMA_TX, 0, LQ_DMA_CH15_INT, 0}, -+ {"MCTRL0", LQ_DMA_RX, 0, LQ_DMA_CH16_INT, 0}, -+ {"MCTRL0", LQ_DMA_TX, 0, LQ_DMA_CH17_INT, 0}, -+ {"MCTRL1", LQ_DMA_RX, 1, LQ_DMA_CH18_INT, 1}, -+ {"MCTRL1", LQ_DMA_TX, 1, LQ_DMA_CH19_INT, 1} -+}; -+ -+struct dma_chan_map *chan_map = default_dma_map; -+volatile u32 g_lq_dma_int_status; -+volatile int g_lq_dma_in_process; /* 0=not in process, 1=in process */ -+ -+void do_dma_tasklet(unsigned long); -+DECLARE_TASKLET(dma_tasklet, do_dma_tasklet, 0); -+ -+u8 *common_buffer_alloc(int len, int *byte_offset, void **opt) -+{ -+ u8 *buffer = kmalloc(len * sizeof(u8), GFP_KERNEL); -+ -+ *byte_offset = 0; -+ -+ return buffer; -+} -+ -+void common_buffer_free(u8 *dataptr, void *opt) -+{ -+ kfree(dataptr); -+} -+ -+void enable_ch_irq(struct dma_channel_info *pCh) -+{ -+ int chan_no = (int)(pCh - dma_chan); -+ unsigned long flag; -+ -+ local_irq_save(flag); -+ lq_w32(chan_no, LQ_DMA_CS); -+ lq_w32(0x4a, LQ_DMA_CIE); -+ lq_w32(lq_r32(LQ_DMA_IRNEN) | (1 << chan_no), LQ_DMA_IRNEN); -+ local_irq_restore(flag); -+ lq_enable_irq(pCh->irq); -+} -+ -+void disable_ch_irq(struct dma_channel_info *pCh) -+{ -+ unsigned long flag; -+ int chan_no = (int) (pCh - dma_chan); -+ -+ local_irq_save(flag); -+ g_lq_dma_int_status &= ~(1 << chan_no); -+ lq_w32(chan_no, LQ_DMA_CS); -+ lq_w32(0, LQ_DMA_CIE); -+ lq_w32(lq_r32(LQ_DMA_IRNEN) & ~(1 << chan_no), LQ_DMA_IRNEN); -+ local_irq_restore(flag); -+ lq_mask_and_ack_irq(pCh->irq); -+} -+ -+void open_chan(struct dma_channel_info *pCh) -+{ -+ unsigned long flag; -+ int chan_no = (int)(pCh - dma_chan); -+ -+ local_irq_save(flag); -+ lq_w32(chan_no, LQ_DMA_CS); -+ lq_w32(lq_r32(LQ_DMA_CCTRL) | 1, LQ_DMA_CCTRL); -+ if (pCh->dir == LQ_DMA_RX) -+ enable_ch_irq(pCh); -+ local_irq_restore(flag); -+} -+ -+void close_chan(struct dma_channel_info *pCh) -+{ -+ unsigned long flag; -+ int chan_no = (int) (pCh - dma_chan); -+ -+ local_irq_save(flag); -+ lq_w32(chan_no, LQ_DMA_CS); -+ lq_w32(lq_r32(LQ_DMA_CCTRL) & ~1, LQ_DMA_CCTRL); -+ disable_ch_irq(pCh); -+ local_irq_restore(flag); -+} -+ -+void reset_chan(struct dma_channel_info *pCh) -+{ -+ int chan_no = (int) (pCh - dma_chan); -+ -+ lq_w32(chan_no, LQ_DMA_CS); -+ lq_w32(lq_r32(LQ_DMA_CCTRL) | 2, LQ_DMA_CCTRL); -+} -+ -+void rx_chan_intr_handler(int chan_no) -+{ -+ struct dma_device_info *pDev = (struct dma_device_info *)dma_chan[chan_no].dma_dev; -+ struct dma_channel_info *pCh = &dma_chan[chan_no]; -+ struct rx_desc *rx_desc_p; -+ int tmp; -+ unsigned long flag; -+ -+ /*handle command complete interrupt */ -+ rx_desc_p = (struct rx_desc *)pCh->desc_base + pCh->curr_desc; -+ if (rx_desc_p->status.field.OWN == CPU_OWN -+ && rx_desc_p->status.field.C -+ && rx_desc_p->status.field.data_length < 1536){ -+ /* Every thing is correct, then we inform the upper layer */ -+ pDev->current_rx_chan = pCh->rel_chan_no; -+ if (pDev->intr_handler) -+ pDev->intr_handler(pDev, RCV_INT); -+ pCh->weight--; -+ } else { -+ local_irq_save(flag); -+ tmp = lq_r32(LQ_DMA_CS); -+ lq_w32(chan_no, LQ_DMA_CS); -+ lq_w32(lq_r32(LQ_DMA_CIS) | 0x7e, LQ_DMA_CIS); -+ lq_w32(tmp, LQ_DMA_CS); -+ g_lq_dma_int_status &= ~(1 << chan_no); -+ local_irq_restore(flag); -+ lq_enable_irq(dma_chan[chan_no].irq); -+ } -+} -+ -+inline void tx_chan_intr_handler(int chan_no) -+{ -+ struct dma_device_info *pDev = (struct dma_device_info *)dma_chan[chan_no].dma_dev; -+ struct dma_channel_info *pCh = &dma_chan[chan_no]; -+ int tmp; -+ unsigned long flag; -+ -+ local_irq_save(flag); -+ tmp = lq_r32(LQ_DMA_CS); -+ lq_w32(chan_no, LQ_DMA_CS); -+ lq_w32(lq_r32(LQ_DMA_CIS) | 0x7e, LQ_DMA_CIS); -+ lq_w32(tmp, LQ_DMA_CS); -+ g_lq_dma_int_status &= ~(1 << chan_no); -+ local_irq_restore(flag); -+ pDev->current_tx_chan = pCh->rel_chan_no; -+ if (pDev->intr_handler) -+ pDev->intr_handler(pDev, TRANSMIT_CPT_INT); -+} -+ -+void do_dma_tasklet(unsigned long unused) -+{ -+ int i; -+ int chan_no = 0; -+ int budget = DMA_INT_BUDGET; -+ int weight = 0; -+ unsigned long flag; -+ -+ while (g_lq_dma_int_status) { -+ if (budget-- < 0) { -+ tasklet_schedule(&dma_tasklet); -+ return; -+ } -+ chan_no = -1; -+ weight = 0; -+ for (i = 0; i < MAX_DMA_CHANNEL_NUM; i++) { -+ if ((g_lq_dma_int_status & (1 << i)) && dma_chan[i].weight > 0) { -+ if (dma_chan[i].weight > weight) { -+ chan_no = i; -+ weight = dma_chan[chan_no].weight; -+ } -+ } -+ } -+ -+ if (chan_no >= 0) { -+ if (chan_map[chan_no].dir == LQ_DMA_RX) -+ rx_chan_intr_handler(chan_no); -+ else -+ tx_chan_intr_handler(chan_no); -+ } else { -+ for (i = 0; i < MAX_DMA_CHANNEL_NUM; i++) -+ dma_chan[i].weight = dma_chan[i].default_weight; -+ } -+ } -+ -+ local_irq_save(flag); -+ g_lq_dma_in_process = 0; -+ if (g_lq_dma_int_status) { -+ g_lq_dma_in_process = 1; -+ tasklet_schedule(&dma_tasklet); -+ } -+ local_irq_restore(flag); -+} -+ -+irqreturn_t dma_interrupt(int irq, void *dev_id) -+{ -+ struct dma_channel_info *pCh; -+ int chan_no = 0; -+ int tmp; -+ -+ pCh = (struct dma_channel_info *)dev_id; -+ chan_no = (int)(pCh - dma_chan); -+ if (chan_no < 0 || chan_no > 19) -+ BUG(); -+ -+ tmp = lq_r32(LQ_DMA_IRNEN); -+ lq_w32(0, LQ_DMA_IRNEN); -+ g_lq_dma_int_status |= 1 << chan_no; -+ lq_w32(tmp, LQ_DMA_IRNEN); -+ lq_mask_and_ack_irq(irq); -+ -+ if (!g_lq_dma_in_process) { -+ g_lq_dma_in_process = 1; -+ tasklet_schedule(&dma_tasklet); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+struct dma_device_info *dma_device_reserve(char *dev_name) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_DMA_DEVICE_NUM; i++) { -+ if (strcmp(dev_name, dma_devs[i].device_name) == 0) { -+ if (dma_devs[i].reserved) -+ return NULL; -+ dma_devs[i].reserved = 1; -+ break; -+ } -+ } -+ -+ return &dma_devs[i]; -+} -+EXPORT_SYMBOL(dma_device_reserve); -+ -+void dma_device_release(struct dma_device_info *dev) -+{ -+ dev->reserved = 0; -+} -+EXPORT_SYMBOL(dma_device_release); -+ -+void dma_device_register(struct dma_device_info *dev) -+{ -+ int i, j; -+ int chan_no = 0; -+ u8 *buffer; -+ int byte_offset; -+ unsigned long flag; -+ struct dma_device_info *pDev; -+ struct dma_channel_info *pCh; -+ struct rx_desc *rx_desc_p; -+ struct tx_desc *tx_desc_p; -+ -+ for (i = 0; i < dev->max_tx_chan_num; i++) { -+ pCh = dev->tx_chan[i]; -+ if (pCh->control == LQ_DMA_CH_ON) { -+ chan_no = (int)(pCh - dma_chan); -+ for (j = 0; j < pCh->desc_len; j++) { -+ tx_desc_p = (struct tx_desc *)pCh->desc_base + j; -+ memset(tx_desc_p, 0, sizeof(struct tx_desc)); -+ } -+ local_irq_save(flag); -+ lq_w32(chan_no, LQ_DMA_CS); -+ /* check if the descriptor length is changed */ -+ if (lq_r32(LQ_DMA_CDLEN) != pCh->desc_len) -+ lq_w32(pCh->desc_len, LQ_DMA_CDLEN); -+ -+ lq_w32(lq_r32(LQ_DMA_CCTRL) & ~1, LQ_DMA_CCTRL); -+ lq_w32(lq_r32(LQ_DMA_CCTRL) | 2, LQ_DMA_CCTRL); -+ while (lq_r32(LQ_DMA_CCTRL) & 2) -+ ; -+ lq_w32(lq_r32(LQ_DMA_IRNEN) | (1 << chan_no), LQ_DMA_IRNEN); -+ lq_w32(0x30100, LQ_DMA_CCTRL); /* reset and enable channel,enable channel later */ -+ local_irq_restore(flag); -+ } -+ } -+ -+ for (i = 0; i < dev->max_rx_chan_num; i++) { -+ pCh = dev->rx_chan[i]; -+ if (pCh->control == LQ_DMA_CH_ON) { -+ chan_no = (int)(pCh - dma_chan); -+ -+ for (j = 0; j < pCh->desc_len; j++) { -+ rx_desc_p = (struct rx_desc *)pCh->desc_base + j; -+ pDev = (struct dma_device_info *)(pCh->dma_dev); -+ buffer = pDev->buffer_alloc(pCh->packet_size, &byte_offset, (void *)&(pCh->opt[j])); -+ if (!buffer) -+ break; -+ -+ dma_cache_inv((unsigned long) buffer, pCh->packet_size); -+ -+ rx_desc_p->Data_Pointer = (u32)CPHYSADDR((u32)buffer); -+ rx_desc_p->status.word = 0; -+ rx_desc_p->status.field.byte_offset = byte_offset; -+ rx_desc_p->status.field.OWN = DMA_OWN; -+ rx_desc_p->status.field.data_length = pCh->packet_size; -+ } -+ -+ local_irq_save(flag); -+ lq_w32(chan_no, LQ_DMA_CS); -+ /* check if the descriptor length is changed */ -+ if (lq_r32(LQ_DMA_CDLEN) != pCh->desc_len) -+ lq_w32(pCh->desc_len, LQ_DMA_CDLEN); -+ lq_w32(lq_r32(LQ_DMA_CCTRL) & ~1, LQ_DMA_CCTRL); -+ lq_w32(lq_r32(LQ_DMA_CCTRL) | 2, LQ_DMA_CCTRL); -+ while (lq_r32(LQ_DMA_CCTRL) & 2) -+ ; -+ lq_w32(0x0a, LQ_DMA_CIE); /* fix me, should enable all the interrupts here? */ -+ lq_w32(lq_r32(LQ_DMA_IRNEN) | (1 << chan_no), LQ_DMA_IRNEN); -+ lq_w32(0x30000, LQ_DMA_CCTRL); -+ local_irq_restore(flag); -+ lq_enable_irq(dma_chan[chan_no].irq); -+ } -+ } -+} -+EXPORT_SYMBOL(dma_device_register); -+ -+void dma_device_unregister(struct dma_device_info *dev) -+{ -+ int i, j; -+ int chan_no; -+ struct dma_channel_info *pCh; -+ struct rx_desc *rx_desc_p; -+ struct tx_desc *tx_desc_p; -+ unsigned long flag; -+ -+ for (i = 0; i < dev->max_tx_chan_num; i++) { -+ pCh = dev->tx_chan[i]; -+ if (pCh->control == LQ_DMA_CH_ON) { -+ chan_no = (int)(dev->tx_chan[i] - dma_chan); -+ local_irq_save(flag); -+ lq_w32(chan_no, LQ_DMA_CS); -+ pCh->curr_desc = 0; -+ pCh->prev_desc = 0; -+ pCh->control = LQ_DMA_CH_OFF; -+ lq_w32(0, LQ_DMA_CIE); /* fix me, should disable all the interrupts here? */ -+ lq_w32(lq_r32(LQ_DMA_IRNEN) & ~(1 << chan_no), LQ_DMA_IRNEN); /* disable interrupts */ -+ lq_w32(lq_r32(LQ_DMA_CCTRL) & ~1, LQ_DMA_CCTRL); -+ while (lq_r32(LQ_DMA_CCTRL) & 1) -+ ; -+ local_irq_restore(flag); -+ -+ for (j = 0; j < pCh->desc_len; j++) { -+ tx_desc_p = (struct tx_desc *)pCh->desc_base + j; -+ if ((tx_desc_p->status.field.OWN == CPU_OWN && tx_desc_p->status.field.C) -+ || (tx_desc_p->status.field.OWN == DMA_OWN && tx_desc_p->status.field.data_length > 0)) { -+ dev->buffer_free((u8 *) __va(tx_desc_p->Data_Pointer), (void *)pCh->opt[j]); -+ } -+ tx_desc_p->status.field.OWN = CPU_OWN; -+ memset(tx_desc_p, 0, sizeof(struct tx_desc)); -+ } -+ /* TODO should free buffer that is not transferred by dma */ -+ } -+ } -+ -+ for (i = 0; i < dev->max_rx_chan_num; i++) { -+ pCh = dev->rx_chan[i]; -+ chan_no = (int)(dev->rx_chan[i] - dma_chan); -+ lq_disable_irq(pCh->irq); -+ -+ local_irq_save(flag); -+ g_lq_dma_int_status &= ~(1 << chan_no); -+ pCh->curr_desc = 0; -+ pCh->prev_desc = 0; -+ pCh->control = LQ_DMA_CH_OFF; -+ -+ lq_w32(chan_no, LQ_DMA_CS); -+ lq_w32(0, LQ_DMA_CIE); /* fix me, should disable all the interrupts here? */ -+ lq_w32(lq_r32(LQ_DMA_IRNEN) & ~(1 << chan_no), LQ_DMA_IRNEN); /* disable interrupts */ -+ lq_w32(lq_r32(LQ_DMA_CCTRL) & ~1, LQ_DMA_CCTRL); -+ while (lq_r32(LQ_DMA_CCTRL) & 1) -+ ; -+ -+ local_irq_restore(flag); -+ for (j = 0; j < pCh->desc_len; j++) { -+ rx_desc_p = (struct rx_desc *) pCh->desc_base + j; -+ if ((rx_desc_p->status.field.OWN == CPU_OWN -+ && rx_desc_p->status.field.C) -+ || (rx_desc_p->status.field.OWN == DMA_OWN -+ && rx_desc_p->status.field.data_length > 0)) { -+ dev->buffer_free((u8 *) -+ __va(rx_desc_p->Data_Pointer), -+ (void *) pCh->opt[j]); -+ } -+ } -+ } -+} -+EXPORT_SYMBOL(dma_device_unregister); -+ -+int dma_device_read(struct dma_device_info *dma_dev, u8 **dataptr, void **opt) -+{ -+ u8 *buf; -+ int len; -+ int byte_offset = 0; -+ void *p = NULL; -+ struct dma_channel_info *pCh = dma_dev->rx_chan[dma_dev->current_rx_chan]; -+ struct rx_desc *rx_desc_p; -+ -+ /* get the rx data first */ -+ rx_desc_p = (struct rx_desc *) pCh->desc_base + pCh->curr_desc; -+ if (!(rx_desc_p->status.field.OWN == CPU_OWN && rx_desc_p->status.field.C)) -+ return 0; -+ -+ buf = (u8 *) __va(rx_desc_p->Data_Pointer); -+ *(u32 *)dataptr = (u32)buf; -+ len = rx_desc_p->status.field.data_length; -+ -+ if (opt) -+ *(int *)opt = (int)pCh->opt[pCh->curr_desc]; -+ -+ /* replace with a new allocated buffer */ -+ buf = dma_dev->buffer_alloc(pCh->packet_size, &byte_offset, &p); -+ -+ if (buf) { -+ dma_cache_inv((unsigned long) buf, pCh->packet_size); -+ pCh->opt[pCh->curr_desc] = p; -+ wmb(); -+ -+ rx_desc_p->Data_Pointer = (u32) CPHYSADDR((u32) buf); -+ rx_desc_p->status.word = (DMA_OWN << 31) | ((byte_offset) << 23) | pCh->packet_size; -+ wmb(); -+ } else { -+ *(u32 *) dataptr = 0; -+ if (opt) -+ *(int *) opt = 0; -+ len = 0; -+ } -+ -+ /* increase the curr_desc pointer */ -+ pCh->curr_desc++; -+ if (pCh->curr_desc == pCh->desc_len) -+ pCh->curr_desc = 0; -+ -+ return len; -+} -+EXPORT_SYMBOL(dma_device_read); -+ -+int dma_device_write(struct dma_device_info *dma_dev, u8 *dataptr, int len, void *opt) -+{ -+ unsigned long flag; -+ u32 tmp, byte_offset; -+ struct dma_channel_info *pCh; -+ int chan_no; -+ struct tx_desc *tx_desc_p; -+ local_irq_save(flag); -+ -+ pCh = dma_dev->tx_chan[dma_dev->current_tx_chan]; -+ chan_no = (int)(pCh - (struct dma_channel_info *) dma_chan); -+ -+ tx_desc_p = (struct tx_desc *)pCh->desc_base + pCh->prev_desc; -+ while (tx_desc_p->status.field.OWN == CPU_OWN && tx_desc_p->status.field.C) { -+ dma_dev->buffer_free((u8 *) __va(tx_desc_p->Data_Pointer), pCh->opt[pCh->prev_desc]); -+ memset(tx_desc_p, 0, sizeof(struct tx_desc)); -+ pCh->prev_desc = (pCh->prev_desc + 1) % (pCh->desc_len); -+ tx_desc_p = (struct tx_desc *)pCh->desc_base + pCh->prev_desc; -+ } -+ tx_desc_p = (struct tx_desc *)pCh->desc_base + pCh->curr_desc; -+ /* Check whether this descriptor is available */ -+ if (tx_desc_p->status.field.OWN == DMA_OWN || tx_desc_p->status.field.C) { -+ /* if not, the tell the upper layer device */ -+ dma_dev->intr_handler (dma_dev, TX_BUF_FULL_INT); -+ local_irq_restore(flag); -+ printk(KERN_INFO "%s %d: failed to write!\n", __func__, __LINE__); -+ -+ return 0; -+ } -+ pCh->opt[pCh->curr_desc] = opt; -+ /* byte offset----to adjust the starting address of the data buffer, should be multiple of the burst length. */ -+ byte_offset = ((u32) CPHYSADDR((u32) dataptr)) % ((dma_dev->tx_burst_len) * 4); -+ dma_cache_wback((unsigned long) dataptr, len); -+ wmb(); -+ tx_desc_p->Data_Pointer = (u32) CPHYSADDR((u32) dataptr) - byte_offset; -+ wmb(); -+ tx_desc_p->status.word = (DMA_OWN << 31) | DMA_DESC_SOP_SET | DMA_DESC_EOP_SET | ((byte_offset) << 23) | len; -+ wmb(); -+ -+ pCh->curr_desc++; -+ if (pCh->curr_desc == pCh->desc_len) -+ pCh->curr_desc = 0; -+ -+ /*Check whether this descriptor is available */ -+ tx_desc_p = (struct tx_desc *) pCh->desc_base + pCh->curr_desc; -+ if (tx_desc_p->status.field.OWN == DMA_OWN) { -+ /*if not , the tell the upper layer device */ -+ dma_dev->intr_handler (dma_dev, TX_BUF_FULL_INT); -+ } -+ -+ lq_w32(chan_no, LQ_DMA_CS); -+ tmp = lq_r32(LQ_DMA_CCTRL); -+ -+ if (!(tmp & 1)) -+ pCh->open(pCh); -+ -+ local_irq_restore(flag); -+ -+ return len; -+} -+EXPORT_SYMBOL(dma_device_write); -+ -+int map_dma_chan(struct dma_chan_map *map) -+{ -+ int i, j; -+ int result; -+ -+ for (i = 0; i < MAX_DMA_DEVICE_NUM; i++) -+ strcpy(dma_devs[i].device_name, global_device_name[i]); -+ -+ for (i = 0; i < MAX_DMA_CHANNEL_NUM; i++) { -+ dma_chan[i].irq = map[i].irq; -+ result = request_irq(dma_chan[i].irq, dma_interrupt, IRQF_DISABLED, map[i].dev_name, (void *)&dma_chan[i]); -+ if (result) { -+ printk(KERN_WARNING "error, cannot get dma_irq!\n"); -+ free_irq(dma_chan[i].irq, (void *) &dma_interrupt); -+ -+ return -EFAULT; -+ } -+ } -+ -+ for (i = 0; i < MAX_DMA_DEVICE_NUM; i++) { -+ dma_devs[i].num_tx_chan = 0; /*set default tx channel number to be one */ -+ dma_devs[i].num_rx_chan = 0; /*set default rx channel number to be one */ -+ dma_devs[i].max_rx_chan_num = 0; -+ dma_devs[i].max_tx_chan_num = 0; -+ dma_devs[i].buffer_alloc = &common_buffer_alloc; -+ dma_devs[i].buffer_free = &common_buffer_free; -+ dma_devs[i].intr_handler = NULL; -+ dma_devs[i].tx_burst_len = 4; -+ dma_devs[i].rx_burst_len = 4; -+ if (i == 0) { -+ lq_w32(0, LQ_DMA_PS); -+ lq_w32(lq_r32(LQ_DMA_PCTRL) | ((0xf << 8) | (1 << 6)), LQ_DMA_PCTRL); /*enable dma drop */ -+ } -+ -+ if (i == 1) { -+ lq_w32(1, LQ_DMA_PS); -+ lq_w32(0x14, LQ_DMA_PCTRL); /*deu port setting */ -+ } -+ -+ for (j = 0; j < MAX_DMA_CHANNEL_NUM; j++) { -+ dma_chan[j].byte_offset = 0; -+ dma_chan[j].open = &open_chan; -+ dma_chan[j].close = &close_chan; -+ dma_chan[j].reset = &reset_chan; -+ dma_chan[j].enable_irq = &enable_ch_irq; -+ dma_chan[j].disable_irq = &disable_ch_irq; -+ dma_chan[j].rel_chan_no = map[j].rel_chan_no; -+ dma_chan[j].control = LQ_DMA_CH_OFF; -+ dma_chan[j].default_weight = LQ_DMA_CH_DEFAULT_WEIGHT; -+ dma_chan[j].weight = dma_chan[j].default_weight; -+ dma_chan[j].curr_desc = 0; -+ dma_chan[j].prev_desc = 0; -+ } -+ -+ for (j = 0; j < MAX_DMA_CHANNEL_NUM; j++) { -+ if (strcmp(dma_devs[i].device_name, map[j].dev_name) == 0) { -+ if (map[j].dir == LQ_DMA_RX) { -+ dma_chan[j].dir = LQ_DMA_RX; -+ dma_devs[i].max_rx_chan_num++; -+ dma_devs[i].rx_chan[dma_devs[i].max_rx_chan_num - 1] = &dma_chan[j]; -+ dma_devs[i].rx_chan[dma_devs[i].max_rx_chan_num - 1]->pri = map[j].pri; -+ dma_chan[j].dma_dev = (void *)&dma_devs[i]; -+ } else if (map[j].dir == LQ_DMA_TX) { -+ /*TX direction */ -+ dma_chan[j].dir = LQ_DMA_TX; -+ dma_devs[i].max_tx_chan_num++; -+ dma_devs[i].tx_chan[dma_devs[i].max_tx_chan_num - 1] = &dma_chan[j]; -+ dma_devs[i].tx_chan[dma_devs[i].max_tx_chan_num - 1]->pri = map[j].pri; -+ dma_chan[j].dma_dev = (void *)&dma_devs[i]; -+ } else { -+ printk(KERN_WARNING "WRONG DMA MAP!\n"); -+ } -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+void dma_chip_init(void) -+{ -+ int i; -+ -+ /* enable DMA from PMU */ -+ lq_pmu_enable(PMU_DMA); -+ -+ /* reset DMA */ -+ lq_w32(lq_r32(LQ_DMA_CTRL) | 1, LQ_DMA_CTRL); -+ -+ /* disable all interrupts */ -+ lq_w32(0, LQ_DMA_IRNEN); -+ -+ for (i = 0; i < MAX_DMA_CHANNEL_NUM; i++) { -+ lq_w32(i, LQ_DMA_CS); -+ lq_w32(0x2, LQ_DMA_CCTRL); -+ lq_w32(0x80000040, LQ_DMA_CPOLL); -+ lq_w32(lq_r32(LQ_DMA_CCTRL) & ~0x1, LQ_DMA_CCTRL); -+ } -+} -+ -+int lq_dma_init(void) -+{ -+ int i; -+ -+ dma_chip_init(); -+ -+ if (map_dma_chan(default_dma_map)) -+ BUG(); -+ -+ g_desc_list = (u64 *)KSEG1ADDR(__get_free_page(GFP_DMA)); -+ -+ if (g_desc_list == NULL) { -+ printk(KERN_WARNING "no memory for desriptor\n"); -+ return -ENOMEM; -+ } -+ -+ memset(g_desc_list, 0, PAGE_SIZE); -+ -+ for (i = 0; i < MAX_DMA_CHANNEL_NUM; i++) { -+ dma_chan[i].desc_base = (u32)g_desc_list + i * LQ_DMA_DESCRIPTOR_OFFSET * 8; -+ dma_chan[i].curr_desc = 0; -+ dma_chan[i].desc_len = LQ_DMA_DESCRIPTOR_OFFSET; -+ -+ lq_w32(i, LQ_DMA_CS); -+ lq_w32((u32)CPHYSADDR(dma_chan[i].desc_base), LQ_DMA_CDBA); -+ lq_w32(dma_chan[i].desc_len, LQ_DMA_CDLEN); -+ } -+ return 0; -+} -+ -+arch_initcall(lq_dma_init); -+ -+void dma_cleanup(void) -+{ -+ int i; -+ -+ free_page(KSEG0ADDR((unsigned long) g_desc_list)); -+ for (i = 0; i < MAX_DMA_CHANNEL_NUM; i++) -+ free_irq(dma_chan[i].irq, (void *)&dma_interrupt); -+} -+ -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/arch/mips/lantiq/xway/pmu.c -@@ -0,0 +1,36 @@ -+/* -+ * 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/kernel.h> -+#include <linux/module.h> -+#include <linux/version.h> -+ -+#include <xway.h> -+ -+#define LQ_PMU_PWDCR ((u32 *)(LQ_PMU_BASE_ADDR + 0x001C)) -+#define LQ_PMU_PWDSR ((u32 *)(LQ_PMU_BASE_ADDR + 0x0020)) -+ -+void -+lq_pmu_enable(unsigned int module) -+{ -+ int err = 1000000; -+ -+ lq_w32(lq_r32(LQ_PMU_PWDCR) & ~module, LQ_PMU_PWDCR); -+ while (--err && (lq_r32(LQ_PMU_PWDSR) & module)); -+ -+ if (!err) -+ panic("activating PMU module failed!"); -+} -+EXPORT_SYMBOL(lq_pmu_enable); -+ -+void -+lq_pmu_disable(unsigned int module) -+{ -+ lq_w32(lq_r32(LQ_PMU_PWDCR) | module, LQ_PMU_PWDCR); -+} -+EXPORT_SYMBOL(lq_pmu_disable); ---- /dev/null -+++ b/arch/mips/lantiq/xway/timer.c -@@ -0,0 +1,828 @@ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/version.h> -+#include <linux/types.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/init.h> -+#include <linux/uaccess.h> -+#include <linux/unistd.h> -+#include <linux/errno.h> -+#include <linux/interrupt.h> -+#include <linux/sched.h> -+ -+#include <asm/irq.h> -+#include <asm/div64.h> -+ -+#include <xway.h> -+#include <xway_irq.h> -+#include <lantiq_timer.h> -+ -+#define MAX_NUM_OF_32BIT_TIMER_BLOCKS 6 -+ -+#ifdef TIMER1A -+#define FIRST_TIMER TIMER1A -+#else -+#define FIRST_TIMER 2 -+#endif -+ -+/* -+ * GPTC divider is set or not. -+ */ -+#define GPTU_CLC_RMC_IS_SET 0 -+ -+/* -+ * Timer Interrupt (IRQ) -+ */ -+/* Must be adjusted when ICU driver is available */ -+#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22) -+ -+/* -+ * Bits Operation -+ */ -+#define GET_BITS(x, msb, lsb) \ -+ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb)) -+#define SET_BITS(x, msb, lsb, value) \ -+ (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | \ -+ (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb))) -+ -+/* -+ * GPTU Register Mapping -+ */ -+#define LQ_GPTU (KSEG1 + 0x1E100A00) -+#define LQ_GPTU_CLC ((volatile u32 *)(LQ_GPTU + 0x0000)) -+#define LQ_GPTU_ID ((volatile u32 *)(LQ_GPTU + 0x0008)) -+#define LQ_GPTU_CON(n, X) ((volatile u32 *)(LQ_GPTU + 0x0010 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ -+#define LQ_GPTU_RUN(n, X) ((volatile u32 *)(LQ_GPTU + 0x0018 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ -+#define LQ_GPTU_RELOAD(n, X) ((volatile u32 *)(LQ_GPTU + 0x0020 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ -+#define LQ_GPTU_COUNT(n, X) ((volatile u32 *)(LQ_GPTU + 0x0028 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */ -+#define LQ_GPTU_IRNEN ((volatile u32 *)(LQ_GPTU + 0x00F4)) -+#define LQ_GPTU_IRNICR ((volatile u32 *)(LQ_GPTU + 0x00F8)) -+#define LQ_GPTU_IRNCR ((volatile u32 *)(LQ_GPTU + 0x00FC)) -+ -+/* -+ * Clock Control Register -+ */ -+#define GPTU_CLC_SMC GET_BITS(*LQ_GPTU_CLC, 23, 16) -+#define GPTU_CLC_RMC GET_BITS(*LQ_GPTU_CLC, 15, 8) -+#define GPTU_CLC_FSOE (*LQ_GPTU_CLC & (1 << 5)) -+#define GPTU_CLC_EDIS (*LQ_GPTU_CLC & (1 << 3)) -+#define GPTU_CLC_SPEN (*LQ_GPTU_CLC & (1 << 2)) -+#define GPTU_CLC_DISS (*LQ_GPTU_CLC & (1 << 1)) -+#define GPTU_CLC_DISR (*LQ_GPTU_CLC & (1 << 0)) -+ -+#define GPTU_CLC_SMC_SET(value) SET_BITS(0, 23, 16, (value)) -+#define GPTU_CLC_RMC_SET(value) SET_BITS(0, 15, 8, (value)) -+#define GPTU_CLC_FSOE_SET(value) ((value) ? (1 << 5) : 0) -+#define GPTU_CLC_SBWE_SET(value) ((value) ? (1 << 4) : 0) -+#define GPTU_CLC_EDIS_SET(value) ((value) ? (1 << 3) : 0) -+#define GPTU_CLC_SPEN_SET(value) ((value) ? (1 << 2) : 0) -+#define GPTU_CLC_DISR_SET(value) ((value) ? (1 << 0) : 0) -+ -+/* -+ * ID Register -+ */ -+#define GPTU_ID_ID GET_BITS(*LQ_GPTU_ID, 15, 8) -+#define GPTU_ID_CFG GET_BITS(*LQ_GPTU_ID, 7, 5) -+#define GPTU_ID_REV GET_BITS(*LQ_GPTU_ID, 4, 0) -+ -+/* -+ * Control Register of Timer/Counter nX -+ * n is the index of block (1 based index) -+ * X is either A or B -+ */ -+#define GPTU_CON_SRC_EG(n, X) (*LQ_GPTU_CON(n, X) & (1 << 10)) -+#define GPTU_CON_SRC_EXT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 9)) -+#define GPTU_CON_SYNC(n, X) (*LQ_GPTU_CON(n, X) & (1 << 8)) -+#define GPTU_CON_EDGE(n, X) GET_BITS(*LQ_GPTU_CON(n, X), 7, 6) -+#define GPTU_CON_INV(n, X) (*LQ_GPTU_CON(n, X) & (1 << 5)) -+#define GPTU_CON_EXT(n, X) (*LQ_GPTU_CON(n, A) & (1 << 4)) /* Timer/Counter B does not have this bit */ -+#define GPTU_CON_STP(n, X) (*LQ_GPTU_CON(n, X) & (1 << 3)) -+#define GPTU_CON_CNT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 2)) -+#define GPTU_CON_DIR(n, X) (*LQ_GPTU_CON(n, X) & (1 << 1)) -+#define GPTU_CON_EN(n, X) (*LQ_GPTU_CON(n, X) & (1 << 0)) -+ -+#define GPTU_CON_SRC_EG_SET(value) ((value) ? 0 : (1 << 10)) -+#define GPTU_CON_SRC_EXT_SET(value) ((value) ? (1 << 9) : 0) -+#define GPTU_CON_SYNC_SET(value) ((value) ? (1 << 8) : 0) -+#define GPTU_CON_EDGE_SET(value) SET_BITS(0, 7, 6, (value)) -+#define GPTU_CON_INV_SET(value) ((value) ? (1 << 5) : 0) -+#define GPTU_CON_EXT_SET(value) ((value) ? (1 << 4) : 0) -+#define GPTU_CON_STP_SET(value) ((value) ? (1 << 3) : 0) -+#define GPTU_CON_CNT_SET(value) ((value) ? (1 << 2) : 0) -+#define GPTU_CON_DIR_SET(value) ((value) ? (1 << 1) : 0) -+ -+#define GPTU_RUN_RL_SET(value) ((value) ? (1 << 2) : 0) -+#define GPTU_RUN_CEN_SET(value) ((value) ? (1 << 1) : 0) -+#define GPTU_RUN_SEN_SET(value) ((value) ? (1 << 0) : 0) -+ -+#define GPTU_IRNEN_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0) -+#define GPTU_IRNCR_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0) -+ -+#define TIMER_FLAG_MASK_SIZE(x) (x & 0x0001) -+#define TIMER_FLAG_MASK_TYPE(x) (x & 0x0002) -+#define TIMER_FLAG_MASK_STOP(x) (x & 0x0004) -+#define TIMER_FLAG_MASK_DIR(x) (x & 0x0008) -+#define TIMER_FLAG_NONE_EDGE 0x0000 -+#define TIMER_FLAG_MASK_EDGE(x) (x & 0x0030) -+#define TIMER_FLAG_REAL 0x0000 -+#define TIMER_FLAG_INVERT 0x0040 -+#define TIMER_FLAG_MASK_INVERT(x) (x & 0x0040) -+#define TIMER_FLAG_MASK_TRIGGER(x) (x & 0x0070) -+#define TIMER_FLAG_MASK_SYNC(x) (x & 0x0080) -+#define TIMER_FLAG_CALLBACK_IN_HB 0x0200 -+#define TIMER_FLAG_MASK_HANDLE(x) (x & 0x0300) -+#define TIMER_FLAG_MASK_SRC(x) (x & 0x1000) -+ -+struct timer_dev_timer { -+ unsigned int f_irq_on; -+ unsigned int irq; -+ unsigned int flag; -+ unsigned long arg1; -+ unsigned long arg2; -+}; -+ -+struct timer_dev { -+ struct mutex gptu_mutex; -+ unsigned int number_of_timers; -+ unsigned int occupation; -+ unsigned int f_gptu_on; -+ struct timer_dev_timer timer[MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2]; -+}; -+ -+static long gptu_ioctl(struct file *, unsigned int, unsigned long); -+static int gptu_open(struct inode *, struct file *); -+static int gptu_release(struct inode *, struct file *); -+ -+static struct file_operations gptu_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = gptu_ioctl, -+ .open = gptu_open, -+ .release = gptu_release -+}; -+ -+static struct miscdevice gptu_miscdev = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "gptu", -+ .fops = &gptu_fops, -+}; -+ -+static struct timer_dev timer_dev; -+ -+static irqreturn_t timer_irq_handler(int irq, void *p) -+{ -+ unsigned int timer; -+ unsigned int flag; -+ struct timer_dev_timer *dev_timer = (struct timer_dev_timer *)p; -+ -+ timer = irq - TIMER_INTERRUPT; -+ if (timer < timer_dev.number_of_timers -+ && dev_timer == &timer_dev.timer[timer]) { -+ /* Clear interrupt. */ -+ lq_w32(1 << timer, LQ_GPTU_IRNCR); -+ -+ /* Call user hanler or signal. */ -+ flag = dev_timer->flag; -+ if (!(timer & 0x01) -+ || TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) { -+ /* 16-bit timer or timer A of 32-bit timer */ -+ switch (TIMER_FLAG_MASK_HANDLE(flag)) { -+ case TIMER_FLAG_CALLBACK_IN_IRQ: -+ case TIMER_FLAG_CALLBACK_IN_HB: -+ if (dev_timer->arg1) -+ (*(timer_callback)dev_timer->arg1)(dev_timer->arg2); -+ break; -+ case TIMER_FLAG_SIGNAL: -+ send_sig((int)dev_timer->arg2, (struct task_struct *)dev_timer->arg1, 0); -+ break; -+ } -+ } -+ } -+ return IRQ_HANDLED; -+} -+ -+static inline void lq_enable_gptu(void) -+{ -+ lq_pmu_enable(PMU_GPT); -+ -+ /* Set divider as 1, disable write protection for SPEN, enable module. */ -+ *LQ_GPTU_CLC = -+ GPTU_CLC_SMC_SET(0x00) | -+ GPTU_CLC_RMC_SET(0x01) | -+ GPTU_CLC_FSOE_SET(0) | -+ GPTU_CLC_SBWE_SET(1) | -+ GPTU_CLC_EDIS_SET(0) | -+ GPTU_CLC_SPEN_SET(0) | -+ GPTU_CLC_DISR_SET(0); -+} -+ -+static inline void lq_disable_gptu(void) -+{ -+ lq_w32(0x00, LQ_GPTU_IRNEN); -+ lq_w32(0xfff, LQ_GPTU_IRNCR); -+ -+ /* Set divider as 0, enable write protection for SPEN, disable module. */ -+ *LQ_GPTU_CLC = -+ GPTU_CLC_SMC_SET(0x00) | -+ GPTU_CLC_RMC_SET(0x00) | -+ GPTU_CLC_FSOE_SET(0) | -+ GPTU_CLC_SBWE_SET(0) | -+ GPTU_CLC_EDIS_SET(0) | -+ GPTU_CLC_SPEN_SET(0) | -+ GPTU_CLC_DISR_SET(1); -+ -+ lq_pmu_disable(PMU_GPT); -+} -+ -+int lq_request_timer(unsigned int timer, unsigned int flag, -+ unsigned long value, unsigned long arg1, unsigned long arg2) -+{ -+ int ret = 0; -+ unsigned int con_reg, irnen_reg; -+ int n, X; -+ -+ if (timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ printk(KERN_INFO "request_timer(%d, 0x%08X, %lu)...", -+ timer, flag, value); -+ -+ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) -+ value &= 0xFFFF; -+ else -+ timer &= ~0x01; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ /* -+ * Allocate timer. -+ */ -+ if (timer < FIRST_TIMER) { -+ unsigned int mask; -+ unsigned int shift; -+ /* This takes care of TIMER1B which is the only choice for Voice TAPI system */ -+ unsigned int offset = TIMER2A; -+ -+ /* -+ * Pick up a free timer. -+ */ -+ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) { -+ mask = 1 << offset; -+ shift = 1; -+ } else { -+ mask = 3 << offset; -+ shift = 2; -+ } -+ for (timer = offset; -+ timer < offset + timer_dev.number_of_timers; -+ timer += shift, mask <<= shift) -+ if (!(timer_dev.occupation & mask)) { -+ timer_dev.occupation |= mask; -+ break; -+ } -+ if (timer >= offset + timer_dev.number_of_timers) { -+ printk("failed![%d]\n", __LINE__); -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } else -+ ret = timer; -+ } else { -+ register unsigned int mask; -+ -+ /* -+ * Check if the requested timer is free. -+ */ -+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if ((timer_dev.occupation & mask)) { -+ printk("failed![%d] mask %#x, timer_dev.occupation %#x\n", -+ __LINE__, mask, timer_dev.occupation); -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EBUSY; -+ } else { -+ timer_dev.occupation |= mask; -+ ret = 0; -+ } -+ } -+ -+ /* -+ * Prepare control register value. -+ */ -+ switch (TIMER_FLAG_MASK_EDGE(flag)) { -+ default: -+ case TIMER_FLAG_NONE_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x00); -+ break; -+ case TIMER_FLAG_RISE_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x01); -+ break; -+ case TIMER_FLAG_FALL_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x02); -+ break; -+ case TIMER_FLAG_ANY_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x03); -+ break; -+ } -+ if (TIMER_FLAG_MASK_TYPE(flag) == TIMER_FLAG_TIMER) -+ con_reg |= -+ TIMER_FLAG_MASK_SRC(flag) == -+ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : -+ GPTU_CON_SRC_EXT_SET(0); -+ else -+ con_reg |= -+ TIMER_FLAG_MASK_SRC(flag) == -+ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : -+ GPTU_CON_SRC_EG_SET(0); -+ con_reg |= -+ TIMER_FLAG_MASK_SYNC(flag) == -+ TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : -+ GPTU_CON_SYNC_SET(1); -+ con_reg |= -+ TIMER_FLAG_MASK_INVERT(flag) == -+ TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1); -+ con_reg |= -+ TIMER_FLAG_MASK_SIZE(flag) == -+ TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : -+ GPTU_CON_EXT_SET(1); -+ con_reg |= -+ TIMER_FLAG_MASK_STOP(flag) == -+ TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0); -+ con_reg |= -+ TIMER_FLAG_MASK_TYPE(flag) == -+ TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : -+ GPTU_CON_CNT_SET(1); -+ con_reg |= -+ TIMER_FLAG_MASK_DIR(flag) == -+ TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0); -+ -+ /* -+ * Fill up running data. -+ */ -+ timer_dev.timer[timer - FIRST_TIMER].flag = flag; -+ timer_dev.timer[timer - FIRST_TIMER].arg1 = arg1; -+ timer_dev.timer[timer - FIRST_TIMER].arg2 = arg2; -+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) -+ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flag; -+ -+ /* -+ * Enable GPTU module. -+ */ -+ if (!timer_dev.f_gptu_on) { -+ lq_enable_gptu(); -+ timer_dev.f_gptu_on = 1; -+ } -+ -+ /* -+ * Enable IRQ. -+ */ -+ if (TIMER_FLAG_MASK_HANDLE(flag) != TIMER_FLAG_NO_HANDLE) { -+ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL) -+ timer_dev.timer[timer - FIRST_TIMER].arg1 = -+ (unsigned long) find_task_by_vpid((int) arg1); -+ -+ irnen_reg = 1 << (timer - FIRST_TIMER); -+ -+ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL -+ || (TIMER_FLAG_MASK_HANDLE(flag) == -+ TIMER_FLAG_CALLBACK_IN_IRQ -+ && timer_dev.timer[timer - FIRST_TIMER].arg1)) { -+ enable_irq(timer_dev.timer[timer - FIRST_TIMER].irq); -+ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 1; -+ } -+ } else -+ irnen_reg = 0; -+ -+ /* -+ * Write config register, reload value and enable interrupt. -+ */ -+ n = timer >> 1; -+ X = timer & 0x01; -+ *LQ_GPTU_CON(n, X) = con_reg; -+ *LQ_GPTU_RELOAD(n, X) = value; -+ /* printk("reload value = %d\n", (u32)value); */ -+ *LQ_GPTU_IRNEN |= irnen_reg; -+ -+ mutex_unlock(&timer_dev.gptu_mutex); -+ printk("successful!\n"); -+ return ret; -+} -+EXPORT_SYMBOL(lq_request_timer); -+ -+int lq_free_timer(unsigned int timer) -+{ -+ unsigned int flag; -+ unsigned int mask; -+ int n, X; -+ -+ if (!timer_dev.f_gptu_on) -+ return -EINVAL; -+ -+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ flag = timer_dev.timer[timer - FIRST_TIMER].flag; -+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) -+ timer &= ~0x01; -+ -+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if (((timer_dev.occupation & mask) ^ mask)) { -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } -+ -+ n = timer >> 1; -+ X = timer & 0x01; -+ -+ if (GPTU_CON_EN(n, X)) -+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1); -+ -+ *LQ_GPTU_IRNEN &= ~GPTU_IRNEN_TC_SET(n, X, 1); -+ *LQ_GPTU_IRNCR |= GPTU_IRNCR_TC_SET(n, X, 1); -+ -+ if (timer_dev.timer[timer - FIRST_TIMER].f_irq_on) { -+ disable_irq(timer_dev.timer[timer - FIRST_TIMER].irq); -+ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 0; -+ } -+ -+ timer_dev.occupation &= ~mask; -+ if (!timer_dev.occupation && timer_dev.f_gptu_on) { -+ lq_disable_gptu(); -+ timer_dev.f_gptu_on = 0; -+ } -+ -+ mutex_unlock(&timer_dev.gptu_mutex); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lq_free_timer); -+ -+int lq_start_timer(unsigned int timer, int is_resume) -+{ -+ unsigned int flag; -+ unsigned int mask; -+ int n, X; -+ -+ if (!timer_dev.f_gptu_on) -+ return -EINVAL; -+ -+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ flag = timer_dev.timer[timer - FIRST_TIMER].flag; -+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) -+ timer &= ~0x01; -+ -+ mask = (TIMER_FLAG_MASK_SIZE(flag) == -+ TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if (((timer_dev.occupation & mask) ^ mask)) { -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } -+ -+ n = timer >> 1; -+ X = timer & 0x01; -+ -+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_RL_SET(!is_resume) | GPTU_RUN_SEN_SET(1); -+ -+ mutex_unlock(&timer_dev.gptu_mutex); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lq_start_timer); -+ -+int lq_stop_timer(unsigned int timer) -+{ -+ unsigned int flag; -+ unsigned int mask; -+ int n, X; -+ -+ if (!timer_dev.f_gptu_on) -+ return -EINVAL; -+ -+ if (timer < FIRST_TIMER -+ || timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ flag = timer_dev.timer[timer - FIRST_TIMER].flag; -+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) -+ timer &= ~0x01; -+ -+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if (((timer_dev.occupation & mask) ^ mask)) { -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } -+ -+ n = timer >> 1; -+ X = timer & 0x01; -+ -+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1); -+ -+ mutex_unlock(&timer_dev.gptu_mutex); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lq_stop_timer); -+ -+int lq_reset_counter_flags(u32 timer, u32 flags) -+{ -+ unsigned int oflag; -+ unsigned int mask, con_reg; -+ int n, X; -+ -+ if (!timer_dev.f_gptu_on) -+ return -EINVAL; -+ -+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ oflag = timer_dev.timer[timer - FIRST_TIMER].flag; -+ if (TIMER_FLAG_MASK_SIZE(oflag) != TIMER_FLAG_16BIT) -+ timer &= ~0x01; -+ -+ mask = (TIMER_FLAG_MASK_SIZE(oflag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if (((timer_dev.occupation & mask) ^ mask)) { -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } -+ -+ switch (TIMER_FLAG_MASK_EDGE(flags)) { -+ default: -+ case TIMER_FLAG_NONE_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x00); -+ break; -+ case TIMER_FLAG_RISE_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x01); -+ break; -+ case TIMER_FLAG_FALL_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x02); -+ break; -+ case TIMER_FLAG_ANY_EDGE: -+ con_reg = GPTU_CON_EDGE_SET(0x03); -+ break; -+ } -+ if (TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER) -+ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : GPTU_CON_SRC_EXT_SET(0); -+ else -+ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : GPTU_CON_SRC_EG_SET(0); -+ con_reg |= TIMER_FLAG_MASK_SYNC(flags) == TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : GPTU_CON_SYNC_SET(1); -+ con_reg |= TIMER_FLAG_MASK_INVERT(flags) == TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1); -+ con_reg |= TIMER_FLAG_MASK_SIZE(flags) == TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : GPTU_CON_EXT_SET(1); -+ con_reg |= TIMER_FLAG_MASK_STOP(flags) == TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0); -+ con_reg |= TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : GPTU_CON_CNT_SET(1); -+ con_reg |= TIMER_FLAG_MASK_DIR(flags) == TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0); -+ -+ timer_dev.timer[timer - FIRST_TIMER].flag = flags; -+ if (TIMER_FLAG_MASK_SIZE(flags) != TIMER_FLAG_16BIT) -+ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flags; -+ -+ n = timer >> 1; -+ X = timer & 0x01; -+ -+ *LQ_GPTU_CON(n, X) = con_reg; -+ smp_wmb(); -+ printk(KERN_INFO "[%s]: counter%d oflags %#x, nflags %#x, GPTU_CON %#x\n", __func__, timer, oflag, flags, *LQ_GPTU_CON(n, X)); -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return 0; -+} -+EXPORT_SYMBOL(lq_reset_counter_flags); -+ -+int lq_get_count_value(unsigned int timer, unsigned long *value) -+{ -+ unsigned int flag; -+ unsigned int mask; -+ int n, X; -+ -+ if (!timer_dev.f_gptu_on) -+ return -EINVAL; -+ -+ if (timer < FIRST_TIMER -+ || timer >= FIRST_TIMER + timer_dev.number_of_timers) -+ return -EINVAL; -+ -+ mutex_lock(&timer_dev.gptu_mutex); -+ -+ flag = timer_dev.timer[timer - FIRST_TIMER].flag; -+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT) -+ timer &= ~0x01; -+ -+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer; -+ if (((timer_dev.occupation & mask) ^ mask)) { -+ mutex_unlock(&timer_dev.gptu_mutex); -+ return -EINVAL; -+ } -+ -+ n = timer >> 1; -+ X = timer & 0x01; -+ -+ *value = *LQ_GPTU_COUNT(n, X); -+ -+ mutex_unlock(&timer_dev.gptu_mutex); -+ -+ return 0; -+} -+EXPORT_SYMBOL(lq_get_count_value); -+ -+u32 lq_cal_divider(unsigned long freq) -+{ -+ u64 module_freq, fpi = lq_get_fpi_bus_clock(2); -+ u32 clock_divider = 1; -+ module_freq = fpi * 1000; -+ do_div(module_freq, clock_divider * freq); -+ return module_freq; -+} -+EXPORT_SYMBOL(lq_cal_divider); -+ -+int lq_set_timer(unsigned int timer, unsigned int freq, int is_cyclic, -+ int is_ext_src, unsigned int handle_flag, unsigned long arg1, -+ unsigned long arg2) -+{ -+ unsigned long divider; -+ unsigned int flag; -+ -+ divider = lq_cal_divider(freq); -+ if (divider == 0) -+ return -EINVAL; -+ flag = ((divider & ~0xFFFF) ? TIMER_FLAG_32BIT : TIMER_FLAG_16BIT) -+ | (is_cyclic ? TIMER_FLAG_CYCLIC : TIMER_FLAG_ONCE) -+ | (is_ext_src ? TIMER_FLAG_EXT_SRC : TIMER_FLAG_INT_SRC) -+ | TIMER_FLAG_TIMER | TIMER_FLAG_DOWN -+ | TIMER_FLAG_MASK_HANDLE(handle_flag); -+ -+ printk(KERN_INFO "lq_set_timer(%d, %d), divider = %lu\n", -+ timer, freq, divider); -+ return lq_request_timer(timer, flag, divider, arg1, arg2); -+} -+EXPORT_SYMBOL(lq_set_timer); -+ -+int lq_set_counter(unsigned int timer, unsigned int flag, u32 reload, -+ unsigned long arg1, unsigned long arg2) -+{ -+ printk(KERN_INFO "lq_set_counter(%d, %#x, %d)\n", timer, flag, reload); -+ return lq_request_timer(timer, flag, reload, arg1, arg2); -+} -+EXPORT_SYMBOL(lq_set_counter); -+ -+static long gptu_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ int ret; -+ struct gptu_ioctl_param param; -+ -+ if (!access_ok(VERIFY_READ, arg, sizeof(struct gptu_ioctl_param))) -+ return -EFAULT; -+ copy_from_user(¶m, (void *) arg, sizeof(param)); -+ -+ if ((((cmd == GPTU_REQUEST_TIMER || cmd == GPTU_SET_TIMER -+ || GPTU_SET_COUNTER) && param.timer < 2) -+ || cmd == GPTU_GET_COUNT_VALUE || cmd == GPTU_CALCULATE_DIVIDER) -+ && !access_ok(VERIFY_WRITE, arg, -+ sizeof(struct gptu_ioctl_param))) -+ return -EFAULT; -+ -+ switch (cmd) { -+ case GPTU_REQUEST_TIMER: -+ ret = lq_request_timer(param.timer, param.flag, param.value, -+ (unsigned long) param.pid, -+ (unsigned long) param.sig); -+ if (ret > 0) { -+ copy_to_user(&((struct gptu_ioctl_param *) arg)-> -+ timer, &ret, sizeof(&ret)); -+ ret = 0; -+ } -+ break; -+ case GPTU_FREE_TIMER: -+ ret = lq_free_timer(param.timer); -+ break; -+ case GPTU_START_TIMER: -+ ret = lq_start_timer(param.timer, param.flag); -+ break; -+ case GPTU_STOP_TIMER: -+ ret = lq_stop_timer(param.timer); -+ break; -+ case GPTU_GET_COUNT_VALUE: -+ ret = lq_get_count_value(param.timer, ¶m.value); -+ if (!ret) -+ copy_to_user(&((struct gptu_ioctl_param *) arg)-> -+ value, ¶m.value, -+ sizeof(param.value)); -+ break; -+ case GPTU_CALCULATE_DIVIDER: -+ param.value = lq_cal_divider(param.value); -+ if (param.value == 0) -+ ret = -EINVAL; -+ else { -+ copy_to_user(&((struct gptu_ioctl_param *) arg)-> -+ value, ¶m.value, -+ sizeof(param.value)); -+ ret = 0; -+ } -+ break; -+ case GPTU_SET_TIMER: -+ ret = lq_set_timer(param.timer, param.value, -+ TIMER_FLAG_MASK_STOP(param.flag) != -+ TIMER_FLAG_ONCE ? 1 : 0, -+ TIMER_FLAG_MASK_SRC(param.flag) == -+ TIMER_FLAG_EXT_SRC ? 1 : 0, -+ TIMER_FLAG_MASK_HANDLE(param.flag) == -+ TIMER_FLAG_SIGNAL ? TIMER_FLAG_SIGNAL : -+ TIMER_FLAG_NO_HANDLE, -+ (unsigned long) param.pid, -+ (unsigned long) param.sig); -+ if (ret > 0) { -+ copy_to_user(&((struct gptu_ioctl_param *) arg)-> -+ timer, &ret, sizeof(&ret)); -+ ret = 0; -+ } -+ break; -+ case GPTU_SET_COUNTER: -+ lq_set_counter(param.timer, param.flag, param.value, 0, 0); -+ if (ret > 0) { -+ copy_to_user(&((struct gptu_ioctl_param *) arg)-> -+ timer, &ret, sizeof(&ret)); -+ ret = 0; -+ } -+ break; -+ default: -+ ret = -ENOTTY; -+ } -+ -+ return ret; -+} -+ -+static int gptu_open(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static int gptu_release(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+int __init lq_gptu_init(void) -+{ -+ int ret; -+ unsigned int i; -+ -+ lq_w32(0, LQ_GPTU_IRNEN); -+ lq_w32(0xfff, LQ_GPTU_IRNCR); -+ -+ memset(&timer_dev, 0, sizeof(timer_dev)); -+ mutex_init(&timer_dev.gptu_mutex); -+ -+ lq_enable_gptu(); -+ timer_dev.number_of_timers = GPTU_ID_CFG * 2; -+ lq_disable_gptu(); -+ if (timer_dev.number_of_timers > MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2) -+ timer_dev.number_of_timers = MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2; -+ printk(KERN_INFO "gptu: totally %d 16-bit timers/counters\n", timer_dev.number_of_timers); -+ -+ ret = misc_register(&gptu_miscdev); -+ if (ret) { -+ printk(KERN_ERR "gptu: can't misc_register, get error %d\n", -ret); -+ return ret; -+ } else { -+ printk(KERN_INFO "gptu: misc_register on minor %d\n", gptu_miscdev.minor); -+ } -+ -+ for (i = 0; i < timer_dev.number_of_timers; i++) { -+ ret = request_irq(TIMER_INTERRUPT + i, timer_irq_handler, IRQF_TIMER, gptu_miscdev.name, &timer_dev.timer[i]); -+ if (ret) { -+ for (; i >= 0; i--) -+ free_irq(TIMER_INTERRUPT + i, &timer_dev.timer[i]); -+ misc_deregister(&gptu_miscdev); -+ printk(KERN_ERR "gptu: failed in requesting irq (%d), get error %d\n", i, -ret); -+ return ret; -+ } else { -+ timer_dev.timer[i].irq = TIMER_INTERRUPT + i; -+ disable_irq(timer_dev.timer[i].irq); -+ printk(KERN_INFO "gptu: succeeded to request irq %d\n", timer_dev.timer[i].irq); -+ } -+ } -+ -+ return 0; -+} -+ -+void __exit lq_gptu_exit(void) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < timer_dev.number_of_timers; i++) { -+ if (timer_dev.timer[i].f_irq_on) -+ disable_irq(timer_dev.timer[i].irq); -+ free_irq(timer_dev.timer[i].irq, &timer_dev.timer[i]); -+ } -+ lq_disable_gptu(); -+ misc_deregister(&gptu_miscdev); -+} -+ -+module_init(lq_gptu_init); -+module_exit(lq_gptu_exit); ---- /dev/null -+++ b/arch/mips/lantiq/xway/timer.h -@@ -0,0 +1,155 @@ -+#ifndef __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ -+#define __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ -+ -+ -+/****************************************************************************** -+ Copyright (c) 2002, Infineon Technologies. All rights reserved. -+ -+ No Warranty -+ Because the program is licensed free of charge, there is no warranty for -+ the program, to the extent permitted by applicable law. Except when -+ otherwise stated in writing the copyright holders and/or other parties -+ provide the program "as is" without warranty of any kind, either -+ expressed or implied, including, but not limited to, the implied -+ warranties of merchantability and fitness for a particular purpose. The -+ entire risk as to the quality and performance of the program is with -+ you. should the program prove defective, you assume the cost of all -+ necessary servicing, repair or correction. -+ -+ In no event unless required by applicable law or agreed to in writing -+ will any copyright holder, or any other party who may modify and/or -+ redistribute the program as permitted above, be liable to you for -+ damages, including any general, special, incidental or consequential -+ damages arising out of the use or inability to use the program -+ (including but not limited to loss of data or data being rendered -+ inaccurate or losses sustained by you or third parties or a failure of -+ the program to operate with any other programs), even if such holder or -+ other party has been advised of the possibility of such damages. -+******************************************************************************/ -+ -+ -+/* -+ * #################################### -+ * Definition -+ * #################################### -+ */ -+ -+/* -+ * Available Timer/Counter Index -+ */ -+#define TIMER(n, X) (n * 2 + (X ? 1 : 0)) -+#define TIMER_ANY 0x00 -+#define TIMER1A TIMER(1, 0) -+#define TIMER1B TIMER(1, 1) -+#define TIMER2A TIMER(2, 0) -+#define TIMER2B TIMER(2, 1) -+#define TIMER3A TIMER(3, 0) -+#define TIMER3B TIMER(3, 1) -+ -+/* -+ * Flag of Timer/Counter -+ * These flags specify the way in which timer is configured. -+ */ -+/* Bit size of timer/counter. */ -+#define TIMER_FLAG_16BIT 0x0000 -+#define TIMER_FLAG_32BIT 0x0001 -+/* Switch between timer and counter. */ -+#define TIMER_FLAG_TIMER 0x0000 -+#define TIMER_FLAG_COUNTER 0x0002 -+/* Stop or continue when overflowing/underflowing. */ -+#define TIMER_FLAG_ONCE 0x0000 -+#define TIMER_FLAG_CYCLIC 0x0004 -+/* Count up or counter down. */ -+#define TIMER_FLAG_UP 0x0000 -+#define TIMER_FLAG_DOWN 0x0008 -+/* Count on specific level or edge. */ -+#define TIMER_FLAG_HIGH_LEVEL_SENSITIVE 0x0000 -+#define TIMER_FLAG_LOW_LEVEL_SENSITIVE 0x0040 -+#define TIMER_FLAG_RISE_EDGE 0x0010 -+#define TIMER_FLAG_FALL_EDGE 0x0020 -+#define TIMER_FLAG_ANY_EDGE 0x0030 -+/* Signal is syncronous to module clock or not. */ -+#define TIMER_FLAG_UNSYNC 0x0000 -+#define TIMER_FLAG_SYNC 0x0080 -+/* Different interrupt handle type. */ -+#define TIMER_FLAG_NO_HANDLE 0x0000 -+#if defined(__KERNEL__) -+ #define TIMER_FLAG_CALLBACK_IN_IRQ 0x0100 -+#endif // defined(__KERNEL__) -+#define TIMER_FLAG_SIGNAL 0x0300 -+/* Internal clock source or external clock source */ -+#define TIMER_FLAG_INT_SRC 0x0000 -+#define TIMER_FLAG_EXT_SRC 0x1000 -+ -+ -+/* -+ * ioctl Command -+ */ -+#define GPTU_REQUEST_TIMER 0x01 /* General method to setup timer/counter. */ -+#define GPTU_FREE_TIMER 0x02 /* Free timer/counter. */ -+#define GPTU_START_TIMER 0x03 /* Start or resume timer/counter. */ -+#define GPTU_STOP_TIMER 0x04 /* Suspend timer/counter. */ -+#define GPTU_GET_COUNT_VALUE 0x05 /* Get current count value. */ -+#define GPTU_CALCULATE_DIVIDER 0x06 /* Calculate timer divider from given freq.*/ -+#define GPTU_SET_TIMER 0x07 /* Simplified method to setup timer. */ -+#define GPTU_SET_COUNTER 0x08 /* Simplified method to setup counter. */ -+ -+/* -+ * Data Type Used to Call ioctl -+ */ -+struct gptu_ioctl_param { -+ unsigned int timer; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * -+ * GPTU_SET_COUNTER, this field is ID of expected * -+ * timer/counter. If it's zero, a timer/counter would * -+ * be dynamically allocated and ID would be stored in * -+ * this field. * -+ * In command GPTU_GET_COUNT_VALUE, this field is * -+ * ignored. * -+ * In other command, this field is ID of timer/counter * -+ * allocated. */ -+ unsigned int flag; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * -+ * GPTU_SET_COUNTER, this field contains flags to * -+ * specify how to configure timer/counter. * -+ * In command GPTU_START_TIMER, zero indicate start * -+ * and non-zero indicate resume timer/counter. * -+ * In other command, this field is ignored. */ -+ unsigned long value; /* In command GPTU_REQUEST_TIMER, this field contains * -+ * init/reload value. * -+ * In command GPTU_SET_TIMER, this field contains * -+ * frequency (0.001Hz) of timer. * -+ * In command GPTU_GET_COUNT_VALUE, current count * -+ * value would be stored in this field. * -+ * In command GPTU_CALCULATE_DIVIDER, this field * -+ * contains frequency wanted, and after calculation, * -+ * divider would be stored in this field to overwrite * -+ * the frequency. * -+ * In other command, this field is ignored. */ -+ int pid; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * -+ * if signal is required, this field contains process * -+ * ID to which signal would be sent. * -+ * In other command, this field is ignored. */ -+ int sig; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * -+ * if signal is required, this field contains signal * -+ * number which would be sent. * -+ * In other command, this field is ignored. */ -+}; -+ -+/* -+ * #################################### -+ * Data Type -+ * #################################### -+ */ -+typedef void (*timer_callback)(unsigned long arg); -+ -+extern int ifxmips_request_timer(unsigned int, unsigned int, unsigned long, unsigned long, unsigned long); -+extern int ifxmips_free_timer(unsigned int); -+extern int ifxmips_start_timer(unsigned int, int); -+extern int ifxmips_stop_timer(unsigned int); -+extern int ifxmips_reset_counter_flags(u32 timer, u32 flags); -+extern int ifxmips_get_count_value(unsigned int, unsigned long *); -+extern u32 ifxmips_cal_divider(unsigned long); -+extern int ifxmips_set_timer(unsigned int, unsigned int, int, int, unsigned int, unsigned long, unsigned long); -+extern int ifxmips_set_counter(unsigned int timer, unsigned int flag, -+ u32 reload, unsigned long arg1, unsigned long arg2); -+ -+#endif /* __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ */ ---- /dev/null -+++ b/arch/mips/lantiq/xway/Makefile -@@ -0,0 +1,5 @@ -+obj-y := pmu.o prom.o dma.o timer.o reset.o clk-xway.o -+obj-y += gpio.o gpio_ebu.o gpio_leds.o devices.o -+obj-$(CONFIG_LANTIQ_MACH_EASY50812) += mach-easy50812.o -+obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o -+obj-$(CONFIG_LANTIQ_MACH_EASY4010) += mach-easy4010.o ---- /dev/null -+++ b/arch/mips/lantiq/xway/clk-xway.c -@@ -0,0 +1,219 @@ -+/* -+ * 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) 2007 Xu Liang, infineon -+ * 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 <xway.h> -+ -+static unsigned int lq_ram_clocks[] = {CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; -+#define DDR_HZ lq_ram_clocks[lq_r32(LQ_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 CGU_PLL0_PHASE_DIVIDER_ENABLE (lq_r32(LQ_CGU_PLL0_CFG) & (1 << 31)) -+#define CGU_PLL0_BYPASS (lq_r32(LQ_CGU_PLL0_CFG) & (1 << 30)) -+#define CGU_PLL0_CFG_DSMSEL (lq_r32(LQ_CGU_PLL0_CFG) & (1 << 28)) -+#define CGU_PLL0_CFG_FRAC_EN (lq_r32(LQ_CGU_PLL0_CFG) & (1 << 27)) -+#define CGU_PLL1_SRC (lq_r32(LQ_CGU_PLL1_CFG) & (1 << 31)) -+#define CGU_PLL2_PHASE_DIVIDER_ENABLE (lq_r32(LQ_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(*LQ_CGU_PLL0_CFG, 26, 17) -+#define CGU_PLL0_CFG_PLLN GET_BITS(*LQ_CGU_PLL0_CFG, 12, 6) -+#define CGU_PLL0_CFG_PLLM GET_BITS(*LQ_CGU_PLL0_CFG, 5, 2) -+#define CGU_PLL2_SRC GET_BITS(*LQ_CGU_PLL2_CFG, 18, 17) -+#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(*LQ_CGU_PLL2_CFG, 16, 13) -+ -+#define LQ_GPTU_GPT_CLC ((u32 *)(LQ_GPTU_BASE_ADDR + 0x0000)) -+#define LQ_CGU_PLL0_CFG ((u32 *)(LQ_CGU_BASE_ADDR + 0x0004)) -+#define LQ_CGU_PLL1_CFG ((u32 *)(LQ_CGU_BASE_ADDR + 0x0008)) -+#define LQ_CGU_PLL2_CFG ((u32 *)(LQ_CGU_BASE_ADDR + 0x000C)) -+#define LQ_CGU_SYS ((u32 *)(LQ_CGU_BASE_ADDR + 0x0010)) -+#define LQ_CGU_UPDATE ((u32 *)(LQ_CGU_BASE_ADDR + 0x0014)) -+#define LQ_CGU_IF_CLK ((u32 *)(LQ_CGU_BASE_ADDR + 0x0018)) -+#define LQ_CGU_OSC_CON ((u32 *)(LQ_CGU_BASE_ADDR + 0x001C)) -+#define LQ_CGU_SMD ((u32 *)(LQ_CGU_BASE_ADDR + 0x0020)) -+#define LQ_CGU_CT1SR ((u32 *)(LQ_CGU_BASE_ADDR + 0x0028)) -+#define LQ_CGU_CT2SR ((u32 *)(LQ_CGU_BASE_ADDR + 0x002C)) -+#define LQ_CGU_PCMCR ((u32 *)(LQ_CGU_BASE_ADDR + 0x0030)) -+#define LQ_CGU_PCI_CR ((u32 *)(LQ_CGU_BASE_ADDR + 0x0034)) -+#define LQ_CGU_PD_PC ((u32 *)(LQ_CGU_BASE_ADDR + 0x0038)) -+#define LQ_CGU_FMR ((u32 *)(LQ_CGU_BASE_ADDR + 0x003C)) -+ -+static unsigned int lq_get_pll0_fdiv(void); -+ -+static inline unsigned int -+get_input_clock(int pll) -+{ -+ switch (pll) { -+ case 0: -+ if (lq_r32(LQ_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 lq_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 -+lq_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 -+lq_get_pll0_fdiv(void) -+{ -+ unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1; -+ return (lq_get_pll0_fosc() + (div >> 1)) / div; -+} -+ -+unsigned int -+lq_get_io_region_clock(void) -+{ -+ unsigned int ret = lq_get_pll0_fosc(); -+ switch (lq_r32(LQ_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(lq_get_io_region_clock); -+ -+unsigned int -+lq_get_fpi_bus_clock(int fpi) -+{ -+ unsigned int ret = lq_get_io_region_clock(); -+ if ((fpi == 2) && (lq_r32(LQ_CGU_SYS) & CGU_SYS_FPI_SEL)) -+ ret >>= 1; -+ return ret; -+} -+EXPORT_SYMBOL(lq_get_fpi_bus_clock); -+ -+unsigned int -+lq_get_cpu_hz(void) -+{ -+ switch (lq_r32(LQ_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(lq_get_cpu_hz); -+ -+unsigned int -+lq_get_fpi_hz(void) -+{ -+ unsigned int ddr_clock = DDR_HZ; -+ if (lq_r32(LQ_CGU_SYS) & 0x40) -+ return ddr_clock >> 1; -+ return ddr_clock; -+} -+EXPORT_SYMBOL(lq_get_fpi_hz); -+ -+ ---- /dev/null -+++ b/arch/mips/lantiq/xway/gpio.c -@@ -0,0 +1,206 @@ -+/* -+ * 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/slab.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/gpio.h> -+ -+#include <lantiq.h> -+ -+#define LQ_GPIO0_BASE_ADDR 0x1E100B10 -+#define LQ_GPIO1_BASE_ADDR 0x1E100B40 -+#define LQ_GPIO_SIZE 0x30 -+ -+#define LQ_GPIO_OUT 0x00 -+#define LQ_GPIO_IN 0x04 -+#define LQ_GPIO_DIR 0x08 -+#define LQ_GPIO_ALTSEL0 0x0C -+#define LQ_GPIO_ALTSEL1 0x10 -+#define LQ_GPIO_OD 0x14 -+ -+#define PINS_PER_PORT 16 -+ -+#define lq_gpio_getbit(m, r, p) !!(lq_r32(m + r) & (1 << p)) -+#define lq_gpio_setbit(m, r, p) lq_w32_mask(0, (1 << p), m + r) -+#define lq_gpio_clearbit(m, r, p) lq_w32_mask((1 << p), 0, m + r) -+ -+struct lq_gpio -+{ -+ void __iomem *membase; -+ struct gpio_chip chip; -+}; -+ -+int -+gpio_to_irq(unsigned int gpio) -+{ -+ return -EINVAL; -+} -+EXPORT_SYMBOL(gpio_to_irq); -+ -+int -+lq_gpio_setconfig(unsigned int pin, unsigned int reg, unsigned int val) -+{ -+ void __iomem *membase = (void*)KSEG1ADDR(LQ_GPIO0_BASE_ADDR); -+ if(pin >= (2 * PINS_PER_PORT)) -+ return -EINVAL; -+ if(pin >= PINS_PER_PORT) -+ { -+ pin -= PINS_PER_PORT; -+ membase += LQ_GPIO_SIZE; -+ } -+ if(val) -+ lq_w32_mask(0, (1 << pin), membase + reg); -+ else -+ lq_w32_mask((1 << pin), 0, membase + reg); -+ return 0; -+} -+EXPORT_SYMBOL(lq_gpio_setconfig); -+ -+int -+lq_gpio_request(unsigned int pin, unsigned int alt0, -+ unsigned int alt1, unsigned int dir, const char *name) -+{ -+ void __iomem *membase = (void*)KSEG1ADDR(LQ_GPIO0_BASE_ADDR); -+ if(pin >= (2 * PINS_PER_PORT)) -+ return -EINVAL; -+ if(gpio_request(pin, name)) -+ { -+ printk("failed to register %s gpio\n", name); -+ return -EBUSY; -+ } -+ if(dir) -+ gpio_direction_output(pin, 1); -+ else -+ gpio_direction_input(pin); -+ if(pin >= PINS_PER_PORT) -+ { -+ pin -= PINS_PER_PORT; -+ membase += LQ_GPIO_SIZE; -+ } -+ if(alt0) -+ lq_gpio_setbit(membase, LQ_GPIO_ALTSEL0, pin); -+ else -+ lq_gpio_clearbit(membase, LQ_GPIO_ALTSEL0, pin); -+ if(alt1) -+ lq_gpio_setbit(membase, LQ_GPIO_ALTSEL1, pin); -+ else -+ lq_gpio_clearbit(membase, LQ_GPIO_ALTSEL1, pin); -+ return 0; -+} -+EXPORT_SYMBOL(lq_gpio_request); -+ -+static void -+lq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) -+{ -+ struct lq_gpio *lq_gpio = container_of(chip, struct lq_gpio, chip); -+ if(value) -+ lq_gpio_setbit(lq_gpio->membase, LQ_GPIO_OUT, offset); -+ else -+ lq_gpio_clearbit(lq_gpio->membase, LQ_GPIO_OUT, offset); -+} -+ -+static int -+lq_gpio_get(struct gpio_chip *chip, unsigned int offset) -+{ -+ struct lq_gpio *lq_gpio = container_of(chip, struct lq_gpio, chip); -+ return lq_gpio_getbit(lq_gpio->membase, LQ_GPIO_IN, offset); -+} -+ -+static int -+lq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) -+{ -+ struct lq_gpio *lq_gpio = container_of(chip, struct lq_gpio, chip); -+ lq_gpio_clearbit(lq_gpio->membase, LQ_GPIO_OD, offset); -+ lq_gpio_clearbit(lq_gpio->membase, LQ_GPIO_DIR, offset); -+ return 0; -+} -+ -+static int -+lq_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value) -+{ -+ struct lq_gpio *lq_gpio = container_of(chip, struct lq_gpio, chip); -+ lq_gpio_setbit(lq_gpio->membase, LQ_GPIO_OD, offset); -+ lq_gpio_setbit(lq_gpio->membase, LQ_GPIO_DIR, offset); -+ lq_gpio_set(chip, offset, value); -+ return 0; -+} -+ -+static int -+lq_gpio_req(struct gpio_chip *chip, unsigned offset) -+{ -+ struct lq_gpio *lq_gpio = container_of(chip, struct lq_gpio, chip); -+ lq_gpio_clearbit(lq_gpio->membase, LQ_GPIO_ALTSEL0, offset); -+ lq_gpio_clearbit(lq_gpio->membase, LQ_GPIO_ALTSEL1, offset); -+ return 0; -+} -+ -+static int -+lq_gpio_probe(struct platform_device *pdev) -+{ -+ struct lq_gpio *lq_gpio = kzalloc(sizeof(struct lq_gpio), GFP_KERNEL); -+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ int ret = 0; -+ if(!res) -+ { -+ ret = -ENOENT; -+ goto err_free; -+ } -+ res = request_mem_region(res->start, resource_size(res), -+ dev_name(&pdev->dev)); -+ if(!res) -+ { -+ ret = -EBUSY; -+ goto err_free; -+ } -+ lq_gpio->membase = ioremap_nocache(res->start, resource_size(res)); -+ if(!lq_gpio->membase) -+ { -+ ret = -ENOMEM; -+ goto err_release_mem_region; -+ } -+ lq_gpio->chip.label = "lq_gpio"; -+ lq_gpio->chip.direction_input = lq_gpio_direction_input; -+ lq_gpio->chip.direction_output = lq_gpio_direction_output; -+ lq_gpio->chip.get = lq_gpio_get; -+ lq_gpio->chip.set = lq_gpio_set; -+ lq_gpio->chip.request = lq_gpio_req; -+ lq_gpio->chip.base = PINS_PER_PORT * pdev->id; -+ lq_gpio->chip.ngpio = PINS_PER_PORT; -+ platform_set_drvdata(pdev, lq_gpio); -+ ret = gpiochip_add(&lq_gpio->chip); -+ if(!ret) -+ return 0; -+ -+ iounmap(lq_gpio->membase); -+err_release_mem_region: -+ release_mem_region(res->start, resource_size(res)); -+err_free: -+ kfree(lq_gpio); -+ return ret; -+} -+ -+static struct platform_driver -+lq_gpio_driver = { -+ .probe = lq_gpio_probe, -+ .driver = { -+ .name = "lq_gpio", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+int __init -+lq_gpio_init(void) -+{ -+ int ret = platform_driver_register(&lq_gpio_driver); -+ if(ret) -+ printk(KERN_INFO "lq_gpio : Error registering platfom driver!"); -+ return ret; -+} -+ -+postcore_initcall(lq_gpio_init); ---- /dev/null -+++ b/arch/mips/lantiq/xway/reset.c -@@ -0,0 +1,53 @@ -+/* -+ * 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/io.h> -+#include <linux/pm.h> -+#include <asm/reboot.h> -+ -+#include <xway.h> -+ -+#define LQ_RCU_RST ((u32 *)(LQ_RCU_BASE_ADDR + 0x0010)) -+#define LQ_RCU_RST_ALL 0x40000000 -+ -+static void -+lq_machine_restart(char *command) -+{ -+ printk(KERN_NOTICE "System restart\n"); -+ local_irq_disable(); -+ lq_w32(lq_r32(LQ_RCU_RST) | LQ_RCU_RST_ALL, LQ_RCU_RST); -+ for(;;); -+} -+ -+static void -+lq_machine_halt(void) -+{ -+ printk(KERN_NOTICE "System halted.\n"); -+ local_irq_disable(); -+ for(;;); -+} -+ -+static void -+lq_machine_power_off(void) -+{ -+ printk(KERN_NOTICE "Please turn off the power now.\n"); -+ local_irq_disable(); -+ for(;;); -+} -+ -+static int __init -+mips_reboot_setup(void) -+{ -+ _machine_restart = lq_machine_restart; -+ _machine_halt = lq_machine_halt; -+ pm_power_off = lq_machine_power_off; -+ return 0; -+} -+ -+arch_initcall(mips_reboot_setup); diff --git a/target/linux/lantiq/patches/105-header_xway.patch b/target/linux/lantiq/patches/105-header_xway.patch deleted file mode 100644 index 18e37a7..0000000 --- a/target/linux/lantiq/patches/105-header_xway.patch +++ /dev/null @@ -1,565 +0,0 @@ ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/xway/irq.h -@@ -0,0 +1,18 @@ -+/* -+ * 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> -+ */ -+ -+#ifndef __LANTIQ_IRQ_H -+#define __LANTIQ_IRQ_H -+ -+#include <xway_irq.h> -+ -+#define NR_IRQS 256 -+ -+#include_next <irq.h> -+ -+#endif ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/lantiq_timer.h -@@ -0,0 +1,155 @@ -+#ifndef __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ -+#define __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ -+ -+ -+/****************************************************************************** -+ Copyright (c) 2002, Infineon Technologies. All rights reserved. -+ -+ No Warranty -+ Because the program is licensed free of charge, there is no warranty for -+ the program, to the extent permitted by applicable law. Except when -+ otherwise stated in writing the copyright holders and/or other parties -+ provide the program "as is" without warranty of any kind, either -+ expressed or implied, including, but not limited to, the implied -+ warranties of merchantability and fitness for a particular purpose. The -+ entire risk as to the quality and performance of the program is with -+ you. should the program prove defective, you assume the cost of all -+ necessary servicing, repair or correction. -+ -+ In no event unless required by applicable law or agreed to in writing -+ will any copyright holder, or any other party who may modify and/or -+ redistribute the program as permitted above, be liable to you for -+ damages, including any general, special, incidental or consequential -+ damages arising out of the use or inability to use the program -+ (including but not limited to loss of data or data being rendered -+ inaccurate or losses sustained by you or third parties or a failure of -+ the program to operate with any other programs), even if such holder or -+ other party has been advised of the possibility of such damages. -+******************************************************************************/ -+ -+ -+/* -+ * #################################### -+ * Definition -+ * #################################### -+ */ -+ -+/* -+ * Available Timer/Counter Index -+ */ -+#define TIMER(n, X) (n * 2 + (X ? 1 : 0)) -+#define TIMER_ANY 0x00 -+#define TIMER1A TIMER(1, 0) -+#define TIMER1B TIMER(1, 1) -+#define TIMER2A TIMER(2, 0) -+#define TIMER2B TIMER(2, 1) -+#define TIMER3A TIMER(3, 0) -+#define TIMER3B TIMER(3, 1) -+ -+/* -+ * Flag of Timer/Counter -+ * These flags specify the way in which timer is configured. -+ */ -+/* Bit size of timer/counter. */ -+#define TIMER_FLAG_16BIT 0x0000 -+#define TIMER_FLAG_32BIT 0x0001 -+/* Switch between timer and counter. */ -+#define TIMER_FLAG_TIMER 0x0000 -+#define TIMER_FLAG_COUNTER 0x0002 -+/* Stop or continue when overflowing/underflowing. */ -+#define TIMER_FLAG_ONCE 0x0000 -+#define TIMER_FLAG_CYCLIC 0x0004 -+/* Count up or counter down. */ -+#define TIMER_FLAG_UP 0x0000 -+#define TIMER_FLAG_DOWN 0x0008 -+/* Count on specific level or edge. */ -+#define TIMER_FLAG_HIGH_LEVEL_SENSITIVE 0x0000 -+#define TIMER_FLAG_LOW_LEVEL_SENSITIVE 0x0040 -+#define TIMER_FLAG_RISE_EDGE 0x0010 -+#define TIMER_FLAG_FALL_EDGE 0x0020 -+#define TIMER_FLAG_ANY_EDGE 0x0030 -+/* Signal is syncronous to module clock or not. */ -+#define TIMER_FLAG_UNSYNC 0x0000 -+#define TIMER_FLAG_SYNC 0x0080 -+/* Different interrupt handle type. */ -+#define TIMER_FLAG_NO_HANDLE 0x0000 -+#if defined(__KERNEL__) -+ #define TIMER_FLAG_CALLBACK_IN_IRQ 0x0100 -+#endif // defined(__KERNEL__) -+#define TIMER_FLAG_SIGNAL 0x0300 -+/* Internal clock source or external clock source */ -+#define TIMER_FLAG_INT_SRC 0x0000 -+#define TIMER_FLAG_EXT_SRC 0x1000 -+ -+ -+/* -+ * ioctl Command -+ */ -+#define GPTU_REQUEST_TIMER 0x01 /* General method to setup timer/counter. */ -+#define GPTU_FREE_TIMER 0x02 /* Free timer/counter. */ -+#define GPTU_START_TIMER 0x03 /* Start or resume timer/counter. */ -+#define GPTU_STOP_TIMER 0x04 /* Suspend timer/counter. */ -+#define GPTU_GET_COUNT_VALUE 0x05 /* Get current count value. */ -+#define GPTU_CALCULATE_DIVIDER 0x06 /* Calculate timer divider from given freq.*/ -+#define GPTU_SET_TIMER 0x07 /* Simplified method to setup timer. */ -+#define GPTU_SET_COUNTER 0x08 /* Simplified method to setup counter. */ -+ -+/* -+ * Data Type Used to Call ioctl -+ */ -+struct gptu_ioctl_param { -+ unsigned int timer; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * -+ * GPTU_SET_COUNTER, this field is ID of expected * -+ * timer/counter. If it's zero, a timer/counter would * -+ * be dynamically allocated and ID would be stored in * -+ * this field. * -+ * In command GPTU_GET_COUNT_VALUE, this field is * -+ * ignored. * -+ * In other command, this field is ID of timer/counter * -+ * allocated. */ -+ unsigned int flag; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and * -+ * GPTU_SET_COUNTER, this field contains flags to * -+ * specify how to configure timer/counter. * -+ * In command GPTU_START_TIMER, zero indicate start * -+ * and non-zero indicate resume timer/counter. * -+ * In other command, this field is ignored. */ -+ unsigned long value; /* In command GPTU_REQUEST_TIMER, this field contains * -+ * init/reload value. * -+ * In command GPTU_SET_TIMER, this field contains * -+ * frequency (0.001Hz) of timer. * -+ * In command GPTU_GET_COUNT_VALUE, current count * -+ * value would be stored in this field. * -+ * In command GPTU_CALCULATE_DIVIDER, this field * -+ * contains frequency wanted, and after calculation, * -+ * divider would be stored in this field to overwrite * -+ * the frequency. * -+ * In other command, this field is ignored. */ -+ int pid; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * -+ * if signal is required, this field contains process * -+ * ID to which signal would be sent. * -+ * In other command, this field is ignored. */ -+ int sig; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, * -+ * if signal is required, this field contains signal * -+ * number which would be sent. * -+ * In other command, this field is ignored. */ -+}; -+ -+/* -+ * #################################### -+ * Data Type -+ * #################################### -+ */ -+typedef void (*timer_callback)(unsigned long arg); -+ -+extern int lq_request_timer(unsigned int, unsigned int, unsigned long, unsigned long, unsigned long); -+extern int lq_free_timer(unsigned int); -+extern int lq_start_timer(unsigned int, int); -+extern int lq_stop_timer(unsigned int); -+extern int lq_reset_counter_flags(u32 timer, u32 flags); -+extern int lq_get_count_value(unsigned int, unsigned long *); -+extern u32 lq_cal_divider(unsigned long); -+extern int lq_set_timer(unsigned int, unsigned int, int, int, unsigned int, unsigned long, unsigned long); -+extern int lq_set_counter(unsigned int timer, unsigned int flag, -+ u32 reload, unsigned long arg1, unsigned long arg2); -+ -+#endif /* __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ */ ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/xway/xway.h -@@ -0,0 +1,121 @@ -+/* -+ * 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) 2005 infineon -+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> -+ */ -+ -+#ifdef CONFIG_SOC_LANTIQ_XWAY -+ -+#ifndef _LQ_XWAY_H__ -+#define _LQ_XWAY_H__ -+ -+#include <lantiq.h> -+ -+/* request a non-gpio and set the PIO config */ -+extern int lq_gpio_request(unsigned int pin, unsigned int alt0, -+ unsigned int alt1, unsigned int dir, const char *name); -+extern int lq_gpio_setconfig(unsigned int pin, unsigned int reg, unsigned int val); -+ -+extern void lq_pmu_enable(unsigned int module); -+extern void lq_pmu_disable(unsigned int module); -+ -+extern unsigned int lq_get_fpi_bus_clock(int bus); -+ -+#define BOARD_SYSTEM_TYPE "LANTIQ" -+ -+/*------------ Chip IDs */ -+#define SOC_ID_DANUBE1 0x129 -+#define SOC_ID_DANUBE2 0x12B -+#define SOC_ID_TWINPASS 0x12D -+#define SOC_ID_ARX188 0x16C -+#define SOC_ID_ARX168 0x16D -+#define SOC_ID_ARX182 0x16F -+ -+/*------------ SoC Types */ -+#define SOC_TYPE_DANUBE 0x01 -+#define SOC_TYPE_TWINPASS 0x02 -+#define SOC_TYPE_AR9 0x03 -+ -+/*------------ ASC0/1 */ -+#define LQ_ASC0_BASE 0x1E100400 -+#define LQ_ASC1_BASE 0x1E100C00 -+#define LQ_ASC_SIZE 0x400 -+ -+/*------------ RCU */ -+#define LQ_RCU_BASE_ADDR 0xBF203000 -+ -+/*------------ GPTU */ -+#define LQ_GPTU_BASE_ADDR 0xB8000300 -+ -+/*------------ EBU */ -+#define LQ_EBU_GPIO_START 0x14000000 -+#define LQ_EBU_GPIO_SIZE 0x1000 -+ -+#define LQ_EBU_BASE_ADDR 0xBE105300 -+ -+#define LQ_EBU_BUSCON0 ((u32 *)(LQ_EBU_BASE_ADDR + 0x0060)) -+#define LQ_EBU_PCC_CON ((u32 *)(LQ_EBU_BASE_ADDR + 0x0090)) -+#define LQ_EBU_PCC_IEN ((u32 *)(LQ_EBU_BASE_ADDR + 0x00A4)) -+#define LQ_EBU_PCC_ISTAT ((u32 *)(LQ_EBU_BASE_ADDR + 0x00A0)) -+#define LQ_EBU_BUSCON1 ((u32 *)(LQ_EBU_BASE_ADDR + 0x0064)) -+#define LQ_EBU_ADDRSEL1 ((u32 *)(LQ_EBU_BASE_ADDR + 0x0024)) -+ -+#define EBU_WRDIS 0x80000000 -+ -+/*------------ CGU */ -+#define LQ_CGU_BASE_ADDR (KSEG1 + 0x1F103000) -+ -+/*------------ PMU */ -+#define LQ_PMU_BASE_ADDR (KSEG1 + 0x1F102000) -+ -+#define PMU_DMA 0x0020 -+#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 */ -+#define LQ_PPE32_BASE_ADDR 0xBE180000 -+#define LQ_PPE32_SIZE 0x40000 -+ -+/*------------ DMA */ -+#define LQ_DMA_BASE_ADDR 0xBE104100 -+ -+/*------------ PCI */ -+#define PCI_CR_PR_BASE_ADDR (KSEG1 + 0x1E105400) -+#define PCI_CS_PR_BASE_ADDR (KSEG1 + 0x17000000) -+ -+/*------------ WDT */ -+#define LQ_WDT_BASE 0x1F8803F0 -+#define LQ_WDT_SIZE 0x10 -+ -+/*------------ Serial To Parallel conversion */ -+#define LQ_STP_BASE 0x1E100BB0 -+#define LQ_STP_SIZE 0x40 -+ -+/*------------ GPIO */ -+#define LQ_GPIO0_BASE_ADDR 0x1E100B10 -+#define LQ_GPIO1_BASE_ADDR 0x1E100B40 -+#define LQ_GPIO_SIZE 0x30 -+ -+/*------------ SSC */ -+#define LQ_SSC_BASE_ADDR (KSEG1 + 0x1e100800) -+ -+/*------------ MEI */ -+#define LQ_MEI_BASE_ADDR (KSEG1 + 0x1E116000) -+ -+/*------------ DEU */ -+#define LQ_DEU_BASE (KSEG1 + 0x1E103100) -+ -+/*------------ MPS */ -+#define LQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000) -+#define LQ_MPS_CHIPID ((u32 *)(LQ_MPS_BASE_ADDR + 0x0344)) -+ -+#endif -+ -+#endif ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h -@@ -0,0 +1,194 @@ -+/* -+ * 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) 2005 infineon -+ * Copyright (C) 2007 John Crispin <blogic@openwrt.org> -+ * -+ */ -+#ifndef _LQ_DMA_H__ -+#define _LQ_DMA_H__ -+ -+#define RCV_INT 1 -+#define TX_BUF_FULL_INT 2 -+#define TRANSMIT_CPT_INT 4 -+#define LQ_DMA_CH_ON 1 -+#define LQ_DMA_CH_OFF 0 -+#define LQ_DMA_CH_DEFAULT_WEIGHT 100 -+ -+enum attr_t{ -+ TX = 0, -+ RX = 1, -+ RESERVED = 2, -+ DEFAULT = 3, -+}; -+ -+#define DMA_OWN 1 -+#define CPU_OWN 0 -+#define DMA_MAJOR 250 -+ -+#define DMA_DESC_OWN_CPU 0x0 -+#define DMA_DESC_OWN_DMA 0x80000000 -+#define DMA_DESC_CPT_SET 0x40000000 -+#define DMA_DESC_SOP_SET 0x20000000 -+#define DMA_DESC_EOP_SET 0x10000000 -+ -+#define MISCFG_MASK 0x40 -+#define RDERR_MASK 0x20 -+#define CHOFF_MASK 0x10 -+#define DESCPT_MASK 0x8 -+#define DUR_MASK 0x4 -+#define EOP_MASK 0x2 -+ -+#define DMA_DROP_MASK (1<<31) -+ -+#define LQ_DMA_RX -1 -+#define LQ_DMA_TX 1 -+ -+struct dma_chan_map { -+ const char *dev_name; -+ enum attr_t dir; -+ int pri; -+ int irq; -+ int rel_chan_no; -+}; -+ -+#ifdef CONFIG_CPU_LITTLE_ENDIAN -+struct rx_desc { -+ u32 data_length:16; -+ volatile u32 reserved:7; -+ volatile u32 byte_offset:2; -+ volatile u32 Burst_length_offset:3; -+ volatile u32 EoP:1; -+ volatile u32 Res:1; -+ volatile u32 C:1; -+ volatile u32 OWN:1; -+ volatile u32 Data_Pointer; /* fixme: should be 28 bits here */ -+}; -+ -+struct tx_desc { -+ volatile u32 data_length:16; -+ volatile u32 reserved1:7; -+ volatile u32 byte_offset:5; -+ volatile u32 EoP:1; -+ volatile u32 SoP:1; -+ volatile u32 C:1; -+ volatile u32 OWN:1; -+ volatile u32 Data_Pointer; /* fixme: should be 28 bits here */ -+}; -+#else /* BIG */ -+struct rx_desc { -+ union { -+ struct { -+ volatile u32 OWN:1; -+ volatile u32 C:1; -+ volatile u32 SoP:1; -+ volatile u32 EoP:1; -+ volatile u32 Burst_length_offset:3; -+ volatile u32 byte_offset:2; -+ volatile u32 reserve:7; -+ volatile u32 data_length:16; -+ } field; -+ volatile u32 word; -+ } status; -+ volatile u32 Data_Pointer; -+}; -+ -+struct tx_desc { -+ union { -+ struct { -+ volatile u32 OWN:1; -+ volatile u32 C:1; -+ volatile u32 SoP:1; -+ volatile u32 EoP:1; -+ volatile u32 byte_offset:5; -+ volatile u32 reserved:7; -+ volatile u32 data_length:16; -+ } field; -+ volatile u32 word; -+ } status; -+ volatile u32 Data_Pointer; -+}; -+#endif /* ENDIAN */ -+ -+struct dma_channel_info { -+ /* relative channel number */ -+ int rel_chan_no; -+ /* class for this channel for QoS */ -+ int pri; -+ /* specify byte_offset */ -+ int byte_offset; -+ /* direction */ -+ int dir; -+ /* irq number */ -+ int irq; -+ /* descriptor parameter */ -+ int desc_base; -+ int desc_len; -+ int curr_desc; -+ int prev_desc; /* only used if it is a tx channel*/ -+ /* weight setting for WFQ algorithm*/ -+ int weight; -+ int default_weight; -+ int packet_size; -+ int burst_len; -+ /* on or off of this channel */ -+ int control; -+ /* optional information for the upper layer devices */ -+#if defined(CONFIG_LQ_ETHERNET_D2) || defined(CONFIG_LQ_PPA) -+ void *opt[64]; -+#else -+ void *opt[25]; -+#endif -+ /* Pointer to the peripheral device who is using this channel */ -+ void *dma_dev; -+ /* channel operations */ -+ void (*open)(struct dma_channel_info *pCh); -+ void (*close)(struct dma_channel_info *pCh); -+ void (*reset)(struct dma_channel_info *pCh); -+ void (*enable_irq)(struct dma_channel_info *pCh); -+ void (*disable_irq)(struct dma_channel_info *pCh); -+}; -+ -+struct dma_device_info { -+ /* device name of this peripheral */ -+ char device_name[15]; -+ int reserved; -+ int tx_burst_len; -+ int rx_burst_len; -+ int default_weight; -+ int current_tx_chan; -+ int current_rx_chan; -+ int num_tx_chan; -+ int num_rx_chan; -+ int max_rx_chan_num; -+ int max_tx_chan_num; -+ struct dma_channel_info *tx_chan[20]; -+ struct dma_channel_info *rx_chan[20]; -+ /*functions, optional*/ -+ u8 *(*buffer_alloc)(int len, int *offset, void **opt); -+ void (*buffer_free)(u8 *dataptr, void *opt); -+ int (*intr_handler)(struct dma_device_info *info, int status); -+ void *priv; /* used by peripheral driver only */ -+}; -+ -+struct dma_device_info *dma_device_reserve(char *dev_name); -+void dma_device_release(struct dma_device_info *dev); -+void dma_device_register(struct dma_device_info *info); -+void dma_device_unregister(struct dma_device_info *info); -+int dma_device_read(struct dma_device_info *info, u8 **dataptr, void **opt); -+int dma_device_write(struct dma_device_info *info, u8 *dataptr, int len, -+ void *opt); -+ -+#endif -+ ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/xway/xway_irq.h -@@ -0,0 +1,62 @@ -+/* -+ * 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> -+ */ -+ -+#ifndef _LANTIQ_XWAY_IRQ_H__ -+#define _LANTIQ_XWAY_IRQ_H__ -+ -+#define INT_NUM_IRQ0 8 -+#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0) -+#define INT_NUM_IM1_IRL0 (INT_NUM_IRQ0 + 32) -+#define INT_NUM_IM2_IRL0 (INT_NUM_IRQ0 + 64) -+#define INT_NUM_IM3_IRL0 (INT_NUM_IRQ0 + 96) -+#define INT_NUM_IM4_IRL0 (INT_NUM_IRQ0 + 128) -+#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0) -+ -+#define LQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 7)) -+#define LQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 7) + 2) -+#define LQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 7) + 3) -+ -+#define LQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15) -+#define LQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14) -+#define LQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16) -+ -+#define LQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21) -+#define LQ_MEI_INT (INT_NUM_IM1_IRL0 + 23) -+ -+#define LQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23) -+#define LQ_USB_INT (INT_NUM_IM1_IRL0 + 22) -+#define LQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23) -+ -+#define MIPS_CPU_TIMER_IRQ 7 -+ -+#define LQ_DMA_CH0_INT (INT_NUM_IM2_IRL0) -+#define LQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1) -+#define LQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2) -+#define LQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3) -+#define LQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4) -+#define LQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5) -+#define LQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6) -+#define LQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7) -+#define LQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8) -+#define LQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9) -+#define LQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10) -+#define LQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11) -+#define LQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25) -+#define LQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26) -+#define LQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27) -+#define LQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28) -+#define LQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29) -+#define LQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30) -+#define LQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16) -+#define LQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21) -+ -+#define LQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24) -+ -+#define INT_NUM_IM4_IRL14 (INT_NUM_IM4_IRL0 + 14) -+ -+#endif diff --git a/target/linux/lantiq/patches/106-early_printk.patch b/target/linux/lantiq/patches/106-early_printk.patch deleted file mode 100644 index 1cf402c..0000000 --- a/target/linux/lantiq/patches/106-early_printk.patch +++ /dev/null @@ -1,93 +0,0 @@ ---- a/arch/mips/lantiq/Kconfig -+++ b/arch/mips/lantiq/Kconfig -@@ -33,4 +33,19 @@ - #source "arch/mips/lantiq/falcon/Kconfig" - source "arch/mips/lantiq/xway/Kconfig" - -+if EARLY_PRINTK -+choice -+ prompt "Early printk port" -+ default LANTIQ_PROM_ASC1 -+ help -+ Choose which serial port is used, until the console driver is loaded -+ -+config LANTIQ_PROM_ASC0 -+ bool "ASC0" -+ -+config LANTIQ_PROM_ASC1 -+ bool "ASC1" -+endchoice -+endif -+ - endif ---- /dev/null -+++ b/arch/mips/lantiq/early_printk.c -@@ -0,0 +1,68 @@ -+/* -+ * 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/cpu.h> -+ -+#include <lantiq.h> -+ -+#ifdef CONFIG_SOC_LANTIQ_XWAY -+#include <xway.h> -+#ifdef CONFIG_LANTIQ_PROM_ASC0 -+#define LQ_ASC_BASE KSEG1ADDR(LQ_ASC0_BASE) -+#else -+#define LQ_ASC_BASE KSEG1ADDR(LQ_ASC1_BASE) -+#endif -+ -+#elif defined(CONFIG_SOC_LANTIQ_FALCON) -+#include <falcon/gpon_reg_base.h> -+#ifdef CONFIG_LANTIQ_PROM_ASC0 -+#define LQ_ASC_BASE GPON_ASC0_BASE -+#else -+#define LQ_ASC_BASE GPON_ASC1_BASE -+#endif -+ -+#endif -+ -+#define ASC_BUF 1024 -+#define LQ_ASC_FSTAT 0x0048 -+#define LQ_ASC_TBUF 0x0020 -+#define TXMASK 0x3F00 -+#define TXOFFSET 8 -+ -+static char buf[ASC_BUF]; -+ -+void -+prom_putchar(char c) -+{ -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ while ((lq_r32((u32 *)(LQ_ASC_BASE + LQ_ASC_FSTAT)) & TXMASK) >> TXOFFSET); -+ -+ if (c == '\n') -+ lq_w32('\r', (u32 *)(LQ_ASC_BASE + LQ_ASC_TBUF)); -+ lq_w32(c, (u32 *)(LQ_ASC_BASE + LQ_ASC_TBUF)); -+ local_irq_restore(flags); -+} -+ -+void -+early_printf(const char *fmt, ...) -+{ -+ va_list args; -+ int l; -+ char *p, *buf_end; -+ -+ va_start(args, fmt); -+ l = vsnprintf(buf, ASC_BUF, fmt, args); -+ va_end(args); -+ buf_end = buf + l; -+ -+ for (p = buf; p < buf_end; p++) -+ prom_putchar(*p); -+} diff --git a/target/linux/lantiq/patches/110-machine.patch b/target/linux/lantiq/patches/110-machine.patch deleted file mode 100644 index cf4652e..0000000 --- a/target/linux/lantiq/patches/110-machine.patch +++ /dev/null @@ -1,63 +0,0 @@ ---- a/arch/mips/lantiq/setup.c -+++ b/arch/mips/lantiq/setup.c -@@ -12,7 +12,8 @@ - #include <linux/ioport.h> - - #include <lantiq.h> --#include <lantiq_regs.h> -+ -+#include <machine.h> - - void __init - plat_mem_setup(void) -@@ -31,6 +32,7 @@ - ioport_resource.end = IOPORT_RESOURCE_END; - iomem_resource.start = IOMEM_RESOURCE_START; - iomem_resource.end = IOMEM_RESOURCE_END; -+ set_io_port_base((unsigned long) KSEG1); - - while (*envp) - { -@@ -45,3 +47,25 @@ - memsize *= 1024 * 1024; - add_memory_region(0x00000000, memsize, BOOT_MEM_RAM); - } -+ -+static int __init -+lq_machine_setup(void) -+{ -+ mips_machine_setup(); -+ return 0; -+} -+ -+static void __init -+mach_generic_init(void) -+{ -+} -+ -+MIPS_MACHINE(LANTIQ_MACH_GENERIC, -+ "Generic", -+ "Generic", -+ mach_generic_init); -+ -+arch_initcall(lq_machine_setup); -+ -+/* for backward compatibility, define "board=" as alias for "machtype=" */ -+__setup("board=", mips_machtype_setup); ---- /dev/null -+++ b/arch/mips/include/asm/mach-lantiq/machine.h -@@ -0,0 +1,14 @@ -+#include <asm/mips_machine.h> -+ -+enum lantiq_mach_type { -+ LANTIQ_MACH_GENERIC, -+ -+ /* FALCON */ -+ LANTIQ_MACH_EASY98000, /* Falcon Eval Board, NOR Flash */ -+ LANTIQ_MACH_EASY98020, /* Falcon Reference Board */ -+ -+ /* XWAY */ -+ LANTIQ_MACH_EASY4010, /* Twinpass evalkit */ -+ LANTIQ_MACH_EASY50712, /* Danube evalkit */ -+ LANTIQ_MACH_EASY50812, /* AR9 eval board */ -+}; diff --git a/target/linux/lantiq/patches/210-nor.patch b/target/linux/lantiq/patches/210-nor.patch deleted file mode 100644 index fe2ce6d..0000000 --- a/target/linux/lantiq/patches/210-nor.patch +++ /dev/null @@ -1,208 +0,0 @@ ---- a/drivers/mtd/maps/Kconfig -+++ b/drivers/mtd/maps/Kconfig -@@ -260,6 +260,12 @@ - Support for parsing CFE image tag and creating MTD partitions on - Broadcom BCM63xx boards. - -+config MTD_LANTIQ -+ bool "Lantiq SoC NOR support" -+ depends on LANTIQ && MTD_PARTITIONS -+ help -+ Support for NOR flsh chips on Lantiq SoC -+ - config MTD_DILNETPC - tristate "CFI Flash device mapped on DIL/Net PC" - depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN ---- a/drivers/mtd/maps/Makefile -+++ b/drivers/mtd/maps/Makefile -@@ -59,3 +59,4 @@ - obj-$(CONFIG_MTD_VMU) += vmu-flash.o - obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o - obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o -+obj-$(CONFIG_MTD_LANTIQ) += lantiq.o ---- /dev/null -+++ b/drivers/mtd/maps/lantiq.c -@@ -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 -+ * by the Free Software Foundation. -+ * -+ * Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE -+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org> -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/io.h> -+#include <linux/init.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+#include <linux/mtd/cfi.h> -+#include <linux/magic.h> -+#include <linux/platform_device.h> -+#include <linux/mtd/physmap.h> -+#include <linux/mtd/cfi.h> -+ -+#include <lantiq.h> -+#include <lantiq_platform.h> -+ -+#ifdef CONFIG_SOC_LANTIQ_XWAY -+#include <xway.h> -+#endif -+static int ltq_mtd_probing; -+ -+static map_word -+lq_read16(struct map_info *map, unsigned long adr) -+{ -+ unsigned long flags; -+ map_word temp; -+ spin_lock_irqsave(&ebu_lock, flags); -+ if (ltq_mtd_probing) -+ adr ^= 2; -+ temp.x[0] = *((__u16 *)(map->virt + adr)); -+ spin_unlock_irqrestore(&ebu_lock, flags); -+ return temp; -+} -+ -+static void -+lq_write16(struct map_info *map, map_word d, unsigned long adr) -+{ -+ unsigned long flags; -+ spin_lock_irqsave(&ebu_lock, flags); -+ if (ltq_mtd_probing) -+ adr ^= 2; -+ *((__u16 *)(map->virt + adr)) = d.x[0]; -+ spin_unlock_irqrestore(&ebu_lock, flags); -+} -+ -+void -+lq_copy_from(struct map_info *map, void *to, -+ unsigned long from, ssize_t len) -+{ -+ unsigned char *p; -+ unsigned char *to_8; -+ unsigned long flags; -+ spin_lock_irqsave(&ebu_lock, flags); -+ from = (unsigned long)(from + map->virt); -+ p = (unsigned char *) from; -+ to_8 = (unsigned char *) to; -+ while (len--) -+ *to_8++ = *p++; -+ spin_unlock_irqrestore(&ebu_lock, flags); -+} -+ -+void -+lq_copy_to(struct map_info *map, unsigned long to, -+ const void *from, ssize_t len) -+{ -+ unsigned char *p = (unsigned char *)from; -+ unsigned char *to_8; -+ unsigned long flags; -+ spin_lock_irqsave(&ebu_lock, flags); -+ to += (unsigned long) map->virt; -+ to_8 = (unsigned char *)to; -+ while (len--) -+ *p++ = *to_8++; -+ spin_unlock_irqrestore(&ebu_lock, flags); -+} -+ -+static const char *part_probe_types[] = { "cmdlinepart", NULL }; -+ -+static struct map_info lq_map = { -+ .name = "lq_nor", -+ .bankwidth = 2, -+ .read = lq_read16, -+ .write = lq_write16, -+ .copy_from = lq_copy_from, -+ .copy_to = lq_copy_to, -+}; -+ -+static int -+lq_mtd_probe(struct platform_device *pdev) -+{ -+ struct physmap_flash_data *lq_mtd_data = -+ (struct physmap_flash_data*) dev_get_platdata(&pdev->dev); -+ struct mtd_info *lq_mtd = NULL; -+ struct mtd_partition *parts = NULL; -+ struct resource *res = 0; -+ int nr_parts = 0; -+ struct cfi_private *cfi; -+ -+#ifdef CONFIG_SOC_LANTIQ_XWAY -+ lq_w32(lq_r32(LQ_EBU_BUSCON0) & ~EBU_WRDIS, LQ_EBU_BUSCON0); -+#endif -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if(!res) -+ { -+ dev_err(&pdev->dev, "failed to get memory resource"); -+ return -ENOENT; -+ } -+ res = request_mem_region(res->start, resource_size(res), -+ dev_name(&pdev->dev)); -+ if(!res) -+ { -+ dev_err(&pdev->dev, "failed to request mem resource"); -+ return -EBUSY; -+ } -+ -+ lq_map.phys = res->start; -+ lq_map.size = resource_size(res); -+ lq_map.virt = ioremap_nocache(lq_map.phys, lq_map.size); -+ -+ if (!lq_map.virt ) { -+ dev_err(&pdev->dev, "failed to ioremap!\n"); -+ return -EIO; -+ } -+ -+ ltq_mtd_probing = 1; -+ lq_mtd = (struct mtd_info *) do_map_probe("cfi_probe", &lq_map); -+ ltq_mtd_probing = 0; -+ if (!lq_mtd) { -+ iounmap(lq_map.virt); -+ dev_err(&pdev->dev, "probing failed\n"); -+ return -ENXIO; -+ } -+ -+ lq_mtd->owner = THIS_MODULE; -+ cfi = lq_map.fldrv_priv; -+ cfi->addr_unlock1 ^= 1; -+ cfi->addr_unlock2 ^= 1; -+ -+ nr_parts = parse_mtd_partitions(lq_mtd, part_probe_types, &parts, 0); -+ if (nr_parts > 0) { -+ dev_info(&pdev->dev, "using %d partitions from cmdline", nr_parts); -+ } else { -+ nr_parts = lq_mtd_data->nr_parts; -+ parts = lq_mtd_data->parts; -+ } -+ -+ add_mtd_partitions(lq_mtd, parts, nr_parts); -+ return 0; -+} -+ -+static struct platform_driver lq_mtd_driver = { -+ .probe = lq_mtd_probe, -+ .driver = { -+ .name = "lq_nor", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+int __init -+init_lq_mtd(void) -+{ -+ int ret = platform_driver_register(&lq_mtd_driver); -+ if (ret) -+ printk(KERN_INFO "lq_nor: error registering platfom driver"); -+ return ret; -+} -+ -+module_init(init_lq_mtd); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); -+MODULE_DESCRIPTION("Lantiq SoC NOR"); diff --git a/target/linux/lantiq/patches/230-xway_etop.patch b/target/linux/lantiq/patches/230-xway_etop.patch deleted file mode 100644 index 2ba8427..0000000 --- a/target/linux/lantiq/patches/230-xway_etop.patch +++ /dev/null @@ -1,585 +0,0 @@ ---- a/drivers/net/Kconfig -+++ b/drivers/net/Kconfig -@@ -235,6 +235,12 @@ - - source "drivers/net/arm/Kconfig" - -+config LANTIQ_ETOP -+ tristate "Lantiq SoC ETOP driver" -+ depends on SOC_LANTIQ_XWAY -+ help -+ Support for the MII0 inside the Lantiq SoC -+ - config AX88796 - tristate "ASIX AX88796 NE2000 clone support" - depends on ARM || MIPS || SUPERH ---- a/drivers/net/Makefile -+++ b/drivers/net/Makefile -@@ -212,6 +212,7 @@ - obj-$(CONFIG_MVME16x_NET) += 82596.o - obj-$(CONFIG_BVME6000_NET) += 82596.o - obj-$(CONFIG_SC92031) += sc92031.o -+obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o - - # This is also a 82596 and should probably be merged - obj-$(CONFIG_LP486E) += lp486e.o ---- /dev/null -+++ b/drivers/net/lantiq_etop.c -@@ -0,0 +1,557 @@ -+/* -+ * 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) 2005 Wu Qi Ming <Qi-Ming.Wu@infineon.com> -+ * Copyright (C) 2008 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 <asm/checksum.h> -+ -+#include <xway.h> -+#include <xway_dma.h> -+#include <lantiq_platform.h> -+ -+#define ETHERNET_PACKET_DMA_BUFFER_SIZE 0x600 -+#define LQ_PPE32_MEM_MAP ((u32 *)(LQ_PPE32_BASE_ADDR + 0x10000)) -+#define LQ_PPE32_SRST ((u32 *)(LQ_PPE32_BASE_ADDR + 0x10080)) -+ -+/* mdio access */ -+#define LQ_PPE32_MDIO_CFG ((u32 *)(LQ_PPE32_BASE_ADDR + 0x11800)) -+#define LQ_PPE32_MDIO_ACC ((u32 *)(LQ_PPE32_BASE_ADDR + 0x11804)) -+ -+#define MDIO_ACC_REQUEST 0x80000000 -+#define MDIO_ACC_READ 0x40000000 -+#define MDIO_ACC_ADDR_MASK 0x1f -+#define MDIO_ACC_ADDR_OFFSET 0x15 -+#define MDIO_ACC_REG_MASK 0x1f -+#define MDIO_ACC_REG_OFFSET 0x10 -+#define MDIO_ACC_VAL_MASK 0xffff -+ -+/* configuration */ -+#define LQ_PPE32_CFG ((u32 *)(LQ_PPE32_MEM_MAP + 0x1808)) -+ -+#define PPE32_MII_MASK 0xfffffffc -+#define PPE32_MII_NORMAL 0x8 -+#define PPE32_MII_REVERSE 0xe -+ -+/* packet length */ -+#define LQ_PPE32_IG_PLEN_CTRL ((u32 *)(LQ_PPE32_MEM_MAP + 0x1820)) -+ -+#define PPE32_PLEN_OVER 0x5ee -+#define PPE32_PLEN_UNDER 0x400000 -+ -+/* enet */ -+#define LQ_PPE32_ENET_MAC_CFG ((u32 *)(LQ_PPE32_MEM_MAP + 0x1840)) -+ -+#define PPE32_CGEN 0x800 -+ -+struct lq_mii_priv { -+ struct net_device_stats stats; -+ struct dma_device_info *dma_device; -+ struct sk_buff *skb; -+ -+ struct mii_bus *mii_bus; -+ struct phy_device *phydev; -+ int oldlink, oldspeed, oldduplex; -+}; -+ -+static struct net_device *lq_etop_dev; -+static unsigned char mac_addr[MAX_ADDR_LEN]; -+ -+static int lq_mdiobus_write(struct mii_bus *bus, int phy_addr, -+ int phy_reg, u16 phy_data) -+{ -+ u32 val = MDIO_ACC_REQUEST | -+ ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) | -+ ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET) | -+ phy_data; -+ -+ while (lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST) -+ ; -+ lq_w32(val, LQ_PPE32_MDIO_ACC); -+ -+ return 0; -+} -+ -+static int lq_mdiobus_read(struct mii_bus *bus, int phy_addr, int phy_reg) -+{ -+ u32 val = MDIO_ACC_REQUEST | MDIO_ACC_READ | -+ ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) | -+ ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET); -+ -+ while (lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST) -+ ; -+ lq_w32(val, LQ_PPE32_MDIO_ACC); -+ while (lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST) -+ ; -+ val = lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_VAL_MASK; -+ return val; -+} -+ -+int lq_mii_open(struct net_device *dev) -+{ -+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev); -+ struct dma_device_info *dma_dev = priv->dma_device; -+ int i; -+ -+ for (i = 0; i < dma_dev->max_rx_chan_num; i++) { -+ if ((dma_dev->rx_chan[i])->control == LQ_DMA_CH_ON) -+ (dma_dev->rx_chan[i])->open(dma_dev->rx_chan[i]); -+ } -+ netif_start_queue(dev); -+ return 0; -+} -+ -+int lq_mii_release(struct net_device *dev) -+{ -+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev); -+ struct dma_device_info *dma_dev = priv->dma_device; -+ int i; -+ -+ for (i = 0; i < dma_dev->max_rx_chan_num; i++) -+ dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]); -+ netif_stop_queue(dev); -+ return 0; -+} -+ -+int lq_mii_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev) -+{ -+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev); -+ unsigned char *buf = NULL; -+ struct sk_buff *skb = NULL; -+ int len = 0; -+ -+ len = dma_device_read(dma_dev, &buf, (void **)&skb); -+ -+ if (len >= ETHERNET_PACKET_DMA_BUFFER_SIZE) { -+ printk(KERN_INFO "lq_etop: packet too large %d\n", len); -+ goto lq_mii_hw_receive_err_exit; -+ } -+ -+ /* remove CRC */ -+ len -= 4; -+ if (skb == NULL) { -+ printk(KERN_INFO "lq_etop: cannot restore pointer\n"); -+ goto lq_mii_hw_receive_err_exit; -+ } -+ -+ if (len > (skb->end - skb->tail)) { -+ printk(KERN_INFO "lq_etop: BUG, len:%d end:%p tail:%p\n", -+ (len+4), skb->end, skb->tail); -+ goto lq_mii_hw_receive_err_exit; -+ } -+ -+ skb_put(skb, len); -+ skb->dev = dev; -+ -+ if (priv->phydev && priv->phydev->netif_rx) { -+ priv->phydev->netif_rx(skb); -+ } else { -+ skb->protocol = eth_type_trans(skb, dev); -+ netif_rx(skb); -+ } -+ -+ priv->stats.rx_packets++; -+ priv->stats.rx_bytes += len; -+ return 0; -+ -+lq_mii_hw_receive_err_exit: -+ if (len == 0) { -+ if (skb) -+ dev_kfree_skb_any(skb); -+ priv->stats.rx_errors++; -+ priv->stats.rx_dropped++; -+ return -EIO; -+ } else { -+ return len; -+ } -+} -+ -+int lq_mii_hw_tx(char *buf, int len, struct net_device *dev) -+{ -+ int ret = 0; -+ struct lq_mii_priv *priv = netdev_priv(dev); -+ struct dma_device_info *dma_dev = priv->dma_device; -+ ret = dma_device_write(dma_dev, buf, len, priv->skb); -+ return ret; -+} -+ -+int lq_mii_tx(struct sk_buff *skb, struct net_device *dev) -+{ -+ int len; -+ char *data; -+ struct lq_mii_priv *priv = netdev_priv(dev); -+ struct dma_device_info *dma_dev = priv->dma_device; -+ -+ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; -+ data = skb->data; -+ priv->skb = skb; -+ dev->trans_start = jiffies; -+ /* TODO: we got more than 1 dma channel, -+ so we should do something intelligent here to select one */ -+ dma_dev->current_tx_chan = 0; -+ -+ wmb(); -+ -+ if (lq_mii_hw_tx(data, len, dev) != len) { -+ dev_kfree_skb_any(skb); -+ priv->stats.tx_errors++; -+ priv->stats.tx_dropped++; -+ } else { -+ priv->stats.tx_packets++; -+ priv->stats.tx_bytes += len; -+ } -+ -+ return 0; -+} -+ -+void lq_mii_tx_timeout(struct net_device *dev) -+{ -+ int i; -+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev); -+ -+ priv->stats.tx_errors++; -+ for (i = 0; i < priv->dma_device->max_tx_chan_num; i++) -+ priv->dma_device->tx_chan[i]->disable_irq(priv->dma_device->tx_chan[i]); -+ netif_wake_queue(dev); -+ return; -+} -+ -+int dma_intr_handler(struct dma_device_info *dma_dev, int status) -+{ -+ int i; -+ -+ switch (status) { -+ case RCV_INT: -+ lq_mii_hw_receive(lq_etop_dev, dma_dev); -+ break; -+ -+ case TX_BUF_FULL_INT: -+ printk(KERN_INFO "lq_etop: tx buffer full\n"); -+ netif_stop_queue(lq_etop_dev); -+ for (i = 0; i < dma_dev->max_tx_chan_num; i++) { -+ if ((dma_dev->tx_chan[i])->control == LQ_DMA_CH_ON) -+ dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]); -+ } -+ break; -+ -+ case TRANSMIT_CPT_INT: -+ for (i = 0; i < dma_dev->max_tx_chan_num; i++) -+ dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]); -+ -+ netif_wake_queue(lq_etop_dev); -+ break; -+ } -+ -+ return 0; -+} -+ -+unsigned char *lq_etop_dma_buffer_alloc(int len, int *byte_offset, void **opt) -+{ -+ unsigned char *buffer = NULL; -+ struct sk_buff *skb = NULL; -+ -+ skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE); -+ if (skb == NULL) -+ return NULL; -+ -+ buffer = (unsigned char *)(skb->data); -+ skb_reserve(skb, 2); -+ *(int *)opt = (int)skb; -+ *byte_offset = 2; -+ -+ return buffer; -+} -+ -+void lq_etop_dma_buffer_free(unsigned char *dataptr, void *opt) -+{ -+ struct sk_buff *skb = NULL; -+ -+ if (opt == NULL) { -+ kfree(dataptr); -+ } else { -+ skb = (struct sk_buff *)opt; -+ dev_kfree_skb_any(skb); -+ } -+} -+ -+static void -+lq_adjust_link(struct net_device *dev) -+{ -+ struct lq_mii_priv *priv = netdev_priv(dev); -+ struct phy_device *phydev = priv->phydev; -+ int new_state = 0; -+ -+ /* Did anything change? */ -+ if (priv->oldlink != phydev->link || -+ priv->oldduplex != phydev->duplex || -+ priv->oldspeed != phydev->speed) { -+ /* Yes, so update status and mark as changed */ -+ new_state = 1; -+ priv->oldduplex = phydev->duplex; -+ priv->oldspeed = phydev->speed; -+ priv->oldlink = phydev->link; -+ } -+ -+ /* If link status changed, show new status */ -+ if (new_state) -+ phy_print_status(phydev); -+} -+ -+static int mii_probe(struct net_device *dev) -+{ -+ struct lq_mii_priv *priv = netdev_priv(dev); -+ struct phy_device *phydev = NULL; -+ int phy_addr; -+ -+ priv->oldlink = 0; -+ priv->oldspeed = 0; -+ priv->oldduplex = -1; -+ -+ /* find the first (lowest address) PHY on the current MAC's MII bus */ -+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { -+ if (priv->mii_bus->phy_map[phy_addr]) { -+ phydev = priv->mii_bus->phy_map[phy_addr]; -+ break; /* break out with first one found */ -+ } -+ } -+ -+ if (!phydev) { -+ printk (KERN_ERR "%s: no PHY found\n", dev->name); -+ return -ENODEV; -+ } -+ -+ /* now we are supposed to have a proper phydev, to attach to... */ -+ BUG_ON(!phydev); -+ BUG_ON(phydev->attached_dev); -+ -+ phydev = phy_connect(dev, dev_name(&phydev->dev), &lq_adjust_link, -+ 0, PHY_INTERFACE_MODE_MII); -+ -+ if (IS_ERR(phydev)) { -+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); -+ return PTR_ERR(phydev); -+ } -+ -+ /* mask with MAC supported features */ -+ phydev->supported &= (SUPPORTED_10baseT_Half -+ | SUPPORTED_10baseT_Full -+ | SUPPORTED_100baseT_Half -+ | SUPPORTED_100baseT_Full -+ | SUPPORTED_Autoneg -+ /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */ -+ | SUPPORTED_MII -+ | SUPPORTED_TP); -+ -+ phydev->advertising = phydev->supported; -+ -+ priv->phydev = phydev; -+ -+ printk(KERN_INFO "%s: attached PHY driver [%s] " -+ "(mii_bus:phy_addr=%s, irq=%d)\n", -+ dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq); -+ -+ return 0; -+} -+ -+ -+static int lq_mii_dev_init(struct net_device *dev) -+{ -+ int i; -+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev); -+ ether_setup(dev); -+ dev->watchdog_timeo = 10 * HZ; -+ dev->mtu = 1500; -+ memset(priv, 0, sizeof(struct lq_mii_priv)); -+ priv->dma_device = dma_device_reserve("PPE"); -+ if (!priv->dma_device) { -+ BUG(); -+ return -ENODEV; -+ } -+ priv->dma_device->buffer_alloc = &lq_etop_dma_buffer_alloc; -+ priv->dma_device->buffer_free = &lq_etop_dma_buffer_free; -+ priv->dma_device->intr_handler = &dma_intr_handler; -+ priv->dma_device->max_rx_chan_num = 4; -+ -+ for (i = 0; i < priv->dma_device->max_rx_chan_num; i++) { -+ priv->dma_device->rx_chan[i]->packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE; -+ priv->dma_device->rx_chan[i]->control = LQ_DMA_CH_ON; -+ } -+ -+ for (i = 0; i < priv->dma_device->max_tx_chan_num; i++) -+ if (i == 0) -+ priv->dma_device->tx_chan[i]->control = LQ_DMA_CH_ON; -+ else -+ priv->dma_device->tx_chan[i]->control = LQ_DMA_CH_OFF; -+ -+ dma_device_register(priv->dma_device); -+ -+ printk(KERN_INFO "%s: using mac=", dev->name); -+ for (i = 0; i < 6; i++) { -+ dev->dev_addr[i] = mac_addr[i]; -+ printk("%02X%c", dev->dev_addr[i], (i == 5) ? ('\n') : (':')); -+ } -+ -+ priv->mii_bus = mdiobus_alloc(); -+ if (priv->mii_bus == NULL) -+ return -ENOMEM; -+ -+ priv->mii_bus->priv = dev; -+ priv->mii_bus->read = lq_mdiobus_read; -+ priv->mii_bus->write = lq_mdiobus_write; -+ priv->mii_bus->name = "lq_mii"; -+ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0); -+ priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); -+ for(i = 0; i < PHY_MAX_ADDR; ++i) -+ priv->mii_bus->irq[i] = PHY_POLL; -+ -+ mdiobus_register(priv->mii_bus); -+ -+ return mii_probe(dev); -+} -+ -+static void lq_mii_chip_init(int mode) -+{ -+ lq_pmu_enable(PMU_DMA); -+ lq_pmu_enable(PMU_PPE); -+ -+ if (mode == REV_MII_MODE) -+ lq_w32_mask(PPE32_MII_MASK, PPE32_MII_REVERSE, LQ_PPE32_CFG); -+ else if (mode == MII_MODE) -+ lq_w32_mask(PPE32_MII_MASK, PPE32_MII_NORMAL, LQ_PPE32_CFG); -+ lq_w32(PPE32_PLEN_UNDER | PPE32_PLEN_OVER, LQ_PPE32_IG_PLEN_CTRL); -+ lq_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG); -+ wmb(); -+} -+ -+static int lq_mii_eth_mac_addr(struct net_device *dev, void *p) -+{ -+ int retcode; -+ -+ retcode = eth_mac_addr(dev, p); -+ -+ if (retcode) -+ return retcode; -+ -+ // set rx_addr for unicast filter -+ lq_w32(((dev->dev_addr[0]<<24)|(dev->dev_addr[1]<<16)|(dev->dev_addr[2]<< 8)|dev->dev_addr[3]), (u32*)(LQ_PPE32_BASE_ADDR|(0x461b<<2))); -+ lq_w32(((dev->dev_addr[4]<<24)|(dev->dev_addr[5]<<16)), (u32*)(LQ_PPE32_BASE_ADDR|(0x461c<<2))); -+ -+ return 0; -+} -+ -+static void lq_mii_set_rx_mode (struct net_device *dev) -+{ -+ // rx_mode promisc: unset unicast filter -+ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI)) -+ lq_w32(lq_r32((u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2))) & ~(1<<28), (u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2))); -+ // enable unicast filter -+ else -+ lq_w32(lq_r32((u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2))) | (1<<28), (u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2))); -+} -+ -+static const struct net_device_ops lq_eth_netdev_ops = { -+ .ndo_init = lq_mii_dev_init, -+ .ndo_open = lq_mii_open, -+ .ndo_stop = lq_mii_release, -+ .ndo_start_xmit = lq_mii_tx, -+ .ndo_tx_timeout = lq_mii_tx_timeout, -+ .ndo_change_mtu = eth_change_mtu, -+ .ndo_set_mac_address = lq_mii_eth_mac_addr, -+ .ndo_validate_addr = eth_validate_addr, -+ .ndo_set_multicast_list = lq_mii_set_rx_mode, -+}; -+ -+static int -+lq_mii_probe(struct platform_device *dev) -+{ -+ int result = 0; -+ struct lq_eth_data *eth = (struct lq_eth_data*)dev->dev.platform_data; -+ lq_etop_dev = alloc_etherdev(sizeof(struct lq_mii_priv)); -+ lq_etop_dev->netdev_ops = &lq_eth_netdev_ops; -+ memcpy(mac_addr, eth->mac, 6); -+ strcpy(lq_etop_dev->name, "eth%d"); -+ lq_mii_chip_init(eth->mii_mode); -+ result = register_netdev(lq_etop_dev); -+ if (result) { -+ printk(KERN_INFO "lq_etop: error %i registering device \"%s\"\n", result, lq_etop_dev->name); -+ goto out; -+ } -+ -+ printk(KERN_INFO "lq_etop: driver loaded!\n"); -+ -+out: -+ return result; -+} -+ -+static int lq_mii_remove(struct platform_device *dev) -+{ -+ struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(lq_etop_dev); -+ -+ printk(KERN_INFO "lq_etop: lq_etop cleanup\n"); -+ -+ dma_device_unregister(priv->dma_device); -+ dma_device_release(priv->dma_device); -+ kfree(priv->dma_device); -+ unregister_netdev(lq_etop_dev); -+ return 0; -+} -+ -+static struct platform_driver lq_mii_driver = { -+ .probe = lq_mii_probe, -+ .remove = lq_mii_remove, -+ .driver = { -+ .name = "lq_etop", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+int __init lq_mii_init(void) -+{ -+ int ret = platform_driver_register(&lq_mii_driver); -+ if (ret) -+ printk(KERN_INFO "lq_etop: Error registering platfom driver!"); -+ return ret; -+} -+ -+static void __exit lq_mii_cleanup(void) -+{ -+ platform_driver_unregister(&lq_mii_driver); -+} -+ -+module_init(lq_mii_init); -+module_exit(lq_mii_cleanup); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); -+MODULE_DESCRIPTION("ethernet driver for IFXMIPS boards"); diff --git a/target/linux/lantiq/patches/250-watchdog.patch b/target/linux/lantiq/patches/250-watchdog.patch deleted file mode 100644 index 96875db..0000000 --- a/target/linux/lantiq/patches/250-watchdog.patch +++ /dev/null @@ -1,246 +0,0 @@ ---- a/drivers/watchdog/Kconfig -+++ b/drivers/watchdog/Kconfig -@@ -930,6 +930,12 @@ - To compile this driver as a loadable module, choose M here. - The module will be called bcm63xx_wdt. - -+config LANTIQ_WDT -+ bool "Lantiq SoC watchdog" -+ depends on LANTIQ -+ help -+ Hardware driver for the Lantiq SoC Watchdog Timer. -+ - # PARISC Architecture - - # POWERPC Architecture ---- a/drivers/watchdog/Makefile -+++ b/drivers/watchdog/Makefile -@@ -119,6 +119,7 @@ - obj-$(CONFIG_TXX9_WDT) += txx9wdt.o - obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o - octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o -+obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o - - # PARISC Architecture - ---- /dev/null -+++ b/drivers/watchdog/lantiq_wdt.c -@@ -0,0 +1,218 @@ -+/* -+ * 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> -+ * Based on EP93xx wdt driver -+ */ -+ -+#include <linux/module.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/miscdevice.h> -+#include <linux/watchdog.h> -+#include <linux/platform_device.h> -+#include <linux/uaccess.h> -+#include <linux/clk.h> -+ -+#include <lantiq.h> -+ -+#define LQ_WDT_PW1 0x00BE0000 -+#define LQ_WDT_PW2 0x00DC0000 -+ -+#define LQ_BIU_WDT_CR 0x0 -+#define LQ_BIU_WDT_SR 0x8 -+ -+#ifndef CONFIG_WATCHDOG_NOWAYOUT -+static int wdt_ok_to_close; -+#endif -+ -+static int wdt_timeout = 30; -+static __iomem void *wdt_membase = NULL; -+static unsigned long io_region_clk = 0; -+ -+static int -+lq_wdt_enable(unsigned int timeout) -+{ -+/* printk("%s:%s[%d] %08X\n", -+ __FILE__, __func__, __LINE__, -+ lq_r32(wdt_membase + LQ_BIU_WDT_SR)); -+ if(!lq_r32(wdt_membase + LQ_BIU_WDT_SR)) -+ { -+*/ lq_w32(LQ_WDT_PW1, wdt_membase + LQ_BIU_WDT_CR); -+ lq_w32(LQ_WDT_PW2 | -+ (0x3 << 26) | /* PWL */ -+ (0x3 << 24) | /* CLKDIV */ -+ (0x1 << 31) | /* enable */ -+ ((timeout * (io_region_clk / 0x40000)) + 0x1000), /* reload */ -+ wdt_membase + LQ_BIU_WDT_CR); -+// } -+ return 0; -+} -+ -+static void -+lq_wdt_disable(void) -+{ -+#ifndef CONFIG_WATCHDOG_NOWAYOUT -+ wdt_ok_to_close = 0; -+#endif -+ lq_w32(LQ_WDT_PW1, wdt_membase + LQ_BIU_WDT_CR); -+ lq_w32(LQ_WDT_PW2, wdt_membase+ LQ_BIU_WDT_CR); -+} -+ -+static ssize_t -+lq_wdt_write(struct file *file, const char __user *data, -+ size_t len, loff_t *ppos) -+{ -+ size_t i; -+ -+ if (!len) -+ return 0; -+ -+#ifndef CONFIG_WATCHDOG_NOWAYOUT -+ for (i = 0; i != len; i++) { -+ char c; -+ if (get_user(c, data + i)) -+ return -EFAULT; -+ if (c == 'V') -+ wdt_ok_to_close = 1; -+ } -+#endif -+ lq_wdt_enable(wdt_timeout); -+ return len; -+} -+ -+static struct watchdog_info ident = { -+ .options = WDIOF_MAGICCLOSE, -+ .identity = "lq_wdt", -+}; -+ -+static int -+lq_wdt_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ int ret = -ENOTTY; -+ -+ switch (cmd) { -+ case WDIOC_GETSUPPORT: -+ ret = copy_to_user((struct watchdog_info __user *)arg, &ident, -+ sizeof(ident)) ? -EFAULT : 0; -+ break; -+ -+ case WDIOC_GETTIMEOUT: -+ ret = put_user(wdt_timeout, (int __user *)arg); -+ break; -+ -+ case WDIOC_SETTIMEOUT: -+ ret = get_user(wdt_timeout, (int __user *)arg); -+ break; -+ -+ case WDIOC_KEEPALIVE: -+ lq_wdt_enable(wdt_timeout); -+ ret = 0; -+ break; -+ } -+ return ret; -+} -+ -+static int -+lq_wdt_open(struct inode *inode, struct file *file) -+{ -+ lq_wdt_enable(wdt_timeout); -+ return nonseekable_open(inode, file); -+} -+ -+static int -+lq_wdt_release(struct inode *inode, struct file *file) -+{ -+#ifndef CONFIG_WATCHDOG_NOWAYOUT -+ if (wdt_ok_to_close) -+ lq_wdt_disable(); -+ else -+#endif -+ printk(KERN_ERR "lq_wdt: watchdog closed without warning," -+ " rebooting system\n"); -+ return 0; -+} -+ -+static const struct file_operations lq_wdt_fops = { -+ .owner = THIS_MODULE, -+ .write = lq_wdt_write, -+ .unlocked_ioctl = lq_wdt_ioctl, -+ .open = lq_wdt_open, -+ .release = lq_wdt_release, -+}; -+ -+static struct miscdevice lq_wdt_miscdev = { -+ .minor = WATCHDOG_MINOR, -+ .name = "watchdog", -+ .fops = &lq_wdt_fops, -+}; -+ -+static int -+lq_wdt_probe(struct platform_device *pdev) -+{ -+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ struct clk *clk; -+ int ret = 0; -+ if(!res) -+ return -ENOENT; -+ res = request_mem_region(res->start, resource_size(res), -+ dev_name(&pdev->dev)); -+ if(!res) -+ return -EBUSY; -+ wdt_membase = ioremap_nocache(res->start, resource_size(res)); -+ if(!wdt_membase) -+ { -+ ret = -ENOMEM; -+ goto err_release_mem_region; -+ } -+ clk = clk_get(&pdev->dev, "io"); -+ io_region_clk = clk_get_rate(clk);; -+ ret = misc_register(&lq_wdt_miscdev); -+ if(!ret) -+ return 0; -+ -+ iounmap(wdt_membase); -+err_release_mem_region: -+ release_mem_region(res->start, resource_size(res)); -+ return ret; -+} -+ -+static int -+lq_wdt_remove(struct platform_device *dev) -+{ -+ lq_wdt_disable(); -+ misc_deregister(&lq_wdt_miscdev); -+ return 0; -+} -+ -+static struct platform_driver lq_wdt_driver = { -+ .probe = lq_wdt_probe, -+ .remove = lq_wdt_remove, -+ .driver = { -+ .name = "lq_wdt", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init -+init_lq_wdt(void) -+{ -+ return platform_driver_register(&lq_wdt_driver); -+} -+ -+static void __exit -+exit_lq_wdt(void) -+{ -+ platform_driver_unregister(&lq_wdt_driver); -+} -+ -+module_init(init_lq_wdt); -+module_exit(exit_lq_wdt); -+ -+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); -+MODULE_DESCRIPTION("ifxmips Watchdog"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/target/linux/lantiq/patches/260-pci.patch b/target/linux/lantiq/patches/260-pci.patch deleted file mode 100644 index 462ce6e..0000000 --- a/target/linux/lantiq/patches/260-pci.patch +++ /dev/null @@ -1,446 +0,0 @@ ---- a/arch/mips/pci/Makefile -+++ b/arch/mips/pci/Makefile -@@ -55,6 +55,7 @@ - obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o - obj-$(CONFIG_MIKROTIK_RB532) += pci-rc32434.o ops-rc32434.o fixup-rc32434.o - obj-$(CONFIG_CPU_CAVIUM_OCTEON) += pci-octeon.o pcie-octeon.o -+obj-$(CONFIG_LANTIQ) += pci-lantiq.o ops-lantiq.o - - ifdef CONFIG_PCI_MSI - obj-$(CONFIG_CPU_CAVIUM_OCTEON) += msi-octeon.o ---- /dev/null -+++ b/arch/mips/pci/ops-lantiq.c -@@ -0,0 +1,127 @@ -+/* -+ * 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/types.h> -+#include <linux/pci.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/delay.h> -+#include <linux/mm.h> -+#include <asm/addrspace.h> -+#include <linux/vmalloc.h> -+ -+#include <xway.h> -+ -+#define LQ_PCI_CFG_BUSNUM_SHF 16 -+#define LQ_PCI_CFG_DEVNUM_SHF 11 -+#define LQ_PCI_CFG_FUNNUM_SHF 8 -+ -+#define PCI_ACCESS_READ 0 -+#define PCI_ACCESS_WRITE 1 -+ -+extern u32 lq_pci_mapped_cfg; -+ -+static int -+lq_pci_config_access(unsigned char access_type, -+ struct pci_bus *bus, unsigned int devfn, unsigned int where, u32 *data) -+{ -+ unsigned long cfg_base; -+ unsigned long flags; -+ -+ u32 temp; -+ -+ /* we support slot from 0 to 15 */ -+ /* dev_fn 0&0x68 (AD29) is ifxmips itself */ -+ if ((bus->number != 0) || ((devfn & 0xf8) > 0x78) -+ || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68)) -+ return 1; -+ -+ spin_lock_irqsave(&ebu_lock, flags); -+ -+ cfg_base = lq_pci_mapped_cfg; -+ cfg_base |= (bus->number << LQ_PCI_CFG_BUSNUM_SHF) | (devfn << -+ LQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3); -+ -+ /* Perform access */ -+ if (access_type == PCI_ACCESS_WRITE) -+ { -+#ifdef CONFIG_SWAP_IO_SPACE -+ lq_w32(swab32(*data), ((u32*)cfg_base)); -+#else -+ lq_w32(*data, ((u32*)cfg_base)); -+#endif -+ } else { -+ *data = lq_r32(((u32*)(cfg_base))); -+#ifdef CONFIG_SWAP_IO_SPACE -+ *data = swab32(*data); -+#endif -+ } -+ wmb(); -+ -+ /* clean possible Master abort */ -+ cfg_base = (lq_pci_mapped_cfg | (0x0 << LQ_PCI_CFG_FUNNUM_SHF)) + 4; -+ temp = lq_r32(((u32*)(cfg_base))); -+#ifdef CONFIG_SWAP_IO_SPACE -+ temp = swab32 (temp); -+#endif -+ cfg_base = (lq_pci_mapped_cfg | (0x68 << LQ_PCI_CFG_FUNNUM_SHF)) + 4; -+ lq_w32(temp, ((u32*)cfg_base)); -+ -+ spin_unlock_irqrestore(&ebu_lock, flags); -+ -+ if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ)) -+ return 1; -+ -+ return 0; -+} -+ -+int -+lq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 * val) -+{ -+ u32 data = 0; -+ -+ if (lq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ -+ if (size == 1) -+ *val = (data >> ((where & 3) << 3)) & 0xff; -+ else if (size == 2) -+ *val = (data >> ((where & 3) << 3)) & 0xffff; -+ else -+ *val = data; -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+int -+lq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn, -+ int where, int size, u32 val) -+{ -+ u32 data = 0; -+ -+ if (size == 4) -+ { -+ data = val; -+ } else { -+ if (lq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data)) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ -+ if (size == 1) -+ data = (data & ~(0xff << ((where & 3) << 3))) | -+ (val << ((where & 3) << 3)); -+ else if (size == 2) -+ data = (data & ~(0xffff << ((where & 3) << 3))) | -+ (val << ((where & 3) << 3)); -+ } -+ -+ if (lq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data)) -+ return PCIBIOS_DEVICE_NOT_FOUND; -+ -+ return PCIBIOS_SUCCESSFUL; -+} ---- /dev/null -+++ b/arch/mips/pci/pci-lantiq.c -@@ -0,0 +1,303 @@ -+/* -+ * 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/types.h> -+#include <linux/pci.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/delay.h> -+#include <linux/mm.h> -+#include <linux/vmalloc.h> -+#include <linux/platform_device.h> -+ -+#include <asm/gpio.h> -+#include <asm/addrspace.h> -+ -+#include <xway.h> -+#include <xway_irq.h> -+#include <lantiq_platform.h> -+ -+#define LQ_PCI_CFG_BASE 0x17000000 -+#define LQ_PCI_CFG_SIZE 0x00008000 -+#define LQ_PCI_MEM_BASE 0x18000000 -+#define LQ_PCI_MEM_SIZE 0x02000000 -+#define LQ_PCI_IO_BASE 0x1AE00000 -+#define LQ_PCI_IO_SIZE 0x00200000 -+ -+#define PCI_CR_FCI_ADDR_MAP0 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00C0)) -+#define PCI_CR_FCI_ADDR_MAP1 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00C4)) -+#define PCI_CR_FCI_ADDR_MAP2 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00C8)) -+#define PCI_CR_FCI_ADDR_MAP3 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00CC)) -+#define PCI_CR_FCI_ADDR_MAP4 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00D0)) -+#define PCI_CR_FCI_ADDR_MAP5 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00D4)) -+#define PCI_CR_FCI_ADDR_MAP6 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00D8)) -+#define PCI_CR_FCI_ADDR_MAP7 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00DC)) -+#define PCI_CR_CLK_CTRL ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0000)) -+#define PCI_CR_PCI_IRM ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0028)) -+#define PCI_CR_PCI_MOD ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0030)) -+#define PCI_CR_PC_ARB ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0080)) -+#define PCI_CR_FCI_ADDR_MAP11hg ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00E4)) -+#define PCI_CR_BAR11MASK ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0044)) -+#define PCI_CR_BAR12MASK ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0048)) -+#define PCI_CR_BAR13MASK ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x004C)) -+#define PCI_CR_PCI_ADDR_MAP11 ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x0064)) -+#define PCI_CR_FCI_BURST_LENGTH ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x00E8)) -+#define PCI_CR_PCI_EOI ((u32 *)(PCI_CR_PR_BASE_ADDR + 0x002C)) -+ -+#define PCI_CS_STS_CMD ((u32 *)(PCI_CS_PR_BASE_ADDR + 0x0004)) -+#define PCI_CS_BASE_ADDR1 ((u32 *)(PCI_CS_PR_BASE_ADDR + 0x0010)) -+ -+#define PCI_MASTER0_REQ_MASK_2BITS 8 -+#define PCI_MASTER1_REQ_MASK_2BITS 10 -+#define PCI_MASTER2_REQ_MASK_2BITS 12 -+#define INTERNAL_ARB_ENABLE_BIT 0 -+ -+#define LQ_CGU_IFCCR ((u32 *)(LQ_CGU_BASE_ADDR + 0x0018)) -+#define LQ_CGU_PCICR ((u32 *)(LQ_CGU_BASE_ADDR + 0x0034)) -+ -+extern int lq_pci_read_config_dword(struct pci_bus *bus, -+ unsigned int devfn, int where, int size, u32 *val); -+extern int lq_pci_write_config_dword(struct pci_bus *bus, -+ unsigned int devfn, int where, int size, u32 val); -+ -+u32 lq_pci_mapped_cfg; -+ -+int (*lqpci_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 lq_pci_req_mask = 0xf; -+ -+static int *lq_pci_irq_map; -+ -+struct pci_ops lq_pci_ops = -+{ -+ .read = lq_pci_read_config_dword, -+ .write = lq_pci_write_config_dword -+}; -+ -+static struct resource pci_io_resource = -+{ -+ .name = "pci io space", -+ .start = LQ_PCI_IO_BASE, -+ .end = LQ_PCI_IO_BASE + LQ_PCI_IO_SIZE - 1, -+ .flags = IORESOURCE_IO -+}; -+ -+static struct resource pci_mem_resource = -+{ -+ .name = "pci memory space", -+ .start = LQ_PCI_MEM_BASE, -+ .end = LQ_PCI_MEM_BASE + LQ_PCI_MEM_SIZE - 1, -+ .flags = IORESOURCE_MEM -+}; -+ -+static struct pci_controller lq_pci_controller = -+{ -+ .pci_ops = &lq_pci_ops, -+ .mem_resource = &pci_mem_resource, -+ .mem_offset = 0x00000000UL, -+ .io_resource = &pci_io_resource, -+ .io_offset = 0x00000000UL, -+}; -+ -+int -+pcibios_plat_dev_init(struct pci_dev *dev) -+{ -+ if (lqpci_plat_dev_init) -+ return lqpci_plat_dev_init(dev); -+ -+ return 0; -+} -+ -+static u32 -+lq_calc_bar11mask(void) -+{ -+ u32 mem, bar11mask; -+ -+ /* BAR11MASK value depends on available memory on system. */ -+ mem = num_physpages * PAGE_SIZE; -+ bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) -1)) -1)) | 8; -+ -+ return bar11mask; -+} -+ -+struct ltq_pci_gpio_map { -+ int pin; -+ int alt0; -+ int alt1; -+ int dir; -+ char *name; -+}; -+ -+static struct ltq_pci_gpio_map gmap[] = { -+ { 0, 1, 0, 0, "pci-exin0" }, -+ { 1, 1, 0, 0, "pci-exin1" }, -+ { 2, 1, 0, 0, "pci-exin2" }, -+ { 30, 1, 0, 1, "pci-gnt1" }, -+ { 23, 1, 0, 1, "pci-gnt2" }, -+ { 19, 1, 0, 1, "pci-gnt3" }, -+ { 29, 1, 0, 0, "pci-req1" }, -+ { 31, 1, 0, 0, "pci-req2" }, -+ { 3, 1, 0, 0, "pci-req3" }, -+}; -+ -+static void -+lq_pci_setup_gpio(int gpio) -+{ -+ int i; -+ for (i = 0; i < ARRAY_SIZE(gmap); i++) -+ { -+ if(gpio & (1 << i)) -+ { -+ lq_gpio_request(gmap[i].pin, gmap[i].alt0, -+ gmap[i].alt1, gmap[i].dir, gmap[i].name); -+ } -+ } -+ for(i = 0; i < 3; i++) -+ { -+ if(gpio & (1 << i)) -+ { -+ lq_w32(lq_r32((u32*)0xBF101000) | (0x6 << (i * 4)), (u32*)0xBF101000); -+ lq_w32(lq_r32((u32*)0xBF101004) & ~(1 << i), (u32*)0xBF101004); -+ lq_w32(lq_r32((u32*)0xBF10100C) | (1 << i), (u32*)0xBF10100C); -+ } -+ } -+ lq_gpio_request(21, 0, 0, 1, "pci-reset"); -+ lq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & 0x7; -+} -+ -+static int __init -+lq_pci_startup(struct lq_pci_data *conf) -+{ -+ u32 temp_buffer; -+ -+ /* set clock to 33Mhz */ -+ lq_w32(lq_r32(LQ_CGU_IFCCR) & ~0xf00000, LQ_CGU_IFCCR); -+ lq_w32(lq_r32(LQ_CGU_IFCCR) | 0x800000, LQ_CGU_IFCCR); -+ if (conf->clock == PCI_CLOCK_EXT) -+ { -+ lq_w32(lq_r32(LQ_CGU_IFCCR) & ~(1 << 16), LQ_CGU_IFCCR); -+ lq_w32((1 << 30), LQ_CGU_PCICR); -+ } else { -+ lq_w32(lq_r32(LQ_CGU_IFCCR) | (1 << 16), LQ_CGU_IFCCR); -+ lq_w32((1 << 31) | (1 << 30), LQ_CGU_PCICR); -+ } -+ -+ /* setup pci clock and gpis used by pci */ -+ lq_pci_setup_gpio(conf->gpio); -+ -+ /* enable auto-switching between PCI and EBU */ -+ lq_w32(0xa, PCI_CR_CLK_CTRL); -+ -+ /* busy, i.e. configuration is not done, PCI access has to be retried */ -+ lq_w32(lq_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD); -+ wmb (); -+ /* BUS Master/IO/MEM access */ -+ lq_w32(lq_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD); -+ -+ /* enable external 2 PCI masters */ -+ temp_buffer = lq_r32(PCI_CR_PC_ARB); -+ temp_buffer &= (~((lq_pci_req_mask & 0xf) << 16)); -+ -+ /* enable internal arbiter */ -+ temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT); -+ /* enable internal PCI master reqest */ -+ temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS)); -+ -+ /* enable EBU request */ -+ temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS)); -+ -+ /* enable all external masters request */ -+ temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS)); -+ lq_w32(temp_buffer, PCI_CR_PC_ARB); -+ wmb (); -+ -+ /* setup BAR memory regions */ -+ lq_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0); -+ lq_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1); -+ lq_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2); -+ lq_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3); -+ lq_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4); -+ lq_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5); -+ lq_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6); -+ lq_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7); -+ lq_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg); -+ -+ lq_w32(lq_calc_bar11mask(), PCI_CR_BAR11MASK); -+ lq_w32(0, PCI_CR_PCI_ADDR_MAP11); -+ lq_w32(0, PCI_CS_BASE_ADDR1); -+ -+ /* both TX and RX endian swap are enabled */ -+ lq_w32(lq_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI); -+ wmb (); -+ -+ /*TODO: disable BAR2 & BAR3 - why was this in the origianl infineon code */ -+ lq_w32(lq_r32(PCI_CR_BAR12MASK) | 0x80000000, PCI_CR_BAR12MASK); -+ lq_w32(lq_r32(PCI_CR_BAR13MASK) | 0x80000000, PCI_CR_BAR13MASK); -+ -+ /* use 8 dw burst length */ -+ lq_w32(0x303, PCI_CR_FCI_BURST_LENGTH); -+ lq_w32(lq_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD); -+ wmb(); -+ -+ /* setup irq line */ -+ lq_w32(lq_r32(LQ_EBU_PCC_CON) | 0xc, LQ_EBU_PCC_CON); -+ lq_w32(lq_r32(LQ_EBU_PCC_IEN) | 0x10, LQ_EBU_PCC_IEN); -+ -+ /* toggle reset pin */ -+ gpio_set_value(21, 0); -+ wmb(); -+ mdelay(1); -+ gpio_set_value(21, 1); -+ return 0; -+} -+ -+int __init -+pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin){ -+ printk("%s:%s[%d]%d %d\n", __FILE__, __func__, __LINE__, slot, pin); -+ if(lq_pci_irq_map[slot]) -+ return lq_pci_irq_map[slot]; -+ printk("lq_pci: trying to map irq for unknown slot %d\n", slot); -+ return 0; -+} -+ -+static int -+lq_pci_probe(struct platform_device *pdev) -+{ -+ struct lq_pci_data *lq_pci_data = (struct lq_pci_data*) pdev->dev.platform_data; -+ extern int pci_probe_only; -+ pci_probe_only = 0; -+ lq_pci_irq_map = lq_pci_data->irq; -+ lq_pci_startup(lq_pci_data); -+ lq_pci_mapped_cfg = -+ (u32)ioremap_nocache(LQ_PCI_CFG_BASE, LQ_PCI_CFG_SIZE); -+ lq_pci_controller.io_map_base = mips_io_port_base + LQ_PCI_IO_BASE; -+ register_pci_controller(&lq_pci_controller); -+ return 0; -+} -+ -+static struct platform_driver -+lq_pci_driver = { -+ .probe = lq_pci_probe, -+ .driver = { -+ .name = "lq_pci", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+int __init -+pcibios_init(void) -+{ -+ int ret = platform_driver_register(&lq_pci_driver); -+ if(ret) -+ printk(KERN_INFO "lq_pci: Error registering platfom driver!"); -+ return ret; -+} -+ -+arch_initcall(pcibios_init); diff --git a/target/linux/lantiq/patches/270-crypto.patch b/target/linux/lantiq/patches/270-crypto.patch deleted file mode 100644 index e99cfd3..0000000 --- a/target/linux/lantiq/patches/270-crypto.patch +++ /dev/null @@ -1,6197 +0,0 @@ ---- a/drivers/crypto/Kconfig -+++ b/drivers/crypto/Kconfig -@@ -252,4 +252,75 @@ - OMAP processors have AES module accelerator. Select this if you - want to use the OMAP module for AES algorithms. - -+config CRYPTO_DEV_LANTIQ -+ tristate "Support for Lantiq crypto engine" -+ select CRYPTO_ALGAPI -+ default y -+ help -+ Will support Lantiq crypto hardware -+ If you are unsure, say M. -+ -+menuconfig CRYPTO_DEV_LANTIQ_DES -+ bool "Lantiq crypto hardware for DES algorithm" -+ depends on CRYPTO_DEV_LANTIQ -+ select CRYPTO_BLKCIPHER -+ default y -+ help -+ Use crypto hardware for DES/3DES algorithm. -+ If unsure say N. -+ -+menuconfig CRYPTO_DEV_LANTIQ_AES -+ bool "Lantiq crypto hardware for AES algorithm" -+ depends on CRYPTO_DEV_LANTIQ -+ select CRYPTO_BLKCIPHER -+ default y -+ help -+ Use crypto hardware for AES algorithm. -+ If unsure say N. -+ -+menuconfig CRYPTO_DEV_LANTIQ_ARC4 -+ bool "Lantiq crypto hardware for ARC4 algorithm" -+ depends on (CRYPTO_DEV_LANTIQ && IFXMIPS_AR9) -+ select CRYPTO_BLKCIPHER -+ default y -+ help -+ Use crypto hardware for ARC4 algorithm. -+ If unsure say N. -+ -+menuconfig CRYPTO_DEV_LANTIQ_MD5 -+ bool "Lantiq crypto hardware for MD5 algorithm" -+ depends on CRYPTO_DEV_LANTIQ -+ select CRYPTO_BLKCIPHER -+ default y -+ help -+ Use crypto hardware for MD5 algorithm. -+ If unsure say N. -+ -+menuconfig CRYPTO_DEV_LANTIQ_SHA1 -+ bool "Lantiq crypto hardware for SHA1 algorithm" -+ depends on CRYPTO_DEV_LANTIQ -+ select CRYPTO_BLKCIPHER -+ default y -+ help -+ Use crypto hardware for SHA1 algorithm. -+ If unsure say N. -+ -+menuconfig CRYPTO_DEV_LANTIQ_SHA1_HMAC -+ bool "Lantiq crypto hardware for SHA1_HMAC algorithm" -+ depends on (CRYPTO_DEV_LANTIQ && IFXMIPS_AR9) -+ select CRYPTO_BLKCIPHER -+ default y -+ help -+ Use crypto hardware for SHA1_HMAC algorithm. -+ If unsure say N. -+ -+menuconfig CRYPTO_DEV_LANTIQ_MD5_HMAC -+ bool "Lantiq crypto hardware for MD5_HMAC algorithms" -+ depends on (CRYPTO_DEV_LANTIQ && IFXMIPS_AR9) -+ select CRYPTO_BLKCIPHER -+ default y -+ help -+ Use crypto hardware for MD5_HMAC algorithm. -+ If unsure say N. -+ - endif # CRYPTO_HW ---- /dev/null -+++ b/drivers/crypto/lantiq/Makefile -@@ -0,0 +1,11 @@ -+obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu.o -+obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu_falcon.o -+obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu_danube.o -+obj-$(CONFIG_CRYPTO_DEV_LANTIQ) += deu_ar9.o -+obj-$(CONFIG_CRYPTO_DEV_LANTIQ_DES) += des.o -+obj-$(CONFIG_CRYPTO_DEV_LANTIQ_AES) += aes.o -+obj-$(CONFIG_CRYPTO_DEV_LANTIQ_ARC4) += arc4.o -+obj-$(CONFIG_CRYPTO_DEV_LANTIQ_SHA1) += sha1.o -+obj-$(CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC) += sha1_hmac.o -+obj-$(CONFIG_CRYPTO_DEV_LANTIQ_MD5) += md5.o -+obj-$(CONFIG_CRYPTO_DEV_LANTIQ_MD5_HMAC) += md5_hmac.o ---- /dev/null -+++ b/drivers/crypto/lantiq/aes.c -@@ -0,0 +1,1029 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file aes.c -+ \ingroup LQ_DEU -+ \brief AES Encryption Driver main file -+*/ -+ -+/** -+ \defgroup LQ_AES_FUNCTIONS LQ_AES_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief Lantiq AES driver Functions -+*/ -+ -+#include <linux/version.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/types.h> -+#include <linux/errno.h> -+#include <linux/crypto.h> -+#include <linux/interrupt.h> -+#include <linux/delay.h> -+#include <asm/byteorder.h> -+#include <crypto/algapi.h> -+#include "deu.h" -+ -+#ifdef CONFIG_CRYPTO_DEV_DMA -+# include "deu_dma.h" -+#endif -+ -+static spinlock_t cipher_lock; -+ -+/* Definition of constants */ -+ -+#define AES_MIN_KEY_SIZE 16 -+#define AES_MAX_KEY_SIZE 32 -+#define AES_BLOCK_SIZE 16 -+#define CTR_RFC3686_NONCE_SIZE 4 -+#define CTR_RFC3686_IV_SIZE 8 -+#define CTR_RFC3686_MAX_KEY_SIZE (AES_MAX_KEY_SIZE \ -+ + CTR_RFC3686_NONCE_SIZE) -+ -+struct aes_ctx { -+ int key_length; -+ u32 buf[AES_MAX_KEY_SIZE]; -+ u8 nonce[CTR_RFC3686_NONCE_SIZE]; -+}; -+ -+/** \fn int aes_set_key(struct crypto_tfm *tfm, const uint8_t *in_key, unsigned int key_len) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief sets the AES keys -+ * \param tfm linux crypto algo transform -+ * \param in_key input key -+ * \param key_len key lengths of 16, 24 and 32 bytes supported -+ * \return -EINVAL - bad key length, 0 - SUCCESS -+*/ -+static int aes_set_key(struct crypto_tfm *tfm, -+ const u8 *in_key, -+ unsigned int key_len) -+{ -+ struct aes_ctx *ctx = crypto_tfm_ctx(tfm); -+ u32 *flags = &tfm->crt_flags; -+ -+ DPRINTF(0, "ctx @%p, key_len %d\n", ctx, key_len); -+ -+ if (key_len != 16 && key_len != 24 && key_len != 32) { -+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; -+ return -EINVAL; -+ } -+ -+ ctx->key_length = key_len; -+ memcpy((u8 *)(ctx->buf), in_key, key_len); -+ -+ return 0; -+} -+ -+#ifndef CONFIG_CRYPTO_DEV_DMA -+/** \fn void deu_aes(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, size_t nbytes, int encdec, int mode) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief main interface to AES hardware -+ * \param ctx_arg crypto algo context -+ * \param out_arg output bytestream -+ * \param in_arg input bytestream -+ * \param iv_arg initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param mode operation mode such as ebc, cbc, ctr -+ * -+*/ -+static void deu_aes(void *ctx_arg, -+ u8 *out_arg, -+ const u8 *in_arg, -+ u8 *iv_arg, -+ size_t nbytes, -+ int encdec, -+ int mode) -+#else -+ -+/** \fn void deu_aes_core(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, size_t nbytes, int encdec, int mode) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief main interface to AES hardware -+ * \param ctx_arg crypto algo context -+ * \param out_arg output bytestream -+ * \param in_arg input bytestream -+ * \param iv_arg initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param mode operation mode such as ebc, cbc, ctr -+ * -+*/ -+static void deu_aes_core(void *ctx_arg, -+ u8 *out_arg, -+ const u8 *in_arg, -+ u8 *iv_arg, -+ size_t nbytes, -+ int encdec, -+ int mode) -+#endif -+ -+{ -+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -+ volatile struct deu_aes *aes = (volatile struct deu_aes *)AES_START; -+ struct aes_ctx *ctx = (struct aes_ctx *)ctx_arg; -+ u32 *in_key = ctx->buf; -+ ulong flag; -+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -+ int key_len = ctx->key_length; -+ -+#ifndef CONFIG_CRYPTO_DEV_DMA -+ int i = 0; -+ int byte_cnt = nbytes; -+#else -+ volatile struct deu_dma *dma = (struct deu_dma *)LQ_DEU_DMA_CON; -+ struct dma_device_info *dma_device = lq_deu[0].dma_device; -+ /* struct deu_drv_priv *deu_priv = -+ * (struct deu_drv_priv *)dma_device->priv; */ -+ int wlen = 0; -+ u32 *outcopy = NULL; -+ u32 *dword_mem_aligned_in = NULL; -+ -+# ifdef CONFIG_CRYPTO_DEV_POLL_DMA -+ u32 timeout = 0; -+ u32 *out_dma = NULL; -+# endif -+#endif -+ -+ DPRINTF(0, "ctx @%p, mode %d, encdec %d\n", ctx, mode, encdec); -+ -+ CRTCL_SECT_START; -+ -+ /* 128, 192 or 256 bit key length */ -+ aes->ctrl.K = key_len / 8 - 2; -+ if (key_len == 128 / 8) { -+ aes->K3R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 0)); -+ aes->K2R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 1)); -+ aes->K1R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 2)); -+ aes->K0R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 3)); -+ } -+ else if (key_len == 192 / 8) { -+ aes->K5R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 0)); -+ aes->K4R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 1)); -+ aes->K3R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 2)); -+ aes->K2R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 3)); -+ aes->K1R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 4)); -+ aes->K0R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 5)); -+ } -+ else if (key_len == 256 / 8) { -+ aes->K7R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 0)); -+ aes->K6R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 1)); -+ aes->K5R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 2)); -+ aes->K4R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 3)); -+ aes->K3R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 4)); -+ aes->K2R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 5)); -+ aes->K1R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 6)); -+ aes->K0R = DEU_ENDIAN_SWAP(*((u32 *)in_key + 7)); -+ } -+ else { -+ CRTCL_SECT_END; -+ return; /* -EINVAL; */ -+ } -+ -+ /* let HW pre-process DEcryption key in any case (even if -+ ENcryption is used). Key Valid (KV) bit is then only -+ checked in decryption routine! */ -+ aes->ctrl.PNK = 1; -+ -+#ifdef CONFIG_CRYPTO_DEV_DMA -+ while (aes->ctrl.BUS) { -+ /* this will not take long */ -+ } -+ AES_DMA_MISC_CONFIG(); -+#endif -+ -+ aes->ctrl.E_D = !encdec; /* encryption */ -+ aes->ctrl.O = mode; /* 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR */ -+ aes->ctrl.SM = 1; /* start after writing input register */ -+ aes->ctrl.DAU = 0; /* Disable Automatic Update of init -+ vector */ -+ aes->ctrl.ARS = 1; /* Autostart Select - write to IHR */ -+ -+ /* aes->ctrl.F = 128; */ /* default; only for CFB and OFB modes; -+ change only for -+ customer-specific apps */ -+ if (mode > 0) { -+ aes->IV3R = DEU_ENDIAN_SWAP(*(u32 *)iv_arg); -+ aes->IV2R = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 1)); -+ aes->IV1R = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 2)); -+ aes->IV0R = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 3)); -+ }; -+ -+#ifndef CONFIG_CRYPTO_DEV_DMA -+ i = 0; -+ while (byte_cnt >= 16) { -+ aes->ID3R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 0)); -+ aes->ID2R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 1)); -+ aes->ID1R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 2)); -+ /* start crypto */ -+ aes->ID0R = INPUT_ENDIAN_SWAP(*((u32 *)in_arg + (i * 4) + 3)); -+ -+ while (aes->ctrl.BUS) { -+ /* this will not take long */ -+ } -+ -+ *((volatile u32 *)out_arg + (i * 4) + 0) = aes->OD3R; -+ *((volatile u32 *)out_arg + (i * 4) + 1) = aes->OD2R; -+ *((volatile u32 *)out_arg + (i * 4) + 2) = aes->OD1R; -+ *((volatile u32 *)out_arg + (i * 4) + 3) = aes->OD0R; -+ -+ i++; -+ byte_cnt -= 16; -+ } -+#else /* dma */ -+ /* Prepare Rx buf length used in dma psuedo interrupt */ -+ /* deu_priv->deu_rx_buf = out_arg; */ -+ /* deu_priv->deu_rx_len = nbytes; */ -+ -+ /* memory alignment issue */ -+ dword_mem_aligned_in = (u32 *)DEU_DWORD_REORDERING(in_arg, -+ aes_buff_in, -+ BUFFER_IN, nbytes); -+ -+ dma->ctrl.ALGO = 1; /* AES */ -+ dma->ctrl.BS = 0; -+ aes->ctrl.DAU = 0; -+ dma->ctrl.EN = 1; -+ -+ while (aes->ctrl.BUS) { -+ /* wait for AES to be ready */ -+ }; -+ -+ wlen = dma_device_write(dma_device, (u8 *)dword_mem_aligned_in, -+ nbytes, NULL); -+ if (wlen != nbytes) { -+ dma->ctrl.EN = 0; -+ CRTCL_SECT_END; -+ printk(KERN_ERR "[%s %s %d]: dma_device_write fail!\n", -+ __FILE__, __func__, __LINE__); -+ return; /* -EINVAL; */ -+ } -+ -+ WAIT_AES_DMA_READY(); -+ -+# ifdef CONFIG_CRYPTO_DEV_POLL_DMA -+ outcopy = (u32 *)DEU_DWORD_REORDERING(out_arg, aes_buff_out, -+ BUFFER_OUT, nbytes); -+ -+ /* polling DMA rx channel */ -+ while ((dma_device_read(dma_device, (u8 **)&out_dma, NULL)) == 0) { -+ timeout++; -+ -+ if (timeout >= 333000) { -+ dma->ctrl.EN = 0; -+ CRTCL_SECT_END; -+ printk (KERN_ERR "[%s %s %d]: timeout!!\n", -+ __FILE__, __func__, __LINE__); -+ return; /* -EINVAL; */ -+ } -+ } -+ -+ WAIT_AES_DMA_READY(); -+ -+ AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes); -+ -+# else /* not working at the moment.. */ -+ CRTCL_SECT_END; -+ -+ /* sleep and wait for Rx finished */ -+ DEU_WAIT_EVENT(deu_priv->deu_thread_wait, DEU_EVENT, -+ deu_priv->deu_event_flags); -+ -+ CRTCL_SECT_START; -+# endif -+ -+#endif /* dma */ -+ -+ /* tc.chen : copy iv_arg back */ -+ if (mode > 0) { -+ *((u32 *)iv_arg) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg)); -+ *((u32 *)iv_arg + 1) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 1)); -+ *((u32 *)iv_arg + 2) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 2)); -+ *((u32 *)iv_arg + 3) = DEU_ENDIAN_SWAP(*((u32 *)iv_arg + 3)); -+ } -+ -+ CRTCL_SECT_END; -+} -+ -+/** \fn int ctr_rfc3686_aes_set_key(struct crypto_tfm *tfm, const uint8_t *in_key, unsigned int key_len) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief sets RFC3686 key -+ * \param tfm linux crypto algo transform -+ * \param in_key input key -+ * \param key_len key lengths of 20, 28 and 36 bytes supported; last 4 bytes is nonce -+ * \return 0 - SUCCESS -+ * -EINVAL - bad key length -+*/ -+static int ctr_rfc3686_aes_set_key(struct crypto_tfm *tfm, -+ const uint8_t *in_key, -+ unsigned int key_len) -+{ -+ struct aes_ctx *ctx = crypto_tfm_ctx(tfm); -+ u32 *flags = &tfm->crt_flags; -+ -+ memcpy(ctx->nonce, in_key + (key_len - CTR_RFC3686_NONCE_SIZE), -+ CTR_RFC3686_NONCE_SIZE); -+ -+ key_len -= CTR_RFC3686_NONCE_SIZE; /* remove 4 bytes of nonce */ -+ -+ if (key_len != 16 && key_len != 24 && key_len != 32) { -+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; -+ return -EINVAL; -+ } -+ -+ ctx->key_length = key_len; -+ -+ memcpy((u8 *)(ctx->buf), in_key, key_len); -+ -+ return 0; -+} -+ -+/** \fn void deu_aes(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief main interface with DEU hardware in DMA mode -+ * \param ctx_arg crypto algo context -+ * \param out_arg output bytestream -+ * \param in_arg input bytestream -+ * \param iv_arg initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param mode operation mode such as ebc, cbc, ctr -+*/ -+ -+#ifdef CONFIG_CRYPTO_DEV_DMA -+static void deu_aes(void *ctx_arg, -+ u8 *out_arg, -+ const u8 *in_arg, -+ u8 *iv_arg, -+ u32 nbytes, -+ int encdec, -+ int mode) -+{ -+ u32 remain = nbytes; -+ u32 inc; -+ -+ while (remain > 0) { -+ if (remain >= DEU_MAX_PACKET_SIZE) -+ inc = DEU_MAX_PACKET_SIZE; -+ else -+ inc = remain; -+ -+ remain -= inc; -+ -+ deu_aes_core(ctx_arg, out_arg, in_arg, iv_arg, inc, encdec, -+ mode); -+ -+ out_arg += inc; -+ in_arg += inc; -+ } -+} -+#endif -+ -+/* definitions from linux/include/crypto.h: -+#define CRYPTO_TFM_MODE_ECB 0x00000001 -+#define CRYPTO_TFM_MODE_CBC 0x00000002 -+#define CRYPTO_TFM_MODE_CFB 0x00000004 -+#define CRYPTO_TFM_MODE_CTR 0x00000008 -+#define CRYPTO_TFM_MODE_OFB 0x00000010 -+but hardware definition: 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR */ -+ -+/** \fn void deu_aes_ecb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief sets AES hardware to ECB mode -+ * \param ctx crypto algo context -+ * \param dst output bytestream -+ * \param src input bytestream -+ * \param iv initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param inplace not used -+*/ -+static void deu_aes_ecb(void *ctx, -+ uint8_t *dst, -+ const uint8_t *src, -+ uint8_t *iv, -+ size_t nbytes, -+ int encdec, -+ int inplace) -+{ -+ deu_aes(ctx, dst, src, NULL, nbytes, encdec, 0); -+} -+ -+/** \fn void deu_aes_cbc(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief sets AES hardware to CBC mode -+ * \param ctx crypto algo context -+ * \param dst output bytestream -+ * \param src input bytestream -+ * \param iv initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param inplace not used -+*/ -+static void deu_aes_cbc(void *ctx, -+ uint8_t *dst, -+ const uint8_t *src, -+ uint8_t *iv, -+ size_t nbytes, -+ int encdec, -+ int inplace) -+{ -+ deu_aes(ctx, dst, src, iv, nbytes, encdec, 1); -+} -+ -+#if 0 -+/** \fn void deu_aes_ofb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief sets AES hardware to OFB mode -+ * \param ctx crypto algo context -+ * \param dst output bytestream -+ * \param src input bytestream -+ * \param iv initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param inplace not used -+*/ -+static void deu_aes_ofb(void *ctx, -+ uint8_t *dst, -+ const uint8_t *src, -+ uint8_t *iv, -+ size_t nbytes, -+ int encdec, -+ int inplace) -+{ -+ deu_aes(ctx, dst, src, iv, nbytes, encdec, 2); -+} -+ -+/** \fn void deu_aes_cfb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief sets AES hardware to CFB mode -+ * \param ctx crypto algo context -+ * \param dst output bytestream -+ * \param src input bytestream -+ * \param iv initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param inplace not used -+*/ -+static void deu_aes_cfb(void *ctx, -+ uint8_t *dst, -+ const uint8_t *src, -+ uint8_t *iv, -+ size_t nbytes, -+ int encdec, -+ int inplace) -+{ -+ deu_aes(ctx, dst, src, iv, nbytes, encdec, 3); -+} -+#endif -+ -+/** \fn void deu_aes_ctr(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief sets AES hardware to CTR mode -+ * \param ctx crypto algo context -+ * \param dst output bytestream -+ * \param src input bytestream -+ * \param iv initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param inplace not used -+*/ -+static void deu_aes_ctr(void *ctx, -+ uint8_t *dst, -+ const uint8_t *src, -+ uint8_t *iv, -+ size_t nbytes, -+ int encdec, -+ int inplace) -+{ -+ deu_aes(ctx, dst, src, iv, nbytes, encdec, 4); -+} -+ -+/** \fn void aes_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief encrypt AES_BLOCK_SIZE of data -+ * \param tfm linux crypto algo transform -+ * \param out output bytestream -+ * \param in input bytestream -+*/ -+static void aes_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) -+{ -+ struct aes_ctx *ctx = crypto_tfm_ctx(tfm); -+ deu_aes(ctx, out, in, NULL, AES_BLOCK_SIZE, CRYPTO_DIR_ENCRYPT, 0); -+} -+ -+/** \fn void aes_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief decrypt AES_BLOCK_SIZE of data -+ * \param tfm linux crypto algo transform -+ * \param out output bytestream -+ * \param in input bytestream -+*/ -+static void aes_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) -+{ -+ struct aes_ctx *ctx = crypto_tfm_ctx(tfm); -+ deu_aes(ctx, out, in, NULL, AES_BLOCK_SIZE, CRYPTO_DIR_DECRYPT, 0); -+} -+ -+/* -+ * \brief AES function mappings -+*/ -+static struct crypto_alg aes_alg = { -+ .cra_name = "aes", -+ .cra_driver_name = "lq_deu-aes", -+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER, -+ .cra_blocksize = AES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct aes_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), -+ .cra_u = { -+ .cipher = { -+ .cia_min_keysize = AES_MIN_KEY_SIZE, -+ .cia_max_keysize = AES_MAX_KEY_SIZE, -+ .cia_setkey = aes_set_key, -+ .cia_encrypt = aes_encrypt, -+ .cia_decrypt = aes_decrypt, -+ } -+ } -+}; -+ -+/** \fn int ecb_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief ECB AES encrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+ * \return err -+*/ -+static int ecb_aes_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ nbytes -= (nbytes % AES_BLOCK_SIZE); -+ deu_aes_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ NULL, nbytes, CRYPTO_DIR_ENCRYPT, 0); -+ nbytes &= AES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/** \fn int ecb_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief ECB AES decrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+ * \return err -+*/ -+static int ecb_aes_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ nbytes -= (nbytes % AES_BLOCK_SIZE); -+ deu_aes_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ NULL, nbytes, CRYPTO_DIR_DECRYPT, 0); -+ nbytes &= AES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/* -+ * \brief AES function mappings -+*/ -+static struct crypto_alg ecb_aes_alg = { -+ .cra_name = "ecb(aes)", -+ .cra_driver_name = "lq_deu-ecb(aes)", -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = AES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct aes_ctx), -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = AES_MIN_KEY_SIZE, -+ .max_keysize = AES_MAX_KEY_SIZE, -+ .setkey = aes_set_key, -+ .encrypt = ecb_aes_encrypt, -+ .decrypt = ecb_aes_decrypt, -+ } -+ } -+}; -+ -+/** \fn int cbc_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief CBC AES encrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+ * \return err -+*/ -+static int cbc_aes_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ u8 *iv = walk.iv; -+ nbytes -= (nbytes % AES_BLOCK_SIZE); -+ deu_aes_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ iv, nbytes, CRYPTO_DIR_ENCRYPT, 0); -+ nbytes &= AES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/** \fn int cbc_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief CBC AES decrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+ * \return err -+*/ -+static int cbc_aes_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ u8 *iv = walk.iv; -+ nbytes -= (nbytes % AES_BLOCK_SIZE); -+ deu_aes_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ iv, nbytes, CRYPTO_DIR_DECRYPT, 0); -+ nbytes &= AES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/* -+ * \brief AES function mappings -+*/ -+static struct crypto_alg cbc_aes_alg = { -+ .cra_name = "cbc(aes)", -+ .cra_driver_name = "lq_deu-cbc(aes)", -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = AES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct aes_ctx), -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = AES_MIN_KEY_SIZE, -+ .max_keysize = AES_MAX_KEY_SIZE, -+ .ivsize = AES_BLOCK_SIZE, -+ .setkey = aes_set_key, -+ .encrypt = cbc_aes_encrypt, -+ .decrypt = cbc_aes_decrypt, -+ } -+ } -+}; -+ -+/** \fn int ctr_basic_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief Counter mode AES encrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+ * \return err -+*/ -+static int ctr_basic_aes_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ u8 *iv = walk.iv; -+ nbytes -= (nbytes % AES_BLOCK_SIZE); -+ deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ iv, nbytes, CRYPTO_DIR_ENCRYPT, 0); -+ nbytes &= AES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/** \fn int ctr_basic_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief Counter mode AES decrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+ * \return err -+*/ -+static int ctr_basic_aes_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ u8 *iv = walk.iv; -+ nbytes -= (nbytes % AES_BLOCK_SIZE); -+ deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ iv, nbytes, CRYPTO_DIR_DECRYPT, 0); -+ nbytes &= AES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/* -+ * \brief AES function mappings -+*/ -+static struct crypto_alg ctr_basic_aes_alg = { -+ .cra_name = "ctr(aes)", -+ .cra_driver_name = "lq_deu-ctr(aes)", -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = AES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct aes_ctx), -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(ctr_basic_aes_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = AES_MIN_KEY_SIZE, -+ .max_keysize = AES_MAX_KEY_SIZE, -+ .ivsize = AES_BLOCK_SIZE, -+ .setkey = aes_set_key, -+ .encrypt = ctr_basic_aes_encrypt, -+ .decrypt = ctr_basic_aes_decrypt, -+ } -+ } -+}; -+ -+/** \fn int ctr_rfc3686_aes_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief Counter mode AES (rfc3686) encrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+ * \return err -+*/ -+static int ctr_rfc3686_aes_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ u8 rfc3686_iv[16]; -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ /* set up counter block */ -+ memcpy(rfc3686_iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE); -+ memcpy(rfc3686_iv + CTR_RFC3686_NONCE_SIZE, walk.iv, -+ CTR_RFC3686_IV_SIZE); -+ -+ /* initialize counter portion of counter block */ -+ *(__be32 *)(rfc3686_iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) = -+ cpu_to_be32(1); -+ -+ while ((nbytes = walk.nbytes)) { -+ nbytes -= (nbytes % AES_BLOCK_SIZE); -+ deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ rfc3686_iv, nbytes, CRYPTO_DIR_ENCRYPT, 0); -+ nbytes &= AES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/** \fn int ctr_rfc3686_aes_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief Counter mode AES (rfc3686) decrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+ * \return err -+*/ -+static int ctr_rfc3686_aes_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ u8 rfc3686_iv[16]; -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ /* set up counter block */ -+ memcpy(rfc3686_iv, ctx->nonce, CTR_RFC3686_NONCE_SIZE); -+ memcpy(rfc3686_iv + CTR_RFC3686_NONCE_SIZE, walk.iv, -+ CTR_RFC3686_IV_SIZE); -+ -+ /* initialize counter portion of counter block */ -+ *(__be32 *)(rfc3686_iv + CTR_RFC3686_NONCE_SIZE + CTR_RFC3686_IV_SIZE) = -+ cpu_to_be32(1); -+ -+ while ((nbytes = walk.nbytes)) { -+ nbytes -= (nbytes % AES_BLOCK_SIZE); -+ deu_aes_ctr(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ rfc3686_iv, nbytes, CRYPTO_DIR_DECRYPT, 0); -+ nbytes &= AES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/* -+ * \brief AES function mappings -+*/ -+static struct crypto_alg ctr_rfc3686_aes_alg = { -+ .cra_name = "rfc3686(ctr(aes))", -+ .cra_driver_name = "lq_deu-ctr-rfc3686(aes)", -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = AES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct aes_ctx), -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(ctr_rfc3686_aes_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = AES_MIN_KEY_SIZE, -+ .max_keysize = CTR_RFC3686_MAX_KEY_SIZE, -+ .ivsize = CTR_RFC3686_IV_SIZE, -+ .setkey = ctr_rfc3686_aes_set_key, -+ .encrypt = ctr_rfc3686_aes_encrypt, -+ .decrypt = ctr_rfc3686_aes_decrypt, -+ } -+ } -+}; -+ -+/** \fn int lq_deu_init_aes (void) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief function to initialize AES driver -+ * \return ret -+*/ -+int lq_deu_init_aes(void) -+{ -+ int ret; -+ -+ if ((ret = crypto_register_alg(&aes_alg))) -+ goto aes_err; -+ -+ if ((ret = crypto_register_alg(&ecb_aes_alg))) -+ goto ecb_aes_err; -+ -+ if ((ret = crypto_register_alg(&cbc_aes_alg))) -+ goto cbc_aes_err; -+ -+ if ((ret = crypto_register_alg(&ctr_basic_aes_alg))) -+ goto ctr_basic_aes_err; -+ -+ if ((ret = crypto_register_alg(&ctr_rfc3686_aes_alg))) -+ goto ctr_rfc3686_aes_err; -+ -+ deu_aes_chip_init(); -+ -+ CRTCL_SECT_INIT; -+ -+#ifdef CONFIG_CRYPTO_DEV_DMA -+ if (ALLOCATE_MEMORY(BUFFER_IN, AES_ALGO) < 0) { -+ printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n", -+ __FILE__, __func__, __LINE__); -+ goto ctr_rfc3686_aes_err; -+ } -+ if (ALLOCATE_MEMORY(BUFFER_OUT, AES_ALGO) < 0) { -+ printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n", -+ __FILE__, __func__, __LINE__); -+ goto ctr_rfc3686_aes_err; -+ } -+#endif -+ -+ printk(KERN_NOTICE "Lantiq DEU AES initialized%s.\n", -+ disable_deudma ? "" : " (DMA)"); -+ return ret; -+ -+ctr_rfc3686_aes_err: -+ crypto_unregister_alg(&ctr_rfc3686_aes_alg); -+ printk(KERN_ERR "Lantiq ctr_rfc3686_aes initialization failed!\n"); -+ return ret; -+ctr_basic_aes_err: -+ crypto_unregister_alg(&ctr_basic_aes_alg); -+ printk(KERN_ERR "Lantiq ctr_basic_aes initialization failed!\n"); -+ return ret; -+cbc_aes_err: -+ crypto_unregister_alg(&cbc_aes_alg); -+ printk(KERN_ERR "Lantiq cbc_aes initialization failed!\n"); -+ return ret; -+ecb_aes_err: -+ crypto_unregister_alg(&ecb_aes_alg); -+ printk(KERN_ERR "Lantiq aes initialization failed!\n"); -+ return ret; -+aes_err: -+ printk(KERN_ERR "Lantiq DEU AES initialization failed!\n"); -+ return ret; -+} -+ -+/** \fn void lq_deu_fini_aes(void) -+ * \ingroup LQ_AES_FUNCTIONS -+ * \brief unregister aes driver -+*/ -+void lq_deu_fini_aes(void) -+{ -+ crypto_unregister_alg(&aes_alg); -+ crypto_unregister_alg(&ecb_aes_alg); -+ crypto_unregister_alg(&cbc_aes_alg); -+ crypto_unregister_alg(&ctr_basic_aes_alg); -+ crypto_unregister_alg(&ctr_rfc3686_aes_alg); -+ -+#ifdef CONFIG_CRYPTO_DEV_DMA -+ FREE_MEMORY(aes_buff_in); -+ FREE_MEMORY(aes_buff_out); -+#endif -+} ---- /dev/null -+++ b/drivers/crypto/lantiq/arc4.c -@@ -0,0 +1,397 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file arc4.c -+ \ingroup LQ_DEU -+ \brief ARC4 encryption DEU driver file -+*/ -+ -+/** -+ \defgroup LQ_ARC4_FUNCTIONS LQ_ARC4_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief Lantiq DEU driver functions -+*/ -+ -+#include <linux/version.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/types.h> -+#include <linux/errno.h> -+#include <linux/crypto.h> -+#include <crypto/algapi.h> -+#include <linux/interrupt.h> -+#include <asm/byteorder.h> -+#include <linux/delay.h> -+ -+#ifdef CONFIG_SOL_LANTIQ_XWAY -+ -+#include "deu.h" -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ -+static spinlock_t cipher_lock; -+ -+/* Preprocessor declerations */ -+#define ARC4_MIN_KEY_SIZE 1 -+/* #define ARC4_MAX_KEY_SIZE 256 */ -+#define ARC4_MAX_KEY_SIZE 16 -+#define ARC4_BLOCK_SIZE 1 -+ -+/* -+ * \brief arc4 private structure -+*/ -+struct arc4_ctx { -+ int key_length; -+ u8 buf[120]; -+}; -+ -+/** \fn static void deu_arc4(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode) -+ \ingroup LQ_ARC4_FUNCTIONS -+ \brief main interface to AES hardware -+ \param ctx_arg crypto algo context -+ \param out_arg output bytestream -+ \param in_arg input bytestream -+ \param iv_arg initialization vector -+ \param nbytes length of bytestream -+ \param encdec 1 for encrypt; 0 for decrypt -+ \param mode operation mode such as ebc, cbc, ctr -+*/ -+static void deu_arc4(void *ctx_arg, -+ u8 *out_arg, -+ const u8 *in_arg, -+ u8 *iv_arg, -+ u32 nbytes, -+ int encdec, -+ int mode) -+{ -+ volatile struct deu_arc4 *arc4 = (struct deu_arc4 *) ARC4_START; -+ int i = 0; -+ ulong flag; -+ -+#if 1 /* need to handle nbytes not multiple of 16 */ -+ volatile u32 tmp_array32[4]; -+ volatile u8 *tmp_ptr8; -+ int remaining_bytes, j; -+#endif -+ -+ CRTCL_SECT_START; -+ -+ arc4->IDLEN = nbytes; -+ -+#if 1 -+ while (i < nbytes) { -+ arc4->ID3R = *((u32 *) in_arg + (i>>2) + 0); -+ arc4->ID2R = *((u32 *) in_arg + (i>>2) + 1); -+ arc4->ID1R = *((u32 *) in_arg + (i>>2) + 2); -+ arc4->ID0R = *((u32 *) in_arg + (i>>2) + 3); -+ -+ arc4->ctrl.GO = 1; -+ -+ while (arc4->ctrl.BUS) { -+ /* this will not take long */ } -+ -+#if 1 -+ /* need to handle nbytes not multiple of 16 */ -+ tmp_array32[0] = arc4->OD3R; -+ tmp_array32[1] = arc4->OD2R; -+ tmp_array32[2] = arc4->OD1R; -+ tmp_array32[3] = arc4->OD0R; -+ -+ remaining_bytes = nbytes - i; -+ if (remaining_bytes > 16) -+ remaining_bytes = 16; -+ -+ tmp_ptr8 = (u8 *)&tmp_array32[0]; -+ for (j = 0; j < remaining_bytes; j++) -+ *out_arg++ = *tmp_ptr8++; -+#else -+ *((u32 *) out_arg + (i>>2) + 0) = arc4->OD3R; -+ *((u32 *) out_arg + (i>>2) + 1) = arc4->OD2R; -+ *((u32 *) out_arg + (i>>2) + 2) = arc4->OD1R; -+ *((u32 *) out_arg + (i>>2) + 3) = arc4->OD0R; -+#endif -+ -+ i += 16; -+ } -+#else /* dma */ -+ -+#endif /* dma */ -+ -+ CRTCL_SECT_END; -+} -+ -+/** \fn arc4_chip_init(void) -+ \ingroup LQ_ARC4_FUNCTIONS -+ \brief initialize arc4 hardware -+*/ -+static void arc4_chip_init(void) -+{ -+ /* do nothing */ -+} -+ -+/** \fn static int arc4_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) -+ \ingroup LQ_ARC4_FUNCTIONS -+ \brief sets ARC4 key -+ \param tfm linux crypto algo transform -+ \param in_key input key -+ \param key_len key lengths less than or equal to 16 bytes supported -+*/ -+static int arc4_set_key(struct crypto_tfm *tfm, -+ const u8 *inkey, -+ unsigned int key_len) -+{ -+ /* struct arc4_ctx *ctx = crypto_tfm_ctx(tfm); */ -+ volatile struct deu_arc4 *arc4 = (struct deu_arc4 *) ARC4_START; -+ -+ u32 *in_key = (u32 *)inkey; -+ -+ /* must program all bits at one go?!!! */ -+#if 1 -+ /* #ifndef CONFIG_CRYPTO_DEV_VR9_DMA */ -+ *LQ_ARC4_CON = ( (1<<31) | ((key_len - 1)<<27) | (1<<26) | (3<<16) ); -+ /* NDC=1,ENDI=1,GO=0,KSAE=1,SM=0 */ -+ -+ arc4->K3R = *((u32 *) in_key + 0); -+ arc4->K2R = *((u32 *) in_key + 1); -+ arc4->K1R = *((u32 *) in_key + 2); -+ arc4->K0R = *((u32 *) in_key + 3); -+#else /* dma */ -+ *AMAZONS_ARC4_CON = ( (1<<31) | ((key_len - 1)<<27) | (1<<26) | (3<<16) | (1<<4) ); -+ /* NDC=1,ENDI=1,GO=0,KSAE=1,SM=1 */ -+ -+ arc4->K3R = *((u32 *) in_key + 0); -+ arc4->K2R = *((u32 *) in_key + 1); -+ arc4->K1R = *((u32 *) in_key + 2); -+ arc4->K0R = *((u32 *) in_key + 3); -+ -+#if 0 -+ arc4->K3R = deu_endian_swap(*((u32 *) in_key + 0)); -+ arc4->K2R = deu_endian_swap(*((u32 *) in_key + 1)); -+ arc4->K1R = deu_endian_swap(*((u32 *) in_key + 2)); -+ arc4->K0R = deu_endian_swap(*((u32 *) in_key + 3)); -+#endif -+ -+#endif -+ -+#if 0 /* arc4 is a ugly state machine, KSAE can only be set once per session */ -+ ctx->key_length = key_len; -+ -+ memcpy((u8 *)(ctx->buf), in_key, key_len); -+#endif -+ -+ return 0; -+} -+ -+/** \fn static void deu_arc4_ecb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) -+ \ingroup LQ_ARC4_FUNCTIONS -+ \brief sets ARC4 hardware to ECB mode -+ \param ctx crypto algo context -+ \param dst output bytestream -+ \param src input bytestream -+ \param iv initialization vector -+ \param nbytes length of bytestream -+ \param encdec 1 for encrypt; 0 for decrypt -+ \param inplace not used -+*/ -+static void deu_arc4_ecb(void *ctx, -+ uint8_t *dst, -+ const uint8_t *src, -+ uint8_t *iv, -+ size_t nbytes, -+ int encdec, -+ int inplace) -+{ -+ deu_arc4(ctx, dst, src, NULL, nbytes, encdec, 0); -+} -+ -+/** \fn static void arc4_crypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -+ \ingroup LQ_ARC4_FUNCTIONS -+ \brief encrypt/decrypt ARC4_BLOCK_SIZE of data -+ \param tfm linux crypto algo transform -+ \param out output bytestream -+ \param in input bytestream -+*/ -+static void arc4_crypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -+{ -+ struct arc4_ctx *ctx = crypto_tfm_ctx(tfm); -+ -+ deu_arc4(ctx, out, in, NULL, ARC4_BLOCK_SIZE, -+ CRYPTO_DIR_DECRYPT, CRYPTO_TFM_MODE_ECB); -+} -+ -+/* -+ * \brief ARC4 function mappings -+*/ -+static struct crypto_alg arc4_alg = { -+ .cra_name = "arc4", -+ .cra_driver_name = "lq_deu-arc4", -+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER, -+ .cra_blocksize = ARC4_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct arc4_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(arc4_alg.cra_list), -+ .cra_u = { -+ .cipher = { -+ .cia_min_keysize = ARC4_MIN_KEY_SIZE, -+ .cia_max_keysize = ARC4_MAX_KEY_SIZE, -+ .cia_setkey = arc4_set_key, -+ .cia_encrypt = arc4_crypt, -+ .cia_decrypt = arc4_crypt, -+ } -+ } -+}; -+ -+/** \fn static int ecb_arc4_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ \ingroup LQ_ARC4_FUNCTIONS -+ \brief ECB ARC4 encrypt using linux crypto blkcipher -+ \param desc blkcipher descriptor -+ \param dst output scatterlist -+ \param src input scatterlist -+ \param nbytes data size in bytes -+*/ -+static int ecb_arc4_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct arc4_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ DPRINTF(1, "\n"); -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ deu_arc4_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ NULL, nbytes, CRYPTO_DIR_ENCRYPT, 0); -+ nbytes &= ARC4_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/** \fn static int ecb_arc4_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ \ingroup LQ_ARC4_FUNCTIONS -+ \brief ECB ARC4 decrypt using linux crypto blkcipher -+ \param desc blkcipher descriptor -+ \param dst output scatterlist -+ \param src input scatterlist -+ \param nbytes data size in bytes -+*/ -+static int ecb_arc4_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct arc4_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ DPRINTF(1, "\n"); -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ deu_arc4_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ NULL, nbytes, CRYPTO_DIR_DECRYPT, 0); -+ nbytes &= ARC4_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/* -+ * \brief ARC4 function mappings -+*/ -+static struct crypto_alg ecb_arc4_alg = { -+ .cra_name = "ecb(arc4)", -+ .cra_driver_name = "lq_deu-ecb(arc4)", -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = ARC4_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct arc4_ctx), -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(ecb_arc4_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = ARC4_MIN_KEY_SIZE, -+ .max_keysize = ARC4_MAX_KEY_SIZE, -+ .setkey = arc4_set_key, -+ .encrypt = ecb_arc4_encrypt, -+ .decrypt = ecb_arc4_decrypt, -+ } -+ } -+}; -+ -+/** \fn int lq_deu_init_arc4(void) -+ \ingroup LQ_ARC4_FUNCTIONS -+ \brief initialize arc4 driver -+*/ -+int lq_deu_init_arc4(void) -+{ -+ int ret; -+ -+ if ((ret = crypto_register_alg(&arc4_alg))) -+ goto arc4_err; -+ -+ if ((ret = crypto_register_alg(&ecb_arc4_alg))) -+ goto ecb_arc4_err; -+ -+ arc4_chip_init(); -+ -+ CRTCL_SECT_INIT; -+ -+ printk(KERN_NOTICE "Lantiq DEU ARC4 initialized %s.\n", -+ disable_deudma ? "" : " (DMA)"); -+ return ret; -+ -+arc4_err: -+ crypto_unregister_alg(&arc4_alg); -+ printk(KERN_ERR "Lantiq arc4 initialization failed!\n"); -+ return ret; -+ecb_arc4_err: -+ crypto_unregister_alg(&ecb_arc4_alg); -+ printk(KERN_ERR "Lantiq ecb_arc4 initialization failed!\n"); -+ -+ return ret; -+} -+ -+/** \fn void lq_deu_fini_arc4(void) -+ \ingroup LQ_ARC4_FUNCTIONS -+ \brief unregister arc4 driver -+*/ -+void lq_deu_fini_arc4(void) -+{ -+ crypto_unregister_alg(&arc4_alg); -+ crypto_unregister_alg(&ecb_arc4_alg); -+} -+ -+#endif -+ -+#endif ---- /dev/null -+++ b/drivers/crypto/lantiq/des.c -@@ -0,0 +1,929 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver -+*/ -+ -+/** -+ \file des.c -+ \ingroup LQ_DEU -+ \brief DES encryption DEU driver file -+*/ -+ -+/** -+ \defgroup LQ_DES_FUNCTIONS LQ_DES_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief Lantiq DES Encryption functions -+*/ -+ -+#include <linux/version.h> -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/types.h> -+#include <linux/errno.h> -+#include <linux/crypto.h> -+#include <linux/interrupt.h> -+#include <linux/delay.h> -+#include <asm/byteorder.h> -+#include <crypto/algapi.h> -+ -+#ifdef CONFIG_SOL_LANTIQ_XWAY -+ -+#include "deu.h" -+ -+#ifdef CONFIG_CRYPTO_DEV_DMA -+# include "deu_dma.h" -+#endif -+ -+static spinlock_t cipher_lock; -+ -+/* Preprocessor declarations */ -+#define DES_KEY_SIZE 8 -+#define DES_EXPKEY_WORDS 32 -+#define DES_BLOCK_SIZE 8 -+#define DES3_EDE_KEY_SIZE (3 * DES_KEY_SIZE) -+#define DES3_EDE_EXPKEY_WORDS (3 * DES_EXPKEY_WORDS) -+#define DES3_EDE_BLOCK_SIZE DES_BLOCK_SIZE -+ -+struct des_ctx { -+ int controlr_M; -+ int key_length; -+ u8 iv[DES_BLOCK_SIZE]; -+ u32 expkey[DES3_EDE_EXPKEY_WORDS]; -+}; -+ -+/** \fn int des_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief sets DES key -+ * \param tfm linux crypto algo transform -+ * \param key input key -+ * \param key_len key length -+*/ -+static int des_setkey(struct crypto_tfm *tfm, -+ const u8 *key, -+ unsigned int key_len) -+{ -+ struct des_ctx *ctx = crypto_tfm_ctx(tfm); -+ -+ DPRINTF(0, "ctx @%p, key_len %d %d\n", ctx, key_len); -+ -+ ctx->controlr_M = 0; /* des */ -+ ctx->key_length = key_len; -+ -+ memcpy((u8 *)(ctx->expkey), key, key_len); -+ -+ return 0; -+} -+ -+#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+/** \fn void deu_des(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief main interface to DES hardware -+ * \param ctx_arg crypto algo context -+ * \param out_arg output bytestream -+ * \param in_arg input bytestream -+ * \param iv_arg initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param mode operation mode such as ebc, cbc -+*/ -+ -+static void deu_des(void *ctx_arg, -+ u8 *out_arg, -+ const u8 *in_arg, -+ u8 *iv_arg, -+ u32 nbytes, -+ int encdec, -+ int mode) -+#else -+/** \fn void deu_des_core(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief main interface to DES hardware -+ * \param ctx_arg crypto algo context -+ * \param out_arg output bytestream -+ * \param in_arg input bytestream -+ * \param iv_arg initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param mode operation mode such as ebc, cbc -+*/ -+static void deu_des_core(void *ctx_arg, -+ u8 *out_arg, -+ const u8 *in_arg, -+ u8 *iv_arg, -+ u32 nbytes, -+ int encdec, -+ int mode) -+#endif -+{ -+ volatile struct deu_des *des = (struct deu_des *) DES_3DES_START; -+ struct des_ctx *dctx = ctx_arg; -+ u32 *key = dctx->expkey; -+ ulong flag; -+ -+#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ int i = 0; -+ int nblocks = 0; -+#else -+ volatile struct deu_dma *dma = (struct deu_dma *) LQ_DEU_DMA_CON; -+ struct dma_device_info *dma_device = lq_deu[0].dma_device; -+ /* struct deu_drv_priv *deu_priv = -+ * (struct deu_drv_priv *)dma_device->priv; */ -+ int wlen = 0; -+ u32 *outcopy = NULL; -+ u32 *dword_mem_aligned_in = NULL; -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_POLL_DMA -+ u32 timeout = 0; -+ u32 *out_dma = NULL; -+#endif -+ -+#endif -+ -+ DPRINTF(0, "ctx @%p, mode %d, encdec %d\n", dctx, mode, encdec); -+ -+ CRTCL_SECT_START; -+ -+ des->ctrl.E_D = !encdec; /* encryption */ -+ des->ctrl.O = mode; /* 0 ECB, 1 CBC, 2 OFB, 3 CFB, 4 CTR */ -+ des->ctrl.SM = 1; /* start after writing input register */ -+ des->ctrl.DAU = 0; /* Disable Automatic Update of init vect */ -+ des->ctrl.ARS = 1; /* Autostart Select - write to IHR */ -+ -+ des->ctrl.M = dctx->controlr_M; -+ /* write keys */ -+ if (dctx->controlr_M == 0) { -+ /* DES mode */ -+ des->K1HR = DEU_ENDIAN_SWAP(*((u32 *) key + 0)); -+ des->K1LR = DEU_ENDIAN_SWAP(*((u32 *) key + 1)); -+#ifdef CRYPTO_DEBUG -+ printk("key1: %x\n", (*((u32 *) key + 0))); -+ printk("key2: %x\n", (*((u32 *) key + 1))); -+#endif -+ } else { -+ /* 3DES mode (EDE-x) */ -+ switch (dctx->key_length) { -+ case 24: -+ des->K3HR = DEU_ENDIAN_SWAP(*((u32 *) key + 4)); -+ des->K3LR = DEU_ENDIAN_SWAP(*((u32 *) key + 5)); -+ /* no break; */ -+ case 16: -+ des->K2HR = DEU_ENDIAN_SWAP(*((u32 *) key + 2)); -+ des->K2LR = DEU_ENDIAN_SWAP(*((u32 *) key + 3)); -+ /* no break; */ -+ case 8: -+ des->K1HR = DEU_ENDIAN_SWAP(*((u32 *) key + 0)); -+ des->K1LR = DEU_ENDIAN_SWAP(*((u32 *) key + 1)); -+ break; -+ default: -+ CRTCL_SECT_END; -+ return; -+ } -+ } -+ -+ /* write init vector (not required for ECB mode) */ -+ if (mode > 0) { -+ des->IVHR = DEU_ENDIAN_SWAP(*(u32 *) iv_arg); -+ des->IVLR = DEU_ENDIAN_SWAP(*((u32 *) iv_arg + 1)); -+ } -+ -+#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ nblocks = nbytes / 4; -+ -+ for (i = 0; i < nblocks; i += 2) { -+ /* wait for busy bit to clear */ -+ -+ /*--- Workaround --------------------------------------------- -+ do a dummy read to the busy flag because it is not raised -+ early enough in CFB/OFB 3DES modes */ -+#ifdef CRYPTO_DEBUG -+ printk("ihr: %x\n", (*((u32 *) in_arg + i))); -+ printk("ilr: %x\n", (*((u32 *) in_arg + 1 + i))); -+#endif -+ des->IHR = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + i)); -+ /* start crypto */ -+ des->ILR = INPUT_ENDIAN_SWAP(*((u32 *) in_arg + 1 + i)); -+ -+ while (des->ctrl.BUS) { -+ /* this will not take long */ -+ } -+ -+ *((u32 *) out_arg + 0 + i) = des->OHR; -+ *((u32 *) out_arg + 1 + i) = des->OLR; -+ -+#ifdef CRYPTO_DEBUG -+ printk("ohr: %x\n", (*((u32 *) out_arg + i))); -+ printk("olr: %x\n", (*((u32 *) out_arg + 1 + i))); -+#endif -+ } -+ -+#else /* dma mode */ -+ -+ /* Prepare Rx buf length used in dma psuedo interrupt */ -+ /* deu_priv->deu_rx_buf = out_arg; */ -+ /* deu_priv->deu_rx_len = nbytes; */ -+ -+ /* memory alignment issue */ -+ dword_mem_aligned_in = (u32 *) DEU_DWORD_REORDERING(in_arg, des_buff_in, -+ BUFFER_IN, nbytes); -+ -+ dma->ctrl.ALGO = 0; /* DES */ -+ des->ctrl.DAU = 0; -+ dma->ctrl.BS = 0; -+ dma->ctrl.EN = 1; -+ -+ while (des->ctrl.BUS) { -+ /* wait for AES to be ready */ -+ }; -+ -+ wlen = dma_device_write(dma_device, (u8 *) dword_mem_aligned_in, nbytes, -+ NULL); -+ if (wlen != nbytes) { -+ dma->ctrl.EN = 0; -+ CRTCL_SECT_END; -+ printk(KERN_ERR "[%s %s %d]: dma_device_write fail!\n", -+ __FILE__, __func__, __LINE__); -+ return; /* -EINVAL; */ -+ } -+ -+ WAIT_DES_DMA_READY(); -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_POLL_DMA -+ outcopy = (u32 *) DEU_DWORD_REORDERING(out_arg, des_buff_out, -+ BUFFER_OUT, nbytes); -+ -+ /* polling DMA rx channel */ -+ while ((dma_device_read(dma_device, (u8 **) &out_dma, NULL)) == 0) { -+ timeout++; -+ -+ if (timeout >= 333000) { -+ dma->ctrl.EN = 0; -+ CRTCL_SECT_END; -+ printk(KERN_ERR "[%s %s %d]: timeout!!\n", -+ __FILE__, __func__, __LINE__); -+ return; /* -EINVAL; */ -+ } -+ } -+ -+ WAIT_DES_DMA_READY(); -+ -+ DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes); -+#else -+ CRTCL_SECT_END; /* Sleep and wait for Rx finished */ -+ DEU_WAIT_EVENT(deu_priv->deu_thread_wait, DEU_EVENT, -+ deu_priv->deu_event_flags); -+ CRTCL_SECT_START; -+#endif -+ -+#endif /* dma mode */ -+ -+ if (mode > 0) { -+ *(u32 *) iv_arg = DEU_ENDIAN_SWAP(des->IVHR); -+ *((u32 *) iv_arg + 1) = DEU_ENDIAN_SWAP(des->IVLR); -+ }; -+ -+ CRTCL_SECT_END; -+} -+ -+/* definitions from linux/include/crypto.h: -+#define CRYPTO_TFM_MODE_ECB 0x00000001 -+#define CRYPTO_TFM_MODE_CBC 0x00000002 -+#define CRYPTO_TFM_MODE_CFB 0x00000004 -+#define CRYPTO_TFM_MODE_CTR 0x00000008 -+#define CRYPTO_TFM_MODE_OFB 0x00000010 -+but hardware definition: 0 ECB 1 CBC 2 OFB 3 CFB 4 CTR */ -+ -+/** \fn void deu_des(void *ctx_arg, u8 *out_arg, const u8 *in_arg, u8 *iv_arg, u32 nbytes, int encdec, int mode) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief main interface to DES hardware -+ * \param ctx_arg crypto algo context -+ * \param out_arg output bytestream -+ * \param in_arg input bytestream -+ * \param iv_arg initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param mode operation mode such as ebc, cbc -+*/ -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+static void deu_des(void *ctx_arg, -+ u8 *out_arg, -+ const u8 *in_arg, -+ u8 *iv_arg, -+ u32 nbytes, -+ int encdec, -+ int mode) -+{ -+ u32 remain = nbytes; -+ u32 inc; -+ -+ DPRINTF(0, "\n"); -+ -+ while (remain > 0) { -+ if (remain >= DEU_MAX_PACKET_SIZE) -+ inc = DEU_MAX_PACKET_SIZE; -+ else -+ inc = remain; -+ -+ remain -= inc; -+ -+ deu_des_core(ctx_arg, out_arg, in_arg, iv_arg, inc, encdec, -+ mode); -+ -+ out_arg += inc; -+ in_arg += inc; -+ } -+} -+#endif -+ -+/** \fn void deu_des_ecb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief sets DES hardware to ECB mode -+ * \param ctx crypto algo context -+ * \param dst output bytestream -+ * \param src input bytestream -+ * \param iv initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param inplace not used -+*/ -+ -+static void deu_des_ecb(void *ctx, -+ uint8_t *dst, -+ const uint8_t *src, -+ uint8_t *iv, -+ size_t nbytes, -+ int encdec, -+ int inplace) -+{ -+ DPRINTF(0, "ctx @%p\n", ctx); -+ deu_des(ctx, dst, src, NULL, nbytes, encdec, 0); -+} -+ -+/** \fn void deu_des_cbc(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief sets DES hardware to CBC mode -+ * \param ctx crypto algo context -+ * \param dst output bytestream -+ * \param src input bytestream -+ * \param iv initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param inplace not used -+*/ -+static void deu_des_cbc(void *ctx, -+ uint8_t *dst, -+ const uint8_t *src, -+ uint8_t *iv, -+ size_t nbytes, -+ int encdec, -+ int inplace) -+{ -+ DPRINTF(0, "ctx @%p\n", ctx); -+ deu_des(ctx, dst, src, iv, nbytes, encdec, 1); -+} -+ -+#if 0 -+/** \fn void deu_des_ofb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief sets DES hardware to OFB mode -+ * \param ctx crypto algo context -+ * \param dst output bytestream -+ * \param src input bytestream -+ * \param iv initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param inplace not used -+*/ -+static void deu_des_ofb(void *ctx, -+ uint8_t *dst, -+ const uint8_t *src, -+ uint8_t *iv, -+ size_t nbytes, -+ int encdec, -+ int inplace) -+{ -+ DPRINTF(0, "ctx @%p\n", ctx); -+ deu_des(ctx, dst, src, iv, nbytes, encdec, 2); -+} -+ -+/** \fn void deu_des_cfb(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) -+ \ingroup LQ_DES_FUNCTIONS -+ \brief sets DES hardware to CFB mode -+ \param ctx crypto algo context -+ \param dst output bytestream -+ \param src input bytestream -+ \param iv initialization vector -+ \param nbytes length of bytestream -+ \param encdec 1 for encrypt; 0 for decrypt -+ \param inplace not used -+*/ -+static void deu_des_cfb(void *ctx, -+ uint8_t *dst, -+ const uint8_t *src, -+ uint8_t *iv, -+ size_t nbytes, -+ int encdec, -+ int inplace) -+{ -+ DPRINTF(0, "ctx @%p\n", ctx); -+ deu_des(ctx, dst, src, iv, nbytes, encdec, 3); -+} -+ -+/** \fn void deu_des_ctr(void *ctx, uint8_t *dst, const uint8_t *src, uint8_t *iv, size_t nbytes, int encdec, int inplace) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief sets DES hardware to CTR mode -+ * \param ctx crypto algo context -+ * \param dst output bytestream -+ * \param src input bytestream -+ * \param iv initialization vector -+ * \param nbytes length of bytestream -+ * \param encdec 1 for encrypt; 0 for decrypt -+ * \param inplace not used -+*/ -+static void deu_des_ctr(void *ctx, -+ uint8_t *dst, -+ const uint8_t *src, -+ uint8_t *iv, -+ size_t nbytes, -+ int encdec, -+ int inplace) -+{ -+ DPRINTF(0, "ctx @%p\n", ctx); -+ deu_des(ctx, dst, src, iv, nbytes, encdec, 4); -+} -+#endif -+ -+/** \fn void des_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief encrypt DES_BLOCK_SIZE of data -+ * \param tfm linux crypto algo transform -+ * \param out output bytestream -+ * \param in input bytestream -+*/ -+static void des_encrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) -+{ -+ struct des_ctx *ctx = crypto_tfm_ctx(tfm); -+ DPRINTF(0, "ctx @%p\n", ctx); -+ deu_des(ctx, out, in, NULL, DES_BLOCK_SIZE, CRYPTO_DIR_ENCRYPT, 0); -+} -+ -+/** \fn void des_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief encrypt DES_BLOCK_SIZE of data -+ * \param tfm linux crypto algo transform -+ * \param out output bytestream -+ * \param in input bytestream -+*/ -+static void des_decrypt(struct crypto_tfm *tfm, uint8_t *out, const uint8_t *in) -+{ -+ struct des_ctx *ctx = crypto_tfm_ctx(tfm); -+ DPRINTF(0, "ctx @%p\n", ctx); -+ deu_des(ctx, out, in, NULL, DES_BLOCK_SIZE, CRYPTO_DIR_DECRYPT, 0); -+} -+ -+/* -+ * \brief RFC2451: -+ * -+ * For DES-EDE3, there is no known need to reject weak or -+ * complementation keys. Any weakness is obviated by the use of -+ * multiple keys. -+ * -+ * However, if the first two or last two independent 64-bit keys are -+ * equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the -+ * same as DES. Implementers MUST reject keys that exhibit this -+ * property. -+ * -+ */ -+ -+/** \fn int des3_ede_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief sets 3DES key -+ * \param tfm linux crypto algo transform -+ * \param key input key -+ * \param keylen key length -+*/ -+static int des3_ede_setkey(struct crypto_tfm *tfm, -+ const u8 *key, -+ unsigned int key_len) -+{ -+ struct des_ctx *ctx = crypto_tfm_ctx(tfm); -+ -+ DPRINTF(0, "ctx @%p, key_len %d\n", ctx, key_len); -+ -+ ctx->controlr_M = key_len / 8 + 1; /* 3DES EDE1 / EDE2 / EDE3 Mode */ -+ ctx->key_length = key_len; -+ -+ memcpy((u8 *)(ctx->expkey), key, key_len); -+ -+ return 0; -+} -+ -+/* -+ * \brief DES function mappings -+*/ -+static struct crypto_alg des_alg = { -+ .cra_name = "des", -+ .cra_driver_name = "lq_deu-des", -+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER, -+ .cra_blocksize = DES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct des_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_alignmask = 3, -+ .cra_list = LIST_HEAD_INIT(des_alg.cra_list), -+ .cra_u = { -+ .cipher = { -+ .cia_min_keysize = DES_KEY_SIZE, -+ .cia_max_keysize = DES_KEY_SIZE, -+ .cia_setkey = des_setkey, -+ .cia_encrypt = des_encrypt, -+ .cia_decrypt = des_decrypt -+ } -+ } -+}; -+ -+/* -+ * \brief DES function mappings -+*/ -+static struct crypto_alg des3_ede_alg = { -+ .cra_name = "des3_ede", -+ .cra_driver_name = "lq_deu-des3_ede", -+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER, -+ .cra_blocksize = DES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct des_ctx), -+ .cra_module = THIS_MODULE, -+ .cra_alignmask = 3, -+ .cra_list = LIST_HEAD_INIT(des3_ede_alg.cra_list), -+ .cra_u = { -+ .cipher = { -+ .cia_min_keysize = DES_KEY_SIZE, -+ .cia_max_keysize = DES_KEY_SIZE, -+ .cia_setkey = des3_ede_setkey, -+ .cia_encrypt = des_encrypt, -+ .cia_decrypt = des_decrypt -+ } -+ } -+}; -+ -+/** \fn int ecb_des_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief ECB DES encrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+*/ -+static int ecb_des_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ DPRINTF(0, "ctx @%p\n", ctx); -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ nbytes -= (nbytes % DES_BLOCK_SIZE); -+ deu_des_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ NULL, nbytes, CRYPTO_DIR_ENCRYPT, 0); -+ nbytes &= DES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/** \fn int ecb_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief ECB DES decrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+ * \return err -+*/ -+static int ecb_des_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ DPRINTF(0, "ctx @%p\n", ctx); -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ nbytes -= (nbytes % DES_BLOCK_SIZE); -+ deu_des_ecb(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ NULL, nbytes, CRYPTO_DIR_DECRYPT, 0); -+ nbytes &= DES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/* -+ * \brief DES function mappings -+*/ -+static struct crypto_alg ecb_des_alg = { -+ .cra_name = "ecb(des)", -+ .cra_driver_name = "lq_deu-ecb(des)", -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = DES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct des_ctx), -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = DES_KEY_SIZE, -+ .max_keysize = DES_KEY_SIZE, -+ .setkey = des_setkey, -+ .encrypt = ecb_des_encrypt, -+ .decrypt = ecb_des_decrypt, -+ } -+ } -+}; -+ -+/* -+ * \brief DES function mappings -+*/ -+static struct crypto_alg ecb_des3_ede_alg = { -+ .cra_name = "ecb(des3_ede)", -+ .cra_driver_name = "lq_deu-ecb(des3_ede)", -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = DES3_EDE_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct des_ctx), -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(ecb_des3_ede_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = DES3_EDE_KEY_SIZE, -+ .max_keysize = DES3_EDE_KEY_SIZE, -+ .setkey = des3_ede_setkey, -+ .encrypt = ecb_des_encrypt, -+ .decrypt = ecb_des_decrypt, -+ } -+ } -+}; -+ -+/** \fn int cbc_des_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief CBC DES encrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+ * \return err -+*/ -+static int cbc_des_encrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ DPRINTF(0, "ctx @%p\n", ctx); -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ u8 *iv = walk.iv; -+ /* printk("iv = %08x\n", *(u32 *)iv); */ -+ nbytes -= (nbytes % DES_BLOCK_SIZE); -+ deu_des_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ iv, nbytes, CRYPTO_DIR_ENCRYPT, 0); -+ nbytes &= DES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/** \fn int cbc_des_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief CBC DES decrypt using linux crypto blkcipher -+ * \param desc blkcipher descriptor -+ * \param dst output scatterlist -+ * \param src input scatterlist -+ * \param nbytes data size in bytes -+ * \return err -+*/ -+static int cbc_des_decrypt(struct blkcipher_desc *desc, -+ struct scatterlist *dst, -+ struct scatterlist *src, -+ unsigned int nbytes) -+{ -+ struct des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); -+ struct blkcipher_walk walk; -+ int err; -+ -+ DPRINTF(0, "ctx @%p\n", ctx); -+ -+ blkcipher_walk_init(&walk, dst, src, nbytes); -+ err = blkcipher_walk_virt(desc, &walk); -+ -+ while ((nbytes = walk.nbytes)) { -+ u8 *iv = walk.iv; -+ /* printk("iv = %08x\n", *(u32 *)iv); */ -+ nbytes -= (nbytes % DES_BLOCK_SIZE); -+ deu_des_cbc(ctx, walk.dst.virt.addr, walk.src.virt.addr, -+ iv, nbytes, CRYPTO_DIR_DECRYPT, 0); -+ nbytes &= DES_BLOCK_SIZE - 1; -+ err = blkcipher_walk_done(desc, &walk, nbytes); -+ } -+ -+ return err; -+} -+ -+/* -+ * \brief DES function mappings -+*/ -+static struct crypto_alg cbc_des_alg = { -+ .cra_name = "cbc(des)", -+ .cra_driver_name = "lq_deu-cbc(des)", -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = DES_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct des_ctx), -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = DES_KEY_SIZE, -+ .max_keysize = DES_KEY_SIZE, -+ .ivsize = DES_BLOCK_SIZE, -+ .setkey = des_setkey, -+ .encrypt = cbc_des_encrypt, -+ .decrypt = cbc_des_decrypt, -+ } -+ } -+}; -+ -+/* -+ * \brief DES function mappings -+*/ -+static struct crypto_alg cbc_des3_ede_alg = { -+ .cra_name = "cbc(des3_ede)", -+ .cra_driver_name = "lq_deu-cbc(des3_ede)", -+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, -+ .cra_blocksize = DES3_EDE_BLOCK_SIZE, -+ .cra_ctxsize = sizeof(struct des_ctx), -+ .cra_type = &crypto_blkcipher_type, -+ .cra_module = THIS_MODULE, -+ .cra_list = LIST_HEAD_INIT(cbc_des3_ede_alg.cra_list), -+ .cra_u = { -+ .blkcipher = { -+ .min_keysize = DES3_EDE_KEY_SIZE, -+ .max_keysize = DES3_EDE_KEY_SIZE, -+ .ivsize = DES_BLOCK_SIZE, -+ .setkey = des3_ede_setkey, -+ .encrypt = cbc_des_encrypt, -+ .decrypt = cbc_des_decrypt, -+ } -+ } -+}; -+ -+/** \fn int lq_deu_init_des(void) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief initialize des driver -+*/ -+int lq_deu_init_des(void) -+{ -+ int ret = 0; -+ -+ ret = crypto_register_alg(&des_alg); -+ if (ret < 0) -+ goto des_err; -+ -+ ret = crypto_register_alg(&ecb_des_alg); -+ if (ret < 0) -+ goto ecb_des_err; -+ -+ ret = crypto_register_alg(&cbc_des_alg); -+ if (ret < 0) -+ goto cbc_des_err; -+ -+ ret = crypto_register_alg(&des3_ede_alg); -+ if (ret < 0) -+ goto des3_ede_err; -+ -+ ret = crypto_register_alg(&ecb_des3_ede_alg); -+ if (ret < 0) -+ goto ecb_des3_ede_err; -+ -+ ret = crypto_register_alg(&cbc_des3_ede_alg); -+ if (ret < 0) -+ goto cbc_des3_ede_err; -+ -+ deu_des_chip_init(); -+ -+ CRTCL_SECT_INIT; -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ if (ALLOCATE_MEMORY(BUFFER_IN, DES_ALGO) < 0) { -+ printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n", -+ __FILE__, __func__, __LINE__); -+ goto cbc_des3_ede_err; -+ } -+ if (ALLOCATE_MEMORY(BUFFER_OUT, DES_ALGO) < 0) { -+ printk(KERN_ERR "[%s %s %d]: malloc memory fail!\n", -+ __FILE__, __func__, __LINE__); -+ goto cbc_des3_ede_err; -+ } -+#endif -+ -+ printk(KERN_NOTICE "Lantiq DEU DES initialized%s.\n", -+ disable_deudma ? "" : " (DMA)"); -+ return ret; -+ -+des_err: -+ crypto_unregister_alg(&des_alg); -+ printk(KERN_ERR "Lantiq des initialization failed!\n"); -+ -+ return ret; -+ -+ecb_des_err: -+ crypto_unregister_alg(&ecb_des_alg); -+ printk(KERN_ERR "Lantiq ecb_des initialization failed!\n"); -+ -+ return ret; -+ -+cbc_des_err: -+ crypto_unregister_alg(&cbc_des_alg); -+ printk(KERN_ERR "Lantiq cbc_des initialization failed!\n"); -+ -+ return ret; -+ -+des3_ede_err: -+ crypto_unregister_alg(&des3_ede_alg); -+ printk(KERN_ERR "Lantiq des3_ede initialization failed!\n"); -+ -+ return ret; -+ -+ecb_des3_ede_err: -+ crypto_unregister_alg(&ecb_des3_ede_alg); -+ printk(KERN_ERR "Lantiq ecb_des3_ede initialization failed!\n"); -+ -+ return ret; -+ -+cbc_des3_ede_err: -+ crypto_unregister_alg(&cbc_des3_ede_alg); -+ printk(KERN_ERR "Lantiq cbc_des3_ede initialization failed!\n"); -+ -+ return ret; -+} -+ -+/** \fn void lq_deu_fini_des(void) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief unregister des driver -+*/ -+void lq_deu_fini_des(void) -+{ -+ crypto_unregister_alg(&des_alg); -+ crypto_unregister_alg(&ecb_des_alg); -+ crypto_unregister_alg(&cbc_des_alg); -+ crypto_unregister_alg(&des3_ede_alg); -+ crypto_unregister_alg(&ecb_des3_ede_alg); -+ crypto_unregister_alg(&cbc_des3_ede_alg); -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ FREE_MEMORY(des_buff_in); -+ FREE_MEMORY(des_buff_out); -+#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA_DANUBE */ -+} -+ -+#endif ---- /dev/null -+++ b/drivers/crypto/lantiq/deu.c -@@ -0,0 +1,195 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file deu.c -+ \ingroup LQ_DEU -+ \brief main DEU driver file -+*/ -+ -+/** -+ \defgroup LQ_DEU_FUNCTIONS LQ_DEU_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief Lantiq DEU functions -+*/ -+ -+#include <linux/version.h> -+#if defined(CONFIG_MODVERSIONS) -+#define MODVERSIONS -+#include <linux/modversions.h> -+#endif -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/types.h> -+#include <linux/errno.h> -+#include <linux/crypto.h> -+#include <linux/proc_fs.h> -+#include <linux/fs.h> /* Stuff about file systems that we need */ -+#include <asm/byteorder.h> -+ -+#if 0 -+#ifdef CONFIG_SOC_LANTIQ_XWAY -+# include <lq_pmu.h> -+#endif -+#endif -+ -+#include "deu.h" -+ -+struct lq_crypto_priv lq_crypto_ops; -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+int disable_deudma = 0; -+#else -+int disable_deudma = 1; -+#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA */ -+ -+#ifdef CRYPTO_DEBUG -+char deu_debug_level = 3; -+#endif -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_MODULE -+# define STATIC static -+#else -+# define STATIC -+#endif -+ -+/** \fn static int lq_deu_init(void) -+ * \ingroup LQ_DEU_FUNCTIONS -+ * \brief link all modules that have been selected in kernel config for Lantiq HW crypto support -+ * \return ret -+*/ -+int lq_deu_init(void) -+{ -+ int ret = -ENOSYS; -+ u32 config; -+ -+ printk(KERN_INFO "Lantiq crypto hardware driver version %s\n", -+ LQ_DEU_DRV_VERSION); -+ -+ config = deu_chip_init(); -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ deu_dma_init(); -+#endif -+ -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_AES) -+ if(config & LQ_DEU_ID_AES) { -+ if ((ret = lq_deu_init_aes())) { -+ printk(KERN_ERR "Lantiq AES initialization failed!\n"); -+ } -+ } else { -+ printk(KERN_ERR "Lantiq AES not supported!\n"); -+ } -+#endif -+ -+#ifdef CONFIG_SOL_LANTIQ_XWAY -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_DES) -+ if(config & LQ_DEU_ID_DES) { -+ if ((ret = lq_deu_init_des())) { -+ printk(KERN_ERR "Lantiq DES initialization failed!\n"); -+ } -+ } else { -+ printk(KERN_ERR "Lantiq DES not supported!\n"); -+ } -+#endif -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_ARC4) && defined(CONFIG_CRYPTO_DEV_LANTIQ_DMA) -+ if ((ret = lq_deu_init_arc4())) { -+ printk(KERN_ERR "Lantiq ARC4 initialization failed!\n"); -+ } -+#endif -+#endif -+ -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1) -+ if(config & LQ_DEU_ID_HASH) { -+ if ((ret = lq_deu_init_sha1())) { -+ printk(KERN_ERR "Lantiq SHA1 initialization failed!\n"); -+ } -+ } else { -+ printk(KERN_ERR "Lantiq SHA1 not supported!\n"); -+ } -+#endif -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5) -+ if(config & LQ_DEU_ID_HASH) { -+ if ((ret = lq_deu_init_md5())) { -+ printk(KERN_ERR "Lantiq MD5 initialization failed!\n"); -+ } -+ } else { -+ printk(KERN_ERR "Lantiq MD5 not supported!\n"); -+ } -+#endif -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC) -+ if ((ret = lq_deu_init_sha1_hmac())) { -+ printk(KERN_ERR "Lantiq SHA1_HMAC initialization failed!\n"); -+ } -+#endif -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5_HMAC) -+ if ((ret = lq_deu_init_md5_hmac())) { -+ printk(KERN_ERR "Lantiq MD5_HMAC initialization failed!\n"); -+ } -+#endif -+ return ret; -+} -+ -+/** \fn static void lq_deu_fini(void) -+ * \ingroup LQ_DEU_FUNCTIONS -+ * \brief remove the loaded crypto algorithms -+*/ -+void lq_deu_exit(void) -+{ -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_AES) -+ lq_deu_fini_aes(); -+#endif -+#ifdef CONFIG_SOL_LANTIQ_XWAY -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_DES) -+ lq_deu_fini_des(); -+#endif -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_ARC4) \ -+ && defined(CONFIG_CRYPTO_DEV_LANTIQ_DMA) -+ lq_deu_fini_arc4(); -+#endif -+#endif -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1) -+ lq_deu_fini_sha1(); -+#endif -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5) -+ lq_deu_fini_md5(); -+#endif -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC) -+ lq_deu_fini_sha1_hmac(); -+#endif -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_MD5_HMAC) -+ lq_deu_fini_md5_hmac(); -+#endif -+ -+ printk("DEU has exited successfully\n"); -+ -+#if defined(CONFIG_CRYPTO_DEV_LANTIQ_DMA) -+ deu_dma_exit(); -+ printk("DMA has deregistered successfully\n"); -+#endif -+} -+ -+EXPORT_SYMBOL(lq_deu_init); -+EXPORT_SYMBOL(lq_deu_exit); ---- /dev/null -+++ b/drivers/crypto/lantiq/deu.h -@@ -0,0 +1,248 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file deu.h -+ \brief Main DEU driver header file -+*/ -+ -+/** -+ \defgroup LQ_DEU_DEFINITIONS LQ_DEU_DEFINITIONS -+ \ingroup LQ_DEU -+ \brief Lantiq DEU definitions -+*/ -+ -+ -+#ifndef DEU_H -+#define DEU_H -+ -+#undef CRYPTO_DEBUG -+ -+#define LQ_DEU_DRV_VERSION "1.0.1" -+ -+#if defined(CONFIG_LANTIQ_DANUBE) -+# include "deu_danube.h" -+#elif defined(CONFIG_LANTIQ_AR9) -+# include "deu_ar9.h" -+#elif defined(CONFIG_SOC_LANTIQ_FALCON) -+# include "deu_falcon.h" -+#else -+//# error "Unknown platform" -+# include "deu_danube.h" -+#endif -+ -+struct lq_crypto_priv { -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ u32 *des_buff_in; -+ u32 *des_buff_out; -+ u32 *aes_buff_in; -+ u32 *aes_buff_out; -+ -+ int (*dma_init)(void); -+ void (*dma_exit)(void); -+ u32 (*dma_align)(const u8 *, u32 *, int, int); -+ void (*aes_dma_memcpy)(u32 *, u32 *, u8 *, int); -+ void (*des_dma_memcpy)(u32 *, u32 *, u8 *, int); -+ int (*aes_dma_malloc)(int); -+ int (*des_dma_malloc)(int); -+ void (*dma_free)(u32 *); -+#endif -+ -+ u32 (*endian_swap)(u32); -+ u32 (*input_swap)(u32); -+ void (*aes_chip_init)(void); -+ void (*des_chip_init)(void); -+ u32 (*chip_init)(void); -+}; -+ -+extern struct lq_crypto_priv lq_crypto_ops; -+ -+#define LQ_DEU_ALIGNMENT 16 -+ -+#define PFX "lq_deu: " -+ -+#define LQ_DEU_CRA_PRIORITY 300 -+#define LQ_DEU_COMPOSITE_PRIORITY 400 -+ -+#define CRYPTO_DIR_ENCRYPT 1 -+#define CRYPTO_DIR_DECRYPT 0 -+ -+#define CRTCL_SECT_INIT spin_lock_init(&cipher_lock) -+#define CRTCL_SECT_START spin_lock_irqsave(&cipher_lock, flag) -+#define CRTCL_SECT_END spin_unlock_irqrestore(&cipher_lock, flag) -+ -+#define LQ_DEU_ID_REV 0x00001F -+#define LQ_DEU_ID_ID 0x00FF00 -+#define LQ_DEU_ID_DMA 0x010000 -+#define LQ_DEU_ID_HASH 0x020000 -+#define LQ_DEU_ID_AES 0x040000 -+#define LQ_DEU_ID_3DES 0x080000 -+#define LQ_DEU_ID_DES 0x100000 -+ -+extern int disable_deudma; -+ -+int lq_deu_init(void); -+void lq_deu_exit(void); -+ -+int lq_deu_init_des(void); -+int lq_deu_init_aes(void); -+int lq_deu_init_arc4(void); -+int lq_deu_init_sha1(void); -+int lq_deu_init_md5(void); -+int lq_deu_init_sha1_hmac(void); -+int lq_deu_init_md5_hmac(void); -+ -+void lq_deu_fini_des(void); -+void lq_deu_fini_aes(void); -+void lq_deu_fini_arc4(void); -+void lq_deu_fini_sha1(void); -+void lq_deu_fini_md5(void); -+void lq_deu_fini_sha1_hmac(void); -+void lq_deu_fini_md5_hmac(void); -+ -+/* board specific functions */ -+/* { */ -+static inline u32 deu_chip_init(void) -+{ -+ return lq_crypto_ops.chip_init(); -+} -+ -+static inline void deu_des_chip_init(void) -+{ -+ lq_crypto_ops.des_chip_init(); -+} -+ -+static inline void deu_aes_chip_init(void) -+{ -+ lq_crypto_ops.aes_chip_init(); -+} -+ -+static inline u32 deu_input_swap(u32 input) -+{ -+ return lq_crypto_ops.input_swap(input); -+} -+ -+static inline u32 deu_endian_swap(u32 input) -+{ -+ return lq_crypto_ops.endian_swap(input); -+} -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+static inline int deu_aes_dma_malloc(int value) -+{ -+ return lq_crypto_ops.aes_dma_malloc(value); -+} -+ -+static inline int deu_des_dma_malloc(int value) -+{ -+ return lq_crypto_ops.des_dma_malloc(value); -+} -+ -+static inline u32 *deu_dma_align(const u8 *arg, -+ u32 *buff_alloc, -+ int in_out, -+ int nbytes) -+{ -+ return lq_crypto_ops.dma_align(arg, buff_alloc, in_out, nbytes); -+} -+ -+static inline void deu_aes_dma_memcpy(u32 *outcopy, -+ u32 *out_dma, -+ u8 *out_arg, -+ int nbytes) -+{ -+ lq_crypto_ops.aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes); -+} -+ -+static inline void deu_des_dma_memcpy(u32 *outcopy, -+ u32 *out_dma, -+ u8 *out_arg, -+ int nbytes) -+{ -+ lq_crypto_ops.des_dma_memcpy(outcopy, out_dma, out_arg, nbytes); -+} -+ -+static inline void deu_dma_free(u32 *addr) -+{ -+ lq_crypto_ops.dma_free(addr); -+} -+ -+static inline int deu_dma_init(void) -+{ -+ lq_crypto_ops.dma_init(); -+} -+ -+static inline void deu_dma_exit(void) -+{ -+ lq_crypto_ops.dma_exit(); -+} -+#endif -+ -+/* } */ -+ -+#define DEU_WAKELIST_INIT(queue) \ -+ init_waitqueue_head(&queue) -+ -+#define DEU_WAIT_EVENT_TIMEOUT(queue, event, flags, timeout) \ -+ do { \ -+ wait_event_interruptible_timeout((queue), \ -+ test_bit((event), \ -+ &(flags)), (timeout)); \ -+ clear_bit((event), &(flags)); \ -+ }while (0) -+ -+ -+#define DEU_WAKEUP_EVENT(queue, event, flags) \ -+ do { \ -+ set_bit((event), &(flags)); \ -+ wake_up_interruptible(&(queue)); \ -+ }while (0) -+ -+#define DEU_WAIT_EVENT(queue, event, flags) \ -+ do { \ -+ wait_event_interruptible(queue, \ -+ test_bit((event), &(flags))); \ -+ clear_bit((event), &(flags)); \ -+ }while (0) -+ -+struct deu_drv_priv { -+ wait_queue_head_t deu_thread_wait; -+#define DEU_EVENT 1 -+ volatile long deu_event_flags; -+ u8 *deu_rx_buf; -+ u32 deu_rx_len; -+}; -+ -+#ifdef CRYPTO_DEBUG -+extern char deu_debug_level; -+# define DPRINTF(level, format, args...) \ -+ if (level < deu_debug_level) \ -+ printk(KERN_INFO "[%s %s %d]: " format, \ -+ __FILE__, __func__, __LINE__, ##args) -+#else -+# define DPRINTF(level, format, args...) do { } while(0) -+#endif -+ -+#endif /* DEU_H */ ---- /dev/null -+++ b/drivers/crypto/lantiq/deu_ar9.c -@@ -0,0 +1,327 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/types.h> -+#include <linux/errno.h> -+#include <asm/io.h> /* dma_cache_inv */ -+#include <linux/platform_device.h> -+ -+#ifdef CONFIG_SOC_LANTIQ_XWAY -+ -+#include "deu.h" -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file deu_ar9.c -+ \brief Lantiq DEU board specific driver file for ar9 -+*/ -+ -+/** -+ \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief board specific functions -+*/ -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+struct lq_deu_device lq_deu[1]; -+ -+static u8 *g_dma_page_ptr = NULL; -+static u8 *g_dma_block = NULL; -+static u8 *g_dma_block2 = NULL; -+ -+/** \fn int dma_init(void) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief Initialize DMA for DEU usage. DMA specific registers are -+ * intialized here, including a pointer to the device, memory -+ * space for the device and DEU-DMA descriptors -+ * \return -1: fail, 0: SUCCESS -+*/ -+static int dma_init(void) -+{ -+ volatile struct deu_dma *dma = (struct deu_dma *) LQ_DEU_DMA_CON; -+ struct dma_device_info *dma_device = NULL; -+ int i = 0; -+ -+ struct dma_device_info *deu_dma_device_ptr; -+ -+ /* get one free page and share between g_dma_block and g_dma_block2 */ -+ printk("PAGE_SIZE = %ld\n", PAGE_SIZE); -+ /* need 16-byte alignment memory block */ -+ g_dma_page_ptr = (u8 *)__get_free_page(GFP_KERNEL); -+ /* need 16-byte alignment memory block */ -+ g_dma_block = g_dma_page_ptr; -+ /* need 16-byte alignment memory block */ -+ g_dma_block2 = (u8 *)(g_dma_page_ptr + (PAGE_SIZE >> 1)); -+ -+ /* deu_dma_priv_init(); */ -+ -+ deu_dma_device_ptr = dma_device_reserve("DEU"); -+ if (!deu_dma_device_ptr) { -+ printk("DEU: reserve DMA fail!\n"); -+ return -1; -+ } -+ lq_deu[0].dma_device = deu_dma_device_ptr; -+ -+ dma_device = deu_dma_device_ptr; -+ /* dma_device->priv = &deu_dma_priv; */ -+ dma_device->buffer_alloc = &deu_dma_buffer_alloc; -+ dma_device->buffer_free = &deu_dma_buffer_free; -+ dma_device->intr_handler = &deu_dma_intr_handler; -+ -+ dma_device->tx_endianness_mode = LQ_DMA_ENDIAN_TYPE3; -+ dma_device->rx_endianness_mode = LQ_DMA_ENDIAN_TYPE3; -+ dma_device->port_num = 1; -+ dma_device->tx_burst_len = 2; -+ dma_device->rx_burst_len = 2; -+ dma_device->max_rx_chan_num = 1; -+ dma_device->max_tx_chan_num = 1; -+ dma_device->port_packet_drop_enable = 0; -+ -+ for (i = 0; i < dma_device->max_rx_chan_num; i++) { -+ dma_device->rx_chan[i]->packet_size = DEU_MAX_PACKET_SIZE; -+ dma_device->rx_chan[i]->desc_len = 1; -+ dma_device->rx_chan[i]->control = LQ_DMA_CH_ON; -+ dma_device->rx_chan[i]->byte_offset = 0; -+ dma_device->rx_chan[i]->chan_poll_enable = 1; -+ } -+ -+ for (i = 0; i < dma_device->max_tx_chan_num; i++) { -+ dma_device->tx_chan[i]->control = LQ_DMA_CH_ON; -+ dma_device->tx_chan[i]->desc_len = 1; -+ dma_device->tx_chan[i]->chan_poll_enable = 1; -+ } -+ -+ dma_device->current_tx_chan = 0; -+ dma_device->current_rx_chan = 0; -+ -+ i = dma_device_register(dma_device); -+ for (i = 0; i < dma_device->max_rx_chan_num; i++) { -+ (dma_device->rx_chan[i])->open(dma_device->rx_chan[i]); -+ } -+ -+ dma->ctrl.BS = 0; -+ dma->ctrl.RXCLS = 0; -+ dma->ctrl.EN = 1; -+ -+ return 0; -+} -+ -+/** \fn u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief Not used for AR9 -+ * \param arg Pointer to the input / output memory address -+ * \param buffer_alloc A pointer to the buffer -+ * \param in_buff Input (if == 1) or Output (if == 0) buffer -+ * \param nbytes Number of bytes of data -+*/ -+static u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes) -+{ -+ return (u32 *) arg; -+} -+ -+/** \fn void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief copy the DMA data to the memory address space for AES -+ * \param outcopy Not used -+ * \param out_dma A pointer to the memory address that stores the DMA data -+ * \param out_arg The pointer to the memory address that needs to be copied to] -+ * \param nbytes Number of bytes of data -+*/ -+static void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) -+{ -+ memcpy(out_arg, out_dma, nbytes); -+} -+ -+/** \fn void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief copy the DMA data to the memory address space for DES -+ * \param outcopy Not used -+ * \param out_dma A pointer to the memory address that stores the DMA data -+ * \param out_arg The pointer to the memory address that needs to be copied to] -+ * \param nbytes Number of bytes of data -+*/ -+static void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) -+{ -+ memcpy(out_arg, out_dma, nbytes); -+} -+ -+/** \fn dma_exit(void) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief unregister dma devices after exit -+*/ -+static void dma_exit(void) -+{ -+ if (g_dma_page_ptr) -+ free_page((u32) g_dma_page_ptr); -+ dma_device_release(lq_deu[0].dma_device); -+ dma_device_unregister(lq_deu[0].dma_device); -+} -+#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA */ -+ -+/** \fn u32 endian_swap(u32 input) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief Swap data given to the function -+ * \param input Data input to be swapped -+ * \return either the swapped data or the input data depending on whether it is in DMA mode or FPI mode -+*/ -+static u32 endian_swap(u32 input) -+{ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ u8 *ptr = (u8 *)&input; -+ return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]); -+#else -+ return input; -+#endif -+} -+ -+/** \fn u32 input_swap(u32 input) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief Not used -+ * \return input -+*/ -+static u32 input_swap(u32 input) -+{ -+ return input; -+} -+ -+/** \fn void aes_chip_init(void) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief initialize AES hardware -+*/ -+static void aes_chip_init(void) -+{ -+ volatile struct deu_aes *aes = (struct deu_aes *) AES_START; -+ -+ aes->ctrl.SM = 1; -+#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ aes->ctrl.ARS = 1; -+#else -+ aes->ctrl.NDC = 1; /* to write to ENDI */ -+ asm("sync"); -+ aes->ctrl.ENDI = 0; -+ asm("sync"); -+ aes->ctrl.ARS = 0; /* 0 for dma */ -+ asm("sync"); -+#endif -+} -+ -+/** \fn void des_chip_init(void) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief initialize DES hardware -+*/ -+static void des_chip_init(void) -+{ -+ volatile struct deu_des *des = (struct deu_des *) DES_3DES_START; -+ -+#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ /* start crypto engine with write to ILR */ -+ des->ctrl.SM = 1; -+ asm("sync"); -+ des->ctrl.ARS = 1; -+#else -+ des->ctrl.SM = 1; -+ des->ctrl.NDC = 1; -+ asm("sync"); -+ des->ctrl.ENDI = 0; -+ asm("sync"); -+ des->ctrl.ARS = 0; /* 0 for dma */ -+ -+#endif -+} -+ -+static u32 chip_init(void) -+{ -+ volatile struct deu_clk_ctrl *clc = (struct deu_clk_ctrl *) LQ_DEU_CLK; -+ -+#if 0 -+ lq_pmu_enable(1<<20); -+#endif -+ -+ clc->FSOE = 0; -+ clc->SBWE = 0; -+ clc->SPEN = 0; -+ clc->SBWE = 0; -+ clc->DISS = 0; -+ clc->DISR = 0; -+ -+ return *LQ_DEU_ID; -+} -+ -+static int lq_crypto_probe(struct platform_device *pdev) -+{ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ lq_crypto_ops.dma_init = dma_init; -+ lq_crypto_ops.dma_exit = dma_exit; -+ lq_crypto_ops.aes_dma_memcpy = aes_dma_memcpy; -+ lq_crypto_ops.des_dma_memcpy = des_dma_memcpy; -+ lq_crypto_ops.aes_dma_malloc = aes_dma_malloc; -+ lq_crypto_ops.des_dma_malloc = des_dma_malloc; -+ lq_crypto_ops.dma_align = dma_align; -+ lq_crypto_ops.dma_free = dma_free; -+#endif -+ -+ lq_crypto_ops.endian_swap = endian_swap; -+ lq_crypto_ops.input_swap = input_swap; -+ lq_crypto_ops.aes_chip_init = aes_chip_init; -+ lq_crypto_ops.des_chip_init = des_chip_init; -+ lq_crypto_ops.chip_init = chip_init; -+ -+ printk("lq_ar9_deu: driver loaded!\n"); -+ -+ lq_deu_init(); -+ -+ return 0; -+} -+ -+static int lq_crypto_remove(struct platform_device *pdev) -+{ -+ lq_deu_exit(); -+ -+ return 0; -+} -+ -+static struct platform_driver lq_crypto = { -+ .probe = lq_crypto_probe, -+ .remove = lq_crypto_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "lq_ar9_deu" -+ } -+}; -+ -+static int __init lq_crypto_init(void) -+{ -+ return platform_driver_register(&lq_crypto); -+} -+module_init(lq_crypto_init); -+ -+static void __exit lq_crypto_exit(void) -+{ -+ platform_driver_unregister(&lq_crypto); -+} -+module_exit(lq_crypto_exit); -+ -+#endif ---- /dev/null -+++ b/drivers/crypto/lantiq/deu_ar9.h -@@ -0,0 +1,291 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus / Infineon Technologies -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief DEU driver module -+*/ -+ -+/** -+ \defgroup LQ_DEU_DEFINITIONS LQ_DEU_DEFINITIONS -+ \ingroup LQ_DEU -+ \brief Lantiq DEU definitions -+*/ -+ -+/** -+ \file deu_ar9.h -+ \brief DEU driver header file -+*/ -+ -+ -+#ifndef DEU_AR9_H -+#define DEU_AR9_H -+ -+#define LQ_DEU_BASE_ADDR (KSEG1 | 0x1E103100) -+#define LQ_DEU_CLK ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0000)) -+#define LQ_DEU_ID ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0008)) -+#define LQ_DES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0010)) -+#define LQ_AES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0050)) -+#define LQ_HASH_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x00B0)) -+#define LQ_ARC4_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0100)) -+ -+#define ARC4_START LQ_ARC4_CON -+#define DES_3DES_START LQ_DES_CON -+#define HASH_START LQ_HASH_CON -+#define AES_START LQ_AES_CON -+ -+#ifdef CONFIG_CRYPTO_DEV_DMA -+# include "deu_dma.h" -+# define DEU_DWORD_REORDERING(ptr, buffer, in_out, bytes) \ -+ deu_dma_align(ptr, buffer, in_out, bytes) -+# define AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ -+ deu_aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes) -+# define DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ -+ deu_des_dma_memcpy(outcopy, out_dma, out_arg, nbytes) -+# define BUFFER_IN 1 -+# define BUFFER_OUT 0 -+# define AES_ALGO 1 -+# define DES_ALGO 0 -+# define ALLOCATE_MEMORY(val, type) 1 -+# define FREE_MEMORY(buff) -+extern struct lq_deu_device lq_deu[1]; -+#endif /* CONFIG_CRYPTO_DEV_DMA */ -+ -+/* SHA CONSTANTS */ -+#define HASH_CON_VALUE 0x0700002C -+ -+#define INPUT_ENDIAN_SWAP(input) deu_input_swap(input) -+#define DEU_ENDIAN_SWAP(input) deu_endian_swap(input) -+#define DELAY_PERIOD 10 -+#define FIND_DEU_CHIP_VERSION chip_version() -+ -+#define WAIT_AES_DMA_READY() \ -+ do { \ -+ int i; \ -+ volatile struct deu_dma *dma = \ -+ (struct deu_dma *) LQ_DEU_DMA_CON; \ -+ volatile struct deu_aes *aes = \ -+ (volatile struct deu_aes *) AES_START; \ -+ for (i = 0; i < 10; i++) \ -+ udelay(DELAY_PERIOD); \ -+ while (dma->ctrl.BSY) {}; \ -+ while (aes->ctrl.BUS) {}; \ -+ } while (0) -+ -+#define WAIT_DES_DMA_READY() \ -+ do { \ -+ int i; \ -+ volatile struct deu_dma *dma = \ -+ (struct deu_dma *) LQ_DEU_DMA_CON; \ -+ volatile struct deu_des *des = \ -+ (struct deu_des *) DES_3DES_START; \ -+ for (i = 0; i < 10; i++) \ -+ udelay(DELAY_PERIOD); \ -+ while (dma->ctrl.BSY) {}; \ -+ while (des->ctrl.BUS) {}; \ -+ } while (0) -+ -+#define AES_DMA_MISC_CONFIG() \ -+ do { \ -+ volatile struct deu_aes *aes = \ -+ (volatile struct deu_aes *) AES_START; \ -+ aes->ctrl.KRE = 1; \ -+ aes->ctrl.GO = 1; \ -+ } while(0) -+ -+#define SHA_HASH_INIT \ -+ do { \ -+ volatile struct deu_hash *hash = \ -+ (struct deu_hash *) HASH_START; \ -+ hash->ctrl.SM = 1; \ -+ hash->ctrl.ALGO = 0; \ -+ hash->ctrl.INIT = 1; \ -+ } while(0) -+ -+/* DEU Common Structures for AR9*/ -+ -+struct deu_clk_ctrl { -+ u32 Res:26; -+ u32 FSOE:1; -+ u32 SBWE:1; -+ u32 EDIS:1; -+ u32 SPEN:1; -+ u32 DISS:1; -+ u32 DISR:1; -+}; -+ -+struct deu_des { -+ struct deu_des_ctrl { /* 10h */ -+ u32 KRE:1; -+ u32 reserved1:5; -+ u32 GO:1; -+ u32 STP:1; -+ u32 Res2:6; -+ u32 NDC:1; -+ u32 ENDI:1; -+ u32 Res3:2; -+ u32 F:3; -+ u32 O:3; -+ u32 BUS:1; -+ u32 DAU:1; -+ u32 ARS:1; -+ u32 SM:1; -+ u32 E_D:1; -+ u32 M:3; -+ } ctrl; -+ -+ u32 IHR; /* 14h */ -+ u32 ILR; /* 18h */ -+ u32 K1HR; /* 1c */ -+ u32 K1LR; -+ u32 K2HR; -+ u32 K2LR; -+ u32 K3HR; -+ u32 K3LR; /* 30h */ -+ u32 IVHR; /* 34h */ -+ u32 IVLR; /* 38 */ -+ u32 OHR; /* 3c */ -+ u32 OLR; /* 40 */ -+}; -+ -+struct deu_aes { -+ struct deu_aes_ctrl { -+ u32 KRE:1; -+ u32 reserved1:4; -+ u32 PNK:1; -+ u32 GO:1; -+ u32 STP:1; -+ u32 reserved2:6; -+ u32 NDC:1; -+ u32 ENDI:1; -+ u32 reserved3:2; -+ u32 F:3; /* fbs */ -+ u32 O:3; /* om */ -+ u32 BUS:1; /* bsy */ -+ u32 DAU:1; -+ u32 ARS:1; -+ u32 SM:1; -+ u32 E_D:1; -+ u32 KV:1; -+ u32 K:2; /* KL */ -+ } ctrl; -+ -+ u32 ID3R; /* 80h */ -+ u32 ID2R; /* 84h */ -+ u32 ID1R; /* 88h */ -+ u32 ID0R; /* 8Ch */ -+ u32 K7R; /* 90h */ -+ u32 K6R; /* 94h */ -+ u32 K5R; /* 98h */ -+ u32 K4R; /* 9Ch */ -+ u32 K3R; /* A0h */ -+ u32 K2R; /* A4h */ -+ u32 K1R; /* A8h */ -+ u32 K0R; /* ACh */ -+ u32 IV3R; /* B0h */ -+ u32 IV2R; /* B4h */ -+ u32 IV1R; /* B8h */ -+ u32 IV0R; /* BCh */ -+ u32 OD3R; /* D4h */ -+ u32 OD2R; /* D8h */ -+ u32 OD1R; /* DCh */ -+ u32 OD0R; /* E0h */ -+}; -+ -+struct deu_arc4 { -+ struct arc4_controlr { -+ u32 KRE:1; -+ u32 KLEN:4; -+ u32 KSAE:1; -+ u32 GO:1; -+ u32 STP:1; -+ u32 reserved1:6; -+ u32 NDC:1; -+ u32 ENDI:1; -+ u32 reserved2:8; -+ u32 BUS:1; /* bsy */ -+ u32 reserved3:1; -+ u32 ARS:1; -+ u32 SM:1; -+ u32 reserved4:4; -+ } ctrl; -+ -+ u32 K3R; /* 104h */ -+ u32 K2R; /* 108h */ -+ u32 K1R; /* 10Ch */ -+ u32 K0R; /* 110h */ -+ u32 IDLEN; /* 114h */ -+ u32 ID3R; /* 118h */ -+ u32 ID2R; /* 11Ch */ -+ u32 ID1R; /* 120h */ -+ u32 ID0R; /* 124h */ -+ u32 OD3R; /* 128h */ -+ u32 OD2R; /* 12Ch */ -+ u32 OD1R; /* 130h */ -+ u32 OD0R; /* 134h */ -+}; -+ -+struct deu_hash { -+ struct deu_hash_ctrl { -+ u32 reserved1:5; -+ u32 KHS:1; -+ u32 GO:1; -+ u32 INIT:1; -+ u32 reserved2:6; -+ u32 NDC:1; -+ u32 ENDI:1; -+ u32 reserved3:7; -+ u32 DGRY:1; -+ u32 BSY:1; -+ u32 reserved4:1; -+ u32 IRCL:1; -+ u32 SM:1; -+ u32 KYUE:1; -+ u32 HMEN:1; -+ u32 SSEN:1; -+ u32 ALGO:1; -+ } ctrl; -+ -+ u32 MR; /* B4h */ -+ u32 D1R; /* B8h */ -+ u32 D2R; /* BCh */ -+ u32 D3R; /* C0h */ -+ u32 D4R; /* C4h */ -+ u32 D5R; /* C8h */ -+ u32 dummy; /* CCh */ -+ u32 KIDX; /* D0h */ -+ u32 KEY; /* D4h */ -+ u32 DBN; /* D8h */ -+}; -+ -+struct deu_dma { -+ struct deu_dma_ctrl { -+ u32 reserved1:22; -+ u32 BS:2; -+ u32 BSY:1; -+ u32 reserved2:1; -+ u32 ALGO:2; -+ u32 RXCLS:2; -+ u32 reserved3:1; -+ u32 EN:1; -+ } ctrl; -+}; -+ -+#endif /* DEU_AR9_H */ ---- /dev/null -+++ b/drivers/crypto/lantiq/deu_danube.c -@@ -0,0 +1,484 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/types.h> -+#include <linux/errno.h> -+#include <asm/io.h> /* dma_cache_inv */ -+#include <linux/platform_device.h> -+ -+#ifdef CONFIG_SOC_LANTIQ_XWAY -+ -+#include "deu.h" -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief DEU driver module -+*/ -+ -+/** -+ \file deu_danube.c -+ \ingroup LQ_DEU -+ \brief board specific DEU driver file for danube -+*/ -+ -+/** -+ \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief board specific DEU functions -+*/ -+ -+static int danube_pre_1_4; -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+u32 *des_buff_in = NULL; -+u32 *des_buff_out = NULL; -+u32 *aes_buff_in = NULL; -+u32 *aes_buff_out = NULL; -+ -+struct lq_deu_device lq_deu[1]; -+ -+static u8 *g_dma_page_ptr = NULL; -+static u8 *g_dma_block = NULL; -+static u8 *g_dma_block2 = NULL; -+ -+/** \fn int dma_init(void) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief Initialize DMA for DEU usage. DMA specific registers are -+ * intialized here, including a pointer to the device, memory -+ * space for the device and DEU-DMA descriptors -+ * \return -1 if fail, otherwise return 0 -+*/ -+static int dma_init(void) -+{ -+ struct dma_device_info *dma_device = NULL; -+ int i = 0; -+ volatile struct deu_dma *dma = (struct deu_dma *) LQ_DEU_DMA_CON; -+ struct dma_device_info *deu_dma_device_ptr; -+ -+ /* get one free page and share between g_dma_block and g_dma_block2 */ -+ printk("PAGE_SIZE = %ld\n", PAGE_SIZE); -+ /* need 16-byte alignment memory block */ -+ g_dma_page_ptr = (u8 *)__get_free_page(GFP_KERNEL); -+ /* need 16-byte alignment memory block */ -+ g_dma_block = g_dma_page_ptr; -+ /* need 16-byte alignment memory block */ -+ g_dma_block2 = (u8 *)(g_dma_page_ptr + (PAGE_SIZE >> 1)); -+ -+ deu_dma_device_ptr = dma_device_reserve("DEU"); -+ if (!deu_dma_device_ptr) { -+ printk("DEU: reserve DMA fail!\n"); -+ return -1; -+ } -+ lq_deu[0].dma_device = deu_dma_device_ptr; -+ dma_device = deu_dma_device_ptr; -+ /* dma_device->priv = &deu_dma_priv; */ -+ dma_device->buffer_alloc = &deu_dma_buffer_alloc; -+ dma_device->buffer_free = &deu_dma_buffer_free; -+ dma_device->intr_handler = &deu_dma_intr_handler; -+ dma_device->tx_endianness_mode = LQ_DMA_ENDIAN_TYPE3; -+ dma_device->rx_endianness_mode = LQ_DMA_ENDIAN_TYPE3; -+ dma_device->port_num = 1; -+ dma_device->tx_burst_len = 4; -+ dma_device->max_rx_chan_num = 1; -+ dma_device->max_tx_chan_num = 1; -+ dma_device->port_packet_drop_enable = 0; -+ -+ for (i = 0; i < dma_device->max_rx_chan_num; i++) { -+ dma_device->rx_chan[i]->packet_size = DEU_MAX_PACKET_SIZE; -+ dma_device->rx_chan[i]->desc_len = 1; -+ dma_device->rx_chan[i]->control = LQ_DMA_CH_ON; -+ dma_device->rx_chan[i]->byte_offset = 0; -+ dma_device->rx_chan[i]->chan_poll_enable = 1; -+ -+ } -+ -+ for (i = 0; i < dma_device->max_tx_chan_num; i++) { -+ dma_device->tx_chan[i]->control = LQ_DMA_CH_ON; -+ dma_device->tx_chan[i]->desc_len = 1; -+ dma_device->tx_chan[i]->chan_poll_enable = 1; -+ } -+ -+ dma_device->current_tx_chan = 0; -+ dma_device->current_rx_chan = 0; -+ -+ dma_device_register(dma_device); -+ for (i = 0; i < dma_device->max_rx_chan_num; i++) { -+ (dma_device->rx_chan[i])->open(dma_device->rx_chan[i]); -+ } -+ -+ dma->ctrl.BS = 0; -+ dma->ctrl.RXCLS = 0; -+ dma->ctrl.EN = 1; -+ -+ -+ *LQ_DMA_PS = 1; -+ -+ /* DANUBE PRE 1.4 SOFTWARE FIX */ -+ if (danube_pre_1_4) -+ *LQ_DMA_PCTRL = 0x14; -+ else -+ *LQ_DMA_PCTRL = 0xF14; -+ -+ return 0; -+} -+ -+/** \fn u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief A fix to align mis-aligned address for Danube version 1.3 chips -+ * which has memory alignment issues. -+ * \param arg Pointer to the input / output memory address -+ * \param buffer_alloc A pointer to the buffer -+ * \param in_buff Input (if == 1) or Output (if == 0) buffer -+ * \param nbytes Number of bytes of data -+ * \return returns arg: if address is aligned, buffer_alloc: if memory address is not aligned -+*/ -+static u32 *dma_align(const u8 *arg, u32 *buffer_alloc, int in_buff, int nbytes) -+{ -+ if (danube_pre_1_4) { -+ /* for input buffer */ -+ if (in_buff) { -+ if (((u32) arg) & 0xF) { -+ memcpy(buffer_alloc, arg, nbytes); -+ return (u32 *) buffer_alloc; -+ } else { -+ return (u32 *) arg; -+ } -+ } -+ else { -+ /* for output buffer */ -+ if (((u32) arg) & 0x3) -+ return buffer_alloc; -+ else -+ return (u32 *) arg; -+ } -+ } -+ -+ return (u32 *) arg; -+} -+ -+/** \fn void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief copy the DMA data to the memory address space for AES. The swaping -+ * of the 4 bytes is done only for Danube version 1.3 (FIX). Otherwise, -+ * it is a direct memory copy to out_arg pointer -+ * \param outcopy Pointer to the address to store swapped copy -+ * \param out_dma A pointer to the memory address that stores the DMA data -+ * \param out_arg The pointer to the memory address that needs to be copied to -+ * \param nbytes Number of bytes of data -+*/ -+static void aes_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) -+{ -+ int i = 0; -+ int x = 0; -+ -+ /* DANUBE PRE 1.4 SOFTWARE FIX */ -+ if (danube_pre_1_4) { -+ for (i = 0; i < (nbytes / 4); i++) { -+ x = i ^ 0x3; -+ outcopy[i] = out_dma[x]; -+ -+ } -+ if (((u32) out_arg) & 0x3) { -+ memcpy((u8 *)out_arg, outcopy, nbytes); -+ } -+ } else { -+ memcpy(out_arg, out_dma, nbytes); -+ } -+} -+ -+/** \fn void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief copy the DMA data to the memory address space for DES. The swaping -+ * of the 4 bytes is done only for Danube version 1.3 (FIX). Otherwise, -+ * it is a direct memory copy to out_arg pointer -+ * \param outcopy Pointer to the address to store swapped copy -+ * \param out_dma A pointer to the memory address that stores the DMA data -+ * \param out_arg The pointer to the memory address that needs to be copied to -+ * \param nbytes Number of bytes of data -+*/ -+static void des_dma_memcpy(u32 *outcopy, u32 *out_dma, u8 *out_arg, int nbytes) -+{ -+ int i = 0; -+ int x = 0; -+ -+ /* DANUBE PRE 1.4 SOFTWARE FIX */ -+ if (danube_pre_1_4) { -+ for (i = 0; i < (nbytes / 4); i++) { -+ x = i ^ 1; -+ outcopy[i] = out_dma[x]; -+ -+ } -+ if (((u32) out_arg) & 0x3) { -+ memcpy((u8 *)out_arg, outcopy, nbytes); -+ } -+ } else { -+ memcpy(out_arg, out_dma, nbytes); -+ } -+} -+ -+/** \fn int des_dma_malloc(int value) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief allocates memory to the necessary memory input/output buffer -+ * location, used during the DES algorithm DMA transfer (memory -+ * alignment issues) -+ * \param value value determinds whether the calling of the function is for a -+ * input buffer or for an output buffer memory allocation -+*/ -+static int des_dma_malloc(int value) -+{ -+ if (danube_pre_1_4) { -+ if (value == BUFFER_IN) { -+ des_buff_in = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC); -+ if (!des_buff_in) -+ return -1; -+ else -+ return 0; -+ } -+ else { -+ des_buff_out = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC); -+ if (!des_buff_out) -+ return -1; -+ else -+ return 0; -+ } -+ } else { -+ return 0; -+ } -+} -+ -+/** \fn int aes_dma_malloc(int value) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief allocates memory to the necessary memory input/output buffer -+ * location, used during the AES algorithm DMA transfer (memory -+ * alignment issues) -+ * \param value value determinds whether the calling of the function is for a -+ * input buffer or for an output buffer memory allocation -+*/ -+static int aes_dma_malloc(int value) -+{ -+ if (danube_pre_1_4) { -+ if (value == BUFFER_IN) { -+ aes_buff_in = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC); -+ if (!aes_buff_in) -+ return -1; -+ else -+ return 0; -+ } -+ else { -+ aes_buff_out = kmalloc(DEU_MAX_PACKET_SIZE, GFP_ATOMIC); -+ if (!aes_buff_out) -+ return -1; -+ else -+ return 0; -+ } -+ } else { -+ return 0; -+ } -+} -+ -+/** \fn void dma_free(u32 *addr) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief frees previously allocated memory -+ * \param addr memory address of the buffer that needs to be freed -+*/ -+static void dma_free(u32 *addr) -+{ -+ if (addr) -+ kfree(addr); -+ return; -+} -+ -+/** \fn dma_exit(void) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief unregister dma devices after exit -+*/ -+static void dma_exit(void) -+{ -+ if (g_dma_page_ptr) -+ free_page((u32) g_dma_page_ptr); -+ dma_device_release(lq_deu[0].dma_device); -+ dma_device_unregister(lq_deu[0].dma_device); -+} -+#endif /* CONFIG_CRYPTO_DEV_LANTIQ_DMA */ -+ -+/** \fn u32 endian_swap(u32 input) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief function is not used -+ * \param input Data input to be swapped -+ * \return input -+*/ -+static u32 endian_swap(u32 input) -+{ -+ return input; -+} -+ -+/** \fn u32 input_swap(u32 input) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief Swap the input data if the current chip is Danube version -+ * 1.4 and do nothing to the data if the current chip is -+ * Danube version 1.3 -+ * \param input data that needs to be swapped -+ * \return input or swapped input -+*/ -+static u32 input_swap(u32 input) -+{ -+ if (!danube_pre_1_4) { -+ u8 *ptr = (u8 *)&input; -+ return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]); -+ } else { -+ return input; -+ } -+} -+ -+/** \fn void aes_chip_init(void) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief initialize AES hardware -+*/ -+static void aes_chip_init(void) -+{ -+ volatile struct deu_aes *aes = (struct deu_aes *) AES_START; -+ -+#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ /* start crypto engine with write to ILR */ -+ aes->ctrl.SM = 1; -+ aes->ctrl.ARS = 1; -+#else -+ aes->ctrl.SM = 1; -+ aes->ctrl.ARS = 1; /* 0 for dma */ -+#endif -+} -+ -+/** \fn void des_chip_init(void) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief initialize DES hardware -+*/ -+static void des_chip_init(void) -+{ -+ volatile struct deu_des *des = (struct deu_des *) DES_3DES_START; -+ -+#ifndef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ /* start crypto engine with write to ILR */ -+ des->ctrl.SM = 1; -+ des->ctrl.ARS = 1; -+#else -+ des->ctrl.SM = 1; -+ des->ctrl.ARS = 1; /* 0 for dma */ -+#endif -+} -+ -+/** \fn void deu_chip_version(void) -+ * \ingroup LQ_DES_FUNCTIONS -+ * \brief To find the version of the chip by looking at the chip ID -+ * \param danube_pre_1_4 (sets to 1 if Chip is Danube less than v1.4) -+*/ -+static void deu_chip_version(void) -+{ -+ /* DANUBE PRE 1.4 SOFTWARE FIX */ -+ int chip_id = 0; -+ chip_id = *LQ_MPS_CHIPID; -+ chip_id >>= 28; -+ -+ if (chip_id >= 4) { -+ danube_pre_1_4 = 0; -+ printk("Danube Chip ver. 1.4 detected. \n"); -+ } -+ else { -+ danube_pre_1_4 = 1; -+ printk("Danube Chip ver. 1.3 or below detected. \n"); -+ } -+} -+ -+static u32 chip_init(void) -+{ -+ volatile struct deu_clk_ctrl *clc = (struct deu_clk_ctrl *) LQ_DEU_CLK; -+ -+#if 0 -+ lq_pmu_enable(1<<20); -+#endif -+ -+ deu_chip_version(); -+ -+ clc->FSOE = 0; -+ clc->SBWE = 0; -+ clc->SPEN = 0; -+ clc->SBWE = 0; -+ clc->DISS = 0; -+ clc->DISR = 0; -+ -+ return *LQ_DEU_ID; -+} -+ -+static int lq_crypto_probe(struct platform_device *pdev) -+{ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ lq_crypto_ops.dma_init = dma_init; -+ lq_crypto_ops.dma_exit = dma_exit; -+ lq_crypto_ops.aes_dma_memcpy = aes_dma_memcpy; -+ lq_crypto_ops.des_dma_memcpy = des_dma_memcpy; -+ lq_crypto_ops.aes_dma_malloc = aes_dma_malloc; -+ lq_crypto_ops.des_dma_malloc = des_dma_malloc; -+ lq_crypto_ops.dma_align = dma_align; -+ lq_crypto_ops.dma_free = dma_free; -+#endif -+ -+ lq_crypto_ops.endian_swap = endian_swap; -+ lq_crypto_ops.input_swap = input_swap; -+ lq_crypto_ops.aes_chip_init = aes_chip_init; -+ lq_crypto_ops.des_chip_init = des_chip_init; -+ lq_crypto_ops.chip_init = chip_init; -+ -+ printk("lq_danube_deu: driver loaded!\n"); -+ -+ lq_deu_init(); -+ -+ return 0; -+} -+ -+static int lq_crypto_remove(struct platform_device *pdev) -+{ -+ lq_deu_exit(); -+ -+ return 0; -+} -+ -+static struct platform_driver lq_crypto = { -+ .probe = lq_crypto_probe, -+ .remove = lq_crypto_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "lq_danube_deu" -+ } -+}; -+ -+static int __init lq_crypto_init(void) -+{ -+ return platform_driver_register(&lq_crypto); -+} -+module_init(lq_crypto_init); -+ -+static void __exit lq_crypto_exit(void) -+{ -+ platform_driver_unregister(&lq_crypto); -+} -+module_exit(lq_crypto_exit); -+ -+#endif ---- /dev/null -+++ b/drivers/crypto/lantiq/deu_danube.h -@@ -0,0 +1,255 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus / Infineon Technologies -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief DEU driver module -+*/ -+ -+/** -+ \file deu_danube.h -+ \brief board specific driver header file for danube -+*/ -+ -+/** -+ \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief board specific DEU header files -+*/ -+ -+#ifndef DEU_DANUBE_H -+#define DEU_DANUBE_H -+ -+#define LQ_DEU_BASE_ADDR (KSEG1 | 0x1E103100) -+#define LQ_DEU_CLK ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0000)) -+#define LQ_DEU_ID ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0008)) -+#define LQ_DES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0010)) -+#define LQ_AES_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0050)) -+#define LQ_HASH_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x00B0)) -+#define LQ_ARC4_CON ((volatile u32 *)(LQ_DEU_BASE_ADDR + 0x0100)) -+ -+#define ARC4_START LQ_ARC4_CON -+#define DES_3DES_START LQ_DES_CON -+#define HASH_START LQ_HASH_CON -+#define AES_START LQ_AES_CON -+ -+#define LQ_MPS (KSEG1 | 0x1F107000) -+#define LQ_MPS_CHIPID ((volatile u32*)(LQ_MPS + 0x0344)) -+#define LQ_MPS_CHIPID_VERSION_GET(value) (((value) >> 28) & 0xF) -+#define LQ_MPS_CHIPID_VERSION_SET(value) (((value) & 0xF) << 28) -+#define LQ_MPS_CHIPID_PARTNUM_GET(value) (((value) >> 12) & 0xFFFF) -+#define LQ_MPS_CHIPID_PARTNUM_SET(value) (((value) & 0xFFFF) << 12) -+#define LQ_MPS_CHIPID_MANID_GET(value) (((value) >> 1) & 0x7FF) -+#define LQ_MPS_CHIPID_MANID_SET(value) (((value) & 0x7FF) << 1) -+ -+#ifdef CONFIG_CRYPTO_DEV_DMA -+# define DEU_DWORD_REORDERING(ptr, buffer, in_out, bytes) \ -+ deu_dma_align(ptr, buffer, in_out, bytes) -+# define AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ -+ deu_aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes) -+# define DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ -+ deu_des_dma_memcpy(outcopy, out_dma, out_arg, nbytes) -+# define BUFFER_IN 1 -+# define BUFFER_OUT 0 -+# define DELAY_PERIOD 9 -+# define AES_ALGO 1 -+# define DES_ALGO 0 -+# define FREE_MEMORY(buff) deu_dma_free(buff) -+# define ALLOCATE_MEMORY(val, type) type ? \ -+ deu_aes_dma_malloc(val) : \ -+ deu_des_dma_malloc(val) -+#endif /* CONFIG_CRYPTO_DEV_DMA */ -+ -+#define INPUT_ENDIAN_SWAP(input) deu_input_swap(input) -+#define DEU_ENDIAN_SWAP(input) deu_endian_swap(input) -+#define AES_DMA_MISC_CONFIG() -+ -+#define WAIT_AES_DMA_READY() \ -+ do { \ -+ int i; \ -+ volatile struct deu_dma *dma = \ -+ (struct deu_dma *) LQ_DEU_DMA_CON; \ -+ volatile struct deu_aes *aes = \ -+ (volatile struct deu_aes *) AES_START; \ -+ for (i = 0; i < 10; i++) \ -+ udelay(DELAY_PERIOD); \ -+ while (dma->ctrl.BSY) {}; \ -+ while (aes->ctrl.BUS) {}; \ -+ } while (0) -+ -+#define WAIT_DES_DMA_READY() \ -+ do { \ -+ int i; \ -+ volatile struct deu_dma *dma = \ -+ (struct deu_dma *) LQ_DEU_DMA_CON; \ -+ volatile struct deu_des *des = \ -+ (struct deu_des *) DES_3DES_START; \ -+ for (i = 0; i < 10; i++) \ -+ udelay(DELAY_PERIOD); \ -+ while (dma->ctrl.BSY) {}; \ -+ while (des->ctrl.BUS) {}; \ -+ } while (0) -+ -+#define SHA_HASH_INIT \ -+ do { \ -+ volatile struct deu_hash *hash = \ -+ (struct deu_hash *) HASH_START; \ -+ hash->ctrl.SM = 1; \ -+ hash->ctrl.ALGO = 0; \ -+ hash->ctrl.INIT = 1; \ -+ } while(0) -+ -+/* DEU STRUCTURES */ -+ -+struct deu_clk_ctrl { -+ u32 Res:26; -+ u32 FSOE:1; -+ u32 SBWE:1; -+ u32 EDIS:1; -+ u32 SPEN:1; -+ u32 DISS:1; -+ u32 DISR:1; -+}; -+ -+struct deu_des { -+ struct deu_des_ctrl { -+ u32 KRE:1; -+ u32 reserved1:5; -+ u32 GO:1; -+ u32 STP:1; -+ u32 Res2:6; -+ u32 NDC:1; -+ u32 ENDI:1; -+ u32 Res3:2; -+ u32 F:3; -+ u32 O:3; -+ u32 BUS:1; -+ u32 DAU:1; -+ u32 ARS:1; -+ u32 SM:1; -+ u32 E_D:1; -+ u32 M:3; -+ } ctrl; -+ -+ u32 IHR; -+ u32 ILR; -+ u32 K1HR; -+ u32 K1LR; -+ u32 K2HR; -+ u32 K2LR; -+ u32 K3HR; -+ u32 K3LR; -+ u32 IVHR; -+ u32 IVLR; -+ u32 OHR; -+ u32 OLR; -+}; -+ -+struct deu_aes { -+ struct deu_aes_ctrl { -+ u32 KRE:1; -+ u32 reserved1:4; -+ u32 PNK:1; -+ u32 GO:1; -+ u32 STP:1; -+ u32 reserved2:6; -+ u32 NDC:1; -+ u32 ENDI:1; -+ u32 reserved3:2; -+ u32 F:3; /* fbs */ -+ u32 O:3; /* om */ -+ u32 BUS:1; /* bsy */ -+ u32 DAU:1; -+ u32 ARS:1; -+ u32 SM:1; -+ u32 E_D:1; -+ u32 KV:1; -+ u32 K:2; /* KL */ -+ } ctrl; -+ -+ u32 ID3R; /* 80h */ -+ u32 ID2R; /* 84h */ -+ u32 ID1R; /* 88h */ -+ u32 ID0R; /* 8Ch */ -+ u32 K7R; /* 90h */ -+ u32 K6R; /* 94h */ -+ u32 K5R; /* 98h */ -+ u32 K4R; /* 9Ch */ -+ u32 K3R; /* A0h */ -+ u32 K2R; /* A4h */ -+ u32 K1R; /* A8h */ -+ u32 K0R; /* ACh */ -+ u32 IV3R; /* B0h */ -+ u32 IV2R; /* B4h */ -+ u32 IV1R; /* B8h */ -+ u32 IV0R; /* BCh */ -+ u32 OD3R; /* D4h */ -+ u32 OD2R; /* D8h */ -+ u32 OD1R; /* DCh */ -+ u32 OD0R; /* E0h */ -+}; -+ -+struct deu_hash { -+ struct deu_hash_ctrl { -+ u32 reserved1:5; -+ u32 KHS:1; -+ u32 GO:1; -+ u32 INIT:1; -+ u32 reserved2:6; -+ u32 NDC:1; -+ u32 ENDI:1; -+ u32 reserved3:7; -+ u32 DGRY:1; -+ u32 BSY:1; -+ u32 reserved4:1; -+ u32 IRCL:1; -+ u32 SM:1; -+ u32 KYUE:1; -+ u32 HMEN:1; -+ u32 SSEN:1; -+ u32 ALGO:1; -+ } ctrl; -+ -+ u32 MR; /* B4h */ -+ u32 D1R; /* B8h */ -+ u32 D2R; /* BCh */ -+ u32 D3R; /* C0h */ -+ u32 D4R; /* C4h */ -+ u32 D5R; /* C8h */ -+ u32 dummy; /* CCh */ -+ u32 KIDX; /* D0h */ -+ u32 KEY; /* D4h */ -+ u32 DBN; /* D8h */ -+}; -+ -+struct deu_dma { -+ struct deu_dma_ctrl { -+ u32 reserved1:22; -+ u32 BS:2; -+ u32 BSY:1; -+ u32 reserved2:1; -+ u32 ALGO:2; -+ u32 RXCLS:2; -+ u32 reserved3:1; -+ u32 EN:1; -+ } ctrl; -+}; -+ -+#endif /* DEU_DANUBE_H */ ---- /dev/null -+++ b/drivers/crypto/lantiq/deu_dma.c -@@ -0,0 +1,147 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup LQ_API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file deu_dma.c -+ \ingroup LQ_DEU -+ \brief DMA DEU driver file -+*/ -+ -+/** -+ \defgroup LQ_DMA_FUNCTIONS LQ_DMA_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief DMA DEU driver functions -+*/ -+ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/types.h> -+#include <linux/errno.h> -+#include <linux/delay.h> -+#include <asm/io.h> -+#include "deu.h" -+#include "deu_dma.h" -+ -+/* extern struct deu_drv_priv deu_dma_priv; */ -+ -+/** \fn int deu_dma_intr_handler(struct dma_device_info *dma_dev, int status) -+ * \ingroup LQ_DMA_FUNCTIONS -+ * \brief callback function for DEU DMA interrupt -+ * \param dma_dev dma device -+ * \param status not used -+*/ -+int deu_dma_intr_handler(struct dma_device_info *dma_dev, int status) -+{ -+#if 0 -+ int len = 0; -+ while (len <= 20000) { len++; } -+ u8 *buf; -+ int len = 0; -+ -+ struct deu_drv_priv *deu_priv = (struct deu_drv_priv *)dma_dev->priv; -+ /* printk("status:%d \n",status); */ -+ switch(status) { -+ case RCV_INT: -+ len = dma_device_read(dma_dev, (u8 **)&buf, NULL); -+ if ( len != deu_priv->deu_rx_len) { -+ printk(KERN_ERR "%s packet length %d is not " -+ "equal to expect %d\n", -+ __func__, len, deu_priv->deu_rx_len); -+ return -1; -+ } -+ memcpy(deu_priv->deu_rx_buf, buf, deu_priv->deu_rx_len); -+ /* Reset for next usage */ -+ deu_priv->deu_rx_buf = NULL; -+ deu_priv->deu_rx_len = 0; -+ DEU_WAKEUP_EVENT(deu_priv->deu_thread_wait, DEU_EVENT, -+ deu_priv->deu_event_flags); -+ break; -+ case TX_BUF_FULL_INT: -+ /* delay for buffer to be cleared */ -+ while (len <= 20000) { len++; } -+ break; -+ -+ case TRANSMIT_CPT_INT: -+ break; -+ default: -+ break; -+ } -+#endif -+ return 0; -+} -+ -+extern u8 *g_dma_block; -+extern u8 *g_dma_block2; -+ -+/** \fn u8 *deu_dma_buffer_alloc(int len, int *byte_offset, void **opt) -+ * \ingroup LQ_DMA_FUNCTIONS -+ * \brief callback function for allocating buffers for dma receive descriptors -+ * \param len not used -+ * \param byte_offset dma byte offset -+ * \param *opt not used -+ * -+*/ -+u8 *deu_dma_buffer_alloc(int len, int *byte_offset, void **opt) -+{ -+ u8 *swap = NULL; -+ -+ /* dma-core needs at least 2 blocks of memory */ -+ swap = g_dma_block; -+ g_dma_block = g_dma_block2; -+ g_dma_block2 = swap; -+ -+ /* dma_cache_wback_inv((unsigned long) g_dma_block,(PAGE_SIZE >> 1)); */ -+ *byte_offset = 0; -+ -+ return g_dma_block; -+} -+ -+/** \fn int deu_dma_buffer_free(u8 * dataptr, void *opt) -+ * \ingroup LQ_DMA_FUNCTIONS -+ * \brief callback function for freeing dma transmit descriptors -+ * \param dataptr data pointer to be freed -+ * \param opt not used -+*/ -+int deu_dma_buffer_free(u8 *dataptr, void *opt) -+{ -+#if 0 -+ printk("Trying to free memory buffer\n"); -+ if (dataptr == NULL && opt == NULL) -+ return 0; -+ else if (opt == NULL) { -+ kfree(dataptr); -+ return 1; -+ } -+ else if (dataptr == NULL) { -+ kfree(opt); -+ return 1; -+ } -+ else { -+ kfree(opt); -+ kfree(dataptr); -+ } -+#endif -+ return 0; -+} ---- /dev/null -+++ b/drivers/crypto/lantiq/deu_dma.h -@@ -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 as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+/** -+ \addtogroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file deu_dma.h -+ \ingroup LQ_DEU -+ \brief DMA DEU driver header file -+*/ -+ -+#ifndef DEU_DMA_H -+#define DEU_DMA_H -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/mm.h> -+#include <linux/crypto.h> -+#include <asm/scatterlist.h> -+#include <asm/byteorder.h> -+#include <linux/skbuff.h> -+#include <linux/netdevice.h> -+ -+#include <asm/ifx/irq.h> -+#include <asm/ifx/ifx_dma_core.h> -+#ifndef CONFIG_CRYPTO_DEV_POLL_DMA -+# define CONFIG_CRYPTO_DEV_POLL_DMA -+#endif -+ -+/* must match the size of memory block allocated for -+ * g_dma_block and g_dma_block2 */ -+#define DEU_MAX_PACKET_SIZE (PAGE_SIZE >> 1) -+ -+struct lq_deu_device { -+ struct dma_device_info *dma_device; -+ u8 *dst; -+ u8 *src; -+ int len; -+ int dst_count; -+ int src_count; -+ int recv_count; -+ int packet_size; -+ int packet_num; -+ wait_queue_t wait; -+}; -+ -+extern struct lq_deu_device lq_deu[1]; -+ -+extern int deu_dma_intr_handler(struct dma_device_info *, int); -+extern u8 *deu_dma_buffer_alloc(int, int *, void **); -+extern int deu_dma_buffer_free(u8 *, void *); -+extern void deu_dma_inactivate_poll(struct dma_device_info* dma_dev); -+extern void deu_dma_activate_poll(struct dma_device_info* dma_dev); -+extern struct dma_device_info* deu_dma_reserve(struct dma_device_info** -+ dma_device); -+extern int deu_dma_release(struct dma_device_info** dma_device); -+ -+#endif /* IFMIPS_DEU_DMA_H */ ---- /dev/null -+++ b/drivers/crypto/lantiq/md5.c -@@ -0,0 +1,285 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file md5.c -+ \ingroup LQ_DEU -+ \brief MD5 encryption DEU driver file -+*/ -+ -+/** -+ \defgroup LQ_MD5_FUNCTIONS LQ_MD5_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief Lantiq DEU MD5 functions -+*/ -+ -+#include <crypto/internal/hash.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/string.h> -+#include <linux/crypto.h> -+#include <linux/types.h> -+#include <asm/byteorder.h> -+#include "deu.h" -+ -+#define MD5_DIGEST_SIZE 16 -+#define MD5_HMAC_BLOCK_SIZE 64 -+#define MD5_BLOCK_WORDS 16 -+#define MD5_HASH_WORDS 4 -+ -+static spinlock_t cipher_lock; -+ -+struct md5_ctx { -+ u32 hash[MD5_HASH_WORDS]; -+ u32 block[MD5_BLOCK_WORDS]; -+ u64 byte_count; -+}; -+ -+/** \fn static u32 md5_endian_swap(u32 input) -+ * \ingroup LQ_MD5_FUNCTIONS -+ * \brief perform dword level endian swap -+ * \param input value of dword that requires to be swapped -+*/ -+static u32 md5_endian_swap(u32 input) -+{ -+ u8 *ptr = (u8 *)&input; -+ -+ return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]); -+} -+ -+/** \fn static void md5_transform(u32 *hash, u32 const *in) -+ * \ingroup LQ_MD5_FUNCTIONS -+ * \brief main interface to md5 hardware -+ * \param hash current hash value -+ * \param in 64-byte block of input -+*/ -+static void md5_transform(u32 *hash, u32 const *in) -+{ -+ int i; -+ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; -+ ulong flag; -+ -+ CRTCL_SECT_START; -+ -+ for (i = 0; i < 16; i++) { -+ hashs->MR = md5_endian_swap(in[i]); -+ }; -+ -+ /* wait for processing */ -+ while (hashs->ctrl.BSY) { -+ /* this will not take long */ -+ } -+ -+ CRTCL_SECT_END; -+} -+ -+/** \fn static inline void md5_transform_helper(struct md5_ctx *ctx) -+ * \ingroup LQ_MD5_FUNCTIONS -+ * \brief interfacing function for md5_transform() -+ * \param ctx crypto context -+*/ -+static inline void md5_transform_helper(struct md5_ctx *ctx) -+{ -+ /* le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); */ -+ md5_transform(ctx->hash, ctx->block); -+} -+ -+/** \fn static void md5_init(struct crypto_tfm *tfm) -+ * \ingroup LQ_MD5_FUNCTIONS -+ * \brief initialize md5 hardware -+ * \param tfm linux crypto algo transform -+*/ -+static int md5_init(struct shash_desc *desc) -+{ -+ struct md5_ctx *mctx = shash_desc_ctx(desc); -+ volatile struct deu_hash *hash = (struct deu_hash *) HASH_START; -+ -+ hash->ctrl.SM = 1; -+ hash->ctrl.ALGO = 1; /* 1 = md5 0 = sha1 */ -+ hash->ctrl.INIT = 1; /* Initialize the hash operation by writing -+ a '1' to the INIT bit. */ -+ -+ mctx->byte_count = 0; -+ -+ return 0; -+} -+ -+/** \fn static void md5_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) -+ * \ingroup LQ_MD5_FUNCTIONS -+ * \brief on-the-fly md5 computation -+ * \param tfm linux crypto algo transform -+ * \param data input data -+ * \param len size of input data -+*/ -+static int md5_update(struct shash_desc *desc, const u8 *data, unsigned int len) -+{ -+ struct md5_ctx *mctx = shash_desc_ctx(desc); -+ const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); -+ -+ mctx->byte_count += len; -+ -+ if (avail > len) { -+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), -+ data, len); -+ return 0; -+ } -+ -+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), -+ data, avail); -+ -+ md5_transform_helper(mctx); -+ data += avail; -+ len -= avail; -+ -+ while (len >= sizeof(mctx->block)) { -+ memcpy(mctx->block, data, sizeof(mctx->block)); -+ md5_transform_helper(mctx); -+ data += sizeof(mctx->block); -+ len -= sizeof(mctx->block); -+ } -+ -+ memcpy(mctx->block, data, len); -+ -+ return 0; -+} -+ -+/** \fn static void md5_final(struct crypto_tfm *tfm, u8 *out) -+ * \ingroup LQ_MD5_FUNCTIONS -+ * \brief compute final md5 value -+ * \param tfm linux crypto algo transform -+ * \param out final md5 output value -+*/ -+static int md5_final(struct shash_desc *desc, u8 *out) -+{ -+ struct md5_ctx *mctx = shash_desc_ctx(desc); -+ const unsigned int offset = mctx->byte_count & 0x3f; -+ char *p = (char *)mctx->block + offset; -+ int padding = 56 - (offset + 1); -+ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; -+ unsigned long flag; -+ -+ *p++ = 0x80; -+ if (padding < 0) { -+ memset(p, 0x00, padding + sizeof (u64)); -+ md5_transform_helper(mctx); -+ p = (char *)mctx->block; -+ padding = 56; -+ } -+ -+ memset(p, 0, padding); -+ mctx->block[14] = md5_endian_swap(mctx->byte_count << 3); -+ mctx->block[15] = md5_endian_swap(mctx->byte_count >> 29); -+ -+#if 0 -+ le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - -+ sizeof(u64)) / sizeof(u32)); -+#endif -+ -+ md5_transform(mctx->hash, mctx->block); -+ -+ CRTCL_SECT_START; -+ -+ *((u32 *) out + 0) = md5_endian_swap(hashs->D1R); -+ *((u32 *) out + 1) = md5_endian_swap(hashs->D2R); -+ *((u32 *) out + 2) = md5_endian_swap(hashs->D3R); -+ *((u32 *) out + 3) = md5_endian_swap(hashs->D4R); -+ -+ CRTCL_SECT_END; -+ -+ /* Wipe context */ -+ memset(mctx, 0, sizeof(*mctx)); -+ -+ return 0; -+} -+ -+static int md5_export(struct shash_desc *desc, void *out) -+{ -+ struct md5_ctx *sctx = shash_desc_ctx(desc); -+ -+ memcpy(out, sctx, sizeof(*sctx)); -+ return 0; -+} -+ -+static int md5_import(struct shash_desc *desc, const void *in) -+{ -+ struct md5_ctx *sctx = shash_desc_ctx(desc); -+ -+ memcpy(sctx, in, sizeof(*sctx)); -+ return 0; -+} -+ -+/* -+ * \brief MD5 function mappings -+*/ -+static struct shash_alg md5_alg = { -+ .digestsize = MD5_DIGEST_SIZE, -+ .init = md5_init, -+ .update = md5_update, -+ .final = md5_final, -+ .export = md5_export, -+ .import = md5_import, -+ .descsize = sizeof(struct md5_ctx), -+ .statesize = sizeof(struct md5_ctx), -+ .base = { -+ .cra_name = "md5", -+ .cra_driver_name = "lq_deu-md5", -+ .cra_flags = CRYPTO_ALG_TYPE_SHASH, -+ .cra_blocksize = MD5_HMAC_BLOCK_SIZE, -+ .cra_module = THIS_MODULE, -+ } -+}; -+ -+/** \fn int lq_deu_init_md5(void) -+ * \ingroup LQ_MD5_FUNCTIONS -+ * \brief initialize md5 driver -+*/ -+int lq_deu_init_md5(void) -+{ -+ int ret; -+ -+ if ((ret = crypto_register_shash(&md5_alg))) -+ goto md5_err; -+ -+ CRTCL_SECT_INIT; -+ -+ printk(KERN_NOTICE "Lantiq DEU MD5 initialized%s.\n", -+ disable_deudma ? "" : " (DMA)"); -+ return ret; -+ -+md5_err: -+ printk(KERN_ERR "Lantiq DEU MD5 initialization failed!\n"); -+ return ret; -+} -+ -+/** \fn void lq_deu_fini_md5(void) -+ * \ingroup LQ_MD5_FUNCTIONS -+ * \brief unregister md5 driver -+*/ -+ -+void lq_deu_fini_md5(void) -+{ -+ crypto_unregister_shash(&md5_alg); -+} -+ ---- /dev/null -+++ b/drivers/crypto/lantiq/md5_hmac.c -@@ -0,0 +1,329 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file md5_hmac.c -+ \ingroup LQ_DEU -+ \brief MD5-HMAC encryption DEU driver file -+*/ -+ -+/** -+ \defgroup LQ_MD5_HMAC_FUNCTIONS LQ_MD5_HMAC_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief Lantiq md5-hmac driver functions -+*/ -+ -+#include <crypto/internal/hash.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/string.h> -+#include <linux/crypto.h> -+#include <linux/types.h> -+#include <asm/byteorder.h> -+#include "deu.h" -+ -+#define MD5_DIGEST_SIZE 16 -+#define MD5_HMAC_BLOCK_SIZE 64 -+#define MD5_BLOCK_WORDS 16 -+#define MD5_HASH_WORDS 4 -+#define MD5_HMAC_DBN_TEMP_SIZE 1024 /* size in dword, -+ needed for dbn workaround */ -+ -+static spinlock_t cipher_lock; -+ -+struct md5_hmac_ctx { -+ u32 hash[MD5_HASH_WORDS]; -+ u32 block[MD5_BLOCK_WORDS]; -+ u64 byte_count; -+ u32 dbn; -+ u32 temp[MD5_HMAC_DBN_TEMP_SIZE]; -+}; -+ -+/** \fn static u32 md5_endian_swap(u32 input) -+ * \ingroup LQ_MD5_HMAC_FUNCTIONS -+ * \brief perform dword level endian swap -+ * \param input value of dword that requires to be swapped -+*/ -+static u32 md5_endian_swap(u32 input) -+{ -+ u8 *ptr = (u8 *)&input; -+ -+ return ((ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0]); -+} -+ -+/** \fn static void md5_hmac_transform(struct crypto_tfm *tfm, u32 const *in) -+ * \ingroup LQ_MD5_HMAC_FUNCTIONS -+ * \brief save input block to context -+ * \param tfm linux crypto algo transform -+ * \param in 64-byte block of input -+*/ -+static void md5_hmac_transform(struct shash_desc *desc, u32 const *in) -+{ -+ struct md5_hmac_ctx *mctx = shash_desc_ctx(desc); -+ -+ memcpy(&mctx->temp[mctx->dbn<<4], in, 64); /* dbn workaround */ -+ mctx->dbn += 1; -+ -+ if ( (mctx->dbn<<4) > MD5_HMAC_DBN_TEMP_SIZE ) -+ { -+ printk("MD5_HMAC_DBN_TEMP_SIZE exceeded\n"); -+ } -+} -+ -+/** \fn int md5_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) -+ * \ingroup LQ_MD5_HMAC_FUNCTIONS -+ * \brief sets md5 hmac key -+ * \param tfm linux crypto algo transform -+ * \param key input key -+ * \param keylen key length greater than 64 bytes IS NOT SUPPORTED -+*/ -+static int md5_hmac_setkey(struct crypto_shash *tfm, -+ const u8 *key, -+ unsigned int keylen) -+{ -+ volatile struct deu_hash *hash = (struct deu_hash *) HASH_START; -+ int i, j; -+ u32 *in_key = (u32 *)key; -+ -+ hash->KIDX = 0x80000000; /* reset all 16 words of the key to '0' */ -+ asm("sync"); -+ -+ j = 0; -+ for (i = 0; i < keylen; i+=4) -+ { -+ hash->KIDX = j; -+ asm("sync"); -+ hash->KEY = *((u32 *) in_key + j); -+ j++; -+ } -+ -+ return 0; -+} -+ -+/** \fn void md5_hmac_init(struct crypto_tfm *tfm) -+ * \ingroup LQ_MD5_HMAC_FUNCTIONS -+ * \brief initialize md5 hmac context -+ * \param tfm linux crypto algo transform -+*/ -+static int md5_hmac_init(struct shash_desc *desc) -+{ -+ struct md5_hmac_ctx *mctx = shash_desc_ctx(desc); -+ -+ memset(mctx, 0, sizeof(struct md5_hmac_ctx)); -+ mctx->dbn = 0; /* dbn workaround */ -+ return 0; -+} -+ -+/** \fn void md5_hmac_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) -+ * \ingroup LQ_MD5_HMAC_FUNCTIONS -+ * \brief on-the-fly md5 hmac computation -+ * \param tfm linux crypto algo transform -+ * \param data input data -+ * \param len size of input data -+*/ -+static int md5_hmac_update(struct shash_desc *desc, -+ const u8 *data, -+ unsigned int len) -+{ -+ struct md5_hmac_ctx *mctx = shash_desc_ctx(desc); -+ const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); -+ -+ mctx->byte_count += len; -+ -+ if (avail > len) { -+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), -+ data, len); -+ return 0; -+ } -+ -+ memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), -+ data, avail); -+ -+ md5_hmac_transform(desc, mctx->block); -+ data += avail; -+ len -= avail; -+ -+ while (len >= sizeof(mctx->block)) { -+ memcpy(mctx->block, data, sizeof(mctx->block)); -+ md5_hmac_transform(desc, mctx->block); -+ data += sizeof(mctx->block); -+ len -= sizeof(mctx->block); -+ } -+ -+ memcpy(mctx->block, data, len); -+ -+ return 0; -+} -+ -+/** \fn void md5_hmac_final(struct crypto_tfm *tfm, u8 *out) -+ * \ingroup LQ_MD5_HMAC_FUNCTIONS -+ * \brief compute final md5 hmac value -+ * \param tfm linux crypto algo transform -+ * \param out final md5 hmac output value -+*/ -+static int md5_hmac_final(struct shash_desc *desc, u8 *out) -+{ -+ struct md5_hmac_ctx *mctx = shash_desc_ctx(desc); -+ const unsigned int offset = mctx->byte_count & 0x3f; -+ char *p = (char *)mctx->block + offset; -+ int padding = 56 - (offset + 1); -+ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; -+ u32 flag; -+ int i = 0; -+ int dbn; -+ u32 *in = &mctx->temp[0]; -+ -+ *p++ = 0x80; -+ if (padding < 0) { -+ memset(p, 0x00, padding + sizeof (u64)); -+ md5_hmac_transform(desc, mctx->block); -+ p = (char *)mctx->block; -+ padding = 56; -+ } -+ -+ memset(p, 0, padding); -+ /* need to add 512 bit of the IPAD operation */ -+ mctx->block[14] = md5_endian_swap((mctx->byte_count + 64) << 3); -+ mctx->block[15] = 0x00000000; -+ -+ md5_hmac_transform(desc, mctx->block); -+ -+ CRTCL_SECT_START; -+ -+ printk("dbn = %d\n", mctx->dbn); -+ hashs->DBN = mctx->dbn; -+ -+ /* khs, go, init, ndc, endi, kyue, hmen, md5 */ -+ *LQ_HASH_CON = 0x0703002D; -+ -+ /* wait for processing */ -+ while (hashs->ctrl.BSY) { -+ /* this will not take long */ -+ } -+ -+ for (dbn = 0; dbn < mctx->dbn; dbn++) -+ { -+ for (i = 0; i < 16; i++) { -+ hashs->MR = in[i]; -+ }; -+ -+ hashs->ctrl.GO = 1; -+ asm("sync"); -+ -+ /* wait for processing */ -+ while (hashs->ctrl.BSY) { -+ /* this will not take long */ -+ } -+ -+ in += 16; -+ } -+ -+#if 1 -+ /* wait for digest ready */ -+ while (! hashs->ctrl.DGRY) { -+ /* this will not take long */ -+ } -+#endif -+ -+ *((u32 *) out + 0) = hashs->D1R; -+ *((u32 *) out + 1) = hashs->D2R; -+ *((u32 *) out + 2) = hashs->D3R; -+ *((u32 *) out + 3) = hashs->D4R; -+ *((u32 *) out + 4) = hashs->D5R; -+ -+ CRTCL_SECT_END; -+ -+ return 0; -+} -+ -+static int md5_hmac_export(struct shash_desc *desc, void *out) -+{ -+ struct md5_hmac_ctx *sctx = shash_desc_ctx(desc); -+ -+ memcpy(out, sctx, sizeof(*sctx)); -+ return 0; -+} -+ -+static int md5_hmac_import(struct shash_desc *desc, const void *in) -+{ -+ struct md5_hmac_ctx *sctx = shash_desc_ctx(desc); -+ -+ memcpy(sctx, in, sizeof(*sctx)); -+ return 0; -+} -+ -+/* -+ * \brief MD5_HMAC function mappings -+*/ -+static struct shash_alg md5_hmac_alg = { -+ .digestsize = MD5_DIGEST_SIZE, -+ .init = md5_hmac_init, -+ .update = md5_hmac_update, -+ .final = md5_hmac_final, -+ .setkey = md5_hmac_setkey, -+ .export = md5_hmac_export, -+ .import = md5_hmac_import, -+ .descsize = sizeof(struct md5_hmac_ctx), -+ .statesize = sizeof(struct md5_hmac_ctx), -+ .base = { -+ .cra_name = "hmac(md5)", -+ .cra_driver_name = "lq_deu-md5_hmac", -+ .cra_flags = CRYPTO_ALG_TYPE_SHASH, -+ .cra_blocksize = MD5_HMAC_BLOCK_SIZE, -+ .cra_module = THIS_MODULE, -+ } -+}; -+ -+/** \fn int lq_deu_init_md5_hmac(void) -+ * \ingroup LQ_MD5_HMAC_FUNCTIONS -+ * \brief initialize md5 hmac driver -+*/ -+int lq_deu_init_md5_hmac(void) -+{ -+ int ret; -+ -+ if ((ret = crypto_register_shash(&md5_hmac_alg))) -+ goto md5_hmac_err; -+ -+ CRTCL_SECT_INIT; -+ -+ printk(KERN_NOTICE "Lantiq DEU MD5_HMAC initialized%s.\n", -+ disable_deudma ? "" : " (DMA)"); -+ return ret; -+ -+md5_hmac_err: -+ printk(KERN_ERR "Lantiq DEU MD5_HMAC initialization failed!\n"); -+ return ret; -+} -+ -+/** \fn void lq_deu_fini_md5_hmac(void) -+ * \ingroup LQ_MD5_HMAC_FUNCTIONS -+ * \brief unregister md5 hmac driver -+*/ -+void lq_deu_fini_md5_hmac(void) -+{ -+ crypto_unregister_shash(&md5_hmac_alg); -+} -+ ---- /dev/null -+++ b/drivers/crypto/lantiq/sha1.c -@@ -0,0 +1,262 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file sha1.c -+ \ingroup LQ_DEU -+ \brief SHA1 encryption DEU driver file -+*/ -+ -+/** -+ \defgroup LQ_SHA1_FUNCTIONS LQ_SHA1_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief Lantiq DEU sha1 functions -+*/ -+ -+ -+#include <crypto/internal/hash.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/mm.h> -+#include <linux/crypto.h> -+#include <linux/cryptohash.h> -+#include <crypto/sha.h> -+#include <linux/types.h> -+#include <asm/scatterlist.h> -+#include <asm/byteorder.h> -+#include "deu.h" -+ -+#define SHA1_DIGEST_SIZE 20 -+#define SHA1_HMAC_BLOCK_SIZE 64 -+ -+static spinlock_t cipher_lock; -+ -+/* -+ * \brief SHA1 private structure -+*/ -+struct sha1_ctx { -+ u64 count; -+ u32 state[5]; -+ u8 buffer[64]; -+}; -+ -+/** \fn static void sha1_transform(u32 *state, const u32 *in) -+ * \ingroup LQ_SHA1_FUNCTIONS -+ * \brief main interface to sha1 hardware -+ * \param state current state -+ * \param in 64-byte block of input -+*/ -+static void sha1_transform(u32 *state, const u32 *in) -+{ -+ int i = 0; -+ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; -+ unsigned long flag; -+ -+ CRTCL_SECT_START; -+ -+ for (i = 0; i < 16; i++) { -+ hashs->MR = in[i]; -+ }; -+ -+ /* wait for processing */ -+ while (hashs->ctrl.BSY) { -+ /* this will not take long */ -+ } -+ -+ CRTCL_SECT_END; -+} -+ -+/** \fn static void sha1_init(struct crypto_tfm *tfm) -+ * \ingroup LQ_SHA1_FUNCTIONS -+ * \brief initialize sha1 hardware -+ * \param tfm linux crypto algo transform -+*/ -+static int sha1_init(struct shash_desc *desc) -+{ -+ struct sha1_ctx *sctx = shash_desc_ctx(desc); -+ -+ SHA_HASH_INIT; -+ -+ sctx->count = 0; -+ -+ return 0; -+} -+ -+/** \fn static void sha1_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) -+ * \ingroup LQ_SHA1_FUNCTIONS -+ * \brief on-the-fly sha1 computation -+ * \param tfm linux crypto algo transform -+ * \param data input data -+ * \param len size of input data -+*/ -+static int sha1_update(struct shash_desc *desc, const u8 *data, unsigned int len) -+{ -+ struct sha1_ctx *sctx = shash_desc_ctx(desc); -+ unsigned int i, j; -+ -+ j = (sctx->count >> 3) & 0x3f; -+ sctx->count += len << 3; -+ -+ if ((j + len) > 63) { -+ memcpy(&sctx->buffer[j], data, (i = 64 - j)); -+ sha1_transform(sctx->state, (const u32 *)sctx->buffer); -+ for (; i + 63 < len; i += 64) { -+ sha1_transform(sctx->state, (const u32 *)&data[i]); -+ } -+ -+ j = 0; -+ } else { -+ i = 0; -+ } -+ -+ memcpy(&sctx->buffer[j], &data[i], len - i); -+ -+ return 0; -+} -+ -+/** \fn static void sha1_final(struct crypto_tfm *tfm, u8 *out) -+ * \ingroup LQ_SHA1_FUNCTIONS -+ * \brief compute final sha1 value -+ * \param tfm linux crypto algo transform -+ * \param out final md5 output value -+*/ -+static int sha1_final(struct shash_desc *desc, u8 *out) -+{ -+ struct sha1_ctx *sctx = shash_desc_ctx(desc); -+ u32 index, padlen; -+ u64 t; -+ u8 bits[8] = { 0, }; -+ static const u8 padding[64] = { 0x80, }; -+ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; -+ ulong flag; -+ -+ t = sctx->count; -+ bits[7] = 0xff & t; -+ t >>= 8; -+ bits[6] = 0xff & t; -+ t >>= 8; -+ bits[5] = 0xff & t; -+ t >>= 8; -+ bits[4] = 0xff & t; -+ t >>= 8; -+ bits[3] = 0xff & t; -+ t >>= 8; -+ bits[2] = 0xff & t; -+ t >>= 8; -+ bits[1] = 0xff & t; -+ t >>= 8; -+ bits[0] = 0xff & t; -+ -+ /* Pad out to 56 mod 64 */ -+ index = (sctx->count >> 3) & 0x3f; -+ padlen = (index < 56) ? (56 - index) : ((64 + 56) - index); -+ sha1_update(desc, padding, padlen); -+ -+ /* Append length */ -+ sha1_update(desc, bits, sizeof bits); -+ -+ CRTCL_SECT_START; -+ -+ *((u32 *) out + 0) = hashs->D1R; -+ *((u32 *) out + 1) = hashs->D2R; -+ *((u32 *) out + 2) = hashs->D3R; -+ *((u32 *) out + 3) = hashs->D4R; -+ *((u32 *) out + 4) = hashs->D5R; -+ -+ CRTCL_SECT_END; -+ -+ /* Wipe context*/ -+ memset(sctx, 0, sizeof *sctx); -+ -+ return 0; -+} -+ -+static int sha1_export(struct shash_desc *desc, void *out) -+{ -+ struct sha1_ctx *sctx = shash_desc_ctx(desc); -+ -+ memcpy(out, sctx, sizeof(*sctx)); -+ return 0; -+} -+ -+static int sha1_import(struct shash_desc *desc, const void *in) -+{ -+ struct sha1_ctx *sctx = shash_desc_ctx(desc); -+ -+ memcpy(sctx, in, sizeof(*sctx)); -+ return 0; -+} -+ -+/* -+ * \brief SHA1 function mappings -+*/ -+static struct shash_alg deu_sha1_alg = { -+ .digestsize = SHA1_DIGEST_SIZE, -+ .init = sha1_init, -+ .update = sha1_update, -+ .final = sha1_final, -+ .export = sha1_export, -+ .import = sha1_import, -+ .descsize = sizeof(struct sha1_ctx), -+ .statesize = sizeof(struct sha1_ctx), -+ .base = { -+ .cra_name = "sha1", -+ .cra_driver_name = "lq_deu-sha1", -+ .cra_flags = CRYPTO_ALG_TYPE_SHASH, -+ .cra_blocksize = SHA1_HMAC_BLOCK_SIZE, -+ .cra_module = THIS_MODULE, -+ } -+}; -+ -+/** \fn int lq_deu_init_sha1(void) -+ * \ingroup LQ_SHA1_FUNCTIONS -+ * \brief initialize sha1 driver -+*/ -+int lq_deu_init_sha1(void) -+{ -+ int ret; -+ -+ if ((ret = crypto_register_shash(&deu_sha1_alg))) -+ goto sha1_err; -+ -+ CRTCL_SECT_INIT; -+ -+ printk(KERN_NOTICE "Lantiq DEU SHA1 initialized%s.\n", -+ disable_deudma ? "" : " (DMA)"); -+ return ret; -+ -+sha1_err: -+ printk(KERN_ERR "Lantiq DEU SHA1 initialization failed!\n"); -+ return ret; -+} -+ -+/** \fn void lq_deu_fini_sha1(void) -+ * \ingroup LQ_SHA1_FUNCTIONS -+ * \brief unregister sha1 driver -+*/ -+void lq_deu_fini_sha1(void) -+{ -+ crypto_unregister_shash(&deu_sha1_alg); -+} ---- /dev/null -+++ b/drivers/crypto/lantiq/sha1_hmac.c -@@ -0,0 +1,325 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file sha1_hmac.c -+ \ingroup LQ_DEU -+ \brief SHA1-HMAC DEU driver file -+*/ -+ -+/** -+ \defgroup LQ_SHA1_HMAC_FUNCTIONS LQ_SHA1_HMAC_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief Lantiq sha1 hmac functions -+*/ -+ -+ -+#include <crypto/internal/hash.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/mm.h> -+#include <linux/crypto.h> -+#include <linux/cryptohash.h> -+#include <linux/types.h> -+#include <asm/scatterlist.h> -+#include <asm/byteorder.h> -+#include <linux/delay.h> -+#include "deu.h" -+ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_SHA1_HMAC -+ -+#define SHA1_DIGEST_SIZE 20 -+#define SHA1_HMAC_BLOCK_SIZE 64 -+/* size in dword, needed for dbn workaround */ -+#define SHA1_HMAC_DBN_TEMP_SIZE 1024 -+ -+static spinlock_t cipher_lock; -+ -+struct sha1_hmac_ctx { -+ u64 count; -+ u32 state[5]; -+ u8 buffer[64]; -+ u32 dbn; -+ u32 temp[SHA1_HMAC_DBN_TEMP_SIZE]; -+}; -+ -+/** \fn static void sha1_hmac_transform(struct crypto_tfm *tfm, u32 const *in) -+ * \ingroup LQ_SHA1_HMAC_FUNCTIONS -+ * \brief save input block to context -+ * \param tfm linux crypto algo transform -+ * \param in 64-byte block of input -+*/ -+static void sha1_hmac_transform(struct shash_desc *desc, u32 const *in) -+{ -+ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); -+ -+ memcpy(&sctx->temp[sctx->dbn<<4], in, 64); /* dbn workaround */ -+ sctx->dbn += 1; -+ -+ if ((sctx->dbn<<4) > SHA1_HMAC_DBN_TEMP_SIZE) { -+ printk("SHA1_HMAC_DBN_TEMP_SIZE exceeded\n"); -+ } -+} -+ -+/** \fn int sha1_hmac_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) -+ * \ingroup LQ_SHA1_HMAC_FUNCTIONS -+ * \brief sets sha1 hmac key -+ * \param tfm linux crypto algo transform -+ * \param key input key -+ * \param keylen key length greater than 64 bytes IS NOT SUPPORTED -+*/ -+static int sha1_hmac_setkey(struct crypto_shash *tfm, -+ const u8 *key, -+ unsigned int keylen) -+{ -+ volatile struct deu_hash *hash = (struct deu_hash *) HASH_START; -+ int i, j; -+ u32 *in_key = (u32 *)key; -+ -+ hash->KIDX = 0x80000000; /* reset all 16 words of the key to '0' */ -+ asm("sync"); -+ -+ j = 0; -+ for (i = 0; i < keylen; i+=4) -+ { -+ hash->KIDX = j; -+ asm("sync"); -+ hash->KEY = *((u32 *) in_key + j); -+ j++; -+ } -+ -+ return 0; -+} -+ -+static int sha1_hmac_export(struct shash_desc *desc, void *out) -+{ -+ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); -+ -+ memcpy(out, sctx, sizeof(*sctx)); -+ return 0; -+} -+ -+static int sha1_hmac_import(struct shash_desc *desc, const void *in) -+{ -+ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); -+ -+ memcpy(sctx, in, sizeof(*sctx)); -+ return 0; -+} -+ -+/** \fn void sha1_hmac_init(struct crypto_tfm *tfm) -+ * \ingroup LQ_SHA1_HMAC_FUNCTIONS -+ * \brief initialize sha1 hmac context -+ * \param tfm linux crypto algo transform -+*/ -+static int sha1_hmac_init(struct shash_desc *desc) -+{ -+ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); -+ -+ memset(sctx, 0, sizeof(struct sha1_hmac_ctx)); -+ sctx->dbn = 0; /* dbn workaround */ -+ -+ return 0; -+} -+ -+/** \fn static void sha1_hmac_update(struct crypto_tfm *tfm, const u8 *data, unsigned int len) -+ * \ingroup LQ_SHA1_HMAC_FUNCTIONS -+ * \brief on-the-fly sha1 hmac computation -+ * \param tfm linux crypto algo transform -+ * \param data input data -+ * \param len size of input data -+*/ -+static int sha1_hmac_update(struct shash_desc *desc, const u8 *data, -+ unsigned int len) -+{ -+ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); -+ unsigned int i, j; -+ -+ j = (sctx->count >> 3) & 0x3f; -+ sctx->count += len << 3; -+ /* printk("sctx->count = %d\n", (sctx->count >> 3)); */ -+ -+ if ((j + len) > 63) { -+ memcpy(&sctx->buffer[j], data, (i = 64 - j)); -+ sha1_hmac_transform(desc, (const u32 *)sctx->buffer); -+ for (; i + 63 < len; i += 64) { -+ sha1_hmac_transform(desc, (const u32 *)&data[i]); -+ } -+ -+ j = 0; -+ } else { -+ i = 0; -+ } -+ -+ memcpy(&sctx->buffer[j], &data[i], len - i); -+ -+ return 0; -+} -+ -+/** \fn static void sha1_hmac_final(struct crypto_tfm *tfm, u8 *out) -+ * \ingroup LQ_SHA1_HMAC_FUNCTIONS -+ * \brief ompute final sha1 hmac value -+ * \param tfm linux crypto algo transform -+ * \param out final sha1 hmac output value -+*/ -+static int sha1_hmac_final(struct shash_desc *desc, u8 *out) -+{ -+ struct sha1_hmac_ctx *sctx = shash_desc_ctx(desc); -+ u32 index, padlen; -+ u64 t; -+ u8 bits[8] = { 0, }; -+ static const u8 padding[64] = { 0x80, }; -+ volatile struct deu_hash *hashs = (struct deu_hash *) HASH_START; -+ ulong flag; -+ int i = 0; -+ int dbn; -+ u32 *in = &sctx->temp[0]; -+ -+ t = sctx->count + 512; /* need to add 512 bit of the IPAD operation */ -+ bits[7] = 0xff & t; -+ t >>= 8; -+ bits[6] = 0xff & t; -+ t >>= 8; -+ bits[5] = 0xff & t; -+ t >>= 8; -+ bits[4] = 0xff & t; -+ t >>= 8; -+ bits[3] = 0xff & t; -+ t >>= 8; -+ bits[2] = 0xff & t; -+ t >>= 8; -+ bits[1] = 0xff & t; -+ t >>= 8; -+ bits[0] = 0xff & t; -+ -+ /* Pad out to 56 mod 64 */ -+ index = (sctx->count >> 3) & 0x3f; -+ padlen = (index < 56) ? (56 - index) : ((64 + 56) - index); -+ sha1_hmac_update(desc, padding, padlen); -+ -+ /* Append length */ -+ sha1_hmac_update(desc, bits, sizeof bits); -+ -+ CRTCL_SECT_START; -+ -+ hashs->DBN = sctx->dbn; -+ -+ /* for vr9 change, ENDI = 1 */ -+ *LQ_HASH_CON = HASH_CON_VALUE; -+ -+ /* wait for processing */ -+ while (hashs->ctrl.BSY) { -+ /* this will not take long */ -+ } -+ -+ for (dbn = 0; dbn < sctx->dbn; dbn++) -+ { -+ for (i = 0; i < 16; i++) { -+ hashs->MR = in[i]; -+ }; -+ -+ hashs->ctrl.GO = 1; -+ asm("sync"); -+ -+ /* wait for processing */ -+ while (hashs->ctrl.BSY) { -+ /* this will not take long */ -+ } -+ -+ in += 16; -+ -+ return 0; -+ } -+ -+#if 1 -+ /* wait for digest ready */ -+ while (! hashs->ctrl.DGRY) { -+ /* this will not take long */ -+ } -+#endif -+ -+ *((u32 *) out + 0) = hashs->D1R; -+ *((u32 *) out + 1) = hashs->D2R; -+ *((u32 *) out + 2) = hashs->D3R; -+ *((u32 *) out + 3) = hashs->D4R; -+ *((u32 *) out + 4) = hashs->D5R; -+ -+ CRTCL_SECT_END; -+} -+ -+/* -+ * \brief SHA1-HMAC function mappings -+*/ -+static struct shash_alg sha1_hmac_alg = { -+ .digestsize = SHA1_DIGEST_SIZE, -+ .init = sha1_hmac_init, -+ .update = sha1_hmac_update, -+ .final = sha1_hmac_final, -+ .export = sha1_hmac_export, -+ .import = sha1_hmac_import, -+ .setkey = sha1_hmac_setkey, -+ .descsize = sizeof(struct sha1_hmac_ctx), -+ .statesize = sizeof(struct sha1_hmac_ctx), -+ .base = { -+ .cra_name = "hmac(sha1)", -+ .cra_driver_name = "lq_deu-sha1_hmac", -+ .cra_flags = CRYPTO_ALG_TYPE_SHASH, -+ .cra_blocksize = SHA1_HMAC_BLOCK_SIZE, -+ .cra_module = THIS_MODULE, -+ } -+}; -+ -+/** \fn int lq_deu_init_sha1_hmac(void) -+ * \ingroup LQ_SHA1_HMAC_FUNCTIONS -+ * \brief initialize sha1 hmac driver -+*/ -+int lq_deu_init_sha1_hmac(void) -+{ -+ int ret; -+ -+ if ((ret = crypto_register_shash(&sha1_hmac_alg))) -+ goto sha1_err; -+ -+ CRTCL_SECT_INIT; -+ -+ printk(KERN_NOTICE "Lantiq DEU SHA1_HMAC initialized%s.\n", -+ disable_deudma ? "" : " (DMA)"); -+ return ret; -+ -+sha1_err: -+ printk(KERN_ERR "Lantiq DEU SHA1_HMAC initialization failed!\n"); -+ return ret; -+} -+ -+/** \fn void lq_deu_fini_sha1_hmac(void) -+ * \ingroup LQ_SHA1_HMAC_FUNCTIONS -+ * \brief unregister sha1 hmac driver -+*/ -+void lq_deu_fini_sha1_hmac(void) -+{ -+ crypto_unregister_shash(&sha1_hmac_alg); -+} -+ -+#endif ---- /dev/null -+++ b/drivers/crypto/lantiq/deu_falcon.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 as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus -+ */ -+ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/types.h> -+#include <linux/errno.h> -+#include <asm/io.h> /* dma_cache_inv */ -+#include <linux/platform_device.h> -+ -+#ifdef CONFIG_SOC_LANTIQ_FALCON -+ -+#include "deu.h" -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief Lantiq DEU driver module -+*/ -+ -+/** -+ \file deu_falcon.c -+ \brief Lantiq DEU board specific driver file for ar9 -+*/ -+ -+/** -+ \defgroup BOARD_SPECIFIC_FUNCTIONS LQ_BOARD_SPECIFIC_FUNCTIONS -+ \ingroup LQ_DEU -+ \brief board specific functions -+*/ -+ -+#include <falcon/gpon_reg_base.h> -+#include <falcon/sys1_reg.h> -+#include <falcon/status_reg.h> -+#include <falcon/sysctrl.h> -+ -+#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) -+ -+static gpon_sys1_t * const sys1 = (gpon_sys1_t *)GPON_SYS1_BASE; -+static gpon_status_t * const status = (gpon_status_t *)GPON_STATUS_BASE; -+ -+/** \fn u32 endian_swap(u32 input) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief Swap data given to the function -+ * \param input Data input to be swapped -+ * \return either the swapped data or the input data depending on whether it is in DMA mode or FPI mode -+*/ -+static u32 endian_swap(u32 input) -+{ -+ return input; -+} -+ -+/** \fn u32 input_swap(u32 input) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief Not used -+ * \return input -+*/ -+static u32 input_swap(u32 input) -+{ -+ return input; -+} -+ -+/** \fn void aes_chip_init(void) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief initialize AES hardware -+*/ -+static void aes_chip_init(void) -+{ -+ volatile struct deu_aes *aes = (struct deu_aes *) AES_START; -+ -+ aes->ctrl.SM = 1; -+ aes->ctrl.ARS = 1; -+} -+ -+/** \fn void des_chip_init(void) -+ * \ingroup BOARD_SPECIFIC_FUNCTIONS -+ * \brief initialize DES hardware -+*/ -+static void des_chip_init(void) -+{ -+} -+ -+static u32 chip_init(void) -+{ -+ sys1_hw_clk_enable(CLKEN_SHA1_SET | CLKEN_AES_SET); -+ sys1_hw_activate(ACT_SHA1_SET | ACT_AES_SET); -+ -+ return LQ_DEU_ID_AES | LQ_DEU_ID_HASH; -+} -+ -+static int lq_crypto_probe(struct platform_device *pdev) -+{ -+#ifdef CONFIG_CRYPTO_DEV_LANTIQ_DMA -+ lq_crypto_ops.dma_init = NULL; -+ lq_crypto_ops.dma_exit = NULL; -+ lq_crypto_ops.aes_dma_memcpy = NULL; -+ lq_crypto_ops.des_dma_memcpy = NULL; -+ lq_crypto_ops.aes_dma_malloc = NULL; -+ lq_crypto_ops.des_dma_malloc = NULL; -+ lq_crypto_ops.dma_align = NULL; -+ lq_crypto_ops.dma_free = NULL; -+#endif -+ -+ lq_crypto_ops.endian_swap = endian_swap; -+ lq_crypto_ops.input_swap = input_swap; -+ lq_crypto_ops.aes_chip_init = aes_chip_init; -+ lq_crypto_ops.des_chip_init = des_chip_init; -+ lq_crypto_ops.chip_init = chip_init; -+ -+ printk("lq_falcon_deu: driver loaded!\n"); -+ -+ lq_deu_init(); -+ -+ return 0; -+} -+ -+static int lq_crypto_remove(struct platform_device *pdev) -+{ -+ lq_deu_exit(); -+ -+ return 0; -+} -+ -+static struct platform_driver lq_crypto = { -+ .probe = lq_crypto_probe, -+ .remove = lq_crypto_remove, -+ .driver = { -+ .owner = THIS_MODULE, -+ .name = "lq_falcon_deu" -+ } -+}; -+ -+static int __init lq_crypto_init(void) -+{ -+ return platform_driver_register(&lq_crypto); -+} -+module_init(lq_crypto_init); -+ -+static void __exit lq_crypto_exit(void) -+{ -+ platform_driver_unregister(&lq_crypto); -+} -+module_exit(lq_crypto_exit); -+ -+#endif ---- /dev/null -+++ b/drivers/crypto/lantiq/deu_falcon.h -@@ -0,0 +1,281 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com> -+ * Copyright (C) 2009 Mohammad Firdaus / Infineon Technologies -+ */ -+ -+/** -+ \defgroup LQ_DEU LQ_DEU_DRIVERS -+ \ingroup API -+ \brief DEU driver module -+*/ -+ -+/** -+ \defgroup LQ_DEU_DEFINITIONS LQ_DEU_DEFINITIONS -+ \ingroup LQ_DEU -+ \brief Lantiq DEU definitions -+*/ -+ -+/** -+ \file deu_falcon.h -+ \brief DEU driver header file -+*/ -+ -+ -+#ifndef DEU_FALCON_H -+#define DEU_FALCON_H -+ -+#define HASH_START 0xbd008100 -+#define AES_START 0xbd008000 -+ -+#ifdef CONFIG_CRYPTO_DEV_DMA -+# include "deu_dma.h" -+# define DEU_DWORD_REORDERING(ptr, buffer, in_out, bytes) \ -+ deu_dma_align(ptr, buffer, in_out, bytes) -+# define AES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ -+ deu_aes_dma_memcpy(outcopy, out_dma, out_arg, nbytes) -+# define DES_MEMORY_COPY(outcopy, out_dma, out_arg, nbytes) \ -+ deu_des_dma_memcpy(outcopy, out_dma, out_arg, nbytes) -+# define BUFFER_IN 1 -+# define BUFFER_OUT 0 -+# define AES_ALGO 1 -+# define DES_ALGO 0 -+# define ALLOCATE_MEMORY(val, type) 1 -+# define FREE_MEMORY(buff) -+extern struct lq_deu_device lq_deu[1]; -+#endif /* CONFIG_CRYPTO_DEV_DMA */ -+ -+/* SHA CONSTANTS */ -+#define HASH_CON_VALUE 0x0700002C -+ -+#define INPUT_ENDIAN_SWAP(input) deu_input_swap(input) -+#define DEU_ENDIAN_SWAP(input) deu_endian_swap(input) -+#define DELAY_PERIOD 10 -+#define FIND_DEU_CHIP_VERSION chip_version() -+ -+#define WAIT_AES_DMA_READY() \ -+ do { \ -+ int i; \ -+ volatile struct deu_dma *dma = \ -+ (struct deu_dma *) LQ_DEU_DMA_CON; \ -+ volatile struct deu_aes *aes = \ -+ (volatile struct deu_aes *) AES_START; \ -+ for (i = 0; i < 10; i++) \ -+ udelay(DELAY_PERIOD); \ -+ while (dma->ctrl.BSY) {}; \ -+ while (aes->ctrl.BUS) {}; \ -+ } while (0) -+ -+#define WAIT_DES_DMA_READY() \ -+ do { \ -+ int i; \ -+ volatile struct deu_dma *dma = \ -+ (struct deu_dma *) LQ_DEU_DMA_CON; \ -+ volatile struct deu_des *des = \ -+ (struct deu_des *) DES_3DES_START; \ -+ for (i = 0; i < 10; i++) \ -+ udelay(DELAY_PERIOD); \ -+ while (dma->ctrl.BSY) {}; \ -+ while (des->ctrl.BUS) {}; \ -+ } while (0) -+ -+#define AES_DMA_MISC_CONFIG() \ -+ do { \ -+ volatile struct deu_aes *aes = \ -+ (volatile struct deu_aes *) AES_START; \ -+ aes->ctrl.KRE = 1; \ -+ aes->ctrl.GO = 1; \ -+ } while(0) -+ -+#define SHA_HASH_INIT \ -+ do { \ -+ volatile struct deu_hash *hash = \ -+ (struct deu_hash *) HASH_START; \ -+ hash->ctrl.SM = 1; \ -+ hash->ctrl.ALGO = 0; \ -+ hash->ctrl.INIT = 1; \ -+ } while(0) -+ -+/* DEU Common Structures for Falcon*/ -+ -+struct deu_clk_ctrl { -+ u32 Res:26; -+ u32 FSOE:1; -+ u32 SBWE:1; -+ u32 EDIS:1; -+ u32 SPEN:1; -+ u32 DISS:1; -+ u32 DISR:1; -+}; -+ -+struct deu_des { -+ struct deu_des_ctrl { /* 10h */ -+ u32 KRE:1; -+ u32 reserved1:5; -+ u32 GO:1; -+ u32 STP:1; -+ u32 Res2:6; -+ u32 NDC:1; -+ u32 ENDI:1; -+ u32 Res3:2; -+ u32 F:3; -+ u32 O:3; -+ u32 BUS:1; -+ u32 DAU:1; -+ u32 ARS:1; -+ u32 SM:1; -+ u32 E_D:1; -+ u32 M:3; -+ } ctrl; -+ -+ u32 IHR; /* 14h */ -+ u32 ILR; /* 18h */ -+ u32 K1HR; /* 1c */ -+ u32 K1LR; -+ u32 K2HR; -+ u32 K2LR; -+ u32 K3HR; -+ u32 K3LR; /* 30h */ -+ u32 IVHR; /* 34h */ -+ u32 IVLR; /* 38 */ -+ u32 OHR; /* 3c */ -+ u32 OLR; /* 40 */ -+}; -+ -+struct deu_aes { -+ struct deu_aes_ctrl { -+ u32 KRE:1; -+ u32 reserved1:4; -+ u32 PNK:1; -+ u32 GO:1; -+ u32 STP:1; -+ u32 reserved2:6; -+ u32 NDC:1; -+ u32 ENDI:1; -+ u32 reserved3:2; -+ u32 F:3; /* fbs */ -+ u32 O:3; /* om */ -+ u32 BUS:1; /* bsy */ -+ u32 DAU:1; -+ u32 ARS:1; -+ u32 SM:1; -+ u32 E_D:1; -+ u32 KV:1; -+ u32 K:2; /* KL */ -+ } ctrl; -+ -+ u32 ID3R; /* 80h */ -+ u32 ID2R; /* 84h */ -+ u32 ID1R; /* 88h */ -+ u32 ID0R; /* 8Ch */ -+ u32 K7R; /* 90h */ -+ u32 K6R; /* 94h */ -+ u32 K5R; /* 98h */ -+ u32 K4R; /* 9Ch */ -+ u32 K3R; /* A0h */ -+ u32 K2R; /* A4h */ -+ u32 K1R; /* A8h */ -+ u32 K0R; /* ACh */ -+ u32 IV3R; /* B0h */ -+ u32 IV2R; /* B4h */ -+ u32 IV1R; /* B8h */ -+ u32 IV0R; /* BCh */ -+ u32 OD3R; /* D4h */ -+ u32 OD2R; /* D8h */ -+ u32 OD1R; /* DCh */ -+ u32 OD0R; /* E0h */ -+}; -+ -+struct deu_arc4 { -+ struct arc4_controlr { -+ u32 KRE:1; -+ u32 KLEN:4; -+ u32 KSAE:1; -+ u32 GO:1; -+ u32 STP:1; -+ u32 reserved1:6; -+ u32 NDC:1; -+ u32 ENDI:1; -+ u32 reserved2:8; -+ u32 BUS:1; /* bsy */ -+ u32 reserved3:1; -+ u32 ARS:1; -+ u32 SM:1; -+ u32 reserved4:4; -+ } ctrl; -+ -+ u32 K3R; /* 104h */ -+ u32 K2R; /* 108h */ -+ u32 K1R; /* 10Ch */ -+ u32 K0R; /* 110h */ -+ u32 IDLEN; /* 114h */ -+ u32 ID3R; /* 118h */ -+ u32 ID2R; /* 11Ch */ -+ u32 ID1R; /* 120h */ -+ u32 ID0R; /* 124h */ -+ u32 OD3R; /* 128h */ -+ u32 OD2R; /* 12Ch */ -+ u32 OD1R; /* 130h */ -+ u32 OD0R; /* 134h */ -+}; -+ -+struct deu_hash { -+ struct deu_hash_ctrl { -+ u32 reserved1:5; -+ u32 KHS:1; -+ u32 GO:1; -+ u32 INIT:1; -+ u32 reserved2:6; -+ u32 NDC:1; -+ u32 ENDI:1; -+ u32 reserved3:7; -+ u32 DGRY:1; -+ u32 BSY:1; -+ u32 reserved4:1; -+ u32 IRCL:1; -+ u32 SM:1; -+ u32 KYUE:1; -+ u32 HMEN:1; -+ u32 SSEN:1; -+ u32 ALGO:1; -+ } ctrl; -+ -+ u32 MR; /* B4h */ -+ u32 D1R; /* B8h */ -+ u32 D2R; /* BCh */ -+ u32 D3R; /* C0h */ -+ u32 D4R; /* C4h */ -+ u32 D5R; /* C8h */ -+ u32 dummy; /* CCh */ -+ u32 KIDX; /* D0h */ -+ u32 KEY; /* D4h */ -+ u32 DBN; /* D8h */ -+}; -+ -+struct deu_dma { -+ struct deu_dma_ctrl { -+ u32 reserved1:22; -+ u32 BS:2; -+ u32 BSY:1; -+ u32 reserved2:1; -+ u32 ALGO:2; -+ u32 RXCLS:2; -+ u32 reserved3:1; -+ u32 EN:1; -+ } ctrl; -+}; -+ -+#endif /* DEU_FALCON_H */ ---- a/arch/mips/lantiq/xway/devices.h -+++ b/arch/mips/lantiq/xway/devices.h -@@ -24,5 +24,6 @@ - extern void __init lq_register_ethernet(struct lq_eth_data *eth); - extern void __init lq_register_asc(int port); - extern void __init lq_register_gpio_buttons(struct gpio_button *buttons, int cnt); -+extern void __init lq_register_crypto(const char *name); - - #endif ---- a/arch/mips/lantiq/xway/mach-easy50712.c -+++ b/arch/mips/lantiq/xway/mach-easy50712.c -@@ -74,6 +74,7 @@ - lq_register_wdt(); - lq_register_pci(&lq_pci_data); - lq_register_ethernet(&lq_eth_data); -+ lq_register_crypto("lq_danube_deu"); - } - - MIPS_MACHINE(LANTIQ_MACH_EASY50712, ---- a/arch/mips/lantiq/xway/mach-easy50812.c -+++ b/arch/mips/lantiq/xway/mach-easy50812.c -@@ -73,6 +73,7 @@ - lq_register_wdt(); - lq_register_pci(&lq_pci_data); - lq_register_ethernet(&lq_eth_data); -+ lq_register_crypto("lq_ar9_deu"); - } - - MIPS_MACHINE(LANTIQ_MACH_EASY50812, diff --git a/target/linux/lantiq/patches/916-m25p80-fast-read.patch b/target/linux/lantiq/patches/916-m25p80-fast-read.patch deleted file mode 100644 index 3bbe57f..0000000 --- a/target/linux/lantiq/patches/916-m25p80-fast-read.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/drivers/mtd/devices/m25p80.c -+++ b/drivers/mtd/devices/m25p80.c -@@ -206,6 +206,7 @@ static void m25p_addr2cmd(struct m25p *f - cmd[1] = addr >> (flash->addr_width * 8 - 8); - cmd[2] = addr >> (flash->addr_width * 8 - 16); - cmd[3] = addr >> (flash->addr_width * 8 - 24); -+ cmd[4] = 0; - } - - static int m25p_cmdsz(struct m25p *flash) diff --git a/target/linux/lantiq/patches/941-spi2.patch b/target/linux/lantiq/patches/941-spi2.patch deleted file mode 100644 index 9cc23a1..0000000 --- a/target/linux/lantiq/patches/941-spi2.patch +++ /dev/null @@ -1,1103 +0,0 @@ -From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> -Date: Thu, 3 Mar 2011 17:15:30 +0000 (+0100) -Subject: SPI: lantiq: Add driver for Lantiq SoC SPI controller -X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=653c95b8b9066c9c6ac08bd64d0ceee439e9fd90;hp=3d21b04682ae8eb1c1965aba39d1796e8c5ad84b - -SPI: lantiq: Add driver for Lantiq SoC SPI controller - -Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> ---- - ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -176,6 +176,14 @@ - This enables using the Freescale i.MX SPI controllers in master - mode. - -+config SPI_LANTIQ -+ tristate "Lantiq SoC SPI controller" -+ depends on SOC_LANTIQ_XWAY -+ select SPI_BITBANG -+ help -+ This driver supports the Lantiq SoC SPI controller in master -+ mode. -+ - config SPI_LM70_LLP - tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)" - depends on PARPORT && EXPERIMENTAL ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -24,6 +24,7 @@ - obj-$(CONFIG_SPI_GPIO) += spi_gpio.o - obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o - obj-$(CONFIG_SPI_IMX) += spi_imx.o -+obj-$(CONFIG_SPI_LANTIQ) += spi_lantiq.o - obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o - obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o - obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o ---- /dev/null -+++ b/drivers/spi/spi_lantiq.c -@@ -0,0 +1,1063 @@ -+/* -+ * Lantiq SoC SPI controller -+ * -+ * Copyright (C) 2011 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> -+ * -+ * This program is free software; you can distribute it and/or modify it -+ * under the terms of the GNU General Public License (Version 2) as -+ * published by the Free Software Foundation. -+ */ -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/workqueue.h> -+#include <linux/platform_device.h> -+#include <linux/io.h> -+#include <linux/sched.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+#include <linux/completion.h> -+#include <linux/spinlock.h> -+#include <linux/err.h> -+#include <linux/clk.h> -+#include <linux/gpio.h> -+#include <linux/spi/spi.h> -+#include <linux/spi/spi_bitbang.h> -+ -+#include <xway.h> -+#include <xway_irq.h> -+#include <lantiq_platform.h> -+ -+#define LQ_SPI_CLC 0x00 /* Clock control */ -+#define LQ_SPI_PISEL 0x04 /* Port input select */ -+#define LQ_SPI_ID 0x08 /* Identification */ -+#define LQ_SPI_CON 0x10 /* Control */ -+#define LQ_SPI_STAT 0x14 /* Status */ -+#define LQ_SPI_WHBSTATE 0x18 /* Write HW modified state */ -+#define LQ_SPI_TB 0x20 /* Transmit buffer */ -+#define LQ_SPI_RB 0x24 /* Receive buffer */ -+#define LQ_SPI_RXFCON 0x30 /* Receive FIFO control */ -+#define LQ_SPI_TXFCON 0x34 /* Transmit FIFO control */ -+#define LQ_SPI_FSTAT 0x38 /* FIFO status */ -+#define LQ_SPI_BRT 0x40 /* Baudrate timer */ -+#define LQ_SPI_BRSTAT 0x44 /* Baudrate timer status */ -+#define LQ_SPI_SFCON 0x60 /* Serial frame control */ -+#define LQ_SPI_SFSTAT 0x64 /* Serial frame status */ -+#define LQ_SPI_GPOCON 0x70 /* General purpose output control */ -+#define LQ_SPI_GPOSTAT 0x74 /* General purpose output status */ -+#define LQ_SPI_FGPO 0x78 /* Forced general purpose output */ -+#define LQ_SPI_RXREQ 0x80 /* Receive request */ -+#define LQ_SPI_RXCNT 0x84 /* Receive count */ -+#define LQ_SPI_DMACON 0xEC /* DMA control */ -+#define LQ_SPI_IRNEN 0xF4 /* Interrupt node enable */ -+#define LQ_SPI_IRNICR 0xF8 /* Interrupt node interrupt capture */ -+#define LQ_SPI_IRNCR 0xFC /* Interrupt node control */ -+ -+#define LQ_SPI_CLC_SMC_SHIFT 16 /* Clock divider for sleep mode */ -+#define LQ_SPI_CLC_SMC_MASK 0xFF -+#define LQ_SPI_CLC_RMC_SHIFT 8 /* Clock divider for normal run mode */ -+#define LQ_SPI_CLC_RMC_MASK 0xFF -+#define LQ_SPI_CLC_DISS BIT(1) /* Disable status bit */ -+#define LQ_SPI_CLC_DISR BIT(0) /* Disable request bit */ -+ -+#define LQ_SPI_ID_TXFS_SHIFT 24 /* Implemented TX FIFO size */ -+#define LQ_SPI_ID_TXFS_MASK 0x3F -+#define LQ_SPI_ID_RXFS_SHIFT 16 /* Implemented RX FIFO size */ -+#define LQ_SPI_ID_RXFS_MASK 0x3F -+#define LQ_SPI_ID_REV_MASK 0x1F /* Hardware revision number */ -+#define LQ_SPI_ID_CFG BIT(5) /* DMA interface support */ -+ -+#define LQ_SPI_CON_BM_SHIFT 16 /* Data width selection */ -+#define LQ_SPI_CON_BM_MASK 0x1F -+#define LQ_SPI_CON_EM BIT(24) /* Echo mode */ -+#define LQ_SPI_CON_IDLE BIT(23) /* Idle bit value */ -+#define LQ_SPI_CON_ENBV BIT(22) /* Enable byte valid control */ -+#define LQ_SPI_CON_RUEN BIT(12) /* Receive underflow error enable */ -+#define LQ_SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */ -+#define LQ_SPI_CON_AEN BIT(10) /* Abort error enable */ -+#define LQ_SPI_CON_REN BIT(9) /* Receive overflow error enable */ -+#define LQ_SPI_CON_TEN BIT(8) /* Transmit overflow error enable */ -+#define LQ_SPI_CON_LB BIT(7) /* Loopback control */ -+#define LQ_SPI_CON_PO BIT(6) /* Clock polarity control */ -+#define LQ_SPI_CON_PH BIT(5) /* Clock phase control */ -+#define LQ_SPI_CON_HB BIT(4) /* Heading control */ -+#define LQ_SPI_CON_RXOFF BIT(1) /* Switch receiver off */ -+#define LQ_SPI_CON_TXOFF BIT(0) /* Switch transmitter off */ -+ -+#define LQ_SPI_STAT_RXBV_MASK 0x7 -+#define LQ_SPI_STAT_RXBV_SHIFT 28 -+#define LQ_SPI_STAT_BSY BIT(13) /* Busy flag */ -+#define LQ_SPI_STAT_RUE BIT(12) /* Receive underflow error flag */ -+#define LQ_SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */ -+#define LQ_SPI_STAT_AE BIT(10) /* Abort error flag */ -+#define LQ_SPI_STAT_RE BIT(9) /* Receive error flag */ -+#define LQ_SPI_STAT_TE BIT(8) /* Transmit error flag */ -+#define LQ_SPI_STAT_MS BIT(1) /* Master/slave select bit */ -+#define LQ_SPI_STAT_EN BIT(0) /* Enable bit */ -+ -+#define LQ_SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */ -+#define LQ_SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */ -+#define LQ_SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */ -+#define LQ_SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */ -+#define LQ_SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */ -+#define LQ_SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */ -+#define LQ_SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */ -+#define LQ_SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */ -+#define LQ_SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */ -+#define LQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */ -+#define LQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */ -+#define LQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */ -+#define LQ_SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */ -+#define LQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */ -+#define LQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */ -+#define LQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */ -+#define LQ_SPI_WHBSTATE_CLR_ERRORS 0x0F50 -+ -+#define LQ_SPI_RXFCON_RXFITL_SHIFT 8 /* FIFO interrupt trigger level */ -+#define LQ_SPI_RXFCON_RXFITL_MASK 0x3F -+#define LQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */ -+#define LQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */ -+ -+#define LQ_SPI_TXFCON_TXFITL_SHIFT 8 /* FIFO interrupt trigger level */ -+#define LQ_SPI_TXFCON_TXFITL_MASK 0x3F -+#define LQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */ -+#define LQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */ -+ -+#define LQ_SPI_FSTAT_RXFFL_MASK 0x3f -+#define LQ_SPI_FSTAT_RXFFL_SHIFT 0 -+#define LQ_SPI_FSTAT_TXFFL_MASK 0x3f -+#define LQ_SPI_FSTAT_TXFFL_SHIFT 8 -+ -+#define LQ_SPI_GPOCON_ISCSBN_SHIFT 8 -+#define LQ_SPI_GPOCON_INVOUTN_SHIFT 0 -+ -+#define LQ_SPI_FGPO_SETOUTN_SHIFT 8 -+#define LQ_SPI_FGPO_CLROUTN_SHIFT 0 -+ -+#define LQ_SPI_RXREQ_RXCNT_MASK 0xFFFF /* Receive count value */ -+#define LQ_SPI_RXCNT_TODO_MASK 0xFFFF /* Recevie to-do value */ -+ -+#define LQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */ -+#define LQ_SPI_IRNEN_E BIT(2) /* Error end interrupt request */ -+#define LQ_SPI_IRNEN_T BIT(1) /* Transmit end interrupt request */ -+#define LQ_SPI_IRNEN_R BIT(0) /* Receive end interrupt request */ -+#define LQ_SPI_IRNEN_ALL 0xF -+ -+/* Hard-wired GPIOs used by SPI controller */ -+#define LQ_SPI_GPIO_DI 16 -+#define LQ_SPI_GPIO_DO 17 -+#define LQ_SPI_GPIO_CLK 18 -+ -+struct lq_spi { -+ struct spi_bitbang bitbang; -+ struct completion done; -+ spinlock_t lock; -+ -+ struct device *dev; -+ void __iomem *base; -+ struct clk *clk; -+ -+ int status; -+ int irq[3]; -+ -+ const u8 *tx; -+ u8 *rx; -+ u32 tx_cnt; -+ u32 rx_cnt; -+ u32 len; -+ struct spi_transfer *curr_transfer; -+ -+ u32 (*get_tx) (struct lq_spi *); -+ -+ u16 txfs; -+ u16 rxfs; -+ unsigned dma_support:1; -+ unsigned cfg_mode:1; -+ -+}; -+ -+struct lq_spi_controller_state { -+ void (*cs_activate) (struct spi_device *); -+ void (*cs_deactivate) (struct spi_device *); -+}; -+ -+struct lq_spi_irq_map { -+ char *name; -+ irq_handler_t handler; -+}; -+ -+struct lq_spi_cs_gpio_map { -+ unsigned gpio; -+ unsigned altsel0; -+ unsigned altsel1; -+}; -+ -+static inline struct lq_spi *lq_spi_to_hw(struct spi_device *spi) -+{ -+ return spi_master_get_devdata(spi->master); -+} -+ -+static inline u32 lq_spi_reg_read(struct lq_spi *hw, u32 reg) -+{ -+ return ioread32be(hw->base + reg); -+} -+ -+static inline void lq_spi_reg_write(struct lq_spi *hw, u32 val, u32 reg) -+{ -+ iowrite32be(val, hw->base + reg); -+} -+ -+static inline void lq_spi_reg_setbit(struct lq_spi *hw, u32 bits, u32 reg) -+{ -+ u32 val; -+ -+ val = lq_spi_reg_read(hw, reg); -+ val |= bits; -+ lq_spi_reg_write(hw, val, reg); -+} -+ -+static inline void lq_spi_reg_clearbit(struct lq_spi *hw, u32 bits, u32 reg) -+{ -+ u32 val; -+ -+ val = lq_spi_reg_read(hw, reg); -+ val &= ~bits; -+ lq_spi_reg_write(hw, val, reg); -+} -+ -+static void lq_spi_hw_enable(struct lq_spi *hw) -+{ -+ u32 clc; -+ -+ /* Power-up mdule */ -+ lq_pmu_enable(PMU_SPI); -+ -+ /* -+ * Set clock divider for run mode to 1 to -+ * run at same frequency as FPI bus -+ */ -+ clc = (1 << LQ_SPI_CLC_RMC_SHIFT); -+ lq_spi_reg_write(hw, clc, LQ_SPI_CLC); -+} -+ -+static void lq_spi_hw_disable(struct lq_spi *hw) -+{ -+ /* Set clock divider to 0 and set module disable bit */ -+ lq_spi_reg_write(hw, LQ_SPI_CLC_DISS, LQ_SPI_CLC); -+ -+ /* Power-down mdule */ -+ lq_pmu_disable(PMU_SPI); -+} -+ -+static void lq_spi_reset_fifos(struct lq_spi *hw) -+{ -+ u32 val; -+ -+ /* -+ * Enable and flush FIFOs. Set interrupt trigger level to -+ * half of FIFO count implemented in hardware. -+ */ -+ if (hw->txfs > 1) { -+ val = hw->txfs << (LQ_SPI_TXFCON_TXFITL_SHIFT - 1); -+ val |= LQ_SPI_TXFCON_TXFEN | LQ_SPI_TXFCON_TXFLU; -+ lq_spi_reg_write(hw, val, LQ_SPI_TXFCON); -+ } -+ -+ if (hw->rxfs > 1) { -+ val = hw->rxfs << (LQ_SPI_RXFCON_RXFITL_SHIFT - 1); -+ val |= LQ_SPI_RXFCON_RXFEN | LQ_SPI_RXFCON_RXFLU; -+ lq_spi_reg_write(hw, val, LQ_SPI_RXFCON); -+ } -+} -+ -+static inline int lq_spi_wait_ready(struct lq_spi *hw) -+{ -+ u32 stat; -+ unsigned long timeout; -+ -+ timeout = jiffies + msecs_to_jiffies(200); -+ -+ do { -+ stat = lq_spi_reg_read(hw, LQ_SPI_STAT); -+ if (!(stat & LQ_SPI_STAT_BSY)) -+ return 0; -+ -+ cond_resched(); -+ } while (!time_after_eq(jiffies, timeout)); -+ -+ dev_err(hw->dev, "SPI wait ready timed out\n"); -+ -+ return -ETIMEDOUT; -+} -+ -+static void lq_spi_config_mode_set(struct lq_spi *hw) -+{ -+ if (hw->cfg_mode) -+ return; -+ -+ /* -+ * Putting the SPI module in config mode is only safe if no -+ * transfer is in progress as indicated by busy flag STATE.BSY. -+ */ -+ if (lq_spi_wait_ready(hw)) { -+ lq_spi_reset_fifos(hw); -+ hw->status = -ETIMEDOUT; -+ } -+ lq_spi_reg_write(hw, LQ_SPI_WHBSTATE_CLREN, LQ_SPI_WHBSTATE); -+ -+ hw->cfg_mode = 1; -+} -+ -+static void lq_spi_run_mode_set(struct lq_spi *hw) -+{ -+ if (!hw->cfg_mode) -+ return; -+ -+ lq_spi_reg_write(hw, LQ_SPI_WHBSTATE_SETEN, LQ_SPI_WHBSTATE); -+ -+ hw->cfg_mode = 0; -+} -+ -+static u32 lq_spi_tx_word_u8(struct lq_spi *hw) -+{ -+ const u8 *tx = hw->tx; -+ u32 data = *tx++; -+ -+ hw->tx_cnt++; -+ hw->tx++; -+ -+ return data; -+} -+ -+static u32 lq_spi_tx_word_u16(struct lq_spi *hw) -+{ -+ const u16 *tx = (u16 *) hw->tx; -+ u32 data = *tx++; -+ -+ hw->tx_cnt += 2; -+ hw->tx += 2; -+ -+ return data; -+} -+ -+static u32 lq_spi_tx_word_u32(struct lq_spi *hw) -+{ -+ const u32 *tx = (u32 *) hw->tx; -+ u32 data = *tx++; -+ -+ hw->tx_cnt += 4; -+ hw->tx += 4; -+ -+ return data; -+} -+ -+static void lq_spi_bits_per_word_set(struct spi_device *spi) -+{ -+ struct lq_spi *hw = lq_spi_to_hw(spi); -+ u32 bm; -+ u8 bits_per_word = spi->bits_per_word; -+ -+ /* -+ * Use either default value of SPI device or value -+ * from current transfer. -+ */ -+ if (hw->curr_transfer && hw->curr_transfer->bits_per_word) -+ bits_per_word = hw->curr_transfer->bits_per_word; -+ -+ if (bits_per_word <= 8) -+ hw->get_tx = lq_spi_tx_word_u8; -+ else if (bits_per_word <= 16) -+ hw->get_tx = lq_spi_tx_word_u16; -+ else if (bits_per_word <= 32) -+ hw->get_tx = lq_spi_tx_word_u32; -+ -+ /* CON.BM value = bits_per_word - 1 */ -+ bm = (bits_per_word - 1) << LQ_SPI_CON_BM_SHIFT; -+ -+ lq_spi_reg_clearbit(hw, LQ_SPI_CON_BM_MASK << -+ LQ_SPI_CON_BM_SHIFT, LQ_SPI_CON); -+ lq_spi_reg_setbit(hw, bm, LQ_SPI_CON); -+} -+ -+static void lq_spi_speed_set(struct spi_device *spi) -+{ -+ struct lq_spi *hw = lq_spi_to_hw(spi); -+ u32 br, max_speed_hz, spi_clk; -+ u32 speed_hz = spi->max_speed_hz; -+ -+ /* -+ * Use either default value of SPI device or value -+ * from current transfer. -+ */ -+ if (hw->curr_transfer && hw->curr_transfer->speed_hz) -+ speed_hz = hw->curr_transfer->speed_hz; -+ -+ /* -+ * 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); -+ -+ /* -+ * Maximum SPI clock frequency in master mode is half of -+ * SPI module clock frequency. Maximum reload value of -+ * baudrate generator BR is 2^16. -+ */ -+ max_speed_hz = spi_clk / 2; -+ if (speed_hz >= max_speed_hz) -+ br = 0; -+ else -+ br = (max_speed_hz / speed_hz) - 1; -+ -+ if (br > 0xFFFF) -+ br = 0xFFFF; -+ -+ lq_spi_reg_write(hw, br, LQ_SPI_BRT); -+} -+ -+static void lq_spi_clockmode_set(struct spi_device *spi) -+{ -+ struct lq_spi *hw = lq_spi_to_hw(spi); -+ u32 con; -+ -+ con = lq_spi_reg_read(hw, LQ_SPI_CON); -+ -+ /* -+ * SPI mode mapping in CON register: -+ * Mode CPOL CPHA CON.PO CON.PH -+ * 0 0 0 0 1 -+ * 1 0 1 0 0 -+ * 2 1 0 1 1 -+ * 3 1 1 1 0 -+ */ -+ if (spi->mode & SPI_CPHA) -+ con &= ~LQ_SPI_CON_PH; -+ else -+ con |= LQ_SPI_CON_PH; -+ -+ if (spi->mode & SPI_CPOL) -+ con |= LQ_SPI_CON_PO; -+ else -+ con &= ~LQ_SPI_CON_PO; -+ -+ /* Set heading control */ -+ if (spi->mode & SPI_LSB_FIRST) -+ con &= ~LQ_SPI_CON_HB; -+ else -+ con |= LQ_SPI_CON_HB; -+ -+ lq_spi_reg_write(hw, con, LQ_SPI_CON); -+} -+ -+static void lq_spi_xmit_set(struct lq_spi *hw, struct spi_transfer *t) -+{ -+ u32 con; -+ -+ con = lq_spi_reg_read(hw, LQ_SPI_CON); -+ -+ if (t) { -+ if (t->tx_buf && t->rx_buf) { -+ con &= ~(LQ_SPI_CON_TXOFF | LQ_SPI_CON_RXOFF); -+ } else if (t->rx_buf) { -+ con &= ~LQ_SPI_CON_RXOFF; -+ con |= LQ_SPI_CON_TXOFF; -+ } else if (t->tx_buf) { -+ con &= ~LQ_SPI_CON_TXOFF; -+ con |= LQ_SPI_CON_RXOFF; -+ } -+ } else -+ con |= (LQ_SPI_CON_TXOFF | LQ_SPI_CON_RXOFF); -+ -+ lq_spi_reg_write(hw, con, LQ_SPI_CON); -+} -+ -+static void lq_spi_gpio_cs_activate(struct spi_device *spi) -+{ -+ struct lq_spi_controller_data *cdata = spi->controller_data; -+ int val = spi->mode & SPI_CS_HIGH ? 1 : 0; -+ -+ gpio_set_value(cdata->gpio, val); -+} -+ -+static void lq_spi_gpio_cs_deactivate(struct spi_device *spi) -+{ -+ struct lq_spi_controller_data *cdata = spi->controller_data; -+ int val = spi->mode & SPI_CS_HIGH ? 0 : 1; -+ -+ gpio_set_value(cdata->gpio, val); -+} -+ -+static void lq_spi_internal_cs_activate(struct spi_device *spi) -+{ -+ struct lq_spi *hw = lq_spi_to_hw(spi); -+ u32 fgpo; -+ -+ fgpo = (1 << (spi->chip_select + LQ_SPI_FGPO_CLROUTN_SHIFT)); -+ lq_spi_reg_setbit(hw, fgpo, LQ_SPI_FGPO); -+} -+ -+static void lq_spi_internal_cs_deactivate(struct spi_device *spi) -+{ -+ struct lq_spi *hw = lq_spi_to_hw(spi); -+ u32 fgpo; -+ -+ fgpo = (1 << (spi->chip_select + LQ_SPI_FGPO_SETOUTN_SHIFT)); -+ lq_spi_reg_setbit(hw, fgpo, LQ_SPI_FGPO); -+} -+ -+static void lq_spi_chipselect(struct spi_device *spi, int cs) -+{ -+ struct lq_spi *hw = lq_spi_to_hw(spi); -+ struct lq_spi_controller_state *cstate = spi->controller_state; -+ -+ switch (cs) { -+ case BITBANG_CS_ACTIVE: -+ lq_spi_bits_per_word_set(spi); -+ lq_spi_speed_set(spi); -+ lq_spi_clockmode_set(spi); -+ lq_spi_run_mode_set(hw); -+ -+ cstate->cs_activate(spi); -+ break; -+ -+ case BITBANG_CS_INACTIVE: -+ cstate->cs_deactivate(spi); -+ -+ lq_spi_config_mode_set(hw); -+ -+ break; -+ } -+} -+ -+static int lq_spi_setup_transfer(struct spi_device *spi, -+ struct spi_transfer *t) -+{ -+ struct lq_spi *hw = lq_spi_to_hw(spi); -+ u8 bits_per_word = spi->bits_per_word; -+ -+ hw->curr_transfer = t; -+ -+ if (t && t->bits_per_word) -+ bits_per_word = t->bits_per_word; -+ -+ if (bits_per_word > 32) -+ return -EINVAL; -+ -+ lq_spi_config_mode_set(hw); -+ -+ return 0; -+} -+ -+static const struct lq_spi_cs_gpio_map lq_spi_cs[] = { -+ { 15, 1, 0 }, -+ { 22, 1, 0 }, -+ { 13, 0, 1 }, -+ { 10, 0, 1 }, -+ { 9, 0, 1 }, -+ { 11, 1, 1 }, -+}; -+ -+static int lq_spi_setup(struct spi_device *spi) -+{ -+ struct lq_spi *hw = lq_spi_to_hw(spi); -+ struct lq_spi_controller_data *cdata = spi->controller_data; -+ struct lq_spi_controller_state *cstate; -+ u32 gpocon, fgpo; -+ int ret; -+ -+ /* Set default word length to 8 if not set */ -+ if (!spi->bits_per_word) -+ spi->bits_per_word = 8; -+ -+ if (spi->bits_per_word > 32) -+ return -EINVAL; -+ -+ if (!spi->controller_state) { -+ cstate = kzalloc(sizeof(struct lq_spi_controller_state), -+ GFP_KERNEL); -+ if (!cstate) -+ return -ENOMEM; -+ -+ spi->controller_state = cstate; -+ } else -+ return 0; -+ -+ /* -+ * Up to six GPIOs can be connected to the SPI module -+ * via GPIO alternate function to control the chip select lines. -+ * For more flexibility in board layout this driver can also control -+ * the CS lines via GPIO API. If GPIOs should be used, board setup code -+ * have to register the SPI device with struct lq_spi_controller_data -+ * attached. -+ */ -+ if (cdata && cdata->gpio) { -+ ret = gpio_request(cdata->gpio, "spi-cs"); -+ if (ret) -+ return -EBUSY; -+ -+ ret = spi->mode & SPI_CS_HIGH ? 0 : 1; -+ gpio_direction_output(cdata->gpio, ret); -+ -+ cstate->cs_activate = lq_spi_gpio_cs_activate; -+ cstate->cs_deactivate = lq_spi_gpio_cs_deactivate; -+ } else { -+ ret = lq_gpio_request(lq_spi_cs[spi->chip_select].gpio, -+ lq_spi_cs[spi->chip_select].altsel0, -+ lq_spi_cs[spi->chip_select].altsel1, -+ 1, "spi-cs"); -+ if (ret) -+ return -EBUSY; -+ -+ gpocon = (1 << (spi->chip_select + -+ LQ_SPI_GPOCON_ISCSBN_SHIFT)); -+ -+ if (spi->mode & SPI_CS_HIGH) -+ gpocon |= (1 << spi->chip_select); -+ -+ fgpo = (1 << (spi->chip_select + LQ_SPI_FGPO_SETOUTN_SHIFT)); -+ -+ lq_spi_reg_setbit(hw, gpocon, LQ_SPI_GPOCON); -+ lq_spi_reg_setbit(hw, fgpo, LQ_SPI_FGPO); -+ -+ cstate->cs_activate = lq_spi_internal_cs_activate; -+ cstate->cs_deactivate = lq_spi_internal_cs_deactivate; -+ } -+ -+ return 0; -+} -+ -+static void lq_spi_cleanup(struct spi_device *spi) -+{ -+ struct lq_spi_controller_data *cdata = spi->controller_data; -+ struct lq_spi_controller_state *cstate = spi->controller_state; -+ unsigned gpio; -+ -+ if (cdata && cdata->gpio) -+ gpio = cdata->gpio; -+ else -+ gpio = lq_spi_cs[spi->chip_select].gpio; -+ -+ gpio_free(gpio); -+ kfree(cstate); -+} -+ -+static void lq_spi_txfifo_write(struct lq_spi *hw) -+{ -+ u32 fstat, data; -+ u16 fifo_space; -+ -+ /* Determine how much FIFOs are free for TX data */ -+ fstat = lq_spi_reg_read(hw, LQ_SPI_FSTAT); -+ fifo_space = hw->txfs - ((fstat >> LQ_SPI_FSTAT_TXFFL_SHIFT) & -+ LQ_SPI_FSTAT_TXFFL_MASK); -+ -+ if (!fifo_space) -+ return; -+ -+ while (hw->tx_cnt < hw->len && fifo_space) { -+ data = hw->get_tx(hw); -+ lq_spi_reg_write(hw, data, LQ_SPI_TB); -+ fifo_space--; -+ } -+} -+ -+static void lq_spi_rxfifo_read(struct lq_spi *hw) -+{ -+ u32 fstat, data, *rx32; -+ u16 fifo_fill; -+ u8 rxbv, shift, *rx8; -+ -+ /* Determine how much FIFOs are filled with RX data */ -+ fstat = lq_spi_reg_read(hw, LQ_SPI_FSTAT); -+ fifo_fill = ((fstat >> LQ_SPI_FSTAT_RXFFL_SHIFT) -+ & LQ_SPI_FSTAT_RXFFL_MASK); -+ -+ if (!fifo_fill) -+ return; -+ -+ /* -+ * The 32 bit FIFO is always used completely independent from the -+ * bits_per_word value. Thus four bytes have to be read at once -+ * per FIFO. -+ */ -+ rx32 = (u32 *) hw->rx; -+ while (hw->len - hw->rx_cnt >= 4 && fifo_fill) { -+ *rx32++ = lq_spi_reg_read(hw, LQ_SPI_RB); -+ hw->rx_cnt += 4; -+ hw->rx += 4; -+ fifo_fill--; -+ } -+ -+ /* -+ * If there are remaining bytes, read byte count from STAT.RXBV -+ * register and read the data byte-wise. -+ */ -+ while (fifo_fill && hw->rx_cnt < hw->len) { -+ rxbv = (lq_spi_reg_read(hw, LQ_SPI_STAT) >> -+ LQ_SPI_STAT_RXBV_SHIFT) & LQ_SPI_STAT_RXBV_MASK; -+ data = lq_spi_reg_read(hw, LQ_SPI_RB); -+ -+ shift = (rxbv - 1) * 8; -+ rx8 = hw->rx; -+ -+ while (rxbv) { -+ *rx8++ = (data >> shift) & 0xFF; -+ rxbv--; -+ shift -= 8; -+ hw->rx_cnt++; -+ hw->rx++; -+ } -+ -+ fifo_fill--; -+ } -+} -+ -+static void lq_spi_rxreq_set(struct lq_spi *hw) -+{ -+ u32 rxreq, rxreq_max, rxtodo; -+ -+ rxtodo = lq_spi_reg_read(hw, LQ_SPI_RXCNT) & LQ_SPI_RXCNT_TODO_MASK; -+ -+ /* -+ * In RX-only mode the serial clock is activated only after writing -+ * the expected amount of RX bytes into RXREQ register. -+ * To avoid receive overflows at high clocks it is better to request -+ * only the amount of bytes that fits into all FIFOs. This value -+ * depends on the FIFO size implemented in hardware. -+ */ -+ rxreq = hw->len - hw->rx_cnt; -+ rxreq_max = hw->rxfs << 2; -+ rxreq = min(rxreq_max, rxreq); -+ -+ if (!rxtodo && rxreq) -+ lq_spi_reg_write(hw, rxreq, LQ_SPI_RXREQ); -+} -+ -+static inline void lq_spi_complete(struct lq_spi *hw) -+{ -+ complete(&hw->done); -+} -+ -+irqreturn_t lq_spi_tx_irq(int irq, void *data) -+{ -+ struct lq_spi *hw = data; -+ unsigned long flags; -+ int completed = 0; -+ -+ spin_lock_irqsave(&hw->lock, flags); -+ -+ if (hw->tx_cnt < hw->len) -+ lq_spi_txfifo_write(hw); -+ -+ if (hw->tx_cnt == hw->len) -+ completed = 1; -+ -+ spin_unlock_irqrestore(&hw->lock, flags); -+ -+ if (completed) -+ lq_spi_complete(hw); -+ -+ return IRQ_HANDLED; -+} -+ -+irqreturn_t lq_spi_rx_irq(int irq, void *data) -+{ -+ struct lq_spi *hw = data; -+ unsigned long flags; -+ int completed = 0; -+ -+ spin_lock_irqsave(&hw->lock, flags); -+ -+ if (hw->rx_cnt < hw->len) { -+ lq_spi_rxfifo_read(hw); -+ -+ if (hw->tx && hw->tx_cnt < hw->len) -+ lq_spi_txfifo_write(hw); -+ } -+ -+ if (hw->rx_cnt == hw->len) -+ completed = 1; -+ else if (!hw->tx) -+ lq_spi_rxreq_set(hw); -+ -+ spin_unlock_irqrestore(&hw->lock, flags); -+ -+ if (completed) -+ lq_spi_complete(hw); -+ -+ return IRQ_HANDLED; -+} -+ -+irqreturn_t lq_spi_err_irq(int irq, void *data) -+{ -+ struct lq_spi *hw = data; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&hw->lock, flags); -+ -+ /* Disable all interrupts */ -+ lq_spi_reg_clearbit(hw, LQ_SPI_IRNEN_ALL, LQ_SPI_IRNEN); -+ -+ /* Clear all error flags */ -+ lq_spi_reg_write(hw, LQ_SPI_WHBSTATE_CLR_ERRORS, LQ_SPI_WHBSTATE); -+ -+ /* Flush FIFOs */ -+ lq_spi_reg_setbit(hw, LQ_SPI_RXFCON_RXFLU, LQ_SPI_RXFCON); -+ lq_spi_reg_setbit(hw, LQ_SPI_TXFCON_TXFLU, LQ_SPI_TXFCON); -+ -+ hw->status = -EIO; -+ spin_unlock_irqrestore(&hw->lock, flags); -+ -+ lq_spi_complete(hw); -+ -+ return IRQ_HANDLED; -+} -+ -+static int lq_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) -+{ -+ struct lq_spi *hw = lq_spi_to_hw(spi); -+ u32 irq_flags = 0; -+ -+ hw->tx = t->tx_buf; -+ hw->rx = t->rx_buf; -+ hw->len = t->len; -+ hw->tx_cnt = 0; -+ hw->rx_cnt = 0; -+ hw->status = 0; -+ INIT_COMPLETION(hw->done); -+ -+ lq_spi_xmit_set(hw, t); -+ -+ /* Enable error interrupts */ -+ lq_spi_reg_setbit(hw, LQ_SPI_IRNEN_E, LQ_SPI_IRNEN); -+ -+ if (hw->tx) { -+ /* Initially fill TX FIFO with as much data as possible */ -+ lq_spi_txfifo_write(hw); -+ irq_flags |= LQ_SPI_IRNEN_T; -+ -+ /* Always enable RX interrupt in Full Duplex mode */ -+ if (hw->rx) -+ irq_flags |= LQ_SPI_IRNEN_R; -+ } else if (hw->rx) { -+ /* Start RX clock */ -+ lq_spi_rxreq_set(hw); -+ -+ /* Enable RX interrupt to receive data from RX FIFOs */ -+ irq_flags |= LQ_SPI_IRNEN_R; -+ } -+ -+ /* Enable TX or RX interrupts */ -+ lq_spi_reg_setbit(hw, irq_flags, LQ_SPI_IRNEN); -+ wait_for_completion_interruptible(&hw->done); -+ -+ /* Disable all interrupts */ -+ lq_spi_reg_clearbit(hw, LQ_SPI_IRNEN_ALL, LQ_SPI_IRNEN); -+ -+ /* -+ * Return length of current transfer for bitbang utility code if -+ * no errors occured during transmission. -+ */ -+ if (!hw->status) -+ hw->status = hw->len; -+ -+ return hw->status; -+} -+ -+static const struct lq_spi_irq_map lq_spi_irqs[] = { -+ { "spi_tx", lq_spi_tx_irq }, -+ { "spi_rx", lq_spi_rx_irq }, -+ { "spi_err", lq_spi_err_irq }, -+}; -+ -+static int __init lq_spi_probe(struct platform_device *pdev) -+{ -+ struct spi_master *master; -+ struct resource *r; -+ struct lq_spi *hw; -+ struct lq_spi_platform_data *pdata = pdev->dev.platform_data; -+ int ret, i; -+ u32 data, id; -+ -+ master = spi_alloc_master(&pdev->dev, sizeof(struct lq_spi)); -+ if (!master) { -+ dev_err(&pdev->dev, "spi_alloc_master\n"); -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ hw = spi_master_get_devdata(master); -+ -+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (r == NULL) { -+ dev_err(&pdev->dev, "platform_get_resource\n"); -+ ret = -ENOENT; -+ goto err_master; -+ } -+ -+ r = devm_request_mem_region(&pdev->dev, r->start, resource_size(r), -+ pdev->name); -+ if (!r) { -+ dev_err(&pdev->dev, "devm_request_mem_region\n"); -+ ret = -ENXIO; -+ goto err_master; -+ } -+ -+ hw->base = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r)); -+ if (!hw->base) { -+ dev_err(&pdev->dev, "devm_ioremap_nocache\n"); -+ ret = -ENXIO; -+ goto err_master; -+ } -+ -+ hw->clk = clk_get(&pdev->dev, "fpi"); -+ if (IS_ERR(hw->clk)) { -+ dev_err(&pdev->dev, "clk_get\n"); -+ ret = PTR_ERR(hw->clk); -+ goto err_master; -+ } -+ -+ memset(hw->irq, 0, sizeof(hw->irq)); -+ for (i = 0; i < ARRAY_SIZE(lq_spi_irqs); i++) { -+ ret = platform_get_irq_byname(pdev, lq_spi_irqs[i].name); -+ if (0 > ret) { -+ dev_err(&pdev->dev, "platform_get_irq_byname\n"); -+ goto err_irq; -+ } -+ -+ hw->irq[i] = ret; -+ ret = request_irq(hw->irq[i], lq_spi_irqs[i].handler, -+ 0, lq_spi_irqs[i].name, hw); -+ if (ret) { -+ dev_err(&pdev->dev, "request_irq\n"); -+ goto err_irq; -+ } -+ } -+ -+ hw->bitbang.master = spi_master_get(master); -+ hw->bitbang.chipselect = lq_spi_chipselect; -+ hw->bitbang.setup_transfer = lq_spi_setup_transfer; -+ hw->bitbang.txrx_bufs = lq_spi_txrx_bufs; -+ -+ master->bus_num = pdev->id; -+ master->num_chipselect = pdata->num_chipselect; -+ master->setup = lq_spi_setup; -+ master->cleanup = lq_spi_cleanup; -+ -+ hw->dev = &pdev->dev; -+ init_completion(&hw->done); -+ spin_lock_init(&hw->lock); -+ -+ /* Set GPIO alternate functions to SPI */ -+ lq_gpio_request(LQ_SPI_GPIO_DI, 1, 0, 0, "spi-di"); -+ lq_gpio_request(LQ_SPI_GPIO_DO, 1, 0, 1, "spi-do"); -+ lq_gpio_request(LQ_SPI_GPIO_CLK, 1, 0, 1, "spi-clk"); -+ -+ lq_spi_hw_enable(hw); -+ -+ /* Read module capabilities */ -+ id = lq_spi_reg_read(hw, LQ_SPI_ID); -+ hw->txfs = (id >> LQ_SPI_ID_TXFS_SHIFT) & LQ_SPI_ID_TXFS_MASK; -+ hw->rxfs = (id >> LQ_SPI_ID_TXFS_SHIFT) & LQ_SPI_ID_TXFS_MASK; -+ hw->dma_support = (id & LQ_SPI_ID_CFG) ? 1 : 0; -+ -+ lq_spi_config_mode_set(hw); -+ -+ /* Enable error checking, disable TX/RX, set idle value high */ -+ data = LQ_SPI_CON_RUEN | LQ_SPI_CON_AEN | -+ LQ_SPI_CON_TEN | LQ_SPI_CON_REN | -+ LQ_SPI_CON_TXOFF | LQ_SPI_CON_RXOFF | LQ_SPI_CON_IDLE; -+ lq_spi_reg_write(hw, data, LQ_SPI_CON); -+ -+ /* Enable master mode and clear error flags */ -+ lq_spi_reg_write(hw, LQ_SPI_WHBSTATE_SETMS | -+ LQ_SPI_WHBSTATE_CLR_ERRORS, LQ_SPI_WHBSTATE); -+ -+ /* Reset GPIO/CS registers */ -+ lq_spi_reg_write(hw, 0x0, LQ_SPI_GPOCON); -+ lq_spi_reg_write(hw, 0xFF00, LQ_SPI_FGPO); -+ -+ /* Enable and flush FIFOs */ -+ lq_spi_reset_fifos(hw); -+ -+ ret = spi_bitbang_start(&hw->bitbang); -+ if (ret) { -+ dev_err(&pdev->dev, "spi_bitbang_start\n"); -+ goto err_bitbang; -+ } -+ -+ platform_set_drvdata(pdev, hw); -+ -+ pr_info("Lantiq SoC SPI controller rev %u (TXFS %u, RXFS %u, DMA %u)\n", -+ id & LQ_SPI_ID_REV_MASK, hw->txfs, hw->rxfs, hw->dma_support); -+ -+ return 0; -+ -+err_bitbang: -+ lq_spi_hw_disable(hw); -+ -+err_irq: -+ clk_put(hw->clk); -+ -+ for (; i > 0; i--) -+ free_irq(hw->irq[i], hw); -+ -+err_master: -+ spi_master_put(master); -+ -+err: -+ return ret; -+} -+ -+static int __exit lq_spi_remove(struct platform_device *pdev) -+{ -+ struct lq_spi *hw = platform_get_drvdata(pdev); -+ int ret, i; -+ -+ ret = spi_bitbang_stop(&hw->bitbang); -+ if (ret) -+ return ret; -+ -+ platform_set_drvdata(pdev, NULL); -+ -+ lq_spi_config_mode_set(hw); -+ lq_spi_hw_disable(hw); -+ -+ for (i = 0; i < ARRAY_SIZE(hw->irq); i++) -+ if (0 < hw->irq[i]) -+ free_irq(hw->irq[i], hw); -+ -+ gpio_free(LQ_SPI_GPIO_DI); -+ gpio_free(LQ_SPI_GPIO_DO); -+ gpio_free(LQ_SPI_GPIO_CLK); -+ -+ clk_put(hw->clk); -+ spi_master_put(hw->bitbang.master); -+ -+ return 0; -+} -+ -+static struct platform_driver lq_spi_driver = { -+ .driver = { -+ .name = "ltq-spi", -+ .owner = THIS_MODULE, -+ }, -+ .remove = __exit_p(lq_spi_remove), -+}; -+ -+static int __init lq_spi_init(void) -+{ -+ return platform_driver_probe(&lq_spi_driver, lq_spi_probe); -+} -+module_init(lq_spi_init); -+ -+static void __exit lq_spi_exit(void) -+{ -+ platform_driver_unregister(&lq_spi_driver); -+} -+module_exit(lq_spi_exit); -+ -+MODULE_DESCRIPTION("Lantiq SoC SPI controller driver"); -+MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:ltq-spi"); diff --git a/target/linux/lantiq/patches/942-spi3.patch b/target/linux/lantiq/patches/942-spi3.patch deleted file mode 100644 index c09125f..0000000 --- a/target/linux/lantiq/patches/942-spi3.patch +++ /dev/null @@ -1,66 +0,0 @@ -From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> -Date: Thu, 3 Mar 2011 20:42:26 +0000 (+0100) -Subject: MIPS: lantiq: Add device register helper for SPI controller and devices -X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=b35b07062b718ece9b9cb7b23b12d83a087eafb0;hp=653c95b8b9066c9c6ac08bd64d0ceee439e9fd90 - -MIPS: lantiq: Add device register helper for SPI controller and devices - -Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com> ---- - ---- a/arch/mips/lantiq/xway/devices.c -+++ b/arch/mips/lantiq/xway/devices.c -@@ -22,6 +22,7 @@ - #include <linux/gpio.h> - #include <linux/gpio_buttons.h> - #include <linux/leds.h> -+#include <linux/spi/spi.h> - - #include <asm/bootinfo.h> - #include <asm/irq.h> -@@ -332,5 +333,27 @@ - lantiq_emulate_madwifi_eep = 1; - } - -+static struct resource lq_spi_resources[] = { -+ { -+ .start = LQ_SSC_BASE_ADDR, -+ .end = LQ_SSC_BASE_ADDR + LQ_SSC_SIZE - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ IRQ_RES(spi_tx, LQ_SSC_TIR), -+ IRQ_RES(spi_rx, LQ_SSC_RIR), -+ IRQ_RES(spi_err, LQ_SSC_EIR), -+}; - -+static struct platform_device lq_spi = { -+ .name = "ltq-spi", -+ .resource = lq_spi_resources, -+ .num_resources = ARRAY_SIZE(lq_spi_resources), -+}; - -+void __init lq_register_spi(struct lq_spi_platform_data *pdata, -+ struct spi_board_info const *info, unsigned n) -+{ -+ spi_register_board_info(info, n); -+ lq_spi.dev.platform_data = pdata; -+ platform_device_register(&lq_spi); -+} ---- a/arch/mips/lantiq/xway/devices.h -+++ b/arch/mips/lantiq/xway/devices.h -@@ -11,6 +11,7 @@ - - #include <lantiq_platform.h> - #include <xway_irq.h> -+#include <linux/spi/spi.h> - - extern void __init lq_register_gpio(void); - extern void __init lq_register_gpio_stp(void); -@@ -25,5 +26,7 @@ - extern void __init lq_register_asc(int port); - extern void __init lq_register_gpio_buttons(struct gpio_button *buttons, int cnt); - extern void __init lq_register_crypto(const char *name); -+extern void lq_register_spi(struct lq_spi_platform_data *pdata, -+ struct spi_board_info const *info, unsigned n); - - #endif diff --git a/target/linux/lantiq/xway/config-2.6.32 b/target/linux/lantiq/xway/config-2.6.32 new file mode 100644 index 0000000..6444768 --- /dev/null +++ b/target/linux/lantiq/xway/config-2.6.32 @@ -0,0 +1,31 @@ +CONFIG_ADM6996_PHY=y +CONFIG_AR8216_PHY=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_DEVPORT=y +# CONFIG_DM9000 is not set +CONFIG_HW_HAS_PCI=y +# CONFIG_I2C_DESIGNWARE is not set +CONFIG_INPUT=y +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_GPIO_BUTTONS is not set +CONFIG_INPUT_POLLDEV=y +# CONFIG_INPUT_YEALINK is not set +# CONFIG_ISDN is not set +CONFIG_LANTIQ_ETOP=y +CONFIG_LANTIQ_MACH_ARV45XX=y +CONFIG_LANTIQ_MACH_EASY50712=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_RTL8306_PHY=y +# CONFIG_SOC_AMAZON_SE 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_MASTER=y +# CONFIG_SPI_SPIDEV is not set +# CONFIG_TC35815 is not set +CONFIG_USB_SUPPORT=y diff --git a/target/linux/lantiq/xway/config-default b/target/linux/lantiq/xway/config-default index bcd0521..ecb8970 100644 --- a/target/linux/lantiq/xway/config-default +++ b/target/linux/lantiq/xway/config-default @@ -1,8 +1,24 @@ 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_CRYPTO_ALGAPI=y CONFIG_CRYPTO_ALGAPI2=y -CONFIG_HAVE_IDE=y +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_HW_HAS_PCI=y CONFIG_INPUT=y CONFIG_INPUT_EVDEV=y @@ -11,17 +27,25 @@ CONFIG_INPUT_POLLDEV=y # CONFIG_ISDN is not set CONFIG_LANTIQ_ETOP=y CONFIG_LANTIQ_MACH_ARV45XX=y -CONFIG_LANTIQ_MACH_EASY4010=y CONFIG_LANTIQ_MACH_EASY50712=y -CONFIG_LANTIQ_MACH_EASY50812=y -# CONFIG_LANTIQ_PROM_ASC0 is not set -CONFIG_LANTIQ_PROM_ASC1=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_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PERF_USE_VMALLOC=y +# CONFIG_PREEMPT_RCU is not set +# CONFIG_QUOTACTL is not set CONFIG_RTL8306_PHY=y -# CONFIG_SOC_LANTIQ_FALCON is not set -CONFIG_SOC_LANTIQ_XWAY=y +# CONFIG_SOC_AMAZON_SE 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_SUPPORT=y +CONFIG_XZ_DEC=y diff --git a/target/linux/lantiq/xway/target.mk b/target/linux/lantiq/xway/target.mk index 7cc0d25..9891b44 100644 --- a/target/linux/lantiq/xway/target.mk +++ b/target/linux/lantiq/xway/target.mk @@ -3,8 +3,8 @@ SUBTARGET:=xway BOARDNAME:=Xway FEATURES:=squashfs jffs2 atm -DEFAULT_PACKAGES+=kmod-pppoa ppp-mod-pppoa linux-atm atm-tools br2684ctl kmod-ltq-dsl ltq-dsl-app +DEFAULT_PACKAGES+=kmod-pppoa ppp-mod-pppoa linux-atm atm-tools br2684ctl kmod-ltq-dsl ltq-dsl-app swconfig define Target/Description - Lantiq XWAY (danube/twinpass/ar9/ase) + Lantiq XWAY (danube/twinpass/ar9) endef |