From c278400c52c14203894c5dc0d63cf385239d8329 Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 10:54:51 -0400 Subject: C6X: build infrastructure Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann --- arch/c6x/Kconfig | 174 ++++++++++++++++++++++++++++++++++++ arch/c6x/Makefile | 60 +++++++++++++ arch/c6x/boot/Makefile | 30 +++++++ arch/c6x/configs/dsk6455_defconfig | 44 +++++++++ arch/c6x/configs/evmc6457_defconfig | 41 +++++++++ arch/c6x/configs/evmc6472_defconfig | 42 +++++++++ arch/c6x/configs/evmc6474_defconfig | 42 +++++++++ arch/c6x/include/asm/Kbuild | 54 +++++++++++ arch/c6x/kernel/Makefile | 12 +++ arch/c6x/kernel/vmlinux.lds.S | 162 +++++++++++++++++++++++++++++++++ arch/c6x/lib/Makefile | 7 ++ arch/c6x/mm/Makefile | 5 ++ arch/c6x/platforms/Kconfig | 16 ++++ arch/c6x/platforms/Makefile | 12 +++ 14 files changed, 701 insertions(+) create mode 100644 arch/c6x/Kconfig create mode 100644 arch/c6x/Makefile create mode 100644 arch/c6x/boot/Makefile create mode 100644 arch/c6x/configs/dsk6455_defconfig create mode 100644 arch/c6x/configs/evmc6457_defconfig create mode 100644 arch/c6x/configs/evmc6472_defconfig create mode 100644 arch/c6x/configs/evmc6474_defconfig create mode 100644 arch/c6x/include/asm/Kbuild create mode 100644 arch/c6x/kernel/Makefile create mode 100644 arch/c6x/kernel/vmlinux.lds.S create mode 100644 arch/c6x/lib/Makefile create mode 100644 arch/c6x/mm/Makefile create mode 100644 arch/c6x/platforms/Kconfig create mode 100644 arch/c6x/platforms/Makefile (limited to 'arch') diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig new file mode 100644 index 000000000000..26e67f0f0051 --- /dev/null +++ b/arch/c6x/Kconfig @@ -0,0 +1,174 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# + +config TMS320C6X + def_bool y + select CLKDEV_LOOKUP + select GENERIC_IRQ_SHOW + select HAVE_ARCH_TRACEHOOK + select HAVE_DMA_API_DEBUG + select HAVE_GENERIC_HARDIRQS + select HAVE_MEMBLOCK + select HAVE_SPARSE_IRQ + select OF + select OF_EARLY_FLATTREE + +config MMU + def_bool n + +config ZONE_DMA + def_bool y + +config FPU + def_bool n + +config HIGHMEM + def_bool n + +config NUMA + def_bool n + +config RWSEM_GENERIC_SPINLOCK + def_bool y + +config RWSEM_XCHGADD_ALGORITHM + def_bool n + +config GENERIC_CALIBRATE_DELAY + def_bool y + +config GENERIC_HWEIGHT + def_bool y + +config GENERIC_CLOCKEVENTS + def_bool y + +config GENERIC_CLOCKEVENTS_BROADCAST + bool + +config GENERIC_BUG + def_bool y + +config COMMON_CLKDEV + def_bool y + +config C6X_BIG_KERNEL + bool "Build a big kernel" + help + The C6X function call instruction has a limited range of +/- 2MiB. + This is sufficient for most kernels, but some kernel configurations + with lots of compiled-in functionality may require a larger range + for function calls. Use this option to have the compiler generate + function calls with 32-bit range. This will make the kernel both + larger and slower. + + If unsure, say N. + +source "init/Kconfig" + +# Use the generic interrupt handling code in kernel/irq/ + +source "kernel/Kconfig.freezer" + +config CMDLINE_BOOL + bool "Default bootloader kernel arguments" + +config CMDLINE + string "Kernel command line" + depends on CMDLINE_BOOL + default "console=ttyS0,57600" + help + On some architectures there is currently no way for the boot loader + to pass arguments to the kernel. For these architectures, you should + supply some command-line options at build time by entering them + here. + +config CMDLINE_FORCE + bool "Force default kernel command string" + depends on CMDLINE_BOOL + default n + help + Set this to have arguments from the default kernel command string + override those passed by the boot loader. + +config CPU_BIG_ENDIAN + bool "Build big-endian kernel" + default n + help + Say Y if you plan on running a kernel in big-endian mode. + Note that your board must be properly built and your board + port must properly enable any big-endian related features + of your chipset/board/processor. + +config FORCE_MAX_ZONEORDER + int "Maximum zone order" + default "13" + help + The kernel memory allocator divides physically contiguous memory + blocks into "zones", where each zone is a power of two number of + pages. This option selects the largest power of two that the kernel + keeps in the memory allocator. If you need to allocate very large + blocks of physically contiguous memory, then you may need to + increase this value. + + This config option is actually maximum order plus one. For example, + a value of 11 means that the largest free memory block is 2^10 pages. + +menu "Processor type and features" + +source "arch/c6x/platforms/Kconfig" + +config TMS320C6X_CACHES_ON + bool "L2 cache support" + default y + +config KERNEL_RAM_BASE_ADDRESS + hex "Virtual address of memory base" + default 0xe0000000 if SOC_TMS320C6455 + default 0xe0000000 if SOC_TMS320C6457 + default 0xe0000000 if SOC_TMS320C6472 + default 0x80000000 + +source "mm/Kconfig" + +source "kernel/Kconfig.preempt" + +source "kernel/Kconfig.hz" +source "kernel/time/Kconfig" + +endmenu + +menu "Executable file formats" + +source "fs/Kconfig.binfmt" + +endmenu + +source "net/Kconfig" + +source "drivers/Kconfig" + +source "fs/Kconfig" + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config ACCESS_CHECK + bool "Check the user pointer address" + default y + help + Usually the pointer transfer from user space is checked to see if its + address is in the kernel space. + + Say N here to disable that check to improve the performance. + +endmenu diff --git a/arch/c6x/Makefile b/arch/c6x/Makefile new file mode 100644 index 000000000000..1d08dd070277 --- /dev/null +++ b/arch/c6x/Makefile @@ -0,0 +1,60 @@ +# +# linux/arch/c6x/Makefile +# +# 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. +# + +cflags-y += -mno-dsbt -msdata=none + +cflags-$(CONFIG_C6X_BIG_KERNEL) += -mlong-calls + +CFLAGS_MODULE += -mlong-calls -mno-dsbt -msdata=none + +CHECKFLAGS += + +KBUILD_CFLAGS += $(cflags-y) +KBUILD_AFLAGS += $(cflags-y) + +ifdef CONFIG_CPU_BIG_ENDIAN +KBUILD_CFLAGS += -mbig-endian +KBUILD_AFLAGS += -mbig-endian +LINKFLAGS += -mbig-endian +KBUILD_LDFLAGS += -mbig-endian +LDFLAGS += -EB +endif + +head-y := arch/c6x/kernel/head.o +core-y += arch/c6x/kernel/ arch/c6x/mm/ arch/c6x/platforms/ +libs-y += arch/c6x/lib/ + +# Default to vmlinux.bin, override when needed +all: vmlinux.bin + +boot := arch/$(ARCH)/boot + +# Are we making a dtbImage. target? If so, crack out the boardname +DTB:=$(subst dtbImage.,,$(filter dtbImage.%, $(MAKECMDGOALS))) +export DTB + +ifneq ($(DTB),) +core-y += $(boot)/ +endif + +# With make 3.82 we cannot mix normal and wildcard targets + +vmlinux.bin: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@) + +dtbImage.%: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@) + +archclean: + $(Q)$(MAKE) $(clean)=$(boot) + +define archhelp + @echo ' vmlinux.bin - Binary kernel image (arch/$(ARCH)/boot/vmlinux.bin)' + @echo ' dtbImage.
- ELF image with $(arch)/boot/dts/
.dts linked in' + @echo ' - stripped elf with fdt blob' +endef diff --git a/arch/c6x/boot/Makefile b/arch/c6x/boot/Makefile new file mode 100644 index 000000000000..ecca820e6041 --- /dev/null +++ b/arch/c6x/boot/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for bootable kernel images +# + +OBJCOPYFLAGS_vmlinux.bin := -O binary +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +DTC_FLAGS ?= -p 1024 + +ifneq ($(DTB),) +obj-y += linked_dtb.o +endif + +$(obj)/%.dtb: $(src)/dts/%.dts FORCE + $(call cmd,dtc) + +quiet_cmd_cp = CP $< $@$2 + cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false) + +# Generate builtin.dtb from $(DTB).dtb +$(obj)/builtin.dtb: $(obj)/$(DTB).dtb + $(call if_changed,cp) + +$(obj)/linked_dtb.o: $(obj)/builtin.dtb + +$(obj)/dtbImage.%: vmlinux + $(call if_changed,objcopy) + +clean-files := $(obj)/*.dtb diff --git a/arch/c6x/configs/dsk6455_defconfig b/arch/c6x/configs/dsk6455_defconfig new file mode 100644 index 000000000000..4663487c67a1 --- /dev/null +++ b/arch/c6x/configs/dsk6455_defconfig @@ -0,0 +1,44 @@ +CONFIG_SOC_TMS320C6455=y +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_SPARSE_IRQ=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EXPERT=y +# CONFIG_FUTEX is not set +# CONFIG_SLUB_DEBUG is not set +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="" +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=2 +CONFIG_BLK_DEV_RAM_SIZE=17000 +CONFIG_MISC_DEVICES=y +# CONFIG_INPUT is not set +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_CRC16=y +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +CONFIG_MTD=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_PHYSMAP_OF=y diff --git a/arch/c6x/configs/evmc6457_defconfig b/arch/c6x/configs/evmc6457_defconfig new file mode 100644 index 000000000000..bba40e195ec4 --- /dev/null +++ b/arch/c6x/configs/evmc6457_defconfig @@ -0,0 +1,41 @@ +CONFIG_SOC_TMS320C6457=y +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_SPARSE_IRQ=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EXPERT=y +# CONFIG_FUTEX is not set +# CONFIG_SLUB_DEBUG is not set +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="" +CONFIG_BOARD_EVM6457=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=2 +CONFIG_BLK_DEV_RAM_SIZE=17000 +CONFIG_MISC_DEVICES=y +# CONFIG_INPUT is not set +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_CRC16=y +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_BUGVERBOSE is not set diff --git a/arch/c6x/configs/evmc6472_defconfig b/arch/c6x/configs/evmc6472_defconfig new file mode 100644 index 000000000000..8c46155f6d31 --- /dev/null +++ b/arch/c6x/configs/evmc6472_defconfig @@ -0,0 +1,42 @@ +CONFIG_SOC_TMS320C6472=y +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_SPARSE_IRQ=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EXPERT=y +# CONFIG_FUTEX is not set +# CONFIG_SLUB_DEBUG is not set +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_FORCE is not set +CONFIG_BOARD_EVM6472=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=2 +CONFIG_BLK_DEV_RAM_SIZE=17000 +CONFIG_MISC_DEVICES=y +# CONFIG_INPUT is not set +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_CRC16=y +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_BUGVERBOSE is not set diff --git a/arch/c6x/configs/evmc6474_defconfig b/arch/c6x/configs/evmc6474_defconfig new file mode 100644 index 000000000000..15533f632313 --- /dev/null +++ b/arch/c6x/configs/evmc6474_defconfig @@ -0,0 +1,42 @@ +CONFIG_SOC_TMS320C6474=y +CONFIG_EXPERIMENTAL=y +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_SYSVIPC=y +CONFIG_SPARSE_IRQ=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EXPERT=y +# CONFIG_FUTEX is not set +# CONFIG_SLUB_DEBUG is not set +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_FORCE is not set +CONFIG_BOARD_EVM6474=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=2 +CONFIG_BLK_DEV_RAM_SIZE=17000 +CONFIG_MISC_DEVICES=y +# CONFIG_INPUT is not set +# CONFIG_SERIO is not set +# CONFIG_VT is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_HWMON is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_MISC_FILESYSTEMS is not set +CONFIG_CRC16=y +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_BUGVERBOSE is not set diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild new file mode 100644 index 000000000000..13dcf78adf91 --- /dev/null +++ b/arch/c6x/include/asm/Kbuild @@ -0,0 +1,54 @@ +include include/asm-generic/Kbuild.asm + +generic-y += atomic.h +generic-y += auxvec.h +generic-y += bitsperlong.h +generic-y += bug.h +generic-y += bugs.h +generic-y += cputime.h +generic-y += current.h +generic-y += device.h +generic-y += div64.h +generic-y += dma.h +generic-y += emergency-restart.h +generic-y += errno.h +generic-y += fb.h +generic-y += fcntl.h +generic-y += futex.h +generic-y += hw_irq.h +generic-y += io.h +generic-y += ioctl.h +generic-y += ioctls.h +generic-y += ipcbuf.h +generic-y += irq_regs.h +generic-y += kdebug.h +generic-y += kmap_types.h +generic-y += local.h +generic-y += mman.h +generic-y += mmu_context.h +generic-y += msgbuf.h +generic-y += param.h +generic-y += pci.h +generic-y += percpu.h +generic-y += pgalloc.h +generic-y += poll.h +generic-y += posix_types.h +generic-y += resource.h +generic-y += scatterlist.h +generic-y += segment.h +generic-y += sembuf.h +generic-y += shmbuf.h +generic-y += shmparam.h +generic-y += siginfo.h +generic-y += socket.h +generic-y += sockios.h +generic-y += stat.h +generic-y += statfs.h +generic-y += termbits.h +generic-y += termios.h +generic-y += tlbflush.h +generic-y += topology.h +generic-y += types.h +generic-y += ucontext.h +generic-y += user.h +generic-y += vga.h diff --git a/arch/c6x/kernel/Makefile b/arch/c6x/kernel/Makefile new file mode 100644 index 000000000000..580a515a9443 --- /dev/null +++ b/arch/c6x/kernel/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for arch/c6x/kernel/ +# + +extra-y := head.o vmlinux.lds + +obj-y := process.o traps.o irq.o signal.o ptrace.o +obj-y += setup.o sys_c6x.o time.o devicetree.o +obj-y += switch_to.o entry.o vectors.o c6x_ksyms.o +obj-y += soc.o dma.o + +obj-$(CONFIG_MODULES) += module.o diff --git a/arch/c6x/kernel/vmlinux.lds.S b/arch/c6x/kernel/vmlinux.lds.S new file mode 100644 index 000000000000..1d81c4c129ec --- /dev/null +++ b/arch/c6x/kernel/vmlinux.lds.S @@ -0,0 +1,162 @@ +/* + * ld script for the c6x kernel + * + * Copyright (C) 2010, 2011 Texas Instruments Incorporated + * Mark Salter + */ +#include +#include +#include + +ENTRY(_c_int00) + +#if defined(CONFIG_CPU_BIG_ENDIAN) +jiffies = jiffies_64 + 4; +#else +jiffies = jiffies_64; +#endif + +#define READONLY_SEGMENT_START \ + . = PAGE_OFFSET; +#define READWRITE_SEGMENT_START \ + . = ALIGN(128); \ + _data_lma = .; + +SECTIONS +{ + /* + * Start kernel read only segment + */ + READONLY_SEGMENT_START + + .vectors : + { + _vectors_start = .; + *(.vectors) + . = ALIGN(0x400); + _vectors_end = .; + } + + . = ALIGN(0x1000); + .cmdline : + { + *(.cmdline) + } + + /* + * This section contains data which may be shared with other + * cores. It needs to be a fixed offset from PAGE_OFFSET + * regardless of kernel configuration. + */ + .virtio_ipc_dev : + { + *(.virtio_ipc_dev) + } + + . = ALIGN(PAGE_SIZE); + .init : + { + _stext = .; + _sinittext = .; + HEAD_TEXT + INIT_TEXT + _einittext = .; + } + + __init_begin = _stext; + INIT_DATA_SECTION(16) + + PERCPU_SECTION(128) + + . = ALIGN(PAGE_SIZE); + __init_end = .; + + .text : + { + _text = .; + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT + IRQENTRY_TEXT + KPROBES_TEXT + *(.fixup) + *(.gnu.warning) + } + + EXCEPTION_TABLE(16) + NOTES + + RO_DATA_SECTION(PAGE_SIZE) + .const : + { + *(.const .const.* .gnu.linkonce.r.*) + *(.switch) + } + + . = ALIGN (8) ; + __fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) + { + _fdt_start = . ; /* place for fdt blob */ + *(__fdt_blob) ; /* Any link-placed DTB */ + BYTE(0); /* section always has contents */ + . = _fdt_start + 0x4000; /* Pad up to 16kbyte */ + _fdt_end = . ; + } + + _etext = .; + + /* + * Start kernel read-write segment. + */ + READWRITE_SEGMENT_START + _sdata = .; + + .fardata : AT(ADDR(.fardata) - LOAD_OFFSET) + { + INIT_TASK_DATA(THREAD_SIZE) + NOSAVE_DATA + PAGE_ALIGNED_DATA(PAGE_SIZE) + CACHELINE_ALIGNED_DATA(128) + READ_MOSTLY_DATA(128) + DATA_DATA + CONSTRUCTORS + *(.data1) + *(.fardata .fardata.*) + *(.data.debug_bpt) + } + + .neardata ALIGN(8) : AT(ADDR(.neardata) - LOAD_OFFSET) + { + *(.neardata2 .neardata2.* .gnu.linkonce.s2.*) + *(.neardata .neardata.* .gnu.linkonce.s.*) + . = ALIGN(8); + } + + _edata = .; + + __bss_start = .; + SBSS(8) + BSS(8) + .far : + { + . = ALIGN(8); + *(.dynfar) + *(.far .far.* .gnu.linkonce.b.*) + . = ALIGN(8); + } + __bss_stop = .; + + _end = .; + + DWARF_DEBUG + + /DISCARD/ : + { + EXIT_TEXT + EXIT_DATA + EXIT_CALL + *(.discard) + *(.discard.*) + *(.interp) + } +} diff --git a/arch/c6x/lib/Makefile b/arch/c6x/lib/Makefile new file mode 100644 index 000000000000..ffd3c659091a --- /dev/null +++ b/arch/c6x/lib/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for arch/c6x/lib/ +# + +lib-y := divu.o divi.o pop_rts.o push_rts.o remi.o remu.o strasgi.o llshru.o +lib-y += llshr.o llshl.o negll.o mpyll.o divremi.o divremu.o +lib-y += checksum.o csum_64plus.o memcpy_64plus.o strasgi_64plus.o diff --git a/arch/c6x/mm/Makefile b/arch/c6x/mm/Makefile new file mode 100644 index 000000000000..136a97576c61 --- /dev/null +++ b/arch/c6x/mm/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the linux c6x-specific parts of the memory manager. +# + +obj-y := init.o dma-coherent.o diff --git a/arch/c6x/platforms/Kconfig b/arch/c6x/platforms/Kconfig new file mode 100644 index 000000000000..401ee678fd01 --- /dev/null +++ b/arch/c6x/platforms/Kconfig @@ -0,0 +1,16 @@ + +config SOC_TMS320C6455 + bool "TMS320C6455" + default n + +config SOC_TMS320C6457 + bool "TMS320C6457" + default n + +config SOC_TMS320C6472 + bool "TMS320C6472" + default n + +config SOC_TMS320C6474 + bool "TMS320C6474" + default n diff --git a/arch/c6x/platforms/Makefile b/arch/c6x/platforms/Makefile new file mode 100644 index 000000000000..9a95b9bca8d0 --- /dev/null +++ b/arch/c6x/platforms/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for arch/c6x/platforms +# +# Copyright 2010, 2011 Texas Instruments Incorporated +# + +obj-y = platform.o cache.o megamod-pic.o pll.o plldata.o timer64.o +obj-y += dscr.o + +# SoC objects +obj-$(CONFIG_SOC_TMS320C6455) += emif.o +obj-$(CONFIG_SOC_TMS320C6457) += emif.o -- cgit v1.2.3 From c1a144d77a6ca3a14ba3c0fec30bc4fd20b3d817 Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 11:00:02 -0400 Subject: C6X: early boot code Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter This patch provides the early boot code for C6X architecture. There is a 16 entry vector table which is used to direct reset and interrupt events. The vector table entries contain a small amount of code (maximum of 8 opcodes) which simply branches to the actual event handling code. The head.S code simply clears BSS, setups up a few control registers, and calls machine_init followed by start_kernel. The machine_init code in setup.c does the early flat tree parsing (memory, commandline, etc). At setup_arch time, the code does the usual memory setup and minimally scans the devicetree for any needed information. Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann --- arch/c6x/kernel/head.S | 84 ++++++++ arch/c6x/kernel/setup.c | 498 ++++++++++++++++++++++++++++++++++++++++++++++ arch/c6x/kernel/vectors.S | 81 ++++++++ 3 files changed, 663 insertions(+) create mode 100644 arch/c6x/kernel/head.S create mode 100644 arch/c6x/kernel/setup.c create mode 100644 arch/c6x/kernel/vectors.S (limited to 'arch') diff --git a/arch/c6x/kernel/head.S b/arch/c6x/kernel/head.S new file mode 100644 index 000000000000..133eab6edf6b --- /dev/null +++ b/arch/c6x/kernel/head.S @@ -0,0 +1,84 @@ +; +; Port on Texas Instruments TMS320C6x architecture +; +; Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated +; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 +#include +#include + + __HEAD +ENTRY(_c_int00) + ;; Save magic and pointer + MV .S1 A4,A10 + MV .S2 B4,B10 + MVKL .S2 __bss_start,B5 + MVKH .S2 __bss_start,B5 + MVKL .S2 __bss_stop,B6 + MVKH .S2 __bss_stop,B6 + SUB .L2 B6,B5,B6 ; bss size + + ;; Set the stack pointer + MVKL .S2 current_ksp,B0 + MVKH .S2 current_ksp,B0 + LDW .D2T2 *B0,B15 + + ;; clear bss + SHR .S2 B6,3,B0 ; number of dwords to clear + ZERO .L2 B13 + ZERO .L2 B12 +bss_loop: + BDEC .S2 bss_loop,B0 + NOP 3 + CMPLT .L2 B0,0,B1 + [!B1] STDW .D2T2 B13:B12,*B5++[1] + + NOP 4 + AND .D2 ~7,B15,B15 + + ;; Clear GIE and PGIE + MVC .S2 CSR,B2 + CLR .S2 B2,0,1,B2 + MVC .S2 B2,CSR + MVC .S2 TSR,B2 + CLR .S2 B2,0,1,B2 + MVC .S2 B2,TSR + MVC .S2 ITSR,B2 + CLR .S2 B2,0,1,B2 + MVC .S2 B2,ITSR + MVC .S2 NTSR,B2 + CLR .S2 B2,0,1,B2 + MVC .S2 B2,NTSR + + ;; pass DTB pointer to machine_init (or zero if none) + MVKL .S1 OF_DT_HEADER,A0 + MVKH .S1 OF_DT_HEADER,A0 + CMPEQ .L1 A10,A0,A0 + [A0] MV .S1X B10,A4 + [!A0] MVK .S1 0,A4 + +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 machine_init,A0 + MVKH .S1 machine_init,A0 + B .S2X A0 + ADDKPC .S2 0f,B3,4 +0: +#else + CALLP .S2 machine_init,B3 +#endif + + ;; Jump to Linux init +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 start_kernel,A0 + MVKH .S1 start_kernel,A0 + B .S2X A0 +#else + B .S2 start_kernel +#endif + NOP 5 +L1: BNOP .S2 L1,5 diff --git a/arch/c6x/kernel/setup.c b/arch/c6x/kernel/setup.c new file mode 100644 index 000000000000..3c2858f0d91e --- /dev/null +++ b/arch/c6x/kernel/setup.c @@ -0,0 +1,498 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include + +static const char *c6x_soc_name; + +int c6x_num_cores; +EXPORT_SYMBOL_GPL(c6x_num_cores); + +unsigned int c6x_silicon_rev; +EXPORT_SYMBOL_GPL(c6x_silicon_rev); + +/* + * Device status register. This holds information + * about device configuration needed by some drivers. + */ +unsigned int c6x_devstat; +EXPORT_SYMBOL_GPL(c6x_devstat); + +/* + * Some SoCs have fuse registers holding a unique MAC + * address. This is parsed out of the device tree with + * the resulting MAC being held here. + */ +unsigned char c6x_fuse_mac[6]; + +unsigned long memory_start; +unsigned long memory_end; + +unsigned long ram_start; +unsigned long ram_end; + +/* Uncached memory for DMA consistent use (memdma=) */ +static unsigned long dma_start __initdata; +static unsigned long dma_size __initdata; + +char c6x_command_line[COMMAND_LINE_SIZE]; + +#if defined(CONFIG_CMDLINE_BOOL) +static const char default_command_line[COMMAND_LINE_SIZE] __section(.cmdline) = + CONFIG_CMDLINE; +#endif + +struct cpuinfo_c6x { + const char *cpu_name; + const char *cpu_voltage; + const char *mmu; + const char *fpu; + char *cpu_rev; + unsigned int core_id; + char __cpu_rev[5]; +}; + +static DEFINE_PER_CPU(struct cpuinfo_c6x, cpu_data); + +unsigned int ticks_per_ns_scaled; +EXPORT_SYMBOL(ticks_per_ns_scaled); + +unsigned int c6x_core_freq; + +static void __init get_cpuinfo(void) +{ + unsigned cpu_id, rev_id, csr; + struct clk *coreclk = clk_get_sys(NULL, "core"); + unsigned long core_khz; + u64 tmp; + struct cpuinfo_c6x *p; + struct device_node *node, *np; + + p = &per_cpu(cpu_data, smp_processor_id()); + + if (!IS_ERR(coreclk)) + c6x_core_freq = clk_get_rate(coreclk); + else { + printk(KERN_WARNING + "Cannot find core clock frequency. Using 700MHz\n"); + c6x_core_freq = 700000000; + } + + core_khz = c6x_core_freq / 1000; + + tmp = (uint64_t)core_khz << C6X_NDELAY_SCALE; + do_div(tmp, 1000000); + ticks_per_ns_scaled = tmp; + + csr = get_creg(CSR); + cpu_id = csr >> 24; + rev_id = (csr >> 16) & 0xff; + + p->mmu = "none"; + p->fpu = "none"; + p->cpu_voltage = "unknown"; + + switch (cpu_id) { + case 0: + p->cpu_name = "C67x"; + p->fpu = "yes"; + break; + case 2: + p->cpu_name = "C62x"; + break; + case 8: + p->cpu_name = "C64x"; + break; + case 12: + p->cpu_name = "C64x"; + break; + case 16: + p->cpu_name = "C64x+"; + p->cpu_voltage = "1.2"; + break; + default: + p->cpu_name = "unknown"; + break; + } + + if (cpu_id < 16) { + switch (rev_id) { + case 0x1: + if (cpu_id > 8) { + p->cpu_rev = "DM640/DM641/DM642/DM643"; + p->cpu_voltage = "1.2 - 1.4"; + } else { + p->cpu_rev = "C6201"; + p->cpu_voltage = "2.5"; + } + break; + case 0x2: + p->cpu_rev = "C6201B/C6202/C6211"; + p->cpu_voltage = "1.8"; + break; + case 0x3: + p->cpu_rev = "C6202B/C6203/C6204/C6205"; + p->cpu_voltage = "1.5"; + break; + case 0x201: + p->cpu_rev = "C6701 revision 0 (early CPU)"; + p->cpu_voltage = "1.8"; + break; + case 0x202: + p->cpu_rev = "C6701/C6711/C6712"; + p->cpu_voltage = "1.8"; + break; + case 0x801: + p->cpu_rev = "C64x"; + p->cpu_voltage = "1.5"; + break; + default: + p->cpu_rev = "unknown"; + } + } else { + p->cpu_rev = p->__cpu_rev; + snprintf(p->__cpu_rev, sizeof(p->__cpu_rev), "0x%x", cpu_id); + } + + p->core_id = get_coreid(); + + node = of_find_node_by_name(NULL, "cpus"); + if (node) { + for_each_child_of_node(node, np) + if (!strcmp("cpu", np->name)) + ++c6x_num_cores; + of_node_put(node); + } + + node = of_find_node_by_name(NULL, "soc"); + if (node) { + if (of_property_read_string(node, "model", &c6x_soc_name)) + c6x_soc_name = "unknown"; + of_node_put(node); + } else + c6x_soc_name = "unknown"; + + printk(KERN_INFO "CPU%d: %s rev %s, %s volts, %uMHz\n", + p->core_id, p->cpu_name, p->cpu_rev, + p->cpu_voltage, c6x_core_freq / 1000000); +} + +/* + * Early parsing of the command line + */ +static u32 mem_size __initdata; + +/* "mem=" parsing. */ +static int __init early_mem(char *p) +{ + if (!p) + return -EINVAL; + + mem_size = memparse(p, &p); + /* don't remove all of memory when handling "mem={invalid}" */ + if (mem_size == 0) + return -EINVAL; + + return 0; +} +early_param("mem", early_mem); + +/* "memdma=[@
]" parsing. */ +static int __init early_memdma(char *p) +{ + if (!p) + return -EINVAL; + + dma_size = memparse(p, &p); + if (*p == '@') + dma_start = memparse(p, &p); + + return 0; +} +early_param("memdma", early_memdma); + +int __init c6x_add_memory(phys_addr_t start, unsigned long size) +{ + static int ram_found __initdata; + + /* We only handle one bank (the one with PAGE_OFFSET) for now */ + if (ram_found) + return -EINVAL; + + if (start > PAGE_OFFSET || PAGE_OFFSET >= (start + size)) + return 0; + + ram_start = start; + ram_end = start + size; + + ram_found = 1; + return 0; +} + +/* + * Do early machine setup and device tree parsing. This is called very + * early on the boot process. + */ +notrace void __init machine_init(unsigned long dt_ptr) +{ + struct boot_param_header *dtb = __va(dt_ptr); + struct boot_param_header *fdt = (struct boot_param_header *)_fdt_start; + + /* interrupts must be masked */ + set_creg(IER, 2); + + /* + * Set the Interrupt Service Table (IST) to the beginning of the + * vector table. + */ + set_ist(_vectors_start); + + lockdep_init(); + + /* + * dtb is passed in from bootloader. + * fdt is linked in blob. + */ + if (dtb && dtb != fdt) + fdt = dtb; + + /* Do some early initialization based on the flat device tree */ + early_init_devtree(fdt); + + /* parse_early_param needs a boot_command_line */ + strlcpy(boot_command_line, c6x_command_line, COMMAND_LINE_SIZE); + parse_early_param(); +} + +void __init setup_arch(char **cmdline_p) +{ + int bootmap_size; + struct memblock_region *reg; + + printk(KERN_INFO "Initializing kernel\n"); + + /* Initialize command line */ + *cmdline_p = c6x_command_line; + + memblock_init(); + + memory_end = ram_end; + memory_end &= ~(PAGE_SIZE - 1); + + if (mem_size && (PAGE_OFFSET + PAGE_ALIGN(mem_size)) < memory_end) + memory_end = PAGE_OFFSET + PAGE_ALIGN(mem_size); + + /* add block that this kernel can use */ + memblock_add(PAGE_OFFSET, memory_end - PAGE_OFFSET); + + /* reserve kernel text/data/bss */ + memblock_reserve(PAGE_OFFSET, + PAGE_ALIGN((unsigned long)&_end - PAGE_OFFSET)); + + if (dma_size) { + /* align to cacheability granularity */ + dma_size = CACHE_REGION_END(dma_size); + + if (!dma_start) + dma_start = memory_end - dma_size; + + /* align to cacheability granularity */ + dma_start = CACHE_REGION_START(dma_start); + + /* reserve DMA memory taken from kernel memory */ + if (memblock_is_region_memory(dma_start, dma_size)) + memblock_reserve(dma_start, dma_size); + } + + memory_start = PAGE_ALIGN((unsigned int) &_end); + + printk(KERN_INFO "Memory Start=%08lx, Memory End=%08lx\n", + memory_start, memory_end); + +#ifdef CONFIG_BLK_DEV_INITRD + /* + * Reserve initrd memory if in kernel memory. + */ + if (initrd_start < initrd_end) + if (memblock_is_region_memory(initrd_start, + initrd_end - initrd_start)) + memblock_reserve(initrd_start, + initrd_end - initrd_start); +#endif + + init_mm.start_code = (unsigned long) &_stext; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = memory_start; + init_mm.brk = memory_start; + + /* + * Give all the memory to the bootmap allocator, tell it to put the + * boot mem_map at the start of memory + */ + bootmap_size = init_bootmem_node(NODE_DATA(0), + memory_start >> PAGE_SHIFT, + PAGE_OFFSET >> PAGE_SHIFT, + memory_end >> PAGE_SHIFT); + memblock_reserve(memory_start, bootmap_size); + + memblock_analyze(); + unflatten_device_tree(); + + c6x_cache_init(); + + /* Set the whole external memory as non-cacheable */ + disable_caching(ram_start, ram_end - 1); + + /* Set caching of external RAM used by Linux */ + for_each_memblock(memory, reg) + enable_caching(CACHE_REGION_START(reg->base), + CACHE_REGION_START(reg->base + reg->size - 1)); + +#ifdef CONFIG_BLK_DEV_INITRD + /* + * Enable caching for initrd which falls outside kernel memory. + */ + if (initrd_start < initrd_end) { + if (!memblock_is_region_memory(initrd_start, + initrd_end - initrd_start)) + enable_caching(CACHE_REGION_START(initrd_start), + CACHE_REGION_START(initrd_end - 1)); + } +#endif + + /* + * Disable caching for dma coherent memory taken from kernel memory. + */ + if (dma_size && memblock_is_region_memory(dma_start, dma_size)) + disable_caching(dma_start, + CACHE_REGION_START(dma_start + dma_size - 1)); + + /* Initialize the coherent memory allocator */ + coherent_mem_init(dma_start, dma_size); + + /* + * Free all memory as a starting point. + */ + free_bootmem(PAGE_OFFSET, memory_end - PAGE_OFFSET); + + /* + * Then reserve memory which is already being used. + */ + for_each_memblock(reserved, reg) { + pr_debug("reserved - 0x%08x-0x%08x\n", + (u32) reg->base, (u32) reg->size); + reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT); + } + + max_low_pfn = PFN_DOWN(memory_end); + min_low_pfn = PFN_UP(memory_start); + max_mapnr = max_low_pfn - min_low_pfn; + + /* Get kmalloc into gear */ + paging_init(); + + /* + * Probe for Device State Configuration Registers. + * We have to do this early in case timer needs to be enabled + * through DSCR. + */ + dscr_probe(); + + /* We do this early for timer and core clock frequency */ + c64x_setup_clocks(); + + /* Get CPU info */ + get_cpuinfo(); + +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif +} + +#define cpu_to_ptr(n) ((void *)((long)(n)+1)) +#define ptr_to_cpu(p) ((long)(p) - 1) + +static int show_cpuinfo(struct seq_file *m, void *v) +{ + int n = ptr_to_cpu(v); + struct cpuinfo_c6x *p = &per_cpu(cpu_data, n); + + if (n == 0) { + seq_printf(m, + "soc\t\t: %s\n" + "soc revision\t: 0x%x\n" + "soc cores\t: %d\n", + c6x_soc_name, c6x_silicon_rev, c6x_num_cores); + } + + seq_printf(m, + "\n" + "processor\t: %d\n" + "cpu\t\t: %s\n" + "core revision\t: %s\n" + "core voltage\t: %s\n" + "core id\t\t: %d\n" + "mmu\t\t: %s\n" + "fpu\t\t: %s\n" + "cpu MHz\t\t: %u\n" + "bogomips\t: %lu.%02lu\n\n", + n, + p->cpu_name, p->cpu_rev, p->cpu_voltage, + p->core_id, p->mmu, p->fpu, + (c6x_core_freq + 500000) / 1000000, + (loops_per_jiffy/(500000/HZ)), + (loops_per_jiffy/(5000/HZ))%100); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < nr_cpu_ids ? cpu_to_ptr(*pos) : NULL; +} +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return NULL; +} +static void c_stop(struct seq_file *m, void *v) +{ +} + +const struct seq_operations cpuinfo_op = { + c_start, + c_stop, + c_next, + show_cpuinfo +}; diff --git a/arch/c6x/kernel/vectors.S b/arch/c6x/kernel/vectors.S new file mode 100644 index 000000000000..c95c66fc71e8 --- /dev/null +++ b/arch/c6x/kernel/vectors.S @@ -0,0 +1,81 @@ +; +; Port on Texas Instruments TMS320C6x architecture +; +; Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated +; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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. +; +; This section handles all the interrupt vector routines. +; At RESET the processor sets up the DRAM timing parameters and +; branches to the label _c_int00 which handles initialization for the C code. +; + +#define ALIGNMENT 5 + + .macro IRQVEC name, handler + .align ALIGNMENT + .hidden \name + .global \name +\name: +#ifdef CONFIG_C6X_BIG_KERNEL + STW .D2T1 A0,*B15--[2] + || MVKL .S1 \handler,A0 + MVKH .S1 \handler,A0 + B .S2X A0 + LDW .D2T1 *++B15[2],A0 + NOP 4 + NOP + NOP + .endm +#else /* CONFIG_C6X_BIG_KERNEL */ + B .S2 \handler + NOP + NOP + NOP + NOP + NOP + NOP + NOP + .endm +#endif /* CONFIG_C6X_BIG_KERNEL */ + + .sect ".vectors","ax" + .align ALIGNMENT + .global RESET + .hidden RESET +RESET: +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 _c_int00,A0 ; branch to _c_int00 + MVKH .S1 _c_int00,A0 + B .S2X A0 +#else + B .S2 _c_int00 + NOP + NOP +#endif + NOP + NOP + NOP + NOP + NOP + + + IRQVEC NMI,_nmi_handler ; NMI interrupt + IRQVEC AINT,_bad_interrupt ; reserved + IRQVEC MSGINT,_bad_interrupt ; reserved + + IRQVEC INT4,_int4_handler + IRQVEC INT5,_int5_handler + IRQVEC INT6,_int6_handler + IRQVEC INT7,_int7_handler + IRQVEC INT8,_int8_handler + IRQVEC INT9,_int9_handler + IRQVEC INT10,_int10_handler + IRQVEC INT11,_int11_handler + IRQVEC INT12,_int12_handler + IRQVEC INT13,_int13_handler + IRQVEC INT14,_int14_handler + IRQVEC INT15,_int15_handler -- cgit v1.2.3 From 041cadca7008f08fb4785f2288c8127c16faa529 Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 4 Oct 2011 12:12:20 -0400 Subject: C6X: devicetree support This is the basic devicetree support for C6X. Currently, four boards are supported. Each one uses a different SoC part. Two of the four supported SoCs are multicore. One with 3 cores and the other with 6 cores. There is no coherency between the core-level caches, so SMP is not an option. It is possible to run separate kernel instances on the various cores. There is currently no C6X bootloader support for device trees so we build in the DTB for now. There are some interesting twists to the hardware which are of note for device tree support. Each core has its own interrupt controller which is controlled by special purpose core registers. This core controller provides 12 general purpose prioritized interrupt sources. Each core is contained within a hardware "module" which provides L1 and L2 caches, power control, and another interrupt controller which cascades into the core interrupt controller. These core module functions are controlled by memory mapped registers. The addresses for these registers are the same for each core. That is, when coreN accesses a module-level MMIO register at a given address, it accesses the register for coreN even though other cores would use the same address to access the register in the module containing those cores. Other hardware modules (timers, enet, etc) which are memory mapped can be accessed by all cores. The timers need some further explanation for multicore SoCs. Even though all timer control registers are visible to all cores, interrupt routing or other considerations may make a given timer more suitable for use by a core than some other timer. Because of this and the desire to have the same image run on more than one core, the timer nodes have a "ti,core-mask" property which is used by the driver to scan for a suitable timer to use. Signed-off-by: Mark Salter Signed-off-by: Aurelien Jacquiot Acked-by: Arnd Bergmann --- arch/c6x/boot/dts/dsk6455.dts | 62 +++++++++++++++++ arch/c6x/boot/dts/evmc6457.dts | 48 +++++++++++++ arch/c6x/boot/dts/evmc6472.dts | 73 ++++++++++++++++++++ arch/c6x/boot/dts/evmc6474.dts | 58 ++++++++++++++++ arch/c6x/boot/dts/tms320c6455.dtsi | 96 ++++++++++++++++++++++++++ arch/c6x/boot/dts/tms320c6457.dtsi | 68 +++++++++++++++++++ arch/c6x/boot/dts/tms320c6472.dtsi | 134 +++++++++++++++++++++++++++++++++++++ arch/c6x/boot/dts/tms320c6474.dtsi | 89 ++++++++++++++++++++++++ arch/c6x/boot/linked_dtb.S | 2 + arch/c6x/kernel/devicetree.c | 53 +++++++++++++++ arch/c6x/platforms/platform.c | 17 +++++ 11 files changed, 700 insertions(+) create mode 100644 arch/c6x/boot/dts/dsk6455.dts create mode 100644 arch/c6x/boot/dts/evmc6457.dts create mode 100644 arch/c6x/boot/dts/evmc6472.dts create mode 100644 arch/c6x/boot/dts/evmc6474.dts create mode 100644 arch/c6x/boot/dts/tms320c6455.dtsi create mode 100644 arch/c6x/boot/dts/tms320c6457.dtsi create mode 100644 arch/c6x/boot/dts/tms320c6472.dtsi create mode 100644 arch/c6x/boot/dts/tms320c6474.dtsi create mode 100644 arch/c6x/boot/linked_dtb.S create mode 100644 arch/c6x/kernel/devicetree.c create mode 100644 arch/c6x/platforms/platform.c (limited to 'arch') diff --git a/arch/c6x/boot/dts/dsk6455.dts b/arch/c6x/boot/dts/dsk6455.dts new file mode 100644 index 000000000000..2b71f800618d --- /dev/null +++ b/arch/c6x/boot/dts/dsk6455.dts @@ -0,0 +1,62 @@ +/* + * arch/c6x/boot/dts/dsk6455.dts + * + * DSK6455 Evaluation Platform For TMS320C6455 + * Copyright (C) 2011 Texas Instruments Incorporated + * + * Author: Mark Salter + * + * 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. + * + */ + +/dts-v1/; + +/include/ "tms320c6455.dtsi" + +/ { + model = "Spectrum Digital DSK6455"; + compatible = "spectrum-digital,dsk6455"; + + chosen { + bootargs = "root=/dev/nfs ip=dhcp rw"; + }; + + memory { + device_type = "memory"; + reg = <0xE0000000 0x08000000>; + }; + + soc { + megamod_pic: interrupt-controller@1800000 { + interrupts = < 12 13 14 15 >; + }; + + emifa@70000000 { + flash@3,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x3 0x0 0x400000>; + bank-width = <1>; + device-width = <1>; + partition@0 { + reg = <0x0 0x400000>; + label = "NOR"; + }; + }; + }; + + timer1: timer@2980000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 69 >; + }; + + clock-controller@029a0000 { + clock-frequency = <50000000>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/evmc6457.dts b/arch/c6x/boot/dts/evmc6457.dts new file mode 100644 index 000000000000..0301eb9a8ff8 --- /dev/null +++ b/arch/c6x/boot/dts/evmc6457.dts @@ -0,0 +1,48 @@ +/* + * arch/c6x/boot/dts/evmc6457.dts + * + * EVMC6457 Evaluation Platform For TMS320C6457 + * + * Copyright (C) 2011 Texas Instruments Incorporated + * + * Author: Mark Salter + * + * 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. + * + */ + +/dts-v1/; + +/include/ "tms320c6457.dtsi" + +/ { + model = "eInfochips EVMC6457"; + compatible = "einfochips,evmc6457"; + + chosen { + bootargs = "console=hvc root=/dev/nfs ip=dhcp rw"; + }; + + memory { + device_type = "memory"; + reg = <0xE0000000 0x10000000>; + }; + + soc { + megamod_pic: interrupt-controller@1800000 { + interrupts = < 12 13 14 15 >; + }; + + timer0: timer@2940000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 67 >; + }; + + clock-controller@29a0000 { + clock-frequency = <60000000>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/evmc6472.dts b/arch/c6x/boot/dts/evmc6472.dts new file mode 100644 index 000000000000..3e207b449a93 --- /dev/null +++ b/arch/c6x/boot/dts/evmc6472.dts @@ -0,0 +1,73 @@ +/* + * arch/c6x/boot/dts/evmc6472.dts + * + * EVMC6472 Evaluation Platform For TMS320C6472 + * + * Copyright (C) 2011 Texas Instruments Incorporated + * + * Author: Mark Salter + * + * 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. + * + */ + +/dts-v1/; + +/include/ "tms320c6472.dtsi" + +/ { + model = "eInfochips EVMC6472"; + compatible = "einfochips,evmc6472"; + + chosen { + bootargs = "console=hvc root=/dev/nfs ip=dhcp rw"; + }; + + memory { + device_type = "memory"; + reg = <0xE0000000 0x10000000>; + }; + + soc { + megamod_pic: interrupt-controller@1800000 { + interrupts = < 12 13 14 15 >; + }; + + timer0: timer@25e0000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + timer1: timer@25f0000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + timer2: timer@2600000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + timer3: timer@2610000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + timer4: timer@2620000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + timer5: timer@2630000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; + + clock-controller@29a0000 { + clock-frequency = <25000000>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/evmc6474.dts b/arch/c6x/boot/dts/evmc6474.dts new file mode 100644 index 000000000000..4dc291292bc4 --- /dev/null +++ b/arch/c6x/boot/dts/evmc6474.dts @@ -0,0 +1,58 @@ +/* + * arch/c6x/boot/dts/evmc6474.dts + * + * EVMC6474 Evaluation Platform For TMS320C6474 + * + * Copyright (C) 2011 Texas Instruments Incorporated + * + * Author: Mark Salter + * + * 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. + * + */ + +/dts-v1/; + +/include/ "tms320c6474.dtsi" + +/ { + model = "Spectrum Digital EVMC6474"; + compatible = "spectrum-digital,evmc6474"; + + chosen { + bootargs = "console=hvc root=/dev/nfs ip=dhcp rw"; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x08000000>; + }; + + soc { + megamod_pic: interrupt-controller@1800000 { + interrupts = < 12 13 14 15 >; + }; + + timer3: timer@2940000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 39 >; + }; + + timer4: timer@2950000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 41 >; + }; + + timer5: timer@2960000 { + interrupt-parent = <&megamod_pic>; + interrupts = < 43 >; + }; + + clock-controller@29a0000 { + clock-frequency = <50000000>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/tms320c6455.dtsi b/arch/c6x/boot/dts/tms320c6455.dtsi new file mode 100644 index 000000000000..a804ec1e018b --- /dev/null +++ b/arch/c6x/boot/dts/tms320c6455.dtsi @@ -0,0 +1,96 @@ + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + model = "ti,c64x+"; + reg = <0>; + }; + }; + + soc { + compatible = "simple-bus"; + model = "tms320c6455"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + core_pic: interrupt-controller { + interrupt-controller; + #interrupt-cells = <1>; + compatible = "ti,c64x+core-pic"; + }; + + /* + * Megamodule interrupt controller + */ + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1800000 0x1000>; + interrupt-parent = <&core_pic>; + }; + + cache-controller@1840000 { + compatible = "ti,c64x+cache"; + reg = <0x01840000 0x8400>; + }; + + emifa@70000000 { + compatible = "ti,c64x+emifa", "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0x70000000 0x100>; + ranges = <0x2 0x0 0xa0000000 0x00000008 + 0x3 0x0 0xb0000000 0x00400000 + 0x4 0x0 0xc0000000 0x10000000 + 0x5 0x0 0xD0000000 0x10000000>; + + ti,dscr-dev-enable = <13>; + ti,emifa-burst-priority = <255>; + ti,emifa-ce-config = <0x00240120 + 0x00240120 + 0x00240122 + 0x00240122>; + }; + + timer1: timer@2980000 { + compatible = "ti,c64x+timer64"; + reg = <0x2980000 0x40>; + ti,dscr-dev-enable = <4>; + }; + + clock-controller@029a0000 { + compatible = "ti,c6455-pll", "ti,c64x+pll"; + reg = <0x029a0000 0x200>; + ti,c64x+pll-bypass-delay = <1440>; + ti,c64x+pll-reset-delay = <15360>; + ti,c64x+pll-lock-delay = <24000>; + }; + + device-state-config-regs@2a80000 { + compatible = "ti,c64x+dscr"; + reg = <0x02a80000 0x41000>; + + ti,dscr-devstat = <0>; + ti,dscr-silicon-rev = <8 28 0xf>; + ti,dscr-rmii-resets = <0 0x40020 0x00040000>; + + ti,dscr-locked-regs = <0x40008 0x40004 0x0f0a0b00>; + ti,dscr-devstate-ctl-regs = + <0 12 0x40008 1 0 0 2 + 12 1 0x40008 3 0 30 2 + 13 2 0x4002c 1 0xffffffff 0 1>; + ti,dscr-devstate-stat-regs = + <0 10 0x40014 1 0 0 3 + 10 2 0x40018 1 0 0 3>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/tms320c6457.dtsi b/arch/c6x/boot/dts/tms320c6457.dtsi new file mode 100644 index 000000000000..35f40709a719 --- /dev/null +++ b/arch/c6x/boot/dts/tms320c6457.dtsi @@ -0,0 +1,68 @@ + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + model = "ti,c64x+"; + reg = <0>; + }; + }; + + soc { + compatible = "simple-bus"; + model = "tms320c6457"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + core_pic: interrupt-controller { + interrupt-controller; + #interrupt-cells = <1>; + compatible = "ti,c64x+core-pic"; + }; + + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&core_pic>; + reg = <0x1800000 0x1000>; + }; + + cache-controller@1840000 { + compatible = "ti,c64x+cache"; + reg = <0x01840000 0x8400>; + }; + + device-state-controller@2880800 { + compatible = "ti,c64x+dscr"; + reg = <0x02880800 0x400>; + + ti,dscr-devstat = <0x20>; + ti,dscr-silicon-rev = <0x18 28 0xf>; + ti,dscr-mac-fuse-regs = <0x114 3 4 5 6 + 0x118 0 0 1 2>; + ti,dscr-kick-regs = <0x38 0x83E70B13 + 0x3c 0x95A4F1E0>; + }; + + timer0: timer@2940000 { + compatible = "ti,c64x+timer64"; + reg = <0x2940000 0x40>; + }; + + clock-controller@29a0000 { + compatible = "ti,c6457-pll", "ti,c64x+pll"; + reg = <0x029a0000 0x200>; + ti,c64x+pll-bypass-delay = <300>; + ti,c64x+pll-reset-delay = <24000>; + ti,c64x+pll-lock-delay = <50000>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/tms320c6472.dtsi b/arch/c6x/boot/dts/tms320c6472.dtsi new file mode 100644 index 000000000000..b488aaec65c0 --- /dev/null +++ b/arch/c6x/boot/dts/tms320c6472.dtsi @@ -0,0 +1,134 @@ + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + reg = <0>; + model = "ti,c64x+"; + }; + cpu@1 { + device_type = "cpu"; + reg = <1>; + model = "ti,c64x+"; + }; + cpu@2 { + device_type = "cpu"; + reg = <2>; + model = "ti,c64x+"; + }; + cpu@3 { + device_type = "cpu"; + reg = <3>; + model = "ti,c64x+"; + }; + cpu@4 { + device_type = "cpu"; + reg = <4>; + model = "ti,c64x+"; + }; + cpu@5 { + device_type = "cpu"; + reg = <5>; + model = "ti,c64x+"; + }; + }; + + soc { + compatible = "simple-bus"; + model = "tms320c6472"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + core_pic: interrupt-controller { + compatible = "ti,c64x+core-pic"; + interrupt-controller; + #interrupt-cells = <1>; + }; + + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1800000 0x1000>; + interrupt-parent = <&core_pic>; + }; + + cache-controller@1840000 { + compatible = "ti,c64x+cache"; + reg = <0x01840000 0x8400>; + }; + + timer0: timer@25e0000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x01 >; + reg = <0x25e0000 0x40>; + }; + + timer1: timer@25f0000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x02 >; + reg = <0x25f0000 0x40>; + }; + + timer2: timer@2600000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x04 >; + reg = <0x2600000 0x40>; + }; + + timer3: timer@2610000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x08 >; + reg = <0x2610000 0x40>; + }; + + timer4: timer@2620000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x10 >; + reg = <0x2620000 0x40>; + }; + + timer5: timer@2630000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x20 >; + reg = <0x2630000 0x40>; + }; + + clock-controller@29a0000 { + compatible = "ti,c6472-pll", "ti,c64x+pll"; + reg = <0x029a0000 0x200>; + ti,c64x+pll-bypass-delay = <200>; + ti,c64x+pll-reset-delay = <12000>; + ti,c64x+pll-lock-delay = <80000>; + }; + + device-state-controller@2a80000 { + compatible = "ti,c64x+dscr"; + reg = <0x02a80000 0x1000>; + + ti,dscr-devstat = <0>; + ti,dscr-silicon-rev = <0x70c 16 0xff>; + + ti,dscr-mac-fuse-regs = <0x700 1 2 3 4 + 0x704 5 6 0 0>; + + ti,dscr-rmii-resets = <0x208 1 + 0x20c 1>; + + ti,dscr-locked-regs = <0x200 0x204 0x0a1e183a + 0x40c 0x420 0xbea7 + 0x41c 0x420 0xbea7>; + + ti,dscr-privperm = <0x41c 0xaaaaaaaa>; + + ti,dscr-devstate-ctl-regs = <0 13 0x200 1 0 0 1>; + }; + }; +}; diff --git a/arch/c6x/boot/dts/tms320c6474.dtsi b/arch/c6x/boot/dts/tms320c6474.dtsi new file mode 100644 index 000000000000..cc601bf348a1 --- /dev/null +++ b/arch/c6x/boot/dts/tms320c6474.dtsi @@ -0,0 +1,89 @@ + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + reg = <0>; + model = "ti,c64x+"; + }; + cpu@1 { + device_type = "cpu"; + reg = <1>; + model = "ti,c64x+"; + }; + cpu@2 { + device_type = "cpu"; + reg = <2>; + model = "ti,c64x+"; + }; + }; + + soc { + compatible = "simple-bus"; + model = "tms320c6474"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + core_pic: interrupt-controller { + interrupt-controller; + #interrupt-cells = <1>; + compatible = "ti,c64x+core-pic"; + }; + + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1800000 0x1000>; + interrupt-parent = <&core_pic>; + }; + + cache-controller@1840000 { + compatible = "ti,c64x+cache"; + reg = <0x01840000 0x8400>; + }; + + timer3: timer@2940000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x04 >; + reg = <0x2940000 0x40>; + }; + + timer4: timer@2950000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x02 >; + reg = <0x2950000 0x40>; + }; + + timer5: timer@2960000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x01 >; + reg = <0x2960000 0x40>; + }; + + device-state-controller@2880800 { + compatible = "ti,c64x+dscr"; + reg = <0x02880800 0x400>; + + ti,dscr-devstat = <0x004>; + ti,dscr-silicon-rev = <0x014 28 0xf>; + ti,dscr-mac-fuse-regs = <0x34 3 4 5 6 + 0x38 0 0 1 2>; + }; + + clock-controller@29a0000 { + compatible = "ti,c6474-pll", "ti,c64x+pll"; + reg = <0x029a0000 0x200>; + ti,c64x+pll-bypass-delay = <120>; + ti,c64x+pll-reset-delay = <30000>; + ti,c64x+pll-lock-delay = <60000>; + }; + }; +}; diff --git a/arch/c6x/boot/linked_dtb.S b/arch/c6x/boot/linked_dtb.S new file mode 100644 index 000000000000..57a4454eaec3 --- /dev/null +++ b/arch/c6x/boot/linked_dtb.S @@ -0,0 +1,2 @@ +.section __fdt_blob,"a" +.incbin "arch/c6x/boot/builtin.dtb" diff --git a/arch/c6x/kernel/devicetree.c b/arch/c6x/kernel/devicetree.c new file mode 100644 index 000000000000..bdb56f09d0ac --- /dev/null +++ b/arch/c6x/kernel/devicetree.c @@ -0,0 +1,53 @@ +/* + * Architecture specific OF callbacks. + * + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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 +#include +#include +#include +#include + +void __init early_init_devtree(void *params) +{ + /* Setup flat device-tree pointer */ + initial_boot_params = params; + + /* Retrieve various informations from the /chosen node of the + * device-tree, including the platform type, initrd location and + * size and more ... + */ + of_scan_flat_dt(early_init_dt_scan_chosen, c6x_command_line); + + /* Scan memory nodes and rebuild MEMBLOCKs */ + of_scan_flat_dt(early_init_dt_scan_root, NULL); + of_scan_flat_dt(early_init_dt_scan_memory, NULL); +} + + +#ifdef CONFIG_BLK_DEV_INITRD +void __init early_init_dt_setup_initrd_arch(unsigned long start, + unsigned long end) +{ + initrd_start = (unsigned long)__va(start); + initrd_end = (unsigned long)__va(end); + initrd_below_start_ok = 1; +} +#endif + +void __init early_init_dt_add_memory_arch(u64 base, u64 size) +{ + c6x_add_memory(base, size); +} + +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +{ + return __va(memblock_alloc(size, align)); +} diff --git a/arch/c6x/platforms/platform.c b/arch/c6x/platforms/platform.c new file mode 100644 index 000000000000..26c1a355d600 --- /dev/null +++ b/arch/c6x/platforms/platform.c @@ -0,0 +1,17 @@ +/* + * Copyright 2011 Texas Instruments Incorporated + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include + +static int __init c6x_device_probe(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + return 0; +} +core_initcall(c6x_device_probe); -- cgit v1.2.3 From 14aa7e8bf6d84c9a42c48e7f93472d830f694b1e Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 12:17:19 -0400 Subject: C6X: memory management and DMA support Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter The C6X architecture currently lacks an MMU so memory management is relatively simple. There is no bus snooping between L2 and main memory but coherent DMA memory is supported by making regions of main memory uncached. If such a region is desired, it can be specified on the commandline with a "memdma=" argument. Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann --- arch/c6x/include/asm/dma-mapping.h | 91 ++++++++++++++++++++++ arch/c6x/kernel/dma.c | 153 +++++++++++++++++++++++++++++++++++++ arch/c6x/mm/dma-coherent.c | 143 ++++++++++++++++++++++++++++++++++ arch/c6x/mm/init.c | 113 +++++++++++++++++++++++++++ 4 files changed, 500 insertions(+) create mode 100644 arch/c6x/include/asm/dma-mapping.h create mode 100644 arch/c6x/kernel/dma.c create mode 100644 arch/c6x/mm/dma-coherent.c create mode 100644 arch/c6x/mm/init.c (limited to 'arch') diff --git a/arch/c6x/include/asm/dma-mapping.h b/arch/c6x/include/asm/dma-mapping.h new file mode 100644 index 000000000000..03579fd99dba --- /dev/null +++ b/arch/c6x/include/asm/dma-mapping.h @@ -0,0 +1,91 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot + * + * 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_C6X_DMA_MAPPING_H +#define _ASM_C6X_DMA_MAPPING_H + +#include +#include + +#define dma_supported(d, m) 1 + +static inline int dma_set_mask(struct device *dev, u64 dma_mask) +{ + if (!dev->dma_mask || !dma_supported(dev, dma_mask)) + return -EIO; + + *dev->dma_mask = dma_mask; + + return 0; +} + +/* + * DMA errors are defined by all-bits-set in the DMA address. + */ +static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + return dma_addr == ~0; +} + +extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, + size_t size, enum dma_data_direction dir); + +extern void dma_unmap_single(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir); + +extern int dma_map_sg(struct device *dev, struct scatterlist *sglist, + int nents, enum dma_data_direction direction); + +extern void dma_unmap_sg(struct device *dev, struct scatterlist *sglist, + int nents, enum dma_data_direction direction); + +static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction dir) +{ + dma_addr_t handle; + + handle = dma_map_single(dev, page_address(page) + offset, size, dir); + + debug_dma_map_page(dev, page, offset, size, dir, handle, false); + + return handle; +} + +static inline void dma_unmap_page(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir) +{ + dma_unmap_single(dev, handle, size, dir); + + debug_dma_unmap_page(dev, handle, size, dir, false); +} + +extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir); + +extern void dma_sync_single_for_device(struct device *dev, dma_addr_t handle, + size_t size, + enum dma_data_direction dir); + +extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir); + +extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir); + +extern void coherent_mem_init(u32 start, u32 size); +extern void *dma_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t); +extern void dma_free_coherent(struct device *, size_t, void *, dma_addr_t); + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent((d), (s), (h), (f)) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent((d), (s), (v), (h)) + +#endif /* _ASM_C6X_DMA_MAPPING_H */ diff --git a/arch/c6x/kernel/dma.c b/arch/c6x/kernel/dma.c new file mode 100644 index 000000000000..ab7b12de144d --- /dev/null +++ b/arch/c6x/kernel/dma.c @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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 +#include +#include +#include +#include + +#include + +static void c6x_dma_sync(dma_addr_t handle, size_t size, + enum dma_data_direction dir) +{ + unsigned long paddr = handle; + + BUG_ON(!valid_dma_direction(dir)); + + switch (dir) { + case DMA_FROM_DEVICE: + L2_cache_block_invalidate(paddr, paddr + size); + break; + case DMA_TO_DEVICE: + L2_cache_block_writeback(paddr, paddr + size); + break; + case DMA_BIDIRECTIONAL: + L2_cache_block_writeback_invalidate(paddr, paddr + size); + break; + default: + break; + } +} + +dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, + enum dma_data_direction dir) +{ + dma_addr_t addr = virt_to_phys(ptr); + + c6x_dma_sync(addr, size, dir); + + debug_dma_map_page(dev, virt_to_page(ptr), + (unsigned long)ptr & ~PAGE_MASK, size, + dir, addr, true); + return addr; +} +EXPORT_SYMBOL(dma_map_single); + + +void dma_unmap_single(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir) +{ + c6x_dma_sync(handle, size, dir); + + debug_dma_unmap_page(dev, handle, size, dir, true); +} +EXPORT_SYMBOL(dma_unmap_single); + + +int dma_map_sg(struct device *dev, struct scatterlist *sglist, + int nents, enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sglist, sg, nents, i) + sg->dma_address = dma_map_single(dev, sg_virt(sg), sg->length, + dir); + + debug_dma_map_sg(dev, sglist, nents, nents, dir); + + return nents; +} +EXPORT_SYMBOL(dma_map_sg); + + +void dma_unmap_sg(struct device *dev, struct scatterlist *sglist, + int nents, enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sglist, sg, nents, i) + dma_unmap_single(dev, sg_dma_address(sg), sg->length, dir); + + debug_dma_unmap_sg(dev, sglist, nents, dir); +} +EXPORT_SYMBOL(dma_unmap_sg); + +void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir) +{ + c6x_dma_sync(handle, size, dir); + + debug_dma_sync_single_for_cpu(dev, handle, size, dir); +} +EXPORT_SYMBOL(dma_sync_single_for_cpu); + + +void dma_sync_single_for_device(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir) +{ + c6x_dma_sync(handle, size, dir); + + debug_dma_sync_single_for_device(dev, handle, size, dir); +} +EXPORT_SYMBOL(dma_sync_single_for_device); + + +void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, + int nents, enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sglist, sg, nents, i) + dma_sync_single_for_cpu(dev, sg_dma_address(sg), + sg->length, dir); + + debug_dma_sync_sg_for_cpu(dev, sglist, nents, dir); +} +EXPORT_SYMBOL(dma_sync_sg_for_cpu); + + +void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, + int nents, enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sglist, sg, nents, i) + dma_sync_single_for_device(dev, sg_dma_address(sg), + sg->length, dir); + + debug_dma_sync_sg_for_device(dev, sglist, nents, dir); +} +EXPORT_SYMBOL(dma_sync_sg_for_device); + + +/* Number of entries preallocated for DMA-API debugging */ +#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) + +static int __init dma_init(void) +{ + dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); + + return 0; +} +fs_initcall(dma_init); diff --git a/arch/c6x/mm/dma-coherent.c b/arch/c6x/mm/dma-coherent.c new file mode 100644 index 000000000000..4187e5180373 --- /dev/null +++ b/arch/c6x/mm/dma-coherent.c @@ -0,0 +1,143 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot + * + * 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. + * + * DMA uncached mapping support. + * + * Using code pulled from ARM + * Copyright (C) 2000-2004 Russell King + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * DMA coherent memory management, can be redefined using the memdma= + * kernel command line + */ + +/* none by default */ +static phys_addr_t dma_base; +static u32 dma_size; +static u32 dma_pages; + +static unsigned long *dma_bitmap; + +/* bitmap lock */ +static DEFINE_SPINLOCK(dma_lock); + +/* + * Return a DMA coherent and contiguous memory chunk from the DMA memory + */ +static inline u32 __alloc_dma_pages(int order) +{ + unsigned long flags; + u32 pos; + + spin_lock_irqsave(&dma_lock, flags); + pos = bitmap_find_free_region(dma_bitmap, dma_pages, order); + spin_unlock_irqrestore(&dma_lock, flags); + + return dma_base + (pos << PAGE_SHIFT); +} + +static void __free_dma_pages(u32 addr, int order) +{ + unsigned long flags; + u32 pos = (addr - dma_base) >> PAGE_SHIFT; + + if (addr < dma_base || (pos + (1 << order)) >= dma_pages) { + printk(KERN_ERR "%s: freeing outside range.\n", __func__); + BUG(); + } + + spin_lock_irqsave(&dma_lock, flags); + bitmap_release_region(dma_bitmap, pos, order); + spin_unlock_irqrestore(&dma_lock, flags); +} + +/* + * Allocate DMA coherent memory space and return both the kernel + * virtual and DMA address for that space. + */ +void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *handle, gfp_t gfp) +{ + u32 paddr; + int order; + + if (!dma_size || !size) + return NULL; + + order = get_count_order(((size - 1) >> PAGE_SHIFT) + 1); + + paddr = __alloc_dma_pages(order); + + if (handle) + *handle = paddr; + + if (!paddr) + return NULL; + + return phys_to_virt(paddr); +} +EXPORT_SYMBOL(dma_alloc_coherent); + +/* + * Free DMA coherent memory as defined by the above mapping. + */ +void dma_free_coherent(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle) +{ + int order; + + if (!dma_size || !size) + return; + + order = get_count_order(((size - 1) >> PAGE_SHIFT) + 1); + + __free_dma_pages(virt_to_phys(vaddr), order); +} +EXPORT_SYMBOL(dma_free_coherent); + +/* + * Initialise the coherent DMA memory allocator using the given uncached region. + */ +void __init coherent_mem_init(phys_addr_t start, u32 size) +{ + phys_addr_t bitmap_phys; + + if (!size) + return; + + printk(KERN_INFO + "Coherent memory (DMA) region start=0x%x size=0x%x\n", + start, size); + + dma_base = start; + dma_size = size; + + /* allocate bitmap */ + dma_pages = dma_size >> PAGE_SHIFT; + if (dma_size & (PAGE_SIZE - 1)) + ++dma_pages; + + bitmap_phys = memblock_alloc(BITS_TO_LONGS(dma_pages) * sizeof(long), + sizeof(long)); + + dma_bitmap = phys_to_virt(bitmap_phys); + memset(dma_bitmap, 0, dma_pages * PAGE_SIZE); +} diff --git a/arch/c6x/mm/init.c b/arch/c6x/mm/init.c new file mode 100644 index 000000000000..89395f09648a --- /dev/null +++ b/arch/c6x/mm/init.c @@ -0,0 +1,113 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 +#include +#include +#include +#ifdef CONFIG_BLK_DEV_RAM +#include +#endif +#include + +#include + +/* + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +unsigned long empty_zero_page; +EXPORT_SYMBOL(empty_zero_page); + +/* + * paging_init() continues the virtual memory environment setup which + * was begun by the code in arch/head.S. + * The parameters are pointers to where to stick the starting and ending + * addresses of available kernel virtual memory. + */ +void __init paging_init(void) +{ + struct pglist_data *pgdat = NODE_DATA(0); + unsigned long zones_size[MAX_NR_ZONES] = {0, }; + + empty_zero_page = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + /* + * Set up user data space + */ + set_fs(KERNEL_DS); + + /* + * Define zones + */ + zones_size[ZONE_NORMAL] = (memory_end - PAGE_OFFSET) >> PAGE_SHIFT; + pgdat->node_zones[ZONE_NORMAL].zone_start_pfn = + __pa(PAGE_OFFSET) >> PAGE_SHIFT; + + free_area_init(zones_size); +} + +void __init mem_init(void) +{ + int codek, datak; + unsigned long tmp; + unsigned long len = memory_end - memory_start; + + high_memory = (void *)(memory_end & PAGE_MASK); + + /* this will put all memory onto the freelists */ + totalram_pages = free_all_bootmem(); + + codek = (_etext - _stext) >> 10; + datak = (_end - _sdata) >> 10; + + tmp = nr_free_pages() << PAGE_SHIFT; + printk(KERN_INFO "Memory: %luk/%luk RAM (%dk kernel code, %dk data)\n", + tmp >> 10, len >> 10, codek, datak); +} + +#ifdef CONFIG_BLK_DEV_INITRD +void __init free_initrd_mem(unsigned long start, unsigned long end) +{ + int pages = 0; + for (; start < end; start += PAGE_SIZE) { + ClearPageReserved(virt_to_page(start)); + init_page_count(virt_to_page(start)); + free_page(start); + totalram_pages++; + pages++; + } + printk(KERN_INFO "Freeing initrd memory: %luk freed\n", + (pages * PAGE_SIZE) >> 10); +} +#endif + +void __init free_initmem(void) +{ + unsigned long addr; + + /* + * The following code should be cool even if these sections + * are not page aligned. + */ + addr = PAGE_ALIGN((unsigned long)(__init_begin)); + + /* next to check that the page we free is not a partial page */ + for (; addr + PAGE_SIZE < (unsigned long)(__init_end); + addr += PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + init_page_count(virt_to_page(addr)); + free_page(addr); + totalram_pages++; + } + printk(KERN_INFO "Freeing unused kernel memory: %dK freed\n", + (int) ((addr - PAGE_ALIGN((long) &__init_begin)) >> 10)); +} -- cgit v1.2.3 From 687b12baecae2aa3af9df05c12b90d8e9ef21fa7 Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 11:03:44 -0400 Subject: C6X: process management Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann --- arch/c6x/include/asm/processor.h | 132 +++++++++++++++++++ arch/c6x/include/asm/thread_info.h | 121 +++++++++++++++++ arch/c6x/kernel/process.c | 263 +++++++++++++++++++++++++++++++++++++ arch/c6x/kernel/switch_to.S | 74 +++++++++++ 4 files changed, 590 insertions(+) create mode 100644 arch/c6x/include/asm/processor.h create mode 100644 arch/c6x/include/asm/thread_info.h create mode 100644 arch/c6x/kernel/process.c create mode 100644 arch/c6x/kernel/switch_to.S (limited to 'arch') diff --git a/arch/c6x/include/asm/processor.h b/arch/c6x/include/asm/processor.h new file mode 100644 index 000000000000..8154c4ee8c9c --- /dev/null +++ b/arch/c6x/include/asm/processor.h @@ -0,0 +1,132 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) + * + * Updated for 2.6.34: Mark Salter + * + * 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_C6X_PROCESSOR_H +#define _ASM_C6X_PROCESSOR_H + +#include +#include +#include + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() \ +({ \ + void *__pc; \ + asm("mvc .S2 pce1,%0\n" : "=b"(__pc)); \ + __pc; \ +}) + +/* + * User space process size. This is mostly meaningless for NOMMU + * but some C6X processors may have RAM addresses up to 0xFFFFFFFF. + * Since calls like mmap() can return an address or an error, we + * have to allow room for error returns when code does something + * like: + * + * addr = do_mmap(...) + * if ((unsigned long)addr >= TASK_SIZE) + * ... its an error code, not an address ... + * + * Here, we allow for 4096 error codes which means we really can't + * use the last 4K page on systems with RAM extending all the way + * to the end of the 32-bit address space. + */ +#define TASK_SIZE 0xFFFFF000 + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. We won't be using it + */ +#define TASK_UNMAPPED_BASE 0 + +struct thread_struct { + unsigned long long b15_14; + unsigned long long a15_14; + unsigned long long b13_12; + unsigned long long a13_12; + unsigned long long b11_10; + unsigned long long a11_10; + unsigned long long ricl_icl; + unsigned long usp; /* user stack pointer */ + unsigned long pc; /* kernel pc */ + unsigned long wchan; +}; + +#define INIT_THREAD \ +{ \ + .usp = 0, \ + .wchan = 0, \ +} + +#define INIT_MMAP { \ + &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, \ + NULL, NULL } + +#define task_pt_regs(task) \ + ((struct pt_regs *)(THREAD_START_SP + task_stack_page(task)) - 1) + +#define alloc_kernel_stack() __get_free_page(GFP_KERNEL) +#define free_kernel_stack(page) free_page((page)) + + +/* Forward declaration, a strange C thing */ +struct task_struct; + +extern void start_thread(struct pt_regs *regs, unsigned int pc, + unsigned long usp); + +/* Free all resources held by a thread. */ +static inline void release_thread(struct task_struct *dead_task) +{ +} + +/* Prepare to copy thread state - unlazy all lazy status */ +#define prepare_to_copy(tsk) do { } while (0) + +extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + +#define copy_segments(tsk, mm) do { } while (0) +#define release_segments(mm) do { } while (0) + +/* + * saved PC of a blocked thread. + */ +#define thread_saved_pc(tsk) (task_pt_regs(tsk)->pc) + +/* + * saved kernel SP and DP of a blocked thread. + */ +#ifdef _BIG_ENDIAN +#define thread_saved_ksp(tsk) \ + (*(unsigned long *)&(tsk)->thread.b15_14) +#define thread_saved_dp(tsk) \ + (*(((unsigned long *)&(tsk)->thread.b15_14) + 1)) +#else +#define thread_saved_ksp(tsk) \ + (*(((unsigned long *)&(tsk)->thread.b15_14) + 1)) +#define thread_saved_dp(tsk) \ + (*(unsigned long *)&(tsk)->thread.b15_14) +#endif + +extern unsigned long get_wchan(struct task_struct *p); + +#define KSTK_EIP(tsk) (task_pt_regs(task)->pc) +#define KSTK_ESP(tsk) (task_pt_regs(task)->sp) + +#define cpu_relax() do { } while (0) + +extern const struct seq_operations cpuinfo_op; + +#endif /* ASM_C6X_PROCESSOR_H */ diff --git a/arch/c6x/include/asm/thread_info.h b/arch/c6x/include/asm/thread_info.h new file mode 100644 index 000000000000..fd99148cda9d --- /dev/null +++ b/arch/c6x/include/asm/thread_info.h @@ -0,0 +1,121 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) + * + * Updated for 2.6.3x: Mark Salter + * + * 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_C6X_THREAD_INFO_H +#define _ASM_C6X_THREAD_INFO_H + +#ifdef __KERNEL__ + +#include + +#ifdef CONFIG_4KSTACKS +#define THREAD_SIZE 4096 +#define THREAD_SHIFT 12 +#define THREAD_ORDER 0 +#else +#define THREAD_SIZE 8192 +#define THREAD_SHIFT 13 +#define THREAD_ORDER 1 +#endif + +#define THREAD_START_SP (THREAD_SIZE - 8) + +#ifndef __ASSEMBLY__ + +typedef struct { + unsigned long seg; +} mm_segment_t; + +/* + * low level task data. + */ +struct thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + int cpu; /* cpu we're on */ + int preempt_count; /* 0 = preemptable, <0 = BUG */ + mm_segment_t addr_limit; /* thread address space */ + struct restart_block restart_block; +}; + +/* + * macros/functions for gaining access to the thread information structure + * + * preempt_count needs to be 1 initially, until the scheduler is functional. + */ +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = INIT_PREEMPT_COUNT, \ + .addr_limit = KERNEL_DS, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + }, \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + +/* get the thread information struct of current task */ +static inline __attribute__((const)) +struct thread_info *current_thread_info(void) +{ + struct thread_info *ti; + asm volatile (" clr .s2 B15,0,%1,%0\n" + : "=b" (ti) + : "Iu5" (THREAD_SHIFT - 1)); + return ti; +} + +#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR + +/* thread information allocation */ +#ifdef CONFIG_DEBUG_STACK_USAGE +#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO) +#else +#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK) +#endif + +#define alloc_thread_info_node(tsk, node) \ + ((struct thread_info *)__get_free_pages(THREAD_FLAGS, THREAD_ORDER)) + +#define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER) +#define get_thread_info(ti) get_task_struct((ti)->task) +#define put_thread_info(ti) put_task_struct((ti)->task) +#endif /* __ASSEMBLY__ */ + +#define PREEMPT_ACTIVE 0x10000000 + +/* + * thread information flag bit numbers + * - pending work-to-be-done flags are in LSW + * - other flags in MSW + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ +#define TIF_SIGPENDING 2 /* signal pending */ +#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +#define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */ + +#define TIF_POLLING_NRFLAG 16 /* true if polling TIF_NEED_RESCHED */ +#define TIF_MEMDIE 17 /* OOM killer killed process */ + +#define TIF_WORK_MASK 0x00007FFE /* work on irq/exception return */ +#define TIF_ALLWORK_MASK 0x00007FFF /* work on any return to u-space */ + +#endif /* __KERNEL__ */ + +#endif /* _ASM_C6X_THREAD_INFO_H */ diff --git a/arch/c6x/kernel/process.c b/arch/c6x/kernel/process.c new file mode 100644 index 000000000000..aa65c879323b --- /dev/null +++ b/arch/c6x/kernel/process.c @@ -0,0 +1,263 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 +#include +#include +#include +#include +#include +#include +#include + +#include + +/* hooks for board specific support */ +void (*c6x_restart)(void); +void (*c6x_halt)(void); + +extern asmlinkage void ret_from_fork(void); + +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); + +/* + * Initial thread structure. + */ +union thread_union init_thread_union __init_task_data = { + INIT_THREAD_INFO(init_task) +}; + +/* + * Initial task structure. + */ +struct task_struct init_task = INIT_TASK(init_task); +EXPORT_SYMBOL(init_task); + +/* + * power off function, if any + */ +void (*pm_power_off)(void); +EXPORT_SYMBOL(pm_power_off); + +static void c6x_idle(void) +{ + unsigned long tmp; + + /* + * Put local_irq_enable and idle in same execute packet + * to make them atomic and avoid race to idle with + * interrupts enabled. + */ + asm volatile (" mvc .s2 CSR,%0\n" + " or .d2 1,%0,%0\n" + " mvc .s2 %0,CSR\n" + "|| idle\n" + : "=b"(tmp)); +} + +/* + * The idle loop for C64x + */ +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + while (1) { + tick_nohz_stop_sched_tick(1); + while (1) { + local_irq_disable(); + if (need_resched()) { + local_irq_enable(); + break; + } + c6x_idle(); /* enables local irqs */ + } + tick_nohz_restart_sched_tick(); + + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } +} + +static void halt_loop(void) +{ + printk(KERN_EMERG "System Halted, OK to turn off power\n"); + local_irq_disable(); + while (1) + asm volatile("idle\n"); +} + +void machine_restart(char *__unused) +{ + if (c6x_restart) + c6x_restart(); + halt_loop(); +} + +void machine_halt(void) +{ + if (c6x_halt) + c6x_halt(); + halt_loop(); +} + +void machine_power_off(void) +{ + if (pm_power_off) + pm_power_off(); + halt_loop(); +} + +static void kernel_thread_helper(int dummy, void *arg, int (*fn)(void *)) +{ + do_exit(fn(arg)); +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + struct pt_regs regs; + + /* + * copy_thread sets a4 to zero (child return from fork) + * so we can't just set things up to directly return to + * fn. + */ + memset(®s, 0, sizeof(regs)); + regs.b4 = (unsigned long) arg; + regs.a6 = (unsigned long) fn; + regs.pc = (unsigned long) kernel_thread_helper; + local_save_flags(regs.csr); + regs.csr |= 1; + regs.tsr = 5; /* Set GEE and GIE in TSR */ + + /* Ok, create the new process.. */ + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, -1, ®s, + 0, NULL, NULL); +} +EXPORT_SYMBOL(kernel_thread); + +void flush_thread(void) +{ +} + +void exit_thread(void) +{ +} + +SYSCALL_DEFINE1(c6x_clone, struct pt_regs *, regs) +{ + unsigned long clone_flags; + unsigned long newsp; + + /* syscall puts clone_flags in A4 and usp in B4 */ + clone_flags = regs->orig_a4; + if (regs->b4) + newsp = regs->b4; + else + newsp = regs->sp; + + return do_fork(clone_flags, newsp, regs, 0, (int __user *)regs->a6, + (int __user *)regs->b6); +} + +/* + * Do necessary setup to start up a newly executed thread. + */ +void start_thread(struct pt_regs *regs, unsigned int pc, unsigned long usp) +{ + /* + * The binfmt loader will setup a "full" stack, but the C6X + * operates an "empty" stack. So we adjust the usp so that + * argc doesn't get destroyed if an interrupt is taken before + * it is read from the stack. + * + * NB: Library startup code needs to match this. + */ + usp -= 8; + + set_fs(USER_DS); + regs->pc = pc; + regs->sp = usp; + regs->tsr |= 0x40; /* set user mode */ + current->thread.usp = usp; +} + +/* + * Copy a new thread context in its stack. + */ +int copy_thread(unsigned long clone_flags, unsigned long usp, + unsigned long ustk_size, + struct task_struct *p, struct pt_regs *regs) +{ + struct pt_regs *childregs; + + childregs = task_pt_regs(p); + + *childregs = *regs; + childregs->a4 = 0; + + if (usp == -1) + /* case of __kernel_thread: we return to supervisor space */ + childregs->sp = (unsigned long)(childregs + 1); + else + /* Otherwise use the given stack */ + childregs->sp = usp; + + /* Set usp/ksp */ + p->thread.usp = childregs->sp; + /* switch_to uses stack to save/restore 14 callee-saved regs */ + thread_saved_ksp(p) = (unsigned long)childregs - 8; + p->thread.pc = (unsigned int) ret_from_fork; + p->thread.wchan = (unsigned long) ret_from_fork; +#ifdef __DSBT__ + { + unsigned long dp; + + asm volatile ("mv .S2 b14,%0\n" : "=b"(dp)); + + thread_saved_dp(p) = dp; + if (usp == -1) + childregs->dp = dp; + } +#endif + return 0; +} + +/* + * c6x_execve() executes a new program. + */ +SYSCALL_DEFINE4(c6x_execve, const char __user *, name, + const char __user *const __user *, argv, + const char __user *const __user *, envp, + struct pt_regs *, regs) +{ + int error; + char *filename; + + filename = getname(name); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + + error = do_execve(filename, argv, envp, regs); + putname(filename); +out: + return error; +} + +unsigned long get_wchan(struct task_struct *p) +{ + return p->thread.wchan; +} diff --git a/arch/c6x/kernel/switch_to.S b/arch/c6x/kernel/switch_to.S new file mode 100644 index 000000000000..09177ed0fa5c --- /dev/null +++ b/arch/c6x/kernel/switch_to.S @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter (msalter@redhat.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 +#include + +#define SP B15 + + /* + * void __switch_to(struct thread_info *prev, + * struct thread_info *next, + * struct task_struct *tsk) ; + */ +ENTRY(__switch_to) + LDDW .D2T2 *+B4(THREAD_B15_14),B7:B6 + || MV .L2X A4,B5 ; prev + || MV .L1X B4,A5 ; next + || MVC .S2 RILC,B1 + + STW .D2T2 B3,*+B5(THREAD_PC) + || STDW .D1T1 A13:A12,*+A4(THREAD_A13_12) + || MVC .S2 ILC,B0 + + LDW .D2T2 *+B4(THREAD_PC),B3 + || LDDW .D1T1 *+A5(THREAD_A13_12),A13:A12 + + STDW .D1T1 A11:A10,*+A4(THREAD_A11_10) + || STDW .D2T2 B1:B0,*+B5(THREAD_RICL_ICL) +#ifndef __DSBT__ + || MVKL .S2 current_ksp,B1 +#endif + + STDW .D2T2 B15:B14,*+B5(THREAD_B15_14) + || STDW .D1T1 A15:A14,*+A4(THREAD_A15_14) +#ifndef __DSBT__ + || MVKH .S2 current_ksp,B1 +#endif + + ;; Switch to next SP + MV .S2 B7,SP +#ifdef __DSBT__ + || STW .D2T2 B7,*+B14(current_ksp) +#else + || STW .D2T2 B7,*B1 + || MV .L2 B6,B14 +#endif + || LDDW .D1T1 *+A5(THREAD_RICL_ICL),A1:A0 + + STDW .D2T2 B11:B10,*+B5(THREAD_B11_10) + || LDDW .D1T1 *+A5(THREAD_A15_14),A15:A14 + + STDW .D2T2 B13:B12,*+B5(THREAD_B13_12) + || LDDW .D1T1 *+A5(THREAD_A11_10),A11:A10 + + B .S2 B3 ; return in next E1 + || LDDW .D2T2 *+B4(THREAD_B13_12),B13:B12 + + LDDW .D2T2 *+B4(THREAD_B11_10),B11:B10 + NOP + + MV .L2X A0,B0 + || MV .S1 A6,A4 + + MVC .S2 B0,ILC + || MV .L2X A1,B1 + + MVC .S2 B1,RILC +ENDPROC(__switch_to) -- cgit v1.2.3 From 03a347558749caaab482f34410ae5d27e893db89 Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 11:04:34 -0400 Subject: C6X: signal management Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann --- arch/c6x/include/asm/sigcontext.h | 80 ++++++++ arch/c6x/include/asm/signal.h | 17 ++ arch/c6x/kernel/signal.c | 377 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 474 insertions(+) create mode 100644 arch/c6x/include/asm/sigcontext.h create mode 100644 arch/c6x/include/asm/signal.h create mode 100644 arch/c6x/kernel/signal.c (limited to 'arch') diff --git a/arch/c6x/include/asm/sigcontext.h b/arch/c6x/include/asm/sigcontext.h new file mode 100644 index 000000000000..eb702f39cde7 --- /dev/null +++ b/arch/c6x/include/asm/sigcontext.h @@ -0,0 +1,80 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_SIGCONTEXT_H +#define _ASM_C6X_SIGCONTEXT_H + + +struct sigcontext { + unsigned long sc_mask; /* old sigmask */ + unsigned long sc_sp; /* old user stack pointer */ + + unsigned long sc_a4; + unsigned long sc_b4; + unsigned long sc_a6; + unsigned long sc_b6; + unsigned long sc_a8; + unsigned long sc_b8; + + unsigned long sc_a0; + unsigned long sc_a1; + unsigned long sc_a2; + unsigned long sc_a3; + unsigned long sc_a5; + unsigned long sc_a7; + unsigned long sc_a9; + + unsigned long sc_b0; + unsigned long sc_b1; + unsigned long sc_b2; + unsigned long sc_b3; + unsigned long sc_b5; + unsigned long sc_b7; + unsigned long sc_b9; + + unsigned long sc_a16; + unsigned long sc_a17; + unsigned long sc_a18; + unsigned long sc_a19; + unsigned long sc_a20; + unsigned long sc_a21; + unsigned long sc_a22; + unsigned long sc_a23; + unsigned long sc_a24; + unsigned long sc_a25; + unsigned long sc_a26; + unsigned long sc_a27; + unsigned long sc_a28; + unsigned long sc_a29; + unsigned long sc_a30; + unsigned long sc_a31; + + unsigned long sc_b16; + unsigned long sc_b17; + unsigned long sc_b18; + unsigned long sc_b19; + unsigned long sc_b20; + unsigned long sc_b21; + unsigned long sc_b22; + unsigned long sc_b23; + unsigned long sc_b24; + unsigned long sc_b25; + unsigned long sc_b26; + unsigned long sc_b27; + unsigned long sc_b28; + unsigned long sc_b29; + unsigned long sc_b30; + unsigned long sc_b31; + + unsigned long sc_csr; + unsigned long sc_pc; +}; + +#endif /* _ASM_C6X_SIGCONTEXT_H */ diff --git a/arch/c6x/include/asm/signal.h b/arch/c6x/include/asm/signal.h new file mode 100644 index 000000000000..f1cd870596a3 --- /dev/null +++ b/arch/c6x/include/asm/signal.h @@ -0,0 +1,17 @@ +#ifndef _ASM_C6X_SIGNAL_H +#define _ASM_C6X_SIGNAL_H + +#include + +#ifndef __ASSEMBLY__ +#include + +struct pt_regs; + +extern asmlinkage int do_rt_sigreturn(struct pt_regs *regs); +extern asmlinkage void do_notify_resume(struct pt_regs *regs, + u32 thread_info_flags, + int syscall); +#endif + +#endif /* _ASM_C6X_SIGNAL_H */ diff --git a/arch/c6x/kernel/signal.c b/arch/c6x/kernel/signal.c new file mode 100644 index 000000000000..304f675826e9 --- /dev/null +++ b/arch/c6x/kernel/signal.c @@ -0,0 +1,377 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) + * + * Updated for 2.6.34: Mark Salter + * + * 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 +#include +#include +#include + +#include +#include + + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +/* + * Do a signal return, undo the signal stack. + */ + +#define RETCODE_SIZE (9 << 2) /* 9 instructions = 36 bytes */ + +struct rt_sigframe { + struct siginfo __user *pinfo; + void __user *puc; + struct siginfo info; + struct ucontext uc; + unsigned long retcode[RETCODE_SIZE >> 2]; +}; + +static int restore_sigcontext(struct pt_regs *regs, + struct sigcontext __user *sc) +{ + int err = 0; + + /* The access_ok check was done by caller, so use __get_user here */ +#define COPY(x) (err |= __get_user(regs->x, &sc->sc_##x)) + + COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8); + COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9); + COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9); + + COPY(a16); COPY(a17); COPY(a18); COPY(a19); + COPY(a20); COPY(a21); COPY(a22); COPY(a23); + COPY(a24); COPY(a25); COPY(a26); COPY(a27); + COPY(a28); COPY(a29); COPY(a30); COPY(a31); + COPY(b16); COPY(b17); COPY(b18); COPY(b19); + COPY(b20); COPY(b21); COPY(b22); COPY(b23); + COPY(b24); COPY(b25); COPY(b26); COPY(b27); + COPY(b28); COPY(b29); COPY(b30); COPY(b31); + + COPY(csr); COPY(pc); + +#undef COPY + + return err; +} + +asmlinkage int do_rt_sigreturn(struct pt_regs *regs) +{ + struct rt_sigframe __user *frame; + sigset_t set; + + /* + * Since we stacked the signal on a dword boundary, + * 'sp' should be dword aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (regs->sp & 7) + goto badframe; + + frame = (struct rt_sigframe __user *) ((unsigned long) regs->sp + 8); + + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) + goto badframe; + + return regs->a4; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, + unsigned long mask) +{ + int err = 0; + + err |= __put_user(mask, &sc->sc_mask); + + /* The access_ok check was done by caller, so use __put_user here */ +#define COPY(x) (err |= __put_user(regs->x, &sc->sc_##x)) + + COPY(sp); COPY(a4); COPY(b4); COPY(a6); COPY(b6); COPY(a8); COPY(b8); + COPY(a0); COPY(a1); COPY(a2); COPY(a3); COPY(a5); COPY(a7); COPY(a9); + COPY(b0); COPY(b1); COPY(b2); COPY(b3); COPY(b5); COPY(b7); COPY(b9); + + COPY(a16); COPY(a17); COPY(a18); COPY(a19); + COPY(a20); COPY(a21); COPY(a22); COPY(a23); + COPY(a24); COPY(a25); COPY(a26); COPY(a27); + COPY(a28); COPY(a29); COPY(a30); COPY(a31); + COPY(b16); COPY(b17); COPY(b18); COPY(b19); + COPY(b20); COPY(b21); COPY(b22); COPY(b23); + COPY(b24); COPY(b25); COPY(b26); COPY(b27); + COPY(b28); COPY(b29); COPY(b30); COPY(b31); + + COPY(csr); COPY(pc); + +#undef COPY + + return err; +} + +static inline void __user *get_sigframe(struct k_sigaction *ka, + struct pt_regs *regs, + unsigned long framesize) +{ + unsigned long sp = regs->sp; + + /* + * This is the X/Open sanctioned signal stack switching. + */ + if ((ka->sa.sa_flags & SA_ONSTACK) && sas_ss_flags(sp) == 0) + sp = current->sas_ss_sp + current->sas_ss_size; + + /* + * No matter what happens, 'sp' must be dword + * aligned. Otherwise, nasty things will happen + */ + return (void __user *)((sp - framesize) & ~7); +} + +static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe __user *frame; + unsigned long __user *retcode; + int err = 0; + + frame = get_sigframe(ka, regs, sizeof(*frame)); + + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto segv_and_exit; + + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + + /* Clear all the bits of the ucontext we don't use. */ + err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + + err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace */ + retcode = (unsigned long __user *) &frame->retcode; + + /* The access_ok check was done above, so use __put_user here */ +#define COPY(x) (err |= __put_user(x, retcode++)) + + COPY(0x0000002AUL | (__NR_rt_sigreturn << 7)); + /* MVK __NR_rt_sigreturn,B0 */ + COPY(0x10000000UL); /* SWE */ + COPY(0x00006000UL); /* NOP 4 */ + COPY(0x00006000UL); /* NOP 4 */ + COPY(0x00006000UL); /* NOP 4 */ + COPY(0x00006000UL); /* NOP 4 */ + COPY(0x00006000UL); /* NOP 4 */ + COPY(0x00006000UL); /* NOP 4 */ + COPY(0x00006000UL); /* NOP 4 */ + +#undef COPY + + if (err) + goto segv_and_exit; + + flush_icache_range((unsigned long) &frame->retcode, + (unsigned long) &frame->retcode + RETCODE_SIZE); + + retcode = (unsigned long __user *) &frame->retcode; + + /* Change user context to branch to signal handler */ + regs->sp = (unsigned long) frame - 8; + regs->b3 = (unsigned long) retcode; + regs->pc = (unsigned long) ka->sa.sa_handler; + + /* Give the signal number to the handler */ + regs->a4 = signr; + + /* + * For realtime signals we must also set the second and third + * arguments for the signal handler. + * -- Peter Maydell 2000-12-06 + */ + regs->b4 = (unsigned long)&frame->info; + regs->a6 = (unsigned long)&frame->uc; + + return 0; + +segv_and_exit: + force_sigsegv(signr, current); + return -EFAULT; +} + +static inline void +handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) +{ + switch (regs->a4) { + case -ERESTARTNOHAND: + if (!has_handler) + goto do_restart; + regs->a4 = -EINTR; + break; + + case -ERESTARTSYS: + if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { + regs->a4 = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: +do_restart: + regs->a4 = regs->orig_a4; + regs->pc -= 4; + break; + } +} + +/* + * handle the actual delivery of a signal to userspace + */ +static int handle_signal(int sig, + siginfo_t *info, struct k_sigaction *ka, + sigset_t *oldset, struct pt_regs *regs, + int syscall) +{ + int ret; + + /* Are we from a system call? */ + if (syscall) { + /* If so, check system call restarting.. */ + switch (regs->a4) { + case -ERESTART_RESTARTBLOCK: + case -ERESTARTNOHAND: + regs->a4 = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { + regs->a4 = -EINTR; + break; + } + + /* fallthrough */ + case -ERESTARTNOINTR: + regs->a4 = regs->orig_a4; + regs->pc -= 4; + } + } + + /* Set up the stack frame */ + ret = setup_rt_frame(sig, ka, info, oldset, regs); + if (ret == 0) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, + &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } + + return ret; +} + +/* + * handle a potential signal + */ +static void do_signal(struct pt_regs *regs, int syscall) +{ + struct k_sigaction ka; + siginfo_t info; + sigset_t *oldset; + int signr; + + /* we want the common case to go fast, which is why we may in certain + * cases get here from kernel mode */ + if (!user_mode(regs)) + return; + + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else + oldset = ¤t->blocked; + + signr = get_signal_to_deliver(&info, &ka, regs, NULL); + if (signr > 0) { + if (handle_signal(signr, &info, &ka, oldset, + regs, syscall) == 0) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signr, &info, &ka, regs, 0); + } + + return; + } + + /* did we come from a system call? */ + if (syscall) { + /* restart the system call - no handlers present */ + switch (regs->a4) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + regs->a4 = regs->orig_a4; + regs->pc -= 4; + break; + + case -ERESTART_RESTARTBLOCK: + regs->a4 = regs->orig_a4; + regs->b0 = __NR_restart_syscall; + regs->pc -= 4; + break; + } + } + + /* if there's no signal to deliver, we just put the saved sigmask + * back */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } +} + +/* + * notification of userspace execution resumption + * - triggered by current->work.notify_resume + */ +asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags, + int syscall) +{ + /* deal with pending signal delivery */ + if (thread_info_flags & ((1 << TIF_SIGPENDING) | + (1 << TIF_RESTORE_SIGMASK))) + do_signal(regs, syscall); + + if (thread_info_flags & (1 << TIF_NOTIFY_RESUME)) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); + } +} -- cgit v1.2.3 From 546a39546c64ad7e73796c5508ef5487af42cae2 Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 11:05:33 -0400 Subject: C6X: time management Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Reviewed-by: Thomas Gleixner Acked-by: Arnd Bergmann --- arch/c6x/include/asm/timer64.h | 6 ++ arch/c6x/include/asm/timex.h | 33 ++++++ arch/c6x/kernel/time.c | 65 ++++++++++++ arch/c6x/platforms/timer64.c | 236 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 340 insertions(+) create mode 100644 arch/c6x/include/asm/timer64.h create mode 100644 arch/c6x/include/asm/timex.h create mode 100644 arch/c6x/kernel/time.c create mode 100644 arch/c6x/platforms/timer64.c (limited to 'arch') diff --git a/arch/c6x/include/asm/timer64.h b/arch/c6x/include/asm/timer64.h new file mode 100644 index 000000000000..bbe27bb9887e --- /dev/null +++ b/arch/c6x/include/asm/timer64.h @@ -0,0 +1,6 @@ +#ifndef _C6X_TIMER64_H +#define _C6X_TIMER64_H + +extern void __init timer64_init(void); + +#endif /* _C6X_TIMER64_H */ diff --git a/arch/c6x/include/asm/timex.h b/arch/c6x/include/asm/timex.h new file mode 100644 index 000000000000..508c3ec971f9 --- /dev/null +++ b/arch/c6x/include/asm/timex.h @@ -0,0 +1,33 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) + * + * Modified for 2.6.34: Mark Salter + * + * 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_C6X_TIMEX_H +#define _ASM_C6X_TIMEX_H + +#define CLOCK_TICK_RATE ((1000 * 1000000UL) / 6) + +/* 64-bit timestamp */ +typedef unsigned long long cycles_t; + +static inline cycles_t get_cycles(void) +{ + unsigned l, h; + + asm volatile (" dint\n" + " mvc .s2 TSCL,%0\n" + " mvc .s2 TSCH,%1\n" + " rint\n" + : "=b"(l), "=b"(h)); + return ((cycles_t)h << 32) | l; +} + +#endif /* _ASM_C6X_TIMEX_H */ diff --git a/arch/c6x/kernel/time.c b/arch/c6x/kernel/time.c new file mode 100644 index 000000000000..4c9f136165f7 --- /dev/null +++ b/arch/c6x/kernel/time.c @@ -0,0 +1,65 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static u32 sched_clock_multiplier; +#define SCHED_CLOCK_SHIFT 16 + +static cycle_t tsc_read(struct clocksource *cs) +{ + return get_cycles(); +} + +static struct clocksource clocksource_tsc = { + .name = "timestamp", + .rating = 300, + .read = tsc_read, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +/* + * scheduler clock - returns current time in nanoseconds. + */ +u64 sched_clock(void) +{ + u64 tsc = get_cycles(); + + return (tsc * sched_clock_multiplier) >> SCHED_CLOCK_SHIFT; +} + +void time_init(void) +{ + u64 tmp = (u64)NSEC_PER_SEC << SCHED_CLOCK_SHIFT; + + do_div(tmp, c6x_core_freq); + sched_clock_multiplier = tmp; + + clocksource_register_hz(&clocksource_tsc, c6x_core_freq); + + /* write anything into TSCL to enable counting */ + set_creg(TSCL, 0); + + /* probe for timer64 event timer */ + timer64_init(); +} diff --git a/arch/c6x/platforms/timer64.c b/arch/c6x/platforms/timer64.c new file mode 100644 index 000000000000..783415861dae --- /dev/null +++ b/arch/c6x/platforms/timer64.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2010, 2011 Texas Instruments Incorporated + * Contributed by: Mark Salter (msalter@redhat.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 +#include +#include +#include +#include +#include +#include +#include +#include + +struct timer_regs { + u32 reserved0; + u32 emumgt; + u32 reserved1; + u32 reserved2; + u32 cntlo; + u32 cnthi; + u32 prdlo; + u32 prdhi; + u32 tcr; + u32 tgcr; + u32 wdtcr; +}; + +static struct timer_regs __iomem *timer; + +#define TCR_TSTATLO 0x001 +#define TCR_INVOUTPLO 0x002 +#define TCR_INVINPLO 0x004 +#define TCR_CPLO 0x008 +#define TCR_ENAMODELO_ONCE 0x040 +#define TCR_ENAMODELO_CONT 0x080 +#define TCR_ENAMODELO_MASK 0x0c0 +#define TCR_PWIDLO_MASK 0x030 +#define TCR_CLKSRCLO 0x100 +#define TCR_TIENLO 0x200 +#define TCR_TSTATHI (0x001 << 16) +#define TCR_INVOUTPHI (0x002 << 16) +#define TCR_CPHI (0x008 << 16) +#define TCR_PWIDHI_MASK (0x030 << 16) +#define TCR_ENAMODEHI_ONCE (0x040 << 16) +#define TCR_ENAMODEHI_CONT (0x080 << 16) +#define TCR_ENAMODEHI_MASK (0x0c0 << 16) + +#define TGCR_TIMLORS 0x001 +#define TGCR_TIMHIRS 0x002 +#define TGCR_TIMMODE_UD32 0x004 +#define TGCR_TIMMODE_WDT64 0x008 +#define TGCR_TIMMODE_CD32 0x00c +#define TGCR_TIMMODE_MASK 0x00c +#define TGCR_PSCHI_MASK (0x00f << 8) +#define TGCR_TDDRHI_MASK (0x00f << 12) + +/* + * Timer clocks are divided down from the CPU clock + * The divisor is in the EMUMGTCLKSPD register + */ +#define TIMER_DIVISOR \ + ((soc_readl(&timer->emumgt) & (0xf << 16)) >> 16) + +#define TIMER64_RATE (c6x_core_freq / TIMER_DIVISOR) + +#define TIMER64_MODE_DISABLED 0 +#define TIMER64_MODE_ONE_SHOT TCR_ENAMODELO_ONCE +#define TIMER64_MODE_PERIODIC TCR_ENAMODELO_CONT + +static int timer64_mode; +static int timer64_devstate_id = -1; + +static void timer64_config(unsigned long period) +{ + u32 tcr = soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK; + + soc_writel(tcr, &timer->tcr); + soc_writel(period - 1, &timer->prdlo); + soc_writel(0, &timer->cntlo); + tcr |= timer64_mode; + soc_writel(tcr, &timer->tcr); +} + +static void timer64_enable(void) +{ + u32 val; + + if (timer64_devstate_id >= 0) + dscr_set_devstate(timer64_devstate_id, DSCR_DEVSTATE_ENABLED); + + /* disable timer, reset count */ + soc_writel(soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK, &timer->tcr); + soc_writel(0, &timer->prdlo); + + /* use internal clock and 1 cycle pulse width */ + val = soc_readl(&timer->tcr); + soc_writel(val & ~(TCR_CLKSRCLO | TCR_PWIDLO_MASK), &timer->tcr); + + /* dual 32-bit unchained mode */ + val = soc_readl(&timer->tgcr) & ~TGCR_TIMMODE_MASK; + soc_writel(val, &timer->tgcr); + soc_writel(val | (TGCR_TIMLORS | TGCR_TIMMODE_UD32), &timer->tgcr); +} + +static void timer64_disable(void) +{ + /* disable timer, reset count */ + soc_writel(soc_readl(&timer->tcr) & ~TCR_ENAMODELO_MASK, &timer->tcr); + soc_writel(0, &timer->prdlo); + + if (timer64_devstate_id >= 0) + dscr_set_devstate(timer64_devstate_id, DSCR_DEVSTATE_DISABLED); +} + +static int next_event(unsigned long delta, + struct clock_event_device *evt) +{ + timer64_config(delta); + return 0; +} + +static void set_clock_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + timer64_enable(); + timer64_mode = TIMER64_MODE_PERIODIC; + timer64_config(TIMER64_RATE / HZ); + break; + case CLOCK_EVT_MODE_ONESHOT: + timer64_enable(); + timer64_mode = TIMER64_MODE_ONE_SHOT; + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + timer64_mode = TIMER64_MODE_DISABLED; + timer64_disable(); + break; + case CLOCK_EVT_MODE_RESUME: + break; + } +} + +static struct clock_event_device t64_clockevent_device = { + .name = "TIMER64_EVT32_TIMER", + .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, + .rating = 200, + .set_mode = set_clock_mode, + .set_next_event = next_event, +}; + +static irqreturn_t timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *cd = &t64_clockevent_device; + + cd->event_handler(cd); + + return IRQ_HANDLED; +} + +static struct irqaction timer_iact = { + .name = "timer", + .flags = IRQF_TIMER, + .handler = timer_interrupt, + .dev_id = &t64_clockevent_device, +}; + +void __init timer64_init(void) +{ + struct clock_event_device *cd = &t64_clockevent_device; + struct device_node *np, *first = NULL; + u32 val; + int err, found = 0; + + for_each_compatible_node(np, NULL, "ti,c64x+timer64") { + err = of_property_read_u32(np, "ti,core-mask", &val); + if (!err) { + if (val & (1 << get_coreid())) { + found = 1; + break; + } + } else if (!first) + first = np; + } + if (!found) { + /* try first one with no core-mask */ + if (first) + np = of_node_get(first); + else { + pr_debug("Cannot find ti,c64x+timer64 timer.\n"); + return; + } + } + + timer = of_iomap(np, 0); + if (!timer) { + pr_debug("%s: Cannot map timer registers.\n", np->full_name); + goto out; + } + pr_debug("%s: Timer registers=%p.\n", np->full_name, timer); + + cd->irq = irq_of_parse_and_map(np, 0); + if (cd->irq == NO_IRQ) { + pr_debug("%s: Cannot find interrupt.\n", np->full_name); + iounmap(timer); + goto out; + } + + /* If there is a device state control, save the ID. */ + err = of_property_read_u32(np, "ti,dscr-dev-enable", &val); + if (!err) + timer64_devstate_id = val; + + pr_debug("%s: Timer irq=%d.\n", np->full_name, cd->irq); + + clockevents_calc_mult_shift(cd, c6x_core_freq / TIMER_DIVISOR, 5); + + cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); + cd->min_delta_ns = clockevent_delta2ns(250, cd); + + cd->cpumask = cpumask_of(smp_processor_id()); + + clockevents_register_device(cd); + setup_irq(cd->irq, &timer_iact); + +out: + of_node_put(np); + return; +} -- cgit v1.2.3 From ec500af3059b474df35418c41c684c1cde830c81 Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 11:06:27 -0400 Subject: C6X: interrupt handling Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Reviewed-by: Thomas Gleixner Acked-by: Arnd Bergmann --- arch/c6x/include/asm/hardirq.h | 20 + arch/c6x/include/asm/irq.h | 302 +++++++++++++++ arch/c6x/include/asm/irqflags.h | 72 ++++ arch/c6x/include/asm/megamod-pic.h | 9 + arch/c6x/kernel/irq.c | 728 +++++++++++++++++++++++++++++++++++++ arch/c6x/platforms/megamod-pic.c | 349 ++++++++++++++++++ 6 files changed, 1480 insertions(+) create mode 100644 arch/c6x/include/asm/hardirq.h create mode 100644 arch/c6x/include/asm/irq.h create mode 100644 arch/c6x/include/asm/irqflags.h create mode 100644 arch/c6x/include/asm/megamod-pic.h create mode 100644 arch/c6x/kernel/irq.c create mode 100644 arch/c6x/platforms/megamod-pic.c (limited to 'arch') diff --git a/arch/c6x/include/asm/hardirq.h b/arch/c6x/include/asm/hardirq.h new file mode 100644 index 000000000000..9621954f98f4 --- /dev/null +++ b/arch/c6x/include/asm/hardirq.h @@ -0,0 +1,20 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_HARDIRQ_H +#define _ASM_C6X_HARDIRQ_H + +extern void ack_bad_irq(int irq); +#define ack_bad_irq ack_bad_irq + +#include + +#endif /* _ASM_C6X_HARDIRQ_H */ diff --git a/arch/c6x/include/asm/irq.h b/arch/c6x/include/asm/irq.h new file mode 100644 index 000000000000..a6ae3c9d9c40 --- /dev/null +++ b/arch/c6x/include/asm/irq.h @@ -0,0 +1,302 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) + * + * Large parts taken directly from powerpc. + * + * 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_C6X_IRQ_H +#define _ASM_C6X_IRQ_H + +#include +#include +#include +#include + +#define irq_canonicalize(irq) (irq) + +/* + * The C64X+ core has 16 IRQ vectors. One each is used by Reset and NMI. Two + * are reserved. The remaining 12 vectors are used to route SoC interrupts. + * These interrupt vectors are prioritized with IRQ 4 having the highest + * priority and IRQ 15 having the lowest. + * + * The C64x+ megamodule provides a PIC which combines SoC IRQ sources into a + * single core IRQ vector. There are four combined sources, each of which + * feed into one of the 12 general interrupt vectors. The remaining 8 vectors + * can each route a single SoC interrupt directly. + */ +#define NR_PRIORITY_IRQS 16 + +#define NR_IRQS_LEGACY NR_PRIORITY_IRQS + +/* Total number of virq in the platform */ +#define NR_IRQS 256 + +/* This number is used when no interrupt has been assigned */ +#define NO_IRQ 0 + +/* This type is the placeholder for a hardware interrupt number. It has to + * be big enough to enclose whatever representation is used by a given + * platform. + */ +typedef unsigned long irq_hw_number_t; + +/* Interrupt controller "host" data structure. This could be defined as a + * irq domain controller. That is, it handles the mapping between hardware + * and virtual interrupt numbers for a given interrupt domain. The host + * structure is generally created by the PIC code for a given PIC instance + * (though a host can cover more than one PIC if they have a flat number + * model). It's the host callbacks that are responsible for setting the + * irq_chip on a given irq_desc after it's been mapped. + * + * The host code and data structures are fairly agnostic to the fact that + * we use an open firmware device-tree. We do have references to struct + * device_node in two places: in irq_find_host() to find the host matching + * a given interrupt controller node, and of course as an argument to its + * counterpart host->ops->match() callback. However, those are treated as + * generic pointers by the core and the fact that it's actually a device-node + * pointer is purely a convention between callers and implementation. This + * code could thus be used on other architectures by replacing those two + * by some sort of arch-specific void * "token" used to identify interrupt + * controllers. + */ +struct irq_host; +struct radix_tree_root; +struct device_node; + +/* Functions below are provided by the host and called whenever a new mapping + * is created or an old mapping is disposed. The host can then proceed to + * whatever internal data structures management is required. It also needs + * to setup the irq_desc when returning from map(). + */ +struct irq_host_ops { + /* Match an interrupt controller device node to a host, returns + * 1 on a match + */ + int (*match)(struct irq_host *h, struct device_node *node); + + /* Create or update a mapping between a virtual irq number and a hw + * irq number. This is called only once for a given mapping. + */ + int (*map)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw); + + /* Dispose of such a mapping */ + void (*unmap)(struct irq_host *h, unsigned int virq); + + /* Translate device-tree interrupt specifier from raw format coming + * from the firmware to a irq_hw_number_t (interrupt line number) and + * type (sense) that can be passed to set_irq_type(). In the absence + * of this callback, irq_create_of_mapping() and irq_of_parse_and_map() + * will return the hw number in the first cell and IRQ_TYPE_NONE for + * the type (which amount to keeping whatever default value the + * interrupt controller has for that line) + */ + int (*xlate)(struct irq_host *h, struct device_node *ctrler, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type); +}; + +struct irq_host { + struct list_head link; + + /* type of reverse mapping technique */ + unsigned int revmap_type; +#define IRQ_HOST_MAP_PRIORITY 0 /* core priority irqs, get irqs 1..15 */ +#define IRQ_HOST_MAP_NOMAP 1 /* no fast reverse mapping */ +#define IRQ_HOST_MAP_LINEAR 2 /* linear map of interrupts */ +#define IRQ_HOST_MAP_TREE 3 /* radix tree */ + union { + struct { + unsigned int size; + unsigned int *revmap; + } linear; + struct radix_tree_root tree; + } revmap_data; + struct irq_host_ops *ops; + void *host_data; + irq_hw_number_t inval_irq; + + /* Optional device node pointer */ + struct device_node *of_node; +}; + +struct irq_data; +extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); +extern irq_hw_number_t virq_to_hw(unsigned int virq); +extern bool virq_is_host(unsigned int virq, struct irq_host *host); + +/** + * irq_alloc_host - Allocate a new irq_host data structure + * @of_node: optional device-tree node of the interrupt controller + * @revmap_type: type of reverse mapping to use + * @revmap_arg: for IRQ_HOST_MAP_LINEAR linear only: size of the map + * @ops: map/unmap host callbacks + * @inval_irq: provide a hw number in that host space that is always invalid + * + * Allocates and initialize and irq_host structure. Note that in the case of + * IRQ_HOST_MAP_LEGACY, the map() callback will be called before this returns + * for all legacy interrupts except 0 (which is always the invalid irq for + * a legacy controller). For a IRQ_HOST_MAP_LINEAR, the map is allocated by + * this call as well. For a IRQ_HOST_MAP_TREE, the radix tree will be allocated + * later during boot automatically (the reverse mapping will use the slow path + * until that happens). + */ +extern struct irq_host *irq_alloc_host(struct device_node *of_node, + unsigned int revmap_type, + unsigned int revmap_arg, + struct irq_host_ops *ops, + irq_hw_number_t inval_irq); + + +/** + * irq_find_host - Locates a host for a given device node + * @node: device-tree node of the interrupt controller + */ +extern struct irq_host *irq_find_host(struct device_node *node); + + +/** + * irq_set_default_host - Set a "default" host + * @host: default host pointer + * + * For convenience, it's possible to set a "default" host that will be used + * whenever NULL is passed to irq_create_mapping(). It makes life easier for + * platforms that want to manipulate a few hard coded interrupt numbers that + * aren't properly represented in the device-tree. + */ +extern void irq_set_default_host(struct irq_host *host); + + +/** + * irq_set_virq_count - Set the maximum number of virt irqs + * @count: number of linux virtual irqs, capped with NR_IRQS + * + * This is mainly for use by platforms like iSeries who want to program + * the virtual irq number in the controller to avoid the reverse mapping + */ +extern void irq_set_virq_count(unsigned int count); + + +/** + * irq_create_mapping - Map a hardware interrupt into linux virq space + * @host: host owning this hardware interrupt or NULL for default host + * @hwirq: hardware irq number in that host space + * + * Only one mapping per hardware interrupt is permitted. Returns a linux + * virq number. + * If the sense/trigger is to be specified, set_irq_type() should be called + * on the number returned from that call. + */ +extern unsigned int irq_create_mapping(struct irq_host *host, + irq_hw_number_t hwirq); + + +/** + * irq_dispose_mapping - Unmap an interrupt + * @virq: linux virq number of the interrupt to unmap + */ +extern void irq_dispose_mapping(unsigned int virq); + +/** + * irq_find_mapping - Find a linux virq from an hw irq number. + * @host: host owning this hardware interrupt + * @hwirq: hardware irq number in that host space + * + * This is a slow path, for use by generic code. It's expected that an + * irq controller implementation directly calls the appropriate low level + * mapping function. + */ +extern unsigned int irq_find_mapping(struct irq_host *host, + irq_hw_number_t hwirq); + +/** + * irq_create_direct_mapping - Allocate a virq for direct mapping + * @host: host to allocate the virq for or NULL for default host + * + * This routine is used for irq controllers which can choose the hardware + * interrupt numbers they generate. In such a case it's simplest to use + * the linux virq as the hardware interrupt number. + */ +extern unsigned int irq_create_direct_mapping(struct irq_host *host); + +/** + * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping. + * @host: host owning this hardware interrupt + * @virq: linux irq number + * @hwirq: hardware irq number in that host space + * + * This is for use by irq controllers that use a radix tree reverse + * mapping for fast lookup. + */ +extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, + irq_hw_number_t hwirq); + +/** + * irq_radix_revmap_lookup - Find a linux virq from a hw irq number. + * @host: host owning this hardware interrupt + * @hwirq: hardware irq number in that host space + * + * This is a fast path, for use by irq controller code that uses radix tree + * revmaps + */ +extern unsigned int irq_radix_revmap_lookup(struct irq_host *host, + irq_hw_number_t hwirq); + +/** + * irq_linear_revmap - Find a linux virq from a hw irq number. + * @host: host owning this hardware interrupt + * @hwirq: hardware irq number in that host space + * + * This is a fast path, for use by irq controller code that uses linear + * revmaps. It does fallback to the slow path if the revmap doesn't exist + * yet and will create the revmap entry with appropriate locking + */ + +extern unsigned int irq_linear_revmap(struct irq_host *host, + irq_hw_number_t hwirq); + + + +/** + * irq_alloc_virt - Allocate virtual irq numbers + * @host: host owning these new virtual irqs + * @count: number of consecutive numbers to allocate + * @hint: pass a hint number, the allocator will try to use a 1:1 mapping + * + * This is a low level function that is used internally by irq_create_mapping() + * and that can be used by some irq controllers implementations for things + * like allocating ranges of numbers for MSIs. The revmaps are left untouched. + */ +extern unsigned int irq_alloc_virt(struct irq_host *host, + unsigned int count, + unsigned int hint); + +/** + * irq_free_virt - Free virtual irq numbers + * @virq: virtual irq number of the first interrupt to free + * @count: number of interrupts to free + * + * This function is the opposite of irq_alloc_virt. It will not clear reverse + * maps, this should be done previously by unmap'ing the interrupt. In fact, + * all interrupts covered by the range being freed should have been unmapped + * prior to calling this. + */ +extern void irq_free_virt(unsigned int virq, unsigned int count); + +extern void __init init_pic_c64xplus(void); + +extern void init_IRQ(void); + +struct pt_regs; + +extern asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs); + +extern unsigned long irq_err_count; + +#endif /* _ASM_C6X_IRQ_H */ diff --git a/arch/c6x/include/asm/irqflags.h b/arch/c6x/include/asm/irqflags.h new file mode 100644 index 000000000000..cf78e09e18c3 --- /dev/null +++ b/arch/c6x/include/asm/irqflags.h @@ -0,0 +1,72 @@ +/* + * C6X IRQ flag handling + * + * Copyright (C) 2010 Texas Instruments Incorporated + * Written by Mark Salter (msalter@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#ifndef _ASM_IRQFLAGS_H +#define _ASM_IRQFLAGS_H + +#ifndef __ASSEMBLY__ + +/* read interrupt enabled status */ +static inline unsigned long arch_local_save_flags(void) +{ + unsigned long flags; + + asm volatile (" mvc .s2 CSR,%0\n" : "=b"(flags)); + return flags; +} + +/* set interrupt enabled status */ +static inline void arch_local_irq_restore(unsigned long flags) +{ + asm volatile (" mvc .s2 %0,CSR\n" : : "b"(flags)); +} + +/* unconditionally enable interrupts */ +static inline void arch_local_irq_enable(void) +{ + unsigned long flags = arch_local_save_flags(); + flags |= 1; + arch_local_irq_restore(flags); +} + +/* unconditionally disable interrupts */ +static inline void arch_local_irq_disable(void) +{ + unsigned long flags = arch_local_save_flags(); + flags &= ~1; + arch_local_irq_restore(flags); +} + +/* get status and disable interrupts */ +static inline unsigned long arch_local_irq_save(void) +{ + unsigned long flags; + + flags = arch_local_save_flags(); + arch_local_irq_restore(flags & ~1); + return flags; +} + +/* test flags */ +static inline int arch_irqs_disabled_flags(unsigned long flags) +{ + return (flags & 1) == 0; +} + +/* test hardware interrupt enable bit */ +static inline int arch_irqs_disabled(void) +{ + return arch_irqs_disabled_flags(arch_local_save_flags()); +} + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_IRQFLAGS_H */ diff --git a/arch/c6x/include/asm/megamod-pic.h b/arch/c6x/include/asm/megamod-pic.h new file mode 100644 index 000000000000..eca0a8678034 --- /dev/null +++ b/arch/c6x/include/asm/megamod-pic.h @@ -0,0 +1,9 @@ +#ifndef _C6X_MEGAMOD_PIC_H +#define _C6X_MEGAMOD_PIC_H + +#ifdef __KERNEL__ + +extern void __init megamod_pic_init(void); + +#endif /* __KERNEL__ */ +#endif /* _C6X_MEGAMOD_PIC_H */ diff --git a/arch/c6x/kernel/irq.c b/arch/c6x/kernel/irq.c new file mode 100644 index 000000000000..0929e4b2b244 --- /dev/null +++ b/arch/c6x/kernel/irq.c @@ -0,0 +1,728 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * + * This borrows heavily from powerpc version, which is: + * + * Derived from arch/i386/kernel/irq.c + * Copyright (C) 1992 Linus Torvalds + * Adapted from arch/i386 by Gary Thomas + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Updated and modified by Cort Dougan + * Copyright (C) 1996-2001 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras + * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +unsigned long irq_err_count; + +static DEFINE_RAW_SPINLOCK(core_irq_lock); + +static void mask_core_irq(struct irq_data *data) +{ + unsigned int prio = data->irq; + + BUG_ON(prio < 4 || prio >= NR_PRIORITY_IRQS); + + raw_spin_lock(&core_irq_lock); + and_creg(IER, ~(1 << prio)); + raw_spin_unlock(&core_irq_lock); +} + +static void unmask_core_irq(struct irq_data *data) +{ + unsigned int prio = data->irq; + + raw_spin_lock(&core_irq_lock); + or_creg(IER, 1 << prio); + raw_spin_unlock(&core_irq_lock); +} + +static struct irq_chip core_chip = { + .name = "core", + .irq_mask = mask_core_irq, + .irq_unmask = unmask_core_irq, +}; + +asmlinkage void c6x_do_IRQ(unsigned int prio, struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + + irq_enter(); + + BUG_ON(prio < 4 || prio >= NR_PRIORITY_IRQS); + + generic_handle_irq(prio); + + irq_exit(); + + set_irq_regs(old_regs); +} + +static struct irq_host *core_host; + +static int core_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + if (hw < 4 || hw >= NR_PRIORITY_IRQS) + return -EINVAL; + + irq_set_status_flags(virq, IRQ_LEVEL); + irq_set_chip_and_handler(virq, &core_chip, handle_level_irq); + return 0; +} + +static struct irq_host_ops core_host_ops = { + .map = core_host_map, +}; + +void __init init_IRQ(void) +{ + struct device_node *np; + + /* Mask all priority IRQs */ + and_creg(IER, ~0xfff0); + + np = of_find_compatible_node(NULL, NULL, "ti,c64x+core-pic"); + if (np != NULL) { + /* create the core host */ + core_host = irq_alloc_host(np, IRQ_HOST_MAP_PRIORITY, 0, + &core_host_ops, 0); + if (core_host) + irq_set_default_host(core_host); + of_node_put(np); + } + + printk(KERN_INFO "Core interrupt controller initialized\n"); + + /* now we're ready for other SoC controllers */ + megamod_pic_init(); + + /* Clear all general IRQ flags */ + set_creg(ICR, 0xfff0); +} + +void ack_bad_irq(int irq) +{ + printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); + irq_err_count++; +} + +int arch_show_interrupts(struct seq_file *p, int prec) +{ + seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); + return 0; +} + +/* + * IRQ controller and virtual interrupts + */ + +/* The main irq map itself is an array of NR_IRQ entries containing the + * associate host and irq number. An entry with a host of NULL is free. + * An entry can be allocated if it's free, the allocator always then sets + * hwirq first to the host's invalid irq number and then fills ops. + */ +struct irq_map_entry { + irq_hw_number_t hwirq; + struct irq_host *host; +}; + +static LIST_HEAD(irq_hosts); +static DEFINE_RAW_SPINLOCK(irq_big_lock); +static DEFINE_MUTEX(revmap_trees_mutex); +static struct irq_map_entry irq_map[NR_IRQS]; +static unsigned int irq_virq_count = NR_IRQS; +static struct irq_host *irq_default_host; + +irq_hw_number_t irqd_to_hwirq(struct irq_data *d) +{ + return irq_map[d->irq].hwirq; +} +EXPORT_SYMBOL_GPL(irqd_to_hwirq); + +irq_hw_number_t virq_to_hw(unsigned int virq) +{ + return irq_map[virq].hwirq; +} +EXPORT_SYMBOL_GPL(virq_to_hw); + +bool virq_is_host(unsigned int virq, struct irq_host *host) +{ + return irq_map[virq].host == host; +} +EXPORT_SYMBOL_GPL(virq_is_host); + +static int default_irq_host_match(struct irq_host *h, struct device_node *np) +{ + return h->of_node != NULL && h->of_node == np; +} + +struct irq_host *irq_alloc_host(struct device_node *of_node, + unsigned int revmap_type, + unsigned int revmap_arg, + struct irq_host_ops *ops, + irq_hw_number_t inval_irq) +{ + struct irq_host *host; + unsigned int size = sizeof(struct irq_host); + unsigned int i; + unsigned int *rmap; + unsigned long flags; + + /* Allocate structure and revmap table if using linear mapping */ + if (revmap_type == IRQ_HOST_MAP_LINEAR) + size += revmap_arg * sizeof(unsigned int); + host = kzalloc(size, GFP_KERNEL); + if (host == NULL) + return NULL; + + /* Fill structure */ + host->revmap_type = revmap_type; + host->inval_irq = inval_irq; + host->ops = ops; + host->of_node = of_node_get(of_node); + + if (host->ops->match == NULL) + host->ops->match = default_irq_host_match; + + raw_spin_lock_irqsave(&irq_big_lock, flags); + + /* Check for the priority controller. */ + if (revmap_type == IRQ_HOST_MAP_PRIORITY) { + if (irq_map[0].host != NULL) { + raw_spin_unlock_irqrestore(&irq_big_lock, flags); + of_node_put(host->of_node); + kfree(host); + return NULL; + } + irq_map[0].host = host; + } + + list_add(&host->link, &irq_hosts); + raw_spin_unlock_irqrestore(&irq_big_lock, flags); + + /* Additional setups per revmap type */ + switch (revmap_type) { + case IRQ_HOST_MAP_PRIORITY: + /* 0 is always the invalid number for priority */ + host->inval_irq = 0; + /* setup us as the host for all priority interrupts */ + for (i = 1; i < NR_PRIORITY_IRQS; i++) { + irq_map[i].hwirq = i; + smp_wmb(); + irq_map[i].host = host; + smp_wmb(); + + ops->map(host, i, i); + } + break; + case IRQ_HOST_MAP_LINEAR: + rmap = (unsigned int *)(host + 1); + for (i = 0; i < revmap_arg; i++) + rmap[i] = NO_IRQ; + host->revmap_data.linear.size = revmap_arg; + smp_wmb(); + host->revmap_data.linear.revmap = rmap; + break; + case IRQ_HOST_MAP_TREE: + INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL); + break; + default: + break; + } + + pr_debug("irq: Allocated host of type %d @0x%p\n", revmap_type, host); + + return host; +} + +struct irq_host *irq_find_host(struct device_node *node) +{ + struct irq_host *h, *found = NULL; + unsigned long flags; + + /* We might want to match the legacy controller last since + * it might potentially be set to match all interrupts in + * the absence of a device node. This isn't a problem so far + * yet though... + */ + raw_spin_lock_irqsave(&irq_big_lock, flags); + list_for_each_entry(h, &irq_hosts, link) + if (h->ops->match(h, node)) { + found = h; + break; + } + raw_spin_unlock_irqrestore(&irq_big_lock, flags); + return found; +} +EXPORT_SYMBOL_GPL(irq_find_host); + +void irq_set_default_host(struct irq_host *host) +{ + pr_debug("irq: Default host set to @0x%p\n", host); + + irq_default_host = host; +} + +void irq_set_virq_count(unsigned int count) +{ + pr_debug("irq: Trying to set virq count to %d\n", count); + + BUG_ON(count < NR_PRIORITY_IRQS); + if (count < NR_IRQS) + irq_virq_count = count; +} + +static int irq_setup_virq(struct irq_host *host, unsigned int virq, + irq_hw_number_t hwirq) +{ + int res; + + res = irq_alloc_desc_at(virq, 0); + if (res != virq) { + pr_debug("irq: -> allocating desc failed\n"); + goto error; + } + + /* map it */ + smp_wmb(); + irq_map[virq].hwirq = hwirq; + smp_mb(); + + if (host->ops->map(host, virq, hwirq)) { + pr_debug("irq: -> mapping failed, freeing\n"); + goto errdesc; + } + + irq_clear_status_flags(virq, IRQ_NOREQUEST); + + return 0; + +errdesc: + irq_free_descs(virq, 1); +error: + irq_free_virt(virq, 1); + return -1; +} + +unsigned int irq_create_direct_mapping(struct irq_host *host) +{ + unsigned int virq; + + if (host == NULL) + host = irq_default_host; + + BUG_ON(host == NULL); + WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP); + + virq = irq_alloc_virt(host, 1, 0); + if (virq == NO_IRQ) { + pr_debug("irq: create_direct virq allocation failed\n"); + return NO_IRQ; + } + + pr_debug("irq: create_direct obtained virq %d\n", virq); + + if (irq_setup_virq(host, virq, virq)) + return NO_IRQ; + + return virq; +} + +unsigned int irq_create_mapping(struct irq_host *host, + irq_hw_number_t hwirq) +{ + unsigned int virq, hint; + + pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq); + + /* Look for default host if nececssary */ + if (host == NULL) + host = irq_default_host; + if (host == NULL) { + printk(KERN_WARNING "irq_create_mapping called for" + " NULL host, hwirq=%lx\n", hwirq); + WARN_ON(1); + return NO_IRQ; + } + pr_debug("irq: -> using host @%p\n", host); + + /* Check if mapping already exists */ + virq = irq_find_mapping(host, hwirq); + if (virq != NO_IRQ) { + pr_debug("irq: -> existing mapping on virq %d\n", virq); + return virq; + } + + /* Allocate a virtual interrupt number */ + hint = hwirq % irq_virq_count; + virq = irq_alloc_virt(host, 1, hint); + if (virq == NO_IRQ) { + pr_debug("irq: -> virq allocation failed\n"); + return NO_IRQ; + } + + if (irq_setup_virq(host, virq, hwirq)) + return NO_IRQ; + + pr_debug("irq: irq %lu on host %s mapped to virtual irq %u\n", + hwirq, host->of_node ? host->of_node->full_name : "null", virq); + + return virq; +} +EXPORT_SYMBOL_GPL(irq_create_mapping); + +unsigned int irq_create_of_mapping(struct device_node *controller, + const u32 *intspec, unsigned int intsize) +{ + struct irq_host *host; + irq_hw_number_t hwirq; + unsigned int type = IRQ_TYPE_NONE; + unsigned int virq; + + if (controller == NULL) + host = irq_default_host; + else + host = irq_find_host(controller); + if (host == NULL) { + printk(KERN_WARNING "irq: no irq host found for %s !\n", + controller->full_name); + return NO_IRQ; + } + + /* If host has no translation, then we assume interrupt line */ + if (host->ops->xlate == NULL) + hwirq = intspec[0]; + else { + if (host->ops->xlate(host, controller, intspec, intsize, + &hwirq, &type)) + return NO_IRQ; + } + + /* Create mapping */ + virq = irq_create_mapping(host, hwirq); + if (virq == NO_IRQ) + return virq; + + /* Set type if specified and different than the current one */ + if (type != IRQ_TYPE_NONE && + type != (irqd_get_trigger_type(irq_get_irq_data(virq)))) + irq_set_irq_type(virq, type); + return virq; +} +EXPORT_SYMBOL_GPL(irq_create_of_mapping); + +void irq_dispose_mapping(unsigned int virq) +{ + struct irq_host *host; + irq_hw_number_t hwirq; + + if (virq == NO_IRQ) + return; + + /* Never unmap priority interrupts */ + if (virq < NR_PRIORITY_IRQS) + return; + + host = irq_map[virq].host; + if (WARN_ON(host == NULL)) + return; + + irq_set_status_flags(virq, IRQ_NOREQUEST); + + /* remove chip and handler */ + irq_set_chip_and_handler(virq, NULL, NULL); + + /* Make sure it's completed */ + synchronize_irq(virq); + + /* Tell the PIC about it */ + if (host->ops->unmap) + host->ops->unmap(host, virq); + smp_mb(); + + /* Clear reverse map */ + hwirq = irq_map[virq].hwirq; + switch (host->revmap_type) { + case IRQ_HOST_MAP_LINEAR: + if (hwirq < host->revmap_data.linear.size) + host->revmap_data.linear.revmap[hwirq] = NO_IRQ; + break; + case IRQ_HOST_MAP_TREE: + mutex_lock(&revmap_trees_mutex); + radix_tree_delete(&host->revmap_data.tree, hwirq); + mutex_unlock(&revmap_trees_mutex); + break; + } + + /* Destroy map */ + smp_mb(); + irq_map[virq].hwirq = host->inval_irq; + + irq_free_descs(virq, 1); + /* Free it */ + irq_free_virt(virq, 1); +} +EXPORT_SYMBOL_GPL(irq_dispose_mapping); + +unsigned int irq_find_mapping(struct irq_host *host, + irq_hw_number_t hwirq) +{ + unsigned int i; + unsigned int hint = hwirq % irq_virq_count; + + /* Look for default host if nececssary */ + if (host == NULL) + host = irq_default_host; + if (host == NULL) + return NO_IRQ; + + /* Slow path does a linear search of the map */ + i = hint; + do { + if (irq_map[i].host == host && + irq_map[i].hwirq == hwirq) + return i; + i++; + if (i >= irq_virq_count) + i = 4; + } while (i != hint); + return NO_IRQ; +} +EXPORT_SYMBOL_GPL(irq_find_mapping); + +unsigned int irq_radix_revmap_lookup(struct irq_host *host, + irq_hw_number_t hwirq) +{ + struct irq_map_entry *ptr; + unsigned int virq; + + if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE)) + return irq_find_mapping(host, hwirq); + + /* + * The ptr returned references the static global irq_map. + * but freeing an irq can delete nodes along the path to + * do the lookup via call_rcu. + */ + rcu_read_lock(); + ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq); + rcu_read_unlock(); + + /* + * If found in radix tree, then fine. + * Else fallback to linear lookup - this should not happen in practice + * as it means that we failed to insert the node in the radix tree. + */ + if (ptr) + virq = ptr - irq_map; + else + virq = irq_find_mapping(host, hwirq); + + return virq; +} + +void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq, + irq_hw_number_t hwirq) +{ + if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE)) + return; + + if (virq != NO_IRQ) { + mutex_lock(&revmap_trees_mutex); + radix_tree_insert(&host->revmap_data.tree, hwirq, + &irq_map[virq]); + mutex_unlock(&revmap_trees_mutex); + } +} + +unsigned int irq_linear_revmap(struct irq_host *host, + irq_hw_number_t hwirq) +{ + unsigned int *revmap; + + if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR)) + return irq_find_mapping(host, hwirq); + + /* Check revmap bounds */ + if (unlikely(hwirq >= host->revmap_data.linear.size)) + return irq_find_mapping(host, hwirq); + + /* Check if revmap was allocated */ + revmap = host->revmap_data.linear.revmap; + if (unlikely(revmap == NULL)) + return irq_find_mapping(host, hwirq); + + /* Fill up revmap with slow path if no mapping found */ + if (unlikely(revmap[hwirq] == NO_IRQ)) + revmap[hwirq] = irq_find_mapping(host, hwirq); + + return revmap[hwirq]; +} + +unsigned int irq_alloc_virt(struct irq_host *host, + unsigned int count, + unsigned int hint) +{ + unsigned long flags; + unsigned int i, j, found = NO_IRQ; + + if (count == 0 || count > (irq_virq_count - NR_PRIORITY_IRQS)) + return NO_IRQ; + + raw_spin_lock_irqsave(&irq_big_lock, flags); + + /* Use hint for 1 interrupt if any */ + if (count == 1 && hint >= NR_PRIORITY_IRQS && + hint < irq_virq_count && irq_map[hint].host == NULL) { + found = hint; + goto hint_found; + } + + /* Look for count consecutive numbers in the allocatable + * (non-legacy) space + */ + for (i = NR_PRIORITY_IRQS, j = 0; i < irq_virq_count; i++) { + if (irq_map[i].host != NULL) + j = 0; + else + j++; + + if (j == count) { + found = i - count + 1; + break; + } + } + if (found == NO_IRQ) { + raw_spin_unlock_irqrestore(&irq_big_lock, flags); + return NO_IRQ; + } + hint_found: + for (i = found; i < (found + count); i++) { + irq_map[i].hwirq = host->inval_irq; + smp_wmb(); + irq_map[i].host = host; + } + raw_spin_unlock_irqrestore(&irq_big_lock, flags); + return found; +} + +void irq_free_virt(unsigned int virq, unsigned int count) +{ + unsigned long flags; + unsigned int i; + + WARN_ON(virq < NR_PRIORITY_IRQS); + WARN_ON(count == 0 || (virq + count) > irq_virq_count); + + if (virq < NR_PRIORITY_IRQS) { + if (virq + count < NR_PRIORITY_IRQS) + return; + count -= NR_PRIORITY_IRQS - virq; + virq = NR_PRIORITY_IRQS; + } + + if (count > irq_virq_count || virq > irq_virq_count - count) { + if (virq > irq_virq_count) + return; + count = irq_virq_count - virq; + } + + raw_spin_lock_irqsave(&irq_big_lock, flags); + for (i = virq; i < (virq + count); i++) { + struct irq_host *host; + + host = irq_map[i].host; + irq_map[i].hwirq = host->inval_irq; + smp_wmb(); + irq_map[i].host = NULL; + } + raw_spin_unlock_irqrestore(&irq_big_lock, flags); +} + +#ifdef CONFIG_VIRQ_DEBUG +static int virq_debug_show(struct seq_file *m, void *private) +{ + unsigned long flags; + struct irq_desc *desc; + const char *p; + static const char none[] = "none"; + void *data; + int i; + + seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", + "chip name", "chip data", "host name"); + + for (i = 1; i < nr_irqs; i++) { + desc = irq_to_desc(i); + if (!desc) + continue; + + raw_spin_lock_irqsave(&desc->lock, flags); + + if (desc->action && desc->action->handler) { + struct irq_chip *chip; + + seq_printf(m, "%5d ", i); + seq_printf(m, "0x%05lx ", irq_map[i].hwirq); + + chip = irq_desc_get_chip(desc); + if (chip && chip->name) + p = chip->name; + else + p = none; + seq_printf(m, "%-15s ", p); + + data = irq_desc_get_chip_data(desc); + seq_printf(m, "0x%16p ", data); + + if (irq_map[i].host && irq_map[i].host->of_node) + p = irq_map[i].host->of_node->full_name; + else + p = none; + seq_printf(m, "%s\n", p); + } + + raw_spin_unlock_irqrestore(&desc->lock, flags); + } + + return 0; +} + +static int virq_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, virq_debug_show, inode->i_private); +} + +static const struct file_operations virq_debug_fops = { + .open = virq_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init irq_debugfs_init(void) +{ + if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, + NULL, &virq_debug_fops) == NULL) + return -ENOMEM; + + return 0; +} +device_initcall(irq_debugfs_init); +#endif /* CONFIG_VIRQ_DEBUG */ diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c new file mode 100644 index 000000000000..7c37a947fb1c --- /dev/null +++ b/arch/c6x/platforms/megamod-pic.c @@ -0,0 +1,349 @@ +/* + * Support for C64x+ Megamodule Interrupt Controller + * + * Copyright (C) 2010, 2011 Texas Instruments Incorporated + * Contributed by: Mark Salter + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define NR_COMBINERS 4 +#define NR_MUX_OUTPUTS 12 + +#define IRQ_UNMAPPED 0xffff + +/* + * Megamodule Interrupt Controller register layout + */ +struct megamod_regs { + u32 evtflag[8]; + u32 evtset[8]; + u32 evtclr[8]; + u32 reserved0[8]; + u32 evtmask[8]; + u32 mevtflag[8]; + u32 expmask[8]; + u32 mexpflag[8]; + u32 intmux_unused; + u32 intmux[7]; + u32 reserved1[8]; + u32 aegmux[2]; + u32 reserved2[14]; + u32 intxstat; + u32 intxclr; + u32 intdmask; + u32 reserved3[13]; + u32 evtasrt; +}; + +struct megamod_pic { + struct irq_host *irqhost; + struct megamod_regs __iomem *regs; + raw_spinlock_t lock; + + /* hw mux mapping */ + unsigned int output_to_irq[NR_MUX_OUTPUTS]; +}; + +static struct megamod_pic *mm_pic; + +struct megamod_cascade_data { + struct megamod_pic *pic; + int index; +}; + +static struct megamod_cascade_data cascade_data[NR_COMBINERS]; + +static void mask_megamod(struct irq_data *data) +{ + struct megamod_pic *pic = irq_data_get_irq_chip_data(data); + irq_hw_number_t src = irqd_to_hwirq(data); + u32 __iomem *evtmask = &pic->regs->evtmask[src / 32]; + + raw_spin_lock(&pic->lock); + soc_writel(soc_readl(evtmask) | (1 << (src & 31)), evtmask); + raw_spin_unlock(&pic->lock); +} + +static void unmask_megamod(struct irq_data *data) +{ + struct megamod_pic *pic = irq_data_get_irq_chip_data(data); + irq_hw_number_t src = irqd_to_hwirq(data); + u32 __iomem *evtmask = &pic->regs->evtmask[src / 32]; + + raw_spin_lock(&pic->lock); + soc_writel(soc_readl(evtmask) & ~(1 << (src & 31)), evtmask); + raw_spin_unlock(&pic->lock); +} + +static struct irq_chip megamod_chip = { + .name = "megamod", + .irq_mask = mask_megamod, + .irq_unmask = unmask_megamod, +}; + +static void megamod_irq_cascade(unsigned int irq, struct irq_desc *desc) +{ + struct megamod_cascade_data *cascade; + struct megamod_pic *pic; + u32 events; + int n, idx; + + cascade = irq_desc_get_handler_data(desc); + + pic = cascade->pic; + idx = cascade->index; + + while ((events = soc_readl(&pic->regs->mevtflag[idx])) != 0) { + n = __ffs(events); + + irq = irq_linear_revmap(pic->irqhost, idx * 32 + n); + + soc_writel(1 << n, &pic->regs->evtclr[idx]); + + generic_handle_irq(irq); + } +} + +static int megamod_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct megamod_pic *pic = h->host_data; + int i; + + /* We shouldn't see a hwirq which is muxed to core controller */ + for (i = 0; i < NR_MUX_OUTPUTS; i++) + if (pic->output_to_irq[i] == hw) + return -1; + + irq_set_chip_data(virq, pic); + irq_set_chip_and_handler(virq, &megamod_chip, handle_level_irq); + + /* Set default irq type */ + irq_set_irq_type(virq, IRQ_TYPE_NONE); + + return 0; +} + +static int megamod_xlate(struct irq_host *h, struct device_node *ct, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type) + +{ + /* megamod intspecs must have 1 cell */ + BUG_ON(intsize != 1); + *out_hwirq = intspec[0]; + *out_type = IRQ_TYPE_NONE; + return 0; +} + +static struct irq_host_ops megamod_host_ops = { + .map = megamod_map, + .xlate = megamod_xlate, +}; + +static void __init set_megamod_mux(struct megamod_pic *pic, int src, int output) +{ + int index, offset; + u32 val; + + if (src < 0 || src >= (NR_COMBINERS * 32)) { + pic->output_to_irq[output] = IRQ_UNMAPPED; + return; + } + + /* four mappings per mux register */ + index = output / 4; + offset = (output & 3) * 8; + + val = soc_readl(&pic->regs->intmux[index]); + val &= ~(0xff << offset); + val |= src << offset; + soc_writel(val, &pic->regs->intmux[index]); +} + +/* + * Parse the MUX mapping, if one exists. + * + * The MUX map is an array of up to 12 cells; one for each usable core priority + * interrupt. The value of a given cell is the megamodule interrupt source + * which is to me MUXed to the output corresponding to the cell position + * withing the array. The first cell in the array corresponds to priority + * 4 and the last (12th) cell corresponds to priority 15. The allowed + * values are 4 - ((NR_COMBINERS * 32) - 1). Note that the combined interrupt + * sources (0 - 3) are not allowed to be mapped through this property. They + * are handled through the "interrupts" property. This allows us to use a + * value of zero as a "do not map" placeholder. + */ +static void __init parse_priority_map(struct megamod_pic *pic, + int *mapping, int size) +{ + struct device_node *np = pic->irqhost->of_node; + const __be32 *map; + int i, maplen; + u32 val; + + map = of_get_property(np, "ti,c64x+megamod-pic-mux", &maplen); + if (map) { + maplen /= 4; + if (maplen > size) + maplen = size; + + for (i = 0; i < maplen; i++) { + val = be32_to_cpup(map); + if (val && val >= 4) + mapping[i] = val; + ++map; + } + } +} + +static struct megamod_pic * __init init_megamod_pic(struct device_node *np) +{ + struct megamod_pic *pic; + int i, irq; + int mapping[NR_MUX_OUTPUTS]; + + pr_info("Initializing C64x+ Megamodule PIC\n"); + + pic = kzalloc(sizeof(struct megamod_pic), GFP_KERNEL); + if (!pic) { + pr_err("%s: Could not alloc PIC structure.\n", np->full_name); + return NULL; + } + + pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, + NR_COMBINERS * 32, &megamod_host_ops, + IRQ_UNMAPPED); + if (!pic->irqhost) { + pr_err("%s: Could not alloc host.\n", np->full_name); + goto error_free; + } + + pic->irqhost->host_data = pic; + + raw_spin_lock_init(&pic->lock); + + pic->regs = of_iomap(np, 0); + if (!pic->regs) { + pr_err("%s: Could not map registers.\n", np->full_name); + goto error_free; + } + + /* Initialize MUX map */ + for (i = 0; i < ARRAY_SIZE(mapping); i++) + mapping[i] = IRQ_UNMAPPED; + + parse_priority_map(pic, mapping, ARRAY_SIZE(mapping)); + + /* + * We can have up to 12 interrupts cascading to the core controller. + * These cascades can be from the combined interrupt sources or for + * individual interrupt sources. The "interrupts" property only + * deals with the cascaded combined interrupts. The individual + * interrupts muxed to the core controller use the core controller + * as their interrupt parent. + */ + for (i = 0; i < NR_COMBINERS; i++) { + + irq = irq_of_parse_and_map(np, i); + if (irq == NO_IRQ) + continue; + + /* + * We count on the core priority interrupts (4 - 15) being + * direct mapped. Check that device tree provided something + * in that range. + */ + if (irq < 4 || irq >= NR_PRIORITY_IRQS) { + pr_err("%s: combiner-%d virq %d out of range!\n", + np->full_name, i, irq); + continue; + } + + /* record the mapping */ + mapping[irq - 4] = i; + + pr_debug("%s: combiner-%d cascading to virq %d\n", + np->full_name, i, irq); + + cascade_data[i].pic = pic; + cascade_data[i].index = i; + + /* mask and clear all events in combiner */ + soc_writel(~0, &pic->regs->evtmask[i]); + soc_writel(~0, &pic->regs->evtclr[i]); + + irq_set_handler_data(irq, &cascade_data[i]); + irq_set_chained_handler(irq, megamod_irq_cascade); + } + + /* Finally, set up the MUX registers */ + for (i = 0; i < NR_MUX_OUTPUTS; i++) { + if (mapping[i] != IRQ_UNMAPPED) { + pr_debug("%s: setting mux %d to priority %d\n", + np->full_name, mapping[i], i + 4); + set_megamod_mux(pic, mapping[i], i); + } + } + + return pic; + +error_free: + kfree(pic); + + return NULL; +} + +/* + * Return next active event after ACK'ing it. + * Return -1 if no events active. + */ +static int get_exception(void) +{ + int i, bit; + u32 mask; + + for (i = 0; i < NR_COMBINERS; i++) { + mask = soc_readl(&mm_pic->regs->mexpflag[i]); + if (mask) { + bit = __ffs(mask); + soc_writel(1 << bit, &mm_pic->regs->evtclr[i]); + return (i * 32) + bit; + } + } + return -1; +} + +static void assert_event(unsigned int val) +{ + soc_writel(val, &mm_pic->regs->evtasrt); +} + +void __init megamod_pic_init(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "ti,c64x+megamod-pic"); + if (!np) + return; + + mm_pic = init_megamod_pic(np); + of_node_put(np); + + soc_ops.get_exception = get_exception; + soc_ops.assert_event = assert_event; + + return; +} -- cgit v1.2.3 From 8a0c9e0348479f1b85c640da4795bdd775970bf3 Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 12:21:06 -0400 Subject: C6X: syscalls Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann [msalter@redhat.com: add include of linux/module.h to sys_c6x.c] Signed-off-by: Mark Salter --- arch/c6x/include/asm/syscalls.h | 55 ++++++++++++++++++++++++++++++ arch/c6x/include/asm/unistd.h | 26 +++++++++++++++ arch/c6x/kernel/sys_c6x.c | 74 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 arch/c6x/include/asm/syscalls.h create mode 100644 arch/c6x/include/asm/unistd.h create mode 100644 arch/c6x/kernel/sys_c6x.c (limited to 'arch') diff --git a/arch/c6x/include/asm/syscalls.h b/arch/c6x/include/asm/syscalls.h new file mode 100644 index 000000000000..aed53da703c9 --- /dev/null +++ b/arch/c6x/include/asm/syscalls.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#ifndef __ASM_C6X_SYSCALLS_H +#define __ASM_C6X_SYSCALLS_H + +#include +#include +#include + +/* The array of function pointers for syscalls. */ +extern void *sys_call_table[]; + +/* The following are trampolines in entry.S to handle 64-bit arguments */ +extern long sys_pread_c6x(unsigned int fd, char __user *buf, + size_t count, off_t pos_low, off_t pos_high); +extern long sys_pwrite_c6x(unsigned int fd, const char __user *buf, + size_t count, off_t pos_low, off_t pos_high); +extern long sys_truncate64_c6x(const char __user *path, + off_t length_low, off_t length_high); +extern long sys_ftruncate64_c6x(unsigned int fd, + off_t length_low, off_t length_high); +extern long sys_fadvise64_c6x(int fd, u32 offset_lo, u32 offset_hi, + u32 len, int advice); +extern long sys_fadvise64_64_c6x(int fd, u32 offset_lo, u32 offset_hi, + u32 len_lo, u32 len_hi, int advice); +extern long sys_fallocate_c6x(int fd, int mode, + u32 offset_lo, u32 offset_hi, + u32 len_lo, u32 len_hi); +extern int sys_cache_sync(unsigned long s, unsigned long e); + +struct pt_regs; + +extern asmlinkage long sys_c6x_clone(struct pt_regs *regs); +extern asmlinkage long sys_c6x_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp, + struct pt_regs *regs); + + +#include + +#endif /* __ASM_C6X_SYSCALLS_H */ diff --git a/arch/c6x/include/asm/unistd.h b/arch/c6x/include/asm/unistd.h new file mode 100644 index 000000000000..6d54ea4262eb --- /dev/null +++ b/arch/c6x/include/asm/unistd.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * + * Based on arch/tile version. + * + * 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, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ +#if !defined(_ASM_C6X_UNISTD_H) || defined(__SYSCALL) +#define _ASM_C6X_UNISTD_H + +/* Use the standard ABI for syscalls. */ +#include + +/* C6X-specific syscalls. */ +#define __NR_cache_sync (__NR_arch_specific_syscall + 0) +__SYSCALL(__NR_cache_sync, sys_cache_sync) + +#endif /* _ASM_C6X_UNISTD_H */ diff --git a/arch/c6x/kernel/sys_c6x.c b/arch/c6x/kernel/sys_c6x.c new file mode 100644 index 000000000000..3e9bdfbee8ad --- /dev/null +++ b/arch/c6x/kernel/sys_c6x.c @@ -0,0 +1,74 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 +#include +#include + +#include + +#ifdef CONFIG_ACCESS_CHECK +int _access_ok(unsigned long addr, unsigned long size) +{ + if (!size) + return 1; + + if (!addr || addr > (0xffffffffUL - (size - 1))) + goto _bad_access; + + if (segment_eq(get_fs(), KERNEL_DS)) + return 1; + + if (memory_start <= addr && (addr + size - 1) < memory_end) + return 1; + +_bad_access: + pr_debug("Bad access attempt: pid[%d] addr[%08lx] size[0x%lx]\n", + current->pid, addr, size); + return 0; +} +EXPORT_SYMBOL(_access_ok); +#endif + +/* sys_cache_sync -- sync caches over given range */ +asmlinkage int sys_cache_sync(unsigned long s, unsigned long e) +{ + L1D_cache_block_writeback_invalidate(s, e); + L1P_cache_block_invalidate(s, e); + + return 0; +} + +/* Provide the actual syscall number to call mapping. */ +#undef __SYSCALL +#define __SYSCALL(nr, call) [nr] = (call), + +/* + * Use trampolines + */ +#define sys_pread64 sys_pread_c6x +#define sys_pwrite64 sys_pwrite_c6x +#define sys_truncate64 sys_truncate64_c6x +#define sys_ftruncate64 sys_ftruncate64_c6x +#define sys_fadvise64 sys_fadvise64_c6x +#define sys_fadvise64_64 sys_fadvise64_64_c6x +#define sys_fallocate sys_fallocate_c6x + +/* Use sys_mmap_pgoff directly */ +#define sys_mmap2 sys_mmap_pgoff + +/* + * Note that we can't include here since the header + * guard will defeat us; checks for __SYSCALL as well. + */ +void *sys_call_table[__NR_syscalls] = { + [0 ... __NR_syscalls-1] = sys_ni_syscall, +#include +}; -- cgit v1.2.3 From e94e668251ab31b17ef6dcd16ba7fe05ffc1917a Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 11:10:02 -0400 Subject: C6X: build infrastructure Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann --- arch/c6x/include/asm/traps.h | 36 ++ arch/c6x/kernel/asm-offsets.c | 123 +++++++ arch/c6x/kernel/entry.S | 803 ++++++++++++++++++++++++++++++++++++++++++ arch/c6x/kernel/traps.c | 423 ++++++++++++++++++++++ 4 files changed, 1385 insertions(+) create mode 100644 arch/c6x/include/asm/traps.h create mode 100644 arch/c6x/kernel/asm-offsets.c create mode 100644 arch/c6x/kernel/entry.S create mode 100644 arch/c6x/kernel/traps.c (limited to 'arch') diff --git a/arch/c6x/include/asm/traps.h b/arch/c6x/include/asm/traps.h new file mode 100644 index 000000000000..62124d7b1b5f --- /dev/null +++ b/arch/c6x/include/asm/traps.h @@ -0,0 +1,36 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_TRAPS_H +#define _ASM_C6X_TRAPS_H + +#define EXCEPT_TYPE_NXF 31 /* NMI */ +#define EXCEPT_TYPE_EXC 30 /* external exception */ +#define EXCEPT_TYPE_IXF 1 /* internal exception */ +#define EXCEPT_TYPE_SXF 0 /* software exception */ + +#define EXCEPT_CAUSE_LBX (1 << 7) /* loop buffer exception */ +#define EXCEPT_CAUSE_PRX (1 << 6) /* privilege exception */ +#define EXCEPT_CAUSE_RAX (1 << 5) /* resource access exception */ +#define EXCEPT_CAUSE_RCX (1 << 4) /* resource conflict exception */ +#define EXCEPT_CAUSE_OPX (1 << 3) /* opcode exception */ +#define EXCEPT_CAUSE_EPX (1 << 2) /* execute packet exception */ +#define EXCEPT_CAUSE_FPX (1 << 1) /* fetch packet exception */ +#define EXCEPT_CAUSE_IFX (1 << 0) /* instruction fetch exception */ + +struct exception_info { + char *kernel_str; + int signo; + int code; +}; + +extern int (*c6x_nmi_handler)(struct pt_regs *regs); + +#endif /* _ASM_C6X_TRAPS_H */ diff --git a/arch/c6x/kernel/asm-offsets.c b/arch/c6x/kernel/asm-offsets.c new file mode 100644 index 000000000000..759ad6d207b6 --- /dev/null +++ b/arch/c6x/kernel/asm-offsets.c @@ -0,0 +1,123 @@ +/* + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed + * to extract and format the required data. + */ + +#include +#include +#include +#include +#include + +void foo(void) +{ + OFFSET(REGS_A16, pt_regs, a16); + OFFSET(REGS_A17, pt_regs, a17); + OFFSET(REGS_A18, pt_regs, a18); + OFFSET(REGS_A19, pt_regs, a19); + OFFSET(REGS_A20, pt_regs, a20); + OFFSET(REGS_A21, pt_regs, a21); + OFFSET(REGS_A22, pt_regs, a22); + OFFSET(REGS_A23, pt_regs, a23); + OFFSET(REGS_A24, pt_regs, a24); + OFFSET(REGS_A25, pt_regs, a25); + OFFSET(REGS_A26, pt_regs, a26); + OFFSET(REGS_A27, pt_regs, a27); + OFFSET(REGS_A28, pt_regs, a28); + OFFSET(REGS_A29, pt_regs, a29); + OFFSET(REGS_A30, pt_regs, a30); + OFFSET(REGS_A31, pt_regs, a31); + + OFFSET(REGS_B16, pt_regs, b16); + OFFSET(REGS_B17, pt_regs, b17); + OFFSET(REGS_B18, pt_regs, b18); + OFFSET(REGS_B19, pt_regs, b19); + OFFSET(REGS_B20, pt_regs, b20); + OFFSET(REGS_B21, pt_regs, b21); + OFFSET(REGS_B22, pt_regs, b22); + OFFSET(REGS_B23, pt_regs, b23); + OFFSET(REGS_B24, pt_regs, b24); + OFFSET(REGS_B25, pt_regs, b25); + OFFSET(REGS_B26, pt_regs, b26); + OFFSET(REGS_B27, pt_regs, b27); + OFFSET(REGS_B28, pt_regs, b28); + OFFSET(REGS_B29, pt_regs, b29); + OFFSET(REGS_B30, pt_regs, b30); + OFFSET(REGS_B31, pt_regs, b31); + + OFFSET(REGS_A0, pt_regs, a0); + OFFSET(REGS_A1, pt_regs, a1); + OFFSET(REGS_A2, pt_regs, a2); + OFFSET(REGS_A3, pt_regs, a3); + OFFSET(REGS_A4, pt_regs, a4); + OFFSET(REGS_A5, pt_regs, a5); + OFFSET(REGS_A6, pt_regs, a6); + OFFSET(REGS_A7, pt_regs, a7); + OFFSET(REGS_A8, pt_regs, a8); + OFFSET(REGS_A9, pt_regs, a9); + OFFSET(REGS_A10, pt_regs, a10); + OFFSET(REGS_A11, pt_regs, a11); + OFFSET(REGS_A12, pt_regs, a12); + OFFSET(REGS_A13, pt_regs, a13); + OFFSET(REGS_A14, pt_regs, a14); + OFFSET(REGS_A15, pt_regs, a15); + + OFFSET(REGS_B0, pt_regs, b0); + OFFSET(REGS_B1, pt_regs, b1); + OFFSET(REGS_B2, pt_regs, b2); + OFFSET(REGS_B3, pt_regs, b3); + OFFSET(REGS_B4, pt_regs, b4); + OFFSET(REGS_B5, pt_regs, b5); + OFFSET(REGS_B6, pt_regs, b6); + OFFSET(REGS_B7, pt_regs, b7); + OFFSET(REGS_B8, pt_regs, b8); + OFFSET(REGS_B9, pt_regs, b9); + OFFSET(REGS_B10, pt_regs, b10); + OFFSET(REGS_B11, pt_regs, b11); + OFFSET(REGS_B12, pt_regs, b12); + OFFSET(REGS_B13, pt_regs, b13); + OFFSET(REGS_DP, pt_regs, dp); + OFFSET(REGS_SP, pt_regs, sp); + + OFFSET(REGS_TSR, pt_regs, tsr); + OFFSET(REGS_ORIG_A4, pt_regs, orig_a4); + + DEFINE(REGS__END, sizeof(struct pt_regs)); + BLANK(); + + OFFSET(THREAD_PC, thread_struct, pc); + OFFSET(THREAD_B15_14, thread_struct, b15_14); + OFFSET(THREAD_A15_14, thread_struct, a15_14); + OFFSET(THREAD_B13_12, thread_struct, b13_12); + OFFSET(THREAD_A13_12, thread_struct, a13_12); + OFFSET(THREAD_B11_10, thread_struct, b11_10); + OFFSET(THREAD_A11_10, thread_struct, a11_10); + OFFSET(THREAD_RICL_ICL, thread_struct, ricl_icl); + BLANK(); + + OFFSET(TASK_STATE, task_struct, state); + BLANK(); + + OFFSET(THREAD_INFO_FLAGS, thread_info, flags); + OFFSET(THREAD_INFO_PREEMPT_COUNT, thread_info, preempt_count); + BLANK(); + + /* These would be unneccessary if we ran asm files + * through the preprocessor. + */ + DEFINE(KTHREAD_SIZE, THREAD_SIZE); + DEFINE(KTHREAD_SHIFT, THREAD_SHIFT); + DEFINE(KTHREAD_START_SP, THREAD_START_SP); + DEFINE(ENOSYS_, ENOSYS); + DEFINE(NR_SYSCALLS_, __NR_syscalls); + + DEFINE(_TIF_SYSCALL_TRACE, (1< +; +; 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 +#include +#include +#include +#include +#include + +; Registers naming +#define DP B14 +#define SP B15 + +#ifndef CONFIG_PREEMPT +#define resume_kernel restore_all +#endif + + .altmacro + + .macro MASK_INT reg + MVC .S2 CSR,reg + CLR .S2 reg,0,0,reg + MVC .S2 reg,CSR + .endm + + .macro UNMASK_INT reg + MVC .S2 CSR,reg + SET .S2 reg,0,0,reg + MVC .S2 reg,CSR + .endm + + .macro GET_THREAD_INFO reg + SHR .S1X SP,THREAD_SHIFT,reg + SHL .S1 reg,THREAD_SHIFT,reg + .endm + + ;; + ;; This defines the normal kernel pt_regs layout. + ;; + .macro SAVE_ALL __rp __tsr + STW .D2T2 B0,*SP--[2] ; save original B0 + MVKL .S2 current_ksp,B0 + MVKH .S2 current_ksp,B0 + LDW .D2T2 *B0,B1 ; KSP + + NOP 3 + STW .D2T2 B1,*+SP[1] ; save original B1 + XOR .D2 SP,B1,B0 ; (SP ^ KSP) + LDW .D2T2 *+SP[1],B1 ; restore B0/B1 + LDW .D2T2 *++SP[2],B0 + SHR .S2 B0,THREAD_SHIFT,B0 ; 0 if already using kstack + [B0] STDW .D2T2 SP:DP,*--B1[1] ; user: save user sp/dp kstack + [B0] MV .S2 B1,SP ; and switch to kstack +||[!B0] STDW .D2T2 SP:DP,*--SP[1] ; kernel: save on current stack + + SUBAW .D2 SP,2,SP + + ADD .D1X SP,-8,A15 + || STDW .D2T1 A15:A14,*SP--[16] ; save A15:A14 + + STDW .D2T2 B13:B12,*SP--[1] + || STDW .D1T1 A13:A12,*A15--[1] + || MVC .S2 __rp,B13 + + STDW .D2T2 B11:B10,*SP--[1] + || STDW .D1T1 A11:A10,*A15--[1] + || MVC .S2 CSR,B12 + + STDW .D2T2 B9:B8,*SP--[1] + || STDW .D1T1 A9:A8,*A15--[1] + || MVC .S2 RILC,B11 + STDW .D2T2 B7:B6,*SP--[1] + || STDW .D1T1 A7:A6,*A15--[1] + || MVC .S2 ILC,B10 + + STDW .D2T2 B5:B4,*SP--[1] + || STDW .D1T1 A5:A4,*A15--[1] + + STDW .D2T2 B3:B2,*SP--[1] + || STDW .D1T1 A3:A2,*A15--[1] + || MVC .S2 __tsr,B5 + + STDW .D2T2 B1:B0,*SP--[1] + || STDW .D1T1 A1:A0,*A15--[1] + || MV .S1X B5,A5 + + STDW .D2T2 B31:B30,*SP--[1] + || STDW .D1T1 A31:A30,*A15--[1] + STDW .D2T2 B29:B28,*SP--[1] + || STDW .D1T1 A29:A28,*A15--[1] + STDW .D2T2 B27:B26,*SP--[1] + || STDW .D1T1 A27:A26,*A15--[1] + STDW .D2T2 B25:B24,*SP--[1] + || STDW .D1T1 A25:A24,*A15--[1] + STDW .D2T2 B23:B22,*SP--[1] + || STDW .D1T1 A23:A22,*A15--[1] + STDW .D2T2 B21:B20,*SP--[1] + || STDW .D1T1 A21:A20,*A15--[1] + STDW .D2T2 B19:B18,*SP--[1] + || STDW .D1T1 A19:A18,*A15--[1] + STDW .D2T2 B17:B16,*SP--[1] + || STDW .D1T1 A17:A16,*A15--[1] + + STDW .D2T2 B13:B12,*SP--[1] ; save PC and CSR + + STDW .D2T2 B11:B10,*SP--[1] ; save RILC and ILC + STDW .D2T1 A5:A4,*SP--[1] ; save TSR and orig A4 + + ;; We left an unused word on the stack just above pt_regs. + ;; It is used to save whether or not this frame is due to + ;; a syscall. It is cleared here, but the syscall handler + ;; sets it to a non-zero value. + MVK .L2 0,B1 + STW .D2T2 B1,*+SP(REGS__END+8) ; clear syscall flag + .endm + + .macro RESTORE_ALL __rp __tsr + LDDW .D2T2 *++SP[1],B9:B8 ; get TSR (B9) + LDDW .D2T2 *++SP[1],B11:B10 ; get RILC (B11) and ILC (B10) + LDDW .D2T2 *++SP[1],B13:B12 ; get PC (B13) and CSR (B12) + + ADDAW .D1X SP,30,A15 + + LDDW .D1T1 *++A15[1],A17:A16 + || LDDW .D2T2 *++SP[1],B17:B16 + LDDW .D1T1 *++A15[1],A19:A18 + || LDDW .D2T2 *++SP[1],B19:B18 + LDDW .D1T1 *++A15[1],A21:A20 + || LDDW .D2T2 *++SP[1],B21:B20 + LDDW .D1T1 *++A15[1],A23:A22 + || LDDW .D2T2 *++SP[1],B23:B22 + LDDW .D1T1 *++A15[1],A25:A24 + || LDDW .D2T2 *++SP[1],B25:B24 + LDDW .D1T1 *++A15[1],A27:A26 + || LDDW .D2T2 *++SP[1],B27:B26 + LDDW .D1T1 *++A15[1],A29:A28 + || LDDW .D2T2 *++SP[1],B29:B28 + LDDW .D1T1 *++A15[1],A31:A30 + || LDDW .D2T2 *++SP[1],B31:B30 + + LDDW .D1T1 *++A15[1],A1:A0 + || LDDW .D2T2 *++SP[1],B1:B0 + + LDDW .D1T1 *++A15[1],A3:A2 + || LDDW .D2T2 *++SP[1],B3:B2 + || MVC .S2 B9,__tsr + LDDW .D1T1 *++A15[1],A5:A4 + || LDDW .D2T2 *++SP[1],B5:B4 + || MVC .S2 B11,RILC + LDDW .D1T1 *++A15[1],A7:A6 + || LDDW .D2T2 *++SP[1],B7:B6 + || MVC .S2 B10,ILC + + LDDW .D1T1 *++A15[1],A9:A8 + || LDDW .D2T2 *++SP[1],B9:B8 + || MVC .S2 B13,__rp + + LDDW .D1T1 *++A15[1],A11:A10 + || LDDW .D2T2 *++SP[1],B11:B10 + || MVC .S2 B12,CSR + + LDDW .D1T1 *++A15[1],A13:A12 + || LDDW .D2T2 *++SP[1],B13:B12 + + MV .D2X A15,SP + || MVKL .S1 current_ksp,A15 + MVKH .S1 current_ksp,A15 + || ADDAW .D1X SP,6,A14 + STW .D1T1 A14,*A15 ; save kernel stack pointer + + LDDW .D2T1 *++SP[1],A15:A14 + + B .S2 __rp ; return from interruption + LDDW .D2T2 *+SP[1],SP:DP + NOP 4 + .endm + + .section .text + + ;; + ;; Jump to schedule() then return to ret_from_exception + ;; +_reschedule: +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 schedule,A0 + MVKH .S1 schedule,A0 + B .S2X A0 +#else + B .S1 schedule +#endif + ADDKPC .S2 ret_from_exception,B3,4 + + ;; + ;; Called before syscall handler when process is being debugged + ;; +tracesys_on: +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 syscall_trace_entry,A0 + MVKH .S1 syscall_trace_entry,A0 + B .S2X A0 +#else + B .S1 syscall_trace_entry +#endif + ADDKPC .S2 ret_from_syscall_trace,B3,3 + ADD .S1X 8,SP,A4 + +ret_from_syscall_trace: + ;; tracing returns (possibly new) syscall number + MV .D2X A4,B0 + || MVK .S2 __NR_syscalls,B1 + CMPLTU .L2 B0,B1,B1 + + [!B1] BNOP .S2 ret_from_syscall_function,5 + || MVK .S1 -ENOSYS,A4 + + ;; reload syscall args from (possibly modified) stack frame + ;; and get syscall handler addr from sys_call_table: + LDW .D2T2 *+SP(REGS_B4+8),B4 + || MVKL .S2 sys_call_table,B1 + LDW .D2T1 *+SP(REGS_A6+8),A6 + || MVKH .S2 sys_call_table,B1 + LDW .D2T2 *+B1[B0],B0 + || MVKL .S2 ret_from_syscall_function,B3 + LDW .D2T2 *+SP(REGS_B6+8),B6 + || MVKH .S2 ret_from_syscall_function,B3 + LDW .D2T1 *+SP(REGS_A8+8),A8 + LDW .D2T2 *+SP(REGS_B8+8),B8 + NOP + ; B0 = sys_call_table[__NR_*] + BNOP .S2 B0,5 ; branch to syscall handler + || LDW .D2T1 *+SP(REGS_ORIG_A4+8),A4 + +syscall_exit_work: + AND .D1 _TIF_SYSCALL_TRACE,A2,A0 + [!A0] BNOP .S1 work_pending,5 + [A0] B .S2 syscall_trace_exit + ADDKPC .S2 resume_userspace,B3,1 + MVC .S2 CSR,B1 + SET .S2 B1,0,0,B1 + MVC .S2 B1,CSR ; enable ints + +work_pending: + AND .D1 _TIF_NEED_RESCHED,A2,A0 + [!A0] BNOP .S1 work_notifysig,5 + +work_resched: +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 schedule,A1 + MVKH .S1 schedule,A1 + B .S2X A1 +#else + B .S2 schedule +#endif + ADDKPC .S2 work_rescheduled,B3,4 +work_rescheduled: + ;; make sure we don't miss an interrupt setting need_resched or + ;; sigpending between sampling and the rti + MASK_INT B2 + GET_THREAD_INFO A12 + LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2 + MVK .S1 _TIF_WORK_MASK,A1 + MVK .S1 _TIF_NEED_RESCHED,A3 + NOP 2 + AND .D1 A1,A2,A0 + || AND .S1 A3,A2,A1 + [!A0] BNOP .S1 restore_all,5 + [A1] BNOP .S1 work_resched,5 + +work_notifysig: + B .S2 do_notify_resume + LDW .D2T1 *+SP(REGS__END+8),A6 ; syscall flag + ADDKPC .S2 resume_userspace,B3,1 + ADD .S1X 8,SP,A4 ; pt_regs pointer is first arg + MV .D2X A2,B4 ; thread_info flags is second arg + + ;; + ;; On C64x+, the return way from exception and interrupt + ;; is a little bit different + ;; +ENTRY(ret_from_exception) +#ifdef CONFIG_PREEMPT + MASK_INT B2 +#endif + +ENTRY(ret_from_interrupt) + ;; + ;; Check if we are comming from user mode. + ;; + LDW .D2T2 *+SP(REGS_TSR+8),B0 + MVK .S2 0x40,B1 + NOP 3 + AND .D2 B0,B1,B0 + [!B0] BNOP .S2 resume_kernel,5 + +resume_userspace: + ;; make sure we don't miss an interrupt setting need_resched or + ;; sigpending between sampling and the rti + MASK_INT B2 + GET_THREAD_INFO A12 + LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2 + MVK .S1 _TIF_WORK_MASK,A1 + MVK .S1 _TIF_NEED_RESCHED,A3 + NOP 2 + AND .D1 A1,A2,A0 + [A0] BNOP .S1 work_pending,5 + BNOP .S1 restore_all,5 + + ;; + ;; System call handling + ;; B0 = syscall number (in sys_call_table) + ;; A4,B4,A6,B6,A8,B8 = arguments of the syscall function + ;; A4 is the return value register + ;; +system_call_saved: + MVK .L2 1,B2 + STW .D2T2 B2,*+SP(REGS__END+8) ; set syscall flag + MVC .S2 B2,ECR ; ack the software exception + + UNMASK_INT B2 ; re-enable global IT + +system_call_saved_noack: + ;; Check system call number + MVK .S2 __NR_syscalls,B1 +#ifdef CONFIG_C6X_BIG_KERNEL + || MVKL .S1 sys_ni_syscall,A0 +#endif + CMPLTU .L2 B0,B1,B1 +#ifdef CONFIG_C6X_BIG_KERNEL + || MVKH .S1 sys_ni_syscall,A0 +#endif + + ;; Check for ptrace + GET_THREAD_INFO A12 + +#ifdef CONFIG_C6X_BIG_KERNEL + [!B1] B .S2X A0 +#else + [!B1] B .S2 sys_ni_syscall +#endif + [!B1] ADDKPC .S2 ret_from_syscall_function,B3,4 + + ;; Get syscall handler addr from sys_call_table + ;; call tracesys_on or call syscall handler + LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2 + || MVKL .S2 sys_call_table,B1 + MVKH .S2 sys_call_table,B1 + LDW .D2T2 *+B1[B0],B0 + NOP 2 + ; A2 = thread_info flags + AND .D1 _TIF_SYSCALL_TRACE,A2,A2 + [A2] BNOP .S1 tracesys_on,5 + ;; B0 = _sys_call_table[__NR_*] + B .S2 B0 + ADDKPC .S2 ret_from_syscall_function,B3,4 + +ret_from_syscall_function: + STW .D2T1 A4,*+SP(REGS_A4+8) ; save return value in A4 + ; original A4 is in orig_A4 +syscall_exit: + ;; make sure we don't miss an interrupt setting need_resched or + ;; sigpending between sampling and the rti + MASK_INT B2 + LDW .D1T1 *+A12(THREAD_INFO_FLAGS),A2 + MVK .S1 _TIF_ALLWORK_MASK,A1 + NOP 3 + AND .D1 A1,A2,A2 ; check for work to do + [A2] BNOP .S1 syscall_exit_work,5 + +restore_all: + RESTORE_ALL NRP,NTSR + + ;; + ;; After a fork we jump here directly from resume, + ;; so that A4 contains the previous task structure. + ;; +ENTRY(ret_from_fork) +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 schedule_tail,A0 + MVKH .S1 schedule_tail,A0 + B .S2X A0 +#else + B .S2 schedule_tail +#endif + ADDKPC .S2 ret_from_fork_2,B3,4 +ret_from_fork_2: + ;; return 0 in A4 for child process + GET_THREAD_INFO A12 + BNOP .S2 syscall_exit,3 + MVK .L2 0,B0 + STW .D2T2 B0,*+SP(REGS_A4+8) +ENDPROC(ret_from_fork) + + ;; + ;; These are the interrupt handlers, responsible for calling __do_IRQ() + ;; int6 is used for syscalls (see _system_call entry) + ;; + .macro SAVE_ALL_INT + SAVE_ALL IRP,ITSR + .endm + + .macro CALL_INT int +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 c6x_do_IRQ,A0 + MVKH .S1 c6x_do_IRQ,A0 + BNOP .S2X A0,1 + MVK .S1 int,A4 + ADDAW .D2 SP,2,B4 + MVKL .S2 ret_from_interrupt,B3 + MVKH .S2 ret_from_interrupt,B3 +#else + CALLP .S2 c6x_do_IRQ,B3 + || MVK .S1 int,A4 + || ADDAW .D2 SP,2,B4 + B .S1 ret_from_interrupt + NOP 5 +#endif + .endm + +ENTRY(_int4_handler) + SAVE_ALL_INT + CALL_INT 4 +ENDPROC(_int4_handler) + +ENTRY(_int5_handler) + SAVE_ALL_INT + CALL_INT 5 +ENDPROC(_int5_handler) + +ENTRY(_int6_handler) + SAVE_ALL_INT + CALL_INT 6 +ENDPROC(_int6_handler) + +ENTRY(_int7_handler) + SAVE_ALL_INT + CALL_INT 7 +ENDPROC(_int7_handler) + +ENTRY(_int8_handler) + SAVE_ALL_INT + CALL_INT 8 +ENDPROC(_int8_handler) + +ENTRY(_int9_handler) + SAVE_ALL_INT + CALL_INT 9 +ENDPROC(_int9_handler) + +ENTRY(_int10_handler) + SAVE_ALL_INT + CALL_INT 10 +ENDPROC(_int10_handler) + +ENTRY(_int11_handler) + SAVE_ALL_INT + CALL_INT 11 +ENDPROC(_int11_handler) + +ENTRY(_int12_handler) + SAVE_ALL_INT + CALL_INT 12 +ENDPROC(_int12_handler) + +ENTRY(_int13_handler) + SAVE_ALL_INT + CALL_INT 13 +ENDPROC(_int13_handler) + +ENTRY(_int14_handler) + SAVE_ALL_INT + CALL_INT 14 +ENDPROC(_int14_handler) + +ENTRY(_int15_handler) + SAVE_ALL_INT + CALL_INT 15 +ENDPROC(_int15_handler) + + ;; + ;; Handler for uninitialized and spurious interrupts + ;; +ENTRY(_bad_interrupt) + B .S2 IRP + NOP 5 +ENDPROC(_bad_interrupt) + + ;; + ;; Entry for NMI/exceptions/syscall + ;; +ENTRY(_nmi_handler) + SAVE_ALL NRP,NTSR + + MVC .S2 EFR,B2 + CMPEQ .L2 1,B2,B2 + || MVC .S2 TSR,B1 + CLR .S2 B1,10,10,B1 + MVC .S2 B1,TSR +#ifdef CONFIG_C6X_BIG_KERNEL + [!B2] MVKL .S1 process_exception,A0 + [!B2] MVKH .S1 process_exception,A0 + [!B2] B .S2X A0 +#else + [!B2] B .S2 process_exception +#endif + [B2] B .S2 system_call_saved + [!B2] ADDAW .D2 SP,2,B1 + [!B2] MV .D1X B1,A4 + ADDKPC .S2 ret_from_trap,B3,2 + +ret_from_trap: + MV .D2X A4,B0 + [!B0] BNOP .S2 ret_from_exception,5 + +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S2 system_call_saved_noack,B3 + MVKH .S2 system_call_saved_noack,B3 +#endif + LDW .D2T2 *+SP(REGS_B0+8),B0 + LDW .D2T1 *+SP(REGS_A4+8),A4 + LDW .D2T2 *+SP(REGS_B4+8),B4 + LDW .D2T1 *+SP(REGS_A6+8),A6 + LDW .D2T2 *+SP(REGS_B6+8),B6 + LDW .D2T1 *+SP(REGS_A8+8),A8 +#ifdef CONFIG_C6X_BIG_KERNEL + || B .S2 B3 +#else + || B .S2 system_call_saved_noack +#endif + LDW .D2T2 *+SP(REGS_B8+8),B8 + NOP 4 +ENDPROC(_nmi_handler) + + ;; + ;; Jump to schedule() then return to ret_from_isr + ;; +#ifdef CONFIG_PREEMPT +resume_kernel: + GET_THREAD_INFO A12 + LDW .D1T1 *+A12(THREAD_INFO_PREEMPT_COUNT),A1 + NOP 4 + [A1] BNOP .S2 restore_all,5 + +preempt_schedule: + GET_THREAD_INFO A2 + LDW .D1T1 *+A2(THREAD_INFO_FLAGS),A1 +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S2 preempt_schedule_irq,B0 + MVKH .S2 preempt_schedule_irq,B0 + NOP 2 +#else + NOP 4 +#endif + AND .D1 _TIF_NEED_RESCHED,A1,A1 + [!A1] BNOP .S2 restore_all,5 +#ifdef CONFIG_C6X_BIG_KERNEL + B .S2 B0 +#else + B .S2 preempt_schedule_irq +#endif + ADDKPC .S2 preempt_schedule,B3,4 +#endif /* CONFIG_PREEMPT */ + +ENTRY(enable_exception) + DINT + MVC .S2 TSR,B0 + MVC .S2 B3,NRP + MVK .L2 0xc,B1 + OR .D2 B0,B1,B0 + MVC .S2 B0,TSR ; Set GEE and XEN in TSR + B .S2 NRP + NOP 5 +ENDPROC(enable_exception) + +ENTRY(sys_sigaltstack) +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 do_sigaltstack,A0 ; branch to do_sigaltstack + MVKH .S1 do_sigaltstack,A0 + B .S2X A0 +#else + B .S2 do_sigaltstack +#endif + LDW .D2T1 *+SP(REGS_SP+8),A6 + NOP 4 +ENDPROC(sys_sigaltstack) + + ;; kernel_execve +ENTRY(kernel_execve) + MVK .S2 __NR_execve,B0 + SWE + BNOP .S2 B3,5 +ENDPROC(kernel_execve) + + ;; + ;; Special system calls + ;; return address is in B3 + ;; +ENTRY(sys_clone) + ADD .D1X SP,8,A4 +#ifdef CONFIG_C6X_BIG_KERNEL + || MVKL .S1 sys_c6x_clone,A0 + MVKH .S1 sys_c6x_clone,A0 + BNOP .S2X A0,5 +#else + || B .S2 sys_c6x_clone + NOP 5 +#endif +ENDPROC(sys_clone) + +ENTRY(sys_rt_sigreturn) + ADD .D1X SP,8,A4 +#ifdef CONFIG_C6X_BIG_KERNEL + || MVKL .S1 do_rt_sigreturn,A0 + MVKH .S1 do_rt_sigreturn,A0 + BNOP .S2X A0,5 +#else + || B .S2 do_rt_sigreturn + NOP 5 +#endif +ENDPROC(sys_rt_sigreturn) + +ENTRY(sys_execve) + ADDAW .D2 SP,2,B6 ; put regs addr in 4th parameter + ; & adjust regs stack addr + LDW .D2T2 *+SP(REGS_B4+8),B4 + + ;; c6x_execve(char *name, char **argv, + ;; char **envp, struct pt_regs *regs) +#ifdef CONFIG_C6X_BIG_KERNEL + || MVKL .S1 sys_c6x_execve,A0 + MVKH .S1 sys_c6x_execve,A0 + B .S2X A0 +#else + || B .S2 sys_c6x_execve +#endif + STW .D2T2 B3,*SP--[2] + ADDKPC .S2 ret_from_c6x_execve,B3,3 + +ret_from_c6x_execve: + LDW .D2T2 *++SP[2],B3 + NOP 4 + BNOP .S2 B3,5 +ENDPROC(sys_execve) + +ENTRY(sys_pread_c6x) + MV .D2X A8,B7 +#ifdef CONFIG_C6X_BIG_KERNEL + || MVKL .S1 sys_pread64,A0 + MVKH .S1 sys_pread64,A0 + BNOP .S2X A0,5 +#else + || B .S2 sys_pread64 + NOP 5 +#endif +ENDPROC(sys_pread_c6x) + +ENTRY(sys_pwrite_c6x) + MV .D2X A8,B7 +#ifdef CONFIG_C6X_BIG_KERNEL + || MVKL .S1 sys_pwrite64,A0 + MVKH .S1 sys_pwrite64,A0 + BNOP .S2X A0,5 +#else + || B .S2 sys_pwrite64 + NOP 5 +#endif +ENDPROC(sys_pwrite_c6x) + +;; On Entry +;; A4 - path +;; B4 - offset_lo (LE), offset_hi (BE) +;; A6 - offset_lo (BE), offset_hi (LE) +ENTRY(sys_truncate64_c6x) +#ifdef CONFIG_CPU_BIG_ENDIAN + MV .S2 B4,B5 + MV .D2X A6,B4 +#else + MV .D2X A6,B5 +#endif +#ifdef CONFIG_C6X_BIG_KERNEL + || MVKL .S1 sys_truncate64,A0 + MVKH .S1 sys_truncate64,A0 + BNOP .S2X A0,5 +#else + || B .S2 sys_truncate64 + NOP 5 +#endif +ENDPROC(sys_truncate64_c6x) + +;; On Entry +;; A4 - fd +;; B4 - offset_lo (LE), offset_hi (BE) +;; A6 - offset_lo (BE), offset_hi (LE) +ENTRY(sys_ftruncate64_c6x) +#ifdef CONFIG_CPU_BIG_ENDIAN + MV .S2 B4,B5 + MV .D2X A6,B4 +#else + MV .D2X A6,B5 +#endif +#ifdef CONFIG_C6X_BIG_KERNEL + || MVKL .S1 sys_ftruncate64,A0 + MVKH .S1 sys_ftruncate64,A0 + BNOP .S2X A0,5 +#else + || B .S2 sys_ftruncate64 + NOP 5 +#endif +ENDPROC(sys_ftruncate64_c6x) + +#ifdef __ARCH_WANT_SYSCALL_OFF_T +;; On Entry +;; A4 - fd +;; B4 - offset_lo (LE), offset_hi (BE) +;; A6 - offset_lo (BE), offset_hi (LE) +;; B6 - len +;; A8 - advice +ENTRY(sys_fadvise64_c6x) +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 sys_fadvise64,A0 + MVKH .S1 sys_fadvise64,A0 + BNOP .S2X A0,2 +#else + B .S2 sys_fadvise64 + NOP 2 +#endif +#ifdef CONFIG_CPU_BIG_ENDIAN + MV .L2 B4,B5 + || MV .D2X A6,B4 +#else + MV .D2X A6,B5 +#endif + MV .D1X B6,A6 + MV .D2X A8,B6 +#endif +ENDPROC(sys_fadvise64_c6x) + +;; On Entry +;; A4 - fd +;; B4 - offset_lo (LE), offset_hi (BE) +;; A6 - offset_lo (BE), offset_hi (LE) +;; B6 - len_lo (LE), len_hi (BE) +;; A8 - len_lo (BE), len_hi (LE) +;; B8 - advice +ENTRY(sys_fadvise64_64_c6x) +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 sys_fadvise64_64,A0 + MVKH .S1 sys_fadvise64_64,A0 + BNOP .S2X A0,2 +#else + B .S2 sys_fadvise64_64 + NOP 2 +#endif +#ifdef CONFIG_CPU_BIG_ENDIAN + MV .L2 B4,B5 + || MV .D2X A6,B4 + MV .L1 A8,A6 + || MV .D1X B6,A7 +#else + MV .D2X A6,B5 + MV .L1 A8,A7 + || MV .D1X B6,A6 +#endif + MV .L2 B8,B6 +ENDPROC(sys_fadvise64_64_c6x) + +;; On Entry +;; A4 - fd +;; B4 - mode +;; A6 - offset_hi +;; B6 - offset_lo +;; A8 - len_hi +;; B8 - len_lo +ENTRY(sys_fallocate_c6x) +#ifdef CONFIG_C6X_BIG_KERNEL + MVKL .S1 sys_fallocate,A0 + MVKH .S1 sys_fallocate,A0 + BNOP .S2X A0,1 +#else + B .S2 sys_fallocate + NOP +#endif + MV .D1 A6,A7 + MV .D1X B6,A6 + MV .D2X A8,B7 + MV .D2 B8,B6 +ENDPROC(sys_fallocate_c6x) + + ;; put this in .neardata for faster access when using DSBT mode + .section .neardata,"aw",@progbits + .global current_ksp + .hidden current_ksp +current_ksp: + .word init_thread_union + THREAD_START_SP diff --git a/arch/c6x/kernel/traps.c b/arch/c6x/kernel/traps.c new file mode 100644 index 000000000000..f50e3edd6dad --- /dev/null +++ b/arch/c6x/kernel/traps.c @@ -0,0 +1,423 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 +#include +#include +#include + +#include +#include + +int (*c6x_nmi_handler)(struct pt_regs *regs); + +void __init trap_init(void) +{ + ack_exception(EXCEPT_TYPE_NXF); + ack_exception(EXCEPT_TYPE_EXC); + ack_exception(EXCEPT_TYPE_IXF); + ack_exception(EXCEPT_TYPE_SXF); + enable_exception(); +} + +void show_regs(struct pt_regs *regs) +{ + pr_err("\n"); + pr_err("PC: %08lx SP: %08lx\n", regs->pc, regs->sp); + pr_err("Status: %08lx ORIG_A4: %08lx\n", regs->csr, regs->orig_a4); + pr_err("A0: %08lx B0: %08lx\n", regs->a0, regs->b0); + pr_err("A1: %08lx B1: %08lx\n", regs->a1, regs->b1); + pr_err("A2: %08lx B2: %08lx\n", regs->a2, regs->b2); + pr_err("A3: %08lx B3: %08lx\n", regs->a3, regs->b3); + pr_err("A4: %08lx B4: %08lx\n", regs->a4, regs->b4); + pr_err("A5: %08lx B5: %08lx\n", regs->a5, regs->b5); + pr_err("A6: %08lx B6: %08lx\n", regs->a6, regs->b6); + pr_err("A7: %08lx B7: %08lx\n", regs->a7, regs->b7); + pr_err("A8: %08lx B8: %08lx\n", regs->a8, regs->b8); + pr_err("A9: %08lx B9: %08lx\n", regs->a9, regs->b9); + pr_err("A10: %08lx B10: %08lx\n", regs->a10, regs->b10); + pr_err("A11: %08lx B11: %08lx\n", regs->a11, regs->b11); + pr_err("A12: %08lx B12: %08lx\n", regs->a12, regs->b12); + pr_err("A13: %08lx B13: %08lx\n", regs->a13, regs->b13); + pr_err("A14: %08lx B14: %08lx\n", regs->a14, regs->dp); + pr_err("A15: %08lx B15: %08lx\n", regs->a15, regs->sp); + pr_err("A16: %08lx B16: %08lx\n", regs->a16, regs->b16); + pr_err("A17: %08lx B17: %08lx\n", regs->a17, regs->b17); + pr_err("A18: %08lx B18: %08lx\n", regs->a18, regs->b18); + pr_err("A19: %08lx B19: %08lx\n", regs->a19, regs->b19); + pr_err("A20: %08lx B20: %08lx\n", regs->a20, regs->b20); + pr_err("A21: %08lx B21: %08lx\n", regs->a21, regs->b21); + pr_err("A22: %08lx B22: %08lx\n", regs->a22, regs->b22); + pr_err("A23: %08lx B23: %08lx\n", regs->a23, regs->b23); + pr_err("A24: %08lx B24: %08lx\n", regs->a24, regs->b24); + pr_err("A25: %08lx B25: %08lx\n", regs->a25, regs->b25); + pr_err("A26: %08lx B26: %08lx\n", regs->a26, regs->b26); + pr_err("A27: %08lx B27: %08lx\n", regs->a27, regs->b27); + pr_err("A28: %08lx B28: %08lx\n", regs->a28, regs->b28); + pr_err("A29: %08lx B29: %08lx\n", regs->a29, regs->b29); + pr_err("A30: %08lx B30: %08lx\n", regs->a30, regs->b30); + pr_err("A31: %08lx B31: %08lx\n", regs->a31, regs->b31); +} + +void dump_stack(void) +{ + unsigned long stack; + + show_stack(current, &stack); +} +EXPORT_SYMBOL(dump_stack); + + +void die(char *str, struct pt_regs *fp, int nr) +{ + console_verbose(); + pr_err("%s: %08x\n", str, nr); + show_regs(fp); + + pr_err("Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, (PAGE_SIZE + + (unsigned long) current)); + + dump_stack(); + while (1) + ; +} + +static void die_if_kernel(char *str, struct pt_regs *fp, int nr) +{ + if (user_mode(fp)) + return; + + die(str, fp, nr); +} + + +/* Internal exceptions */ +static struct exception_info iexcept_table[10] = { + { "Oops - instruction fetch", SIGBUS, BUS_ADRERR }, + { "Oops - fetch packet", SIGBUS, BUS_ADRERR }, + { "Oops - execute packet", SIGILL, ILL_ILLOPC }, + { "Oops - undefined instruction", SIGILL, ILL_ILLOPC }, + { "Oops - resource conflict", SIGILL, ILL_ILLOPC }, + { "Oops - resource access", SIGILL, ILL_PRVREG }, + { "Oops - privilege", SIGILL, ILL_PRVOPC }, + { "Oops - loops buffer", SIGILL, ILL_ILLOPC }, + { "Oops - software exception", SIGILL, ILL_ILLTRP }, + { "Oops - unknown exception", SIGILL, ILL_ILLOPC } +}; + +/* External exceptions */ +static struct exception_info eexcept_table[128] = { + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - external exception", SIGBUS, BUS_ADRERR }, + { "Oops - CPU memory protection fault", SIGSEGV, SEGV_ACCERR }, + { "Oops - CPU memory protection fault in L1P", SIGSEGV, SEGV_ACCERR }, + { "Oops - DMA memory protection fault in L1P", SIGSEGV, SEGV_ACCERR }, + { "Oops - CPU memory protection fault in L1D", SIGSEGV, SEGV_ACCERR }, + { "Oops - DMA memory protection fault in L1D", SIGSEGV, SEGV_ACCERR }, + { "Oops - CPU memory protection fault in L2", SIGSEGV, SEGV_ACCERR }, + { "Oops - DMA memory protection fault in L2", SIGSEGV, SEGV_ACCERR }, + { "Oops - EMC CPU memory protection fault", SIGSEGV, SEGV_ACCERR }, + { "Oops - EMC bus error", SIGBUS, BUS_ADRERR } +}; + +static void do_trap(struct exception_info *except_info, struct pt_regs *regs) +{ + unsigned long addr = instruction_pointer(regs); + siginfo_t info; + + if (except_info->code != TRAP_BRKPT) + pr_err("TRAP: %s PC[0x%lx] signo[%d] code[%d]\n", + except_info->kernel_str, regs->pc, + except_info->signo, except_info->code); + + die_if_kernel(except_info->kernel_str, regs, addr); + + info.si_signo = except_info->signo; + info.si_errno = 0; + info.si_code = except_info->code; + info.si_addr = (void __user *)addr; + + force_sig_info(except_info->signo, &info, current); +} + +/* + * Process an internal exception (non maskable) + */ +static int process_iexcept(struct pt_regs *regs) +{ + unsigned int iexcept_report = get_iexcept(); + unsigned int iexcept_num; + + ack_exception(EXCEPT_TYPE_IXF); + + pr_err("IEXCEPT: PC[0x%lx]\n", regs->pc); + + while (iexcept_report) { + iexcept_num = __ffs(iexcept_report); + iexcept_report &= ~(1 << iexcept_num); + set_iexcept(iexcept_report); + if (*(unsigned int *)regs->pc == BKPT_OPCODE) { + /* This is a breakpoint */ + struct exception_info bkpt_exception = { + "Oops - undefined instruction", + SIGTRAP, TRAP_BRKPT + }; + do_trap(&bkpt_exception, regs); + iexcept_report &= ~(0xFF); + set_iexcept(iexcept_report); + continue; + } + + do_trap(&iexcept_table[iexcept_num], regs); + } + return 0; +} + +/* + * Process an external exception (maskable) + */ +static void process_eexcept(struct pt_regs *regs) +{ + int evt; + + pr_err("EEXCEPT: PC[0x%lx]\n", regs->pc); + + while ((evt = soc_get_exception()) >= 0) + do_trap(&eexcept_table[evt], regs); + + ack_exception(EXCEPT_TYPE_EXC); +} + +/* + * Main exception processing + */ +asmlinkage int process_exception(struct pt_regs *regs) +{ + unsigned int type; + unsigned int type_num; + unsigned int ie_num = 9; /* default is unknown exception */ + + while ((type = get_except_type()) != 0) { + type_num = fls(type) - 1; + + switch (type_num) { + case EXCEPT_TYPE_NXF: + ack_exception(EXCEPT_TYPE_NXF); + if (c6x_nmi_handler) + (c6x_nmi_handler)(regs); + else + pr_alert("NMI interrupt!\n"); + break; + + case EXCEPT_TYPE_IXF: + if (process_iexcept(regs)) + return 1; + break; + + case EXCEPT_TYPE_EXC: + process_eexcept(regs); + break; + + case EXCEPT_TYPE_SXF: + ie_num = 8; + default: + ack_exception(type_num); + do_trap(&iexcept_table[ie_num], regs); + break; + } + } + return 0; +} + +static int kstack_depth_to_print = 48; + +static void show_trace(unsigned long *stack, unsigned long *endstack) +{ + unsigned long addr; + int i; + + pr_debug("Call trace:"); + i = 0; + while (stack + 1 <= endstack) { + addr = *stack++; + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (__kernel_text_address(addr)) { +#ifndef CONFIG_KALLSYMS + if (i % 5 == 0) + pr_debug("\n "); +#endif + pr_debug(" [<%08lx>]", addr); + print_symbol(" %s\n", addr); + i++; + } + } + pr_debug("\n"); +} + +void show_stack(struct task_struct *task, unsigned long *stack) +{ + unsigned long *p, *endstack; + int i; + + if (!stack) { + if (task && task != current) + /* We know this is a kernel stack, + so this is the start/end */ + stack = (unsigned long *)thread_saved_ksp(task); + else + stack = (unsigned long *)&stack; + } + endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) + & -THREAD_SIZE); + + pr_debug("Stack from %08lx:", (unsigned long)stack); + for (i = 0, p = stack; i < kstack_depth_to_print; i++) { + if (p + 1 > endstack) + break; + if (i % 8 == 0) + pr_cont("\n "); + pr_cont(" %08lx", *p++); + } + pr_cont("\n"); + show_trace(stack, endstack); +} + +int is_valid_bugaddr(unsigned long addr) +{ + return __kernel_text_address(addr); +} -- cgit v1.2.3 From 81ec98898188639ac53413605681b3e3bb0a2ff1 Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 4 Oct 2011 11:10:50 -0400 Subject: C6X: clocks The C6X SoCs contain several PLL controllers each with up to 16 clock outputs feeding into the cores or peripheral clock domains. The hardware is very similar to arm/mach-davinci clocks. This is still a work in progress which needs to be updated once device tree clock binding changes shake out. Signed-off-by: Mark Salter Signed-off-by: Aurelien Jacquiot Acked-by: Arnd Bergmann --- arch/c6x/include/asm/clkdev.h | 22 +++ arch/c6x/include/asm/clock.h | 148 ++++++++++++++ arch/c6x/platforms/pll.c | 444 ++++++++++++++++++++++++++++++++++++++++++ arch/c6x/platforms/plldata.c | 404 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 1018 insertions(+) create mode 100644 arch/c6x/include/asm/clkdev.h create mode 100644 arch/c6x/include/asm/clock.h create mode 100644 arch/c6x/platforms/pll.c create mode 100644 arch/c6x/platforms/plldata.c (limited to 'arch') diff --git a/arch/c6x/include/asm/clkdev.h b/arch/c6x/include/asm/clkdev.h new file mode 100644 index 000000000000..76a070b1c2e5 --- /dev/null +++ b/arch/c6x/include/asm/clkdev.h @@ -0,0 +1,22 @@ +#ifndef _ASM_CLKDEV_H +#define _ASM_CLKDEV_H + +#include + +struct clk; + +static inline int __clk_get(struct clk *clk) +{ + return 1; +} + +static inline void __clk_put(struct clk *clk) +{ +} + +static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) +{ + return kzalloc(size, GFP_KERNEL); +} + +#endif /* _ASM_CLKDEV_H */ diff --git a/arch/c6x/include/asm/clock.h b/arch/c6x/include/asm/clock.h new file mode 100644 index 000000000000..bcf42b2b4b1e --- /dev/null +++ b/arch/c6x/include/asm/clock.h @@ -0,0 +1,148 @@ +/* + * TI C64X clock definitions + * + * Copyright (C) 2010, 2011 Texas Instruments. + * Contributed by: Mark Salter + * + * Copied heavily from arm/mach-davinci/clock.h, so: + * + * Copyright (C) 2006-2007 Texas Instruments. + * Copyright (C) 2008-2009 Deep Root Systems, LLC + * + * 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_C6X_CLOCK_H +#define _ASM_C6X_CLOCK_H + +#ifndef __ASSEMBLER__ + +#include + +/* PLL/Reset register offsets */ +#define PLLCTL 0x100 +#define PLLM 0x110 +#define PLLPRE 0x114 +#define PLLDIV1 0x118 +#define PLLDIV2 0x11c +#define PLLDIV3 0x120 +#define PLLPOST 0x128 +#define PLLCMD 0x138 +#define PLLSTAT 0x13c +#define PLLALNCTL 0x140 +#define PLLDCHANGE 0x144 +#define PLLCKEN 0x148 +#define PLLCKSTAT 0x14c +#define PLLSYSTAT 0x150 +#define PLLDIV4 0x160 +#define PLLDIV5 0x164 +#define PLLDIV6 0x168 +#define PLLDIV7 0x16c +#define PLLDIV8 0x170 +#define PLLDIV9 0x174 +#define PLLDIV10 0x178 +#define PLLDIV11 0x17c +#define PLLDIV12 0x180 +#define PLLDIV13 0x184 +#define PLLDIV14 0x188 +#define PLLDIV15 0x18c +#define PLLDIV16 0x190 + +/* PLLM register bits */ +#define PLLM_PLLM_MASK 0xff +#define PLLM_VAL(x) ((x) - 1) + +/* PREDIV register bits */ +#define PLLPREDIV_EN BIT(15) +#define PLLPREDIV_VAL(x) ((x) - 1) + +/* PLLCTL register bits */ +#define PLLCTL_PLLEN BIT(0) +#define PLLCTL_PLLPWRDN BIT(1) +#define PLLCTL_PLLRST BIT(3) +#define PLLCTL_PLLDIS BIT(4) +#define PLLCTL_PLLENSRC BIT(5) +#define PLLCTL_CLKMODE BIT(8) + +/* PLLCMD register bits */ +#define PLLCMD_GOSTAT BIT(0) + +/* PLLSTAT register bits */ +#define PLLSTAT_GOSTAT BIT(0) + +/* PLLDIV register bits */ +#define PLLDIV_EN BIT(15) +#define PLLDIV_RATIO_MASK 0x1f +#define PLLDIV_RATIO(x) ((x) - 1) + +struct pll_data; + +struct clk { + struct list_head node; + struct module *owner; + const char *name; + unsigned long rate; + int usecount; + u32 flags; + struct clk *parent; + struct list_head children; /* list of children */ + struct list_head childnode; /* parent's child list node */ + struct pll_data *pll_data; + u32 div; + unsigned long (*recalc) (struct clk *); + int (*set_rate) (struct clk *clk, unsigned long rate); + int (*round_rate) (struct clk *clk, unsigned long rate); +}; + +/* Clock flags: SoC-specific flags start at BIT(16) */ +#define ALWAYS_ENABLED BIT(1) +#define CLK_PLL BIT(2) /* PLL-derived clock */ +#define PRE_PLL BIT(3) /* source is before PLL mult/div */ +#define FIXED_DIV_PLL BIT(4) /* fixed divisor from PLL */ +#define FIXED_RATE_PLL BIT(5) /* fixed ouput rate PLL */ + +#define MAX_PLL_SYSCLKS 16 + +struct pll_data { + void __iomem *base; + u32 num; + u32 flags; + u32 input_rate; + u32 bypass_delay; /* in loops */ + u32 reset_delay; /* in loops */ + u32 lock_delay; /* in loops */ + struct clk sysclks[MAX_PLL_SYSCLKS + 1]; +}; + +/* pll_data flag bit */ +#define PLL_HAS_PRE BIT(0) +#define PLL_HAS_MUL BIT(1) +#define PLL_HAS_POST BIT(2) + +#define CLK(dev, con, ck) \ + { \ + .dev_id = dev, \ + .con_id = con, \ + .clk = ck, \ + } \ + +extern void c6x_clks_init(struct clk_lookup *clocks); +extern int clk_register(struct clk *clk); +extern void clk_unregister(struct clk *clk); +extern void c64x_setup_clocks(void); + +extern struct pll_data c6x_soc_pll1; + +extern struct clk clkin1; +extern struct clk c6x_core_clk; +extern struct clk c6x_i2c_clk; +extern struct clk c6x_watchdog_clk; +extern struct clk c6x_mcbsp1_clk; +extern struct clk c6x_mcbsp2_clk; +extern struct clk c6x_mdio_clk; + +#endif + +#endif /* _ASM_C6X_CLOCK_H */ diff --git a/arch/c6x/platforms/pll.c b/arch/c6x/platforms/pll.c new file mode 100644 index 000000000000..3aa898f7ce4d --- /dev/null +++ b/arch/c6x/platforms/pll.c @@ -0,0 +1,444 @@ +/* + * Clock and PLL control for C64x+ devices + * + * Copyright (C) 2010, 2011 Texas Instruments. + * Contributed by: Mark Salter + * + * Copied heavily from arm/mach-davinci/clock.c, so: + * + * Copyright (C) 2006-2007 Texas Instruments. + * Copyright (C) 2008-2009 Deep Root Systems, LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include +#include + +static LIST_HEAD(clocks); +static DEFINE_MUTEX(clocks_mutex); +static DEFINE_SPINLOCK(clockfw_lock); + +static void __clk_enable(struct clk *clk) +{ + if (clk->parent) + __clk_enable(clk->parent); + clk->usecount++; +} + +static void __clk_disable(struct clk *clk) +{ + if (WARN_ON(clk->usecount == 0)) + return; + --clk->usecount; + + if (clk->parent) + __clk_disable(clk->parent); +} + +int clk_enable(struct clk *clk) +{ + unsigned long flags; + + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + spin_lock_irqsave(&clockfw_lock, flags); + __clk_enable(clk); + spin_unlock_irqrestore(&clockfw_lock, flags); + + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ + unsigned long flags; + + if (clk == NULL || IS_ERR(clk)) + return; + + spin_lock_irqsave(&clockfw_lock, flags); + __clk_disable(clk); + spin_unlock_irqrestore(&clockfw_lock, flags); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + return clk->rate; +} +EXPORT_SYMBOL(clk_get_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + if (clk->round_rate) + return clk->round_rate(clk, rate); + + return clk->rate; +} +EXPORT_SYMBOL(clk_round_rate); + +/* Propagate rate to children */ +static void propagate_rate(struct clk *root) +{ + struct clk *clk; + + list_for_each_entry(clk, &root->children, childnode) { + if (clk->recalc) + clk->rate = clk->recalc(clk); + propagate_rate(clk); + } +} + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + int ret = -EINVAL; + + if (clk == NULL || IS_ERR(clk)) + return ret; + + if (clk->set_rate) + ret = clk->set_rate(clk, rate); + + spin_lock_irqsave(&clockfw_lock, flags); + if (ret == 0) { + if (clk->recalc) + clk->rate = clk->recalc(clk); + propagate_rate(clk); + } + spin_unlock_irqrestore(&clockfw_lock, flags); + + return ret; +} +EXPORT_SYMBOL(clk_set_rate); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long flags; + + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + /* Cannot change parent on enabled clock */ + if (WARN_ON(clk->usecount)) + return -EINVAL; + + mutex_lock(&clocks_mutex); + clk->parent = parent; + list_del_init(&clk->childnode); + list_add(&clk->childnode, &clk->parent->children); + mutex_unlock(&clocks_mutex); + + spin_lock_irqsave(&clockfw_lock, flags); + if (clk->recalc) + clk->rate = clk->recalc(clk); + propagate_rate(clk); + spin_unlock_irqrestore(&clockfw_lock, flags); + + return 0; +} +EXPORT_SYMBOL(clk_set_parent); + +int clk_register(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + + if (WARN(clk->parent && !clk->parent->rate, + "CLK: %s parent %s has no rate!\n", + clk->name, clk->parent->name)) + return -EINVAL; + + mutex_lock(&clocks_mutex); + list_add_tail(&clk->node, &clocks); + if (clk->parent) + list_add_tail(&clk->childnode, &clk->parent->children); + mutex_unlock(&clocks_mutex); + + /* If rate is already set, use it */ + if (clk->rate) + return 0; + + /* Else, see if there is a way to calculate it */ + if (clk->recalc) + clk->rate = clk->recalc(clk); + + /* Otherwise, default to parent rate */ + else if (clk->parent) + clk->rate = clk->parent->rate; + + return 0; +} +EXPORT_SYMBOL(clk_register); + +void clk_unregister(struct clk *clk) +{ + if (clk == NULL || IS_ERR(clk)) + return; + + mutex_lock(&clocks_mutex); + list_del(&clk->node); + list_del(&clk->childnode); + mutex_unlock(&clocks_mutex); +} +EXPORT_SYMBOL(clk_unregister); + + +static u32 pll_read(struct pll_data *pll, int reg) +{ + return soc_readl(pll->base + reg); +} + +static unsigned long clk_sysclk_recalc(struct clk *clk) +{ + u32 v, plldiv = 0; + struct pll_data *pll; + unsigned long rate = clk->rate; + + if (WARN_ON(!clk->parent)) + return rate; + + rate = clk->parent->rate; + + /* the parent must be a PLL */ + if (WARN_ON(!clk->parent->pll_data)) + return rate; + + pll = clk->parent->pll_data; + + /* If pre-PLL, source clock is before the multiplier and divider(s) */ + if (clk->flags & PRE_PLL) + rate = pll->input_rate; + + if (!clk->div) { + pr_debug("%s: (no divider) rate = %lu KHz\n", + clk->name, rate / 1000); + return rate; + } + + if (clk->flags & FIXED_DIV_PLL) { + rate /= clk->div; + pr_debug("%s: (fixed divide by %d) rate = %lu KHz\n", + clk->name, clk->div, rate / 1000); + return rate; + } + + v = pll_read(pll, clk->div); + if (v & PLLDIV_EN) + plldiv = (v & PLLDIV_RATIO_MASK) + 1; + + if (plldiv == 0) + plldiv = 1; + + rate /= plldiv; + + pr_debug("%s: (divide by %d) rate = %lu KHz\n", + clk->name, plldiv, rate / 1000); + + return rate; +} + +static unsigned long clk_leafclk_recalc(struct clk *clk) +{ + if (WARN_ON(!clk->parent)) + return clk->rate; + + pr_debug("%s: (parent %s) rate = %lu KHz\n", + clk->name, clk->parent->name, clk->parent->rate / 1000); + + return clk->parent->rate; +} + +static unsigned long clk_pllclk_recalc(struct clk *clk) +{ + u32 ctrl, mult = 0, prediv = 0, postdiv = 0; + u8 bypass; + struct pll_data *pll = clk->pll_data; + unsigned long rate = clk->rate; + + if (clk->flags & FIXED_RATE_PLL) + return rate; + + ctrl = pll_read(pll, PLLCTL); + rate = pll->input_rate = clk->parent->rate; + + if (ctrl & PLLCTL_PLLEN) + bypass = 0; + else + bypass = 1; + + if (pll->flags & PLL_HAS_MUL) { + mult = pll_read(pll, PLLM); + mult = (mult & PLLM_PLLM_MASK) + 1; + } + if (pll->flags & PLL_HAS_PRE) { + prediv = pll_read(pll, PLLPRE); + if (prediv & PLLDIV_EN) + prediv = (prediv & PLLDIV_RATIO_MASK) + 1; + else + prediv = 0; + } + if (pll->flags & PLL_HAS_POST) { + postdiv = pll_read(pll, PLLPOST); + if (postdiv & PLLDIV_EN) + postdiv = (postdiv & PLLDIV_RATIO_MASK) + 1; + else + postdiv = 1; + } + + if (!bypass) { + if (prediv) + rate /= prediv; + if (mult) + rate *= mult; + if (postdiv) + rate /= postdiv; + + pr_debug("PLL%d: input = %luMHz, pre[%d] mul[%d] post[%d] " + "--> %luMHz output.\n", + pll->num, clk->parent->rate / 1000000, + prediv, mult, postdiv, rate / 1000000); + } else + pr_debug("PLL%d: input = %luMHz, bypass mode.\n", + pll->num, clk->parent->rate / 1000000); + + return rate; +} + + +static void __init __init_clk(struct clk *clk) +{ + INIT_LIST_HEAD(&clk->node); + INIT_LIST_HEAD(&clk->children); + INIT_LIST_HEAD(&clk->childnode); + + if (!clk->recalc) { + + /* Check if clock is a PLL */ + if (clk->pll_data) + clk->recalc = clk_pllclk_recalc; + + /* Else, if it is a PLL-derived clock */ + else if (clk->flags & CLK_PLL) + clk->recalc = clk_sysclk_recalc; + + /* Otherwise, it is a leaf clock (PSC clock) */ + else if (clk->parent) + clk->recalc = clk_leafclk_recalc; + } +} + +void __init c6x_clks_init(struct clk_lookup *clocks) +{ + struct clk_lookup *c; + struct clk *clk; + size_t num_clocks = 0; + + for (c = clocks; c->clk; c++) { + clk = c->clk; + + __init_clk(clk); + clk_register(clk); + num_clocks++; + + /* Turn on clocks that Linux doesn't otherwise manage */ + if (clk->flags & ALWAYS_ENABLED) + clk_enable(clk); + } + + clkdev_add_table(clocks, num_clocks); +} + +#ifdef CONFIG_DEBUG_FS + +#include +#include + +#define CLKNAME_MAX 10 /* longest clock name */ +#define NEST_DELTA 2 +#define NEST_MAX 4 + +static void +dump_clock(struct seq_file *s, unsigned nest, struct clk *parent) +{ + char *state; + char buf[CLKNAME_MAX + NEST_DELTA * NEST_MAX]; + struct clk *clk; + unsigned i; + + if (parent->flags & CLK_PLL) + state = "pll"; + else + state = ""; + + /* name */ + memset(buf, ' ', sizeof(buf) - 1); + buf[sizeof(buf) - 1] = 0; + i = strlen(parent->name); + memcpy(buf + nest, parent->name, + min(i, (unsigned)(sizeof(buf) - 1 - nest))); + + seq_printf(s, "%s users=%2d %-3s %9ld Hz\n", + buf, parent->usecount, state, clk_get_rate(parent)); + /* REVISIT show device associations too */ + + /* cost is now small, but not linear... */ + list_for_each_entry(clk, &parent->children, childnode) { + dump_clock(s, nest + NEST_DELTA, clk); + } +} + +static int c6x_ck_show(struct seq_file *m, void *v) +{ + struct clk *clk; + + /* + * Show clock tree; We trust nonzero usecounts equate to PSC enables... + */ + mutex_lock(&clocks_mutex); + list_for_each_entry(clk, &clocks, node) + if (!clk->parent) + dump_clock(m, 0, clk); + mutex_unlock(&clocks_mutex); + + return 0; +} + +static int c6x_ck_open(struct inode *inode, struct file *file) +{ + return single_open(file, c6x_ck_show, NULL); +} + +static const struct file_operations c6x_ck_operations = { + .open = c6x_ck_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init c6x_clk_debugfs_init(void) +{ + debugfs_create_file("c6x_clocks", S_IFREG | S_IRUGO, NULL, NULL, + &c6x_ck_operations); + + return 0; +} +device_initcall(c6x_clk_debugfs_init); +#endif /* CONFIG_DEBUG_FS */ diff --git a/arch/c6x/platforms/plldata.c b/arch/c6x/platforms/plldata.c new file mode 100644 index 000000000000..2cfd6f42968f --- /dev/null +++ b/arch/c6x/platforms/plldata.c @@ -0,0 +1,404 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * Common SoC clock support. + */ + +/* Default input for PLL1 */ +struct clk clkin1 = { + .name = "clkin1", + .node = LIST_HEAD_INIT(clkin1.node), + .children = LIST_HEAD_INIT(clkin1.children), + .childnode = LIST_HEAD_INIT(clkin1.childnode), +}; + +struct pll_data c6x_soc_pll1 = { + .num = 1, + .sysclks = { + { + .name = "pll1", + .parent = &clkin1, + .pll_data = &c6x_soc_pll1, + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk1", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk2", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk3", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk4", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk5", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk6", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk7", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk8", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk9", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk10", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk11", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk12", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk13", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk14", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk15", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + { + .name = "pll1_sysclk16", + .parent = &c6x_soc_pll1.sysclks[0], + .flags = CLK_PLL, + }, + }, +}; + +/* CPU core clock */ +struct clk c6x_core_clk = { + .name = "core", +}; + +/* miscellaneous IO clocks */ +struct clk c6x_i2c_clk = { + .name = "i2c", +}; + +struct clk c6x_watchdog_clk = { + .name = "watchdog", +}; + +struct clk c6x_mcbsp1_clk = { + .name = "mcbsp1", +}; + +struct clk c6x_mcbsp2_clk = { + .name = "mcbsp2", +}; + +struct clk c6x_mdio_clk = { + .name = "mdio", +}; + + +#ifdef CONFIG_SOC_TMS320C6455 +static struct clk_lookup c6455_clks[] = { + CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]), + CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]), + CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]), + CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]), + CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]), + CLK(NULL, "core", &c6x_core_clk), + CLK("i2c_davinci.1", NULL, &c6x_i2c_clk), + CLK("watchdog", NULL, &c6x_watchdog_clk), + CLK("2c81800.mdio", NULL, &c6x_mdio_clk), + CLK("", NULL, NULL) +}; + + +static void __init c6455_setup_clocks(struct device_node *node) +{ + struct pll_data *pll = &c6x_soc_pll1; + struct clk *sysclks = pll->sysclks; + + pll->flags = PLL_HAS_PRE | PLL_HAS_MUL; + + sysclks[2].flags |= FIXED_DIV_PLL; + sysclks[2].div = 3; + sysclks[3].flags |= FIXED_DIV_PLL; + sysclks[3].div = 6; + sysclks[4].div = PLLDIV4; + sysclks[5].div = PLLDIV5; + + c6x_core_clk.parent = &sysclks[0]; + c6x_i2c_clk.parent = &sysclks[3]; + c6x_watchdog_clk.parent = &sysclks[3]; + c6x_mdio_clk.parent = &sysclks[3]; + + c6x_clks_init(c6455_clks); +} +#endif /* CONFIG_SOC_TMS320C6455 */ + +#ifdef CONFIG_SOC_TMS320C6457 +static struct clk_lookup c6457_clks[] = { + CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]), + CLK(NULL, "pll1_sysclk1", &c6x_soc_pll1.sysclks[1]), + CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]), + CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]), + CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]), + CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]), + CLK(NULL, "core", &c6x_core_clk), + CLK("i2c_davinci.1", NULL, &c6x_i2c_clk), + CLK("watchdog", NULL, &c6x_watchdog_clk), + CLK("2c81800.mdio", NULL, &c6x_mdio_clk), + CLK("", NULL, NULL) +}; + +static void __init c6457_setup_clocks(struct device_node *node) +{ + struct pll_data *pll = &c6x_soc_pll1; + struct clk *sysclks = pll->sysclks; + + pll->flags = PLL_HAS_MUL | PLL_HAS_POST; + + sysclks[1].flags |= FIXED_DIV_PLL; + sysclks[1].div = 1; + sysclks[2].flags |= FIXED_DIV_PLL; + sysclks[2].div = 3; + sysclks[3].flags |= FIXED_DIV_PLL; + sysclks[3].div = 6; + sysclks[4].div = PLLDIV4; + sysclks[5].div = PLLDIV5; + + c6x_core_clk.parent = &sysclks[1]; + c6x_i2c_clk.parent = &sysclks[3]; + c6x_watchdog_clk.parent = &sysclks[5]; + c6x_mdio_clk.parent = &sysclks[5]; + + c6x_clks_init(c6457_clks); +} +#endif /* CONFIG_SOC_TMS320C6455 */ + +#ifdef CONFIG_SOC_TMS320C6472 +static struct clk_lookup c6472_clks[] = { + CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]), + CLK(NULL, "pll1_sysclk1", &c6x_soc_pll1.sysclks[1]), + CLK(NULL, "pll1_sysclk2", &c6x_soc_pll1.sysclks[2]), + CLK(NULL, "pll1_sysclk3", &c6x_soc_pll1.sysclks[3]), + CLK(NULL, "pll1_sysclk4", &c6x_soc_pll1.sysclks[4]), + CLK(NULL, "pll1_sysclk5", &c6x_soc_pll1.sysclks[5]), + CLK(NULL, "pll1_sysclk6", &c6x_soc_pll1.sysclks[6]), + CLK(NULL, "pll1_sysclk7", &c6x_soc_pll1.sysclks[7]), + CLK(NULL, "pll1_sysclk8", &c6x_soc_pll1.sysclks[8]), + CLK(NULL, "pll1_sysclk9", &c6x_soc_pll1.sysclks[9]), + CLK(NULL, "pll1_sysclk10", &c6x_soc_pll1.sysclks[10]), + CLK(NULL, "core", &c6x_core_clk), + CLK("i2c_davinci.1", NULL, &c6x_i2c_clk), + CLK("watchdog", NULL, &c6x_watchdog_clk), + CLK("2c81800.mdio", NULL, &c6x_mdio_clk), + CLK("", NULL, NULL) +}; + +/* assumptions used for delay loop calculations */ +#define MIN_CLKIN1_KHz 15625 +#define MAX_CORE_KHz 700000 +#define MIN_PLLOUT_KHz MIN_CLKIN1_KHz + +static void __init c6472_setup_clocks(struct device_node *node) +{ + struct pll_data *pll = &c6x_soc_pll1; + struct clk *sysclks = pll->sysclks; + int i; + + pll->flags = PLL_HAS_MUL; + + for (i = 1; i <= 6; i++) { + sysclks[i].flags |= FIXED_DIV_PLL; + sysclks[i].div = 1; + } + + sysclks[7].flags |= FIXED_DIV_PLL; + sysclks[7].div = 3; + sysclks[8].flags |= FIXED_DIV_PLL; + sysclks[8].div = 6; + sysclks[9].flags |= FIXED_DIV_PLL; + sysclks[9].div = 2; + sysclks[10].div = PLLDIV10; + + c6x_core_clk.parent = &sysclks[get_coreid() + 1]; + c6x_i2c_clk.parent = &sysclks[8]; + c6x_watchdog_clk.parent = &sysclks[8]; + c6x_mdio_clk.parent = &sysclks[5]; + + c6x_clks_init(c6472_clks); +} +#endif /* CONFIG_SOC_TMS320C6472 */ + + +#ifdef CONFIG_SOC_TMS320C6474 +static struct clk_lookup c6474_clks[] = { + CLK(NULL, "pll1", &c6x_soc_pll1.sysclks[0]), + CLK(NULL, "pll1_sysclk7", &c6x_soc_pll1.sysclks[7]), + CLK(NULL, "pll1_sysclk9", &c6x_soc_pll1.sysclks[9]), + CLK(NULL, "pll1_sysclk10", &c6x_soc_pll1.sysclks[10]), + CLK(NULL, "pll1_sysclk11", &c6x_soc_pll1.sysclks[11]), + CLK(NULL, "pll1_sysclk12", &c6x_soc_pll1.sysclks[12]), + CLK(NULL, "pll1_sysclk13", &c6x_soc_pll1.sysclks[13]), + CLK(NULL, "core", &c6x_core_clk), + CLK("i2c_davinci.1", NULL, &c6x_i2c_clk), + CLK("mcbsp.1", NULL, &c6x_mcbsp1_clk), + CLK("mcbsp.2", NULL, &c6x_mcbsp2_clk), + CLK("watchdog", NULL, &c6x_watchdog_clk), + CLK("2c81800.mdio", NULL, &c6x_mdio_clk), + CLK("", NULL, NULL) +}; + +static void __init c6474_setup_clocks(struct device_node *node) +{ + struct pll_data *pll = &c6x_soc_pll1; + struct clk *sysclks = pll->sysclks; + + pll->flags = PLL_HAS_MUL; + + sysclks[7].flags |= FIXED_DIV_PLL; + sysclks[7].div = 1; + sysclks[9].flags |= FIXED_DIV_PLL; + sysclks[9].div = 3; + sysclks[10].flags |= FIXED_DIV_PLL; + sysclks[10].div = 6; + + sysclks[11].div = PLLDIV11; + + sysclks[12].flags |= FIXED_DIV_PLL; + sysclks[12].div = 2; + + sysclks[13].div = PLLDIV13; + + c6x_core_clk.parent = &sysclks[7]; + c6x_i2c_clk.parent = &sysclks[10]; + c6x_watchdog_clk.parent = &sysclks[10]; + c6x_mcbsp1_clk.parent = &sysclks[10]; + c6x_mcbsp2_clk.parent = &sysclks[10]; + + c6x_clks_init(c6474_clks); +} +#endif /* CONFIG_SOC_TMS320C6474 */ + +static struct of_device_id c6x_clkc_match[] __initdata = { +#ifdef CONFIG_SOC_TMS320C6455 + { .compatible = "ti,c6455-pll", .data = c6455_setup_clocks }, +#endif +#ifdef CONFIG_SOC_TMS320C6457 + { .compatible = "ti,c6457-pll", .data = c6457_setup_clocks }, +#endif +#ifdef CONFIG_SOC_TMS320C6472 + { .compatible = "ti,c6472-pll", .data = c6472_setup_clocks }, +#endif +#ifdef CONFIG_SOC_TMS320C6474 + { .compatible = "ti,c6474-pll", .data = c6474_setup_clocks }, +#endif + { .compatible = "ti,c64x+pll" }, + {} +}; + +void __init c64x_setup_clocks(void) +{ + void (*__setup_clocks)(struct device_node *np); + struct pll_data *pll = &c6x_soc_pll1; + struct device_node *node; + const struct of_device_id *id; + int err; + u32 val; + + node = of_find_matching_node(NULL, c6x_clkc_match); + if (!node) + return; + + pll->base = of_iomap(node, 0); + if (!pll->base) + goto out; + + err = of_property_read_u32(node, "clock-frequency", &val); + if (err || val == 0) { + pr_err("%s: no clock-frequency found! Using %dMHz\n", + node->full_name, (int)val / 1000000); + val = 25000000; + } + clkin1.rate = val; + + err = of_property_read_u32(node, "ti,c64x+pll-bypass-delay", &val); + if (err) + val = 5000; + pll->bypass_delay = val; + + err = of_property_read_u32(node, "ti,c64x+pll-reset-delay", &val); + if (err) + val = 30000; + pll->reset_delay = val; + + err = of_property_read_u32(node, "ti,c64x+pll-lock-delay", &val); + if (err) + val = 30000; + pll->lock_delay = val; + + /* id->data is a pointer to SoC-specific setup */ + id = of_match_node(c6x_clkc_match, node); + if (id && id->data) { + __setup_clocks = id->data; + __setup_clocks(node); + } + +out: + of_node_put(node); +} -- cgit v1.2.3 From 784bdcd0aa1d8ce38025bcfaa321146762738fe0 Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 11:11:35 -0400 Subject: C6X: cache control Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann --- arch/c6x/include/asm/cache.h | 90 ++++++++ arch/c6x/include/asm/cacheflush.h | 65 ++++++ arch/c6x/platforms/cache.c | 445 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 600 insertions(+) create mode 100644 arch/c6x/include/asm/cache.h create mode 100644 arch/c6x/include/asm/cacheflush.h create mode 100644 arch/c6x/platforms/cache.c (limited to 'arch') diff --git a/arch/c6x/include/asm/cache.h b/arch/c6x/include/asm/cache.h new file mode 100644 index 000000000000..6d521d96d941 --- /dev/null +++ b/arch/c6x/include/asm/cache.h @@ -0,0 +1,90 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2005, 2006, 2009, 2010 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_CACHE_H +#define _ASM_C6X_CACHE_H + +#include + +/* + * Cache line size + */ +#define L1D_CACHE_BYTES 64 +#define L1P_CACHE_BYTES 32 +#define L2_CACHE_BYTES 128 + +/* + * L2 used as cache + */ +#define L2MODE_SIZE L2MODE_256K_CACHE + +/* + * For practical reasons the L1_CACHE_BYTES defines should not be smaller than + * the L2 line size + */ +#define L1_CACHE_BYTES L2_CACHE_BYTES + +#define L2_CACHE_ALIGN_LOW(x) \ + (((x) & ~(L2_CACHE_BYTES - 1))) +#define L2_CACHE_ALIGN_UP(x) \ + (((x) + (L2_CACHE_BYTES - 1)) & ~(L2_CACHE_BYTES - 1)) +#define L2_CACHE_ALIGN_CNT(x) \ + (((x) + (sizeof(int) - 1)) & ~(sizeof(int) - 1)) + +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES +#define ARCH_SLAB_MINALIGN L1_CACHE_BYTES + +/* + * This is the granularity of hardware cacheability control. + */ +#define CACHEABILITY_ALIGN 0x01000000 + +/* + * Align a physical address to MAR regions + */ +#define CACHE_REGION_START(v) \ + (((u32) (v)) & ~(CACHEABILITY_ALIGN - 1)) +#define CACHE_REGION_END(v) \ + (((u32) (v) + (CACHEABILITY_ALIGN - 1)) & ~(CACHEABILITY_ALIGN - 1)) + +extern void __init c6x_cache_init(void); + +extern void enable_caching(unsigned long start, unsigned long end); +extern void disable_caching(unsigned long start, unsigned long end); + +extern void L1_cache_off(void); +extern void L1_cache_on(void); + +extern void L1P_cache_global_invalidate(void); +extern void L1D_cache_global_invalidate(void); +extern void L1D_cache_global_writeback(void); +extern void L1D_cache_global_writeback_invalidate(void); +extern void L2_cache_set_mode(unsigned int mode); +extern void L2_cache_global_writeback_invalidate(void); +extern void L2_cache_global_writeback(void); + +extern void L1P_cache_block_invalidate(unsigned int start, unsigned int end); +extern void L1D_cache_block_invalidate(unsigned int start, unsigned int end); +extern void L1D_cache_block_writeback_invalidate(unsigned int start, + unsigned int end); +extern void L1D_cache_block_writeback(unsigned int start, unsigned int end); +extern void L2_cache_block_invalidate(unsigned int start, unsigned int end); +extern void L2_cache_block_writeback(unsigned int start, unsigned int end); +extern void L2_cache_block_writeback_invalidate(unsigned int start, + unsigned int end); +extern void L2_cache_block_invalidate_nowait(unsigned int start, + unsigned int end); +extern void L2_cache_block_writeback_nowait(unsigned int start, + unsigned int end); + +extern void L2_cache_block_writeback_invalidate_nowait(unsigned int start, + unsigned int end); + +#endif /* _ASM_C6X_CACHE_H */ diff --git a/arch/c6x/include/asm/cacheflush.h b/arch/c6x/include/asm/cacheflush.h new file mode 100644 index 000000000000..df5db90dbe56 --- /dev/null +++ b/arch/c6x/include/asm/cacheflush.h @@ -0,0 +1,65 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_CACHEFLUSH_H +#define _ASM_C6X_CACHEFLUSH_H + +#include + +#include +#include +#include +#include +#include + +/* + * virtually-indexed cache management (our cache is physically indexed) + */ +#define flush_cache_all() do {} while (0) +#define flush_cache_mm(mm) do {} while (0) +#define flush_cache_dup_mm(mm) do {} while (0) +#define flush_cache_range(mm, start, end) do {} while (0) +#define flush_cache_page(vma, vmaddr, pfn) do {} while (0) +#define flush_cache_vmap(start, end) do {} while (0) +#define flush_cache_vunmap(start, end) do {} while (0) +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 +#define flush_dcache_page(page) do {} while (0) +#define flush_dcache_mmap_lock(mapping) do {} while (0) +#define flush_dcache_mmap_unlock(mapping) do {} while (0) + +/* + * physically-indexed cache management + */ +#define flush_icache_range(s, e) \ +do { \ + L1D_cache_block_writeback((s), (e)); \ + L1P_cache_block_invalidate((s), (e)); \ +} while (0) + +#define flush_icache_page(vma, page) \ +do { \ + if ((vma)->vm_flags & PROT_EXEC) \ + L1D_cache_block_writeback_invalidate(page_address(page), \ + (unsigned long) page_address(page) + PAGE_SIZE)); \ + L1P_cache_block_invalidate(page_address(page), \ + (unsigned long) page_address(page) + PAGE_SIZE)); \ +} while (0) + + +#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ +do { \ + memcpy(dst, src, len); \ + flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \ +} while (0) + +#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ + memcpy(dst, src, len) + +#endif /* _ASM_C6X_CACHEFLUSH_H */ diff --git a/arch/c6x/platforms/cache.c b/arch/c6x/platforms/cache.c new file mode 100644 index 000000000000..86318a16a252 --- /dev/null +++ b/arch/c6x/platforms/cache.c @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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 +#include +#include + +#include +#include + +/* + * Internal Memory Control Registers for caches + */ +#define IMCR_CCFG 0x0000 +#define IMCR_L1PCFG 0x0020 +#define IMCR_L1PCC 0x0024 +#define IMCR_L1DCFG 0x0040 +#define IMCR_L1DCC 0x0044 +#define IMCR_L2ALLOC0 0x2000 +#define IMCR_L2ALLOC1 0x2004 +#define IMCR_L2ALLOC2 0x2008 +#define IMCR_L2ALLOC3 0x200c +#define IMCR_L2WBAR 0x4000 +#define IMCR_L2WWC 0x4004 +#define IMCR_L2WIBAR 0x4010 +#define IMCR_L2WIWC 0x4014 +#define IMCR_L2IBAR 0x4018 +#define IMCR_L2IWC 0x401c +#define IMCR_L1PIBAR 0x4020 +#define IMCR_L1PIWC 0x4024 +#define IMCR_L1DWIBAR 0x4030 +#define IMCR_L1DWIWC 0x4034 +#define IMCR_L1DWBAR 0x4040 +#define IMCR_L1DWWC 0x4044 +#define IMCR_L1DIBAR 0x4048 +#define IMCR_L1DIWC 0x404c +#define IMCR_L2WB 0x5000 +#define IMCR_L2WBINV 0x5004 +#define IMCR_L2INV 0x5008 +#define IMCR_L1PINV 0x5028 +#define IMCR_L1DWB 0x5040 +#define IMCR_L1DWBINV 0x5044 +#define IMCR_L1DINV 0x5048 +#define IMCR_MAR_BASE 0x8000 +#define IMCR_MAR96_111 0x8180 +#define IMCR_MAR128_191 0x8200 +#define IMCR_MAR224_239 0x8380 +#define IMCR_L2MPFAR 0xa000 +#define IMCR_L2MPFSR 0xa004 +#define IMCR_L2MPFCR 0xa008 +#define IMCR_L2MPLK0 0xa100 +#define IMCR_L2MPLK1 0xa104 +#define IMCR_L2MPLK2 0xa108 +#define IMCR_L2MPLK3 0xa10c +#define IMCR_L2MPLKCMD 0xa110 +#define IMCR_L2MPLKSTAT 0xa114 +#define IMCR_L2MPPA_BASE 0xa200 +#define IMCR_L1PMPFAR 0xa400 +#define IMCR_L1PMPFSR 0xa404 +#define IMCR_L1PMPFCR 0xa408 +#define IMCR_L1PMPLK0 0xa500 +#define IMCR_L1PMPLK1 0xa504 +#define IMCR_L1PMPLK2 0xa508 +#define IMCR_L1PMPLK3 0xa50c +#define IMCR_L1PMPLKCMD 0xa510 +#define IMCR_L1PMPLKSTAT 0xa514 +#define IMCR_L1PMPPA_BASE 0xa600 +#define IMCR_L1DMPFAR 0xac00 +#define IMCR_L1DMPFSR 0xac04 +#define IMCR_L1DMPFCR 0xac08 +#define IMCR_L1DMPLK0 0xad00 +#define IMCR_L1DMPLK1 0xad04 +#define IMCR_L1DMPLK2 0xad08 +#define IMCR_L1DMPLK3 0xad0c +#define IMCR_L1DMPLKCMD 0xad10 +#define IMCR_L1DMPLKSTAT 0xad14 +#define IMCR_L1DMPPA_BASE 0xae00 +#define IMCR_L2PDWAKE0 0xc040 +#define IMCR_L2PDWAKE1 0xc044 +#define IMCR_L2PDSLEEP0 0xc050 +#define IMCR_L2PDSLEEP1 0xc054 +#define IMCR_L2PDSTAT0 0xc060 +#define IMCR_L2PDSTAT1 0xc064 + +/* + * CCFG register values and bits + */ +#define L2MODE_0K_CACHE 0x0 +#define L2MODE_32K_CACHE 0x1 +#define L2MODE_64K_CACHE 0x2 +#define L2MODE_128K_CACHE 0x3 +#define L2MODE_256K_CACHE 0x7 + +#define L2PRIO_URGENT 0x0 +#define L2PRIO_HIGH 0x1 +#define L2PRIO_MEDIUM 0x2 +#define L2PRIO_LOW 0x3 + +#define CCFG_ID 0x100 /* Invalidate L1P bit */ +#define CCFG_IP 0x200 /* Invalidate L1D bit */ + +static void __iomem *cache_base; + +/* + * L1 & L2 caches generic functions + */ +#define imcr_get(reg) soc_readl(cache_base + (reg)) +#define imcr_set(reg, value) \ +do { \ + soc_writel((value), cache_base + (reg)); \ + soc_readl(cache_base + (reg)); \ +} while (0) + +static void cache_block_operation_wait(unsigned int wc_reg) +{ + /* Wait for completion */ + while (imcr_get(wc_reg)) + cpu_relax(); +} + +static DEFINE_SPINLOCK(cache_lock); + +/* + * Generic function to perform a block cache operation as + * invalidate or writeback/invalidate + */ +static void cache_block_operation(unsigned int *start, + unsigned int *end, + unsigned int bar_reg, + unsigned int wc_reg) +{ + unsigned long flags; + unsigned int wcnt = + (L2_CACHE_ALIGN_CNT((unsigned int) end) + - L2_CACHE_ALIGN_LOW((unsigned int) start)) >> 2; + unsigned int wc = 0; + + for (; wcnt; wcnt -= wc, start += wc) { +loop: + spin_lock_irqsave(&cache_lock, flags); + + /* + * If another cache operation is occuring + */ + if (unlikely(imcr_get(wc_reg))) { + spin_unlock_irqrestore(&cache_lock, flags); + + /* Wait for previous operation completion */ + cache_block_operation_wait(wc_reg); + + /* Try again */ + goto loop; + } + + imcr_set(bar_reg, L2_CACHE_ALIGN_LOW((unsigned int) start)); + + if (wcnt > 0xffff) + wc = 0xffff; + else + wc = wcnt; + + /* Set word count value in the WC register */ + imcr_set(wc_reg, wc & 0xffff); + + spin_unlock_irqrestore(&cache_lock, flags); + + /* Wait for completion */ + cache_block_operation_wait(wc_reg); + } +} + +static void cache_block_operation_nowait(unsigned int *start, + unsigned int *end, + unsigned int bar_reg, + unsigned int wc_reg) +{ + unsigned long flags; + unsigned int wcnt = + (L2_CACHE_ALIGN_CNT((unsigned int) end) + - L2_CACHE_ALIGN_LOW((unsigned int) start)) >> 2; + unsigned int wc = 0; + + for (; wcnt; wcnt -= wc, start += wc) { + + spin_lock_irqsave(&cache_lock, flags); + + imcr_set(bar_reg, L2_CACHE_ALIGN_LOW((unsigned int) start)); + + if (wcnt > 0xffff) + wc = 0xffff; + else + wc = wcnt; + + /* Set word count value in the WC register */ + imcr_set(wc_reg, wc & 0xffff); + + spin_unlock_irqrestore(&cache_lock, flags); + + /* Don't wait for completion on last cache operation */ + if (wcnt > 0xffff) + cache_block_operation_wait(wc_reg); + } +} + +/* + * L1 caches management + */ + +/* + * Disable L1 caches + */ +void L1_cache_off(void) +{ + unsigned int dummy; + + imcr_set(IMCR_L1PCFG, 0); + dummy = imcr_get(IMCR_L1PCFG); + + imcr_set(IMCR_L1DCFG, 0); + dummy = imcr_get(IMCR_L1DCFG); +} + +/* + * Enable L1 caches + */ +void L1_cache_on(void) +{ + unsigned int dummy; + + imcr_set(IMCR_L1PCFG, 7); + dummy = imcr_get(IMCR_L1PCFG); + + imcr_set(IMCR_L1DCFG, 7); + dummy = imcr_get(IMCR_L1DCFG); +} + +/* + * L1P global-invalidate all + */ +void L1P_cache_global_invalidate(void) +{ + unsigned int set = 1; + imcr_set(IMCR_L1PINV, set); + while (imcr_get(IMCR_L1PINV) & 1) + cpu_relax(); +} + +/* + * L1D global-invalidate all + * + * Warning: this operation causes all updated data in L1D to + * be discarded rather than written back to the lower levels of + * memory + */ +void L1D_cache_global_invalidate(void) +{ + unsigned int set = 1; + imcr_set(IMCR_L1DINV, set); + while (imcr_get(IMCR_L1DINV) & 1) + cpu_relax(); +} + +void L1D_cache_global_writeback(void) +{ + unsigned int set = 1; + imcr_set(IMCR_L1DWB, set); + while (imcr_get(IMCR_L1DWB) & 1) + cpu_relax(); +} + +void L1D_cache_global_writeback_invalidate(void) +{ + unsigned int set = 1; + imcr_set(IMCR_L1DWBINV, set); + while (imcr_get(IMCR_L1DWBINV) & 1) + cpu_relax(); +} + +/* + * L2 caches management + */ + +/* + * Set L2 operation mode + */ +void L2_cache_set_mode(unsigned int mode) +{ + unsigned int ccfg = imcr_get(IMCR_CCFG); + + /* Clear and set the L2MODE bits in CCFG */ + ccfg &= ~7; + ccfg |= (mode & 7); + imcr_set(IMCR_CCFG, ccfg); + ccfg = imcr_get(IMCR_CCFG); +} + +/* + * L2 global-writeback and global-invalidate all + */ +void L2_cache_global_writeback_invalidate(void) +{ + imcr_set(IMCR_L2WBINV, 1); + while (imcr_get(IMCR_L2WBINV)) + cpu_relax(); +} + +/* + * L2 global-writeback all + */ +void L2_cache_global_writeback(void) +{ + imcr_set(IMCR_L2WB, 1); + while (imcr_get(IMCR_L2WB)) + cpu_relax(); +} + +/* + * Cacheability controls + */ +void enable_caching(unsigned long start, unsigned long end) +{ + unsigned int mar = IMCR_MAR_BASE + ((start >> 24) << 2); + unsigned int mar_e = IMCR_MAR_BASE + ((end >> 24) << 2); + + for (; mar <= mar_e; mar += 4) + imcr_set(mar, imcr_get(mar) | 1); +} + +void disable_caching(unsigned long start, unsigned long end) +{ + unsigned int mar = IMCR_MAR_BASE + ((start >> 24) << 2); + unsigned int mar_e = IMCR_MAR_BASE + ((end >> 24) << 2); + + for (; mar <= mar_e; mar += 4) + imcr_set(mar, imcr_get(mar) & ~1); +} + + +/* + * L1 block operations + */ +void L1P_cache_block_invalidate(unsigned int start, unsigned int end) +{ + cache_block_operation((unsigned int *) start, + (unsigned int *) end, + IMCR_L1PIBAR, IMCR_L1PIWC); +} + +void L1D_cache_block_invalidate(unsigned int start, unsigned int end) +{ + cache_block_operation((unsigned int *) start, + (unsigned int *) end, + IMCR_L1DIBAR, IMCR_L1DIWC); +} + +void L1D_cache_block_writeback_invalidate(unsigned int start, unsigned int end) +{ + cache_block_operation((unsigned int *) start, + (unsigned int *) end, + IMCR_L1DWIBAR, IMCR_L1DWIWC); +} + +void L1D_cache_block_writeback(unsigned int start, unsigned int end) +{ + cache_block_operation((unsigned int *) start, + (unsigned int *) end, + IMCR_L1DWBAR, IMCR_L1DWWC); +} + +/* + * L2 block operations + */ +void L2_cache_block_invalidate(unsigned int start, unsigned int end) +{ + cache_block_operation((unsigned int *) start, + (unsigned int *) end, + IMCR_L2IBAR, IMCR_L2IWC); +} + +void L2_cache_block_writeback(unsigned int start, unsigned int end) +{ + cache_block_operation((unsigned int *) start, + (unsigned int *) end, + IMCR_L2WBAR, IMCR_L2WWC); +} + +void L2_cache_block_writeback_invalidate(unsigned int start, unsigned int end) +{ + cache_block_operation((unsigned int *) start, + (unsigned int *) end, + IMCR_L2WIBAR, IMCR_L2WIWC); +} + +void L2_cache_block_invalidate_nowait(unsigned int start, unsigned int end) +{ + cache_block_operation_nowait((unsigned int *) start, + (unsigned int *) end, + IMCR_L2IBAR, IMCR_L2IWC); +} + +void L2_cache_block_writeback_nowait(unsigned int start, unsigned int end) +{ + cache_block_operation_nowait((unsigned int *) start, + (unsigned int *) end, + IMCR_L2WBAR, IMCR_L2WWC); +} + +void L2_cache_block_writeback_invalidate_nowait(unsigned int start, + unsigned int end) +{ + cache_block_operation_nowait((unsigned int *) start, + (unsigned int *) end, + IMCR_L2WIBAR, IMCR_L2WIWC); +} + + +/* + * L1 and L2 caches configuration + */ +void __init c6x_cache_init(void) +{ + struct device_node *node; + + node = of_find_compatible_node(NULL, NULL, "ti,c64x+cache"); + if (!node) + return; + + cache_base = of_iomap(node, 0); + + of_node_put(node); + + if (!cache_base) + return; + + /* Set L2 caches on the the whole L2 SRAM memory */ + L2_cache_set_mode(L2MODE_SIZE); + + /* Enable L1 */ + L1_cache_on(); +} -- cgit v1.2.3 From 64236ac1444eecca4b7b51270879d58bd291c8c2 Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 11:12:27 -0400 Subject: C6X: loadable module support Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann --- arch/c6x/include/asm/module.h | 33 ++++++++++++ arch/c6x/kernel/c6x_ksyms.c | 66 +++++++++++++++++++++++ arch/c6x/kernel/module.c | 123 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 arch/c6x/include/asm/module.h create mode 100644 arch/c6x/kernel/c6x_ksyms.c create mode 100644 arch/c6x/kernel/module.c (limited to 'arch') diff --git a/arch/c6x/include/asm/module.h b/arch/c6x/include/asm/module.h new file mode 100644 index 000000000000..a453f9744f42 --- /dev/null +++ b/arch/c6x/include/asm/module.h @@ -0,0 +1,33 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) + * + * Updated for 2.6.34 by: Mark Salter (msalter@redhat.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 _ASM_C6X_MODULE_H +#define _ASM_C6X_MODULE_H + +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr +#define Elf_Addr Elf32_Addr +#define Elf_Word Elf32_Word + +/* + * This file contains the C6x architecture specific module code. + */ +struct mod_arch_specific { +}; + +struct loaded_sections { + unsigned int new_vaddr; + unsigned int loaded; +}; + +#endif /* _ASM_C6X_MODULE_H */ diff --git a/arch/c6x/kernel/c6x_ksyms.c b/arch/c6x/kernel/c6x_ksyms.c new file mode 100644 index 000000000000..0ba3e0bba3e1 --- /dev/null +++ b/arch/c6x/kernel/c6x_ksyms.c @@ -0,0 +1,66 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 +#include +#include + +/* + * libgcc functions - used internally by the compiler... + */ +extern int __c6xabi_divi(int dividend, int divisor); +EXPORT_SYMBOL(__c6xabi_divi); + +extern unsigned __c6xabi_divu(unsigned dividend, unsigned divisor); +EXPORT_SYMBOL(__c6xabi_divu); + +extern int __c6xabi_remi(int dividend, int divisor); +EXPORT_SYMBOL(__c6xabi_remi); + +extern unsigned __c6xabi_remu(unsigned dividend, unsigned divisor); +EXPORT_SYMBOL(__c6xabi_remu); + +extern int __c6xabi_divremi(int dividend, int divisor); +EXPORT_SYMBOL(__c6xabi_divremi); + +extern unsigned __c6xabi_divremu(unsigned dividend, unsigned divisor); +EXPORT_SYMBOL(__c6xabi_divremu); + +extern unsigned long long __c6xabi_mpyll(unsigned long long src1, + unsigned long long src2); +EXPORT_SYMBOL(__c6xabi_mpyll); + +extern long long __c6xabi_negll(long long src); +EXPORT_SYMBOL(__c6xabi_negll); + +extern unsigned long long __c6xabi_llshl(unsigned long long src1, uint src2); +EXPORT_SYMBOL(__c6xabi_llshl); + +extern long long __c6xabi_llshr(long long src1, uint src2); +EXPORT_SYMBOL(__c6xabi_llshr); + +extern unsigned long long __c6xabi_llshru(unsigned long long src1, uint src2); +EXPORT_SYMBOL(__c6xabi_llshru); + +extern void __c6xabi_strasgi(int *dst, const int *src, unsigned cnt); +EXPORT_SYMBOL(__c6xabi_strasgi); + +extern void __c6xabi_push_rts(void); +EXPORT_SYMBOL(__c6xabi_push_rts); + +extern void __c6xabi_pop_rts(void); +EXPORT_SYMBOL(__c6xabi_pop_rts); + +extern void __c6xabi_strasgi_64plus(int *dst, const int *src, unsigned cnt); +EXPORT_SYMBOL(__c6xabi_strasgi_64plus); + +/* lib functions */ +EXPORT_SYMBOL(memcpy); diff --git a/arch/c6x/kernel/module.c b/arch/c6x/kernel/module.c new file mode 100644 index 000000000000..5fc03f18f56c --- /dev/null +++ b/arch/c6x/kernel/module.c @@ -0,0 +1,123 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2005, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Thomas Charleux (thomas.charleux@jaluna.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 +#include +#include +#include + +static inline int fixup_pcr(u32 *ip, Elf32_Addr dest, u32 maskbits, int shift) +{ + u32 opcode; + long ep = (long)ip & ~31; + long delta = ((long)dest - ep) >> 2; + long mask = (1 << maskbits) - 1; + + if ((delta >> (maskbits - 1)) == 0 || + (delta >> (maskbits - 1)) == -1) { + opcode = *ip; + opcode &= ~(mask << shift); + opcode |= ((delta & mask) << shift); + *ip = opcode; + + pr_debug("REL PCR_S%d[%p] dest[%p] opcode[%08x]\n", + maskbits, ip, (void *)dest, opcode); + + return 0; + } + pr_err("PCR_S%d reloc %p -> %p out of range!\n", + maskbits, ip, (void *)dest); + + return -1; +} + +/* + * apply a RELA relocation + */ +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + Elf32_Rela *rel = (void *) sechdrs[relsec].sh_addr; + Elf_Sym *sym; + u32 *location, opcode; + unsigned int i; + Elf32_Addr v; + Elf_Addr offset = 0; + + pr_debug("Applying relocate section %u to %u with offset 0x%x\n", + relsec, sechdrs[relsec].sh_info, offset); + + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[i].r_offset - offset; + + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + sym = (Elf_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rel[i].r_info); + + /* this is the adjustment to be made */ + v = sym->st_value + rel[i].r_addend; + + switch (ELF32_R_TYPE(rel[i].r_info)) { + case R_C6000_ABS32: + pr_debug("RELA ABS32: [%p] = 0x%x\n", location, v); + *location = v; + break; + case R_C6000_ABS16: + pr_debug("RELA ABS16: [%p] = 0x%x\n", location, v); + *(u16 *)location = v; + break; + case R_C6000_ABS8: + pr_debug("RELA ABS8: [%p] = 0x%x\n", location, v); + *(u8 *)location = v; + break; + case R_C6000_ABS_L16: + opcode = *location; + opcode &= ~0x7fff80; + opcode |= ((v & 0xffff) << 7); + pr_debug("RELA ABS_L16[%p] v[0x%x] opcode[0x%x]\n", + location, v, opcode); + *location = opcode; + break; + case R_C6000_ABS_H16: + opcode = *location; + opcode &= ~0x7fff80; + opcode |= ((v >> 9) & 0x7fff80); + pr_debug("RELA ABS_H16[%p] v[0x%x] opcode[0x%x]\n", + location, v, opcode); + *location = opcode; + break; + case R_C6000_PCR_S21: + if (fixup_pcr(location, v, 21, 7)) + return -ENOEXEC; + break; + case R_C6000_PCR_S12: + if (fixup_pcr(location, v, 12, 16)) + return -ENOEXEC; + break; + case R_C6000_PCR_S10: + if (fixup_pcr(location, v, 10, 13)) + return -ENOEXEC; + break; + default: + pr_err("module %s: Unknown RELA relocation: %u\n", + me->name, ELF32_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + } + + return 0; +} -- cgit v1.2.3 From 52679b2d735492bce02503bafb333da87fae22c2 Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 11:13:21 -0400 Subject: C6X: ptrace support Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann --- arch/c6x/include/asm/ptrace.h | 174 +++++++++++++++++++++++++++++++++++++++ arch/c6x/kernel/ptrace.c | 187 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 361 insertions(+) create mode 100644 arch/c6x/include/asm/ptrace.h create mode 100644 arch/c6x/kernel/ptrace.c (limited to 'arch') diff --git a/arch/c6x/include/asm/ptrace.h b/arch/c6x/include/asm/ptrace.h new file mode 100644 index 000000000000..21e8d7931fe7 --- /dev/null +++ b/arch/c6x/include/asm/ptrace.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2004, 2006, 2009, 2010 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) + * + * Updated for 2.6.34: Mark Salter + * + * 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_C6X_PTRACE_H +#define _ASM_C6X_PTRACE_H + +#define BKPT_OPCODE 0x56454314 /* illegal opcode */ + +#ifdef _BIG_ENDIAN +#define PT_LO(odd, even) odd +#define PT_HI(odd, even) even +#else +#define PT_LO(odd, even) even +#define PT_HI(odd, even) odd +#endif + +#define PT_A4_ORG PT_LO(1, 0) +#define PT_TSR PT_HI(1, 0) +#define PT_ILC PT_LO(3, 2) +#define PT_RILC PT_HI(3, 2) +#define PT_CSR PT_LO(5, 4) +#define PT_PC PT_HI(5, 4) +#define PT_B16 PT_LO(7, 6) +#define PT_B17 PT_HI(7, 6) +#define PT_B18 PT_LO(9, 8) +#define PT_B19 PT_HI(9, 8) +#define PT_B20 PT_LO(11, 10) +#define PT_B21 PT_HI(11, 10) +#define PT_B22 PT_LO(13, 12) +#define PT_B23 PT_HI(13, 12) +#define PT_B24 PT_LO(15, 14) +#define PT_B25 PT_HI(15, 14) +#define PT_B26 PT_LO(17, 16) +#define PT_B27 PT_HI(17, 16) +#define PT_B28 PT_LO(19, 18) +#define PT_B29 PT_HI(19, 18) +#define PT_B30 PT_LO(21, 20) +#define PT_B31 PT_HI(21, 20) +#define PT_B0 PT_LO(23, 22) +#define PT_B1 PT_HI(23, 22) +#define PT_B2 PT_LO(25, 24) +#define PT_B3 PT_HI(25, 24) +#define PT_B4 PT_LO(27, 26) +#define PT_B5 PT_HI(27, 26) +#define PT_B6 PT_LO(29, 28) +#define PT_B7 PT_HI(29, 28) +#define PT_B8 PT_LO(31, 30) +#define PT_B9 PT_HI(31, 30) +#define PT_B10 PT_LO(33, 32) +#define PT_B11 PT_HI(33, 32) +#define PT_B12 PT_LO(35, 34) +#define PT_B13 PT_HI(35, 34) +#define PT_A16 PT_LO(37, 36) +#define PT_A17 PT_HI(37, 36) +#define PT_A18 PT_LO(39, 38) +#define PT_A19 PT_HI(39, 38) +#define PT_A20 PT_LO(41, 40) +#define PT_A21 PT_HI(41, 40) +#define PT_A22 PT_LO(43, 42) +#define PT_A23 PT_HI(43, 42) +#define PT_A24 PT_LO(45, 44) +#define PT_A25 PT_HI(45, 44) +#define PT_A26 PT_LO(47, 46) +#define PT_A27 PT_HI(47, 46) +#define PT_A28 PT_LO(49, 48) +#define PT_A29 PT_HI(49, 48) +#define PT_A30 PT_LO(51, 50) +#define PT_A31 PT_HI(51, 50) +#define PT_A0 PT_LO(53, 52) +#define PT_A1 PT_HI(53, 52) +#define PT_A2 PT_LO(55, 54) +#define PT_A3 PT_HI(55, 54) +#define PT_A4 PT_LO(57, 56) +#define PT_A5 PT_HI(57, 56) +#define PT_A6 PT_LO(59, 58) +#define PT_A7 PT_HI(59, 58) +#define PT_A8 PT_LO(61, 60) +#define PT_A9 PT_HI(61, 60) +#define PT_A10 PT_LO(63, 62) +#define PT_A11 PT_HI(63, 62) +#define PT_A12 PT_LO(65, 64) +#define PT_A13 PT_HI(65, 64) +#define PT_A14 PT_LO(67, 66) +#define PT_A15 PT_HI(67, 66) +#define PT_B14 PT_LO(69, 68) +#define PT_B15 PT_HI(69, 68) + +#define NR_PTREGS 70 + +#define PT_DP PT_B14 /* Data Segment Pointer (B14) */ +#define PT_SP PT_B15 /* Stack Pointer (B15) */ + +#ifndef __ASSEMBLY__ + +#ifdef _BIG_ENDIAN +#define REG_PAIR(odd, even) unsigned long odd; unsigned long even +#else +#define REG_PAIR(odd, even) unsigned long even; unsigned long odd +#endif + +/* + * this struct defines the way the registers are stored on the + * stack during a system call. fields defined with REG_PAIR + * are saved and restored using double-word memory operations + * which means the word ordering of the pair depends on endianess. + */ +struct pt_regs { + REG_PAIR(tsr, orig_a4); + REG_PAIR(rilc, ilc); + REG_PAIR(pc, csr); + + REG_PAIR(b17, b16); + REG_PAIR(b19, b18); + REG_PAIR(b21, b20); + REG_PAIR(b23, b22); + REG_PAIR(b25, b24); + REG_PAIR(b27, b26); + REG_PAIR(b29, b28); + REG_PAIR(b31, b30); + + REG_PAIR(b1, b0); + REG_PAIR(b3, b2); + REG_PAIR(b5, b4); + REG_PAIR(b7, b6); + REG_PAIR(b9, b8); + REG_PAIR(b11, b10); + REG_PAIR(b13, b12); + + REG_PAIR(a17, a16); + REG_PAIR(a19, a18); + REG_PAIR(a21, a20); + REG_PAIR(a23, a22); + REG_PAIR(a25, a24); + REG_PAIR(a27, a26); + REG_PAIR(a29, a28); + REG_PAIR(a31, a30); + + REG_PAIR(a1, a0); + REG_PAIR(a3, a2); + REG_PAIR(a5, a4); + REG_PAIR(a7, a6); + REG_PAIR(a9, a8); + REG_PAIR(a11, a10); + REG_PAIR(a13, a12); + + REG_PAIR(a15, a14); + REG_PAIR(sp, dp); +}; + +#ifdef __KERNEL__ + +#include + +#define user_mode(regs) ((((regs)->tsr) & 0x40) != 0) + +#define instruction_pointer(regs) ((regs)->pc) +#define profile_pc(regs) instruction_pointer(regs) +#define user_stack_pointer(regs) ((regs)->sp) + +extern void show_regs(struct pt_regs *); + +extern asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs); +extern asmlinkage void syscall_trace_exit(struct pt_regs *regs); + +#endif /* __KERNEL__ */ +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_C6X_PTRACE_H */ diff --git a/arch/c6x/kernel/ptrace.c b/arch/c6x/kernel/ptrace.c new file mode 100644 index 000000000000..3c494e84444d --- /dev/null +++ b/arch/c6x/kernel/ptrace.c @@ -0,0 +1,187 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) + * + * Updated for 2.6.34: Mark Salter + * + * 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 +#include +#include +#include + +#include + +#define PT_REG_SIZE (sizeof(struct pt_regs)) + +/* + * Called by kernel/ptrace.c when detaching. + */ +void ptrace_disable(struct task_struct *child) +{ + /* nothing to do */ +} + +/* + * Get a register number from live pt_regs for the specified task. + */ +static inline long get_reg(struct task_struct *task, int regno) +{ + long *addr = (long *)task_pt_regs(task); + + if (regno == PT_TSR || regno == PT_CSR) + return 0; + + return addr[regno]; +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, + int regno, + unsigned long data) +{ + unsigned long *addr = (unsigned long *)task_pt_regs(task); + + if (regno != PT_TSR && regno != PT_CSR) + addr[regno] = data; + + return 0; +} + +/* regset get/set implementations */ + +static int gpr_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, + regs, + 0, sizeof(*regs)); +} + +static int gpr_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + int ret; + struct pt_regs *regs = task_pt_regs(target); + + /* Don't copyin TSR or CSR */ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + ®s, + 0, PT_TSR * sizeof(long)); + if (ret) + return ret; + + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + PT_TSR * sizeof(long), + (PT_TSR + 1) * sizeof(long)); + if (ret) + return ret; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + ®s, + (PT_TSR + 1) * sizeof(long), + PT_CSR * sizeof(long)); + if (ret) + return ret; + + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + PT_CSR * sizeof(long), + (PT_CSR + 1) * sizeof(long)); + if (ret) + return ret; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + ®s, + (PT_CSR + 1) * sizeof(long), -1); + return ret; +} + +enum c6x_regset { + REGSET_GPR, +}; + +static const struct user_regset c6x_regsets[] = { + [REGSET_GPR] = { + .core_note_type = NT_PRSTATUS, + .n = ELF_NGREG, + .size = sizeof(u32), + .align = sizeof(u32), + .get = gpr_get, + .set = gpr_set + }, +}; + +static const struct user_regset_view user_c6x_native_view = { + .name = "tic6x", + .e_machine = EM_TI_C6000, + .regsets = c6x_regsets, + .n = ARRAY_SIZE(c6x_regsets), +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + return &user_c6x_native_view; +} + +/* + * Perform ptrace request + */ +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) +{ + int ret = 0; + + switch (request) { + /* + * write the word at location addr. + */ + case PTRACE_POKETEXT: + ret = generic_ptrace_pokedata(child, addr, data); + if (ret == 0 && request == PTRACE_POKETEXT) + flush_icache_range(addr, addr + 4); + break; + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + return ret; +} + +/* + * handle tracing of system call entry + * - return the revised system call number or ULONG_MAX to cause ENOSYS + */ +asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs) +{ + if (tracehook_report_syscall_entry(regs)) + /* tracing decided this syscall should not happen, so + * We'll return a bogus call number to get an ENOSYS + * error, but leave the original number in + * regs->orig_a4 + */ + return ULONG_MAX; + + return regs->b0; +} + +/* + * handle tracing of system call exit + */ +asmlinkage void syscall_trace_exit(struct pt_regs *regs) +{ + tracehook_report_syscall_exit(regs, 0); +} -- cgit v1.2.3 From a7f626c1948ab6178d2338831c5ffea7385e9f7f Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 11:14:47 -0400 Subject: C6X: headers Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann --- arch/c6x/include/asm/asm-offsets.h | 1 + arch/c6x/include/asm/bitops.h | 105 +++++++++++++++++++++++ arch/c6x/include/asm/byteorder.h | 12 +++ arch/c6x/include/asm/delay.h | 67 +++++++++++++++ arch/c6x/include/asm/elf.h | 113 ++++++++++++++++++++++++ arch/c6x/include/asm/ftrace.h | 6 ++ arch/c6x/include/asm/linkage.h | 30 +++++++ arch/c6x/include/asm/memblock.h | 4 + arch/c6x/include/asm/mmu.h | 18 ++++ arch/c6x/include/asm/mutex.h | 6 ++ arch/c6x/include/asm/page.h | 11 +++ arch/c6x/include/asm/pgtable.h | 81 ++++++++++++++++++ arch/c6x/include/asm/procinfo.h | 28 ++++++ arch/c6x/include/asm/prom.h | 1 + arch/c6x/include/asm/sections.h | 12 +++ arch/c6x/include/asm/setup.h | 32 +++++++ arch/c6x/include/asm/string.h | 21 +++++ arch/c6x/include/asm/swab.h | 54 ++++++++++++ arch/c6x/include/asm/syscall.h | 123 +++++++++++++++++++++++++++ arch/c6x/include/asm/system.h | 168 ++++++++++++++++++++++++++++++++++++ arch/c6x/include/asm/tlb.h | 8 ++ arch/c6x/include/asm/uaccess.h | 107 +++++++++++++++++++++++ arch/c6x/include/asm/unaligned.h | 170 +++++++++++++++++++++++++++++++++++++ 23 files changed, 1178 insertions(+) create mode 100644 arch/c6x/include/asm/asm-offsets.h create mode 100644 arch/c6x/include/asm/bitops.h create mode 100644 arch/c6x/include/asm/byteorder.h create mode 100644 arch/c6x/include/asm/delay.h create mode 100644 arch/c6x/include/asm/elf.h create mode 100644 arch/c6x/include/asm/ftrace.h create mode 100644 arch/c6x/include/asm/linkage.h create mode 100644 arch/c6x/include/asm/memblock.h create mode 100644 arch/c6x/include/asm/mmu.h create mode 100644 arch/c6x/include/asm/mutex.h create mode 100644 arch/c6x/include/asm/page.h create mode 100644 arch/c6x/include/asm/pgtable.h create mode 100644 arch/c6x/include/asm/procinfo.h create mode 100644 arch/c6x/include/asm/prom.h create mode 100644 arch/c6x/include/asm/sections.h create mode 100644 arch/c6x/include/asm/setup.h create mode 100644 arch/c6x/include/asm/string.h create mode 100644 arch/c6x/include/asm/swab.h create mode 100644 arch/c6x/include/asm/syscall.h create mode 100644 arch/c6x/include/asm/system.h create mode 100644 arch/c6x/include/asm/tlb.h create mode 100644 arch/c6x/include/asm/uaccess.h create mode 100644 arch/c6x/include/asm/unaligned.h (limited to 'arch') diff --git a/arch/c6x/include/asm/asm-offsets.h b/arch/c6x/include/asm/asm-offsets.h new file mode 100644 index 000000000000..d370ee36a182 --- /dev/null +++ b/arch/c6x/include/asm/asm-offsets.h @@ -0,0 +1 @@ +#include diff --git a/arch/c6x/include/asm/bitops.h b/arch/c6x/include/asm/bitops.h new file mode 100644 index 000000000000..39ab7e874d96 --- /dev/null +++ b/arch/c6x/include/asm/bitops.h @@ -0,0 +1,105 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_BITOPS_H +#define _ASM_C6X_BITOPS_H + +#ifdef __KERNEL__ + +#include + +#include +#include + +/* + * clear_bit() doesn't provide any barrier for the compiler. + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() + +/* + * We are lucky, DSP is perfect for bitops: do it in 3 cycles + */ + +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + * Note __ffs(0) = undef, __ffs(1) = 0, __ffs(0x80000000) = 31. + * + */ +static inline unsigned long __ffs(unsigned long x) +{ + asm (" bitr .M1 %0,%0\n" + " nop\n" + " lmbd .L1 1,%0,%0\n" + : "+a"(x)); + + return x; +} + +/* + * ffz - find first zero in word. + * @word: The word to search + * + * Undefined if no zero exists, so code should check against ~0UL first. + */ +#define ffz(x) __ffs(~(x)) + +/** + * fls - find last (most-significant) bit set + * @x: the word to search + * + * This is defined the same way as ffs. + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. + */ +static inline int fls(int x) +{ + if (!x) + return 0; + + asm (" lmbd .L1 1,%0,%0\n" : "+a"(x)); + + return 32 - x; +} + +/** + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + * Note ffs(0) = 0, ffs(1) = 1, ffs(0x80000000) = 32. + */ +static inline int ffs(int x) +{ + if (!x) + return 0; + + return __ffs(x) + 1; +} + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#endif /* __KERNEL__ */ +#endif /* _ASM_C6X_BITOPS_H */ diff --git a/arch/c6x/include/asm/byteorder.h b/arch/c6x/include/asm/byteorder.h new file mode 100644 index 000000000000..166038db342b --- /dev/null +++ b/arch/c6x/include/asm/byteorder.h @@ -0,0 +1,12 @@ +#ifndef _ASM_C6X_BYTEORDER_H +#define _ASM_C6X_BYTEORDER_H + +#include + +#ifdef _BIG_ENDIAN +#include +#else /* _BIG_ENDIAN */ +#include +#endif /* _BIG_ENDIAN */ + +#endif /* _ASM_BYTEORDER_H */ diff --git a/arch/c6x/include/asm/delay.h b/arch/c6x/include/asm/delay.h new file mode 100644 index 000000000000..f314c2e9eb54 --- /dev/null +++ b/arch/c6x/include/asm/delay.h @@ -0,0 +1,67 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_DELAY_H +#define _ASM_C6X_DELAY_H + +#include + +extern unsigned int ticks_per_ns_scaled; + +static inline void __delay(unsigned long loops) +{ + uint32_t tmp; + + /* 6 cycles per loop */ + asm volatile (" mv .s1 %0,%1\n" + "0: [%1] b .s1 0b\n" + " add .l1 -6,%0,%0\n" + " cmplt .l1 1,%0,%1\n" + " nop 3\n" + : "+a"(loops), "=A"(tmp)); +} + +static inline void _c6x_tickdelay(unsigned int x) +{ + uint32_t cnt, endcnt; + + asm volatile (" mvc .s2 TSCL,%0\n" + " add .s2x %0,%1,%2\n" + " || mvk .l2 1,B0\n" + "0: [B0] b .s2 0b\n" + " mvc .s2 TSCL,%0\n" + " sub .s2 %0,%2,%0\n" + " cmpgt .l2 0,%0,B0\n" + " nop 2\n" + : "=b"(cnt), "+a"(x), "=b"(endcnt) : : "B0"); +} + +/* use scaled math to avoid slow division */ +#define C6X_NDELAY_SCALE 10 + +static inline void _ndelay(unsigned int n) +{ + _c6x_tickdelay((ticks_per_ns_scaled * n) >> C6X_NDELAY_SCALE); +} + +static inline void _udelay(unsigned int n) +{ + while (n >= 10) { + _ndelay(10000); + n -= 10; + } + while (n-- > 0) + _ndelay(1000); +} + +#define udelay(x) _udelay((unsigned int)(x)) +#define ndelay(x) _ndelay((unsigned int)(x)) + +#endif /* _ASM_C6X_DELAY_H */ diff --git a/arch/c6x/include/asm/elf.h b/arch/c6x/include/asm/elf.h new file mode 100644 index 000000000000..d57865ba2c44 --- /dev/null +++ b/arch/c6x/include/asm/elf.h @@ -0,0 +1,113 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_ELF_H +#define _ASM_C6X_ELF_H + +/* + * ELF register definitions.. + */ +#include + +typedef unsigned long elf_greg_t; +typedef unsigned long elf_fpreg_t; + +#define ELF_NGREG 58 +#define ELF_NFPREG 1 + +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; +typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x)->e_machine == EM_TI_C6000) + +#define elf_check_const_displacement(x) (1) + +/* + * These are used to set parameters in the core dumps. + */ +#ifdef __LITTLE_ENDIAN__ +#define ELF_DATA ELFDATA2LSB +#else +#define ELF_DATA ELFDATA2MSB +#endif + +#define ELF_CLASS ELFCLASS32 +#define ELF_ARCH EM_TI_C6000 + +/* Nothing for now. Need to setup DP... */ +#define ELF_PLAT_INIT(_r) + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#define ELF_CORE_COPY_REGS(_dest, _regs) \ + memcpy((char *) &_dest, (char *) _regs, \ + sizeof(struct pt_regs)); + +/* This yields a mask that user programs can use to figure out what + instruction set this cpu supports. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. */ + +#define ELF_PLATFORM (NULL) + +#define SET_PERSONALITY(ex) set_personality(PER_LINUX) + +/* C6X specific section types */ +#define SHT_C6000_UNWIND 0x70000001 +#define SHT_C6000_PREEMPTMAP 0x70000002 +#define SHT_C6000_ATTRIBUTES 0x70000003 + +/* C6X specific DT_ tags */ +#define DT_C6000_DSBT_BASE 0x70000000 +#define DT_C6000_DSBT_SIZE 0x70000001 +#define DT_C6000_PREEMPTMAP 0x70000002 +#define DT_C6000_DSBT_INDEX 0x70000003 + +/* C6X specific relocs */ +#define R_C6000_NONE 0 +#define R_C6000_ABS32 1 +#define R_C6000_ABS16 2 +#define R_C6000_ABS8 3 +#define R_C6000_PCR_S21 4 +#define R_C6000_PCR_S12 5 +#define R_C6000_PCR_S10 6 +#define R_C6000_PCR_S7 7 +#define R_C6000_ABS_S16 8 +#define R_C6000_ABS_L16 9 +#define R_C6000_ABS_H16 10 +#define R_C6000_SBR_U15_B 11 +#define R_C6000_SBR_U15_H 12 +#define R_C6000_SBR_U15_W 13 +#define R_C6000_SBR_S16 14 +#define R_C6000_SBR_L16_B 15 +#define R_C6000_SBR_L16_H 16 +#define R_C6000_SBR_L16_W 17 +#define R_C6000_SBR_H16_B 18 +#define R_C6000_SBR_H16_H 19 +#define R_C6000_SBR_H16_W 20 +#define R_C6000_SBR_GOT_U15_W 21 +#define R_C6000_SBR_GOT_L16_W 22 +#define R_C6000_SBR_GOT_H16_W 23 +#define R_C6000_DSBT_INDEX 24 +#define R_C6000_PREL31 25 +#define R_C6000_COPY 26 +#define R_C6000_ALIGN 253 +#define R_C6000_FPHEAD 254 +#define R_C6000_NOCMP 255 + +#endif /*_ASM_C6X_ELF_H */ diff --git a/arch/c6x/include/asm/ftrace.h b/arch/c6x/include/asm/ftrace.h new file mode 100644 index 000000000000..3701958d3d1c --- /dev/null +++ b/arch/c6x/include/asm/ftrace.h @@ -0,0 +1,6 @@ +#ifndef _ASM_C6X_FTRACE_H +#define _ASM_C6X_FTRACE_H + +/* empty */ + +#endif /* _ASM_C6X_FTRACE_H */ diff --git a/arch/c6x/include/asm/linkage.h b/arch/c6x/include/asm/linkage.h new file mode 100644 index 000000000000..376925c47d57 --- /dev/null +++ b/arch/c6x/include/asm/linkage.h @@ -0,0 +1,30 @@ +#ifndef _ASM_C6X_LINKAGE_H +#define _ASM_C6X_LINKAGE_H + +#ifdef __ASSEMBLER__ + +#define __ALIGN .align 2 +#define __ALIGN_STR ".align 2" + +#ifndef __DSBT__ +#define ENTRY(name) \ + .global name @ \ + __ALIGN @ \ +name: +#else +#define ENTRY(name) \ + .global name @ \ + .hidden name @ \ + __ALIGN @ \ +name: +#endif + +#define ENDPROC(name) \ + .type name, @function @ \ + .size name, . - name + +#endif + +#include + +#endif /* _ASM_C6X_LINKAGE_H */ diff --git a/arch/c6x/include/asm/memblock.h b/arch/c6x/include/asm/memblock.h new file mode 100644 index 000000000000..1181a979a823 --- /dev/null +++ b/arch/c6x/include/asm/memblock.h @@ -0,0 +1,4 @@ +#ifndef _ASM_C6X_MEMBLOCK_H +#define _ASM_C6X_MEMBLOCK_H + +#endif /* _ASM_C6X_MEMBLOCK_H */ diff --git a/arch/c6x/include/asm/mmu.h b/arch/c6x/include/asm/mmu.h new file mode 100644 index 000000000000..41592bf16067 --- /dev/null +++ b/arch/c6x/include/asm/mmu.h @@ -0,0 +1,18 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_MMU_H +#define _ASM_C6X_MMU_H + +typedef struct { + unsigned long end_brk; +} mm_context_t; + +#endif /* _ASM_C6X_MMU_H */ diff --git a/arch/c6x/include/asm/mutex.h b/arch/c6x/include/asm/mutex.h new file mode 100644 index 000000000000..7a7248e0462d --- /dev/null +++ b/arch/c6x/include/asm/mutex.h @@ -0,0 +1,6 @@ +#ifndef _ASM_C6X_MUTEX_H +#define _ASM_C6X_MUTEX_H + +#include + +#endif /* _ASM_C6X_MUTEX_H */ diff --git a/arch/c6x/include/asm/page.h b/arch/c6x/include/asm/page.h new file mode 100644 index 000000000000..d18e2b0c7aea --- /dev/null +++ b/arch/c6x/include/asm/page.h @@ -0,0 +1,11 @@ +#ifndef _ASM_C6X_PAGE_H +#define _ASM_C6X_PAGE_H + +#define VM_DATA_DEFAULT_FLAGS \ + (VM_READ | VM_WRITE | \ + ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +#include + +#endif /* _ASM_C6X_PAGE_H */ diff --git a/arch/c6x/include/asm/pgtable.h b/arch/c6x/include/asm/pgtable.h new file mode 100644 index 000000000000..68c8af4f1f97 --- /dev/null +++ b/arch/c6x/include/asm/pgtable.h @@ -0,0 +1,81 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_PGTABLE_H +#define _ASM_C6X_PGTABLE_H + +#include + +#include +#include + +/* + * All 32bit addresses are effectively valid for vmalloc... + * Sort of meaningless for non-VM targets. + */ +#define VMALLOC_START 0 +#define VMALLOC_END 0xffffffff + +#define pgd_present(pgd) (1) +#define pgd_none(pgd) (0) +#define pgd_bad(pgd) (0) +#define pgd_clear(pgdp) +#define kern_addr_valid(addr) (1) + +#define pmd_offset(a, b) ((void *)0) +#define pmd_none(x) (!pmd_val(x)) +#define pmd_present(x) (pmd_val(x)) +#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) +#define pmd_bad(x) (pmd_val(x) & ~PAGE_MASK) + +#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */ +#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */ +#define pgprot_noncached(prot) (prot) + +extern void paging_init(void); + +#define __swp_type(x) (0) +#define __swp_offset(x) (0) +#define __swp_entry(typ, off) ((swp_entry_t) { ((typ) | ((off) << 7)) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +static inline int pte_file(pte_t pte) +{ + return 0; +} + +#define set_pte(pteptr, pteval) (*(pteptr) = pteval) +#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page) +extern unsigned long empty_zero_page; + +#define swapper_pg_dir ((pgd_t *) 0) + +/* + * No page table caches to initialise + */ +#define pgtable_cache_init() do { } while (0) +#define io_remap_pfn_range remap_pfn_range + +#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ + remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) + +#include + +#endif /* _ASM_C6X_PGTABLE_H */ diff --git a/arch/c6x/include/asm/procinfo.h b/arch/c6x/include/asm/procinfo.h new file mode 100644 index 000000000000..c139d1e71f87 --- /dev/null +++ b/arch/c6x/include/asm/procinfo.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Mark Salter (msalter@redhat.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 _ASM_C6X_PROCINFO_H +#define _ASM_C6X_PROCINFO_H + +#ifdef __KERNEL__ + +struct proc_info_list { + unsigned int cpu_val; + unsigned int cpu_mask; + const char *arch_name; + const char *elf_name; + unsigned int elf_hwcap; +}; + +#else /* __KERNEL__ */ +#include +#warning "Please include asm/elf.h instead" +#endif /* __KERNEL__ */ + +#endif /* _ASM_C6X_PROCINFO_H */ diff --git a/arch/c6x/include/asm/prom.h b/arch/c6x/include/asm/prom.h new file mode 100644 index 000000000000..b4ec95f07518 --- /dev/null +++ b/arch/c6x/include/asm/prom.h @@ -0,0 +1 @@ +/* dummy prom.h; here to make linux/of.h's #includes happy */ diff --git a/arch/c6x/include/asm/sections.h b/arch/c6x/include/asm/sections.h new file mode 100644 index 000000000000..f703989d837a --- /dev/null +++ b/arch/c6x/include/asm/sections.h @@ -0,0 +1,12 @@ +#ifndef _ASM_C6X_SECTIONS_H +#define _ASM_C6X_SECTIONS_H + +#include + +extern char _vectors_start[]; +extern char _vectors_end[]; + +extern char _data_lma[]; +extern char _fdt_start[], _fdt_end[]; + +#endif /* _ASM_C6X_SECTIONS_H */ diff --git a/arch/c6x/include/asm/setup.h b/arch/c6x/include/asm/setup.h new file mode 100644 index 000000000000..1808f279f82e --- /dev/null +++ b/arch/c6x/include/asm/setup.h @@ -0,0 +1,32 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_SETUP_H +#define _ASM_C6X_SETUP_H + +#define COMMAND_LINE_SIZE 1024 + +#ifndef __ASSEMBLY__ +extern char c6x_command_line[COMMAND_LINE_SIZE]; + +extern int c6x_add_memory(phys_addr_t start, unsigned long size); + +extern unsigned long ram_start; +extern unsigned long ram_end; + +extern int c6x_num_cores; +extern unsigned int c6x_silicon_rev; +extern unsigned int c6x_devstat; +extern unsigned char c6x_fuse_mac[6]; + +extern void machine_init(unsigned long dt_ptr); + +#endif /* !__ASSEMBLY__ */ +#endif /* _ASM_C6X_SETUP_H */ diff --git a/arch/c6x/include/asm/string.h b/arch/c6x/include/asm/string.h new file mode 100644 index 000000000000..b21517c80a17 --- /dev/null +++ b/arch/c6x/include/asm/string.h @@ -0,0 +1,21 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_STRING_H +#define _ASM_C6X_STRING_H + +#include +#include + +asmlinkage extern void *memcpy(void *to, const void *from, size_t n); + +#define __HAVE_ARCH_MEMCPY + +#endif /* _ASM_C6X_STRING_H */ diff --git a/arch/c6x/include/asm/swab.h b/arch/c6x/include/asm/swab.h new file mode 100644 index 000000000000..fd4bb0520e5e --- /dev/null +++ b/arch/c6x/include/asm/swab.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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_C6X_SWAB_H +#define _ASM_C6X_SWAB_H + +static inline __attribute_const__ __u16 __c6x_swab16(__u16 val) +{ + asm("swap4 .l1 %0,%0\n" : "+a"(val)); + return val; +} + +static inline __attribute_const__ __u32 __c6x_swab32(__u32 val) +{ + asm("swap4 .l1 %0,%0\n" + "swap2 .l1 %0,%0\n" + : "+a"(val)); + return val; +} + +static inline __attribute_const__ __u64 __c6x_swab64(__u64 val) +{ + asm(" swap2 .s1 %p0,%P0\n" + "|| swap2 .l1 %P0,%p0\n" + " swap4 .l1 %p0,%p0\n" + " swap4 .l1 %P0,%P0\n" + : "+a"(val)); + return val; +} + +static inline __attribute_const__ __u32 __c6x_swahw32(__u32 val) +{ + asm("swap2 .l1 %0,%0\n" : "+a"(val)); + return val; +} + +static inline __attribute_const__ __u32 __c6x_swahb32(__u32 val) +{ + asm("swap4 .l1 %0,%0\n" : "+a"(val)); + return val; +} + +#define __arch_swab16 __c6x_swab16 +#define __arch_swab32 __c6x_swab32 +#define __arch_swab64 __c6x_swab64 +#define __arch_swahw32 __c6x_swahw32 +#define __arch_swahb32 __c6x_swahb32 + +#endif /* _ASM_C6X_SWAB_H */ diff --git a/arch/c6x/include/asm/syscall.h b/arch/c6x/include/asm/syscall.h new file mode 100644 index 000000000000..ae2be315ee9c --- /dev/null +++ b/arch/c6x/include/asm/syscall.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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. + */ + +#ifndef __ASM_C6X_SYSCALL_H +#define __ASM_C6X_SYSCALL_H + +#include +#include + +static inline int syscall_get_nr(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->b0; +} + +static inline void syscall_rollback(struct task_struct *task, + struct pt_regs *regs) +{ + /* do nothing */ +} + +static inline long syscall_get_error(struct task_struct *task, + struct pt_regs *regs) +{ + return IS_ERR_VALUE(regs->a4) ? regs->a4 : 0; +} + +static inline long syscall_get_return_value(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->a4; +} + +static inline void syscall_set_return_value(struct task_struct *task, + struct pt_regs *regs, + int error, long val) +{ + regs->a4 = error ?: val; +} + +static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, unsigned int i, + unsigned int n, unsigned long *args) +{ + switch (i) { + case 0: + if (!n--) + break; + *args++ = regs->a4; + case 1: + if (!n--) + break; + *args++ = regs->b4; + case 2: + if (!n--) + break; + *args++ = regs->a6; + case 3: + if (!n--) + break; + *args++ = regs->b6; + case 4: + if (!n--) + break; + *args++ = regs->a8; + case 5: + if (!n--) + break; + *args++ = regs->b8; + case 6: + if (!n--) + break; + default: + BUG(); + } +} + +static inline void syscall_set_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + const unsigned long *args) +{ + switch (i) { + case 0: + if (!n--) + break; + regs->a4 = *args++; + case 1: + if (!n--) + break; + regs->b4 = *args++; + case 2: + if (!n--) + break; + regs->a6 = *args++; + case 3: + if (!n--) + break; + regs->b6 = *args++; + case 4: + if (!n--) + break; + regs->a8 = *args++; + case 5: + if (!n--) + break; + regs->a9 = *args++; + case 6: + if (!n) + break; + default: + BUG(); + } +} + +#endif /* __ASM_C6X_SYSCALLS_H */ diff --git a/arch/c6x/include/asm/system.h b/arch/c6x/include/asm/system.h new file mode 100644 index 000000000000..e076dc0eacc8 --- /dev/null +++ b/arch/c6x/include/asm/system.h @@ -0,0 +1,168 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 _ASM_C6X_SYSTEM_H +#define _ASM_C6X_SYSTEM_H + +#include +#include + +#define prepare_to_switch() do { } while (0) + +struct task_struct; +struct thread_struct; +asmlinkage void *__switch_to(struct thread_struct *prev, + struct thread_struct *next, + struct task_struct *tsk); + +#define switch_to(prev, next, last) \ + do { \ + current->thread.wchan = (u_long) __builtin_return_address(0); \ + (last) = __switch_to(&(prev)->thread, \ + &(next)->thread, (prev)); \ + mb(); \ + current->thread.wchan = 0; \ + } while (0) + +/* Reset the board */ +#define HARD_RESET_NOW() + +#define get_creg(reg) \ + ({ unsigned int __x; \ + asm volatile ("mvc .s2 " #reg ",%0\n" : "=b"(__x)); __x; }) + +#define set_creg(reg, v) \ + do { unsigned int __x = (unsigned int)(v); \ + asm volatile ("mvc .s2 %0," #reg "\n" : : "b"(__x)); \ + } while (0) + +#define or_creg(reg, n) \ + do { unsigned __x, __n = (unsigned)(n); \ + asm volatile ("mvc .s2 " #reg ",%0\n" \ + "or .l2 %1,%0,%0\n" \ + "mvc .s2 %0," #reg "\n" \ + "nop\n" \ + : "=&b"(__x) : "b"(__n)); \ + } while (0) + +#define and_creg(reg, n) \ + do { unsigned __x, __n = (unsigned)(n); \ + asm volatile ("mvc .s2 " #reg ",%0\n" \ + "and .l2 %1,%0,%0\n" \ + "mvc .s2 %0," #reg "\n" \ + "nop\n" \ + : "=&b"(__x) : "b"(__n)); \ + } while (0) + +#define get_coreid() (get_creg(DNUM) & 0xff) + +/* Set/get IST */ +#define set_ist(x) set_creg(ISTP, x) +#define get_ist() get_creg(ISTP) + +/* + * Exception management + */ +asmlinkage void enable_exception(void); +#define disable_exception() +#define get_except_type() get_creg(EFR) +#define ack_exception(type) set_creg(ECR, 1 << (type)) +#define get_iexcept() get_creg(IERR) +#define set_iexcept(mask) set_creg(IERR, (mask)) + +/* + * Misc. functions + */ +#define nop() asm("NOP\n"); +#define mb() barrier() +#define rmb() barrier() +#define wmb() barrier() +#define set_mb(var, value) do { var = value; mb(); } while (0) +#define set_wmb(var, value) do { var = value; wmb(); } while (0) + +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#define smp_read_barrier_depends() do { } while (0) + +#define xchg(ptr, x) \ + ((__typeof__(*(ptr)))__xchg((unsigned int)(x), (void *) (ptr), \ + sizeof(*(ptr)))) +#define tas(ptr) xchg((ptr), 1) + +unsigned int _lmbd(unsigned int, unsigned int); +unsigned int _bitr(unsigned int); + +struct __xchg_dummy { unsigned int a[100]; }; +#define __xg(x) ((volatile struct __xchg_dummy *)(x)) + +static inline unsigned int __xchg(unsigned int x, volatile void *ptr, int size) +{ + unsigned int tmp; + unsigned long flags; + + local_irq_save(flags); + + switch (size) { + case 1: + tmp = 0; + tmp = *((unsigned char *) ptr); + *((unsigned char *) ptr) = (unsigned char) x; + break; + case 2: + tmp = 0; + tmp = *((unsigned short *) ptr); + *((unsigned short *) ptr) = x; + break; + case 4: + tmp = 0; + tmp = *((unsigned int *) ptr); + *((unsigned int *) ptr) = x; + break; + } + local_irq_restore(flags); + return tmp; +} + +#include + +/* + * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make + * them available. + */ +#define cmpxchg_local(ptr, o, n) \ + ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), \ + (unsigned long)(o), \ + (unsigned long)(n), \ + sizeof(*(ptr)))) +#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) + +#include + +#define _extu(x, s, e) \ + ({ unsigned int __x; \ + asm volatile ("extu .S2 %3,%1,%2,%0\n" : \ + "=b"(__x) : "n"(s), "n"(e), "b"(x)); \ + __x; }) + + +extern unsigned int c6x_core_freq; + +struct pt_regs; + +extern void die(char *str, struct pt_regs *fp, int nr); +extern asmlinkage int process_exception(struct pt_regs *regs); +extern void time_init(void); +extern void free_initmem(void); + +extern void (*c6x_restart)(void); +extern void (*c6x_halt)(void); + +#endif /* _ASM_C6X_SYSTEM_H */ diff --git a/arch/c6x/include/asm/tlb.h b/arch/c6x/include/asm/tlb.h new file mode 100644 index 000000000000..8709e5e29d2d --- /dev/null +++ b/arch/c6x/include/asm/tlb.h @@ -0,0 +1,8 @@ +#ifndef _ASM_C6X_TLB_H +#define _ASM_C6X_TLB_H + +#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) + +#include + +#endif /* _ASM_C6X_TLB_H */ diff --git a/arch/c6x/include/asm/uaccess.h b/arch/c6x/include/asm/uaccess.h new file mode 100644 index 000000000000..453dd263bee3 --- /dev/null +++ b/arch/c6x/include/asm/uaccess.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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_C6X_UACCESS_H +#define _ASM_C6X_UACCESS_H + +#include +#include +#include + +#ifdef CONFIG_ACCESS_CHECK +#define __access_ok _access_ok +#endif + +/* + * __copy_from_user/copy_to_user are based on ones in asm-generic/uaccess.h + * + * C6X supports unaligned 32 and 64 bit loads and stores. + */ +static inline __must_check long __copy_from_user(void *to, + const void __user *from, unsigned long n) +{ + u32 tmp32; + u64 tmp64; + + if (__builtin_constant_p(n)) { + switch (n) { + case 1: + *(u8 *)to = *(u8 __force *)from; + return 0; + case 4: + asm volatile ("ldnw .d1t1 *%2,%0\n" + "nop 4\n" + "stnw .d1t1 %0,*%1\n" + : "=&a"(tmp32) + : "A"(to), "a"(from) + : "memory"); + return 0; + case 8: + asm volatile ("ldndw .d1t1 *%2,%0\n" + "nop 4\n" + "stndw .d1t1 %0,*%1\n" + : "=&a"(tmp64) + : "a"(to), "a"(from) + : "memory"); + return 0; + default: + break; + } + } + + memcpy(to, (const void __force *)from, n); + return 0; +} + +static inline __must_check long __copy_to_user(void __user *to, + const void *from, unsigned long n) +{ + u32 tmp32; + u64 tmp64; + + if (__builtin_constant_p(n)) { + switch (n) { + case 1: + *(u8 __force *)to = *(u8 *)from; + return 0; + case 4: + asm volatile ("ldnw .d1t1 *%2,%0\n" + "nop 4\n" + "stnw .d1t1 %0,*%1\n" + : "=&a"(tmp32) + : "a"(to), "a"(from) + : "memory"); + return 0; + case 8: + asm volatile ("ldndw .d1t1 *%2,%0\n" + "nop 4\n" + "stndw .d1t1 %0,*%1\n" + : "=&a"(tmp64) + : "a"(to), "a"(from) + : "memory"); + return 0; + default: + break; + } + } + + memcpy((void __force *)to, from, n); + return 0; +} + +#define __copy_to_user __copy_to_user +#define __copy_from_user __copy_from_user + +extern int _access_ok(unsigned long addr, unsigned long size); +#ifdef CONFIG_ACCESS_CHECK +#define __access_ok _access_ok +#endif + +#include + +#endif /* _ASM_C6X_UACCESS_H */ diff --git a/arch/c6x/include/asm/unaligned.h b/arch/c6x/include/asm/unaligned.h new file mode 100644 index 000000000000..b976cb740eaa --- /dev/null +++ b/arch/c6x/include/asm/unaligned.h @@ -0,0 +1,170 @@ +/* + * Port on Texas Instruments TMS320C6x architecture + * + * Copyright (C) 2004, 2009, 2010 Texas Instruments Incorporated + * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) + * Rewritten for 2.6.3x: Mark Salter + * + * 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_C6X_UNALIGNED_H +#define _ASM_C6X_UNALIGNED_H + +#include + +/* + * The C64x+ can do unaligned word and dword accesses in hardware + * using special load/store instructions. + */ + +static inline u16 get_unaligned_le16(const void *p) +{ + const u8 *_p = p; + return _p[0] | _p[1] << 8; +} + +static inline u16 get_unaligned_be16(const void *p) +{ + const u8 *_p = p; + return _p[0] << 8 | _p[1]; +} + +static inline void put_unaligned_le16(u16 val, void *p) +{ + u8 *_p = p; + _p[0] = val; + _p[1] = val >> 8; +} + +static inline void put_unaligned_be16(u16 val, void *p) +{ + u8 *_p = p; + _p[0] = val >> 8; + _p[1] = val; +} + +static inline u32 get_unaligned32(const void *p) +{ + u32 val = (u32) p; + asm (" ldnw .d1t1 *%0,%0\n" + " nop 4\n" + : "+a"(val)); + return val; +} + +static inline void put_unaligned32(u32 val, void *p) +{ + asm volatile (" stnw .d2t1 %0,*%1\n" + : : "a"(val), "b"(p) : "memory"); +} + +static inline u64 get_unaligned64(const void *p) +{ + u64 val; + asm volatile (" ldndw .d1t1 *%1,%0\n" + " nop 4\n" + : "=a"(val) : "a"(p)); + return val; +} + +static inline void put_unaligned64(u64 val, const void *p) +{ + asm volatile (" stndw .d2t1 %0,*%1\n" + : : "a"(val), "b"(p) : "memory"); +} + +#ifdef CONFIG_CPU_BIG_ENDIAN + +#define get_unaligned_le32(p) __swab32(get_unaligned32(p)) +#define get_unaligned_le64(p) __swab64(get_unaligned64(p)) +#define get_unaligned_be32(p) get_unaligned32(p) +#define get_unaligned_be64(p) get_unaligned64(p) +#define put_unaligned_le32(v, p) put_unaligned32(__swab32(v), (p)) +#define put_unaligned_le64(v, p) put_unaligned64(__swab64(v), (p)) +#define put_unaligned_be32(v, p) put_unaligned32((v), (p)) +#define put_unaligned_be64(v, p) put_unaligned64((v), (p)) +#define get_unaligned __get_unaligned_be +#define put_unaligned __put_unaligned_be + +#else + +#define get_unaligned_le32(p) get_unaligned32(p) +#define get_unaligned_le64(p) get_unaligned64(p) +#define get_unaligned_be32(p) __swab32(get_unaligned32(p)) +#define get_unaligned_be64(p) __swab64(get_unaligned64(p)) +#define put_unaligned_le32(v, p) put_unaligned32((v), (p)) +#define put_unaligned_le64(v, p) put_unaligned64((v), (p)) +#define put_unaligned_be32(v, p) put_unaligned32(__swab32(v), (p)) +#define put_unaligned_be64(v, p) put_unaligned64(__swab64(v), (p)) +#define get_unaligned __get_unaligned_le +#define put_unaligned __put_unaligned_le + +#endif + +/* + * Cause a link-time error if we try an unaligned access other than + * 1,2,4 or 8 bytes long + */ +extern int __bad_unaligned_access_size(void); + +#define __get_unaligned_le(ptr) (typeof(*(ptr)))({ \ + sizeof(*(ptr)) == 1 ? *(ptr) : \ + (sizeof(*(ptr)) == 2 ? get_unaligned_le16((ptr)) : \ + (sizeof(*(ptr)) == 4 ? get_unaligned_le32((ptr)) : \ + (sizeof(*(ptr)) == 8 ? get_unaligned_le64((ptr)) : \ + __bad_unaligned_access_size()))); \ + }) + +#define __get_unaligned_be(ptr) (__force typeof(*(ptr)))({ \ + sizeof(*(ptr)) == 1 ? *(ptr) : \ + (sizeof(*(ptr)) == 2 ? get_unaligned_be16((ptr)) : \ + (sizeof(*(ptr)) == 4 ? get_unaligned_be32((ptr)) : \ + (sizeof(*(ptr)) == 8 ? get_unaligned_be64((ptr)) : \ + __bad_unaligned_access_size()))); \ + }) + +#define __put_unaligned_le(val, ptr) ({ \ + void *__gu_p = (ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: \ + *(u8 *)__gu_p = (__force u8)(val); \ + break; \ + case 2: \ + put_unaligned_le16((__force u16)(val), __gu_p); \ + break; \ + case 4: \ + put_unaligned_le32((__force u32)(val), __gu_p); \ + break; \ + case 8: \ + put_unaligned_le64((__force u64)(val), __gu_p); \ + break; \ + default: \ + __bad_unaligned_access_size(); \ + break; \ + } \ + (void)0; }) + +#define __put_unaligned_be(val, ptr) ({ \ + void *__gu_p = (ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: \ + *(u8 *)__gu_p = (__force u8)(val); \ + break; \ + case 2: \ + put_unaligned_be16((__force u16)(val), __gu_p); \ + break; \ + case 4: \ + put_unaligned_be32((__force u32)(val), __gu_p); \ + break; \ + case 8: \ + put_unaligned_be64((__force u64)(val), __gu_p); \ + break; \ + default: \ + __bad_unaligned_access_size(); \ + break; \ + } \ + (void)0; }) + +#endif /* _ASM_C6X_UNALIGNED_H */ -- cgit v1.2.3 From 09831ca73443bd819ad7993db5409b19c899ba33 Mon Sep 17 00:00:00 2001 From: Aurelien Jacquiot Date: Tue, 4 Oct 2011 11:15:51 -0400 Subject: C6X: library code Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter Signed-off-by: Aurelien Jacquiot Signed-off-by: Mark Salter Acked-by: Arnd Bergmann --- arch/c6x/include/asm/checksum.h | 34 ++++ arch/c6x/lib/checksum.c | 36 ++++ arch/c6x/lib/csum_64plus.S | 419 ++++++++++++++++++++++++++++++++++++++++ arch/c6x/lib/divi.S | 53 +++++ arch/c6x/lib/divremi.S | 46 +++++ arch/c6x/lib/divremu.S | 87 +++++++++ arch/c6x/lib/divu.S | 98 ++++++++++ arch/c6x/lib/llshl.S | 37 ++++ arch/c6x/lib/llshr.S | 38 ++++ arch/c6x/lib/llshru.S | 38 ++++ arch/c6x/lib/memcpy_64plus.S | 46 +++++ arch/c6x/lib/mpyll.S | 49 +++++ arch/c6x/lib/negll.S | 31 +++ arch/c6x/lib/pop_rts.S | 32 +++ arch/c6x/lib/push_rts.S | 31 +++ arch/c6x/lib/remi.S | 64 ++++++ arch/c6x/lib/remu.S | 82 ++++++++ arch/c6x/lib/strasgi.S | 89 +++++++++ arch/c6x/lib/strasgi_64plus.S | 39 ++++ 19 files changed, 1349 insertions(+) create mode 100644 arch/c6x/include/asm/checksum.h create mode 100644 arch/c6x/lib/checksum.c create mode 100644 arch/c6x/lib/csum_64plus.S create mode 100644 arch/c6x/lib/divi.S create mode 100644 arch/c6x/lib/divremi.S create mode 100644 arch/c6x/lib/divremu.S create mode 100644 arch/c6x/lib/divu.S create mode 100644 arch/c6x/lib/llshl.S create mode 100644 arch/c6x/lib/llshr.S create mode 100644 arch/c6x/lib/llshru.S create mode 100644 arch/c6x/lib/memcpy_64plus.S create mode 100644 arch/c6x/lib/mpyll.S create mode 100644 arch/c6x/lib/negll.S create mode 100644 arch/c6x/lib/pop_rts.S create mode 100644 arch/c6x/lib/push_rts.S create mode 100644 arch/c6x/lib/remi.S create mode 100644 arch/c6x/lib/remu.S create mode 100644 arch/c6x/lib/strasgi.S create mode 100644 arch/c6x/lib/strasgi_64plus.S (limited to 'arch') diff --git a/arch/c6x/include/asm/checksum.h b/arch/c6x/include/asm/checksum.h new file mode 100644 index 000000000000..7246816d6e4d --- /dev/null +++ b/arch/c6x/include/asm/checksum.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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_C6X_CHECKSUM_H +#define _ASM_C6X_CHECKSUM_H + +static inline __wsum +csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, + unsigned short proto, __wsum sum) +{ + unsigned long long tmp; + + asm ("add .d1 %1,%5,%1\n" + "|| addu .l1 %3,%4,%0\n" + "addu .l1 %2,%0,%0\n" +#ifndef CONFIG_CPU_BIG_ENDIAN + "|| shl .s1 %1,8,%1\n" +#endif + "addu .l1 %1,%0,%0\n" + "add .l1 %P0,%p0,%2\n" + : "=&a"(tmp), "+a"(len), "+a"(sum) + : "a" (saddr), "a" (daddr), "a" (proto)); + return sum; +} +#define csum_tcpudp_nofold csum_tcpudp_nofold + +#include + +#endif /* _ASM_C6X_CHECKSUM_H */ diff --git a/arch/c6x/lib/checksum.c b/arch/c6x/lib/checksum.c new file mode 100644 index 000000000000..67cc93b0b932 --- /dev/null +++ b/arch/c6x/lib/checksum.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 + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include + +#include + +/* + * copy from fs while checksumming, otherwise like csum_partial + */ +__wsum +csum_partial_copy_from_user(const void __user *src, void *dst, int len, + __wsum sum, int *csum_err) +{ + int missing; + + missing = __copy_from_user(dst, src, len); + if (missing) { + memset(dst + len - missing, 0, missing); + *csum_err = -EFAULT; + } else + *csum_err = 0; + + return csum_partial(dst, len, sum); +} +EXPORT_SYMBOL(csum_partial_copy_from_user); + +/* These are from csum_64plus.S */ +EXPORT_SYMBOL(csum_partial); +EXPORT_SYMBOL(csum_partial_copy); +EXPORT_SYMBOL(ip_compute_csum); +EXPORT_SYMBOL(ip_fast_csum); diff --git a/arch/c6x/lib/csum_64plus.S b/arch/c6x/lib/csum_64plus.S new file mode 100644 index 000000000000..6d2589647227 --- /dev/null +++ b/arch/c6x/lib/csum_64plus.S @@ -0,0 +1,419 @@ +; +; linux/arch/c6x/lib/csum_64plus.s +; +; Port on Texas Instruments TMS320C6x architecture +; +; Copyright (C) 2006, 2009, 2010, 2011 Texas Instruments Incorporated +; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 + +; +;unsigned int csum_partial_copy(const char *src, char * dst, +; int len, int sum) +; +; A4: src +; B4: dst +; A6: len +; B6: sum +; return csum in A4 +; + + .text +ENTRY(csum_partial_copy) + MVC .S2 ILC,B30 + + MV .D1X B6,A31 ; given csum + ZERO .D1 A9 ; csum (a side) +|| ZERO .D2 B9 ; csum (b side) +|| SHRU .S2X A6,2,B5 ; len / 4 + + ;; Check alignment and size + AND .S1 3,A4,A1 +|| AND .S2 3,B4,B0 + OR .L2X B0,A1,B0 ; non aligned condition +|| MVC .S2 B5,ILC +|| MVK .D2 1,B2 +|| MV .D1X B5,A1 ; words condition + [!A1] B .S1 L8 + [B0] BNOP .S1 L6,5 + + SPLOOP 1 + + ;; Main loop for aligned words + LDW .D1T1 *A4++,A7 + NOP 4 + MV .S2X A7,B7 +|| EXTU .S1 A7,0,16,A16 + STW .D2T2 B7,*B4++ +|| MPYU .M2 B7,B2,B8 +|| ADD .L1 A16,A9,A9 + NOP + SPKERNEL 8,0 +|| ADD .L2 B8,B9,B9 + + ZERO .D1 A1 +|| ADD .L1X A9,B9,A9 ; add csum from a and b sides + +L6: + [!A1] BNOP .S1 L8,5 + + ;; Main loop for non-aligned words + SPLOOP 2 + || MVK .L1 1,A2 + + LDNW .D1T1 *A4++,A7 + NOP 3 + + NOP + MV .S2X A7,B7 + || EXTU .S1 A7,0,16,A16 + || MPYU .M1 A7,A2,A8 + + ADD .L1 A16,A9,A9 + SPKERNEL 6,0 + || STNW .D2T2 B7,*B4++ + || ADD .L1 A8,A9,A9 + +L8: AND .S2X 2,A6,B5 + CMPGT .L2 B5,0,B0 + [!B0] BNOP .S1 L82,4 + + ;; Manage half-word + ZERO .L1 A7 +|| ZERO .D1 A8 + +#ifdef CONFIG_CPU_BIG_ENDIAN + + LDBU .D1T1 *A4++,A7 + LDBU .D1T1 *A4++,A8 + NOP 3 + SHL .S1 A7,8,A0 + ADD .S1 A8,A9,A9 + STB .D2T1 A7,*B4++ +|| ADD .S1 A0,A9,A9 + STB .D2T1 A8,*B4++ + +#else + + LDBU .D1T1 *A4++,A7 + LDBU .D1T1 *A4++,A8 + NOP 3 + ADD .S1 A7,A9,A9 + SHL .S1 A8,8,A0 + + STB .D2T1 A7,*B4++ +|| ADD .S1 A0,A9,A9 + STB .D2T1 A8,*B4++ + +#endif + + ;; Manage eventually the last byte +L82: AND .S2X 1,A6,B0 + [!B0] BNOP .S1 L9,5 + +|| ZERO .L1 A7 + +L83: LDBU .D1T1 *A4++,A7 + NOP 4 + + MV .L2X A7,B7 + +#ifdef CONFIG_CPU_BIG_ENDIAN + + STB .D2T2 B7,*B4++ +|| SHL .S1 A7,8,A7 + ADD .S1 A7,A9,A9 + +#else + + STB .D2T2 B7,*B4++ +|| ADD .S1 A7,A9,A9 + +#endif + + ;; Fold the csum +L9: SHRU .S2X A9,16,B0 + [!B0] BNOP .S1 L10,5 + +L91: SHRU .S2X A9,16,B4 +|| EXTU .S1 A9,16,16,A3 + ADD .D1X A3,B4,A9 + + SHRU .S1 A9,16,A0 + [A0] BNOP .S1 L91,5 + +L10: ADD .D1 A31,A9,A9 + MV .D1 A9,A4 + + BNOP .S2 B3,4 + MVC .S2 B30,ILC +ENDPROC(csum_partial_copy) + +; +;unsigned short +;ip_fast_csum(unsigned char *iph, unsigned int ihl) +;{ +; unsigned int checksum = 0; +; unsigned short *tosum = (unsigned short *) iph; +; int len; +; +; len = ihl*4; +; +; if (len <= 0) +; return 0; +; +; while(len) { +; len -= 2; +; checksum += *tosum++; +; } +; if (len & 1) +; checksum += *(unsigned char*) tosum; +; +; while(checksum >> 16) +; checksum = (checksum & 0xffff) + (checksum >> 16); +; +; return ~checksum; +;} +; +; A4: iph +; B4: ihl +; return checksum in A4 +; + .text + +ENTRY(ip_fast_csum) + ZERO .D1 A5 + || MVC .S2 ILC,B30 + SHL .S2 B4,2,B0 + CMPGT .L2 B0,0,B1 + [!B1] BNOP .S1 L15,4 + [!B1] ZERO .D1 A3 + + [!B0] B .S1 L12 + SHRU .S2 B0,1,B0 + MVC .S2 B0,ILC + NOP 3 + + SPLOOP 1 + LDHU .D1T1 *A4++,A3 + NOP 3 + NOP + SPKERNEL 5,0 + || ADD .L1 A3,A5,A5 + +L12: SHRU .S1 A5,16,A0 + [!A0] BNOP .S1 L14,5 + +L13: SHRU .S2X A5,16,B4 + EXTU .S1 A5,16,16,A3 + ADD .D1X A3,B4,A5 + SHRU .S1 A5,16,A0 + [A0] BNOP .S1 L13,5 + +L14: NOT .D1 A5,A3 + EXTU .S1 A3,16,16,A3 + +L15: BNOP .S2 B3,3 + MVC .S2 B30,ILC + MV .D1 A3,A4 +ENDPROC(ip_fast_csum) + +; +;unsigned short +;do_csum(unsigned char *buff, unsigned int len) +;{ +; int odd, count; +; unsigned int result = 0; +; +; if (len <= 0) +; goto out; +; odd = 1 & (unsigned long) buff; +; if (odd) { +;#ifdef __LITTLE_ENDIAN +; result += (*buff << 8); +;#else +; result = *buff; +;#endif +; len--; +; buff++; +; } +; count = len >> 1; /* nr of 16-bit words.. */ +; if (count) { +; if (2 & (unsigned long) buff) { +; result += *(unsigned short *) buff; +; count--; +; len -= 2; +; buff += 2; +; } +; count >>= 1; /* nr of 32-bit words.. */ +; if (count) { +; unsigned int carry = 0; +; do { +; unsigned int w = *(unsigned int *) buff; +; count--; +; buff += 4; +; result += carry; +; result += w; +; carry = (w > result); +; } while (count); +; result += carry; +; result = (result & 0xffff) + (result >> 16); +; } +; if (len & 2) { +; result += *(unsigned short *) buff; +; buff += 2; +; } +; } +; if (len & 1) +;#ifdef __LITTLE_ENDIAN +; result += *buff; +;#else +; result += (*buff << 8); +;#endif +; result = (result & 0xffff) + (result >> 16); +; /* add up carry.. */ +; result = (result & 0xffff) + (result >> 16); +; if (odd) +; result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +;out: +; return result; +;} +; +; A4: buff +; B4: len +; return checksum in A4 +; + +ENTRY(do_csum) + CMPGT .L2 B4,0,B0 + [!B0] BNOP .S1 L26,3 + EXTU .S1 A4,31,31,A0 + + MV .L1 A0,A3 +|| MV .S1X B3,A5 +|| MV .L2 B4,B3 +|| ZERO .D1 A1 + +#ifdef CONFIG_CPU_BIG_ENDIAN + [A0] SUB .L2 B3,1,B3 +|| [A0] LDBU .D1T1 *A4++,A1 +#else + [!A0] BNOP .S1 L21,5 +|| [A0] LDBU .D1T1 *A4++,A0 + SUB .L2 B3,1,B3 +|| SHL .S1 A0,8,A1 +L21: +#endif + SHR .S2 B3,1,B0 + [!B0] BNOP .S1 L24,3 + MVK .L1 2,A0 + AND .L1 A4,A0,A0 + + [!A0] BNOP .S1 L22,5 +|| [A0] LDHU .D1T1 *A4++,A0 + SUB .L2 B0,1,B0 +|| SUB .S2 B3,2,B3 +|| ADD .L1 A0,A1,A1 +L22: + SHR .S2 B0,1,B0 +|| ZERO .L1 A0 + + [!B0] BNOP .S1 L23,5 +|| [B0] MVC .S2 B0,ILC + + SPLOOP 3 + SPMASK L1 +|| MV .L1 A1,A2 +|| LDW .D1T1 *A4++,A1 + + NOP 4 + ADD .L1 A0,A1,A0 + ADD .L1 A2,A0,A2 + + SPKERNEL 1,2 +|| CMPGTU .L1 A1,A2,A0 + + ADD .L1 A0,A2,A6 + EXTU .S1 A6,16,16,A7 + SHRU .S2X A6,16,B0 + NOP 1 + ADD .L1X A7,B0,A1 +L23: + MVK .L2 2,B0 + AND .L2 B3,B0,B0 + [B0] LDHU .D1T1 *A4++,A0 + NOP 4 + [B0] ADD .L1 A0,A1,A1 +L24: + EXTU .S2 B3,31,31,B0 +#ifdef CONFIG_CPU_BIG_ENDIAN + [!B0] BNOP .S1 L25,4 +|| [B0] LDBU .D1T1 *A4,A0 + SHL .S1 A0,8,A0 + ADD .L1 A0,A1,A1 +L25: +#else + [B0] LDBU .D1T1 *A4,A0 + NOP 4 + [B0] ADD .L1 A0,A1,A1 +#endif + EXTU .S1 A1,16,16,A0 + SHRU .S2X A1,16,B0 + NOP 1 + ADD .L1X A0,B0,A0 + SHRU .S1 A0,16,A1 + ADD .L1 A0,A1,A0 + EXTU .S1 A0,16,16,A1 + EXTU .S1 A1,16,24,A2 + + EXTU .S1 A1,24,16,A0 +|| MV .L2X A3,B0 + + [B0] OR .L1 A0,A2,A1 +L26: + NOP 1 + BNOP .S2X A5,4 + MV .L1 A1,A4 +ENDPROC(do_csum) + +;__wsum csum_partial(const void *buff, int len, __wsum wsum) +;{ +; unsigned int sum = (__force unsigned int)wsum; +; unsigned int result = do_csum(buff, len); +; +; /* add in old sum, and carry.. */ +; result += sum; +; if (sum > result) +; result += 1; +; return (__force __wsum)result; +;} +; +ENTRY(csum_partial) + MV .L1X B3,A9 +|| CALLP .S2 do_csum,B3 +|| MV .S1 A6,A8 + BNOP .S2X A9,2 + ADD .L1 A8,A4,A1 + CMPGTU .L1 A8,A1,A0 + ADD .L1 A1,A0,A4 +ENDPROC(csum_partial) + +;unsigned short +;ip_compute_csum(unsigned char *buff, unsigned int len) +; +; A4: buff +; B4: len +; return checksum in A4 + +ENTRY(ip_compute_csum) + MV .L1X B3,A9 +|| CALLP .S2 do_csum,B3 + BNOP .S2X A9,3 + NOT .S1 A4,A4 + CLR .S1 A4,16,31,A4 +ENDPROC(ip_compute_csum) diff --git a/arch/c6x/lib/divi.S b/arch/c6x/lib/divi.S new file mode 100644 index 000000000000..4bde924f2a98 --- /dev/null +++ b/arch/c6x/lib/divi.S @@ -0,0 +1,53 @@ +;; Copyright 2010 Free Software Foundation, Inc. +;; Contributed by Bernd Schmidt . +;; +;; 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 + + ;; ABI considerations for the divide functions + ;; The following registers are call-used: + ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5 + ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4 + ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4 + ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4 + ;; + ;; In our implementation, divu and remu are leaf functions, + ;; while both divi and remi call into divu. + ;; A0 is not clobbered by any of the functions. + ;; divu does not clobber B2 either, which is taken advantage of + ;; in remi. + ;; divi uses B5 to hold the original return address during + ;; the call to divu. + ;; remi uses B2 and A5 to hold the input values during the + ;; call to divu. It stores B3 in on the stack. + + .text +ENTRY(__c6xabi_divi) + call .s2 __c6xabi_divu +|| mv .d2 B3, B5 +|| cmpgt .l1 0, A4, A1 +|| cmpgt .l2 0, B4, B1 + + [A1] neg .l1 A4, A4 +|| [B1] neg .l2 B4, B4 +|| xor .s1x A1, B1, A1 + [A1] addkpc .s2 _divu_ret, B3, 4 +_divu_ret: + neg .l1 A4, A4 +|| mv .l2 B3,B5 +|| ret .s2 B5 + nop 5 +ENDPROC(__c6xabi_divi) diff --git a/arch/c6x/lib/divremi.S b/arch/c6x/lib/divremi.S new file mode 100644 index 000000000000..64bc5aa95ad3 --- /dev/null +++ b/arch/c6x/lib/divremi.S @@ -0,0 +1,46 @@ +;; Copyright 2010 Free Software Foundation, Inc. +;; Contributed by Bernd Schmidt . +;; +;; 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 + + .text +ENTRY(__c6xabi_divremi) + stw .d2t2 B3, *B15--[2] +|| cmpgt .l1 0, A4, A1 +|| cmpgt .l2 0, B4, B2 +|| mv .s1 A4, A5 +|| call .s2 __c6xabi_divu + + [A1] neg .l1 A4, A4 +|| [B2] neg .l2 B4, B4 +|| xor .s2x B2, A1, B0 +|| mv .d2 B4, B2 + + [B0] addkpc .s2 _divu_ret_1, B3, 1 + [!B0] addkpc .s2 _divu_ret_2, B3, 1 + nop 2 +_divu_ret_1: + neg .l1 A4, A4 +_divu_ret_2: + ldw .d2t2 *++B15[2], B3 + + mpy32 .m1x A4, B2, A6 + nop 3 + ret .s2 B3 + sub .l1 A5, A6, A5 + nop 4 +ENDPROC(__c6xabi_divremi) diff --git a/arch/c6x/lib/divremu.S b/arch/c6x/lib/divremu.S new file mode 100644 index 000000000000..caa9f23ee167 --- /dev/null +++ b/arch/c6x/lib/divremu.S @@ -0,0 +1,87 @@ +;; Copyright 2011 Free Software Foundation, Inc. +;; Contributed by Bernd Schmidt . +;; +;; 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 + + .text +ENTRY(__c6xabi_divremu) + ;; We use a series of up to 31 subc instructions. First, we find + ;; out how many leading zero bits there are in the divisor. This + ;; gives us both a shift count for aligning (shifting) the divisor + ;; to the, and the number of times we have to execute subc. + + ;; At the end, we have both the remainder and most of the quotient + ;; in A4. The top bit of the quotient is computed first and is + ;; placed in A2. + + ;; Return immediately if the dividend is zero. Setting B4 to 1 + ;; is a trick to allow us to leave the following insns in the jump + ;; delay slot without affecting the result. + mv .s2x A4, B1 + + [b1] lmbd .l2 1, B4, B1 +||[!b1] b .s2 B3 ; RETURN A +||[!b1] mvk .d2 1, B4 + +||[!b1] zero .s1 A5 + mv .l1x B1, A6 +|| shl .s2 B4, B1, B4 + + ;; The loop performs a maximum of 28 steps, so we do the + ;; first 3 here. + cmpltu .l1x A4, B4, A2 + [!A2] sub .l1x A4, B4, A4 +|| shru .s2 B4, 1, B4 +|| xor .s1 1, A2, A2 + + shl .s1 A2, 31, A2 +|| [b1] subc .l1x A4,B4,A4 +|| [b1] add .s2 -1, B1, B1 + [b1] subc .l1x A4,B4,A4 +|| [b1] add .s2 -1, B1, B1 + + ;; RETURN A may happen here (note: must happen before the next branch) +__divremu0: + cmpgt .l2 B1, 7, B0 +|| [b1] subc .l1x A4,B4,A4 +|| [b1] add .s2 -1, B1, B1 + [b1] subc .l1x A4,B4,A4 +|| [b1] add .s2 -1, B1, B1 +|| [b0] b .s1 __divremu0 + [b1] subc .l1x A4,B4,A4 +|| [b1] add .s2 -1, B1, B1 + [b1] subc .l1x A4,B4,A4 +|| [b1] add .s2 -1, B1, B1 + [b1] subc .l1x A4,B4,A4 +|| [b1] add .s2 -1, B1, B1 + [b1] subc .l1x A4,B4,A4 +|| [b1] add .s2 -1, B1, B1 + [b1] subc .l1x A4,B4,A4 +|| [b1] add .s2 -1, B1, B1 + ;; loop backwards branch happens here + + ret .s2 B3 +|| mvk .s1 32, A1 + sub .l1 A1, A6, A6 +|| extu .s1 A4, A6, A5 + shl .s1 A4, A6, A4 + shru .s1 A4, 1, A4 +|| sub .l1 A6, 1, A6 + or .l1 A2, A4, A4 + shru .s1 A4, A6, A4 + nop +ENDPROC(__c6xabi_divremu) diff --git a/arch/c6x/lib/divu.S b/arch/c6x/lib/divu.S new file mode 100644 index 000000000000..64af3c006dd3 --- /dev/null +++ b/arch/c6x/lib/divu.S @@ -0,0 +1,98 @@ +;; Copyright 2010 Free Software Foundation, Inc. +;; Contributed by Bernd Schmidt . +;; +;; 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 + + ;; ABI considerations for the divide functions + ;; The following registers are call-used: + ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5 + ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4 + ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4 + ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4 + ;; + ;; In our implementation, divu and remu are leaf functions, + ;; while both divi and remi call into divu. + ;; A0 is not clobbered by any of the functions. + ;; divu does not clobber B2 either, which is taken advantage of + ;; in remi. + ;; divi uses B5 to hold the original return address during + ;; the call to divu. + ;; remi uses B2 and A5 to hold the input values during the + ;; call to divu. It stores B3 in on the stack. + + .text +ENTRY(__c6xabi_divu) + ;; We use a series of up to 31 subc instructions. First, we find + ;; out how many leading zero bits there are in the divisor. This + ;; gives us both a shift count for aligning (shifting) the divisor + ;; to the, and the number of times we have to execute subc. + + ;; At the end, we have both the remainder and most of the quotient + ;; in A4. The top bit of the quotient is computed first and is + ;; placed in A2. + + ;; Return immediately if the dividend is zero. + mv .s2x A4, B1 + [B1] lmbd .l2 1, B4, B1 +|| [!B1] b .s2 B3 ; RETURN A +|| [!B1] mvk .d2 1, B4 + mv .l1x B1, A6 +|| shl .s2 B4, B1, B4 + + ;; The loop performs a maximum of 28 steps, so we do the + ;; first 3 here. + cmpltu .l1x A4, B4, A2 + [!A2] sub .l1x A4, B4, A4 +|| shru .s2 B4, 1, B4 +|| xor .s1 1, A2, A2 + + shl .s1 A2, 31, A2 +|| [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + + ;; RETURN A may happen here (note: must happen before the next branch) +_divu_loop: + cmpgt .l2 B1, 7, B0 +|| [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 +|| [B0] b .s1 _divu_loop + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + ;; loop backwards branch happens here + + ret .s2 B3 +|| mvk .s1 32, A1 + sub .l1 A1, A6, A6 + shl .s1 A4, A6, A4 + shru .s1 A4, 1, A4 +|| sub .l1 A6, 1, A6 + or .l1 A2, A4, A4 + shru .s1 A4, A6, A4 + nop +ENDPROC(__c6xabi_divu) diff --git a/arch/c6x/lib/llshl.S b/arch/c6x/lib/llshl.S new file mode 100644 index 000000000000..7b105e2d1b78 --- /dev/null +++ b/arch/c6x/lib/llshl.S @@ -0,0 +1,37 @@ +;; Copyright (C) 2010 Texas Instruments Incorporated +;; Contributed by Mark Salter . +;; +;; 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. + +;; uint64_t __c6xabi_llshl(uint64_t val, uint shift) + +#include + + .text +ENTRY(__c6xabi_llshl) + mv .l1x B4,A1 + [!A1] b .s2 B3 ; just return if zero shift + mvk .s1 32,A0 + sub .d1 A0,A1,A0 + cmplt .l1 0,A0,A2 + [A2] shru .s1 A4,A0,A0 + [!A2] neg .l1 A0,A5 +|| [A2] shl .s1 A5,A1,A5 + [!A2] shl .s1 A4,A5,A5 +|| [A2] or .d1 A5,A0,A5 +|| [!A2] mvk .l1 0,A4 + [A2] shl .s1 A4,A1,A4 + bnop .s2 B3,5 +ENDPROC(__c6xabi_llshl) diff --git a/arch/c6x/lib/llshr.S b/arch/c6x/lib/llshr.S new file mode 100644 index 000000000000..fde1bec7cf5a --- /dev/null +++ b/arch/c6x/lib/llshr.S @@ -0,0 +1,38 @@ +;; Copyright (C) 2010 Texas Instruments Incorporated +;; Contributed by Mark Salter . +;; +;; 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. + +;; uint64_t __c6xabi_llshr(uint64_t val, uint shift) + +#include + + .text +ENTRY(__c6xabi_llshr) + mv .l1x B4,A1 + [!A1] b .s2 B3 ; return if zero shift count + mvk .s1 32,A0 + sub .d1 A0,A1,A0 + cmplt .l1 0,A0,A2 + [A2] shl .s1 A5,A0,A0 + nop + [!A2] neg .l1 A0,A4 +|| [A2] shru .s1 A4,A1,A4 + [!A2] shr .s1 A5,A4,A4 +|| [A2] or .d1 A4,A0,A4 + [!A2] shr .s1 A5,0x1f,A5 + [A2] shr .s1 A5,A1,A5 + bnop .s2 B3,5 +ENDPROC(__c6xabi_llshr) diff --git a/arch/c6x/lib/llshru.S b/arch/c6x/lib/llshru.S new file mode 100644 index 000000000000..596ae3ff5c0f --- /dev/null +++ b/arch/c6x/lib/llshru.S @@ -0,0 +1,38 @@ +;; Copyright (C) 2010 Texas Instruments Incorporated +;; Contributed by Mark Salter . +;; +;; 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. + +;; uint64_t __c6xabi_llshru(uint64_t val, uint shift) + +#include + + .text +ENTRY(__c6xabi_llshru) + mv .l1x B4,A1 + [!A1] b .s2 B3 ; return if zero shift count + mvk .s1 32,A0 + sub .d1 A0,A1,A0 + cmplt .l1 0,A0,A2 + [A2] shl .s1 A5,A0,A0 + nop + [!A2] neg .l1 A0,A4 +|| [A2] shru .s1 A4,A1,A4 + [!A2] shru .s1 A5,A4,A4 +|| [A2] or .d1 A4,A0,A4 +|| [!A2] mvk .l1 0,A5 + [A2] shru .s1 A5,A1,A5 + bnop .s2 B3,5 +ENDPROC(__c6xabi_llshru) diff --git a/arch/c6x/lib/memcpy_64plus.S b/arch/c6x/lib/memcpy_64plus.S new file mode 100644 index 000000000000..0bbc2cbf9318 --- /dev/null +++ b/arch/c6x/lib/memcpy_64plus.S @@ -0,0 +1,46 @@ +; Port on Texas Instruments TMS320C6x architecture +; +; Copyright (C) 2006, 2009, 2010 Texas Instruments Incorporated +; Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.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 + + .text + +ENTRY(memcpy) + AND .L1 0x1,A6,A0 + || AND .S1 0x2,A6,A1 + || AND .L2X 0x4,A6,B0 + || MV .D1 A4,A3 + || MVC .S2 ILC,B2 + + [A0] LDB .D2T1 *B4++,A5 + [A1] LDB .D2T1 *B4++,A7 + [A1] LDB .D2T1 *B4++,A8 + [B0] LDNW .D2T1 *B4++,A9 + || SHRU .S2X A6,0x3,B1 + [!B1] BNOP .S2 B3,1 + + [A0] STB .D1T1 A5,*A3++ + ||[B1] MVC .S2 B1,ILC + [A1] STB .D1T1 A7,*A3++ + [A1] STB .D1T1 A8,*A3++ + [B0] STNW .D1T1 A9,*A3++ ; return when len < 8 + + SPLOOP 2 + + LDNDW .D2T1 *B4++,A9:A8 + NOP 3 + + NOP + SPKERNEL 0,0 + || STNDW .D1T1 A9:A8,*A3++ + + BNOP .S2 B3,4 + MVC .S2 B2,ILC +ENDPROC(memcpy) diff --git a/arch/c6x/lib/mpyll.S b/arch/c6x/lib/mpyll.S new file mode 100644 index 000000000000..f1034418b4db --- /dev/null +++ b/arch/c6x/lib/mpyll.S @@ -0,0 +1,49 @@ +;; Copyright (C) 2010 Texas Instruments Incorporated +;; Contributed by Mark Salter . +;; +;; 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 + + ;; uint64_t __c6xabi_mpyll(uint64_t x, uint64_t y) + ;; + ;; 64x64 multiply + ;; First compute partial results using 32-bit parts of x and y: + ;; + ;; b63 b32 b31 b0 + ;; ----------------------------- + ;; | 1 | 0 | + ;; ----------------------------- + ;; + ;; P0 = X0*Y0 + ;; P1 = X0*Y1 + X1*Y0 + ;; P2 = X1*Y1 + ;; + ;; result = (P2 << 64) + (P1 << 32) + P0 + ;; + ;; Since the result is also 64-bit, we can skip the P2 term. + + .text +ENTRY(__c6xabi_mpyll) + mpy32u .m1x A4,B4,A1:A0 ; X0*Y0 + b .s2 B3 + || mpy32u .m2x B5,A4,B1:B0 ; X0*Y1 (don't need upper 32-bits) + || mpy32u .m1x A5,B4,A3:A2 ; X1*Y0 (don't need upper 32-bits) + nop + nop + mv .s1 A0,A4 + add .l1x A2,B0,A5 + add .s1 A1,A5,A5 +ENDPROC(__c6xabi_mpyll) diff --git a/arch/c6x/lib/negll.S b/arch/c6x/lib/negll.S new file mode 100644 index 000000000000..82f4bcec9afb --- /dev/null +++ b/arch/c6x/lib/negll.S @@ -0,0 +1,31 @@ +;; Copyright (C) 2010 Texas Instruments Incorporated +;; Contributed by Mark Salter . +;; +;; 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. + +;; int64_t __c6xabi_negll(int64_t val) + +#include + + .text +ENTRY(__c6xabi_negll) + b .s2 B3 + mvk .l1 0,A0 + subu .l1 A0,A4,A3:A2 + sub .l1 A0,A5,A0 +|| ext .s1 A3,24,24,A5 + add .l1 A5,A0,A5 + mv .s1 A2,A4 +ENDPROC(__c6xabi_negll) diff --git a/arch/c6x/lib/pop_rts.S b/arch/c6x/lib/pop_rts.S new file mode 100644 index 000000000000..d7d96c70e9e7 --- /dev/null +++ b/arch/c6x/lib/pop_rts.S @@ -0,0 +1,32 @@ +;; Copyright 2010 Free Software Foundation, Inc. +;; Contributed by Bernd Schmidt . +;; +;; 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 + + .text + +ENTRY(__c6xabi_pop_rts) + lddw .d2t2 *++B15, B3:B2 + lddw .d2t1 *++B15, A11:A10 + lddw .d2t2 *++B15, B11:B10 + lddw .d2t1 *++B15, A13:A12 + lddw .d2t2 *++B15, B13:B12 + lddw .d2t1 *++B15, A15:A14 +|| b .s2 B3 + ldw .d2t2 *++B15[2], B14 + nop 4 +ENDPROC(__c6xabi_pop_rts) diff --git a/arch/c6x/lib/push_rts.S b/arch/c6x/lib/push_rts.S new file mode 100644 index 000000000000..f6e3db3b6065 --- /dev/null +++ b/arch/c6x/lib/push_rts.S @@ -0,0 +1,31 @@ +;; Copyright 2010 Free Software Foundation, Inc. +;; Contributed by Bernd Schmidt . +;; +;; 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 + + .text + +ENTRY(__c6xabi_push_rts) + stw .d2t2 B14, *B15--[2] + stdw .d2t1 A15:A14, *B15-- +|| b .s2x A3 + stdw .d2t2 B13:B12, *B15-- + stdw .d2t1 A13:A12, *B15-- + stdw .d2t2 B11:B10, *B15-- + stdw .d2t1 A11:A10, *B15-- + stdw .d2t2 B3:B2, *B15-- +ENDPROC(__c6xabi_push_rts) diff --git a/arch/c6x/lib/remi.S b/arch/c6x/lib/remi.S new file mode 100644 index 000000000000..6f2ca18c3f98 --- /dev/null +++ b/arch/c6x/lib/remi.S @@ -0,0 +1,64 @@ +;; Copyright 2010 Free Software Foundation, Inc. +;; Contributed by Bernd Schmidt . +;; +;; 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 + + ;; ABI considerations for the divide functions + ;; The following registers are call-used: + ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5 + ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4 + ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4 + ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4 + ;; + ;; In our implementation, divu and remu are leaf functions, + ;; while both divi and remi call into divu. + ;; A0 is not clobbered by any of the functions. + ;; divu does not clobber B2 either, which is taken advantage of + ;; in remi. + ;; divi uses B5 to hold the original return address during + ;; the call to divu. + ;; remi uses B2 and A5 to hold the input values during the + ;; call to divu. It stores B3 in on the stack. + + .text + +ENTRY(__c6xabi_remi) + stw .d2t2 B3, *B15--[2] +|| cmpgt .l1 0, A4, A1 +|| cmpgt .l2 0, B4, B2 +|| mv .s1 A4, A5 +|| call .s2 __c6xabi_divu + + [A1] neg .l1 A4, A4 +|| [B2] neg .l2 B4, B4 +|| xor .s2x B2, A1, B0 +|| mv .d2 B4, B2 + + [B0] addkpc .s2 _divu_ret_1, B3, 1 + [!B0] addkpc .s2 _divu_ret_2, B3, 1 + nop 2 +_divu_ret_1: + neg .l1 A4, A4 +_divu_ret_2: + ldw .d2t2 *++B15[2], B3 + + mpy32 .m1x A4, B2, A6 + nop 3 + ret .s2 B3 + sub .l1 A5, A6, A4 + nop 4 +ENDPROC(__c6xabi_remi) diff --git a/arch/c6x/lib/remu.S b/arch/c6x/lib/remu.S new file mode 100644 index 000000000000..3fae719185ab --- /dev/null +++ b/arch/c6x/lib/remu.S @@ -0,0 +1,82 @@ +;; Copyright 2010 Free Software Foundation, Inc. +;; Contributed by Bernd Schmidt . +;; +;; 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 + + ;; ABI considerations for the divide functions + ;; The following registers are call-used: + ;; __c6xabi_divi A0,A1,A2,A4,A6,B0,B1,B2,B4,B5 + ;; __c6xabi_divu A0,A1,A2,A4,A6,B0,B1,B2,B4 + ;; __c6xabi_remi A1,A2,A4,A5,A6,B0,B1,B2,B4 + ;; __c6xabi_remu A1,A4,A5,A7,B0,B1,B2,B4 + ;; + ;; In our implementation, divu and remu are leaf functions, + ;; while both divi and remi call into divu. + ;; A0 is not clobbered by any of the functions. + ;; divu does not clobber B2 either, which is taken advantage of + ;; in remi. + ;; divi uses B5 to hold the original return address during + ;; the call to divu. + ;; remi uses B2 and A5 to hold the input values during the + ;; call to divu. It stores B3 in on the stack. + + + .text + +ENTRY(__c6xabi_remu) + ;; The ABI seems designed to prevent these functions calling each other, + ;; so we duplicate most of the divsi3 code here. + mv .s2x A4, B1 + lmbd .l2 1, B4, B1 +|| [!B1] b .s2 B3 ; RETURN A +|| [!B1] mvk .d2 1, B4 + + mv .l1x B1, A7 +|| shl .s2 B4, B1, B4 + + cmpltu .l1x A4, B4, A1 + [!A1] sub .l1x A4, B4, A4 + shru .s2 B4, 1, B4 + +_remu_loop: + cmpgt .l2 B1, 7, B0 +|| [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + ;; RETURN A may happen here (note: must happen before the next branch) + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 +|| [B0] b .s1 _remu_loop + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + ;; loop backwards branch happens here + + ret .s2 B3 + [B1] subc .l1x A4,B4,A4 +|| [B1] add .s2 -1, B1, B1 + [B1] subc .l1x A4,B4,A4 + + extu .s1 A4, A7, A4 + nop 2 +ENDPROC(__c6xabi_remu) diff --git a/arch/c6x/lib/strasgi.S b/arch/c6x/lib/strasgi.S new file mode 100644 index 000000000000..de2740765536 --- /dev/null +++ b/arch/c6x/lib/strasgi.S @@ -0,0 +1,89 @@ +;; Copyright 2010 Free Software Foundation, Inc. +;; Contributed by Bernd Schmidt . +;; +;; 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 + + .text + +ENTRY(__c6xabi_strasgi) + ;; This is essentially memcpy, with alignment known to be at least + ;; 4, and the size a multiple of 4 greater than or equal to 28. + ldw .d2t1 *B4++, A0 +|| mvk .s2 16, B1 + ldw .d2t1 *B4++, A1 +|| mvk .s2 20, B2 +|| sub .d1 A6, 24, A6 + ldw .d2t1 *B4++, A5 + ldw .d2t1 *B4++, A7 +|| mv .l2x A6, B7 + ldw .d2t1 *B4++, A8 + ldw .d2t1 *B4++, A9 +|| mv .s2x A0, B5 +|| cmpltu .l2 B2, B7, B0 + +_strasgi_loop: + stw .d1t2 B5, *A4++ +|| [B0] ldw .d2t1 *B4++, A0 +|| mv .s2x A1, B5 +|| mv .l2 B7, B6 + + [B0] sub .d2 B6, 24, B7 +|| [B0] b .s2 _strasgi_loop +|| cmpltu .l2 B1, B6, B0 + + [B0] ldw .d2t1 *B4++, A1 +|| stw .d1t2 B5, *A4++ +|| mv .s2x A5, B5 +|| cmpltu .l2 12, B6, B0 + + [B0] ldw .d2t1 *B4++, A5 +|| stw .d1t2 B5, *A4++ +|| mv .s2x A7, B5 +|| cmpltu .l2 8, B6, B0 + + [B0] ldw .d2t1 *B4++, A7 +|| stw .d1t2 B5, *A4++ +|| mv .s2x A8, B5 +|| cmpltu .l2 4, B6, B0 + + [B0] ldw .d2t1 *B4++, A8 +|| stw .d1t2 B5, *A4++ +|| mv .s2x A9, B5 +|| cmpltu .l2 0, B6, B0 + + [B0] ldw .d2t1 *B4++, A9 +|| stw .d1t2 B5, *A4++ +|| mv .s2x A0, B5 +|| cmpltu .l2 B2, B7, B0 + + ;; loop back branch happens here + + cmpltu .l2 B1, B6, B0 +|| ret .s2 b3 + + [B0] stw .d1t1 A1, *A4++ +|| cmpltu .l2 12, B6, B0 + [B0] stw .d1t1 A5, *A4++ +|| cmpltu .l2 8, B6, B0 + [B0] stw .d1t1 A7, *A4++ +|| cmpltu .l2 4, B6, B0 + [B0] stw .d1t1 A8, *A4++ +|| cmpltu .l2 0, B6, B0 + [B0] stw .d1t1 A9, *A4++ + + ;; return happens here +ENDPROC(__c6xabi_strasgi) diff --git a/arch/c6x/lib/strasgi_64plus.S b/arch/c6x/lib/strasgi_64plus.S new file mode 100644 index 000000000000..c9fd159b5fa2 --- /dev/null +++ b/arch/c6x/lib/strasgi_64plus.S @@ -0,0 +1,39 @@ +;; Copyright 2010 Free Software Foundation, Inc. +;; Contributed by Bernd Schmidt . +;; +;; 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 + + .text + +ENTRY(__c6xabi_strasgi_64plus) + shru .s2x a6, 2, b31 +|| mv .s1 a4, a30 +|| mv .d2 b4, b30 + + add .s2 -4, b31, b31 + + sploopd 1 +|| mvc .s2 b31, ilc + ldw .d2t2 *b30++, b31 + nop 4 + mv .s1x b31,a31 + spkernel 6, 0 +|| stw .d1t1 a31, *a30++ + + ret .s2 b3 + nop 5 +ENDPROC(__c6xabi_strasgi_64plus) -- cgit v1.2.3 From 69910a284cee7864c9bf96e13505a4ab35ab8dce Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 4 Oct 2011 11:17:47 -0400 Subject: C6X: general SoC support This patch provides a soc_ops struct which provides hooks for SoC functionality which doesn't fit well into other places. Signed-off-by: Mark Salter Signed-off-by: Aurelien Jacquiot Acked-by: Arnd Bergmann --- arch/c6x/include/asm/soc.h | 35 ++++++++++++++++++ arch/c6x/kernel/soc.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 arch/c6x/include/asm/soc.h create mode 100644 arch/c6x/kernel/soc.c (limited to 'arch') diff --git a/arch/c6x/include/asm/soc.h b/arch/c6x/include/asm/soc.h new file mode 100644 index 000000000000..43f50159e59b --- /dev/null +++ b/arch/c6x/include/asm/soc.h @@ -0,0 +1,35 @@ +/* + * Miscellaneous SoC-specific hooks. + * + * Copyright (C) 2011 Texas Instruments Incorporated + * + * Author: Mark Salter + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ +#ifndef _ASM_C6X_SOC_H +#define _ASM_C6X_SOC_H + +struct soc_ops { + /* Return active exception event or -1 if none */ + int (*get_exception)(void); + + /* Assert an event */ + void (*assert_event)(unsigned int evt); +}; + +extern struct soc_ops soc_ops; + +extern int soc_get_exception(void); +extern void soc_assert_event(unsigned int event); +extern int soc_mac_addr(unsigned int index, u8 *addr); + +/* + * for mmio on SoC devices. regs are always same byte order as cpu. + */ +#define soc_readl(addr) __raw_readl(addr) +#define soc_writel(b, addr) __raw_writel((b), (addr)) + +#endif /* _ASM_C6X_SOC_H */ diff --git a/arch/c6x/kernel/soc.c b/arch/c6x/kernel/soc.c new file mode 100644 index 000000000000..dd45bc39af0e --- /dev/null +++ b/arch/c6x/kernel/soc.c @@ -0,0 +1,91 @@ +/* + * Miscellaneous SoC-specific hooks. + * + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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 +#include +#include +#include +#include +#include + +struct soc_ops soc_ops; + +int soc_get_exception(void) +{ + if (!soc_ops.get_exception) + return -1; + return soc_ops.get_exception(); +} + +void soc_assert_event(unsigned int evt) +{ + if (soc_ops.assert_event) + soc_ops.assert_event(evt); +} + +static u8 cmdline_mac[6]; + +static int __init get_mac_addr_from_cmdline(char *str) +{ + int count, i, val; + + for (count = 0; count < 6 && *str; count++, str += 3) { + if (!isxdigit(str[0]) || !isxdigit(str[1])) + return 0; + if (str[2] != ((count < 5) ? ':' : '\0')) + return 0; + + for (i = 0, val = 0; i < 2; i++) { + val = val << 4; + val |= isdigit(str[i]) ? + str[i] - '0' : toupper(str[i]) - 'A' + 10; + } + cmdline_mac[count] = val; + } + return 1; +} +__setup("emac_addr=", get_mac_addr_from_cmdline); + +/* + * Setup the MAC address for SoC ethernet devices. + * + * Before calling this function, the ethernet driver will have + * initialized the addr with local-mac-address from the device + * tree (if found). Allow command line to override, but not + * the fused address. + */ +int soc_mac_addr(unsigned int index, u8 *addr) +{ + int i, have_dt_mac = 0, have_cmdline_mac = 0, have_fuse_mac = 0; + + for (i = 0; i < 6; i++) { + if (cmdline_mac[i]) + have_cmdline_mac = 1; + if (c6x_fuse_mac[i]) + have_fuse_mac = 1; + if (addr[i]) + have_dt_mac = 1; + } + + /* cmdline overrides all */ + if (have_cmdline_mac) + memcpy(addr, cmdline_mac, 6); + else if (!have_dt_mac) { + if (have_fuse_mac) + memcpy(addr, c6x_fuse_mac, 6); + else + random_ether_addr(addr); + } + + /* adjust for specific EMAC device */ + addr[5] += index * c6x_num_cores; + return 1; +} +EXPORT_SYMBOL_GPL(soc_mac_addr); -- cgit v1.2.3 From 6bbfd8975cf3b78aadd1513a25bf7b5c04866a6f Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 4 Oct 2011 11:18:46 -0400 Subject: C6X: EMIF - External Memory Interface Several SoC parts provide a simple bridge to support external memory mapped devices. This code probes the device tree for an EMIF node and sets up the bridge registers if such a node is found. Beyond initial set up, there is no further need to access the bridge control registers. External devices on the bus are accessed through their MMIO registers using suitable drivers. The bridge hardware does provide for timeout and other error interrupts, but these are not yet supported. Signed-off-by: Mark Salter Signed-off-by: Aurelien Jacquiot Acked-by: Arnd Bergmann --- arch/c6x/platforms/emif.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 arch/c6x/platforms/emif.c (limited to 'arch') diff --git a/arch/c6x/platforms/emif.c b/arch/c6x/platforms/emif.c new file mode 100644 index 000000000000..6a0d4ff972ed --- /dev/null +++ b/arch/c6x/platforms/emif.c @@ -0,0 +1,88 @@ +/* + * External Memory Interface + * + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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 +#include +#include +#include +#include + +#define NUM_EMIFA_CHIP_ENABLES 4 + +struct emifa_regs { + u32 midr; + u32 stat; + u32 reserved1[6]; + u32 bprio; + u32 reserved2[23]; + u32 ce_config; + u32 cecfg[NUM_EMIFA_CHIP_ENABLES]; + u32 reserved3[4]; + u32 awcc; + u32 reserved4[7]; + u32 intraw; + u32 intmsk; + u32 intmskset; + u32 intmskclr; +}; + +static struct of_device_id emifa_match[] __initdata = { + { .compatible = "ti,c64x+emifa" }, + {} +}; + +/* + * Parse device tree for existence of an EMIF (External Memory Interface) + * and initialize it if found. + */ +static int __init c6x_emifa_init(void) +{ + struct emifa_regs __iomem *regs; + struct device_node *node; + const __be32 *p; + u32 val; + int i, len, err; + + node = of_find_matching_node(NULL, emifa_match); + if (!node) + return 0; + + regs = of_iomap(node, 0); + if (!regs) + return 0; + + /* look for a dscr-based enable for emifa pin buffers */ + err = of_property_read_u32_array(node, "ti,dscr-dev-enable", &val, 1); + if (!err) + dscr_set_devstate(val, DSCR_DEVSTATE_ENABLED); + + /* set up the chip enables */ + p = of_get_property(node, "ti,emifa-ce-config", &len); + if (p) { + len /= sizeof(u32); + if (len > NUM_EMIFA_CHIP_ENABLES) + len = NUM_EMIFA_CHIP_ENABLES; + for (i = 0; i <= len; i++) + soc_writel(be32_to_cpup(&p[i]), ®s->cecfg[i]); + } + + err = of_property_read_u32_array(node, "ti,emifa-burst-priority", &val, 1); + if (!err) + soc_writel(val, ®s->bprio); + + err = of_property_read_u32_array(node, "ti,emifa-async-wait-control", &val, 1); + if (!err) + soc_writel(val, ®s->awcc); + + iounmap(regs); + of_node_put(node); + return 0; +} +pure_initcall(c6x_emifa_init); -- cgit v1.2.3 From 9de98fb4ec4c91597feedc521120c16fca54a5b6 Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 4 Oct 2011 11:20:28 -0400 Subject: C6X: DSCR - Device State Configuration Registers All SoCs provide an area of device configuration registers called the DSCR. The location of specific registers as well as their use varies considerably from implementation to implementation. Rather than having to rely on additional SoC-specific DSCR code for each new supported SoC, this code generalize things as much as possible using device tree properties. Initialization must take place early on (setup_arch time) in case the event timer device needs to be enable via the DSCR. Signed-off-by: Mark Salter Signed-off-by: Aurelien Jacquiot Acked-by: Arnd Bergmann --- arch/c6x/include/asm/dscr.h | 34 +++ arch/c6x/platforms/dscr.c | 598 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 632 insertions(+) create mode 100644 arch/c6x/include/asm/dscr.h create mode 100644 arch/c6x/platforms/dscr.c (limited to 'arch') diff --git a/arch/c6x/include/asm/dscr.h b/arch/c6x/include/asm/dscr.h new file mode 100644 index 000000000000..561ba8332042 --- /dev/null +++ b/arch/c6x/include/asm/dscr.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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_C6X_DSCR_H +#define _ASM_C6X_DSCR_H + +enum dscr_devstate_t { + DSCR_DEVSTATE_ENABLED, + DSCR_DEVSTATE_DISABLED, +}; + +/* + * Set the device state of the device with the given ID. + * + * Individual drivers should use this to enable or disable the + * hardware device. The devid used to identify the device being + * controlled should be a property in the device's tree node. + */ +extern void dscr_set_devstate(int devid, enum dscr_devstate_t state); + +/* + * Assert or de-assert an RMII reset. + */ +extern void dscr_rmii_reset(int id, int assert); + +extern void dscr_probe(void); + +#endif /* _ASM_C6X_DSCR_H */ diff --git a/arch/c6x/platforms/dscr.c b/arch/c6x/platforms/dscr.c new file mode 100644 index 000000000000..f848a65ee646 --- /dev/null +++ b/arch/c6x/platforms/dscr.c @@ -0,0 +1,598 @@ +/* + * Device State Control Registers driver + * + * Copyright (C) 2011 Texas Instruments Incorporated + * Author: Mark Salter + * + * 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. + */ + +/* + * The Device State Control Registers (DSCR) provide SoC level control over + * a number of peripherals. Details vary considerably among the various SoC + * parts. In general, the DSCR block will provide one or more configuration + * registers often protected by a lock register. One or more key values must + * be written to a lock register in order to unlock the configuration register. + * The configuration register may be used to enable (and disable in some + * cases) SoC pin drivers, peripheral clock sources (internal or pin), etc. + * In some cases, a configuration register is write once or the individual + * bits are write once. That is, you may be able to enable a device, but + * will not be able to disable it. + * + * In addition to device configuration, the DSCR block may provide registers + * which are used to reset SoC peripherals, provide device ID information, + * provide MAC addresses, and other miscellaneous functions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_DEVSTATE_IDS 32 +#define MAX_DEVCTL_REGS 8 +#define MAX_DEVSTAT_REGS 8 +#define MAX_LOCKED_REGS 4 +#define MAX_SOC_EMACS 2 + +struct rmii_reset_reg { + u32 reg; + u32 mask; +}; + +/* + * Some registerd may be locked. In order to write to these + * registers, the key value must first be written to the lockreg. + */ +struct locked_reg { + u32 reg; /* offset from base */ + u32 lockreg; /* offset from base */ + u32 key; /* unlock key */ +}; + +/* + * This describes a contiguous area of like control bits used to enable/disable + * SoC devices. Each controllable device is given an ID which is used by the + * individual device drivers to control the device state. These IDs start at + * zero and are assigned sequentially to the control bitfield ranges described + * by this structure. + */ +struct devstate_ctl_reg { + u32 reg; /* register holding the control bits */ + u8 start_id; /* start id of this range */ + u8 num_ids; /* number of devices in this range */ + u8 enable_only; /* bits are write-once to enable only */ + u8 enable; /* value used to enable device */ + u8 disable; /* value used to disable device */ + u8 shift; /* starting (rightmost) bit in range */ + u8 nbits; /* number of bits per device */ +}; + + +/* + * This describes a region of status bits indicating the state of + * various devices. This is used internally to wait for status + * change completion when enabling/disabling a device. Status is + * optional and not all device controls will have a corresponding + * status. + */ +struct devstate_stat_reg { + u32 reg; /* register holding the status bits */ + u8 start_id; /* start id of this range */ + u8 num_ids; /* number of devices in this range */ + u8 enable; /* value indicating enabled state */ + u8 disable; /* value indicating disabled state */ + u8 shift; /* starting (rightmost) bit in range */ + u8 nbits; /* number of bits per device */ +}; + +struct devstate_info { + struct devstate_ctl_reg *ctl; + struct devstate_stat_reg *stat; +}; + +/* These are callbacks to SOC-specific code. */ +struct dscr_ops { + void (*init)(struct device_node *node); +}; + +struct dscr_regs { + spinlock_t lock; + void __iomem *base; + u32 kick_reg[2]; + u32 kick_key[2]; + struct locked_reg locked[MAX_LOCKED_REGS]; + struct devstate_info devstate_info[MAX_DEVSTATE_IDS]; + struct rmii_reset_reg rmii_resets[MAX_SOC_EMACS]; + struct devstate_ctl_reg devctl[MAX_DEVCTL_REGS]; + struct devstate_stat_reg devstat[MAX_DEVSTAT_REGS]; +}; + +static struct dscr_regs dscr; + +static struct locked_reg *find_locked_reg(u32 reg) +{ + int i; + + for (i = 0; i < MAX_LOCKED_REGS; i++) + if (dscr.locked[i].key && reg == dscr.locked[i].reg) + return &dscr.locked[i]; + return NULL; +} + +/* + * Write to a register with one lock + */ +static void dscr_write_locked1(u32 reg, u32 val, + u32 lock, u32 key) +{ + void __iomem *reg_addr = dscr.base + reg; + void __iomem *lock_addr = dscr.base + lock; + + /* + * For some registers, the lock is relocked after a short number + * of cycles. We have to put the lock write and register write in + * the same fetch packet to meet this timing. The .align ensures + * the two stw instructions are in the same fetch packet. + */ + asm volatile ("b .s2 0f\n" + "nop 5\n" + " .align 5\n" + "0:\n" + "stw .D1T2 %3,*%2\n" + "stw .D1T2 %1,*%0\n" + : + : "a"(reg_addr), "b"(val), "a"(lock_addr), "b"(key) + ); + + /* in case the hw doesn't reset the lock */ + soc_writel(0, lock_addr); +} + +/* + * Write to a register protected by two lock registers + */ +static void dscr_write_locked2(u32 reg, u32 val, + u32 lock0, u32 key0, + u32 lock1, u32 key1) +{ + soc_writel(key0, dscr.base + lock0); + soc_writel(key1, dscr.base + lock1); + soc_writel(val, dscr.base + reg); + soc_writel(0, dscr.base + lock0); + soc_writel(0, dscr.base + lock1); +} + +static void dscr_write(u32 reg, u32 val) +{ + struct locked_reg *lock; + + lock = find_locked_reg(reg); + if (lock) + dscr_write_locked1(reg, val, lock->lockreg, lock->key); + else if (dscr.kick_key[0]) + dscr_write_locked2(reg, val, dscr.kick_reg[0], dscr.kick_key[0], + dscr.kick_reg[1], dscr.kick_key[1]); + else + soc_writel(val, dscr.base + reg); +} + + +/* + * Drivers can use this interface to enable/disable SoC IP blocks. + */ +void dscr_set_devstate(int id, enum dscr_devstate_t state) +{ + struct devstate_ctl_reg *ctl; + struct devstate_stat_reg *stat; + struct devstate_info *info; + u32 ctl_val, val; + int ctl_shift, ctl_mask; + unsigned long flags; + + if (!dscr.base) + return; + + if (id < 0 || id >= MAX_DEVSTATE_IDS) + return; + + info = &dscr.devstate_info[id]; + ctl = info->ctl; + stat = info->stat; + + if (ctl == NULL) + return; + + ctl_shift = ctl->shift + ctl->nbits * (id - ctl->start_id); + ctl_mask = ((1 << ctl->nbits) - 1) << ctl_shift; + + switch (state) { + case DSCR_DEVSTATE_ENABLED: + ctl_val = ctl->enable << ctl_shift; + break; + case DSCR_DEVSTATE_DISABLED: + if (ctl->enable_only) + return; + ctl_val = ctl->disable << ctl_shift; + break; + default: + return; + } + + spin_lock_irqsave(&dscr.lock, flags); + + val = soc_readl(dscr.base + ctl->reg); + val &= ~ctl_mask; + val |= ctl_val; + + dscr_write(ctl->reg, val); + + spin_unlock_irqrestore(&dscr.lock, flags); + + if (!stat) + return; + + ctl_shift = stat->shift + stat->nbits * (id - stat->start_id); + + if (state == DSCR_DEVSTATE_ENABLED) + ctl_val = stat->enable; + else + ctl_val = stat->disable; + + do { + val = soc_readl(dscr.base + stat->reg); + val >>= ctl_shift; + val &= ((1 << stat->nbits) - 1); + } while (val != ctl_val); +} +EXPORT_SYMBOL(dscr_set_devstate); + +/* + * Drivers can use this to reset RMII module. + */ +void dscr_rmii_reset(int id, int assert) +{ + struct rmii_reset_reg *r; + unsigned long flags; + u32 val; + + if (id < 0 || id >= MAX_SOC_EMACS) + return; + + r = &dscr.rmii_resets[id]; + if (r->mask == 0) + return; + + spin_lock_irqsave(&dscr.lock, flags); + + val = soc_readl(dscr.base + r->reg); + if (assert) + dscr_write(r->reg, val | r->mask); + else + dscr_write(r->reg, val & ~(r->mask)); + + spin_unlock_irqrestore(&dscr.lock, flags); +} +EXPORT_SYMBOL(dscr_rmii_reset); + +static void __init dscr_parse_devstat(struct device_node *node, + void __iomem *base) +{ + u32 val; + int err; + + err = of_property_read_u32_array(node, "ti,dscr-devstat", &val, 1); + if (!err) + c6x_devstat = soc_readl(base + val); + printk(KERN_INFO "DEVSTAT: %08x\n", c6x_devstat); +} + +static void __init dscr_parse_silicon_rev(struct device_node *node, + void __iomem *base) +{ + u32 vals[3]; + int err; + + err = of_property_read_u32_array(node, "ti,dscr-silicon-rev", vals, 3); + if (!err) { + c6x_silicon_rev = soc_readl(base + vals[0]); + c6x_silicon_rev >>= vals[1]; + c6x_silicon_rev &= vals[2]; + } +} + +/* + * Some SoCs will have a pair of fuse registers which hold + * an ethernet MAC address. The "ti,dscr-mac-fuse-regs" + * property is a mapping from fuse register bytes to MAC + * address bytes. The expected format is: + * + * ti,dscr-mac-fuse-regs = + * + * reg0 and reg1 are the offsets of the two fuse registers. + * b3-b0 positionally represent bytes within the fuse register. + * b3 is the most significant byte and b0 is the least. + * Allowable values for b3-b0 are: + * + * 0 = fuse register byte not used in MAC address + * 1-6 = index+1 into c6x_fuse_mac[] + */ +static void __init dscr_parse_mac_fuse(struct device_node *node, + void __iomem *base) +{ + u32 vals[10], fuse; + int f, i, j, err; + + err = of_property_read_u32_array(node, "ti,dscr-mac-fuse-regs", + vals, 10); + if (err) + return; + + for (f = 0; f < 2; f++) { + fuse = soc_readl(base + vals[f * 5]); + for (j = (f * 5) + 1, i = 24; i >= 0; i -= 8, j++) + if (vals[j] && vals[j] <= 6) + c6x_fuse_mac[vals[j] - 1] = fuse >> i; + } +} + +static void __init dscr_parse_rmii_resets(struct device_node *node, + void __iomem *base) +{ + const __be32 *p; + int i, size; + + /* look for RMII reset registers */ + p = of_get_property(node, "ti,dscr-rmii-resets", &size); + if (p) { + /* parse all the reg/mask pairs we can handle */ + size /= (sizeof(*p) * 2); + if (size > MAX_SOC_EMACS) + size = MAX_SOC_EMACS; + + for (i = 0; i < size; i++) { + dscr.rmii_resets[i].reg = be32_to_cpup(p++); + dscr.rmii_resets[i].mask = be32_to_cpup(p++); + } + } +} + + +static void __init dscr_parse_privperm(struct device_node *node, + void __iomem *base) +{ + u32 vals[2]; + int err; + + err = of_property_read_u32_array(node, "ti,dscr-privperm", vals, 2); + if (err) + return; + dscr_write(vals[0], vals[1]); +} + +/* + * SoCs may have "locked" DSCR registers which can only be written + * to only after writing a key value to a lock registers. These + * regisers can be described with the "ti,dscr-locked-regs" property. + * This property provides a list of register descriptions with each + * description consisting of three values. + * + * ti,dscr-locked-regs = ; + * + * reg is the offset of the locked register + * lockreg is the offset of the lock register + * key is the unlock key written to lockreg + * + */ +static void __init dscr_parse_locked_regs(struct device_node *node, + void __iomem *base) +{ + struct locked_reg *r; + const __be32 *p; + int i, size; + + p = of_get_property(node, "ti,dscr-locked-regs", &size); + if (p) { + /* parse all the register descriptions we can handle */ + size /= (sizeof(*p) * 3); + if (size > MAX_LOCKED_REGS) + size = MAX_LOCKED_REGS; + + for (i = 0; i < size; i++) { + r = &dscr.locked[i]; + + r->reg = be32_to_cpup(p++); + r->lockreg = be32_to_cpup(p++); + r->key = be32_to_cpup(p++); + } + } +} + +/* + * SoCs may have DSCR registers which are only write enabled after + * writing specific key values to two registers. The two key registers + * and the key values can be parsed from a "ti,dscr-kick-regs" + * propety with the following layout: + * + * ti,dscr-kick-regs = + * + * kickreg is the offset of the "kick" register + * key is the value which unlocks writing for protected regs + */ +static void __init dscr_parse_kick_regs(struct device_node *node, + void __iomem *base) +{ + u32 vals[4]; + int err; + + err = of_property_read_u32_array(node, "ti,dscr-kick-regs", vals, 4); + if (!err) { + dscr.kick_reg[0] = vals[0]; + dscr.kick_key[0] = vals[1]; + dscr.kick_reg[1] = vals[2]; + dscr.kick_key[1] = vals[3]; + } +} + + +/* + * SoCs may provide controls to enable/disable individual IP blocks. These + * controls in the DSCR usually control pin drivers but also may control + * clocking and or resets. The device tree is used to describe the bitfields + * in registers used to control device state. The number of bits and their + * values may vary even within the same register. + * + * The layout of these bitfields is described by the ti,dscr-devstate-ctl-regs + * property. This property is a list where each element describes a contiguous + * range of control fields with like properties. Each element of the list + * consists of 7 cells with the following values: + * + * start_id num_ids reg enable disable start_bit nbits + * + * start_id is device id for the first device control in the range + * num_ids is the number of device controls in the range + * reg is the offset of the register holding the control bits + * enable is the value to enable a device + * disable is the value to disable a device (0xffffffff if cannot disable) + * start_bit is the bit number of the first bit in the range + * nbits is the number of bits per device control + */ +static void __init dscr_parse_devstate_ctl_regs(struct device_node *node, + void __iomem *base) +{ + struct devstate_ctl_reg *r; + const __be32 *p; + int i, j, size; + + p = of_get_property(node, "ti,dscr-devstate-ctl-regs", &size); + if (p) { + /* parse all the ranges we can handle */ + size /= (sizeof(*p) * 7); + if (size > MAX_DEVCTL_REGS) + size = MAX_DEVCTL_REGS; + + for (i = 0; i < size; i++) { + r = &dscr.devctl[i]; + + r->start_id = be32_to_cpup(p++); + r->num_ids = be32_to_cpup(p++); + r->reg = be32_to_cpup(p++); + r->enable = be32_to_cpup(p++); + r->disable = be32_to_cpup(p++); + if (r->disable == 0xffffffff) + r->enable_only = 1; + r->shift = be32_to_cpup(p++); + r->nbits = be32_to_cpup(p++); + + for (j = r->start_id; + j < (r->start_id + r->num_ids); + j++) + dscr.devstate_info[j].ctl = r; + } + } +} + +/* + * SoCs may provide status registers indicating the state (enabled/disabled) of + * devices on the SoC. The device tree is used to describe the bitfields in + * registers used to provide device status. The number of bits and their + * values used to provide status may vary even within the same register. + * + * The layout of these bitfields is described by the ti,dscr-devstate-stat-regs + * property. This property is a list where each element describes a contiguous + * range of status fields with like properties. Each element of the list + * consists of 7 cells with the following values: + * + * start_id num_ids reg enable disable start_bit nbits + * + * start_id is device id for the first device status in the range + * num_ids is the number of devices covered by the range + * reg is the offset of the register holding the status bits + * enable is the value indicating device is enabled + * disable is the value indicating device is disabled + * start_bit is the bit number of the first bit in the range + * nbits is the number of bits per device status + */ +static void __init dscr_parse_devstate_stat_regs(struct device_node *node, + void __iomem *base) +{ + struct devstate_stat_reg *r; + const __be32 *p; + int i, j, size; + + p = of_get_property(node, "ti,dscr-devstate-stat-regs", &size); + if (p) { + /* parse all the ranges we can handle */ + size /= (sizeof(*p) * 7); + if (size > MAX_DEVSTAT_REGS) + size = MAX_DEVSTAT_REGS; + + for (i = 0; i < size; i++) { + r = &dscr.devstat[i]; + + r->start_id = be32_to_cpup(p++); + r->num_ids = be32_to_cpup(p++); + r->reg = be32_to_cpup(p++); + r->enable = be32_to_cpup(p++); + r->disable = be32_to_cpup(p++); + r->shift = be32_to_cpup(p++); + r->nbits = be32_to_cpup(p++); + + for (j = r->start_id; + j < (r->start_id + r->num_ids); + j++) + dscr.devstate_info[j].stat = r; + } + } +} + +static struct of_device_id dscr_ids[] __initdata = { + { .compatible = "ti,c64x+dscr" }, + {} +}; + +/* + * Probe for DSCR area. + * + * This has to be done early on in case timer or interrupt controller + * needs something. e.g. On C6455 SoC, timer must be enabled through + * DSCR before it is functional. + */ +void __init dscr_probe(void) +{ + struct device_node *node; + void __iomem *base; + + spin_lock_init(&dscr.lock); + + node = of_find_matching_node(NULL, dscr_ids); + if (!node) + return; + + base = of_iomap(node, 0); + if (!base) { + of_node_put(node); + return; + } + + dscr.base = base; + + dscr_parse_devstat(node, base); + dscr_parse_silicon_rev(node, base); + dscr_parse_mac_fuse(node, base); + dscr_parse_rmii_resets(node, base); + dscr_parse_locked_regs(node, base); + dscr_parse_kick_regs(node, base); + dscr_parse_devstate_ctl_regs(node, base); + dscr_parse_devstate_stat_regs(node, base); + dscr_parse_privperm(node, base); +} -- cgit v1.2.3 From db8196df4bb6f117caa163aa73b0f16fd62290bd Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 13 Oct 2011 22:34:23 +0530 Subject: dmaengine: move drivers to dma_transfer_direction fixup usage of dma direction by introducing dma_transfer_direction, this patch moves dma/drivers/* to use new enum Cc: Jassi Brar Cc: Russell King Cc: Viresh Kumar Cc: Linus Walleij Cc: Nicolas Ferre Cc: Mika Westerberg Cc: H Hartley Sweeten Cc: Li Yang Cc: Zhang Wei Cc: Sascha Hauer Cc: Guennadi Liakhovetski Cc: Shawn Guo Cc: Yong Wang Cc: Tomoya MORINAGA Cc: Boojin Kim Cc: Barry Song Acked-by: Mika Westerberg Acked-by: Linus Walleij Acked-by: Viresh Kumar Acked-by: Nicolas Ferre Signed-off-by: Vinod Koul --- arch/arm/mach-ep93xx/include/mach/dma.h | 6 +++--- arch/arm/plat-nomadik/include/plat/ste_dma40.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-ep93xx/include/mach/dma.h b/arch/arm/mach-ep93xx/include/mach/dma.h index 46d4d876e6fb..e82c642fa53c 100644 --- a/arch/arm/mach-ep93xx/include/mach/dma.h +++ b/arch/arm/mach-ep93xx/include/mach/dma.h @@ -37,7 +37,7 @@ */ struct ep93xx_dma_data { int port; - enum dma_data_direction direction; + enum dma_transfer_direction direction; const char *name; }; @@ -80,14 +80,14 @@ static inline bool ep93xx_dma_chan_is_m2p(struct dma_chan *chan) * channel supports given DMA direction. Only M2P channels have such * limitation, for M2M channels the direction is configurable. */ -static inline enum dma_data_direction +static inline enum dma_transfer_direction ep93xx_dma_chan_direction(struct dma_chan *chan) { if (!ep93xx_dma_chan_is_m2p(chan)) return DMA_NONE; /* even channels are for TX, odd for RX */ - return (chan->chan_id % 2 == 0) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + return (chan->chan_id % 2 == 0) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; } #endif /* __ASM_ARCH_DMA_H */ diff --git a/arch/arm/plat-nomadik/include/plat/ste_dma40.h b/arch/arm/plat-nomadik/include/plat/ste_dma40.h index 685c78716d95..38b041a40db4 100644 --- a/arch/arm/plat-nomadik/include/plat/ste_dma40.h +++ b/arch/arm/plat-nomadik/include/plat/ste_dma40.h @@ -187,7 +187,7 @@ static inline struct dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan, dma_addr_t addr, unsigned int size, - enum dma_data_direction direction, + enum dma_transfer_direction direction, unsigned long flags) { struct scatterlist sg; @@ -209,7 +209,7 @@ static inline struct dma_async_tx_descriptor *stedma40_slave_mem(struct dma_chan *chan, dma_addr_t addr, unsigned int size, - enum dma_data_direction direction, + enum dma_transfer_direction direction, unsigned long flags) { return NULL; -- cgit v1.2.3 From 800100afc7a01ed581702bfaa6014f646e6eff5d Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 11 Oct 2011 13:23:29 +0200 Subject: h8300: drivers/serial/Kconfig was moved commit ab4382d27412e7e3e7c936e8d50d8888dfac3df8 moved drivers/serial/Kconfig to drivers/tty/serial/Kconfig, so we need to source the latter file. Signed-off-by: Paul Bolle Signed-off-by: Jiri Kosina --- arch/h8300/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 7ed7714573c8..d1f377f5d3b6 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig @@ -195,7 +195,7 @@ config UNIX98_PTYS source "drivers/char/pcmcia/Kconfig" -source "drivers/serial/Kconfig" +source "drivers/tty/serial/Kconfig" source "drivers/i2c/Kconfig" -- cgit v1.2.3 From 3007c48a6a1bc6c7b81d5d9890bcbd5c0b519235 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sun, 23 Oct 2011 17:23:54 +0200 Subject: treewide: remove commented out Kconfig entries These Kconfig entries have been commented out since (at least) v2.6.12-rc2 (the first commit of the git repository). There's no indication why they're commented out. They might as well be removed. Signed-off-by: Paul Bolle Signed-off-by: Jiri Kosina --- arch/frv/Kconfig | 10 ---------- arch/mips/Kconfig | 4 ---- arch/mips/sgi-ip27/Kconfig | 6 ------ 3 files changed, 20 deletions(-) (limited to 'arch') diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig index bad27a6ff407..c5e69abb4889 100644 --- a/arch/frv/Kconfig +++ b/arch/frv/Kconfig @@ -341,16 +341,6 @@ source "drivers/pci/Kconfig" source "drivers/pcmcia/Kconfig" -#config MATH_EMULATION -# bool "Math emulation support (EXPERIMENTAL)" -# depends on EXPERIMENTAL -# help -# At some point in the future, this will cause floating-point math -# instructions to be emulated by the kernel on machines that lack a -# floating-point math coprocessor. Thrill-seekers and chronically -# sleep-deprived psychotic hacker types can say Y now, everyone else -# should probably wait a while. - menu "Power management options" config ARCH_SUSPEND_POSSIBLE diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index b122adc8bdbb..c616420efe8b 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2386,10 +2386,6 @@ config TC Linux driver support status is documented at: -#config ACCESSBUS -# bool "Access.Bus support" -# depends on TC - config MMU bool default y diff --git a/arch/mips/sgi-ip27/Kconfig b/arch/mips/sgi-ip27/Kconfig index bc5e9769bb73..4b2ea282b9c7 100644 --- a/arch/mips/sgi-ip27/Kconfig +++ b/arch/mips/sgi-ip27/Kconfig @@ -1,9 +1,3 @@ -#config SGI_SN0_XXL -# bool "IP27 XXL" -# depends on SGI_IP27 -# This options adds support for userspace processes up to 16TB size. -# Normally the limit is just .5TB. - choice prompt "Node addressing mode" depends on SGI_IP27 -- cgit v1.2.3 From ff5f483f30918759e78371a8deb498c46fdae051 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sun, 23 Oct 2011 17:25:59 +0200 Subject: powerpc: 4xx: remove commented out Kconfig entries These Kconfig entries have been commented out ever since commit f6557331 ("[...] Re-organize Kconfig code for 4xx in arch/powerpc"). There's no indication why they're commented out. It looks like they're just "old, unused [...] config options" that were not removed, as other entries were in that commit, but only commented out. They might as well be removed now. Signed-off-by: Paul Bolle Signed-off-by: Jiri Kosina --- arch/powerpc/platforms/40x/Kconfig | 38 -------------------------------------- arch/powerpc/platforms/44x/Kconfig | 16 ---------------- 2 files changed, 54 deletions(-) (limited to 'arch') diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index d733d7ca939c..e568e85813ae 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig @@ -1,19 +1,3 @@ -#config BUBINGA -# bool "Bubinga" -# depends on 40x -# default n -# select 405EP -# help -# This option enables support for the IBM 405EP evaluation board. - -#config CPCI405 -# bool "CPCI405" -# depends on 40x -# default n -# select 405GP -# help -# This option enables support for the CPCI405 board. - config ACADIA bool "Acadia" depends on 40x @@ -73,14 +57,6 @@ config MAKALU help This option enables support for the AMCC PPC405EX board. -#config SYCAMORE -# bool "Sycamore" -# depends on 40x -# default n -# select 405GPR -# help -# This option enables support for the IBM PPC405GPr evaluation board. - config WALNUT bool "Walnut" depends on 40x @@ -185,17 +161,3 @@ config IBM405_ERR77 # All 40x-based cores, up until the 405GPR and 405EP have this errata. config IBM405_ERR51 bool - -#config BIOS_FIXUP -# bool -# depends on BUBINGA || EP405 || SYCAMORE || WALNUT -# default y - -#config PPC4xx_DMA -# bool "PPC4xx DMA controller support" -# depends on 4xx - -#config PPC4xx_EDMA -# bool -# depends on !STB03xxx && PPC4xx_DMA -# default y diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index e958b6f48ec2..595e28a241bb 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -197,22 +197,6 @@ config ICON help This option enables support for the AMCC PPC440SPe evaluation board. -#config LUAN -# bool "Luan" -# depends on 44x -# default n -# select 440SP -# help -# This option enables support for the IBM PPC440SP evaluation board. - -#config OCOTEA -# bool "Ocotea" -# depends on 44x -# default n -# select 440GX -# help -# This option enables support for the IBM PPC440GX evaluation board. - config XILINX_VIRTEX440_GENERIC_BOARD bool "Generic Xilinx Virtex 5 FXT board support" depends on 44x -- cgit v1.2.3 From 20dd5a356efcb5bf574baa9adccc775158f13ae1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 14 Oct 2011 10:35:16 +0530 Subject: plat-samsung: move to dma_transfer_direction fixup usage of dma direction by introducing dma_transfer_direction, this patch moves samsung drivers to use new enum Cc: Ben Dooks Cc: Kukjin Kim Cc: Boojin Kim Acked-by: Kukjin Kim Signed-off-by: Vinod Koul --- arch/arm/plat-samsung/dma-ops.c | 4 ++-- arch/arm/plat-samsung/include/plat/dma-ops.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/plat-samsung/dma-ops.c b/arch/arm/plat-samsung/dma-ops.c index 6e3d9abc9e2e..3df0bad036c2 100644 --- a/arch/arm/plat-samsung/dma-ops.c +++ b/arch/arm/plat-samsung/dma-ops.c @@ -35,14 +35,14 @@ static unsigned samsung_dmadev_request(enum dma_ch dma_ch, chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch); - if (info->direction == DMA_FROM_DEVICE) { + if (info->direction == DMA_DEV_TO_MEM) { memset(&slave_config, 0, sizeof(struct dma_slave_config)); slave_config.direction = info->direction; slave_config.src_addr = info->fifo; slave_config.src_addr_width = info->width; slave_config.src_maxburst = 1; dmaengine_slave_config(chan, &slave_config); - } else if (info->direction == DMA_TO_DEVICE) { + } else if (info->direction == DMA_MEM_TO_DEV) { memset(&slave_config, 0, sizeof(struct dma_slave_config)); slave_config.direction = info->direction; slave_config.dst_addr = info->fifo; diff --git a/arch/arm/plat-samsung/include/plat/dma-ops.h b/arch/arm/plat-samsung/include/plat/dma-ops.h index 4c1a363526cf..12561152fb97 100644 --- a/arch/arm/plat-samsung/include/plat/dma-ops.h +++ b/arch/arm/plat-samsung/include/plat/dma-ops.h @@ -17,7 +17,7 @@ struct samsung_dma_prep_info { enum dma_transaction_type cap; - enum dma_data_direction direction; + enum dma_transfer_direction direction; dma_addr_t buf; unsigned long period; unsigned long len; @@ -27,7 +27,7 @@ struct samsung_dma_prep_info { struct samsung_dma_info { enum dma_transaction_type cap; - enum dma_data_direction direction; + enum dma_transfer_direction direction; enum dma_slave_buswidth width; dma_addr_t fifo; struct s3c2410_dma_client *client; -- cgit v1.2.3 From eeb3151ced1307c418e4c00433f814e210e4b899 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Tue, 11 Oct 2011 17:31:55 +0200 Subject: ARM: pxa: Fix typo 'CONFIG_BACKLIGHT_PWM__MODULE' Signed-off-by: Paul Bolle Acked-by: Marek Vasut Signed-off-by: Jiri Kosina --- arch/arm/mach-pxa/colibri-pxa270-income.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-pxa/colibri-pxa270-income.c b/arch/arm/mach-pxa/colibri-pxa270-income.c index 80538b8806ed..248804bb2c9d 100644 --- a/arch/arm/mach-pxa/colibri-pxa270-income.c +++ b/arch/arm/mach-pxa/colibri-pxa270-income.c @@ -183,7 +183,7 @@ static inline void income_lcd_init(void) {} /****************************************************************************** * Backlight ******************************************************************************/ -#if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM__MODULE) +#if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE) static struct platform_pwm_backlight_data income_backlight_data = { .pwm_id = 0, .max_brightness = 0x3ff, -- cgit v1.2.3 From bfc994b5fcdee8d29ee7a6aafc025fe0863f0f83 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sun, 30 Oct 2011 12:51:41 +0100 Subject: Kconfig: remove a few puzzling comments These comments mention CONFIG options that do not exist: not as a symbol in a Kconfig file (without the CONFIG_ prefix) and neither as a symbol (with that prefix) in the code. There's one reference to XSCALE_PMU_TIMER as a negative dependency. But XSCALE_PMU_TIMER is never defined (CONFIG_XSCALE_PMU_TIMER is also unused in the code). It shows up with type "unknown" if you search for it in menuconfig. Apparently a negative dependency on an unknown symbol is always true. That negative dependency can be removed too. Signed-off-by: Paul Bolle Signed-off-by: Jiri Kosina --- arch/arm/Kconfig | 3 +-- arch/cris/Kconfig.debug | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7536b9cbb072..49e41d6dffb9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1083,10 +1083,9 @@ config IWMMXT Enable support for iWMMXt context switching at run time if running on a CPU that supports it. -# bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER config XSCALE_PMU bool - depends on CPU_XSCALE && !XSCALE_PMU_TIMER + depends on CPU_XSCALE default y config CPU_HAS_PMU diff --git a/arch/cris/Kconfig.debug b/arch/cris/Kconfig.debug index 0b9a630dc812..14881e81e8a3 100644 --- a/arch/cris/Kconfig.debug +++ b/arch/cris/Kconfig.debug @@ -1,6 +1,5 @@ menu "Kernel hacking" -#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC config PROFILING bool "Kernel profiling support" -- cgit v1.2.3 From f854b5bc264023b21bbcb4b358cd858d5d45a4cb Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Wed, 12 Oct 2011 14:04:22 +0200 Subject: ARM: imx: Fix typo 'MACH_MX31_3DS_MXC_NAND_USE_BBT' Signed-off-by: Paul Bolle Tested-by: Fabio Estevam Signed-off-by: Jiri Kosina --- arch/arm/mach-imx/mach-mx31_3ds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c index c20be7530927..5750ca55c1f7 100644 --- a/arch/arm/mach-imx/mach-mx31_3ds.c +++ b/arch/arm/mach-imx/mach-mx31_3ds.c @@ -542,7 +542,7 @@ static const struct mxc_nand_platform_data mx31_3ds_nand_board_info __initconst = { .width = 1, .hw_ecc = 1, -#ifdef MACH_MX31_3DS_MXC_NAND_USE_BBT +#ifdef CONFIG_MACH_MX31_3DS_MXC_NAND_USE_BBT .flash_bbt = 1, #endif }; -- cgit v1.2.3 From b462c20e2915e6eca2fb812b4f63c94e7e042b9a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 3 Nov 2011 16:15:37 +0900 Subject: ARM: S3C64XX: Update for conversion to SAMSUNG_GPIO_EXTRA The conversion of the S3C64XX GPIOs to the generic Samsung GPIOs mean that rather than using the previous S3C24XX_GPIO_EXTRA configuration the driver now uses SAMSUNG_GPIO_EXTRA. Since SAMSUNG_GPIO_EXTRA requires the arch to include the extra space in ARCH_NR_GPIOs add it on to BOARD_NR_GPIOs (in case boards are relying on the existing reservation). Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/include/mach/gpio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio.h b/arch/arm/mach-s3c64xx/include/mach/gpio.h index 6e34c2f6e670..8b540c42d5dd 100644 --- a/arch/arm/mach-s3c64xx/include/mach/gpio.h +++ b/arch/arm/mach-s3c64xx/include/mach/gpio.h @@ -88,6 +88,6 @@ enum s3c_gpio_number { /* define the number of gpios we need to the one after the GPQ() range */ #define GPIO_BOARD_START (S3C64XX_GPQ(S3C64XX_GPIO_Q_NR) + 1) -#define BOARD_NR_GPIOS 16 +#define BOARD_NR_GPIOS (16 + CONFIG_SAMSUNG_GPIO_EXTRA) #define ARCH_NR_GPIOS (GPIO_BOARD_START + BOARD_NR_GPIOS) -- cgit v1.2.3 From 4ff13995b512cfadef44e0bf5cb15298d6094519 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 3 Nov 2011 16:15:38 +0900 Subject: ARM: SAMSUNG: Fix GPIO space reservation for S3C64xx platforms The conversion to use SAMSUNG_GPIO_EXTRA rather than S3C24XX_GPIO_EXTRA broke a number of S3C64xx boards which had been using the symbols provided to reserve a range of GPIOs for board specific use. Fix this by adding equivalent symbols for the new shared driver and updating the relevant boards to use the new symbols. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/Kconfig | 6 +++--- arch/arm/plat-samsung/Kconfig | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index 5552e048c2be..4d8c489edc04 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig @@ -188,7 +188,7 @@ config SMDK6410_WM1190_EV1 depends on MACH_SMDK6410 select REGULATOR select REGULATOR_WM8350 - select S3C24XX_GPIO_EXTRA64 + select SAMSUNG_GPIO_EXTRA64 select MFD_WM8350_I2C select MFD_WM8350_CONFIG_MODE_0 select MFD_WM8350_CONFIG_MODE_3 @@ -206,7 +206,7 @@ config SMDK6410_WM1192_EV1 depends on MACH_SMDK6410 select REGULATOR select REGULATOR_WM831X - select S3C24XX_GPIO_EXTRA64 + select SAMSUNG_GPIO_EXTRA64 select MFD_WM831X select MFD_WM831X_I2C help @@ -287,7 +287,7 @@ config MACH_WLF_CRAGG_6410 select S3C_DEV_WDT select S3C_DEV_RTC select S3C64XX_DEV_SPI - select S3C24XX_GPIO_EXTRA128 + select SAMSUNG_GPIO_EXTRA128 select I2C help Machine support for the Wolfson Cragganmore S3C6410 variant. diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index 313eb26cfa62..bb0af66bb487 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -88,12 +88,20 @@ config S5P_GPIO_DRVSTR config SAMSUNG_GPIO_EXTRA int "Number of additional GPIO pins" + default 128 if SAMSUNG_GPIO_EXTRA128 + default 64 if SAMSUNG_GPIO_EXTRA64 default 0 help Use additional GPIO space in addition to the GPIO's the SOC provides. This allows expanding the GPIO space for use with GPIO expanders. +config SAMSUNG_GPIO_EXTRA64 + bool + +config SAMSUNG_GPIO_EXTRA128 + bool + config S3C_GPIO_SPACE int "Space between gpio banks" default 0 -- cgit v1.2.3 From aaed44e1672c61b28dcae6e3d7bd5d15aef362f3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 3 Nov 2011 16:28:15 +0900 Subject: ARM: S3C64XX: Correct reservation of GPIOs for CPU module on Cragganmore The gpio_base for the PMIC on the CPU module was being incorrectly set to be the same as that for the CODEC causing the two GPIO drivers to collide. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/include/mach/crag6410.h | 3 ++- arch/arm/mach-s3c64xx/mach-crag6410.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-s3c64xx/include/mach/crag6410.h b/arch/arm/mach-s3c64xx/include/mach/crag6410.h index be9074e17dfd..1cc1cc82e754 100644 --- a/arch/arm/mach-s3c64xx/include/mach/crag6410.h +++ b/arch/arm/mach-s3c64xx/include/mach/crag6410.h @@ -17,7 +17,8 @@ #define GLENFARCLAS_PMIC_IRQ_BASE (IRQ_BOARD_START + 64) #define PCA935X_GPIO_BASE GPIO_BOARD_START -#define CODEC_GPIO_BASE (GPIO_BOARD_START + 8) +#define CODEC_GPIO_BASE (GPIO_BOARD_START + 8) #define GLENFARCLAS_PMIC_GPIO_BASE (GPIO_BOARD_START + 16) +#define BANFF_PMIC_GPIO_BASE (GPIO_BOARD_START + 32) #endif diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index d04b65448510..8b04a46e9f6d 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -500,7 +500,7 @@ static struct wm831x_touch_pdata touch_pdata __initdata = { static struct wm831x_pdata crag_pmic_pdata __initdata = { .wm831x_num = 1, .irq_base = BANFF_PMIC_IRQ_BASE, - .gpio_base = GPIO_BOARD_START + 8, + .gpio_base = BANFF_PMIC_GPIO_BASE, .backup = &banff_backup_pdata, -- cgit v1.2.3 From 731e0cc639364646d36981d90ab0b6af12b8face Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Wed, 11 Aug 2010 17:02:43 -0700 Subject: cpufreq: OMAP: cleanup for multi-SoC support, move into drivers/cpufreq Move OMAP cpufreq driver from arch/arm/mach-omap2 into drivers/cpufreq, along with a few cleanups: - generalize support for better handling of different SoCs in the OMAP - use OPP layer instead of OMAP clock internals for frequency table init Signed-off-by: Santosh Shilimkar [khilman@ti.com: move to drivers] Signed-off-by: Kevin Hilman --- arch/arm/plat-omap/Makefile | 1 - arch/arm/plat-omap/cpu-omap.c | 171 ------------------------------------------ 2 files changed, 172 deletions(-) delete mode 100644 arch/arm/plat-omap/cpu-omap.c (limited to 'arch') diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 985262242f25..a53eca33627f 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_ARCH_OMAP4) += omap_device.o obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o -obj-$(CONFIG_CPU_FREQ) += cpu-omap.o obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c deleted file mode 100644 index da4f68dbba1d..000000000000 --- a/arch/arm/plat-omap/cpu-omap.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * linux/arch/arm/plat-omap/cpu-omap.c - * - * CPU frequency scaling for OMAP - * - * Copyright (C) 2005 Nokia Corporation - * Written by Tony Lindgren - * - * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define VERY_HI_RATE 900000000 - -static struct cpufreq_frequency_table *freq_table; - -#ifdef CONFIG_ARCH_OMAP1 -#define MPU_CLK "mpu" -#else -#define MPU_CLK "virt_prcm_set" -#endif - -static struct clk *mpu_clk; - -/* TODO: Add support for SDRAM timing changes */ - -static int omap_verify_speed(struct cpufreq_policy *policy) -{ - if (freq_table) - return cpufreq_frequency_table_verify(policy, freq_table); - - if (policy->cpu) - return -EINVAL; - - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - - policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000; - policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000; - cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, - policy->cpuinfo.max_freq); - return 0; -} - -static unsigned int omap_getspeed(unsigned int cpu) -{ - unsigned long rate; - - if (cpu) - return 0; - - rate = clk_get_rate(mpu_clk) / 1000; - return rate; -} - -static int omap_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) -{ - struct cpufreq_freqs freqs; - int ret = 0; - - /* Ensure desired rate is within allowed range. Some govenors - * (ondemand) will just pass target_freq=0 to get the minimum. */ - if (target_freq < policy->min) - target_freq = policy->min; - if (target_freq > policy->max) - target_freq = policy->max; - - freqs.old = omap_getspeed(0); - freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; - freqs.cpu = 0; - - if (freqs.old == freqs.new) - return ret; - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); -#ifdef CONFIG_CPU_FREQ_DEBUG - printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n", - freqs.old, freqs.new); -#endif - ret = clk_set_rate(mpu_clk, freqs.new * 1000); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - - return ret; -} - -static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) -{ - int result = 0; - - mpu_clk = clk_get(NULL, MPU_CLK); - if (IS_ERR(mpu_clk)) - return PTR_ERR(mpu_clk); - - if (policy->cpu != 0) - return -EINVAL; - - policy->cur = policy->min = policy->max = omap_getspeed(0); - - clk_init_cpufreq_table(&freq_table); - if (freq_table) { - result = cpufreq_frequency_table_cpuinfo(policy, freq_table); - if (!result) - cpufreq_frequency_table_get_attr(freq_table, - policy->cpu); - } else { - policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; - policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, - VERY_HI_RATE) / 1000; - } - - /* FIXME: what's the actual transition time? */ - policy->cpuinfo.transition_latency = 300 * 1000; - - return 0; -} - -static int omap_cpu_exit(struct cpufreq_policy *policy) -{ - clk_exit_cpufreq_table(&freq_table); - clk_put(mpu_clk); - return 0; -} - -static struct freq_attr *omap_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - -static struct cpufreq_driver omap_driver = { - .flags = CPUFREQ_STICKY, - .verify = omap_verify_speed, - .target = omap_target, - .get = omap_getspeed, - .init = omap_cpu_init, - .exit = omap_cpu_exit, - .name = "omap", - .attr = omap_cpufreq_attr, -}; - -static int __init omap_cpufreq_init(void) -{ - return cpufreq_register_driver(&omap_driver); -} - -arch_initcall(omap_cpufreq_init); - -/* - * if ever we want to remove this, upon cleanup call: - * - * cpufreq_unregister_driver() - * cpufreq_frequency_table_put_attr() - */ - -- cgit v1.2.3 From 81559f9ad3d88c033e4ec3b6468012dbfda3b31d Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 18 Oct 2011 13:33:02 +0300 Subject: crypto: twofish-x86_64-3way - add lrw support Patch adds LRW support for twofish-x86_64-3way by using lrw_crypt(). Patch has been tested with tcrypt and automated filesystem tests. Tcrypt benchmarks results (twofish-3way/twofish-asm speed ratios): Intel Celeron T1600 (fam:6, model:15, step:13): size lrw-enc lrw-dec 16B 0.99x 1.00x 64B 1.17x 1.17x 256B 1.26x 1.27x 1024B 1.30x 1.31x 8192B 1.31x 1.32x AMD Phenom II 1055T (fam:16, model:10): size lrw-enc lrw-dec 16B 1.06x 1.01x 64B 1.08x 1.14x 256B 1.19x 1.20x 1024B 1.21x 1.22x 8192B 1.23x 1.24x Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- arch/x86/crypto/twofish_glue_3way.c | 135 ++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) (limited to 'arch') diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c index 5ede9c444c3e..fa9151df3637 100644 --- a/arch/x86/crypto/twofish_glue_3way.c +++ b/arch/x86/crypto/twofish_glue_3way.c @@ -32,6 +32,11 @@ #include #include #include +#include + +#if defined(CONFIG_CRYPTO_LRW) || defined(CONFIG_CRYPTO_LRW_MODULE) +#define HAS_LRW +#endif /* regular block cipher functions from twofish_x86_64 module */ asmlinkage void twofish_enc_blk(struct twofish_ctx *ctx, u8 *dst, @@ -432,6 +437,124 @@ static struct crypto_alg blk_ctr_alg = { }, }; +#ifdef HAS_LRW + +static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) +{ + const unsigned int bsize = TF_BLOCK_SIZE; + struct twofish_ctx *ctx = priv; + int i; + + if (nbytes == 3 * bsize) { + twofish_enc_blk_3way(ctx, srcdst, srcdst); + return; + } + + for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) + twofish_enc_blk(ctx, srcdst, srcdst); +} + +static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) +{ + const unsigned int bsize = TF_BLOCK_SIZE; + struct twofish_ctx *ctx = priv; + int i; + + if (nbytes == 3 * bsize) { + twofish_dec_blk_3way(ctx, srcdst, srcdst); + return; + } + + for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) + twofish_dec_blk(ctx, srcdst, srcdst); +} + +struct twofish_lrw_ctx { + struct lrw_table_ctx lrw_table; + struct twofish_ctx twofish_ctx; +}; + +static int lrw_twofish_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct twofish_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + err = __twofish_setkey(&ctx->twofish_ctx, key, keylen - TF_BLOCK_SIZE, + &tfm->crt_flags); + if (err) + return err; + + return lrw_init_table(&ctx->lrw_table, key + keylen - TF_BLOCK_SIZE); +} + +static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[3]; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = &ctx->twofish_ctx, + .crypt_fn = encrypt_callback, + }; + + return lrw_crypt(desc, dst, src, nbytes, &req); +} + +static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[3]; + struct lrw_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .table_ctx = &ctx->lrw_table, + .crypt_ctx = &ctx->twofish_ctx, + .crypt_fn = decrypt_callback, + }; + + return lrw_crypt(desc, dst, src, nbytes, &req); +} + +static void lrw_exit_tfm(struct crypto_tfm *tfm) +{ + struct twofish_lrw_ctx *ctx = crypto_tfm_ctx(tfm); + + lrw_free_table(&ctx->lrw_table); +} + +static struct crypto_alg blk_lrw_alg = { + .cra_name = "lrw(twofish)", + .cra_driver_name = "lrw-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = TF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct twofish_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_lrw_alg.cra_list), + .cra_exit = lrw_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE + TF_BLOCK_SIZE, + .max_keysize = TF_MAX_KEY_SIZE + TF_BLOCK_SIZE, + .ivsize = TF_BLOCK_SIZE, + .setkey = lrw_twofish_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}; + +#endif + int __init init(void) { int err; @@ -445,9 +568,18 @@ int __init init(void) err = crypto_register_alg(&blk_ctr_alg); if (err) goto ctr_err; +#ifdef HAS_LRW + err = crypto_register_alg(&blk_lrw_alg); + if (err) + goto blk_lrw_err; +#endif return 0; +#ifdef HAS_LRW +blk_lrw_err: + crypto_unregister_alg(&blk_ctr_alg); +#endif ctr_err: crypto_unregister_alg(&blk_cbc_alg); cbc_err: @@ -458,6 +590,9 @@ ecb_err: void __exit fini(void) { +#ifdef HAS_LRW + crypto_unregister_alg(&blk_lrw_alg); +#endif crypto_unregister_alg(&blk_ctr_alg); crypto_unregister_alg(&blk_cbc_alg); crypto_unregister_alg(&blk_ecb_alg); -- cgit v1.2.3 From bae6d3038b7faff187f4207448a40b9912cf787d Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 18 Oct 2011 13:33:43 +0300 Subject: crypto: twofish-x86_64-3way - add xts support Patch adds XTS support for twofish-x86_64-3way by using xts_crypt(). Patch has been tested with tcrypt and automated filesystem tests. Tcrypt benchmarks results (twofish-3way/twofish-asm speed ratios): Intel Celeron T1600 (fam:6, model:15, step:13): size xts-enc xts-dec 16B 0.98x 1.00x 64B 1.14x 1.15x 256B 1.23x 1.25x 1024B 1.26x 1.29x 8192B 1.28x 1.30x AMD Phenom II 1055T (fam:16, model:10): size xts-enc xts-dec 16B 1.03x 1.03x 64B 1.13x 1.16x 256B 1.20x 1.20x 1024B 1.22x 1.22x 8192B 1.22x 1.21x Signed-off-by: Jussi Kivilinna Signed-off-by: Herbert Xu --- arch/x86/crypto/twofish_glue_3way.c | 119 +++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c index fa9151df3637..954f59eeb7b4 100644 --- a/arch/x86/crypto/twofish_glue_3way.c +++ b/arch/x86/crypto/twofish_glue_3way.c @@ -33,11 +33,16 @@ #include #include #include +#include #if defined(CONFIG_CRYPTO_LRW) || defined(CONFIG_CRYPTO_LRW_MODULE) #define HAS_LRW #endif +#if defined(CONFIG_CRYPTO_XTS) || defined(CONFIG_CRYPTO_XTS_MODULE) +#define HAS_XTS +#endif + /* regular block cipher functions from twofish_x86_64 module */ asmlinkage void twofish_enc_blk(struct twofish_ctx *ctx, u8 *dst, const u8 *src); @@ -437,7 +442,7 @@ static struct crypto_alg blk_ctr_alg = { }, }; -#ifdef HAS_LRW +#if defined(HAS_LRW) || defined(HAS_XTS) static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) { @@ -469,6 +474,10 @@ static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) twofish_dec_blk(ctx, srcdst, srcdst); } +#endif + +#ifdef HAS_LRW + struct twofish_lrw_ctx { struct lrw_table_ctx lrw_table; struct twofish_ctx twofish_ctx; @@ -555,6 +564,99 @@ static struct crypto_alg blk_lrw_alg = { #endif +#ifdef HAS_XTS + +struct twofish_xts_ctx { + struct twofish_ctx tweak_ctx; + struct twofish_ctx crypt_ctx; +}; + +static int xts_twofish_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct twofish_xts_ctx *ctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; + int err; + + /* key consists of keys of equal size concatenated, therefore + * the length must be even + */ + if (keylen % 2) { + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + /* first half of xts-key is for crypt */ + err = __twofish_setkey(&ctx->crypt_ctx, key, keylen / 2, flags); + if (err) + return err; + + /* second half of xts-key is for tweak */ + return __twofish_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2, + flags); +} + +static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[3]; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = &ctx->tweak_ctx, + .tweak_fn = XTS_TWEAK_CAST(twofish_enc_blk), + .crypt_ctx = &ctx->crypt_ctx, + .crypt_fn = encrypt_callback, + }; + + return xts_crypt(desc, dst, src, nbytes, &req); +} + +static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + be128 buf[3]; + struct xts_crypt_req req = { + .tbuf = buf, + .tbuflen = sizeof(buf), + + .tweak_ctx = &ctx->tweak_ctx, + .tweak_fn = XTS_TWEAK_CAST(twofish_enc_blk), + .crypt_ctx = &ctx->crypt_ctx, + .crypt_fn = decrypt_callback, + }; + + return xts_crypt(desc, dst, src, nbytes, &req); +} + +static struct crypto_alg blk_xts_alg = { + .cra_name = "xts(twofish)", + .cra_driver_name = "xts-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = TF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct twofish_xts_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_xts_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE * 2, + .max_keysize = TF_MAX_KEY_SIZE * 2, + .ivsize = TF_BLOCK_SIZE, + .setkey = xts_twofish_setkey, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, + }, + }, +}; + +#endif + int __init init(void) { int err; @@ -573,13 +675,23 @@ int __init init(void) if (err) goto blk_lrw_err; #endif +#ifdef HAS_XTS + err = crypto_register_alg(&blk_xts_alg); + if (err) + goto blk_xts_err; +#endif return 0; +#ifdef HAS_XTS + crypto_unregister_alg(&blk_xts_alg); +blk_xts_err: +#endif #ifdef HAS_LRW + crypto_unregister_alg(&blk_lrw_alg); blk_lrw_err: - crypto_unregister_alg(&blk_ctr_alg); #endif + crypto_unregister_alg(&blk_ctr_alg); ctr_err: crypto_unregister_alg(&blk_cbc_alg); cbc_err: @@ -590,6 +702,9 @@ ecb_err: void __exit fini(void) { +#ifdef HAS_XTS + crypto_unregister_alg(&blk_xts_alg); +#endif #ifdef HAS_LRW crypto_unregister_alg(&blk_lrw_alg); #endif -- cgit v1.2.3 From 6e3e939f3b1bf8534b32ad09ff199d88800835a0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Nov 2011 10:15:42 +0100 Subject: net: add wireless TX status socket option The 802.1X EAPOL handshake hostapd does requires knowing whether the frame was ack'ed by the peer. Currently, we fudge this pretty badly by not even transmitting the frame as a normal data frame but injecting it with radiotap and getting the status out of radiotap monitor as well. This is rather complex, confuses users (mon.wlan0 presence) and doesn't work with all hardware. To get rid of that hack, introduce a real wifi TX status option for data frame transmissions. This works similar to the existing TX timestamping in that it reflects the SKB back to the socket's error queue with a SCM_WIFI_STATUS cmsg that has an int indicating ACK status (0/1). Since it is possible that at some point we will want to have TX timestamping and wifi status in a single errqueue SKB (there's little point in not doing that), redefine SO_EE_ORIGIN_TIMESTAMPING to SO_EE_ORIGIN_TXSTATUS which can collect more than just the timestamp; keep the old constant as an alias of course. Currently the internal APIs don't make that possible, but it wouldn't be hard to split them up in a way that makes it possible. Thanks to Neil Horman for helping me figure out the functions that add the control messages. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- arch/alpha/include/asm/socket.h | 3 +++ arch/arm/include/asm/socket.h | 3 +++ arch/avr32/include/asm/socket.h | 3 +++ arch/cris/include/asm/socket.h | 3 +++ arch/frv/include/asm/socket.h | 3 +++ arch/h8300/include/asm/socket.h | 3 +++ arch/ia64/include/asm/socket.h | 3 +++ arch/m32r/include/asm/socket.h | 3 +++ arch/m68k/include/asm/socket.h | 3 +++ arch/mips/include/asm/socket.h | 3 +++ arch/mn10300/include/asm/socket.h | 3 +++ arch/parisc/include/asm/socket.h | 3 +++ arch/powerpc/include/asm/socket.h | 3 +++ arch/s390/include/asm/socket.h | 3 +++ arch/sparc/include/asm/socket.h | 3 +++ arch/xtensa/include/asm/socket.h | 3 +++ 16 files changed, 48 insertions(+) (limited to 'arch') diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h index 06edfefc3373..082355f159e6 100644 --- a/arch/alpha/include/asm/socket.h +++ b/arch/alpha/include/asm/socket.h @@ -69,6 +69,9 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/arch/arm/include/asm/socket.h b/arch/arm/include/asm/socket.h index 90ffd04b8e74..dec6f9afb3cf 100644 --- a/arch/arm/include/asm/socket.h +++ b/arch/arm/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/avr32/include/asm/socket.h b/arch/avr32/include/asm/socket.h index c8d1fae49476..247b88c760be 100644 --- a/arch/avr32/include/asm/socket.h +++ b/arch/avr32/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* __ASM_AVR32_SOCKET_H */ diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h index 1a4a61909ca8..e269264df7c4 100644 --- a/arch/cris/include/asm/socket.h +++ b/arch/cris/include/asm/socket.h @@ -64,6 +64,9 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/include/asm/socket.h b/arch/frv/include/asm/socket.h index a6b26880c1ec..ce80fdadcce5 100644 --- a/arch/frv/include/asm/socket.h +++ b/arch/frv/include/asm/socket.h @@ -62,5 +62,8 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h index 04c0f4596eb5..cf1daab6f27e 100644 --- a/arch/h8300/include/asm/socket.h +++ b/arch/h8300/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/ia64/include/asm/socket.h b/arch/ia64/include/asm/socket.h index 51427eaa51ba..4b03664e3fb5 100644 --- a/arch/ia64/include/asm/socket.h +++ b/arch/ia64/include/asm/socket.h @@ -71,4 +71,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_IA64_SOCKET_H */ diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h index 469787c30098..e8b8c5bb053c 100644 --- a/arch/m32r/include/asm/socket.h +++ b/arch/m32r/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_M32R_SOCKET_H */ diff --git a/arch/m68k/include/asm/socket.h b/arch/m68k/include/asm/socket.h index 9bf49c87d954..d4708ce466e0 100644 --- a/arch/m68k/include/asm/socket.h +++ b/arch/m68k/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/mips/include/asm/socket.h b/arch/mips/include/asm/socket.h index 9de5190f2487..ad5c0a7a02a7 100644 --- a/arch/mips/include/asm/socket.h +++ b/arch/mips/include/asm/socket.h @@ -82,6 +82,9 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #ifdef __KERNEL__ /** sock_type - Socket types diff --git a/arch/mn10300/include/asm/socket.h b/arch/mn10300/include/asm/socket.h index 4e60c4281288..876356d78522 100644 --- a/arch/mn10300/include/asm/socket.h +++ b/arch/mn10300/include/asm/socket.h @@ -62,4 +62,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h index 225b7d6a1a0a..d28c51b61067 100644 --- a/arch/parisc/include/asm/socket.h +++ b/arch/parisc/include/asm/socket.h @@ -61,6 +61,9 @@ #define SO_RXQ_OVFL 0x4021 +#define SO_WIFI_STATUS 0x4022 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h index 866f7606da68..2fc2af8fbf59 100644 --- a/arch/powerpc/include/asm/socket.h +++ b/arch/powerpc/include/asm/socket.h @@ -69,4 +69,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/arch/s390/include/asm/socket.h b/arch/s390/include/asm/socket.h index fdff1e995c73..67b5c1b14b51 100644 --- a/arch/s390/include/asm/socket.h +++ b/arch/s390/include/asm/socket.h @@ -70,4 +70,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _ASM_SOCKET_H */ diff --git a/arch/sparc/include/asm/socket.h b/arch/sparc/include/asm/socket.h index 9d3fefcff2f5..8af1b64168b3 100644 --- a/arch/sparc/include/asm/socket.h +++ b/arch/sparc/include/asm/socket.h @@ -58,6 +58,9 @@ #define SO_RXQ_OVFL 0x0024 +#define SO_WIFI_STATUS 0x0025 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h index cbdf2ffaacff..bb06968be227 100644 --- a/arch/xtensa/include/asm/socket.h +++ b/arch/xtensa/include/asm/socket.h @@ -73,4 +73,7 @@ #define SO_RXQ_OVFL 40 +#define SO_WIFI_STATUS 41 +#define SCM_WIFI_STATUS SO_WIFI_STATUS + #endif /* _XTENSA_SOCKET_H */ -- cgit v1.2.3 From 650e3f0d66ade2a614d854765dae3bbc9a87f58d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Nov 2011 10:33:03 -0800 Subject: ARM: msm: Consolidate and move DEBUG_LL to DEBUG_LL choice Now that DEBUG_LL is a choice we can move MSM's homegrown choice menu to DEBUG_LL. Signed-off-by: Stephen Boyd Signed-off-by: David Brown --- arch/arm/Kconfig.debug | 21 ++++++++++++++++ arch/arm/mach-msm/Kconfig | 32 ------------------------- arch/arm/mach-msm/include/mach/debug-macro.S | 19 +++------------ arch/arm/mach-msm/include/mach/msm_iomap-7x00.h | 12 ---------- arch/arm/mach-msm/include/mach/msm_iomap-7x30.h | 12 ---------- arch/arm/mach-msm/include/mach/msm_iomap-8x50.h | 12 ---------- arch/arm/mach-msm/include/mach/msm_iomap.h | 12 ++++++++++ arch/arm/mach-msm/io.c | 9 ++++--- 8 files changed, 42 insertions(+), 87 deletions(-) (limited to 'arch') diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index c5213e78606b..333b6a416d2f 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -247,6 +247,27 @@ choice their output to the standard serial port on the RealView PB1176 platform. + config DEBUG_MSM_UART1 + bool "Kernel low-level debugging messages via MSM UART1" + depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50 + help + Say Y here if you want the debug print routines to direct + their output to the first serial port on MSM devices. + + config DEBUG_MSM_UART2 + bool "Kernel low-level debugging messages via MSM UART2" + depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50 + help + Say Y here if you want the debug print routines to direct + their output to the second serial port on MSM devices. + + config DEBUG_MSM_UART3 + bool "Kernel low-level debugging messages via MSM UART3" + depends on ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50 + help + Say Y here if you want the debug print routines to direct + their output to the third serial port on MSM devices. + endchoice config EARLY_PRINTK diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index ebde97f5d5f0..5b07b6104e5d 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -13,7 +13,6 @@ config ARCH_MSM7X00A select CPU_V6 select GPIO_MSM_V1 select MSM_PROC_COMM - select HAS_MSM_DEBUG_UART_PHYS config ARCH_MSM7X30 bool "MSM7x30" @@ -25,7 +24,6 @@ config ARCH_MSM7X30 select MSM_GPIOMUX select GPIO_MSM_V1 select MSM_PROC_COMM - select HAS_MSM_DEBUG_UART_PHYS config ARCH_QSD8X50 bool "QSD8X50" @@ -37,7 +35,6 @@ config ARCH_QSD8X50 select MSM_GPIOMUX select GPIO_MSM_V1 select MSM_PROC_COMM - select HAS_MSM_DEBUG_UART_PHYS config ARCH_MSM8X60 bool "MSM8X60" @@ -73,9 +70,6 @@ config ARCH_MSM_ARM11 config ARCH_MSM_SCORPION bool -config HAS_MSM_DEBUG_UART_PHYS - bool - config MSM_VIC bool @@ -152,32 +146,6 @@ config MACH_MSM8960_RUMI3 endmenu -config MSM_DEBUG_UART - int - default 1 if MSM_DEBUG_UART1 - default 2 if MSM_DEBUG_UART2 - default 3 if MSM_DEBUG_UART3 - -if HAS_MSM_DEBUG_UART_PHYS -choice - prompt "Debug UART" - - default MSM_DEBUG_UART_NONE - - config MSM_DEBUG_UART_NONE - bool "None" - - config MSM_DEBUG_UART1 - bool "UART1" - - config MSM_DEBUG_UART2 - bool "UART2" - - config MSM_DEBUG_UART3 - bool "UART3" -endchoice -endif - config MSM_SMD_PKG3 bool diff --git a/arch/arm/mach-msm/include/mach/debug-macro.S b/arch/arm/mach-msm/include/mach/debug-macro.S index 2dc73ccddb11..db1f22830d64 100644 --- a/arch/arm/mach-msm/include/mach/debug-macro.S +++ b/arch/arm/mach-msm/include/mach/debug-macro.S @@ -1,4 +1,4 @@ -/* arch/arm/mach-msm7200/include/mach/debug-macro.S +/* * * Copyright (C) 2007 Google, Inc. * Author: Brian Swetland @@ -14,15 +14,14 @@ * */ - - #include #include -#if defined(CONFIG_HAS_MSM_DEBUG_UART_PHYS) && !defined(CONFIG_MSM_DEBUG_UART_NONE) .macro addruart, rp, rv, tmp +#ifdef MSM_DEBUG_UART_PHYS ldr \rp, =MSM_DEBUG_UART_PHYS ldr \rv, =MSM_DEBUG_UART_BASE +#endif .endm .macro senduart,rd,rx @@ -36,18 +35,6 @@ tst \rd, #0x04 beq 1001b .endm -#else - .macro addruart, rp, rv, tmp - mov \rv, #0xff000000 - orr \rv, \rv, #0x00f00000 - .endm - - .macro senduart,rd,rx - .endm - - .macro waituart,rd,rx - .endm -#endif .macro busyuart,rd,rx .endm diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h index 94fe9fe6feb3..8af46123dab6 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x00.h @@ -78,18 +78,6 @@ #define MSM_UART3_PHYS 0xA9C00000 #define MSM_UART3_SIZE SZ_4K -#ifdef CONFIG_MSM_DEBUG_UART -#define MSM_DEBUG_UART_BASE 0xE1000000 -#if CONFIG_MSM_DEBUG_UART == 1 -#define MSM_DEBUG_UART_PHYS MSM_UART1_PHYS -#elif CONFIG_MSM_DEBUG_UART == 2 -#define MSM_DEBUG_UART_PHYS MSM_UART2_PHYS -#elif CONFIG_MSM_DEBUG_UART == 3 -#define MSM_DEBUG_UART_PHYS MSM_UART3_PHYS -#endif -#define MSM_DEBUG_UART_SIZE SZ_4K -#endif - #define MSM_SDC1_PHYS 0xA0400000 #define MSM_SDC1_SIZE SZ_4K diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h index 37694442d1bd..198202c267c8 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap-7x30.h @@ -89,18 +89,6 @@ #define MSM_UART3_PHYS 0xACC00000 #define MSM_UART3_SIZE SZ_4K -#ifdef CONFIG_MSM_DEBUG_UART -#define MSM_DEBUG_UART_BASE 0xE1000000 -#if CONFIG_MSM_DEBUG_UART == 1 -#define MSM_DEBUG_UART_PHYS MSM_UART1_PHYS -#elif CONFIG_MSM_DEBUG_UART == 2 -#define MSM_DEBUG_UART_PHYS MSM_UART2_PHYS -#elif CONFIG_MSM_DEBUG_UART == 3 -#define MSM_DEBUG_UART_PHYS MSM_UART3_PHYS -#endif -#define MSM_DEBUG_UART_SIZE SZ_4K -#endif - #define MSM_MDC_BASE IOMEM(0xE0200000) #define MSM_MDC_PHYS 0xAA500000 #define MSM_MDC_SIZE SZ_1M diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h index d67cd73316f4..0faa894729b7 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x50.h @@ -83,18 +83,6 @@ #define MSM_UART3_PHYS 0xA9C00000 #define MSM_UART3_SIZE SZ_4K -#ifdef CONFIG_MSM_DEBUG_UART -#define MSM_DEBUG_UART_BASE 0xE1000000 -#if CONFIG_MSM_DEBUG_UART == 1 -#define MSM_DEBUG_UART_PHYS MSM_UART1_PHYS -#elif CONFIG_MSM_DEBUG_UART == 2 -#define MSM_DEBUG_UART_PHYS MSM_UART2_PHYS -#elif CONFIG_MSM_DEBUG_UART == 3 -#define MSM_DEBUG_UART_PHYS MSM_UART3_PHYS -#endif -#define MSM_DEBUG_UART_SIZE SZ_4K -#endif - #define MSM_MDC_BASE IOMEM(0xE0200000) #define MSM_MDC_PHYS 0xAA500000 #define MSM_MDC_SIZE SZ_1M diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h index 4ded15238b60..90682f4599d3 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap.h @@ -55,6 +55,18 @@ #include "msm_iomap-8960.h" +#define MSM_DEBUG_UART_SIZE SZ_4K +#if defined(CONFIG_DEBUG_MSM_UART1) +#define MSM_DEBUG_UART_BASE 0xE1000000 +#define MSM_DEBUG_UART_PHYS MSM_UART1_PHYS +#elif defined(CONFIG_DEBUG_MSM_UART2) +#define MSM_DEBUG_UART_BASE 0xE1000000 +#define MSM_DEBUG_UART_PHYS MSM_UART2_PHYS +#elif defined(CONFIG_DEBUG_MSM_UART3) +#define MSM_DEBUG_UART_BASE 0xE1000000 +#define MSM_DEBUG_UART_PHYS MSM_UART3_PHYS +#endif + /* Virtual addresses shared across all MSM targets. */ #define MSM_CSR_BASE IOMEM(0xE0001000) #define MSM_QGIC_DIST_BASE IOMEM(0xF0000000) diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index 8759ecf7454f..03036afe6266 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -47,7 +47,8 @@ static struct map_desc msm_io_desc[] __initdata = { MSM_CHIP_DEVICE(GPIO1, MSM7X00), MSM_CHIP_DEVICE(GPIO2, MSM7X00), MSM_DEVICE(CLK_CTL), -#ifdef CONFIG_MSM_DEBUG_UART +#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \ + defined(CONFIG_DEBUG_MSM_UART3) MSM_DEVICE(DEBUG_UART), #endif #ifdef CONFIG_ARCH_MSM7X30 @@ -84,7 +85,8 @@ static struct map_desc qsd8x50_io_desc[] __initdata = { MSM_DEVICE(SCPLL), MSM_DEVICE(AD5), MSM_DEVICE(MDC), -#ifdef CONFIG_MSM_DEBUG_UART +#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \ + defined(CONFIG_DEBUG_MSM_UART3) MSM_DEVICE(DEBUG_UART), #endif { @@ -146,7 +148,8 @@ static struct map_desc msm7x30_io_desc[] __initdata = { MSM_DEVICE(SAW), MSM_DEVICE(GCC), MSM_DEVICE(TCSR), -#ifdef CONFIG_MSM_DEBUG_UART +#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \ + defined(CONFIG_DEBUG_MSM_UART3) MSM_DEVICE(DEBUG_UART), #endif { -- cgit v1.2.3 From a3d3ef9d4fd57cfd407c8d2d0a7daec000468ebf Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Nov 2011 10:33:04 -0800 Subject: msm: Support DEBUG_LL on MSM8660 and MSM8960 Add support for DEBUG_LL on the 8660 and 8960 development boards. While we're here cleanup the uncompress.h code a bit. Avoid the use of readl/writel as those are Linux specific APIs that aren't guaranteed to work in the decompressor. Cc: Nicolas Pitre Signed-off-by: Stephen Boyd Acked-by: Nicolas Pitre Signed-off-by: David Brown --- arch/arm/Kconfig.debug | 16 ++++++++++ arch/arm/mach-msm/Kconfig | 3 ++ arch/arm/mach-msm/include/mach/debug-macro.S | 32 ++++++++++++++++++-- arch/arm/mach-msm/include/mach/msm_iomap-8960.h | 5 ++++ arch/arm/mach-msm/include/mach/msm_iomap-8x60.h | 5 ++++ arch/arm/mach-msm/include/mach/uncompress.h | 39 ++++++++++++++++++++----- arch/arm/mach-msm/io.c | 6 ++++ 7 files changed, 95 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 333b6a416d2f..4c1eb7dd2a7e 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -268,6 +268,22 @@ choice Say Y here if you want the debug print routines to direct their output to the third serial port on MSM devices. + config DEBUG_MSM8660_UART + bool "Kernel low-level debugging messages via MSM 8660 UART" + depends on ARCH_MSM8X60 + select MSM_HAS_DEBUG_UART_HS + help + Say Y here if you want the debug print routines to direct + their output to the serial port on MSM 8660 devices. + + config DEBUG_MSM8960_UART + bool "Kernel low-level debugging messages via MSM 8960 UART" + depends on ARCH_MSM8960 + select MSM_HAS_DEBUG_UART_HS + help + Say Y here if you want the debug print routines to direct + their output to the serial port on MSM 8960 devices. + endchoice config EARLY_PRINTK diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig index 5b07b6104e5d..000ddf0a4f33 100644 --- a/arch/arm/mach-msm/Kconfig +++ b/arch/arm/mach-msm/Kconfig @@ -60,6 +60,9 @@ config ARCH_MSM8960 endchoice +config MSM_HAS_DEBUG_UART_HS + bool + config MSM_SOC_REV_A bool config ARCH_MSM_SCORPIONMP diff --git a/arch/arm/mach-msm/include/mach/debug-macro.S b/arch/arm/mach-msm/include/mach/debug-macro.S index db1f22830d64..3ffd8668c9a5 100644 --- a/arch/arm/mach-msm/include/mach/debug-macro.S +++ b/arch/arm/mach-msm/include/mach/debug-macro.S @@ -1,6 +1,7 @@ /* * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -24,17 +25,42 @@ #endif .endm - .macro senduart,rd,rx + .macro senduart, rd, rx +#ifdef CONFIG_MSM_HAS_DEBUG_UART_HS + @ Write the 1 character to UARTDM_TF + str \rd, [\rx, #0x70] +#else teq \rx, #0 strne \rd, [\rx, #0x0C] +#endif .endm - .macro waituart,rd,rx + .macro waituart, rd, rx +#ifdef CONFIG_MSM_HAS_DEBUG_UART_HS + @ check for TX_EMT in UARTDM_SR + ldr \rd, [\rx, #0x08] + tst \rd, #0x08 + bne 1002f + @ wait for TXREADY in UARTDM_ISR +1001: ldr \rd, [\rx, #0x14] + tst \rd, #0x80 + beq 1001b +1002: + @ Clear TX_READY by writing to the UARTDM_CR register + mov \rd, #0x300 + str \rd, [\rx, #0x10] + @ Write 0x1 to NCF register + mov \rd, #0x1 + str \rd, [\rx, #0x40] + @ UARTDM reg. Read to induce delay + ldr \rd, [\rx, #0x08] +#else @ wait for TX_READY 1001: ldr \rd, [\rx, #0x08] tst \rd, #0x04 beq 1001b +#endif .endm - .macro busyuart,rd,rx + .macro busyuart, rd, rx .endm diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8960.h b/arch/arm/mach-msm/include/mach/msm_iomap-8960.h index 3c9d9602a318..800b55767e6b 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap-8960.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap-8960.h @@ -45,4 +45,9 @@ #define MSM8960_TMR0_PHYS 0x0208A000 #define MSM8960_TMR0_SIZE SZ_4K +#ifdef CONFIG_DEBUG_MSM8960_UART +#define MSM_DEBUG_UART_BASE 0xE1040000 +#define MSM_DEBUG_UART_PHYS 0x16440000 +#endif + #endif diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h index 3b19b8f244b8..54e12caa8d86 100644 --- a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h +++ b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h @@ -62,4 +62,9 @@ #define MSM8X60_TMR0_PHYS 0x02040000 #define MSM8X60_TMR0_SIZE SZ_4K +#ifdef CONFIG_DEBUG_MSM8660_UART +#define MSM_DEBUG_UART_BASE 0xE1040000 +#define MSM_DEBUG_UART_PHYS 0x19C40000 +#endif + #endif diff --git a/arch/arm/mach-msm/include/mach/uncompress.h b/arch/arm/mach-msm/include/mach/uncompress.h index d94292c29d8e..169a84007456 100644 --- a/arch/arm/mach-msm/include/mach/uncompress.h +++ b/arch/arm/mach-msm/include/mach/uncompress.h @@ -1,6 +1,6 @@ -/* arch/arm/mach-msm/include/mach/uncompress.h - * +/* * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -14,17 +14,40 @@ */ #ifndef __ASM_ARCH_MSM_UNCOMPRESS_H +#define __ASM_ARCH_MSM_UNCOMPRESS_H + +#include +#include + +#define UART_CSR (*(volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x08)) +#define UART_TF (*(volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x0c)) -#include "hardware.h" -#include "linux/io.h" -#include "mach/msm_iomap.h" +#define UART_DM_SR (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x08))) +#define UART_DM_CR (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x10))) +#define UART_DM_ISR (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x14))) +#define UART_DM_NCHAR (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x40))) +#define UART_DM_TF (*((volatile uint32_t *)(MSM_DEBUG_UART_PHYS + 0x70))) static void putc(int c) { #if defined(MSM_DEBUG_UART_PHYS) - unsigned base = MSM_DEBUG_UART_PHYS; - while (!(readl(base + 0x08) & 0x04)) ; - writel(c, base + 0x0c); +#ifdef CONFIG_MSM_HAS_DEBUG_UART_HS + /* + * Wait for TX_READY to be set; but skip it if we have a + * TX underrun. + */ + if (UART_DM_SR & 0x08) + while (!(UART_DM_ISR & 0x80)) + cpu_relax(); + + UART_DM_CR = 0x300; + UART_DM_NCHAR = 0x1; + UART_DM_TF = c; +#else + while (!(UART_CSR & 0x04)) + cpu_relax(); + UART_TF = c; +#endif #endif } diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c index 03036afe6266..578b04e42deb 100644 --- a/arch/arm/mach-msm/io.c +++ b/arch/arm/mach-msm/io.c @@ -111,6 +111,9 @@ static struct map_desc msm8x60_io_desc[] __initdata = { MSM_CHIP_DEVICE(TMR0, MSM8X60), MSM_DEVICE(ACC), MSM_DEVICE(GCC), +#ifdef CONFIG_DEBUG_MSM8660_UART + MSM_DEVICE(DEBUG_UART), +#endif }; void __init msm_map_msm8x60_io(void) @@ -125,6 +128,9 @@ static struct map_desc msm8960_io_desc[] __initdata = { MSM_CHIP_DEVICE(QGIC_CPU, MSM8960), MSM_CHIP_DEVICE(TMR, MSM8960), MSM_CHIP_DEVICE(TMR0, MSM8960), +#ifdef CONFIG_DEBUG_MSM8960_UART + MSM_DEVICE(DEBUG_UART), +#endif }; void __init msm_map_msm8960_io(void) -- cgit v1.2.3 From 2852ccaed4461365e6627fadb9e214a52fa3c600 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Nov 2011 10:34:03 -0800 Subject: msm: timer: Tighten #ifdef for local timer support It is more correct to only define the local timer support code when CONFIG_LOCAL_TIMERS=y. Signed-off-by: Stephen Boyd Signed-off-by: David Brown --- arch/arm/mach-msm/timer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index afeeca52fc66..1cab55983d52 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -279,7 +279,7 @@ static void __init msm_timer_init(void) } } -#ifdef CONFIG_SMP +#ifdef CONFIG_LOCAL_TIMERS int __cpuinit local_timer_setup(struct clock_event_device *evt) { static bool local_timer_inited; @@ -321,8 +321,7 @@ void local_timer_stop(struct clock_event_device *evt) evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); disable_percpu_irq(evt->irq); } - -#endif +#endif /* CONFIG_LOCAL_TIMERS */ struct sys_timer msm_timer = { .init = msm_timer_init -- cgit v1.2.3 From 4a1840755294b2a14236ee7b9c74ede261156b09 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Nov 2011 10:34:04 -0800 Subject: msm: timer: Cleanup #includes and #defines Remove unused/unnecessary #defines, #includes, and use the BIT macro appropriately. Signed-off-by: Stephen Boyd Signed-off-by: David Brown --- arch/arm/mach-msm/timer.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 1cab55983d52..ce389ca4950f 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -13,44 +13,32 @@ * */ +#include +#include #include -#include #include #include -#include -#include -#include #include #include #include +#include #include #include +#include #define TIMER_MATCH_VAL 0x0000 #define TIMER_COUNT_VAL 0x0004 #define TIMER_ENABLE 0x0008 -#define TIMER_ENABLE_CLR_ON_MATCH_EN 2 -#define TIMER_ENABLE_EN 1 +#define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1) +#define TIMER_ENABLE_EN BIT(0) #define TIMER_CLEAR 0x000C #define DGT_CLK_CTL 0x0034 -enum { - DGT_CLK_CTL_DIV_1 = 0, - DGT_CLK_CTL_DIV_2 = 1, - DGT_CLK_CTL_DIV_3 = 2, - DGT_CLK_CTL_DIV_4 = 3, -}; -#define CSR_PROTECTION 0x0020 -#define CSR_PROTECTION_EN 1 +#define DGT_CLK_CTL_DIV_4 0x3 #define GPT_HZ 32768 -enum timer_location { - LOCAL_TIMER = 0, - GLOBAL_TIMER = 1, -}; - #define MSM_GLOBAL_TIMER MSM_CLOCK_DGT /* TODO: Remove these ifdefs */ -- cgit v1.2.3 From dd15ab814149df65187943c32ca09e4eeaac0047 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Nov 2011 10:34:05 -0800 Subject: msm: timer: Use GPT for clockevents and DGT for clocksource The clocksource shouldn't stop ticking when the clockevent stops. This is exactly what happens today with MSM timers. The same hardware is used for both the clockevent and the clocksource because the ratings of the two are the same. Fix this by registering a clockevent based on the GPT and a clocksource based on the DGT. This removes any other possible configuration (e.g. a GPT clocksource and a DGT clockevent) but that shouldn't be a big issue since we want higher precision timing than high precision scheduling interrupts. Signed-off-by: Stephen Boyd Cc: Thomas Gleixner Cc: Marc Zyngier Signed-off-by: David Brown --- arch/arm/mach-msm/timer.c | 121 ++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 69 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index ce389ca4950f..405e8a925202 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -1,6 +1,7 @@ -/* linux/arch/arm/mach-msm/timer.c +/* * * Copyright (C) 2007 Google, Inc. + * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -39,7 +40,7 @@ #define GPT_HZ 32768 -#define MSM_GLOBAL_TIMER MSM_CLOCK_DGT +#define MSM_GLOBAL_TIMER MSM_CLOCK_GPT /* TODO: Remove these ifdefs */ #if defined(CONFIG_ARCH_QSD8X50) @@ -153,25 +154,10 @@ static struct msm_clock msm_clocks[] = { .set_next_event = msm_timer_set_next_event, .set_mode = msm_timer_set_mode, }, - .clocksource = { - .name = "gp_timer", - .rating = 200, - .read = msm_read_timer_count, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - }, .irq = INT_GP_TIMER_EXP, .freq = GPT_HZ, }, [MSM_CLOCK_DGT] = { - .clockevent = { - .name = "dg_timer", - .features = CLOCK_EVT_FEAT_ONESHOT, - .shift = 32 + MSM_DGT_SHIFT, - .rating = 300, - .set_next_event = msm_timer_set_next_event, - .set_mode = msm_timer_set_mode, - }, .clocksource = { .name = "dg_timer", .rating = 300, @@ -179,7 +165,6 @@ static struct msm_clock msm_clocks[] = { .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }, - .irq = INT_DEBUG_TIMER_EXP, .freq = DGT_HZ >> MSM_DGT_SHIFT, .shift = MSM_DGT_SHIFT, } @@ -187,10 +172,13 @@ static struct msm_clock msm_clocks[] = { static void __init msm_timer_init(void) { - int i; + struct msm_clock *clock; + struct clock_event_device *ce = &msm_clocks[MSM_CLOCK_GPT].clockevent; + struct clocksource *cs = &msm_clocks[MSM_CLOCK_DGT].clocksource; int res; int global_offset = 0; + if (cpu_is_msm7x01()) { msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE; msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10; @@ -213,58 +201,55 @@ static void __init msm_timer_init(void) writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); #endif - for (i = 0; i < ARRAY_SIZE(msm_clocks); i++) { - struct msm_clock *clock = &msm_clocks[i]; - struct clock_event_device *ce = &clock->clockevent; - struct clocksource *cs = &clock->clocksource; - - clock->local_counter = clock->regbase + TIMER_COUNT_VAL; - clock->global_counter = clock->local_counter + global_offset; - - writel(0, clock->regbase + TIMER_ENABLE); - writel(0, clock->regbase + TIMER_CLEAR); - writel(~0, clock->regbase + TIMER_MATCH_VAL); + clock = &msm_clocks[MSM_CLOCK_GPT]; + clock->local_counter = clock->regbase + TIMER_COUNT_VAL; - ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift); - /* allow at least 10 seconds to notice that the timer wrapped */ - ce->max_delta_ns = - clockevent_delta2ns(0xf0000000 >> clock->shift, ce); - /* 4 gets rounded down to 3 */ - ce->min_delta_ns = clockevent_delta2ns(4, ce); - ce->cpumask = cpumask_of(0); - - res = clocksource_register_hz(cs, clock->freq); - if (res) - printk(KERN_ERR "msm_timer_init: clocksource_register " - "failed for %s\n", cs->name); - - ce->irq = clock->irq; - if (cpu_is_msm8x60() || cpu_is_msm8960()) { - clock->percpu_evt = alloc_percpu(struct clock_event_device *); - if (!clock->percpu_evt) { - pr_err("msm_timer_init: memory allocation " - "failed for %s\n", ce->name); - continue; - } - - *__this_cpu_ptr(clock->percpu_evt) = ce; - res = request_percpu_irq(ce->irq, msm_timer_interrupt, - ce->name, clock->percpu_evt); - if (!res) - enable_percpu_irq(ce->irq, 0); - } else { - clock->evt = ce; - res = request_irq(ce->irq, msm_timer_interrupt, - IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING, - ce->name, &clock->evt); + writel_relaxed(0, clock->regbase + TIMER_ENABLE); + writel_relaxed(0, clock->regbase + TIMER_CLEAR); + writel_relaxed(~0, clock->regbase + TIMER_MATCH_VAL); + ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift); + /* + * allow at least 10 seconds to notice that the timer + * wrapped + */ + ce->max_delta_ns = + clockevent_delta2ns(0xf0000000 >> clock->shift, ce); + /* 4 gets rounded down to 3 */ + ce->min_delta_ns = clockevent_delta2ns(4, ce); + ce->cpumask = cpumask_of(0); + + ce->irq = clock->irq; + if (cpu_is_msm8x60() || cpu_is_msm8960()) { + clock->percpu_evt = alloc_percpu(struct clock_event_device *); + if (!clock->percpu_evt) { + pr_err("memory allocation failed for %s\n", ce->name); + goto err; } - if (res) - pr_err("msm_timer_init: request_irq failed for %s\n", - ce->name); - - clockevents_register_device(ce); + *__this_cpu_ptr(clock->percpu_evt) = ce; + res = request_percpu_irq(ce->irq, msm_timer_interrupt, + ce->name, clock->percpu_evt); + if (!res) + enable_percpu_irq(ce->irq, 0); + } else { + clock->evt = ce; + res = request_irq(ce->irq, msm_timer_interrupt, + IRQF_TIMER | IRQF_NOBALANCING | + IRQF_TRIGGER_RISING, ce->name, &clock->evt); } + + if (res) + pr_err("request_irq failed for %s\n", ce->name); + + clockevents_register_device(ce); +err: + clock = &msm_clocks[MSM_CLOCK_DGT]; + clock->local_counter = clock->regbase + TIMER_COUNT_VAL; + clock->global_counter = clock->local_counter + global_offset; + writel_relaxed(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); + res = clocksource_register_hz(cs, clock->freq); + if (res) + pr_err("clocksource_register failed for %s\n", cs->name); } #ifdef CONFIG_LOCAL_TIMERS @@ -277,8 +262,6 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt) if (!smp_processor_id()) return 0; - writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); - if (!local_timer_inited) { writel(0, clock->regbase + TIMER_ENABLE); writel(0, clock->regbase + TIMER_CLEAR); -- cgit v1.2.3 From a850c3f6446d30b47c984d3f9e45c935385fd592 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Nov 2011 10:34:06 -0800 Subject: msm: timer: Fix ONESHOT mode interrupts MSM timers don't support an interrupt enable/disable bit. Therefore, when the timer is free running it's possible for the count to wrap and the match value to match again even though a set_next_event() call hasn't been made since the last match. Workaround the lack of an interrupt enable bit by explicitly stopping the timer in the interrupt handler when the clockevent is in ONESHOT mode. This should prevent any possibility of the timer wrapping and matching more than once per set_next_event(). Signed-off-by: Stephen Boyd Cc: Thomas Gleixner Cc: Marc Zyngier Signed-off-by: David Brown --- arch/arm/mach-msm/timer.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 405e8a925202..9f3671a43314 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -81,11 +81,20 @@ enum { static struct msm_clock msm_clocks[]; +static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt); + static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = *(struct clock_event_device **)dev_id; if (evt->event_handler == NULL) return IRQ_HANDLED; + /* Stop the timer tick */ + if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { + struct msm_clock *clock = clockevent_to_clock(evt); + u32 ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE); + ctrl &= ~TIMER_ENABLE_EN; + writel_relaxed(ctrl, clock->regbase + TIMER_ENABLE); + } evt->event_handler(evt); return IRQ_HANDLED; } @@ -118,10 +127,12 @@ static int msm_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt) { struct msm_clock *clock = clockevent_to_clock(evt); - uint32_t now = readl(clock->local_counter); - uint32_t alarm = now + (cycles << clock->shift); + u32 match = cycles << clock->shift; + u32 ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE); - writel(alarm, clock->regbase + TIMER_MATCH_VAL); + writel_relaxed(0, clock->regbase + TIMER_CLEAR); + writel_relaxed(match, clock->regbase + TIMER_MATCH_VAL); + writel_relaxed(ctrl | TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); return 0; } @@ -129,19 +140,23 @@ static void msm_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { struct msm_clock *clock = clockevent_to_clock(evt); + u32 ctrl; + + ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE); + ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN); switch (mode) { case CLOCK_EVT_MODE_RESUME: case CLOCK_EVT_MODE_PERIODIC: break; case CLOCK_EVT_MODE_ONESHOT: - writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); + /* Timer is enabled in set_next_event */ break; case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: - writel(0, clock->regbase + TIMER_ENABLE); break; } + writel_relaxed(ctrl, clock->regbase + TIMER_ENABLE); } static struct msm_clock msm_clocks[] = { -- cgit v1.2.3 From 2a00c1068b2c1ae451e230ef8bd010d7b2f56f54 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Nov 2011 10:34:07 -0800 Subject: msm: timer: Remove msm_clocks[] and simplify code We can simplify the timer code now that we only use the DGT for the clocksource and the GPT for the clockevent. Get rid of the msm_clocks[] array and propagate the changes throughout the code. This reduces the lines of code in this file and improves readability. Signed-off-by: Stephen Boyd Cc: Thomas Gleixner Cc: Marc Zyngier Signed-off-by: David Brown --- arch/arm/mach-msm/timer.c | 221 ++++++++++++++++------------------------------ 1 file changed, 76 insertions(+), 145 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 9f3671a43314..fc0646442e09 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -40,8 +40,6 @@ #define GPT_HZ 32768 -#define MSM_GLOBAL_TIMER MSM_CLOCK_GPT - /* TODO: Remove these ifdefs */ #if defined(CONFIG_ARCH_QSD8X50) #define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */ @@ -57,31 +55,7 @@ #define MSM_DGT_SHIFT (5) #endif -struct msm_clock { - struct clock_event_device clockevent; - struct clocksource clocksource; - unsigned int irq; - void __iomem *regbase; - uint32_t freq; - uint32_t shift; - void __iomem *global_counter; - void __iomem *local_counter; - union { - struct clock_event_device *evt; - struct clock_event_device __percpu **percpu_evt; - }; -}; - -enum { - MSM_CLOCK_GPT, - MSM_CLOCK_DGT, - NR_TIMERS, -}; - - -static struct msm_clock msm_clocks[]; - -static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt); +static void __iomem *event_base; static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) { @@ -90,59 +64,31 @@ static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; /* Stop the timer tick */ if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { - struct msm_clock *clock = clockevent_to_clock(evt); - u32 ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE); + u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); ctrl &= ~TIMER_ENABLE_EN; - writel_relaxed(ctrl, clock->regbase + TIMER_ENABLE); + writel_relaxed(ctrl, event_base + TIMER_ENABLE); } evt->event_handler(evt); return IRQ_HANDLED; } -static cycle_t msm_read_timer_count(struct clocksource *cs) -{ - struct msm_clock *clk = container_of(cs, struct msm_clock, clocksource); - - /* - * Shift timer count down by a constant due to unreliable lower bits - * on some targets. - */ - return readl(clk->global_counter) >> clk->shift; -} - -static struct msm_clock *clockevent_to_clock(struct clock_event_device *evt) -{ -#ifdef CONFIG_SMP - int i; - for (i = 0; i < NR_TIMERS; i++) - if (evt == &(msm_clocks[i].clockevent)) - return &msm_clocks[i]; - return &msm_clocks[MSM_GLOBAL_TIMER]; -#else - return container_of(evt, struct msm_clock, clockevent); -#endif -} - static int msm_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - struct msm_clock *clock = clockevent_to_clock(evt); - u32 match = cycles << clock->shift; - u32 ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE); + u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); - writel_relaxed(0, clock->regbase + TIMER_CLEAR); - writel_relaxed(match, clock->regbase + TIMER_MATCH_VAL); - writel_relaxed(ctrl | TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); + writel_relaxed(0, event_base + TIMER_CLEAR); + writel_relaxed(cycles, event_base + TIMER_MATCH_VAL); + writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE); return 0; } static void msm_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { - struct msm_clock *clock = clockevent_to_clock(evt); u32 ctrl; - ctrl = readl_relaxed(clock->regbase + TIMER_ENABLE); + ctrl = readl_relaxed(event_base + TIMER_ENABLE); ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN); switch (mode) { @@ -156,59 +102,61 @@ static void msm_timer_set_mode(enum clock_event_mode mode, case CLOCK_EVT_MODE_SHUTDOWN: break; } - writel_relaxed(ctrl, clock->regbase + TIMER_ENABLE); + writel_relaxed(ctrl, event_base + TIMER_ENABLE); } -static struct msm_clock msm_clocks[] = { - [MSM_CLOCK_GPT] = { - .clockevent = { - .name = "gp_timer", - .features = CLOCK_EVT_FEAT_ONESHOT, - .shift = 32, - .rating = 200, - .set_next_event = msm_timer_set_next_event, - .set_mode = msm_timer_set_mode, - }, - .irq = INT_GP_TIMER_EXP, - .freq = GPT_HZ, - }, - [MSM_CLOCK_DGT] = { - .clocksource = { - .name = "dg_timer", - .rating = 300, - .read = msm_read_timer_count, - .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - }, - .freq = DGT_HZ >> MSM_DGT_SHIFT, - .shift = MSM_DGT_SHIFT, - } +static struct clock_event_device msm_clockevent = { + .name = "gp_timer", + .features = CLOCK_EVT_FEAT_ONESHOT, + .shift = 32, + .rating = 200, + .set_next_event = msm_timer_set_next_event, + .set_mode = msm_timer_set_mode, +}; + +static union { + struct clock_event_device *evt; + struct clock_event_device __percpu **percpu_evt; +} msm_evt; + +static void __iomem *source_base; + +static cycle_t msm_read_timer_count(struct clocksource *cs) +{ + /* + * Shift timer count down by a constant due to unreliable lower bits + * on some targets. + */ + return readl_relaxed(source_base + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT; +} + +static struct clocksource msm_clocksource = { + .name = "dg_timer", + .rating = 300, + .read = msm_read_timer_count, + .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static void __init msm_timer_init(void) { - struct msm_clock *clock; - struct clock_event_device *ce = &msm_clocks[MSM_CLOCK_GPT].clockevent; - struct clocksource *cs = &msm_clocks[MSM_CLOCK_DGT].clocksource; + struct clock_event_device *ce = &msm_clockevent; + struct clocksource *cs = &msm_clocksource; int res; - int global_offset = 0; - if (cpu_is_msm7x01()) { - msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE; - msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10; + event_base = MSM_CSR_BASE; + source_base = MSM_CSR_BASE + 0x10; } else if (cpu_is_msm7x30()) { - msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE + 0x04; - msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x24; + event_base = MSM_CSR_BASE + 0x04; + source_base = MSM_CSR_BASE + 0x24; } else if (cpu_is_qsd8x50()) { - msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE; - msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10; + event_base = MSM_CSR_BASE; + source_base = MSM_CSR_BASE + 0x10; } else if (cpu_is_msm8x60() || cpu_is_msm8960()) { - msm_clocks[MSM_CLOCK_GPT].regbase = MSM_TMR_BASE + 0x04; - msm_clocks[MSM_CLOCK_DGT].regbase = MSM_TMR_BASE + 0x24; - - /* Use CPU0's timer as the global timer. */ - global_offset = MSM_TMR0_BASE - MSM_TMR_BASE; + event_base = MSM_TMR_BASE + 0x04; + /* Use CPU0's timer as the global clock source. */ + source_base = MSM_TMR0_BASE + 0x24; } else BUG(); @@ -216,88 +164,71 @@ static void __init msm_timer_init(void) writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); #endif - clock = &msm_clocks[MSM_CLOCK_GPT]; - clock->local_counter = clock->regbase + TIMER_COUNT_VAL; - - writel_relaxed(0, clock->regbase + TIMER_ENABLE); - writel_relaxed(0, clock->regbase + TIMER_CLEAR); - writel_relaxed(~0, clock->regbase + TIMER_MATCH_VAL); - ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift); + writel_relaxed(0, event_base + TIMER_ENABLE); + writel_relaxed(0, event_base + TIMER_CLEAR); + writel_relaxed(~0, event_base + TIMER_MATCH_VAL); + ce->mult = div_sc(GPT_HZ, NSEC_PER_SEC, ce->shift); /* * allow at least 10 seconds to notice that the timer * wrapped */ - ce->max_delta_ns = - clockevent_delta2ns(0xf0000000 >> clock->shift, ce); + ce->max_delta_ns = clockevent_delta2ns(0xf0000000, ce); /* 4 gets rounded down to 3 */ ce->min_delta_ns = clockevent_delta2ns(4, ce); ce->cpumask = cpumask_of(0); - ce->irq = clock->irq; + ce->irq = INT_GP_TIMER_EXP; if (cpu_is_msm8x60() || cpu_is_msm8960()) { - clock->percpu_evt = alloc_percpu(struct clock_event_device *); - if (!clock->percpu_evt) { + msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *); + if (!msm_evt.percpu_evt) { pr_err("memory allocation failed for %s\n", ce->name); goto err; } - - *__this_cpu_ptr(clock->percpu_evt) = ce; + *__this_cpu_ptr(msm_evt.percpu_evt) = ce; res = request_percpu_irq(ce->irq, msm_timer_interrupt, - ce->name, clock->percpu_evt); + ce->name, msm_evt.percpu_evt); if (!res) enable_percpu_irq(ce->irq, 0); } else { - clock->evt = ce; + msm_evt.evt = ce; res = request_irq(ce->irq, msm_timer_interrupt, IRQF_TIMER | IRQF_NOBALANCING | - IRQF_TRIGGER_RISING, ce->name, &clock->evt); + IRQF_TRIGGER_RISING, ce->name, &msm_evt.evt); } if (res) pr_err("request_irq failed for %s\n", ce->name); - clockevents_register_device(ce); err: - clock = &msm_clocks[MSM_CLOCK_DGT]; - clock->local_counter = clock->regbase + TIMER_COUNT_VAL; - clock->global_counter = clock->local_counter + global_offset; - writel_relaxed(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE); - res = clocksource_register_hz(cs, clock->freq); + writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE); + res = clocksource_register_hz(cs, DGT_HZ >> MSM_DGT_SHIFT); if (res) - pr_err("clocksource_register failed for %s\n", cs->name); + pr_err("clocksource_register failed\n"); } #ifdef CONFIG_LOCAL_TIMERS int __cpuinit local_timer_setup(struct clock_event_device *evt) { - static bool local_timer_inited; - struct msm_clock *clock = &msm_clocks[MSM_GLOBAL_TIMER]; - /* Use existing clock_event for cpu 0 */ if (!smp_processor_id()) return 0; - if (!local_timer_inited) { - writel(0, clock->regbase + TIMER_ENABLE); - writel(0, clock->regbase + TIMER_CLEAR); - writel(~0, clock->regbase + TIMER_MATCH_VAL); - local_timer_inited = true; - } - evt->irq = clock->irq; + writel_relaxed(0, event_base + TIMER_ENABLE); + writel_relaxed(0, event_base + TIMER_CLEAR); + writel_relaxed(~0, event_base + TIMER_MATCH_VAL); + evt->irq = msm_clockevent.irq; evt->name = "local_timer"; - evt->features = CLOCK_EVT_FEAT_ONESHOT; - evt->rating = clock->clockevent.rating; + evt->features = msm_clockevent.features; + evt->rating = msm_clockevent.rating; evt->set_mode = msm_timer_set_mode; evt->set_next_event = msm_timer_set_next_event; - evt->shift = clock->clockevent.shift; - evt->mult = div_sc(clock->freq, NSEC_PER_SEC, evt->shift); - evt->max_delta_ns = - clockevent_delta2ns(0xf0000000 >> clock->shift, evt); + evt->shift = msm_clockevent.shift; + evt->mult = div_sc(GPT_HZ, NSEC_PER_SEC, evt->shift); + evt->max_delta_ns = clockevent_delta2ns(0xf0000000, evt); evt->min_delta_ns = clockevent_delta2ns(4, evt); - *__this_cpu_ptr(clock->percpu_evt) = evt; + *__this_cpu_ptr(msm_evt.percpu_evt) = evt; enable_percpu_irq(evt->irq, 0); - clockevents_register_device(evt); return 0; } -- cgit v1.2.3 From 2081a6b57fba2717fa4b04fe978abad238e1f9e4 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Nov 2011 10:34:08 -0800 Subject: msm: timer: Remove SoC specific #ifdefs The timer frequency is currently ifdefed in addition to setting the DGT clock's divider value on SCORPIONMP targets. Setup the frequency dynamically using the existing cpu_is_*() branches and assign a custom clocksource read function for 7x01a to get the shift out of the generic path. Signed-off-by: Stephen Boyd Cc: Thomas Gleixner Cc: Marc Zyngier Signed-off-by: David Brown --- arch/arm/mach-msm/timer.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index fc0646442e09..ca0a957d8626 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -40,20 +40,7 @@ #define GPT_HZ 32768 -/* TODO: Remove these ifdefs */ -#if defined(CONFIG_ARCH_QSD8X50) -#define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */ -#define MSM_DGT_SHIFT (0) -#elif defined(CONFIG_ARCH_MSM7X30) -#define DGT_HZ (24576000 / 4) /* 24.576 MHz (LPXO) / 4 by default */ -#define MSM_DGT_SHIFT (0) -#elif defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960) -#define DGT_HZ (27000000 / 4) /* 27 MHz (PXO) / 4 by default */ -#define MSM_DGT_SHIFT (0) -#else -#define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */ -#define MSM_DGT_SHIFT (5) -#endif +#define MSM_DGT_SHIFT 5 static void __iomem *event_base; @@ -122,19 +109,24 @@ static union { static void __iomem *source_base; static cycle_t msm_read_timer_count(struct clocksource *cs) +{ + return readl_relaxed(source_base + TIMER_COUNT_VAL); +} + +static cycle_t msm_read_timer_count_shift(struct clocksource *cs) { /* * Shift timer count down by a constant due to unreliable lower bits * on some targets. */ - return readl_relaxed(source_base + TIMER_COUNT_VAL) >> MSM_DGT_SHIFT; + return msm_read_timer_count(cs) >> MSM_DGT_SHIFT; } static struct clocksource msm_clocksource = { .name = "dg_timer", .rating = 300, .read = msm_read_timer_count, - .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)), + .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -143,27 +135,31 @@ static void __init msm_timer_init(void) struct clock_event_device *ce = &msm_clockevent; struct clocksource *cs = &msm_clocksource; int res; + u32 dgt_hz; if (cpu_is_msm7x01()) { event_base = MSM_CSR_BASE; source_base = MSM_CSR_BASE + 0x10; + dgt_hz = 19200000 >> MSM_DGT_SHIFT; /* 600 KHz */ + cs->read = msm_read_timer_count_shift; + cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)); } else if (cpu_is_msm7x30()) { event_base = MSM_CSR_BASE + 0x04; source_base = MSM_CSR_BASE + 0x24; + dgt_hz = 24576000 / 4; } else if (cpu_is_qsd8x50()) { event_base = MSM_CSR_BASE; source_base = MSM_CSR_BASE + 0x10; + dgt_hz = 19200000 / 4; } else if (cpu_is_msm8x60() || cpu_is_msm8960()) { event_base = MSM_TMR_BASE + 0x04; /* Use CPU0's timer as the global clock source. */ source_base = MSM_TMR0_BASE + 0x24; + dgt_hz = 27000000 / 4; + writel_relaxed(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); } else BUG(); -#ifdef CONFIG_ARCH_MSM_SCORPIONMP - writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); -#endif - writel_relaxed(0, event_base + TIMER_ENABLE); writel_relaxed(0, event_base + TIMER_CLEAR); writel_relaxed(~0, event_base + TIMER_MATCH_VAL); @@ -201,7 +197,7 @@ static void __init msm_timer_init(void) clockevents_register_device(ce); err: writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE); - res = clocksource_register_hz(cs, DGT_HZ >> MSM_DGT_SHIFT); + res = clocksource_register_hz(cs, dgt_hz); if (res) pr_err("clocksource_register failed\n"); } -- cgit v1.2.3 From dde7d61e7f9bf0e844df375412ec5d51650db486 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Nov 2011 10:34:09 -0800 Subject: msm: timer: Setup interrupt after registering clockevent Some bootloaders may leave a pending interrupt for the timer and thus msm_timer_interrupt() has a check for a NULL event handler. Unmask and register for the interrupt after registering the clockevent so that we can get the NULL pointer check out of the fast path. Signed-off-by: Stephen Boyd Cc: Thomas Gleixner Cc: Marc Zyngier Signed-off-by: David Brown --- arch/arm/mach-msm/timer.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index ca0a957d8626..3d80fbf34165 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -47,8 +47,6 @@ static void __iomem *event_base; static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = *(struct clock_event_device **)dev_id; - if (evt->event_handler == NULL) - return IRQ_HANDLED; /* Stop the timer tick */ if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); @@ -174,6 +172,7 @@ static void __init msm_timer_init(void) ce->cpumask = cpumask_of(0); ce->irq = INT_GP_TIMER_EXP; + clockevents_register_device(ce); if (cpu_is_msm8x60() || cpu_is_msm8960()) { msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *); if (!msm_evt.percpu_evt) { @@ -194,7 +193,6 @@ static void __init msm_timer_init(void) if (res) pr_err("request_irq failed for %s\n", ce->name); - clockevents_register_device(ce); err: writel_relaxed(TIMER_ENABLE_EN, source_base + TIMER_ENABLE); res = clocksource_register_hz(cs, dgt_hz); @@ -224,8 +222,8 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt) evt->min_delta_ns = clockevent_delta2ns(4, evt); *__this_cpu_ptr(msm_evt.percpu_evt) = evt; - enable_percpu_irq(evt->irq, 0); clockevents_register_device(evt); + enable_percpu_irq(evt->irq, 0); return 0; } -- cgit v1.2.3 From 27fdb577435e336e4b00b9e51626f9002b88a86c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Nov 2011 10:34:10 -0800 Subject: msm: timer: Use clockevents_config_and_register() Don't open code the min/max delta logic. Use the generic version instead. Also expand the number of bits we can handle because there isn't anything that says we can't handle all 32 bits. Before: max_delta_ns: 122880426391799 min_delta_ns: 122070 mult: 140737 shift: 32 After: max_delta_ns: 131071523464981 min_delta_ns: 122069 mult: 70369 shift: 31 Signed-off-by: Stephen Boyd Cc: Thomas Gleixner Cc: Marc Zyngier Signed-off-by: David Brown --- arch/arm/mach-msm/timer.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 3d80fbf34165..11d0d8f2656c 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c @@ -93,7 +93,6 @@ static void msm_timer_set_mode(enum clock_event_mode mode, static struct clock_event_device msm_clockevent = { .name = "gp_timer", .features = CLOCK_EVT_FEAT_ONESHOT, - .shift = 32, .rating = 200, .set_next_event = msm_timer_set_next_event, .set_mode = msm_timer_set_mode, @@ -161,18 +160,10 @@ static void __init msm_timer_init(void) writel_relaxed(0, event_base + TIMER_ENABLE); writel_relaxed(0, event_base + TIMER_CLEAR); writel_relaxed(~0, event_base + TIMER_MATCH_VAL); - ce->mult = div_sc(GPT_HZ, NSEC_PER_SEC, ce->shift); - /* - * allow at least 10 seconds to notice that the timer - * wrapped - */ - ce->max_delta_ns = clockevent_delta2ns(0xf0000000, ce); - /* 4 gets rounded down to 3 */ - ce->min_delta_ns = clockevent_delta2ns(4, ce); ce->cpumask = cpumask_of(0); ce->irq = INT_GP_TIMER_EXP; - clockevents_register_device(ce); + clockevents_config_and_register(ce, GPT_HZ, 4, 0xffffffff); if (cpu_is_msm8x60() || cpu_is_msm8960()) { msm_evt.percpu_evt = alloc_percpu(struct clock_event_device *); if (!msm_evt.percpu_evt) { -- cgit v1.2.3 From a528721da08a793e0cec6ef6281d404eddd6e27b Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 4 Nov 2011 15:05:24 +0000 Subject: ARM: restart: add restart hook to machine_desc record Add a restart hook to the machine_desc record so we don't have to populate all platforms with init_early methods to initialize the arm_pm_restart function pointer. Acked-by: Nicolas Pitre Acked-by: Will Deacon Acked-by: H Hartley Sweeten Acked-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/include/asm/mach/arch.h | 1 + arch/arm/kernel/setup.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'arch') diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 7d19425dd496..8aa397a5ea72 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -45,6 +45,7 @@ struct machine_desc { #ifdef CONFIG_MULTI_IRQ_HANDLER void (*handle_irq)(struct pt_regs *); #endif + void (*restart)(char, const char *); }; /* diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 7e7977ab994f..4755e2827dc3 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -922,6 +922,9 @@ void __init setup_arch(char **cmdline_p) paging_init(mdesc); request_standard_resources(mdesc); + if (mdesc->restart) + arm_pm_restart = mdesc->restart; + unflatten_device_tree(); #ifdef CONFIG_SMP -- cgit v1.2.3 From b44c350d4104265cf3a6b4355dc1ee05c16aa5de Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 1 Nov 2011 14:27:33 +0000 Subject: ARM: restart: allow platforms more flexibility specifying restart mode Change 'soft_reboot' into a more generic 'restart_mode' variable, allowing the default restart mode to be specified. Acked-by: Nicolas Pitre Acked-by: Will Deacon Acked-by: H Hartley Sweeten Signed-off-by: Russell King --- arch/arm/include/asm/mach/arch.h | 8 ++++---- arch/arm/kernel/setup.c | 4 ++-- arch/arm/mach-ebsa110/core.c | 2 +- arch/arm/mach-footbridge/cats-hw.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 8aa397a5ea72..6fe6cf0895c9 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -30,10 +30,10 @@ struct machine_desc { unsigned int video_start; /* start of video RAM */ unsigned int video_end; /* end of video RAM */ - unsigned int reserve_lp0 :1; /* never has lp0 */ - unsigned int reserve_lp1 :1; /* never has lp1 */ - unsigned int reserve_lp2 :1; /* never has lp2 */ - unsigned int soft_reboot :1; /* soft reboot */ + unsigned char reserve_lp0 :1; /* never has lp0 */ + unsigned char reserve_lp1 :1; /* never has lp1 */ + unsigned char reserve_lp2 :1; /* never has lp2 */ + char restart_mode; /* default restart mode */ void (*fixup)(struct tag *, char **, struct meminfo *); void (*reserve)(void);/* reserve mem blocks */ diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 4755e2827dc3..a753880e984b 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -902,8 +902,8 @@ void __init setup_arch(char **cmdline_p) machine_desc = mdesc; machine_name = mdesc->name; - if (mdesc->soft_reboot) - reboot_setup("s"); + if (mdesc->restart_mode) + reboot_setup(&mdesc->restart_mode); init_mm.start_code = (unsigned long) _text; init_mm.end_code = (unsigned long) _etext; diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c index d0ce8abdd4b6..ce3ed244c4b0 100644 --- a/arch/arm/mach-ebsa110/core.c +++ b/arch/arm/mach-ebsa110/core.c @@ -283,7 +283,7 @@ MACHINE_START(EBSA110, "EBSA110") .atag_offset = 0x400, .reserve_lp0 = 1, .reserve_lp2 = 1, - .soft_reboot = 1, + .restart_mode = 's', .map_io = ebsa110_map_io, .init_irq = ebsa110_init_irq, .timer = &ebsa110_timer, diff --git a/arch/arm/mach-footbridge/cats-hw.c b/arch/arm/mach-footbridge/cats-hw.c index d5f178540928..60b6774e1eaa 100644 --- a/arch/arm/mach-footbridge/cats-hw.c +++ b/arch/arm/mach-footbridge/cats-hw.c @@ -86,7 +86,7 @@ fixup_cats(struct tag *tags, char **cmdline, struct meminfo *mi) MACHINE_START(CATS, "Chalice-CATS") /* Maintainer: Philip Blundell */ .atag_offset = 0x100, - .soft_reboot = 1, + .restart_mode = 's', .fixup = fixup_cats, .map_io = footbridge_map_io, .init_irq = footbridge_init_irq, -- cgit v1.2.3 From 34adeda943e1fb10e8de022b834996e04241fa7d Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 1 Nov 2011 16:24:18 +0000 Subject: ARM: restart: add default restart modes for PXA mioa701, spitz and tosa Add a default restart mode to reflect the hard-coded restart mode found in these files. Acked-by: Nicolas Pitre Acked-by: Will Deacon Acked-by: H Hartley Sweeten Acked-by: Robert Jarzmik Signed-off-by: Russell King --- arch/arm/mach-pxa/mioa701.c | 1 + arch/arm/mach-pxa/spitz.c | 3 +++ arch/arm/mach-pxa/tosa.c | 1 + 3 files changed, 5 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index b938fc2c316a..4f47a760398f 100644 --- a/arch/arm/mach-pxa/mioa701.c +++ b/arch/arm/mach-pxa/mioa701.c @@ -752,6 +752,7 @@ static void mioa701_machine_exit(void) MACHINE_START(MIOA701, "MIO A701") .atag_offset = 0x100, + .restart_mode = 's', .map_io = &pxa27x_map_io, .init_irq = &pxa27x_init_irq, .handle_irq = &pxa27x_handle_irq, diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 953a9195f9e5..2f57d94de727 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -982,6 +982,7 @@ static void __init spitz_fixup(struct tag *tags, char **cmdline, #ifdef CONFIG_MACH_SPITZ MACHINE_START(SPITZ, "SHARP Spitz") + .restart_mode = 'g', .fixup = spitz_fixup, .map_io = pxa27x_map_io, .init_irq = pxa27x_init_irq, @@ -993,6 +994,7 @@ MACHINE_END #ifdef CONFIG_MACH_BORZOI MACHINE_START(BORZOI, "SHARP Borzoi") + .restart_mode = 'g', .fixup = spitz_fixup, .map_io = pxa27x_map_io, .init_irq = pxa27x_init_irq, @@ -1004,6 +1006,7 @@ MACHINE_END #ifdef CONFIG_MACH_AKITA MACHINE_START(AKITA, "SHARP Akita") + .restart_mode = 'g', .fixup = spitz_fixup, .map_io = pxa27x_map_io, .init_irq = pxa27x_init_irq, diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 402b0c96613b..ef6453041cf1 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -970,6 +970,7 @@ static void __init fixup_tosa(struct tag *tags, char **cmdline, } MACHINE_START(TOSA, "SHARP Tosa") + .restart_mode = 'g', .fixup = fixup_tosa, .map_io = pxa25x_map_io, .nr_irqs = TOSA_NR_IRQS, -- cgit v1.2.3 From ac15e00b1efe705b66a36d1a6a9db7f6ed524c43 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 31 Oct 2011 09:22:22 +0000 Subject: ARM: restart: move reboot failure handing into machine_restart() Move the failure to reboot into machine_restart() to always catch this condition, even if a platform decides to hook the restarting via arm_pm_restart(). Acked-by: Nicolas Pitre Acked-by: Will Deacon Acked-by: H Hartley Sweeten Acked-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/kernel/process.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 75316f0dd02a..3bda1c379776 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -114,18 +114,8 @@ void arm_machine_restart(char mode, const char *cmd) /* Push out any further dirty data, and ensure cache is empty */ flush_cache_all(); - /* - * Now call the architecture specific reboot code. - */ + /* Now call the architecture specific reboot code. */ arch_reset(mode, cmd); - - /* - * Whoops - the architecture was unable to reboot. - * Tell the user! - */ - mdelay(1000); - printk("Reboot failed -- System halted\n"); - while (1); } /* @@ -250,7 +240,15 @@ void machine_power_off(void) void machine_restart(char *cmd) { machine_shutdown(); + arm_pm_restart(reboot_mode, cmd); + + /* Give a grace period for failure to restart of 1s */ + mdelay(1000); + + /* Whoops - the platform was unable to reboot. Tell the user! */ + printk("Reboot failed -- System halted\n"); + while (1); } void __show_regs(struct pt_regs *regs) -- cgit v1.2.3 From 5aafec15bdc54cf0722696c95091d7bd674bfcad Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 1 Nov 2011 10:15:27 +0000 Subject: ARM: restart: remove argument to setup_mm_for_reboot() setup_mm_for_reboot() doesn't make use of its argument, so remove it. Acked-by: Nicolas Pitre Acked-by: Will Deacon Acked-by: H Hartley Sweeten Acked-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/kernel/machine_kexec.c | 4 ++-- arch/arm/kernel/process.c | 4 ++-- arch/arm/mm/idmap.c | 2 +- arch/arm/mm/nommu.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index c1b4463dcc83..cc40b965d42a 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c @@ -16,7 +16,7 @@ extern const unsigned char relocate_new_kernel[]; extern const unsigned int relocate_new_kernel_size; -extern void setup_mm_for_reboot(char mode); +extern void setup_mm_for_reboot(void); extern unsigned long kexec_start_address; extern unsigned long kexec_indirection_page; @@ -114,7 +114,7 @@ void machine_kexec(struct kimage *image) kexec_reinit(); local_irq_disable(); local_fiq_disable(); - setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/ + setup_mm_for_reboot(); flush_cache_all(); outer_flush_all(); outer_disable(); diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 3bda1c379776..4181738452fc 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -57,7 +57,7 @@ static const char *isa_modes[] = { "ARM" , "Thumb" , "Jazelle", "ThumbEE" }; -extern void setup_mm_for_reboot(char mode); +extern void setup_mm_for_reboot(void); static volatile int hlt_counter; @@ -103,7 +103,7 @@ void arm_machine_restart(char mode, const char *cmd) * we may need it to insert some 1:1 mappings so that * soft boot works. */ - setup_mm_for_reboot(mode); + setup_mm_for_reboot(); /* Clean and invalidate caches */ flush_cache_all(); diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c index 2be9139a4ef3..296ad2eaddb0 100644 --- a/arch/arm/mm/idmap.c +++ b/arch/arm/mm/idmap.c @@ -78,7 +78,7 @@ void identity_mapping_del(pgd_t *pgd, unsigned long addr, unsigned long end) * the user-mode pages. This will then ensure that we have predictable * results when turning the mmu off */ -void setup_mm_for_reboot(char mode) +void setup_mm_for_reboot(void) { /* * We need to access to user-mode page tables here. For kernel threads diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index 941a98c9e8aa..88417514b2c6 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c @@ -43,7 +43,7 @@ void __init paging_init(struct machine_desc *mdesc) /* * We don't need to do anything here for nommu machines. */ -void setup_mm_for_reboot(char mode) +void setup_mm_for_reboot(void) { } -- cgit v1.2.3 From 6c01ba445cecb2d8085cf0b5a6ddfb170ad22616 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 10 Nov 2011 18:45:52 -0800 Subject: ARM: mach-shmobile: R-Mobile A1 support. This adds preliminary support for the R8A7740 (R-Mobile A1) CPU Timer, serial, gic, clock are supported at this point. This patch is based on v0.1 manual Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Kconfig | 7 + arch/arm/mach-shmobile/Makefile | 2 + arch/arm/mach-shmobile/clock-r8a7740.c | 378 +++++++++++++++++ arch/arm/mach-shmobile/include/mach/common.h | 6 + arch/arm/mach-shmobile/include/mach/r8a7740.h | 584 ++++++++++++++++++++++++++ arch/arm/mach-shmobile/intc-r8a7740.c | 45 ++ arch/arm/mach-shmobile/setup-r8a7740.c | 246 +++++++++++ 7 files changed, 1268 insertions(+) create mode 100644 arch/arm/mach-shmobile/clock-r8a7740.c create mode 100644 arch/arm/mach-shmobile/include/mach/r8a7740.h create mode 100644 arch/arm/mach-shmobile/intc-r8a7740.c create mode 100644 arch/arm/mach-shmobile/setup-r8a7740.c (limited to 'arch') diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 0828fab2b65c..329a3cb7f99b 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -28,6 +28,13 @@ config ARCH_SH73A0 select ARM_GIC select I2C +config ARCH_R8A7740 + bool "R-Mobile A1 (R8A77400)" + select CPU_V7 + select SH_CLK_CPG + select ARCH_WANT_OPTIONAL_GPIOLIB + select ARM_GIC + comment "SH-Mobile Board Type" config MACH_G3EVM diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 2aec2f732515..d61f1eca159a 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_ARCH_SH7367) += setup-sh7367.o clock-sh7367.o intc-sh7367.o obj-$(CONFIG_ARCH_SH7377) += setup-sh7377.o clock-sh7377.o intc-sh7377.o obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o +obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o # SMP objects smp-y := platsmp.o headsmp.o @@ -29,6 +30,7 @@ obj-$(CONFIG_ARCH_SH7367) += entry-intc.o obj-$(CONFIG_ARCH_SH7377) += entry-intc.o obj-$(CONFIG_ARCH_SH7372) += entry-intc.o obj-$(CONFIG_ARCH_SH73A0) += entry-gic.o +obj-$(CONFIG_ARCH_R8A7740) += entry-gic.o # PM objects obj-$(CONFIG_SUSPEND) += suspend.o diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c new file mode 100644 index 000000000000..5bb02f224077 --- /dev/null +++ b/arch/arm/mach-shmobile/clock-r8a7740.c @@ -0,0 +1,378 @@ +/* + * R8A7740 processor support + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2011 Kuninori Morimoto + * + * 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 + * + * 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 +#include +#include +#include +#include +#include +#include + +/* + * | MDx | XTAL1/EXTAL1 | System | EXTALR | + * Clock |-------+-----------------+ clock | 32.768 | RCLK + * Mode | 2/1/0 | src MHz | source | KHz | source + * -------+-------+-----------------+-----------+--------+---------- + * 0 | 0 0 0 | External 20~50 | XTAL1 | O | EXTALR + * 1 | 0 0 1 | Crystal 20~30 | XTAL1 | O | EXTALR + * 2 | 0 1 0 | External 40~50 | XTAL1 / 2 | O | EXTALR + * 3 | 0 1 1 | Crystal 40~50 | XTAL1 / 2 | O | EXTALR + * 4 | 1 0 0 | External 20~50 | XTAL1 | x | XTAL1 / 1024 + * 5 | 1 0 1 | Crystal 20~30 | XTAL1 | x | XTAL1 / 1024 + * 6 | 1 1 0 | External 40~50 | XTAL1 / 2 | x | XTAL1 / 2048 + * 7 | 1 1 1 | Crystal 40~50 | XTAL1 / 2 | x | XTAL1 / 2048 + */ + +/* CPG registers */ +#define FRQCRA 0xe6150000 +#define FRQCRB 0xe6150004 +#define FRQCRC 0xe61500e0 +#define PLLC01CR 0xe6150028 + +#define SUBCKCR 0xe6150080 + +#define MSTPSR0 0xe6150030 +#define MSTPSR1 0xe6150038 +#define MSTPSR2 0xe6150040 +#define MSTPSR3 0xe6150048 +#define MSTPSR4 0xe615004c +#define SMSTPCR0 0xe6150130 +#define SMSTPCR1 0xe6150134 +#define SMSTPCR2 0xe6150138 +#define SMSTPCR3 0xe615013c +#define SMSTPCR4 0xe6150140 + +/* Fixed 32 KHz root clock from EXTALR pin */ +static struct clk extalr_clk = { + .rate = 32768, +}; + +/* + * 25MHz default rate for the EXTAL1 root input clock. + * If needed, reset this with clk_set_rate() from the platform code. + */ +static struct clk extal1_clk = { + .rate = 25000000, +}; + +/* + * 48MHz default rate for the EXTAL2 root input clock. + * If needed, reset this with clk_set_rate() from the platform code. + */ +static struct clk extal2_clk = { + .rate = 48000000, +}; + +/* + * 27MHz default rate for the DV_CLKI root input clock. + * If needed, reset this with clk_set_rate() from the platform code. + */ +static struct clk dv_clk = { + .rate = 27000000, +}; + +static unsigned long div_recalc(struct clk *clk) +{ + return clk->parent->rate / (int)(clk->priv); +} + +static struct clk_ops div_clk_ops = { + .recalc = div_recalc, +}; + +/* extal1 / 2 */ +static struct clk extal1_div2_clk = { + .ops = &div_clk_ops, + .priv = (void *)2, + .parent = &extal1_clk, +}; + +/* extal1 / 1024 */ +static struct clk extal1_div1024_clk = { + .ops = &div_clk_ops, + .priv = (void *)1024, + .parent = &extal1_clk, +}; + +/* extal1 / 2 / 1024 */ +static struct clk extal1_div2048_clk = { + .ops = &div_clk_ops, + .priv = (void *)1024, + .parent = &extal1_div2_clk, +}; + +/* extal2 / 2 */ +static struct clk extal2_div2_clk = { + .ops = &div_clk_ops, + .priv = (void *)2, + .parent = &extal2_clk, +}; + +static struct clk_ops followparent_clk_ops = { + .recalc = followparent_recalc, +}; + +/* Main clock */ +static struct clk system_clk = { + .ops = &followparent_clk_ops, +}; + +static struct clk system_div2_clk = { + .ops = &div_clk_ops, + .priv = (void *)2, + .parent = &system_clk, +}; + +/* r_clk */ +static struct clk r_clk = { + .ops = &followparent_clk_ops, +}; + +/* PLLC0/PLLC1 */ +static unsigned long pllc01_recalc(struct clk *clk) +{ + unsigned long mult = 1; + + if (__raw_readl(PLLC01CR) & (1 << 14)) + mult = ((__raw_readl(clk->enable_reg) >> 24) & 0x7f) + 1; + + return clk->parent->rate * mult; +} + +static struct clk_ops pllc01_clk_ops = { + .recalc = pllc01_recalc, +}; + +static struct clk pllc0_clk = { + .ops = &pllc01_clk_ops, + .flags = CLK_ENABLE_ON_INIT, + .parent = &system_clk, + .enable_reg = (void __iomem *)FRQCRC, +}; + +static struct clk pllc1_clk = { + .ops = &pllc01_clk_ops, + .flags = CLK_ENABLE_ON_INIT, + .parent = &system_div2_clk, + .enable_reg = (void __iomem *)FRQCRA, +}; + +/* PLLC1 / 2 */ +static struct clk pllc1_div2_clk = { + .ops = &div_clk_ops, + .priv = (void *)2, + .parent = &pllc1_clk, +}; + +struct clk *main_clks[] = { + &extalr_clk, + &extal1_clk, + &extal2_clk, + &extal1_div2_clk, + &extal1_div1024_clk, + &extal1_div2048_clk, + &extal2_div2_clk, + &dv_clk, + &system_clk, + &system_div2_clk, + &r_clk, + &pllc0_clk, + &pllc1_clk, + &pllc1_div2_clk, +}; + +static void div4_kick(struct clk *clk) +{ + unsigned long value; + + /* set KICK bit in FRQCRB to update hardware setting */ + value = __raw_readl(FRQCRB); + value |= (1 << 31); + __raw_writel(value, FRQCRB); +} + +static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18, + 24, 32, 36, 48, 0, 72, 96, 0 }; + +static struct clk_div_mult_table div4_div_mult_table = { + .divisors = divisors, + .nr_divisors = ARRAY_SIZE(divisors), +}; + +static struct clk_div4_table div4_table = { + .div_mult_table = &div4_div_mult_table, + .kick = div4_kick, +}; + +enum { + DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_HP, + DIV4_HPP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP, + DIV4_NR +}; + +struct clk div4_clks[DIV4_NR] = { + [DIV4_I] = SH_CLK_DIV4(&pllc1_clk, FRQCRA, 20, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_ZG] = SH_CLK_DIV4(&pllc1_clk, FRQCRA, 16, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_B] = SH_CLK_DIV4(&pllc1_clk, FRQCRA, 8, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_M1] = SH_CLK_DIV4(&pllc1_clk, FRQCRA, 4, 0x6fff, CLK_ENABLE_ON_INIT), + [DIV4_HP] = SH_CLK_DIV4(&pllc1_clk, FRQCRB, 4, 0x6fff, 0), + [DIV4_HPP] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 20, 0x6fff, 0), + [DIV4_S] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 12, 0x6fff, 0), + [DIV4_ZB] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 8, 0x6fff, 0), + [DIV4_M3] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 4, 0x6fff, 0), + [DIV4_CP] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 0, 0x6fff, 0), +}; + +enum { + DIV6_SUB, + DIV6_NR +}; + +static struct clk div6_clks[DIV6_NR] = { + [DIV6_SUB] = SH_CLK_DIV6(&pllc1_div2_clk, SUBCKCR, 0), +}; + +enum { + MSTP125, + MSTP116, MSTP111, + + MSTP230, + MSTP222, + MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, + + MSTP329, MSTP323, + + MSTP_NR +}; + +static struct clk mstp_clks[MSTP_NR] = { + [MSTP125] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */ + [MSTP116] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */ + [MSTP111] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR1, 11, 0), /* TMU1 */ + + [MSTP230] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 30, 0), /* SCIFA6 */ + [MSTP222] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 22, 0), /* SCIFA7 */ + [MSTP207] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */ + [MSTP206] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */ + [MSTP204] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */ + [MSTP203] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 3, 0), /* SCIFA1 */ + [MSTP202] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 2, 0), /* SCIFA2 */ + [MSTP201] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */ + [MSTP200] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ + + [MSTP329] = SH_CLK_MSTP32(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ + [MSTP323] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */ +}; + +static struct clk_lookup lookups[] = { + /* main clocks */ + CLKDEV_CON_ID("extalr", &extalr_clk), + CLKDEV_CON_ID("extal1", &extal1_clk), + CLKDEV_CON_ID("extal2", &extal2_clk), + CLKDEV_CON_ID("extal1_div2", &extal1_div2_clk), + CLKDEV_CON_ID("extal1_div1024", &extal1_div1024_clk), + CLKDEV_CON_ID("extal1_div2048", &extal1_div2048_clk), + CLKDEV_CON_ID("extal2_div2", &extal2_div2_clk), + CLKDEV_CON_ID("dv_clk", &dv_clk), + CLKDEV_CON_ID("system_clk", &system_clk), + CLKDEV_CON_ID("system_div2_clk", &system_div2_clk), + CLKDEV_CON_ID("r_clk", &r_clk), + CLKDEV_CON_ID("pllc0_clk", &pllc0_clk), + CLKDEV_CON_ID("pllc1_clk", &pllc1_clk), + CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk), + + /* DIV4 clocks */ + CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]), + CLKDEV_CON_ID("zg_clk", &div4_clks[DIV4_ZG]), + CLKDEV_CON_ID("b_clk", &div4_clks[DIV4_B]), + CLKDEV_CON_ID("m1_clk", &div4_clks[DIV4_M1]), + CLKDEV_CON_ID("hp_clk", &div4_clks[DIV4_HP]), + CLKDEV_CON_ID("hpp_clk", &div4_clks[DIV4_HPP]), + CLKDEV_CON_ID("s_clk", &div4_clks[DIV4_S]), + CLKDEV_CON_ID("zb_clk", &div4_clks[DIV4_ZB]), + CLKDEV_CON_ID("m3_clk", &div4_clks[DIV4_M3]), + CLKDEV_CON_ID("cp_clk", &div4_clks[DIV4_CP]), + + /* DIV6 clocks */ + CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), + + /* MSTP32 clocks */ + CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP111]), + CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), + CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP125]), + + CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), + CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), + CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), + CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), + CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), + CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP206]), + CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), + + CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP222]), + CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP230]), + + CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), + CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), +}; + +void __init r8a7740_clock_init(u8 md_ck) +{ + int k, ret = 0; + + /* detect system clock parent */ + if (md_ck & MD_CK1) + system_clk.parent = &extal1_div2_clk; + else + system_clk.parent = &extal1_clk; + + /* detect RCLK parent */ + switch (md_ck & (MD_CK2 | MD_CK1)) { + case MD_CK2 | MD_CK1: + r_clk.parent = &extal1_div2048_clk; + break; + case MD_CK2: + r_clk.parent = &extal1_div1024_clk; + break; + case MD_CK1: + default: + r_clk.parent = &extalr_clk; + break; + } + + for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) + ret = clk_register(main_clks[k]); + + if (!ret) + ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); + + if (!ret) + ret = sh_clk_div6_register(div6_clks, DIV6_NR); + + if (!ret) + ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + + if (!ret) + clk_init(); + else + panic("failed to setup r8a7740 clocks\n"); +} diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 834bd6cd508f..5055a00a83d4 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h @@ -53,4 +53,10 @@ extern void sh73a0_secondary_init(unsigned int cpu); extern int sh73a0_boot_secondary(unsigned int cpu); extern void sh73a0_smp_prepare_cpus(void); +extern void r8a7740_init_irq(void); +extern void r8a7740_add_early_devices(void); +extern void r8a7740_add_standard_devices(void); +extern void r8a7740_clock_init(u8 md_ck); +extern void r8a7740_pinmux_init(void); + #endif /* __ARCH_MACH_COMMON_H */ diff --git a/arch/arm/mach-shmobile/include/mach/r8a7740.h b/arch/arm/mach-shmobile/include/mach/r8a7740.h new file mode 100644 index 000000000000..9d447abb969c --- /dev/null +++ b/arch/arm/mach-shmobile/include/mach/r8a7740.h @@ -0,0 +1,584 @@ +/* + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2011 Kuninori Morimoto + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __ASM_R8A7740_H__ +#define __ASM_R8A7740_H__ + +/* + * MD_CKx pin + */ +#define MD_CK2 (1 << 2) +#define MD_CK1 (1 << 1) +#define MD_CK0 (1 << 0) + +/* + * Pin Function Controller: + * GPIO_FN_xx - GPIO used to select pin function + * GPIO_PORTxx - GPIO mapped to real I/O pin on CPU + */ +enum { + /* PORT */ + GPIO_PORT0, GPIO_PORT1, GPIO_PORT2, GPIO_PORT3, GPIO_PORT4, + GPIO_PORT5, GPIO_PORT6, GPIO_PORT7, GPIO_PORT8, GPIO_PORT9, + + GPIO_PORT10, GPIO_PORT11, GPIO_PORT12, GPIO_PORT13, GPIO_PORT14, + GPIO_PORT15, GPIO_PORT16, GPIO_PORT17, GPIO_PORT18, GPIO_PORT19, + + GPIO_PORT20, GPIO_PORT21, GPIO_PORT22, GPIO_PORT23, GPIO_PORT24, + GPIO_PORT25, GPIO_PORT26, GPIO_PORT27, GPIO_PORT28, GPIO_PORT29, + + GPIO_PORT30, GPIO_PORT31, GPIO_PORT32, GPIO_PORT33, GPIO_PORT34, + GPIO_PORT35, GPIO_PORT36, GPIO_PORT37, GPIO_PORT38, GPIO_PORT39, + + GPIO_PORT40, GPIO_PORT41, GPIO_PORT42, GPIO_PORT43, GPIO_PORT44, + GPIO_PORT45, GPIO_PORT46, GPIO_PORT47, GPIO_PORT48, GPIO_PORT49, + + GPIO_PORT50, GPIO_PORT51, GPIO_PORT52, GPIO_PORT53, GPIO_PORT54, + GPIO_PORT55, GPIO_PORT56, GPIO_PORT57, GPIO_PORT58, GPIO_PORT59, + + GPIO_PORT60, GPIO_PORT61, GPIO_PORT62, GPIO_PORT63, GPIO_PORT64, + GPIO_PORT65, GPIO_PORT66, GPIO_PORT67, GPIO_PORT68, GPIO_PORT69, + + GPIO_PORT70, GPIO_PORT71, GPIO_PORT72, GPIO_PORT73, GPIO_PORT74, + GPIO_PORT75, GPIO_PORT76, GPIO_PORT77, GPIO_PORT78, GPIO_PORT79, + + GPIO_PORT80, GPIO_PORT81, GPIO_PORT82, GPIO_PORT83, GPIO_PORT84, + GPIO_PORT85, GPIO_PORT86, GPIO_PORT87, GPIO_PORT88, GPIO_PORT89, + + GPIO_PORT90, GPIO_PORT91, GPIO_PORT92, GPIO_PORT93, GPIO_PORT94, + GPIO_PORT95, GPIO_PORT96, GPIO_PORT97, GPIO_PORT98, GPIO_PORT99, + + GPIO_PORT100, GPIO_PORT101, GPIO_PORT102, GPIO_PORT103, GPIO_PORT104, + GPIO_PORT105, GPIO_PORT106, GPIO_PORT107, GPIO_PORT108, GPIO_PORT109, + + GPIO_PORT110, GPIO_PORT111, GPIO_PORT112, GPIO_PORT113, GPIO_PORT114, + GPIO_PORT115, GPIO_PORT116, GPIO_PORT117, GPIO_PORT118, GPIO_PORT119, + + GPIO_PORT120, GPIO_PORT121, GPIO_PORT122, GPIO_PORT123, GPIO_PORT124, + GPIO_PORT125, GPIO_PORT126, GPIO_PORT127, GPIO_PORT128, GPIO_PORT129, + + GPIO_PORT130, GPIO_PORT131, GPIO_PORT132, GPIO_PORT133, GPIO_PORT134, + GPIO_PORT135, GPIO_PORT136, GPIO_PORT137, GPIO_PORT138, GPIO_PORT139, + + GPIO_PORT140, GPIO_PORT141, GPIO_PORT142, GPIO_PORT143, GPIO_PORT144, + GPIO_PORT145, GPIO_PORT146, GPIO_PORT147, GPIO_PORT148, GPIO_PORT149, + + GPIO_PORT150, GPIO_PORT151, GPIO_PORT152, GPIO_PORT153, GPIO_PORT154, + GPIO_PORT155, GPIO_PORT156, GPIO_PORT157, GPIO_PORT158, GPIO_PORT159, + + GPIO_PORT160, GPIO_PORT161, GPIO_PORT162, GPIO_PORT163, GPIO_PORT164, + GPIO_PORT165, GPIO_PORT166, GPIO_PORT167, GPIO_PORT168, GPIO_PORT169, + + GPIO_PORT170, GPIO_PORT171, GPIO_PORT172, GPIO_PORT173, GPIO_PORT174, + GPIO_PORT175, GPIO_PORT176, GPIO_PORT177, GPIO_PORT178, GPIO_PORT179, + + GPIO_PORT180, GPIO_PORT181, GPIO_PORT182, GPIO_PORT183, GPIO_PORT184, + GPIO_PORT185, GPIO_PORT186, GPIO_PORT187, GPIO_PORT188, GPIO_PORT189, + + GPIO_PORT190, GPIO_PORT191, GPIO_PORT192, GPIO_PORT193, GPIO_PORT194, + GPIO_PORT195, GPIO_PORT196, GPIO_PORT197, GPIO_PORT198, GPIO_PORT199, + + GPIO_PORT200, GPIO_PORT201, GPIO_PORT202, GPIO_PORT203, GPIO_PORT204, + GPIO_PORT205, GPIO_PORT206, GPIO_PORT207, GPIO_PORT208, GPIO_PORT209, + + GPIO_PORT210, GPIO_PORT211, + + /* IRQ */ + GPIO_FN_IRQ0_PORT2, GPIO_FN_IRQ0_PORT13, + GPIO_FN_IRQ1, + GPIO_FN_IRQ2_PORT11, GPIO_FN_IRQ2_PORT12, + GPIO_FN_IRQ3_PORT10, GPIO_FN_IRQ3_PORT14, + GPIO_FN_IRQ4_PORT15, GPIO_FN_IRQ4_PORT172, + GPIO_FN_IRQ5_PORT0, GPIO_FN_IRQ5_PORT1, + GPIO_FN_IRQ6_PORT121, GPIO_FN_IRQ6_PORT173, + GPIO_FN_IRQ7_PORT120, GPIO_FN_IRQ7_PORT209, + GPIO_FN_IRQ8, + GPIO_FN_IRQ9_PORT118, GPIO_FN_IRQ9_PORT210, + GPIO_FN_IRQ10, + GPIO_FN_IRQ11, + GPIO_FN_IRQ12_PORT42, GPIO_FN_IRQ12_PORT97, + GPIO_FN_IRQ13_PORT64, GPIO_FN_IRQ13_PORT98, + GPIO_FN_IRQ14_PORT63, GPIO_FN_IRQ14_PORT99, + GPIO_FN_IRQ15_PORT62, GPIO_FN_IRQ15_PORT100, + GPIO_FN_IRQ16_PORT68, GPIO_FN_IRQ16_PORT211, + GPIO_FN_IRQ17, + GPIO_FN_IRQ18, + GPIO_FN_IRQ19, + GPIO_FN_IRQ20, + GPIO_FN_IRQ21, + GPIO_FN_IRQ22, + GPIO_FN_IRQ23, + GPIO_FN_IRQ24, + GPIO_FN_IRQ25, + GPIO_FN_IRQ26_PORT58, GPIO_FN_IRQ26_PORT81, + GPIO_FN_IRQ27_PORT57, GPIO_FN_IRQ27_PORT168, + GPIO_FN_IRQ28_PORT56, GPIO_FN_IRQ28_PORT169, + GPIO_FN_IRQ29_PORT50, GPIO_FN_IRQ29_PORT170, + GPIO_FN_IRQ30_PORT49, GPIO_FN_IRQ30_PORT171, + GPIO_FN_IRQ31_PORT41, GPIO_FN_IRQ31_PORT167, + + /* Function */ + + /* DBGT */ + GPIO_FN_DBGMDT2, GPIO_FN_DBGMDT1, GPIO_FN_DBGMDT0, + GPIO_FN_DBGMD10, GPIO_FN_DBGMD11, GPIO_FN_DBGMD20, + GPIO_FN_DBGMD21, + + /* FSI */ + GPIO_FN_FSIAISLD_PORT0, /* FSIAISLD Port 0/5 */ + GPIO_FN_FSIAISLD_PORT5, + GPIO_FN_FSIASPDIF_PORT9, /* FSIASPDIF Port 9/18 */ + GPIO_FN_FSIASPDIF_PORT18, + GPIO_FN_FSIAOSLD1, GPIO_FN_FSIAOSLD2, + GPIO_FN_FSIAOLR, GPIO_FN_FSIAOBT, + GPIO_FN_FSIAOSLD, GPIO_FN_FSIAOMC, + GPIO_FN_FSIACK, GPIO_FN_FSIAILR, + GPIO_FN_FSIAIBT, + + /* FMSI */ + GPIO_FN_FMSISLD_PORT1, /* FMSISLD Port 1/6 */ + GPIO_FN_FMSISLD_PORT6, + GPIO_FN_FMSIILR, GPIO_FN_FMSIIBT, + GPIO_FN_FMSIOLR, GPIO_FN_FMSIOBT, + GPIO_FN_FMSICK, GPIO_FN_FMSOILR, + GPIO_FN_FMSOIBT, GPIO_FN_FMSOOLR, + GPIO_FN_FMSOOBT, GPIO_FN_FMSOSLD, + GPIO_FN_FMSOCK, + + /* SCIFA0 */ + GPIO_FN_SCIFA0_SCK, GPIO_FN_SCIFA0_CTS, + GPIO_FN_SCIFA0_RTS, GPIO_FN_SCIFA0_RXD, + GPIO_FN_SCIFA0_TXD, + + /* SCIFA1 */ + GPIO_FN_SCIFA1_CTS, GPIO_FN_SCIFA1_SCK, + GPIO_FN_SCIFA1_RXD, GPIO_FN_SCIFA1_TXD, + GPIO_FN_SCIFA1_RTS, + + /* SCIFA2 */ + GPIO_FN_SCIFA2_SCK_PORT22, /* SCIFA2_SCK Port 22/199 */ + GPIO_FN_SCIFA2_SCK_PORT199, + GPIO_FN_SCIFA2_RXD, GPIO_FN_SCIFA2_TXD, + GPIO_FN_SCIFA2_CTS, GPIO_FN_SCIFA2_RTS, + + /* SCIFA3 */ + GPIO_FN_SCIFA3_RTS_PORT105, /* MSEL5CR_8_0 */ + GPIO_FN_SCIFA3_SCK_PORT116, + GPIO_FN_SCIFA3_CTS_PORT117, + GPIO_FN_SCIFA3_RXD_PORT174, + GPIO_FN_SCIFA3_TXD_PORT175, + + GPIO_FN_SCIFA3_RTS_PORT161, /* MSEL5CR_8_1 */ + GPIO_FN_SCIFA3_SCK_PORT158, + GPIO_FN_SCIFA3_CTS_PORT162, + GPIO_FN_SCIFA3_RXD_PORT159, + GPIO_FN_SCIFA3_TXD_PORT160, + + /* SCIFA4 */ + GPIO_FN_SCIFA4_RXD_PORT12, /* MSEL5CR[12:11] = 00 */ + GPIO_FN_SCIFA4_TXD_PORT13, + + GPIO_FN_SCIFA4_RXD_PORT204, /* MSEL5CR[12:11] = 01 */ + GPIO_FN_SCIFA4_TXD_PORT203, + + GPIO_FN_SCIFA4_RXD_PORT94, /* MSEL5CR[12:11] = 10 */ + GPIO_FN_SCIFA4_TXD_PORT93, + + GPIO_FN_SCIFA4_SCK_PORT21, /* SCIFA4_SCK Port 21/205 */ + GPIO_FN_SCIFA4_SCK_PORT205, + + /* SCIFA5 */ + GPIO_FN_SCIFA5_TXD_PORT20, /* MSEL5CR[15:14] = 00 */ + GPIO_FN_SCIFA5_RXD_PORT10, + + GPIO_FN_SCIFA5_RXD_PORT207, /* MSEL5CR[15:14] = 01 */ + GPIO_FN_SCIFA5_TXD_PORT208, + + GPIO_FN_SCIFA5_TXD_PORT91, /* MSEL5CR[15:14] = 10 */ + GPIO_FN_SCIFA5_RXD_PORT92, + + GPIO_FN_SCIFA5_SCK_PORT23, /* SCIFA5_SCK Port 23/206 */ + GPIO_FN_SCIFA5_SCK_PORT206, + + /* SCIFA6 */ + GPIO_FN_SCIFA6_SCK, GPIO_FN_SCIFA6_RXD, GPIO_FN_SCIFA6_TXD, + + /* SCIFA7 */ + GPIO_FN_SCIFA7_TXD, GPIO_FN_SCIFA7_RXD, + + /* SCIFAB */ + GPIO_FN_SCIFB_SCK_PORT190, /* MSEL5CR_17_0 */ + GPIO_FN_SCIFB_RXD_PORT191, + GPIO_FN_SCIFB_TXD_PORT192, + GPIO_FN_SCIFB_RTS_PORT186, + GPIO_FN_SCIFB_CTS_PORT187, + + GPIO_FN_SCIFB_SCK_PORT2, /* MSEL5CR_17_1 */ + GPIO_FN_SCIFB_RXD_PORT3, + GPIO_FN_SCIFB_TXD_PORT4, + GPIO_FN_SCIFB_RTS_PORT172, + GPIO_FN_SCIFB_CTS_PORT173, + + /* LCD0 */ + GPIO_FN_LCDC0_SELECT, + GPIO_FN_LCD0_D0, GPIO_FN_LCD0_D1, GPIO_FN_LCD0_D2, + GPIO_FN_LCD0_D3, GPIO_FN_LCD0_D4, GPIO_FN_LCD0_D5, + GPIO_FN_LCD0_D6, GPIO_FN_LCD0_D7, GPIO_FN_LCD0_D8, + GPIO_FN_LCD0_D9, GPIO_FN_LCD0_D10, GPIO_FN_LCD0_D11, + GPIO_FN_LCD0_D12, GPIO_FN_LCD0_D13, GPIO_FN_LCD0_D14, + GPIO_FN_LCD0_D15, GPIO_FN_LCD0_D16, GPIO_FN_LCD0_D17, + GPIO_FN_LCD0_DON, GPIO_FN_LCD0_VCPWC, GPIO_FN_LCD0_VEPWC, + + GPIO_FN_LCD0_DCK, GPIO_FN_LCD0_VSYN, /* for RGB */ + GPIO_FN_LCD0_HSYN, GPIO_FN_LCD0_DISP, /* for RGB */ + + GPIO_FN_LCD0_WR, GPIO_FN_LCD0_RD, /* for SYS */ + GPIO_FN_LCD0_CS, GPIO_FN_LCD0_RS, /* for SYS */ + + GPIO_FN_LCD0_D18_PORT163, GPIO_FN_LCD0_D19_PORT162, + GPIO_FN_LCD0_D20_PORT161, GPIO_FN_LCD0_D21_PORT158, + GPIO_FN_LCD0_D22_PORT160, GPIO_FN_LCD0_D23_PORT159, + GPIO_FN_LCD0_LCLK_PORT165, /* MSEL5CR_6_1 */ + + GPIO_FN_LCD0_D18_PORT40, GPIO_FN_LCD0_D19_PORT4, + GPIO_FN_LCD0_D20_PORT3, GPIO_FN_LCD0_D21_PORT2, + GPIO_FN_LCD0_D22_PORT0, GPIO_FN_LCD0_D23_PORT1, + GPIO_FN_LCD0_LCLK_PORT102, /* MSEL5CR_6_0 */ + + /* LCD1 */ + GPIO_FN_LCDC1_SELECT, + GPIO_FN_LCD1_D0, GPIO_FN_LCD1_D1, GPIO_FN_LCD1_D2, + GPIO_FN_LCD1_D3, GPIO_FN_LCD1_D4, GPIO_FN_LCD1_D5, + GPIO_FN_LCD1_D6, GPIO_FN_LCD1_D7, GPIO_FN_LCD1_D8, + GPIO_FN_LCD1_D9, GPIO_FN_LCD1_D10, GPIO_FN_LCD1_D11, + GPIO_FN_LCD1_D12, GPIO_FN_LCD1_D13, GPIO_FN_LCD1_D14, + GPIO_FN_LCD1_D15, GPIO_FN_LCD1_D16, GPIO_FN_LCD1_D17, + GPIO_FN_LCD1_D18, GPIO_FN_LCD1_D19, GPIO_FN_LCD1_D20, + GPIO_FN_LCD1_D21, GPIO_FN_LCD1_D22, GPIO_FN_LCD1_D23, + GPIO_FN_LCD1_DON, GPIO_FN_LCD1_VCPWC, + GPIO_FN_LCD1_LCLK, GPIO_FN_LCD1_VEPWC, + + GPIO_FN_LCD1_DCK, GPIO_FN_LCD1_VSYN, /* for RGB */ + GPIO_FN_LCD1_HSYN, GPIO_FN_LCD1_DISP, /* for RGB */ + + GPIO_FN_LCD1_WR, GPIO_FN_LCD1_RD, /* for SYS */ + GPIO_FN_LCD1_CS, GPIO_FN_LCD1_RS, /* for SYS */ + + /* RSPI */ + GPIO_FN_RSPI_SSL0_A, GPIO_FN_RSPI_SSL1_A, + GPIO_FN_RSPI_SSL2_A, GPIO_FN_RSPI_SSL3_A, + GPIO_FN_RSPI_MOSI_A, GPIO_FN_RSPI_MISO_A, + GPIO_FN_RSPI_CK_A, + + /* VIO CKO */ + GPIO_FN_VIO_CKO1, + GPIO_FN_VIO_CKO2, + GPIO_FN_VIO_CKO_1, + GPIO_FN_VIO_CKO, + + /* VIO0 */ + GPIO_FN_VIO0_D0, GPIO_FN_VIO0_D1, GPIO_FN_VIO0_D2, + GPIO_FN_VIO0_D3, GPIO_FN_VIO0_D4, GPIO_FN_VIO0_D5, + GPIO_FN_VIO0_D6, GPIO_FN_VIO0_D7, GPIO_FN_VIO0_D8, + GPIO_FN_VIO0_D9, GPIO_FN_VIO0_D10, GPIO_FN_VIO0_D11, + GPIO_FN_VIO0_D12, GPIO_FN_VIO0_VD, GPIO_FN_VIO0_HD, + GPIO_FN_VIO0_CLK, GPIO_FN_VIO0_FIELD, + + GPIO_FN_VIO0_D13_PORT26, /* MSEL5CR_27_0 */ + GPIO_FN_VIO0_D14_PORT25, + GPIO_FN_VIO0_D15_PORT24, + + GPIO_FN_VIO0_D13_PORT22, /* MSEL5CR_27_1 */ + GPIO_FN_VIO0_D14_PORT95, + GPIO_FN_VIO0_D15_PORT96, + + /* VIO1 */ + GPIO_FN_VIO1_D0, GPIO_FN_VIO1_D1, GPIO_FN_VIO1_D2, + GPIO_FN_VIO1_D3, GPIO_FN_VIO1_D4, GPIO_FN_VIO1_D5, + GPIO_FN_VIO1_D6, GPIO_FN_VIO1_D7, GPIO_FN_VIO1_VD, + GPIO_FN_VIO1_HD, GPIO_FN_VIO1_CLK, GPIO_FN_VIO1_FIELD, + + /* TPU0 */ + GPIO_FN_TPU0TO0, GPIO_FN_TPU0TO1, + GPIO_FN_TPU0TO3, + GPIO_FN_TPU0TO2_PORT66, /* TPU0TO2 Port 66/202 */ + GPIO_FN_TPU0TO2_PORT202, + + /* SSP1 0 */ + GPIO_FN_STP0_IPD0, GPIO_FN_STP0_IPD1, GPIO_FN_STP0_IPD2, + GPIO_FN_STP0_IPD3, GPIO_FN_STP0_IPD4, GPIO_FN_STP0_IPD5, + GPIO_FN_STP0_IPD6, GPIO_FN_STP0_IPD7, GPIO_FN_STP0_IPEN, + GPIO_FN_STP0_IPCLK, GPIO_FN_STP0_IPSYNC, + + /* SSP1 1 */ + GPIO_FN_STP1_IPD1, GPIO_FN_STP1_IPD2, GPIO_FN_STP1_IPD3, + GPIO_FN_STP1_IPD4, GPIO_FN_STP1_IPD5, GPIO_FN_STP1_IPD6, + GPIO_FN_STP1_IPD7, GPIO_FN_STP1_IPCLK, GPIO_FN_STP1_IPSYNC, + + GPIO_FN_STP1_IPD0_PORT186, /* MSEL5CR_23_0 */ + GPIO_FN_STP1_IPEN_PORT187, + + GPIO_FN_STP1_IPD0_PORT194, /* MSEL5CR_23_1 */ + GPIO_FN_STP1_IPEN_PORT193, + + /* SIM */ + GPIO_FN_SIM_RST, GPIO_FN_SIM_CLK, + GPIO_FN_SIM_D_PORT22, /* SIM_D Port 22/199 */ + GPIO_FN_SIM_D_PORT199, + + /* SDHI0 */ + GPIO_FN_SDHI0_D0, GPIO_FN_SDHI0_D1, GPIO_FN_SDHI0_D2, + GPIO_FN_SDHI0_D3, GPIO_FN_SDHI0_CD, GPIO_FN_SDHI0_WP, + GPIO_FN_SDHI0_CMD, GPIO_FN_SDHI0_CLK, + + /* SDHI1 */ + GPIO_FN_SDHI1_D0, GPIO_FN_SDHI1_D1, GPIO_FN_SDHI1_D2, + GPIO_FN_SDHI1_D3, GPIO_FN_SDHI1_CD, GPIO_FN_SDHI1_WP, + GPIO_FN_SDHI1_CMD, GPIO_FN_SDHI1_CLK, + + /* SDHI2 */ + GPIO_FN_SDHI2_D0, GPIO_FN_SDHI2_D1, GPIO_FN_SDHI2_D2, + GPIO_FN_SDHI2_D3, GPIO_FN_SDHI2_CLK, GPIO_FN_SDHI2_CMD, + + GPIO_FN_SDHI2_CD_PORT24, /* MSEL5CR_19_0 */ + GPIO_FN_SDHI2_WP_PORT25, + + GPIO_FN_SDHI2_WP_PORT177, /* MSEL5CR_19_1 */ + GPIO_FN_SDHI2_CD_PORT202, + + /* MSIOF2 */ + GPIO_FN_MSIOF2_TXD, GPIO_FN_MSIOF2_RXD, GPIO_FN_MSIOF2_TSCK, + GPIO_FN_MSIOF2_SS2, GPIO_FN_MSIOF2_TSYNC, GPIO_FN_MSIOF2_SS1, + GPIO_FN_MSIOF2_MCK1, GPIO_FN_MSIOF2_MCK0, GPIO_FN_MSIOF2_RSYNC, + GPIO_FN_MSIOF2_RSCK, + + /* KEYSC */ + GPIO_FN_KEYIN4, GPIO_FN_KEYIN5, + GPIO_FN_KEYIN6, GPIO_FN_KEYIN7, + GPIO_FN_KEYOUT0, GPIO_FN_KEYOUT1, GPIO_FN_KEYOUT2, + GPIO_FN_KEYOUT3, GPIO_FN_KEYOUT4, GPIO_FN_KEYOUT5, + GPIO_FN_KEYOUT6, GPIO_FN_KEYOUT7, + + GPIO_FN_KEYIN0_PORT43, /* MSEL4CR_18_0 */ + GPIO_FN_KEYIN1_PORT44, + GPIO_FN_KEYIN2_PORT45, + GPIO_FN_KEYIN3_PORT46, + + GPIO_FN_KEYIN0_PORT58, /* MSEL4CR_18_1 */ + GPIO_FN_KEYIN1_PORT57, + GPIO_FN_KEYIN2_PORT56, + GPIO_FN_KEYIN3_PORT55, + + /* VOU */ + GPIO_FN_DV_D0, GPIO_FN_DV_D1, GPIO_FN_DV_D2, GPIO_FN_DV_D3, + GPIO_FN_DV_D4, GPIO_FN_DV_D5, GPIO_FN_DV_D6, GPIO_FN_DV_D7, + GPIO_FN_DV_D8, GPIO_FN_DV_D9, GPIO_FN_DV_D10, GPIO_FN_DV_D11, + GPIO_FN_DV_D12, GPIO_FN_DV_D13, GPIO_FN_DV_D14, GPIO_FN_DV_D15, + GPIO_FN_DV_CLK, + GPIO_FN_DV_VSYNC, + GPIO_FN_DV_HSYNC, + + /* MEMC */ + GPIO_FN_MEMC_AD0, GPIO_FN_MEMC_AD1, GPIO_FN_MEMC_AD2, + GPIO_FN_MEMC_AD3, GPIO_FN_MEMC_AD4, GPIO_FN_MEMC_AD5, + GPIO_FN_MEMC_AD6, GPIO_FN_MEMC_AD7, GPIO_FN_MEMC_AD8, + GPIO_FN_MEMC_AD9, GPIO_FN_MEMC_AD10, GPIO_FN_MEMC_AD11, + GPIO_FN_MEMC_AD12, GPIO_FN_MEMC_AD13, GPIO_FN_MEMC_AD14, + GPIO_FN_MEMC_AD15, GPIO_FN_MEMC_CS0, GPIO_FN_MEMC_INT, + GPIO_FN_MEMC_NWE, GPIO_FN_MEMC_NOE, + + GPIO_FN_MEMC_CS1, /* MSEL4CR_6_0 */ + GPIO_FN_MEMC_ADV, + GPIO_FN_MEMC_WAIT, + GPIO_FN_MEMC_BUSCLK, + + GPIO_FN_MEMC_A1, /* MSEL4CR_6_1 */ + GPIO_FN_MEMC_DREQ0, + GPIO_FN_MEMC_DREQ1, + GPIO_FN_MEMC_A0, + + /* MMC */ + GPIO_FN_MMC0_D0_PORT68, GPIO_FN_MMC0_D1_PORT69, + GPIO_FN_MMC0_D2_PORT70, GPIO_FN_MMC0_D3_PORT71, + GPIO_FN_MMC0_D4_PORT72, GPIO_FN_MMC0_D5_PORT73, + GPIO_FN_MMC0_D6_PORT74, GPIO_FN_MMC0_D7_PORT75, + GPIO_FN_MMC0_CLK_PORT66, + GPIO_FN_MMC0_CMD_PORT67, /* MSEL4CR_15_0 */ + + GPIO_FN_MMC1_D0_PORT149, GPIO_FN_MMC1_D1_PORT148, + GPIO_FN_MMC1_D2_PORT147, GPIO_FN_MMC1_D3_PORT146, + GPIO_FN_MMC1_D4_PORT145, GPIO_FN_MMC1_D5_PORT144, + GPIO_FN_MMC1_D6_PORT143, GPIO_FN_MMC1_D7_PORT142, + GPIO_FN_MMC1_CLK_PORT103, + GPIO_FN_MMC1_CMD_PORT104, /* MSEL4CR_15_1 */ + + /* MSIOF0 */ + GPIO_FN_MSIOF0_SS1, GPIO_FN_MSIOF0_SS2, + GPIO_FN_MSIOF0_RXD, GPIO_FN_MSIOF0_TXD, + GPIO_FN_MSIOF0_MCK0, GPIO_FN_MSIOF0_MCK1, + GPIO_FN_MSIOF0_RSYNC, GPIO_FN_MSIOF0_RSCK, + GPIO_FN_MSIOF0_TSCK, GPIO_FN_MSIOF0_TSYNC, + + /* MSIOF1 */ + GPIO_FN_MSIOF1_RSCK, GPIO_FN_MSIOF1_RSYNC, + GPIO_FN_MSIOF1_MCK0, GPIO_FN_MSIOF1_MCK1, + + GPIO_FN_MSIOF1_SS2_PORT116, GPIO_FN_MSIOF1_SS1_PORT117, + GPIO_FN_MSIOF1_RXD_PORT118, GPIO_FN_MSIOF1_TXD_PORT119, + GPIO_FN_MSIOF1_TSYNC_PORT120, + GPIO_FN_MSIOF1_TSCK_PORT121, /* MSEL4CR_10_0 */ + + GPIO_FN_MSIOF1_SS1_PORT67, GPIO_FN_MSIOF1_TSCK_PORT72, + GPIO_FN_MSIOF1_TSYNC_PORT73, GPIO_FN_MSIOF1_TXD_PORT74, + GPIO_FN_MSIOF1_RXD_PORT75, + GPIO_FN_MSIOF1_SS2_PORT202, /* MSEL4CR_10_1 */ + + /* GPIO */ + GPIO_FN_GPO0, GPIO_FN_GPI0, + GPIO_FN_GPO1, GPIO_FN_GPI1, + + /* USB0 */ + GPIO_FN_USB0_OCI, GPIO_FN_USB0_PPON, GPIO_FN_VBUS, + + /* USB1 */ + GPIO_FN_USB1_OCI, GPIO_FN_USB1_PPON, + + /* BBIF1 */ + GPIO_FN_BBIF1_RXD, GPIO_FN_BBIF1_TXD, GPIO_FN_BBIF1_TSYNC, + GPIO_FN_BBIF1_TSCK, GPIO_FN_BBIF1_RSCK, GPIO_FN_BBIF1_RSYNC, + GPIO_FN_BBIF1_FLOW, GPIO_FN_BBIF1_RX_FLOW_N, + + /* BBIF2 */ + GPIO_FN_BBIF2_TXD2_PORT5, /* MSEL5CR_0_0 */ + GPIO_FN_BBIF2_RXD2_PORT60, + GPIO_FN_BBIF2_TSYNC2_PORT6, + GPIO_FN_BBIF2_TSCK2_PORT59, + + GPIO_FN_BBIF2_RXD2_PORT90, /* MSEL5CR_0_1 */ + GPIO_FN_BBIF2_TXD2_PORT183, + GPIO_FN_BBIF2_TSCK2_PORT89, + GPIO_FN_BBIF2_TSYNC2_PORT184, + + /* BSC / FLCTL / PCMCIA */ + GPIO_FN_CS0, GPIO_FN_CS2, GPIO_FN_CS4, + GPIO_FN_CS5B, GPIO_FN_CS6A, + GPIO_FN_CS5A_PORT105, /* CS5A PORT 19/105 */ + GPIO_FN_CS5A_PORT19, + GPIO_FN_IOIS16, /* ? */ + + GPIO_FN_A0, GPIO_FN_A1, GPIO_FN_A2, GPIO_FN_A3, + GPIO_FN_A4_FOE, /* share with FLCTL */ + GPIO_FN_A5_FCDE, /* share with FLCTL */ + GPIO_FN_A6, GPIO_FN_A7, GPIO_FN_A8, GPIO_FN_A9, + GPIO_FN_A10, GPIO_FN_A11, GPIO_FN_A12, GPIO_FN_A13, + GPIO_FN_A14, GPIO_FN_A15, GPIO_FN_A16, GPIO_FN_A17, + GPIO_FN_A18, GPIO_FN_A19, GPIO_FN_A20, GPIO_FN_A21, + GPIO_FN_A22, GPIO_FN_A23, GPIO_FN_A24, GPIO_FN_A25, + GPIO_FN_A26, + + GPIO_FN_D0_NAF0, GPIO_FN_D1_NAF1, /* share with FLCTL */ + GPIO_FN_D2_NAF2, GPIO_FN_D3_NAF3, /* share with FLCTL */ + GPIO_FN_D4_NAF4, GPIO_FN_D5_NAF5, /* share with FLCTL */ + GPIO_FN_D6_NAF6, GPIO_FN_D7_NAF7, /* share with FLCTL */ + GPIO_FN_D8_NAF8, GPIO_FN_D9_NAF9, /* share with FLCTL */ + GPIO_FN_D10_NAF10, GPIO_FN_D11_NAF11, /* share with FLCTL */ + GPIO_FN_D12_NAF12, GPIO_FN_D13_NAF13, /* share with FLCTL */ + GPIO_FN_D14_NAF14, GPIO_FN_D15_NAF15, /* share with FLCTL */ + + GPIO_FN_D16, GPIO_FN_D17, GPIO_FN_D18, GPIO_FN_D19, + GPIO_FN_D20, GPIO_FN_D21, GPIO_FN_D22, GPIO_FN_D23, + GPIO_FN_D24, GPIO_FN_D25, GPIO_FN_D26, GPIO_FN_D27, + GPIO_FN_D28, GPIO_FN_D29, GPIO_FN_D30, GPIO_FN_D31, + + GPIO_FN_WE0_FWE, /* share with FLCTL */ + GPIO_FN_WE1, + GPIO_FN_WE2_ICIORD, /* share with PCMCIA */ + GPIO_FN_WE3_ICIOWR, /* share with PCMCIA */ + GPIO_FN_CKO, GPIO_FN_BS, GPIO_FN_RDWR, + GPIO_FN_RD_FSC, /* share with FLCTL */ + GPIO_FN_WAIT_PORT177, /* WAIT Port 90/177 */ + GPIO_FN_WAIT_PORT90, + + GPIO_FN_FCE0, GPIO_FN_FCE1, GPIO_FN_FRB, /* FLCTL */ + + /* IRDA */ + GPIO_FN_IRDA_FIRSEL, GPIO_FN_IRDA_IN, GPIO_FN_IRDA_OUT, + + /* ATAPI */ + GPIO_FN_IDE_D0, GPIO_FN_IDE_D1, GPIO_FN_IDE_D2, + GPIO_FN_IDE_D3, GPIO_FN_IDE_D4, GPIO_FN_IDE_D5, + GPIO_FN_IDE_D6, GPIO_FN_IDE_D7, GPIO_FN_IDE_D8, + GPIO_FN_IDE_D9, GPIO_FN_IDE_D10, GPIO_FN_IDE_D11, + GPIO_FN_IDE_D12, GPIO_FN_IDE_D13, GPIO_FN_IDE_D14, + GPIO_FN_IDE_D15, GPIO_FN_IDE_A0, GPIO_FN_IDE_A1, + GPIO_FN_IDE_A2, GPIO_FN_IDE_CS0, GPIO_FN_IDE_CS1, + GPIO_FN_IDE_IOWR, GPIO_FN_IDE_IORD, GPIO_FN_IDE_IORDY, + GPIO_FN_IDE_INT, GPIO_FN_IDE_RST, GPIO_FN_IDE_DIRECTION, + GPIO_FN_IDE_EXBUF_ENB, GPIO_FN_IDE_IODACK, GPIO_FN_IDE_IODREQ, + + /* RMII */ + GPIO_FN_RMII_CRS_DV, GPIO_FN_RMII_RX_ER, GPIO_FN_RMII_RXD0, + GPIO_FN_RMII_RXD1, GPIO_FN_RMII_TX_EN, GPIO_FN_RMII_TXD0, + GPIO_FN_RMII_MDC, GPIO_FN_RMII_TXD1, GPIO_FN_RMII_MDIO, + GPIO_FN_RMII_REF50CK, /* for RMII */ + GPIO_FN_RMII_REF125CK, /* for GMII */ + + /* GEther */ + GPIO_FN_ET_TX_CLK, GPIO_FN_ET_TX_EN, GPIO_FN_ET_ETXD0, + GPIO_FN_ET_ETXD1, GPIO_FN_ET_ETXD2, GPIO_FN_ET_ETXD3, + GPIO_FN_ET_ETXD4, GPIO_FN_ET_ETXD5, /* for GEther */ + GPIO_FN_ET_ETXD6, GPIO_FN_ET_ETXD7, /* for GEther */ + GPIO_FN_ET_COL, GPIO_FN_ET_TX_ER, + GPIO_FN_ET_RX_CLK, GPIO_FN_ET_RX_DV, + GPIO_FN_ET_ERXD0, GPIO_FN_ET_ERXD1, + GPIO_FN_ET_ERXD2, GPIO_FN_ET_ERXD3, + GPIO_FN_ET_ERXD4, GPIO_FN_ET_ERXD5, /* for GEther */ + GPIO_FN_ET_ERXD6, GPIO_FN_ET_ERXD7, /* for GEther */ + GPIO_FN_ET_RX_ER, GPIO_FN_ET_CRS, + GPIO_FN_ET_MDC, GPIO_FN_ET_MDIO, + GPIO_FN_ET_LINK, GPIO_FN_ET_PHY_INT, + GPIO_FN_ET_WOL, GPIO_FN_ET_GTX_CLK, + + /* DMA0 */ + GPIO_FN_DREQ0, GPIO_FN_DACK0, + + /* DMA1 */ + GPIO_FN_DREQ1, GPIO_FN_DACK1, + + /* SYSC */ + GPIO_FN_RESETOUTS, + GPIO_FN_RESETP_PULLUP, + GPIO_FN_RESETP_PLAIN, + + /* SDENC */ + GPIO_FN_SDENC_CPG, + GPIO_FN_SDENC_DV_CLKI, + + /* IRREM */ + GPIO_FN_IROUT, + + /* DEBUG */ + GPIO_FN_EDEBGREQ_PULLDOWN, + GPIO_FN_EDEBGREQ_PULLUP, + + GPIO_FN_TRACEAUD_FROM_VIO, + GPIO_FN_TRACEAUD_FROM_LCDC0, + GPIO_FN_TRACEAUD_FROM_MEMC, +}; + +#endif /* __ASM_R8A7740_H__ */ diff --git a/arch/arm/mach-shmobile/intc-r8a7740.c b/arch/arm/mach-shmobile/intc-r8a7740.c new file mode 100644 index 000000000000..c62a2059f2f7 --- /dev/null +++ b/arch/arm/mach-shmobile/intc-r8a7740.c @@ -0,0 +1,45 @@ +/* + * R8A7740 processor support + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2011 Kuninori Morimoto + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#define INTA_CTRL 0xe605807c + +static int r8a7740_set_wake(struct irq_data *data, unsigned int on) +{ + return 0; /* always allow wakeup */ +} + +void __init r8a7740_init_irq(void) +{ + void __iomem *gic_dist_base = __io(0xf0001000); + void __iomem *gic_cpu_base = __io(0xf0000000); + + /* + * Change INT_SEL INTCA->GIC + * (on GPIO) + */ + __raw_writel(__raw_readl(INTA_CTRL) & ~(1 << 1), INTA_CTRL); + + gic_init(0, 29, gic_dist_base, gic_cpu_base); + gic_arch_extn.irq_set_wake = r8a7740_set_wake; +} diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c new file mode 100644 index 000000000000..55485187f0c7 --- /dev/null +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -0,0 +1,246 @@ +/* + * R8A7740 processor support + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2011 Kuninori Morimoto + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* SCIFA0 */ +static struct plat_sci_port scif0_platform_data = { + .mapbase = 0xe6c40000, + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE, + .scbrr_algo_id = SCBRR_ALGO_4, + .type = PORT_SCIFA, + .irqs = SCIx_IRQ_MUXED(gic_spi(100)), +}; + +static struct platform_device scif0_device = { + .name = "sh-sci", + .id = 0, + .dev = { + .platform_data = &scif0_platform_data, + }, +}; + +/* SCIFA1 */ +static struct plat_sci_port scif1_platform_data = { + .mapbase = 0xe6c50000, + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE, + .scbrr_algo_id = SCBRR_ALGO_4, + .type = PORT_SCIFA, + .irqs = SCIx_IRQ_MUXED(gic_spi(101)), +}; + +static struct platform_device scif1_device = { + .name = "sh-sci", + .id = 1, + .dev = { + .platform_data = &scif1_platform_data, + }, +}; + +/* SCIFA2 */ +static struct plat_sci_port scif2_platform_data = { + .mapbase = 0xe6c60000, + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE, + .scbrr_algo_id = SCBRR_ALGO_4, + .type = PORT_SCIFA, + .irqs = SCIx_IRQ_MUXED(gic_spi(102)), +}; + +static struct platform_device scif2_device = { + .name = "sh-sci", + .id = 2, + .dev = { + .platform_data = &scif2_platform_data, + }, +}; + +/* SCIFA3 */ +static struct plat_sci_port scif3_platform_data = { + .mapbase = 0xe6c70000, + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE, + .scbrr_algo_id = SCBRR_ALGO_4, + .type = PORT_SCIFA, + .irqs = SCIx_IRQ_MUXED(gic_spi(103)), +}; + +static struct platform_device scif3_device = { + .name = "sh-sci", + .id = 3, + .dev = { + .platform_data = &scif3_platform_data, + }, +}; + +/* SCIFA4 */ +static struct plat_sci_port scif4_platform_data = { + .mapbase = 0xe6c80000, + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE, + .scbrr_algo_id = SCBRR_ALGO_4, + .type = PORT_SCIFA, + .irqs = SCIx_IRQ_MUXED(gic_spi(104)), +}; + +static struct platform_device scif4_device = { + .name = "sh-sci", + .id = 4, + .dev = { + .platform_data = &scif4_platform_data, + }, +}; + +/* SCIFA5 */ +static struct plat_sci_port scif5_platform_data = { + .mapbase = 0xe6cb0000, + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE, + .scbrr_algo_id = SCBRR_ALGO_4, + .type = PORT_SCIFA, + .irqs = SCIx_IRQ_MUXED(gic_spi(105)), +}; + +static struct platform_device scif5_device = { + .name = "sh-sci", + .id = 5, + .dev = { + .platform_data = &scif5_platform_data, + }, +}; + +/* SCIFA6 */ +static struct plat_sci_port scif6_platform_data = { + .mapbase = 0xe6cc0000, + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE, + .scbrr_algo_id = SCBRR_ALGO_4, + .type = PORT_SCIFA, + .irqs = SCIx_IRQ_MUXED(gic_spi(106)), +}; + +static struct platform_device scif6_device = { + .name = "sh-sci", + .id = 6, + .dev = { + .platform_data = &scif6_platform_data, + }, +}; + +/* SCIFA7 */ +static struct plat_sci_port scif7_platform_data = { + .mapbase = 0xe6cd0000, + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE, + .scbrr_algo_id = SCBRR_ALGO_4, + .type = PORT_SCIFA, + .irqs = SCIx_IRQ_MUXED(gic_spi(107)), +}; + +static struct platform_device scif7_device = { + .name = "sh-sci", + .id = 7, + .dev = { + .platform_data = &scif7_platform_data, + }, +}; + +/* SCIFB */ +static struct plat_sci_port scifb_platform_data = { + .mapbase = 0xe6c30000, + .flags = UPF_BOOT_AUTOCONF, + .scscr = SCSCR_RE | SCSCR_TE, + .scbrr_algo_id = SCBRR_ALGO_4, + .type = PORT_SCIFB, + .irqs = SCIx_IRQ_MUXED(gic_spi(108)), +}; + +static struct platform_device scifb_device = { + .name = "sh-sci", + .id = 8, + .dev = { + .platform_data = &scifb_platform_data, + }, +}; + +/* CMT */ +static struct sh_timer_config cmt10_platform_data = { + .name = "CMT10", + .channel_offset = 0x10, + .timer_bit = 0, + .clockevent_rating = 125, + .clocksource_rating = 125, +}; + +static struct resource cmt10_resources[] = { + [0] = { + .name = "CMT10", + .start = 0xe6138010, + .end = 0xe613801b, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(58), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device cmt10_device = { + .name = "sh_cmt", + .id = 10, + .dev = { + .platform_data = &cmt10_platform_data, + }, + .resource = cmt10_resources, + .num_resources = ARRAY_SIZE(cmt10_resources), +}; + +static struct platform_device *r8a7740_early_devices[] __initdata = { + &scif0_device, + &scif1_device, + &scif2_device, + &scif3_device, + &scif4_device, + &scif5_device, + &scif6_device, + &scif7_device, + &scifb_device, + &cmt10_device, +}; + +void __init r8a7740_add_standard_devices(void) +{ + platform_add_devices(r8a7740_early_devices, + ARRAY_SIZE(r8a7740_early_devices)); +} + +void __init r8a7740_add_early_devices(void) +{ + early_platform_add_devices(r8a7740_early_devices, + ARRAY_SIZE(r8a7740_early_devices)); +} -- cgit v1.2.3 From 5ade0672f2a2142de216ca705692c9d3238ee650 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 10 Nov 2011 18:46:08 -0800 Subject: ARM: mach-shmobile: r8a7740: add PFC support. This adds PFC support for the R8A7740 (R-Mobile A1) CPU This patch is based on v0.1 manual Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Makefile | 1 + arch/arm/mach-shmobile/pfc-r8a7740.c | 2562 ++++++++++++++++++++++++++++++++++ 2 files changed, 2563 insertions(+) create mode 100644 arch/arm/mach-shmobile/pfc-r8a7740.c (limited to 'arch') diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index d61f1eca159a..2bd2d3ba8ffe 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -24,6 +24,7 @@ pfc-$(CONFIG_ARCH_SH7367) += pfc-sh7367.o pfc-$(CONFIG_ARCH_SH7377) += pfc-sh7377.o pfc-$(CONFIG_ARCH_SH7372) += pfc-sh7372.o pfc-$(CONFIG_ARCH_SH73A0) += pfc-sh73a0.o +pfc-$(CONFIG_ARCH_R8A7740) += pfc-r8a7740.o # IRQ objects obj-$(CONFIG_ARCH_SH7367) += entry-intc.o diff --git a/arch/arm/mach-shmobile/pfc-r8a7740.c b/arch/arm/mach-shmobile/pfc-r8a7740.c new file mode 100644 index 000000000000..a4fff6950b03 --- /dev/null +++ b/arch/arm/mach-shmobile/pfc-r8a7740.c @@ -0,0 +1,2562 @@ +/* + * R8A7740 processor support + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2011 Kuninori Morimoto + * + * 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; version 2 of the + * License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include +#include +#include + +#define CPU_ALL_PORT(fn, pfx, sfx) \ + PORT_10(fn, pfx, sfx), PORT_90(fn, pfx, sfx), \ + PORT_10(fn, pfx##10, sfx), PORT_90(fn, pfx##1, sfx), \ + PORT_10(fn, pfx##20, sfx), \ + PORT_1(fn, pfx##210, sfx), PORT_1(fn, pfx##211, sfx) + +enum { + PINMUX_RESERVED = 0, + + /* PORT0_DATA -> PORT211_DATA */ + PINMUX_DATA_BEGIN, + PORT_ALL(DATA), + PINMUX_DATA_END, + + /* PORT0_IN -> PORT211_IN */ + PINMUX_INPUT_BEGIN, + PORT_ALL(IN), + PINMUX_INPUT_END, + + /* PORT0_IN_PU -> PORT211_IN_PU */ + PINMUX_INPUT_PULLUP_BEGIN, + PORT_ALL(IN_PU), + PINMUX_INPUT_PULLUP_END, + + /* PORT0_IN_PD -> PORT211_IN_PD */ + PINMUX_INPUT_PULLDOWN_BEGIN, + PORT_ALL(IN_PD), + PINMUX_INPUT_PULLDOWN_END, + + /* PORT0_OUT -> PORT211_OUT */ + PINMUX_OUTPUT_BEGIN, + PORT_ALL(OUT), + PINMUX_OUTPUT_END, + + PINMUX_FUNCTION_BEGIN, + PORT_ALL(FN_IN), /* PORT0_FN_IN -> PORT211_FN_IN */ + PORT_ALL(FN_OUT), /* PORT0_FN_OUT -> PORT211_FN_OUT */ + PORT_ALL(FN0), /* PORT0_FN0 -> PORT211_FN0 */ + PORT_ALL(FN1), /* PORT0_FN1 -> PORT211_FN1 */ + PORT_ALL(FN2), /* PORT0_FN2 -> PORT211_FN2 */ + PORT_ALL(FN3), /* PORT0_FN3 -> PORT211_FN3 */ + PORT_ALL(FN4), /* PORT0_FN4 -> PORT211_FN4 */ + PORT_ALL(FN5), /* PORT0_FN5 -> PORT211_FN5 */ + PORT_ALL(FN6), /* PORT0_FN6 -> PORT211_FN6 */ + PORT_ALL(FN7), /* PORT0_FN7 -> PORT211_FN7 */ + + MSEL1CR_31_0, MSEL1CR_31_1, + MSEL1CR_30_0, MSEL1CR_30_1, + MSEL1CR_29_0, MSEL1CR_29_1, + MSEL1CR_28_0, MSEL1CR_28_1, + MSEL1CR_27_0, MSEL1CR_27_1, + MSEL1CR_26_0, MSEL1CR_26_1, + MSEL1CR_16_0, MSEL1CR_16_1, + MSEL1CR_15_0, MSEL1CR_15_1, + MSEL1CR_14_0, MSEL1CR_14_1, + MSEL1CR_13_0, MSEL1CR_13_1, + MSEL1CR_12_0, MSEL1CR_12_1, + MSEL1CR_9_0, MSEL1CR_9_1, + MSEL1CR_7_0, MSEL1CR_7_1, + MSEL1CR_6_0, MSEL1CR_6_1, + MSEL1CR_5_0, MSEL1CR_5_1, + MSEL1CR_4_0, MSEL1CR_4_1, + MSEL1CR_3_0, MSEL1CR_3_1, + MSEL1CR_2_0, MSEL1CR_2_1, + MSEL1CR_0_0, MSEL1CR_0_1, + + MSEL3CR_15_0, MSEL3CR_15_1, /* Trace / Debug ? */ + MSEL3CR_6_0, MSEL3CR_6_1, + + MSEL4CR_19_0, MSEL4CR_19_1, + MSEL4CR_18_0, MSEL4CR_18_1, + MSEL4CR_15_0, MSEL4CR_15_1, + MSEL4CR_10_0, MSEL4CR_10_1, + MSEL4CR_6_0, MSEL4CR_6_1, + MSEL4CR_4_0, MSEL4CR_4_1, + MSEL4CR_1_0, MSEL4CR_1_1, + + MSEL5CR_31_0, MSEL5CR_31_1, /* irq/fiq output */ + MSEL5CR_30_0, MSEL5CR_30_1, + MSEL5CR_29_0, MSEL5CR_29_1, + MSEL5CR_27_0, MSEL5CR_27_1, + MSEL5CR_25_0, MSEL5CR_25_1, + MSEL5CR_23_0, MSEL5CR_23_1, + MSEL5CR_21_0, MSEL5CR_21_1, + MSEL5CR_19_0, MSEL5CR_19_1, + MSEL5CR_17_0, MSEL5CR_17_1, + MSEL5CR_15_0, MSEL5CR_15_1, + MSEL5CR_14_0, MSEL5CR_14_1, + MSEL5CR_13_0, MSEL5CR_13_1, + MSEL5CR_12_0, MSEL5CR_12_1, + MSEL5CR_11_0, MSEL5CR_11_1, + MSEL5CR_10_0, MSEL5CR_10_1, + MSEL5CR_8_0, MSEL5CR_8_1, + MSEL5CR_7_0, MSEL5CR_7_1, + MSEL5CR_6_0, MSEL5CR_6_1, + MSEL5CR_5_0, MSEL5CR_5_1, + MSEL5CR_4_0, MSEL5CR_4_1, + MSEL5CR_3_0, MSEL5CR_3_1, + MSEL5CR_2_0, MSEL5CR_2_1, + MSEL5CR_0_0, MSEL5CR_0_1, + PINMUX_FUNCTION_END, + + PINMUX_MARK_BEGIN, + + /* IRQ */ + IRQ0_PORT2_MARK, IRQ0_PORT13_MARK, + IRQ1_MARK, + IRQ2_PORT11_MARK, IRQ2_PORT12_MARK, + IRQ3_PORT10_MARK, IRQ3_PORT14_MARK, + IRQ4_PORT15_MARK, IRQ4_PORT172_MARK, + IRQ5_PORT0_MARK, IRQ5_PORT1_MARK, + IRQ6_PORT121_MARK, IRQ6_PORT173_MARK, + IRQ7_PORT120_MARK, IRQ7_PORT209_MARK, + IRQ8_MARK, + IRQ9_PORT118_MARK, IRQ9_PORT210_MARK, + IRQ10_MARK, + IRQ11_MARK, + IRQ12_PORT42_MARK, IRQ12_PORT97_MARK, + IRQ13_PORT64_MARK, IRQ13_PORT98_MARK, + IRQ14_PORT63_MARK, IRQ14_PORT99_MARK, + IRQ15_PORT62_MARK, IRQ15_PORT100_MARK, + IRQ16_PORT68_MARK, IRQ16_PORT211_MARK, + IRQ17_MARK, + IRQ18_MARK, + IRQ19_MARK, + IRQ20_MARK, + IRQ21_MARK, + IRQ22_MARK, + IRQ23_MARK, + IRQ24_MARK, + IRQ25_MARK, + IRQ26_PORT58_MARK, IRQ26_PORT81_MARK, + IRQ27_PORT57_MARK, IRQ27_PORT168_MARK, + IRQ28_PORT56_MARK, IRQ28_PORT169_MARK, + IRQ29_PORT50_MARK, IRQ29_PORT170_MARK, + IRQ30_PORT49_MARK, IRQ30_PORT171_MARK, + IRQ31_PORT41_MARK, IRQ31_PORT167_MARK, + + /* Function */ + + /* DBGT */ + DBGMDT2_MARK, DBGMDT1_MARK, DBGMDT0_MARK, + DBGMD10_MARK, DBGMD11_MARK, DBGMD20_MARK, + DBGMD21_MARK, + + /* FSI */ + FSIAISLD_PORT0_MARK, /* FSIAISLD Port 0/5 */ + FSIAISLD_PORT5_MARK, + FSIASPDIF_PORT9_MARK, /* FSIASPDIF Port 9/18 */ + FSIASPDIF_PORT18_MARK, + FSIAOSLD1_MARK, FSIAOSLD2_MARK, FSIAOLR_MARK, + FSIAOBT_MARK, FSIAOSLD_MARK, FSIAOMC_MARK, + FSIACK_MARK, FSIAILR_MARK, FSIAIBT_MARK, + + /* FMSI */ + FMSISLD_PORT1_MARK, /* FMSISLD Port 1/6 */ + FMSISLD_PORT6_MARK, + FMSIILR_MARK, FMSIIBT_MARK, FMSIOLR_MARK, FMSIOBT_MARK, + FMSICK_MARK, FMSOILR_MARK, FMSOIBT_MARK, FMSOOLR_MARK, + FMSOOBT_MARK, FMSOSLD_MARK, FMSOCK_MARK, + + /* SCIFA0 */ + SCIFA0_SCK_MARK, SCIFA0_CTS_MARK, SCIFA0_RTS_MARK, + SCIFA0_RXD_MARK, SCIFA0_TXD_MARK, + + /* SCIFA1 */ + SCIFA1_CTS_MARK, SCIFA1_SCK_MARK, SCIFA1_RXD_MARK, + SCIFA1_TXD_MARK, SCIFA1_RTS_MARK, + + /* SCIFA2 */ + SCIFA2_SCK_PORT22_MARK, /* SCIFA2_SCK Port 22/199 */ + SCIFA2_SCK_PORT199_MARK, + SCIFA2_RXD_MARK, SCIFA2_TXD_MARK, + SCIFA2_CTS_MARK, SCIFA2_RTS_MARK, + + /* SCIFA3 */ + SCIFA3_RTS_PORT105_MARK, /* MSEL5CR_8_0 */ + SCIFA3_SCK_PORT116_MARK, + SCIFA3_CTS_PORT117_MARK, + SCIFA3_RXD_PORT174_MARK, + SCIFA3_TXD_PORT175_MARK, + + SCIFA3_RTS_PORT161_MARK, /* MSEL5CR_8_1 */ + SCIFA3_SCK_PORT158_MARK, + SCIFA3_CTS_PORT162_MARK, + SCIFA3_RXD_PORT159_MARK, + SCIFA3_TXD_PORT160_MARK, + + /* SCIFA4 */ + SCIFA4_RXD_PORT12_MARK, /* MSEL5CR[12:11] = 00 */ + SCIFA4_TXD_PORT13_MARK, + + SCIFA4_RXD_PORT204_MARK, /* MSEL5CR[12:11] = 01 */ + SCIFA4_TXD_PORT203_MARK, + + SCIFA4_RXD_PORT94_MARK, /* MSEL5CR[12:11] = 10 */ + SCIFA4_TXD_PORT93_MARK, + + SCIFA4_SCK_PORT21_MARK, /* SCIFA4_SCK Port 21/205 */ + SCIFA4_SCK_PORT205_MARK, + + /* SCIFA5 */ + SCIFA5_TXD_PORT20_MARK, /* MSEL5CR[15:14] = 00 */ + SCIFA5_RXD_PORT10_MARK, + + SCIFA5_RXD_PORT207_MARK, /* MSEL5CR[15:14] = 01 */ + SCIFA5_TXD_PORT208_MARK, + + SCIFA5_TXD_PORT91_MARK, /* MSEL5CR[15:14] = 10 */ + SCIFA5_RXD_PORT92_MARK, + + SCIFA5_SCK_PORT23_MARK, /* SCIFA5_SCK Port 23/206 */ + SCIFA5_SCK_PORT206_MARK, + + /* SCIFA6 */ + SCIFA6_SCK_MARK, SCIFA6_RXD_MARK, SCIFA6_TXD_MARK, + + /* SCIFA7 */ + SCIFA7_TXD_MARK, SCIFA7_RXD_MARK, + + /* SCIFAB */ + SCIFB_SCK_PORT190_MARK, /* MSEL5CR_17_0 */ + SCIFB_RXD_PORT191_MARK, + SCIFB_TXD_PORT192_MARK, + SCIFB_RTS_PORT186_MARK, + SCIFB_CTS_PORT187_MARK, + + SCIFB_SCK_PORT2_MARK, /* MSEL5CR_17_1 */ + SCIFB_RXD_PORT3_MARK, + SCIFB_TXD_PORT4_MARK, + SCIFB_RTS_PORT172_MARK, + SCIFB_CTS_PORT173_MARK, + + /* LCD0 */ + LCDC0_SELECT_MARK, + + LCD0_D0_MARK, LCD0_D1_MARK, LCD0_D2_MARK, LCD0_D3_MARK, + LCD0_D4_MARK, LCD0_D5_MARK, LCD0_D6_MARK, LCD0_D7_MARK, + LCD0_D8_MARK, LCD0_D9_MARK, LCD0_D10_MARK, LCD0_D11_MARK, + LCD0_D12_MARK, LCD0_D13_MARK, LCD0_D14_MARK, LCD0_D15_MARK, + LCD0_D16_MARK, LCD0_D17_MARK, + LCD0_DON_MARK, LCD0_VCPWC_MARK, LCD0_VEPWC_MARK, + LCD0_DCK_MARK, LCD0_VSYN_MARK, /* for RGB */ + LCD0_HSYN_MARK, LCD0_DISP_MARK, /* for RGB */ + LCD0_WR_MARK, LCD0_RD_MARK, /* for SYS */ + LCD0_CS_MARK, LCD0_RS_MARK, /* for SYS */ + + LCD0_D21_PORT158_MARK, LCD0_D23_PORT159_MARK, /* MSEL5CR_6_1 */ + LCD0_D22_PORT160_MARK, LCD0_D20_PORT161_MARK, + LCD0_D19_PORT162_MARK, LCD0_D18_PORT163_MARK, + LCD0_LCLK_PORT165_MARK, + + LCD0_D18_PORT40_MARK, LCD0_D22_PORT0_MARK, /* MSEL5CR_6_0 */ + LCD0_D23_PORT1_MARK, LCD0_D21_PORT2_MARK, + LCD0_D20_PORT3_MARK, LCD0_D19_PORT4_MARK, + LCD0_LCLK_PORT102_MARK, + + /* LCD1 */ + LCDC1_SELECT_MARK, + + LCD1_D0_MARK, LCD1_D1_MARK, LCD1_D2_MARK, LCD1_D3_MARK, + LCD1_D4_MARK, LCD1_D5_MARK, LCD1_D6_MARK, LCD1_D7_MARK, + LCD1_D8_MARK, LCD1_D9_MARK, LCD1_D10_MARK, LCD1_D11_MARK, + LCD1_D12_MARK, LCD1_D13_MARK, LCD1_D14_MARK, LCD1_D15_MARK, + LCD1_D16_MARK, LCD1_D17_MARK, LCD1_D18_MARK, LCD1_D19_MARK, + LCD1_D20_MARK, LCD1_D21_MARK, LCD1_D22_MARK, LCD1_D23_MARK, + LCD1_DON_MARK, LCD1_VCPWC_MARK, + LCD1_LCLK_MARK, LCD1_VEPWC_MARK, + + LCD1_DCK_MARK, LCD1_VSYN_MARK, /* for RGB */ + LCD1_HSYN_MARK, LCD1_DISP_MARK, /* for RGB */ + LCD1_RS_MARK, LCD1_CS_MARK, /* for SYS */ + LCD1_RD_MARK, LCD1_WR_MARK, /* for SYS */ + + /* RSPI */ + RSPI_SSL0_A_MARK, RSPI_SSL1_A_MARK, RSPI_SSL2_A_MARK, + RSPI_SSL3_A_MARK, RSPI_CK_A_MARK, RSPI_MOSI_A_MARK, + RSPI_MISO_A_MARK, + + /* VIO CKO */ + VIO_CKO1_MARK, /* needs fixup */ + VIO_CKO2_MARK, + VIO_CKO_1_MARK, + VIO_CKO_MARK, + + /* VIO0 */ + VIO0_D0_MARK, VIO0_D1_MARK, VIO0_D2_MARK, VIO0_D3_MARK, + VIO0_D4_MARK, VIO0_D5_MARK, VIO0_D6_MARK, VIO0_D7_MARK, + VIO0_D8_MARK, VIO0_D9_MARK, VIO0_D10_MARK, VIO0_D11_MARK, + VIO0_D12_MARK, VIO0_VD_MARK, VIO0_HD_MARK, VIO0_CLK_MARK, + VIO0_FIELD_MARK, + + VIO0_D13_PORT26_MARK, /* MSEL5CR_27_0 */ + VIO0_D14_PORT25_MARK, + VIO0_D15_PORT24_MARK, + + VIO0_D13_PORT22_MARK, /* MSEL5CR_27_1 */ + VIO0_D14_PORT95_MARK, + VIO0_D15_PORT96_MARK, + + /* VIO1 */ + VIO1_D0_MARK, VIO1_D1_MARK, VIO1_D2_MARK, VIO1_D3_MARK, + VIO1_D4_MARK, VIO1_D5_MARK, VIO1_D6_MARK, VIO1_D7_MARK, + VIO1_VD_MARK, VIO1_HD_MARK, VIO1_CLK_MARK, VIO1_FIELD_MARK, + + /* TPU0 */ + TPU0TO0_MARK, TPU0TO1_MARK, TPU0TO3_MARK, + TPU0TO2_PORT66_MARK, /* TPU0TO2 Port 66/202 */ + TPU0TO2_PORT202_MARK, + + /* SSP1 0 */ + STP0_IPD0_MARK, STP0_IPD1_MARK, STP0_IPD2_MARK, STP0_IPD3_MARK, + STP0_IPD4_MARK, STP0_IPD5_MARK, STP0_IPD6_MARK, STP0_IPD7_MARK, + STP0_IPEN_MARK, STP0_IPCLK_MARK, STP0_IPSYNC_MARK, + + /* SSP1 1 */ + STP1_IPD1_MARK, STP1_IPD2_MARK, STP1_IPD3_MARK, STP1_IPD4_MARK, + STP1_IPD5_MARK, STP1_IPD6_MARK, STP1_IPD7_MARK, STP1_IPCLK_MARK, + STP1_IPSYNC_MARK, + + STP1_IPD0_PORT186_MARK, /* MSEL5CR_23_0 */ + STP1_IPEN_PORT187_MARK, + + STP1_IPD0_PORT194_MARK, /* MSEL5CR_23_1 */ + STP1_IPEN_PORT193_MARK, + + /* SIM */ + SIM_RST_MARK, SIM_CLK_MARK, + SIM_D_PORT22_MARK, /* SIM_D Port 22/199 */ + SIM_D_PORT199_MARK, + + /* SDHI0 */ + SDHI0_D0_MARK, SDHI0_D1_MARK, SDHI0_D2_MARK, SDHI0_D3_MARK, + SDHI0_CD_MARK, SDHI0_WP_MARK, SDHI0_CMD_MARK, SDHI0_CLK_MARK, + + /* SDHI1 */ + SDHI1_D0_MARK, SDHI1_D1_MARK, SDHI1_D2_MARK, SDHI1_D3_MARK, + SDHI1_CD_MARK, SDHI1_WP_MARK, SDHI1_CMD_MARK, SDHI1_CLK_MARK, + + /* SDHI2 */ + SDHI2_D0_MARK, SDHI2_D1_MARK, SDHI2_D2_MARK, SDHI2_D3_MARK, + SDHI2_CLK_MARK, SDHI2_CMD_MARK, + + SDHI2_CD_PORT24_MARK, /* MSEL5CR_19_0 */ + SDHI2_WP_PORT25_MARK, + + SDHI2_WP_PORT177_MARK, /* MSEL5CR_19_1 */ + SDHI2_CD_PORT202_MARK, + + /* MSIOF2 */ + MSIOF2_TXD_MARK, MSIOF2_RXD_MARK, MSIOF2_TSCK_MARK, + MSIOF2_SS2_MARK, MSIOF2_TSYNC_MARK, MSIOF2_SS1_MARK, + MSIOF2_MCK1_MARK, MSIOF2_MCK0_MARK, MSIOF2_RSYNC_MARK, + MSIOF2_RSCK_MARK, + + /* KEYSC */ + KEYIN4_MARK, KEYIN5_MARK, KEYIN6_MARK, KEYIN7_MARK, + KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK, + KEYOUT4_MARK, KEYOUT5_MARK, KEYOUT6_MARK, KEYOUT7_MARK, + + KEYIN0_PORT43_MARK, /* MSEL4CR_18_0 */ + KEYIN1_PORT44_MARK, + KEYIN2_PORT45_MARK, + KEYIN3_PORT46_MARK, + + KEYIN0_PORT58_MARK, /* MSEL4CR_18_1 */ + KEYIN1_PORT57_MARK, + KEYIN2_PORT56_MARK, + KEYIN3_PORT55_MARK, + + /* VOU */ + DV_D0_MARK, DV_D1_MARK, DV_D2_MARK, DV_D3_MARK, + DV_D4_MARK, DV_D5_MARK, DV_D6_MARK, DV_D7_MARK, + DV_D8_MARK, DV_D9_MARK, DV_D10_MARK, DV_D11_MARK, + DV_D12_MARK, DV_D13_MARK, DV_D14_MARK, DV_D15_MARK, + DV_CLK_MARK, DV_VSYNC_MARK, DV_HSYNC_MARK, + + /* MEMC */ + MEMC_AD0_MARK, MEMC_AD1_MARK, MEMC_AD2_MARK, MEMC_AD3_MARK, + MEMC_AD4_MARK, MEMC_AD5_MARK, MEMC_AD6_MARK, MEMC_AD7_MARK, + MEMC_AD8_MARK, MEMC_AD9_MARK, MEMC_AD10_MARK, MEMC_AD11_MARK, + MEMC_AD12_MARK, MEMC_AD13_MARK, MEMC_AD14_MARK, MEMC_AD15_MARK, + MEMC_CS0_MARK, MEMC_INT_MARK, MEMC_NWE_MARK, MEMC_NOE_MARK, + + MEMC_CS1_MARK, /* MSEL4CR_6_0 */ + MEMC_ADV_MARK, + MEMC_WAIT_MARK, + MEMC_BUSCLK_MARK, + + MEMC_A1_MARK, /* MSEL4CR_6_1 */ + MEMC_DREQ0_MARK, + MEMC_DREQ1_MARK, + MEMC_A0_MARK, + + /* MMC */ + MMC0_D0_PORT68_MARK, MMC0_D1_PORT69_MARK, MMC0_D2_PORT70_MARK, + MMC0_D3_PORT71_MARK, MMC0_D4_PORT72_MARK, MMC0_D5_PORT73_MARK, + MMC0_D6_PORT74_MARK, MMC0_D7_PORT75_MARK, MMC0_CLK_PORT66_MARK, + MMC0_CMD_PORT67_MARK, /* MSEL4CR_15_0 */ + + MMC1_D0_PORT149_MARK, MMC1_D1_PORT148_MARK, MMC1_D2_PORT147_MARK, + MMC1_D3_PORT146_MARK, MMC1_D4_PORT145_MARK, MMC1_D5_PORT144_MARK, + MMC1_D6_PORT143_MARK, MMC1_D7_PORT142_MARK, MMC1_CLK_PORT103_MARK, + MMC1_CMD_PORT104_MARK, /* MSEL4CR_15_1 */ + + /* MSIOF0 */ + MSIOF0_SS1_MARK, MSIOF0_SS2_MARK, MSIOF0_RXD_MARK, + MSIOF0_TXD_MARK, MSIOF0_MCK0_MARK, MSIOF0_MCK1_MARK, + MSIOF0_RSYNC_MARK, MSIOF0_RSCK_MARK, MSIOF0_TSCK_MARK, + MSIOF0_TSYNC_MARK, + + /* MSIOF1 */ + MSIOF1_RSCK_MARK, MSIOF1_RSYNC_MARK, + MSIOF1_MCK0_MARK, MSIOF1_MCK1_MARK, + + MSIOF1_SS2_PORT116_MARK, MSIOF1_SS1_PORT117_MARK, + MSIOF1_RXD_PORT118_MARK, MSIOF1_TXD_PORT119_MARK, + MSIOF1_TSYNC_PORT120_MARK, + MSIOF1_TSCK_PORT121_MARK, /* MSEL4CR_10_0 */ + + MSIOF1_SS1_PORT67_MARK, MSIOF1_TSCK_PORT72_MARK, + MSIOF1_TSYNC_PORT73_MARK, MSIOF1_TXD_PORT74_MARK, + MSIOF1_RXD_PORT75_MARK, + MSIOF1_SS2_PORT202_MARK, /* MSEL4CR_10_1 */ + + /* GPIO */ + GPO0_MARK, GPI0_MARK, GPO1_MARK, GPI1_MARK, + + /* USB0 */ + USB0_OCI_MARK, USB0_PPON_MARK, VBUS_MARK, + + /* USB1 */ + USB1_OCI_MARK, USB1_PPON_MARK, + + /* BBIF1 */ + BBIF1_RXD_MARK, BBIF1_TXD_MARK, BBIF1_TSYNC_MARK, + BBIF1_TSCK_MARK, BBIF1_RSCK_MARK, BBIF1_RSYNC_MARK, + BBIF1_FLOW_MARK, BBIF1_RX_FLOW_N_MARK, + + /* BBIF2 */ + BBIF2_TXD2_PORT5_MARK, /* MSEL5CR_0_0 */ + BBIF2_RXD2_PORT60_MARK, + BBIF2_TSYNC2_PORT6_MARK, + BBIF2_TSCK2_PORT59_MARK, + + BBIF2_RXD2_PORT90_MARK, /* MSEL5CR_0_1 */ + BBIF2_TXD2_PORT183_MARK, + BBIF2_TSCK2_PORT89_MARK, + BBIF2_TSYNC2_PORT184_MARK, + + /* BSC / FLCTL / PCMCIA */ + CS0_MARK, CS2_MARK, CS4_MARK, + CS5B_MARK, CS6A_MARK, + CS5A_PORT105_MARK, /* CS5A PORT 19/105 */ + CS5A_PORT19_MARK, + IOIS16_MARK, /* ? */ + + A0_MARK, A1_MARK, A2_MARK, A3_MARK, + A4_FOE_MARK, /* share with FLCTL */ + A5_FCDE_MARK, /* share with FLCTL */ + A6_MARK, A7_MARK, A8_MARK, A9_MARK, + A10_MARK, A11_MARK, A12_MARK, A13_MARK, + A14_MARK, A15_MARK, A16_MARK, A17_MARK, + A18_MARK, A19_MARK, A20_MARK, A21_MARK, + A22_MARK, A23_MARK, A24_MARK, A25_MARK, + A26_MARK, + + D0_NAF0_MARK, D1_NAF1_MARK, D2_NAF2_MARK, /* share with FLCTL */ + D3_NAF3_MARK, D4_NAF4_MARK, D5_NAF5_MARK, /* share with FLCTL */ + D6_NAF6_MARK, D7_NAF7_MARK, D8_NAF8_MARK, /* share with FLCTL */ + D9_NAF9_MARK, D10_NAF10_MARK, D11_NAF11_MARK, /* share with FLCTL */ + D12_NAF12_MARK, D13_NAF13_MARK, D14_NAF14_MARK, /* share with FLCTL */ + D15_NAF15_MARK, /* share with FLCTL */ + D16_MARK, D17_MARK, D18_MARK, D19_MARK, + D20_MARK, D21_MARK, D22_MARK, D23_MARK, + D24_MARK, D25_MARK, D26_MARK, D27_MARK, + D28_MARK, D29_MARK, D30_MARK, D31_MARK, + + WE0_FWE_MARK, /* share with FLCTL */ + WE1_MARK, + WE2_ICIORD_MARK, /* share with PCMCIA */ + WE3_ICIOWR_MARK, /* share with PCMCIA */ + CKO_MARK, BS_MARK, RDWR_MARK, + RD_FSC_MARK, /* share with FLCTL */ + WAIT_PORT177_MARK, /* WAIT Port 90/177 */ + WAIT_PORT90_MARK, + + FCE0_MARK, FCE1_MARK, FRB_MARK, /* FLCTL */ + + /* IRDA */ + IRDA_FIRSEL_MARK, IRDA_IN_MARK, IRDA_OUT_MARK, + + /* ATAPI */ + IDE_D0_MARK, IDE_D1_MARK, IDE_D2_MARK, IDE_D3_MARK, + IDE_D4_MARK, IDE_D5_MARK, IDE_D6_MARK, IDE_D7_MARK, + IDE_D8_MARK, IDE_D9_MARK, IDE_D10_MARK, IDE_D11_MARK, + IDE_D12_MARK, IDE_D13_MARK, IDE_D14_MARK, IDE_D15_MARK, + IDE_A0_MARK, IDE_A1_MARK, IDE_A2_MARK, IDE_CS0_MARK, + IDE_CS1_MARK, IDE_IOWR_MARK, IDE_IORD_MARK, IDE_IORDY_MARK, + IDE_INT_MARK, IDE_RST_MARK, IDE_DIRECTION_MARK, + IDE_EXBUF_ENB_MARK, IDE_IODACK_MARK, IDE_IODREQ_MARK, + + /* RMII */ + RMII_CRS_DV_MARK, RMII_RX_ER_MARK, RMII_RXD0_MARK, + RMII_RXD1_MARK, RMII_TX_EN_MARK, RMII_TXD0_MARK, + RMII_MDC_MARK, RMII_TXD1_MARK, RMII_MDIO_MARK, + RMII_REF50CK_MARK, /* for RMII */ + RMII_REF125CK_MARK, /* for GMII */ + + /* GEther */ + ET_TX_CLK_MARK, ET_TX_EN_MARK, ET_ETXD0_MARK, ET_ETXD1_MARK, + ET_ETXD2_MARK, ET_ETXD3_MARK, + ET_ETXD4_MARK, ET_ETXD5_MARK, /* for GEther */ + ET_ETXD6_MARK, ET_ETXD7_MARK, /* for GEther */ + ET_COL_MARK, ET_TX_ER_MARK, ET_RX_CLK_MARK, ET_RX_DV_MARK, + ET_ERXD0_MARK, ET_ERXD1_MARK, ET_ERXD2_MARK, ET_ERXD3_MARK, + ET_ERXD4_MARK, ET_ERXD5_MARK, /* for GEther */ + ET_ERXD6_MARK, ET_ERXD7_MARK, /* for GEther */ + ET_RX_ER_MARK, ET_CRS_MARK, ET_MDC_MARK, ET_MDIO_MARK, + ET_LINK_MARK, ET_PHY_INT_MARK, ET_WOL_MARK, ET_GTX_CLK_MARK, + + /* DMA0 */ + DREQ0_MARK, DACK0_MARK, + + /* DMA1 */ + DREQ1_MARK, DACK1_MARK, + + /* SYSC */ + RESETOUTS_MARK, RESETP_PULLUP_MARK, RESETP_PLAIN_MARK, + + /* IRREM */ + IROUT_MARK, + + /* SDENC */ + SDENC_CPG_MARK, SDENC_DV_CLKI_MARK, + + /* DEBUG */ + EDEBGREQ_PULLUP_MARK, /* for JTAG */ + EDEBGREQ_PULLDOWN_MARK, + + TRACEAUD_FROM_VIO_MARK, /* for TRACE/AUD */ + TRACEAUD_FROM_LCDC0_MARK, + TRACEAUD_FROM_MEMC_MARK, + + PINMUX_MARK_END, +}; + +static pinmux_enum_t pinmux_data[] = { + /* specify valid pin states for each pin in GPIO mode */ + + /* I/O and Pull U/D */ + PORT_DATA_IO_PD(0), PORT_DATA_IO_PD(1), + PORT_DATA_IO_PD(2), PORT_DATA_IO_PD(3), + PORT_DATA_IO_PD(4), PORT_DATA_IO_PD(5), + PORT_DATA_IO_PD(6), PORT_DATA_IO(7), + PORT_DATA_IO(8), PORT_DATA_IO(9), + + PORT_DATA_IO_PD(10), PORT_DATA_IO_PD(11), + PORT_DATA_IO_PD(12), PORT_DATA_IO_PU_PD(13), + PORT_DATA_IO_PD(14), PORT_DATA_IO_PD(15), + PORT_DATA_IO_PD(16), PORT_DATA_IO_PD(17), + PORT_DATA_IO(18), PORT_DATA_IO_PU(19), + + PORT_DATA_IO_PU_PD(20), PORT_DATA_IO_PD(21), + PORT_DATA_IO_PU_PD(22), PORT_DATA_IO(23), + PORT_DATA_IO_PU(24), PORT_DATA_IO_PU(25), + PORT_DATA_IO_PU(26), PORT_DATA_IO_PU(27), + PORT_DATA_IO_PU(28), PORT_DATA_IO_PU(29), + + PORT_DATA_IO_PU(30), PORT_DATA_IO_PD(31), + PORT_DATA_IO_PD(32), PORT_DATA_IO_PD(33), + PORT_DATA_IO_PD(34), PORT_DATA_IO_PU(35), + PORT_DATA_IO_PU(36), PORT_DATA_IO_PD(37), + PORT_DATA_IO_PU(38), PORT_DATA_IO_PD(39), + + PORT_DATA_IO_PU_PD(40), PORT_DATA_IO_PD(41), + PORT_DATA_IO_PD(42), PORT_DATA_IO_PU_PD(43), + PORT_DATA_IO_PU_PD(44), PORT_DATA_IO_PU_PD(45), + PORT_DATA_IO_PU_PD(46), PORT_DATA_IO_PU_PD(47), + PORT_DATA_IO_PU_PD(48), PORT_DATA_IO_PU_PD(49), + + PORT_DATA_IO_PU_PD(50), PORT_DATA_IO_PD(51), + PORT_DATA_IO_PD(52), PORT_DATA_IO_PD(53), + PORT_DATA_IO_PD(54), PORT_DATA_IO_PU_PD(55), + PORT_DATA_IO_PU_PD(56), PORT_DATA_IO_PU_PD(57), + PORT_DATA_IO_PU_PD(58), PORT_DATA_IO_PU_PD(59), + + PORT_DATA_IO_PU_PD(60), PORT_DATA_IO_PD(61), + PORT_DATA_IO_PD(62), PORT_DATA_IO_PD(63), + PORT_DATA_IO_PD(64), PORT_DATA_IO_PD(65), + PORT_DATA_IO_PU_PD(66), PORT_DATA_IO_PU_PD(67), + PORT_DATA_IO_PU_PD(68), PORT_DATA_IO_PU_PD(69), + + PORT_DATA_IO_PU_PD(70), PORT_DATA_IO_PU_PD(71), + PORT_DATA_IO_PU_PD(72), PORT_DATA_IO_PU_PD(73), + PORT_DATA_IO_PU_PD(74), PORT_DATA_IO_PU_PD(75), + PORT_DATA_IO_PU_PD(76), PORT_DATA_IO_PU_PD(77), + PORT_DATA_IO_PU_PD(78), PORT_DATA_IO_PU_PD(79), + + PORT_DATA_IO_PU_PD(80), PORT_DATA_IO_PU_PD(81), + PORT_DATA_IO(82), PORT_DATA_IO_PU_PD(83), + PORT_DATA_IO(84), PORT_DATA_IO_PD(85), + PORT_DATA_IO_PD(86), PORT_DATA_IO_PD(87), + PORT_DATA_IO_PD(88), PORT_DATA_IO_PD(89), + + PORT_DATA_IO_PD(90), PORT_DATA_IO_PU_PD(91), + PORT_DATA_IO_PU_PD(92), PORT_DATA_IO_PU_PD(93), + PORT_DATA_IO_PU_PD(94), PORT_DATA_IO_PU_PD(95), + PORT_DATA_IO_PU_PD(96), PORT_DATA_IO_PU_PD(97), + PORT_DATA_IO_PU_PD(98), PORT_DATA_IO_PU_PD(99), + + PORT_DATA_IO_PU_PD(100), PORT_DATA_IO(101), + PORT_DATA_IO_PU(102), PORT_DATA_IO_PU_PD(103), + PORT_DATA_IO_PU(104), PORT_DATA_IO_PU(105), + PORT_DATA_IO_PU_PD(106), PORT_DATA_IO(107), + PORT_DATA_IO(108), PORT_DATA_IO(109), + + PORT_DATA_IO(110), PORT_DATA_IO(111), + PORT_DATA_IO(112), PORT_DATA_IO(113), + PORT_DATA_IO_PU_PD(114), PORT_DATA_IO(115), + PORT_DATA_IO_PD(116), PORT_DATA_IO_PD(117), + PORT_DATA_IO_PD(118), PORT_DATA_IO_PD(119), + + PORT_DATA_IO_PD(120), PORT_DATA_IO_PD(121), + PORT_DATA_IO_PD(122), PORT_DATA_IO_PD(123), + PORT_DATA_IO_PD(124), PORT_DATA_IO(125), + PORT_DATA_IO(126), PORT_DATA_IO(127), + PORT_DATA_IO(128), PORT_DATA_IO(129), + + PORT_DATA_IO(130), PORT_DATA_IO(131), + PORT_DATA_IO(132), PORT_DATA_IO(133), + PORT_DATA_IO(134), PORT_DATA_IO(135), + PORT_DATA_IO(136), PORT_DATA_IO(137), + PORT_DATA_IO(138), PORT_DATA_IO(139), + + PORT_DATA_IO(140), PORT_DATA_IO(141), + PORT_DATA_IO_PU(142), PORT_DATA_IO_PU(143), + PORT_DATA_IO_PU(144), PORT_DATA_IO_PU(145), + PORT_DATA_IO_PU(146), PORT_DATA_IO_PU(147), + PORT_DATA_IO_PU(148), PORT_DATA_IO_PU(149), + + PORT_DATA_IO_PU(150), PORT_DATA_IO_PU(151), + PORT_DATA_IO_PU(152), PORT_DATA_IO_PU(153), + PORT_DATA_IO_PU(154), PORT_DATA_IO_PU(155), + PORT_DATA_IO_PU(156), PORT_DATA_IO_PU(157), + PORT_DATA_IO_PD(158), PORT_DATA_IO_PD(159), + + PORT_DATA_IO_PU_PD(160), PORT_DATA_IO_PD(161), + PORT_DATA_IO_PD(162), PORT_DATA_IO_PD(163), + PORT_DATA_IO_PD(164), PORT_DATA_IO_PD(165), + PORT_DATA_IO_PU(166), PORT_DATA_IO_PU(167), + PORT_DATA_IO_PU(168), PORT_DATA_IO_PU(169), + + PORT_DATA_IO_PU(170), PORT_DATA_IO_PU(171), + PORT_DATA_IO_PD(172), PORT_DATA_IO_PD(173), + PORT_DATA_IO_PD(174), PORT_DATA_IO_PD(175), + PORT_DATA_IO_PU(176), PORT_DATA_IO_PU_PD(177), + PORT_DATA_IO_PU(178), PORT_DATA_IO_PD(179), + + PORT_DATA_IO_PD(180), PORT_DATA_IO_PU(181), + PORT_DATA_IO_PU(182), PORT_DATA_IO(183), + PORT_DATA_IO_PD(184), PORT_DATA_IO_PD(185), + PORT_DATA_IO_PD(186), PORT_DATA_IO_PD(187), + PORT_DATA_IO_PD(188), PORT_DATA_IO_PD(189), + + PORT_DATA_IO_PD(190), PORT_DATA_IO_PD(191), + PORT_DATA_IO_PD(192), PORT_DATA_IO_PU_PD(193), + PORT_DATA_IO_PU_PD(194), PORT_DATA_IO_PD(195), + PORT_DATA_IO_PU_PD(196), PORT_DATA_IO_PD(197), + PORT_DATA_IO_PU_PD(198), PORT_DATA_IO_PU_PD(199), + + PORT_DATA_IO_PU_PD(200), PORT_DATA_IO_PU(201), + PORT_DATA_IO_PU_PD(202), PORT_DATA_IO(203), + PORT_DATA_IO_PU_PD(204), PORT_DATA_IO_PU_PD(205), + PORT_DATA_IO_PU_PD(206), PORT_DATA_IO_PU_PD(207), + PORT_DATA_IO_PU_PD(208), PORT_DATA_IO_PD(209), + + PORT_DATA_IO_PD(210), PORT_DATA_IO_PD(211), + + /* Port0 */ + PINMUX_DATA(DBGMDT2_MARK, PORT0_FN1), + PINMUX_DATA(FSIAISLD_PORT0_MARK, PORT0_FN2, MSEL5CR_3_0), + PINMUX_DATA(FSIAOSLD1_MARK, PORT0_FN3), + PINMUX_DATA(LCD0_D22_PORT0_MARK, PORT0_FN4, MSEL5CR_6_0), + PINMUX_DATA(SCIFA7_RXD_MARK, PORT0_FN6), + PINMUX_DATA(LCD1_D4_MARK, PORT0_FN7), + PINMUX_DATA(IRQ5_PORT0_MARK, PORT0_FN0, MSEL1CR_5_0), + + /* Port1 */ + PINMUX_DATA(DBGMDT1_MARK, PORT1_FN1), + PINMUX_DATA(FMSISLD_PORT1_MARK, PORT1_FN2, MSEL5CR_5_0), + PINMUX_DATA(FSIAOSLD2_MARK, PORT1_FN3), + PINMUX_DATA(LCD0_D23_PORT1_MARK, PORT1_FN4, MSEL5CR_6_0), + PINMUX_DATA(SCIFA7_TXD_MARK, PORT1_FN6), + PINMUX_DATA(LCD1_D3_MARK, PORT1_FN7), + PINMUX_DATA(IRQ5_PORT1_MARK, PORT1_FN0, MSEL1CR_5_1), + + /* Port2 */ + PINMUX_DATA(DBGMDT0_MARK, PORT2_FN1), + PINMUX_DATA(SCIFB_SCK_PORT2_MARK, PORT2_FN2, MSEL5CR_17_1), + PINMUX_DATA(LCD0_D21_PORT2_MARK, PORT2_FN4, MSEL5CR_6_0), + PINMUX_DATA(LCD1_D2_MARK, PORT2_FN7), + PINMUX_DATA(IRQ0_PORT2_MARK, PORT2_FN0, MSEL1CR_0_1), + + /* Port3 */ + PINMUX_DATA(DBGMD21_MARK, PORT3_FN1), + PINMUX_DATA(SCIFB_RXD_PORT3_MARK, PORT3_FN2, MSEL5CR_17_1), + PINMUX_DATA(LCD0_D20_PORT3_MARK, PORT3_FN4, MSEL5CR_6_0), + PINMUX_DATA(LCD1_D1_MARK, PORT3_FN7), + + /* Port4 */ + PINMUX_DATA(DBGMD20_MARK, PORT4_FN1), + PINMUX_DATA(SCIFB_TXD_PORT4_MARK, PORT4_FN2, MSEL5CR_17_1), + PINMUX_DATA(LCD0_D19_PORT4_MARK, PORT4_FN4, MSEL5CR_6_0), + PINMUX_DATA(LCD1_D0_MARK, PORT4_FN7), + + /* Port5 */ + PINMUX_DATA(DBGMD11_MARK, PORT5_FN1), + PINMUX_DATA(BBIF2_TXD2_PORT5_MARK, PORT5_FN2, MSEL5CR_0_0), + PINMUX_DATA(FSIAISLD_PORT5_MARK, PORT5_FN4, MSEL5CR_3_1), + PINMUX_DATA(RSPI_SSL0_A_MARK, PORT5_FN6), + PINMUX_DATA(LCD1_VCPWC_MARK, PORT5_FN7), + + /* Port6 */ + PINMUX_DATA(DBGMD10_MARK, PORT6_FN1), + PINMUX_DATA(BBIF2_TSYNC2_PORT6_MARK, PORT6_FN2, MSEL5CR_0_0), + PINMUX_DATA(FMSISLD_PORT6_MARK, PORT6_FN4, MSEL5CR_5_1), + PINMUX_DATA(RSPI_SSL1_A_MARK, PORT6_FN6), + PINMUX_DATA(LCD1_VEPWC_MARK, PORT6_FN7), + + /* Port7 */ + PINMUX_DATA(FSIAOLR_MARK, PORT7_FN1), + + /* Port8 */ + PINMUX_DATA(FSIAOBT_MARK, PORT8_FN1), + + /* Port9 */ + PINMUX_DATA(FSIAOSLD_MARK, PORT9_FN1), + PINMUX_DATA(FSIASPDIF_PORT9_MARK, PORT9_FN2, MSEL5CR_4_0), + + /* Port10 */ + PINMUX_DATA(FSIAOMC_MARK, PORT10_FN1), + PINMUX_DATA(SCIFA5_RXD_PORT10_MARK, PORT10_FN3, MSEL5CR_14_0, MSEL5CR_15_0), + PINMUX_DATA(IRQ3_PORT10_MARK, PORT10_FN0, MSEL1CR_3_0), + + /* Port11 */ + PINMUX_DATA(FSIACK_MARK, PORT11_FN1), + PINMUX_DATA(IRQ2_PORT11_MARK, PORT11_FN0, MSEL1CR_2_0), + + /* Port12 */ + PINMUX_DATA(FSIAILR_MARK, PORT12_FN1), + PINMUX_DATA(SCIFA4_RXD_PORT12_MARK, PORT12_FN2, MSEL5CR_12_0, MSEL5CR_11_0), + PINMUX_DATA(LCD1_RS_MARK, PORT12_FN6), + PINMUX_DATA(LCD1_DISP_MARK, PORT12_FN7), + PINMUX_DATA(IRQ2_PORT12_MARK, PORT12_FN0, MSEL1CR_2_1), + + /* Port13 */ + PINMUX_DATA(FSIAIBT_MARK, PORT13_FN1), + PINMUX_DATA(SCIFA4_TXD_PORT13_MARK, PORT13_FN2, MSEL5CR_12_0, MSEL5CR_11_0), + PINMUX_DATA(LCD1_RD_MARK, PORT13_FN7), + PINMUX_DATA(IRQ0_PORT13_MARK, PORT13_FN0, MSEL1CR_0_0), + + /* Port14 */ + PINMUX_DATA(FMSOILR_MARK, PORT14_FN1), + PINMUX_DATA(FMSIILR_MARK, PORT14_FN2), + PINMUX_DATA(VIO_CKO1_MARK, PORT14_FN3), + PINMUX_DATA(LCD1_D23_MARK, PORT14_FN7), + PINMUX_DATA(IRQ3_PORT14_MARK, PORT14_FN0, MSEL1CR_3_1), + + /* Port15 */ + PINMUX_DATA(FMSOIBT_MARK, PORT15_FN1), + PINMUX_DATA(FMSIIBT_MARK, PORT15_FN2), + PINMUX_DATA(VIO_CKO2_MARK, PORT15_FN3), + PINMUX_DATA(LCD1_D22_MARK, PORT15_FN7), + PINMUX_DATA(IRQ4_PORT15_MARK, PORT15_FN0, MSEL1CR_4_0), + + /* Port16 */ + PINMUX_DATA(FMSOOLR_MARK, PORT16_FN1), + PINMUX_DATA(FMSIOLR_MARK, PORT16_FN2), + + /* Port17 */ + PINMUX_DATA(FMSOOBT_MARK, PORT17_FN1), + PINMUX_DATA(FMSIOBT_MARK, PORT17_FN2), + + /* Port18 */ + PINMUX_DATA(FMSOSLD_MARK, PORT18_FN1), + PINMUX_DATA(FSIASPDIF_PORT18_MARK, PORT18_FN2, MSEL5CR_4_1), + + /* Port19 */ + PINMUX_DATA(FMSICK_MARK, PORT19_FN1), + PINMUX_DATA(CS5A_PORT19_MARK, PORT19_FN7, MSEL5CR_2_1), + PINMUX_DATA(IRQ10_MARK, PORT19_FN0), + + /* Port20 */ + PINMUX_DATA(FMSOCK_MARK, PORT20_FN1), + PINMUX_DATA(SCIFA5_TXD_PORT20_MARK, PORT20_FN3, MSEL5CR_15_0, MSEL5CR_14_0), + PINMUX_DATA(IRQ1_MARK, PORT20_FN0), + + /* Port21 */ + PINMUX_DATA(SCIFA1_CTS_MARK, PORT21_FN1), + PINMUX_DATA(SCIFA4_SCK_PORT21_MARK, PORT21_FN2, MSEL5CR_10_0), + PINMUX_DATA(TPU0TO1_MARK, PORT21_FN4), + PINMUX_DATA(VIO1_FIELD_MARK, PORT21_FN5), + PINMUX_DATA(STP0_IPD5_MARK, PORT21_FN6), + PINMUX_DATA(LCD1_D10_MARK, PORT21_FN7), + + /* Port22 */ + PINMUX_DATA(SCIFA2_SCK_PORT22_MARK, PORT22_FN1, MSEL5CR_7_0), + PINMUX_DATA(SIM_D_PORT22_MARK, PORT22_FN4, MSEL5CR_21_0), + PINMUX_DATA(VIO0_D13_PORT22_MARK, PORT22_FN7, MSEL5CR_27_1), + + /* Port23 */ + PINMUX_DATA(SCIFA1_RTS_MARK, PORT23_FN1), + PINMUX_DATA(SCIFA5_SCK_PORT23_MARK, PORT23_FN3, MSEL5CR_13_0), + PINMUX_DATA(TPU0TO0_MARK, PORT23_FN4), + PINMUX_DATA(VIO_CKO_1_MARK, PORT23_FN5), + PINMUX_DATA(STP0_IPD2_MARK, PORT23_FN6), + PINMUX_DATA(LCD1_D7_MARK, PORT23_FN7), + + /* Port24 */ + PINMUX_DATA(VIO0_D15_PORT24_MARK, PORT24_FN1, MSEL5CR_27_0), + PINMUX_DATA(VIO1_D7_MARK, PORT24_FN5), + PINMUX_DATA(SCIFA6_SCK_MARK, PORT24_FN6), + PINMUX_DATA(SDHI2_CD_PORT24_MARK, PORT24_FN7, MSEL5CR_19_0), + + /* Port25 */ + PINMUX_DATA(VIO0_D14_PORT25_MARK, PORT25_FN1, MSEL5CR_27_0), + PINMUX_DATA(VIO1_D6_MARK, PORT25_FN5), + PINMUX_DATA(SCIFA6_RXD_MARK, PORT25_FN6), + PINMUX_DATA(SDHI2_WP_PORT25_MARK, PORT25_FN7, MSEL5CR_19_0), + + /* Port26 */ + PINMUX_DATA(VIO0_D13_PORT26_MARK, PORT26_FN1, MSEL5CR_27_0), + PINMUX_DATA(VIO1_D5_MARK, PORT26_FN5), + PINMUX_DATA(SCIFA6_TXD_MARK, PORT26_FN6), + + /* Port27 - Port39 Function */ + PINMUX_DATA(VIO0_D7_MARK, PORT27_FN1), + PINMUX_DATA(VIO0_D6_MARK, PORT28_FN1), + PINMUX_DATA(VIO0_D5_MARK, PORT29_FN1), + PINMUX_DATA(VIO0_D4_MARK, PORT30_FN1), + PINMUX_DATA(VIO0_D3_MARK, PORT31_FN1), + PINMUX_DATA(VIO0_D2_MARK, PORT32_FN1), + PINMUX_DATA(VIO0_D1_MARK, PORT33_FN1), + PINMUX_DATA(VIO0_D0_MARK, PORT34_FN1), + PINMUX_DATA(VIO0_CLK_MARK, PORT35_FN1), + PINMUX_DATA(VIO_CKO_MARK, PORT36_FN1), + PINMUX_DATA(VIO0_HD_MARK, PORT37_FN1), + PINMUX_DATA(VIO0_FIELD_MARK, PORT38_FN1), + PINMUX_DATA(VIO0_VD_MARK, PORT39_FN1), + + /* Port38 IRQ */ + PINMUX_DATA(IRQ25_MARK, PORT38_FN0), + + /* Port40 */ + PINMUX_DATA(LCD0_D18_PORT40_MARK, PORT40_FN4, MSEL5CR_6_0), + PINMUX_DATA(RSPI_CK_A_MARK, PORT40_FN6), + PINMUX_DATA(LCD1_LCLK_MARK, PORT40_FN7), + + /* Port41 */ + PINMUX_DATA(LCD0_D17_MARK, PORT41_FN1), + PINMUX_DATA(MSIOF2_SS1_MARK, PORT41_FN2), + PINMUX_DATA(IRQ31_PORT41_MARK, PORT41_FN0, MSEL1CR_31_1), + + /* Port42 */ + PINMUX_DATA(LCD0_D16_MARK, PORT42_FN1), + PINMUX_DATA(MSIOF2_MCK1_MARK, PORT42_FN2), + PINMUX_DATA(IRQ12_PORT42_MARK, PORT42_FN0, MSEL1CR_12_1), + + /* Port43 */ + PINMUX_DATA(LCD0_D15_MARK, PORT43_FN1), + PINMUX_DATA(MSIOF2_MCK0_MARK, PORT43_FN2), + PINMUX_DATA(KEYIN0_PORT43_MARK, PORT43_FN3, MSEL4CR_18_0), + PINMUX_DATA(DV_D15_MARK, PORT43_FN6), + + /* Port44 */ + PINMUX_DATA(LCD0_D14_MARK, PORT44_FN1), + PINMUX_DATA(MSIOF2_RSYNC_MARK, PORT44_FN2), + PINMUX_DATA(KEYIN1_PORT44_MARK, PORT44_FN3, MSEL4CR_18_0), + PINMUX_DATA(DV_D14_MARK, PORT44_FN6), + + /* Port45 */ + PINMUX_DATA(LCD0_D13_MARK, PORT45_FN1), + PINMUX_DATA(MSIOF2_RSCK_MARK, PORT45_FN2), + PINMUX_DATA(KEYIN2_PORT45_MARK, PORT45_FN3, MSEL4CR_18_0), + PINMUX_DATA(DV_D13_MARK, PORT45_FN6), + + /* Port46 */ + PINMUX_DATA(LCD0_D12_MARK, PORT46_FN1), + PINMUX_DATA(KEYIN3_PORT46_MARK, PORT46_FN3, MSEL4CR_18_0), + PINMUX_DATA(DV_D12_MARK, PORT46_FN6), + + /* Port47 */ + PINMUX_DATA(LCD0_D11_MARK, PORT47_FN1), + PINMUX_DATA(KEYIN4_MARK, PORT47_FN3), + PINMUX_DATA(DV_D11_MARK, PORT47_FN6), + + /* Port48 */ + PINMUX_DATA(LCD0_D10_MARK, PORT48_FN1), + PINMUX_DATA(KEYIN5_MARK, PORT48_FN3), + PINMUX_DATA(DV_D10_MARK, PORT48_FN6), + + /* Port49 */ + PINMUX_DATA(LCD0_D9_MARK, PORT49_FN1), + PINMUX_DATA(KEYIN6_MARK, PORT49_FN3), + PINMUX_DATA(DV_D9_MARK, PORT49_FN6), + PINMUX_DATA(IRQ30_PORT49_MARK, PORT49_FN0, MSEL1CR_30_1), + + /* Port50 */ + PINMUX_DATA(LCD0_D8_MARK, PORT50_FN1), + PINMUX_DATA(KEYIN7_MARK, PORT50_FN3), + PINMUX_DATA(DV_D8_MARK, PORT50_FN6), + PINMUX_DATA(IRQ29_PORT50_MARK, PORT50_FN0, MSEL1CR_29_1), + + /* Port51 */ + PINMUX_DATA(LCD0_D7_MARK, PORT51_FN1), + PINMUX_DATA(KEYOUT0_MARK, PORT51_FN3), + PINMUX_DATA(DV_D7_MARK, PORT51_FN6), + + /* Port52 */ + PINMUX_DATA(LCD0_D6_MARK, PORT52_FN1), + PINMUX_DATA(KEYOUT1_MARK, PORT52_FN3), + PINMUX_DATA(DV_D6_MARK, PORT52_FN6), + + /* Port53 */ + PINMUX_DATA(LCD0_D5_MARK, PORT53_FN1), + PINMUX_DATA(KEYOUT2_MARK, PORT53_FN3), + PINMUX_DATA(DV_D5_MARK, PORT53_FN6), + + /* Port54 */ + PINMUX_DATA(LCD0_D4_MARK, PORT54_FN1), + PINMUX_DATA(KEYOUT3_MARK, PORT54_FN3), + PINMUX_DATA(DV_D4_MARK, PORT54_FN6), + + /* Port55 */ + PINMUX_DATA(LCD0_D3_MARK, PORT55_FN1), + PINMUX_DATA(KEYOUT4_MARK, PORT55_FN3), + PINMUX_DATA(KEYIN3_PORT55_MARK, PORT55_FN4, MSEL4CR_18_1), + PINMUX_DATA(DV_D3_MARK, PORT55_FN6), + + /* Port56 */ + PINMUX_DATA(LCD0_D2_MARK, PORT56_FN1), + PINMUX_DATA(KEYOUT5_MARK, PORT56_FN3), + PINMUX_DATA(KEYIN2_PORT56_MARK, PORT56_FN4, MSEL4CR_18_1), + PINMUX_DATA(DV_D2_MARK, PORT56_FN6), + PINMUX_DATA(IRQ28_PORT56_MARK, PORT56_FN0, MSEL1CR_28_1), + + /* Port57 */ + PINMUX_DATA(LCD0_D1_MARK, PORT57_FN1), + PINMUX_DATA(KEYOUT6_MARK, PORT57_FN3), + PINMUX_DATA(KEYIN1_PORT57_MARK, PORT57_FN4, MSEL4CR_18_1), + PINMUX_DATA(DV_D1_MARK, PORT57_FN6), + PINMUX_DATA(IRQ27_PORT57_MARK, PORT57_FN0, MSEL1CR_27_1), + + /* Port58 */ + PINMUX_DATA(LCD0_D0_MARK, PORT58_FN1), + PINMUX_DATA(KEYOUT7_MARK, PORT58_FN3), + PINMUX_DATA(KEYIN0_PORT58_MARK, PORT58_FN4, MSEL4CR_18_1), + PINMUX_DATA(DV_D0_MARK, PORT58_FN6), + PINMUX_DATA(IRQ26_PORT58_MARK, PORT58_FN0, MSEL1CR_26_1), + + /* Port59 */ + PINMUX_DATA(LCD0_VCPWC_MARK, PORT59_FN1), + PINMUX_DATA(BBIF2_TSCK2_PORT59_MARK, PORT59_FN2, MSEL5CR_0_0), + PINMUX_DATA(RSPI_MOSI_A_MARK, PORT59_FN6), + + /* Port60 */ + PINMUX_DATA(LCD0_VEPWC_MARK, PORT60_FN1), + PINMUX_DATA(BBIF2_RXD2_PORT60_MARK, PORT60_FN2, MSEL5CR_0_0), + PINMUX_DATA(RSPI_MISO_A_MARK, PORT60_FN6), + + /* Port61 */ + PINMUX_DATA(LCD0_DON_MARK, PORT61_FN1), + PINMUX_DATA(MSIOF2_TXD_MARK, PORT61_FN2), + + /* Port62 */ + PINMUX_DATA(LCD0_DCK_MARK, PORT62_FN1), + PINMUX_DATA(LCD0_WR_MARK, PORT62_FN4), + PINMUX_DATA(DV_CLK_MARK, PORT62_FN6), + PINMUX_DATA(IRQ15_PORT62_MARK, PORT62_FN0, MSEL1CR_15_1), + + /* Port63 */ + PINMUX_DATA(LCD0_VSYN_MARK, PORT63_FN1), + PINMUX_DATA(DV_VSYNC_MARK, PORT63_FN6), + PINMUX_DATA(IRQ14_PORT63_MARK, PORT63_FN0, MSEL1CR_14_1), + + /* Port64 */ + PINMUX_DATA(LCD0_HSYN_MARK, PORT64_FN1), + PINMUX_DATA(LCD0_CS_MARK, PORT64_FN4), + PINMUX_DATA(DV_HSYNC_MARK, PORT64_FN6), + PINMUX_DATA(IRQ13_PORT64_MARK, PORT64_FN0, MSEL1CR_13_1), + + /* Port65 */ + PINMUX_DATA(LCD0_DISP_MARK, PORT65_FN1), + PINMUX_DATA(MSIOF2_TSCK_MARK, PORT65_FN2), + PINMUX_DATA(LCD0_RS_MARK, PORT65_FN4), + + /* Port66 */ + PINMUX_DATA(MEMC_INT_MARK, PORT66_FN1), + PINMUX_DATA(TPU0TO2_PORT66_MARK, PORT66_FN3, MSEL5CR_25_0), + PINMUX_DATA(MMC0_CLK_PORT66_MARK, PORT66_FN4, MSEL4CR_15_0), + PINMUX_DATA(SDHI1_CLK_MARK, PORT66_FN6), + + /* Port67 - Port73 Function1 */ + PINMUX_DATA(MEMC_CS0_MARK, PORT67_FN1), + PINMUX_DATA(MEMC_AD8_MARK, PORT68_FN1), + PINMUX_DATA(MEMC_AD9_MARK, PORT69_FN1), + PINMUX_DATA(MEMC_AD10_MARK, PORT70_FN1), + PINMUX_DATA(MEMC_AD11_MARK, PORT71_FN1), + PINMUX_DATA(MEMC_AD12_MARK, PORT72_FN1), + PINMUX_DATA(MEMC_AD13_MARK, PORT73_FN1), + + /* Port67 - Port73 Function2 */ + PINMUX_DATA(MSIOF1_SS1_PORT67_MARK, PORT67_FN2, MSEL4CR_10_1), + PINMUX_DATA(MSIOF1_RSCK_MARK, PORT68_FN2), + PINMUX_DATA(MSIOF1_RSYNC_MARK, PORT69_FN2), + PINMUX_DATA(MSIOF1_MCK0_MARK, PORT70_FN2), + PINMUX_DATA(MSIOF1_MCK1_MARK, PORT71_FN2), + PINMUX_DATA(MSIOF1_TSCK_PORT72_MARK, PORT72_FN2, MSEL4CR_10_1), + PINMUX_DATA(MSIOF1_TSYNC_PORT73_MARK, PORT73_FN2, MSEL4CR_10_1), + + /* Port67 - Port73 Function4 */ + PINMUX_DATA(MMC0_CMD_PORT67_MARK, PORT67_FN4, MSEL4CR_15_0), + PINMUX_DATA(MMC0_D0_PORT68_MARK, PORT68_FN4, MSEL4CR_15_0), + PINMUX_DATA(MMC0_D1_PORT69_MARK, PORT69_FN4, MSEL4CR_15_0), + PINMUX_DATA(MMC0_D2_PORT70_MARK, PORT70_FN4, MSEL4CR_15_0), + PINMUX_DATA(MMC0_D3_PORT71_MARK, PORT71_FN4, MSEL4CR_15_0), + PINMUX_DATA(MMC0_D4_PORT72_MARK, PORT72_FN4, MSEL4CR_15_0), + PINMUX_DATA(MMC0_D5_PORT73_MARK, PORT73_FN4, MSEL4CR_15_0), + + /* Port67 - Port73 Function6 */ + PINMUX_DATA(SDHI1_CMD_MARK, PORT67_FN6), + PINMUX_DATA(SDHI1_D0_MARK, PORT68_FN6), + PINMUX_DATA(SDHI1_D1_MARK, PORT69_FN6), + PINMUX_DATA(SDHI1_D2_MARK, PORT70_FN6), + PINMUX_DATA(SDHI1_D3_MARK, PORT71_FN6), + PINMUX_DATA(SDHI1_CD_MARK, PORT72_FN6), + PINMUX_DATA(SDHI1_WP_MARK, PORT73_FN6), + + /* Port67 - Port71 IRQ */ + PINMUX_DATA(IRQ20_MARK, PORT67_FN0), + PINMUX_DATA(IRQ16_PORT68_MARK, PORT68_FN0, MSEL1CR_16_0), + PINMUX_DATA(IRQ17_MARK, PORT69_FN0), + PINMUX_DATA(IRQ18_MARK, PORT70_FN0), + PINMUX_DATA(IRQ19_MARK, PORT71_FN0), + + /* Port74 */ + PINMUX_DATA(MEMC_AD14_MARK, PORT74_FN1), + PINMUX_DATA(MSIOF1_TXD_PORT74_MARK, PORT74_FN2, MSEL4CR_10_1), + PINMUX_DATA(MMC0_D6_PORT74_MARK, PORT74_FN4, MSEL4CR_15_0), + PINMUX_DATA(STP1_IPD7_MARK, PORT74_FN6), + PINMUX_DATA(LCD1_D21_MARK, PORT74_FN7), + + /* Port75 */ + PINMUX_DATA(MEMC_AD15_MARK, PORT75_FN1), + PINMUX_DATA(MSIOF1_RXD_PORT75_MARK, PORT75_FN2, MSEL4CR_10_1), + PINMUX_DATA(MMC0_D7_PORT75_MARK, PORT75_FN4, MSEL4CR_15_0), + PINMUX_DATA(STP1_IPD6_MARK, PORT75_FN6), + PINMUX_DATA(LCD1_D20_MARK, PORT75_FN7), + + /* Port76 - Port80 Function */ + PINMUX_DATA(SDHI0_CMD_MARK, PORT76_FN1), + PINMUX_DATA(SDHI0_D0_MARK, PORT77_FN1), + PINMUX_DATA(SDHI0_D1_MARK, PORT78_FN1), + PINMUX_DATA(SDHI0_D2_MARK, PORT79_FN1), + PINMUX_DATA(SDHI0_D3_MARK, PORT80_FN1), + + /* Port81 */ + PINMUX_DATA(SDHI0_CD_MARK, PORT81_FN1), + PINMUX_DATA(IRQ26_PORT81_MARK, PORT81_FN0, MSEL1CR_26_0), + + /* Port82 - Port88 Function */ + PINMUX_DATA(SDHI0_CLK_MARK, PORT82_FN1), + PINMUX_DATA(SDHI0_WP_MARK, PORT83_FN1), + PINMUX_DATA(RESETOUTS_MARK, PORT84_FN1), + PINMUX_DATA(USB0_PPON_MARK, PORT85_FN1), + PINMUX_DATA(USB0_OCI_MARK, PORT86_FN1), + PINMUX_DATA(USB1_PPON_MARK, PORT87_FN1), + PINMUX_DATA(USB1_OCI_MARK, PORT88_FN1), + + /* Port89 */ + PINMUX_DATA(DREQ0_MARK, PORT89_FN1), + PINMUX_DATA(BBIF2_TSCK2_PORT89_MARK, PORT89_FN2, MSEL5CR_0_1), + PINMUX_DATA(RSPI_SSL3_A_MARK, PORT89_FN6), + + /* Port90 */ + PINMUX_DATA(DACK0_MARK, PORT90_FN1), + PINMUX_DATA(BBIF2_RXD2_PORT90_MARK, PORT90_FN2, MSEL5CR_0_1), + PINMUX_DATA(RSPI_SSL2_A_MARK, PORT90_FN6), + PINMUX_DATA(WAIT_PORT90_MARK, PORT90_FN7, MSEL5CR_2_1), + + /* Port91 */ + PINMUX_DATA(MEMC_AD0_MARK, PORT91_FN1), + PINMUX_DATA(BBIF1_RXD_MARK, PORT91_FN2), + PINMUX_DATA(SCIFA5_TXD_PORT91_MARK, PORT91_FN3, MSEL5CR_15_1, MSEL5CR_14_0), + PINMUX_DATA(LCD1_D5_MARK, PORT91_FN7), + + /* Port92 */ + PINMUX_DATA(MEMC_AD1_MARK, PORT92_FN1), + PINMUX_DATA(BBIF1_TSYNC_MARK, PORT92_FN2), + PINMUX_DATA(SCIFA5_RXD_PORT92_MARK, PORT92_FN3, MSEL5CR_15_1, MSEL5CR_14_0), + PINMUX_DATA(STP0_IPD1_MARK, PORT92_FN6), + PINMUX_DATA(LCD1_D6_MARK, PORT92_FN7), + + /* Port93 */ + PINMUX_DATA(MEMC_AD2_MARK, PORT93_FN1), + PINMUX_DATA(BBIF1_TSCK_MARK, PORT93_FN2), + PINMUX_DATA(SCIFA4_TXD_PORT93_MARK, PORT93_FN3, MSEL5CR_12_1, MSEL5CR_11_0), + PINMUX_DATA(STP0_IPD3_MARK, PORT93_FN6), + PINMUX_DATA(LCD1_D8_MARK, PORT93_FN7), + + /* Port94 */ + PINMUX_DATA(MEMC_AD3_MARK, PORT94_FN1), + PINMUX_DATA(BBIF1_TXD_MARK, PORT94_FN2), + PINMUX_DATA(SCIFA4_RXD_PORT94_MARK, PORT94_FN3, MSEL5CR_12_1, MSEL5CR_11_0), + PINMUX_DATA(STP0_IPD4_MARK, PORT94_FN6), + PINMUX_DATA(LCD1_D9_MARK, PORT94_FN7), + + /* Port95 */ + PINMUX_DATA(MEMC_CS1_MARK, PORT95_FN1, MSEL4CR_6_0), + PINMUX_DATA(MEMC_A1_MARK, PORT95_FN1, MSEL4CR_6_1), + + PINMUX_DATA(SCIFA2_CTS_MARK, PORT95_FN2), + PINMUX_DATA(SIM_RST_MARK, PORT95_FN4), + PINMUX_DATA(VIO0_D14_PORT95_MARK, PORT95_FN7, MSEL5CR_27_1), + PINMUX_DATA(IRQ22_MARK, PORT95_FN0), + + /* Port96 */ + PINMUX_DATA(MEMC_ADV_MARK, PORT96_FN1, MSEL4CR_6_0), + PINMUX_DATA(MEMC_DREQ0_MARK, PORT96_FN1, MSEL4CR_6_1), + + PINMUX_DATA(SCIFA2_RTS_MARK, PORT96_FN2), + PINMUX_DATA(SIM_CLK_MARK, PORT96_FN4), + PINMUX_DATA(VIO0_D15_PORT96_MARK, PORT96_FN7, MSEL5CR_27_1), + PINMUX_DATA(IRQ23_MARK, PORT96_FN0), + + /* Port97 */ + PINMUX_DATA(MEMC_AD4_MARK, PORT97_FN1), + PINMUX_DATA(BBIF1_RSCK_MARK, PORT97_FN2), + PINMUX_DATA(LCD1_CS_MARK, PORT97_FN6), + PINMUX_DATA(LCD1_HSYN_MARK, PORT97_FN7), + PINMUX_DATA(IRQ12_PORT97_MARK, PORT97_FN0, MSEL1CR_12_0), + + /* Port98 */ + PINMUX_DATA(MEMC_AD5_MARK, PORT98_FN1), + PINMUX_DATA(BBIF1_RSYNC_MARK, PORT98_FN2), + PINMUX_DATA(LCD1_VSYN_MARK, PORT98_FN7), + PINMUX_DATA(IRQ13_PORT98_MARK, PORT98_FN0, MSEL1CR_13_0), + + /* Port99 */ + PINMUX_DATA(MEMC_AD6_MARK, PORT99_FN1), + PINMUX_DATA(BBIF1_FLOW_MARK, PORT99_FN2), + PINMUX_DATA(LCD1_WR_MARK, PORT99_FN6), + PINMUX_DATA(LCD1_DCK_MARK, PORT99_FN7), + PINMUX_DATA(IRQ14_PORT99_MARK, PORT99_FN0, MSEL1CR_14_0), + + /* Port100 */ + PINMUX_DATA(MEMC_AD7_MARK, PORT100_FN1), + PINMUX_DATA(BBIF1_RX_FLOW_N_MARK, PORT100_FN2), + PINMUX_DATA(LCD1_DON_MARK, PORT100_FN7), + PINMUX_DATA(IRQ15_PORT100_MARK, PORT100_FN0, MSEL1CR_15_0), + + /* Port101 */ + PINMUX_DATA(FCE0_MARK, PORT101_FN1), + + /* Port102 */ + PINMUX_DATA(FRB_MARK, PORT102_FN1), + PINMUX_DATA(LCD0_LCLK_PORT102_MARK, PORT102_FN4, MSEL5CR_6_0), + + /* Port103 */ + PINMUX_DATA(CS5B_MARK, PORT103_FN1), + PINMUX_DATA(FCE1_MARK, PORT103_FN2), + PINMUX_DATA(MMC1_CLK_PORT103_MARK, PORT103_FN3, MSEL4CR_15_1), + + /* Port104 */ + PINMUX_DATA(CS6A_MARK, PORT104_FN1), + PINMUX_DATA(MMC1_CMD_PORT104_MARK, PORT104_FN3, MSEL4CR_15_1), + PINMUX_DATA(IRQ11_MARK, PORT104_FN0), + + /* Port105 */ + PINMUX_DATA(CS5A_PORT105_MARK, PORT105_FN1, MSEL5CR_2_0), + PINMUX_DATA(SCIFA3_RTS_PORT105_MARK, PORT105_FN4, MSEL5CR_8_0), + + /* Port106 */ + PINMUX_DATA(IOIS16_MARK, PORT106_FN1), + PINMUX_DATA(IDE_EXBUF_ENB_MARK, PORT106_FN6), + + /* Port107 - Port115 Function */ + PINMUX_DATA(WE3_ICIOWR_MARK, PORT107_FN1), + PINMUX_DATA(WE2_ICIORD_MARK, PORT108_FN1), + PINMUX_DATA(CS0_MARK, PORT109_FN1), + PINMUX_DATA(CS2_MARK, PORT110_FN1), + PINMUX_DATA(CS4_MARK, PORT111_FN1), + PINMUX_DATA(WE1_MARK, PORT112_FN1), + PINMUX_DATA(WE0_FWE_MARK, PORT113_FN1), + PINMUX_DATA(RDWR_MARK, PORT114_FN1), + PINMUX_DATA(RD_FSC_MARK, PORT115_FN1), + + /* Port116 */ + PINMUX_DATA(A25_MARK, PORT116_FN1), + PINMUX_DATA(MSIOF0_SS2_MARK, PORT116_FN2), + PINMUX_DATA(MSIOF1_SS2_PORT116_MARK, PORT116_FN3, MSEL4CR_10_0), + PINMUX_DATA(SCIFA3_SCK_PORT116_MARK, PORT116_FN4, MSEL5CR_8_0), + PINMUX_DATA(GPO1_MARK, PORT116_FN5), + + /* Port117 */ + PINMUX_DATA(A24_MARK, PORT117_FN1), + PINMUX_DATA(MSIOF0_SS1_MARK, PORT117_FN2), + PINMUX_DATA(MSIOF1_SS1_PORT117_MARK, PORT117_FN3, MSEL4CR_10_0), + PINMUX_DATA(SCIFA3_CTS_PORT117_MARK, PORT117_FN4, MSEL5CR_8_0), + PINMUX_DATA(GPO0_MARK, PORT117_FN5), + + /* Port118 */ + PINMUX_DATA(A23_MARK, PORT118_FN1), + PINMUX_DATA(MSIOF0_MCK1_MARK, PORT118_FN2), + PINMUX_DATA(MSIOF1_RXD_PORT118_MARK, PORT118_FN3, MSEL4CR_10_0), + PINMUX_DATA(GPI1_MARK, PORT118_FN5), + PINMUX_DATA(IRQ9_PORT118_MARK, PORT118_FN0, MSEL1CR_9_0), + + /* Port119 */ + PINMUX_DATA(A22_MARK, PORT119_FN1), + PINMUX_DATA(MSIOF0_MCK0_MARK, PORT119_FN2), + PINMUX_DATA(MSIOF1_TXD_PORT119_MARK, PORT119_FN3, MSEL4CR_10_0), + PINMUX_DATA(GPI0_MARK, PORT119_FN5), + PINMUX_DATA(IRQ8_MARK, PORT119_FN0), + + /* Port120 */ + PINMUX_DATA(A21_MARK, PORT120_FN1), + PINMUX_DATA(MSIOF0_RSYNC_MARK, PORT120_FN2), + PINMUX_DATA(MSIOF1_TSYNC_PORT120_MARK, PORT120_FN3, MSEL4CR_10_0), + PINMUX_DATA(IRQ7_PORT120_MARK, PORT120_FN0, MSEL1CR_7_0), + + /* Port121 */ + PINMUX_DATA(A20_MARK, PORT121_FN1), + PINMUX_DATA(MSIOF0_RSCK_MARK, PORT121_FN2), + PINMUX_DATA(MSIOF1_TSCK_PORT121_MARK, PORT121_FN3, MSEL4CR_10_0), + PINMUX_DATA(IRQ6_PORT121_MARK, PORT121_FN0, MSEL1CR_6_0), + + /* Port122 */ + PINMUX_DATA(A19_MARK, PORT122_FN1), + PINMUX_DATA(MSIOF0_RXD_MARK, PORT122_FN2), + + /* Port123 */ + PINMUX_DATA(A18_MARK, PORT123_FN1), + PINMUX_DATA(MSIOF0_TSCK_MARK, PORT123_FN2), + + /* Port124 */ + PINMUX_DATA(A17_MARK, PORT124_FN1), + PINMUX_DATA(MSIOF0_TSYNC_MARK, PORT124_FN2), + + /* Port125 - Port141 Function */ + PINMUX_DATA(A16_MARK, PORT125_FN1), + PINMUX_DATA(A15_MARK, PORT126_FN1), + PINMUX_DATA(A14_MARK, PORT127_FN1), + PINMUX_DATA(A13_MARK, PORT128_FN1), + PINMUX_DATA(A12_MARK, PORT129_FN1), + PINMUX_DATA(A11_MARK, PORT130_FN1), + PINMUX_DATA(A10_MARK, PORT131_FN1), + PINMUX_DATA(A9_MARK, PORT132_FN1), + PINMUX_DATA(A8_MARK, PORT133_FN1), + PINMUX_DATA(A7_MARK, PORT134_FN1), + PINMUX_DATA(A6_MARK, PORT135_FN1), + PINMUX_DATA(A5_FCDE_MARK, PORT136_FN1), + PINMUX_DATA(A4_FOE_MARK, PORT137_FN1), + PINMUX_DATA(A3_MARK, PORT138_FN1), + PINMUX_DATA(A2_MARK, PORT139_FN1), + PINMUX_DATA(A1_MARK, PORT140_FN1), + PINMUX_DATA(CKO_MARK, PORT141_FN1), + + /* Port142 - Port157 Function1 */ + PINMUX_DATA(D15_NAF15_MARK, PORT142_FN1), + PINMUX_DATA(D14_NAF14_MARK, PORT143_FN1), + PINMUX_DATA(D13_NAF13_MARK, PORT144_FN1), + PINMUX_DATA(D12_NAF12_MARK, PORT145_FN1), + PINMUX_DATA(D11_NAF11_MARK, PORT146_FN1), + PINMUX_DATA(D10_NAF10_MARK, PORT147_FN1), + PINMUX_DATA(D9_NAF9_MARK, PORT148_FN1), + PINMUX_DATA(D8_NAF8_MARK, PORT149_FN1), + PINMUX_DATA(D7_NAF7_MARK, PORT150_FN1), + PINMUX_DATA(D6_NAF6_MARK, PORT151_FN1), + PINMUX_DATA(D5_NAF5_MARK, PORT152_FN1), + PINMUX_DATA(D4_NAF4_MARK, PORT153_FN1), + PINMUX_DATA(D3_NAF3_MARK, PORT154_FN1), + PINMUX_DATA(D2_NAF2_MARK, PORT155_FN1), + PINMUX_DATA(D1_NAF1_MARK, PORT156_FN1), + PINMUX_DATA(D0_NAF0_MARK, PORT157_FN1), + + /* Port142 - Port149 Function3 */ + PINMUX_DATA(MMC1_D7_PORT142_MARK, PORT142_FN3, MSEL4CR_15_1), + PINMUX_DATA(MMC1_D6_PORT143_MARK, PORT143_FN3, MSEL4CR_15_1), + PINMUX_DATA(MMC1_D5_PORT144_MARK, PORT144_FN3, MSEL4CR_15_1), + PINMUX_DATA(MMC1_D4_PORT145_MARK, PORT145_FN3, MSEL4CR_15_1), + PINMUX_DATA(MMC1_D3_PORT146_MARK, PORT146_FN3, MSEL4CR_15_1), + PINMUX_DATA(MMC1_D2_PORT147_MARK, PORT147_FN3, MSEL4CR_15_1), + PINMUX_DATA(MMC1_D1_PORT148_MARK, PORT148_FN3, MSEL4CR_15_1), + PINMUX_DATA(MMC1_D0_PORT149_MARK, PORT149_FN3, MSEL4CR_15_1), + + /* Port158 */ + PINMUX_DATA(D31_MARK, PORT158_FN1), + PINMUX_DATA(SCIFA3_SCK_PORT158_MARK, PORT158_FN2, MSEL5CR_8_1), + PINMUX_DATA(RMII_REF125CK_MARK, PORT158_FN3), + PINMUX_DATA(LCD0_D21_PORT158_MARK, PORT158_FN4, MSEL5CR_6_1), + PINMUX_DATA(IRDA_FIRSEL_MARK, PORT158_FN5), + PINMUX_DATA(IDE_D15_MARK, PORT158_FN6), + + /* Port159 */ + PINMUX_DATA(D30_MARK, PORT159_FN1), + PINMUX_DATA(SCIFA3_RXD_PORT159_MARK, PORT159_FN2, MSEL5CR_8_1), + PINMUX_DATA(RMII_REF50CK_MARK, PORT159_FN3), + PINMUX_DATA(LCD0_D23_PORT159_MARK, PORT159_FN4, MSEL5CR_6_1), + PINMUX_DATA(IDE_D14_MARK, PORT159_FN6), + + /* Port160 */ + PINMUX_DATA(D29_MARK, PORT160_FN1), + PINMUX_DATA(SCIFA3_TXD_PORT160_MARK, PORT160_FN2, MSEL5CR_8_1), + PINMUX_DATA(LCD0_D22_PORT160_MARK, PORT160_FN4, MSEL5CR_6_1), + PINMUX_DATA(VIO1_HD_MARK, PORT160_FN5), + PINMUX_DATA(IDE_D13_MARK, PORT160_FN6), + + /* Port161 */ + PINMUX_DATA(D28_MARK, PORT161_FN1), + PINMUX_DATA(SCIFA3_RTS_PORT161_MARK, PORT161_FN2, MSEL5CR_8_1), + PINMUX_DATA(ET_RX_DV_MARK, PORT161_FN3), + PINMUX_DATA(LCD0_D20_PORT161_MARK, PORT161_FN4, MSEL5CR_6_1), + PINMUX_DATA(IRDA_IN_MARK, PORT161_FN5), + PINMUX_DATA(IDE_D12_MARK, PORT161_FN6), + + /* Port162 */ + PINMUX_DATA(D27_MARK, PORT162_FN1), + PINMUX_DATA(SCIFA3_CTS_PORT162_MARK, PORT162_FN2, MSEL5CR_8_1), + PINMUX_DATA(LCD0_D19_PORT162_MARK, PORT162_FN4, MSEL5CR_6_1), + PINMUX_DATA(IRDA_OUT_MARK, PORT162_FN5), + PINMUX_DATA(IDE_D11_MARK, PORT162_FN6), + + /* Port163 */ + PINMUX_DATA(D26_MARK, PORT163_FN1), + PINMUX_DATA(MSIOF2_SS2_MARK, PORT163_FN2), + PINMUX_DATA(ET_COL_MARK, PORT163_FN3), + PINMUX_DATA(LCD0_D18_PORT163_MARK, PORT163_FN4, MSEL5CR_6_1), + PINMUX_DATA(IROUT_MARK, PORT163_FN5), + PINMUX_DATA(IDE_D10_MARK, PORT163_FN6), + + /* Port164 */ + PINMUX_DATA(D25_MARK, PORT164_FN1), + PINMUX_DATA(MSIOF2_TSYNC_MARK, PORT164_FN2), + PINMUX_DATA(ET_PHY_INT_MARK, PORT164_FN3), + PINMUX_DATA(LCD0_RD_MARK, PORT164_FN4), + PINMUX_DATA(IDE_D9_MARK, PORT164_FN6), + + /* Port165 */ + PINMUX_DATA(D24_MARK, PORT165_FN1), + PINMUX_DATA(MSIOF2_RXD_MARK, PORT165_FN2), + PINMUX_DATA(LCD0_LCLK_PORT165_MARK, PORT165_FN4, MSEL5CR_6_1), + PINMUX_DATA(IDE_D8_MARK, PORT165_FN6), + + /* Port166 - Port171 Function1 */ + PINMUX_DATA(D21_MARK, PORT166_FN1), + PINMUX_DATA(D20_MARK, PORT167_FN1), + PINMUX_DATA(D19_MARK, PORT168_FN1), + PINMUX_DATA(D18_MARK, PORT169_FN1), + PINMUX_DATA(D17_MARK, PORT170_FN1), + PINMUX_DATA(D16_MARK, PORT171_FN1), + + /* Port166 - Port171 Function3 */ + PINMUX_DATA(ET_ETXD5_MARK, PORT166_FN3), + PINMUX_DATA(ET_ETXD4_MARK, PORT167_FN3), + PINMUX_DATA(ET_ETXD3_MARK, PORT168_FN3), + PINMUX_DATA(ET_ETXD2_MARK, PORT169_FN3), + PINMUX_DATA(ET_ETXD1_MARK, PORT170_FN3), + PINMUX_DATA(ET_ETXD0_MARK, PORT171_FN3), + + /* Port166 - Port171 Function6 */ + PINMUX_DATA(IDE_D5_MARK, PORT166_FN6), + PINMUX_DATA(IDE_D4_MARK, PORT167_FN6), + PINMUX_DATA(IDE_D3_MARK, PORT168_FN6), + PINMUX_DATA(IDE_D2_MARK, PORT169_FN6), + PINMUX_DATA(IDE_D1_MARK, PORT170_FN6), + PINMUX_DATA(IDE_D0_MARK, PORT171_FN6), + + /* Port167 - Port171 IRQ */ + PINMUX_DATA(IRQ31_PORT167_MARK, PORT167_FN0, MSEL1CR_31_0), + PINMUX_DATA(IRQ27_PORT168_MARK, PORT168_FN0, MSEL1CR_27_0), + PINMUX_DATA(IRQ28_PORT169_MARK, PORT169_FN0, MSEL1CR_28_0), + PINMUX_DATA(IRQ29_PORT170_MARK, PORT170_FN0, MSEL1CR_29_0), + PINMUX_DATA(IRQ30_PORT171_MARK, PORT171_FN0, MSEL1CR_30_0), + + /* Port172 */ + PINMUX_DATA(D23_MARK, PORT172_FN1), + PINMUX_DATA(SCIFB_RTS_PORT172_MARK, PORT172_FN2, MSEL5CR_17_1), + PINMUX_DATA(ET_ETXD7_MARK, PORT172_FN3), + PINMUX_DATA(IDE_D7_MARK, PORT172_FN6), + PINMUX_DATA(IRQ4_PORT172_MARK, PORT172_FN0, MSEL1CR_4_1), + + /* Port173 */ + PINMUX_DATA(D22_MARK, PORT173_FN1), + PINMUX_DATA(SCIFB_CTS_PORT173_MARK, PORT173_FN2, MSEL5CR_17_1), + PINMUX_DATA(ET_ETXD6_MARK, PORT173_FN3), + PINMUX_DATA(IDE_D6_MARK, PORT173_FN6), + PINMUX_DATA(IRQ6_PORT173_MARK, PORT173_FN0, MSEL1CR_6_1), + + /* Port174 */ + PINMUX_DATA(A26_MARK, PORT174_FN1), + PINMUX_DATA(MSIOF0_TXD_MARK, PORT174_FN2), + PINMUX_DATA(ET_RX_CLK_MARK, PORT174_FN3), + PINMUX_DATA(SCIFA3_RXD_PORT174_MARK, PORT174_FN4, MSEL5CR_8_0), + + /* Port175 */ + PINMUX_DATA(A0_MARK, PORT175_FN1), + PINMUX_DATA(BS_MARK, PORT175_FN2), + PINMUX_DATA(ET_WOL_MARK, PORT175_FN3), + PINMUX_DATA(SCIFA3_TXD_PORT175_MARK, PORT175_FN4, MSEL5CR_8_0), + + /* Port176 */ + PINMUX_DATA(ET_GTX_CLK_MARK, PORT176_FN3), + + /* Port177 */ + PINMUX_DATA(WAIT_PORT177_MARK, PORT177_FN1, MSEL5CR_2_0), + PINMUX_DATA(ET_LINK_MARK, PORT177_FN3), + PINMUX_DATA(IDE_IOWR_MARK, PORT177_FN6), + PINMUX_DATA(SDHI2_WP_PORT177_MARK, PORT177_FN7, MSEL5CR_19_1), + + /* Port178 */ + PINMUX_DATA(VIO0_D12_MARK, PORT178_FN1), + PINMUX_DATA(VIO1_D4_MARK, PORT178_FN5), + PINMUX_DATA(IDE_IORD_MARK, PORT178_FN6), + + /* Port179 */ + PINMUX_DATA(VIO0_D11_MARK, PORT179_FN1), + PINMUX_DATA(VIO1_D3_MARK, PORT179_FN5), + PINMUX_DATA(IDE_IORDY_MARK, PORT179_FN6), + + /* Port180 */ + PINMUX_DATA(VIO0_D10_MARK, PORT180_FN1), + PINMUX_DATA(TPU0TO3_MARK, PORT180_FN4), + PINMUX_DATA(VIO1_D2_MARK, PORT180_FN5), + PINMUX_DATA(IDE_INT_MARK, PORT180_FN6), + PINMUX_DATA(IRQ24_MARK, PORT180_FN0), + + /* Port181 */ + PINMUX_DATA(VIO0_D9_MARK, PORT181_FN1), + PINMUX_DATA(VIO1_D1_MARK, PORT181_FN5), + PINMUX_DATA(IDE_RST_MARK, PORT181_FN6), + + /* Port182 */ + PINMUX_DATA(VIO0_D8_MARK, PORT182_FN1), + PINMUX_DATA(VIO1_D0_MARK, PORT182_FN5), + PINMUX_DATA(IDE_DIRECTION_MARK, PORT182_FN6), + + /* Port183 */ + PINMUX_DATA(DREQ1_MARK, PORT183_FN1), + PINMUX_DATA(BBIF2_TXD2_PORT183_MARK, PORT183_FN2, MSEL5CR_0_1), + PINMUX_DATA(ET_TX_EN_MARK, PORT183_FN3), + + /* Port184 */ + PINMUX_DATA(DACK1_MARK, PORT184_FN1), + PINMUX_DATA(BBIF2_TSYNC2_PORT184_MARK, PORT184_FN2, MSEL5CR_0_1), + PINMUX_DATA(ET_TX_CLK_MARK, PORT184_FN3), + + /* Port185 - Port192 Function1 */ + PINMUX_DATA(SCIFA1_SCK_MARK, PORT185_FN1), + PINMUX_DATA(SCIFB_RTS_PORT186_MARK, PORT186_FN1, MSEL5CR_17_0), + PINMUX_DATA(SCIFB_CTS_PORT187_MARK, PORT187_FN1, MSEL5CR_17_0), + PINMUX_DATA(SCIFA0_SCK_MARK, PORT188_FN1), + PINMUX_DATA(SCIFB_SCK_PORT190_MARK, PORT190_FN1, MSEL5CR_17_0), + PINMUX_DATA(SCIFB_RXD_PORT191_MARK, PORT191_FN1, MSEL5CR_17_0), + PINMUX_DATA(SCIFB_TXD_PORT192_MARK, PORT192_FN1, MSEL5CR_17_0), + + /* Port185 - Port192 Function3 */ + PINMUX_DATA(ET_ERXD0_MARK, PORT185_FN3), + PINMUX_DATA(ET_ERXD1_MARK, PORT186_FN3), + PINMUX_DATA(ET_ERXD2_MARK, PORT187_FN3), + PINMUX_DATA(ET_ERXD3_MARK, PORT188_FN3), + PINMUX_DATA(ET_ERXD4_MARK, PORT189_FN3), + PINMUX_DATA(ET_ERXD5_MARK, PORT190_FN3), + PINMUX_DATA(ET_ERXD6_MARK, PORT191_FN3), + PINMUX_DATA(ET_ERXD7_MARK, PORT192_FN3), + + /* Port185 - Port192 Function6 */ + PINMUX_DATA(STP1_IPCLK_MARK, PORT185_FN6), + PINMUX_DATA(STP1_IPD0_PORT186_MARK, PORT186_FN6, MSEL5CR_23_0), + PINMUX_DATA(STP1_IPEN_PORT187_MARK, PORT187_FN6, MSEL5CR_23_0), + PINMUX_DATA(STP1_IPSYNC_MARK, PORT188_FN6), + PINMUX_DATA(STP0_IPCLK_MARK, PORT189_FN6), + PINMUX_DATA(STP0_IPD0_MARK, PORT190_FN6), + PINMUX_DATA(STP0_IPEN_MARK, PORT191_FN6), + PINMUX_DATA(STP0_IPSYNC_MARK, PORT192_FN6), + + /* Port193 */ + PINMUX_DATA(SCIFA0_CTS_MARK, PORT193_FN1), + PINMUX_DATA(RMII_CRS_DV_MARK, PORT193_FN3), + PINMUX_DATA(STP1_IPEN_PORT193_MARK, PORT193_FN6, MSEL5CR_23_1), /* ? */ + PINMUX_DATA(LCD1_D17_MARK, PORT193_FN7), + + /* Port194 */ + PINMUX_DATA(SCIFA0_RTS_MARK, PORT194_FN1), + PINMUX_DATA(RMII_RX_ER_MARK, PORT194_FN3), + PINMUX_DATA(STP1_IPD0_PORT194_MARK, PORT194_FN6, MSEL5CR_23_1), /* ? */ + PINMUX_DATA(LCD1_D16_MARK, PORT194_FN7), + + /* Port195 */ + PINMUX_DATA(SCIFA1_RXD_MARK, PORT195_FN1), + PINMUX_DATA(RMII_RXD0_MARK, PORT195_FN3), + PINMUX_DATA(STP1_IPD3_MARK, PORT195_FN6), + PINMUX_DATA(LCD1_D15_MARK, PORT195_FN7), + + /* Port196 */ + PINMUX_DATA(SCIFA1_TXD_MARK, PORT196_FN1), + PINMUX_DATA(RMII_RXD1_MARK, PORT196_FN3), + PINMUX_DATA(STP1_IPD2_MARK, PORT196_FN6), + PINMUX_DATA(LCD1_D14_MARK, PORT196_FN7), + + /* Port197 */ + PINMUX_DATA(SCIFA0_RXD_MARK, PORT197_FN1), + PINMUX_DATA(VIO1_CLK_MARK, PORT197_FN5), + PINMUX_DATA(STP1_IPD5_MARK, PORT197_FN6), + PINMUX_DATA(LCD1_D19_MARK, PORT197_FN7), + + /* Port198 */ + PINMUX_DATA(SCIFA0_TXD_MARK, PORT198_FN1), + PINMUX_DATA(VIO1_VD_MARK, PORT198_FN5), + PINMUX_DATA(STP1_IPD4_MARK, PORT198_FN6), + PINMUX_DATA(LCD1_D18_MARK, PORT198_FN7), + + /* Port199 */ + PINMUX_DATA(MEMC_NWE_MARK, PORT199_FN1), + PINMUX_DATA(SCIFA2_SCK_PORT199_MARK, PORT199_FN2, MSEL5CR_7_1), + PINMUX_DATA(RMII_TX_EN_MARK, PORT199_FN3), + PINMUX_DATA(SIM_D_PORT199_MARK, PORT199_FN4, MSEL5CR_21_1), + PINMUX_DATA(STP1_IPD1_MARK, PORT199_FN6), + PINMUX_DATA(LCD1_D13_MARK, PORT199_FN7), + + /* Port200 */ + PINMUX_DATA(MEMC_NOE_MARK, PORT200_FN1), + PINMUX_DATA(SCIFA2_RXD_MARK, PORT200_FN2), + PINMUX_DATA(RMII_TXD0_MARK, PORT200_FN3), + PINMUX_DATA(STP0_IPD7_MARK, PORT200_FN6), + PINMUX_DATA(LCD1_D12_MARK, PORT200_FN7), + + /* Port201 */ + PINMUX_DATA(MEMC_WAIT_MARK, PORT201_FN1, MSEL4CR_6_0), + PINMUX_DATA(MEMC_DREQ1_MARK, PORT201_FN1, MSEL4CR_6_1), + + PINMUX_DATA(SCIFA2_TXD_MARK, PORT201_FN2), + PINMUX_DATA(RMII_TXD1_MARK, PORT201_FN3), + PINMUX_DATA(STP0_IPD6_MARK, PORT201_FN6), + PINMUX_DATA(LCD1_D11_MARK, PORT201_FN7), + + /* Port202 */ + PINMUX_DATA(MEMC_BUSCLK_MARK, PORT202_FN1, MSEL4CR_6_0), + PINMUX_DATA(MEMC_A0_MARK, PORT202_FN1, MSEL4CR_6_1), + + PINMUX_DATA(MSIOF1_SS2_PORT202_MARK, PORT202_FN2, MSEL4CR_10_1), + PINMUX_DATA(RMII_MDC_MARK, PORT202_FN3), + PINMUX_DATA(TPU0TO2_PORT202_MARK, PORT202_FN4, MSEL5CR_25_1), + PINMUX_DATA(IDE_CS0_MARK, PORT202_FN6), + PINMUX_DATA(SDHI2_CD_PORT202_MARK, PORT202_FN7, MSEL5CR_19_1), + PINMUX_DATA(IRQ21_MARK, PORT202_FN0), + + /* Port203 - Port208 Function1 */ + PINMUX_DATA(SDHI2_CLK_MARK, PORT203_FN1), + PINMUX_DATA(SDHI2_CMD_MARK, PORT204_FN1), + PINMUX_DATA(SDHI2_D0_MARK, PORT205_FN1), + PINMUX_DATA(SDHI2_D1_MARK, PORT206_FN1), + PINMUX_DATA(SDHI2_D2_MARK, PORT207_FN1), + PINMUX_DATA(SDHI2_D3_MARK, PORT208_FN1), + + /* Port203 - Port208 Function3 */ + PINMUX_DATA(ET_TX_ER_MARK, PORT203_FN3), + PINMUX_DATA(ET_RX_ER_MARK, PORT204_FN3), + PINMUX_DATA(ET_CRS_MARK, PORT205_FN3), + PINMUX_DATA(ET_MDC_MARK, PORT206_FN3), + PINMUX_DATA(ET_MDIO_MARK, PORT207_FN3), + PINMUX_DATA(RMII_MDIO_MARK, PORT208_FN3), + + /* Port203 - Port208 Function6 */ + PINMUX_DATA(IDE_A2_MARK, PORT203_FN6), + PINMUX_DATA(IDE_A1_MARK, PORT204_FN6), + PINMUX_DATA(IDE_A0_MARK, PORT205_FN6), + PINMUX_DATA(IDE_IODACK_MARK, PORT206_FN6), + PINMUX_DATA(IDE_IODREQ_MARK, PORT207_FN6), + PINMUX_DATA(IDE_CS1_MARK, PORT208_FN6), + + /* Port203 - Port208 Function7 */ + PINMUX_DATA(SCIFA4_TXD_PORT203_MARK, PORT203_FN7, MSEL5CR_12_0, MSEL5CR_11_1), + PINMUX_DATA(SCIFA4_RXD_PORT204_MARK, PORT204_FN7, MSEL5CR_12_0, MSEL5CR_11_1), + PINMUX_DATA(SCIFA4_SCK_PORT205_MARK, PORT205_FN7, MSEL5CR_10_1), + PINMUX_DATA(SCIFA5_SCK_PORT206_MARK, PORT206_FN7, MSEL5CR_13_1), + PINMUX_DATA(SCIFA5_RXD_PORT207_MARK, PORT207_FN7, MSEL5CR_15_0, MSEL5CR_14_1), + PINMUX_DATA(SCIFA5_TXD_PORT208_MARK, PORT208_FN7, MSEL5CR_15_0, MSEL5CR_14_1), + + /* Port209 */ + PINMUX_DATA(VBUS_MARK, PORT209_FN1), + PINMUX_DATA(IRQ7_PORT209_MARK, PORT209_FN0, MSEL1CR_7_1), + + /* Port210 */ + PINMUX_DATA(IRQ9_PORT210_MARK, PORT210_FN0, MSEL1CR_9_1), + + /* Port211 */ + PINMUX_DATA(IRQ16_PORT211_MARK, PORT211_FN0, MSEL1CR_16_1), + + /* LCDC select */ + PINMUX_DATA(LCDC0_SELECT_MARK, MSEL3CR_6_0), + PINMUX_DATA(LCDC1_SELECT_MARK, MSEL3CR_6_1), + + /* SDENC */ + PINMUX_DATA(SDENC_CPG_MARK, MSEL4CR_19_0), + PINMUX_DATA(SDENC_DV_CLKI_MARK, MSEL4CR_19_1), + + /* SYSC */ + PINMUX_DATA(RESETP_PULLUP_MARK, MSEL4CR_4_0), + PINMUX_DATA(RESETP_PLAIN_MARK, MSEL4CR_4_1), + + /* DEBUG */ + PINMUX_DATA(EDEBGREQ_PULLDOWN_MARK, MSEL4CR_1_0), + PINMUX_DATA(EDEBGREQ_PULLUP_MARK, MSEL4CR_1_1), + + PINMUX_DATA(TRACEAUD_FROM_VIO_MARK, MSEL5CR_30_0, MSEL5CR_29_0), + PINMUX_DATA(TRACEAUD_FROM_LCDC0_MARK, MSEL5CR_30_0, MSEL5CR_29_1), + PINMUX_DATA(TRACEAUD_FROM_MEMC_MARK, MSEL5CR_30_1, MSEL5CR_29_0), +}; + +static struct pinmux_gpio pinmux_gpios[] = { + + /* PORT */ + GPIO_PORT_ALL(), + + /* IRQ */ + GPIO_FN(IRQ0_PORT2), GPIO_FN(IRQ0_PORT13), + GPIO_FN(IRQ1), + GPIO_FN(IRQ2_PORT11), GPIO_FN(IRQ2_PORT12), + GPIO_FN(IRQ3_PORT10), GPIO_FN(IRQ3_PORT14), + GPIO_FN(IRQ4_PORT15), GPIO_FN(IRQ4_PORT172), + GPIO_FN(IRQ5_PORT0), GPIO_FN(IRQ5_PORT1), + GPIO_FN(IRQ6_PORT121), GPIO_FN(IRQ6_PORT173), + GPIO_FN(IRQ7_PORT120), GPIO_FN(IRQ7_PORT209), + GPIO_FN(IRQ8), + GPIO_FN(IRQ9_PORT118), GPIO_FN(IRQ9_PORT210), + GPIO_FN(IRQ10), + GPIO_FN(IRQ11), + GPIO_FN(IRQ12_PORT42), GPIO_FN(IRQ12_PORT97), + GPIO_FN(IRQ13_PORT64), GPIO_FN(IRQ13_PORT98), + GPIO_FN(IRQ14_PORT63), GPIO_FN(IRQ14_PORT99), + GPIO_FN(IRQ15_PORT62), GPIO_FN(IRQ15_PORT100), + GPIO_FN(IRQ16_PORT68), GPIO_FN(IRQ16_PORT211), + GPIO_FN(IRQ17), + GPIO_FN(IRQ18), + GPIO_FN(IRQ19), + GPIO_FN(IRQ20), + GPIO_FN(IRQ21), + GPIO_FN(IRQ22), + GPIO_FN(IRQ23), + GPIO_FN(IRQ24), + GPIO_FN(IRQ25), + GPIO_FN(IRQ26_PORT58), GPIO_FN(IRQ26_PORT81), + GPIO_FN(IRQ27_PORT57), GPIO_FN(IRQ27_PORT168), + GPIO_FN(IRQ28_PORT56), GPIO_FN(IRQ28_PORT169), + GPIO_FN(IRQ29_PORT50), GPIO_FN(IRQ29_PORT170), + GPIO_FN(IRQ30_PORT49), GPIO_FN(IRQ30_PORT171), + GPIO_FN(IRQ31_PORT41), GPIO_FN(IRQ31_PORT167), + + /* Function */ + + /* DBGT */ + GPIO_FN(DBGMDT2), GPIO_FN(DBGMDT1), GPIO_FN(DBGMDT0), + GPIO_FN(DBGMD10), GPIO_FN(DBGMD11), GPIO_FN(DBGMD20), + GPIO_FN(DBGMD21), + + /* FSI */ + GPIO_FN(FSIAISLD_PORT0), /* FSIAISLD Port 0/5 */ + GPIO_FN(FSIAISLD_PORT5), + GPIO_FN(FSIASPDIF_PORT9), /* FSIASPDIF Port 9/18 */ + GPIO_FN(FSIASPDIF_PORT18), + GPIO_FN(FSIAOSLD1), GPIO_FN(FSIAOSLD2), GPIO_FN(FSIAOLR), + GPIO_FN(FSIAOBT), GPIO_FN(FSIAOSLD), GPIO_FN(FSIAOMC), + GPIO_FN(FSIACK), GPIO_FN(FSIAILR), GPIO_FN(FSIAIBT), + + /* FMSI */ + GPIO_FN(FMSISLD_PORT1), /* FMSISLD Port 1/6 */ + GPIO_FN(FMSISLD_PORT6), + GPIO_FN(FMSIILR), GPIO_FN(FMSIIBT), GPIO_FN(FMSIOLR), + GPIO_FN(FMSIOBT), GPIO_FN(FMSICK), GPIO_FN(FMSOILR), + GPIO_FN(FMSOIBT), GPIO_FN(FMSOOLR), GPIO_FN(FMSOOBT), + GPIO_FN(FMSOSLD), GPIO_FN(FMSOCK), + + /* SCIFA0 */ + GPIO_FN(SCIFA0_SCK), GPIO_FN(SCIFA0_CTS), GPIO_FN(SCIFA0_RTS), + GPIO_FN(SCIFA0_RXD), GPIO_FN(SCIFA0_TXD), + + /* SCIFA1 */ + GPIO_FN(SCIFA1_CTS), GPIO_FN(SCIFA1_SCK), + GPIO_FN(SCIFA1_RXD), GPIO_FN(SCIFA1_TXD), GPIO_FN(SCIFA1_RTS), + + /* SCIFA2 */ + GPIO_FN(SCIFA2_SCK_PORT22), /* SCIFA2_SCK Port 22/199 */ + GPIO_FN(SCIFA2_SCK_PORT199), + GPIO_FN(SCIFA2_RXD), GPIO_FN(SCIFA2_TXD), + GPIO_FN(SCIFA2_CTS), GPIO_FN(SCIFA2_RTS), + + /* SCIFA3 */ + GPIO_FN(SCIFA3_RTS_PORT105), /* MSEL5CR_8_0 */ + GPIO_FN(SCIFA3_SCK_PORT116), + GPIO_FN(SCIFA3_CTS_PORT117), + GPIO_FN(SCIFA3_RXD_PORT174), + GPIO_FN(SCIFA3_TXD_PORT175), + + GPIO_FN(SCIFA3_RTS_PORT161), /* MSEL5CR_8_1 */ + GPIO_FN(SCIFA3_SCK_PORT158), + GPIO_FN(SCIFA3_CTS_PORT162), + GPIO_FN(SCIFA3_RXD_PORT159), + GPIO_FN(SCIFA3_TXD_PORT160), + + /* SCIFA4 */ + GPIO_FN(SCIFA4_RXD_PORT12), /* MSEL5CR[12:11] = 00 */ + GPIO_FN(SCIFA4_TXD_PORT13), + + GPIO_FN(SCIFA4_RXD_PORT204), /* MSEL5CR[12:11] = 01 */ + GPIO_FN(SCIFA4_TXD_PORT203), + + GPIO_FN(SCIFA4_RXD_PORT94), /* MSEL5CR[12:11] = 10 */ + GPIO_FN(SCIFA4_TXD_PORT93), + + GPIO_FN(SCIFA4_SCK_PORT21), /* SCIFA4_SCK Port 21/205 */ + GPIO_FN(SCIFA4_SCK_PORT205), + + /* SCIFA5 */ + GPIO_FN(SCIFA5_TXD_PORT20), /* MSEL5CR[15:14] = 00 */ + GPIO_FN(SCIFA5_RXD_PORT10), + + GPIO_FN(SCIFA5_RXD_PORT207), /* MSEL5CR[15:14] = 01 */ + GPIO_FN(SCIFA5_TXD_PORT208), + + GPIO_FN(SCIFA5_TXD_PORT91), /* MSEL5CR[15:14] = 10 */ + GPIO_FN(SCIFA5_RXD_PORT92), + + GPIO_FN(SCIFA5_SCK_PORT23), /* SCIFA5_SCK Port 23/206 */ + GPIO_FN(SCIFA5_SCK_PORT206), + + /* SCIFA6 */ + GPIO_FN(SCIFA6_SCK), GPIO_FN(SCIFA6_RXD), GPIO_FN(SCIFA6_TXD), + + /* SCIFA7 */ + GPIO_FN(SCIFA7_TXD), GPIO_FN(SCIFA7_RXD), + + /* SCIFAB */ + GPIO_FN(SCIFB_SCK_PORT190), /* MSEL5CR_17_0 */ + GPIO_FN(SCIFB_RXD_PORT191), + GPIO_FN(SCIFB_TXD_PORT192), + GPIO_FN(SCIFB_RTS_PORT186), + GPIO_FN(SCIFB_CTS_PORT187), + + GPIO_FN(SCIFB_SCK_PORT2), /* MSEL5CR_17_1 */ + GPIO_FN(SCIFB_RXD_PORT3), + GPIO_FN(SCIFB_TXD_PORT4), + GPIO_FN(SCIFB_RTS_PORT172), + GPIO_FN(SCIFB_CTS_PORT173), + + /* LCD0 */ + GPIO_FN(LCD0_D0), GPIO_FN(LCD0_D1), GPIO_FN(LCD0_D2), + GPIO_FN(LCD0_D3), GPIO_FN(LCD0_D4), GPIO_FN(LCD0_D5), + GPIO_FN(LCD0_D6), GPIO_FN(LCD0_D7), GPIO_FN(LCD0_D8), + GPIO_FN(LCD0_D9), GPIO_FN(LCD0_D10), GPIO_FN(LCD0_D11), + GPIO_FN(LCD0_D12), GPIO_FN(LCD0_D13), GPIO_FN(LCD0_D14), + GPIO_FN(LCD0_D15), GPIO_FN(LCD0_D16), GPIO_FN(LCD0_D17), + GPIO_FN(LCD0_DON), GPIO_FN(LCD0_VCPWC), GPIO_FN(LCD0_VEPWC), + GPIO_FN(LCD0_DCK), GPIO_FN(LCD0_VSYN), + GPIO_FN(LCD0_HSYN), GPIO_FN(LCD0_DISP), + GPIO_FN(LCD0_WR), GPIO_FN(LCD0_RD), + GPIO_FN(LCD0_CS), GPIO_FN(LCD0_RS), + + GPIO_FN(LCD0_D18_PORT163), GPIO_FN(LCD0_D19_PORT162), + GPIO_FN(LCD0_D20_PORT161), GPIO_FN(LCD0_D21_PORT158), + GPIO_FN(LCD0_D22_PORT160), GPIO_FN(LCD0_D23_PORT159), + GPIO_FN(LCD0_LCLK_PORT165), /* MSEL5CR_6_1 */ + + GPIO_FN(LCD0_D18_PORT40), GPIO_FN(LCD0_D19_PORT4), + GPIO_FN(LCD0_D20_PORT3), GPIO_FN(LCD0_D21_PORT2), + GPIO_FN(LCD0_D22_PORT0), GPIO_FN(LCD0_D23_PORT1), + GPIO_FN(LCD0_LCLK_PORT102), /* MSEL5CR_6_0 */ + + /* LCD1 */ + GPIO_FN(LCD1_D0), GPIO_FN(LCD1_D1), GPIO_FN(LCD1_D2), + GPIO_FN(LCD1_D3), GPIO_FN(LCD1_D4), GPIO_FN(LCD1_D5), + GPIO_FN(LCD1_D6), GPIO_FN(LCD1_D7), GPIO_FN(LCD1_D8), + GPIO_FN(LCD1_D9), GPIO_FN(LCD1_D10), GPIO_FN(LCD1_D11), + GPIO_FN(LCD1_D12), GPIO_FN(LCD1_D13), GPIO_FN(LCD1_D14), + GPIO_FN(LCD1_D15), GPIO_FN(LCD1_D16), GPIO_FN(LCD1_D17), + GPIO_FN(LCD1_D18), GPIO_FN(LCD1_D19), GPIO_FN(LCD1_D20), + GPIO_FN(LCD1_D21), GPIO_FN(LCD1_D22), GPIO_FN(LCD1_D23), + GPIO_FN(LCD1_RS), GPIO_FN(LCD1_RD), GPIO_FN(LCD1_CS), + GPIO_FN(LCD1_WR), GPIO_FN(LCD1_DCK), GPIO_FN(LCD1_DON), + GPIO_FN(LCD1_VCPWC), GPIO_FN(LCD1_LCLK), GPIO_FN(LCD1_HSYN), + GPIO_FN(LCD1_VSYN), GPIO_FN(LCD1_VEPWC), GPIO_FN(LCD1_DISP), + + /* RSPI */ + GPIO_FN(RSPI_SSL0_A), GPIO_FN(RSPI_SSL1_A), GPIO_FN(RSPI_SSL2_A), + GPIO_FN(RSPI_SSL3_A), GPIO_FN(RSPI_CK_A), GPIO_FN(RSPI_MOSI_A), + GPIO_FN(RSPI_MISO_A), + + /* VIO CKO */ + GPIO_FN(VIO_CKO1), + GPIO_FN(VIO_CKO2), + GPIO_FN(VIO_CKO_1), + GPIO_FN(VIO_CKO), + + /* VIO0 */ + GPIO_FN(VIO0_D0), GPIO_FN(VIO0_D1), GPIO_FN(VIO0_D2), + GPIO_FN(VIO0_D3), GPIO_FN(VIO0_D4), GPIO_FN(VIO0_D5), + GPIO_FN(VIO0_D6), GPIO_FN(VIO0_D7), GPIO_FN(VIO0_D8), + GPIO_FN(VIO0_D9), GPIO_FN(VIO0_D10), GPIO_FN(VIO0_D11), + GPIO_FN(VIO0_D12), GPIO_FN(VIO0_VD), GPIO_FN(VIO0_HD), + GPIO_FN(VIO0_CLK), GPIO_FN(VIO0_FIELD), + + GPIO_FN(VIO0_D13_PORT26), /* MSEL5CR_27_0 */ + GPIO_FN(VIO0_D14_PORT25), + GPIO_FN(VIO0_D15_PORT24), + + GPIO_FN(VIO0_D13_PORT22), /* MSEL5CR_27_1 */ + GPIO_FN(VIO0_D14_PORT95), + GPIO_FN(VIO0_D15_PORT96), + + /* VIO1 */ + GPIO_FN(VIO1_D0), GPIO_FN(VIO1_D1), GPIO_FN(VIO1_D2), + GPIO_FN(VIO1_D3), GPIO_FN(VIO1_D4), GPIO_FN(VIO1_D5), + GPIO_FN(VIO1_D6), GPIO_FN(VIO1_D7), GPIO_FN(VIO1_VD), + GPIO_FN(VIO1_HD), GPIO_FN(VIO1_CLK), GPIO_FN(VIO1_FIELD), + + /* TPU0 */ + GPIO_FN(TPU0TO0), GPIO_FN(TPU0TO1), GPIO_FN(TPU0TO3), + GPIO_FN(TPU0TO2_PORT66), /* TPU0TO2 Port 66/202 */ + GPIO_FN(TPU0TO2_PORT202), + + /* SSP1 0 */ + GPIO_FN(STP0_IPD0), GPIO_FN(STP0_IPD1), GPIO_FN(STP0_IPD2), + GPIO_FN(STP0_IPD3), GPIO_FN(STP0_IPD4), GPIO_FN(STP0_IPD5), + GPIO_FN(STP0_IPD6), GPIO_FN(STP0_IPD7), GPIO_FN(STP0_IPEN), + GPIO_FN(STP0_IPCLK), GPIO_FN(STP0_IPSYNC), + + /* SSP1 1 */ + GPIO_FN(STP1_IPD1), GPIO_FN(STP1_IPD2), GPIO_FN(STP1_IPD3), + GPIO_FN(STP1_IPD4), GPIO_FN(STP1_IPD5), GPIO_FN(STP1_IPD6), + GPIO_FN(STP1_IPD7), GPIO_FN(STP1_IPCLK), GPIO_FN(STP1_IPSYNC), + + GPIO_FN(STP1_IPD0_PORT186), /* MSEL5CR_23_0 */ + GPIO_FN(STP1_IPEN_PORT187), + + GPIO_FN(STP1_IPD0_PORT194), /* MSEL5CR_23_1 */ + GPIO_FN(STP1_IPEN_PORT193), + + /* SIM */ + GPIO_FN(SIM_RST), GPIO_FN(SIM_CLK), + GPIO_FN(SIM_D_PORT22), /* SIM_D Port 22/199 */ + GPIO_FN(SIM_D_PORT199), + + /* SDHI0 */ + GPIO_FN(SDHI0_D0), GPIO_FN(SDHI0_D1), GPIO_FN(SDHI0_D2), + GPIO_FN(SDHI0_D3), GPIO_FN(SDHI0_CD), GPIO_FN(SDHI0_WP), + GPIO_FN(SDHI0_CMD), GPIO_FN(SDHI0_CLK), + + /* SDHI1 */ + GPIO_FN(SDHI1_D0), GPIO_FN(SDHI1_D1), GPIO_FN(SDHI1_D2), + GPIO_FN(SDHI1_D3), GPIO_FN(SDHI1_CD), GPIO_FN(SDHI1_WP), + GPIO_FN(SDHI1_CMD), GPIO_FN(SDHI1_CLK), + + /* SDHI2 */ + GPIO_FN(SDHI2_D0), GPIO_FN(SDHI2_D1), GPIO_FN(SDHI2_D2), + GPIO_FN(SDHI2_D3), GPIO_FN(SDHI2_CLK), GPIO_FN(SDHI2_CMD), + + GPIO_FN(SDHI2_CD_PORT24), /* MSEL5CR_19_0 */ + GPIO_FN(SDHI2_WP_PORT25), + + GPIO_FN(SDHI2_WP_PORT177), /* MSEL5CR_19_1 */ + GPIO_FN(SDHI2_CD_PORT202), + + /* MSIOF2 */ + GPIO_FN(MSIOF2_TXD), GPIO_FN(MSIOF2_RXD), GPIO_FN(MSIOF2_TSCK), + GPIO_FN(MSIOF2_SS2), GPIO_FN(MSIOF2_TSYNC), GPIO_FN(MSIOF2_SS1), + GPIO_FN(MSIOF2_MCK1), GPIO_FN(MSIOF2_MCK0), GPIO_FN(MSIOF2_RSYNC), + GPIO_FN(MSIOF2_RSCK), + + /* KEYSC */ + GPIO_FN(KEYIN4), GPIO_FN(KEYIN5), + GPIO_FN(KEYIN6), GPIO_FN(KEYIN7), + GPIO_FN(KEYOUT0), GPIO_FN(KEYOUT1), GPIO_FN(KEYOUT2), + GPIO_FN(KEYOUT3), GPIO_FN(KEYOUT4), GPIO_FN(KEYOUT5), + GPIO_FN(KEYOUT6), GPIO_FN(KEYOUT7), + + GPIO_FN(KEYIN0_PORT43), /* MSEL4CR_18_0 */ + GPIO_FN(KEYIN1_PORT44), + GPIO_FN(KEYIN2_PORT45), + GPIO_FN(KEYIN3_PORT46), + + GPIO_FN(KEYIN0_PORT58), /* MSEL4CR_18_1 */ + GPIO_FN(KEYIN1_PORT57), + GPIO_FN(KEYIN2_PORT56), + GPIO_FN(KEYIN3_PORT55), + + /* VOU */ + GPIO_FN(DV_D0), GPIO_FN(DV_D1), GPIO_FN(DV_D2), + GPIO_FN(DV_D3), GPIO_FN(DV_D4), GPIO_FN(DV_D5), + GPIO_FN(DV_D6), GPIO_FN(DV_D7), GPIO_FN(DV_D8), + GPIO_FN(DV_D9), GPIO_FN(DV_D10), GPIO_FN(DV_D11), + GPIO_FN(DV_D12), GPIO_FN(DV_D13), GPIO_FN(DV_D14), + GPIO_FN(DV_D15), GPIO_FN(DV_CLK), + GPIO_FN(DV_VSYNC), GPIO_FN(DV_HSYNC), + + /* MEMC */ + GPIO_FN(MEMC_AD0), GPIO_FN(MEMC_AD1), GPIO_FN(MEMC_AD2), + GPIO_FN(MEMC_AD3), GPIO_FN(MEMC_AD4), GPIO_FN(MEMC_AD5), + GPIO_FN(MEMC_AD6), GPIO_FN(MEMC_AD7), GPIO_FN(MEMC_AD8), + GPIO_FN(MEMC_AD9), GPIO_FN(MEMC_AD10), GPIO_FN(MEMC_AD11), + GPIO_FN(MEMC_AD12), GPIO_FN(MEMC_AD13), GPIO_FN(MEMC_AD14), + GPIO_FN(MEMC_AD15), GPIO_FN(MEMC_CS0), GPIO_FN(MEMC_INT), + GPIO_FN(MEMC_NWE), GPIO_FN(MEMC_NOE), GPIO_FN(MEMC_CS1), + GPIO_FN(MEMC_A1), GPIO_FN(MEMC_ADV), GPIO_FN(MEMC_DREQ0), + GPIO_FN(MEMC_WAIT), GPIO_FN(MEMC_DREQ1), GPIO_FN(MEMC_BUSCLK), + GPIO_FN(MEMC_A0), + + /* MMC */ + GPIO_FN(MMC0_D0_PORT68), GPIO_FN(MMC0_D1_PORT69), + GPIO_FN(MMC0_D2_PORT70), GPIO_FN(MMC0_D3_PORT71), + GPIO_FN(MMC0_D4_PORT72), GPIO_FN(MMC0_D5_PORT73), + GPIO_FN(MMC0_D6_PORT74), GPIO_FN(MMC0_D7_PORT75), + GPIO_FN(MMC0_CLK_PORT66), + GPIO_FN(MMC0_CMD_PORT67), /* MSEL4CR_15_0 */ + + GPIO_FN(MMC1_D0_PORT149), GPIO_FN(MMC1_D1_PORT148), + GPIO_FN(MMC1_D2_PORT147), GPIO_FN(MMC1_D3_PORT146), + GPIO_FN(MMC1_D4_PORT145), GPIO_FN(MMC1_D5_PORT144), + GPIO_FN(MMC1_D6_PORT143), GPIO_FN(MMC1_D7_PORT142), + GPIO_FN(MMC1_CLK_PORT103), + GPIO_FN(MMC1_CMD_PORT104), /* MSEL4CR_15_1 */ + + /* MSIOF0 */ + GPIO_FN(MSIOF0_SS1), GPIO_FN(MSIOF0_SS2), GPIO_FN(MSIOF0_RXD), + GPIO_FN(MSIOF0_TXD), GPIO_FN(MSIOF0_MCK0), GPIO_FN(MSIOF0_MCK1), + GPIO_FN(MSIOF0_RSYNC), GPIO_FN(MSIOF0_RSCK), GPIO_FN(MSIOF0_TSCK), + GPIO_FN(MSIOF0_TSYNC), + + /* MSIOF1 */ + GPIO_FN(MSIOF1_RSCK), GPIO_FN(MSIOF1_RSYNC), + GPIO_FN(MSIOF1_MCK0), GPIO_FN(MSIOF1_MCK1), + + GPIO_FN(MSIOF1_SS2_PORT116), GPIO_FN(MSIOF1_SS1_PORT117), + GPIO_FN(MSIOF1_RXD_PORT118), GPIO_FN(MSIOF1_TXD_PORT119), + GPIO_FN(MSIOF1_TSYNC_PORT120), + GPIO_FN(MSIOF1_TSCK_PORT121), /* MSEL4CR_10_0 */ + + GPIO_FN(MSIOF1_SS1_PORT67), GPIO_FN(MSIOF1_TSCK_PORT72), + GPIO_FN(MSIOF1_TSYNC_PORT73), GPIO_FN(MSIOF1_TXD_PORT74), + GPIO_FN(MSIOF1_RXD_PORT75), + GPIO_FN(MSIOF1_SS2_PORT202), /* MSEL4CR_10_1 */ + + /* GPIO */ + GPIO_FN(GPO0), GPIO_FN(GPI0), + GPIO_FN(GPO1), GPIO_FN(GPI1), + + /* USB0 */ + GPIO_FN(USB0_OCI), GPIO_FN(USB0_PPON), GPIO_FN(VBUS), + + /* USB1 */ + GPIO_FN(USB1_OCI), GPIO_FN(USB1_PPON), + + /* BBIF1 */ + GPIO_FN(BBIF1_RXD), GPIO_FN(BBIF1_TXD), GPIO_FN(BBIF1_TSYNC), + GPIO_FN(BBIF1_TSCK), GPIO_FN(BBIF1_RSCK), GPIO_FN(BBIF1_RSYNC), + GPIO_FN(BBIF1_FLOW), GPIO_FN(BBIF1_RX_FLOW_N), + + /* BBIF2 */ + GPIO_FN(BBIF2_TXD2_PORT5), /* MSEL5CR_0_0 */ + GPIO_FN(BBIF2_RXD2_PORT60), + GPIO_FN(BBIF2_TSYNC2_PORT6), + GPIO_FN(BBIF2_TSCK2_PORT59), + + GPIO_FN(BBIF2_RXD2_PORT90), /* MSEL5CR_0_1 */ + GPIO_FN(BBIF2_TXD2_PORT183), + GPIO_FN(BBIF2_TSCK2_PORT89), + GPIO_FN(BBIF2_TSYNC2_PORT184), + + /* BSC / FLCTL / PCMCIA */ + GPIO_FN(CS0), GPIO_FN(CS2), GPIO_FN(CS4), + GPIO_FN(CS5B), GPIO_FN(CS6A), + GPIO_FN(CS5A_PORT105), /* CS5A PORT 19/105 */ + GPIO_FN(CS5A_PORT19), + GPIO_FN(IOIS16), /* ? */ + + GPIO_FN(A0), GPIO_FN(A1), GPIO_FN(A2), GPIO_FN(A3), + GPIO_FN(A4_FOE), GPIO_FN(A5_FCDE), /* share with FLCTL */ + GPIO_FN(A6), GPIO_FN(A7), GPIO_FN(A8), GPIO_FN(A9), + GPIO_FN(A10), GPIO_FN(A11), GPIO_FN(A12), GPIO_FN(A13), + GPIO_FN(A14), GPIO_FN(A15), GPIO_FN(A16), GPIO_FN(A17), + GPIO_FN(A18), GPIO_FN(A19), GPIO_FN(A20), GPIO_FN(A21), + GPIO_FN(A22), GPIO_FN(A23), GPIO_FN(A24), GPIO_FN(A25), + GPIO_FN(A26), + + GPIO_FN(D0_NAF0), GPIO_FN(D1_NAF1), /* share with FLCTL */ + GPIO_FN(D2_NAF2), GPIO_FN(D3_NAF3), /* share with FLCTL */ + GPIO_FN(D4_NAF4), GPIO_FN(D5_NAF5), /* share with FLCTL */ + GPIO_FN(D6_NAF6), GPIO_FN(D7_NAF7), /* share with FLCTL */ + GPIO_FN(D8_NAF8), GPIO_FN(D9_NAF9), /* share with FLCTL */ + GPIO_FN(D10_NAF10), GPIO_FN(D11_NAF11), /* share with FLCTL */ + GPIO_FN(D12_NAF12), GPIO_FN(D13_NAF13), /* share with FLCTL */ + GPIO_FN(D14_NAF14), GPIO_FN(D15_NAF15), /* share with FLCTL */ + GPIO_FN(D16), GPIO_FN(D17), GPIO_FN(D18), GPIO_FN(D19), + GPIO_FN(D20), GPIO_FN(D21), GPIO_FN(D22), GPIO_FN(D23), + GPIO_FN(D24), GPIO_FN(D25), GPIO_FN(D26), GPIO_FN(D27), + GPIO_FN(D28), GPIO_FN(D29), GPIO_FN(D30), GPIO_FN(D31), + + GPIO_FN(WE0_FWE), /* share with FLCTL */ + GPIO_FN(WE1), + GPIO_FN(WE2_ICIORD), /* share with PCMCIA */ + GPIO_FN(WE3_ICIOWR), /* share with PCMCIA */ + GPIO_FN(CKO), GPIO_FN(BS), GPIO_FN(RDWR), + GPIO_FN(RD_FSC), /* share with FLCTL */ + GPIO_FN(WAIT_PORT177), /* WAIT Port 90/177 */ + GPIO_FN(WAIT_PORT90), + + GPIO_FN(FCE0), GPIO_FN(FCE1), GPIO_FN(FRB), /* FLCTL */ + + /* IRDA */ + GPIO_FN(IRDA_FIRSEL), GPIO_FN(IRDA_IN), GPIO_FN(IRDA_OUT), + + /* ATAPI */ + GPIO_FN(IDE_D0), GPIO_FN(IDE_D1), GPIO_FN(IDE_D2), + GPIO_FN(IDE_D3), GPIO_FN(IDE_D4), GPIO_FN(IDE_D5), + GPIO_FN(IDE_D6), GPIO_FN(IDE_D7), GPIO_FN(IDE_D8), + GPIO_FN(IDE_D9), GPIO_FN(IDE_D10), GPIO_FN(IDE_D11), + GPIO_FN(IDE_D12), GPIO_FN(IDE_D13), GPIO_FN(IDE_D14), + GPIO_FN(IDE_D15), GPIO_FN(IDE_A0), GPIO_FN(IDE_A1), + GPIO_FN(IDE_A2), GPIO_FN(IDE_CS0), GPIO_FN(IDE_CS1), + GPIO_FN(IDE_IOWR), GPIO_FN(IDE_IORD), GPIO_FN(IDE_IORDY), + GPIO_FN(IDE_INT), GPIO_FN(IDE_RST), GPIO_FN(IDE_DIRECTION), + GPIO_FN(IDE_EXBUF_ENB), GPIO_FN(IDE_IODACK), GPIO_FN(IDE_IODREQ), + + /* RMII */ + GPIO_FN(RMII_CRS_DV), GPIO_FN(RMII_RX_ER), GPIO_FN(RMII_RXD0), + GPIO_FN(RMII_RXD1), GPIO_FN(RMII_TX_EN), GPIO_FN(RMII_TXD0), + GPIO_FN(RMII_MDC), GPIO_FN(RMII_TXD1), GPIO_FN(RMII_MDIO), + GPIO_FN(RMII_REF50CK), GPIO_FN(RMII_REF125CK), /* for GMII */ + + /* GEther */ + GPIO_FN(ET_TX_CLK), GPIO_FN(ET_TX_EN), GPIO_FN(ET_ETXD0), + GPIO_FN(ET_ETXD1), GPIO_FN(ET_ETXD2), GPIO_FN(ET_ETXD3), + GPIO_FN(ET_ETXD4), GPIO_FN(ET_ETXD5), /* for GEther */ + GPIO_FN(ET_ETXD6), GPIO_FN(ET_ETXD7), /* for GEther */ + GPIO_FN(ET_COL), GPIO_FN(ET_TX_ER), GPIO_FN(ET_RX_CLK), + GPIO_FN(ET_RX_DV), GPIO_FN(ET_ERXD0), GPIO_FN(ET_ERXD1), + GPIO_FN(ET_ERXD2), GPIO_FN(ET_ERXD3), + GPIO_FN(ET_ERXD4), GPIO_FN(ET_ERXD5), /* for GEther */ + GPIO_FN(ET_ERXD6), GPIO_FN(ET_ERXD7), /* for GEther */ + GPIO_FN(ET_RX_ER), GPIO_FN(ET_CRS), GPIO_FN(ET_MDC), + GPIO_FN(ET_MDIO), GPIO_FN(ET_LINK), GPIO_FN(ET_PHY_INT), + GPIO_FN(ET_WOL), GPIO_FN(ET_GTX_CLK), + + /* DMA0 */ + GPIO_FN(DREQ0), GPIO_FN(DACK0), + + /* DMA1 */ + GPIO_FN(DREQ1), GPIO_FN(DACK1), + + /* SYSC */ + GPIO_FN(RESETOUTS), + + /* IRREM */ + GPIO_FN(IROUT), + + /* LCDC */ + GPIO_FN(LCDC0_SELECT), + GPIO_FN(LCDC1_SELECT), + + /* SDENC */ + GPIO_FN(SDENC_CPG), + GPIO_FN(SDENC_DV_CLKI), + + /* SYSC */ + GPIO_FN(RESETP_PULLUP), + GPIO_FN(RESETP_PLAIN), + + /* DEBUG */ + GPIO_FN(EDEBGREQ_PULLDOWN), + GPIO_FN(EDEBGREQ_PULLUP), + + GPIO_FN(TRACEAUD_FROM_VIO), + GPIO_FN(TRACEAUD_FROM_LCDC0), + GPIO_FN(TRACEAUD_FROM_MEMC), +}; + +static struct pinmux_cfg_reg pinmux_config_regs[] = { + PORTCR(0, 0xe6050000), /* PORT0CR */ + PORTCR(1, 0xe6050001), /* PORT1CR */ + PORTCR(2, 0xe6050002), /* PORT2CR */ + PORTCR(3, 0xe6050003), /* PORT3CR */ + PORTCR(4, 0xe6050004), /* PORT4CR */ + PORTCR(5, 0xe6050005), /* PORT5CR */ + PORTCR(6, 0xe6050006), /* PORT6CR */ + PORTCR(7, 0xe6050007), /* PORT7CR */ + PORTCR(8, 0xe6050008), /* PORT8CR */ + PORTCR(9, 0xe6050009), /* PORT9CR */ + PORTCR(10, 0xe605000a), /* PORT10CR */ + PORTCR(11, 0xe605000b), /* PORT11CR */ + PORTCR(12, 0xe605000c), /* PORT12CR */ + PORTCR(13, 0xe605000d), /* PORT13CR */ + PORTCR(14, 0xe605000e), /* PORT14CR */ + PORTCR(15, 0xe605000f), /* PORT15CR */ + PORTCR(16, 0xe6050010), /* PORT16CR */ + PORTCR(17, 0xe6050011), /* PORT17CR */ + PORTCR(18, 0xe6050012), /* PORT18CR */ + PORTCR(19, 0xe6050013), /* PORT19CR */ + PORTCR(20, 0xe6050014), /* PORT20CR */ + PORTCR(21, 0xe6050015), /* PORT21CR */ + PORTCR(22, 0xe6050016), /* PORT22CR */ + PORTCR(23, 0xe6050017), /* PORT23CR */ + PORTCR(24, 0xe6050018), /* PORT24CR */ + PORTCR(25, 0xe6050019), /* PORT25CR */ + PORTCR(26, 0xe605001a), /* PORT26CR */ + PORTCR(27, 0xe605001b), /* PORT27CR */ + PORTCR(28, 0xe605001c), /* PORT28CR */ + PORTCR(29, 0xe605001d), /* PORT29CR */ + PORTCR(30, 0xe605001e), /* PORT30CR */ + PORTCR(31, 0xe605001f), /* PORT31CR */ + PORTCR(32, 0xe6050020), /* PORT32CR */ + PORTCR(33, 0xe6050021), /* PORT33CR */ + PORTCR(34, 0xe6050022), /* PORT34CR */ + PORTCR(35, 0xe6050023), /* PORT35CR */ + PORTCR(36, 0xe6050024), /* PORT36CR */ + PORTCR(37, 0xe6050025), /* PORT37CR */ + PORTCR(38, 0xe6050026), /* PORT38CR */ + PORTCR(39, 0xe6050027), /* PORT39CR */ + PORTCR(40, 0xe6050028), /* PORT40CR */ + PORTCR(41, 0xe6050029), /* PORT41CR */ + PORTCR(42, 0xe605002a), /* PORT42CR */ + PORTCR(43, 0xe605002b), /* PORT43CR */ + PORTCR(44, 0xe605002c), /* PORT44CR */ + PORTCR(45, 0xe605002d), /* PORT45CR */ + PORTCR(46, 0xe605002e), /* PORT46CR */ + PORTCR(47, 0xe605002f), /* PORT47CR */ + PORTCR(48, 0xe6050030), /* PORT48CR */ + PORTCR(49, 0xe6050031), /* PORT49CR */ + PORTCR(50, 0xe6050032), /* PORT50CR */ + PORTCR(51, 0xe6050033), /* PORT51CR */ + PORTCR(52, 0xe6050034), /* PORT52CR */ + PORTCR(53, 0xe6050035), /* PORT53CR */ + PORTCR(54, 0xe6050036), /* PORT54CR */ + PORTCR(55, 0xe6050037), /* PORT55CR */ + PORTCR(56, 0xe6050038), /* PORT56CR */ + PORTCR(57, 0xe6050039), /* PORT57CR */ + PORTCR(58, 0xe605003a), /* PORT58CR */ + PORTCR(59, 0xe605003b), /* PORT59CR */ + PORTCR(60, 0xe605003c), /* PORT60CR */ + PORTCR(61, 0xe605003d), /* PORT61CR */ + PORTCR(62, 0xe605003e), /* PORT62CR */ + PORTCR(63, 0xe605003f), /* PORT63CR */ + PORTCR(64, 0xe6050040), /* PORT64CR */ + PORTCR(65, 0xe6050041), /* PORT65CR */ + PORTCR(66, 0xe6050042), /* PORT66CR */ + PORTCR(67, 0xe6050043), /* PORT67CR */ + PORTCR(68, 0xe6050044), /* PORT68CR */ + PORTCR(69, 0xe6050045), /* PORT69CR */ + PORTCR(70, 0xe6050046), /* PORT70CR */ + PORTCR(71, 0xe6050047), /* PORT71CR */ + PORTCR(72, 0xe6050048), /* PORT72CR */ + PORTCR(73, 0xe6050049), /* PORT73CR */ + PORTCR(74, 0xe605004a), /* PORT74CR */ + PORTCR(75, 0xe605004b), /* PORT75CR */ + PORTCR(76, 0xe605004c), /* PORT76CR */ + PORTCR(77, 0xe605004d), /* PORT77CR */ + PORTCR(78, 0xe605004e), /* PORT78CR */ + PORTCR(79, 0xe605004f), /* PORT79CR */ + PORTCR(80, 0xe6050050), /* PORT80CR */ + PORTCR(81, 0xe6050051), /* PORT81CR */ + PORTCR(82, 0xe6050052), /* PORT82CR */ + PORTCR(83, 0xe6050053), /* PORT83CR */ + + PORTCR(84, 0xe6051054), /* PORT84CR */ + PORTCR(85, 0xe6051055), /* PORT85CR */ + PORTCR(86, 0xe6051056), /* PORT86CR */ + PORTCR(87, 0xe6051057), /* PORT87CR */ + PORTCR(88, 0xe6051058), /* PORT88CR */ + PORTCR(89, 0xe6051059), /* PORT89CR */ + PORTCR(90, 0xe605105a), /* PORT90CR */ + PORTCR(91, 0xe605105b), /* PORT91CR */ + PORTCR(92, 0xe605105c), /* PORT92CR */ + PORTCR(93, 0xe605105d), /* PORT93CR */ + PORTCR(94, 0xe605105e), /* PORT94CR */ + PORTCR(95, 0xe605105f), /* PORT95CR */ + PORTCR(96, 0xe6051060), /* PORT96CR */ + PORTCR(97, 0xe6051061), /* PORT97CR */ + PORTCR(98, 0xe6051062), /* PORT98CR */ + PORTCR(99, 0xe6051063), /* PORT99CR */ + PORTCR(100, 0xe6051064), /* PORT100CR */ + PORTCR(101, 0xe6051065), /* PORT101CR */ + PORTCR(102, 0xe6051066), /* PORT102CR */ + PORTCR(103, 0xe6051067), /* PORT103CR */ + PORTCR(104, 0xe6051068), /* PORT104CR */ + PORTCR(105, 0xe6051069), /* PORT105CR */ + PORTCR(106, 0xe605106a), /* PORT106CR */ + PORTCR(107, 0xe605106b), /* PORT107CR */ + PORTCR(108, 0xe605106c), /* PORT108CR */ + PORTCR(109, 0xe605106d), /* PORT109CR */ + PORTCR(110, 0xe605106e), /* PORT110CR */ + PORTCR(111, 0xe605106f), /* PORT111CR */ + PORTCR(112, 0xe6051070), /* PORT112CR */ + PORTCR(113, 0xe6051071), /* PORT113CR */ + PORTCR(114, 0xe6051072), /* PORT114CR */ + + PORTCR(115, 0xe6052073), /* PORT115CR */ + PORTCR(116, 0xe6052074), /* PORT116CR */ + PORTCR(117, 0xe6052075), /* PORT117CR */ + PORTCR(118, 0xe6052076), /* PORT118CR */ + PORTCR(119, 0xe6052077), /* PORT119CR */ + PORTCR(120, 0xe6052078), /* PORT120CR */ + PORTCR(121, 0xe6052079), /* PORT121CR */ + PORTCR(122, 0xe605207a), /* PORT122CR */ + PORTCR(123, 0xe605207b), /* PORT123CR */ + PORTCR(124, 0xe605207c), /* PORT124CR */ + PORTCR(125, 0xe605207d), /* PORT125CR */ + PORTCR(126, 0xe605207e), /* PORT126CR */ + PORTCR(127, 0xe605207f), /* PORT127CR */ + PORTCR(128, 0xe6052080), /* PORT128CR */ + PORTCR(129, 0xe6052081), /* PORT129CR */ + PORTCR(130, 0xe6052082), /* PORT130CR */ + PORTCR(131, 0xe6052083), /* PORT131CR */ + PORTCR(132, 0xe6052084), /* PORT132CR */ + PORTCR(133, 0xe6052085), /* PORT133CR */ + PORTCR(134, 0xe6052086), /* PORT134CR */ + PORTCR(135, 0xe6052087), /* PORT135CR */ + PORTCR(136, 0xe6052088), /* PORT136CR */ + PORTCR(137, 0xe6052089), /* PORT137CR */ + PORTCR(138, 0xe605208a), /* PORT138CR */ + PORTCR(139, 0xe605208b), /* PORT139CR */ + PORTCR(140, 0xe605208c), /* PORT140CR */ + PORTCR(141, 0xe605208d), /* PORT141CR */ + PORTCR(142, 0xe605208e), /* PORT142CR */ + PORTCR(143, 0xe605208f), /* PORT143CR */ + PORTCR(144, 0xe6052090), /* PORT144CR */ + PORTCR(145, 0xe6052091), /* PORT145CR */ + PORTCR(146, 0xe6052092), /* PORT146CR */ + PORTCR(147, 0xe6052093), /* PORT147CR */ + PORTCR(148, 0xe6052094), /* PORT148CR */ + PORTCR(149, 0xe6052095), /* PORT149CR */ + PORTCR(150, 0xe6052096), /* PORT150CR */ + PORTCR(151, 0xe6052097), /* PORT151CR */ + PORTCR(152, 0xe6052098), /* PORT152CR */ + PORTCR(153, 0xe6052099), /* PORT153CR */ + PORTCR(154, 0xe605209a), /* PORT154CR */ + PORTCR(155, 0xe605209b), /* PORT155CR */ + PORTCR(156, 0xe605209c), /* PORT156CR */ + PORTCR(157, 0xe605209d), /* PORT157CR */ + PORTCR(158, 0xe605209e), /* PORT158CR */ + PORTCR(159, 0xe605209f), /* PORT159CR */ + PORTCR(160, 0xe60520a0), /* PORT160CR */ + PORTCR(161, 0xe60520a1), /* PORT161CR */ + PORTCR(162, 0xe60520a2), /* PORT162CR */ + PORTCR(163, 0xe60520a3), /* PORT163CR */ + PORTCR(164, 0xe60520a4), /* PORT164CR */ + PORTCR(165, 0xe60520a5), /* PORT165CR */ + PORTCR(166, 0xe60520a6), /* PORT166CR */ + PORTCR(167, 0xe60520a7), /* PORT167CR */ + PORTCR(168, 0xe60520a8), /* PORT168CR */ + PORTCR(169, 0xe60520a9), /* PORT169CR */ + PORTCR(170, 0xe60520aa), /* PORT170CR */ + PORTCR(171, 0xe60520ab), /* PORT171CR */ + PORTCR(172, 0xe60520ac), /* PORT172CR */ + PORTCR(173, 0xe60520ad), /* PORT173CR */ + PORTCR(174, 0xe60520ae), /* PORT174CR */ + PORTCR(175, 0xe60520af), /* PORT175CR */ + PORTCR(176, 0xe60520b0), /* PORT176CR */ + PORTCR(177, 0xe60520b1), /* PORT177CR */ + PORTCR(178, 0xe60520b2), /* PORT178CR */ + PORTCR(179, 0xe60520b3), /* PORT179CR */ + PORTCR(180, 0xe60520b4), /* PORT180CR */ + PORTCR(181, 0xe60520b5), /* PORT181CR */ + PORTCR(182, 0xe60520b6), /* PORT182CR */ + PORTCR(183, 0xe60520b7), /* PORT183CR */ + PORTCR(184, 0xe60520b8), /* PORT184CR */ + PORTCR(185, 0xe60520b9), /* PORT185CR */ + PORTCR(186, 0xe60520ba), /* PORT186CR */ + PORTCR(187, 0xe60520bb), /* PORT187CR */ + PORTCR(188, 0xe60520bc), /* PORT188CR */ + PORTCR(189, 0xe60520bd), /* PORT189CR */ + PORTCR(190, 0xe60520be), /* PORT190CR */ + PORTCR(191, 0xe60520bf), /* PORT191CR */ + PORTCR(192, 0xe60520c0), /* PORT192CR */ + PORTCR(193, 0xe60520c1), /* PORT193CR */ + PORTCR(194, 0xe60520c2), /* PORT194CR */ + PORTCR(195, 0xe60520c3), /* PORT195CR */ + PORTCR(196, 0xe60520c4), /* PORT196CR */ + PORTCR(197, 0xe60520c5), /* PORT197CR */ + PORTCR(198, 0xe60520c6), /* PORT198CR */ + PORTCR(199, 0xe60520c7), /* PORT199CR */ + PORTCR(200, 0xe60520c8), /* PORT200CR */ + PORTCR(201, 0xe60520c9), /* PORT201CR */ + PORTCR(202, 0xe60520ca), /* PORT202CR */ + PORTCR(203, 0xe60520cb), /* PORT203CR */ + PORTCR(204, 0xe60520cc), /* PORT204CR */ + PORTCR(205, 0xe60520cd), /* PORT205CR */ + PORTCR(206, 0xe60520ce), /* PORT206CR */ + PORTCR(207, 0xe60520cf), /* PORT207CR */ + PORTCR(208, 0xe60520d0), /* PORT208CR */ + PORTCR(209, 0xe60520d1), /* PORT209CR */ + + PORTCR(210, 0xe60530d2), /* PORT210CR */ + PORTCR(211, 0xe60530d3), /* PORT211CR */ + + { PINMUX_CFG_REG("MSEL1CR", 0xe605800c, 32, 1) { + MSEL1CR_31_0, MSEL1CR_31_1, + MSEL1CR_30_0, MSEL1CR_30_1, + MSEL1CR_29_0, MSEL1CR_29_1, + MSEL1CR_28_0, MSEL1CR_28_1, + MSEL1CR_27_0, MSEL1CR_27_1, + MSEL1CR_26_0, MSEL1CR_26_1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + MSEL1CR_16_0, MSEL1CR_16_1, + MSEL1CR_15_0, MSEL1CR_15_1, + MSEL1CR_14_0, MSEL1CR_14_1, + MSEL1CR_13_0, MSEL1CR_13_1, + MSEL1CR_12_0, MSEL1CR_12_1, + 0, 0, 0, 0, + MSEL1CR_9_0, MSEL1CR_9_1, + 0, 0, + MSEL1CR_7_0, MSEL1CR_7_1, + MSEL1CR_6_0, MSEL1CR_6_1, + MSEL1CR_5_0, MSEL1CR_5_1, + MSEL1CR_4_0, MSEL1CR_4_1, + MSEL1CR_3_0, MSEL1CR_3_1, + MSEL1CR_2_0, MSEL1CR_2_1, + 0, 0, + MSEL1CR_0_0, MSEL1CR_0_1, + } + }, + { PINMUX_CFG_REG("MSEL3CR", 0xE6058020, 32, 1) { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + MSEL3CR_15_0, MSEL3CR_15_1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + MSEL3CR_6_0, MSEL3CR_6_1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + } + }, + { PINMUX_CFG_REG("MSEL4CR", 0xE6058024, 32, 1) { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + MSEL4CR_19_0, MSEL4CR_19_1, + MSEL4CR_18_0, MSEL4CR_18_1, + 0, 0, 0, 0, + MSEL4CR_15_0, MSEL4CR_15_1, + 0, 0, 0, 0, 0, 0, 0, 0, + MSEL4CR_10_0, MSEL4CR_10_1, + 0, 0, 0, 0, 0, 0, + MSEL4CR_6_0, MSEL4CR_6_1, + 0, 0, + MSEL4CR_4_0, MSEL4CR_4_1, + 0, 0, 0, 0, + MSEL4CR_1_0, MSEL4CR_1_1, + 0, 0, + } + }, + { PINMUX_CFG_REG("MSEL5CR", 0xE6058028, 32, 1) { + MSEL5CR_31_0, MSEL5CR_31_1, + MSEL5CR_30_0, MSEL5CR_30_1, + MSEL5CR_29_0, MSEL5CR_29_1, + 0, 0, + MSEL5CR_27_0, MSEL5CR_27_1, + 0, 0, + MSEL5CR_25_0, MSEL5CR_25_1, + 0, 0, + MSEL5CR_23_0, MSEL5CR_23_1, + 0, 0, + MSEL5CR_21_0, MSEL5CR_21_1, + 0, 0, + MSEL5CR_19_0, MSEL5CR_19_1, + 0, 0, + MSEL5CR_17_0, MSEL5CR_17_1, + 0, 0, + MSEL5CR_15_0, MSEL5CR_15_1, + MSEL5CR_14_0, MSEL5CR_14_1, + MSEL5CR_13_0, MSEL5CR_13_1, + MSEL5CR_12_0, MSEL5CR_12_1, + MSEL5CR_11_0, MSEL5CR_11_1, + MSEL5CR_10_0, MSEL5CR_10_1, + 0, 0, + MSEL5CR_8_0, MSEL5CR_8_1, + MSEL5CR_7_0, MSEL5CR_7_1, + MSEL5CR_6_0, MSEL5CR_6_1, + MSEL5CR_5_0, MSEL5CR_5_1, + MSEL5CR_4_0, MSEL5CR_4_1, + MSEL5CR_3_0, MSEL5CR_3_1, + MSEL5CR_2_0, MSEL5CR_2_1, + 0, 0, + MSEL5CR_0_0, MSEL5CR_0_1, + } + }, + { }, +}; + +static struct pinmux_data_reg pinmux_data_regs[] = { + { PINMUX_DATA_REG("PORTL031_000DR", 0xe6054800, 32) { + PORT31_DATA, PORT30_DATA, PORT29_DATA, PORT28_DATA, + PORT27_DATA, PORT26_DATA, PORT25_DATA, PORT24_DATA, + PORT23_DATA, PORT22_DATA, PORT21_DATA, PORT20_DATA, + PORT19_DATA, PORT18_DATA, PORT17_DATA, PORT16_DATA, + PORT15_DATA, PORT14_DATA, PORT13_DATA, PORT12_DATA, + PORT11_DATA, PORT10_DATA, PORT9_DATA, PORT8_DATA, + PORT7_DATA, PORT6_DATA, PORT5_DATA, PORT4_DATA, + PORT3_DATA, PORT2_DATA, PORT1_DATA, PORT0_DATA } + }, + { PINMUX_DATA_REG("PORTL063_032DR", 0xe6054804, 32) { + PORT63_DATA, PORT62_DATA, PORT61_DATA, PORT60_DATA, + PORT59_DATA, PORT58_DATA, PORT57_DATA, PORT56_DATA, + PORT55_DATA, PORT54_DATA, PORT53_DATA, PORT52_DATA, + PORT51_DATA, PORT50_DATA, PORT49_DATA, PORT48_DATA, + PORT47_DATA, PORT46_DATA, PORT45_DATA, PORT44_DATA, + PORT43_DATA, PORT42_DATA, PORT41_DATA, PORT40_DATA, + PORT39_DATA, PORT38_DATA, PORT37_DATA, PORT36_DATA, + PORT35_DATA, PORT34_DATA, PORT33_DATA, PORT32_DATA } + }, + { PINMUX_DATA_REG("PORTL095_064DR", 0xe6054808, 32) { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + PORT83_DATA, PORT82_DATA, PORT81_DATA, PORT80_DATA, + PORT79_DATA, PORT78_DATA, PORT77_DATA, PORT76_DATA, + PORT75_DATA, PORT74_DATA, PORT73_DATA, PORT72_DATA, + PORT71_DATA, PORT70_DATA, PORT69_DATA, PORT68_DATA, + PORT67_DATA, PORT66_DATA, PORT65_DATA, PORT64_DATA } + }, + { PINMUX_DATA_REG("PORTD095_064DR", 0xe6055808, 32) { + PORT95_DATA, PORT94_DATA, PORT93_DATA, PORT92_DATA, + PORT91_DATA, PORT90_DATA, PORT89_DATA, PORT88_DATA, + PORT87_DATA, PORT86_DATA, PORT85_DATA, PORT84_DATA, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 } + }, + { PINMUX_DATA_REG("PORTD127_096DR", 0xe605580c, 32) { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, PORT114_DATA, PORT113_DATA, PORT112_DATA, + PORT111_DATA, PORT110_DATA, PORT109_DATA, PORT108_DATA, + PORT107_DATA, PORT106_DATA, PORT105_DATA, PORT104_DATA, + PORT103_DATA, PORT102_DATA, PORT101_DATA, PORT100_DATA, + PORT99_DATA, PORT98_DATA, PORT97_DATA, PORT96_DATA } + }, + { PINMUX_DATA_REG("PORTR127_096DR", 0xe605680C, 32) { + PORT127_DATA, PORT126_DATA, PORT125_DATA, PORT124_DATA, + PORT123_DATA, PORT122_DATA, PORT121_DATA, PORT120_DATA, + PORT119_DATA, PORT118_DATA, PORT117_DATA, PORT116_DATA, + PORT115_DATA, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 } + }, + { PINMUX_DATA_REG("PORTR159_128DR", 0xe6056810, 32) { + PORT159_DATA, PORT158_DATA, PORT157_DATA, PORT156_DATA, + PORT155_DATA, PORT154_DATA, PORT153_DATA, PORT152_DATA, + PORT151_DATA, PORT150_DATA, PORT149_DATA, PORT148_DATA, + PORT147_DATA, PORT146_DATA, PORT145_DATA, PORT144_DATA, + PORT143_DATA, PORT142_DATA, PORT141_DATA, PORT140_DATA, + PORT139_DATA, PORT138_DATA, PORT137_DATA, PORT136_DATA, + PORT135_DATA, PORT134_DATA, PORT133_DATA, PORT132_DATA, + PORT131_DATA, PORT130_DATA, PORT129_DATA, PORT128_DATA } + }, + { PINMUX_DATA_REG("PORTR191_160DR", 0xe6056814, 32) { + PORT191_DATA, PORT190_DATA, PORT189_DATA, PORT188_DATA, + PORT187_DATA, PORT186_DATA, PORT185_DATA, PORT184_DATA, + PORT183_DATA, PORT182_DATA, PORT181_DATA, PORT180_DATA, + PORT179_DATA, PORT178_DATA, PORT177_DATA, PORT176_DATA, + PORT175_DATA, PORT174_DATA, PORT173_DATA, PORT172_DATA, + PORT171_DATA, PORT170_DATA, PORT169_DATA, PORT168_DATA, + PORT167_DATA, PORT166_DATA, PORT165_DATA, PORT164_DATA, + PORT163_DATA, PORT162_DATA, PORT161_DATA, PORT160_DATA } + }, + { PINMUX_DATA_REG("PORTR223_192DR", 0xe6056818, 32) { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, PORT209_DATA, PORT208_DATA, + PORT207_DATA, PORT206_DATA, PORT205_DATA, PORT204_DATA, + PORT203_DATA, PORT202_DATA, PORT201_DATA, PORT200_DATA, + PORT199_DATA, PORT198_DATA, PORT197_DATA, PORT196_DATA, + PORT195_DATA, PORT194_DATA, PORT193_DATA, PORT192_DATA } + }, + { PINMUX_DATA_REG("PORTU223_192DR", 0xe6057818, 32) { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + PORT211_DATA, PORT210_DATA, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 } + }, + { }, +}; + +static struct pinmux_info r8a7740_pinmux_info = { + .name = "r8a7740_pfc", + .reserved_id = PINMUX_RESERVED, + .data = { PINMUX_DATA_BEGIN, + PINMUX_DATA_END }, + .input = { PINMUX_INPUT_BEGIN, + PINMUX_INPUT_END }, + .input_pu = { PINMUX_INPUT_PULLUP_BEGIN, + PINMUX_INPUT_PULLUP_END }, + .input_pd = { PINMUX_INPUT_PULLDOWN_BEGIN, + PINMUX_INPUT_PULLDOWN_END }, + .output = { PINMUX_OUTPUT_BEGIN, + PINMUX_OUTPUT_END }, + .mark = { PINMUX_MARK_BEGIN, + PINMUX_MARK_END }, + .function = { PINMUX_FUNCTION_BEGIN, + PINMUX_FUNCTION_END }, + + .first_gpio = GPIO_PORT0, + .last_gpio = GPIO_FN_TRACEAUD_FROM_MEMC, + + .gpios = pinmux_gpios, + .cfg_regs = pinmux_config_regs, + .data_regs = pinmux_data_regs, + + .gpio_data = pinmux_data, + .gpio_data_size = ARRAY_SIZE(pinmux_data), +}; + +void r8a7740_pinmux_init(void) +{ + register_pinmux(&r8a7740_pinmux_info); +} -- cgit v1.2.3 From 6831f3a9184a1c5400e4fa2f2d3172b6dfb2c805 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 10 Nov 2011 18:46:23 -0800 Subject: ARM: mach-shmobile: r8a7740: add i2c support This patch adds I2C support to r8a7740 CPU which has lasting errata on I2C I/O pad reset. This patch is including work-around. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/setup-r8a7740.c | 106 +++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 55485187f0c7..e16860f04934 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -17,8 +17,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include +#include #include #include #include @@ -233,10 +235,114 @@ static struct platform_device *r8a7740_early_devices[] __initdata = { &cmt10_device, }; +/* I2C */ +static struct resource i2c0_resources[] = { + [0] = { + .name = "IIC0", + .start = 0xfff20000, + .end = 0xfff20425 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(201), + .end = gic_spi(204), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource i2c1_resources[] = { + [0] = { + .name = "IIC1", + .start = 0xe6c20000, + .end = 0xe6c20425 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = gic_spi(70), + .end = gic_spi(73), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device i2c0_device = { + .name = "i2c-sh_mobile", + .id = 0, + .resource = i2c0_resources, + .num_resources = ARRAY_SIZE(i2c0_resources), +}; + +static struct platform_device i2c1_device = { + .name = "i2c-sh_mobile", + .id = 1, + .resource = i2c1_resources, + .num_resources = ARRAY_SIZE(i2c1_resources), +}; + +static struct platform_device *r8a7740_late_devices[] __initdata = { + &i2c0_device, + &i2c1_device, +}; + +#define ICCR 0x0004 +#define ICSTART 0x0070 + +#define i2c_read(reg, offset) ioread8(reg + offset) +#define i2c_write(reg, offset, data) iowrite8(data, reg + offset) + +/* + * r8a7740 chip has lasting errata on I2C I/O pad reset. + * this is work-around for it. + */ +static void r8a7740_i2c_workaround(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *reg; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (unlikely(!res)) { + pr_err("r8a7740 i2c workaround fail (cannot find resource)\n"); + return; + } + + reg = ioremap(res->start, resource_size(res)); + if (unlikely(!reg)) { + pr_err("r8a7740 i2c workaround fail (cannot map IO)\n"); + return; + } + + i2c_write(reg, ICCR, i2c_read(reg, ICCR) | 0x80); + i2c_read(reg, ICCR); /* dummy read */ + + i2c_write(reg, ICSTART, i2c_read(reg, ICSTART) | 0x10); + i2c_read(reg, ICSTART); /* dummy read */ + + mdelay(100); + + i2c_write(reg, ICCR, 0x01); + i2c_read(reg, ICCR); + i2c_write(reg, ICSTART, 0x00); + i2c_read(reg, ICSTART); + + i2c_write(reg, ICCR, 0x10); + mdelay(100); + i2c_write(reg, ICCR, 0x00); + mdelay(100); + i2c_write(reg, ICCR, 0x10); + mdelay(100); + + iounmap(reg); +} + void __init r8a7740_add_standard_devices(void) { + /* I2C work-around */ + r8a7740_i2c_workaround(&i2c0_device); + r8a7740_i2c_workaround(&i2c1_device); + platform_add_devices(r8a7740_early_devices, ARRAY_SIZE(r8a7740_early_devices)); + platform_add_devices(r8a7740_late_devices, + ARRAY_SIZE(r8a7740_late_devices)); } void __init r8a7740_add_early_devices(void) -- cgit v1.2.3 From 215d6cc9230c2a42a643c4cd296680040eeb1f49 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 10 Nov 2011 18:46:35 -0800 Subject: ARM: mach-shmobile: r8a7740: add INTC support R8A7740 GIC can not get external IRQx interrupt directly without GIC - INTC demux support. Current AG5 is using GIC - INTCS demux with special irq relocation. but GIC - INTCA demux is still not supported and it needs irq number re-mapping. OTOH, normal INTC support as before is very enough for R8A7740, because it is not SMP CPU. This patch adds INTCA/INTCS support instead of GIC. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/Kconfig | 1 - arch/arm/mach-shmobile/Makefile | 2 +- arch/arm/mach-shmobile/intc-r8a7740.c | 612 ++++++++++++++++++++++++++++++++- arch/arm/mach-shmobile/setup-r8a7740.c | 28 +- 4 files changed, 614 insertions(+), 29 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 329a3cb7f99b..aa63c968f420 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -33,7 +33,6 @@ config ARCH_R8A7740 select CPU_V7 select SH_CLK_CPG select ARCH_WANT_OPTIONAL_GPIOLIB - select ARM_GIC comment "SH-Mobile Board Type" diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 2bd2d3ba8ffe..971f7038f05a 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -31,7 +31,7 @@ obj-$(CONFIG_ARCH_SH7367) += entry-intc.o obj-$(CONFIG_ARCH_SH7377) += entry-intc.o obj-$(CONFIG_ARCH_SH7372) += entry-intc.o obj-$(CONFIG_ARCH_SH73A0) += entry-gic.o -obj-$(CONFIG_ARCH_R8A7740) += entry-gic.o +obj-$(CONFIG_ARCH_R8A7740) += entry-intc.o # PM objects obj-$(CONFIG_SUSPEND) += suspend.o diff --git a/arch/arm/mach-shmobile/intc-r8a7740.c b/arch/arm/mach-shmobile/intc-r8a7740.c index c62a2059f2f7..272c84c20c83 100644 --- a/arch/arm/mach-shmobile/intc-r8a7740.c +++ b/arch/arm/mach-shmobile/intc-r8a7740.c @@ -18,28 +18,614 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include +#include +#include #include #include -#include +#include +#include +#include +#include -#define INTA_CTRL 0xe605807c +/* + * INTCA + */ +enum { + UNUSED_INTCA = 0, + + /* interrupt sources INTCA */ + DIRC, + ATAPI, + IIC1_ALI, IIC1_TACKI, IIC1_WAITI, IIC1_DTEI, + AP_ARM_COMMTX, AP_ARM_COMMRX, + MFI, MFIS, + BBIF1, BBIF2, + USBHSDMAC, + USBF_OUL_SOF, USBF_IXL_INT, + SGX540, + CMT1_0, CMT1_1, CMT1_2, CMT1_3, + CMT2, + CMT3, + KEYSC, + SCIFA0, SCIFA1, SCIFA2, SCIFA3, + MSIOF2, MSIOF1, + SCIFA4, SCIFA5, SCIFB, + FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I, + SDHI0_0, SDHI0_1, SDHI0_2, SDHI0_3, + SDHI1_0, SDHI1_1, SDHI1_2, SDHI1_3, + AP_ARM_L2CINT, + IRDA, + TPU0, + SCIFA6, SCIFA7, + GbEther, + ICBS0, + DDM, + SDHI2_0, SDHI2_1, SDHI2_2, SDHI2_3, + RWDT0, + DMAC1_1_DEI0, DMAC1_1_DEI1, DMAC1_1_DEI2, DMAC1_1_DEI3, + DMAC1_2_DEI4, DMAC1_2_DEI5, DMAC1_2_DADERR, + DMAC2_1_DEI0, DMAC2_1_DEI1, DMAC2_1_DEI2, DMAC2_1_DEI3, + DMAC2_2_DEI4, DMAC2_2_DEI5, DMAC2_2_DADERR, + DMAC3_1_DEI0, DMAC3_1_DEI1, DMAC3_1_DEI2, DMAC3_1_DEI3, + DMAC3_2_DEI4, DMAC3_2_DEI5, DMAC3_2_DADERR, + SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM, + USBH_INT, USBH_OHCI, USBH_EHCI, USBH_PME, USBH_BIND, + RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF, + SPU2_0, SPU2_1, + FSI, FMSI, + IPMMU, + AP_ARM_CTIIRQ, AP_ARM_PMURQ, + MFIS2, + CPORTR2S, + CMT14, CMT15, + MMCIF_0, MMCIF_1, MMCIF_2, + SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI, + STPRO_0, STPRO_1, STPRO_2, STPRO_3, STPRO_4, + + /* interrupt groups INTCA */ + DMAC1_1, DMAC1_2, + DMAC2_1, DMAC2_2, + DMAC3_1, DMAC3_2, + AP_ARM1, AP_ARM2, + SDHI0, SDHI1, SDHI2, + SHWYSTAT, + USBF, USBH1, USBH2, + RSPI, SPU2, FLCTL, IIC1, +}; + +static struct intc_vect intca_vectors[] __initdata = { + INTC_VECT(DIRC, 0x0560), + INTC_VECT(ATAPI, 0x05E0), + INTC_VECT(IIC1_ALI, 0x0780), + INTC_VECT(IIC1_TACKI, 0x07A0), + INTC_VECT(IIC1_WAITI, 0x07C0), + INTC_VECT(IIC1_DTEI, 0x07E0), + INTC_VECT(AP_ARM_COMMTX, 0x0840), + INTC_VECT(AP_ARM_COMMRX, 0x0860), + INTC_VECT(MFI, 0x0900), + INTC_VECT(MFIS, 0x0920), + INTC_VECT(BBIF1, 0x0940), + INTC_VECT(BBIF2, 0x0960), + INTC_VECT(USBHSDMAC, 0x0A00), + INTC_VECT(USBF_OUL_SOF, 0x0A20), + INTC_VECT(USBF_IXL_INT, 0x0A40), + INTC_VECT(SGX540, 0x0A60), + INTC_VECT(CMT1_0, 0x0B00), + INTC_VECT(CMT1_1, 0x0B20), + INTC_VECT(CMT1_2, 0x0B40), + INTC_VECT(CMT1_3, 0x0B60), + INTC_VECT(CMT2, 0x0B80), + INTC_VECT(CMT3, 0x0BA0), + INTC_VECT(KEYSC, 0x0BE0), + INTC_VECT(SCIFA0, 0x0C00), + INTC_VECT(SCIFA1, 0x0C20), + INTC_VECT(SCIFA2, 0x0C40), + INTC_VECT(SCIFA3, 0x0C60), + INTC_VECT(MSIOF2, 0x0C80), + INTC_VECT(MSIOF1, 0x0D00), + INTC_VECT(SCIFA4, 0x0D20), + INTC_VECT(SCIFA5, 0x0D40), + INTC_VECT(SCIFB, 0x0D60), + INTC_VECT(FLCTL_FLSTEI, 0x0D80), + INTC_VECT(FLCTL_FLTENDI, 0x0DA0), + INTC_VECT(FLCTL_FLTREQ0I, 0x0DC0), + INTC_VECT(FLCTL_FLTREQ1I, 0x0DE0), + INTC_VECT(SDHI0_0, 0x0E00), + INTC_VECT(SDHI0_1, 0x0E20), + INTC_VECT(SDHI0_2, 0x0E40), + INTC_VECT(SDHI0_3, 0x0E60), + INTC_VECT(SDHI1_0, 0x0E80), + INTC_VECT(SDHI1_1, 0x0EA0), + INTC_VECT(SDHI1_2, 0x0EC0), + INTC_VECT(SDHI1_3, 0x0EE0), + INTC_VECT(AP_ARM_L2CINT, 0x0FA0), + INTC_VECT(IRDA, 0x0480), + INTC_VECT(TPU0, 0x04A0), + INTC_VECT(SCIFA6, 0x04C0), + INTC_VECT(SCIFA7, 0x04E0), + INTC_VECT(GbEther, 0x0500), + INTC_VECT(ICBS0, 0x0540), + INTC_VECT(DDM, 0x1140), + INTC_VECT(SDHI2_0, 0x1200), + INTC_VECT(SDHI2_1, 0x1220), + INTC_VECT(SDHI2_2, 0x1240), + INTC_VECT(SDHI2_3, 0x1260), + INTC_VECT(RWDT0, 0x1280), + INTC_VECT(DMAC1_1_DEI0, 0x2000), + INTC_VECT(DMAC1_1_DEI1, 0x2020), + INTC_VECT(DMAC1_1_DEI2, 0x2040), + INTC_VECT(DMAC1_1_DEI3, 0x2060), + INTC_VECT(DMAC1_2_DEI4, 0x2080), + INTC_VECT(DMAC1_2_DEI5, 0x20A0), + INTC_VECT(DMAC1_2_DADERR, 0x20C0), + INTC_VECT(DMAC2_1_DEI0, 0x2100), + INTC_VECT(DMAC2_1_DEI1, 0x2120), + INTC_VECT(DMAC2_1_DEI2, 0x2140), + INTC_VECT(DMAC2_1_DEI3, 0x2160), + INTC_VECT(DMAC2_2_DEI4, 0x2180), + INTC_VECT(DMAC2_2_DEI5, 0x21A0), + INTC_VECT(DMAC2_2_DADERR, 0x21C0), + INTC_VECT(DMAC3_1_DEI0, 0x2200), + INTC_VECT(DMAC3_1_DEI1, 0x2220), + INTC_VECT(DMAC3_1_DEI2, 0x2240), + INTC_VECT(DMAC3_1_DEI3, 0x2260), + INTC_VECT(DMAC3_2_DEI4, 0x2280), + INTC_VECT(DMAC3_2_DEI5, 0x22A0), + INTC_VECT(DMAC3_2_DADERR, 0x22C0), + INTC_VECT(SHWYSTAT_RT, 0x1300), + INTC_VECT(SHWYSTAT_HS, 0x1320), + INTC_VECT(SHWYSTAT_COM, 0x1340), + INTC_VECT(USBH_INT, 0x1540), + INTC_VECT(USBH_OHCI, 0x1560), + INTC_VECT(USBH_EHCI, 0x1580), + INTC_VECT(USBH_PME, 0x15A0), + INTC_VECT(USBH_BIND, 0x15C0), + INTC_VECT(RSPI_OVRF, 0x1780), + INTC_VECT(RSPI_SPTEF, 0x17A0), + INTC_VECT(RSPI_SPRF, 0x17C0), + INTC_VECT(SPU2_0, 0x1800), + INTC_VECT(SPU2_1, 0x1820), + INTC_VECT(FSI, 0x1840), + INTC_VECT(FMSI, 0x1860), + INTC_VECT(IPMMU, 0x1920), + INTC_VECT(AP_ARM_CTIIRQ, 0x1980), + INTC_VECT(AP_ARM_PMURQ, 0x19A0), + INTC_VECT(MFIS2, 0x1A00), + INTC_VECT(CPORTR2S, 0x1A20), + INTC_VECT(CMT14, 0x1A40), + INTC_VECT(CMT15, 0x1A60), + INTC_VECT(MMCIF_0, 0x1AA0), + INTC_VECT(MMCIF_1, 0x1AC0), + INTC_VECT(MMCIF_2, 0x1AE0), + INTC_VECT(SIM_ERI, 0x1C00), + INTC_VECT(SIM_RXI, 0x1C20), + INTC_VECT(SIM_TXI, 0x1C40), + INTC_VECT(SIM_TEI, 0x1C60), + INTC_VECT(STPRO_0, 0x1C80), + INTC_VECT(STPRO_1, 0x1CA0), + INTC_VECT(STPRO_2, 0x1CC0), + INTC_VECT(STPRO_3, 0x1CE0), + INTC_VECT(STPRO_4, 0x1D00), +}; + +static struct intc_group intca_groups[] __initdata = { + INTC_GROUP(DMAC1_1, + DMAC1_1_DEI0, DMAC1_1_DEI1, DMAC1_1_DEI2, DMAC1_1_DEI3), + INTC_GROUP(DMAC1_2, + DMAC1_2_DEI4, DMAC1_2_DEI5, DMAC1_2_DADERR), + INTC_GROUP(DMAC2_1, + DMAC2_1_DEI0, DMAC2_1_DEI1, DMAC2_1_DEI2, DMAC2_1_DEI3), + INTC_GROUP(DMAC2_2, + DMAC2_2_DEI4, DMAC2_2_DEI5, DMAC2_2_DADERR), + INTC_GROUP(DMAC3_1, + DMAC3_1_DEI0, DMAC3_1_DEI1, DMAC3_1_DEI2, DMAC3_1_DEI3), + INTC_GROUP(DMAC3_2, + DMAC3_2_DEI4, DMAC3_2_DEI5, DMAC3_2_DADERR), + INTC_GROUP(AP_ARM1, + AP_ARM_COMMTX, AP_ARM_COMMRX), + INTC_GROUP(AP_ARM2, + AP_ARM_CTIIRQ, AP_ARM_PMURQ), + INTC_GROUP(USBF, + USBF_OUL_SOF, USBF_IXL_INT), + INTC_GROUP(SDHI0, + SDHI0_0, SDHI0_1, SDHI0_2, SDHI0_3), + INTC_GROUP(SDHI1, + SDHI1_0, SDHI1_1, SDHI1_2, SDHI1_3), + INTC_GROUP(SDHI2, + SDHI2_0, SDHI2_1, SDHI2_2, SDHI2_3), + INTC_GROUP(SHWYSTAT, + SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM), + INTC_GROUP(USBH1, /* FIXME */ + USBH_INT, USBH_OHCI), + INTC_GROUP(USBH2, /* FIXME */ + USBH_EHCI, + USBH_PME, USBH_BIND), + INTC_GROUP(RSPI, + RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF), + INTC_GROUP(SPU2, + SPU2_0, SPU2_1), + INTC_GROUP(FLCTL, + FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I), + INTC_GROUP(IIC1, + IIC1_ALI, IIC1_TACKI, IIC1_WAITI, IIC1_DTEI), +}; + +static struct intc_mask_reg intca_mask_registers[] __initdata = { + { /* IMR0A / IMCR0A */ 0xe6940080, 0xe69400c0, 8, + { DMAC2_1_DEI3, DMAC2_1_DEI2, DMAC2_1_DEI1, DMAC2_1_DEI0, + 0, 0, AP_ARM_COMMTX, AP_ARM_COMMRX } }, + { /* IMR1A / IMCR1A */ 0xe6940084, 0xe69400c4, 8, + { ATAPI, 0, DIRC, 0, + DMAC1_1_DEI3, DMAC1_1_DEI2, DMAC1_1_DEI1, DMAC1_1_DEI0 } }, + { /* IMR2A / IMCR2A */ 0xe6940088, 0xe69400c8, 8, + { 0, 0, 0, 0, + BBIF1, BBIF2, MFIS, MFI } }, + { /* IMR3A / IMCR3A */ 0xe694008c, 0xe69400cc, 8, + { DMAC3_1_DEI3, DMAC3_1_DEI2, DMAC3_1_DEI1, DMAC3_1_DEI0, + DMAC3_2_DADERR, DMAC3_2_DEI5, DMAC3_2_DEI4, IRDA } }, + { /* IMR4A / IMCR4A */ 0xe6940090, 0xe69400d0, 8, + { DDM, 0, 0, 0, + 0, 0, 0, 0 } }, + { /* IMR5A / IMCR5A */ 0xe6940094, 0xe69400d4, 8, + { KEYSC, DMAC1_2_DADERR, DMAC1_2_DEI5, DMAC1_2_DEI4, + SCIFA3, SCIFA2, SCIFA1, SCIFA0 } }, + { /* IMR6A / IMCR6A */ 0xe6940098, 0xe69400d8, 8, + { SCIFB, SCIFA5, SCIFA4, MSIOF1, + 0, 0, MSIOF2, 0 } }, + { /* IMR7A / IMCR7A */ 0xe694009c, 0xe69400dc, 8, + { SDHI0_3, SDHI0_2, SDHI0_1, SDHI0_0, + FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } }, + { /* IMR8A / IMCR8A */ 0xe69400a0, 0xe69400e0, 8, + { SDHI1_3, SDHI1_2, SDHI1_1, SDHI1_0, + 0, USBHSDMAC, 0, AP_ARM_L2CINT } }, + { /* IMR9A / IMCR9A */ 0xe69400a4, 0xe69400e4, 8, + { CMT1_3, CMT1_2, CMT1_1, CMT1_0, + CMT2, USBF_IXL_INT, USBF_OUL_SOF, SGX540 } }, + { /* IMR10A / IMCR10A */ 0xe69400a8, 0xe69400e8, 8, + { 0, DMAC2_2_DADERR, DMAC2_2_DEI5, DMAC2_2_DEI4, + 0, 0, 0, 0 } }, + { /* IMR11A / IMCR11A */ 0xe69400ac, 0xe69400ec, 8, + { IIC1_DTEI, IIC1_WAITI, IIC1_TACKI, IIC1_ALI, + ICBS0, 0, 0, 0 } }, + { /* IMR12A / IMCR12A */ 0xe69400b0, 0xe69400f0, 8, + { 0, 0, TPU0, SCIFA6, + SCIFA7, GbEther, 0, 0 } }, + { /* IMR13A / IMCR13A */ 0xe69400b4, 0xe69400f4, 8, + { SDHI2_3, SDHI2_2, SDHI2_1, SDHI2_0, + 0, CMT3, 0, RWDT0 } }, + { /* IMR0A3 / IMCR0A3 */ 0xe6950080, 0xe69500c0, 8, + { SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM, 0, + 0, 0, 0, 0 } }, + /* IMR1A3 / IMCR1A3 */ + { /* IMR2A3 / IMCR2A3 */ 0xe6950088, 0xe69500c8, 8, + { 0, 0, USBH_INT, USBH_OHCI, + USBH_EHCI, USBH_PME, USBH_BIND, 0 } }, + /* IMR3A3 / IMCR3A3 */ + { /* IMR4A3 / IMCR4A3 */ 0xe6950090, 0xe69500d0, 8, + { 0, 0, 0, 0, + RSPI_OVRF, RSPI_SPTEF, RSPI_SPRF, 0 } }, + { /* IMR5A3 / IMCR5A3 */ 0xe6950094, 0xe69500d4, 8, + { SPU2_0, SPU2_1, FSI, FMSI, + 0, 0, 0, 0 } }, + { /* IMR6A3 / IMCR6A3 */ 0xe6950098, 0xe69500d8, 8, + { 0, IPMMU, 0, 0, + AP_ARM_CTIIRQ, AP_ARM_PMURQ, 0, 0 } }, + { /* IMR7A3 / IMCR7A3 */ 0xe695009c, 0xe69500dc, 8, + { MFIS2, CPORTR2S, CMT14, CMT15, + 0, MMCIF_0, MMCIF_1, MMCIF_2 } }, + /* IMR8A3 / IMCR8A3 */ + { /* IMR9A3 / IMCR9A3 */ 0xe69500a4, 0xe69500e4, 8, + { SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI, + STPRO_0, STPRO_1, STPRO_2, STPRO_3 } }, + { /* IMR10A3 / IMCR10A3 */ 0xe69500a8, 0xe69500e8, 8, + { STPRO_4, 0, 0, 0, + 0, 0, 0, 0 } }, +}; + +static struct intc_prio_reg intca_prio_registers[] __initdata = { + { 0xe6940000, 0, 16, 4, /* IPRAA */ { DMAC3_1, DMAC3_2, CMT2, ICBS0 } }, + { 0xe6940004, 0, 16, 4, /* IPRBA */ { IRDA, 0, BBIF1, BBIF2 } }, + { 0xe6940008, 0, 16, 4, /* IPRCA */ { ATAPI, 0, CMT1_1, AP_ARM1 } }, + { 0xe694000c, 0, 16, 4, /* IPRDA */ { 0, 0, CMT1_2, 0 } }, + { 0xe6940010, 0, 16, 4, /* IPREA */ { DMAC1_1, MFIS, MFI, USBF } }, + { 0xe6940014, 0, 16, 4, /* IPRFA */ { KEYSC, DMAC1_2, + SGX540, CMT1_0 } }, + { 0xe6940018, 0, 16, 4, /* IPRGA */ { SCIFA0, SCIFA1, + SCIFA2, SCIFA3 } }, + { 0xe694001c, 0, 16, 4, /* IPRGH */ { MSIOF2, USBHSDMAC, + FLCTL, SDHI0 } }, + { 0xe6940020, 0, 16, 4, /* IPRIA */ { MSIOF1, SCIFA4, 0, IIC1 } }, + { 0xe6940024, 0, 16, 4, /* IPRJA */ { DMAC2_1, DMAC2_2, + AP_ARM_L2CINT, 0 } }, + { 0xe6940028, 0, 16, 4, /* IPRKA */ { 0, CMT1_3, 0, SDHI1 } }, + { 0xe694002c, 0, 16, 4, /* IPRLA */ { TPU0, SCIFA6, + SCIFA7, GbEther } }, + { 0xe6940030, 0, 16, 4, /* IPRMA */ { 0, CMT3, 0, RWDT0 } }, + { 0xe6940034, 0, 16, 4, /* IPRNA */ { SCIFB, SCIFA5, 0, DDM } }, + { 0xe6940038, 0, 16, 4, /* IPROA */ { 0, 0, DIRC, SDHI2 } }, + { 0xe6950000, 0, 16, 4, /* IPRAA3 */ { SHWYSTAT, 0, 0, 0 } }, + /* IPRBA3 */ + /* IPRCA3 */ + /* IPRDA3 */ + { 0xe6950010, 0, 16, 4, /* IPREA3 */ { USBH1, 0, 0, 0 } }, + { 0xe6950014, 0, 16, 4, /* IPRFA3 */ { USBH2, 0, 0, 0 } }, + /* IPRGA3 */ + /* IPRHA3 */ + /* IPRIA3 */ + { 0xe6950024, 0, 16, 4, /* IPRJA3 */ { RSPI, 0, 0, 0 } }, + { 0xe6950028, 0, 16, 4, /* IPRKA3 */ { SPU2, 0, FSI, FMSI } }, + /* IPRLA3 */ + { 0xe6950030, 0, 16, 4, /* IPRMA3 */ { IPMMU, 0, 0, 0 } }, + { 0xe6950034, 0, 16, 4, /* IPRNA3 */ { AP_ARM2, 0, 0, 0 } }, + { 0xe6950038, 0, 16, 4, /* IPROA3 */ { MFIS2, CPORTR2S, + CMT14, CMT15 } }, + { 0xe695003c, 0, 16, 4, /* IPRPA3 */ { 0, MMCIF_0, MMCIF_1, MMCIF_2 } }, + /* IPRQA3 */ + /* IPRRA3 */ + { 0xe6950048, 0, 16, 4, /* IPRSA3 */ { SIM_ERI, SIM_RXI, + SIM_TXI, SIM_TEI } }, + { 0xe695004c, 0, 16, 4, /* IPRTA3 */ { STPRO_0, STPRO_1, + STPRO_2, STPRO_3 } }, + { 0xe6950050, 0, 16, 4, /* IPRUA3 */ { STPRO_4, 0, 0, 0 } }, +}; + +static DECLARE_INTC_DESC(intca_desc, "r8a7740-intca", + intca_vectors, intca_groups, + intca_mask_registers, intca_prio_registers, + NULL); + +INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000, + INTC_VECT, "r8a7740-intca-irq-pins"); + + +/* + * INTCS + */ +enum { + UNUSED_INTCS = 0, + + INTCS, + + /* interrupt sources INTCS */ + + /* HUDI */ + /* STPRO */ + /* RTDMAC(1) */ + VPU5HA2, + _2DG_TRAP, _2DG_GPM_INT, _2DG_CER_INT, + /* MFI */ + /* BBIF2 */ + VPU5F, + _2DG_BRK_INT, + /* SGX540 */ + /* 2DDMAC */ + /* IPMMU */ + /* RTDMAC 2 */ + /* KEYSC */ + /* MSIOF */ + IIC0_ALI, IIC0_TACKI, IIC0_WAITI, IIC0_DTEI, + TMU0_0, TMU0_1, TMU0_2, + CMT0, + /* CMT2 */ + LMB, + CTI, + VOU, + /* RWDT0 */ + ICB, + VIO6C, + CEU20, CEU21, + JPU, + LCDC0, + LCRC, + /* RTDMAC2(1) */ + /* RTDMAC2(2) */ + LCDC1, + /* SPU2 */ + /* FSI */ + /* FMSI */ + TMU1_0, TMU1_1, TMU1_2, + CMT4, + DISP, + DSRV, + /* MFIS2 */ + CPORTS2R, + + /* interrupt groups INTCS */ + _2DG1, + IIC0, TMU1, +}; + +static struct intc_vect intcs_vectors[] = { + /* HUDI */ + /* STPRO */ + /* RTDMAC(1) */ + INTCS_VECT(VPU5HA2, 0x0880), + INTCS_VECT(_2DG_TRAP, 0x08A0), + INTCS_VECT(_2DG_GPM_INT, 0x08C0), + INTCS_VECT(_2DG_CER_INT, 0x08E0), + /* MFI */ + /* BBIF2 */ + INTCS_VECT(VPU5F, 0x0980), + INTCS_VECT(_2DG_BRK_INT, 0x09A0), + /* SGX540 */ + /* 2DDMAC */ + /* IPMMU */ + /* RTDMAC(2) */ + /* KEYSC */ + /* MSIOF */ + INTCS_VECT(IIC0_ALI, 0x0E00), + INTCS_VECT(IIC0_TACKI, 0x0E20), + INTCS_VECT(IIC0_WAITI, 0x0E40), + INTCS_VECT(IIC0_DTEI, 0x0E60), + INTCS_VECT(TMU0_0, 0x0E80), + INTCS_VECT(TMU0_1, 0x0EA0), + INTCS_VECT(TMU0_2, 0x0EC0), + INTCS_VECT(CMT0, 0x0F00), + /* CMT2 */ + INTCS_VECT(LMB, 0x0F60), + INTCS_VECT(CTI, 0x0400), + INTCS_VECT(VOU, 0x0420), + /* RWDT0 */ + INTCS_VECT(ICB, 0x0480), + INTCS_VECT(VIO6C, 0x04E0), + INTCS_VECT(CEU20, 0x0500), + INTCS_VECT(CEU21, 0x0520), + INTCS_VECT(JPU, 0x0560), + INTCS_VECT(LCDC0, 0x0580), + INTCS_VECT(LCRC, 0x05A0), + /* RTDMAC2(1) */ + /* RTDMAC2(2) */ + INTCS_VECT(LCDC1, 0x1780), + /* SPU2 */ + /* FSI */ + /* FMSI */ + INTCS_VECT(TMU1_0, 0x1900), + INTCS_VECT(TMU1_1, 0x1920), + INTCS_VECT(TMU1_2, 0x1940), + INTCS_VECT(CMT4, 0x1980), + INTCS_VECT(DISP, 0x19A0), + INTCS_VECT(DSRV, 0x19C0), + /* MFIS2 */ + INTCS_VECT(CPORTS2R, 0x1A20), + + INTC_VECT(INTCS, 0xf80), +}; -static int r8a7740_set_wake(struct irq_data *data, unsigned int on) +static struct intc_group intcs_groups[] __initdata = { + INTC_GROUP(_2DG1, /*FIXME*/ + _2DG_CER_INT, _2DG_GPM_INT, _2DG_TRAP), + INTC_GROUP(IIC0, + IIC0_DTEI, IIC0_WAITI, IIC0_TACKI, IIC0_ALI), + INTC_GROUP(TMU1, + TMU1_0, TMU1_1, TMU1_2), +}; + +static struct intc_mask_reg intcs_mask_registers[] = { + /* IMR0SA / IMCR0SA */ /* all 0 */ + { /* IMR1SA / IMCR1SA */ 0xffd20184, 0xffd201c4, 8, + { _2DG_CER_INT, _2DG_GPM_INT, _2DG_TRAP, VPU5HA2, + 0, 0, 0, 0 /*STPRO*/ } }, + { /* IMR2SA / IMCR2SA */ 0xffd20188, 0xffd201c8, 8, + { 0/*STPRO*/, 0, CEU21, VPU5F, + 0/*BBIF2*/, 0, 0, 0/*MFI*/ } }, + { /* IMR3SA / IMCR3SA */ 0xffd2018c, 0xffd201cc, 8, + { 0, 0, 0, 0, /*2DDMAC*/ + VIO6C, 0, 0, ICB } }, + { /* IMR4SA / IMCR4SA */ 0xffd20190, 0xffd201d0, 8, + { 0, 0, VOU, CTI, + JPU, 0, LCRC, LCDC0 } }, + /* IMR5SA / IMCR5SA */ /*KEYSC/RTDMAC2/RTDMAC1*/ + /* IMR6SA / IMCR6SA */ /*MSIOF/SGX540*/ + { /* IMR7SA / IMCR7SA */ 0xffd2019c, 0xffd201dc, 8, + { 0, TMU0_2, TMU0_1, TMU0_0, + 0, 0, 0, 0 } }, + { /* IMR8SA / IMCR8SA */ 0xffd201a0, 0xffd201e0, 8, + { 0, 0, 0, 0, + CEU20, 0, 0, 0 } }, + { /* IMR9SA / IMCR9SA */ 0xffd201a4, 0xffd201e4, 8, + { 0, 0/*RWDT0*/, 0/*CMT2*/, CMT0, + 0, 0, 0, 0 } }, + /* IMR10SA / IMCR10SA */ /*IPMMU*/ + { /* IMR11SA / IMCR11SA */ 0xffd201ac, 0xffd201ec, 8, + { IIC0_DTEI, IIC0_WAITI, IIC0_TACKI, IIC0_ALI, + 0, _2DG_BRK_INT, LMB, 0 } }, + /* IMR12SA / IMCR12SA */ + /* IMR13SA / IMCR13SA */ + /* IMR0SA3 / IMCR0SA3 */ /*RTDMAC2(1)/RTDMAC2(2)*/ + /* IMR1SA3 / IMCR1SA3 */ + /* IMR2SA3 / IMCR2SA3 */ + /* IMR3SA3 / IMCR3SA3 */ + { /* IMR4SA3 / IMCR4SA3 */ 0xffd50190, 0xffd501d0, 8, + { 0, 0, 0, 0, + LCDC1, 0, 0, 0 } }, + /* IMR5SA3 / IMCR5SA3 */ /* SPU2/FSI/FMSI */ + { /* IMR6SA3 / IMCR6SA3 */ 0xffd50198, 0xffd501d8, 8, + { TMU1_0, TMU1_1, TMU1_2, 0, + CMT4, DISP, DSRV, 0 } }, + { /* IMR7SA3 / IMCR7SA3 */ 0xffd5019c, 0xffd501dc, 8, + { 0/*MFIS2*/, CPORTS2R, 0, 0, + 0, 0, 0, 0 } }, + { /* INTAMASK */ 0xffd20104, 0, 16, + { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, INTCS } }, +}; + +/* Priority is needed for INTCA to receive the INTCS interrupt */ +static struct intc_prio_reg intcs_prio_registers[] = { + { 0xffd20000, 0, 16, 4, /* IPRAS */ { CTI, VOU, 0/*2DDMAC*/, ICB } }, + { 0xffd20004, 0, 16, 4, /* IPRBS */ { JPU, LCDC0, 0, LCRC } }, + /* IPRCS */ /*BBIF2*/ + /* IPRDS */ + { 0xffd20010, 0, 16, 4, /* IPRES */ { 0/*RTDMAC(1)*/, VPU5HA2, + 0/*MFI*/, VPU5F } }, + { 0xffd20014, 0, 16, 4, /* IPRFS */ { 0/*KEYSC*/, 0/*RTDMAC(2)*/, + 0/*CMT2*/, CMT0 } }, + { 0xffd20018, 0, 16, 4, /* IPRGS */ { TMU0_0, TMU0_1, + TMU0_2, _2DG1 } }, + { 0xffd2001c, 0, 16, 4, /* IPRHS */ { 0, 0/*STPRO*/, 0/*STPRO*/, + _2DG_BRK_INT/*FIXME*/ } }, + { 0xffd20020, 0, 16, 4, /* IPRIS */ { 0, 0/*MSIOF*/, 0, IIC0 } }, + { 0xffd20024, 0, 16, 4, /* IPRJS */ { CEU20, 0/*SGX540*/, 0, 0 } }, + { 0xffd20028, 0, 16, 4, /* IPRKS */ { VIO6C, 0, LMB, 0 } }, + { 0xffd2002c, 0, 16, 4, /* IPRLS */ { 0/*IPMMU*/, 0, CEU21, 0 } }, + /* IPRMS */ /*RWDT0*/ + /* IPRAS3 */ /*RTDMAC2(1)*/ + /* IPRBS3 */ /*RTDMAC2(2)*/ + /* IPRCS3 */ + /* IPRDS3 */ + /* IPRES3 */ + /* IPRFS3 */ + /* IPRGS3 */ + /* IPRHS3 */ + /* IPRIS3 */ + { 0xffd50024, 0, 16, 4, /* IPRJS3 */ { LCDC1, 0, 0, 0 } }, + /* IPRKS3 */ /*SPU2/FSI/FMSi*/ + /* IPRLS3 */ + { 0xffd50030, 0, 16, 4, /* IPRMS3 */ { TMU1, 0, 0, 0 } }, + { 0xffd50034, 0, 16, 4, /* IPRNS3 */ { CMT4, DISP, DSRV, 0 } }, + { 0xffd50038, 0, 16, 4, /* IPROS3 */ { 0/*MFIS2*/, CPORTS2R, 0, 0 } }, + /* IPRPS3 */ +}; + +static struct resource intcs_resources[] __initdata = { + [0] = { + .start = 0xffd20000, + .end = 0xffd201ff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0xffd50000, + .end = 0xffd501ff, + .flags = IORESOURCE_MEM, + } +}; + +static struct intc_desc intcs_desc __initdata = { + .name = "r8a7740-intcs", + .resource = intcs_resources, + .num_resources = ARRAY_SIZE(intcs_resources), + .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers, + intcs_prio_registers, NULL, NULL), +}; + +static void intcs_demux(unsigned int irq, struct irq_desc *desc) { - return 0; /* always allow wakeup */ + void __iomem *reg = (void *)irq_get_handler_data(irq); + unsigned int evtcodeas = ioread32(reg); + + generic_handle_irq(intcs_evt2irq(evtcodeas)); } void __init r8a7740_init_irq(void) { - void __iomem *gic_dist_base = __io(0xf0001000); - void __iomem *gic_cpu_base = __io(0xf0000000); + void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE); - /* - * Change INT_SEL INTCA->GIC - * (on GPIO) - */ - __raw_writel(__raw_readl(INTA_CTRL) & ~(1 << 1), INTA_CTRL); + register_intc_controller(&intca_desc); + register_intc_controller(&intca_irq_pins_desc); + register_intc_controller(&intcs_desc); - gic_init(0, 29, gic_dist_base, gic_cpu_base); - gic_arch_extn.irq_set_wake = r8a7740_set_wake; + /* demux using INTEVTSA */ + irq_set_handler_data(evt2irq(0xf80), (void *)intevtsa); + irq_set_chained_handler(evt2irq(0xf80), intcs_demux); } diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index e16860f04934..986dca6b3fad 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -35,7 +35,7 @@ static struct plat_sci_port scif0_platform_data = { .scscr = SCSCR_RE | SCSCR_TE, .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIFA, - .irqs = SCIx_IRQ_MUXED(gic_spi(100)), + .irqs = SCIx_IRQ_MUXED(evt2irq(0x0c00)), }; static struct platform_device scif0_device = { @@ -53,7 +53,7 @@ static struct plat_sci_port scif1_platform_data = { .scscr = SCSCR_RE | SCSCR_TE, .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIFA, - .irqs = SCIx_IRQ_MUXED(gic_spi(101)), + .irqs = SCIx_IRQ_MUXED(evt2irq(0x0c20)), }; static struct platform_device scif1_device = { @@ -71,7 +71,7 @@ static struct plat_sci_port scif2_platform_data = { .scscr = SCSCR_RE | SCSCR_TE, .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIFA, - .irqs = SCIx_IRQ_MUXED(gic_spi(102)), + .irqs = SCIx_IRQ_MUXED(evt2irq(0x0c40)), }; static struct platform_device scif2_device = { @@ -89,7 +89,7 @@ static struct plat_sci_port scif3_platform_data = { .scscr = SCSCR_RE | SCSCR_TE, .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIFA, - .irqs = SCIx_IRQ_MUXED(gic_spi(103)), + .irqs = SCIx_IRQ_MUXED(evt2irq(0x0c60)), }; static struct platform_device scif3_device = { @@ -107,7 +107,7 @@ static struct plat_sci_port scif4_platform_data = { .scscr = SCSCR_RE | SCSCR_TE, .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIFA, - .irqs = SCIx_IRQ_MUXED(gic_spi(104)), + .irqs = SCIx_IRQ_MUXED(evt2irq(0x0d20)), }; static struct platform_device scif4_device = { @@ -125,7 +125,7 @@ static struct plat_sci_port scif5_platform_data = { .scscr = SCSCR_RE | SCSCR_TE, .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIFA, - .irqs = SCIx_IRQ_MUXED(gic_spi(105)), + .irqs = SCIx_IRQ_MUXED(evt2irq(0x0d40)), }; static struct platform_device scif5_device = { @@ -143,7 +143,7 @@ static struct plat_sci_port scif6_platform_data = { .scscr = SCSCR_RE | SCSCR_TE, .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIFA, - .irqs = SCIx_IRQ_MUXED(gic_spi(106)), + .irqs = SCIx_IRQ_MUXED(evt2irq(0x04c0)), }; static struct platform_device scif6_device = { @@ -161,7 +161,7 @@ static struct plat_sci_port scif7_platform_data = { .scscr = SCSCR_RE | SCSCR_TE, .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIFA, - .irqs = SCIx_IRQ_MUXED(gic_spi(107)), + .irqs = SCIx_IRQ_MUXED(evt2irq(0x04e0)), }; static struct platform_device scif7_device = { @@ -179,7 +179,7 @@ static struct plat_sci_port scifb_platform_data = { .scscr = SCSCR_RE | SCSCR_TE, .scbrr_algo_id = SCBRR_ALGO_4, .type = PORT_SCIFB, - .irqs = SCIx_IRQ_MUXED(gic_spi(108)), + .irqs = SCIx_IRQ_MUXED(evt2irq(0x0d60)), }; static struct platform_device scifb_device = { @@ -207,7 +207,7 @@ static struct resource cmt10_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = gic_spi(58), + .start = evt2irq(0x0b00), .flags = IORESOURCE_IRQ, }, }; @@ -244,8 +244,8 @@ static struct resource i2c0_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = gic_spi(201), - .end = gic_spi(204), + .start = intcs_evt2irq(0xe00), + .end = intcs_evt2irq(0xe60), .flags = IORESOURCE_IRQ, }, }; @@ -258,8 +258,8 @@ static struct resource i2c1_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = gic_spi(70), - .end = gic_spi(73), + .start = evt2irq(0x780), /* IIC1_ALI1 */ + .end = evt2irq(0x7e0), /* IIC1_DTEI1 */ .flags = IORESOURCE_IRQ, }, }; -- cgit v1.2.3 From d55c9a97f80a7ad64f7c7eab5fb447a8d9a1532a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 10 Nov 2011 18:46:45 -0800 Subject: ARM: mach-shmobile: add bonito board support. This adds basic bonito board (R-Mobile A1) support Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/configs/bonito_defconfig | 72 +++++++++++++ arch/arm/mach-shmobile/Kconfig | 9 +- arch/arm/mach-shmobile/Makefile | 1 + arch/arm/mach-shmobile/board-bonito.c | 187 ++++++++++++++++++++++++++++++++++ 4 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 arch/arm/configs/bonito_defconfig create mode 100644 arch/arm/mach-shmobile/board-bonito.c (limited to 'arch') diff --git a/arch/arm/configs/bonito_defconfig b/arch/arm/configs/bonito_defconfig new file mode 100644 index 000000000000..635bd6994561 --- /dev/null +++ b/arch/arm/configs/bonito_defconfig @@ -0,0 +1,72 @@ +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=16 +# CONFIG_UTS_NS is not set +# CONFIG_IPC_NS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="/your/initramfs/" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_SHMOBILE=y +CONFIG_ARCH_R8A7740=y +CONFIG_MACH_BONITO=y +# CONFIG_SH_TIMER_TMU is not set +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +CONFIG_FORCE_MAX_ZONEORDER=12 +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttySC5,115200 earlyprintk=sh-sci.5,115200 ignore_loglevel" +CONFIG_KEXEC=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_SUSPEND is not set +CONFIG_PM_RUNTIME=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_FIRMWARE_IN_KERNEL is not set +CONFIG_MTD=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_ARM_INTEGRATOR=y +CONFIG_MTD_BLOCK2MTD=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=9 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_SH_MOBILE=y +CONFIG_GPIO_SYSFS=y +# CONFIG_HWMON is not set +# CONFIG_MFD_SUPPORT is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_UIO=y +CONFIG_UIO_PDRV=y +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY_USER is not set +CONFIG_TMPFS=y +# CONFIG_MISC_FILESYSTEMS is not set +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +# CONFIG_ARM_UNWIND is not set diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index aa63c968f420..ef0077e8771e 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -81,6 +81,11 @@ config MACH_KOTA2 select ARCH_REQUIRE_GPIOLIB depends on ARCH_SH73A0 +config MACH_BONITO + bool "bonito board" + select ARCH_REQUIRE_GPIOLIB + depends on ARCH_R8A7740 + comment "SH-Mobile System Configuration" menu "Memory configuration" @@ -89,7 +94,7 @@ config MEMORY_START hex "Physical memory start address" default "0x50000000" if MACH_G3EVM default "0x40000000" if MACH_G4EVM || MACH_AP4EVB || MACH_AG5EVM || \ - MACH_MACKEREL + MACH_MACKEREL || MACH_BONITO default "0x41000000" if MACH_KOTA2 default "0x00000000" ---help--- @@ -101,7 +106,7 @@ config MEMORY_SIZE hex "Physical memory size" default "0x08000000" if MACH_G3EVM default "0x08000000" if MACH_G4EVM - default "0x20000000" if MACH_AG5EVM + default "0x20000000" if MACH_AG5EVM || MACH_BONITO default "0x1e000000" if MACH_KOTA2 default "0x10000000" if MACH_AP4EVB || MACH_MACKEREL default "0x04000000" diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 971f7038f05a..abdae89cacf7 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_MACH_AP4EVB) += board-ap4evb.o obj-$(CONFIG_MACH_AG5EVM) += board-ag5evm.o obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o obj-$(CONFIG_MACH_KOTA2) += board-kota2.o +obj-$(CONFIG_MACH_BONITO) += board-bonito.o # Framework support obj-$(CONFIG_SMP) += $(smp-y) diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c new file mode 100644 index 000000000000..901d7457973a --- /dev/null +++ b/arch/arm/mach-shmobile/board-bonito.c @@ -0,0 +1,187 @@ +/* + * bonito board support + * + * Copyright (C) 2011 Renesas Solutions Corp. + * Copyright (C) 2011 Kuninori Morimoto + * + * 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; version 2 of the License. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * CS Address device note + *---------------------------------------------------------------- + * 0 0x0000_0000 NOR Flash (64MB) SW12 : bit3 = OFF + * 2 0x0800_0000 ExtNOR (64MB) SW12 : bit3 = OFF + * 4 - + * 5A - + * 5B 0x1600_0000 SRAM (8MB) + * 6 0x1800_0000 FPGA (64K) + * 0x1801_0000 Ether (4KB) + * 0x1801_1000 USB (4KB) + */ + +/* + * SW12 + * + * bit1 bit2 bit3 + *---------------------------------------------------------------------------- + * ON NOR WriteProtect NAND WriteProtect CS0 ExtNOR / CS2 NOR + * OFF NOR Not WriteProtect NAND Not WriteProtect CS0 NOR / CS2 ExtNOR + */ + +/* + * FPGA + */ +#define A1MDSR 0x10E0 +#define BVERR 0x1100 +static u16 bonito_fpga_read(u32 offset) +{ + return __raw_readw(0xf0003000 + offset); +} + +static void bonito_fpga_write(u32 offset, u16 val) +{ + __raw_writew(val, 0xf0003000 + offset); +} + +/* + * devices + */ +static struct platform_device *bonito_devices[] __initdata = { +}; + +/* + * map I/O + */ +static struct map_desc bonito_io_desc[] __initdata = { + /* + * for CPGA/INTC/PFC + * 0xe6000000-0xefffffff -> 0xe6000000-0xefffffff + */ + { + .virtual = 0xe6000000, + .pfn = __phys_to_pfn(0xe6000000), + .length = 160 << 20, + .type = MT_DEVICE_NONSHARED + }, +#ifdef CONFIG_CACHE_L2X0 + /* + * for l2x0_init() + * 0xf0100000-0xf0101000 -> 0xf0002000-0xf0003000 + */ + { + .virtual = 0xf0002000, + .pfn = __phys_to_pfn(0xf0100000), + .length = PAGE_SIZE, + .type = MT_DEVICE_NONSHARED + }, +#endif + /* + * for FPGA (0x1800000-0x19ffffff) + * 0x18000000-0x18002000 -> 0xf0003000-0xf0005000 + */ + { + .virtual = 0xf0003000, + .pfn = __phys_to_pfn(0x18000000), + .length = PAGE_SIZE * 2, + .type = MT_DEVICE_NONSHARED + } +}; + +static void __init bonito_map_io(void) +{ + iotable_init(bonito_io_desc, ARRAY_SIZE(bonito_io_desc)); + + /* setup early devices and console here as well */ + r8a7740_add_early_devices(); + shmobile_setup_console(); +} + +/* + * board init + */ +static void __init bonito_init(void) +{ + u16 val; + + r8a7740_pinmux_init(); + + /* FPGA */ + gpio_request(GPIO_FN_CS5B, NULL); + gpio_request(GPIO_FN_CS6A, NULL); + gpio_request(GPIO_FN_CS5A_PORT105, NULL); + gpio_request(GPIO_FN_IRQ10, NULL); + + val = bonito_fpga_read(BVERR); + pr_info("bonito version: cpu %02x, base %02x\n", + ((val >> 8) & 0xFF), + ((val >> 0) & 0xFF)); + + /* SCIFA5 */ + gpio_request(GPIO_FN_SCIFA5_TXD_PORT91, NULL); + gpio_request(GPIO_FN_SCIFA5_RXD_PORT92, NULL); + +#ifdef CONFIG_CACHE_L2X0 + /* Early BRESP enable, Shared attribute override enable, 32K*8way */ + l2x0_init(__io(0xf0002000), 0x40440000, 0x82000fff); +#endif + + r8a7740_add_standard_devices(); + platform_add_devices(bonito_devices, ARRAY_SIZE(bonito_devices)); +} + +static void __init bonito_timer_init(void) +{ + u16 val; + u8 md_ck = 0; + + /* read MD_CK value */ + val = bonito_fpga_read(A1MDSR); + if (val & (1 << 10)) + md_ck |= MD_CK2; + if (val & (1 << 9)) + md_ck |= MD_CK1; + if (val & (1 << 8)) + md_ck |= MD_CK0; + + r8a7740_clock_init(md_ck); + shmobile_timer.init(); +} + +struct sys_timer bonito_timer = { + .init = bonito_timer_init, +}; + +MACHINE_START(BONITO, "bonito") + .map_io = bonito_map_io, + .init_irq = r8a7740_init_irq, + .handle_irq = shmobile_handle_irq_intc, + .init_machine = bonito_init, + .timer = &bonito_timer, +MACHINE_END -- cgit v1.2.3 From b6b37e250558a8348ba9a22ba27376d22bca2c5c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 10 Nov 2011 18:46:56 -0800 Subject: ARM: mach-shmobile: bonito: Add dip-switch selector devices enable/disable are controled by dip-switch on bonito board. If bonito core board is connected to base board, you can check the settings from FPGA. This patch adds basic code and controls SCIFA5 settings Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-bonito.c | 88 ++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 17 deletions(-) (limited to 'arch') diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c index 901d7457973a..efaa5feb39b8 100644 --- a/arch/arm/mach-shmobile/board-bonito.c +++ b/arch/arm/mach-shmobile/board-bonito.c @@ -55,9 +55,22 @@ * OFF NOR Not WriteProtect NAND Not WriteProtect CS0 NOR / CS2 ExtNOR */ +/* + * SCIFA5 (CN42) + * + * S38.3 = ON + * S39.6 = ON + * S43.1 = ON + */ + /* * FPGA */ +#define BUSSWMR1 0x0070 +#define BUSSWMR2 0x0072 +#define BUSSWMR3 0x0074 +#define BUSSWMR4 0x0076 + #define A1MDSR 0x10E0 #define BVERR 0x1100 static u16 bonito_fpga_read(u32 offset) @@ -71,9 +84,15 @@ static void bonito_fpga_write(u32 offset, u16 val) } /* - * devices + * core board devices */ -static struct platform_device *bonito_devices[] __initdata = { +static struct platform_device *bonito_core_devices[] __initdata = { +}; + +/* + * base board devices + */ +static struct platform_device *bonito_base_devices[] __initdata = { }; /* @@ -126,26 +145,18 @@ static void __init bonito_map_io(void) /* * board init */ +#define BIT_ON(sw, bit) (sw & (1 << bit)) +#define BIT_OFF(sw, bit) (!(sw & (1 << bit))) + static void __init bonito_init(void) { u16 val; r8a7740_pinmux_init(); - /* FPGA */ - gpio_request(GPIO_FN_CS5B, NULL); - gpio_request(GPIO_FN_CS6A, NULL); - gpio_request(GPIO_FN_CS5A_PORT105, NULL); - gpio_request(GPIO_FN_IRQ10, NULL); - - val = bonito_fpga_read(BVERR); - pr_info("bonito version: cpu %02x, base %02x\n", - ((val >> 8) & 0xFF), - ((val >> 0) & 0xFF)); - - /* SCIFA5 */ - gpio_request(GPIO_FN_SCIFA5_TXD_PORT91, NULL); - gpio_request(GPIO_FN_SCIFA5_RXD_PORT92, NULL); + /* + * core board settings + */ #ifdef CONFIG_CACHE_L2X0 /* Early BRESP enable, Shared attribute override enable, 32K*8way */ @@ -153,7 +164,50 @@ static void __init bonito_init(void) #endif r8a7740_add_standard_devices(); - platform_add_devices(bonito_devices, ARRAY_SIZE(bonito_devices)); + + platform_add_devices(bonito_core_devices, + ARRAY_SIZE(bonito_core_devices)); + + /* + * base board settings + */ + gpio_request(GPIO_PORT176, NULL); + gpio_direction_input(GPIO_PORT176); + if (!gpio_get_value(GPIO_PORT176)) { + u16 bsw2; + u16 bsw3; + u16 bsw4; + + /* + * FPGA + */ + gpio_request(GPIO_FN_CS5B, NULL); + gpio_request(GPIO_FN_CS6A, NULL); + gpio_request(GPIO_FN_CS5A_PORT105, NULL); + gpio_request(GPIO_FN_IRQ10, NULL); + + val = bonito_fpga_read(BVERR); + pr_info("bonito version: cpu %02x, base %02x\n", + ((val >> 8) & 0xFF), + ((val >> 0) & 0xFF)); + + bsw2 = bonito_fpga_read(BUSSWMR2); + bsw3 = bonito_fpga_read(BUSSWMR3); + bsw4 = bonito_fpga_read(BUSSWMR4); + + /* + * SCIFA5 (CN42) + */ + if (BIT_OFF(bsw2, 1) && /* S38.3 = ON */ + BIT_OFF(bsw3, 9) && /* S39.6 = ON */ + BIT_OFF(bsw4, 4)) { /* S43.1 = ON */ + gpio_request(GPIO_FN_SCIFA5_TXD_PORT91, NULL); + gpio_request(GPIO_FN_SCIFA5_RXD_PORT92, NULL); + } + + platform_add_devices(bonito_base_devices, + ARRAY_SIZE(bonito_base_devices)); + } } static void __init bonito_timer_init(void) -- cgit v1.2.3 From e609b7cb7ab18cf75d4bdd931a33e3caed6cd9e2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 10 Nov 2011 18:47:07 -0800 Subject: ARM: mach-shmobile: bonito: add PMIC settings bonito board needs some settings by pmic which use i2c access. It is dependent on the device to be used. This patch adds standard settings. Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-bonito.c | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'arch') diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c index efaa5feb39b8..d78008bbdf70 100644 --- a/arch/arm/mach-shmobile/board-bonito.c +++ b/arch/arm/mach-shmobile/board-bonito.c @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -83,6 +84,56 @@ static void bonito_fpga_write(u32 offset, u16 val) __raw_writew(val, 0xf0003000 + offset); } +/* +* PMIC settings +* +* FIXME +* +* bonito board needs some settings by pmic which use i2c access. +* pmic settings use device_initcall() here for use it. +*/ +static __u8 *pmic_settings = NULL; +static __u8 pmic_do_2A[] = { + 0x1C, 0x09, + 0x1A, 0x80, + 0xff, 0xff, +}; + +static int __init pmic_init(void) +{ + struct i2c_adapter *a = i2c_get_adapter(0); + struct i2c_msg msg; + __u8 buf[2]; + int i, ret; + + if (!pmic_settings) + return 0; + if (!a) + return 0; + + msg.addr = 0x46; + msg.buf = buf; + msg.len = 2; + msg.flags = 0; + + for (i = 0; ; i += 2) { + buf[0] = pmic_settings[i + 0]; + buf[1] = pmic_settings[i + 1]; + + if ((0xff == buf[0]) && (0xff == buf[1])) + break; + + ret = i2c_transfer(a, &msg, 1); + if (ret < 0) { + pr_err("i2c transfer fail\n"); + break; + } + } + + return 0; +} +device_initcall(pmic_init); + /* * core board devices */ @@ -154,6 +205,8 @@ static void __init bonito_init(void) r8a7740_pinmux_init(); + pmic_settings = pmic_do_2A; + /* * core board settings */ -- cgit v1.2.3 From 665ccfa0904cc0a05aa882d193f9506081824d7c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 10 Nov 2011 18:47:16 -0800 Subject: ARM: mach-shmobile: bonito: Add LCDC0 support Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-bonito.c | 117 +++++++++++++++++++++++++++++++++ arch/arm/mach-shmobile/clock-r8a7740.c | 6 +- 2 files changed, 122 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c index d78008bbdf70..5b014764e2a5 100644 --- a/arch/arm/mach-shmobile/board-bonito.c +++ b/arch/arm/mach-shmobile/board-bonito.c @@ -33,6 +33,7 @@ #include #include #include +#include