From 43f399db72ca82f186ce7040fc39794b102c263f Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sat, 8 Mar 2014 19:06:59 +0100 Subject: some work on qemu with graphic --- target/config/Config.in | 1 + target/config/Config.in.runtime | 4 ++-- target/x86/Makefile | 6 +++--- target/x86_64/Makefile | 6 +++--- target/x86_64/sys-available/shuttle-sa76 | 16 ---------------- target/x86_64/sys-available/tarox-pc | 15 --------------- 6 files changed, 9 insertions(+), 39 deletions(-) delete mode 100644 target/x86_64/sys-available/shuttle-sa76 delete mode 100644 target/x86_64/sys-available/tarox-pc diff --git a/target/config/Config.in b/target/config/Config.in index 5c5f1b6fd..d6e795712 100644 --- a/target/config/Config.in +++ b/target/config/Config.in @@ -619,6 +619,7 @@ config ADK_TARGET_CMDLINE default "console=ttyS0,115200 console=tty0" if ADK_TARGET_SYSTEM_IBM_X40 default "console=ttyS0,115200 console=tty0" if ADK_TARGET_SYSTEM_INTEL_ATOM default "console=ttyS0,115200 console=tty0" if ADK_TARGET_SYSTEM_QEMU_I686 + default "console=ttyS0,115200 console=tty0" if ADK_TARGET_SYSTEM_QEMU_X86_64 default "console=ttyS0,115200 console=tty0" if ADK_TARGET_SYSTEM_QEMU_SPARC64 default "console=ttyS0,9600 console=tty0" if ADK_TARGET_SYSTEM_QEMU_PPC default "console=hvc0 console=tty0" if ADK_TARGET_SYSTEM_QEMU_PPC64 diff --git a/target/config/Config.in.runtime b/target/config/Config.in.runtime index 03cecfca1..3634564ed 100644 --- a/target/config/Config.in.runtime +++ b/target/config/Config.in.runtime @@ -38,8 +38,8 @@ config ADK_RUNTIME_TIMEZONE choice prompt "Console output on embedded system" -default ADK_RUNTIME_CONSOLE_BOTH if ADK_TARGET_WITH_VGA && !ADK_TARGET_SYSTEM_RASPBERRY_PI && !ADK_TARGET_SYSTEM_QEMU_SH4 && !ADK_TARGET_SYSTEM_QEMU_SH4EB && !ADK_TARGET_SYSTEM_LEMOTE_YEELONG && ADK_TARGET_QEMU_WITH_GRAPHIC -default ADK_RUNTIME_CONSOLE_VGA if ADK_TARGET_SYSTEM_RASPBERRY_PI || ADK_TARGET_SYSTEM_QEMU_SH4 || ADK_TARGET_SYSTEM_QEMU_SH4EB || ADK_TARGET_SYSTEM_LEMOTE_YEELONG +default ADK_RUNTIME_CONSOLE_BOTH if ADK_TARGET_WITH_VGA || ADK_TARGET_QEMU_WITH_GRAPHIC && !ADK_TARGET_SYSTEM_RASPBERRY_PI && !ADK_TARGET_SYSTEM_LEMOTE_YEELONG +default ADK_RUNTIME_CONSOLE_VGA if ADK_TARGET_SYSTEM_RASPBERRY_PI || ADK_TARGET_SYSTEM_LEMOTE_YEELONG default ADK_RUNTIME_CONSOLE_SERIAL config ADK_RUNTIME_CONSOLE_VGA diff --git a/target/x86/Makefile b/target/x86/Makefile index f55c97e47..91c9cef17 100644 --- a/target/x86/Makefile +++ b/target/x86/Makefile @@ -34,7 +34,7 @@ ifeq ($(ADK_HARDWARE_QEMU),y) @echo "Use following command to create a QEMU Image:" @echo "./scripts/create.sh qemu-${CPU_ARCH}.img $(FW_DIR)/$(ROOTFSTARBALL)" @echo "Start qemu with following command line:" - @echo 'qemu-system-i386 -nographic -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL) qemu-${CPU_ARCH}.img' + @echo 'qemu-system-i386 ${ADK_QEMU_ARGS} -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL) qemu-${CPU_ARCH}.img' endif ifeq ($(ADK_HARDWARE_VBOX),y) @cp $(KERNEL) $(FW_DIR)/$(TARGET_KERNEL) @@ -54,7 +54,7 @@ imageinstall: $(FW_DIR)/$(INITRAMFS) @echo 'The initramfs image is: ${FW_DIR}/${INITRAMFS}' ifeq ($(ADK_HARDWARE_QEMU),y) @echo "Start qemu with following command line:" - @echo 'qemu-system-i386 -nographic -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL) -initrd ${FW_DIR}/${INITRAMFS}' + @echo 'qemu-system-i386 ${ADK_QEMU_ARGS} -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL) -initrd ${FW_DIR}/${INITRAMFS}' endif endif ifeq ($(ADK_TARGET_FS),initramfs-piggyback) @@ -63,7 +63,7 @@ imageinstall: createinitramfs @echo 'The kernel+initramfs file is: $(FW_DIR)/${TARGET_KERNEL}' ifeq ($(ADK_HARDWARE_QEMU),y) @echo "Start qemu with following command line:" - @echo 'qemu-system-i386 -nographic -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL)' + @echo 'qemu-system-i386 ${ADK_QEMU_ARGS} -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL)' endif endif ifeq (${ADK_TARGET_FS},iso) diff --git a/target/x86_64/Makefile b/target/x86_64/Makefile index 0d0d213d4..596f2923f 100644 --- a/target/x86_64/Makefile +++ b/target/x86_64/Makefile @@ -17,7 +17,7 @@ ifeq ($(ADK_TARGET_SYSTEM_QEMU_X86_64),y) @echo "Use following command to create a QEMU Image:" @echo "./scripts/create.sh qemu-${CPU_ARCH}.img $(FW_DIR)/$(ROOTFSTARBALL)" @echo "Start qemu with following command line:" - @echo 'qemu-system-x86_64 -nographic -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL) qemu-${CPU_ARCH}.img' + @echo 'qemu-system-x86_64 ${ADK_QEMU_ARGS} -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL) qemu-${CPU_ARCH}.img' endif endif ifeq ($(ADK_TARGET_FS),usb) @@ -32,7 +32,7 @@ imageinstall: $(FW_DIR)/$(INITRAMFS) @echo 'The initramfs image is: ${FW_DIR}/${INITRAMFS}' ifeq ($(ADK_TARGET_SYSTEM_QEMU_X86_64),y) @echo "Start qemu with following command line:" - @echo 'qemu-system-x86_64 -nographic -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL) -initrd ${FW_DIR}/${INITRAMFS}' + @echo 'qemu-system-x86_64 ${ADK_QEMU_ARGS} -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL) -initrd ${FW_DIR}/${INITRAMFS}' endif endif ifeq ($(ADK_TARGET_FS),initramfs-piggyback) @@ -41,7 +41,7 @@ imageinstall: createinitramfs @echo 'The kernel file is: $(FW_DIR)/${TARGET_KERNEL}' ifeq ($(ADK_TARGET_SYSTEM_QEMU_X86_64),y) @echo "Start qemu with following command line:" - @echo 'qemu-system-x86_64 -nographic -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL)' + @echo 'qemu-system-x86_64 ${ADK_QEMU_ARGS} -net user -net nic,model=e1000 -kernel $(FW_DIR)/$(TARGET_KERNEL)' endif endif ifeq ($(ADK_TARGET_FS),nfsroot) diff --git a/target/x86_64/sys-available/shuttle-sa76 b/target/x86_64/sys-available/shuttle-sa76 deleted file mode 100644 index 557cc77cd..000000000 --- a/target/x86_64/sys-available/shuttle-sa76 +++ /dev/null @@ -1,16 +0,0 @@ -config ADK_TARGET_SYSTEM_SHUTTLE_SA76 - bool "Shuttle SA76" - depends on ADK_BROKEN - select ADK_x86_64 - select ADK_shuttle_sa76 - select ADK_CPU_AMDFAM10 - select ADK_LINUX_64 - select ADK_KERNEL_SMP - select ADK_TARGET_WITH_VGA - select ADK_TARGET_WITH_SATA - select ADK_TARGET_WITH_INPUT - select ADK_TARGET_WITH_PCI - select ADK_TARGET_WITH_USB - select ADK_TARGET_WITH_USB_BOOT - help - Support for Shuttle SA76 XPC. diff --git a/target/x86_64/sys-available/tarox-pc b/target/x86_64/sys-available/tarox-pc deleted file mode 100644 index d6b068e06..000000000 --- a/target/x86_64/sys-available/tarox-pc +++ /dev/null @@ -1,15 +0,0 @@ -config ADK_TARGET_SYSTEM_TAROX_PC - bool "Tarox PC" - depends on ADK_BROKEN - select ADK_x86_64 - select ADK_tarox_pc - select ADK_LINUX_64 - select ADK_KERNEL_SMP - select ADK_TARGET_WITH_VGA - select ADK_TARGET_WITH_SATA - select ADK_TARGET_WITH_INPUT - select ADK_TARGET_WITH_PCI - select ADK_TARGET_WITH_USB - select ADK_TARGET_WITH_USB_BOOT - help - Support for Tarox Business PC. -- cgit v1.2.3 From 6b4718e4ac35b741141bbaa4c0836d77b22cc02f Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sat, 8 Mar 2014 20:16:45 +0100 Subject: use ADK_HOST_ONLY to mark host only packages --- package/ant/Makefile | 2 ++ package/cmake/Makefile | 11 +---------- package/ecj/Makefile | 2 ++ package/fastjar/Makefile | 2 ++ package/gcj/Makefile | 2 ++ package/scons/Makefile | 2 +- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/package/ant/Makefile b/package/ant/Makefile index 625853bd8..b5b7d86b9 100644 --- a/package/ant/Makefile +++ b/package/ant/Makefile @@ -11,6 +11,8 @@ PKG_DESCR:= ant utility PKG_SECTION:= lang PKG_SITES:= http://archive.apache.org/dist/ant/source/ +PKG_CFLINE_ANT:= depends on ADK_HOST_ONLY + DISTFILES:= apache-$(PKG_NAME)-$(PKG_VERSION)-src.tar.bz2 WRKDIST= $(WRKDIR)/apache-$(PKG_NAME)-$(PKG_VERSION) diff --git a/package/cmake/Makefile b/package/cmake/Makefile index 6cdf53b0b..c444eba19 100644 --- a/package/cmake/Makefile +++ b/package/cmake/Makefile @@ -12,13 +12,12 @@ PKG_SECTION:= lang PKG_URL:= http://www.cmake.org/ PKG_SITES:= http://www.cmake.org/files/v2.8/ -PKG_CFLINE_CMAKE:= depends on ADK_BROKEN +PKG_CFLINE_CMAKE:= depends on ADK_HOST_ONLY include $(TOPDIR)/mk/host.mk include $(TOPDIR)/mk/package.mk $(eval $(call HOST_template,CMAKE,cmake,$(PKG_VERSION)-${PKG_RELEASE})) -$(eval $(call PKG_template,CMAKE,cmake,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION})) HOST_STYLE:= manual CONFIG_STYLE:= manual @@ -35,13 +34,5 @@ cmake-hostinstall: $(INSTALL_BIN) $(WRKBUILD)/bin/cmake \ $(STAGING_HOST_DIR)/usr/bin -do-configure: - (cd $(WRKBUILD); ./configure --prefix=/usr) - -cmake-install: - $(INSTALL_DIR) $(IDIR_CMAKE)/usr/bin - $(INSTALL_BIN) $(WRKINST)/usr/bin/cmake \ - $(IDIR_CMAKE)/usr/bin - include ${TOPDIR}/mk/host-bottom.mk include ${TOPDIR}/mk/pkg-bottom.mk diff --git a/package/ecj/Makefile b/package/ecj/Makefile index 8e4dc6f94..8bba31865 100644 --- a/package/ecj/Makefile +++ b/package/ecj/Makefile @@ -10,6 +10,8 @@ PKG_MD5SUM:= c474fa9d0c35a24037c23b6e476862c1 PKG_DESCR:= ecj java compiler PKG_SECTION:= lang +PKG_CFLINE_ECJ:= depends on ADK_HOST_ONLY + NO_DISTFILES:= 1 include $(TOPDIR)/mk/host.mk diff --git a/package/fastjar/Makefile b/package/fastjar/Makefile index 0f4c1a50c..fe73820fa 100644 --- a/package/fastjar/Makefile +++ b/package/fastjar/Makefile @@ -11,6 +11,8 @@ PKG_DESCR:= fastjar utility PKG_SECTION:= lang PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=fastjar/} +PKG_CFLINE_FASTJAR:= depends on ADK_HOST_ONLY + include $(TOPDIR)/mk/host.mk include $(TOPDIR)/mk/package.mk diff --git a/package/gcj/Makefile b/package/gcj/Makefile index 15c56b204..8273f06b2 100644 --- a/package/gcj/Makefile +++ b/package/gcj/Makefile @@ -11,6 +11,8 @@ PKG_DESCR:= GNU java compiler PKG_SECTION:= lang PKG_SITES:= ${MASTER_SITE_GNU:=gcc/gcc-${PKG_VERSION}/} +PKG_CFLINE_GCJ:= depends on ADK_HOST_ONLY + DISTFILES:= gcc-$(PKG_VERSION).tar.bz2 WRKDIST= ${WRKDIR}/gcc-${PKG_VERSION} diff --git a/package/scons/Makefile b/package/scons/Makefile index 3f8958d40..9e92c9917 100644 --- a/package/scons/Makefile +++ b/package/scons/Makefile @@ -13,7 +13,7 @@ PKG_BUILDDEP:= bzip2-host python2-host PKG_URL:= http://www.scons.org PKG_SITES:= ${MASTER_SITE_SOURCEFORGE:=scons/} -PKG_ARCH_DEPENDS:= native +PKG_CFLINE_SCONS:= depends on ADK_HOST_ONLY include $(TOPDIR)/mk/host.mk include $(TOPDIR)/mk/package.mk -- cgit v1.2.3 From c5eedebec9a31762dd50409c36ea2e1163b339fe Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sun, 9 Mar 2014 11:24:31 +0100 Subject: use WRKSRC, not WRKBUILD for config.{sub,guess} patching. fixes libdb build for musl --- mk/pkg-bottom.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mk/pkg-bottom.mk b/mk/pkg-bottom.mk index 66feea33c..3d70120d1 100644 --- a/mk/pkg-bottom.mk +++ b/mk/pkg-bottom.mk @@ -38,7 +38,7 @@ ifneq ($(filter manual,${CONFIG_STYLE}),) env ${CONFIGURE_ENV} ${MAKE} do-configure $(MAKE_TRACE) else ifneq ($(filter minimal,${CONFIG_STYLE}),) @$(CMD_TRACE) "configuring... " - @cd ${WRKBUILD}; \ + @cd ${WRKSRC}; \ for i in $$(find . -name config.sub);do \ if [ -f $$i ]; then \ ${CP} $$i $$i.bak; \ @@ -57,7 +57,7 @@ else ifneq ($(filter minimal,${CONFIG_STYLE}),) ${CONFIGURE_ARGS} $(MAKE_TRACE) else ifeq ($(strip ${CONFIG_STYLE}),) @$(CMD_TRACE) "configuring... " - @cd ${WRKBUILD}; \ + @cd ${WRKSRC}; \ for i in $$(find . -name config.sub);do \ if [ -f $$i ]; then \ ${CP} $$i $$i.bak; \ -- cgit v1.2.3 From 9fefab63a7256b36807cb0f5eb8a290468582c2c Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Sun, 9 Mar 2014 18:09:34 +0100 Subject: add the stable cubox-i kernel 3.10.30, add kernel patch from solidrun git --- Config.in | 5 + mk/kernel-ver.mk | 6 + scripts/xargs | 9 + target/arm/kernel/cubox-i | 3 - target/linux/config/Config.in.cpu | 22 +- target/linux/config/Config.in.pm | 9 +- .../linux/patches/3.10.30/bsd-compatibility.patch | 2538 + .../linux/patches/3.10.30/solidrun-cubox-i.patch | 584365 ++++++++++++++++++ target/linux/patches/3.10.30/startup.patch | 12 + .../patches/3.10.30/cleankernel.patch | 11 + .../kernel-headers/patches/3.10.30/mkpiggy.patch | 28 + .../kernel-headers/patches/3.10.30/relocs.patch | 2693 + .../kernel-headers/patches/3.10.30/sgidefs.patch | 18 + .../kernel-headers/patches/3.10.30/sortext.patch | 33 + 14 files changed, 589743 insertions(+), 9 deletions(-) create mode 100755 scripts/xargs create mode 100644 target/linux/patches/3.10.30/bsd-compatibility.patch create mode 100644 target/linux/patches/3.10.30/solidrun-cubox-i.patch create mode 100644 target/linux/patches/3.10.30/startup.patch create mode 100644 toolchain/kernel-headers/patches/3.10.30/cleankernel.patch create mode 100644 toolchain/kernel-headers/patches/3.10.30/mkpiggy.patch create mode 100644 toolchain/kernel-headers/patches/3.10.30/relocs.patch create mode 100644 toolchain/kernel-headers/patches/3.10.30/sgidefs.patch create mode 100644 toolchain/kernel-headers/patches/3.10.30/sortext.patch diff --git a/Config.in b/Config.in index 7cee82338..855d79095 100644 --- a/Config.in +++ b/Config.in @@ -121,6 +121,10 @@ config ADK_KERNEL_VERSION_3_11_10 prompt "3.11.10" boolean +config ADK_KERNEL_VERSION_3_10_30 + prompt "3.10.30" + boolean + config ADK_KERNEL_VERSION_3_4_82 prompt "3.4.82" boolean @@ -132,6 +136,7 @@ config ADK_KERNEL_VERSION default "3.13.5" if ADK_KERNEL_VERSION_3_13_5 default "3.12.13" if ADK_KERNEL_VERSION_3_12_13 default "3.11.10" if ADK_KERNEL_VERSION_3_11_10 + default "3.10.30" if ADK_KERNEL_VERSION_3_10_30 default "3.4.82" if ADK_KERNEL_VERSION_3_4_82 help diff --git a/mk/kernel-ver.mk b/mk/kernel-ver.mk index 09362fbae..ef9fee277 100644 --- a/mk/kernel-ver.mk +++ b/mk/kernel-ver.mk @@ -22,6 +22,12 @@ KERNEL_MOD_VERSION:= $(KERNEL_VERSION) KERNEL_RELEASE:= 1 KERNEL_MD5SUM:= 59f352d3f4e2cdf6755f79e09fa09176 endif +ifeq ($(ADK_KERNEL_VERSION_3_10_30),y) +KERNEL_VERSION:= 3.10.30 +KERNEL_MOD_VERSION:= $(KERNEL_VERSION) +KERNEL_RELEASE:= 1 +KERNEL_MD5SUM:= f48ca7dd9f2eb14a2903cb6a4fbe07ed +endif ifeq ($(ADK_KERNEL_VERSION_3_4_82),y) KERNEL_VERSION:= 3.4.82 KERNEL_MOD_VERSION:= $(KERNEL_VERSION) diff --git a/scripts/xargs b/scripts/xargs new file mode 100755 index 000000000..cbe9bd015 --- /dev/null +++ b/scripts/xargs @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# This file is part of the OpenADK project. OpenADK is copyrighted +# material, please see the LICENCE file in the top-level directory. + +if [ -z "$(which gxargs 2>/dev/null)" ];then + /usr/bin/xargs "$@" +else + gxargs "$@" +fi diff --git a/target/arm/kernel/cubox-i b/target/arm/kernel/cubox-i index 4283d564b..9843ee37e 100644 --- a/target/arm/kernel/cubox-i +++ b/target/arm/kernel/cubox-i @@ -6,9 +6,6 @@ CONFIG_ARCH_MX6=y CONFIG_SOC_IMX6Q=y CONFIG_SOC_IMX6SL=y CONFIG_KUSER_HELPERS=y -CONFIG_PREEMPT=y -CONFIG_TREE_PREEMPT_RCU=y -CONFIG_PREEMPT_RCU=y CONFIG_AEABI=y CONFIG_VFP=y CONFIG_VFPv3=y diff --git a/target/linux/config/Config.in.cpu b/target/linux/config/Config.in.cpu index efaf3a658..a8dfd5188 100644 --- a/target/linux/config/Config.in.cpu +++ b/target/linux/config/Config.in.cpu @@ -39,6 +39,14 @@ config ADK_KERNEL_CPU_FREQ boolean default n +config ADK_KERNEL_REGULATOR + boolean + default n + +config ADK_KERNEL_REGULATOR_ANATOP + boolean + default n + config ADK_KERNEL_CPU_FREQ_GOV_PERFORMANCE boolean default n @@ -59,15 +67,25 @@ config ADK_KERNEL_CPU_FREQ_GOV_CONSERVATIVE boolean default n +config ADK_KERNEL_ARM_IMX6_CPUFREQ + prompt "CPU frequency support for cubox-i" + boolean + select ADK_KERNEL_CPU_FREQ + select ADK_KERNEL_REGULATOR + select ADK_KERNEL_REGULATOR_ANATOP + default y if ADK_TARGET_SYSTEM_CUBOX_I + depends on ADK_TARGET_SYSTEM_CUBOX_I + config ADK_KERNEL_ARM_BCM2835_CPUFREQ - prompt "CPU frequency support" + prompt "CPU frequency support for raspberry-pi" boolean select ADK_KERNEL_CPU_FREQ default y if ADK_TARGET_SYSTEM_RASPBERRY_PI + depends on ADK_TARGET_SYSTEM_RASPBERRY_PI choice prompt "Governor" -depends on ADK_KERNEL_ARM_BCM2835_CPUFREQ +depends on ADK_KERNEL_ARM_BCM2835_CPUFREQ || ADK_KERNEL_ARM_IMX6_CPUFREQ config ADK_KERNEL_CPU_FREQ_DEFAULT_GOV_ONDEMAND boolean "ondemand" diff --git a/target/linux/config/Config.in.pm b/target/linux/config/Config.in.pm index deff5b3f6..4bfe42c58 100644 --- a/target/linux/config/Config.in.pm +++ b/target/linux/config/Config.in.pm @@ -1,5 +1,6 @@ -config ADK_KERNEL_PM +config ADK_KERNEL_PM_RUNTIME boolean + default y if ADK_TARGET_SYSTEM_CUBOX_I config ADK_KERNEL_ACPI boolean @@ -28,7 +29,7 @@ depends on ADK_TARGET_WITH_ACPI || ADK_TARGET_SYSTEM_LEMOTE_YEELONG config ADK_HARDWARE_ACPI prompt "Enable ACPI support" boolean - select ADK_KERNEL_PM + select ADK_KERNEL_PM_RUNTIME select ADK_KERNEL_ACPI select ADK_KERNEL_ACPI_SYSFS_POWER select ADK_KERNEL_ACPI_AC @@ -44,7 +45,7 @@ config ADK_HARDWARE_ACPI config ADK_KERNEL_SUSPEND prompt "Enable Suspend-to-RAM support" boolean - select ADK_KERNEL_PM + select ADK_KERNEL_PM_RUNTIME default y if ADK_TARGET_SYSTEM_IBM_X40 default y if ADK_TARGET_SYSTEM_LEMOTE_YEELONG default n @@ -54,7 +55,7 @@ config ADK_KERNEL_SUSPEND config ADK_KERNEL_HIBERNATION prompt "Enable Suspend-to-Disk support" boolean - select ADK_KERNEL_PM + select ADK_KERNEL_PM_RUNTIME select ADK_KERNEL_SWAP select BUSYBOX_SWAPONOFF default y if ADK_TARGET_SYSTEM_IBM_X40 diff --git a/target/linux/patches/3.10.30/bsd-compatibility.patch b/target/linux/patches/3.10.30/bsd-compatibility.patch new file mode 100644 index 000000000..b954b658f --- /dev/null +++ b/target/linux/patches/3.10.30/bsd-compatibility.patch @@ -0,0 +1,2538 @@ +diff -Nur linux-3.11.5.orig/scripts/Makefile.lib linux-3.11.5/scripts/Makefile.lib +--- linux-3.11.5.orig/scripts/Makefile.lib 2013-10-14 03:14:45.000000000 +0200 ++++ linux-3.11.5/scripts/Makefile.lib 2013-10-16 18:09:31.000000000 +0200 +@@ -281,7 +281,12 @@ + size_append = printf $(shell \ + dec_size=0; \ + for F in $1; do \ +- fsize=$$(stat -c "%s" $$F); \ ++ if stat -qs .>/dev/null 2>&1; then \ ++ statcmd='stat -f %z'; \ ++ else \ ++ statcmd='stat -c %s'; \ ++ fi; \ ++ fsize=$$($$statcmd $$F); \ + dec_size=$$(expr $$dec_size + $$fsize); \ + done; \ + printf "%08x\n" $$dec_size | \ +diff -Nur linux-3.11.5.orig/scripts/mod/mk_elfconfig.c linux-3.11.5/scripts/mod/mk_elfconfig.c +--- linux-3.11.5.orig/scripts/mod/mk_elfconfig.c 2013-10-14 03:14:45.000000000 +0200 ++++ linux-3.11.5/scripts/mod/mk_elfconfig.c 2013-10-16 18:09:31.000000000 +0200 +@@ -1,7 +1,18 @@ + #include + #include + #include +-#include ++ ++#define EI_NIDENT (16) ++#define ELFMAG "\177ELF" ++ ++#define SELFMAG 4 ++#define EI_CLASS 4 ++#define ELFCLASS32 1 /* 32-bit objects */ ++#define ELFCLASS64 2 /* 64-bit objects */ ++ ++#define EI_DATA 5 /* Data encoding byte index */ ++#define ELFDATA2LSB 1 /* 2's complement, little endian */ ++#define ELFDATA2MSB 2 /* 2's complement, big endian */ + + int + main(int argc, char **argv) +diff -Nur linux-3.11.5.orig/scripts/mod/modpost.h linux-3.11.5/scripts/mod/modpost.h +--- linux-3.11.5.orig/scripts/mod/modpost.h 2013-10-14 03:14:45.000000000 +0200 ++++ linux-3.11.5/scripts/mod/modpost.h 2013-10-16 18:09:31.000000000 +0200 +@@ -7,7 +7,2453 @@ + #include + #include + #include +-#include ++ ++ ++/* This file defines standard ELF types, structures, and macros. ++ Copyright (C) 1995-1999,2000,2001,2002,2003 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++#ifndef _ELF_H ++#define _ELF_H 1 ++ ++__BEGIN_DECLS ++ ++/* Standard ELF types. */ ++ ++#include ++ ++/* Type for a 16-bit quantity. */ ++typedef uint16_t Elf32_Half; ++typedef uint16_t Elf64_Half; ++ ++/* Types for signed and unsigned 32-bit quantities. */ ++typedef uint32_t Elf32_Word; ++typedef int32_t Elf32_Sword; ++typedef uint32_t Elf64_Word; ++typedef int32_t Elf64_Sword; ++ ++/* Types for signed and unsigned 64-bit quantities. */ ++typedef uint64_t Elf32_Xword; ++typedef int64_t Elf32_Sxword; ++typedef uint64_t Elf64_Xword; ++typedef int64_t Elf64_Sxword; ++ ++/* Type of addresses. */ ++typedef uint32_t Elf32_Addr; ++typedef uint64_t Elf64_Addr; ++ ++/* Type of file offsets. */ ++typedef uint32_t Elf32_Off; ++typedef uint64_t Elf64_Off; ++ ++/* Type for section indices, which are 16-bit quantities. */ ++typedef uint16_t Elf32_Section; ++typedef uint16_t Elf64_Section; ++ ++/* Type for version symbol information. */ ++typedef Elf32_Half Elf32_Versym; ++typedef Elf64_Half Elf64_Versym; ++ ++ ++/* The ELF file header. This appears at the start of every ELF file. */ ++ ++#define EI_NIDENT (16) ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf32_Half e_type; /* Object file type */ ++ Elf32_Half e_machine; /* Architecture */ ++ Elf32_Word e_version; /* Object file version */ ++ Elf32_Addr e_entry; /* Entry point virtual address */ ++ Elf32_Off e_phoff; /* Program header table file offset */ ++ Elf32_Off e_shoff; /* Section header table file offset */ ++ Elf32_Word e_flags; /* Processor-specific flags */ ++ Elf32_Half e_ehsize; /* ELF header size in bytes */ ++ Elf32_Half e_phentsize; /* Program header table entry size */ ++ Elf32_Half e_phnum; /* Program header table entry count */ ++ Elf32_Half e_shentsize; /* Section header table entry size */ ++ Elf32_Half e_shnum; /* Section header table entry count */ ++ Elf32_Half e_shstrndx; /* Section header string table index */ ++} Elf32_Ehdr; ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf64_Half e_type; /* Object file type */ ++ Elf64_Half e_machine; /* Architecture */ ++ Elf64_Word e_version; /* Object file version */ ++ Elf64_Addr e_entry; /* Entry point virtual address */ ++ Elf64_Off e_phoff; /* Program header table file offset */ ++ Elf64_Off e_shoff; /* Section header table file offset */ ++ Elf64_Word e_flags; /* Processor-specific flags */ ++ Elf64_Half e_ehsize; /* ELF header size in bytes */ ++ Elf64_Half e_phentsize; /* Program header table entry size */ ++ Elf64_Half e_phnum; /* Program header table entry count */ ++ Elf64_Half e_shentsize; /* Section header table entry size */ ++ Elf64_Half e_shnum; /* Section header table entry count */ ++ Elf64_Half e_shstrndx; /* Section header string table index */ ++} Elf64_Ehdr; ++ ++/* Fields in the e_ident array. The EI_* macros are indices into the ++ array. The macros under each EI_* macro are the values the byte ++ may have. */ ++ ++#define EI_MAG0 0 /* File identification byte 0 index */ ++#define ELFMAG0 0x7f /* Magic number byte 0 */ ++ ++#define EI_MAG1 1 /* File identification byte 1 index */ ++#define ELFMAG1 'E' /* Magic number byte 1 */ ++ ++#define EI_MAG2 2 /* File identification byte 2 index */ ++#define ELFMAG2 'L' /* Magic number byte 2 */ ++ ++#define EI_MAG3 3 /* File identification byte 3 index */ ++#define ELFMAG3 'F' /* Magic number byte 3 */ ++ ++/* Conglomeration of the identification bytes, for easy testing as a word. */ ++#define ELFMAG "\177ELF" ++#define SELFMAG 4 ++ ++#define EI_CLASS 4 /* File class byte index */ ++#define ELFCLASSNONE 0 /* Invalid class */ ++#define ELFCLASS32 1 /* 32-bit objects */ ++#define ELFCLASS64 2 /* 64-bit objects */ ++#define ELFCLASSNUM 3 ++ ++#define EI_DATA 5 /* Data encoding byte index */ ++#define ELFDATANONE 0 /* Invalid data encoding */ ++#define ELFDATA2LSB 1 /* 2's complement, little endian */ ++#define ELFDATA2MSB 2 /* 2's complement, big endian */ ++#define ELFDATANUM 3 ++ ++#define EI_VERSION 6 /* File version byte index */ ++ /* Value must be EV_CURRENT */ ++ ++#define EI_OSABI 7 /* OS ABI identification */ ++#define ELFOSABI_NONE 0 /* UNIX System V ABI */ ++#define ELFOSABI_SYSV 0 /* Alias. */ ++#define ELFOSABI_HPUX 1 /* HP-UX */ ++#define ELFOSABI_NETBSD 2 /* NetBSD. */ ++#define ELFOSABI_LINUX 3 /* Linux. */ ++#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ ++#define ELFOSABI_AIX 7 /* IBM AIX. */ ++#define ELFOSABI_IRIX 8 /* SGI Irix. */ ++#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ ++#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ ++#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ ++#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ ++#define ELFOSABI_ARM 97 /* ARM */ ++#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ ++ ++#define EI_ABIVERSION 8 /* ABI version */ ++ ++#define EI_PAD 9 /* Byte index of padding bytes */ ++ ++/* Legal values for e_type (object file type). */ ++ ++#define ET_NONE 0 /* No file type */ ++#define ET_REL 1 /* Relocatable file */ ++#define ET_EXEC 2 /* Executable file */ ++#define ET_DYN 3 /* Shared object file */ ++#define ET_CORE 4 /* Core file */ ++#define ET_NUM 5 /* Number of defined types */ ++#define ET_LOOS 0xfe00 /* OS-specific range start */ ++#define ET_HIOS 0xfeff /* OS-specific range end */ ++#define ET_LOPROC 0xff00 /* Processor-specific range start */ ++#define ET_HIPROC 0xffff /* Processor-specific range end */ ++ ++/* Legal values for e_machine (architecture). */ ++ ++#define EM_NONE 0 /* No machine */ ++#define EM_M32 1 /* AT&T WE 32100 */ ++#define EM_SPARC 2 /* SUN SPARC */ ++#define EM_386 3 /* Intel 80386 */ ++#define EM_68K 4 /* Motorola m68k family */ ++#define EM_88K 5 /* Motorola m88k family */ ++#define EM_860 7 /* Intel 80860 */ ++#define EM_MIPS 8 /* MIPS R3000 big-endian */ ++#define EM_S370 9 /* IBM System/370 */ ++#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ ++ ++#define EM_PARISC 15 /* HPPA */ ++#define EM_VPP500 17 /* Fujitsu VPP500 */ ++#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ ++#define EM_960 19 /* Intel 80960 */ ++#define EM_PPC 20 /* PowerPC */ ++#define EM_PPC64 21 /* PowerPC 64-bit */ ++#define EM_S390 22 /* IBM S390 */ ++ ++#define EM_V800 36 /* NEC V800 series */ ++#define EM_FR20 37 /* Fujitsu FR20 */ ++#define EM_RH32 38 /* TRW RH-32 */ ++#define EM_RCE 39 /* Motorola RCE */ ++#define EM_ARM 40 /* ARM */ ++#define EM_FAKE_ALPHA 41 /* Digital Alpha */ ++#define EM_SH 42 /* Hitachi SH */ ++#define EM_SPARCV9 43 /* SPARC v9 64-bit */ ++#define EM_TRICORE 44 /* Siemens Tricore */ ++#define EM_ARC 45 /* Argonaut RISC Core */ ++#define EM_H8_300 46 /* Hitachi H8/300 */ ++#define EM_H8_300H 47 /* Hitachi H8/300H */ ++#define EM_H8S 48 /* Hitachi H8S */ ++#define EM_H8_500 49 /* Hitachi H8/500 */ ++#define EM_IA_64 50 /* Intel Merced */ ++#define EM_MIPS_X 51 /* Stanford MIPS-X */ ++#define EM_COLDFIRE 52 /* Motorola Coldfire */ ++#define EM_68HC12 53 /* Motorola M68HC12 */ ++#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ ++#define EM_PCP 55 /* Siemens PCP */ ++#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ ++#define EM_NDR1 57 /* Denso NDR1 microprocessor */ ++#define EM_STARCORE 58 /* Motorola Start*Core processor */ ++#define EM_ME16 59 /* Toyota ME16 processor */ ++#define EM_ST100 60 /* STMicroelectronic ST100 processor */ ++#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ ++#define EM_X86_64 62 /* AMD x86-64 architecture */ ++#define EM_PDSP 63 /* Sony DSP Processor */ ++ ++#define EM_FX66 66 /* Siemens FX66 microcontroller */ ++#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ ++#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ ++#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ ++#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ ++#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ ++#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ ++#define EM_SVX 73 /* Silicon Graphics SVx */ ++#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ ++#define EM_VAX 75 /* Digital VAX */ ++#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ ++#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ ++#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ ++#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ ++#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ ++#define EM_HUANY 81 /* Harvard University machine-independent object files */ ++#define EM_PRISM 82 /* SiTera Prism */ ++#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ ++#define EM_FR30 84 /* Fujitsu FR30 */ ++#define EM_D10V 85 /* Mitsubishi D10V */ ++#define EM_D30V 86 /* Mitsubishi D30V */ ++#define EM_V850 87 /* NEC v850 */ ++#define EM_M32R 88 /* Mitsubishi M32R */ ++#define EM_MN10300 89 /* Matsushita MN10300 */ ++#define EM_MN10200 90 /* Matsushita MN10200 */ ++#define EM_PJ 91 /* picoJava */ ++#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ ++#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ ++#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ ++#define EM_NUM 95 ++ ++/* If it is necessary to assign new unofficial EM_* values, please ++ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the ++ chances of collision with official or non-GNU unofficial values. */ ++ ++#define EM_ALPHA 0x9026 ++ ++/* Legal values for e_version (version). */ ++ ++#define EV_NONE 0 /* Invalid ELF version */ ++#define EV_CURRENT 1 /* Current version */ ++#define EV_NUM 2 ++ ++/* Section header. */ ++ ++typedef struct ++{ ++ Elf32_Word sh_name; /* Section name (string tbl index) */ ++ Elf32_Word sh_type; /* Section type */ ++ Elf32_Word sh_flags; /* Section flags */ ++ Elf32_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf32_Off sh_offset; /* Section file offset */ ++ Elf32_Word sh_size; /* Section size in bytes */ ++ Elf32_Word sh_link; /* Link to another section */ ++ Elf32_Word sh_info; /* Additional section information */ ++ Elf32_Word sh_addralign; /* Section alignment */ ++ Elf32_Word sh_entsize; /* Entry size if section holds table */ ++} Elf32_Shdr; ++ ++typedef struct ++{ ++ Elf64_Word sh_name; /* Section name (string tbl index) */ ++ Elf64_Word sh_type; /* Section type */ ++ Elf64_Xword sh_flags; /* Section flags */ ++ Elf64_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf64_Off sh_offset; /* Section file offset */ ++ Elf64_Xword sh_size; /* Section size in bytes */ ++ Elf64_Word sh_link; /* Link to another section */ ++ Elf64_Word sh_info; /* Additional section information */ ++ Elf64_Xword sh_addralign; /* Section alignment */ ++ Elf64_Xword sh_entsize; /* Entry size if section holds table */ ++} Elf64_Shdr; ++ ++/* Special section indices. */ ++ ++#define SHN_UNDEF 0 /* Undefined section */ ++#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ ++#define SHN_LOPROC 0xff00 /* Start of processor-specific */ ++#define SHN_HIPROC 0xff1f /* End of processor-specific */ ++#define SHN_LOOS 0xff20 /* Start of OS-specific */ ++#define SHN_HIOS 0xff3f /* End of OS-specific */ ++#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ ++#define SHN_COMMON 0xfff2 /* Associated symbol is common */ ++#define SHN_XINDEX 0xffff /* Index is in extra table. */ ++#define SHN_HIRESERVE 0xffff /* End of reserved indices */ ++ ++/* Legal values for sh_type (section type). */ ++ ++#define SHT_NULL 0 /* Section header table entry unused */ ++#define SHT_PROGBITS 1 /* Program data */ ++#define SHT_SYMTAB 2 /* Symbol table */ ++#define SHT_STRTAB 3 /* String table */ ++#define SHT_RELA 4 /* Relocation entries with addends */ ++#define SHT_HASH 5 /* Symbol hash table */ ++#define SHT_DYNAMIC 6 /* Dynamic linking information */ ++#define SHT_NOTE 7 /* Notes */ ++#define SHT_NOBITS 8 /* Program space with no data (bss) */ ++#define SHT_REL 9 /* Relocation entries, no addends */ ++#define SHT_SHLIB 10 /* Reserved */ ++#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ ++#define SHT_INIT_ARRAY 14 /* Array of constructors */ ++#define SHT_FINI_ARRAY 15 /* Array of destructors */ ++#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ ++#define SHT_GROUP 17 /* Section group */ ++#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ ++#define SHT_NUM 19 /* Number of defined types. */ ++#define SHT_LOOS 0x60000000 /* Start OS-specific */ ++#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ ++#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ ++#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ ++#define SHT_SUNW_move 0x6ffffffa ++#define SHT_SUNW_COMDAT 0x6ffffffb ++#define SHT_SUNW_syminfo 0x6ffffffc ++#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ ++#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ ++#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ ++#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ ++#define SHT_HIOS 0x6fffffff /* End OS-specific type */ ++#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define SHT_LOUSER 0x80000000 /* Start of application-specific */ ++#define SHT_HIUSER 0x8fffffff /* End of application-specific */ ++ ++/* Legal values for sh_flags (section flags). */ ++ ++#define SHF_WRITE (1 << 0) /* Writable */ ++#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ ++#define SHF_EXECINSTR (1 << 2) /* Executable */ ++#define SHF_MERGE (1 << 4) /* Might be merged */ ++#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ ++#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ ++#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ ++#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling ++ required */ ++#define SHF_GROUP (1 << 9) /* Section is member of a group. */ ++#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ ++#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ ++#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ ++ ++/* Section group handling. */ ++#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ ++ ++/* Symbol table entry. */ ++ ++typedef struct ++{ ++ Elf32_Word st_name; /* Symbol name (string tbl index) */ ++ Elf32_Addr st_value; /* Symbol value */ ++ Elf32_Word st_size; /* Symbol size */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf32_Section st_shndx; /* Section index */ ++} Elf32_Sym; ++ ++typedef struct ++{ ++ Elf64_Word st_name; /* Symbol name (string tbl index) */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf64_Section st_shndx; /* Section index */ ++ Elf64_Addr st_value; /* Symbol value */ ++ Elf64_Xword st_size; /* Symbol size */ ++} Elf64_Sym; ++ ++/* The syminfo section if available contains additional information about ++ every dynamic symbol. */ ++ ++typedef struct ++{ ++ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf32_Half si_flags; /* Per symbol flags */ ++} Elf32_Syminfo; ++ ++typedef struct ++{ ++ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf64_Half si_flags; /* Per symbol flags */ ++} Elf64_Syminfo; ++ ++/* Possible values for si_boundto. */ ++#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ ++#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ ++#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ ++ ++/* Possible bitmasks for si_flags. */ ++#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ ++#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ ++#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ ++#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy ++ loaded */ ++/* Syminfo version values. */ ++#define SYMINFO_NONE 0 ++#define SYMINFO_CURRENT 1 ++#define SYMINFO_NUM 2 ++ ++ ++/* How to extract and insert information held in the st_info field. */ ++ ++#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) ++#define ELF32_ST_TYPE(val) ((val) & 0xf) ++#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) ++ ++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ ++#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) ++#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) ++#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) ++ ++/* Legal values for ST_BIND subfield of st_info (symbol binding). */ ++ ++#define STB_LOCAL 0 /* Local symbol */ ++#define STB_GLOBAL 1 /* Global symbol */ ++#define STB_WEAK 2 /* Weak symbol */ ++#define STB_NUM 3 /* Number of defined types. */ ++#define STB_LOOS 10 /* Start of OS-specific */ ++#define STB_HIOS 12 /* End of OS-specific */ ++#define STB_LOPROC 13 /* Start of processor-specific */ ++#define STB_HIPROC 15 /* End of processor-specific */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_NOTYPE 0 /* Symbol type is unspecified */ ++#define STT_OBJECT 1 /* Symbol is a data object */ ++#define STT_FUNC 2 /* Symbol is a code object */ ++#define STT_SECTION 3 /* Symbol associated with a section */ ++#define STT_FILE 4 /* Symbol's name is file name */ ++#define STT_COMMON 5 /* Symbol is a common data object */ ++#define STT_TLS 6 /* Symbol is thread-local data object*/ ++#define STT_NUM 7 /* Number of defined types. */ ++#define STT_LOOS 10 /* Start of OS-specific */ ++#define STT_HIOS 12 /* End of OS-specific */ ++#define STT_LOPROC 13 /* Start of processor-specific */ ++#define STT_HIPROC 15 /* End of processor-specific */ ++ ++ ++/* Symbol table indices are found in the hash buckets and chain table ++ of a symbol hash table section. This special index value indicates ++ the end of a chain, meaning no further symbols are found in that bucket. */ ++ ++#define STN_UNDEF 0 /* End of a chain. */ ++ ++ ++/* How to extract and insert information held in the st_other field. */ ++ ++#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) ++ ++/* For ELF64 the definitions are the same. */ ++#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) ++ ++/* Symbol visibility specification encoded in the st_other field. */ ++#define STV_DEFAULT 0 /* Default symbol visibility rules */ ++#define STV_INTERNAL 1 /* Processor specific hidden class */ ++#define STV_HIDDEN 2 /* Sym unavailable in other modules */ ++#define STV_PROTECTED 3 /* Not preemptible, not exported */ ++ ++ ++/* Relocation table entry without addend (in section of type SHT_REL). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++} Elf32_Rel; ++ ++/* I have seen two different definitions of the Elf64_Rel and ++ Elf64_Rela structures, so we'll leave them out until Novell (or ++ whoever) gets their act together. */ ++/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++} Elf64_Rel; ++ ++/* Relocation table entry with addend (in section of type SHT_RELA). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++ Elf32_Sword r_addend; /* Addend */ ++} Elf32_Rela; ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++ Elf64_Sxword r_addend; /* Addend */ ++} Elf64_Rela; ++ ++/* How to extract and insert information held in the r_info field. */ ++ ++#define ELF32_R_SYM(val) ((val) >> 8) ++#define ELF32_R_TYPE(val) ((val) & 0xff) ++#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) ++ ++#define ELF64_R_SYM(i) ((i) >> 32) ++#define ELF64_R_TYPE(i) ((i) & 0xffffffff) ++#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) ++ ++/* Program segment header. */ ++ ++typedef struct ++{ ++ Elf32_Word p_type; /* Segment type */ ++ Elf32_Off p_offset; /* Segment file offset */ ++ Elf32_Addr p_vaddr; /* Segment virtual address */ ++ Elf32_Addr p_paddr; /* Segment physical address */ ++ Elf32_Word p_filesz; /* Segment size in file */ ++ Elf32_Word p_memsz; /* Segment size in memory */ ++ Elf32_Word p_flags; /* Segment flags */ ++ Elf32_Word p_align; /* Segment alignment */ ++} Elf32_Phdr; ++ ++typedef struct ++{ ++ Elf64_Word p_type; /* Segment type */ ++ Elf64_Word p_flags; /* Segment flags */ ++ Elf64_Off p_offset; /* Segment file offset */ ++ Elf64_Addr p_vaddr; /* Segment virtual address */ ++ Elf64_Addr p_paddr; /* Segment physical address */ ++ Elf64_Xword p_filesz; /* Segment size in file */ ++ Elf64_Xword p_memsz; /* Segment size in memory */ ++ Elf64_Xword p_align; /* Segment alignment */ ++} Elf64_Phdr; ++ ++/* Legal values for p_type (segment type). */ ++ ++#define PT_NULL 0 /* Program header table entry unused */ ++#define PT_LOAD 1 /* Loadable program segment */ ++#define PT_DYNAMIC 2 /* Dynamic linking information */ ++#define PT_INTERP 3 /* Program interpreter */ ++#define PT_NOTE 4 /* Auxiliary information */ ++#define PT_SHLIB 5 /* Reserved */ ++#define PT_PHDR 6 /* Entry for header table itself */ ++#define PT_TLS 7 /* Thread-local storage segment */ ++#define PT_NUM 8 /* Number of defined types */ ++#define PT_LOOS 0x60000000 /* Start of OS-specific */ ++#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ ++#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ ++#define PT_LOSUNW 0x6ffffffa ++#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ ++#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ ++#define PT_HISUNW 0x6fffffff ++#define PT_HIOS 0x6fffffff /* End of OS-specific */ ++#define PT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define PT_HIPROC 0x7fffffff /* End of processor-specific */ ++ ++/* Legal values for p_flags (segment flags). */ ++ ++#define PF_X (1 << 0) /* Segment is executable */ ++#define PF_W (1 << 1) /* Segment is writable */ ++#define PF_R (1 << 2) /* Segment is readable */ ++#define PF_MASKOS 0x0ff00000 /* OS-specific */ ++#define PF_MASKPROC 0xf0000000 /* Processor-specific */ ++ ++/* Legal values for note segment descriptor types for core files. */ ++ ++#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ ++#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ ++#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ ++#define NT_PRXREG 4 /* Contains copy of prxregset struct */ ++#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ ++#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ ++#define NT_AUXV 6 /* Contains copy of auxv array */ ++#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ ++#define NT_ASRS 8 /* Contains copy of asrset struct */ ++#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ ++#define NT_PSINFO 13 /* Contains copy of psinfo struct */ ++#define NT_PRCRED 14 /* Contains copy of prcred struct */ ++#define NT_UTSNAME 15 /* Contains copy of utsname struct */ ++#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ ++#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ ++#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct*/ ++ ++/* Legal values for the note segment descriptor types for object files. */ ++ ++#define NT_VERSION 1 /* Contains a version string. */ ++ ++ ++/* Dynamic section entry. */ ++ ++typedef struct ++{ ++ Elf32_Sword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf32_Word d_val; /* Integer value */ ++ Elf32_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf32_Dyn; ++ ++typedef struct ++{ ++ Elf64_Sxword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf64_Xword d_val; /* Integer value */ ++ Elf64_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf64_Dyn; ++ ++/* Legal values for d_tag (dynamic entry type). */ ++ ++#define DT_NULL 0 /* Marks end of dynamic section */ ++#define DT_NEEDED 1 /* Name of needed library */ ++#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ ++#define DT_PLTGOT 3 /* Processor defined value */ ++#define DT_HASH 4 /* Address of symbol hash table */ ++#define DT_STRTAB 5 /* Address of string table */ ++#define DT_SYMTAB 6 /* Address of symbol table */ ++#define DT_RELA 7 /* Address of Rela relocs */ ++#define DT_RELASZ 8 /* Total size of Rela relocs */ ++#define DT_RELAENT 9 /* Size of one Rela reloc */ ++#define DT_STRSZ 10 /* Size of string table */ ++#define DT_SYMENT 11 /* Size of one symbol table entry */ ++#define DT_INIT 12 /* Address of init function */ ++#define DT_FINI 13 /* Address of termination function */ ++#define DT_SONAME 14 /* Name of shared object */ ++#define DT_RPATH 15 /* Library search path (deprecated) */ ++#define DT_SYMBOLIC 16 /* Start symbol search here */ ++#define DT_REL 17 /* Address of Rel relocs */ ++#define DT_RELSZ 18 /* Total size of Rel relocs */ ++#define DT_RELENT 19 /* Size of one Rel reloc */ ++#define DT_PLTREL 20 /* Type of reloc in PLT */ ++#define DT_DEBUG 21 /* For debugging; unspecified */ ++#define DT_TEXTREL 22 /* Reloc might modify .text */ ++#define DT_JMPREL 23 /* Address of PLT relocs */ ++#define DT_BIND_NOW 24 /* Process relocations of object */ ++#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ ++#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ ++#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ ++#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ ++#define DT_RUNPATH 29 /* Library search path */ ++#define DT_FLAGS 30 /* Flags for the object being loaded */ ++#define DT_ENCODING 32 /* Start of encoded range */ ++#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ ++#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ ++#define DT_NUM 34 /* Number used */ ++#define DT_LOOS 0x6000000d /* Start of OS-specific */ ++#define DT_HIOS 0x6ffff000 /* End of OS-specific */ ++#define DT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define DT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ ++ ++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the ++ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's ++ approach. */ ++#define DT_VALRNGLO 0x6ffffd00 ++#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ ++#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ ++#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ ++#define DT_CHECKSUM 0x6ffffdf8 ++#define DT_PLTPADSZ 0x6ffffdf9 ++#define DT_MOVEENT 0x6ffffdfa ++#define DT_MOVESZ 0x6ffffdfb ++#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ ++#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting ++ the following DT_* entry. */ ++#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ ++#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ ++#define DT_VALRNGHI 0x6ffffdff ++#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ ++#define DT_VALNUM 12 ++ ++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the ++ Dyn.d_un.d_ptr field of the Elf*_Dyn structure. ++ ++ If any adjustment is made to the ELF object after it has been ++ built these entries will need to be adjusted. */ ++#define DT_ADDRRNGLO 0x6ffffe00 ++#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ ++#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ ++#define DT_CONFIG 0x6ffffefa /* Configuration information. */ ++#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ ++#define DT_AUDIT 0x6ffffefc /* Object auditing. */ ++#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ ++#define DT_MOVETAB 0x6ffffefe /* Move table. */ ++#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ ++#define DT_ADDRRNGHI 0x6ffffeff ++#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ ++#define DT_ADDRNUM 10 ++ ++/* The versioning entry types. The next are defined as part of the ++ GNU extension. */ ++#define DT_VERSYM 0x6ffffff0 ++ ++#define DT_RELACOUNT 0x6ffffff9 ++#define DT_RELCOUNT 0x6ffffffa ++ ++/* These were chosen by Sun. */ ++#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ ++#define DT_VERDEF 0x6ffffffc /* Address of version definition ++ table */ ++#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ ++#define DT_VERNEED 0x6ffffffe /* Address of table with needed ++ versions */ ++#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ ++#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ ++#define DT_VERSIONTAGNUM 16 ++ ++/* Sun added these machine-independent extensions in the "processor-specific" ++ range. Be compatible. */ ++#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ ++#define DT_FILTER 0x7fffffff /* Shared object to get values from */ ++#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) ++#define DT_EXTRANUM 3 ++ ++/* Values of `d_un.d_val' in the DT_FLAGS entry. */ ++#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ ++#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ ++#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ ++#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ ++#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ ++ ++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 ++ entry in the dynamic section. */ ++#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ ++#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ ++#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ ++#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ ++#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ ++#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ ++#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ ++#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ ++#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ ++#define DF_1_TRANS 0x00000200 ++#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ ++#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ ++#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ ++#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ ++#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ ++#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ ++#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ ++ ++/* Flags for the feature selection in DT_FEATURE_1. */ ++#define DTF_1_PARINIT 0x00000001 ++#define DTF_1_CONFEXP 0x00000002 ++ ++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ ++#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ ++#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not ++ generally available. */ ++ ++/* Version definition sections. */ ++ ++typedef struct ++{ ++ Elf32_Half vd_version; /* Version revision */ ++ Elf32_Half vd_flags; /* Version information */ ++ Elf32_Half vd_ndx; /* Version Index */ ++ Elf32_Half vd_cnt; /* Number of associated aux entries */ ++ Elf32_Word vd_hash; /* Version name hash value */ ++ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf32_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf32_Verdef; ++ ++typedef struct ++{ ++ Elf64_Half vd_version; /* Version revision */ ++ Elf64_Half vd_flags; /* Version information */ ++ Elf64_Half vd_ndx; /* Version Index */ ++ Elf64_Half vd_cnt; /* Number of associated aux entries */ ++ Elf64_Word vd_hash; /* Version name hash value */ ++ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf64_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf64_Verdef; ++ ++ ++/* Legal values for vd_version (version revision). */ ++#define VER_DEF_NONE 0 /* No version */ ++#define VER_DEF_CURRENT 1 /* Current version */ ++#define VER_DEF_NUM 2 /* Given version number */ ++ ++/* Legal values for vd_flags (version information flags). */ ++#define VER_FLG_BASE 0x1 /* Version definition of file itself */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++/* Versym symbol index values. */ ++#define VER_NDX_LOCAL 0 /* Symbol is local. */ ++#define VER_NDX_GLOBAL 1 /* Symbol is global. */ ++#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ ++#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ ++ ++/* Auxialiary version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vda_name; /* Version or dependency names */ ++ Elf32_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf32_Verdaux; ++ ++typedef struct ++{ ++ Elf64_Word vda_name; /* Version or dependency names */ ++ Elf64_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf64_Verdaux; ++ ++ ++/* Version dependency section. */ ++ ++typedef struct ++{ ++ Elf32_Half vn_version; /* Version of structure */ ++ Elf32_Half vn_cnt; /* Number of associated aux entries */ ++ Elf32_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf32_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf32_Verneed; ++ ++typedef struct ++{ ++ Elf64_Half vn_version; /* Version of structure */ ++ Elf64_Half vn_cnt; /* Number of associated aux entries */ ++ Elf64_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf64_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf64_Verneed; ++ ++ ++/* Legal values for vn_version (version revision). */ ++#define VER_NEED_NONE 0 /* No version */ ++#define VER_NEED_CURRENT 1 /* Current version */ ++#define VER_NEED_NUM 2 /* Given version number */ ++ ++/* Auxiliary needed version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vna_hash; /* Hash value of dependency name */ ++ Elf32_Half vna_flags; /* Dependency specific information */ ++ Elf32_Half vna_other; /* Unused */ ++ Elf32_Word vna_name; /* Dependency name string offset */ ++ Elf32_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf32_Vernaux; ++ ++typedef struct ++{ ++ Elf64_Word vna_hash; /* Hash value of dependency name */ ++ Elf64_Half vna_flags; /* Dependency specific information */ ++ Elf64_Half vna_other; /* Unused */ ++ Elf64_Word vna_name; /* Dependency name string offset */ ++ Elf64_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf64_Vernaux; ++ ++ ++/* Legal values for vna_flags. */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++ ++/* Auxiliary vector. */ ++ ++/* This vector is normally only used by the program interpreter. The ++ usual definition in an ABI supplement uses the name auxv_t. The ++ vector is not usually defined in a standard file, but it ++ can't hurt. We rename it to avoid conflicts. The sizes of these ++ types are an arrangement between the exec server and the program ++ interpreter, so we don't fully specify them here. */ ++ ++typedef struct ++{ ++ int a_type; /* Entry type */ ++ union ++ { ++ long int a_val; /* Integer value */ ++ void *a_ptr; /* Pointer value */ ++ void (*a_fcn) (void); /* Function pointer value */ ++ } a_un; ++} Elf32_auxv_t; ++ ++typedef struct ++{ ++ long int a_type; /* Entry type */ ++ union ++ { ++ long int a_val; /* Integer value */ ++ void *a_ptr; /* Pointer value */ ++ void (*a_fcn) (void); /* Function pointer value */ ++ } a_un; ++} Elf64_auxv_t; ++ ++/* Legal values for a_type (entry type). */ ++ ++#define AT_NULL 0 /* End of vector */ ++#define AT_IGNORE 1 /* Entry should be ignored */ ++#define AT_EXECFD 2 /* File descriptor of program */ ++#define AT_PHDR 3 /* Program headers for program */ ++#define AT_PHENT 4 /* Size of program header entry */ ++#define AT_PHNUM 5 /* Number of program headers */ ++#define AT_PAGESZ 6 /* System page size */ ++#define AT_BASE 7 /* Base address of interpreter */ ++#define AT_FLAGS 8 /* Flags */ ++#define AT_ENTRY 9 /* Entry point of program */ ++#define AT_NOTELF 10 /* Program is not ELF */ ++#define AT_UID 11 /* Real uid */ ++#define AT_EUID 12 /* Effective uid */ ++#define AT_GID 13 /* Real gid */ ++#define AT_EGID 14 /* Effective gid */ ++#define AT_CLKTCK 17 /* Frequency of times() */ ++ ++/* Some more special a_type values describing the hardware. */ ++#define AT_PLATFORM 15 /* String identifying platform. */ ++#define AT_HWCAP 16 /* Machine dependent hints about ++ processor capabilities. */ ++ ++/* This entry gives some information about the FPU initialization ++ performed by the kernel. */ ++#define AT_FPUCW 18 /* Used FPU control word. */ ++ ++/* Cache block sizes. */ ++#define AT_DCACHEBSIZE 19 /* Data cache block size. */ ++#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ ++#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ ++ ++/* A special ignored value for PPC, used by the kernel to control the ++ interpretation of the AUXV. Must be > 16. */ ++#define AT_IGNOREPPC 22 /* Entry should be ignored. */ ++ ++#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ ++ ++/* Pointer to the global system page used for system calls and other ++ nice things. */ ++#define AT_SYSINFO 32 ++#define AT_SYSINFO_EHDR 33 ++ ++ ++/* Note section contents. Each entry in the note section begins with ++ a header of a fixed form. */ ++ ++typedef struct ++{ ++ Elf32_Word n_namesz; /* Length of the note's name. */ ++ Elf32_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf32_Word n_type; /* Type of the note. */ ++} Elf32_Nhdr; ++ ++typedef struct ++{ ++ Elf64_Word n_namesz; /* Length of the note's name. */ ++ Elf64_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf64_Word n_type; /* Type of the note. */ ++} Elf64_Nhdr; ++ ++/* Known names of notes. */ ++ ++/* Solaris entries in the note section have this name. */ ++#define ELF_NOTE_SOLARIS "SUNW Solaris" ++ ++/* Note entries for GNU systems have this name. */ ++#define ELF_NOTE_GNU "GNU" ++ ++ ++/* Defined types of notes for Solaris. */ ++ ++/* Value of descriptor (one word) is desired pagesize for the binary. */ ++#define ELF_NOTE_PAGESIZE_HINT 1 ++ ++ ++/* Defined note types for GNU systems. */ ++ ++/* ABI information. The descriptor consists of words: ++ word 0: OS descriptor ++ word 1: major version of the ABI ++ word 2: minor version of the ABI ++ word 3: subminor version of the ABI ++*/ ++#define ELF_NOTE_ABI 1 ++ ++/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI ++ note section entry. */ ++#define ELF_NOTE_OS_LINUX 0 ++#define ELF_NOTE_OS_GNU 1 ++#define ELF_NOTE_OS_SOLARIS2 2 ++#define ELF_NOTE_OS_FREEBSD 3 ++ ++ ++/* Move records. */ ++typedef struct ++{ ++ Elf32_Xword m_value; /* Symbol value. */ ++ Elf32_Word m_info; /* Size and index. */ ++ Elf32_Word m_poffset; /* Symbol offset. */ ++ Elf32_Half m_repeat; /* Repeat count. */ ++ Elf32_Half m_stride; /* Stride info. */ ++} Elf32_Move; ++ ++typedef struct ++{ ++ Elf64_Xword m_value; /* Symbol value. */ ++ Elf64_Xword m_info; /* Size and index. */ ++ Elf64_Xword m_poffset; /* Symbol offset. */ ++ Elf64_Half m_repeat; /* Repeat count. */ ++ Elf64_Half m_stride; /* Stride info. */ ++} Elf64_Move; ++ ++/* Macro to construct move records. */ ++#define ELF32_M_SYM(info) ((info) >> 8) ++#define ELF32_M_SIZE(info) ((unsigned char) (info)) ++#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) ++ ++#define ELF64_M_SYM(info) ELF32_M_SYM (info) ++#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) ++#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) ++ ++ ++/* Motorola 68k specific definitions. */ ++ ++/* Values for Elf32_Ehdr.e_flags. */ ++#define EF_CPU32 0x00810000 ++ ++/* m68k relocs. */ ++ ++#define R_68K_NONE 0 /* No reloc */ ++#define R_68K_32 1 /* Direct 32 bit */ ++#define R_68K_16 2 /* Direct 16 bit */ ++#define R_68K_8 3 /* Direct 8 bit */ ++#define R_68K_PC32 4 /* PC relative 32 bit */ ++#define R_68K_PC16 5 /* PC relative 16 bit */ ++#define R_68K_PC8 6 /* PC relative 8 bit */ ++#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ ++#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ ++#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ ++#define R_68K_GOT32O 10 /* 32 bit GOT offset */ ++#define R_68K_GOT16O 11 /* 16 bit GOT offset */ ++#define R_68K_GOT8O 12 /* 8 bit GOT offset */ ++#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ ++#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ ++#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ ++#define R_68K_PLT32O 16 /* 32 bit PLT offset */ ++#define R_68K_PLT16O 17 /* 16 bit PLT offset */ ++#define R_68K_PLT8O 18 /* 8 bit PLT offset */ ++#define R_68K_COPY 19 /* Copy symbol at runtime */ ++#define R_68K_GLOB_DAT 20 /* Create GOT entry */ ++#define R_68K_JMP_SLOT 21 /* Create PLT entry */ ++#define R_68K_RELATIVE 22 /* Adjust by program base */ ++/* Keep this the last entry. */ ++#define R_68K_NUM 23 ++ ++/* Intel 80386 specific definitions. */ ++ ++/* i386 relocs. */ ++ ++#define R_386_NONE 0 /* No reloc */ ++#define R_386_32 1 /* Direct 32 bit */ ++#define R_386_PC32 2 /* PC relative 32 bit */ ++#define R_386_GOT32 3 /* 32 bit GOT entry */ ++#define R_386_PLT32 4 /* 32 bit PLT address */ ++#define R_386_COPY 5 /* Copy symbol at runtime */ ++#define R_386_GLOB_DAT 6 /* Create GOT entry */ ++#define R_386_JMP_SLOT 7 /* Create PLT entry */ ++#define R_386_RELATIVE 8 /* Adjust by program base */ ++#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ ++#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ ++#define R_386_32PLT 11 ++#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ ++#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS ++ block offset */ ++#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block ++ offset */ ++#define R_386_TLS_LE 17 /* Offset relative to static TLS ++ block */ ++#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of ++ general dynamic thread local data */ ++#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of ++ local dynamic thread local data ++ in LE code */ ++#define R_386_16 20 ++#define R_386_PC16 21 ++#define R_386_8 22 ++#define R_386_PC8 23 ++#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic ++ thread local data */ ++#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ ++#define R_386_TLS_GD_CALL 26 /* Relocation for call to ++ __tls_get_addr() */ ++#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ ++#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic ++ thread local data in LE code */ ++#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ ++#define R_386_TLS_LDM_CALL 30 /* Relocation for call to ++ __tls_get_addr() in LDM code */ ++#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ ++#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ ++#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS ++ block offset */ ++#define R_386_TLS_LE_32 34 /* Negated offset relative to static ++ TLS block */ ++#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ ++#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ ++#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ ++/* Keep this the last entry. */ ++#define R_386_NUM 38 ++ ++/* SUN SPARC specific definitions. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_REGISTER 13 /* Global register reserved to app. */ ++ ++/* Values for Elf64_Ehdr.e_flags. */ ++ ++#define EF_SPARCV9_MM 3 ++#define EF_SPARCV9_TSO 0 ++#define EF_SPARCV9_PSO 1 ++#define EF_SPARCV9_RMO 2 ++#define EF_SPARC_LEDATA 0x800000 /* little endian data */ ++#define EF_SPARC_EXT_MASK 0xFFFF00 ++#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ ++#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ ++#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ ++#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ ++ ++/* SPARC relocs. */ ++ ++#define R_SPARC_NONE 0 /* No reloc */ ++#define R_SPARC_8 1 /* Direct 8 bit */ ++#define R_SPARC_16 2 /* Direct 16 bit */ ++#define R_SPARC_32 3 /* Direct 32 bit */ ++#define R_SPARC_DISP8 4 /* PC relative 8 bit */ ++#define R_SPARC_DISP16 5 /* PC relative 16 bit */ ++#define R_SPARC_DISP32 6 /* PC relative 32 bit */ ++#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ ++#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ ++#define R_SPARC_HI22 9 /* High 22 bit */ ++#define R_SPARC_22 10 /* Direct 22 bit */ ++#define R_SPARC_13 11 /* Direct 13 bit */ ++#define R_SPARC_LO10 12 /* Truncated 10 bit */ ++#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ ++#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ ++#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ ++#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ ++#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ ++#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ ++#define R_SPARC_COPY 19 /* Copy symbol at runtime */ ++#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ ++#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ ++#define R_SPARC_RELATIVE 22 /* Adjust by program base */ ++#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ ++ ++/* Additional Sparc64 relocs. */ ++ ++#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ ++#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ ++#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ ++#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ ++#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ ++#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ ++#define R_SPARC_10 30 /* Direct 10 bit */ ++#define R_SPARC_11 31 /* Direct 11 bit */ ++#define R_SPARC_64 32 /* Direct 64 bit */ ++#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ ++#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ ++#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ ++#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ ++#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ ++#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ ++#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ ++#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ ++#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ ++#define R_SPARC_7 43 /* Direct 7 bit */ ++#define R_SPARC_5 44 /* Direct 5 bit */ ++#define R_SPARC_6 45 /* Direct 6 bit */ ++#define R_SPARC_DISP64 46 /* PC relative 64 bit */ ++#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ ++#define R_SPARC_HIX22 48 /* High 22 bit complemented */ ++#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ ++#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ ++#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ ++#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ ++#define R_SPARC_REGISTER 53 /* Global register usage */ ++#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ ++#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ ++#define R_SPARC_TLS_GD_HI22 56 ++#define R_SPARC_TLS_GD_LO10 57 ++#define R_SPARC_TLS_GD_ADD 58 ++#define R_SPARC_TLS_GD_CALL 59 ++#define R_SPARC_TLS_LDM_HI22 60 ++#define R_SPARC_TLS_LDM_LO10 61 ++#define R_SPARC_TLS_LDM_ADD 62 ++#define R_SPARC_TLS_LDM_CALL 63 ++#define R_SPARC_TLS_LDO_HIX22 64 ++#define R_SPARC_TLS_LDO_LOX10 65 ++#define R_SPARC_TLS_LDO_ADD 66 ++#define R_SPARC_TLS_IE_HI22 67 ++#define R_SPARC_TLS_IE_LO10 68 ++#define R_SPARC_TLS_IE_LD 69 ++#define R_SPARC_TLS_IE_LDX 70 ++#define R_SPARC_TLS_IE_ADD 71 ++#define R_SPARC_TLS_LE_HIX22 72 ++#define R_SPARC_TLS_LE_LOX10 73 ++#define R_SPARC_TLS_DTPMOD32 74 ++#define R_SPARC_TLS_DTPMOD64 75 ++#define R_SPARC_TLS_DTPOFF32 76 ++#define R_SPARC_TLS_DTPOFF64 77 ++#define R_SPARC_TLS_TPOFF32 78 ++#define R_SPARC_TLS_TPOFF64 79 ++/* Keep this the last entry. */ ++#define R_SPARC_NUM 80 ++ ++/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ ++ ++#define DT_SPARC_REGISTER 0x70000001 ++#define DT_SPARC_NUM 2 ++ ++/* Bits present in AT_HWCAP, primarily for Sparc32. */ ++ ++#define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */ ++#define HWCAP_SPARC_STBAR 2 ++#define HWCAP_SPARC_SWAP 4 ++#define HWCAP_SPARC_MULDIV 8 ++#define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */ ++#define HWCAP_SPARC_ULTRA3 32 ++ ++/* MIPS R3000 specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ ++#define EF_MIPS_PIC 2 /* Contains PIC code */ ++#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ ++#define EF_MIPS_XGOT 8 ++#define EF_MIPS_64BIT_WHIRL 16 ++#define EF_MIPS_ABI2 32 ++#define EF_MIPS_ABI_ON32 64 ++#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ ++ ++/* Legal values for MIPS architecture level. */ ++ ++#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* The following are non-official names and should not be used. */ ++ ++#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* Special section indices. */ ++ ++#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ ++#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ ++#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ ++#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ ++#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ ++#define SHT_MIPS_MSYM 0x70000001 ++#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ ++#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ ++#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ ++#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ ++#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ ++#define SHT_MIPS_PACKAGE 0x70000007 ++#define SHT_MIPS_PACKSYM 0x70000008 ++#define SHT_MIPS_RELD 0x70000009 ++#define SHT_MIPS_IFACE 0x7000000b ++#define SHT_MIPS_CONTENT 0x7000000c ++#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ ++#define SHT_MIPS_SHDR 0x70000010 ++#define SHT_MIPS_FDESC 0x70000011 ++#define SHT_MIPS_EXTSYM 0x70000012 ++#define SHT_MIPS_DENSE 0x70000013 ++#define SHT_MIPS_PDESC 0x70000014 ++#define SHT_MIPS_LOCSYM 0x70000015 ++#define SHT_MIPS_AUXSYM 0x70000016 ++#define SHT_MIPS_OPTSYM 0x70000017 ++#define SHT_MIPS_LOCSTR 0x70000018 ++#define SHT_MIPS_LINE 0x70000019 ++#define SHT_MIPS_RFDESC 0x7000001a ++#define SHT_MIPS_DELTASYM 0x7000001b ++#define SHT_MIPS_DELTAINST 0x7000001c ++#define SHT_MIPS_DELTACLASS 0x7000001d ++#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ ++#define SHT_MIPS_DELTADECL 0x7000001f ++#define SHT_MIPS_SYMBOL_LIB 0x70000020 ++#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ ++#define SHT_MIPS_TRANSLATE 0x70000022 ++#define SHT_MIPS_PIXIE 0x70000023 ++#define SHT_MIPS_XLATE 0x70000024 ++#define SHT_MIPS_XLATE_DEBUG 0x70000025 ++#define SHT_MIPS_WHIRL 0x70000026 ++#define SHT_MIPS_EH_REGION 0x70000027 ++#define SHT_MIPS_XLATE_OLD 0x70000028 ++#define SHT_MIPS_PDR_EXCEPTION 0x70000029 ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ ++#define SHF_MIPS_MERGE 0x20000000 ++#define SHF_MIPS_ADDR 0x40000000 ++#define SHF_MIPS_STRINGS 0x80000000 ++#define SHF_MIPS_NOSTRIP 0x08000000 ++#define SHF_MIPS_LOCAL 0x04000000 ++#define SHF_MIPS_NAMES 0x02000000 ++#define SHF_MIPS_NODUPE 0x01000000 ++ ++ ++/* Symbol tables. */ ++ ++/* MIPS specific values for `st_other'. */ ++#define STO_MIPS_DEFAULT 0x0 ++#define STO_MIPS_INTERNAL 0x1 ++#define STO_MIPS_HIDDEN 0x2 ++#define STO_MIPS_PROTECTED 0x3 ++#define STO_MIPS_SC_ALIGN_UNUSED 0xff ++ ++/* MIPS specific values for `st_info'. */ ++#define STB_MIPS_SPLIT_COMMON 13 ++ ++/* Entries found in sections of type SHT_MIPS_GPTAB. */ ++ ++typedef union ++{ ++ struct ++ { ++ Elf32_Word gt_current_g_value; /* -G value used for compilation */ ++ Elf32_Word gt_unused; /* Not used */ ++ } gt_header; /* First entry in section */ ++ struct ++ { ++ Elf32_Word gt_g_value; /* If this value were used for -G */ ++ Elf32_Word gt_bytes; /* This many bytes would be used */ ++ } gt_entry; /* Subsequent entries in section */ ++} Elf32_gptab; ++ ++/* Entry found in sections of type SHT_MIPS_REGINFO. */ ++ ++typedef struct ++{ ++ Elf32_Word ri_gprmask; /* General registers used */ ++ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ ++ Elf32_Sword ri_gp_value; /* $gp register value */ ++} Elf32_RegInfo; ++ ++/* Entries found in sections of type SHT_MIPS_OPTIONS. */ ++ ++typedef struct ++{ ++ unsigned char kind; /* Determines interpretation of the ++ variable part of descriptor. */ ++ unsigned char size; /* Size of descriptor, including header. */ ++ Elf32_Section section; /* Section header index of section affected, ++ 0 for global options. */ ++ Elf32_Word info; /* Kind-specific information. */ ++} Elf_Options; ++ ++/* Values for `kind' field in Elf_Options. */ ++ ++#define ODK_NULL 0 /* Undefined. */ ++#define ODK_REGINFO 1 /* Register usage information. */ ++#define ODK_EXCEPTIONS 2 /* Exception processing options. */ ++#define ODK_PAD 3 /* Section padding options. */ ++#define ODK_HWPATCH 4 /* Hardware workarounds performed */ ++#define ODK_FILL 5 /* record the fill value used by the linker. */ ++#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ ++#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ ++#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ ++ ++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ ++ ++#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ ++#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ ++#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ ++#define OEX_SMM 0x20000 /* Force sequential memory mode? */ ++#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ ++#define OEX_PRECISEFP OEX_FPDBUG ++#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ ++ ++#define OEX_FPU_INVAL 0x10 ++#define OEX_FPU_DIV0 0x08 ++#define OEX_FPU_OFLO 0x04 ++#define OEX_FPU_UFLO 0x02 ++#define OEX_FPU_INEX 0x01 ++ ++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ ++ ++#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ ++#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ ++#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ ++#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ ++ ++#define OPAD_PREFIX 0x1 ++#define OPAD_POSTFIX 0x2 ++#define OPAD_SYMBOL 0x4 ++ ++/* Entry found in `.options' section. */ ++ ++typedef struct ++{ ++ Elf32_Word hwp_flags1; /* Extra flags. */ ++ Elf32_Word hwp_flags2; /* Extra flags. */ ++} Elf_Options_Hw; ++ ++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ ++ ++#define OHWA0_R4KEOP_CHECKED 0x00000001 ++#define OHWA1_R4KEOP_CLEAN 0x00000002 ++ ++/* MIPS relocs. */ ++ ++#define R_MIPS_NONE 0 /* No reloc */ ++#define R_MIPS_16 1 /* Direct 16 bit */ ++#define R_MIPS_32 2 /* Direct 32 bit */ ++#define R_MIPS_REL32 3 /* PC relative 32 bit */ ++#define R_MIPS_26 4 /* Direct 26 bit shifted */ ++#define R_MIPS_HI16 5 /* High 16 bit */ ++#define R_MIPS_LO16 6 /* Low 16 bit */ ++#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ ++#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ ++#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ ++#define R_MIPS_PC16 10 /* PC relative 16 bit */ ++#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ ++#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ ++ ++#define R_MIPS_SHIFT5 16 ++#define R_MIPS_SHIFT6 17 ++#define R_MIPS_64 18 ++#define R_MIPS_GOT_DISP 19 ++#define R_MIPS_GOT_PAGE 20 ++#define R_MIPS_GOT_OFST 21 ++#define R_MIPS_GOT_HI16 22 ++#define R_MIPS_GOT_LO16 23 ++#define R_MIPS_SUB 24 ++#define R_MIPS_INSERT_A 25 ++#define R_MIPS_INSERT_B 26 ++#define R_MIPS_DELETE 27 ++#define R_MIPS_HIGHER 28 ++#define R_MIPS_HIGHEST 29 ++#define R_MIPS_CALL_HI16 30 ++#define R_MIPS_CALL_LO16 31 ++#define R_MIPS_SCN_DISP 32 ++#define R_MIPS_REL16 33 ++#define R_MIPS_ADD_IMMEDIATE 34 ++#define R_MIPS_PJUMP 35 ++#define R_MIPS_RELGOT 36 ++#define R_MIPS_JALR 37 ++/* Keep this the last entry. */ ++#define R_MIPS_NUM 38 ++ ++/* Legal values for p_type field of Elf32_Phdr. */ ++ ++#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ ++#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ ++#define PT_MIPS_OPTIONS 0x70000002 ++ ++/* Special program header types. */ ++ ++#define PF_MIPS_LOCAL 0x10000000 ++ ++/* Legal values for d_tag field of Elf32_Dyn. */ ++ ++#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ ++#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ ++#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ ++#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ ++#define DT_MIPS_FLAGS 0x70000005 /* Flags */ ++#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ ++#define DT_MIPS_MSYM 0x70000007 ++#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ ++#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ ++#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ ++#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ ++#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ ++#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ ++#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ ++#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ ++#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ ++#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ ++#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ ++#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in ++ DT_MIPS_DELTA_CLASS. */ ++#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ ++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in ++ DT_MIPS_DELTA_INSTANCE. */ ++#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ ++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in ++ DT_MIPS_DELTA_RELOC. */ ++#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta ++ relocations refer to. */ ++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in ++ DT_MIPS_DELTA_SYM. */ ++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the ++ class declaration. */ ++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in ++ DT_MIPS_DELTA_CLASSSYM. */ ++#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ ++#define DT_MIPS_PIXIE_INIT 0x70000023 ++#define DT_MIPS_SYMBOL_LIB 0x70000024 ++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 ++#define DT_MIPS_LOCAL_GOTIDX 0x70000026 ++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 ++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 ++#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ ++#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ ++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b ++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ ++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve ++ function stored in GOT. */ ++#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added ++ by rld on dlopen() calls. */ ++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ ++#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ ++#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ ++#define DT_MIPS_NUM 0x32 ++ ++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ ++ ++#define RHF_NONE 0 /* No flags */ ++#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ ++#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ ++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ ++#define RHF_NO_MOVE (1 << 3) ++#define RHF_SGI_ONLY (1 << 4) ++#define RHF_GUARANTEE_INIT (1 << 5) ++#define RHF_DELTA_C_PLUS_PLUS (1 << 6) ++#define RHF_GUARANTEE_START_INIT (1 << 7) ++#define RHF_PIXIE (1 << 8) ++#define RHF_DEFAULT_DELAY_LOAD (1 << 9) ++#define RHF_REQUICKSTART (1 << 10) ++#define RHF_REQUICKSTARTED (1 << 11) ++#define RHF_CORD (1 << 12) ++#define RHF_NO_UNRES_UNDEF (1 << 13) ++#define RHF_RLD_ORDER_SAFE (1 << 14) ++ ++/* Entries found in sections of type SHT_MIPS_LIBLIST. */ ++ ++typedef struct ++{ ++ Elf32_Word l_name; /* Name (string table index) */ ++ Elf32_Word l_time_stamp; /* Timestamp */ ++ Elf32_Word l_checksum; /* Checksum */ ++ Elf32_Word l_version; /* Interface version */ ++ Elf32_Word l_flags; /* Flags */ ++} Elf32_Lib; ++ ++typedef struct ++{ ++ Elf64_Word l_name; /* Name (string table index) */ ++ Elf64_Word l_time_stamp; /* Timestamp */ ++ Elf64_Word l_checksum; /* Checksum */ ++ Elf64_Word l_version; /* Interface version */ ++ Elf64_Word l_flags; /* Flags */ ++} Elf64_Lib; ++ ++ ++/* Legal values for l_flags. */ ++ ++#define LL_NONE 0 ++#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ ++#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ ++#define LL_REQUIRE_MINOR (1 << 2) ++#define LL_EXPORTS (1 << 3) ++#define LL_DELAY_LOAD (1 << 4) ++#define LL_DELTA (1 << 5) ++ ++/* Entries found in sections of type SHT_MIPS_CONFLICT. */ ++ ++typedef Elf32_Addr Elf32_Conflict; ++ ++ ++/* HPPA specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ ++#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ ++#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ ++#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ ++#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch ++ prediction. */ ++#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ ++#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ ++ ++/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ ++ ++#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ ++#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ ++#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ ++ ++/* Additional section indeces. */ ++ ++#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared ++ symbols in ANSI C. */ ++#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ ++#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ ++#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ ++#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ ++#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ ++ ++#define STT_HP_OPAQUE (STT_LOOS + 0x1) ++#define STT_HP_STUB (STT_LOOS + 0x2) ++ ++/* HPPA relocs. */ ++ ++#define R_PARISC_NONE 0 /* No reloc. */ ++#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ ++#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ ++#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ ++#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ ++#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ ++#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ ++#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ ++#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ ++#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ ++#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ ++#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ ++#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ ++#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ ++#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ ++#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ ++#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ ++#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ ++#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ ++#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ ++#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ ++#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ ++#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ ++#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ ++#define R_PARISC_FPTR64 64 /* 64 bits function address. */ ++#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ ++#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ ++#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ ++#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ ++#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ ++#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ ++#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ ++#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ ++#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ ++#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ ++#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ ++#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ ++#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ ++#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ ++#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ ++#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LORESERVE 128 ++#define R_PARISC_COPY 128 /* Copy relocation. */ ++#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ ++#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ ++#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ ++#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ ++#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ ++#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ ++#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ ++#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ ++#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_HIRESERVE 255 ++ ++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PT_HP_TLS (PT_LOOS + 0x0) ++#define PT_HP_CORE_NONE (PT_LOOS + 0x1) ++#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) ++#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) ++#define PT_HP_CORE_COMM (PT_LOOS + 0x4) ++#define PT_HP_CORE_PROC (PT_LOOS + 0x5) ++#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) ++#define PT_HP_CORE_STACK (PT_LOOS + 0x7) ++#define PT_HP_CORE_SHM (PT_LOOS + 0x8) ++#define PT_HP_CORE_MMF (PT_LOOS + 0x9) ++#define PT_HP_PARALLEL (PT_LOOS + 0x10) ++#define PT_HP_FASTBIND (PT_LOOS + 0x11) ++#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) ++#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) ++#define PT_HP_STACK (PT_LOOS + 0x14) ++ ++#define PT_PARISC_ARCHEXT 0x70000000 ++#define PT_PARISC_UNWIND 0x70000001 ++ ++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PF_PARISC_SBP 0x08000000 ++ ++#define PF_HP_PAGE_SIZE 0x00100000 ++#define PF_HP_FAR_SHARED 0x00200000 ++#define PF_HP_NEAR_SHARED 0x00400000 ++#define PF_HP_CODE 0x01000000 ++#define PF_HP_MODIFY 0x02000000 ++#define PF_HP_LAZYSWAP 0x04000000 ++#define PF_HP_SBP 0x08000000 ++ ++ ++/* Alpha specific definitions. */ ++ ++/* Legal values for e_flags field of Elf64_Ehdr. */ ++ ++#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ ++#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ ++ ++/* Legal values for sh_type field of Elf64_Shdr. */ ++ ++/* These two are primerily concerned with ECOFF debugging info. */ ++#define SHT_ALPHA_DEBUG 0x70000001 ++#define SHT_ALPHA_REGINFO 0x70000002 ++ ++/* Legal values for sh_flags field of Elf64_Shdr. */ ++ ++#define SHF_ALPHA_GPREL 0x10000000 ++ ++/* Legal values for st_other field of Elf64_Sym. */ ++#define STO_ALPHA_NOPV 0x80 /* No PV required. */ ++#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ ++ ++/* Alpha relocs. */ ++ ++#define R_ALPHA_NONE 0 /* No reloc */ ++#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ ++#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ ++#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ ++#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ ++#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ ++#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ ++#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ ++#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ ++#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ ++#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ ++#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ ++#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ ++#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ ++#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ ++#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ ++#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ ++#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ ++#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ ++#define R_ALPHA_TLS_GD_HI 28 ++#define R_ALPHA_TLSGD 29 ++#define R_ALPHA_TLS_LDM 30 ++#define R_ALPHA_DTPMOD64 31 ++#define R_ALPHA_GOTDTPREL 32 ++#define R_ALPHA_DTPREL64 33 ++#define R_ALPHA_DTPRELHI 34 ++#define R_ALPHA_DTPRELLO 35 ++#define R_ALPHA_DTPREL16 36 ++#define R_ALPHA_GOTTPREL 37 ++#define R_ALPHA_TPREL64 38 ++#define R_ALPHA_TPRELHI 39 ++#define R_ALPHA_TPRELLO 40 ++#define R_ALPHA_TPREL16 41 ++/* Keep this the last entry. */ ++#define R_ALPHA_NUM 46 ++ ++/* Magic values of the LITUSE relocation addend. */ ++#define LITUSE_ALPHA_ADDR 0 ++#define LITUSE_ALPHA_BASE 1 ++#define LITUSE_ALPHA_BYTOFF 2 ++#define LITUSE_ALPHA_JSR 3 ++#define LITUSE_ALPHA_TLS_GD 4 ++#define LITUSE_ALPHA_TLS_LDM 5 ++ ++ ++/* PowerPC specific declarations */ ++ ++/* Values for Elf32/64_Ehdr.e_flags. */ ++#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ ++ ++/* Cygnus local bits below */ ++#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ ++#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib ++ flag */ ++ ++/* PowerPC relocations defined by the ABIs */ ++#define R_PPC_NONE 0 ++#define R_PPC_ADDR32 1 /* 32bit absolute address */ ++#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ ++#define R_PPC_ADDR16 3 /* 16bit absolute address */ ++#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ ++#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ ++#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ ++#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ ++#define R_PPC_ADDR14_BRTAKEN 8 ++#define R_PPC_ADDR14_BRNTAKEN 9 ++#define R_PPC_REL24 10 /* PC relative 26 bit */ ++#define R_PPC_REL14 11 /* PC relative 16 bit */ ++#define R_PPC_REL14_BRTAKEN 12 ++#define R_PPC_REL14_BRNTAKEN 13 ++#define R_PPC_GOT16 14 ++#define R_PPC_GOT16_LO 15 ++#define R_PPC_GOT16_HI 16 ++#define R_PPC_GOT16_HA 17 ++#define R_PPC_PLTREL24 18 ++#define R_PPC_COPY 19 ++#define R_PPC_GLOB_DAT 20 ++#define R_PPC_JMP_SLOT 21 ++#define R_PPC_RELATIVE 22 ++#define R_PPC_LOCAL24PC 23 ++#define R_PPC_UADDR32 24 ++#define R_PPC_UADDR16 25 ++#define R_PPC_REL32 26 ++#define R_PPC_PLT32 27 ++#define R_PPC_PLTREL32 28 ++#define R_PPC_PLT16_LO 29 ++#define R_PPC_PLT16_HI 30 ++#define R_PPC_PLT16_HA 31 ++#define R_PPC_SDAREL16 32 ++#define R_PPC_SECTOFF 33 ++#define R_PPC_SECTOFF_LO 34 ++#define R_PPC_SECTOFF_HI 35 ++#define R_PPC_SECTOFF_HA 36 ++ ++/* PowerPC relocations defined for the TLS access ABI. */ ++#define R_PPC_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ ++#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ ++#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ ++#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ ++#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ ++#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ ++#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ ++#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ ++#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ ++ ++/* Keep this the last entry. */ ++#define R_PPC_NUM 95 ++ ++/* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++#define R_PPC_EMB_NADDR32 101 ++#define R_PPC_EMB_NADDR16 102 ++#define R_PPC_EMB_NADDR16_LO 103 ++#define R_PPC_EMB_NADDR16_HI 104 ++#define R_PPC_EMB_NADDR16_HA 105 ++#define R_PPC_EMB_SDAI16 106 ++#define R_PPC_EMB_SDA2I16 107 ++#define R_PPC_EMB_SDA2REL 108 ++#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ ++#define R_PPC_EMB_MRKREF 110 ++#define R_PPC_EMB_RELSEC16 111 ++#define R_PPC_EMB_RELST_LO 112 ++#define R_PPC_EMB_RELST_HI 113 ++#define R_PPC_EMB_RELST_HA 114 ++#define R_PPC_EMB_BIT_FLD 115 ++#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ ++ ++/* Diab tool relocations. */ ++#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ ++#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ ++#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ ++#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ ++#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ ++#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ ++ ++/* This is a phony reloc to handle any old fashioned TOC16 references ++ that may still be in object files. */ ++#define R_PPC_TOC16 255 ++ ++ ++/* PowerPC64 relocations defined by the ABIs */ ++#define R_PPC64_NONE R_PPC_NONE ++#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ ++#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ ++#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ ++#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ ++#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ ++#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ ++#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ ++#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN ++#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN ++#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ ++#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ ++#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN ++#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN ++#define R_PPC64_GOT16 R_PPC_GOT16 ++#define R_PPC64_GOT16_LO R_PPC_GOT16_LO ++#define R_PPC64_GOT16_HI R_PPC_GOT16_HI ++#define R_PPC64_GOT16_HA R_PPC_GOT16_HA ++ ++#define R_PPC64_COPY R_PPC_COPY ++#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT ++#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT ++#define R_PPC64_RELATIVE R_PPC_RELATIVE ++ ++#define R_PPC64_UADDR32 R_PPC_UADDR32 ++#define R_PPC64_UADDR16 R_PPC_UADDR16 ++#define R_PPC64_REL32 R_PPC_REL32 ++#define R_PPC64_PLT32 R_PPC_PLT32 ++#define R_PPC64_PLTREL32 R_PPC_PLTREL32 ++#define R_PPC64_PLT16_LO R_PPC_PLT16_LO ++#define R_PPC64_PLT16_HI R_PPC_PLT16_HI ++#define R_PPC64_PLT16_HA R_PPC_PLT16_HA ++ ++#define R_PPC64_SECTOFF R_PPC_SECTOFF ++#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO ++#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI ++#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA ++#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ ++#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ ++#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ ++#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ ++#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ ++#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ ++#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ ++#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ ++#define R_PPC64_PLT64 45 /* doubleword64 L + A */ ++#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ ++#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ ++#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ ++#define R_PPC64_TOC 51 /* doubleword64 .TOC */ ++#define R_PPC64_PLTGOT16 52 /* half16* M + A */ ++#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ ++#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ ++#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ ++ ++#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ ++#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ ++#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ ++#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ ++#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ ++#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ ++#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ ++#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ ++#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ ++#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ ++#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ ++ ++/* PowerPC64 relocations defined for the TLS access ABI. */ ++#define R_PPC64_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ ++#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ ++#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ ++#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ ++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ ++#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ ++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ ++#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ ++#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ ++#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ ++#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ ++#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ ++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ ++#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ ++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ ++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ ++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ ++ ++/* Keep this the last entry. */ ++#define R_PPC64_NUM 107 ++ ++/* PowerPC64 specific values for the Dyn d_tag field. */ ++#define DT_PPC64_GLINK (DT_LOPROC + 0) ++#define DT_PPC64_NUM 1 ++ ++ ++/* ARM specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_ARM_RELEXEC 0x01 ++#define EF_ARM_HASENTRY 0x02 ++#define EF_ARM_INTERWORK 0x04 ++#define EF_ARM_APCS_26 0x08 ++#define EF_ARM_APCS_FLOAT 0x10 ++#define EF_ARM_PIC 0x20 ++#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ ++#define EF_ARM_NEW_ABI 0x80 ++#define EF_ARM_OLD_ABI 0x100 ++ ++/* Other constants defined in the ARM ELF spec. version B-01. */ ++/* NB. These conflict with values defined above. */ ++#define EF_ARM_SYMSARESORTED 0x04 ++#define EF_ARM_DYNSYMSUSESEGIDX 0x08 ++#define EF_ARM_MAPSYMSFIRST 0x10 ++#define EF_ARM_EABIMASK 0XFF000000 ++ ++#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) ++#define EF_ARM_EABI_UNKNOWN 0x00000000 ++#define EF_ARM_EABI_VER1 0x01000000 ++#define EF_ARM_EABI_VER2 0x02000000 ++ ++/* Additional symbol types for Thumb */ ++#define STT_ARM_TFUNC 0xd ++ ++/* ARM-specific values for sh_flags */ ++#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ ++#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined ++ in the input to a link step */ ++ ++/* ARM-specific program header flags */ ++#define PF_ARM_SB 0x10000000 /* Segment contains the location ++ addressed by the static base */ ++ ++/* ARM relocs. */ ++#define R_ARM_NONE 0 /* No reloc */ ++#define R_ARM_PC24 1 /* PC relative 26 bit branch */ ++#define R_ARM_ABS32 2 /* Direct 32 bit */ ++#define R_ARM_REL32 3 /* PC relative 32 bit */ ++#define R_ARM_PC13 4 ++#define R_ARM_ABS16 5 /* Direct 16 bit */ ++#define R_ARM_ABS12 6 /* Direct 12 bit */ ++#define R_ARM_THM_ABS5 7 ++#define R_ARM_ABS8 8 /* Direct 8 bit */ ++#define R_ARM_SBREL32 9 ++#define R_ARM_THM_PC22 10 ++#define R_ARM_THM_PC8 11 ++#define R_ARM_AMP_VCALL9 12 ++#define R_ARM_SWI24 13 ++#define R_ARM_THM_SWI8 14 ++#define R_ARM_XPC25 15 ++#define R_ARM_THM_XPC22 16 ++#define R_ARM_COPY 20 /* Copy symbol at runtime */ ++#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ ++#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ ++#define R_ARM_RELATIVE 23 /* Adjust by program base */ ++#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ ++#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ ++#define R_ARM_GOT32 26 /* 32 bit GOT entry */ ++#define R_ARM_PLT32 27 /* 32 bit PLT address */ ++#define R_ARM_ALU_PCREL_7_0 32 ++#define R_ARM_ALU_PCREL_15_8 33 ++#define R_ARM_ALU_PCREL_23_15 34 ++#define R_ARM_LDR_SBREL_11_0 35 ++#define R_ARM_ALU_SBREL_19_12 36 ++#define R_ARM_ALU_SBREL_27_20 37 ++#define R_ARM_GNU_VTENTRY 100 ++#define R_ARM_GNU_VTINHERIT 101 ++#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ ++#define R_ARM_THM_PC9 103 /* thumb conditional branch */ ++#define R_ARM_RXPC25 249 ++#define R_ARM_RSBREL32 250 ++#define R_ARM_THM_RPC22 251 ++#define R_ARM_RREL32 252 ++#define R_ARM_RABS22 253 ++#define R_ARM_RPC24 254 ++#define R_ARM_RBASE 255 ++/* Keep this the last entry. */ ++#define R_ARM_NUM 256 ++ ++/* IA-64 specific declarations. */ ++ ++/* Processor specific flags for the Ehdr e_flags field. */ ++#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ ++#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ ++#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ ++#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ ++ ++/* Processor specific flags for the Phdr p_flags field. */ ++#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ ++#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ ++ ++/* Processor specific flags for the Shdr sh_flags field. */ ++#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ ++#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Dyn d_tag field. */ ++#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) ++#define DT_IA_64_NUM 1 ++ ++/* IA-64 relocations. */ ++#define R_IA64_NONE 0x00 /* none */ ++#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ ++#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ ++#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ ++#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ ++#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ ++#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ ++#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ ++#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ ++#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ ++#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ ++#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ ++#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ ++#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ ++#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ ++#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ ++#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ ++#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ ++#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ ++#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ ++#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ ++#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ ++#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ ++#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ ++#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ ++#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ ++#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ ++#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ ++#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ ++#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ ++#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ ++#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ ++#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ ++#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ ++#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ ++#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ ++#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ ++#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ ++#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ ++#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ ++#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ ++#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ ++#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ ++#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ ++#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ ++#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ ++#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ ++#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ ++#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ ++#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ ++#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ ++#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ ++#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ ++#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ ++#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ ++#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ ++#define R_IA64_COPY 0x84 /* copy relocation */ ++#define R_IA64_SUB 0x85 /* Addend and symbol difference */ ++#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ ++#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ ++#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ ++#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ ++#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ ++#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ ++#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ ++#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ ++#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ ++#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ ++#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ ++#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ ++#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ ++#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ ++#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ ++#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ ++ ++/* SH specific declarations */ ++ ++/* SH relocs. */ ++#define R_SH_NONE 0 ++#define R_SH_DIR32 1 ++#define R_SH_REL32 2 ++#define R_SH_DIR8WPN 3 ++#define R_SH_IND12W 4 ++#define R_SH_DIR8WPL 5 ++#define R_SH_DIR8WPZ 6 ++#define R_SH_DIR8BP 7 ++#define R_SH_DIR8W 8 ++#define R_SH_DIR8L 9 ++#define R_SH_SWITCH16 25 ++#define R_SH_SWITCH32 26 ++#define R_SH_USES 27 ++#define R_SH_COUNT 28 ++#define R_SH_ALIGN 29 ++#define R_SH_CODE 30 ++#define R_SH_DATA 31 ++#define R_SH_LABEL 32 ++#define R_SH_SWITCH8 33 ++#define R_SH_GNU_VTINHERIT 34 ++#define R_SH_GNU_VTENTRY 35 ++#define R_SH_TLS_GD_32 144 ++#define R_SH_TLS_LD_32 145 ++#define R_SH_TLS_LDO_32 146 ++#define R_SH_TLS_IE_32 147 ++#define R_SH_TLS_LE_32 148 ++#define R_SH_TLS_DTPMOD32 149 ++#define R_SH_TLS_DTPOFF32 150 ++#define R_SH_TLS_TPOFF32 151 ++#define R_SH_GOT32 160 ++#define R_SH_PLT32 161 ++#define R_SH_COPY 162 ++#define R_SH_GLOB_DAT 163 ++#define R_SH_JMP_SLOT 164 ++#define R_SH_RELATIVE 165 ++#define R_SH_GOTOFF 166 ++#define R_SH_GOTPC 167 ++/* Keep this the last entry. */ ++#define R_SH_NUM 256 ++ ++/* Additional s390 relocs */ ++ ++#define R_390_NONE 0 /* No reloc. */ ++#define R_390_8 1 /* Direct 8 bit. */ ++#define R_390_12 2 /* Direct 12 bit. */ ++#define R_390_16 3 /* Direct 16 bit. */ ++#define R_390_32 4 /* Direct 32 bit. */ ++#define R_390_PC32 5 /* PC relative 32 bit. */ ++#define R_390_GOT12 6 /* 12 bit GOT offset. */ ++#define R_390_GOT32 7 /* 32 bit GOT offset. */ ++#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ ++#define R_390_COPY 9 /* Copy symbol at runtime. */ ++#define R_390_GLOB_DAT 10 /* Create GOT entry. */ ++#define R_390_JMP_SLOT 11 /* Create PLT entry. */ ++#define R_390_RELATIVE 12 /* Adjust by program base. */ ++#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ ++#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ ++#define R_390_GOT16 15 /* 16 bit GOT offset. */ ++#define R_390_PC16 16 /* PC relative 16 bit. */ ++#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ ++#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ ++#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ ++#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ ++#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ ++#define R_390_64 22 /* Direct 64 bit. */ ++#define R_390_PC64 23 /* PC relative 64 bit. */ ++#define R_390_GOT64 24 /* 64 bit GOT offset. */ ++#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ ++#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ ++#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ ++#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ ++#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ ++#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ ++#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ ++#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ ++#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ ++#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ ++#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ ++#define R_390_TLS_GDCALL 38 /* Tag for function call in general ++ dynamic TLS code. */ ++#define R_390_TLS_LDCALL 39 /* Tag for function call in local ++ dynamic TLS code. */ ++#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ ++#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ ++#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS ++ block. */ ++ ++/* Keep this the last entry. */ ++#define R_390_NUM 57 ++ ++/* CRIS relocations. */ ++#define R_CRIS_NONE 0 ++#define R_CRIS_8 1 ++#define R_CRIS_16 2 ++#define R_CRIS_32 3 ++#define R_CRIS_8_PCREL 4 ++#define R_CRIS_16_PCREL 5 ++#define R_CRIS_32_PCREL 6 ++#define R_CRIS_GNU_VTINHERIT 7 ++#define R_CRIS_GNU_VTENTRY 8 ++#define R_CRIS_COPY 9 ++#define R_CRIS_GLOB_DAT 10 ++#define R_CRIS_JUMP_SLOT 11 ++#define R_CRIS_RELATIVE 12 ++#define R_CRIS_16_GOT 13 ++#define R_CRIS_32_GOT 14 ++#define R_CRIS_16_GOTPLT 15 ++#define R_CRIS_32_GOTPLT 16 ++#define R_CRIS_32_GOTREL 17 ++#define R_CRIS_32_PLT_GOTREL 18 ++#define R_CRIS_32_PLT_PCREL 19 ++ ++#define R_CRIS_NUM 20 ++ ++/* AMD x86-64 relocations. */ ++#define R_X86_64_NONE 0 /* No reloc */ ++#define R_X86_64_64 1 /* Direct 64 bit */ ++#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ ++#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ ++#define R_X86_64_PLT32 4 /* 32 bit PLT address */ ++#define R_X86_64_COPY 5 /* Copy symbol at runtime */ ++#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ ++#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ ++#define R_X86_64_RELATIVE 8 /* Adjust by program base */ ++#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative ++ offset to GOT */ ++#define R_X86_64_32 10 /* Direct 32 bit zero extended */ ++#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ ++#define R_X86_64_16 12 /* Direct 16 bit zero extended */ ++#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ ++#define R_X86_64_8 14 /* Direct 8 bit sign extended */ ++#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ ++#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ ++#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ ++#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ ++#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset ++ to two GOT entries for GD symbol */ ++#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset ++ to two GOT entries for LD symbol */ ++#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ ++#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset ++ to GOT entry for IE symbol */ ++#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ ++ ++#define R_X86_64_NUM 24 ++ ++__END_DECLS ++ ++#endif /* elf.h */ + + #include "elfconfig.h" + +@@ -185,3 +2631,4 @@ + void fatal(const char *fmt, ...); + void warn(const char *fmt, ...); + void merror(const char *fmt, ...); ++ +diff -Nur linux-3.11.5.orig/scripts/mod/sumversion.c linux-3.11.5/scripts/mod/sumversion.c +--- linux-3.11.5.orig/scripts/mod/sumversion.c 2013-10-14 03:14:45.000000000 +0200 ++++ linux-3.11.5/scripts/mod/sumversion.c 2013-10-16 18:09:31.000000000 +0200 +@@ -1,4 +1,4 @@ +-#include ++/* #include */ + #ifdef __sun__ + #include + #else +diff -Nur linux-3.11.5.orig/tools/include/tools/linux_types.h linux-3.11.5/tools/include/tools/linux_types.h +--- linux-3.11.5.orig/tools/include/tools/linux_types.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.11.5/tools/include/tools/linux_types.h 2013-10-16 18:09:31.000000000 +0200 +@@ -0,0 +1,22 @@ ++#ifndef __LINUX_TYPES_H ++#define __LINUX_TYPES_H ++ ++#include ++ ++typedef uint8_t __u8; ++typedef uint8_t __be8; ++typedef uint8_t __le8; ++ ++typedef uint16_t __u16; ++typedef uint16_t __be16; ++typedef uint16_t __le16; ++ ++typedef uint32_t __u32; ++typedef uint32_t __be32; ++typedef uint32_t __le32; ++ ++typedef uint64_t __u64; ++typedef uint64_t __be64; ++typedef uint64_t __le64; ++ ++#endif diff --git a/target/linux/patches/3.10.30/solidrun-cubox-i.patch b/target/linux/patches/3.10.30/solidrun-cubox-i.patch new file mode 100644 index 000000000..beaa71b4e --- /dev/null +++ b/target/linux/patches/3.10.30/solidrun-cubox-i.patch @@ -0,0 +1,584365 @@ +diff -Nur linux-3.10.30/Documentation/ABI/testing/sysfs-class-mtd linux-3.10.30-cubox-i/Documentation/ABI/testing/sysfs-class-mtd +--- linux-3.10.30/Documentation/ABI/testing/sysfs-class-mtd 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/ABI/testing/sysfs-class-mtd 2014-03-08 20:32:51.000000000 +0100 +@@ -104,7 +104,7 @@ + One of the following ASCII strings, representing the device + type: + +- absent, ram, rom, nor, nand, dataflash, ubi, unknown ++ absent, ram, rom, nor, nand, mlc-nand, dataflash, ubi, unknown + + What: /sys/class/mtd/mtdX/writesize + Date: April 2009 +@@ -128,9 +128,8 @@ + Contact: linux-mtd@lists.infradead.org + Description: + Maximum number of bit errors that the device is capable of +- correcting within each region covering an ecc step. This will +- always be a non-negative integer. Note that some devices will +- have multiple ecc steps within each writesize region. ++ correcting within each region covering an ECC step (see ++ ecc_step_size). This will always be a non-negative integer. + + In the case of devices lacking any ECC capability, it is 0. + +@@ -173,3 +172,15 @@ + This is generally applicable only to NAND flash devices with ECC + capability. It is ignored on devices lacking ECC capability; + i.e., devices for which ecc_strength is zero. ++ ++What: /sys/class/mtd/mtdX/ecc_step_size ++Date: May 2013 ++KernelVersion: 3.10 ++Contact: linux-mtd@lists.infradead.org ++Description: ++ The size of a single region covered by ECC, known as the ECC ++ step. Devices may have several equally sized ECC steps within ++ each writesize region. ++ ++ It will always be a non-negative integer. In the case of ++ devices lacking any ECC capability, it is 0. +diff -Nur linux-3.10.30/Documentation/DocBook/mtdnand.tmpl linux-3.10.30-cubox-i/Documentation/DocBook/mtdnand.tmpl +--- linux-3.10.30/Documentation/DocBook/mtdnand.tmpl 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/DocBook/mtdnand.tmpl 2014-03-08 20:32:51.000000000 +0100 +@@ -1222,10 +1222,6 @@ + #define NAND_BBT_VERSION 0x00000100 + /* Create a bbt if none axists */ + #define NAND_BBT_CREATE 0x00000200 +-/* Search good / bad pattern through all pages of a block */ +-#define NAND_BBT_SCANALLPAGES 0x00000400 +-/* Scan block empty during good / bad block scan */ +-#define NAND_BBT_SCANEMPTY 0x00000800 + /* Write bbt if neccecary */ + #define NAND_BBT_WRITE 0x00001000 + /* Read and write back block contents when writing bbt */ +diff -Nur linux-3.10.30/Documentation/arm/small_task_packing.txt linux-3.10.30-cubox-i/Documentation/arm/small_task_packing.txt +--- linux-3.10.30/Documentation/arm/small_task_packing.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/arm/small_task_packing.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,136 @@ ++Small Task Packing in the big.LITTLE MP Reference Patch Set ++ ++What is small task packing? ++---- ++Simply that the scheduler will fit as many small tasks on a single CPU ++as possible before using other CPUs. A small task is defined as one ++whose tracked load is less than 90% of a NICE_0 task. This is a change ++from the usual behavior since the scheduler will normally use an idle ++CPU for a waking task unless that task is considered cache hot. ++ ++ ++How is it implemented? ++---- ++Since all small tasks must wake up relatively frequently, the main ++requirement for packing small tasks is to select a partly-busy CPU when ++waking rather than looking for an idle CPU. We use the tracked load of ++the CPU runqueue to determine how heavily loaded each CPU is and the ++tracked load of the task to determine if it will fit on the CPU. We ++always start with the lowest-numbered CPU in a sched domain and stop ++looking when we find a CPU with enough space for the task. ++ ++Some further tweaks are necessary to suppress load balancing when the ++CPU is not fully loaded, otherwise the scheduler attempts to spread ++tasks evenly across the domain. ++ ++ ++How does it interact with the HMP patches? ++---- ++Firstly, we only enable packing on the little domain. The intent is that ++the big domain is intended to spread tasks amongst the available CPUs ++one-task-per-CPU. The little domain however is attempting to use as ++little power as possible while servicing its tasks. ++ ++Secondly, since we offload big tasks onto little CPUs in order to try ++to devote one CPU to each task, we have a threshold above which we do ++not try to pack a task and instead will select an idle CPU if possible. ++This maintains maximum forward progress for busy tasks temporarily ++demoted from big CPUs. ++ ++ ++Can the behaviour be tuned? ++---- ++Yes, the load level of a 'full' CPU can be easily modified in the source ++and is exposed through sysfs as /sys/kernel/hmp/packing_limit to be ++changed at runtime. The presence of the packing behaviour is controlled ++by CONFIG_SCHED_HMP_LITTLE_PACKING and can be disabled at run-time ++using /sys/kernel/hmp/packing_enable. ++The definition of a small task is hard coded as 90% of NICE_0_LOAD ++and cannot be modified at run time. ++ ++ ++Why do I need to tune it? ++---- ++The optimal configuration is likely to be different depending upon the ++design and manufacturing of your SoC. ++ ++In the main, there are two system effects from enabling small task ++packing. ++ ++1. CPU operating point may increase ++2. wakeup latency of tasks may be increased ++ ++There are also likely to be secondary effects from loading one CPU ++rather than spreading tasks. ++ ++Note that all of these system effects are dependent upon the workload ++under consideration. ++ ++ ++CPU Operating Point ++---- ++The primary impact of loading one CPU with a number of light tasks is to ++increase the compute requirement of that CPU since it is no longer idle ++as often. Increased compute requirement causes an increase in the ++frequency of the CPU through CPUfreq. ++ ++Consider this example: ++We have a system with 3 CPUs which can operate at any frequency between ++350MHz and 1GHz. The system has 6 tasks which would each produce 10% ++load at 1GHz. The scheduler has frequency-invariant load scaling ++enabled. Our DVFS governor aims for 80% utilization at the chosen ++frequency. ++ ++Without task packing, these tasks will be spread out amongst all CPUs ++such that each has 2. This will produce roughly 20% system load, and ++the frequency of the package will remain at 350MHz. ++ ++With task packing set to the default packing_limit, all of these tasks ++will sit on one CPU and require a package frequency of ~750MHz to reach ++80% utilization. (0.75 = 0.6 * 0.8). ++ ++When a package operates on a single frequency domain, all CPUs in that ++package share frequency and voltage. ++ ++Depending upon the SoC implementation there can be a significant amount ++of energy lost to leakage from idle CPUs. The decision about how ++loaded a CPU must be to be considered 'full' is therefore controllable ++through sysfs (sys/kernel/hmp/packing_limit) and directly in the code. ++ ++Continuing the example, lets set packing_limit to 450 which means we ++will pack tasks until the total load of all running tasks >= 450. In ++practise, this is very similar to a 55% idle 1Ghz CPU. ++ ++Now we are only able to place 4 tasks on CPU0, and two will overflow ++onto CPU1. CPU0 will have a load of 40% and CPU1 will have a load of ++20%. In order to still hit 80% utilization, CPU0 now only needs to ++operate at (0.4*0.8=0.32) 320MHz, which means that the lowest operating ++point will be selected, the same as in the non-packing case, except that ++now CPU2 is no longer needed and can be power-gated. ++ ++In order to use less energy, the saving from power-gating CPU2 must be ++more than the energy spent running CPU0 for the extra cycles. This ++depends upon the SoC implementation. ++ ++This is obviously a contrived example requiring all the tasks to ++be runnable at the same time, but it illustrates the point. ++ ++ ++Wakeup Latency ++---- ++This is an unavoidable consequence of trying to pack tasks together ++rather than giving them a CPU each. If you cannot find an acceptable ++level of wakeup latency, you should turn packing off. ++ ++Cyclictest is a good test application for determining the added latency ++when configuring packing. ++ ++ ++Why is it turned off for the VersatileExpress V2P_CA15A7 CoreTile? ++---- ++Simply, this core tile only has power gating for the whole A7 package. ++When small task packing is enabled, all our low-energy use cases ++normally fit onto one A7 CPU. We therefore end up with 2 mostly-idle ++CPUs and one mostly-busy CPU. This decreases the amount of time ++available where the whole package is idle and can be turned off. ++ +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/arm/cci.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/arm/cci.txt +--- linux-3.10.30/Documentation/devicetree/bindings/arm/cci.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/arm/cci.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,172 @@ ++======================================================= ++ARM CCI cache coherent interconnect binding description ++======================================================= ++ ++ARM multi-cluster systems maintain intra-cluster coherency through a ++cache coherent interconnect (CCI) that is capable of monitoring bus ++transactions and manage coherency, TLB invalidations and memory barriers. ++ ++It allows snooping and distributed virtual memory message broadcast across ++clusters, through memory mapped interface, with a global control register ++space and multiple sets of interface control registers, one per slave ++interface. ++ ++Bindings for the CCI node follow the ePAPR standard, available from: ++ ++www.power.org/documentation/epapr-version-1-1/ ++ ++with the addition of the bindings described in this document which are ++specific to ARM. ++ ++* CCI interconnect node ++ ++ Description: Describes a CCI cache coherent Interconnect component ++ ++ Node name must be "cci". ++ Node's parent must be the root node /, and the address space visible ++ through the CCI interconnect is the same as the one seen from the ++ root node (ie from CPUs perspective as per DT standard). ++ Every CCI node has to define the following properties: ++ ++ - compatible ++ Usage: required ++ Value type: ++ Definition: must be set to ++ "arm,cci-400" ++ ++ - reg ++ Usage: required ++ Value type: ++ Definition: A standard property. Specifies base physical ++ address of CCI control registers common to all ++ interfaces. ++ ++ - ranges: ++ Usage: required ++ Value type: ++ Definition: A standard property. Follow rules in the ePAPR for ++ hierarchical bus addressing. CCI interfaces ++ addresses refer to the parent node addressing ++ scheme to declare their register bases. ++ ++ CCI interconnect node can define the following child nodes: ++ ++ - CCI control interface nodes ++ ++ Node name must be "slave-if". ++ Parent node must be CCI interconnect node. ++ ++ A CCI control interface node must contain the following ++ properties: ++ ++ - compatible ++ Usage: required ++ Value type: ++ Definition: must be set to ++ "arm,cci-400-ctrl-if" ++ ++ - interface-type: ++ Usage: required ++ Value type: ++ Definition: must be set to one of {"ace", "ace-lite"} ++ depending on the interface type the node ++ represents. ++ ++ - reg: ++ Usage: required ++ Value type: ++ Definition: the base address and size of the ++ corresponding interface programming ++ registers. ++ ++* CCI interconnect bus masters ++ ++ Description: masters in the device tree connected to a CCI port ++ (inclusive of CPUs and their cpu nodes). ++ ++ A CCI interconnect bus master node must contain the following ++ properties: ++ ++ - cci-control-port: ++ Usage: required ++ Value type: ++ Definition: a phandle containing the CCI control interface node ++ the master is connected to. ++ ++Example: ++ ++ cpus { ++ #size-cells = <0>; ++ #address-cells = <1>; ++ ++ CPU0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ cci-control-port = <&cci_control1>; ++ reg = <0x0>; ++ }; ++ ++ CPU1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ cci-control-port = <&cci_control1>; ++ reg = <0x1>; ++ }; ++ ++ CPU2: cpu@100 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a7"; ++ cci-control-port = <&cci_control2>; ++ reg = <0x100>; ++ }; ++ ++ CPU3: cpu@101 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a7"; ++ cci-control-port = <&cci_control2>; ++ reg = <0x101>; ++ }; ++ ++ }; ++ ++ dma0: dma@3000000 { ++ compatible = "arm,pl330", "arm,primecell"; ++ cci-control-port = <&cci_control0>; ++ reg = <0x0 0x3000000 0x0 0x1000>; ++ interrupts = <10>; ++ #dma-cells = <1>; ++ #dma-channels = <8>; ++ #dma-requests = <32>; ++ }; ++ ++ cci@2c090000 { ++ compatible = "arm,cci-400"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x0 0x2c090000 0 0x1000>; ++ ranges = <0x0 0x0 0x2c090000 0x6000>; ++ ++ cci_control0: slave-if@1000 { ++ compatible = "arm,cci-400-ctrl-if"; ++ interface-type = "ace-lite"; ++ reg = <0x1000 0x1000>; ++ }; ++ ++ cci_control1: slave-if@4000 { ++ compatible = "arm,cci-400-ctrl-if"; ++ interface-type = "ace"; ++ reg = <0x4000 0x1000>; ++ }; ++ ++ cci_control2: slave-if@5000 { ++ compatible = "arm,cci-400-ctrl-if"; ++ interface-type = "ace"; ++ reg = <0x5000 0x1000>; ++ }; ++ }; ++ ++This CCI node corresponds to a CCI component whose control registers sits ++at address 0x000000002c090000. ++CCI slave interface @0x000000002c091000 is connected to dma controller dma0. ++CCI slave interface @0x000000002c094000 is connected to CPUs {CPU0, CPU1}; ++CCI slave interface @0x000000002c095000 is connected to CPUs {CPU2, CPU3}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt +--- linux-3.10.30/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,64 @@ ++Freescale Busfreq driver ++ ++It is a generic driver that manages the frequency of the DDR, AHB and AXI buses in the iMX6x architecture. ++It works for both SMP and UP systems and for both DDR3 and LPDDR2 memory types. ++ ++Required properties are listed below: ++- compatible: should be "fsl,imx6_busfreq" ++- clocks: Lists the various clocks used by the busfreq driver ++- interrupts - Lists the interrupts used by the busfreq driver. This is needed only for SMP architecutre. ++- fsl,max_ddr_freq - The max ddr freq for this chip ++ ++Examples: ++For SOC imx6q.dtsi: ++ busfreq { /* BUSFREQ */ ++ compatible = "fsl,imx6_busfreq"; ++ clocks = <&clks 171>, <&clks 6>, <&clks 11>, <&clks 104>, <&clks 172>, <&clks 58>, ++ <&clks 18>, <&clks 60>, <&clks 20>, <&clks 3>; ++ clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", "periph", ++ "periph_pre", "periph_clk2", "periph_clk2_sel", "osc"; ++ interrupts = <0 107 0x04>, <0 112 0x4>, <0 113 0x4>, <0 114 0x4>; ++ interrupt-names = "irq_busfreq_0", "irq_busfreq_1", "irq_busfreq_2", "irq_busfreq_3"; ++ fsl,max_ddr_freq = <528000000>; ++ }; ++ ++The Freescale Busfreq driver supports the following setpoints for the DDR freq: ++enum bus_freq_mode { ++ BUS_FREQ_HIGH, -> The max freq the SOC supports ++ BUS_FREQ_MED, -> Medium setpoint (ex 400MHz for DDR3 when the max is 528MHz) ++ BUS_FREQ_AUDIO, -> Audio playback freq (50MHz) ++ BUS_FREQ_LOW, -> Low power IDLE freq (24MHz) ++}; ++ ++Currently the Freescale Busfreq driver implementation requires drivers to call the following APIs: ++1. request_bus_freq(enum bus_freq_mode): ++ The driver is requesting the system and ddr freq to be set to the requested value. The driver should call this ++ API before it even enables its clocks. ++ ++2. release_bus_freq(enum bus_freq_mode): ++ The driver no longer needs the system and ddr freq at the required value. The driver should call this API after ++ its work is done and it has disabled its clocks. ++ ++Examples: ++In the IPU driver, the requesting and releasing of the required bus frequency is tied into the runtime PM implementation: ++ ++int ipu_runtime_suspend(struct device *dev) ++{ ++ release_bus_freq(BUS_FREQ_HIGH); ++ dev_dbg(dev, "ipu busfreq high release.\n"); ++ ++ return 0; ++} ++ ++int ipu_runtime_resume(struct device *dev) ++{ ++ request_bus_freq(BUS_FREQ_HIGH); ++ dev_dbg(dev, "ipu busfreq high requst.\n"); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops ipu_pm_ops = { ++ SET_RUNTIME_PM_OPS(ipu_runtime_suspend, ipu_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(ipu_suspend, ipu_resume) ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/arm/imx/gpc.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/arm/imx/gpc.txt +--- linux-3.10.30/Documentation/devicetree/bindings/arm/imx/gpc.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/arm/imx/gpc.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,20 @@ ++Freescale imx GPC bindings ++ ++Optional properties: ++- fsl,cpu_pupscr_sw2iso: for powering up CPU, number of 32K clock cycle PGC will wait before negating isolation signal. ++- fsl,cpu_pupscr_sw: for powering up CPU, number of 32K clock cycle PGC will wait before asserting isolation signal. ++- fsl,cpu_pdnscr_iso2sw: for powering down CPU, number of ipg clock cycle PGC will wait before negating isolation signal. ++- fsl,cpu_pdnscr_iso: for powering down CPU, number of ipg clock cycle PGC will wait before asserting isolation signal. ++ ++These properties are for adjusting the GPC PGC CPU power up/down setting, if there is no such property in dts, then default ++value in GPC PGC registers will be used. ++ ++ ++Example: ++ ++ &gpc { ++ fsl,cpu_pupscr_sw2iso = <0xf>; ++ fsl,cpu_pupscr_sw = <0xf>; ++ fsl,cpu_pdnscr_iso2sw = <0x1>; ++ fsl,cpu_pdnscr_iso = <0x1>; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/arm/pmu.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/arm/pmu.txt +--- linux-3.10.30/Documentation/devicetree/bindings/arm/pmu.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/arm/pmu.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -16,6 +16,9 @@ + "arm,arm1176-pmu" + "arm,arm1136-pmu" + - interrupts : 1 combined interrupt or 1 per core. ++- cluster : a phandle to the cluster to which it belongs ++ If there are more than one cluster with same CPU type ++ then there should be separate PMU nodes per cluster. + + Example: + +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/arm/rtsm-dcscb.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/arm/rtsm-dcscb.txt +--- linux-3.10.30/Documentation/devicetree/bindings/arm/rtsm-dcscb.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/arm/rtsm-dcscb.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,19 @@ ++ARM Dual Cluster System Configuration Block ++------------------------------------------- ++ ++The Dual Cluster System Configuration Block (DCSCB) provides basic ++functionality for controlling clocks, resets and configuration pins in ++the Dual Cluster System implemented by the Real-Time System Model (RTSM). ++ ++Required properties: ++ ++- compatible : should be "arm,rtsm,dcscb" ++ ++- reg : physical base address and the size of the registers window ++ ++Example: ++ ++ dcscb@60000000 { ++ compatible = "arm,rtsm,dcscb"; ++ reg = <0x60000000 0x1000>; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/bus/imx-weim.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/bus/imx-weim.txt +--- linux-3.10.30/Documentation/devicetree/bindings/bus/imx-weim.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/bus/imx-weim.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,49 @@ ++Device tree bindings for i.MX Wireless External Interface Module (WEIM) ++ ++The term "wireless" does not imply that the WEIM is literally an interface ++without wires. It simply means that this module was originally designed for ++wireless and mobile applications that use low-power technology. ++ ++The actual devices are instantiated from the child nodes of a WEIM node. ++ ++Required properties: ++ ++ - compatible: Should be set to "fsl,imx6q-weim" ++ - reg: A resource specifier for the register space ++ (see the example below) ++ - clocks: the clock, see the example below. ++ - #address-cells: Must be set to 2 to allow memory address translation ++ - #size-cells: Must be set to 1 to allow CS address passing ++ - ranges: Must be set up to reflect the memory layout with four ++ integer values for each chip-select line in use: ++ ++ 0 ++ ++Timing property for child nodes. It is mandatory, not optional. ++ ++ - fsl,weim-cs-timing: The timing array, contains 6 timing values for the ++ child node. We can get the CS index from the child ++ node's "reg" property. This property contains the values ++ for the registers EIM_CSnGCR1, EIM_CSnGCR2, EIM_CSnRCR1, ++ EIM_CSnRCR2, EIM_CSnWCR1, EIM_CSnWCR2 in this order. ++ ++Example for an imx6q-sabreauto board, the NOR flash connected to the WEIM: ++ ++ weim: weim@021b8000 { ++ compatible = "fsl,imx6q-weim"; ++ reg = <0x021b8000 0x4000>; ++ clocks = <&clks 196>; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0 0 0x08000000 0x08000000>; ++ ++ nor@0,0 { ++ compatible = "cfi-flash"; ++ reg = <0 0 0x02000000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ bank-width = <2>; ++ fsl,weim-cs-timing = <0x00620081 0x00000001 0x1c022000 ++ 0x0000c000 0x1404a38e 0x00000000>; ++ }; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/clock/imx6q-clock.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/clock/imx6q-clock.txt +--- linux-3.10.30/Documentation/devicetree/bindings/clock/imx6q-clock.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/clock/imx6q-clock.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -89,8 +89,6 @@ + gpu3d_shader 74 + ipu1_podf 75 + ipu2_podf 76 +- ldb_di0_podf 77 +- ldb_di1_podf 78 + ipu1_di0_pre 79 + ipu1_di1_pre 80 + ipu2_di0_pre 81 +@@ -208,6 +206,29 @@ + pll4_post_div 193 + pll5_post_div 194 + pll5_video_div 195 ++ eim_slow 196 ++ spdif 197 ++ cko2_sel 198 ++ cko2_podf 199 ++ cko2 200 ++ cko 201 ++ vdoa 202 ++ gpt_3m 203 ++ video_27m 204 ++ ldb_di0_div_7 205 ++ ldb_di1_div_7 206 ++ ldb_di0_div_sel 207 ++ ldb_di1_div_sel 208 ++ pll4_audio_div 209 ++ lvds1_sel 210 ++ lvds1_in 211 ++ lvds1_out 212 ++ caam_mem 213 ++ caam_aclk 214 ++ caam_ipg 215 ++ epit1 216 ++ epit2 217 ++ tzasc2 218 + + Examples: + +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/clock/imx6sl-clock.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/clock/imx6sl-clock.txt +--- linux-3.10.30/Documentation/devicetree/bindings/clock/imx6sl-clock.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/clock/imx6sl-clock.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,10 @@ ++* Clock bindings for Freescale i.MX6 SoloLite ++ ++Required properties: ++- compatible: Should be "fsl,imx6sl-ccm" ++- reg: Address and length of the register set ++- #clock-cells: Should be <1> ++ ++The clock consumer should specify the desired clock by having the clock ++ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6sl-clock.h ++for the full list of i.MX6 SoloLite clock IDs. +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/clock/vf610-clock.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/clock/vf610-clock.txt +--- linux-3.10.30/Documentation/devicetree/bindings/clock/vf610-clock.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/clock/vf610-clock.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,26 @@ ++* Clock bindings for Freescale Vybrid VF610 SOC ++ ++Required properties: ++- compatible: Should be "fsl,vf610-ccm" ++- reg: Address and length of the register set ++- #clock-cells: Should be <1> ++ ++The clock consumer should specify the desired clock by having the clock ++ID in its "clocks" phandle cell. See include/dt-bindings/clock/vf610-clock.h ++for the full list of VF610 clock IDs. ++ ++Examples: ++ ++clks: ccm@4006b000 { ++ compatible = "fsl,vf610-ccm"; ++ reg = <0x4006b000 0x1000>; ++ #clock-cells = <1>; ++}; ++ ++uart1: serial@40028000 { ++ compatible = "fsl,vf610-uart"; ++ reg = <0x40028000 0x1000>; ++ interrupts = <0 62 0x04>; ++ clocks = <&clks VF610_CLK_UART1>; ++ clock-names = "ipg"; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/cpufreq/cpufreq-imx6q.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/cpufreq/cpufreq-imx6q.txt +--- linux-3.10.30/Documentation/devicetree/bindings/cpufreq/cpufreq-imx6q.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/cpufreq/cpufreq-imx6q.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,59 @@ ++iMX6q/iMX6dl/iMX6sl specific CPUFREQ settings ++ ++iMX6q/iMX6dl/iMX6sl has limitation that a couple of voltage rails (VDDSOC_CAP and VDDPU_CAP) ++must track VDDARM_CAP within 50mV: ++VDDARM_CAP - VDDSOC_CAP/VDDPU_CAP <= 50mV ++ ++The VDDSOC_CAP and VDDPU_CAP operating points for various VDDARM_CAP settings are listed below. ++ ++Required properties: ++- fsl,soc-operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt ++ for details. It is a voltage frequency tuple. ++ ++- For other entries in the example below please refer to Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt ++ ++Examples: ++ ++cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu@0 { ++ compatible = "arm,cortex-a9"; ++ reg = <0>; ++ next-level-cache = <&L2>; ++ operating-points = < ++ /* kHz uV */ ++ 1200000 1275000 ++ 996000 1250000 ++ 792000 1175000 ++ 396000 1075000 ++ >; ++ fsl,soc-operating-points = < ++ /* ARM kHz SOC-PU uV */ ++ 1200000 1275000 ++ 996000 1250000 ++ 792000 1175000 ++ 396000 1175000 ++ >; ++ clock-latency = <61036>; /* two CLK32 periods */ ++ }; ++ ++ cpu@1 { ++ compatible = "arm,cortex-a9"; ++ reg = <1>; ++ next-level-cache = <&L2>; ++ }; ++ ++ cpu@2 { ++ compatible = "arm,cortex-a9"; ++ reg = <2>; ++ next-level-cache = <&L2>; ++ }; ++ ++ cpu@3 { ++ compatible = "arm,cortex-a9"; ++ reg = <3>; ++ next-level-cache = <&L2>; ++ }; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt +--- linux-3.10.30/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -4,14 +4,71 @@ + - compatible : Should be "fsl,-sdma" + - reg : Should contain SDMA registers location and length + - interrupts : Should contain SDMA interrupt ++- #dma-cells : Must be <3>. ++ The first cell specifies the DMA request/event ID. See details below ++ about the second and third cell. + - fsl,sdma-ram-script-name : Should contain the full path of SDMA RAM + scripts firmware + ++The second cell of dma phandle specifies the peripheral type of DMA transfer. ++The full ID of peripheral types can be found below. ++ ++ ID transfer type ++ --------------------- ++ 0 MCU domain SSI ++ 1 Shared SSI ++ 2 MMC ++ 3 SDHC ++ 4 MCU domain UART ++ 5 Shared UART ++ 6 FIRI ++ 7 MCU domain CSPI ++ 8 Shared CSPI ++ 9 SIM ++ 10 ATA ++ 11 CCM ++ 12 External peripheral ++ 13 Memory Stick Host Controller ++ 14 Shared Memory Stick Host Controller ++ 15 DSP ++ 16 Memory ++ 17 FIFO type Memory ++ 18 SPDIF ++ 19 IPU Memory ++ 20 ASRC ++ 21 ESAI ++ 22 HDMI Audio ++ ++The third cell specifies the transfer priority as below. ++ ++ ID transfer priority ++ ------------------------- ++ 0 High ++ 1 Medium ++ 2 Low ++ + Examples: + + sdma@83fb0000 { + compatible = "fsl,imx51-sdma", "fsl,imx35-sdma"; + reg = <0x83fb0000 0x4000>; + interrupts = <6>; ++ #dma-cells = <3>; + fsl,sdma-ram-script-name = "sdma-imx51.bin"; + }; ++ ++DMA clients connected to the i.MX SDMA controller must use the format ++described in the dma.txt file. ++ ++Examples: ++ ++ssi2: ssi@70014000 { ++ compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; ++ reg = <0x70014000 0x4000>; ++ interrupts = <30>; ++ clocks = <&clks 49>; ++ dmas = <&sdma 24 1 0>, ++ <&sdma 25 1 0>; ++ dma-names = "rx", "tx"; ++ fsl,fifo-depth = <15>; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/fb/fsl_epdc_fb.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/fb/fsl_epdc_fb.txt +--- linux-3.10.30/Documentation/devicetree/bindings/fb/fsl_epdc_fb.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/fb/fsl_epdc_fb.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,30 @@ ++* Freescale MXC Electrophoretic Display Controller (EPDC) ++ ++Required properties: ++- compatible: Should be "fsl,-epdc". Supported chips include ++ imx6dl and imx6sl ++- reg: Address and length of the register set for EPDC ++- interrupts: Should contain EPDC interrupts ++- clocks: the clocks for EPDC ++- pinctrl-names: should be "default" ++- pinctrl-0: should be pinctrl_ipu1_1 or pinctrl_ipu2_1, which depends on the ++ IPU connected. ++- V3P3_supply: power supply for EPDC_PWRCTRL0 from pmic ++- VCOM_supply: power supply for EPDC_VCOM0 from pmic ++- DISPLAY_supply: power supply enable for pmic ++ ++Examples: ++ ++imx6_epdc@0x020f8000 { ++ compatible = "fsl,imx6dl-epdc"; ++ reg = <0x020f8000 4000>; ++ interrupts = <0 97 0x04>; ++ clocks = <&clks 133>, <&clks 137>; /* ipu2, ipu2_di1 */ ++ clock-names = "epdc-axi", "epdc-pix"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_epdc_0>; ++ V3P3_supply = <&V3P3_reg>; ++ VCOM_supply = <&VCOM_reg>; ++ DISPLAY_supply = <&DISPLAY_reg>; ++ status = "disabled"; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt +--- linux-3.10.30/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,146 @@ ++* FSL IPUv3 Display/FB ++ ++The FSL IPUv3 is Image Processing Unit version 3, a part of video and graphics ++subsystem in an application processor. The goal of the IPU is to provide ++comprehensive support for the flow of data from an image sensor or/and to a ++display device. ++ ++Two IPU units are on the imx6q SOC while only one IPU unit on the imx6dl SOC. ++Each IPU unit has two display interfaces. ++ ++For LDB/LVDS panel, there are two LVDS channels(LVDS0 and LVDS1) which can ++transfer video data, these two channels can be used as ++split/dual/single/separate mode. ++-split mode means display data from DI0 or DI1 will send to both channels ++ LVDS0+LVDS1. ++-dual mode means display data from DI0 or DI1 will be duplicated on LVDS0 ++ and LVDS1, it said, LVDS0 and LVDS1 has the same content. ++-single mode means only work for DI0/DI1->LVDS0 or DI0/DI1->LVDS1. ++-separate mode means you can make DI0/DI1->LVDS0 and DI0/DI1->LVDS1 work ++ at the same time. ++ "ldb=spl0/1" -- split mode on DI0/1 ++ "ldb=dul0/1" -- dual mode on DI0/1 ++ "ldb=sin0/1" -- single mode on LVDS0/1 ++ "ldb=sep0/1" -- separate mode begin from LVDS0/1 ++ ++Required properties for IPU: ++- bypass_reset :Bypass reset to avoid display channel being. ++ stopped by probe since it may start to work in bootloader: 0 or 1. ++- compatible : should be "fsl,imx6q-ipu". ++- reg : the register address range. ++- interrupts : the error and sync interrupts request. ++- clocks : the clock sources that it depends on. ++- clock-names: the related clock names. ++- resets : IPU reset specifier. See reset.txt and fsl,imx-src.txt in ++ Documentation/devicetree/bindings/reset/ for details. ++ ++Required properties for fb: ++- compatible : should be "fsl,mxc_sdc_fb". ++- disp_dev : display device: "ldb", "lcd", "hdmi", "mipi_dsi". ++- mode_str : video mode string: "LDB-XGA" or "LDB-1080P60" for ldb, ++ "CLAA-WVGA" for lcd, "TRULY-WVGA" for TRULY mipi_dsi lcd panel, ++ "1920x1080M@60" for hdmi. ++- default_bpp : default bits per pixel: 8/16/24/32 ++- int_clk : use internal clock as pixel clock: 0 or 1 ++- late_init : to avoid display channel being re-initialized ++ as we've probably setup the channel in bootloader: 0 or 1 ++- interface_pix_fmt : display interface pixel format as below: ++ RGB666 IPU_PIX_FMT_RGB666 ++ RGB565 IPU_PIX_FMT_RGB565 ++ RGB24 IPU_PIX_FMT_RGB24 ++ BGR24 IPU_PIX_FMT_BGR24 ++ GBR24 IPU_PIX_FMT_GBR24 ++ YUV444 IPU_PIX_FMT_YUV444 ++ LVDS666 IPU_PIX_FMT_LVDS666 ++ YUYV IPU_PIX_FMT_YUYV ++ UYVY IPU_PIX_FMT_UYVY ++ YVYV IPU_PIX_FMT_YVYU ++ VYUY IPU_PIX_FMT_VYUY ++ ++Required properties for display: ++- compatible : should be "fsl,lcd" for lcd panel, "fsl,imx6q-ldb" for ldb ++- reg : the register address range if necessary to have. ++- interrupts : the error and sync interrupts if necessary to have. ++- clocks : the clock sources that it depends on if necessary to have. ++- clock-names: the related clock names if necessary to have. ++- ipu_id : ipu id for the first display device: 0 or 1 ++- disp_id : display interface id for the first display interface: 0 or 1 ++- default_ifmt : save as above display interface pixel format for lcd ++- pinctrl-names : should be "default" ++- pinctrl-0 : should be pinctrl_ipu1_1 or pinctrl_ipu2_1, which depends on the ++ IPU connected. ++- sec_ipu_id : secondary ipu id for the second display device(ldb only): 0 or 1 ++- sec_disp_id : secondary display interface id for the second display ++ device(ldb only): 0 or 1 ++- ext_ref : reference resistor select for ldb only: 0 or 1 ++- mode : ldb mode as below: ++ spl0 LDB_SPL_DI0 ++ spl1 LDB_SPL_DI1 ++ dul0 LDB_DUL_DI0 ++ dul1 LDB_DUL_DI1 ++ sin0 LDB_SIN0 ++ sin1 LDB_SIN1 ++ sep0 LDB_SEP0 ++ sep1 LDB_SEP1 ++- gpr : the mux controller for the display engine's display interfaces and the display encoder ++ (only valid for mipi dsi now). ++- disp-power-on-supply : the regulator to control display panel's power. ++ (only valid for mipi dsi now). ++- resets : the gpio pin to reset the display device(only valid for mipi display panel now). ++- lcd_panel : the video mode name for the display device(only valid for mipi display panel now). ++- dev_id : the display engine's identity within the system, which intends to replace ipu_id ++ (only valid for mipi dsi now). ++ ++Example for IPU: ++ ipu1: ipu@02400000 { ++ compatible = "fsl,imx6q-ipu"; ++ reg = <0x02400000 0x400000>; ++ interrupts = <0 6 0x4 0 5 0x4>; ++ clocks = <&clks 130>, <&clks 131>, <&clks 132>, ++ <&clks 39>, <&clks 40>, ++ <&clks 135>, <&clks 136>; ++ clock-names = "bus", "di0", "di1", ++ "di0_sel", "di1_sel", ++ "ldb_di0", "ldb_di1"; ++ resets = <&src 2>; ++ bypass_reset = <0>; ++ }; ++ ++Example for fb: ++ fb0 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "ldb"; ++ interface_pix_fmt = "RGB666"; ++ mode_str ="LDB-XGA"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "okay"; ++ }; ++ ++Example for ldb display: ++ ldb@020e0000 { ++ ipu_id = <1>; ++ disp_id = <0>; ++ ext_ref = <1>; ++ mode = "sep0"; ++ sec_ipu_id = <1>; ++ sec_disp_id = <1>; ++ status = "okay"; ++ }; ++ ++Example for mipi dsi display: ++ mipi_dsi: mipi@021e0000 { ++ compatible = "fsl,imx6q-mipi-dsi"; ++ reg = <0x021e0000 0x4000>; ++ interrupts = <0 102 0x04>; ++ gpr = <&gpr>; ++ clocks = <&clks 138>, <&clks 204>; ++ clock-names = "mipi_pllref_clk", "mipi_cfg_clk"; ++ dev_id = <0>; ++ disp_id = <0>; ++ lcd_panel = "TRULY-WVGA"; ++ disp-power-on-supply = <®_mipi_dsi_pwr_on> ++ resets = <&mipi_dsi_reset>; ++ status = "okay"; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/fb/mxsfb.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/fb/mxsfb.txt +--- linux-3.10.30/Documentation/devicetree/bindings/fb/mxsfb.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/fb/mxsfb.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -3,6 +3,9 @@ + Required properties: + - compatible: Should be "fsl,-lcdif". Supported chips include + imx23 and imx28. ++- pinctrl-names: Should be "default" ++- pinctrl-0: pinctrl setting for lcd ++- lcd-supply: lcd power supply, usually via GPIO + - reg: Address and length of the register set for lcdif + - interrupts: Should contain lcdif interrupts + - display : phandle to display node (see below for details) +@@ -22,6 +25,10 @@ + compatible = "fsl,imx28-lcdif"; + reg = <0x80030000 2000>; + interrupts = <38 86>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&lcdif_24bit_pins_a ++ &lcdif_pins_evk>; ++ lcd-supply = <®_lcd_3v3>; + + display: display { + bits-per-pixel = <32>; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/input/touchscreen/elan-ts.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/input/touchscreen/elan-ts.txt +--- linux-3.10.30/Documentation/devicetree/bindings/input/touchscreen/elan-ts.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/input/touchscreen/elan-ts.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,23 @@ ++* ELAN Resistive Touch Controller ++ ++Required properties: ++- compatible: must be "elan,elan-touch" ++- reg: i2c slave address ++- interrupt-parent: the phandle for the interrupt controller ++- interrupts: touch controller interrupt ++- gpio_elan_cs: the gpio pin for chip select ++- gpio_elan_rst: the gpio pin for chip reset ++- gpio_intr: the gpio pin to be used for interrupt pin ++ ++Example: ++ ++ elan@10 { ++ compatible = "elan,elan-touch"; ++ reg = <0x10>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <28 3>; ++ gpio_elan_cs = <&gpio2 18 0>; ++ gpio_elan_rst = <&gpio3 8 0>; ++ gpio_intr = <&gpio3 28 0>; ++ status = "okay"; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/leds/leds-pwm.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/leds/leds-pwm.txt +--- linux-3.10.30/Documentation/devicetree/bindings/leds/leds-pwm.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/leds/leds-pwm.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -13,6 +13,9 @@ + For the pwms and pwm-names property please refer to: + Documentation/devicetree/bindings/pwm/pwm.txt + - max-brightness : Maximum brightness possible for the LED ++- default-brightness : (optional) Default brightness for the LED ++- active-low : (optional) For PWMs where the LED is wired to supply ++ rather than ground. + - label : (optional) + see Documentation/devicetree/bindings/leds/common.txt + - linux,default-trigger : (optional) +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/mfd/vexpress-spc.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/mfd/vexpress-spc.txt +--- linux-3.10.30/Documentation/devicetree/bindings/mfd/vexpress-spc.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/mfd/vexpress-spc.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,35 @@ ++* ARM Versatile Express Serial Power Controller device tree bindings ++ ++Latest ARM development boards implement a power management interface (serial ++power controller - SPC) that is capable of managing power/voltage and ++operating point transitions, through memory mapped registers interface. ++ ++On testchips like TC2 it also provides a configuration interface that can ++be used to read/write values which cannot be read/written through simple ++memory mapped reads/writes. ++ ++- spc node ++ ++ - compatible: ++ Usage: required ++ Value type: ++ Definition: must be ++ "arm,vexpress-spc,v2p-ca15_a7","arm,vexpress-spc" ++ - reg: ++ Usage: required ++ Value type: ++ Definition: A standard property that specifies the base address ++ and the size of the SPC address space ++ - interrupts: ++ Usage: required ++ Value type: ++ Definition: SPC interrupt configuration. A standard property ++ that follows ePAPR interrupts specifications ++ ++Example: ++ ++spc: spc@7fff0000 { ++ compatible = "arm,vexpress-spc,v2p-ca15_a7","arm,vexpress-spc"; ++ reg = <0 0x7FFF0000 0 0x1000>; ++ interrupts = <0 95 4>; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/mlb/mlb150.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/mlb/mlb150.txt +--- linux-3.10.30/Documentation/devicetree/bindings/mlb/mlb150.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/mlb/mlb150.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,22 @@ ++* Freescale Media Local Bus Host Controller (MLB) for i.MX6Q/DL ++ ++The Media Local Bus Host Controller on Freescale i.MX family ++provides an interface for MOST network. ++ ++Required properties: ++- compatible : Should be "fsl,-mlb150" ++- reg : Should contain mlb registers location and length ++- interrupts : Should contain mlb interrupt ++- clocks: Should contain the mlb clock sources ++- clock-names: Should be the names of mlb clock sources ++- iram : phandle pointing to the SRAM device node ++ ++Examples: ++mlb@0218c000 { ++ compatible = "fsl,imx6q-mlb150"; ++ reg = <0x0218c000 0x4000>; ++ interrupts = <0 53 0x04 0 117 0x04 0 126 0x04>; ++ clocks = <&clks 139>, <&clks 175>; ++ clock-names = "mlb", "pll8_mlb"; ++ iram = <&ocram>; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt +--- linux-3.10.30/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -12,6 +12,11 @@ + Optional properties: + - fsl,cd-controller : Indicate to use controller internal card detection + - fsl,wp-controller : Indicate to use controller internal write protection ++- fsl,delay-line : Specify the number of delay cells for override mode. ++ This is used to set the clock delay for DLL(Delay Line) on override mode ++ to select a proper data sampling window in case the clock quality is not good ++ due to signal path is too long on the board. Please refer to eSDHC/uSDHC ++ chapter, DLL (Delay Line) section in RM for details. + + Examples: + +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/mmc/mmc.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/mmc/mmc.txt +--- linux-3.10.30/Documentation/devicetree/bindings/mmc/mmc.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/mmc/mmc.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -5,6 +5,8 @@ + Interpreted by the OF core: + - reg: Registers location and length. + - interrupts: Interrupts used by the MMC controller. ++- clocks: Clocks needed for the host controller, if any. ++- clock-names: Goes with clocks above. + + Card detection: + If no property below is supplied, host native card detect is used. +@@ -29,6 +31,15 @@ + - cap-power-off-card: powering off the card is safe + - cap-sdio-irq: enable SDIO IRQ signalling on this interface + ++Card power and reset control: ++The following properties can be specified for cases where the MMC ++peripheral needs additional reset, regulator and clock lines. It is for ++example common for WiFi/BT adapters to have these separate from the main ++MMC bus: ++ - card-reset-gpios: Specify GPIOs for card reset (reset active low) ++ - card-external-vcc-supply: Regulator to drive (independent) card VCC ++ - clock with name "card_ext_clock": External clock provided to the card ++ + *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line + polarity properties, we have to fix the meaning of the "normal" and "inverted" + line levels. We choose to follow the SDHCI standard, which specifies both those +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/mtd/gpmi-nand.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/mtd/gpmi-nand.txt +--- linux-3.10.30/Documentation/devicetree/bindings/mtd/gpmi-nand.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/mtd/gpmi-nand.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -17,6 +17,14 @@ + Optional properties: + - nand-on-flash-bbt: boolean to enable on flash bbt option if not + present false ++ - fsl,use-minimum-ecc: Protect this NAND flash with the minimum ECC ++ strength required. The required ECC strength is ++ automatically discoverable for some flash ++ (e.g., according to the ONFI standard). ++ However, note that if this strength is not ++ discoverable or this property is not enabled, ++ the software may chooses an implementation-defined ++ ECC scheme. + + The device tree may optionally contain sub-nodes describing partitions of the + address space. See partition.txt for more detail. +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt +--- linux-3.10.30/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -15,6 +15,13 @@ + Optional properties: + + - clock-frequency : The oscillator frequency driving the flexcan device ++- gpr: phandle to general purpose register node. The remote wakeup control ++ bits is stored here. ++ ++Below are gpios for tranceiver: ++- trx_en_gpio : enable gpio ++- trx_stby_gpio : standby gpio ++- trx_nerr_gpio : NERR gpio + + Example: + +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/pci/designware-pcie.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/pci/designware-pcie.txt +--- linux-3.10.30/Documentation/devicetree/bindings/pci/designware-pcie.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/pci/designware-pcie.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,81 @@ ++* Synopsis Designware PCIe interface ++ ++Required properties: ++- compatible: should contain "snps,dw-pcie" to identify the ++ core, plus an identifier for the specific instance, such ++ as "samsung,exynos5440-pcie" or "fsl,imx6q-pcie". ++- reg: base addresses and lengths of the pcie controller, ++ the phy controller, additional register for the phy controller. ++- interrupts: interrupt values for level interrupt, ++ pulse interrupt, special interrupt. ++- clocks: from common clock binding: handle to pci clock. ++- clock-names: from common clock binding: should be "pcie" and "pcie_bus". ++- #address-cells: set to <3> ++- #size-cells: set to <2> ++- device_type: set to "pci" ++- ranges: ranges for the PCI memory and I/O regions ++- #interrupt-cells: set to <1> ++- interrupt-map-mask and interrupt-map: standard PCI properties ++ to define the mapping of the PCIe interface to interrupt ++ numbers. ++- num-lanes: number of lanes to use ++- reset-gpio: gpio pin number of power good signal ++ ++Optional properties for fsl,imx6q-pcie ++- power-on-gpio: gpio pin number of power-enable signal ++- wake-up-gpio: gpio pin number of incoming wakeup signal ++- disable-gpio: gpio pin number of outgoing rfkill/endpoint disable signal ++ ++Example: ++ ++SoC specific DT Entry: ++ ++ pcie@290000 { ++ compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; ++ reg = <0x290000 0x1000 ++ 0x270000 0x1000 ++ 0x271000 0x40>; ++ interrupts = <0 20 0>, <0 21 0>, <0 22 0>; ++ clocks = <&clock 28>, <&clock 27>; ++ clock-names = "pcie", "pcie_bus"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ ranges = <0x00000800 0 0x40000000 0x40000000 0 0x00001000 /* configuration space */ ++ 0x81000000 0 0 0x40001000 0 0x00010000 /* downstream I/O */ ++ 0x82000000 0 0x40011000 0x40011000 0 0x1ffef000>; /* non-prefetchable memory */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0x0 0 &gic 53>; ++ num-lanes = <4>; ++ }; ++ ++ pcie@2a0000 { ++ compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; ++ reg = <0x2a0000 0x1000 ++ 0x272000 0x1000 ++ 0x271040 0x40>; ++ interrupts = <0 23 0>, <0 24 0>, <0 25 0>; ++ clocks = <&clock 29>, <&clock 27>; ++ clock-names = "pcie", "pcie_bus"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ ranges = <0x00000800 0 0x60000000 0x60000000 0 0x00001000 /* configuration space */ ++ 0x81000000 0 0 0x60001000 0 0x00010000 /* downstream I/O */ ++ 0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; /* non-prefetchable memory */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0x0 0 &gic 56>; ++ num-lanes = <4>; ++ }; ++ ++Board specific DT Entry: ++ ++ pcie@290000 { ++ reset-gpio = <&pin_ctrl 5 0>; ++ }; ++ ++ pcie@2a0000 { ++ reset-gpio = <&pin_ctrl 22 0>; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/pci/mvebu-pci.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/pci/mvebu-pci.txt +--- linux-3.10.30/Documentation/devicetree/bindings/pci/mvebu-pci.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/pci/mvebu-pci.txt 2014-03-08 20:32:51.000000000 +0100 +@@ -0,0 +1,221 @@ ++* Marvell EBU PCIe interfaces ++ ++Mandatory properties: ++- compatible: one of the following values: ++ marvell,armada-370-pcie ++ marvell,armada-xp-pcie ++ marvell,kirkwood-pcie ++- #address-cells, set to <3> ++- #size-cells, set to <2> ++- #interrupt-cells, set to <1> ++- bus-range: PCI bus numbers covered ++- device_type, set to "pci" ++- ranges: ranges for the PCI memory and I/O regions, as well as the ++ MMIO registers to control the PCIe interfaces. ++ ++In addition, the Device Tree node must have sub-nodes describing each ++PCIe interface, having the following mandatory properties: ++- reg: used only for interrupt mapping, so only the first four bytes ++ are used to refer to the correct bus number and device number. ++- assigned-addresses: reference to the MMIO registers used to control ++ this PCIe interface. ++- clocks: the clock associated to this PCIe interface ++- marvell,pcie-port: the physical PCIe port number ++- status: either "disabled" or "okay" ++- device_type, set to "pci" ++- #address-cells, set to <3> ++- #size-cells, set to <2> ++- #interrupt-cells, set to <1> ++- ranges, empty property. ++- interrupt-map-mask and interrupt-map, standard PCI properties to ++ define the mapping of the PCIe interface to interrupt numbers. ++ ++and the following optional properties: ++- marvell,pcie-lane: the physical PCIe lane number, for ports having ++ multiple lanes. If this property is not found, we assume that the ++ value is 0. ++ ++Example: ++ ++pcie-controller { ++ compatible = "marvell,armada-xp-pcie"; ++ status = "disabled"; ++ device_type = "pci"; ++ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ++ bus-range = <0x00 0xff>; ++ ++ ranges = <0x82000000 0 0xd0040000 0xd0040000 0 0x00002000 /* Port 0.0 registers */ ++ 0x82000000 0 0xd0042000 0xd0042000 0 0x00002000 /* Port 2.0 registers */ ++ 0x82000000 0 0xd0044000 0xd0044000 0 0x00002000 /* Port 0.1 registers */ ++ 0x82000000 0 0xd0048000 0xd0048000 0 0x00002000 /* Port 0.2 registers */ ++ 0x82000000 0 0xd004c000 0xd004c000 0 0x00002000 /* Port 0.3 registers */ ++ 0x82000000 0 0xd0080000 0xd0080000 0 0x00002000 /* Port 1.0 registers */ ++ 0x82000000 0 0xd0082000 0xd0082000 0 0x00002000 /* Port 3.0 registers */ ++ 0x82000000 0 0xd0084000 0xd0084000 0 0x00002000 /* Port 1.1 registers */ ++ 0x82000000 0 0xd0088000 0xd0088000 0 0x00002000 /* Port 1.2 registers */ ++ 0x82000000 0 0xd008c000 0xd008c000 0 0x00002000 /* Port 1.3 registers */ ++ 0x82000000 0 0xe0000000 0xe0000000 0 0x08000000 /* non-prefetchable memory */ ++ 0x81000000 0 0 0xe8000000 0 0x00100000>; /* downstream I/O */ ++ ++ pcie@1,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82000800 0 0xd0040000 0 0x2000>; ++ reg = <0x0800 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 58>; ++ marvell,pcie-port = <0>; ++ marvell,pcie-lane = <0>; ++ clocks = <&gateclk 5>; ++ status = "disabled"; ++ }; ++ ++ pcie@2,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82001000 0 0xd0044000 0 0x2000>; ++ reg = <0x1000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 59>; ++ marvell,pcie-port = <0>; ++ marvell,pcie-lane = <1>; ++ clocks = <&gateclk 6>; ++ status = "disabled"; ++ }; ++ ++ pcie@3,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82001800 0 0xd0048000 0 0x2000>; ++ reg = <0x1800 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 60>; ++ marvell,pcie-port = <0>; ++ marvell,pcie-lane = <2>; ++ clocks = <&gateclk 7>; ++ status = "disabled"; ++ }; ++ ++ pcie@4,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82002000 0 0xd004c000 0 0x2000>; ++ reg = <0x2000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 61>; ++ marvell,pcie-port = <0>; ++ marvell,pcie-lane = <3>; ++ clocks = <&gateclk 8>; ++ status = "disabled"; ++ }; ++ ++ pcie@5,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82002800 0 0xd0080000 0 0x2000>; ++ reg = <0x2800 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 62>; ++ marvell,pcie-port = <1>; ++ marvell,pcie-lane = <0>; ++ clocks = <&gateclk 9>; ++ status = "disabled"; ++ }; ++ ++ pcie@6,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82003000 0 0xd0084000 0 0x2000>; ++ reg = <0x3000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 63>; ++ marvell,pcie-port = <1>; ++ marvell,pcie-lane = <1>; ++ clocks = <&gateclk 10>; ++ status = "disabled"; ++ }; ++ ++ pcie@7,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82003800 0 0xd0088000 0 0x2000>; ++ reg = <0x3800 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 64>; ++ marvell,pcie-port = <1>; ++ marvell,pcie-lane = <2>; ++ clocks = <&gateclk 11>; ++ status = "disabled"; ++ }; ++ ++ pcie@8,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82004000 0 0xd008c000 0 0x2000>; ++ reg = <0x4000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 65>; ++ marvell,pcie-port = <1>; ++ marvell,pcie-lane = <3>; ++ clocks = <&gateclk 12>; ++ status = "disabled"; ++ }; ++ pcie@9,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82004800 0 0xd0042000 0 0x2000>; ++ reg = <0x4800 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 99>; ++ marvell,pcie-port = <2>; ++ marvell,pcie-lane = <0>; ++ clocks = <&gateclk 26>; ++ status = "disabled"; ++ }; ++ ++ pcie@10,0 { ++ device_type = "pci"; ++ assigned-addresses = <0x82005000 0 0xd0082000 0 0x2000>; ++ reg = <0x5000 0 0 0 0>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0 0 0 0 &mpic 103>; ++ marvell,pcie-port = <3>; ++ marvell,pcie-lane = <0>; ++ clocks = <&gateclk 27>; ++ status = "disabled"; ++ }; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/pinctrl/fsl,vf610-pinctrl.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/pinctrl/fsl,vf610-pinctrl.txt +--- linux-3.10.30/Documentation/devicetree/bindings/pinctrl/fsl,vf610-pinctrl.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/pinctrl/fsl,vf610-pinctrl.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,41 @@ ++Freescale Vybrid VF610 IOMUX Controller ++ ++Please refer to fsl,imx-pinctrl.txt in this directory for common binding part ++and usage. ++ ++Required properties: ++- compatible: "fsl,vf610-iomuxc" ++- fsl,pins: two integers array, represents a group of pins mux and config ++ setting. The format is fsl,pins = , PIN_FUNC_ID is ++ a pin working on a specific function, CONFIG is the pad setting value ++ such as pull-up, speed, ode for this pin. Please refer to Vybrid VF610 ++ datasheet for the valid pad config settings. ++ ++CONFIG bits definition: ++PAD_CTL_SPEED_LOW (1 << 12) ++PAD_CTL_SPEED_MED (2 << 12) ++PAD_CTL_SPEED_HIGH (3 << 12) ++PAD_CTL_SRE_FAST (1 << 11) ++PAD_CTL_SRE_SLOW (0 << 11) ++PAD_CTL_ODE (1 << 10) ++PAD_CTL_HYS (1 << 9) ++PAD_CTL_DSE_DISABLE (0 << 6) ++PAD_CTL_DSE_150ohm (1 << 6) ++PAD_CTL_DSE_75ohm (2 << 6) ++PAD_CTL_DSE_50ohm (3 << 6) ++PAD_CTL_DSE_37ohm (4 << 6) ++PAD_CTL_DSE_30ohm (5 << 6) ++PAD_CTL_DSE_25ohm (6 << 6) ++PAD_CTL_DSE_20ohm (7 << 6) ++PAD_CTL_PUS_100K_DOWN (0 << 4) ++PAD_CTL_PUS_47K_UP (1 << 4) ++PAD_CTL_PUS_100K_UP (2 << 4) ++PAD_CTL_PUS_22K_UP (3 << 4) ++PAD_CTL_PKE (1 << 3) ++PAD_CTL_PUE (1 << 2) ++PAD_CTL_OBE_ENABLE (1 << 1) ++PAD_CTL_IBE_ENABLE (1 << 0) ++PAD_CTL_OBE_IBE_ENABLE (3 << 0) ++ ++Please refer to vf610-pinfunc.h in device tree source folder ++for all available PIN_FUNC_ID for Vybrid VF610. +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +--- linux-3.10.30/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -71,6 +71,13 @@ + name for integer state ID 0, list entry 1 for state ID 1, and + so on. + ++pinctrl-assert-gpios: ++ List of phandles, each pointing at a GPIO which is used by some ++ board design to steer pins between two peripherals on the board. ++ It plays like a board level pin multiplexer to choose different ++ functions for given pins by pulling up/down the GPIOs. See ++ bindings/gpio/gpio.txt for details of how to specify GPIO. ++ + For example: + + /* For a client device requiring named states */ +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/regulator/max17135-regulator.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/regulator/max17135-regulator.txt +--- linux-3.10.30/Documentation/devicetree/bindings/regulator/max17135-regulator.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/regulator/max17135-regulator.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,112 @@ ++Maxim MAX17135 Voltage Regulator ++ ++The MAX17135 is a complete power-management IC for E-paper displays that ++provides source- and gate-driver power supplies, a high-speed VCOM amplifier, ++and a temperature sensor. It is interfaced to the host controller using an ++i2c interface. ++ ++Required properties : ++- compatible : "maxim,max17135" ++- reg: Specifies the i2c slave address of the pmic block. ++- vneg_pwrup: the timing for VNEG power up ++- gvee_pwrup: the timing for GVEE power up ++- vpos_pwrup: the timing for VPOS power up ++- gvdd_pwrup: the timing for GVDD power up ++- gvdd_pwrdn: the timing for GVDD power down ++- vpos_pwrdn: the timing for VPOS power down ++- gvee_pwrdn: the timing for GVEE power down ++- vneg_pwrdn: the timing for VNEG power down ++- gpio_pmic_pwrgood: gpio setting for EPDC_PWRSTAT ++- gpio_pmic_vcom_ctrl: gpio setting for EPDC_VCOM ++- gpio_pmic_wakeup: gpio setting for EPDC_PWRWAKEUP ++- gpio_pmic_v3p3: gpio setting for EPDC_PWRCTRL0 ++- gpio_pmic_intr: gpio setting for EPDC_PWRINT ++ ++Optional properties : ++- SENSOR-supply: the gpio regulator to control the supply for this chip ++ ++ ++Regulators: The regulators of max17135 that have to be instantiated should be ++included in a sub-node named 'regulators'. Regulator nodes included in this ++sub-node should be of the format as listed below. ++ ++ regulator_name { ++ standard regulator bindings here ++ }; ++ ++Example: ++ max17135@48 { ++ compatible = "maxim,max17135"; ++ reg = <0x48>; ++ vneg_pwrup = <1>; ++ gvee_pwrup = <1>; ++ vpos_pwrup = <2>; ++ gvdd_pwrup = <1>; ++ gvdd_pwrdn = <1>; ++ vpos_pwrdn = <2>; ++ gvee_pwrdn = <1>; ++ vneg_pwrdn = <1>; ++ SENSOR-supply = <®_sensor>; ++ gpio_pmic_pwrgood = <&gpio2 21 0>; ++ gpio_pmic_vcom_ctrl = <&gpio3 17 0>; ++ gpio_pmic_wakeup = <&gpio3 20 0>; ++ gpio_pmic_v3p3 = <&gpio2 20 0>; ++ gpio_pmic_intr = <&gpio2 25 0>; ++ ++ regulators { ++ DISPLAY_reg: DISPLAY { ++ regulator-name = "DISPLAY"; ++ }; ++ ++ GVDD_reg: GVDD { ++ regulator-name = "GVDD"; ++ regulator-min-microvolt = <20000000>; ++ regulator-max-microvolt = <20000000>; ++ }; ++ ++ GVEE_reg: GVEE { ++ regulator-name = "GVEE"; ++ /* 2's-compliment, -22000000 */ ++ regulator-min-microvolt = <0xfeb04e80>; ++ regulator-max-microvolt = <0xfeb04e80>; ++ }; ++ ++ HVINN_reg: HVINN { ++ regulator-name = "HVINN"; ++ /* 2's-compliment, -22000000 */ ++ regulator-min-microvolt = <0xfeb04e80>; ++ regulator-max-microvolt = <0xfeb04e80>; ++ }; ++ ++ HVINP_reg: HVINP { ++ regulator-name = "HVINP"; ++ regulator-min-microvolt = <20000000>; ++ regulator-max-microvolt = <20000000>; ++ }; ++ ++ VCOM_reg: VCOM { ++ regulator-name = "VCOM"; ++ /* 2's-compliment, -4325000 */ ++ regulator-min-microvolt = <0xffbe0178>; ++ /* 2's-compliment, -500000 */ ++ regulator-max-microvolt = <0xfff85ee0>; ++ }; ++ ++ VNEG_reg: VNEG { ++ regulator-name = "VNEG"; ++ /* 2's-compliment, -15000000 */ ++ regulator-min-microvolt = <0xff1b1e40>; ++ regulator-max-microvolt = <0xff1b1e40>; ++ }; ++ ++ VPOS_reg: VPOS { ++ regulator-name = "VPOS"; ++ regulator-min-microvolt = <15000000>; ++ regulator-max-microvolt = <15000000>; ++ }; ++ ++ V3P3_reg: V3P3 { ++ regulator-name = "V3P3"; ++ }; ++ }; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/regulator/pfuze100.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/regulator/pfuze100.txt +--- linux-3.10.30/Documentation/devicetree/bindings/regulator/pfuze100.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/regulator/pfuze100.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,115 @@ ++PFUZE100 family of regulators ++ ++Required properties: ++- compatible: "fsl,pfuze100" ++- reg: I2C slave address ++ ++Required child node: ++- regulators: This is the list of child nodes that specify the regulator ++ initialization data for defined regulators. Please refer to below doc ++ Documentation/devicetree/bindings/regulator/regulator.txt. ++ ++ The valid names for regulators are: ++ sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6 ++ ++Each regulator is defined using the standard binding for regulators. ++ ++Example: ++ ++ pmic: pfuze100@08 { ++ compatible = "fsl,pfuze100"; ++ reg = <0x08>; ++ ++ regulators { ++ sw1a_reg: sw1ab { ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1875000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-ramp-delay = <6250>; ++ }; ++ ++ sw1c_reg: sw1c { ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1875000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw2_reg: sw2 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw3a_reg: sw3a { ++ regulator-min-microvolt = <400000>; ++ regulator-max-microvolt = <1975000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw3b_reg: sw3b { ++ regulator-min-microvolt = <400000>; ++ regulator-max-microvolt = <1975000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw4_reg: sw4 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ swbst_reg: swbst { ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5150000>; ++ }; ++ ++ snvs_reg: vsnvs { ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <3000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vref_reg: vrefddr { ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vgen1_reg: vgen1 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <1550000>; ++ }; ++ ++ vgen2_reg: vgen2 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <1550000>; ++ }; ++ ++ vgen3_reg: vgen3 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ vgen4_reg: vgen4 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vgen5_reg: vgen5 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vgen6_reg: vgen6 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ }; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/reset/gpio-reset.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/reset/gpio-reset.txt +--- linux-3.10.30/Documentation/devicetree/bindings/reset/gpio-reset.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/reset/gpio-reset.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,35 @@ ++GPIO reset controller ++===================== ++ ++A GPIO reset controller controls a single GPIO that is connected to the reset ++pin of a peripheral IC. Please also refer to reset.txt in this directory for ++common reset controller binding usage. ++ ++Required properties: ++- compatible: Should be "gpio-reset" ++- reset-gpios: A gpio used as reset line. The gpio specifier for this property ++ depends on the gpio controller that provides the gpio. ++- #reset-cells: 0, see below ++ ++Optional properties: ++- reset-delay-us: delay in microseconds. The gpio reset line will be asserted for ++ this duration to reset. ++- initially-in-reset: boolean. If not set, the initial state should be a ++ deasserted reset line. If this property exists, the ++ reset line should be kept in reset. ++ ++example: ++ ++sii902x_reset: gpio-reset { ++ compatible = "gpio-reset"; ++ reset-gpios = <&gpio5 0 GPIO_ACTIVE_LOW>; ++ reset-delay-us = <10000>; ++ initially-in-reset; ++ #reset-cells = <0>; ++}; ++ ++/* Device with nRESET pin connected to GPIO5_0 */ ++sii902x@39 { ++ /* ... */ ++ resets = <&sii902x_reset>; /* active-low GPIO5_0, 10 ms delay */ ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/sound/cs42888.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/cs42888.txt +--- linux-3.10.30/Documentation/devicetree/bindings/sound/cs42888.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/cs42888.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,29 @@ ++CS42888 audio CODEC ++ ++This device supports I2C only. ++ ++Required properties: ++ ++ - compatible: "cirrus,cs42888" ++ - reg: the I2C address of the device. ++ - clocks: Phandle to the clock node. ++ - clock-names: Contains name for each entry in clocks. ++ "codec_osc" : the external oscillator. ++ "esai" : the hckt clock from esai. ++ - -supply: Phandle to the regulator . ++ ++Note: cs42888 needs a regulators node and a clocks node. ++ ++Example: ++In this case, the clock is external oscillator. ++ ++codec: cs42888@48 { ++ compatible = "cirrus,cs42888"; ++ reg = <0x048>; ++ clocks = <&codec_osc 0>; ++ clock-names = "codec_osc"; ++ VA-supply = <®_audio>; ++ VD-supply = <®_audio>; ++ VLS-supply = <®_audio>; ++ VLC-supply = <®_audio>; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/sound/fsl,spdif.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/fsl,spdif.txt +--- linux-3.10.30/Documentation/devicetree/bindings/sound/fsl,spdif.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/fsl,spdif.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,54 @@ ++Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller ++ ++The Freescale S/PDIF audio block is a stereo transceiver that allows the ++processor to receive and transmit digital audio via an coaxial cable or ++a fibre cable. ++ ++Required properties: ++ ++ - compatible : Compatible list, must contain "fsl,imx35-spdif". ++ ++ - reg : Offset and length of the register set for the device. ++ ++ - interrupts : Contains the spdif interrupt. ++ ++ - dmas : Generic dma devicetree binding as described in ++ Documentation/devicetree/bindings/dma/dma.txt. ++ ++ - dma-names : Two dmas have to be defined, "tx" and "rx". ++ ++ - clocks : Contains an entry for each entry in clock-names. ++ ++ - clock-names : Includes the following entries: ++ "core" The core clock of spdif controller ++ "rxtx<0-7>" Clock source list for tx and rx clock. ++ This clock list should be identical to ++ the source list connecting to the spdif ++ clock mux in "SPDIF Transceiver Clock ++ Diagram" of SoC reference manual. It ++ can also be referred to TxClk_Source ++ bit of register SPDIF_STC. ++ ++Example: ++ ++spdif: spdif@02004000 { ++ compatible = "fsl,imx35-spdif"; ++ reg = <0x02004000 0x4000>; ++ interrupts = <0 52 0x04>; ++ dmas = <&sdma 14 18 0>, ++ <&sdma 15 18 0>; ++ dma-names = "rx", "tx"; ++ ++ clocks = <&clks 197>, <&clks 3>, ++ <&clks 197>, <&clks 107>, ++ <&clks 0>, <&clks 118>, ++ <&clks 62>, <&clks 139>, ++ <&clks 0>; ++ clock-names = "core", "rxtx0", ++ "rxtx1", "rxtx2", ++ "rxtx3", "rxtx4", ++ "rxtx5", "rxtx6", ++ "rxtx7"; ++ ++ status = "okay"; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/sound/fsl-asrc-p2p.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/fsl-asrc-p2p.txt +--- linux-3.10.30/Documentation/devicetree/bindings/sound/fsl-asrc-p2p.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/fsl-asrc-p2p.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,23 @@ ++* Freescale Asynchronous Sample Rate Converter (ASRC) ++ ++This document is for asrc p2p node. p2p is one of asrc mode. asrc p2p depend on ++MXC_ASRC. ++ ++Required properties: ++ - compatible: Should be "fsl,-asrc-p2p". ++ - fsl,output-rate: the output rate of asrc p2p. which can be <32000> to <192000>, ++ - fsl,output-width: the output width of asrc p2p. which can be <16>, <24>. ++ - fsl,asrc-dma-rx-events: The rx dma event of the asrc, corresponding ++ to 3 pair of asrc. ++ - fsl,asrc-dma-tx-events: The tx dma event of the esai, corresponding ++ to 3 pair of asrc. ++ ++Example: ++asrc_p2p: asrc_p2p { ++ compatible = "fsl,imx6q-asrc-p2p"; ++ fsl,output-rate = <48000>; ++ fsl,output-width = <16>; ++ fsl,asrc-dma-rx-events = <17 18 19>; ++ fsl,asrc-dma-tx-events = <20 21 22>; ++ status = "okay"; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/sound/fsl-easi.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/fsl-easi.txt +--- linux-3.10.30/Documentation/devicetree/bindings/sound/fsl-easi.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/fsl-easi.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,26 @@ ++* Freescale Enhanced Serial Audio Interface (ESAI) ++ ++Required properties: ++ - compatible: Should be "fsl,-esai". ++ - reg: Offset and length of the register set for the device. ++ - interrupts: Contains ESAI interrupt. ++ - clocks: Contains an entry for each entry in clock-names. ++ - fsl,fifo-depth: The number of elements in the transmit and receive FIFOs. ++ This number is the maximum allowed value for TFCR[TFWM]. ++ - fsl,esai-dma-events: The dma event of the esai, , a is the tx dma. ++ b is the rx dma. ++ - fsl,flags: <1> is for ESAI network mode, <2> is for ESAI SYNC mode. ++ <3> is for network and SYNC mode. ++ ++Example: ++ ++esai: esai@02024000 { ++ compatible = "fsl,imx6q-esai"; ++ reg = <0x02024000 0x4000>; ++ interrupts = <0 51 0x04>; ++ clocks = <&clks 118>; ++ fsl,fifo-depth = <128>; ++ fsl,esai-dma-events = <24 23>; ++ fsl,flags = <1>; ++ status = "disabled"; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt +--- linux-3.10.30/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,25 @@ ++Freescale i.MX audio complex with CS42888 codec ++ ++Required properties: ++- compatible : "fsl,imx-audio-cs42888" ++- model : The user-visible name of this sound complex ++- esai-controller : The phandle of the i.MX SSI controller ++- audio-codec : The phandle of the CS42888 audio codec ++ ++Optional properties: ++- asrc-controller : The phandle of the i.MX ASRC controller ++- audio-routing : A list of the connections between audio components. ++ Each entry is a pair of strings, the first being the connection's sink, ++ the second being the connection's source. Valid names could be power ++ supplies, CS42888 pins, and the jacks on the board: ++ ++Example: ++ ++sound { ++ compatible = "fsl,imx6q-sabresd-wm8962", ++ "fsl,imx-audio-wm8962"; ++ model = "cs42888-audio"; ++ esai-controller = <&esai>; ++ asrc-controller = <&asrc_p2p>; ++ audio-codec = <&codec>; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/sound/imx-audio-si476x.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/imx-audio-si476x.txt +--- linux-3.10.30/Documentation/devicetree/bindings/sound/imx-audio-si476x.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/imx-audio-si476x.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,24 @@ ++Freescale i.MX audio complex with si476x codec ++ ++Required properties: ++- compatible : "fsl,imx-audio-si476x" ++- model : The user-visible name of this sound complex ++- ssi-controller : The phandle of the i.MX SSI controller ++ ++- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) ++- mux-ext-port : The external port of the i.MX audio muxer ++ ++Note: The AUDMUX port numbering should start at 1, which is consistent with ++hardware manual. ++ ++Example: ++ ++sound { ++ compatible = "fsl,imx-audio-si476x", ++ "fsl,imx-tuner-si476x"; ++ model = "imx-radio-si476x"; ++ ++ ssi-controller = <&ssi1>; ++ mux-int-port = <2>; ++ mux-ext-port = <5>; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt +--- linux-3.10.30/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,34 @@ ++Freescale i.MX audio complex with S/PDIF transceiver ++ ++Required properties: ++ ++ - compatible : "fsl,imx-audio-spdif" ++ ++ - model : The user-visible name of this sound complex ++ ++ - spdif-controller : The phandle of the i.MX S/PDIF controller ++ ++ ++Optional properties: ++ ++ - spdif-out : This is a boolean property. If present, the transmitting ++ function of S/PDIF will be enabled, indicating there's a physical ++ S/PDIF out connector/jack on the board or it's connecting to some ++ other IP block, such as an HDMI encoder/display-controller. ++ ++ - spdif-in : This is a boolean property. If present, the receiving ++ function of S/PDIF will be enabled, indicating there's a physical ++ S/PDIF in connector/jack on the board. ++ ++* Note: At least one of these two properties should be set in the DT binding. ++ ++ ++Example: ++ ++sound-spdif { ++ compatible = "fsl,imx-audio-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-out; ++ spdif-in; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt +--- linux-3.10.30/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,54 @@ ++Freescale i.MX audio complex with WM8962 codec ++ ++Required properties: ++- compatible : "fsl,imx-audio-wm8962" ++- model : The user-visible name of this sound complex ++- ssi-controller : The phandle of the i.MX SSI controller ++- audio-codec : The phandle of the WM8962 audio codec ++- audio-routing : A list of the connections between audio components. ++ Each entry is a pair of strings, the first being the connection's sink, ++ the second being the connection's source. Valid names could be power ++ supplies, WM8962 pins, and the jacks on the board: ++ ++ Power supplies: ++ * Mic Bias ++ ++ Board connectors: ++ * Mic Jack ++ * Headphone Jack ++ * Ext Spk ++ ++- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) ++- mux-ext-port : The external port of the i.MX audio muxer ++ ++Note: The AUDMUX port numbering should start at 1, which is consistent with ++hardware manual. ++ ++Optional properties: ++- hp-det-gpios : The gpio pin to detect plug in/out event that happens to ++ Headphone jack. ++- mic-det-gpios: The gpio pin to detect plug in/out event that happens to ++ Microphone jack. ++ ++Example: ++ ++sound { ++ compatible = "fsl,imx6q-sabresd-wm8962", ++ "fsl,imx-audio-wm8962"; ++ model = "wm8962-audio"; ++ ssi-controller = <&ssi2>; ++ audio-codec = <&codec>; ++ audio-routing = ++ "Headphone Jack", "HPOUTL", ++ "Headphone Jack", "HPOUTR", ++ "Ext Spk", "SPKOUTL", ++ "Ext Spk", "SPKOUTR", ++ "MICBIAS", "AMIC", ++ "IN3R", "MICBIAS", ++ "DMIC", "MICBIAS", ++ "DMICDAT", "DMIC"; ++ mux-int-port = <2>; ++ mux-ext-port = <3>; ++ hp-det-gpios = <&gpio7 8 1>; ++ mic-det-gpios = <&gpio1 9 1>; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/sound/wm8962.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/wm8962.txt +--- linux-3.10.30/Documentation/devicetree/bindings/sound/wm8962.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/sound/wm8962.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -8,9 +8,40 @@ + + - reg : the I2C address of the device. + ++Optional properties: ++ - spk-mono: This is a boolean property. If present, the SPK_MONO bit ++ of R51 (Class D Control 2) gets set, indicating that the speaker is ++ in mono mode. ++ ++ - amic-mono: This is a boolean property. If present, indicating that the ++ analog micphone is hardware mono input, the driver would enable monomix ++ for it. ++ ++ - dmic-mono: This is a boolean property. If present, indicating that the ++ digital micphone is hardware mono input, the driver would enable monomix ++ for it. ++ ++ - mic-cfg : Default register value for R48 (Additional Control 4). ++ If absent, the default should be the register default. ++ ++ - gpio-cfg : A list of GPIO configuration register values. The list must ++ be 6 entries long. If absent, no configuration of these registers is ++ performed. And note that only the value within [0x0, 0xffff] is valid. ++ Any other value is regarded as setting the GPIO register by its reset ++ value 0x0. ++ + Example: + + codec: wm8962@1a { + compatible = "wlf,wm8962"; + reg = <0x1a>; ++ ++ gpio-cfg = < ++ 0x0000 /* 0:Default */ ++ 0x0000 /* 1:Default */ ++ 0x0013 /* 2:FN_DMICCLK */ ++ 0x0000 /* 3:Default */ ++ 0x8014 /* 4:FN_DMICCDAT */ ++ 0x0000 /* 5:Default */ ++ >; + }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/spi/spi-bus.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/spi/spi-bus.txt +--- linux-3.10.30/Documentation/devicetree/bindings/spi/spi-bus.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/spi/spi-bus.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -55,6 +55,16 @@ + chip select active high + - spi-3wire - (optional) Empty property indicating device requires + 3-wire mode. ++- spi-tx-bus-width - (optional) The bus width(number of data wires) that ++ used for MOSI. Defaults to 1 if not present. ++- spi-rx-bus-width - (optional) The bus width(number of data wires) that ++ used for MISO. Defaults to 1 if not present. ++ ++Some SPI controllers and devices support Dual and Quad SPI transfer mode. ++It allows data in SPI system transfered in 2 wires(DUAL) or 4 wires(QUAD). ++Now the value that spi-tx-bus-width and spi-rx-bus-width can receive is ++only 1(SINGLE), 2(DUAL) and 4(QUAD). ++Dual/Quad mode is not allowed when 3-wire mode is used. + + If a gpio chipselect is used for the SPI slave the gpio number will be passed + via the cs_gpio +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/thermal/imx-thermal.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/thermal/imx-thermal.txt +--- linux-3.10.30/Documentation/devicetree/bindings/thermal/imx-thermal.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/thermal/imx-thermal.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,17 @@ ++* Temperature Monitor (TEMPMON) on Freescale i.MX SoCs ++ ++Required properties: ++- compatible : "fsl,imx6q-thermal" ++- fsl,tempmon : phandle pointer to system controller that contains TEMPMON ++ control registers, e.g. ANATOP on imx6q. ++- fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON ++ calibration data, e.g. OCOTP on imx6q. The details about calibration data ++ can be found in SoC Reference Manual. ++ ++Example: ++ ++tempmon { ++ compatible = "fsl,imx6q-tempmon"; ++ fsl,tempmon = <&anatop>; ++ fsl,tempmon-data = <&ocotp>; ++}; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt +--- linux-3.10.30/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/tty/serial/fsl-imx-uart.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -8,6 +8,8 @@ + Optional properties: + - fsl,uart-has-rtscts : Indicate the uart has rts and cts + - fsl,irda-mode : Indicate the uart supports irda mode ++- fsl,dte-mode : Indicate the uart works in DTE mode. The uart works ++ is DCE mode by default. + + Example: + +@@ -16,4 +18,5 @@ + reg = <0x73fbc000 0x4000>; + interrupts = <31>; + fsl,uart-has-rtscts; ++ fsl,dte-mode; + }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/tty/serial/fsl-lpuart.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/tty/serial/fsl-lpuart.txt +--- linux-3.10.30/Documentation/devicetree/bindings/tty/serial/fsl-lpuart.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/tty/serial/fsl-lpuart.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,14 @@ ++* Freescale low power universal asynchronous receiver/transmitter (lpuart) ++ ++Required properties: ++- compatible : Should be "fsl,-lpuart" ++- reg : Address and length of the register set for the device ++- interrupts : Should contain uart interrupt ++ ++Example: ++ ++uart0: serial@40027000 { ++ compatible = "fsl,vf610-lpuart"; ++ reg = <0x40027000 0x1000>; ++ interrupts = <0 61 0x00>; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt +--- linux-3.10.30/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -5,6 +5,12 @@ + - reg: Should contain registers location and length + - interrupts: Should contain controller interrupt + ++Recommended properies: ++- phy_type: the type of the phy connected to the core. Should be one ++ of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this ++ property the PORTSC register won't be touched ++- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" ++ + Optional properties: + - fsl,usbphy: phandler of usb phy that connects to the only one port + - fsl,usbmisc: phandler of non-core register device, with one argument +@@ -12,6 +18,12 @@ + - vbus-supply: regulator for vbus + - disable-over-current: disable over current detect + - external-vbus-divider: enables off-chip resistor divider for Vbus ++- imx6-usb-charger-detection: enable imx6 usb charger detect function, ++only set it when the user wants SoC usb charger detection capabilities. ++If the user wants to use charger IC's usb charger detection capabilities, ++please do not set it. ++- fsl,anatop: phandle for anatop module, anatop module is only existed ++at imx6 SoC series + + Examples: + usb@02184000 { /* USB OTG */ +@@ -22,4 +34,6 @@ + fsl,usbmisc = <&usbmisc 0>; + disable-over-current; + external-vbus-divider; ++ imx6-usb-charger-detection; ++ fsl,anatop = <&anatop>; + }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/usb/mxs-phy.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/usb/mxs-phy.txt +--- linux-3.10.30/Documentation/devicetree/bindings/usb/mxs-phy.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/usb/mxs-phy.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -1,13 +1,16 @@ + * Freescale MXS USB Phy Device + + Required properties: +-- compatible: Should be "fsl,imx23-usbphy" ++- compatible: "fsl,imx23-usbphy" for imx23 and imx28, "fsl,imx6q-usbphy" ++for imx6dq and imx6dl, "fsl,imx6sl-usbphy" for imx6sl + - reg: Should contain registers location and length + - interrupts: Should contain phy interrupt ++- fsl,anatop: phandle for anatop register, it is only for imx6 SoC series + + Example: + usbphy1: usbphy@020c9000 { + compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; + reg = <0x020c9000 0x1000>; + interrupts = <0 44 0x04>; ++ fsl,anatop = <&anatop>; + }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/video/fsl,csi-v4l2-capture.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/video/fsl,csi-v4l2-capture.txt +--- linux-3.10.30/Documentation/devicetree/bindings/video/fsl,csi-v4l2-capture.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/video/fsl,csi-v4l2-capture.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,61 @@ ++* Freescale CMOS Sensor Interface (CSI) V4L2 Capture ++ ++Required properties for CSI ++- compatible: "fsl,-csi". Supported chip includes imx6sl ++- reg: Address and length of the register set for CSI ++- interrupts: Should contain CSI interrupts ++ ++Required properties for v4l2_capture ++- compatible: should be "fsl,-csi-v4l2", supported socs include imx6sl ++ ++Required properties for sensor ++- compatible: "," ++ please check the supported sensor in the Supported Sensor fields. ++- reg: sensor I2C slave address ++- pinctrl-names: should be "default" for parallel sensor ++- pinctrl-0: should depend on the connection between sensor and i.MX ++ connection between sensor and i.MX could be only legacy parallel on i.MX6SL ++- clocks: should be the clock source provided to sensor. ++- clock-names: should be "csi_mclk" ++- AVDD-supply: set according to the board. ++- DVDD-supply: set according to the board. ++- pwn-gpios: set according to the board. ++- rst-gpios: set according to the board. ++- csi_id: csi id for v4l2 capture device ++ should be 0 for i.MX6SL ++- mclk: should the value of mclk clock send out the sensor. unit is Hz. ++- mclk_source: should be 0 for i.MX6SL ++ ++Supported Sensor ++- ovti, ov5640 ++ ++Example for CSI: ++ csi: csi@020e4000 { ++ compatible = "fsl,imx6sl-csi"; ++ reg = <0x020e4000 0x4000>; ++ interrupts = <0 7 0x04>; ++ status = "disabled"; ++ }; ++ ++Examples for v4l2_capture: ++ csi_v4l2_cap { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ status = "okay"; ++ }; ++ ++Examples for sensors: ++ ov564x: ov564x@3c { ++ compatible = "ovti,ov564x"; ++ reg = <0x3c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_csi_0>; ++ clocks = <&clks IMX6SL_CLK_CSI>; ++ clock-names = "csi_mclk"; ++ AVDD-supply = <&vgen6_reg>; /* 2.8v */ ++ DVDD-supply = <&vgen2_reg>; /* 1.5v*/ ++ pwn-gpios = <&gpio1 25 1>; ++ rst-gpios = <&gpio1 26 0>; ++ csi_id = <0>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/video/fsl,mipi-csi2.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/video/fsl,mipi-csi2.txt +--- linux-3.10.30/Documentation/devicetree/bindings/video/fsl,mipi-csi2.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/video/fsl,mipi-csi2.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,42 @@ ++* Freescale MIPI CSI2 Controller for i.MX6DQ/i.MX6SDL ++ ++Required properties for mipi csi2 controller: ++- compatible: should be "fsl,imx6q-mipi-csi2" ++- reg: contains mipi csi2 register base address and range ++- interrupts: where type is a interrupt type, num is the ++ interrupt number and flag is a field that level/trigger information for ++ the interrupt. ++- clocks: the clock sources that mipi csi2 depends on. ++- clock-names: the name is related to the clock source one by one. ++- status: should be set to "disable". ++ ++Required properties for mipi csi2 on specified board: ++- ipu_id: ipu id which mipi csi2 connected to. ++ should be 0 or 1 for i.MX6DQ; should be 0 for i.MX6SDL ++- csi_id: csi id which mipi csi2 connected to. ++ should be 0 or 1 for i.MX6DQ/i.MX6SDL ++- v_channel: virtual channel which send to MIPI CSI2 controller ++ should keep consistent with the input MIPI signal. ++- lanes: data lanes of input MIPI signal. The maximum data lanes is 4. ++ should keep consistent with the input MIPI signal. ++- status: should be set to "okay". ++ ++Examples: ++for SOC imx6qdl.dtsi: ++ mipi_csi@021dc000 { ++ compatible = "fsl,imx6q-mipi-csi2"; ++ reg = <0x021dc000 0x4000>; ++ interrupts = <0 100 0x04>, <0 101 0x04>; ++ clocks = <&clks 138>, <&clks 53>; ++ clock-names = "dphy_clk", "pixel_clk"; ++ status = "disabled"; ++ }; ++ ++for board imx6qdl-sabresd.dtsi: ++ mipi_csi@021dc000 { ++ status = "okay"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ v_channel = <0>; ++ lanes = <2>; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/video/fsl,pxp.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/video/fsl,pxp.txt +--- linux-3.10.30/Documentation/devicetree/bindings/video/fsl,pxp.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/video/fsl,pxp.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,30 @@ ++* Freescale PxP Controller for i.MX6DL, i.MX6SL ++ ++Required properties for PxP controller: ++- compatible: should be "fsl,-pxp-dma" ++- reg: contains pxp register base address and range ++- interrupts: where type is an interrupt type, num is the ++ interrupt number and flag is a field that level/trigger information for ++ the interrupt. ++- clocks: the clock sources that pxp depends on. ++- clock-names: the name is related to the clock source ++ ++Required properties for pxp on specified board: ++- status: should be set to "okay" if want to use PxP ++ ++Examples: ++for SOC imx6dl.dtsi: ++ pxp@020f0000 { ++ compatible = "fsl,imx6dl-pxp-dma"; ++ reg = <0x020f0000 0x4000>; ++ interrupts = <0 98 0x04>; ++ clocks = <&clks 133>; ++ clock-names = "pxp-axi"; ++ status = "disabled"; ++ }; ++ ++ ++for board imx6dl-sabresd.dts: ++ &pxp { ++ status = "okay"; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/video/fsl,v4l2-capture.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/video/fsl,v4l2-capture.txt +--- linux-3.10.30/Documentation/devicetree/bindings/video/fsl,v4l2-capture.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/video/fsl,v4l2-capture.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,102 @@ ++* Freescale V4L2 Capture for i.MX6DQ/i.MX6SDL ++ ++Required board properties for IPUv3 capture: ++- clocks: should include the clock provided by i.MX6 to sensor ++- clock-names: sensor clock's name should be "ipux_csiy" ++ x should be 1 or 2 for i.MX6DQ; should be 1 for i.MX6SDL ++ y is 0 or 1 for i.MX6DQ/i.MX6SDL ++Note: other detailed information for IPUv3, please refer to ++Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt ++ ++Required properties for v4l2_capture ++- compatible: should be "fsl,imx6q-v4l2-capture" ++- ipu_id: ipu id for v4l2 capture device ++ should be 0 or 1 for i.MX6DQ; should be 0 for i.MX6SDL ++- csi_id: csi id for v4l2 capture device ++ should be 0 or 1 for i.MX6DQ/i.MX6SDL ++- mclk_source: should be 0 or 1. two mclk sources at most now ++- status: should be set to "okay" to enable this device ++ ++Required properties for sensor ++- compatible: "," ++ please check the supported sensor in the Supported Sensor fields. ++- reg: sensor I2C slave address ++- pinctrl-names: should be "default" for parallel sensor ++- pinctrl-0: should depend on the connection between sensor and i.MX ++ connection between sensor and i.MX could be MIPI-CSI2 or legacy parallel ++- clocks: should be the clock source provided to sensor. ++- clock-names: should be "csi_mclk" ++- DOVDD-supply: set according to the board. ++- AVDD-supply: set according to the board. ++- DVDD-supply: set according to the board. ++- pwn-gpios: set according to the board. ++- rst-gpios: set according to the board. ++- csi_id: csi id for v4l2 capture device ++ should be 0 or 1 for i.MX6DQ/i.MX6SDL. ++- mclk: should the value of mclk clock send out the sensor. unit is Hz. ++- mclk_source: should be 0 or 1 and should be the same as the setting in ++ v4l2_capture. ++- cvbs: 1 for CVBS input, 0 YPbPr input. This property is only needed for ++ adv7180 tv decoder. ++ ++Supported Sensor ++- ov5640 ++- ov5642 ++- ov5640_mipi ++- adv7180 ++ ++ ++Example for IPUv3 including capture settings on imx6q-sabresd.dts: ++ ipu1: ipu@02400000 { /* IPU1 */ ++ compatible = "fsl,imx6q-ipuv3"; ++ reg = <0x02400000 0x400000>; ++ interrupts = <0 5 0x04>, < 0 6 0x04>; ++ clocks = <&clks 130>, <&clks 131>, <&clks 132>, <&clks 39>, <&clks 40>, <&clks 169>; ++ clock-names = "ipu1", "ipu1_di0", "ipu1_di1", "ipu1_di0_sel", "ipu1_di1_sel", "ipu1_csi0"; ++ status = "disabled"; ++ }; ++ ++Examples for v4l2_capture: ++ v4l2_cap { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <0>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++Examples for sensors: ++ ov5642: ov5642@3c { ++ compatible = "ovti,ov5642"; ++ reg = <0x3c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ipu1_2>; ++ clocks = <&clks 201>; ++ clock-names = "csi_mclk"; ++ DOVDD-supply = <&vgen4_reg>; /* 1.8v */ ++ AVDD-supply = <&vgen3_reg>; /* 2.8v, on rev C board is VGEN3 */ ++ DVDD-supply = <&vgen2_reg>; /* 1.5v*/ ++ pwn-gpios = <&gpio1 16 1>; /* active low: SD1_DAT0 */ ++ rst-gpios = <&gpio1 17 0>; /* active high: SD1_DAT1 */ ++ csi_id = <0>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ }; ++ ++ adv7180: adv7180@21 { ++ compatible = "adv,adv7180"; ++ reg = <0x21>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ipu1_3>; ++ clocks = <&clks 201>; ++ clock-names = "csi_mclk"; ++ DOVDD-supply = <®_3p3v>; /* 3.3v, enabled via 2.8 VGEN6 */ ++ AVDD-supply = <®_3p3v>; /* 1.8v */ ++ DVDD-supply = <®_3p3v>; /* 1.8v */ ++ PVDD-supply = <®_3p3v>; /* 1.8v */ ++ pwn-gpios = <&max7310_b 2 0>; ++ csi_id = <0>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ cvbs = <1>; ++ }; +diff -Nur linux-3.10.30/Documentation/devicetree/bindings/video/mxc_hdmi_video.txt linux-3.10.30-cubox-i/Documentation/devicetree/bindings/video/mxc_hdmi_video.txt +--- linux-3.10.30/Documentation/devicetree/bindings/video/mxc_hdmi_video.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/devicetree/bindings/video/mxc_hdmi_video.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,20 @@ ++Device-Tree bindings for hdmi video driver ++ ++Required properties: ++- compatible: value should be "fsl,imx6q-hdmi-video". ++- fsl,hdcp: define the property in dts, hdmi driver will initalize for hdcp, ++ otherwise hdcp function will not supported. ++- fsl,phy_reg_vlev: hdmi phy register,Voltage Level Control Register offset 0x0e, ++ adjust hdmi phy signal voltage level. ++- fsl,phy_reg_cksymtx: hdmi phy register, clock symbol and transmitter control ++ register offset 0x09, adjust hdmi signal pre-emphasis. ++ ++Example: ++ ++ hdmi_video { ++ compatible = "fsl,imx6q-hdmi-video"; ++ fsl,hdcp; ++ fsl,phy_reg_vlev = <0x0294>; ++ fsl,phy_reg_cksymtx = <0x800d>; ++ }; ++ +diff -Nur linux-3.10.30/Documentation/driver-model/devres.txt linux-3.10.30-cubox-i/Documentation/driver-model/devres.txt +--- linux-3.10.30/Documentation/driver-model/devres.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/driver-model/devres.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -293,3 +293,6 @@ + PHY + devm_usb_get_phy() + devm_usb_put_phy() ++ ++SPI ++ devm_spi_register_master() +diff -Nur linux-3.10.30/Documentation/kernel-parameters.txt linux-3.10.30-cubox-i/Documentation/kernel-parameters.txt +--- linux-3.10.30/Documentation/kernel-parameters.txt 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/kernel-parameters.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -1240,6 +1240,15 @@ + See comment before ip2_setup() in + drivers/char/ip2/ip2base.c. + ++ irqaffinity= [SMP] Set the default irq affinity mask ++ Format: ++ ,..., ++ or ++ - ++ (must be a positive range in ascending order) ++ or a mixture ++ ,...,- ++ + irqfixup [HW] + When an interrupt is not handled search all handlers + for it. Intended to get systems with badly broken +@@ -3345,6 +3354,21 @@ + that this also can be controlled per-workqueue for + workqueues visible under /sys/bus/workqueue/. + ++ workqueue.power_efficient ++ Per-cpu workqueues are generally preferred because ++ they show better performance thanks to cache ++ locality; unfortunately, per-cpu workqueues tend to ++ be more power hungry than unbound workqueues. ++ ++ Enabling this makes the per-cpu workqueues which ++ were observed to contribute significantly to power ++ consumption unbound, leading to measurably lower ++ power usage at the cost of small performance ++ overhead. ++ ++ The default value of this parameter is determined by ++ the config option CONFIG_WQ_POWER_EFFICIENT_DEFAULT. ++ + x2apic_phys [X86-64,APIC] Use x2apic physical mode instead of + default x2apic cluster mode on platforms + supporting x2apic. +diff -Nur linux-3.10.30/Documentation/vm/zswap.txt linux-3.10.30-cubox-i/Documentation/vm/zswap.txt +--- linux-3.10.30/Documentation/vm/zswap.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/Documentation/vm/zswap.txt 2014-03-08 20:32:52.000000000 +0100 +@@ -0,0 +1,72 @@ ++Overview: ++ ++Zswap is a lightweight compressed cache for swap pages. It takes pages that are ++in the process of being swapped out and attempts to compress them into a ++dynamically allocated RAM-based memory pool. If this process is successful, ++the writeback to the swap device is deferred and, in many cases, avoided ++completely. This results in a significant I/O reduction and performance gains ++for systems that are swapping. ++ ++Zswap provides compressed swap caching that basically trades CPU cycles for ++reduced swap I/O. This trade-off can result in a significant performance ++improvement as reads to/writes from to the compressed cache almost always ++faster that reading from a swap device which incurs the latency of an ++asynchronous block I/O read. ++ ++Some potential benefits: ++* Desktop/laptop users with limited RAM capacities can mitigate the ++ performance impact of swapping. ++* Overcommitted guests that share a common I/O resource can ++ dramatically reduce their swap I/O pressure, avoiding heavy handed I/O ++ throttling by the hypervisor. This allows more work to get done with less ++ impact to the guest workload and guests sharing the I/O subsystem ++* Users with SSDs as swap devices can extend the life of the device by ++ drastically reducing life-shortening writes. ++ ++Zswap evicts pages from compressed cache on an LRU basis to the backing swap ++device when the compressed pool reaches it size limit. This requirement had ++been identified in prior community discussions. ++ ++To enabled zswap, the "enabled" attribute must be set to 1 at boot time. e.g. ++zswap.enabled=1 ++ ++Design: ++ ++Zswap receives pages for compression through the Frontswap API and is able to ++evict pages from its own compressed pool on an LRU basis and write them back to ++the backing swap device in the case that the compressed pool is full. ++ ++Zswap makes use of zbud for the managing the compressed memory pool. Each ++allocation in zbud is not directly accessible by address. Rather, a handle is ++return by the allocation routine and that handle must be mapped before being ++accessed. The compressed memory pool grows on demand and shrinks as compressed ++pages are freed. The pool is not preallocated. ++ ++When a swap page is passed from frontswap to zswap, zswap maintains a mapping ++of the swap entry, a combination of the swap type and swap offset, to the zbud ++handle that references that compressed swap page. This mapping is achieved ++with a red-black tree per swap type. The swap offset is the search key for the ++tree nodes. ++ ++During a page fault on a PTE that is a swap entry, frontswap calls the zswap ++load function to decompress the page into the page allocated by the page fault ++handler. ++ ++Once there are no PTEs referencing a swap page stored in zswap (i.e. the count ++in the swap_map goes to 0) the swap code calls the zswap invalidate function, ++via frontswap, to free the compressed entry. ++ ++Zswap seeks to be simple in its policies. Sysfs attributes allow for two user ++controlled policies: ++* max_compression_ratio - Maximum compression ratio, as as percentage, ++ for an acceptable compressed page. Any page that does not compress by at ++ least this ratio will be rejected. ++* max_pool_percent - The maximum percentage of memory that the compressed ++ pool can occupy. ++ ++Zswap allows the compressor to be selected at kernel boot time by setting the ++“compressor” attribute. The default compressor is lzo. e.g. ++zswap.compressor=deflate ++ ++A debugfs interface is provided for various statistic about pool size, number ++of pages stored, and various counters for the reasons pages are rejected. +diff -Nur linux-3.10.30/arch/arm/Kconfig linux-3.10.30-cubox-i/arch/arm/Kconfig +--- linux-3.10.30/arch/arm/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/Kconfig 2014-03-08 21:32:22.000000000 +0100 +@@ -1494,6 +1494,109 @@ + MultiThreading at a cost of slightly increased overhead in some + places. If unsure say N here. + ++config DISABLE_CPU_SCHED_DOMAIN_BALANCE ++ bool "(EXPERIMENTAL) Disable CPU level scheduler load-balancing" ++ help ++ Disables scheduler load-balancing at CPU sched domain level. ++ ++config SCHED_HMP ++ bool "(EXPERIMENTAL) Heterogenous multiprocessor scheduling" ++ depends on DISABLE_CPU_SCHED_DOMAIN_BALANCE && SCHED_MC && FAIR_GROUP_SCHED && !SCHED_AUTOGROUP ++ help ++ Experimental scheduler optimizations for heterogeneous platforms. ++ Attempts to introspectively select task affinity to optimize power ++ and performance. Basic support for multiple (>2) cpu types is in place, ++ but it has only been tested with two types of cpus. ++ There is currently no support for migration of task groups, hence ++ !SCHED_AUTOGROUP. Furthermore, normal load-balancing must be disabled ++ between cpus of different type (DISABLE_CPU_SCHED_DOMAIN_BALANCE). ++ When turned on, this option adds sys/kernel/hmp directory which ++ contains the following files: ++ up_threshold - the load average threshold used for up migration ++ (0 - 1023) ++ down_threshold - the load average threshold used for down migration ++ (0 - 1023) ++ hmp_domains - a list of cpumasks for the present HMP domains, ++ starting with the 'biggest' and ending with the ++ 'smallest'. ++ Note that both the threshold files can be written at runtime to ++ control scheduler behaviour. ++ ++config SCHED_HMP_PRIO_FILTER ++ bool "(EXPERIMENTAL) Filter HMP migrations by task priority" ++ depends on SCHED_HMP ++ help ++ Enables task priority based HMP migration filter. Any task with ++ a NICE value above the threshold will always be on low-power cpus ++ with less compute capacity. ++ ++config SCHED_HMP_PRIO_FILTER_VAL ++ int "NICE priority threshold" ++ default 5 ++ depends on SCHED_HMP_PRIO_FILTER ++ ++config HMP_FAST_CPU_MASK ++ string "HMP scheduler fast CPU mask" ++ depends on SCHED_HMP ++ help ++ Leave empty to use device tree information. ++ Specify the cpuids of the fast CPUs in the system as a list string, ++ e.g. cpuid 0+1 should be specified as 0-1. ++ ++config HMP_SLOW_CPU_MASK ++ string "HMP scheduler slow CPU mask" ++ depends on SCHED_HMP ++ help ++ Leave empty to use device tree information. ++ Specify the cpuids of the slow CPUs in the system as a list string, ++ e.g. cpuid 0+1 should be specified as 0-1. ++ ++config HMP_VARIABLE_SCALE ++ bool "Allows changing the load tracking scale through sysfs" ++ depends on SCHED_HMP ++ help ++ When turned on, this option exports the load average period value ++ for the load tracking patches through sysfs. ++ The values can be modified to change the rate of load accumulation ++ used for HMP migration. 'load_avg_period_ms' is the time in ms to ++ reach a load average of 0.5 for an idle task of 0 load average ++ ratio which becomes 100% busy. ++ For example, with load_avg_period_ms = 128 and up_threshold = 512, ++ a running task with a load of 0 will be migrated to a bigger CPU after ++ 128ms, because after 128ms its load_avg_ratio is 0.5 and the real ++ up_threshold is 0.5. ++ This patch has the same behavior as changing the Y of the load ++ average computation to ++ (1002/1024)^(LOAD_AVG_PERIOD/load_avg_period_ms) ++ but removes intermediate overflows in computation. ++ ++config HMP_FREQUENCY_INVARIANT_SCALE ++ bool "(EXPERIMENTAL) Frequency-Invariant Tracked Load for HMP" ++ depends on SCHED_HMP && CPU_FREQ ++ help ++ Scales the current load contribution in line with the frequency ++ of the CPU that the task was executed on. ++ In this version, we use a simple linear scale derived from the ++ maximum frequency reported by CPUFreq. ++ Restricting tracked load to be scaled by the CPU's frequency ++ represents the consumption of possible compute capacity ++ (rather than consumption of actual instantaneous capacity as ++ normal) and allows the HMP migration's simple threshold ++ migration strategy to interact more predictably with CPUFreq's ++ asynchronous compute capacity changes. ++ ++config SCHED_HMP_LITTLE_PACKING ++ bool "Small task packing for HMP" ++ depends on SCHED_HMP ++ default n ++ help ++ Allows the HMP Scheduler to pack small tasks into CPUs in the ++ smallest HMP domain. ++ Controlled by two sysfs files in sys/kernel/hmp. ++ packing_enable: 1 to enable, 0 to disable packing. Default 1. ++ packing_limit: runqueue load ratio where a RQ is considered ++ to be full. Default is NICE_0_LOAD * 9/8. ++ + config HAVE_ARM_SCU + bool + help +@@ -1521,6 +1624,31 @@ + for (multi-)cluster based systems, such as big.LITTLE based + systems. + ++config BIG_LITTLE ++ bool "big.LITTLE support (Experimental)" ++ depends on CPU_V7 && SMP ++ select MCPM ++ help ++ This option enables support for the big.LITTLE architecture. ++ ++config BL_SWITCHER ++ bool "big.LITTLE switcher support" ++ depends on BIG_LITTLE && MCPM && HOTPLUG_CPU ++ select CPU_PM ++ select ARM_CPU_SUSPEND ++ help ++ The big.LITTLE "switcher" provides the core functionality to ++ transparently handle transition between a cluster of A15's ++ and a cluster of A7's in a big.LITTLE system. ++ ++config BL_SWITCHER_DUMMY_IF ++ tristate "Simple big.LITTLE switcher user interface" ++ depends on BL_SWITCHER && DEBUG_KERNEL ++ help ++ This is a simple and dummy char dev interface to control ++ the big.LITTLE switcher core code. It is meant for ++ debugging purposes only. ++ + choice + prompt "Memory split" + default VMSPLIT_3G +@@ -1738,6 +1866,7 @@ + range 11 64 if ARCH_SHMOBILE + default "12" if SOC_AM33XX + default "9" if SA1111 ++ default "14" if ARCH_MXC + default "11" + help + The kernel memory allocator divides physically contiguous memory +diff -Nur linux-3.10.30/arch/arm/Kconfig.debug linux-3.10.30-cubox-i/arch/arm/Kconfig.debug +--- linux-3.10.30/arch/arm/Kconfig.debug 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/Kconfig.debug 2014-03-08 20:32:53.000000000 +0100 +@@ -251,6 +251,13 @@ + Say Y here if you want kernel low-level debugging support + on i.MX6Q/DL. + ++ config DEBUG_IMX6SL_UART ++ bool "i.MX6SL Debug UART" ++ depends on SOC_IMX6SL ++ help ++ Say Y here if you want kernel low-level debugging support ++ on i.MX6SL. ++ + config DEBUG_MMP_UART2 + bool "Kernel low-level debugging message via MMP UART2" + depends on ARCH_MMP +@@ -309,6 +316,13 @@ + Say Y here if you want kernel low-level debugging support + on MVEBU based platforms. + ++ config DEBUG_VF_UART ++ bool "Vybrid UART" ++ depends on SOC_VF610 ++ help ++ Say Y here if you want kernel low-level debugging support ++ on Vybrid based platforms. ++ + config DEBUG_NOMADIK_UART + bool "Kernel low-level debugging messages via NOMADIK UART" + depends on ARCH_NOMADIK +@@ -532,7 +546,8 @@ + DEBUG_IMX35_UART || \ + DEBUG_IMX51_UART || \ + DEBUG_IMX53_UART || \ +- DEBUG_IMX6Q_UART ++ DEBUG_IMX6Q_UART || \ ++ DEBUG_IMX6SL_UART + default 1 + depends on ARCH_MXC + help +@@ -631,7 +646,8 @@ + DEBUG_IMX35_UART || \ + DEBUG_IMX51_UART || \ + DEBUG_IMX53_UART ||\ +- DEBUG_IMX6Q_UART ++ DEBUG_IMX6Q_UART || \ ++ DEBUG_IMX6SL_UART + default "debug/mvebu.S" if DEBUG_MVEBU_UART + default "debug/mxs.S" if DEBUG_IMX23_UART || DEBUG_IMX28_UART + default "debug/nomadik.S" if DEBUG_NOMADIK_UART +@@ -646,6 +662,7 @@ + default "debug/ux500.S" if DEBUG_UX500_UART + default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT || \ + DEBUG_VEXPRESS_UART0_CA9 || DEBUG_VEXPRESS_UART0_RS1 ++ default "debug/vf.S" if DEBUG_VF_UART + default "debug/vt8500.S" if DEBUG_VT8500_UART0 + default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1 + default "mach/debug-macro.S" +diff -Nur linux-3.10.30/arch/arm/boot/dts/Makefile linux-3.10.30-cubox-i/arch/arm/boot/dts/Makefile +--- linux-3.10.30/arch/arm/boot/dts/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/Makefile 2014-03-08 20:32:53.000000000 +0100 +@@ -113,14 +113,31 @@ + imx53-mba53.dtb \ + imx53-qsb.dtb \ + imx53-smd.dtb \ ++ imx6dl-cubox-i.dtb \ ++ imx6dl-hummingboard.dtb \ + imx6dl-sabreauto.dtb \ ++ imx6dl-sabreauto-ecspi.dtb \ ++ imx6dl-sabreauto-flexcan1.dtb \ ++ imx6dl-sabreauto-gpmi-weim.dtb \ + imx6dl-sabresd.dtb \ ++ imx6dl-sabresd-hdcp.dtb \ ++ imx6dl-sabresd-ldo.dtb \ + imx6dl-wandboard.dtb \ + imx6q-arm2.dtb \ ++ imx6q-cubox-i.dtb \ + imx6q-sabreauto.dtb \ ++ imx6q-sabreauto-ecspi.dtb \ ++ imx6q-sabreauto-flexcan1.dtb \ ++ imx6q-sabreauto-gpmi-weim.dtb \ + imx6q-sabrelite.dtb \ + imx6q-sabresd.dtb \ +- imx6q-sbc6x.dtb ++ imx6q-sabresd-hdcp.dtb \ ++ imx6q-sabresd-ldo.dtb \ ++ imx6q-sbc6x.dtb \ ++ imx6sl-evk.dtb \ ++ imx6sl-evk-csi.dtb \ ++ imx6sl-evk-ldo.dtb \ ++ vf610-twr.dtb + dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \ + imx23-olinuxino.dtb \ + imx23-stmp378x_devb.dtb \ +@@ -202,7 +219,14 @@ + dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \ + vexpress-v2p-ca9.dtb \ + vexpress-v2p-ca15-tc1.dtb \ +- vexpress-v2p-ca15_a7.dtb ++ vexpress-v2p-ca15_a7.dtb \ ++ rtsm_ve-cortex_a9x2.dtb \ ++ rtsm_ve-cortex_a9x4.dtb \ ++ rtsm_ve-cortex_a15x1.dtb \ ++ rtsm_ve-cortex_a15x2.dtb \ ++ rtsm_ve-cortex_a15x4.dtb \ ++ rtsm_ve-v2p-ca15x1-ca7x1.dtb \ ++ rtsm_ve-v2p-ca15x4-ca7x4.dtb + dtb-$(CONFIG_ARCH_VIRT) += xenvm-4.2.dtb + dtb-$(CONFIG_ARCH_VT8500) += vt8500-bv07.dtb \ + wm8505-ref.dtb \ +diff -Nur linux-3.10.30/arch/arm/boot/dts/clcd-panels.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/clcd-panels.dtsi +--- linux-3.10.30/arch/arm/boot/dts/clcd-panels.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/clcd-panels.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,52 @@ ++/* ++ * ARM Ltd. Versatile Express ++ * ++ */ ++ ++/ { ++ panels { ++ panel@0 { ++ compatible = "panel"; ++ mode = "VGA"; ++ refresh = <60>; ++ xres = <640>; ++ yres = <480>; ++ pixclock = <39721>; ++ left_margin = <40>; ++ right_margin = <24>; ++ upper_margin = <32>; ++ lower_margin = <11>; ++ hsync_len = <96>; ++ vsync_len = <2>; ++ sync = <0>; ++ vmode = "FB_VMODE_NONINTERLACED"; ++ ++ tim2 = "TIM2_BCD", "TIM2_IPC"; ++ cntl = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)"; ++ caps = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888"; ++ bpp = <16>; ++ }; ++ ++ panel@1 { ++ compatible = "panel"; ++ mode = "XVGA"; ++ refresh = <60>; ++ xres = <1024>; ++ yres = <768>; ++ pixclock = <15748>; ++ left_margin = <152>; ++ right_margin = <48>; ++ upper_margin = <23>; ++ lower_margin = <3>; ++ hsync_len = <104>; ++ vsync_len = <4>; ++ sync = <0>; ++ vmode = "FB_VMODE_NONINTERLACED"; ++ ++ tim2 = "TIM2_BCD", "TIM2_IPC"; ++ cntl = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)"; ++ caps = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888"; ++ bpp = <16>; ++ }; ++ }; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/exynos5440-ssdk5440.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/exynos5440-ssdk5440.dts +--- linux-3.10.30/arch/arm/boot/dts/exynos5440-ssdk5440.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/exynos5440-ssdk5440.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -30,4 +30,12 @@ + clock-frequency = <50000000>; + }; + }; ++ ++ pcie@290000 { ++ reset-gpio = <&pin_ctrl 5 0>; ++ }; ++ ++ pcie@2a0000 { ++ reset-gpio = <&pin_ctrl 22 0>; ++ }; + }; +diff -Nur linux-3.10.30/arch/arm/boot/dts/exynos5440.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/exynos5440.dtsi +--- linux-3.10.30/arch/arm/boot/dts/exynos5440.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/exynos5440.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -113,7 +113,7 @@ + clock-names = "spi", "spi_busclk0"; + }; + +- pinctrl { ++ pin_ctrl: pinctrl { + compatible = "samsung,exynos5440-pinctrl"; + reg = <0xE0000 0x1000>; + interrupts = <0 37 0>, <0 38 0>, <0 39 0>, <0 40 0>, +@@ -216,4 +216,44 @@ + clock-names = "rtc"; + status = "disabled"; + }; ++ ++ pcie@290000 { ++ compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; ++ reg = <0x290000 0x1000 ++ 0x270000 0x1000 ++ 0x271000 0x40>; ++ interrupts = <0 20 0>, <0 21 0>, <0 22 0>; ++ clocks = <&clock 28>, <&clock 27>; ++ clock-names = "pcie", "pcie_bus"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ ranges = <0x00000800 0 0x40000000 0x40000000 0 0x00001000 /* configuration space */ ++ 0x81000000 0 0 0x40001000 0 0x00010000 /* downstream I/O */ ++ 0x82000000 0 0x40011000 0x40011000 0 0x1ffef000>; /* non-prefetchable memory */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0x0 0 &gic 53>; ++ num-lanes = <4>; ++ }; ++ ++ pcie@2a0000 { ++ compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; ++ reg = <0x2a0000 0x1000 ++ 0x272000 0x1000 ++ 0x271040 0x40>; ++ interrupts = <0 23 0>, <0 24 0>, <0 25 0>; ++ clocks = <&clock 29>, <&clock 27>; ++ clock-names = "pcie", "pcie_bus"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ ranges = <0x00000800 0 0x60000000 0x60000000 0 0x00001000 /* configuration space */ ++ 0x81000000 0 0 0x60001000 0 0x00010000 /* downstream I/O */ ++ 0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; /* non-prefetchable memory */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0>; ++ interrupt-map = <0x0 0 &gic 56>; ++ num-lanes = <4>; ++ }; + }; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx23.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx23.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx23.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx23.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -20,6 +20,7 @@ + gpio2 = &gpio2; + serial0 = &auart0; + serial1 = &auart1; ++ usbphy0 = &usbphy0; + }; + + cpus { +@@ -360,7 +361,8 @@ + compatible = "fsl,imx23-lcdif"; + reg = <0x80030000 2000>; + interrupts = <46 45>; +- clocks = <&clks 38>; ++ clocks = <&clks 38>, <&clks 38>; ++ clock-names = "pix", "axi"; + status = "disabled"; + }; + +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx28.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx28.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx28.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx28.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -29,6 +29,8 @@ + serial4 = &auart4; + ethernet0 = &mac0; + ethernet1 = &mac1; ++ usbphy0 = &usbphy0; ++ usbphy1 = &usbphy1; + }; + + cpus { +@@ -727,7 +729,8 @@ + compatible = "fsl,imx28-lcdif"; + reg = <0x80030000 0x2000>; + interrupts = <38 86>; +- clocks = <&clks 55>; ++ clocks = <&clks 55>, <&clks 55>; ++ clock-names = "pix", "axi"; + dmas = <&dma_apbh 13>; + dma-names = "rx"; + status = "disabled"; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx53.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx53.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx53.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx53.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -782,5 +782,10 @@ + status = "disabled"; + }; + }; ++ ++ ocram: sram@f8000000 { ++ compatible = "mmio-sram"; ++ reg = <0xf8000000 0x20000>; ++ }; + }; + }; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl-cubox-i.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-cubox-i.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6dl-cubox-i.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-cubox-i.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,12 @@ ++/* ++ * Copyright (C) 2014 Russell King ++ */ ++/dts-v1/; ++ ++#include "imx6dl.dtsi" ++#include "imx6qdl-cubox-i.dtsi" ++ ++/ { ++ model = "SolidRun Cubox-i Solo/DualLite"; ++ compatible = "solidrun,cubox-i/dl", "fsl,imx6dl"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl-hummingboard.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-hummingboard.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6dl-hummingboard.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-hummingboard.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,258 @@ ++/* ++ * Copyright (C) 2013 Russell King ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License version 2. ++ */ ++/dts-v1/; ++ ++#include "imx6dl.dtsi" ++#include "imx6qdl-microsom.dtsi" ++#include "imx6qdl-microsom-ar8035.dtsi" ++ ++/ { ++ model = "SolidRun HummingBoard DL/Solo"; ++ compatible = "solidrun,hummingboard", "fsl,imx6dl"; ++ ++ aliases { ++ mxcfb0 = &mxcfb1; ++ }; ++ ++ ir_recv: ir-receiver { ++ compatible = "gpio-ir-receiver"; ++ gpios = <&gpio1 2 1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_gpio1_2>; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_3p3v: 3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_usbh1_vbus: usb-h1-vbus { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio1 0 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_usbh1_vbus>; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ }; ++ ++ reg_usbotg_vbus: usb-otg-vbus { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio3 22 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_usbotg_vbus>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ }; ++ }; ++ ++ codec: spdif-transmitter { ++ compatible = "linux,spdif-dit"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_spdif>; ++ }; ++ ++ imx-drm { ++ compatible = "fsl,imx-drm"; ++ crtcs = <&ipu1 0>, <&ipu1 1>; ++ connectors = <&hdmi>; ++ }; ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif"; ++ model = "imx-spdif"; ++ /* IMX6 doesn't implement this yet */ ++ spdif-controller = <&spdif>; ++ spdif-out; ++ }; ++ ++ sound-hdmi { ++ compatible = "fsl,imx6q-audio-hdmi", ++ "fsl,imx-audio-hdmi"; ++ model = "imx-audio-hdmi"; ++ hdmi-controller = <&hdmi_audio>; ++ }; ++ ++ mxcfb1: mxc_sdc_fb@0 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "hdmi"; ++ interface_pix_fmt = "RGB24"; ++ mode_str ="1280x720@60"; ++ default_bpp = <32>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_cap_0 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <0>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_cap_1 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++}; ++ ++&flexcan1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_flexcan1>; ++ status = "okay"; ++}; ++ ++&hdmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_hdmi>; ++ ddc = <&i2c2>; ++ status = "okay"; ++ crtcs = <&ipu1 0>; ++}; ++ ++&hdmi_audio { ++ status = "okay"; ++}; ++ ++&hdmi_cec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_hdmi>; ++ status = "okay"; ++}; ++ ++&hdmi_core { ++ ipu_id = <1>; ++ disp_id = <0>; ++ status = "okay"; ++}; ++ ++&hdmi_video { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hdmi_hdcp_1>; ++ fsl,phy_reg_vlev = <0x0294>; ++ fsl,phy_reg_cksymtx = <0x800d>; ++ fsl,hdcp; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1_1>; ++ ++ /* ++ * Not fitted on Carrier-1 board... yet ++ status = "okay"; ++ ++ rtc: pcf8523@68 { ++ compatible = "nxp,pcf8523"; ++ reg = <0x68>; ++ }; ++ */ ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2_2>; ++ status = "okay"; ++}; ++ ++&iomuxc { ++ hummingboard { ++ pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_CLK__FLEXCAN1_RX 0x80000000 ++ MX6QDL_PAD_SD3_CMD__FLEXCAN1_TX 0x80000000 ++ >; ++ }; ++ ++ pinctrl_hummingboard_gpio1_2: hummingboard-gpio1_2 { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 ++ >; ++ }; ++ ++ pinctrl_hummingboard_hdmi: hummingboard-hdmi { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ ++ pinctrl_hummingboard_spdif: hummingboard-spdif { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard_usbh1_vbus: hummingboard-usbh1-vbus { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard_usbotg_vbus: hummingboard-usbotg-vbus { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard_usdhc2_aux: hummingboard-usdhc2-aux { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 ++ >; ++ }; ++ ++ pinctrl_hummingboard_usdhc2: hummingboard-usdhc2 { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 ++ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 ++ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 ++ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 ++ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 ++ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 ++ >; ++ }; ++ }; ++}; ++ ++&spdif { ++ status = "okay"; ++}; ++ ++&usbh1 { ++ vbus-supply = <®_usbh1_vbus>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usbotg_vbus>; ++ status = "okay"; ++}; ++ ++&usdhc2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = < ++ &pinctrl_hummingboard_usdhc2_aux ++ &pinctrl_hummingboard_usdhc2 ++ >; ++ vmmc-supply = <®_3p3v>; ++ cd-gpios = <&gpio1 4 0>; ++ status = "okay"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl-pinfunc.h linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-pinfunc.h +--- linux-3.10.30/arch/arm/boot/dts/imx6dl-pinfunc.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-pinfunc.h 2014-03-08 20:32:53.000000000 +0100 +@@ -14,1072 +14,1076 @@ + * The pin function ID is a tuple of + * + */ +-#define MX6DL_PAD_CSI0_DAT10__IPU1_CSI0_DATA10 0x04c 0x360 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT10__AUD3_RXC 0x04c 0x360 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT10__ECSPI2_MISO 0x04c 0x360 0x7f8 0x2 0x0 +-#define MX6DL_PAD_CSI0_DAT10__UART1_TX_DATA 0x04c 0x360 0x000 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT10__UART1_RX_DATA 0x04c 0x360 0x8fc 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT10__GPIO5_IO28 0x04c 0x360 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT10__ARM_TRACE07 0x04c 0x360 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT11__IPU1_CSI0_DATA11 0x050 0x364 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT11__AUD3_RXFS 0x050 0x364 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT11__ECSPI2_SS0 0x050 0x364 0x800 0x2 0x0 +-#define MX6DL_PAD_CSI0_DAT11__UART1_RX_DATA 0x050 0x364 0x8fc 0x3 0x1 +-#define MX6DL_PAD_CSI0_DAT11__UART1_TX_DATA 0x050 0x364 0x000 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT11__GPIO5_IO29 0x050 0x364 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT11__ARM_TRACE08 0x050 0x364 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x054 0x368 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT12__EIM_DATA08 0x054 0x368 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT12__UART4_TX_DATA 0x054 0x368 0x000 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT12__UART4_RX_DATA 0x054 0x368 0x914 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT12__GPIO5_IO30 0x054 0x368 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT12__ARM_TRACE09 0x054 0x368 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x058 0x36c 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT13__EIM_DATA09 0x058 0x36c 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT13__UART4_RX_DATA 0x058 0x36c 0x914 0x3 0x1 +-#define MX6DL_PAD_CSI0_DAT13__UART4_TX_DATA 0x058 0x36c 0x000 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT13__GPIO5_IO31 0x058 0x36c 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT13__ARM_TRACE10 0x058 0x36c 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x05c 0x370 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT14__EIM_DATA10 0x05c 0x370 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT14__UART5_TX_DATA 0x05c 0x370 0x000 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT14__UART5_RX_DATA 0x05c 0x370 0x91c 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT14__GPIO6_IO00 0x05c 0x370 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT14__ARM_TRACE11 0x05c 0x370 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x060 0x374 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT15__EIM_DATA11 0x060 0x374 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT15__UART5_RX_DATA 0x060 0x374 0x91c 0x3 0x1 +-#define MX6DL_PAD_CSI0_DAT15__UART5_TX_DATA 0x060 0x374 0x000 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT15__GPIO6_IO01 0x060 0x374 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT15__ARM_TRACE12 0x060 0x374 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x064 0x378 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT16__EIM_DATA12 0x064 0x378 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT16__UART4_RTS_B 0x064 0x378 0x910 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT16__UART4_CTS_B 0x064 0x378 0x000 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT16__GPIO6_IO02 0x064 0x378 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT16__ARM_TRACE13 0x064 0x378 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x068 0x37c 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT17__EIM_DATA13 0x068 0x37c 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT17__UART4_CTS_B 0x068 0x37c 0x000 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT17__UART4_RTS_B 0x068 0x37c 0x910 0x3 0x1 +-#define MX6DL_PAD_CSI0_DAT17__GPIO6_IO03 0x068 0x37c 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT17__ARM_TRACE14 0x068 0x37c 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x06c 0x380 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT18__EIM_DATA14 0x06c 0x380 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT18__UART5_RTS_B 0x06c 0x380 0x918 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT18__UART5_CTS_B 0x06c 0x380 0x000 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT18__GPIO6_IO04 0x06c 0x380 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT18__ARM_TRACE15 0x06c 0x380 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x070 0x384 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT19__EIM_DATA15 0x070 0x384 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT19__UART5_CTS_B 0x070 0x384 0x000 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT19__UART5_RTS_B 0x070 0x384 0x918 0x3 0x1 +-#define MX6DL_PAD_CSI0_DAT19__GPIO6_IO05 0x070 0x384 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT4__IPU1_CSI0_DATA04 0x074 0x388 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT4__EIM_DATA02 0x074 0x388 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT4__ECSPI1_SCLK 0x074 0x388 0x7d8 0x2 0x0 +-#define MX6DL_PAD_CSI0_DAT4__KEY_COL5 0x074 0x388 0x8c0 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT4__AUD3_TXC 0x074 0x388 0x000 0x4 0x0 +-#define MX6DL_PAD_CSI0_DAT4__GPIO5_IO22 0x074 0x388 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT4__ARM_TRACE01 0x074 0x388 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT5__IPU1_CSI0_DATA05 0x078 0x38c 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT5__EIM_DATA03 0x078 0x38c 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT5__ECSPI1_MOSI 0x078 0x38c 0x7e0 0x2 0x0 +-#define MX6DL_PAD_CSI0_DAT5__KEY_ROW5 0x078 0x38c 0x8cc 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT5__AUD3_TXD 0x078 0x38c 0x000 0x4 0x0 +-#define MX6DL_PAD_CSI0_DAT5__GPIO5_IO23 0x078 0x38c 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT5__ARM_TRACE02 0x078 0x38c 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT6__IPU1_CSI0_DATA06 0x07c 0x390 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT6__EIM_DATA04 0x07c 0x390 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT6__ECSPI1_MISO 0x07c 0x390 0x7dc 0x2 0x0 +-#define MX6DL_PAD_CSI0_DAT6__KEY_COL6 0x07c 0x390 0x8c4 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT6__AUD3_TXFS 0x07c 0x390 0x000 0x4 0x0 +-#define MX6DL_PAD_CSI0_DAT6__GPIO5_IO24 0x07c 0x390 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT6__ARM_TRACE03 0x07c 0x390 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT7__IPU1_CSI0_DATA07 0x080 0x394 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT7__EIM_DATA05 0x080 0x394 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT7__ECSPI1_SS0 0x080 0x394 0x7e4 0x2 0x0 +-#define MX6DL_PAD_CSI0_DAT7__KEY_ROW6 0x080 0x394 0x8d0 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT7__AUD3_RXD 0x080 0x394 0x000 0x4 0x0 +-#define MX6DL_PAD_CSI0_DAT7__GPIO5_IO25 0x080 0x394 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT7__ARM_TRACE04 0x080 0x394 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT8__IPU1_CSI0_DATA08 0x084 0x398 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT8__EIM_DATA06 0x084 0x398 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT8__ECSPI2_SCLK 0x084 0x398 0x7f4 0x2 0x0 +-#define MX6DL_PAD_CSI0_DAT8__KEY_COL7 0x084 0x398 0x8c8 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT8__I2C1_SDA 0x084 0x398 0x86c 0x4 0x0 +-#define MX6DL_PAD_CSI0_DAT8__GPIO5_IO26 0x084 0x398 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT8__ARM_TRACE05 0x084 0x398 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DAT9__IPU1_CSI0_DATA09 0x088 0x39c 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DAT9__EIM_DATA07 0x088 0x39c 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DAT9__ECSPI2_MOSI 0x088 0x39c 0x7fc 0x2 0x0 +-#define MX6DL_PAD_CSI0_DAT9__KEY_ROW7 0x088 0x39c 0x8d4 0x3 0x0 +-#define MX6DL_PAD_CSI0_DAT9__I2C1_SCL 0x088 0x39c 0x868 0x4 0x0 +-#define MX6DL_PAD_CSI0_DAT9__GPIO5_IO27 0x088 0x39c 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DAT9__ARM_TRACE06 0x088 0x39c 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN 0x08c 0x3a0 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_DATA_EN__EIM_DATA00 0x08c 0x3a0 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x08c 0x3a0 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_DATA_EN__ARM_TRACE_CLK 0x08c 0x3a0 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x090 0x3a4 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_MCLK__CCM_CLKO1 0x090 0x3a4 0x000 0x3 0x0 +-#define MX6DL_PAD_CSI0_MCLK__GPIO5_IO19 0x090 0x3a4 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_MCLK__ARM_TRACE_CTL 0x090 0x3a4 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x094 0x3a8 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_PIXCLK__GPIO5_IO18 0x094 0x3a8 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_PIXCLK__ARM_EVENTO 0x094 0x3a8 0x000 0x7 0x0 +-#define MX6DL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x098 0x3ac 0x000 0x0 0x0 +-#define MX6DL_PAD_CSI0_VSYNC__EIM_DATA01 0x098 0x3ac 0x000 0x1 0x0 +-#define MX6DL_PAD_CSI0_VSYNC__GPIO5_IO21 0x098 0x3ac 0x000 0x5 0x0 +-#define MX6DL_PAD_CSI0_VSYNC__ARM_TRACE00 0x098 0x3ac 0x000 0x7 0x0 +-#define MX6DL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x09c 0x3b0 0x000 0x0 0x0 +-#define MX6DL_PAD_DI0_DISP_CLK__LCD_CLK 0x09c 0x3b0 0x000 0x1 0x0 +-#define MX6DL_PAD_DI0_DISP_CLK__GPIO4_IO16 0x09c 0x3b0 0x000 0x5 0x0 +-#define MX6DL_PAD_DI0_DISP_CLK__LCD_WR_RWN 0x09c 0x3b0 0x000 0x8 0x0 +-#define MX6DL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x0a0 0x3b4 0x000 0x0 0x0 +-#define MX6DL_PAD_DI0_PIN15__LCD_ENABLE 0x0a0 0x3b4 0x000 0x1 0x0 +-#define MX6DL_PAD_DI0_PIN15__AUD6_TXC 0x0a0 0x3b4 0x000 0x2 0x0 +-#define MX6DL_PAD_DI0_PIN15__GPIO4_IO17 0x0a0 0x3b4 0x000 0x5 0x0 +-#define MX6DL_PAD_DI0_PIN15__LCD_RD_E 0x0a0 0x3b4 0x000 0x8 0x0 +-#define MX6DL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x0a4 0x3b8 0x000 0x0 0x0 +-#define MX6DL_PAD_DI0_PIN2__LCD_HSYNC 0x0a4 0x3b8 0x8d8 0x1 0x0 +-#define MX6DL_PAD_DI0_PIN2__AUD6_TXD 0x0a4 0x3b8 0x000 0x2 0x0 +-#define MX6DL_PAD_DI0_PIN2__GPIO4_IO18 0x0a4 0x3b8 0x000 0x5 0x0 +-#define MX6DL_PAD_DI0_PIN2__LCD_RS 0x0a4 0x3b8 0x000 0x8 0x0 +-#define MX6DL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x0a8 0x3bc 0x000 0x0 0x0 +-#define MX6DL_PAD_DI0_PIN3__LCD_VSYNC 0x0a8 0x3bc 0x000 0x1 0x0 +-#define MX6DL_PAD_DI0_PIN3__AUD6_TXFS 0x0a8 0x3bc 0x000 0x2 0x0 +-#define MX6DL_PAD_DI0_PIN3__GPIO4_IO19 0x0a8 0x3bc 0x000 0x5 0x0 +-#define MX6DL_PAD_DI0_PIN3__LCD_CS 0x0a8 0x3bc 0x000 0x8 0x0 +-#define MX6DL_PAD_DI0_PIN4__IPU1_DI0_PIN04 0x0ac 0x3c0 0x000 0x0 0x0 +-#define MX6DL_PAD_DI0_PIN4__LCD_BUSY 0x0ac 0x3c0 0x8d8 0x1 0x1 +-#define MX6DL_PAD_DI0_PIN4__AUD6_RXD 0x0ac 0x3c0 0x000 0x2 0x0 +-#define MX6DL_PAD_DI0_PIN4__SD1_WP 0x0ac 0x3c0 0x92c 0x3 0x0 +-#define MX6DL_PAD_DI0_PIN4__GPIO4_IO20 0x0ac 0x3c0 0x000 0x5 0x0 +-#define MX6DL_PAD_DI0_PIN4__LCD_RESET 0x0ac 0x3c0 0x000 0x8 0x0 +-#define MX6DL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x0b0 0x3c4 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT0__LCD_DATA00 0x0b0 0x3c4 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x0b0 0x3c4 0x000 0x2 0x0 +-#define MX6DL_PAD_DISP0_DAT0__GPIO4_IO21 0x0b0 0x3c4 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x0b4 0x3c8 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT1__LCD_DATA01 0x0b4 0x3c8 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x0b4 0x3c8 0x000 0x2 0x0 +-#define MX6DL_PAD_DISP0_DAT1__GPIO4_IO22 0x0b4 0x3c8 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x0b8 0x3cc 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT10__LCD_DATA10 0x0b8 0x3cc 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT10__GPIO4_IO31 0x0b8 0x3cc 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x0bc 0x3d0 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT11__LCD_DATA11 0x0bc 0x3d0 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT11__GPIO5_IO05 0x0bc 0x3d0 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x0c0 0x3d4 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT12__LCD_DATA12 0x0c0 0x3d4 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT12__GPIO5_IO06 0x0c0 0x3d4 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x0c4 0x3d8 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT13__LCD_DATA13 0x0c4 0x3d8 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT13__AUD5_RXFS 0x0c4 0x3d8 0x7bc 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT13__GPIO5_IO07 0x0c4 0x3d8 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x0c8 0x3dc 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT14__LCD_DATA14 0x0c8 0x3dc 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT14__AUD5_RXC 0x0c8 0x3dc 0x7b8 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT14__GPIO5_IO08 0x0c8 0x3dc 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x0cc 0x3e0 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT15__LCD_DATA15 0x0cc 0x3e0 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT15__ECSPI1_SS1 0x0cc 0x3e0 0x7e8 0x2 0x0 +-#define MX6DL_PAD_DISP0_DAT15__ECSPI2_SS1 0x0cc 0x3e0 0x804 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT15__GPIO5_IO09 0x0cc 0x3e0 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x0d0 0x3e4 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT16__LCD_DATA16 0x0d0 0x3e4 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT16__ECSPI2_MOSI 0x0d0 0x3e4 0x7fc 0x2 0x1 +-#define MX6DL_PAD_DISP0_DAT16__AUD5_TXC 0x0d0 0x3e4 0x7c0 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT16__SDMA_EXT_EVENT0 0x0d0 0x3e4 0x8e8 0x4 0x0 +-#define MX6DL_PAD_DISP0_DAT16__GPIO5_IO10 0x0d0 0x3e4 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x0d4 0x3e8 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT17__LCD_DATA17 0x0d4 0x3e8 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT17__ECSPI2_MISO 0x0d4 0x3e8 0x7f8 0x2 0x1 +-#define MX6DL_PAD_DISP0_DAT17__AUD5_TXD 0x0d4 0x3e8 0x7b4 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT17__SDMA_EXT_EVENT1 0x0d4 0x3e8 0x8ec 0x4 0x0 +-#define MX6DL_PAD_DISP0_DAT17__GPIO5_IO11 0x0d4 0x3e8 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x0d8 0x3ec 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT18__LCD_DATA18 0x0d8 0x3ec 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT18__ECSPI2_SS0 0x0d8 0x3ec 0x800 0x2 0x1 +-#define MX6DL_PAD_DISP0_DAT18__AUD5_TXFS 0x0d8 0x3ec 0x7c4 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT18__AUD4_RXFS 0x0d8 0x3ec 0x7a4 0x4 0x0 +-#define MX6DL_PAD_DISP0_DAT18__GPIO5_IO12 0x0d8 0x3ec 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT18__EIM_CS2_B 0x0d8 0x3ec 0x000 0x7 0x0 +-#define MX6DL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x0dc 0x3f0 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT19__LCD_DATA19 0x0dc 0x3f0 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT19__ECSPI2_SCLK 0x0dc 0x3f0 0x7f4 0x2 0x1 +-#define MX6DL_PAD_DISP0_DAT19__AUD5_RXD 0x0dc 0x3f0 0x7b0 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT19__AUD4_RXC 0x0dc 0x3f0 0x7a0 0x4 0x0 +-#define MX6DL_PAD_DISP0_DAT19__GPIO5_IO13 0x0dc 0x3f0 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT19__EIM_CS3_B 0x0dc 0x3f0 0x000 0x7 0x0 +-#define MX6DL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x0e0 0x3f4 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT2__LCD_DATA02 0x0e0 0x3f4 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT2__ECSPI3_MISO 0x0e0 0x3f4 0x000 0x2 0x0 +-#define MX6DL_PAD_DISP0_DAT2__GPIO4_IO23 0x0e0 0x3f4 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x0e4 0x3f8 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT20__LCD_DATA20 0x0e4 0x3f8 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT20__ECSPI1_SCLK 0x0e4 0x3f8 0x7d8 0x2 0x1 +-#define MX6DL_PAD_DISP0_DAT20__AUD4_TXC 0x0e4 0x3f8 0x7a8 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT20__GPIO5_IO14 0x0e4 0x3f8 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x0e8 0x3fc 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT21__LCD_DATA21 0x0e8 0x3fc 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT21__ECSPI1_MOSI 0x0e8 0x3fc 0x7e0 0x2 0x1 +-#define MX6DL_PAD_DISP0_DAT21__AUD4_TXD 0x0e8 0x3fc 0x79c 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT21__GPIO5_IO15 0x0e8 0x3fc 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x0ec 0x400 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT22__LCD_DATA22 0x0ec 0x400 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT22__ECSPI1_MISO 0x0ec 0x400 0x7dc 0x2 0x1 +-#define MX6DL_PAD_DISP0_DAT22__AUD4_TXFS 0x0ec 0x400 0x7ac 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT22__GPIO5_IO16 0x0ec 0x400 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x0f0 0x404 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT23__LCD_DATA23 0x0f0 0x404 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT23__ECSPI1_SS0 0x0f0 0x404 0x7e4 0x2 0x1 +-#define MX6DL_PAD_DISP0_DAT23__AUD4_RXD 0x0f0 0x404 0x798 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT23__GPIO5_IO17 0x0f0 0x404 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x0f4 0x408 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT3__LCD_DATA03 0x0f4 0x408 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT3__ECSPI3_SS0 0x0f4 0x408 0x000 0x2 0x0 +-#define MX6DL_PAD_DISP0_DAT3__GPIO4_IO24 0x0f4 0x408 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x0f8 0x40c 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT4__LCD_DATA04 0x0f8 0x40c 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT4__ECSPI3_SS1 0x0f8 0x40c 0x000 0x2 0x0 +-#define MX6DL_PAD_DISP0_DAT4__GPIO4_IO25 0x0f8 0x40c 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x0fc 0x410 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT5__LCD_DATA05 0x0fc 0x410 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT5__ECSPI3_SS2 0x0fc 0x410 0x000 0x2 0x0 +-#define MX6DL_PAD_DISP0_DAT5__AUD6_RXFS 0x0fc 0x410 0x000 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT5__GPIO4_IO26 0x0fc 0x410 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x100 0x414 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT6__LCD_DATA06 0x100 0x414 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT6__ECSPI3_SS3 0x100 0x414 0x000 0x2 0x0 +-#define MX6DL_PAD_DISP0_DAT6__AUD6_RXC 0x100 0x414 0x000 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT6__GPIO4_IO27 0x100 0x414 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x104 0x418 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT7__LCD_DATA07 0x104 0x418 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT7__ECSPI3_RDY 0x104 0x418 0x000 0x2 0x0 +-#define MX6DL_PAD_DISP0_DAT7__GPIO4_IO28 0x104 0x418 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x108 0x41c 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT8__LCD_DATA08 0x108 0x41c 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT8__PWM1_OUT 0x108 0x41c 0x000 0x2 0x0 +-#define MX6DL_PAD_DISP0_DAT8__WDOG1_B 0x108 0x41c 0x000 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT8__GPIO4_IO29 0x108 0x41c 0x000 0x5 0x0 +-#define MX6DL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10c 0x420 0x000 0x0 0x0 +-#define MX6DL_PAD_DISP0_DAT9__LCD_DATA09 0x10c 0x420 0x000 0x1 0x0 +-#define MX6DL_PAD_DISP0_DAT9__PWM2_OUT 0x10c 0x420 0x000 0x2 0x0 +-#define MX6DL_PAD_DISP0_DAT9__WDOG2_B 0x10c 0x420 0x000 0x3 0x0 +-#define MX6DL_PAD_DISP0_DAT9__GPIO4_IO30 0x10c 0x420 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_A16__EIM_ADDR16 0x110 0x4e0 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_A16__IPU1_DI1_DISP_CLK 0x110 0x4e0 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_A16__IPU1_CSI1_PIXCLK 0x110 0x4e0 0x8b8 0x2 0x0 +-#define MX6DL_PAD_EIM_A16__GPIO2_IO22 0x110 0x4e0 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_A16__SRC_BOOT_CFG16 0x110 0x4e0 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_A16__EPDC_DATA00 0x110 0x4e0 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_A17__EIM_ADDR17 0x114 0x4e4 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_A17__IPU1_DISP1_DATA12 0x114 0x4e4 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_A17__IPU1_CSI1_DATA12 0x114 0x4e4 0x890 0x2 0x0 +-#define MX6DL_PAD_EIM_A17__GPIO2_IO21 0x114 0x4e4 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_A17__SRC_BOOT_CFG17 0x114 0x4e4 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_A17__EPDC_PWR_STAT 0x114 0x4e4 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_A18__EIM_ADDR18 0x118 0x4e8 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_A18__IPU1_DISP1_DATA13 0x118 0x4e8 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_A18__IPU1_CSI1_DATA13 0x118 0x4e8 0x894 0x2 0x0 +-#define MX6DL_PAD_EIM_A18__GPIO2_IO20 0x118 0x4e8 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_A18__SRC_BOOT_CFG18 0x118 0x4e8 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_A18__EPDC_PWR_CTRL0 0x118 0x4e8 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_A19__EIM_ADDR19 0x11c 0x4ec 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_A19__IPU1_DISP1_DATA14 0x11c 0x4ec 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_A19__IPU1_CSI1_DATA14 0x11c 0x4ec 0x898 0x2 0x0 +-#define MX6DL_PAD_EIM_A19__GPIO2_IO19 0x11c 0x4ec 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_A19__SRC_BOOT_CFG19 0x11c 0x4ec 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_A19__EPDC_PWR_CTRL1 0x11c 0x4ec 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_A20__EIM_ADDR20 0x120 0x4f0 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_A20__IPU1_DISP1_DATA15 0x120 0x4f0 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_A20__IPU1_CSI1_DATA15 0x120 0x4f0 0x89c 0x2 0x0 +-#define MX6DL_PAD_EIM_A20__GPIO2_IO18 0x120 0x4f0 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_A20__SRC_BOOT_CFG20 0x120 0x4f0 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_A20__EPDC_PWR_CTRL2 0x120 0x4f0 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_A21__EIM_ADDR21 0x124 0x4f4 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_A21__IPU1_DISP1_DATA16 0x124 0x4f4 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_A21__IPU1_CSI1_DATA16 0x124 0x4f4 0x8a0 0x2 0x0 +-#define MX6DL_PAD_EIM_A21__GPIO2_IO17 0x124 0x4f4 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_A21__SRC_BOOT_CFG21 0x124 0x4f4 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_A21__EPDC_GDCLK 0x124 0x4f4 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_A22__EIM_ADDR22 0x128 0x4f8 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_A22__IPU1_DISP1_DATA17 0x128 0x4f8 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_A22__IPU1_CSI1_DATA17 0x128 0x4f8 0x8a4 0x2 0x0 +-#define MX6DL_PAD_EIM_A22__GPIO2_IO16 0x128 0x4f8 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_A22__SRC_BOOT_CFG22 0x128 0x4f8 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_A22__EPDC_GDSP 0x128 0x4f8 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_A23__EIM_ADDR23 0x12c 0x4fc 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_A23__IPU1_DISP1_DATA18 0x12c 0x4fc 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_A23__IPU1_CSI1_DATA18 0x12c 0x4fc 0x8a8 0x2 0x0 +-#define MX6DL_PAD_EIM_A23__IPU1_SISG3 0x12c 0x4fc 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_A23__GPIO6_IO06 0x12c 0x4fc 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_A23__SRC_BOOT_CFG23 0x12c 0x4fc 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_A23__EPDC_GDOE 0x12c 0x4fc 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_A24__EIM_ADDR24 0x130 0x500 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_A24__IPU1_DISP1_DATA19 0x130 0x500 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_A24__IPU1_CSI1_DATA19 0x130 0x500 0x8ac 0x2 0x0 +-#define MX6DL_PAD_EIM_A24__IPU1_SISG2 0x130 0x500 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_A24__GPIO5_IO04 0x130 0x500 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_A24__SRC_BOOT_CFG24 0x130 0x500 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_A24__EPDC_GDRL 0x130 0x500 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_A25__EIM_ADDR25 0x134 0x504 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_A25__ECSPI4_SS1 0x134 0x504 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_A25__ECSPI2_RDY 0x134 0x504 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_A25__IPU1_DI1_PIN12 0x134 0x504 0x000 0x3 0x0 +-#define MX6DL_PAD_EIM_A25__IPU1_DI0_D1_CS 0x134 0x504 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_A25__GPIO5_IO02 0x134 0x504 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x134 0x504 0x85c 0x6 0x0 +-#define MX6DL_PAD_EIM_A25__EPDC_DATA15 0x134 0x504 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_A25__EIM_ACLK_FREERUN 0x134 0x504 0x000 0x9 0x0 +-#define MX6DL_PAD_EIM_BCLK__EIM_BCLK 0x138 0x508 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_BCLK__IPU1_DI1_PIN16 0x138 0x508 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_BCLK__GPIO6_IO31 0x138 0x508 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_BCLK__EPDC_SDCE9 0x138 0x508 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_CS0__EIM_CS0_B 0x13c 0x50c 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_CS0__IPU1_DI1_PIN05 0x13c 0x50c 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_CS0__ECSPI2_SCLK 0x13c 0x50c 0x7f4 0x2 0x2 +-#define MX6DL_PAD_EIM_CS0__GPIO2_IO23 0x13c 0x50c 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_CS0__EPDC_DATA06 0x13c 0x50c 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_CS1__EIM_CS1_B 0x140 0x510 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_CS1__IPU1_DI1_PIN06 0x140 0x510 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_CS1__ECSPI2_MOSI 0x140 0x510 0x7fc 0x2 0x2 +-#define MX6DL_PAD_EIM_CS1__GPIO2_IO24 0x140 0x510 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_CS1__EPDC_DATA08 0x140 0x510 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D16__EIM_DATA16 0x144 0x514 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D16__ECSPI1_SCLK 0x144 0x514 0x7d8 0x1 0x2 +-#define MX6DL_PAD_EIM_D16__IPU1_DI0_PIN05 0x144 0x514 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D16__IPU1_CSI1_DATA18 0x144 0x514 0x8a8 0x3 0x1 +-#define MX6DL_PAD_EIM_D16__HDMI_TX_DDC_SDA 0x144 0x514 0x864 0x4 0x0 +-#define MX6DL_PAD_EIM_D16__GPIO3_IO16 0x144 0x514 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D16__I2C2_SDA 0x144 0x514 0x874 0x6 0x0 +-#define MX6DL_PAD_EIM_D16__EPDC_DATA10 0x144 0x514 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D17__EIM_DATA17 0x148 0x518 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D17__ECSPI1_MISO 0x148 0x518 0x7dc 0x1 0x2 +-#define MX6DL_PAD_EIM_D17__IPU1_DI0_PIN06 0x148 0x518 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D17__IPU1_CSI1_PIXCLK 0x148 0x518 0x8b8 0x3 0x1 +-#define MX6DL_PAD_EIM_D17__DCIC1_OUT 0x148 0x518 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D17__GPIO3_IO17 0x148 0x518 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D17__I2C3_SCL 0x148 0x518 0x878 0x6 0x0 +-#define MX6DL_PAD_EIM_D17__EPDC_VCOM0 0x148 0x518 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D18__EIM_DATA18 0x14c 0x51c 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D18__ECSPI1_MOSI 0x14c 0x51c 0x7e0 0x1 0x2 +-#define MX6DL_PAD_EIM_D18__IPU1_DI0_PIN07 0x14c 0x51c 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D18__IPU1_CSI1_DATA17 0x14c 0x51c 0x8a4 0x3 0x1 +-#define MX6DL_PAD_EIM_D18__IPU1_DI1_D0_CS 0x14c 0x51c 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D18__GPIO3_IO18 0x14c 0x51c 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D18__I2C3_SDA 0x14c 0x51c 0x87c 0x6 0x0 +-#define MX6DL_PAD_EIM_D18__EPDC_VCOM1 0x14c 0x51c 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D19__EIM_DATA19 0x150 0x520 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D19__ECSPI1_SS1 0x150 0x520 0x7e8 0x1 0x1 +-#define MX6DL_PAD_EIM_D19__IPU1_DI0_PIN08 0x150 0x520 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D19__IPU1_CSI1_DATA16 0x150 0x520 0x8a0 0x3 0x1 +-#define MX6DL_PAD_EIM_D19__UART1_CTS_B 0x150 0x520 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D19__UART1_RTS_B 0x150 0x520 0x8f8 0x4 0x0 +-#define MX6DL_PAD_EIM_D19__GPIO3_IO19 0x150 0x520 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D19__EPIT1_OUT 0x150 0x520 0x000 0x6 0x0 +-#define MX6DL_PAD_EIM_D19__EPDC_DATA12 0x150 0x520 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D20__EIM_DATA20 0x154 0x524 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D20__ECSPI4_SS0 0x154 0x524 0x808 0x1 0x0 +-#define MX6DL_PAD_EIM_D20__IPU1_DI0_PIN16 0x154 0x524 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D20__IPU1_CSI1_DATA15 0x154 0x524 0x89c 0x3 0x1 +-#define MX6DL_PAD_EIM_D20__UART1_RTS_B 0x154 0x524 0x8f8 0x4 0x1 +-#define MX6DL_PAD_EIM_D20__UART1_CTS_B 0x154 0x524 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D20__GPIO3_IO20 0x154 0x524 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D20__EPIT2_OUT 0x154 0x524 0x000 0x6 0x0 +-#define MX6DL_PAD_EIM_D21__EIM_DATA21 0x158 0x528 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D21__ECSPI4_SCLK 0x158 0x528 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_D21__IPU1_DI0_PIN17 0x158 0x528 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D21__IPU1_CSI1_DATA11 0x158 0x528 0x88c 0x3 0x0 +-#define MX6DL_PAD_EIM_D21__USB_OTG_OC 0x158 0x528 0x920 0x4 0x0 +-#define MX6DL_PAD_EIM_D21__GPIO3_IO21 0x158 0x528 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D21__I2C1_SCL 0x158 0x528 0x868 0x6 0x1 +-#define MX6DL_PAD_EIM_D21__SPDIF_IN 0x158 0x528 0x8f0 0x7 0x0 +-#define MX6DL_PAD_EIM_D22__EIM_DATA22 0x15c 0x52c 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D22__ECSPI4_MISO 0x15c 0x52c 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_D22__IPU1_DI0_PIN01 0x15c 0x52c 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D22__IPU1_CSI1_DATA10 0x15c 0x52c 0x888 0x3 0x0 +-#define MX6DL_PAD_EIM_D22__USB_OTG_PWR 0x15c 0x52c 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D22__GPIO3_IO22 0x15c 0x52c 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D22__SPDIF_OUT 0x15c 0x52c 0x000 0x6 0x0 +-#define MX6DL_PAD_EIM_D22__EPDC_SDCE6 0x15c 0x52c 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D23__EIM_DATA23 0x160 0x530 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D23__IPU1_DI0_D0_CS 0x160 0x530 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_D23__UART3_CTS_B 0x160 0x530 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D23__UART3_RTS_B 0x160 0x530 0x908 0x2 0x0 +-#define MX6DL_PAD_EIM_D23__UART1_DCD_B 0x160 0x530 0x000 0x3 0x0 +-#define MX6DL_PAD_EIM_D23__IPU1_CSI1_DATA_EN 0x160 0x530 0x8b0 0x4 0x0 +-#define MX6DL_PAD_EIM_D23__GPIO3_IO23 0x160 0x530 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D23__IPU1_DI1_PIN02 0x160 0x530 0x000 0x6 0x0 +-#define MX6DL_PAD_EIM_D23__IPU1_DI1_PIN14 0x160 0x530 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_D23__EPDC_DATA11 0x160 0x530 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D24__EIM_DATA24 0x164 0x534 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D24__ECSPI4_SS2 0x164 0x534 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_D24__UART3_TX_DATA 0x164 0x534 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D24__UART3_RX_DATA 0x164 0x534 0x90c 0x2 0x0 +-#define MX6DL_PAD_EIM_D24__ECSPI1_SS2 0x164 0x534 0x7ec 0x3 0x0 +-#define MX6DL_PAD_EIM_D24__ECSPI2_SS2 0x164 0x534 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D24__GPIO3_IO24 0x164 0x534 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D24__AUD5_RXFS 0x164 0x534 0x7bc 0x6 0x1 +-#define MX6DL_PAD_EIM_D24__UART1_DTR_B 0x164 0x534 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_D24__EPDC_SDCE7 0x164 0x534 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D25__EIM_DATA25 0x168 0x538 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D25__ECSPI4_SS3 0x168 0x538 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_D25__UART3_RX_DATA 0x168 0x538 0x90c 0x2 0x1 +-#define MX6DL_PAD_EIM_D25__UART3_TX_DATA 0x168 0x538 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D25__ECSPI1_SS3 0x168 0x538 0x7f0 0x3 0x0 +-#define MX6DL_PAD_EIM_D25__ECSPI2_SS3 0x168 0x538 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D25__GPIO3_IO25 0x168 0x538 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D25__AUD5_RXC 0x168 0x538 0x7b8 0x6 0x1 +-#define MX6DL_PAD_EIM_D25__UART1_DSR_B 0x168 0x538 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_D25__EPDC_SDCE8 0x168 0x538 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D26__EIM_DATA26 0x16c 0x53c 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D26__IPU1_DI1_PIN11 0x16c 0x53c 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_D26__IPU1_CSI0_DATA01 0x16c 0x53c 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D26__IPU1_CSI1_DATA14 0x16c 0x53c 0x898 0x3 0x1 +-#define MX6DL_PAD_EIM_D26__UART2_TX_DATA 0x16c 0x53c 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D26__UART2_RX_DATA 0x16c 0x53c 0x904 0x4 0x0 +-#define MX6DL_PAD_EIM_D26__GPIO3_IO26 0x16c 0x53c 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D26__IPU1_SISG2 0x16c 0x53c 0x000 0x6 0x0 +-#define MX6DL_PAD_EIM_D26__IPU1_DISP1_DATA22 0x16c 0x53c 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_D26__EPDC_SDOED 0x16c 0x53c 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D27__EIM_DATA27 0x170 0x540 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D27__IPU1_DI1_PIN13 0x170 0x540 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_D27__IPU1_CSI0_DATA00 0x170 0x540 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D27__IPU1_CSI1_DATA13 0x170 0x540 0x894 0x3 0x1 +-#define MX6DL_PAD_EIM_D27__UART2_RX_DATA 0x170 0x540 0x904 0x4 0x1 +-#define MX6DL_PAD_EIM_D27__UART2_TX_DATA 0x170 0x540 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D27__GPIO3_IO27 0x170 0x540 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D27__IPU1_SISG3 0x170 0x540 0x000 0x6 0x0 +-#define MX6DL_PAD_EIM_D27__IPU1_DISP1_DATA23 0x170 0x540 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_D27__EPDC_SDOE 0x170 0x540 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D28__EIM_DATA28 0x174 0x544 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D28__I2C1_SDA 0x174 0x544 0x86c 0x1 0x1 +-#define MX6DL_PAD_EIM_D28__ECSPI4_MOSI 0x174 0x544 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D28__IPU1_CSI1_DATA12 0x174 0x544 0x890 0x3 0x1 +-#define MX6DL_PAD_EIM_D28__UART2_CTS_B 0x174 0x544 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D28__UART2_RTS_B 0x174 0x544 0x900 0x4 0x0 +-#define MX6DL_PAD_EIM_D28__GPIO3_IO28 0x174 0x544 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D28__IPU1_EXT_TRIG 0x174 0x544 0x000 0x6 0x0 +-#define MX6DL_PAD_EIM_D28__IPU1_DI0_PIN13 0x174 0x544 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_D28__EPDC_PWR_CTRL3 0x174 0x544 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D29__EIM_DATA29 0x178 0x548 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D29__IPU1_DI1_PIN15 0x178 0x548 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_D29__ECSPI4_SS0 0x178 0x548 0x808 0x2 0x1 +-#define MX6DL_PAD_EIM_D29__UART2_RTS_B 0x178 0x548 0x900 0x4 0x1 +-#define MX6DL_PAD_EIM_D29__UART2_CTS_B 0x178 0x548 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D29__GPIO3_IO29 0x178 0x548 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D29__IPU1_CSI1_VSYNC 0x178 0x548 0x8bc 0x6 0x0 +-#define MX6DL_PAD_EIM_D29__IPU1_DI0_PIN14 0x178 0x548 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_D29__EPDC_PWR_WAKE 0x178 0x548 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D30__EIM_DATA30 0x17c 0x54c 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D30__IPU1_DISP1_DATA21 0x17c 0x54c 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_D30__IPU1_DI0_PIN11 0x17c 0x54c 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D30__IPU1_CSI0_DATA03 0x17c 0x54c 0x000 0x3 0x0 +-#define MX6DL_PAD_EIM_D30__UART3_CTS_B 0x17c 0x54c 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D30__UART3_RTS_B 0x17c 0x54c 0x908 0x4 0x1 +-#define MX6DL_PAD_EIM_D30__GPIO3_IO30 0x17c 0x54c 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D30__USB_H1_OC 0x17c 0x54c 0x924 0x6 0x0 +-#define MX6DL_PAD_EIM_D30__EPDC_SDOEZ 0x17c 0x54c 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D31__EIM_DATA31 0x180 0x550 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_D31__IPU1_DISP1_DATA20 0x180 0x550 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_D31__IPU1_DI0_PIN12 0x180 0x550 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_D31__IPU1_CSI0_DATA02 0x180 0x550 0x000 0x3 0x0 +-#define MX6DL_PAD_EIM_D31__UART3_RTS_B 0x180 0x550 0x908 0x4 0x2 +-#define MX6DL_PAD_EIM_D31__UART3_CTS_B 0x180 0x550 0x000 0x4 0x0 +-#define MX6DL_PAD_EIM_D31__GPIO3_IO31 0x180 0x550 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_D31__USB_H1_PWR 0x180 0x550 0x000 0x6 0x0 +-#define MX6DL_PAD_EIM_D31__EPDC_SDCLK_P 0x180 0x550 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_D31__EIM_ACLK_FREERUN 0x180 0x550 0x000 0x9 0x0 +-#define MX6DL_PAD_EIM_DA0__EIM_AD00 0x184 0x554 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA0__IPU1_DISP1_DATA09 0x184 0x554 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA0__IPU1_CSI1_DATA09 0x184 0x554 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_DA0__GPIO3_IO00 0x184 0x554 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA0__SRC_BOOT_CFG00 0x184 0x554 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA0__EPDC_SDCLK_N 0x184 0x554 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA1__EIM_AD01 0x188 0x558 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA1__IPU1_DISP1_DATA08 0x188 0x558 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA1__IPU1_CSI1_DATA08 0x188 0x558 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_DA1__GPIO3_IO01 0x188 0x558 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA1__SRC_BOOT_CFG01 0x188 0x558 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA1__EPDC_SDLE 0x188 0x558 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA10__EIM_AD10 0x18c 0x55c 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA10__IPU1_DI1_PIN15 0x18c 0x55c 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA10__IPU1_CSI1_DATA_EN 0x18c 0x55c 0x8b0 0x2 0x1 +-#define MX6DL_PAD_EIM_DA10__GPIO3_IO10 0x18c 0x55c 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA10__SRC_BOOT_CFG10 0x18c 0x55c 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA10__EPDC_DATA01 0x18c 0x55c 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA11__EIM_AD11 0x190 0x560 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA11__IPU1_DI1_PIN02 0x190 0x560 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA11__IPU1_CSI1_HSYNC 0x190 0x560 0x8b4 0x2 0x0 +-#define MX6DL_PAD_EIM_DA11__GPIO3_IO11 0x190 0x560 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA11__SRC_BOOT_CFG11 0x190 0x560 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA11__EPDC_DATA03 0x190 0x560 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA12__EIM_AD12 0x194 0x564 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA12__IPU1_DI1_PIN03 0x194 0x564 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA12__IPU1_CSI1_VSYNC 0x194 0x564 0x8bc 0x2 0x1 +-#define MX6DL_PAD_EIM_DA12__GPIO3_IO12 0x194 0x564 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA12__SRC_BOOT_CFG12 0x194 0x564 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA12__EPDC_DATA02 0x194 0x564 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA13__EIM_AD13 0x198 0x568 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA13__IPU1_DI1_D0_CS 0x198 0x568 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA13__GPIO3_IO13 0x198 0x568 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA13__SRC_BOOT_CFG13 0x198 0x568 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA13__EPDC_DATA13 0x198 0x568 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA14__EIM_AD14 0x19c 0x56c 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA14__IPU1_DI1_D1_CS 0x19c 0x56c 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA14__GPIO3_IO14 0x19c 0x56c 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA14__SRC_BOOT_CFG14 0x19c 0x56c 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA14__EPDC_DATA14 0x19c 0x56c 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA15__EIM_AD15 0x1a0 0x570 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA15__IPU1_DI1_PIN01 0x1a0 0x570 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA15__IPU1_DI1_PIN04 0x1a0 0x570 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_DA15__GPIO3_IO15 0x1a0 0x570 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA15__SRC_BOOT_CFG15 0x1a0 0x570 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA15__EPDC_DATA09 0x1a0 0x570 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA2__EIM_AD02 0x1a4 0x574 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA2__IPU1_DISP1_DATA07 0x1a4 0x574 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA2__IPU1_CSI1_DATA07 0x1a4 0x574 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_DA2__GPIO3_IO02 0x1a4 0x574 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA2__SRC_BOOT_CFG02 0x1a4 0x574 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA2__EPDC_BDR0 0x1a4 0x574 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA3__EIM_AD03 0x1a8 0x578 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA3__IPU1_DISP1_DATA06 0x1a8 0x578 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA3__IPU1_CSI1_DATA06 0x1a8 0x578 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_DA3__GPIO3_IO03 0x1a8 0x578 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA3__SRC_BOOT_CFG03 0x1a8 0x578 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA3__EPDC_BDR1 0x1a8 0x578 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA4__EIM_AD04 0x1ac 0x57c 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA4__IPU1_DISP1_DATA05 0x1ac 0x57c 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA4__IPU1_CSI1_DATA05 0x1ac 0x57c 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_DA4__GPIO3_IO04 0x1ac 0x57c 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA4__SRC_BOOT_CFG04 0x1ac 0x57c 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA4__EPDC_SDCE0 0x1ac 0x57c 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA5__EIM_AD05 0x1b0 0x580 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA5__IPU1_DISP1_DATA04 0x1b0 0x580 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA5__IPU1_CSI1_DATA04 0x1b0 0x580 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_DA5__GPIO3_IO05 0x1b0 0x580 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA5__SRC_BOOT_CFG05 0x1b0 0x580 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA5__EPDC_SDCE1 0x1b0 0x580 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA6__EIM_AD06 0x1b4 0x584 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA6__IPU1_DISP1_DATA03 0x1b4 0x584 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA6__IPU1_CSI1_DATA03 0x1b4 0x584 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_DA6__GPIO3_IO06 0x1b4 0x584 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA6__SRC_BOOT_CFG06 0x1b4 0x584 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA6__EPDC_SDCE2 0x1b4 0x584 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA7__EIM_AD07 0x1b8 0x588 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA7__IPU1_DISP1_DATA02 0x1b8 0x588 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA7__IPU1_CSI1_DATA02 0x1b8 0x588 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_DA7__GPIO3_IO07 0x1b8 0x588 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA7__SRC_BOOT_CFG07 0x1b8 0x588 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA7__EPDC_SDCE3 0x1b8 0x588 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA8__EIM_AD08 0x1bc 0x58c 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA8__IPU1_DISP1_DATA01 0x1bc 0x58c 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA8__IPU1_CSI1_DATA01 0x1bc 0x58c 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_DA8__GPIO3_IO08 0x1bc 0x58c 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA8__SRC_BOOT_CFG08 0x1bc 0x58c 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA8__EPDC_SDCE4 0x1bc 0x58c 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_DA9__EIM_AD09 0x1c0 0x590 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_DA9__IPU1_DISP1_DATA00 0x1c0 0x590 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_DA9__IPU1_CSI1_DATA00 0x1c0 0x590 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_DA9__GPIO3_IO09 0x1c0 0x590 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_DA9__SRC_BOOT_CFG09 0x1c0 0x590 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_DA9__EPDC_SDCE5 0x1c0 0x590 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_EB0__EIM_EB0_B 0x1c4 0x594 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_EB0__IPU1_DISP1_DATA11 0x1c4 0x594 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_EB0__IPU1_CSI1_DATA11 0x1c4 0x594 0x88c 0x2 0x1 +-#define MX6DL_PAD_EIM_EB0__CCM_PMIC_READY 0x1c4 0x594 0x7d4 0x4 0x0 +-#define MX6DL_PAD_EIM_EB0__GPIO2_IO28 0x1c4 0x594 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_EB0__SRC_BOOT_CFG27 0x1c4 0x594 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_EB0__EPDC_PWR_COM 0x1c4 0x594 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_EB1__EIM_EB1_B 0x1c8 0x598 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_EB1__IPU1_DISP1_DATA10 0x1c8 0x598 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_EB1__IPU1_CSI1_DATA10 0x1c8 0x598 0x888 0x2 0x1 +-#define MX6DL_PAD_EIM_EB1__GPIO2_IO29 0x1c8 0x598 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_EB1__SRC_BOOT_CFG28 0x1c8 0x598 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_EB1__EPDC_SDSHR 0x1c8 0x598 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_EB2__EIM_EB2_B 0x1cc 0x59c 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_EB2__ECSPI1_SS0 0x1cc 0x59c 0x7e4 0x1 0x2 +-#define MX6DL_PAD_EIM_EB2__IPU1_CSI1_DATA19 0x1cc 0x59c 0x8ac 0x3 0x1 +-#define MX6DL_PAD_EIM_EB2__HDMI_TX_DDC_SCL 0x1cc 0x59c 0x860 0x4 0x0 +-#define MX6DL_PAD_EIM_EB2__GPIO2_IO30 0x1cc 0x59c 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_EB2__I2C2_SCL 0x1cc 0x59c 0x870 0x6 0x0 +-#define MX6DL_PAD_EIM_EB2__SRC_BOOT_CFG30 0x1cc 0x59c 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_EB2__EPDC_DATA05 0x1cc 0x59c 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_EB3__EIM_EB3_B 0x1d0 0x5a0 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_EB3__ECSPI4_RDY 0x1d0 0x5a0 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_EB3__UART3_RTS_B 0x1d0 0x5a0 0x908 0x2 0x3 +-#define MX6DL_PAD_EIM_EB3__UART3_CTS_B 0x1d0 0x5a0 0x000 0x2 0x0 +-#define MX6DL_PAD_EIM_EB3__UART1_RI_B 0x1d0 0x5a0 0x000 0x3 0x0 +-#define MX6DL_PAD_EIM_EB3__IPU1_CSI1_HSYNC 0x1d0 0x5a0 0x8b4 0x4 0x1 +-#define MX6DL_PAD_EIM_EB3__GPIO2_IO31 0x1d0 0x5a0 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_EB3__IPU1_DI1_PIN03 0x1d0 0x5a0 0x000 0x6 0x0 +-#define MX6DL_PAD_EIM_EB3__SRC_BOOT_CFG31 0x1d0 0x5a0 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_EB3__EPDC_SDCE0 0x1d0 0x5a0 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_EB3__EIM_ACLK_FREERUN 0x1d0 0x5a0 0x000 0x9 0x0 +-#define MX6DL_PAD_EIM_LBA__EIM_LBA_B 0x1d4 0x5a4 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_LBA__IPU1_DI1_PIN17 0x1d4 0x5a4 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_LBA__ECSPI2_SS1 0x1d4 0x5a4 0x804 0x2 0x1 +-#define MX6DL_PAD_EIM_LBA__GPIO2_IO27 0x1d4 0x5a4 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_LBA__SRC_BOOT_CFG26 0x1d4 0x5a4 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_LBA__EPDC_DATA04 0x1d4 0x5a4 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_OE__EIM_OE_B 0x1d8 0x5a8 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_OE__IPU1_DI1_PIN07 0x1d8 0x5a8 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_OE__ECSPI2_MISO 0x1d8 0x5a8 0x7f8 0x2 0x2 +-#define MX6DL_PAD_EIM_OE__GPIO2_IO25 0x1d8 0x5a8 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_OE__EPDC_PWR_IRQ 0x1d8 0x5a8 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_RW__EIM_RW 0x1dc 0x5ac 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_RW__IPU1_DI1_PIN08 0x1dc 0x5ac 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_RW__ECSPI2_SS0 0x1dc 0x5ac 0x800 0x2 0x2 +-#define MX6DL_PAD_EIM_RW__GPIO2_IO26 0x1dc 0x5ac 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_RW__SRC_BOOT_CFG29 0x1dc 0x5ac 0x000 0x7 0x0 +-#define MX6DL_PAD_EIM_RW__EPDC_DATA07 0x1dc 0x5ac 0x000 0x8 0x0 +-#define MX6DL_PAD_EIM_WAIT__EIM_WAIT_B 0x1e0 0x5b0 0x000 0x0 0x0 +-#define MX6DL_PAD_EIM_WAIT__EIM_DTACK_B 0x1e0 0x5b0 0x000 0x1 0x0 +-#define MX6DL_PAD_EIM_WAIT__GPIO5_IO00 0x1e0 0x5b0 0x000 0x5 0x0 +-#define MX6DL_PAD_EIM_WAIT__SRC_BOOT_CFG25 0x1e0 0x5b0 0x000 0x7 0x0 +-#define MX6DL_PAD_ENET_CRS_DV__ENET_RX_EN 0x1e4 0x5b4 0x828 0x1 0x0 +-#define MX6DL_PAD_ENET_CRS_DV__ESAI_TX_CLK 0x1e4 0x5b4 0x840 0x2 0x0 +-#define MX6DL_PAD_ENET_CRS_DV__SPDIF_EXT_CLK 0x1e4 0x5b4 0x8f4 0x3 0x0 +-#define MX6DL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1e4 0x5b4 0x000 0x5 0x0 +-#define MX6DL_PAD_ENET_MDC__MLB_DATA 0x1e8 0x5b8 0x8e0 0x0 0x0 +-#define MX6DL_PAD_ENET_MDC__ENET_MDC 0x1e8 0x5b8 0x000 0x1 0x0 +-#define MX6DL_PAD_ENET_MDC__ESAI_TX5_RX0 0x1e8 0x5b8 0x858 0x2 0x0 +-#define MX6DL_PAD_ENET_MDC__ENET_1588_EVENT1_IN 0x1e8 0x5b8 0x000 0x4 0x0 +-#define MX6DL_PAD_ENET_MDC__GPIO1_IO31 0x1e8 0x5b8 0x000 0x5 0x0 +-#define MX6DL_PAD_ENET_MDIO__ENET_MDIO 0x1ec 0x5bc 0x810 0x1 0x0 +-#define MX6DL_PAD_ENET_MDIO__ESAI_RX_CLK 0x1ec 0x5bc 0x83c 0x2 0x0 +-#define MX6DL_PAD_ENET_MDIO__ENET_1588_EVENT1_OUT 0x1ec 0x5bc 0x000 0x4 0x0 +-#define MX6DL_PAD_ENET_MDIO__GPIO1_IO22 0x1ec 0x5bc 0x000 0x5 0x0 +-#define MX6DL_PAD_ENET_MDIO__SPDIF_LOCK 0x1ec 0x5bc 0x000 0x6 0x0 +-#define MX6DL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1f0 0x5c0 0x000 0x1 0x0 +-#define MX6DL_PAD_ENET_REF_CLK__ESAI_RX_FS 0x1f0 0x5c0 0x82c 0x2 0x0 +-#define MX6DL_PAD_ENET_REF_CLK__GPIO1_IO23 0x1f0 0x5c0 0x000 0x5 0x0 +-#define MX6DL_PAD_ENET_REF_CLK__SPDIF_SR_CLK 0x1f0 0x5c0 0x000 0x6 0x0 +-#define MX6DL_PAD_ENET_RX_ER__USB_OTG_ID 0x1f4 0x5c4 0x790 0x0 0x0 +-#define MX6DL_PAD_ENET_RX_ER__ENET_RX_ER 0x1f4 0x5c4 0x000 0x1 0x0 +-#define MX6DL_PAD_ENET_RX_ER__ESAI_RX_HF_CLK 0x1f4 0x5c4 0x834 0x2 0x0 +-#define MX6DL_PAD_ENET_RX_ER__SPDIF_IN 0x1f4 0x5c4 0x8f0 0x3 0x1 +-#define MX6DL_PAD_ENET_RX_ER__ENET_1588_EVENT2_OUT 0x1f4 0x5c4 0x000 0x4 0x0 +-#define MX6DL_PAD_ENET_RX_ER__GPIO1_IO24 0x1f4 0x5c4 0x000 0x5 0x0 +-#define MX6DL_PAD_ENET_RXD0__ENET_RX_DATA0 0x1f8 0x5c8 0x818 0x1 0x0 +-#define MX6DL_PAD_ENET_RXD0__ESAI_TX_HF_CLK 0x1f8 0x5c8 0x838 0x2 0x0 +-#define MX6DL_PAD_ENET_RXD0__SPDIF_OUT 0x1f8 0x5c8 0x000 0x3 0x0 +-#define MX6DL_PAD_ENET_RXD0__GPIO1_IO27 0x1f8 0x5c8 0x000 0x5 0x0 +-#define MX6DL_PAD_ENET_RXD1__MLB_SIG 0x1fc 0x5cc 0x8e4 0x0 0x0 +-#define MX6DL_PAD_ENET_RXD1__ENET_RX_DATA1 0x1fc 0x5cc 0x81c 0x1 0x0 +-#define MX6DL_PAD_ENET_RXD1__ESAI_TX_FS 0x1fc 0x5cc 0x830 0x2 0x0 +-#define MX6DL_PAD_ENET_RXD1__ENET_1588_EVENT3_OUT 0x1fc 0x5cc 0x000 0x4 0x0 +-#define MX6DL_PAD_ENET_RXD1__GPIO1_IO26 0x1fc 0x5cc 0x000 0x5 0x0 +-#define MX6DL_PAD_ENET_TX_EN__ENET_TX_EN 0x200 0x5d0 0x000 0x1 0x0 +-#define MX6DL_PAD_ENET_TX_EN__ESAI_TX3_RX2 0x200 0x5d0 0x850 0x2 0x0 +-#define MX6DL_PAD_ENET_TX_EN__GPIO1_IO28 0x200 0x5d0 0x000 0x5 0x0 +-#define MX6DL_PAD_ENET_TX_EN__I2C4_SCL 0x200 0x5d0 0x880 0x9 0x0 +-#define MX6DL_PAD_ENET_TXD0__ENET_TX_DATA0 0x204 0x5d4 0x000 0x1 0x0 +-#define MX6DL_PAD_ENET_TXD0__ESAI_TX4_RX1 0x204 0x5d4 0x854 0x2 0x0 +-#define MX6DL_PAD_ENET_TXD0__GPIO1_IO30 0x204 0x5d4 0x000 0x5 0x0 +-#define MX6DL_PAD_ENET_TXD1__MLB_CLK 0x208 0x5d8 0x8dc 0x0 0x0 +-#define MX6DL_PAD_ENET_TXD1__ENET_TX_DATA1 0x208 0x5d8 0x000 0x1 0x0 +-#define MX6DL_PAD_ENET_TXD1__ESAI_TX2_RX3 0x208 0x5d8 0x84c 0x2 0x0 +-#define MX6DL_PAD_ENET_TXD1__ENET_1588_EVENT0_IN 0x208 0x5d8 0x000 0x4 0x0 +-#define MX6DL_PAD_ENET_TXD1__GPIO1_IO29 0x208 0x5d8 0x000 0x5 0x0 +-#define MX6DL_PAD_ENET_TXD1__I2C4_SDA 0x208 0x5d8 0x884 0x9 0x0 +-#define MX6DL_PAD_GPIO_0__CCM_CLKO1 0x20c 0x5dc 0x000 0x0 0x0 +-#define MX6DL_PAD_GPIO_0__KEY_COL5 0x20c 0x5dc 0x8c0 0x2 0x1 +-#define MX6DL_PAD_GPIO_0__ASRC_EXT_CLK 0x20c 0x5dc 0x794 0x3 0x0 +-#define MX6DL_PAD_GPIO_0__EPIT1_OUT 0x20c 0x5dc 0x000 0x4 0x0 +-#define MX6DL_PAD_GPIO_0__GPIO1_IO00 0x20c 0x5dc 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_0__USB_H1_PWR 0x20c 0x5dc 0x000 0x6 0x0 +-#define MX6DL_PAD_GPIO_0__SNVS_VIO_5 0x20c 0x5dc 0x000 0x7 0x0 +-#define MX6DL_PAD_GPIO_1__ESAI_RX_CLK 0x210 0x5e0 0x83c 0x0 0x1 +-#define MX6DL_PAD_GPIO_1__WDOG2_B 0x210 0x5e0 0x000 0x1 0x0 +-#define MX6DL_PAD_GPIO_1__KEY_ROW5 0x210 0x5e0 0x8cc 0x2 0x1 +-#define MX6DL_PAD_GPIO_1__USB_OTG_ID 0x210 0x5e0 0x790 0x3 0x1 +-#define MX6DL_PAD_GPIO_1__PWM2_OUT 0x210 0x5e0 0x000 0x4 0x0 +-#define MX6DL_PAD_GPIO_1__GPIO1_IO01 0x210 0x5e0 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_1__SD1_CD_B 0x210 0x5e0 0x000 0x6 0x0 +-#define MX6DL_PAD_GPIO_16__ESAI_TX3_RX2 0x214 0x5e4 0x850 0x0 0x1 +-#define MX6DL_PAD_GPIO_16__ENET_1588_EVENT2_IN 0x214 0x5e4 0x000 0x1 0x0 +-#define MX6DL_PAD_GPIO_16__ENET_REF_CLK 0x214 0x5e4 0x80c 0x2 0x0 +-#define MX6DL_PAD_GPIO_16__SD1_LCTL 0x214 0x5e4 0x000 0x3 0x0 +-#define MX6DL_PAD_GPIO_16__SPDIF_IN 0x214 0x5e4 0x8f0 0x4 0x2 +-#define MX6DL_PAD_GPIO_16__GPIO7_IO11 0x214 0x5e4 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_16__I2C3_SDA 0x214 0x5e4 0x87c 0x6 0x1 +-#define MX6DL_PAD_GPIO_16__JTAG_DE_B 0x214 0x5e4 0x000 0x7 0x0 +-#define MX6DL_PAD_GPIO_17__ESAI_TX0 0x218 0x5e8 0x844 0x0 0x0 +-#define MX6DL_PAD_GPIO_17__ENET_1588_EVENT3_IN 0x218 0x5e8 0x000 0x1 0x0 +-#define MX6DL_PAD_GPIO_17__CCM_PMIC_READY 0x218 0x5e8 0x7d4 0x2 0x1 +-#define MX6DL_PAD_GPIO_17__SDMA_EXT_EVENT0 0x218 0x5e8 0x8e8 0x3 0x1 +-#define MX6DL_PAD_GPIO_17__SPDIF_OUT 0x218 0x5e8 0x000 0x4 0x0 +-#define MX6DL_PAD_GPIO_17__GPIO7_IO12 0x218 0x5e8 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_18__ESAI_TX1 0x21c 0x5ec 0x848 0x0 0x0 +-#define MX6DL_PAD_GPIO_18__ENET_RX_CLK 0x21c 0x5ec 0x814 0x1 0x0 +-#define MX6DL_PAD_GPIO_18__SD3_VSELECT 0x21c 0x5ec 0x000 0x2 0x0 +-#define MX6DL_PAD_GPIO_18__SDMA_EXT_EVENT1 0x21c 0x5ec 0x8ec 0x3 0x1 +-#define MX6DL_PAD_GPIO_18__ASRC_EXT_CLK 0x21c 0x5ec 0x794 0x4 0x1 +-#define MX6DL_PAD_GPIO_18__GPIO7_IO13 0x21c 0x5ec 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_18__SNVS_VIO_5_CTL 0x21c 0x5ec 0x000 0x6 0x0 +-#define MX6DL_PAD_GPIO_19__KEY_COL5 0x220 0x5f0 0x8c0 0x0 0x2 +-#define MX6DL_PAD_GPIO_19__ENET_1588_EVENT0_OUT 0x220 0x5f0 0x000 0x1 0x0 +-#define MX6DL_PAD_GPIO_19__SPDIF_OUT 0x220 0x5f0 0x000 0x2 0x0 +-#define MX6DL_PAD_GPIO_19__CCM_CLKO1 0x220 0x5f0 0x000 0x3 0x0 +-#define MX6DL_PAD_GPIO_19__ECSPI1_RDY 0x220 0x5f0 0x000 0x4 0x0 +-#define MX6DL_PAD_GPIO_19__GPIO4_IO05 0x220 0x5f0 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_19__ENET_TX_ER 0x220 0x5f0 0x000 0x6 0x0 +-#define MX6DL_PAD_GPIO_2__ESAI_TX_FS 0x224 0x5f4 0x830 0x0 0x1 +-#define MX6DL_PAD_GPIO_2__KEY_ROW6 0x224 0x5f4 0x8d0 0x2 0x1 +-#define MX6DL_PAD_GPIO_2__GPIO1_IO02 0x224 0x5f4 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_2__SD2_WP 0x224 0x5f4 0x000 0x6 0x0 +-#define MX6DL_PAD_GPIO_2__MLB_DATA 0x224 0x5f4 0x8e0 0x7 0x1 +-#define MX6DL_PAD_GPIO_3__ESAI_RX_HF_CLK 0x228 0x5f8 0x834 0x0 0x1 +-#define MX6DL_PAD_GPIO_3__I2C3_SCL 0x228 0x5f8 0x878 0x2 0x1 +-#define MX6DL_PAD_GPIO_3__XTALOSC_REF_CLK_24M 0x228 0x5f8 0x000 0x3 0x0 +-#define MX6DL_PAD_GPIO_3__CCM_CLKO2 0x228 0x5f8 0x000 0x4 0x0 +-#define MX6DL_PAD_GPIO_3__GPIO1_IO03 0x228 0x5f8 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_3__USB_H1_OC 0x228 0x5f8 0x924 0x6 0x1 +-#define MX6DL_PAD_GPIO_3__MLB_CLK 0x228 0x5f8 0x8dc 0x7 0x1 +-#define MX6DL_PAD_GPIO_4__ESAI_TX_HF_CLK 0x22c 0x5fc 0x838 0x0 0x1 +-#define MX6DL_PAD_GPIO_4__KEY_COL7 0x22c 0x5fc 0x8c8 0x2 0x1 +-#define MX6DL_PAD_GPIO_4__GPIO1_IO04 0x22c 0x5fc 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_4__SD2_CD_B 0x22c 0x5fc 0x000 0x6 0x0 +-#define MX6DL_PAD_GPIO_5__ESAI_TX2_RX3 0x230 0x600 0x84c 0x0 0x1 +-#define MX6DL_PAD_GPIO_5__KEY_ROW7 0x230 0x600 0x8d4 0x2 0x1 +-#define MX6DL_PAD_GPIO_5__CCM_CLKO1 0x230 0x600 0x000 0x3 0x0 +-#define MX6DL_PAD_GPIO_5__GPIO1_IO05 0x230 0x600 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_5__I2C3_SCL 0x230 0x600 0x878 0x6 0x2 +-#define MX6DL_PAD_GPIO_5__ARM_EVENTI 0x230 0x600 0x000 0x7 0x0 +-#define MX6DL_PAD_GPIO_6__ESAI_TX_CLK 0x234 0x604 0x840 0x0 0x1 +-#define MX6DL_PAD_GPIO_6__I2C3_SDA 0x234 0x604 0x87c 0x2 0x2 +-#define MX6DL_PAD_GPIO_6__GPIO1_IO06 0x234 0x604 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_6__SD2_LCTL 0x234 0x604 0x000 0x6 0x0 +-#define MX6DL_PAD_GPIO_6__MLB_SIG 0x234 0x604 0x8e4 0x7 0x1 +-#define MX6DL_PAD_GPIO_7__ESAI_TX4_RX1 0x238 0x608 0x854 0x0 0x1 +-#define MX6DL_PAD_GPIO_7__EPIT1_OUT 0x238 0x608 0x000 0x2 0x0 +-#define MX6DL_PAD_GPIO_7__FLEXCAN1_TX 0x238 0x608 0x000 0x3 0x0 +-#define MX6DL_PAD_GPIO_7__UART2_TX_DATA 0x238 0x608 0x000 0x4 0x0 +-#define MX6DL_PAD_GPIO_7__UART2_RX_DATA 0x238 0x608 0x904 0x4 0x2 +-#define MX6DL_PAD_GPIO_7__GPIO1_IO07 0x238 0x608 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_7__SPDIF_LOCK 0x238 0x608 0x000 0x6 0x0 +-#define MX6DL_PAD_GPIO_7__USB_OTG_HOST_MODE 0x238 0x608 0x000 0x7 0x0 +-#define MX6DL_PAD_GPIO_7__I2C4_SCL 0x238 0x608 0x880 0x8 0x1 +-#define MX6DL_PAD_GPIO_8__ESAI_TX5_RX0 0x23c 0x60c 0x858 0x0 0x1 +-#define MX6DL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x23c 0x60c 0x000 0x1 0x0 +-#define MX6DL_PAD_GPIO_8__EPIT2_OUT 0x23c 0x60c 0x000 0x2 0x0 +-#define MX6DL_PAD_GPIO_8__FLEXCAN1_RX 0x23c 0x60c 0x7c8 0x3 0x0 +-#define MX6DL_PAD_GPIO_8__UART2_RX_DATA 0x23c 0x60c 0x904 0x4 0x3 +-#define MX6DL_PAD_GPIO_8__UART2_TX_DATA 0x23c 0x60c 0x000 0x4 0x0 +-#define MX6DL_PAD_GPIO_8__GPIO1_IO08 0x23c 0x60c 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_8__SPDIF_SR_CLK 0x23c 0x60c 0x000 0x6 0x0 +-#define MX6DL_PAD_GPIO_8__USB_OTG_PWR_CTL_WAKE 0x23c 0x60c 0x000 0x7 0x0 +-#define MX6DL_PAD_GPIO_8__I2C4_SDA 0x23c 0x60c 0x884 0x8 0x1 +-#define MX6DL_PAD_GPIO_9__ESAI_RX_FS 0x240 0x610 0x82c 0x0 0x1 +-#define MX6DL_PAD_GPIO_9__WDOG1_B 0x240 0x610 0x000 0x1 0x0 +-#define MX6DL_PAD_GPIO_9__KEY_COL6 0x240 0x610 0x8c4 0x2 0x1 +-#define MX6DL_PAD_GPIO_9__CCM_REF_EN_B 0x240 0x610 0x000 0x3 0x0 +-#define MX6DL_PAD_GPIO_9__PWM1_OUT 0x240 0x610 0x000 0x4 0x0 +-#define MX6DL_PAD_GPIO_9__GPIO1_IO09 0x240 0x610 0x000 0x5 0x0 +-#define MX6DL_PAD_GPIO_9__SD1_WP 0x240 0x610 0x92c 0x6 0x1 +-#define MX6DL_PAD_KEY_COL0__ECSPI1_SCLK 0x244 0x62c 0x7d8 0x0 0x3 +-#define MX6DL_PAD_KEY_COL0__ENET_RX_DATA3 0x244 0x62c 0x824 0x1 0x0 +-#define MX6DL_PAD_KEY_COL0__AUD5_TXC 0x244 0x62c 0x7c0 0x2 0x1 +-#define MX6DL_PAD_KEY_COL0__KEY_COL0 0x244 0x62c 0x000 0x3 0x0 +-#define MX6DL_PAD_KEY_COL0__UART4_TX_DATA 0x244 0x62c 0x000 0x4 0x0 +-#define MX6DL_PAD_KEY_COL0__UART4_RX_DATA 0x244 0x62c 0x914 0x4 0x2 +-#define MX6DL_PAD_KEY_COL0__GPIO4_IO06 0x244 0x62c 0x000 0x5 0x0 +-#define MX6DL_PAD_KEY_COL0__DCIC1_OUT 0x244 0x62c 0x000 0x6 0x0 +-#define MX6DL_PAD_KEY_COL1__ECSPI1_MISO 0x248 0x630 0x7dc 0x0 0x3 +-#define MX6DL_PAD_KEY_COL1__ENET_MDIO 0x248 0x630 0x810 0x1 0x1 +-#define MX6DL_PAD_KEY_COL1__AUD5_TXFS 0x248 0x630 0x7c4 0x2 0x1 +-#define MX6DL_PAD_KEY_COL1__KEY_COL1 0x248 0x630 0x000 0x3 0x0 +-#define MX6DL_PAD_KEY_COL1__UART5_TX_DATA 0x248 0x630 0x000 0x4 0x0 +-#define MX6DL_PAD_KEY_COL1__UART5_RX_DATA 0x248 0x630 0x91c 0x4 0x2 +-#define MX6DL_PAD_KEY_COL1__GPIO4_IO08 0x248 0x630 0x000 0x5 0x0 +-#define MX6DL_PAD_KEY_COL1__SD1_VSELECT 0x248 0x630 0x000 0x6 0x0 +-#define MX6DL_PAD_KEY_COL2__ECSPI1_SS1 0x24c 0x634 0x7e8 0x0 0x2 +-#define MX6DL_PAD_KEY_COL2__ENET_RX_DATA2 0x24c 0x634 0x820 0x1 0x0 +-#define MX6DL_PAD_KEY_COL2__FLEXCAN1_TX 0x24c 0x634 0x000 0x2 0x0 +-#define MX6DL_PAD_KEY_COL2__KEY_COL2 0x24c 0x634 0x000 0x3 0x0 +-#define MX6DL_PAD_KEY_COL2__ENET_MDC 0x24c 0x634 0x000 0x4 0x0 +-#define MX6DL_PAD_KEY_COL2__GPIO4_IO10 0x24c 0x634 0x000 0x5 0x0 +-#define MX6DL_PAD_KEY_COL2__USB_H1_PWR_CTL_WAKE 0x24c 0x634 0x000 0x6 0x0 +-#define MX6DL_PAD_KEY_COL3__ECSPI1_SS3 0x250 0x638 0x7f0 0x0 0x1 +-#define MX6DL_PAD_KEY_COL3__ENET_CRS 0x250 0x638 0x000 0x1 0x0 +-#define MX6DL_PAD_KEY_COL3__HDMI_TX_DDC_SCL 0x250 0x638 0x860 0x2 0x1 +-#define MX6DL_PAD_KEY_COL3__KEY_COL3 0x250 0x638 0x000 0x3 0x0 +-#define MX6DL_PAD_KEY_COL3__I2C2_SCL 0x250 0x638 0x870 0x4 0x1 +-#define MX6DL_PAD_KEY_COL3__GPIO4_IO12 0x250 0x638 0x000 0x5 0x0 +-#define MX6DL_PAD_KEY_COL3__SPDIF_IN 0x250 0x638 0x8f0 0x6 0x3 +-#define MX6DL_PAD_KEY_COL4__FLEXCAN2_TX 0x254 0x63c 0x000 0x0 0x0 +-#define MX6DL_PAD_KEY_COL4__IPU1_SISG4 0x254 0x63c 0x000 0x1 0x0 +-#define MX6DL_PAD_KEY_COL4__USB_OTG_OC 0x254 0x63c 0x920 0x2 0x1 +-#define MX6DL_PAD_KEY_COL4__KEY_COL4 0x254 0x63c 0x000 0x3 0x0 +-#define MX6DL_PAD_KEY_COL4__UART5_RTS_B 0x254 0x63c 0x918 0x4 0x2 +-#define MX6DL_PAD_KEY_COL4__UART5_CTS_B 0x254 0x63c 0x000 0x4 0x0 +-#define MX6DL_PAD_KEY_COL4__GPIO4_IO14 0x254 0x63c 0x000 0x5 0x0 +-#define MX6DL_PAD_KEY_ROW0__ECSPI1_MOSI 0x258 0x640 0x7e0 0x0 0x3 +-#define MX6DL_PAD_KEY_ROW0__ENET_TX_DATA3 0x258 0x640 0x000 0x1 0x0 +-#define MX6DL_PAD_KEY_ROW0__AUD5_TXD 0x258 0x640 0x7b4 0x2 0x1 +-#define MX6DL_PAD_KEY_ROW0__KEY_ROW0 0x258 0x640 0x000 0x3 0x0 +-#define MX6DL_PAD_KEY_ROW0__UART4_RX_DATA 0x258 0x640 0x914 0x4 0x3 +-#define MX6DL_PAD_KEY_ROW0__UART4_TX_DATA 0x258 0x640 0x000 0x4 0x0 +-#define MX6DL_PAD_KEY_ROW0__GPIO4_IO07 0x258 0x640 0x000 0x5 0x0 +-#define MX6DL_PAD_KEY_ROW0__DCIC2_OUT 0x258 0x640 0x000 0x6 0x0 +-#define MX6DL_PAD_KEY_ROW1__ECSPI1_SS0 0x25c 0x644 0x7e4 0x0 0x3 +-#define MX6DL_PAD_KEY_ROW1__ENET_COL 0x25c 0x644 0x000 0x1 0x0 +-#define MX6DL_PAD_KEY_ROW1__AUD5_RXD 0x25c 0x644 0x7b0 0x2 0x1 +-#define MX6DL_PAD_KEY_ROW1__KEY_ROW1 0x25c 0x644 0x000 0x3 0x0 +-#define MX6DL_PAD_KEY_ROW1__UART5_RX_DATA 0x25c 0x644 0x91c 0x4 0x3 +-#define MX6DL_PAD_KEY_ROW1__UART5_TX_DATA 0x25c 0x644 0x000 0x4 0x0 +-#define MX6DL_PAD_KEY_ROW1__GPIO4_IO09 0x25c 0x644 0x000 0x5 0x0 +-#define MX6DL_PAD_KEY_ROW1__SD2_VSELECT 0x25c 0x644 0x000 0x6 0x0 +-#define MX6DL_PAD_KEY_ROW2__ECSPI1_SS2 0x260 0x648 0x7ec 0x0 0x1 +-#define MX6DL_PAD_KEY_ROW2__ENET_TX_DATA2 0x260 0x648 0x000 0x1 0x0 +-#define MX6DL_PAD_KEY_ROW2__FLEXCAN1_RX 0x260 0x648 0x7c8 0x2 0x1 +-#define MX6DL_PAD_KEY_ROW2__KEY_ROW2 0x260 0x648 0x000 0x3 0x0 +-#define MX6DL_PAD_KEY_ROW2__SD2_VSELECT 0x260 0x648 0x000 0x4 0x0 +-#define MX6DL_PAD_KEY_ROW2__GPIO4_IO11 0x260 0x648 0x000 0x5 0x0 +-#define MX6DL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x260 0x648 0x85c 0x6 0x1 +-#define MX6DL_PAD_KEY_ROW3__ASRC_EXT_CLK 0x264 0x64c 0x794 0x1 0x2 +-#define MX6DL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 0x264 0x64c 0x864 0x2 0x1 +-#define MX6DL_PAD_KEY_ROW3__KEY_ROW3 0x264 0x64c 0x000 0x3 0x0 +-#define MX6DL_PAD_KEY_ROW3__I2C2_SDA 0x264 0x64c 0x874 0x4 0x1 +-#define MX6DL_PAD_KEY_ROW3__GPIO4_IO13 0x264 0x64c 0x000 0x5 0x0 +-#define MX6DL_PAD_KEY_ROW3__SD1_VSELECT 0x264 0x64c 0x000 0x6 0x0 +-#define MX6DL_PAD_KEY_ROW4__FLEXCAN2_RX 0x268 0x650 0x7cc 0x0 0x0 +-#define MX6DL_PAD_KEY_ROW4__IPU1_SISG5 0x268 0x650 0x000 0x1 0x0 +-#define MX6DL_PAD_KEY_ROW4__USB_OTG_PWR 0x268 0x650 0x000 0x2 0x0 +-#define MX6DL_PAD_KEY_ROW4__KEY_ROW4 0x268 0x650 0x000 0x3 0x0 +-#define MX6DL_PAD_KEY_ROW4__UART5_CTS_B 0x268 0x650 0x000 0x4 0x0 +-#define MX6DL_PAD_KEY_ROW4__UART5_RTS_B 0x268 0x650 0x918 0x4 0x3 +-#define MX6DL_PAD_KEY_ROW4__GPIO4_IO15 0x268 0x650 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_ALE__NAND_ALE 0x26c 0x654 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_ALE__SD4_RESET 0x26c 0x654 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_ALE__GPIO6_IO08 0x26c 0x654 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_CLE__NAND_CLE 0x270 0x658 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_CLE__GPIO6_IO07 0x270 0x658 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_CS0__NAND_CE0_B 0x274 0x65c 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_CS0__GPIO6_IO11 0x274 0x65c 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_CS1__NAND_CE1_B 0x278 0x660 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_CS1__SD4_VSELECT 0x278 0x660 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_CS1__SD3_VSELECT 0x278 0x660 0x000 0x2 0x0 +-#define MX6DL_PAD_NANDF_CS1__GPIO6_IO14 0x278 0x660 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_CS2__NAND_CE2_B 0x27c 0x664 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_CS2__IPU1_SISG0 0x27c 0x664 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_CS2__ESAI_TX0 0x27c 0x664 0x844 0x2 0x1 +-#define MX6DL_PAD_NANDF_CS2__EIM_CRE 0x27c 0x664 0x000 0x3 0x0 +-#define MX6DL_PAD_NANDF_CS2__CCM_CLKO2 0x27c 0x664 0x000 0x4 0x0 +-#define MX6DL_PAD_NANDF_CS2__GPIO6_IO15 0x27c 0x664 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_CS3__NAND_CE3_B 0x280 0x668 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_CS3__IPU1_SISG1 0x280 0x668 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_CS3__ESAI_TX1 0x280 0x668 0x848 0x2 0x1 +-#define MX6DL_PAD_NANDF_CS3__EIM_ADDR26 0x280 0x668 0x000 0x3 0x0 +-#define MX6DL_PAD_NANDF_CS3__GPIO6_IO16 0x280 0x668 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_CS3__I2C4_SDA 0x280 0x668 0x884 0x9 0x2 +-#define MX6DL_PAD_NANDF_D0__NAND_DATA00 0x284 0x66c 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_D0__SD1_DATA4 0x284 0x66c 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_D0__GPIO2_IO00 0x284 0x66c 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_D1__NAND_DATA01 0x288 0x670 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_D1__SD1_DATA5 0x288 0x670 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_D1__GPIO2_IO01 0x288 0x670 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_D2__NAND_DATA02 0x28c 0x674 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_D2__SD1_DATA6 0x28c 0x674 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_D2__GPIO2_IO02 0x28c 0x674 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_D3__NAND_DATA03 0x290 0x678 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_D3__SD1_DATA7 0x290 0x678 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_D3__GPIO2_IO03 0x290 0x678 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_D4__NAND_DATA04 0x294 0x67c 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_D4__SD2_DATA4 0x294 0x67c 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_D4__GPIO2_IO04 0x294 0x67c 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_D5__NAND_DATA05 0x298 0x680 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_D5__SD2_DATA5 0x298 0x680 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_D5__GPIO2_IO05 0x298 0x680 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_D6__NAND_DATA06 0x29c 0x684 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_D6__SD2_DATA6 0x29c 0x684 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_D6__GPIO2_IO06 0x29c 0x684 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_D7__NAND_DATA07 0x2a0 0x688 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_D7__SD2_DATA7 0x2a0 0x688 0x000 0x1 0x0 +-#define MX6DL_PAD_NANDF_D7__GPIO2_IO07 0x2a0 0x688 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_RB0__NAND_READY_B 0x2a4 0x68c 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_RB0__GPIO6_IO10 0x2a4 0x68c 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_WP_B__NAND_WP_B 0x2a8 0x690 0x000 0x0 0x0 +-#define MX6DL_PAD_NANDF_WP_B__GPIO6_IO09 0x2a8 0x690 0x000 0x5 0x0 +-#define MX6DL_PAD_NANDF_WP_B__I2C4_SCL 0x2a8 0x690 0x880 0x9 0x2 +-#define MX6DL_PAD_RGMII_RD0__HSI_RX_READY 0x2ac 0x694 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_RD0__RGMII_RD0 0x2ac 0x694 0x818 0x1 0x1 +-#define MX6DL_PAD_RGMII_RD0__GPIO6_IO25 0x2ac 0x694 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_RD1__HSI_TX_FLAG 0x2b0 0x698 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_RD1__RGMII_RD1 0x2b0 0x698 0x81c 0x1 0x1 +-#define MX6DL_PAD_RGMII_RD1__GPIO6_IO27 0x2b0 0x698 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_RD2__HSI_TX_DATA 0x2b4 0x69c 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_RD2__RGMII_RD2 0x2b4 0x69c 0x820 0x1 0x1 +-#define MX6DL_PAD_RGMII_RD2__GPIO6_IO28 0x2b4 0x69c 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_RD3__HSI_TX_WAKE 0x2b8 0x6a0 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_RD3__RGMII_RD3 0x2b8 0x6a0 0x824 0x1 0x1 +-#define MX6DL_PAD_RGMII_RD3__GPIO6_IO29 0x2b8 0x6a0 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_RX_CTL__USB_H3_DATA 0x2bc 0x6a4 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x2bc 0x6a4 0x828 0x1 0x1 +-#define MX6DL_PAD_RGMII_RX_CTL__GPIO6_IO24 0x2bc 0x6a4 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_RXC__USB_H3_STROBE 0x2c0 0x6a8 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_RXC__RGMII_RXC 0x2c0 0x6a8 0x814 0x1 0x1 +-#define MX6DL_PAD_RGMII_RXC__GPIO6_IO30 0x2c0 0x6a8 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_TD0__HSI_TX_READY 0x2c4 0x6ac 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_TD0__RGMII_TD0 0x2c4 0x6ac 0x000 0x1 0x0 +-#define MX6DL_PAD_RGMII_TD0__GPIO6_IO20 0x2c4 0x6ac 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_TD1__HSI_RX_FLAG 0x2c8 0x6b0 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_TD1__RGMII_TD1 0x2c8 0x6b0 0x000 0x1 0x0 +-#define MX6DL_PAD_RGMII_TD1__GPIO6_IO21 0x2c8 0x6b0 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_TD2__HSI_RX_DATA 0x2cc 0x6b4 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_TD2__RGMII_TD2 0x2cc 0x6b4 0x000 0x1 0x0 +-#define MX6DL_PAD_RGMII_TD2__GPIO6_IO22 0x2cc 0x6b4 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_TD3__HSI_RX_WAKE 0x2d0 0x6b8 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_TD3__RGMII_TD3 0x2d0 0x6b8 0x000 0x1 0x0 +-#define MX6DL_PAD_RGMII_TD3__GPIO6_IO23 0x2d0 0x6b8 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_TX_CTL__USB_H2_STROBE 0x2d4 0x6bc 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x2d4 0x6bc 0x000 0x1 0x0 +-#define MX6DL_PAD_RGMII_TX_CTL__GPIO6_IO26 0x2d4 0x6bc 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_TX_CTL__ENET_REF_CLK 0x2d4 0x6bc 0x80c 0x7 0x1 +-#define MX6DL_PAD_RGMII_TXC__USB_H2_DATA 0x2d8 0x6c0 0x000 0x0 0x0 +-#define MX6DL_PAD_RGMII_TXC__RGMII_TXC 0x2d8 0x6c0 0x000 0x1 0x0 +-#define MX6DL_PAD_RGMII_TXC__SPDIF_EXT_CLK 0x2d8 0x6c0 0x8f4 0x2 0x1 +-#define MX6DL_PAD_RGMII_TXC__GPIO6_IO19 0x2d8 0x6c0 0x000 0x5 0x0 +-#define MX6DL_PAD_RGMII_TXC__XTALOSC_REF_CLK_24M 0x2d8 0x6c0 0x000 0x7 0x0 +-#define MX6DL_PAD_SD1_CLK__SD1_CLK 0x2dc 0x6c4 0x928 0x0 0x1 +-#define MX6DL_PAD_SD1_CLK__GPT_CLKIN 0x2dc 0x6c4 0x000 0x3 0x0 +-#define MX6DL_PAD_SD1_CLK__GPIO1_IO20 0x2dc 0x6c4 0x000 0x5 0x0 +-#define MX6DL_PAD_SD1_CMD__SD1_CMD 0x2e0 0x6c8 0x000 0x0 0x0 +-#define MX6DL_PAD_SD1_CMD__PWM4_OUT 0x2e0 0x6c8 0x000 0x2 0x0 +-#define MX6DL_PAD_SD1_CMD__GPT_COMPARE1 0x2e0 0x6c8 0x000 0x3 0x0 +-#define MX6DL_PAD_SD1_CMD__GPIO1_IO18 0x2e0 0x6c8 0x000 0x5 0x0 +-#define MX6DL_PAD_SD1_DAT0__SD1_DATA0 0x2e4 0x6cc 0x000 0x0 0x0 +-#define MX6DL_PAD_SD1_DAT0__GPT_CAPTURE1 0x2e4 0x6cc 0x000 0x3 0x0 +-#define MX6DL_PAD_SD1_DAT0__GPIO1_IO16 0x2e4 0x6cc 0x000 0x5 0x0 +-#define MX6DL_PAD_SD1_DAT1__SD1_DATA1 0x2e8 0x6d0 0x000 0x0 0x0 +-#define MX6DL_PAD_SD1_DAT1__PWM3_OUT 0x2e8 0x6d0 0x000 0x2 0x0 +-#define MX6DL_PAD_SD1_DAT1__GPT_CAPTURE2 0x2e8 0x6d0 0x000 0x3 0x0 +-#define MX6DL_PAD_SD1_DAT1__GPIO1_IO17 0x2e8 0x6d0 0x000 0x5 0x0 +-#define MX6DL_PAD_SD1_DAT2__SD1_DATA2 0x2ec 0x6d4 0x000 0x0 0x0 +-#define MX6DL_PAD_SD1_DAT2__GPT_COMPARE2 0x2ec 0x6d4 0x000 0x2 0x0 +-#define MX6DL_PAD_SD1_DAT2__PWM2_OUT 0x2ec 0x6d4 0x000 0x3 0x0 +-#define MX6DL_PAD_SD1_DAT2__WDOG1_B 0x2ec 0x6d4 0x000 0x4 0x0 +-#define MX6DL_PAD_SD1_DAT2__GPIO1_IO19 0x2ec 0x6d4 0x000 0x5 0x0 +-#define MX6DL_PAD_SD1_DAT2__WDOG1_RESET_B_DEB 0x2ec 0x6d4 0x000 0x6 0x0 +-#define MX6DL_PAD_SD1_DAT3__SD1_DATA3 0x2f0 0x6d8 0x000 0x0 0x0 +-#define MX6DL_PAD_SD1_DAT3__GPT_COMPARE3 0x2f0 0x6d8 0x000 0x2 0x0 +-#define MX6DL_PAD_SD1_DAT3__PWM1_OUT 0x2f0 0x6d8 0x000 0x3 0x0 +-#define MX6DL_PAD_SD1_DAT3__WDOG2_B 0x2f0 0x6d8 0x000 0x4 0x0 +-#define MX6DL_PAD_SD1_DAT3__GPIO1_IO21 0x2f0 0x6d8 0x000 0x5 0x0 +-#define MX6DL_PAD_SD1_DAT3__WDOG2_RESET_B_DEB 0x2f0 0x6d8 0x000 0x6 0x0 +-#define MX6DL_PAD_SD2_CLK__SD2_CLK 0x2f4 0x6dc 0x930 0x0 0x1 +-#define MX6DL_PAD_SD2_CLK__KEY_COL5 0x2f4 0x6dc 0x8c0 0x2 0x3 +-#define MX6DL_PAD_SD2_CLK__AUD4_RXFS 0x2f4 0x6dc 0x7a4 0x3 0x1 +-#define MX6DL_PAD_SD2_CLK__GPIO1_IO10 0x2f4 0x6dc 0x000 0x5 0x0 +-#define MX6DL_PAD_SD2_CMD__SD2_CMD 0x2f8 0x6e0 0x000 0x0 0x0 +-#define MX6DL_PAD_SD2_CMD__KEY_ROW5 0x2f8 0x6e0 0x8cc 0x2 0x2 +-#define MX6DL_PAD_SD2_CMD__AUD4_RXC 0x2f8 0x6e0 0x7a0 0x3 0x1 +-#define MX6DL_PAD_SD2_CMD__GPIO1_IO11 0x2f8 0x6e0 0x000 0x5 0x0 +-#define MX6DL_PAD_SD2_DAT0__SD2_DATA0 0x2fc 0x6e4 0x000 0x0 0x0 +-#define MX6DL_PAD_SD2_DAT0__AUD4_RXD 0x2fc 0x6e4 0x798 0x3 0x1 +-#define MX6DL_PAD_SD2_DAT0__KEY_ROW7 0x2fc 0x6e4 0x8d4 0x4 0x2 +-#define MX6DL_PAD_SD2_DAT0__GPIO1_IO15 0x2fc 0x6e4 0x000 0x5 0x0 +-#define MX6DL_PAD_SD2_DAT0__DCIC2_OUT 0x2fc 0x6e4 0x000 0x6 0x0 +-#define MX6DL_PAD_SD2_DAT1__SD2_DATA1 0x300 0x6e8 0x000 0x0 0x0 +-#define MX6DL_PAD_SD2_DAT1__EIM_CS2_B 0x300 0x6e8 0x000 0x2 0x0 +-#define MX6DL_PAD_SD2_DAT1__AUD4_TXFS 0x300 0x6e8 0x7ac 0x3 0x1 +-#define MX6DL_PAD_SD2_DAT1__KEY_COL7 0x300 0x6e8 0x8c8 0x4 0x2 +-#define MX6DL_PAD_SD2_DAT1__GPIO1_IO14 0x300 0x6e8 0x000 0x5 0x0 +-#define MX6DL_PAD_SD2_DAT2__SD2_DATA2 0x304 0x6ec 0x000 0x0 0x0 +-#define MX6DL_PAD_SD2_DAT2__EIM_CS3_B 0x304 0x6ec 0x000 0x2 0x0 +-#define MX6DL_PAD_SD2_DAT2__AUD4_TXD 0x304 0x6ec 0x79c 0x3 0x1 +-#define MX6DL_PAD_SD2_DAT2__KEY_ROW6 0x304 0x6ec 0x8d0 0x4 0x2 +-#define MX6DL_PAD_SD2_DAT2__GPIO1_IO13 0x304 0x6ec 0x000 0x5 0x0 +-#define MX6DL_PAD_SD2_DAT3__SD2_DATA3 0x308 0x6f0 0x000 0x0 0x0 +-#define MX6DL_PAD_SD2_DAT3__KEY_COL6 0x308 0x6f0 0x8c4 0x2 0x2 +-#define MX6DL_PAD_SD2_DAT3__AUD4_TXC 0x308 0x6f0 0x7a8 0x3 0x1 +-#define MX6DL_PAD_SD2_DAT3__GPIO1_IO12 0x308 0x6f0 0x000 0x5 0x0 +-#define MX6DL_PAD_SD3_CLK__SD3_CLK 0x30c 0x6f4 0x934 0x0 0x1 +-#define MX6DL_PAD_SD3_CLK__UART2_RTS_B 0x30c 0x6f4 0x900 0x1 0x2 +-#define MX6DL_PAD_SD3_CLK__UART2_CTS_B 0x30c 0x6f4 0x000 0x1 0x0 +-#define MX6DL_PAD_SD3_CLK__FLEXCAN1_RX 0x30c 0x6f4 0x7c8 0x2 0x2 +-#define MX6DL_PAD_SD3_CLK__GPIO7_IO03 0x30c 0x6f4 0x000 0x5 0x0 +-#define MX6DL_PAD_SD3_CMD__SD3_CMD 0x310 0x6f8 0x000 0x0 0x0 +-#define MX6DL_PAD_SD3_CMD__UART2_CTS_B 0x310 0x6f8 0x000 0x1 0x0 +-#define MX6DL_PAD_SD3_CMD__UART2_RTS_B 0x310 0x6f8 0x900 0x1 0x3 +-#define MX6DL_PAD_SD3_CMD__FLEXCAN1_TX 0x310 0x6f8 0x000 0x2 0x0 +-#define MX6DL_PAD_SD3_CMD__GPIO7_IO02 0x310 0x6f8 0x000 0x5 0x0 +-#define MX6DL_PAD_SD3_DAT0__SD3_DATA0 0x314 0x6fc 0x000 0x0 0x0 +-#define MX6DL_PAD_SD3_DAT0__UART1_CTS_B 0x314 0x6fc 0x000 0x1 0x0 +-#define MX6DL_PAD_SD3_DAT0__UART1_RTS_B 0x314 0x6fc 0x8f8 0x1 0x2 +-#define MX6DL_PAD_SD3_DAT0__FLEXCAN2_TX 0x314 0x6fc 0x000 0x2 0x0 +-#define MX6DL_PAD_SD3_DAT0__GPIO7_IO04 0x314 0x6fc 0x000 0x5 0x0 +-#define MX6DL_PAD_SD3_DAT1__SD3_DATA1 0x318 0x700 0x000 0x0 0x0 +-#define MX6DL_PAD_SD3_DAT1__UART1_RTS_B 0x318 0x700 0x8f8 0x1 0x3 +-#define MX6DL_PAD_SD3_DAT1__UART1_CTS_B 0x318 0x700 0x000 0x1 0x0 +-#define MX6DL_PAD_SD3_DAT1__FLEXCAN2_RX 0x318 0x700 0x7cc 0x2 0x1 +-#define MX6DL_PAD_SD3_DAT1__GPIO7_IO05 0x318 0x700 0x000 0x5 0x0 +-#define MX6DL_PAD_SD3_DAT2__SD3_DATA2 0x31c 0x704 0x000 0x0 0x0 +-#define MX6DL_PAD_SD3_DAT2__GPIO7_IO06 0x31c 0x704 0x000 0x5 0x0 +-#define MX6DL_PAD_SD3_DAT3__SD3_DATA3 0x320 0x708 0x000 0x0 0x0 +-#define MX6DL_PAD_SD3_DAT3__UART3_CTS_B 0x320 0x708 0x000 0x1 0x0 +-#define MX6DL_PAD_SD3_DAT3__UART3_RTS_B 0x320 0x708 0x908 0x1 0x4 +-#define MX6DL_PAD_SD3_DAT3__GPIO7_IO07 0x320 0x708 0x000 0x5 0x0 +-#define MX6DL_PAD_SD3_DAT4__SD3_DATA4 0x324 0x70c 0x000 0x0 0x0 +-#define MX6DL_PAD_SD3_DAT4__UART2_RX_DATA 0x324 0x70c 0x904 0x1 0x4 +-#define MX6DL_PAD_SD3_DAT4__UART2_TX_DATA 0x324 0x70c 0x000 0x1 0x0 +-#define MX6DL_PAD_SD3_DAT4__GPIO7_IO01 0x324 0x70c 0x000 0x5 0x0 +-#define MX6DL_PAD_SD3_DAT5__SD3_DATA5 0x328 0x710 0x000 0x0 0x0 +-#define MX6DL_PAD_SD3_DAT5__UART2_TX_DATA 0x328 0x710 0x000 0x1 0x0 +-#define MX6DL_PAD_SD3_DAT5__UART2_RX_DATA 0x328 0x710 0x904 0x1 0x5 +-#define MX6DL_PAD_SD3_DAT5__GPIO7_IO00 0x328 0x710 0x000 0x5 0x0 +-#define MX6DL_PAD_SD3_DAT6__SD3_DATA6 0x32c 0x714 0x000 0x0 0x0 +-#define MX6DL_PAD_SD3_DAT6__UART1_RX_DATA 0x32c 0x714 0x8fc 0x1 0x2 +-#define MX6DL_PAD_SD3_DAT6__UART1_TX_DATA 0x32c 0x714 0x000 0x1 0x0 +-#define MX6DL_PAD_SD3_DAT6__GPIO6_IO18 0x32c 0x714 0x000 0x5 0x0 +-#define MX6DL_PAD_SD3_DAT7__SD3_DATA7 0x330 0x718 0x000 0x0 0x0 +-#define MX6DL_PAD_SD3_DAT7__UART1_TX_DATA 0x330 0x718 0x000 0x1 0x0 +-#define MX6DL_PAD_SD3_DAT7__UART1_RX_DATA 0x330 0x718 0x8fc 0x1 0x3 +-#define MX6DL_PAD_SD3_DAT7__GPIO6_IO17 0x330 0x718 0x000 0x5 0x0 +-#define MX6DL_PAD_SD3_RST__SD3_RESET 0x334 0x71c 0x000 0x0 0x0 +-#define MX6DL_PAD_SD3_RST__UART3_RTS_B 0x334 0x71c 0x908 0x1 0x5 +-#define MX6DL_PAD_SD3_RST__UART3_CTS_B 0x334 0x71c 0x000 0x1 0x0 +-#define MX6DL_PAD_SD3_RST__GPIO7_IO08 0x334 0x71c 0x000 0x5 0x0 +-#define MX6DL_PAD_SD4_CLK__SD4_CLK 0x338 0x720 0x938 0x0 0x1 +-#define MX6DL_PAD_SD4_CLK__NAND_WE_B 0x338 0x720 0x000 0x1 0x0 +-#define MX6DL_PAD_SD4_CLK__UART3_RX_DATA 0x338 0x720 0x90c 0x2 0x2 +-#define MX6DL_PAD_SD4_CLK__UART3_TX_DATA 0x338 0x720 0x000 0x2 0x0 +-#define MX6DL_PAD_SD4_CLK__GPIO7_IO10 0x338 0x720 0x000 0x5 0x0 +-#define MX6DL_PAD_SD4_CMD__SD4_CMD 0x33c 0x724 0x000 0x0 0x0 +-#define MX6DL_PAD_SD4_CMD__NAND_RE_B 0x33c 0x724 0x000 0x1 0x0 +-#define MX6DL_PAD_SD4_CMD__UART3_TX_DATA 0x33c 0x724 0x000 0x2 0x0 +-#define MX6DL_PAD_SD4_CMD__UART3_RX_DATA 0x33c 0x724 0x90c 0x2 0x3 +-#define MX6DL_PAD_SD4_CMD__GPIO7_IO09 0x33c 0x724 0x000 0x5 0x0 +-#define MX6DL_PAD_SD4_DAT0__SD4_DATA0 0x340 0x728 0x000 0x1 0x0 +-#define MX6DL_PAD_SD4_DAT0__NAND_DQS 0x340 0x728 0x000 0x2 0x0 +-#define MX6DL_PAD_SD4_DAT0__GPIO2_IO08 0x340 0x728 0x000 0x5 0x0 +-#define MX6DL_PAD_SD4_DAT1__SD4_DATA1 0x344 0x72c 0x000 0x1 0x0 +-#define MX6DL_PAD_SD4_DAT1__PWM3_OUT 0x344 0x72c 0x000 0x2 0x0 +-#define MX6DL_PAD_SD4_DAT1__GPIO2_IO09 0x344 0x72c 0x000 0x5 0x0 +-#define MX6DL_PAD_SD4_DAT2__SD4_DATA2 0x348 0x730 0x000 0x1 0x0 +-#define MX6DL_PAD_SD4_DAT2__PWM4_OUT 0x348 0x730 0x000 0x2 0x0 +-#define MX6DL_PAD_SD4_DAT2__GPIO2_IO10 0x348 0x730 0x000 0x5 0x0 +-#define MX6DL_PAD_SD4_DAT3__SD4_DATA3 0x34c 0x734 0x000 0x1 0x0 +-#define MX6DL_PAD_SD4_DAT3__GPIO2_IO11 0x34c 0x734 0x000 0x5 0x0 +-#define MX6DL_PAD_SD4_DAT4__SD4_DATA4 0x350 0x738 0x000 0x1 0x0 +-#define MX6DL_PAD_SD4_DAT4__UART2_RX_DATA 0x350 0x738 0x904 0x2 0x6 +-#define MX6DL_PAD_SD4_DAT4__UART2_TX_DATA 0x350 0x738 0x000 0x2 0x0 +-#define MX6DL_PAD_SD4_DAT4__GPIO2_IO12 0x350 0x738 0x000 0x5 0x0 +-#define MX6DL_PAD_SD4_DAT5__SD4_DATA5 0x354 0x73c 0x000 0x1 0x0 +-#define MX6DL_PAD_SD4_DAT5__UART2_RTS_B 0x354 0x73c 0x900 0x2 0x4 +-#define MX6DL_PAD_SD4_DAT5__UART2_CTS_B 0x354 0x73c 0x000 0x2 0x0 +-#define MX6DL_PAD_SD4_DAT5__GPIO2_IO13 0x354 0x73c 0x000 0x5 0x0 +-#define MX6DL_PAD_SD4_DAT6__SD4_DATA6 0x358 0x740 0x000 0x1 0x0 +-#define MX6DL_PAD_SD4_DAT6__UART2_CTS_B 0x358 0x740 0x000 0x2 0x0 +-#define MX6DL_PAD_SD4_DAT6__UART2_RTS_B 0x358 0x740 0x900 0x2 0x5 +-#define MX6DL_PAD_SD4_DAT6__GPIO2_IO14 0x358 0x740 0x000 0x5 0x0 +-#define MX6DL_PAD_SD4_DAT7__SD4_DATA7 0x35c 0x744 0x000 0x1 0x0 +-#define MX6DL_PAD_SD4_DAT7__UART2_TX_DATA 0x35c 0x744 0x000 0x2 0x0 +-#define MX6DL_PAD_SD4_DAT7__UART2_RX_DATA 0x35c 0x744 0x904 0x2 0x7 +-#define MX6DL_PAD_SD4_DAT7__GPIO2_IO15 0x35c 0x744 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__IPU1_CSI0_DATA10 0x04c 0x360 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__AUD3_RXC 0x04c 0x360 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__ECSPI2_MISO 0x04c 0x360 0x7f8 0x2 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x04c 0x360 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__UART1_RX_DATA 0x04c 0x360 0x8fc 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__GPIO5_IO28 0x04c 0x360 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__ARM_TRACE07 0x04c 0x360 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT11__IPU1_CSI0_DATA11 0x050 0x364 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT11__AUD3_RXFS 0x050 0x364 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT11__ECSPI2_SS0 0x050 0x364 0x800 0x2 0x0 ++#define MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x050 0x364 0x8fc 0x3 0x1 ++#define MX6QDL_PAD_CSI0_DAT11__UART1_TX_DATA 0x050 0x364 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT11__GPIO5_IO29 0x050 0x364 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT11__ARM_TRACE08 0x050 0x364 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x054 0x368 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT12__EIM_DATA08 0x054 0x368 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x054 0x368 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT12__UART4_RX_DATA 0x054 0x368 0x914 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT12__GPIO5_IO30 0x054 0x368 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT12__ARM_TRACE09 0x054 0x368 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x058 0x36c 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT13__EIM_DATA09 0x058 0x36c 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x058 0x36c 0x914 0x3 0x1 ++#define MX6QDL_PAD_CSI0_DAT13__UART4_TX_DATA 0x058 0x36c 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31 0x058 0x36c 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT13__ARM_TRACE10 0x058 0x36c 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x05c 0x370 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT14__EIM_DATA10 0x05c 0x370 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT14__UART5_TX_DATA 0x05c 0x370 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT14__UART5_RX_DATA 0x05c 0x370 0x91c 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x05c 0x370 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT14__ARM_TRACE11 0x05c 0x370 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x060 0x374 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT15__EIM_DATA11 0x060 0x374 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT15__UART5_RX_DATA 0x060 0x374 0x91c 0x3 0x1 ++#define MX6QDL_PAD_CSI0_DAT15__UART5_TX_DATA 0x060 0x374 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 0x060 0x374 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT15__ARM_TRACE12 0x060 0x374 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x064 0x378 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__EIM_DATA12 0x064 0x378 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x064 0x378 0x910 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__UART4_CTS_B 0x064 0x378 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__GPIO6_IO02 0x064 0x378 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__ARM_TRACE13 0x064 0x378 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x068 0x37c 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT17__EIM_DATA13 0x068 0x37c 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x068 0x37c 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT17__UART4_RTS_B 0x068 0x37c 0x910 0x3 0x1 ++#define MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 0x068 0x37c 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT17__ARM_TRACE14 0x068 0x37c 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x06c 0x380 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT18__EIM_DATA14 0x06c 0x380 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT18__UART5_RTS_B 0x06c 0x380 0x918 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT18__UART5_CTS_B 0x06c 0x380 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x06c 0x380 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT18__ARM_TRACE15 0x06c 0x380 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x070 0x384 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT19__EIM_DATA15 0x070 0x384 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT19__UART5_CTS_B 0x070 0x384 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT19__UART5_RTS_B 0x070 0x384 0x918 0x3 0x1 ++#define MX6QDL_PAD_CSI0_DAT19__GPIO6_IO05 0x070 0x384 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__IPU1_CSI0_DATA04 0x074 0x388 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__EIM_DATA02 0x074 0x388 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__ECSPI1_SCLK 0x074 0x388 0x7d8 0x2 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__KEY_COL5 0x074 0x388 0x8c0 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x074 0x388 0x000 0x4 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__GPIO5_IO22 0x074 0x388 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__ARM_TRACE01 0x074 0x388 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__IPU1_CSI0_DATA05 0x078 0x38c 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__EIM_DATA03 0x078 0x38c 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__ECSPI1_MOSI 0x078 0x38c 0x7e0 0x2 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__KEY_ROW5 0x078 0x38c 0x8cc 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x078 0x38c 0x000 0x4 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__GPIO5_IO23 0x078 0x38c 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__ARM_TRACE02 0x078 0x38c 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__IPU1_CSI0_DATA06 0x07c 0x390 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__EIM_DATA04 0x07c 0x390 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__ECSPI1_MISO 0x07c 0x390 0x7dc 0x2 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__KEY_COL6 0x07c 0x390 0x8c4 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x07c 0x390 0x000 0x4 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__GPIO5_IO24 0x07c 0x390 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__ARM_TRACE03 0x07c 0x390 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__IPU1_CSI0_DATA07 0x080 0x394 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__EIM_DATA05 0x080 0x394 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__ECSPI1_SS0 0x080 0x394 0x7e4 0x2 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__KEY_ROW6 0x080 0x394 0x8d0 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x080 0x394 0x000 0x4 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__GPIO5_IO25 0x080 0x394 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__ARM_TRACE04 0x080 0x394 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT8__IPU1_CSI0_DATA08 0x084 0x398 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT8__EIM_DATA06 0x084 0x398 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT8__ECSPI2_SCLK 0x084 0x398 0x7f4 0x2 0x0 ++#define MX6QDL_PAD_CSI0_DAT8__KEY_COL7 0x084 0x398 0x8c8 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x084 0x398 0x86c 0x4 0x0 ++#define MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x084 0x398 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT8__ARM_TRACE05 0x084 0x398 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT9__IPU1_CSI0_DATA09 0x088 0x39c 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT9__EIM_DATA07 0x088 0x39c 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT9__ECSPI2_MOSI 0x088 0x39c 0x7fc 0x2 0x0 ++#define MX6QDL_PAD_CSI0_DAT9__KEY_ROW7 0x088 0x39c 0x8d4 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x088 0x39c 0x868 0x4 0x0 ++#define MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x088 0x39c 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT9__ARM_TRACE06 0x088 0x39c 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN 0x08c 0x3a0 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DATA_EN__EIM_DATA00 0x08c 0x3a0 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x08c 0x3a0 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DATA_EN__ARM_TRACE_CLK 0x08c 0x3a0 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x090 0x3a4 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_MCLK__CCM_CLKO1 0x090 0x3a4 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_MCLK__GPIO5_IO19 0x090 0x3a4 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_MCLK__ARM_TRACE_CTL 0x090 0x3a4 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x094 0x3a8 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18 0x094 0x3a8 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_PIXCLK__ARM_EVENTO 0x094 0x3a8 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x098 0x3ac 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_VSYNC__EIM_DATA01 0x098 0x3ac 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21 0x098 0x3ac 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_VSYNC__ARM_TRACE00 0x098 0x3ac 0x000 0x7 0x0 ++#define MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x09c 0x3b0 0x000 0x0 0x0 ++#define MX6QDL_PAD_DI0_DISP_CLK__LCD_CLK 0x09c 0x3b0 0x000 0x1 0x0 ++#define MX6QDL_PAD_DI0_DISP_CLK__GPIO4_IO16 0x09c 0x3b0 0x000 0x5 0x0 ++#define MX6QDL_PAD_DI0_DISP_CLK__LCD_WR_RWN 0x09c 0x3b0 0x000 0x8 0x0 ++#define MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x0a0 0x3b4 0x000 0x0 0x0 ++#define MX6QDL_PAD_DI0_PIN15__LCD_ENABLE 0x0a0 0x3b4 0x000 0x1 0x0 ++#define MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x0a0 0x3b4 0x000 0x2 0x0 ++#define MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x0a0 0x3b4 0x000 0x5 0x0 ++#define MX6QDL_PAD_DI0_PIN15__LCD_RD_E 0x0a0 0x3b4 0x000 0x8 0x0 ++#define MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x0a4 0x3b8 0x000 0x0 0x0 ++#define MX6QDL_PAD_DI0_PIN2__LCD_HSYNC 0x0a4 0x3b8 0x8d8 0x1 0x0 ++#define MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x0a4 0x3b8 0x000 0x2 0x0 ++#define MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x0a4 0x3b8 0x000 0x5 0x0 ++#define MX6QDL_PAD_DI0_PIN2__LCD_RS 0x0a4 0x3b8 0x000 0x8 0x0 ++#define MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x0a8 0x3bc 0x000 0x0 0x0 ++#define MX6QDL_PAD_DI0_PIN3__LCD_VSYNC 0x0a8 0x3bc 0x000 0x1 0x0 ++#define MX6QDL_PAD_DI0_PIN3__AUD6_TXFS 0x0a8 0x3bc 0x000 0x2 0x0 ++#define MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x0a8 0x3bc 0x000 0x5 0x0 ++#define MX6QDL_PAD_DI0_PIN3__LCD_CS 0x0a8 0x3bc 0x000 0x8 0x0 ++#define MX6QDL_PAD_DI0_PIN4__IPU1_DI0_PIN04 0x0ac 0x3c0 0x000 0x0 0x0 ++#define MX6QDL_PAD_DI0_PIN4__LCD_BUSY 0x0ac 0x3c0 0x8d8 0x1 0x1 ++#define MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x0ac 0x3c0 0x000 0x2 0x0 ++#define MX6QDL_PAD_DI0_PIN4__SD1_WP 0x0ac 0x3c0 0x92c 0x3 0x0 ++#define MX6QDL_PAD_DI0_PIN4__GPIO4_IO20 0x0ac 0x3c0 0x000 0x5 0x0 ++#define MX6QDL_PAD_DI0_PIN4__LCD_RESET 0x0ac 0x3c0 0x000 0x8 0x0 ++#define MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x0b0 0x3c4 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT0__LCD_DATA00 0x0b0 0x3c4 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x0b0 0x3c4 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT0__GPIO4_IO21 0x0b0 0x3c4 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x0b4 0x3c8 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT1__LCD_DATA01 0x0b4 0x3c8 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x0b4 0x3c8 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT1__GPIO4_IO22 0x0b4 0x3c8 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x0b8 0x3cc 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT10__LCD_DATA10 0x0b8 0x3cc 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT10__GPIO4_IO31 0x0b8 0x3cc 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x0bc 0x3d0 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT11__LCD_DATA11 0x0bc 0x3d0 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x0bc 0x3d0 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x0c0 0x3d4 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT12__LCD_DATA12 0x0c0 0x3d4 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT12__GPIO5_IO06 0x0c0 0x3d4 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x0c4 0x3d8 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT13__LCD_DATA13 0x0c4 0x3d8 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT13__AUD5_RXFS 0x0c4 0x3d8 0x7bc 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT13__GPIO5_IO07 0x0c4 0x3d8 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x0c8 0x3dc 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT14__LCD_DATA14 0x0c8 0x3dc 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT14__AUD5_RXC 0x0c8 0x3dc 0x7b8 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT14__GPIO5_IO08 0x0c8 0x3dc 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x0cc 0x3e0 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT15__LCD_DATA15 0x0cc 0x3e0 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT15__ECSPI1_SS1 0x0cc 0x3e0 0x7e8 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT15__ECSPI2_SS1 0x0cc 0x3e0 0x804 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT15__GPIO5_IO09 0x0cc 0x3e0 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x0d0 0x3e4 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT16__LCD_DATA16 0x0d0 0x3e4 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT16__ECSPI2_MOSI 0x0d0 0x3e4 0x7fc 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT16__AUD5_TXC 0x0d0 0x3e4 0x7c0 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT16__SDMA_EXT_EVENT0 0x0d0 0x3e4 0x8e8 0x4 0x0 ++#define MX6QDL_PAD_DISP0_DAT16__GPIO5_IO10 0x0d0 0x3e4 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x0d4 0x3e8 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT17__LCD_DATA17 0x0d4 0x3e8 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT17__ECSPI2_MISO 0x0d4 0x3e8 0x7f8 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT17__AUD5_TXD 0x0d4 0x3e8 0x7b4 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT17__SDMA_EXT_EVENT1 0x0d4 0x3e8 0x8ec 0x4 0x0 ++#define MX6QDL_PAD_DISP0_DAT17__GPIO5_IO11 0x0d4 0x3e8 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x0d8 0x3ec 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__LCD_DATA18 0x0d8 0x3ec 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__ECSPI2_SS0 0x0d8 0x3ec 0x800 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS 0x0d8 0x3ec 0x7c4 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__AUD4_RXFS 0x0d8 0x3ec 0x7a4 0x4 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12 0x0d8 0x3ec 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__EIM_CS2_B 0x0d8 0x3ec 0x000 0x7 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x0dc 0x3f0 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__LCD_DATA19 0x0dc 0x3f0 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__ECSPI2_SCLK 0x0dc 0x3f0 0x7f4 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x0dc 0x3f0 0x7b0 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__AUD4_RXC 0x0dc 0x3f0 0x7a0 0x4 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__GPIO5_IO13 0x0dc 0x3f0 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__EIM_CS3_B 0x0dc 0x3f0 0x000 0x7 0x0 ++#define MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x0e0 0x3f4 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT2__LCD_DATA02 0x0e0 0x3f4 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x0e0 0x3f4 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT2__GPIO4_IO23 0x0e0 0x3f4 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x0e4 0x3f8 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT20__LCD_DATA20 0x0e4 0x3f8 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT20__ECSPI1_SCLK 0x0e4 0x3f8 0x7d8 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT20__AUD4_TXC 0x0e4 0x3f8 0x7a8 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14 0x0e4 0x3f8 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x0e8 0x3fc 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT21__LCD_DATA21 0x0e8 0x3fc 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT21__ECSPI1_MOSI 0x0e8 0x3fc 0x7e0 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT21__AUD4_TXD 0x0e8 0x3fc 0x79c 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15 0x0e8 0x3fc 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x0ec 0x400 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT22__LCD_DATA22 0x0ec 0x400 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT22__ECSPI1_MISO 0x0ec 0x400 0x7dc 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT22__AUD4_TXFS 0x0ec 0x400 0x7ac 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT22__GPIO5_IO16 0x0ec 0x400 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x0f0 0x404 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT23__LCD_DATA23 0x0f0 0x404 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT23__ECSPI1_SS0 0x0f0 0x404 0x7e4 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT23__AUD4_RXD 0x0f0 0x404 0x798 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x0f0 0x404 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x0f4 0x408 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT3__LCD_DATA03 0x0f4 0x408 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT3__ECSPI3_SS0 0x0f4 0x408 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x0f4 0x408 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x0f8 0x40c 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT4__LCD_DATA04 0x0f8 0x40c 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT4__ECSPI3_SS1 0x0f8 0x40c 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT4__GPIO4_IO25 0x0f8 0x40c 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x0fc 0x410 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT5__LCD_DATA05 0x0fc 0x410 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT5__ECSPI3_SS2 0x0fc 0x410 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT5__AUD6_RXFS 0x0fc 0x410 0x000 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26 0x0fc 0x410 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x100 0x414 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT6__LCD_DATA06 0x100 0x414 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT6__ECSPI3_SS3 0x100 0x414 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT6__AUD6_RXC 0x100 0x414 0x000 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT6__GPIO4_IO27 0x100 0x414 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x104 0x418 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT7__LCD_DATA07 0x104 0x418 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT7__ECSPI3_RDY 0x104 0x418 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT7__GPIO4_IO28 0x104 0x418 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x108 0x41c 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT8__LCD_DATA08 0x108 0x41c 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x108 0x41c 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x108 0x41c 0x000 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT8__GPIO4_IO29 0x108 0x41c 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10c 0x420 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT9__LCD_DATA09 0x10c 0x420 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT9__PWM2_OUT 0x10c 0x420 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT9__WDOG2_B 0x10c 0x420 0x000 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x10c 0x420 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A16__EIM_ADDR16 0x110 0x4e0 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A16__IPU1_DI1_DISP_CLK 0x110 0x4e0 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A16__IPU1_CSI1_PIXCLK 0x110 0x4e0 0x8b8 0x2 0x0 ++#define MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x110 0x4e0 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A16__SRC_BOOT_CFG16 0x110 0x4e0 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A16__EPDC_DATA00 0x110 0x4e0 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_A17__EIM_ADDR17 0x114 0x4e4 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A17__IPU1_DISP1_DATA12 0x114 0x4e4 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A17__IPU1_CSI1_DATA12 0x114 0x4e4 0x890 0x2 0x0 ++#define MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x114 0x4e4 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A17__SRC_BOOT_CFG17 0x114 0x4e4 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A17__EPDC_PWR_STAT 0x114 0x4e4 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_A18__EIM_ADDR18 0x118 0x4e8 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A18__IPU1_DISP1_DATA13 0x118 0x4e8 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A18__IPU1_CSI1_DATA13 0x118 0x4e8 0x894 0x2 0x0 ++#define MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x118 0x4e8 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A18__SRC_BOOT_CFG18 0x118 0x4e8 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A18__EPDC_PWR_CTRL0 0x118 0x4e8 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_A19__EIM_ADDR19 0x11c 0x4ec 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A19__IPU1_DISP1_DATA14 0x11c 0x4ec 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A19__IPU1_CSI1_DATA14 0x11c 0x4ec 0x898 0x2 0x0 ++#define MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x11c 0x4ec 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A19__SRC_BOOT_CFG19 0x11c 0x4ec 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A19__EPDC_PWR_CTRL1 0x11c 0x4ec 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_A20__EIM_ADDR20 0x120 0x4f0 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A20__IPU1_DISP1_DATA15 0x120 0x4f0 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A20__IPU1_CSI1_DATA15 0x120 0x4f0 0x89c 0x2 0x0 ++#define MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x120 0x4f0 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A20__SRC_BOOT_CFG20 0x120 0x4f0 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A20__EPDC_PWR_CTRL2 0x120 0x4f0 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_A21__EIM_ADDR21 0x124 0x4f4 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A21__IPU1_DISP1_DATA16 0x124 0x4f4 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A21__IPU1_CSI1_DATA16 0x124 0x4f4 0x8a0 0x2 0x0 ++#define MX6QDL_PAD_EIM_A21__GPIO2_IO17 0x124 0x4f4 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A21__SRC_BOOT_CFG21 0x124 0x4f4 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A21__EPDC_GDCLK 0x124 0x4f4 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_A22__EIM_ADDR22 0x128 0x4f8 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A22__IPU1_DISP1_DATA17 0x128 0x4f8 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A22__IPU1_CSI1_DATA17 0x128 0x4f8 0x8a4 0x2 0x0 ++#define MX6QDL_PAD_EIM_A22__GPIO2_IO16 0x128 0x4f8 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A22__SRC_BOOT_CFG22 0x128 0x4f8 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A22__EPDC_GDSP 0x128 0x4f8 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_A23__EIM_ADDR23 0x12c 0x4fc 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A23__IPU1_DISP1_DATA18 0x12c 0x4fc 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A23__IPU1_CSI1_DATA18 0x12c 0x4fc 0x8a8 0x2 0x0 ++#define MX6QDL_PAD_EIM_A23__IPU1_SISG3 0x12c 0x4fc 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_A23__GPIO6_IO06 0x12c 0x4fc 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A23__SRC_BOOT_CFG23 0x12c 0x4fc 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A23__EPDC_GDOE 0x12c 0x4fc 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_A24__EIM_ADDR24 0x130 0x500 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A24__IPU1_DISP1_DATA19 0x130 0x500 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A24__IPU1_CSI1_DATA19 0x130 0x500 0x8ac 0x2 0x0 ++#define MX6QDL_PAD_EIM_A24__IPU1_SISG2 0x130 0x500 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x130 0x500 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A24__SRC_BOOT_CFG24 0x130 0x500 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A24__EPDC_GDRL 0x130 0x500 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_A25__EIM_ADDR25 0x134 0x504 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A25__ECSPI4_SS1 0x134 0x504 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A25__ECSPI2_RDY 0x134 0x504 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_A25__IPU1_DI1_PIN12 0x134 0x504 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_A25__IPU1_DI0_D1_CS 0x134 0x504 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x134 0x504 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x134 0x504 0x85c 0x6 0x0 ++#define MX6QDL_PAD_EIM_A25__EPDC_DATA15 0x134 0x504 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_A25__EIM_ACLK_FREERUN 0x134 0x504 0x000 0x9 0x0 ++#define MX6QDL_PAD_EIM_BCLK__EIM_BCLK 0x138 0x508 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_BCLK__IPU1_DI1_PIN16 0x138 0x508 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x138 0x508 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_BCLK__EPDC_SDCE9 0x138 0x508 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_CS0__EIM_CS0_B 0x13c 0x50c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_CS0__IPU1_DI1_PIN05 0x13c 0x50c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x13c 0x50c 0x7f4 0x2 0x2 ++#define MX6QDL_PAD_EIM_CS0__GPIO2_IO23 0x13c 0x50c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_CS0__EPDC_DATA06 0x13c 0x50c 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_CS1__EIM_CS1_B 0x140 0x510 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_CS1__IPU1_DI1_PIN06 0x140 0x510 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x140 0x510 0x7fc 0x2 0x2 ++#define MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x140 0x510 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_CS1__EPDC_DATA08 0x140 0x510 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D16__EIM_DATA16 0x144 0x514 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x144 0x514 0x7d8 0x1 0x2 ++#define MX6QDL_PAD_EIM_D16__IPU1_DI0_PIN05 0x144 0x514 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D16__IPU1_CSI1_DATA18 0x144 0x514 0x8a8 0x3 0x1 ++#define MX6QDL_PAD_EIM_D16__HDMI_TX_DDC_SDA 0x144 0x514 0x864 0x4 0x0 ++#define MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x144 0x514 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D16__I2C2_SDA 0x144 0x514 0x874 0x6 0x0 ++#define MX6QDL_PAD_EIM_D16__EPDC_DATA10 0x144 0x514 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D17__EIM_DATA17 0x148 0x518 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x148 0x518 0x7dc 0x1 0x2 ++#define MX6QDL_PAD_EIM_D17__IPU1_DI0_PIN06 0x148 0x518 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D17__IPU1_CSI1_PIXCLK 0x148 0x518 0x8b8 0x3 0x1 ++#define MX6QDL_PAD_EIM_D17__DCIC1_OUT 0x148 0x518 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D17__GPIO3_IO17 0x148 0x518 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D17__I2C3_SCL 0x148 0x518 0x878 0x6 0x0 ++#define MX6QDL_PAD_EIM_D17__EPDC_VCOM0 0x148 0x518 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D18__EIM_DATA18 0x14c 0x51c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x14c 0x51c 0x7e0 0x1 0x2 ++#define MX6QDL_PAD_EIM_D18__IPU1_DI0_PIN07 0x14c 0x51c 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D18__IPU1_CSI1_DATA17 0x14c 0x51c 0x8a4 0x3 0x1 ++#define MX6QDL_PAD_EIM_D18__IPU1_DI1_D0_CS 0x14c 0x51c 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D18__GPIO3_IO18 0x14c 0x51c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D18__I2C3_SDA 0x14c 0x51c 0x87c 0x6 0x0 ++#define MX6QDL_PAD_EIM_D18__EPDC_VCOM1 0x14c 0x51c 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D19__EIM_DATA19 0x150 0x520 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D19__ECSPI1_SS1 0x150 0x520 0x7e8 0x1 0x1 ++#define MX6QDL_PAD_EIM_D19__IPU1_DI0_PIN08 0x150 0x520 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D19__IPU1_CSI1_DATA16 0x150 0x520 0x8a0 0x3 0x1 ++#define MX6QDL_PAD_EIM_D19__UART1_CTS_B 0x150 0x520 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D19__UART1_RTS_B 0x150 0x520 0x8f8 0x4 0x0 ++#define MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x150 0x520 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D19__EPIT1_OUT 0x150 0x520 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D19__EPDC_DATA12 0x150 0x520 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D20__EIM_DATA20 0x154 0x524 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D20__ECSPI4_SS0 0x154 0x524 0x808 0x1 0x0 ++#define MX6QDL_PAD_EIM_D20__IPU1_DI0_PIN16 0x154 0x524 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D20__IPU1_CSI1_DATA15 0x154 0x524 0x89c 0x3 0x1 ++#define MX6QDL_PAD_EIM_D20__UART1_RTS_B 0x154 0x524 0x8f8 0x4 0x1 ++#define MX6QDL_PAD_EIM_D20__UART1_CTS_B 0x154 0x524 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x154 0x524 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D20__EPIT2_OUT 0x154 0x524 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D21__EIM_DATA21 0x158 0x528 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D21__ECSPI4_SCLK 0x158 0x528 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D21__IPU1_DI0_PIN17 0x158 0x528 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D21__IPU1_CSI1_DATA11 0x158 0x528 0x88c 0x3 0x0 ++#define MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x158 0x528 0x920 0x4 0x0 ++#define MX6QDL_PAD_EIM_D21__GPIO3_IO21 0x158 0x528 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D21__I2C1_SCL 0x158 0x528 0x868 0x6 0x1 ++#define MX6QDL_PAD_EIM_D21__SPDIF_IN 0x158 0x528 0x8f0 0x7 0x0 ++#define MX6QDL_PAD_EIM_D22__EIM_DATA22 0x15c 0x52c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D22__ECSPI4_MISO 0x15c 0x52c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D22__IPU1_DI0_PIN01 0x15c 0x52c 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D22__IPU1_CSI1_DATA10 0x15c 0x52c 0x888 0x3 0x0 ++#define MX6QDL_PAD_EIM_D22__USB_OTG_PWR 0x15c 0x52c 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x15c 0x52c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D22__SPDIF_OUT 0x15c 0x52c 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D22__EPDC_SDCE6 0x15c 0x52c 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D23__EIM_DATA23 0x160 0x530 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D23__IPU1_DI0_D0_CS 0x160 0x530 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x160 0x530 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D23__UART3_RTS_B 0x160 0x530 0x908 0x2 0x0 ++#define MX6QDL_PAD_EIM_D23__UART1_DCD_B 0x160 0x530 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_D23__IPU1_CSI1_DATA_EN 0x160 0x530 0x8b0 0x4 0x0 ++#define MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x160 0x530 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D23__IPU1_DI1_PIN02 0x160 0x530 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D23__IPU1_DI1_PIN14 0x160 0x530 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D23__EPDC_DATA11 0x160 0x530 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D24__EIM_DATA24 0x164 0x534 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D24__ECSPI4_SS2 0x164 0x534 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x164 0x534 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D24__UART3_RX_DATA 0x164 0x534 0x90c 0x2 0x0 ++#define MX6QDL_PAD_EIM_D24__ECSPI1_SS2 0x164 0x534 0x7ec 0x3 0x0 ++#define MX6QDL_PAD_EIM_D24__ECSPI2_SS2 0x164 0x534 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D24__GPIO3_IO24 0x164 0x534 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D24__AUD5_RXFS 0x164 0x534 0x7bc 0x6 0x1 ++#define MX6QDL_PAD_EIM_D24__UART1_DTR_B 0x164 0x534 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D24__EPDC_SDCE7 0x164 0x534 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D25__EIM_DATA25 0x168 0x538 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D25__ECSPI4_SS3 0x168 0x538 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x168 0x538 0x90c 0x2 0x1 ++#define MX6QDL_PAD_EIM_D25__UART3_TX_DATA 0x168 0x538 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D25__ECSPI1_SS3 0x168 0x538 0x7f0 0x3 0x0 ++#define MX6QDL_PAD_EIM_D25__ECSPI2_SS3 0x168 0x538 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D25__GPIO3_IO25 0x168 0x538 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D25__AUD5_RXC 0x168 0x538 0x7b8 0x6 0x1 ++#define MX6QDL_PAD_EIM_D25__UART1_DSR_B 0x168 0x538 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D25__EPDC_SDCE8 0x168 0x538 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D26__EIM_DATA26 0x16c 0x53c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D26__IPU1_DI1_PIN11 0x16c 0x53c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D26__IPU1_CSI0_DATA01 0x16c 0x53c 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D26__IPU1_CSI1_DATA14 0x16c 0x53c 0x898 0x3 0x1 ++#define MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x16c 0x53c 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D26__UART2_RX_DATA 0x16c 0x53c 0x904 0x4 0x0 ++#define MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x16c 0x53c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D26__IPU1_SISG2 0x16c 0x53c 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D26__IPU1_DISP1_DATA22 0x16c 0x53c 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D26__EPDC_SDOED 0x16c 0x53c 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D27__EIM_DATA27 0x170 0x540 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D27__IPU1_DI1_PIN13 0x170 0x540 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D27__IPU1_CSI0_DATA00 0x170 0x540 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D27__IPU1_CSI1_DATA13 0x170 0x540 0x894 0x3 0x1 ++#define MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x170 0x540 0x904 0x4 0x1 ++#define MX6QDL_PAD_EIM_D27__UART2_TX_DATA 0x170 0x540 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D27__GPIO3_IO27 0x170 0x540 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D27__IPU1_SISG3 0x170 0x540 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D27__IPU1_DISP1_DATA23 0x170 0x540 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D27__EPDC_SDOE 0x170 0x540 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D28__EIM_DATA28 0x174 0x544 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D28__I2C1_SDA 0x174 0x544 0x86c 0x1 0x1 ++#define MX6QDL_PAD_EIM_D28__ECSPI4_MOSI 0x174 0x544 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D28__IPU1_CSI1_DATA12 0x174 0x544 0x890 0x3 0x1 ++#define MX6QDL_PAD_EIM_D28__UART2_CTS_B 0x174 0x544 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D28__UART2_RTS_B 0x174 0x544 0x900 0x4 0x0 ++#define MX6QDL_PAD_EIM_D28__UART2_DTE_CTS_B 0x174 0x544 0x900 0x4 0x0 ++#define MX6QDL_PAD_EIM_D28__UART2_DTE_RTS_B 0x174 0x544 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x174 0x544 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D28__IPU1_EXT_TRIG 0x174 0x544 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D28__IPU1_DI0_PIN13 0x174 0x544 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D28__EPDC_PWR_CTRL3 0x174 0x544 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D29__EIM_DATA29 0x178 0x548 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D29__IPU1_DI1_PIN15 0x178 0x548 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D29__ECSPI4_SS0 0x178 0x548 0x808 0x2 0x1 ++#define MX6QDL_PAD_EIM_D29__UART2_RTS_B 0x178 0x548 0x900 0x4 0x1 ++#define MX6QDL_PAD_EIM_D29__UART2_CTS_B 0x178 0x548 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D29__UART2_DTE_RTS_B 0x178 0x548 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D29__UART2_DTE_CTS_B 0x178 0x548 0x900 0x4 0x1 ++#define MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x178 0x548 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D29__IPU1_CSI1_VSYNC 0x178 0x548 0x8bc 0x6 0x0 ++#define MX6QDL_PAD_EIM_D29__IPU1_DI0_PIN14 0x178 0x548 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D29__EPDC_PWR_WAKE 0x178 0x548 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D30__EIM_DATA30 0x17c 0x54c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D30__IPU1_DISP1_DATA21 0x17c 0x54c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D30__IPU1_DI0_PIN11 0x17c 0x54c 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D30__IPU1_CSI0_DATA03 0x17c 0x54c 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_D30__UART3_CTS_B 0x17c 0x54c 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D30__UART3_RTS_B 0x17c 0x54c 0x908 0x4 0x1 ++#define MX6QDL_PAD_EIM_D30__GPIO3_IO30 0x17c 0x54c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D30__USB_H1_OC 0x17c 0x54c 0x924 0x6 0x0 ++#define MX6QDL_PAD_EIM_D30__EPDC_SDOEZ 0x17c 0x54c 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D31__EIM_DATA31 0x180 0x550 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D31__IPU1_DISP1_DATA20 0x180 0x550 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D31__IPU1_DI0_PIN12 0x180 0x550 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D31__IPU1_CSI0_DATA02 0x180 0x550 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x180 0x550 0x908 0x4 0x2 ++#define MX6QDL_PAD_EIM_D31__UART3_CTS_B 0x180 0x550 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x180 0x550 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D31__USB_H1_PWR 0x180 0x550 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D31__EPDC_SDCLK_P 0x180 0x550 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_D31__EIM_ACLK_FREERUN 0x180 0x550 0x000 0x9 0x0 ++#define MX6QDL_PAD_EIM_DA0__EIM_AD00 0x184 0x554 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA0__IPU1_DISP1_DATA09 0x184 0x554 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA0__IPU1_CSI1_DATA09 0x184 0x554 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x184 0x554 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA0__SRC_BOOT_CFG00 0x184 0x554 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA0__EPDC_SDCLK_N 0x184 0x554 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA1__EIM_AD01 0x188 0x558 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA1__IPU1_DISP1_DATA08 0x188 0x558 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA1__IPU1_CSI1_DATA08 0x188 0x558 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA1__GPIO3_IO01 0x188 0x558 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA1__SRC_BOOT_CFG01 0x188 0x558 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA1__EPDC_SDLE 0x188 0x558 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA10__EIM_AD10 0x18c 0x55c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA10__IPU1_DI1_PIN15 0x18c 0x55c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA10__IPU1_CSI1_DATA_EN 0x18c 0x55c 0x8b0 0x2 0x1 ++#define MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x18c 0x55c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA10__SRC_BOOT_CFG10 0x18c 0x55c 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA10__EPDC_DATA01 0x18c 0x55c 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA11__EIM_AD11 0x190 0x560 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA11__IPU1_DI1_PIN02 0x190 0x560 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA11__IPU1_CSI1_HSYNC 0x190 0x560 0x8b4 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA11__GPIO3_IO11 0x190 0x560 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA11__SRC_BOOT_CFG11 0x190 0x560 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA11__EPDC_DATA03 0x190 0x560 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA12__EIM_AD12 0x194 0x564 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA12__IPU1_DI1_PIN03 0x194 0x564 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA12__IPU1_CSI1_VSYNC 0x194 0x564 0x8bc 0x2 0x1 ++#define MX6QDL_PAD_EIM_DA12__GPIO3_IO12 0x194 0x564 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA12__SRC_BOOT_CFG12 0x194 0x564 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA12__EPDC_DATA02 0x194 0x564 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA13__EIM_AD13 0x198 0x568 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA13__IPU1_DI1_D0_CS 0x198 0x568 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x198 0x568 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA13__SRC_BOOT_CFG13 0x198 0x568 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA13__EPDC_DATA13 0x198 0x568 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA14__EIM_AD14 0x19c 0x56c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA14__IPU1_DI1_D1_CS 0x19c 0x56c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA14__GPIO3_IO14 0x19c 0x56c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA14__SRC_BOOT_CFG14 0x19c 0x56c 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA14__EPDC_DATA14 0x19c 0x56c 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA15__EIM_AD15 0x1a0 0x570 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA15__IPU1_DI1_PIN01 0x1a0 0x570 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA15__IPU1_DI1_PIN04 0x1a0 0x570 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x1a0 0x570 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA15__SRC_BOOT_CFG15 0x1a0 0x570 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA15__EPDC_DATA09 0x1a0 0x570 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA2__EIM_AD02 0x1a4 0x574 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA2__IPU1_DISP1_DATA07 0x1a4 0x574 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA2__IPU1_CSI1_DATA07 0x1a4 0x574 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA2__GPIO3_IO02 0x1a4 0x574 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA2__SRC_BOOT_CFG02 0x1a4 0x574 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA2__EPDC_BDR0 0x1a4 0x574 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA3__EIM_AD03 0x1a8 0x578 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA3__IPU1_DISP1_DATA06 0x1a8 0x578 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA3__IPU1_CSI1_DATA06 0x1a8 0x578 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA3__GPIO3_IO03 0x1a8 0x578 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA3__SRC_BOOT_CFG03 0x1a8 0x578 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA3__EPDC_BDR1 0x1a8 0x578 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA4__EIM_AD04 0x1ac 0x57c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA4__IPU1_DISP1_DATA05 0x1ac 0x57c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA4__IPU1_CSI1_DATA05 0x1ac 0x57c 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x1ac 0x57c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA4__SRC_BOOT_CFG04 0x1ac 0x57c 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA4__EPDC_SDCE0 0x1ac 0x57c 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA5__EIM_AD05 0x1b0 0x580 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA5__IPU1_DISP1_DATA04 0x1b0 0x580 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA5__IPU1_CSI1_DATA04 0x1b0 0x580 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x1b0 0x580 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA5__SRC_BOOT_CFG05 0x1b0 0x580 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA5__EPDC_SDCE1 0x1b0 0x580 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA6__EIM_AD06 0x1b4 0x584 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA6__IPU1_DISP1_DATA03 0x1b4 0x584 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA6__IPU1_CSI1_DATA03 0x1b4 0x584 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA6__GPIO3_IO06 0x1b4 0x584 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA6__SRC_BOOT_CFG06 0x1b4 0x584 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA6__EPDC_SDCE2 0x1b4 0x584 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA7__EIM_AD07 0x1b8 0x588 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA7__IPU1_DISP1_DATA02 0x1b8 0x588 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA7__IPU1_CSI1_DATA02 0x1b8 0x588 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x1b8 0x588 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA7__SRC_BOOT_CFG07 0x1b8 0x588 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA7__EPDC_SDCE3 0x1b8 0x588 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA8__EIM_AD08 0x1bc 0x58c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA8__IPU1_DISP1_DATA01 0x1bc 0x58c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA8__IPU1_CSI1_DATA01 0x1bc 0x58c 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x1bc 0x58c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA8__SRC_BOOT_CFG08 0x1bc 0x58c 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA8__EPDC_SDCE4 0x1bc 0x58c 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_DA9__EIM_AD09 0x1c0 0x590 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA9__IPU1_DISP1_DATA00 0x1c0 0x590 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA9__IPU1_CSI1_DATA00 0x1c0 0x590 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x1c0 0x590 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA9__SRC_BOOT_CFG09 0x1c0 0x590 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA9__EPDC_SDCE5 0x1c0 0x590 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_EB0__EIM_EB0_B 0x1c4 0x594 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_EB0__IPU1_DISP1_DATA11 0x1c4 0x594 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_EB0__IPU1_CSI1_DATA11 0x1c4 0x594 0x88c 0x2 0x1 ++#define MX6QDL_PAD_EIM_EB0__CCM_PMIC_READY 0x1c4 0x594 0x7d4 0x4 0x0 ++#define MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x1c4 0x594 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_EB0__SRC_BOOT_CFG27 0x1c4 0x594 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_EB0__EPDC_PWR_COM 0x1c4 0x594 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_EB1__EIM_EB1_B 0x1c8 0x598 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_EB1__IPU1_DISP1_DATA10 0x1c8 0x598 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_EB1__IPU1_CSI1_DATA10 0x1c8 0x598 0x888 0x2 0x1 ++#define MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x1c8 0x598 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_EB1__SRC_BOOT_CFG28 0x1c8 0x598 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_EB1__EPDC_SDSHR 0x1c8 0x598 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_EB2__EIM_EB2_B 0x1cc 0x59c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_EB2__ECSPI1_SS0 0x1cc 0x59c 0x7e4 0x1 0x2 ++#define MX6QDL_PAD_EIM_EB2__IPU1_CSI1_DATA19 0x1cc 0x59c 0x8ac 0x3 0x1 ++#define MX6QDL_PAD_EIM_EB2__HDMI_TX_DDC_SCL 0x1cc 0x59c 0x860 0x4 0x0 ++#define MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x1cc 0x59c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x1cc 0x59c 0x870 0x6 0x0 ++#define MX6QDL_PAD_EIM_EB2__SRC_BOOT_CFG30 0x1cc 0x59c 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_EB2__EPDC_DATA05 0x1cc 0x59c 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_EB3__EIM_EB3_B 0x1d0 0x5a0 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_EB3__ECSPI4_RDY 0x1d0 0x5a0 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_EB3__UART3_RTS_B 0x1d0 0x5a0 0x908 0x2 0x3 ++#define MX6QDL_PAD_EIM_EB3__UART3_CTS_B 0x1d0 0x5a0 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_EB3__UART1_RI_B 0x1d0 0x5a0 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_EB3__IPU1_CSI1_HSYNC 0x1d0 0x5a0 0x8b4 0x4 0x1 ++#define MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x1d0 0x5a0 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_EB3__IPU1_DI1_PIN03 0x1d0 0x5a0 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_EB3__SRC_BOOT_CFG31 0x1d0 0x5a0 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_EB3__EPDC_SDCE0 0x1d0 0x5a0 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_EB3__EIM_ACLK_FREERUN 0x1d0 0x5a0 0x000 0x9 0x0 ++#define MX6QDL_PAD_EIM_LBA__EIM_LBA_B 0x1d4 0x5a4 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_LBA__IPU1_DI1_PIN17 0x1d4 0x5a4 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_LBA__ECSPI2_SS1 0x1d4 0x5a4 0x804 0x2 0x1 ++#define MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x1d4 0x5a4 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_LBA__SRC_BOOT_CFG26 0x1d4 0x5a4 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_LBA__EPDC_DATA04 0x1d4 0x5a4 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_OE__EIM_OE_B 0x1d8 0x5a8 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_OE__IPU1_DI1_PIN07 0x1d8 0x5a8 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x1d8 0x5a8 0x7f8 0x2 0x2 ++#define MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x1d8 0x5a8 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_OE__EPDC_PWR_IRQ 0x1d8 0x5a8 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_RW__EIM_RW 0x1dc 0x5ac 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_RW__IPU1_DI1_PIN08 0x1dc 0x5ac 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_RW__ECSPI2_SS0 0x1dc 0x5ac 0x800 0x2 0x2 ++#define MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x1dc 0x5ac 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_RW__SRC_BOOT_CFG29 0x1dc 0x5ac 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_RW__EPDC_DATA07 0x1dc 0x5ac 0x000 0x8 0x0 ++#define MX6QDL_PAD_EIM_WAIT__EIM_WAIT_B 0x1e0 0x5b0 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_WAIT__EIM_DTACK_B 0x1e0 0x5b0 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_WAIT__GPIO5_IO00 0x1e0 0x5b0 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_WAIT__SRC_BOOT_CFG25 0x1e0 0x5b0 0x000 0x7 0x0 ++#define MX6QDL_PAD_ENET_CRS_DV__ENET_RX_EN 0x1e4 0x5b4 0x828 0x1 0x0 ++#define MX6QDL_PAD_ENET_CRS_DV__ESAI_TX_CLK 0x1e4 0x5b4 0x840 0x2 0x0 ++#define MX6QDL_PAD_ENET_CRS_DV__SPDIF_EXT_CLK 0x1e4 0x5b4 0x8f4 0x3 0x0 ++#define MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1e4 0x5b4 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_MDC__MLB_DATA 0x1e8 0x5b8 0x8e0 0x0 0x0 ++#define MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1e8 0x5b8 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_MDC__ESAI_TX5_RX0 0x1e8 0x5b8 0x858 0x2 0x0 ++#define MX6QDL_PAD_ENET_MDC__ENET_1588_EVENT1_IN 0x1e8 0x5b8 0x000 0x4 0x0 ++#define MX6QDL_PAD_ENET_MDC__GPIO1_IO31 0x1e8 0x5b8 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1ec 0x5bc 0x810 0x1 0x0 ++#define MX6QDL_PAD_ENET_MDIO__ESAI_RX_CLK 0x1ec 0x5bc 0x83c 0x2 0x0 ++#define MX6QDL_PAD_ENET_MDIO__ENET_1588_EVENT1_OUT 0x1ec 0x5bc 0x000 0x4 0x0 ++#define MX6QDL_PAD_ENET_MDIO__GPIO1_IO22 0x1ec 0x5bc 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_MDIO__SPDIF_LOCK 0x1ec 0x5bc 0x000 0x6 0x0 ++#define MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1f0 0x5c0 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_REF_CLK__ESAI_RX_FS 0x1f0 0x5c0 0x82c 0x2 0x0 ++#define MX6QDL_PAD_ENET_REF_CLK__GPIO1_IO23 0x1f0 0x5c0 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_REF_CLK__SPDIF_SR_CLK 0x1f0 0x5c0 0x000 0x6 0x0 ++#define MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x1f4 0x5c4 0x790 0x0 0x0 ++#define MX6QDL_PAD_ENET_RX_ER__ENET_RX_ER 0x1f4 0x5c4 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_RX_ER__ESAI_RX_HF_CLK 0x1f4 0x5c4 0x834 0x2 0x0 ++#define MX6QDL_PAD_ENET_RX_ER__SPDIF_IN 0x1f4 0x5c4 0x8f0 0x3 0x1 ++#define MX6QDL_PAD_ENET_RX_ER__ENET_1588_EVENT2_OUT 0x1f4 0x5c4 0x000 0x4 0x0 ++#define MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24 0x1f4 0x5c4 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_RXD0__ENET_RX_DATA0 0x1f8 0x5c8 0x818 0x1 0x0 ++#define MX6QDL_PAD_ENET_RXD0__ESAI_TX_HF_CLK 0x1f8 0x5c8 0x838 0x2 0x0 ++#define MX6QDL_PAD_ENET_RXD0__SPDIF_OUT 0x1f8 0x5c8 0x000 0x3 0x0 ++#define MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x1f8 0x5c8 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_RXD1__MLB_SIG 0x1fc 0x5cc 0x8e4 0x0 0x0 ++#define MX6QDL_PAD_ENET_RXD1__ENET_RX_DATA1 0x1fc 0x5cc 0x81c 0x1 0x0 ++#define MX6QDL_PAD_ENET_RXD1__ESAI_TX_FS 0x1fc 0x5cc 0x830 0x2 0x0 ++#define MX6QDL_PAD_ENET_RXD1__ENET_1588_EVENT3_OUT 0x1fc 0x5cc 0x000 0x4 0x0 ++#define MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x1fc 0x5cc 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x200 0x5d0 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_TX_EN__ESAI_TX3_RX2 0x200 0x5d0 0x850 0x2 0x0 ++#define MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x200 0x5d0 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_TX_EN__I2C4_SCL 0x200 0x5d0 0x880 0x9 0x0 ++#define MX6QDL_PAD_ENET_TXD0__ENET_TX_DATA0 0x204 0x5d4 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_TXD0__ESAI_TX4_RX1 0x204 0x5d4 0x854 0x2 0x0 ++#define MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x204 0x5d4 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_TXD1__MLB_CLK 0x208 0x5d8 0x8dc 0x0 0x0 ++#define MX6QDL_PAD_ENET_TXD1__ENET_TX_DATA1 0x208 0x5d8 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_TXD1__ESAI_TX2_RX3 0x208 0x5d8 0x84c 0x2 0x0 ++#define MX6QDL_PAD_ENET_TXD1__ENET_1588_EVENT0_IN 0x208 0x5d8 0x000 0x4 0x0 ++#define MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x208 0x5d8 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_TXD1__I2C4_SDA 0x208 0x5d8 0x884 0x9 0x0 ++#define MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x20c 0x5dc 0x000 0x0 0x0 ++#define MX6QDL_PAD_GPIO_0__KEY_COL5 0x20c 0x5dc 0x8c0 0x2 0x1 ++#define MX6QDL_PAD_GPIO_0__ASRC_EXT_CLK 0x20c 0x5dc 0x794 0x3 0x0 ++#define MX6QDL_PAD_GPIO_0__EPIT1_OUT 0x20c 0x5dc 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x20c 0x5dc 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_0__USB_H1_PWR 0x20c 0x5dc 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_0__SNVS_VIO_5 0x20c 0x5dc 0x000 0x7 0x0 ++#define MX6QDL_PAD_GPIO_1__ESAI_RX_CLK 0x210 0x5e0 0x83c 0x0 0x1 ++#define MX6QDL_PAD_GPIO_1__WDOG2_B 0x210 0x5e0 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_1__KEY_ROW5 0x210 0x5e0 0x8cc 0x2 0x1 ++#define MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x210 0x5e0 0x790 0x3 0x1 ++#define MX6QDL_PAD_GPIO_1__PWM2_OUT 0x210 0x5e0 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_1__GPIO1_IO01 0x210 0x5e0 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_1__SD1_CD_B 0x210 0x5e0 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_16__ESAI_TX3_RX2 0x214 0x5e4 0x850 0x0 0x1 ++#define MX6QDL_PAD_GPIO_16__ENET_1588_EVENT2_IN 0x214 0x5e4 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x214 0x5e4 0x80c 0x2 0x0 ++#define MX6QDL_PAD_GPIO_16__SD1_LCTL 0x214 0x5e4 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_16__SPDIF_IN 0x214 0x5e4 0x8f0 0x4 0x2 ++#define MX6QDL_PAD_GPIO_16__GPIO7_IO11 0x214 0x5e4 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_16__I2C3_SDA 0x214 0x5e4 0x87c 0x6 0x1 ++#define MX6QDL_PAD_GPIO_16__JTAG_DE_B 0x214 0x5e4 0x000 0x7 0x0 ++#define MX6QDL_PAD_GPIO_17__ESAI_TX0 0x218 0x5e8 0x844 0x0 0x0 ++#define MX6QDL_PAD_GPIO_17__ENET_1588_EVENT3_IN 0x218 0x5e8 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_17__CCM_PMIC_READY 0x218 0x5e8 0x7d4 0x2 0x1 ++#define MX6QDL_PAD_GPIO_17__SDMA_EXT_EVENT0 0x218 0x5e8 0x8e8 0x3 0x1 ++#define MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x218 0x5e8 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x218 0x5e8 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_18__ESAI_TX1 0x21c 0x5ec 0x848 0x0 0x0 ++#define MX6QDL_PAD_GPIO_18__ENET_RX_CLK 0x21c 0x5ec 0x814 0x1 0x0 ++#define MX6QDL_PAD_GPIO_18__SD3_VSELECT 0x21c 0x5ec 0x000 0x2 0x0 ++#define MX6QDL_PAD_GPIO_18__SDMA_EXT_EVENT1 0x21c 0x5ec 0x8ec 0x3 0x1 ++#define MX6QDL_PAD_GPIO_18__ASRC_EXT_CLK 0x21c 0x5ec 0x794 0x4 0x1 ++#define MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x21c 0x5ec 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_18__SNVS_VIO_5_CTL 0x21c 0x5ec 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_19__KEY_COL5 0x220 0x5f0 0x8c0 0x0 0x2 ++#define MX6QDL_PAD_GPIO_19__ENET_1588_EVENT0_OUT 0x220 0x5f0 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_19__SPDIF_OUT 0x220 0x5f0 0x000 0x2 0x0 ++#define MX6QDL_PAD_GPIO_19__CCM_CLKO1 0x220 0x5f0 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_19__ECSPI1_RDY 0x220 0x5f0 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x220 0x5f0 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_19__ENET_TX_ER 0x220 0x5f0 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_2__ESAI_TX_FS 0x224 0x5f4 0x830 0x0 0x1 ++#define MX6QDL_PAD_GPIO_2__KEY_ROW6 0x224 0x5f4 0x8d0 0x2 0x1 ++#define MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x224 0x5f4 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_2__SD2_WP 0x224 0x5f4 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_2__MLB_DATA 0x224 0x5f4 0x8e0 0x7 0x1 ++#define MX6QDL_PAD_GPIO_3__ESAI_RX_HF_CLK 0x228 0x5f8 0x834 0x0 0x1 ++#define MX6QDL_PAD_GPIO_3__I2C3_SCL 0x228 0x5f8 0x878 0x2 0x1 ++#define MX6QDL_PAD_GPIO_3__XTALOSC_REF_CLK_24M 0x228 0x5f8 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_3__CCM_CLKO2 0x228 0x5f8 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x228 0x5f8 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_3__USB_H1_OC 0x228 0x5f8 0x924 0x6 0x1 ++#define MX6QDL_PAD_GPIO_3__MLB_CLK 0x228 0x5f8 0x8dc 0x7 0x1 ++#define MX6QDL_PAD_GPIO_4__ESAI_TX_HF_CLK 0x22c 0x5fc 0x838 0x0 0x1 ++#define MX6QDL_PAD_GPIO_4__KEY_COL7 0x22c 0x5fc 0x8c8 0x2 0x1 ++#define MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x22c 0x5fc 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_4__SD2_CD_B 0x22c 0x5fc 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_5__ESAI_TX2_RX3 0x230 0x600 0x84c 0x0 0x1 ++#define MX6QDL_PAD_GPIO_5__KEY_ROW7 0x230 0x600 0x8d4 0x2 0x1 ++#define MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x230 0x600 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x230 0x600 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_5__I2C3_SCL 0x230 0x600 0x878 0x6 0x2 ++#define MX6QDL_PAD_GPIO_5__ARM_EVENTI 0x230 0x600 0x000 0x7 0x0 ++#define MX6QDL_PAD_GPIO_6__ESAI_TX_CLK 0x234 0x604 0x840 0x0 0x1 ++#define MX6QDL_PAD_GPIO_6__I2C3_SDA 0x234 0x604 0x87c 0x2 0x2 ++#define MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x234 0x604 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_6__SD2_LCTL 0x234 0x604 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_6__MLB_SIG 0x234 0x604 0x8e4 0x7 0x1 ++#define MX6QDL_PAD_GPIO_7__ESAI_TX4_RX1 0x238 0x608 0x854 0x0 0x1 ++#define MX6QDL_PAD_GPIO_7__EPIT1_OUT 0x238 0x608 0x000 0x2 0x0 ++#define MX6QDL_PAD_GPIO_7__FLEXCAN1_TX 0x238 0x608 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_7__UART2_TX_DATA 0x238 0x608 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_7__UART2_RX_DATA 0x238 0x608 0x904 0x4 0x2 ++#define MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x238 0x608 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_7__SPDIF_LOCK 0x238 0x608 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_7__USB_OTG_HOST_MODE 0x238 0x608 0x000 0x7 0x0 ++#define MX6QDL_PAD_GPIO_7__I2C4_SCL 0x238 0x608 0x880 0x8 0x1 ++#define MX6QDL_PAD_GPIO_8__ESAI_TX5_RX0 0x23c 0x60c 0x858 0x0 0x1 ++#define MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x23c 0x60c 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_8__EPIT2_OUT 0x23c 0x60c 0x000 0x2 0x0 ++#define MX6QDL_PAD_GPIO_8__FLEXCAN1_RX 0x23c 0x60c 0x7c8 0x3 0x0 ++#define MX6QDL_PAD_GPIO_8__UART2_RX_DATA 0x23c 0x60c 0x904 0x4 0x3 ++#define MX6QDL_PAD_GPIO_8__UART2_TX_DATA 0x23c 0x60c 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x23c 0x60c 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_8__SPDIF_SR_CLK 0x23c 0x60c 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_8__USB_OTG_PWR_CTL_WAKE 0x23c 0x60c 0x000 0x7 0x0 ++#define MX6QDL_PAD_GPIO_8__I2C4_SDA 0x23c 0x60c 0x884 0x8 0x1 ++#define MX6QDL_PAD_GPIO_9__ESAI_RX_FS 0x240 0x610 0x82c 0x0 0x1 ++#define MX6QDL_PAD_GPIO_9__WDOG1_B 0x240 0x610 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_9__KEY_COL6 0x240 0x610 0x8c4 0x2 0x1 ++#define MX6QDL_PAD_GPIO_9__CCM_REF_EN_B 0x240 0x610 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_9__PWM1_OUT 0x240 0x610 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x240 0x610 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_9__SD1_WP 0x240 0x610 0x92c 0x6 0x1 ++#define MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x244 0x62c 0x7d8 0x0 0x3 ++#define MX6QDL_PAD_KEY_COL0__ENET_RX_DATA3 0x244 0x62c 0x824 0x1 0x0 ++#define MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x244 0x62c 0x7c0 0x2 0x1 ++#define MX6QDL_PAD_KEY_COL0__KEY_COL0 0x244 0x62c 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x244 0x62c 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_COL0__UART4_RX_DATA 0x244 0x62c 0x914 0x4 0x2 ++#define MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x244 0x62c 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_COL0__DCIC1_OUT 0x244 0x62c 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x248 0x630 0x7dc 0x0 0x3 ++#define MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x248 0x630 0x810 0x1 0x1 ++#define MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x248 0x630 0x7c4 0x2 0x1 ++#define MX6QDL_PAD_KEY_COL1__KEY_COL1 0x248 0x630 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x248 0x630 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_COL1__UART5_RX_DATA 0x248 0x630 0x91c 0x4 0x2 ++#define MX6QDL_PAD_KEY_COL1__GPIO4_IO08 0x248 0x630 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_COL1__SD1_VSELECT 0x248 0x630 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_COL2__ECSPI1_SS1 0x24c 0x634 0x7e8 0x0 0x2 ++#define MX6QDL_PAD_KEY_COL2__ENET_RX_DATA2 0x24c 0x634 0x820 0x1 0x0 ++#define MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x24c 0x634 0x000 0x2 0x0 ++#define MX6QDL_PAD_KEY_COL2__KEY_COL2 0x24c 0x634 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_COL2__ENET_MDC 0x24c 0x634 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x24c 0x634 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_COL2__USB_H1_PWR_CTL_WAKE 0x24c 0x634 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_COL3__ECSPI1_SS3 0x250 0x638 0x7f0 0x0 0x1 ++#define MX6QDL_PAD_KEY_COL3__ENET_CRS 0x250 0x638 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_COL3__HDMI_TX_DDC_SCL 0x250 0x638 0x860 0x2 0x1 ++#define MX6QDL_PAD_KEY_COL3__KEY_COL3 0x250 0x638 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x250 0x638 0x870 0x4 0x1 ++#define MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x250 0x638 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x250 0x638 0x8f0 0x6 0x3 ++#define MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x254 0x63c 0x000 0x0 0x0 ++#define MX6QDL_PAD_KEY_COL4__IPU1_SISG4 0x254 0x63c 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x254 0x63c 0x920 0x2 0x1 ++#define MX6QDL_PAD_KEY_COL4__KEY_COL4 0x254 0x63c 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_COL4__UART5_RTS_B 0x254 0x63c 0x918 0x4 0x2 ++#define MX6QDL_PAD_KEY_COL4__UART5_CTS_B 0x254 0x63c 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x254 0x63c 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x258 0x640 0x7e0 0x0 0x3 ++#define MX6QDL_PAD_KEY_ROW0__ENET_TX_DATA3 0x258 0x640 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x258 0x640 0x7b4 0x2 0x1 ++#define MX6QDL_PAD_KEY_ROW0__KEY_ROW0 0x258 0x640 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x258 0x640 0x914 0x4 0x3 ++#define MX6QDL_PAD_KEY_ROW0__UART4_TX_DATA 0x258 0x640 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x258 0x640 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_ROW0__DCIC2_OUT 0x258 0x640 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_ROW1__ECSPI1_SS0 0x25c 0x644 0x7e4 0x0 0x3 ++#define MX6QDL_PAD_KEY_ROW1__ENET_COL 0x25c 0x644 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_ROW1__AUD5_RXD 0x25c 0x644 0x7b0 0x2 0x1 ++#define MX6QDL_PAD_KEY_ROW1__KEY_ROW1 0x25c 0x644 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x25c 0x644 0x91c 0x4 0x3 ++#define MX6QDL_PAD_KEY_ROW1__UART5_TX_DATA 0x25c 0x644 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x25c 0x644 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x25c 0x644 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_ROW2__ECSPI1_SS2 0x260 0x648 0x7ec 0x0 0x1 ++#define MX6QDL_PAD_KEY_ROW2__ENET_TX_DATA2 0x260 0x648 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x260 0x648 0x7c8 0x2 0x1 ++#define MX6QDL_PAD_KEY_ROW2__KEY_ROW2 0x260 0x648 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_ROW2__SD2_VSELECT 0x260 0x648 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_ROW2__GPIO4_IO11 0x260 0x648 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x260 0x648 0x85c 0x6 0x1 ++#define MX6QDL_PAD_KEY_ROW3__ASRC_EXT_CLK 0x264 0x64c 0x794 0x1 0x2 ++#define MX6QDL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 0x264 0x64c 0x864 0x2 0x1 ++#define MX6QDL_PAD_KEY_ROW3__KEY_ROW3 0x264 0x64c 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x264 0x64c 0x874 0x4 0x1 ++#define MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x264 0x64c 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_ROW3__SD1_VSELECT 0x264 0x64c 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x268 0x650 0x7cc 0x0 0x0 ++#define MX6QDL_PAD_KEY_ROW4__IPU1_SISG5 0x268 0x650 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_ROW4__USB_OTG_PWR 0x268 0x650 0x000 0x2 0x0 ++#define MX6QDL_PAD_KEY_ROW4__KEY_ROW4 0x268 0x650 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_ROW4__UART5_CTS_B 0x268 0x650 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_ROW4__UART5_RTS_B 0x268 0x650 0x918 0x4 0x3 ++#define MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x268 0x650 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_ALE__NAND_ALE 0x26c 0x654 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_ALE__SD4_RESET 0x26c 0x654 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x26c 0x654 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CLE__NAND_CLE 0x270 0x658 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x270 0x658 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0x274 0x65c 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x274 0x65c 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0x278 0x660 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_CS1__SD4_VSELECT 0x278 0x660 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_CS1__SD3_VSELECT 0x278 0x660 0x000 0x2 0x0 ++#define MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x278 0x660 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CS2__NAND_CE2_B 0x27c 0x664 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_CS2__IPU1_SISG0 0x27c 0x664 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_CS2__ESAI_TX0 0x27c 0x664 0x844 0x2 0x1 ++#define MX6QDL_PAD_NANDF_CS2__EIM_CRE 0x27c 0x664 0x000 0x3 0x0 ++#define MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x27c 0x664 0x000 0x4 0x0 ++#define MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x27c 0x664 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CS3__NAND_CE3_B 0x280 0x668 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_CS3__IPU1_SISG1 0x280 0x668 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_CS3__ESAI_TX1 0x280 0x668 0x848 0x2 0x1 ++#define MX6QDL_PAD_NANDF_CS3__EIM_ADDR26 0x280 0x668 0x000 0x3 0x0 ++#define MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x280 0x668 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CS3__I2C4_SDA 0x280 0x668 0x884 0x9 0x2 ++#define MX6QDL_PAD_NANDF_D0__NAND_DATA00 0x284 0x66c 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D0__SD1_DATA4 0x284 0x66c 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x284 0x66c 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D1__NAND_DATA01 0x288 0x670 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D1__SD1_DATA5 0x288 0x670 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x288 0x670 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D2__NAND_DATA02 0x28c 0x674 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D2__SD1_DATA6 0x28c 0x674 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x28c 0x674 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D3__NAND_DATA03 0x290 0x678 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D3__SD1_DATA7 0x290 0x678 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x290 0x678 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D4__NAND_DATA04 0x294 0x67c 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D4__SD2_DATA4 0x294 0x67c 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x294 0x67c 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D5__NAND_DATA05 0x298 0x680 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D5__SD2_DATA5 0x298 0x680 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x298 0x680 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D6__NAND_DATA06 0x29c 0x684 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D6__SD2_DATA6 0x29c 0x684 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x29c 0x684 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D7__NAND_DATA07 0x2a0 0x688 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D7__SD2_DATA7 0x2a0 0x688 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x2a0 0x688 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0x2a4 0x68c 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_RB0__GPIO6_IO10 0x2a4 0x68c 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0x2a8 0x690 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x2a8 0x690 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_WP_B__I2C4_SCL 0x2a8 0x690 0x880 0x9 0x2 ++#define MX6QDL_PAD_RGMII_RD0__HSI_RX_READY 0x2ac 0x694 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x2ac 0x694 0x818 0x1 0x1 ++#define MX6QDL_PAD_RGMII_RD0__GPIO6_IO25 0x2ac 0x694 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_RD1__HSI_TX_FLAG 0x2b0 0x698 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x2b0 0x698 0x81c 0x1 0x1 ++#define MX6QDL_PAD_RGMII_RD1__GPIO6_IO27 0x2b0 0x698 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_RD2__HSI_TX_DATA 0x2b4 0x69c 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x2b4 0x69c 0x820 0x1 0x1 ++#define MX6QDL_PAD_RGMII_RD2__GPIO6_IO28 0x2b4 0x69c 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_RD3__HSI_TX_WAKE 0x2b8 0x6a0 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x2b8 0x6a0 0x824 0x1 0x1 ++#define MX6QDL_PAD_RGMII_RD3__GPIO6_IO29 0x2b8 0x6a0 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_RX_CTL__USB_H3_DATA 0x2bc 0x6a4 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x2bc 0x6a4 0x828 0x1 0x1 ++#define MX6QDL_PAD_RGMII_RX_CTL__GPIO6_IO24 0x2bc 0x6a4 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_RXC__USB_H3_STROBE 0x2c0 0x6a8 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x2c0 0x6a8 0x814 0x1 0x1 ++#define MX6QDL_PAD_RGMII_RXC__GPIO6_IO30 0x2c0 0x6a8 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TD0__HSI_TX_READY 0x2c4 0x6ac 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x2c4 0x6ac 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TD0__GPIO6_IO20 0x2c4 0x6ac 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TD1__HSI_RX_FLAG 0x2c8 0x6b0 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x2c8 0x6b0 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TD1__GPIO6_IO21 0x2c8 0x6b0 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TD2__HSI_RX_DATA 0x2cc 0x6b4 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x2cc 0x6b4 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TD2__GPIO6_IO22 0x2cc 0x6b4 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TD3__HSI_RX_WAKE 0x2d0 0x6b8 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x2d0 0x6b8 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TD3__GPIO6_IO23 0x2d0 0x6b8 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TX_CTL__USB_H2_STROBE 0x2d4 0x6bc 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x2d4 0x6bc 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TX_CTL__GPIO6_IO26 0x2d4 0x6bc 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TX_CTL__ENET_REF_CLK 0x2d4 0x6bc 0x80c 0x7 0x1 ++#define MX6QDL_PAD_RGMII_TXC__USB_H2_DATA 0x2d8 0x6c0 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x2d8 0x6c0 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TXC__SPDIF_EXT_CLK 0x2d8 0x6c0 0x8f4 0x2 0x1 ++#define MX6QDL_PAD_RGMII_TXC__GPIO6_IO19 0x2d8 0x6c0 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TXC__XTALOSC_REF_CLK_24M 0x2d8 0x6c0 0x000 0x7 0x0 ++#define MX6QDL_PAD_SD1_CLK__SD1_CLK 0x2dc 0x6c4 0x928 0x0 0x1 ++#define MX6QDL_PAD_SD1_CLK__GPT_CLKIN 0x2dc 0x6c4 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_CLK__GPIO1_IO20 0x2dc 0x6c4 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_CMD__SD1_CMD 0x2e0 0x6c8 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x2e0 0x6c8 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD1_CMD__GPT_COMPARE1 0x2e0 0x6c8 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_CMD__GPIO1_IO18 0x2e0 0x6c8 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x2e4 0x6cc 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD1_DAT0__GPT_CAPTURE1 0x2e4 0x6cc 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x2e4 0x6cc 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x2e8 0x6d0 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x2e8 0x6d0 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD1_DAT1__GPT_CAPTURE2 0x2e8 0x6d0 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x2e8 0x6d0 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x2ec 0x6d4 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD1_DAT2__GPT_COMPARE2 0x2ec 0x6d4 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x2ec 0x6d4 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_DAT2__WDOG1_B 0x2ec 0x6d4 0x000 0x4 0x0 ++#define MX6QDL_PAD_SD1_DAT2__GPIO1_IO19 0x2ec 0x6d4 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_DAT2__WDOG1_RESET_B_DEB 0x2ec 0x6d4 0x000 0x6 0x0 ++#define MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x2f0 0x6d8 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD1_DAT3__GPT_COMPARE3 0x2f0 0x6d8 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x2f0 0x6d8 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_DAT3__WDOG2_B 0x2f0 0x6d8 0x000 0x4 0x0 ++#define MX6QDL_PAD_SD1_DAT3__GPIO1_IO21 0x2f0 0x6d8 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_DAT3__WDOG2_RESET_B_DEB 0x2f0 0x6d8 0x000 0x6 0x0 ++#define MX6QDL_PAD_SD2_CLK__SD2_CLK 0x2f4 0x6dc 0x930 0x0 0x1 ++#define MX6QDL_PAD_SD2_CLK__KEY_COL5 0x2f4 0x6dc 0x8c0 0x2 0x3 ++#define MX6QDL_PAD_SD2_CLK__AUD4_RXFS 0x2f4 0x6dc 0x7a4 0x3 0x1 ++#define MX6QDL_PAD_SD2_CLK__GPIO1_IO10 0x2f4 0x6dc 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_CMD__SD2_CMD 0x2f8 0x6e0 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD2_CMD__KEY_ROW5 0x2f8 0x6e0 0x8cc 0x2 0x2 ++#define MX6QDL_PAD_SD2_CMD__AUD4_RXC 0x2f8 0x6e0 0x7a0 0x3 0x1 ++#define MX6QDL_PAD_SD2_CMD__GPIO1_IO11 0x2f8 0x6e0 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x2fc 0x6e4 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x2fc 0x6e4 0x798 0x3 0x1 ++#define MX6QDL_PAD_SD2_DAT0__KEY_ROW7 0x2fc 0x6e4 0x8d4 0x4 0x2 ++#define MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x2fc 0x6e4 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_DAT0__DCIC2_OUT 0x2fc 0x6e4 0x000 0x6 0x0 ++#define MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x300 0x6e8 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD2_DAT1__EIM_CS2_B 0x300 0x6e8 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x300 0x6e8 0x7ac 0x3 0x1 ++#define MX6QDL_PAD_SD2_DAT1__KEY_COL7 0x300 0x6e8 0x8c8 0x4 0x2 ++#define MX6QDL_PAD_SD2_DAT1__GPIO1_IO14 0x300 0x6e8 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x304 0x6ec 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD2_DAT2__EIM_CS3_B 0x304 0x6ec 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x304 0x6ec 0x79c 0x3 0x1 ++#define MX6QDL_PAD_SD2_DAT2__KEY_ROW6 0x304 0x6ec 0x8d0 0x4 0x2 ++#define MX6QDL_PAD_SD2_DAT2__GPIO1_IO13 0x304 0x6ec 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x308 0x6f0 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD2_DAT3__KEY_COL6 0x308 0x6f0 0x8c4 0x2 0x2 ++#define MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x308 0x6f0 0x7a8 0x3 0x1 ++#define MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x308 0x6f0 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_CLK__SD3_CLK 0x30c 0x6f4 0x934 0x0 0x1 ++#define MX6QDL_PAD_SD3_CLK__UART2_RTS_B 0x30c 0x6f4 0x900 0x1 0x2 ++#define MX6QDL_PAD_SD3_CLK__UART2_CTS_B 0x30c 0x6f4 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_CLK__FLEXCAN1_RX 0x30c 0x6f4 0x7c8 0x2 0x2 ++#define MX6QDL_PAD_SD3_CLK__GPIO7_IO03 0x30c 0x6f4 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_CMD__SD3_CMD 0x310 0x6f8 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_CMD__UART2_CTS_B 0x310 0x6f8 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_CMD__UART2_RTS_B 0x310 0x6f8 0x900 0x1 0x3 ++#define MX6QDL_PAD_SD3_CMD__FLEXCAN1_TX 0x310 0x6f8 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD3_CMD__GPIO7_IO02 0x310 0x6f8 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x314 0x6fc 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT0__UART1_CTS_B 0x314 0x6fc 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT0__UART1_RTS_B 0x314 0x6fc 0x8f8 0x1 0x2 ++#define MX6QDL_PAD_SD3_DAT0__FLEXCAN2_TX 0x314 0x6fc 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD3_DAT0__GPIO7_IO04 0x314 0x6fc 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x318 0x700 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT1__UART1_RTS_B 0x318 0x700 0x8f8 0x1 0x3 ++#define MX6QDL_PAD_SD3_DAT1__UART1_CTS_B 0x318 0x700 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT1__FLEXCAN2_RX 0x318 0x700 0x7cc 0x2 0x1 ++#define MX6QDL_PAD_SD3_DAT1__GPIO7_IO05 0x318 0x700 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x31c 0x704 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT2__GPIO7_IO06 0x31c 0x704 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x320 0x708 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT3__UART3_CTS_B 0x320 0x708 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT3__UART3_RTS_B 0x320 0x708 0x908 0x1 0x4 ++#define MX6QDL_PAD_SD3_DAT3__GPIO7_IO07 0x320 0x708 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x324 0x70c 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT4__UART2_RX_DATA 0x324 0x70c 0x904 0x1 0x4 ++#define MX6QDL_PAD_SD3_DAT4__UART2_TX_DATA 0x324 0x70c 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x324 0x70c 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x328 0x710 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT5__UART2_TX_DATA 0x328 0x710 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT5__UART2_RX_DATA 0x328 0x710 0x904 0x1 0x5 ++#define MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x328 0x710 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x32c 0x714 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x32c 0x714 0x8fc 0x1 0x2 ++#define MX6QDL_PAD_SD3_DAT6__UART1_TX_DATA 0x32c 0x714 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT6__GPIO6_IO18 0x32c 0x714 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x330 0x718 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x330 0x718 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT7__UART1_RX_DATA 0x330 0x718 0x8fc 0x1 0x3 ++#define MX6QDL_PAD_SD3_DAT7__GPIO6_IO17 0x330 0x718 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_RST__SD3_RESET 0x334 0x71c 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_RST__UART3_RTS_B 0x334 0x71c 0x908 0x1 0x5 ++#define MX6QDL_PAD_SD3_RST__UART3_CTS_B 0x334 0x71c 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x334 0x71c 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_CLK__SD4_CLK 0x338 0x720 0x938 0x0 0x1 ++#define MX6QDL_PAD_SD4_CLK__NAND_WE_B 0x338 0x720 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_CLK__UART3_RX_DATA 0x338 0x720 0x90c 0x2 0x2 ++#define MX6QDL_PAD_SD4_CLK__UART3_TX_DATA 0x338 0x720 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_CLK__GPIO7_IO10 0x338 0x720 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_CMD__SD4_CMD 0x33c 0x724 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD4_CMD__NAND_RE_B 0x33c 0x724 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_CMD__UART3_TX_DATA 0x33c 0x724 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_CMD__UART3_RX_DATA 0x33c 0x724 0x90c 0x2 0x3 ++#define MX6QDL_PAD_SD4_CMD__GPIO7_IO09 0x33c 0x724 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x340 0x728 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x340 0x728 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT0__GPIO2_IO08 0x340 0x728 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x344 0x72c 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x344 0x72c 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT1__GPIO2_IO09 0x344 0x72c 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x348 0x730 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT2__PWM4_OUT 0x348 0x730 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x348 0x730 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x34c 0x734 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x34c 0x734 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x350 0x738 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x350 0x738 0x904 0x2 0x6 ++#define MX6QDL_PAD_SD4_DAT4__UART2_TX_DATA 0x350 0x738 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT4__GPIO2_IO12 0x350 0x738 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x354 0x73c 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT5__UART2_RTS_B 0x354 0x73c 0x900 0x2 0x4 ++#define MX6QDL_PAD_SD4_DAT5__UART2_CTS_B 0x354 0x73c 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT5__GPIO2_IO13 0x354 0x73c 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x358 0x740 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT6__UART2_CTS_B 0x358 0x740 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT6__UART2_RTS_B 0x358 0x740 0x900 0x2 0x5 ++#define MX6QDL_PAD_SD4_DAT6__GPIO2_IO14 0x358 0x740 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x35c 0x744 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x35c 0x744 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT7__UART2_RX_DATA 0x35c 0x744 0x904 0x2 0x7 ++#define MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x35c 0x744 0x000 0x5 0x0 + + #endif /* __DTS_IMX6DL_PINFUNC_H */ +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl-sabreauto-ecspi.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabreauto-ecspi.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6dl-sabreauto-ecspi.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabreauto-ecspi.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,38 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "imx6dl-sabreauto.dts" ++ ++&ecspi1 { ++ status = "okay"; ++}; ++ ++&flexcan2 { ++ /* max7310_c on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&i2c3 { ++ /* pin conflict with ecspi1 */ ++ status = "disabled"; ++}; ++ ++&uart3 { ++ /* the uart3 depends on the i2c3, so disable it too. */ ++ status = "disabled"; ++}; ++ ++&usbh1 { ++ /* max7310_b on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&usbotg { ++ dr_mode = "peripheral"; ++ status = "okay"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl-sabreauto-flexcan1.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabreauto-flexcan1.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6dl-sabreauto-flexcan1.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabreauto-flexcan1.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "imx6dl-sabreauto.dts" ++ ++&flexcan1{ ++ status = "okay"; ++}; ++ ++&fec { ++ /* pin conflict with flexcan1 */ ++ status = "disabled"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl-sabreauto-gpmi-weim.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabreauto-gpmi-weim.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6dl-sabreauto-gpmi-weim.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabreauto-gpmi-weim.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "imx6dl-sabreauto.dts" ++ ++&ecspi1 { ++ /* pin conflict with weim */ ++ status = "disabled"; ++}; ++ ++&flexcan2 { ++ /* max7310_c on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&gpmi { ++ status = "okay"; ++}; ++ ++&i2c3 { ++ /* pin conflict with weim */ ++ status = "disabled"; ++}; ++ ++&uart3 { ++ /* pin conflict with gpmi and weim */ ++ status = "disabled"; ++}; ++ ++&usbh1 { ++ /* max7310_b on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&usbotg { ++ dr_mode = "peripheral"; ++ status = "okay"; ++}; ++ ++&weim { ++ status = "okay"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl-sabreauto.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabreauto.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6dl-sabreauto.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabreauto.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -16,16 +16,15 @@ + compatible = "fsl,imx6dl-sabreauto", "fsl,imx6dl"; + }; + +-&iomuxc { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_hog>; ++&ldb { ++ ipu_id = <0>; ++ sec_ipu_id = <0>; ++}; ++ ++&mxcfb1 { ++ status = "okay"; ++}; + +- hog { +- pinctrl_hog: hoggrp { +- fsl,pins = < +- MX6DL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000 +- MX6DL_PAD_SD2_DAT2__GPIO1_IO13 0x80000000 +- >; +- }; +- }; ++&mxcfb2 { ++ status = "okay"; + }; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,19 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "imx6dl-sabresd.dts" ++ ++&hdmi_video { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hdmi_hdcp_1>; ++ fsl,hdcp; ++}; ++ ++&i2c2 { ++ status = "disable"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl-sabresd-ldo.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabresd-ldo.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6dl-sabresd-ldo.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabresd-ldo.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "imx6dl-sabresd.dts" ++ ++&cpu0 { ++ arm-supply = <®_arm>; ++ soc-supply = <®_soc>; ++ pu-supply = <®_pu>; /* use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&gpc { ++ fsl,ldo-bypass = <0>; /* use ldo-bypass, u-boot will check it and configure */ ++ fsl,wdog-reset = <1>; /* watchdog select of reset source */ ++ pu-supply = <®_pu>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&gpu { ++ pu-supply = <®_pu>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&vpu { ++ pu-supply = <®_pu>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl-sabresd.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabresd.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6dl-sabresd.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-sabresd.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -16,20 +16,126 @@ + compatible = "fsl,imx6dl-sabresd", "fsl,imx6dl"; + }; + ++&i2c3 { ++ max17135@48 { ++ compatible = "maxim,max17135"; ++ reg = <0x48>; ++ vneg_pwrup = <1>; ++ gvee_pwrup = <1>; ++ vpos_pwrup = <2>; ++ gvdd_pwrup = <1>; ++ gvdd_pwrdn = <1>; ++ vpos_pwrdn = <2>; ++ gvee_pwrdn = <1>; ++ vneg_pwrdn = <1>; ++ SENSOR-supply = <®_sensor>; ++ gpio_pmic_pwrgood = <&gpio2 21 0>; ++ gpio_pmic_vcom_ctrl = <&gpio3 17 0>; ++ gpio_pmic_wakeup = <&gpio3 20 0>; ++ gpio_pmic_v3p3 = <&gpio2 20 0>; ++ gpio_pmic_intr = <&gpio2 25 0>; ++ ++ regulators { ++ DISPLAY_reg: DISPLAY { ++ regulator-name = "DISPLAY"; ++ }; ++ ++ GVDD_reg: GVDD { ++ /* 20v */ ++ regulator-name = "GVDD"; ++ }; ++ ++ GVEE_reg: GVEE { ++ /* -22v */ ++ regulator-name = "GVEE"; ++ }; ++ ++ HVINN_reg: HVINN { ++ /* -22v */ ++ regulator-name = "HVINN"; ++ }; ++ ++ HVINP_reg: HVINP { ++ /* 20v */ ++ regulator-name = "HVINP"; ++ }; ++ ++ VCOM_reg: VCOM { ++ regulator-name = "VCOM"; ++ /* 2's-compliment, -4325000 */ ++ regulator-min-microvolt = <0xffbe0178>; ++ /* 2's-compliment, -500000 */ ++ regulator-max-microvolt = <0xfff85ee0>; ++ }; ++ ++ VNEG_reg: VNEG { ++ /* -15v */ ++ regulator-name = "VNEG"; ++ }; ++ ++ VPOS_reg: VPOS { ++ /* 15v */ ++ regulator-name = "VPOS"; ++ }; ++ ++ V3P3_reg: V3P3 { ++ regulator-name = "V3P3"; ++ }; ++ }; ++ }; ++}; ++ + &iomuxc { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_hog>; ++ pinctrl-0 = <&pinctrl_hog_1>, <&pinctrl_hog_2>; + + hog { +- pinctrl_hog: hoggrp { ++ pinctrl_hog_2: hoggrp-2 { + fsl,pins = < +- MX6DL_PAD_GPIO_4__GPIO1_IO04 0x80000000 +- MX6DL_PAD_GPIO_5__GPIO1_IO05 0x80000000 +- MX6DL_PAD_NANDF_D0__GPIO2_IO00 0x80000000 +- MX6DL_PAD_NANDF_D1__GPIO2_IO01 0x80000000 +- MX6DL_PAD_NANDF_D2__GPIO2_IO02 0x80000000 +- MX6DL_PAD_NANDF_D3__GPIO2_IO03 0x80000000 ++ /* MAX17135 */ ++ MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x80000000 ++ MX6QDL_PAD_EIM_D17__GPIO3_IO17 0x80000000 ++ MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x80000000 ++ MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x80000000 ++ MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x80000000 ++ /* elan touch */ ++ MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x80000000 ++ MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x80000000 ++ MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x170b0 + >; + }; + }; + }; ++ ++&epdc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_epdc_0>; ++ V3P3-supply = <&V3P3_reg>; ++ VCOM-supply = <&VCOM_reg>; ++ DISPLAY-supply = <&DISPLAY_reg>; ++ status = "okay"; ++}; ++ ++&ldb { ++ ipu_id = <0>; ++ sec_ipu_id = <0>; ++}; ++ ++&pxp { ++ status = "okay"; ++}; ++ ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; ++ ++&battery { ++ offset-charger = <1485>; ++ offset-discharger = <1464>; ++ offset-usb-charger = <1285>; ++}; ++ +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl-wandboard.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-wandboard.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6dl-wandboard.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl-wandboard.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -10,6 +10,7 @@ + */ + /dts-v1/; + #include "imx6dl.dtsi" ++#include "imx6qdl-wandboard.dtsi" + + / { + model = "Wandboard i.MX6 Dual Lite Board"; +@@ -19,26 +20,3 @@ + reg = <0x10000000 0x40000000>; + }; + }; +- +-&fec { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_1>; +- phy-mode = "rgmii"; +- status = "okay"; +-}; +- +-&uart1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart1_1>; +- status = "okay"; +-}; +- +-&usbh1 { +- status = "okay"; +-}; +- +-&usdhc3 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc3_2>; +- status = "okay"; +-}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6dl.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx6dl.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6dl.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -8,19 +8,39 @@ + * + */ + +-#include "imx6qdl.dtsi" + #include "imx6dl-pinfunc.h" ++#include "imx6qdl.dtsi" + + / { + cpus { + #address-cells = <1>; + #size-cells = <0>; + +- cpu@0 { ++ cpu0: cpu@0 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <0>; + next-level-cache = <&L2>; ++ operating-points = < ++ /* kHz uV */ ++ 996000 1275000 ++ 792000 1175000 ++ 396000 1075000 ++ >; ++ fsl,soc-operating-points = < ++ /* ARM kHz SOC-PU uV */ ++ 996000 1175000 ++ 792000 1175000 ++ 396000 1175000 ++ >; ++ clock-latency = <61036>; /* two CLK32 periods */ ++ clocks = <&clks 104>, <&clks 6>, <&clks 16>, ++ <&clks 17>, <&clks 170>; ++ clock-names = "arm", "pll2_pfd2_396m", "step", ++ "pll1_sw", "pll1_sys"; ++ arm-supply = <®_arm>; ++ pu-supply = <®_pu>; ++ soc-supply = <®_soc>; + }; + + cpu@1 { +@@ -28,140 +48,125 @@ + device_type = "cpu"; + reg = <1>; + next-level-cache = <&L2>; ++ operating-points = < ++ /* kHz uV */ ++ 996000 1250000 ++ 792000 1175000 ++ 396000 1075000 ++ >; ++ fsl,soc-operating-points = < ++ /* ARM kHz SOC-PU uV */ ++ 996000 1175000 ++ 792000 1175000 ++ 396000 1175000 ++ >; ++ clock-latency = <61036>; /* two CLK32 periods */ ++ clocks = <&clks 104>, <&clks 6>, <&clks 16>, ++ <&clks 17>, <&clks 170>; ++ clock-names = "arm", "pll2_pfd2_396m", "step", ++ "pll1_sw", "pll1_sys"; ++ arm-supply = <®_arm>; ++ pu-supply = <®_pu>; ++ soc-supply = <®_soc>; + }; + }; + + soc { +- aips1: aips-bus@02000000 { +- iomuxc: iomuxc@020e0000 { +- compatible = "fsl,imx6dl-iomuxc"; +- reg = <0x020e0000 0x4000>; + +- enet { +- pinctrl_enet_1: enetgrp-1 { +- fsl,pins = < +- MX6DL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 +- MX6DL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 +- MX6DL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 +- MX6DL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 +- MX6DL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 +- MX6DL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 +- MX6DL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 +- MX6DL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 +- MX6DL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 +- MX6DL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 +- MX6DL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 +- MX6DL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 +- MX6DL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 +- MX6DL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 +- MX6DL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 +- MX6DL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 +- >; +- }; +- +- pinctrl_enet_2: enetgrp-2 { +- fsl,pins = < +- MX6DL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 +- MX6DL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 +- MX6DL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 +- MX6DL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 +- MX6DL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 +- MX6DL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 +- MX6DL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 +- MX6DL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 +- MX6DL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 +- MX6DL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 +- MX6DL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 +- MX6DL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 +- MX6DL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 +- MX6DL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 +- MX6DL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 +- >; +- }; +- }; +- +- uart1 { +- pinctrl_uart1_1: uart1grp-1 { +- fsl,pins = < +- MX6DL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 +- MX6DL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 +- >; +- }; +- }; +- +- uart4 { +- pinctrl_uart4_1: uart4grp-1 { +- fsl,pins = < +- MX6DL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 +- MX6DL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 +- >; +- }; +- }; +- +- usbotg { +- pinctrl_usbotg_2: usbotggrp-2 { +- fsl,pins = < +- MX6DL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 +- >; +- }; +- }; +- +- usdhc2 { +- pinctrl_usdhc2_1: usdhc2grp-1 { +- fsl,pins = < +- MX6DL_PAD_SD2_CMD__SD2_CMD 0x17059 +- MX6DL_PAD_SD2_CLK__SD2_CLK 0x10059 +- MX6DL_PAD_SD2_DAT0__SD2_DATA0 0x17059 +- MX6DL_PAD_SD2_DAT1__SD2_DATA1 0x17059 +- MX6DL_PAD_SD2_DAT2__SD2_DATA2 0x17059 +- MX6DL_PAD_SD2_DAT3__SD2_DATA3 0x17059 +- MX6DL_PAD_NANDF_D4__SD2_DATA4 0x17059 +- MX6DL_PAD_NANDF_D5__SD2_DATA5 0x17059 +- MX6DL_PAD_NANDF_D6__SD2_DATA6 0x17059 +- MX6DL_PAD_NANDF_D7__SD2_DATA7 0x17059 +- >; +- }; +- }; +- +- usdhc3 { +- pinctrl_usdhc3_1: usdhc3grp-1 { +- fsl,pins = < +- MX6DL_PAD_SD3_CMD__SD3_CMD 0x17059 +- MX6DL_PAD_SD3_CLK__SD3_CLK 0x10059 +- MX6DL_PAD_SD3_DAT0__SD3_DATA0 0x17059 +- MX6DL_PAD_SD3_DAT1__SD3_DATA1 0x17059 +- MX6DL_PAD_SD3_DAT2__SD3_DATA2 0x17059 +- MX6DL_PAD_SD3_DAT3__SD3_DATA3 0x17059 +- MX6DL_PAD_SD3_DAT4__SD3_DATA4 0x17059 +- MX6DL_PAD_SD3_DAT5__SD3_DATA5 0x17059 +- MX6DL_PAD_SD3_DAT6__SD3_DATA6 0x17059 +- MX6DL_PAD_SD3_DAT7__SD3_DATA7 0x17059 +- >; +- }; +- +- pinctrl_usdhc3_2: usdhc3grp_2 { +- fsl,pins = < +- MX6DL_PAD_SD3_CMD__SD3_CMD 0x17059 +- MX6DL_PAD_SD3_CLK__SD3_CLK 0x10059 +- MX6DL_PAD_SD3_DAT0__SD3_DATA0 0x17059 +- MX6DL_PAD_SD3_DAT1__SD3_DATA1 0x17059 +- MX6DL_PAD_SD3_DAT2__SD3_DATA2 0x17059 +- MX6DL_PAD_SD3_DAT3__SD3_DATA3 0x17059 +- >; +- }; +- }; ++ busfreq { /* BUSFREQ */ ++ compatible = "fsl,imx6_busfreq"; ++ clocks = <&clks 171>, <&clks 6>, <&clks 11>, <&clks 104>, <&clks 172>, <&clks 58>, ++ <&clks 18>, <&clks 60>, <&clks 20>, <&clks 3>, <&clks 22> , <&clks 8>; ++ clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", "periph", ++ "periph_pre", "periph_clk2", "periph_clk2_sel", "osc", "axi_sel", "pll3_pfd1_540m"; ++ interrupts = <0 107 0x04>, <0 112 0x4>; ++ interrupt-names = "irq_busfreq_0", "irq_busfreq_1"; ++ fsl,max_ddr_freq = <400000000>; ++ }; ++ ++ gpu: gpu@00130000 { ++ compatible = "fsl,imx6dl-gpu", "fsl,imx6q-gpu"; ++ reg = <0x00130000 0x4000>, <0x00134000 0x4000>, ++ <0x0 0x0>; ++ reg-names = "iobase_3d", "iobase_2d", ++ "phys_baseaddr"; ++ interrupts = <0 9 0x04>, <0 10 0x04>; ++ interrupt-names = "irq_3d", "irq_2d"; ++ clocks = <&clks 143>, <&clks 27>, ++ <&clks 121>, <&clks 122>, ++ <&clks 0>; ++ clock-names = "gpu2d_axi_clk", "gpu3d_axi_clk", ++ "gpu2d_clk", "gpu3d_clk", ++ "gpu3d_shader_clk"; ++ resets = <&src 0>, <&src 3>; ++ reset-names = "gpu3d", "gpu2d"; ++ pu-supply = <®_pu>; ++ }; ++ ++ ocram: sram@00900000 { ++ compatible = "mmio-sram"; ++ reg = <0x00900000 0x20000>; ++ clocks = <&clks 142>; ++ }; + ++ hdmi_core: hdmi_core@00120000 { ++ compatible = "fsl,imx6dl-hdmi-core"; ++ reg = <0x00120000 0x9000>; ++ clocks = <&clks 124>, <&clks 123>; ++ clock-names = "hdmi_isfr", "hdmi_iahb"; ++ status = "disabled"; ++ }; ++ ++ hdmi_video: hdmi_video@020e0000 { ++ compatible = "fsl,imx6dl-hdmi-video"; ++ reg = <0x020e0000 0x1000>; ++ reg-names = "hdmi_gpr"; ++ interrupts = <0 115 0x04>; ++ clocks = <&clks 124>, <&clks 123>; ++ clock-names = "hdmi_isfr", "hdmi_iahb"; ++ status = "disabled"; ++ }; ++ ++ hdmi_audio: hdmi_audio@00120000 { ++ compatible = "fsl,imx6dl-hdmi-audio"; ++ clocks = <&clks 124>, <&clks 123>; ++ clock-names = "hdmi_isfr", "hdmi_iahb"; ++ dmas = <&sdma 2 22 0>; ++ dma-names = "tx"; ++ status = "disabled"; ++ }; ++ ++ hdmi_cec: hdmi_cec@00120000 { ++ compatible = "fsl,imx6dl-hdmi-cec"; ++ interrupts = <0 115 0x04>; ++ status = "disabled"; ++ }; ++ ++ aips1: aips-bus@02000000 { ++ vpu@02040000 { ++ iramsize = <0>; ++ status = "okay"; ++ }; + ++ iomuxc: iomuxc@020e0000 { ++ compatible = "fsl,imx6dl-iomuxc"; + }; + + pxp: pxp@020f0000 { ++ compatible = "fsl,imx6dl-pxp-dma"; + reg = <0x020f0000 0x4000>; + interrupts = <0 98 0x04>; ++ clocks = <&clks 133>; ++ clock-names = "pxp-axi"; ++ status = "disabled"; + }; + + epdc: epdc@020f4000 { ++ compatible = "fsl,imx6dl-epdc"; + reg = <0x020f4000 0x4000>; + interrupts = <0 97 0x04>; ++ clocks = <&clks 133>, <&clks 137>; ++ clock-names = "epdc_axi", "epdc_pix"; + }; + + lcdif: lcdif@020f8000 { +@@ -171,6 +176,16 @@ + }; + + aips2: aips-bus@02100000 { ++ mipi_dsi: mipi@021e0000 { ++ compatible = "fsl,imx6dl-mipi-dsi"; ++ reg = <0x021e0000 0x4000>; ++ interrupts = <0 102 0x04>; ++ gpr = <&gpr>; ++ clocks = <&clks 138>, <&clks 204>; ++ clock-names = "mipi_pllref_clk", "mipi_cfg_clk"; ++ status = "disabled"; ++ }; ++ + i2c4: i2c@021f8000 { + #address-cells = <1>; + #size-cells = <0>; +@@ -182,3 +197,54 @@ + }; + }; + }; ++ ++&ldb { ++ clocks = <&clks 33>, <&clks 34>, ++ <&clks 39>, <&clks 40>, ++ <&clks 135>, <&clks 136>; ++ clock-names = "di0_pll", "di1_pll", ++ "di0_sel", "di1_sel", ++ "di0", "di1"; ++ ++ lvds-channel@0 { ++ crtcs = <&ipu1 0>, <&ipu1 1>; ++ }; ++ ++ lvds-channel@1 { ++ crtcs = <&ipu1 0>, <&ipu1 1>; ++ }; ++}; ++ ++&iomuxc { ++ epdc { ++ pinctrl_epdc_0: epdcgrp-0 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_A16__EPDC_DATA00 0x80000000 ++ MX6QDL_PAD_EIM_DA10__EPDC_DATA01 0x80000000 ++ MX6QDL_PAD_EIM_DA12__EPDC_DATA02 0x80000000 ++ MX6QDL_PAD_EIM_DA11__EPDC_DATA03 0x80000000 ++ MX6QDL_PAD_EIM_LBA__EPDC_DATA04 0x80000000 ++ MX6QDL_PAD_EIM_EB2__EPDC_DATA05 0x80000000 ++ MX6QDL_PAD_EIM_CS0__EPDC_DATA06 0x80000000 ++ MX6QDL_PAD_EIM_RW__EPDC_DATA07 0x80000000 ++ MX6QDL_PAD_EIM_A21__EPDC_GDCLK 0x80000000 ++ MX6QDL_PAD_EIM_A22__EPDC_GDSP 0x80000000 ++ MX6QDL_PAD_EIM_A23__EPDC_GDOE 0x80000000 ++ MX6QDL_PAD_EIM_A24__EPDC_GDRL 0x80000000 ++ MX6QDL_PAD_EIM_D31__EPDC_SDCLK_P 0x80000000 ++ MX6QDL_PAD_EIM_D27__EPDC_SDOE 0x80000000 ++ MX6QDL_PAD_EIM_DA1__EPDC_SDLE 0x80000000 ++ MX6QDL_PAD_EIM_EB1__EPDC_SDSHR 0x80000000 ++ MX6QDL_PAD_EIM_DA2__EPDC_BDR0 0x80000000 ++ MX6QDL_PAD_EIM_DA4__EPDC_SDCE0 0x80000000 ++ MX6QDL_PAD_EIM_DA5__EPDC_SDCE1 0x80000000 ++ MX6QDL_PAD_EIM_DA6__EPDC_SDCE2 0x80000000 ++ >; ++ }; ++ }; ++}; ++ ++&hdmi { ++ compatible = "fsl,imx6dl-hdmi"; ++ crtcs = <&ipu1 0>, <&ipu1 1>; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q-arm2.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-arm2.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6q-arm2.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-arm2.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -31,6 +31,15 @@ + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; ++ ++ reg_usb_otg_vbus: usb_otg_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio3 22 0>; ++ enable-active-high; ++ }; + }; + + leds { +@@ -42,6 +51,15 @@ + linux,default-trigger = "heartbeat"; + }; + }; ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif", ++ "fsl,imx-sabreauto-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-out; ++ spdif-in; ++ }; + }; + + &gpmi { +@@ -57,7 +75,7 @@ + hog { + pinctrl_hog: hoggrp { + fsl,pins = < +- MX6Q_PAD_EIM_D25__GPIO3_IO25 0x80000000 ++ MX6QDL_PAD_EIM_D25__GPIO3_IO25 0x80000000 + >; + }; + }; +@@ -65,8 +83,8 @@ + arm2 { + pinctrl_usdhc3_arm2: usdhc3grp-arm2 { + fsl,pins = < +- MX6Q_PAD_NANDF_CS0__GPIO6_IO11 0x80000000 +- MX6Q_PAD_NANDF_CS1__GPIO6_IO14 0x80000000 ++ MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x80000000 ++ MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x80000000 + >; + }; + }; +@@ -79,6 +97,14 @@ + status = "okay"; + }; + ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg_1>; ++ disable-over-current; ++ status = "okay"; ++}; ++ + &usdhc3 { + cd-gpios = <&gpio6 11 0>; + wp-gpios = <&gpio6 14 0>; +@@ -97,6 +123,30 @@ + status = "okay"; + }; + ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2_2>; ++ fsl,dte-mode; ++ fsl,uart-has-rtscts; ++ status = "okay"; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_spdif_2>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2_2>; ++ fsl,dte-mode; ++ fsl,uart-has-rtscts; ++ dma-names = "rx", "tx"; ++ dmas = <&sdma 27 4 0>, <&sdma 28 4 0>; ++ status = "okay"; ++}; ++ + &uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4_1>; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q-cubox-i.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-cubox-i.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6q-cubox-i.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-cubox-i.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,16 @@ ++/* ++ * Copyright (C) 2014 Russell King ++ */ ++/dts-v1/; ++ ++#include "imx6q.dtsi" ++#include "imx6qdl-cubox-i.dtsi" ++ ++/ { ++ model = "SolidRun Cubox-i Dual/Quad"; ++ compatible = "solidrun,cubox-i/q", "fsl,imx6q"; ++}; ++ ++&sata { ++ status = "okay"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q-pinfunc.h linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-pinfunc.h +--- linux-3.10.30/arch/arm/boot/dts/imx6q-pinfunc.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-pinfunc.h 2014-03-08 20:32:53.000000000 +0100 +@@ -14,1028 +14,1032 @@ + * The pin function ID is a tuple of + * + */ +-#define MX6Q_PAD_SD2_DAT1__SD2_DATA1 0x04c 0x360 0x000 0x0 0x0 +-#define MX6Q_PAD_SD2_DAT1__ECSPI5_SS0 0x04c 0x360 0x834 0x1 0x0 +-#define MX6Q_PAD_SD2_DAT1__EIM_CS2_B 0x04c 0x360 0x000 0x2 0x0 +-#define MX6Q_PAD_SD2_DAT1__AUD4_TXFS 0x04c 0x360 0x7c8 0x3 0x0 +-#define MX6Q_PAD_SD2_DAT1__KEY_COL7 0x04c 0x360 0x8f0 0x4 0x0 +-#define MX6Q_PAD_SD2_DAT1__GPIO1_IO14 0x04c 0x360 0x000 0x5 0x0 +-#define MX6Q_PAD_SD2_DAT2__SD2_DATA2 0x050 0x364 0x000 0x0 0x0 +-#define MX6Q_PAD_SD2_DAT2__ECSPI5_SS1 0x050 0x364 0x838 0x1 0x0 +-#define MX6Q_PAD_SD2_DAT2__EIM_CS3_B 0x050 0x364 0x000 0x2 0x0 +-#define MX6Q_PAD_SD2_DAT2__AUD4_TXD 0x050 0x364 0x7b8 0x3 0x0 +-#define MX6Q_PAD_SD2_DAT2__KEY_ROW6 0x050 0x364 0x8f8 0x4 0x0 +-#define MX6Q_PAD_SD2_DAT2__GPIO1_IO13 0x050 0x364 0x000 0x5 0x0 +-#define MX6Q_PAD_SD2_DAT0__SD2_DATA0 0x054 0x368 0x000 0x0 0x0 +-#define MX6Q_PAD_SD2_DAT0__ECSPI5_MISO 0x054 0x368 0x82c 0x1 0x0 +-#define MX6Q_PAD_SD2_DAT0__AUD4_RXD 0x054 0x368 0x7b4 0x3 0x0 +-#define MX6Q_PAD_SD2_DAT0__KEY_ROW7 0x054 0x368 0x8fc 0x4 0x0 +-#define MX6Q_PAD_SD2_DAT0__GPIO1_IO15 0x054 0x368 0x000 0x5 0x0 +-#define MX6Q_PAD_SD2_DAT0__DCIC2_OUT 0x054 0x368 0x000 0x6 0x0 +-#define MX6Q_PAD_RGMII_TXC__USB_H2_DATA 0x058 0x36c 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_TXC__RGMII_TXC 0x058 0x36c 0x000 0x1 0x0 +-#define MX6Q_PAD_RGMII_TXC__SPDIF_EXT_CLK 0x058 0x36c 0x918 0x2 0x0 +-#define MX6Q_PAD_RGMII_TXC__GPIO6_IO19 0x058 0x36c 0x000 0x5 0x0 +-#define MX6Q_PAD_RGMII_TXC__XTALOSC_REF_CLK_24M 0x058 0x36c 0x000 0x7 0x0 +-#define MX6Q_PAD_RGMII_TD0__HSI_TX_READY 0x05c 0x370 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_TD0__RGMII_TD0 0x05c 0x370 0x000 0x1 0x0 +-#define MX6Q_PAD_RGMII_TD0__GPIO6_IO20 0x05c 0x370 0x000 0x5 0x0 +-#define MX6Q_PAD_RGMII_TD1__HSI_RX_FLAG 0x060 0x374 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_TD1__RGMII_TD1 0x060 0x374 0x000 0x1 0x0 +-#define MX6Q_PAD_RGMII_TD1__GPIO6_IO21 0x060 0x374 0x000 0x5 0x0 +-#define MX6Q_PAD_RGMII_TD2__HSI_RX_DATA 0x064 0x378 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_TD2__RGMII_TD2 0x064 0x378 0x000 0x1 0x0 +-#define MX6Q_PAD_RGMII_TD2__GPIO6_IO22 0x064 0x378 0x000 0x5 0x0 +-#define MX6Q_PAD_RGMII_TD3__HSI_RX_WAKE 0x068 0x37c 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_TD3__RGMII_TD3 0x068 0x37c 0x000 0x1 0x0 +-#define MX6Q_PAD_RGMII_TD3__GPIO6_IO23 0x068 0x37c 0x000 0x5 0x0 +-#define MX6Q_PAD_RGMII_RX_CTL__USB_H3_DATA 0x06c 0x380 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x06c 0x380 0x858 0x1 0x0 +-#define MX6Q_PAD_RGMII_RX_CTL__GPIO6_IO24 0x06c 0x380 0x000 0x5 0x0 +-#define MX6Q_PAD_RGMII_RD0__HSI_RX_READY 0x070 0x384 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_RD0__RGMII_RD0 0x070 0x384 0x848 0x1 0x0 +-#define MX6Q_PAD_RGMII_RD0__GPIO6_IO25 0x070 0x384 0x000 0x5 0x0 +-#define MX6Q_PAD_RGMII_TX_CTL__USB_H2_STROBE 0x074 0x388 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x074 0x388 0x000 0x1 0x0 +-#define MX6Q_PAD_RGMII_TX_CTL__GPIO6_IO26 0x074 0x388 0x000 0x5 0x0 +-#define MX6Q_PAD_RGMII_TX_CTL__ENET_REF_CLK 0x074 0x388 0x83c 0x7 0x0 +-#define MX6Q_PAD_RGMII_RD1__HSI_TX_FLAG 0x078 0x38c 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_RD1__RGMII_RD1 0x078 0x38c 0x84c 0x1 0x0 +-#define MX6Q_PAD_RGMII_RD1__GPIO6_IO27 0x078 0x38c 0x000 0x5 0x0 +-#define MX6Q_PAD_RGMII_RD2__HSI_TX_DATA 0x07c 0x390 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_RD2__RGMII_RD2 0x07c 0x390 0x850 0x1 0x0 +-#define MX6Q_PAD_RGMII_RD2__GPIO6_IO28 0x07c 0x390 0x000 0x5 0x0 +-#define MX6Q_PAD_RGMII_RD3__HSI_TX_WAKE 0x080 0x394 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_RD3__RGMII_RD3 0x080 0x394 0x854 0x1 0x0 +-#define MX6Q_PAD_RGMII_RD3__GPIO6_IO29 0x080 0x394 0x000 0x5 0x0 +-#define MX6Q_PAD_RGMII_RXC__USB_H3_STROBE 0x084 0x398 0x000 0x0 0x0 +-#define MX6Q_PAD_RGMII_RXC__RGMII_RXC 0x084 0x398 0x844 0x1 0x0 +-#define MX6Q_PAD_RGMII_RXC__GPIO6_IO30 0x084 0x398 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_A25__EIM_ADDR25 0x088 0x39c 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_A25__ECSPI4_SS1 0x088 0x39c 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_A25__ECSPI2_RDY 0x088 0x39c 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_A25__IPU1_DI1_PIN12 0x088 0x39c 0x000 0x3 0x0 +-#define MX6Q_PAD_EIM_A25__IPU1_DI0_D1_CS 0x088 0x39c 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_A25__GPIO5_IO02 0x088 0x39c 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x088 0x39c 0x88c 0x6 0x0 +-#define MX6Q_PAD_EIM_EB2__EIM_EB2_B 0x08c 0x3a0 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_EB2__ECSPI1_SS0 0x08c 0x3a0 0x800 0x1 0x0 +-#define MX6Q_PAD_EIM_EB2__IPU2_CSI1_DATA19 0x08c 0x3a0 0x8d4 0x3 0x0 +-#define MX6Q_PAD_EIM_EB2__HDMI_TX_DDC_SCL 0x08c 0x3a0 0x890 0x4 0x0 +-#define MX6Q_PAD_EIM_EB2__GPIO2_IO30 0x08c 0x3a0 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_EB2__I2C2_SCL 0x08c 0x3a0 0x8a0 0x6 0x0 +-#define MX6Q_PAD_EIM_EB2__SRC_BOOT_CFG30 0x08c 0x3a0 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_D16__EIM_DATA16 0x090 0x3a4 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D16__ECSPI1_SCLK 0x090 0x3a4 0x7f4 0x1 0x0 +-#define MX6Q_PAD_EIM_D16__IPU1_DI0_PIN05 0x090 0x3a4 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D16__IPU2_CSI1_DATA18 0x090 0x3a4 0x8d0 0x3 0x0 +-#define MX6Q_PAD_EIM_D16__HDMI_TX_DDC_SDA 0x090 0x3a4 0x894 0x4 0x0 +-#define MX6Q_PAD_EIM_D16__GPIO3_IO16 0x090 0x3a4 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D16__I2C2_SDA 0x090 0x3a4 0x8a4 0x6 0x0 +-#define MX6Q_PAD_EIM_D17__EIM_DATA17 0x094 0x3a8 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D17__ECSPI1_MISO 0x094 0x3a8 0x7f8 0x1 0x0 +-#define MX6Q_PAD_EIM_D17__IPU1_DI0_PIN06 0x094 0x3a8 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D17__IPU2_CSI1_PIXCLK 0x094 0x3a8 0x8e0 0x3 0x0 +-#define MX6Q_PAD_EIM_D17__DCIC1_OUT 0x094 0x3a8 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D17__GPIO3_IO17 0x094 0x3a8 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D17__I2C3_SCL 0x094 0x3a8 0x8a8 0x6 0x0 +-#define MX6Q_PAD_EIM_D18__EIM_DATA18 0x098 0x3ac 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D18__ECSPI1_MOSI 0x098 0x3ac 0x7fc 0x1 0x0 +-#define MX6Q_PAD_EIM_D18__IPU1_DI0_PIN07 0x098 0x3ac 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D18__IPU2_CSI1_DATA17 0x098 0x3ac 0x8cc 0x3 0x0 +-#define MX6Q_PAD_EIM_D18__IPU1_DI1_D0_CS 0x098 0x3ac 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D18__GPIO3_IO18 0x098 0x3ac 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D18__I2C3_SDA 0x098 0x3ac 0x8ac 0x6 0x0 +-#define MX6Q_PAD_EIM_D19__EIM_DATA19 0x09c 0x3b0 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D19__ECSPI1_SS1 0x09c 0x3b0 0x804 0x1 0x0 +-#define MX6Q_PAD_EIM_D19__IPU1_DI0_PIN08 0x09c 0x3b0 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D19__IPU2_CSI1_DATA16 0x09c 0x3b0 0x8c8 0x3 0x0 +-#define MX6Q_PAD_EIM_D19__UART1_CTS_B 0x09c 0x3b0 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D19__UART1_RTS_B 0x09c 0x3b0 0x91c 0x4 0x0 +-#define MX6Q_PAD_EIM_D19__GPIO3_IO19 0x09c 0x3b0 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D19__EPIT1_OUT 0x09c 0x3b0 0x000 0x6 0x0 +-#define MX6Q_PAD_EIM_D20__EIM_DATA20 0x0a0 0x3b4 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D20__ECSPI4_SS0 0x0a0 0x3b4 0x824 0x1 0x0 +-#define MX6Q_PAD_EIM_D20__IPU1_DI0_PIN16 0x0a0 0x3b4 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D20__IPU2_CSI1_DATA15 0x0a0 0x3b4 0x8c4 0x3 0x0 +-#define MX6Q_PAD_EIM_D20__UART1_RTS_B 0x0a0 0x3b4 0x91c 0x4 0x1 +-#define MX6Q_PAD_EIM_D20__UART1_CTS_B 0x0a0 0x3b4 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D20__GPIO3_IO20 0x0a0 0x3b4 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D20__EPIT2_OUT 0x0a0 0x3b4 0x000 0x6 0x0 +-#define MX6Q_PAD_EIM_D21__EIM_DATA21 0x0a4 0x3b8 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D21__ECSPI4_SCLK 0x0a4 0x3b8 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_D21__IPU1_DI0_PIN17 0x0a4 0x3b8 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D21__IPU2_CSI1_DATA11 0x0a4 0x3b8 0x8b4 0x3 0x0 +-#define MX6Q_PAD_EIM_D21__USB_OTG_OC 0x0a4 0x3b8 0x944 0x4 0x0 +-#define MX6Q_PAD_EIM_D21__GPIO3_IO21 0x0a4 0x3b8 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D21__I2C1_SCL 0x0a4 0x3b8 0x898 0x6 0x0 +-#define MX6Q_PAD_EIM_D21__SPDIF_IN 0x0a4 0x3b8 0x914 0x7 0x0 +-#define MX6Q_PAD_EIM_D22__EIM_DATA22 0x0a8 0x3bc 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D22__ECSPI4_MISO 0x0a8 0x3bc 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_D22__IPU1_DI0_PIN01 0x0a8 0x3bc 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D22__IPU2_CSI1_DATA10 0x0a8 0x3bc 0x8b0 0x3 0x0 +-#define MX6Q_PAD_EIM_D22__USB_OTG_PWR 0x0a8 0x3bc 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D22__GPIO3_IO22 0x0a8 0x3bc 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D22__SPDIF_OUT 0x0a8 0x3bc 0x000 0x6 0x0 +-#define MX6Q_PAD_EIM_D23__EIM_DATA23 0x0ac 0x3c0 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D23__IPU1_DI0_D0_CS 0x0ac 0x3c0 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_D23__UART3_CTS_B 0x0ac 0x3c0 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D23__UART3_RTS_B 0x0ac 0x3c0 0x92c 0x2 0x0 +-#define MX6Q_PAD_EIM_D23__UART1_DCD_B 0x0ac 0x3c0 0x000 0x3 0x0 +-#define MX6Q_PAD_EIM_D23__IPU2_CSI1_DATA_EN 0x0ac 0x3c0 0x8d8 0x4 0x0 +-#define MX6Q_PAD_EIM_D23__GPIO3_IO23 0x0ac 0x3c0 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D23__IPU1_DI1_PIN02 0x0ac 0x3c0 0x000 0x6 0x0 +-#define MX6Q_PAD_EIM_D23__IPU1_DI1_PIN14 0x0ac 0x3c0 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_EB3__EIM_EB3_B 0x0b0 0x3c4 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_EB3__ECSPI4_RDY 0x0b0 0x3c4 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_EB3__UART3_RTS_B 0x0b0 0x3c4 0x92c 0x2 0x1 +-#define MX6Q_PAD_EIM_EB3__UART3_CTS_B 0x0b0 0x3c4 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_EB3__UART1_RI_B 0x0b0 0x3c4 0x000 0x3 0x0 +-#define MX6Q_PAD_EIM_EB3__IPU2_CSI1_HSYNC 0x0b0 0x3c4 0x8dc 0x4 0x0 +-#define MX6Q_PAD_EIM_EB3__GPIO2_IO31 0x0b0 0x3c4 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_EB3__IPU1_DI1_PIN03 0x0b0 0x3c4 0x000 0x6 0x0 +-#define MX6Q_PAD_EIM_EB3__SRC_BOOT_CFG31 0x0b0 0x3c4 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_D24__EIM_DATA24 0x0b4 0x3c8 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D24__ECSPI4_SS2 0x0b4 0x3c8 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_D24__UART3_TX_DATA 0x0b4 0x3c8 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D24__UART3_RX_DATA 0x0b4 0x3c8 0x930 0x2 0x0 +-#define MX6Q_PAD_EIM_D24__ECSPI1_SS2 0x0b4 0x3c8 0x808 0x3 0x0 +-#define MX6Q_PAD_EIM_D24__ECSPI2_SS2 0x0b4 0x3c8 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D24__GPIO3_IO24 0x0b4 0x3c8 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D24__AUD5_RXFS 0x0b4 0x3c8 0x7d8 0x6 0x0 +-#define MX6Q_PAD_EIM_D24__UART1_DTR_B 0x0b4 0x3c8 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_D25__EIM_DATA25 0x0b8 0x3cc 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D25__ECSPI4_SS3 0x0b8 0x3cc 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_D25__UART3_RX_DATA 0x0b8 0x3cc 0x930 0x2 0x1 +-#define MX6Q_PAD_EIM_D25__UART3_TX_DATA 0x0b8 0x3cc 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D25__ECSPI1_SS3 0x0b8 0x3cc 0x80c 0x3 0x0 +-#define MX6Q_PAD_EIM_D25__ECSPI2_SS3 0x0b8 0x3cc 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D25__GPIO3_IO25 0x0b8 0x3cc 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D25__AUD5_RXC 0x0b8 0x3cc 0x7d4 0x6 0x0 +-#define MX6Q_PAD_EIM_D25__UART1_DSR_B 0x0b8 0x3cc 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_D26__EIM_DATA26 0x0bc 0x3d0 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D26__IPU1_DI1_PIN11 0x0bc 0x3d0 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_D26__IPU1_CSI0_DATA01 0x0bc 0x3d0 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D26__IPU2_CSI1_DATA14 0x0bc 0x3d0 0x8c0 0x3 0x0 +-#define MX6Q_PAD_EIM_D26__UART2_TX_DATA 0x0bc 0x3d0 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D26__UART2_RX_DATA 0x0bc 0x3d0 0x928 0x4 0x0 +-#define MX6Q_PAD_EIM_D26__GPIO3_IO26 0x0bc 0x3d0 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D26__IPU1_SISG2 0x0bc 0x3d0 0x000 0x6 0x0 +-#define MX6Q_PAD_EIM_D26__IPU1_DISP1_DATA22 0x0bc 0x3d0 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_D27__EIM_DATA27 0x0c0 0x3d4 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D27__IPU1_DI1_PIN13 0x0c0 0x3d4 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_D27__IPU1_CSI0_DATA00 0x0c0 0x3d4 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D27__IPU2_CSI1_DATA13 0x0c0 0x3d4 0x8bc 0x3 0x0 +-#define MX6Q_PAD_EIM_D27__UART2_RX_DATA 0x0c0 0x3d4 0x928 0x4 0x1 +-#define MX6Q_PAD_EIM_D27__UART2_TX_DATA 0x0c0 0x3d4 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D27__GPIO3_IO27 0x0c0 0x3d4 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D27__IPU1_SISG3 0x0c0 0x3d4 0x000 0x6 0x0 +-#define MX6Q_PAD_EIM_D27__IPU1_DISP1_DATA23 0x0c0 0x3d4 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_D28__EIM_DATA28 0x0c4 0x3d8 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D28__I2C1_SDA 0x0c4 0x3d8 0x89c 0x1 0x0 +-#define MX6Q_PAD_EIM_D28__ECSPI4_MOSI 0x0c4 0x3d8 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D28__IPU2_CSI1_DATA12 0x0c4 0x3d8 0x8b8 0x3 0x0 +-#define MX6Q_PAD_EIM_D28__UART2_CTS_B 0x0c4 0x3d8 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D28__UART2_RTS_B 0x0c4 0x3d8 0x924 0x4 0x0 +-#define MX6Q_PAD_EIM_D28__GPIO3_IO28 0x0c4 0x3d8 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D28__IPU1_EXT_TRIG 0x0c4 0x3d8 0x000 0x6 0x0 +-#define MX6Q_PAD_EIM_D28__IPU1_DI0_PIN13 0x0c4 0x3d8 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_D29__EIM_DATA29 0x0c8 0x3dc 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D29__IPU1_DI1_PIN15 0x0c8 0x3dc 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_D29__ECSPI4_SS0 0x0c8 0x3dc 0x824 0x2 0x1 +-#define MX6Q_PAD_EIM_D29__UART2_RTS_B 0x0c8 0x3dc 0x924 0x4 0x1 +-#define MX6Q_PAD_EIM_D29__UART2_CTS_B 0x0c8 0x3dc 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D29__GPIO3_IO29 0x0c8 0x3dc 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D29__IPU2_CSI1_VSYNC 0x0c8 0x3dc 0x8e4 0x6 0x0 +-#define MX6Q_PAD_EIM_D29__IPU1_DI0_PIN14 0x0c8 0x3dc 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_D30__EIM_DATA30 0x0cc 0x3e0 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D30__IPU1_DISP1_DATA21 0x0cc 0x3e0 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_D30__IPU1_DI0_PIN11 0x0cc 0x3e0 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D30__IPU1_CSI0_DATA03 0x0cc 0x3e0 0x000 0x3 0x0 +-#define MX6Q_PAD_EIM_D30__UART3_CTS_B 0x0cc 0x3e0 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D30__UART3_RTS_B 0x0cc 0x3e0 0x92c 0x4 0x2 +-#define MX6Q_PAD_EIM_D30__GPIO3_IO30 0x0cc 0x3e0 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D30__USB_H1_OC 0x0cc 0x3e0 0x948 0x6 0x0 +-#define MX6Q_PAD_EIM_D31__EIM_DATA31 0x0d0 0x3e4 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_D31__IPU1_DISP1_DATA20 0x0d0 0x3e4 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_D31__IPU1_DI0_PIN12 0x0d0 0x3e4 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_D31__IPU1_CSI0_DATA02 0x0d0 0x3e4 0x000 0x3 0x0 +-#define MX6Q_PAD_EIM_D31__UART3_RTS_B 0x0d0 0x3e4 0x92c 0x4 0x3 +-#define MX6Q_PAD_EIM_D31__UART3_CTS_B 0x0d0 0x3e4 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_D31__GPIO3_IO31 0x0d0 0x3e4 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_D31__USB_H1_PWR 0x0d0 0x3e4 0x000 0x6 0x0 +-#define MX6Q_PAD_EIM_A24__EIM_ADDR24 0x0d4 0x3e8 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_A24__IPU1_DISP1_DATA19 0x0d4 0x3e8 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_A24__IPU2_CSI1_DATA19 0x0d4 0x3e8 0x8d4 0x2 0x1 +-#define MX6Q_PAD_EIM_A24__IPU2_SISG2 0x0d4 0x3e8 0x000 0x3 0x0 +-#define MX6Q_PAD_EIM_A24__IPU1_SISG2 0x0d4 0x3e8 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_A24__GPIO5_IO04 0x0d4 0x3e8 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_A24__SRC_BOOT_CFG24 0x0d4 0x3e8 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_A23__EIM_ADDR23 0x0d8 0x3ec 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_A23__IPU1_DISP1_DATA18 0x0d8 0x3ec 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_A23__IPU2_CSI1_DATA18 0x0d8 0x3ec 0x8d0 0x2 0x1 +-#define MX6Q_PAD_EIM_A23__IPU2_SISG3 0x0d8 0x3ec 0x000 0x3 0x0 +-#define MX6Q_PAD_EIM_A23__IPU1_SISG3 0x0d8 0x3ec 0x000 0x4 0x0 +-#define MX6Q_PAD_EIM_A23__GPIO6_IO06 0x0d8 0x3ec 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_A23__SRC_BOOT_CFG23 0x0d8 0x3ec 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_A22__EIM_ADDR22 0x0dc 0x3f0 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_A22__IPU1_DISP1_DATA17 0x0dc 0x3f0 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_A22__IPU2_CSI1_DATA17 0x0dc 0x3f0 0x8cc 0x2 0x1 +-#define MX6Q_PAD_EIM_A22__GPIO2_IO16 0x0dc 0x3f0 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_A22__SRC_BOOT_CFG22 0x0dc 0x3f0 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_A21__EIM_ADDR21 0x0e0 0x3f4 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_A21__IPU1_DISP1_DATA16 0x0e0 0x3f4 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_A21__IPU2_CSI1_DATA16 0x0e0 0x3f4 0x8c8 0x2 0x1 +-#define MX6Q_PAD_EIM_A21__GPIO2_IO17 0x0e0 0x3f4 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_A21__SRC_BOOT_CFG21 0x0e0 0x3f4 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_A20__EIM_ADDR20 0x0e4 0x3f8 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_A20__IPU1_DISP1_DATA15 0x0e4 0x3f8 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_A20__IPU2_CSI1_DATA15 0x0e4 0x3f8 0x8c4 0x2 0x1 +-#define MX6Q_PAD_EIM_A20__GPIO2_IO18 0x0e4 0x3f8 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_A20__SRC_BOOT_CFG20 0x0e4 0x3f8 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_A19__EIM_ADDR19 0x0e8 0x3fc 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_A19__IPU1_DISP1_DATA14 0x0e8 0x3fc 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_A19__IPU2_CSI1_DATA14 0x0e8 0x3fc 0x8c0 0x2 0x1 +-#define MX6Q_PAD_EIM_A19__GPIO2_IO19 0x0e8 0x3fc 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_A19__SRC_BOOT_CFG19 0x0e8 0x3fc 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_A18__EIM_ADDR18 0x0ec 0x400 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_A18__IPU1_DISP1_DATA13 0x0ec 0x400 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_A18__IPU2_CSI1_DATA13 0x0ec 0x400 0x8bc 0x2 0x1 +-#define MX6Q_PAD_EIM_A18__GPIO2_IO20 0x0ec 0x400 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_A18__SRC_BOOT_CFG18 0x0ec 0x400 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_A17__EIM_ADDR17 0x0f0 0x404 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_A17__IPU1_DISP1_DATA12 0x0f0 0x404 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_A17__IPU2_CSI1_DATA12 0x0f0 0x404 0x8b8 0x2 0x1 +-#define MX6Q_PAD_EIM_A17__GPIO2_IO21 0x0f0 0x404 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_A17__SRC_BOOT_CFG17 0x0f0 0x404 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_A16__EIM_ADDR16 0x0f4 0x408 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_A16__IPU1_DI1_DISP_CLK 0x0f4 0x408 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_A16__IPU2_CSI1_PIXCLK 0x0f4 0x408 0x8e0 0x2 0x1 +-#define MX6Q_PAD_EIM_A16__GPIO2_IO22 0x0f4 0x408 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_A16__SRC_BOOT_CFG16 0x0f4 0x408 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_CS0__EIM_CS0_B 0x0f8 0x40c 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_CS0__IPU1_DI1_PIN05 0x0f8 0x40c 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_CS0__ECSPI2_SCLK 0x0f8 0x40c 0x810 0x2 0x0 +-#define MX6Q_PAD_EIM_CS0__GPIO2_IO23 0x0f8 0x40c 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_CS1__EIM_CS1_B 0x0fc 0x410 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_CS1__IPU1_DI1_PIN06 0x0fc 0x410 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_CS1__ECSPI2_MOSI 0x0fc 0x410 0x818 0x2 0x0 +-#define MX6Q_PAD_EIM_CS1__GPIO2_IO24 0x0fc 0x410 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_OE__EIM_OE_B 0x100 0x414 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_OE__IPU1_DI1_PIN07 0x100 0x414 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_OE__ECSPI2_MISO 0x100 0x414 0x814 0x2 0x0 +-#define MX6Q_PAD_EIM_OE__GPIO2_IO25 0x100 0x414 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_RW__EIM_RW 0x104 0x418 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_RW__IPU1_DI1_PIN08 0x104 0x418 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_RW__ECSPI2_SS0 0x104 0x418 0x81c 0x2 0x0 +-#define MX6Q_PAD_EIM_RW__GPIO2_IO26 0x104 0x418 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_RW__SRC_BOOT_CFG29 0x104 0x418 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_LBA__EIM_LBA_B 0x108 0x41c 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_LBA__IPU1_DI1_PIN17 0x108 0x41c 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_LBA__ECSPI2_SS1 0x108 0x41c 0x820 0x2 0x0 +-#define MX6Q_PAD_EIM_LBA__GPIO2_IO27 0x108 0x41c 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_LBA__SRC_BOOT_CFG26 0x108 0x41c 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_EB0__EIM_EB0_B 0x10c 0x420 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_EB0__IPU1_DISP1_DATA11 0x10c 0x420 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_EB0__IPU2_CSI1_DATA11 0x10c 0x420 0x8b4 0x2 0x1 +-#define MX6Q_PAD_EIM_EB0__CCM_PMIC_READY 0x10c 0x420 0x7f0 0x4 0x0 +-#define MX6Q_PAD_EIM_EB0__GPIO2_IO28 0x10c 0x420 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_EB0__SRC_BOOT_CFG27 0x10c 0x420 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_EB1__EIM_EB1_B 0x110 0x424 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_EB1__IPU1_DISP1_DATA10 0x110 0x424 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_EB1__IPU2_CSI1_DATA10 0x110 0x424 0x8b0 0x2 0x1 +-#define MX6Q_PAD_EIM_EB1__GPIO2_IO29 0x110 0x424 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_EB1__SRC_BOOT_CFG28 0x110 0x424 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA0__EIM_AD00 0x114 0x428 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA0__IPU1_DISP1_DATA09 0x114 0x428 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA0__IPU2_CSI1_DATA09 0x114 0x428 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_DA0__GPIO3_IO00 0x114 0x428 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA0__SRC_BOOT_CFG00 0x114 0x428 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA1__EIM_AD01 0x118 0x42c 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA1__IPU1_DISP1_DATA08 0x118 0x42c 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA1__IPU2_CSI1_DATA08 0x118 0x42c 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_DA1__GPIO3_IO01 0x118 0x42c 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA1__SRC_BOOT_CFG01 0x118 0x42c 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA2__EIM_AD02 0x11c 0x430 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA2__IPU1_DISP1_DATA07 0x11c 0x430 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA2__IPU2_CSI1_DATA07 0x11c 0x430 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_DA2__GPIO3_IO02 0x11c 0x430 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA2__SRC_BOOT_CFG02 0x11c 0x430 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA3__EIM_AD03 0x120 0x434 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA3__IPU1_DISP1_DATA06 0x120 0x434 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA3__IPU2_CSI1_DATA06 0x120 0x434 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_DA3__GPIO3_IO03 0x120 0x434 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA3__SRC_BOOT_CFG03 0x120 0x434 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA4__EIM_AD04 0x124 0x438 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA4__IPU1_DISP1_DATA05 0x124 0x438 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA4__IPU2_CSI1_DATA05 0x124 0x438 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_DA4__GPIO3_IO04 0x124 0x438 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA4__SRC_BOOT_CFG04 0x124 0x438 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA5__EIM_AD05 0x128 0x43c 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA5__IPU1_DISP1_DATA04 0x128 0x43c 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA5__IPU2_CSI1_DATA04 0x128 0x43c 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_DA5__GPIO3_IO05 0x128 0x43c 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA5__SRC_BOOT_CFG05 0x128 0x43c 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA6__EIM_AD06 0x12c 0x440 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA6__IPU1_DISP1_DATA03 0x12c 0x440 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA6__IPU2_CSI1_DATA03 0x12c 0x440 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_DA6__GPIO3_IO06 0x12c 0x440 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA6__SRC_BOOT_CFG06 0x12c 0x440 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA7__EIM_AD07 0x130 0x444 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA7__IPU1_DISP1_DATA02 0x130 0x444 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA7__IPU2_CSI1_DATA02 0x130 0x444 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_DA7__GPIO3_IO07 0x130 0x444 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA7__SRC_BOOT_CFG07 0x130 0x444 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA8__EIM_AD08 0x134 0x448 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA8__IPU1_DISP1_DATA01 0x134 0x448 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA8__IPU2_CSI1_DATA01 0x134 0x448 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_DA8__GPIO3_IO08 0x134 0x448 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA8__SRC_BOOT_CFG08 0x134 0x448 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA9__EIM_AD09 0x138 0x44c 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA9__IPU1_DISP1_DATA00 0x138 0x44c 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA9__IPU2_CSI1_DATA00 0x138 0x44c 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_DA9__GPIO3_IO09 0x138 0x44c 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA9__SRC_BOOT_CFG09 0x138 0x44c 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA10__EIM_AD10 0x13c 0x450 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA10__IPU1_DI1_PIN15 0x13c 0x450 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA10__IPU2_CSI1_DATA_EN 0x13c 0x450 0x8d8 0x2 0x1 +-#define MX6Q_PAD_EIM_DA10__GPIO3_IO10 0x13c 0x450 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA10__SRC_BOOT_CFG10 0x13c 0x450 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA11__EIM_AD11 0x140 0x454 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA11__IPU1_DI1_PIN02 0x140 0x454 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA11__IPU2_CSI1_HSYNC 0x140 0x454 0x8dc 0x2 0x1 +-#define MX6Q_PAD_EIM_DA11__GPIO3_IO11 0x140 0x454 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA11__SRC_BOOT_CFG11 0x140 0x454 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA12__EIM_AD12 0x144 0x458 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA12__IPU1_DI1_PIN03 0x144 0x458 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA12__IPU2_CSI1_VSYNC 0x144 0x458 0x8e4 0x2 0x1 +-#define MX6Q_PAD_EIM_DA12__GPIO3_IO12 0x144 0x458 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA12__SRC_BOOT_CFG12 0x144 0x458 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA13__EIM_AD13 0x148 0x45c 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA13__IPU1_DI1_D0_CS 0x148 0x45c 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA13__GPIO3_IO13 0x148 0x45c 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA13__SRC_BOOT_CFG13 0x148 0x45c 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA14__EIM_AD14 0x14c 0x460 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA14__IPU1_DI1_D1_CS 0x14c 0x460 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA14__GPIO3_IO14 0x14c 0x460 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA14__SRC_BOOT_CFG14 0x14c 0x460 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_DA15__EIM_AD15 0x150 0x464 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_DA15__IPU1_DI1_PIN01 0x150 0x464 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_DA15__IPU1_DI1_PIN04 0x150 0x464 0x000 0x2 0x0 +-#define MX6Q_PAD_EIM_DA15__GPIO3_IO15 0x150 0x464 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_DA15__SRC_BOOT_CFG15 0x150 0x464 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_WAIT__EIM_WAIT_B 0x154 0x468 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_WAIT__EIM_DTACK_B 0x154 0x468 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_WAIT__GPIO5_IO00 0x154 0x468 0x000 0x5 0x0 +-#define MX6Q_PAD_EIM_WAIT__SRC_BOOT_CFG25 0x154 0x468 0x000 0x7 0x0 +-#define MX6Q_PAD_EIM_BCLK__EIM_BCLK 0x158 0x46c 0x000 0x0 0x0 +-#define MX6Q_PAD_EIM_BCLK__IPU1_DI1_PIN16 0x158 0x46c 0x000 0x1 0x0 +-#define MX6Q_PAD_EIM_BCLK__GPIO6_IO31 0x158 0x46c 0x000 0x5 0x0 +-#define MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x15c 0x470 0x000 0x0 0x0 +-#define MX6Q_PAD_DI0_DISP_CLK__IPU2_DI0_DISP_CLK 0x15c 0x470 0x000 0x1 0x0 +-#define MX6Q_PAD_DI0_DISP_CLK__GPIO4_IO16 0x15c 0x470 0x000 0x5 0x0 +-#define MX6Q_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x160 0x474 0x000 0x0 0x0 +-#define MX6Q_PAD_DI0_PIN15__IPU2_DI0_PIN15 0x160 0x474 0x000 0x1 0x0 +-#define MX6Q_PAD_DI0_PIN15__AUD6_TXC 0x160 0x474 0x000 0x2 0x0 +-#define MX6Q_PAD_DI0_PIN15__GPIO4_IO17 0x160 0x474 0x000 0x5 0x0 +-#define MX6Q_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x164 0x478 0x000 0x0 0x0 +-#define MX6Q_PAD_DI0_PIN2__IPU2_DI0_PIN02 0x164 0x478 0x000 0x1 0x0 +-#define MX6Q_PAD_DI0_PIN2__AUD6_TXD 0x164 0x478 0x000 0x2 0x0 +-#define MX6Q_PAD_DI0_PIN2__GPIO4_IO18 0x164 0x478 0x000 0x5 0x0 +-#define MX6Q_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x168 0x47c 0x000 0x0 0x0 +-#define MX6Q_PAD_DI0_PIN3__IPU2_DI0_PIN03 0x168 0x47c 0x000 0x1 0x0 +-#define MX6Q_PAD_DI0_PIN3__AUD6_TXFS 0x168 0x47c 0x000 0x2 0x0 +-#define MX6Q_PAD_DI0_PIN3__GPIO4_IO19 0x168 0x47c 0x000 0x5 0x0 +-#define MX6Q_PAD_DI0_PIN4__IPU1_DI0_PIN04 0x16c 0x480 0x000 0x0 0x0 +-#define MX6Q_PAD_DI0_PIN4__IPU2_DI0_PIN04 0x16c 0x480 0x000 0x1 0x0 +-#define MX6Q_PAD_DI0_PIN4__AUD6_RXD 0x16c 0x480 0x000 0x2 0x0 +-#define MX6Q_PAD_DI0_PIN4__SD1_WP 0x16c 0x480 0x94c 0x3 0x0 +-#define MX6Q_PAD_DI0_PIN4__GPIO4_IO20 0x16c 0x480 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x170 0x484 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT0__IPU2_DISP0_DATA00 0x170 0x484 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT0__ECSPI3_SCLK 0x170 0x484 0x000 0x2 0x0 +-#define MX6Q_PAD_DISP0_DAT0__GPIO4_IO21 0x170 0x484 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x174 0x488 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT1__IPU2_DISP0_DATA01 0x174 0x488 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT1__ECSPI3_MOSI 0x174 0x488 0x000 0x2 0x0 +-#define MX6Q_PAD_DISP0_DAT1__GPIO4_IO22 0x174 0x488 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x178 0x48c 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT2__IPU2_DISP0_DATA02 0x178 0x48c 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT2__ECSPI3_MISO 0x178 0x48c 0x000 0x2 0x0 +-#define MX6Q_PAD_DISP0_DAT2__GPIO4_IO23 0x178 0x48c 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x17c 0x490 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT3__IPU2_DISP0_DATA03 0x17c 0x490 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT3__ECSPI3_SS0 0x17c 0x490 0x000 0x2 0x0 +-#define MX6Q_PAD_DISP0_DAT3__GPIO4_IO24 0x17c 0x490 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x180 0x494 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT4__IPU2_DISP0_DATA04 0x180 0x494 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT4__ECSPI3_SS1 0x180 0x494 0x000 0x2 0x0 +-#define MX6Q_PAD_DISP0_DAT4__GPIO4_IO25 0x180 0x494 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x184 0x498 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT5__IPU2_DISP0_DATA05 0x184 0x498 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT5__ECSPI3_SS2 0x184 0x498 0x000 0x2 0x0 +-#define MX6Q_PAD_DISP0_DAT5__AUD6_RXFS 0x184 0x498 0x000 0x3 0x0 +-#define MX6Q_PAD_DISP0_DAT5__GPIO4_IO26 0x184 0x498 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x188 0x49c 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT6__IPU2_DISP0_DATA06 0x188 0x49c 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT6__ECSPI3_SS3 0x188 0x49c 0x000 0x2 0x0 +-#define MX6Q_PAD_DISP0_DAT6__AUD6_RXC 0x188 0x49c 0x000 0x3 0x0 +-#define MX6Q_PAD_DISP0_DAT6__GPIO4_IO27 0x188 0x49c 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x18c 0x4a0 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT7__IPU2_DISP0_DATA07 0x18c 0x4a0 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT7__ECSPI3_RDY 0x18c 0x4a0 0x000 0x2 0x0 +-#define MX6Q_PAD_DISP0_DAT7__GPIO4_IO28 0x18c 0x4a0 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x190 0x4a4 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT8__IPU2_DISP0_DATA08 0x190 0x4a4 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT8__PWM1_OUT 0x190 0x4a4 0x000 0x2 0x0 +-#define MX6Q_PAD_DISP0_DAT8__WDOG1_B 0x190 0x4a4 0x000 0x3 0x0 +-#define MX6Q_PAD_DISP0_DAT8__GPIO4_IO29 0x190 0x4a4 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x194 0x4a8 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT9__IPU2_DISP0_DATA09 0x194 0x4a8 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT9__PWM2_OUT 0x194 0x4a8 0x000 0x2 0x0 +-#define MX6Q_PAD_DISP0_DAT9__WDOG2_B 0x194 0x4a8 0x000 0x3 0x0 +-#define MX6Q_PAD_DISP0_DAT9__GPIO4_IO30 0x194 0x4a8 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x198 0x4ac 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT10__IPU2_DISP0_DATA10 0x198 0x4ac 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT10__GPIO4_IO31 0x198 0x4ac 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x19c 0x4b0 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT11__IPU2_DISP0_DATA11 0x19c 0x4b0 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT11__GPIO5_IO05 0x19c 0x4b0 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x1a0 0x4b4 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT12__IPU2_DISP0_DATA12 0x1a0 0x4b4 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT12__GPIO5_IO06 0x1a0 0x4b4 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x1a4 0x4b8 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT13__IPU2_DISP0_DATA13 0x1a4 0x4b8 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT13__AUD5_RXFS 0x1a4 0x4b8 0x7d8 0x3 0x1 +-#define MX6Q_PAD_DISP0_DAT13__GPIO5_IO07 0x1a4 0x4b8 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x1a8 0x4bc 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT14__IPU2_DISP0_DATA14 0x1a8 0x4bc 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT14__AUD5_RXC 0x1a8 0x4bc 0x7d4 0x3 0x1 +-#define MX6Q_PAD_DISP0_DAT14__GPIO5_IO08 0x1a8 0x4bc 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x1ac 0x4c0 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT15__IPU2_DISP0_DATA15 0x1ac 0x4c0 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT15__ECSPI1_SS1 0x1ac 0x4c0 0x804 0x2 0x1 +-#define MX6Q_PAD_DISP0_DAT15__ECSPI2_SS1 0x1ac 0x4c0 0x820 0x3 0x1 +-#define MX6Q_PAD_DISP0_DAT15__GPIO5_IO09 0x1ac 0x4c0 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x1b0 0x4c4 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT16__IPU2_DISP0_DATA16 0x1b0 0x4c4 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT16__ECSPI2_MOSI 0x1b0 0x4c4 0x818 0x2 0x1 +-#define MX6Q_PAD_DISP0_DAT16__AUD5_TXC 0x1b0 0x4c4 0x7dc 0x3 0x0 +-#define MX6Q_PAD_DISP0_DAT16__SDMA_EXT_EVENT0 0x1b0 0x4c4 0x90c 0x4 0x0 +-#define MX6Q_PAD_DISP0_DAT16__GPIO5_IO10 0x1b0 0x4c4 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x1b4 0x4c8 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT17__IPU2_DISP0_DATA17 0x1b4 0x4c8 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT17__ECSPI2_MISO 0x1b4 0x4c8 0x814 0x2 0x1 +-#define MX6Q_PAD_DISP0_DAT17__AUD5_TXD 0x1b4 0x4c8 0x7d0 0x3 0x0 +-#define MX6Q_PAD_DISP0_DAT17__SDMA_EXT_EVENT1 0x1b4 0x4c8 0x910 0x4 0x0 +-#define MX6Q_PAD_DISP0_DAT17__GPIO5_IO11 0x1b4 0x4c8 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x1b8 0x4cc 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT18__IPU2_DISP0_DATA18 0x1b8 0x4cc 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT18__ECSPI2_SS0 0x1b8 0x4cc 0x81c 0x2 0x1 +-#define MX6Q_PAD_DISP0_DAT18__AUD5_TXFS 0x1b8 0x4cc 0x7e0 0x3 0x0 +-#define MX6Q_PAD_DISP0_DAT18__AUD4_RXFS 0x1b8 0x4cc 0x7c0 0x4 0x0 +-#define MX6Q_PAD_DISP0_DAT18__GPIO5_IO12 0x1b8 0x4cc 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT18__EIM_CS2_B 0x1b8 0x4cc 0x000 0x7 0x0 +-#define MX6Q_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x1bc 0x4d0 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT19__IPU2_DISP0_DATA19 0x1bc 0x4d0 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT19__ECSPI2_SCLK 0x1bc 0x4d0 0x810 0x2 0x1 +-#define MX6Q_PAD_DISP0_DAT19__AUD5_RXD 0x1bc 0x4d0 0x7cc 0x3 0x0 +-#define MX6Q_PAD_DISP0_DAT19__AUD4_RXC 0x1bc 0x4d0 0x7bc 0x4 0x0 +-#define MX6Q_PAD_DISP0_DAT19__GPIO5_IO13 0x1bc 0x4d0 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT19__EIM_CS3_B 0x1bc 0x4d0 0x000 0x7 0x0 +-#define MX6Q_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x1c0 0x4d4 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT20__IPU2_DISP0_DATA20 0x1c0 0x4d4 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT20__ECSPI1_SCLK 0x1c0 0x4d4 0x7f4 0x2 0x1 +-#define MX6Q_PAD_DISP0_DAT20__AUD4_TXC 0x1c0 0x4d4 0x7c4 0x3 0x0 +-#define MX6Q_PAD_DISP0_DAT20__GPIO5_IO14 0x1c0 0x4d4 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x1c4 0x4d8 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT21__IPU2_DISP0_DATA21 0x1c4 0x4d8 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT21__ECSPI1_MOSI 0x1c4 0x4d8 0x7fc 0x2 0x1 +-#define MX6Q_PAD_DISP0_DAT21__AUD4_TXD 0x1c4 0x4d8 0x7b8 0x3 0x1 +-#define MX6Q_PAD_DISP0_DAT21__GPIO5_IO15 0x1c4 0x4d8 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x1c8 0x4dc 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT22__IPU2_DISP0_DATA22 0x1c8 0x4dc 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT22__ECSPI1_MISO 0x1c8 0x4dc 0x7f8 0x2 0x1 +-#define MX6Q_PAD_DISP0_DAT22__AUD4_TXFS 0x1c8 0x4dc 0x7c8 0x3 0x1 +-#define MX6Q_PAD_DISP0_DAT22__GPIO5_IO16 0x1c8 0x4dc 0x000 0x5 0x0 +-#define MX6Q_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x1cc 0x4e0 0x000 0x0 0x0 +-#define MX6Q_PAD_DISP0_DAT23__IPU2_DISP0_DATA23 0x1cc 0x4e0 0x000 0x1 0x0 +-#define MX6Q_PAD_DISP0_DAT23__ECSPI1_SS0 0x1cc 0x4e0 0x800 0x2 0x1 +-#define MX6Q_PAD_DISP0_DAT23__AUD4_RXD 0x1cc 0x4e0 0x7b4 0x3 0x1 +-#define MX6Q_PAD_DISP0_DAT23__GPIO5_IO17 0x1cc 0x4e0 0x000 0x5 0x0 +-#define MX6Q_PAD_ENET_MDIO__ENET_MDIO 0x1d0 0x4e4 0x840 0x1 0x0 +-#define MX6Q_PAD_ENET_MDIO__ESAI_RX_CLK 0x1d0 0x4e4 0x86c 0x2 0x0 +-#define MX6Q_PAD_ENET_MDIO__ENET_1588_EVENT1_OUT 0x1d0 0x4e4 0x000 0x4 0x0 +-#define MX6Q_PAD_ENET_MDIO__GPIO1_IO22 0x1d0 0x4e4 0x000 0x5 0x0 +-#define MX6Q_PAD_ENET_MDIO__SPDIF_LOCK 0x1d0 0x4e4 0x000 0x6 0x0 +-#define MX6Q_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1d4 0x4e8 0x000 0x1 0x0 +-#define MX6Q_PAD_ENET_REF_CLK__ESAI_RX_FS 0x1d4 0x4e8 0x85c 0x2 0x0 +-#define MX6Q_PAD_ENET_REF_CLK__GPIO1_IO23 0x1d4 0x4e8 0x000 0x5 0x0 +-#define MX6Q_PAD_ENET_REF_CLK__SPDIF_SR_CLK 0x1d4 0x4e8 0x000 0x6 0x0 +-#define MX6Q_PAD_ENET_RX_ER__USB_OTG_ID 0x1d8 0x4ec 0x000 0x0 0x0 +-#define MX6Q_PAD_ENET_RX_ER__ENET_RX_ER 0x1d8 0x4ec 0x000 0x1 0x0 +-#define MX6Q_PAD_ENET_RX_ER__ESAI_RX_HF_CLK 0x1d8 0x4ec 0x864 0x2 0x0 +-#define MX6Q_PAD_ENET_RX_ER__SPDIF_IN 0x1d8 0x4ec 0x914 0x3 0x1 +-#define MX6Q_PAD_ENET_RX_ER__ENET_1588_EVENT2_OUT 0x1d8 0x4ec 0x000 0x4 0x0 +-#define MX6Q_PAD_ENET_RX_ER__GPIO1_IO24 0x1d8 0x4ec 0x000 0x5 0x0 +-#define MX6Q_PAD_ENET_CRS_DV__ENET_RX_EN 0x1dc 0x4f0 0x858 0x1 0x1 +-#define MX6Q_PAD_ENET_CRS_DV__ESAI_TX_CLK 0x1dc 0x4f0 0x870 0x2 0x0 +-#define MX6Q_PAD_ENET_CRS_DV__SPDIF_EXT_CLK 0x1dc 0x4f0 0x918 0x3 0x1 +-#define MX6Q_PAD_ENET_CRS_DV__GPIO1_IO25 0x1dc 0x4f0 0x000 0x5 0x0 +-#define MX6Q_PAD_ENET_RXD1__MLB_SIG 0x1e0 0x4f4 0x908 0x0 0x0 +-#define MX6Q_PAD_ENET_RXD1__ENET_RX_DATA1 0x1e0 0x4f4 0x84c 0x1 0x1 +-#define MX6Q_PAD_ENET_RXD1__ESAI_TX_FS 0x1e0 0x4f4 0x860 0x2 0x0 +-#define MX6Q_PAD_ENET_RXD1__ENET_1588_EVENT3_OUT 0x1e0 0x4f4 0x000 0x4 0x0 +-#define MX6Q_PAD_ENET_RXD1__GPIO1_IO26 0x1e0 0x4f4 0x000 0x5 0x0 +-#define MX6Q_PAD_ENET_RXD0__ENET_RX_DATA0 0x1e4 0x4f8 0x848 0x1 0x1 +-#define MX6Q_PAD_ENET_RXD0__ESAI_TX_HF_CLK 0x1e4 0x4f8 0x868 0x2 0x0 +-#define MX6Q_PAD_ENET_RXD0__SPDIF_OUT 0x1e4 0x4f8 0x000 0x3 0x0 +-#define MX6Q_PAD_ENET_RXD0__GPIO1_IO27 0x1e4 0x4f8 0x000 0x5 0x0 +-#define MX6Q_PAD_ENET_TX_EN__ENET_TX_EN 0x1e8 0x4fc 0x000 0x1 0x0 +-#define MX6Q_PAD_ENET_TX_EN__ESAI_TX3_RX2 0x1e8 0x4fc 0x880 0x2 0x0 +-#define MX6Q_PAD_ENET_TX_EN__GPIO1_IO28 0x1e8 0x4fc 0x000 0x5 0x0 +-#define MX6Q_PAD_ENET_TXD1__MLB_CLK 0x1ec 0x500 0x900 0x0 0x0 +-#define MX6Q_PAD_ENET_TXD1__ENET_TX_DATA1 0x1ec 0x500 0x000 0x1 0x0 +-#define MX6Q_PAD_ENET_TXD1__ESAI_TX2_RX3 0x1ec 0x500 0x87c 0x2 0x0 +-#define MX6Q_PAD_ENET_TXD1__ENET_1588_EVENT0_IN 0x1ec 0x500 0x000 0x4 0x0 +-#define MX6Q_PAD_ENET_TXD1__GPIO1_IO29 0x1ec 0x500 0x000 0x5 0x0 +-#define MX6Q_PAD_ENET_TXD0__ENET_TX_DATA0 0x1f0 0x504 0x000 0x1 0x0 +-#define MX6Q_PAD_ENET_TXD0__ESAI_TX4_RX1 0x1f0 0x504 0x884 0x2 0x0 +-#define MX6Q_PAD_ENET_TXD0__GPIO1_IO30 0x1f0 0x504 0x000 0x5 0x0 +-#define MX6Q_PAD_ENET_MDC__MLB_DATA 0x1f4 0x508 0x904 0x0 0x0 +-#define MX6Q_PAD_ENET_MDC__ENET_MDC 0x1f4 0x508 0x000 0x1 0x0 +-#define MX6Q_PAD_ENET_MDC__ESAI_TX5_RX0 0x1f4 0x508 0x888 0x2 0x0 +-#define MX6Q_PAD_ENET_MDC__ENET_1588_EVENT1_IN 0x1f4 0x508 0x000 0x4 0x0 +-#define MX6Q_PAD_ENET_MDC__GPIO1_IO31 0x1f4 0x508 0x000 0x5 0x0 +-#define MX6Q_PAD_KEY_COL0__ECSPI1_SCLK 0x1f8 0x5c8 0x7f4 0x0 0x2 +-#define MX6Q_PAD_KEY_COL0__ENET_RX_DATA3 0x1f8 0x5c8 0x854 0x1 0x1 +-#define MX6Q_PAD_KEY_COL0__AUD5_TXC 0x1f8 0x5c8 0x7dc 0x2 0x1 +-#define MX6Q_PAD_KEY_COL0__KEY_COL0 0x1f8 0x5c8 0x000 0x3 0x0 +-#define MX6Q_PAD_KEY_COL0__UART4_TX_DATA 0x1f8 0x5c8 0x000 0x4 0x0 +-#define MX6Q_PAD_KEY_COL0__UART4_RX_DATA 0x1f8 0x5c8 0x938 0x4 0x0 +-#define MX6Q_PAD_KEY_COL0__GPIO4_IO06 0x1f8 0x5c8 0x000 0x5 0x0 +-#define MX6Q_PAD_KEY_COL0__DCIC1_OUT 0x1f8 0x5c8 0x000 0x6 0x0 +-#define MX6Q_PAD_KEY_ROW0__ECSPI1_MOSI 0x1fc 0x5cc 0x7fc 0x0 0x2 +-#define MX6Q_PAD_KEY_ROW0__ENET_TX_DATA3 0x1fc 0x5cc 0x000 0x1 0x0 +-#define MX6Q_PAD_KEY_ROW0__AUD5_TXD 0x1fc 0x5cc 0x7d0 0x2 0x1 +-#define MX6Q_PAD_KEY_ROW0__KEY_ROW0 0x1fc 0x5cc 0x000 0x3 0x0 +-#define MX6Q_PAD_KEY_ROW0__UART4_RX_DATA 0x1fc 0x5cc 0x938 0x4 0x1 +-#define MX6Q_PAD_KEY_ROW0__UART4_TX_DATA 0x1fc 0x5cc 0x000 0x4 0x0 +-#define MX6Q_PAD_KEY_ROW0__GPIO4_IO07 0x1fc 0x5cc 0x000 0x5 0x0 +-#define MX6Q_PAD_KEY_ROW0__DCIC2_OUT 0x1fc 0x5cc 0x000 0x6 0x0 +-#define MX6Q_PAD_KEY_COL1__ECSPI1_MISO 0x200 0x5d0 0x7f8 0x0 0x2 +-#define MX6Q_PAD_KEY_COL1__ENET_MDIO 0x200 0x5d0 0x840 0x1 0x1 +-#define MX6Q_PAD_KEY_COL1__AUD5_TXFS 0x200 0x5d0 0x7e0 0x2 0x1 +-#define MX6Q_PAD_KEY_COL1__KEY_COL1 0x200 0x5d0 0x000 0x3 0x0 +-#define MX6Q_PAD_KEY_COL1__UART5_TX_DATA 0x200 0x5d0 0x000 0x4 0x0 +-#define MX6Q_PAD_KEY_COL1__UART5_RX_DATA 0x200 0x5d0 0x940 0x4 0x0 +-#define MX6Q_PAD_KEY_COL1__GPIO4_IO08 0x200 0x5d0 0x000 0x5 0x0 +-#define MX6Q_PAD_KEY_COL1__SD1_VSELECT 0x200 0x5d0 0x000 0x6 0x0 +-#define MX6Q_PAD_KEY_ROW1__ECSPI1_SS0 0x204 0x5d4 0x800 0x0 0x2 +-#define MX6Q_PAD_KEY_ROW1__ENET_COL 0x204 0x5d4 0x000 0x1 0x0 +-#define MX6Q_PAD_KEY_ROW1__AUD5_RXD 0x204 0x5d4 0x7cc 0x2 0x1 +-#define MX6Q_PAD_KEY_ROW1__KEY_ROW1 0x204 0x5d4 0x000 0x3 0x0 +-#define MX6Q_PAD_KEY_ROW1__UART5_RX_DATA 0x204 0x5d4 0x940 0x4 0x1 +-#define MX6Q_PAD_KEY_ROW1__UART5_TX_DATA 0x204 0x5d4 0x000 0x4 0x0 +-#define MX6Q_PAD_KEY_ROW1__GPIO4_IO09 0x204 0x5d4 0x000 0x5 0x0 +-#define MX6Q_PAD_KEY_ROW1__SD2_VSELECT 0x204 0x5d4 0x000 0x6 0x0 +-#define MX6Q_PAD_KEY_COL2__ECSPI1_SS1 0x208 0x5d8 0x804 0x0 0x2 +-#define MX6Q_PAD_KEY_COL2__ENET_RX_DATA2 0x208 0x5d8 0x850 0x1 0x1 +-#define MX6Q_PAD_KEY_COL2__FLEXCAN1_TX 0x208 0x5d8 0x000 0x2 0x0 +-#define MX6Q_PAD_KEY_COL2__KEY_COL2 0x208 0x5d8 0x000 0x3 0x0 +-#define MX6Q_PAD_KEY_COL2__ENET_MDC 0x208 0x5d8 0x000 0x4 0x0 +-#define MX6Q_PAD_KEY_COL2__GPIO4_IO10 0x208 0x5d8 0x000 0x5 0x0 +-#define MX6Q_PAD_KEY_COL2__USB_H1_PWR_CTL_WAKE 0x208 0x5d8 0x000 0x6 0x0 +-#define MX6Q_PAD_KEY_ROW2__ECSPI1_SS2 0x20c 0x5dc 0x808 0x0 0x1 +-#define MX6Q_PAD_KEY_ROW2__ENET_TX_DATA2 0x20c 0x5dc 0x000 0x1 0x0 +-#define MX6Q_PAD_KEY_ROW2__FLEXCAN1_RX 0x20c 0x5dc 0x7e4 0x2 0x0 +-#define MX6Q_PAD_KEY_ROW2__KEY_ROW2 0x20c 0x5dc 0x000 0x3 0x0 +-#define MX6Q_PAD_KEY_ROW2__SD2_VSELECT 0x20c 0x5dc 0x000 0x4 0x0 +-#define MX6Q_PAD_KEY_ROW2__GPIO4_IO11 0x20c 0x5dc 0x000 0x5 0x0 +-#define MX6Q_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x20c 0x5dc 0x88c 0x6 0x1 +-#define MX6Q_PAD_KEY_COL3__ECSPI1_SS3 0x210 0x5e0 0x80c 0x0 0x1 +-#define MX6Q_PAD_KEY_COL3__ENET_CRS 0x210 0x5e0 0x000 0x1 0x0 +-#define MX6Q_PAD_KEY_COL3__HDMI_TX_DDC_SCL 0x210 0x5e0 0x890 0x2 0x1 +-#define MX6Q_PAD_KEY_COL3__KEY_COL3 0x210 0x5e0 0x000 0x3 0x0 +-#define MX6Q_PAD_KEY_COL3__I2C2_SCL 0x210 0x5e0 0x8a0 0x4 0x1 +-#define MX6Q_PAD_KEY_COL3__GPIO4_IO12 0x210 0x5e0 0x000 0x5 0x0 +-#define MX6Q_PAD_KEY_COL3__SPDIF_IN 0x210 0x5e0 0x914 0x6 0x2 +-#define MX6Q_PAD_KEY_ROW3__ASRC_EXT_CLK 0x214 0x5e4 0x7b0 0x1 0x0 +-#define MX6Q_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 0x214 0x5e4 0x894 0x2 0x1 +-#define MX6Q_PAD_KEY_ROW3__KEY_ROW3 0x214 0x5e4 0x000 0x3 0x0 +-#define MX6Q_PAD_KEY_ROW3__I2C2_SDA 0x214 0x5e4 0x8a4 0x4 0x1 +-#define MX6Q_PAD_KEY_ROW3__GPIO4_IO13 0x214 0x5e4 0x000 0x5 0x0 +-#define MX6Q_PAD_KEY_ROW3__SD1_VSELECT 0x214 0x5e4 0x000 0x6 0x0 +-#define MX6Q_PAD_KEY_COL4__FLEXCAN2_TX 0x218 0x5e8 0x000 0x0 0x0 +-#define MX6Q_PAD_KEY_COL4__IPU1_SISG4 0x218 0x5e8 0x000 0x1 0x0 +-#define MX6Q_PAD_KEY_COL4__USB_OTG_OC 0x218 0x5e8 0x944 0x2 0x1 +-#define MX6Q_PAD_KEY_COL4__KEY_COL4 0x218 0x5e8 0x000 0x3 0x0 +-#define MX6Q_PAD_KEY_COL4__UART5_RTS_B 0x218 0x5e8 0x93c 0x4 0x0 +-#define MX6Q_PAD_KEY_COL4__UART5_CTS_B 0x218 0x5e8 0x000 0x4 0x0 +-#define MX6Q_PAD_KEY_COL4__GPIO4_IO14 0x218 0x5e8 0x000 0x5 0x0 +-#define MX6Q_PAD_KEY_ROW4__FLEXCAN2_RX 0x21c 0x5ec 0x7e8 0x0 0x0 +-#define MX6Q_PAD_KEY_ROW4__IPU1_SISG5 0x21c 0x5ec 0x000 0x1 0x0 +-#define MX6Q_PAD_KEY_ROW4__USB_OTG_PWR 0x21c 0x5ec 0x000 0x2 0x0 +-#define MX6Q_PAD_KEY_ROW4__KEY_ROW4 0x21c 0x5ec 0x000 0x3 0x0 +-#define MX6Q_PAD_KEY_ROW4__UART5_CTS_B 0x21c 0x5ec 0x000 0x4 0x0 +-#define MX6Q_PAD_KEY_ROW4__UART5_RTS_B 0x21c 0x5ec 0x93c 0x4 0x1 +-#define MX6Q_PAD_KEY_ROW4__GPIO4_IO15 0x21c 0x5ec 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_0__CCM_CLKO1 0x220 0x5f0 0x000 0x0 0x0 +-#define MX6Q_PAD_GPIO_0__KEY_COL5 0x220 0x5f0 0x8e8 0x2 0x0 +-#define MX6Q_PAD_GPIO_0__ASRC_EXT_CLK 0x220 0x5f0 0x7b0 0x3 0x1 +-#define MX6Q_PAD_GPIO_0__EPIT1_OUT 0x220 0x5f0 0x000 0x4 0x0 +-#define MX6Q_PAD_GPIO_0__GPIO1_IO00 0x220 0x5f0 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_0__USB_H1_PWR 0x220 0x5f0 0x000 0x6 0x0 +-#define MX6Q_PAD_GPIO_0__SNVS_VIO_5 0x220 0x5f0 0x000 0x7 0x0 +-#define MX6Q_PAD_GPIO_1__ESAI_RX_CLK 0x224 0x5f4 0x86c 0x0 0x1 +-#define MX6Q_PAD_GPIO_1__WDOG2_B 0x224 0x5f4 0x000 0x1 0x0 +-#define MX6Q_PAD_GPIO_1__KEY_ROW5 0x224 0x5f4 0x8f4 0x2 0x0 +-#define MX6Q_PAD_GPIO_1__USB_OTG_ID 0x224 0x5f4 0x000 0x3 0x0 +-#define MX6Q_PAD_GPIO_1__PWM2_OUT 0x224 0x5f4 0x000 0x4 0x0 +-#define MX6Q_PAD_GPIO_1__GPIO1_IO01 0x224 0x5f4 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_1__SD1_CD_B 0x224 0x5f4 0x000 0x6 0x0 +-#define MX6Q_PAD_GPIO_9__ESAI_RX_FS 0x228 0x5f8 0x85c 0x0 0x1 +-#define MX6Q_PAD_GPIO_9__WDOG1_B 0x228 0x5f8 0x000 0x1 0x0 +-#define MX6Q_PAD_GPIO_9__KEY_COL6 0x228 0x5f8 0x8ec 0x2 0x0 +-#define MX6Q_PAD_GPIO_9__CCM_REF_EN_B 0x228 0x5f8 0x000 0x3 0x0 +-#define MX6Q_PAD_GPIO_9__PWM1_OUT 0x228 0x5f8 0x000 0x4 0x0 +-#define MX6Q_PAD_GPIO_9__GPIO1_IO09 0x228 0x5f8 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_9__SD1_WP 0x228 0x5f8 0x94c 0x6 0x1 +-#define MX6Q_PAD_GPIO_3__ESAI_RX_HF_CLK 0x22c 0x5fc 0x864 0x0 0x1 +-#define MX6Q_PAD_GPIO_3__I2C3_SCL 0x22c 0x5fc 0x8a8 0x2 0x1 +-#define MX6Q_PAD_GPIO_3__XTALOSC_REF_CLK_24M 0x22c 0x5fc 0x000 0x3 0x0 +-#define MX6Q_PAD_GPIO_3__CCM_CLKO2 0x22c 0x5fc 0x000 0x4 0x0 +-#define MX6Q_PAD_GPIO_3__GPIO1_IO03 0x22c 0x5fc 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_3__USB_H1_OC 0x22c 0x5fc 0x948 0x6 0x1 +-#define MX6Q_PAD_GPIO_3__MLB_CLK 0x22c 0x5fc 0x900 0x7 0x1 +-#define MX6Q_PAD_GPIO_6__ESAI_TX_CLK 0x230 0x600 0x870 0x0 0x1 +-#define MX6Q_PAD_GPIO_6__I2C3_SDA 0x230 0x600 0x8ac 0x2 0x1 +-#define MX6Q_PAD_GPIO_6__GPIO1_IO06 0x230 0x600 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_6__SD2_LCTL 0x230 0x600 0x000 0x6 0x0 +-#define MX6Q_PAD_GPIO_6__MLB_SIG 0x230 0x600 0x908 0x7 0x1 +-#define MX6Q_PAD_GPIO_2__ESAI_TX_FS 0x234 0x604 0x860 0x0 0x1 +-#define MX6Q_PAD_GPIO_2__KEY_ROW6 0x234 0x604 0x8f8 0x2 0x1 +-#define MX6Q_PAD_GPIO_2__GPIO1_IO02 0x234 0x604 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_2__SD2_WP 0x234 0x604 0x000 0x6 0x0 +-#define MX6Q_PAD_GPIO_2__MLB_DATA 0x234 0x604 0x904 0x7 0x1 +-#define MX6Q_PAD_GPIO_4__ESAI_TX_HF_CLK 0x238 0x608 0x868 0x0 0x1 +-#define MX6Q_PAD_GPIO_4__KEY_COL7 0x238 0x608 0x8f0 0x2 0x1 +-#define MX6Q_PAD_GPIO_4__GPIO1_IO04 0x238 0x608 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_4__SD2_CD_B 0x238 0x608 0x000 0x6 0x0 +-#define MX6Q_PAD_GPIO_5__ESAI_TX2_RX3 0x23c 0x60c 0x87c 0x0 0x1 +-#define MX6Q_PAD_GPIO_5__KEY_ROW7 0x23c 0x60c 0x8fc 0x2 0x1 +-#define MX6Q_PAD_GPIO_5__CCM_CLKO1 0x23c 0x60c 0x000 0x3 0x0 +-#define MX6Q_PAD_GPIO_5__GPIO1_IO05 0x23c 0x60c 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_5__I2C3_SCL 0x23c 0x60c 0x8a8 0x6 0x2 +-#define MX6Q_PAD_GPIO_5__ARM_EVENTI 0x23c 0x60c 0x000 0x7 0x0 +-#define MX6Q_PAD_GPIO_7__ESAI_TX4_RX1 0x240 0x610 0x884 0x0 0x1 +-#define MX6Q_PAD_GPIO_7__ECSPI5_RDY 0x240 0x610 0x000 0x1 0x0 +-#define MX6Q_PAD_GPIO_7__EPIT1_OUT 0x240 0x610 0x000 0x2 0x0 +-#define MX6Q_PAD_GPIO_7__FLEXCAN1_TX 0x240 0x610 0x000 0x3 0x0 +-#define MX6Q_PAD_GPIO_7__UART2_TX_DATA 0x240 0x610 0x000 0x4 0x0 +-#define MX6Q_PAD_GPIO_7__UART2_RX_DATA 0x240 0x610 0x928 0x4 0x2 +-#define MX6Q_PAD_GPIO_7__GPIO1_IO07 0x240 0x610 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_7__SPDIF_LOCK 0x240 0x610 0x000 0x6 0x0 +-#define MX6Q_PAD_GPIO_7__USB_OTG_HOST_MODE 0x240 0x610 0x000 0x7 0x0 +-#define MX6Q_PAD_GPIO_8__ESAI_TX5_RX0 0x244 0x614 0x888 0x0 0x1 +-#define MX6Q_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x244 0x614 0x000 0x1 0x0 +-#define MX6Q_PAD_GPIO_8__EPIT2_OUT 0x244 0x614 0x000 0x2 0x0 +-#define MX6Q_PAD_GPIO_8__FLEXCAN1_RX 0x244 0x614 0x7e4 0x3 0x1 +-#define MX6Q_PAD_GPIO_8__UART2_RX_DATA 0x244 0x614 0x928 0x4 0x3 +-#define MX6Q_PAD_GPIO_8__UART2_TX_DATA 0x244 0x614 0x000 0x4 0x0 +-#define MX6Q_PAD_GPIO_8__GPIO1_IO08 0x244 0x614 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_8__SPDIF_SR_CLK 0x244 0x614 0x000 0x6 0x0 +-#define MX6Q_PAD_GPIO_8__USB_OTG_PWR_CTL_WAKE 0x244 0x614 0x000 0x7 0x0 +-#define MX6Q_PAD_GPIO_16__ESAI_TX3_RX2 0x248 0x618 0x880 0x0 0x1 +-#define MX6Q_PAD_GPIO_16__ENET_1588_EVENT2_IN 0x248 0x618 0x000 0x1 0x0 +-#define MX6Q_PAD_GPIO_16__ENET_REF_CLK 0x248 0x618 0x83c 0x2 0x1 +-#define MX6Q_PAD_GPIO_16__SD1_LCTL 0x248 0x618 0x000 0x3 0x0 +-#define MX6Q_PAD_GPIO_16__SPDIF_IN 0x248 0x618 0x914 0x4 0x3 +-#define MX6Q_PAD_GPIO_16__GPIO7_IO11 0x248 0x618 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_16__I2C3_SDA 0x248 0x618 0x8ac 0x6 0x2 +-#define MX6Q_PAD_GPIO_16__JTAG_DE_B 0x248 0x618 0x000 0x7 0x0 +-#define MX6Q_PAD_GPIO_17__ESAI_TX0 0x24c 0x61c 0x874 0x0 0x0 +-#define MX6Q_PAD_GPIO_17__ENET_1588_EVENT3_IN 0x24c 0x61c 0x000 0x1 0x0 +-#define MX6Q_PAD_GPIO_17__CCM_PMIC_READY 0x24c 0x61c 0x7f0 0x2 0x1 +-#define MX6Q_PAD_GPIO_17__SDMA_EXT_EVENT0 0x24c 0x61c 0x90c 0x3 0x1 +-#define MX6Q_PAD_GPIO_17__SPDIF_OUT 0x24c 0x61c 0x000 0x4 0x0 +-#define MX6Q_PAD_GPIO_17__GPIO7_IO12 0x24c 0x61c 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_18__ESAI_TX1 0x250 0x620 0x878 0x0 0x0 +-#define MX6Q_PAD_GPIO_18__ENET_RX_CLK 0x250 0x620 0x844 0x1 0x1 +-#define MX6Q_PAD_GPIO_18__SD3_VSELECT 0x250 0x620 0x000 0x2 0x0 +-#define MX6Q_PAD_GPIO_18__SDMA_EXT_EVENT1 0x250 0x620 0x910 0x3 0x1 +-#define MX6Q_PAD_GPIO_18__ASRC_EXT_CLK 0x250 0x620 0x7b0 0x4 0x2 +-#define MX6Q_PAD_GPIO_18__GPIO7_IO13 0x250 0x620 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_18__SNVS_VIO_5_CTL 0x250 0x620 0x000 0x6 0x0 +-#define MX6Q_PAD_GPIO_19__KEY_COL5 0x254 0x624 0x8e8 0x0 0x1 +-#define MX6Q_PAD_GPIO_19__ENET_1588_EVENT0_OUT 0x254 0x624 0x000 0x1 0x0 +-#define MX6Q_PAD_GPIO_19__SPDIF_OUT 0x254 0x624 0x000 0x2 0x0 +-#define MX6Q_PAD_GPIO_19__CCM_CLKO1 0x254 0x624 0x000 0x3 0x0 +-#define MX6Q_PAD_GPIO_19__ECSPI1_RDY 0x254 0x624 0x000 0x4 0x0 +-#define MX6Q_PAD_GPIO_19__GPIO4_IO05 0x254 0x624 0x000 0x5 0x0 +-#define MX6Q_PAD_GPIO_19__ENET_TX_ER 0x254 0x624 0x000 0x6 0x0 +-#define MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x258 0x628 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_PIXCLK__GPIO5_IO18 0x258 0x628 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_PIXCLK__ARM_EVENTO 0x258 0x628 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x25c 0x62c 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_MCLK__CCM_CLKO1 0x25c 0x62c 0x000 0x3 0x0 +-#define MX6Q_PAD_CSI0_MCLK__GPIO5_IO19 0x25c 0x62c 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_MCLK__ARM_TRACE_CTL 0x25c 0x62c 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN 0x260 0x630 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DATA_EN__EIM_DATA00 0x260 0x630 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DATA_EN__GPIO5_IO20 0x260 0x630 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DATA_EN__ARM_TRACE_CLK 0x260 0x630 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x264 0x634 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_VSYNC__EIM_DATA01 0x264 0x634 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_VSYNC__GPIO5_IO21 0x264 0x634 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_VSYNC__ARM_TRACE00 0x264 0x634 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT4__IPU1_CSI0_DATA04 0x268 0x638 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT4__EIM_DATA02 0x268 0x638 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT4__ECSPI1_SCLK 0x268 0x638 0x7f4 0x2 0x3 +-#define MX6Q_PAD_CSI0_DAT4__KEY_COL5 0x268 0x638 0x8e8 0x3 0x2 +-#define MX6Q_PAD_CSI0_DAT4__AUD3_TXC 0x268 0x638 0x000 0x4 0x0 +-#define MX6Q_PAD_CSI0_DAT4__GPIO5_IO22 0x268 0x638 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT4__ARM_TRACE01 0x268 0x638 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT5__IPU1_CSI0_DATA05 0x26c 0x63c 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT5__EIM_DATA03 0x26c 0x63c 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT5__ECSPI1_MOSI 0x26c 0x63c 0x7fc 0x2 0x3 +-#define MX6Q_PAD_CSI0_DAT5__KEY_ROW5 0x26c 0x63c 0x8f4 0x3 0x1 +-#define MX6Q_PAD_CSI0_DAT5__AUD3_TXD 0x26c 0x63c 0x000 0x4 0x0 +-#define MX6Q_PAD_CSI0_DAT5__GPIO5_IO23 0x26c 0x63c 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT5__ARM_TRACE02 0x26c 0x63c 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT6__IPU1_CSI0_DATA06 0x270 0x640 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT6__EIM_DATA04 0x270 0x640 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT6__ECSPI1_MISO 0x270 0x640 0x7f8 0x2 0x3 +-#define MX6Q_PAD_CSI0_DAT6__KEY_COL6 0x270 0x640 0x8ec 0x3 0x1 +-#define MX6Q_PAD_CSI0_DAT6__AUD3_TXFS 0x270 0x640 0x000 0x4 0x0 +-#define MX6Q_PAD_CSI0_DAT6__GPIO5_IO24 0x270 0x640 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT6__ARM_TRACE03 0x270 0x640 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT7__IPU1_CSI0_DATA07 0x274 0x644 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT7__EIM_DATA05 0x274 0x644 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT7__ECSPI1_SS0 0x274 0x644 0x800 0x2 0x3 +-#define MX6Q_PAD_CSI0_DAT7__KEY_ROW6 0x274 0x644 0x8f8 0x3 0x2 +-#define MX6Q_PAD_CSI0_DAT7__AUD3_RXD 0x274 0x644 0x000 0x4 0x0 +-#define MX6Q_PAD_CSI0_DAT7__GPIO5_IO25 0x274 0x644 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT7__ARM_TRACE04 0x274 0x644 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT8__IPU1_CSI0_DATA08 0x278 0x648 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT8__EIM_DATA06 0x278 0x648 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT8__ECSPI2_SCLK 0x278 0x648 0x810 0x2 0x2 +-#define MX6Q_PAD_CSI0_DAT8__KEY_COL7 0x278 0x648 0x8f0 0x3 0x2 +-#define MX6Q_PAD_CSI0_DAT8__I2C1_SDA 0x278 0x648 0x89c 0x4 0x1 +-#define MX6Q_PAD_CSI0_DAT8__GPIO5_IO26 0x278 0x648 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT8__ARM_TRACE05 0x278 0x648 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT9__IPU1_CSI0_DATA09 0x27c 0x64c 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT9__EIM_DATA07 0x27c 0x64c 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT9__ECSPI2_MOSI 0x27c 0x64c 0x818 0x2 0x2 +-#define MX6Q_PAD_CSI0_DAT9__KEY_ROW7 0x27c 0x64c 0x8fc 0x3 0x2 +-#define MX6Q_PAD_CSI0_DAT9__I2C1_SCL 0x27c 0x64c 0x898 0x4 0x1 +-#define MX6Q_PAD_CSI0_DAT9__GPIO5_IO27 0x27c 0x64c 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT9__ARM_TRACE06 0x27c 0x64c 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT10__IPU1_CSI0_DATA10 0x280 0x650 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT10__AUD3_RXC 0x280 0x650 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT10__ECSPI2_MISO 0x280 0x650 0x814 0x2 0x2 +-#define MX6Q_PAD_CSI0_DAT10__UART1_TX_DATA 0x280 0x650 0x000 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT10__UART1_RX_DATA 0x280 0x650 0x920 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT10__GPIO5_IO28 0x280 0x650 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT10__ARM_TRACE07 0x280 0x650 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT11__IPU1_CSI0_DATA11 0x284 0x654 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT11__AUD3_RXFS 0x284 0x654 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT11__ECSPI2_SS0 0x284 0x654 0x81c 0x2 0x2 +-#define MX6Q_PAD_CSI0_DAT11__UART1_RX_DATA 0x284 0x654 0x920 0x3 0x1 +-#define MX6Q_PAD_CSI0_DAT11__UART1_TX_DATA 0x284 0x654 0x000 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT11__GPIO5_IO29 0x284 0x654 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT11__ARM_TRACE08 0x284 0x654 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x288 0x658 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT12__EIM_DATA08 0x288 0x658 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT12__UART4_TX_DATA 0x288 0x658 0x000 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT12__UART4_RX_DATA 0x288 0x658 0x938 0x3 0x2 +-#define MX6Q_PAD_CSI0_DAT12__GPIO5_IO30 0x288 0x658 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT12__ARM_TRACE09 0x288 0x658 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x28c 0x65c 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT13__EIM_DATA09 0x28c 0x65c 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT13__UART4_RX_DATA 0x28c 0x65c 0x938 0x3 0x3 +-#define MX6Q_PAD_CSI0_DAT13__UART4_TX_DATA 0x28c 0x65c 0x000 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT13__GPIO5_IO31 0x28c 0x65c 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT13__ARM_TRACE10 0x28c 0x65c 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x290 0x660 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT14__EIM_DATA10 0x290 0x660 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT14__UART5_TX_DATA 0x290 0x660 0x000 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT14__UART5_RX_DATA 0x290 0x660 0x940 0x3 0x2 +-#define MX6Q_PAD_CSI0_DAT14__GPIO6_IO00 0x290 0x660 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT14__ARM_TRACE11 0x290 0x660 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x294 0x664 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT15__EIM_DATA11 0x294 0x664 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT15__UART5_RX_DATA 0x294 0x664 0x940 0x3 0x3 +-#define MX6Q_PAD_CSI0_DAT15__UART5_TX_DATA 0x294 0x664 0x000 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT15__GPIO6_IO01 0x294 0x664 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT15__ARM_TRACE12 0x294 0x664 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x298 0x668 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT16__EIM_DATA12 0x298 0x668 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT16__UART4_RTS_B 0x298 0x668 0x934 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT16__UART4_CTS_B 0x298 0x668 0x000 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT16__GPIO6_IO02 0x298 0x668 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT16__ARM_TRACE13 0x298 0x668 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x29c 0x66c 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT17__EIM_DATA13 0x29c 0x66c 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT17__UART4_CTS_B 0x29c 0x66c 0x000 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT17__UART4_RTS_B 0x29c 0x66c 0x934 0x3 0x1 +-#define MX6Q_PAD_CSI0_DAT17__GPIO6_IO03 0x29c 0x66c 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT17__ARM_TRACE14 0x29c 0x66c 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x2a0 0x670 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT18__EIM_DATA14 0x2a0 0x670 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT18__UART5_RTS_B 0x2a0 0x670 0x93c 0x3 0x2 +-#define MX6Q_PAD_CSI0_DAT18__UART5_CTS_B 0x2a0 0x670 0x000 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT18__GPIO6_IO04 0x2a0 0x670 0x000 0x5 0x0 +-#define MX6Q_PAD_CSI0_DAT18__ARM_TRACE15 0x2a0 0x670 0x000 0x7 0x0 +-#define MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x2a4 0x674 0x000 0x0 0x0 +-#define MX6Q_PAD_CSI0_DAT19__EIM_DATA15 0x2a4 0x674 0x000 0x1 0x0 +-#define MX6Q_PAD_CSI0_DAT19__UART5_CTS_B 0x2a4 0x674 0x000 0x3 0x0 +-#define MX6Q_PAD_CSI0_DAT19__UART5_RTS_B 0x2a4 0x674 0x93c 0x3 0x3 +-#define MX6Q_PAD_CSI0_DAT19__GPIO6_IO05 0x2a4 0x674 0x000 0x5 0x0 +-#define MX6Q_PAD_SD3_DAT7__SD3_DATA7 0x2a8 0x690 0x000 0x0 0x0 +-#define MX6Q_PAD_SD3_DAT7__UART1_TX_DATA 0x2a8 0x690 0x000 0x1 0x0 +-#define MX6Q_PAD_SD3_DAT7__UART1_RX_DATA 0x2a8 0x690 0x920 0x1 0x2 +-#define MX6Q_PAD_SD3_DAT7__GPIO6_IO17 0x2a8 0x690 0x000 0x5 0x0 +-#define MX6Q_PAD_SD3_DAT6__SD3_DATA6 0x2ac 0x694 0x000 0x0 0x0 +-#define MX6Q_PAD_SD3_DAT6__UART1_RX_DATA 0x2ac 0x694 0x920 0x1 0x3 +-#define MX6Q_PAD_SD3_DAT6__UART1_TX_DATA 0x2ac 0x694 0x000 0x1 0x0 +-#define MX6Q_PAD_SD3_DAT6__GPIO6_IO18 0x2ac 0x694 0x000 0x5 0x0 +-#define MX6Q_PAD_SD3_DAT5__SD3_DATA5 0x2b0 0x698 0x000 0x0 0x0 +-#define MX6Q_PAD_SD3_DAT5__UART2_TX_DATA 0x2b0 0x698 0x000 0x1 0x0 +-#define MX6Q_PAD_SD3_DAT5__UART2_RX_DATA 0x2b0 0x698 0x928 0x1 0x4 +-#define MX6Q_PAD_SD3_DAT5__GPIO7_IO00 0x2b0 0x698 0x000 0x5 0x0 +-#define MX6Q_PAD_SD3_DAT4__SD3_DATA4 0x2b4 0x69c 0x000 0x0 0x0 +-#define MX6Q_PAD_SD3_DAT4__UART2_RX_DATA 0x2b4 0x69c 0x928 0x1 0x5 +-#define MX6Q_PAD_SD3_DAT4__UART2_TX_DATA 0x2b4 0x69c 0x000 0x1 0x0 +-#define MX6Q_PAD_SD3_DAT4__GPIO7_IO01 0x2b4 0x69c 0x000 0x5 0x0 +-#define MX6Q_PAD_SD3_CMD__SD3_CMD 0x2b8 0x6a0 0x000 0x0 0x0 +-#define MX6Q_PAD_SD3_CMD__UART2_CTS_B 0x2b8 0x6a0 0x000 0x1 0x0 +-#define MX6Q_PAD_SD3_CMD__UART2_RTS_B 0x2b8 0x6a0 0x924 0x1 0x2 +-#define MX6Q_PAD_SD3_CMD__FLEXCAN1_TX 0x2b8 0x6a0 0x000 0x2 0x0 +-#define MX6Q_PAD_SD3_CMD__GPIO7_IO02 0x2b8 0x6a0 0x000 0x5 0x0 +-#define MX6Q_PAD_SD3_CLK__SD3_CLK 0x2bc 0x6a4 0x000 0x0 0x0 +-#define MX6Q_PAD_SD3_CLK__UART2_RTS_B 0x2bc 0x6a4 0x924 0x1 0x3 +-#define MX6Q_PAD_SD3_CLK__UART2_CTS_B 0x2bc 0x6a4 0x000 0x1 0x0 +-#define MX6Q_PAD_SD3_CLK__FLEXCAN1_RX 0x2bc 0x6a4 0x7e4 0x2 0x2 +-#define MX6Q_PAD_SD3_CLK__GPIO7_IO03 0x2bc 0x6a4 0x000 0x5 0x0 +-#define MX6Q_PAD_SD3_DAT0__SD3_DATA0 0x2c0 0x6a8 0x000 0x0 0x0 +-#define MX6Q_PAD_SD3_DAT0__UART1_CTS_B 0x2c0 0x6a8 0x000 0x1 0x0 +-#define MX6Q_PAD_SD3_DAT0__UART1_RTS_B 0x2c0 0x6a8 0x91c 0x1 0x2 +-#define MX6Q_PAD_SD3_DAT0__FLEXCAN2_TX 0x2c0 0x6a8 0x000 0x2 0x0 +-#define MX6Q_PAD_SD3_DAT0__GPIO7_IO04 0x2c0 0x6a8 0x000 0x5 0x0 +-#define MX6Q_PAD_SD3_DAT1__SD3_DATA1 0x2c4 0x6ac 0x000 0x0 0x0 +-#define MX6Q_PAD_SD3_DAT1__UART1_RTS_B 0x2c4 0x6ac 0x91c 0x1 0x3 +-#define MX6Q_PAD_SD3_DAT1__UART1_CTS_B 0x2c4 0x6ac 0x000 0x1 0x0 +-#define MX6Q_PAD_SD3_DAT1__FLEXCAN2_RX 0x2c4 0x6ac 0x7e8 0x2 0x1 +-#define MX6Q_PAD_SD3_DAT1__GPIO7_IO05 0x2c4 0x6ac 0x000 0x5 0x0 +-#define MX6Q_PAD_SD3_DAT2__SD3_DATA2 0x2c8 0x6b0 0x000 0x0 0x0 +-#define MX6Q_PAD_SD3_DAT2__GPIO7_IO06 0x2c8 0x6b0 0x000 0x5 0x0 +-#define MX6Q_PAD_SD3_DAT3__SD3_DATA3 0x2cc 0x6b4 0x000 0x0 0x0 +-#define MX6Q_PAD_SD3_DAT3__UART3_CTS_B 0x2cc 0x6b4 0x000 0x1 0x0 +-#define MX6Q_PAD_SD3_DAT3__UART3_RTS_B 0x2cc 0x6b4 0x92c 0x1 0x4 +-#define MX6Q_PAD_SD3_DAT3__GPIO7_IO07 0x2cc 0x6b4 0x000 0x5 0x0 +-#define MX6Q_PAD_SD3_RST__SD3_RESET 0x2d0 0x6b8 0x000 0x0 0x0 +-#define MX6Q_PAD_SD3_RST__UART3_RTS_B 0x2d0 0x6b8 0x92c 0x1 0x5 +-#define MX6Q_PAD_SD3_RST__UART3_CTS_B 0x2d0 0x6b8 0x000 0x1 0x0 +-#define MX6Q_PAD_SD3_RST__GPIO7_IO08 0x2d0 0x6b8 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_CLE__NAND_CLE 0x2d4 0x6bc 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_CLE__IPU2_SISG4 0x2d4 0x6bc 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_CLE__GPIO6_IO07 0x2d4 0x6bc 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_ALE__NAND_ALE 0x2d8 0x6c0 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_ALE__SD4_RESET 0x2d8 0x6c0 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_ALE__GPIO6_IO08 0x2d8 0x6c0 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_WP_B__NAND_WP_B 0x2dc 0x6c4 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_WP_B__IPU2_SISG5 0x2dc 0x6c4 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_WP_B__GPIO6_IO09 0x2dc 0x6c4 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_RB0__NAND_READY_B 0x2e0 0x6c8 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_RB0__IPU2_DI0_PIN01 0x2e0 0x6c8 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_RB0__GPIO6_IO10 0x2e0 0x6c8 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_CS0__NAND_CE0_B 0x2e4 0x6cc 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_CS0__GPIO6_IO11 0x2e4 0x6cc 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_CS1__NAND_CE1_B 0x2e8 0x6d0 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_CS1__SD4_VSELECT 0x2e8 0x6d0 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_CS1__SD3_VSELECT 0x2e8 0x6d0 0x000 0x2 0x0 +-#define MX6Q_PAD_NANDF_CS1__GPIO6_IO14 0x2e8 0x6d0 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_CS2__NAND_CE2_B 0x2ec 0x6d4 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_CS2__IPU1_SISG0 0x2ec 0x6d4 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_CS2__ESAI_TX0 0x2ec 0x6d4 0x874 0x2 0x1 +-#define MX6Q_PAD_NANDF_CS2__EIM_CRE 0x2ec 0x6d4 0x000 0x3 0x0 +-#define MX6Q_PAD_NANDF_CS2__CCM_CLKO2 0x2ec 0x6d4 0x000 0x4 0x0 +-#define MX6Q_PAD_NANDF_CS2__GPIO6_IO15 0x2ec 0x6d4 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_CS2__IPU2_SISG0 0x2ec 0x6d4 0x000 0x6 0x0 +-#define MX6Q_PAD_NANDF_CS3__NAND_CE3_B 0x2f0 0x6d8 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_CS3__IPU1_SISG1 0x2f0 0x6d8 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_CS3__ESAI_TX1 0x2f0 0x6d8 0x878 0x2 0x1 +-#define MX6Q_PAD_NANDF_CS3__EIM_ADDR26 0x2f0 0x6d8 0x000 0x3 0x0 +-#define MX6Q_PAD_NANDF_CS3__GPIO6_IO16 0x2f0 0x6d8 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_CS3__IPU2_SISG1 0x2f0 0x6d8 0x000 0x6 0x0 +-#define MX6Q_PAD_SD4_CMD__SD4_CMD 0x2f4 0x6dc 0x000 0x0 0x0 +-#define MX6Q_PAD_SD4_CMD__NAND_RE_B 0x2f4 0x6dc 0x000 0x1 0x0 +-#define MX6Q_PAD_SD4_CMD__UART3_TX_DATA 0x2f4 0x6dc 0x000 0x2 0x0 +-#define MX6Q_PAD_SD4_CMD__UART3_RX_DATA 0x2f4 0x6dc 0x930 0x2 0x2 +-#define MX6Q_PAD_SD4_CMD__GPIO7_IO09 0x2f4 0x6dc 0x000 0x5 0x0 +-#define MX6Q_PAD_SD4_CLK__SD4_CLK 0x2f8 0x6e0 0x000 0x0 0x0 +-#define MX6Q_PAD_SD4_CLK__NAND_WE_B 0x2f8 0x6e0 0x000 0x1 0x0 +-#define MX6Q_PAD_SD4_CLK__UART3_RX_DATA 0x2f8 0x6e0 0x930 0x2 0x3 +-#define MX6Q_PAD_SD4_CLK__UART3_TX_DATA 0x2f8 0x6e0 0x000 0x2 0x0 +-#define MX6Q_PAD_SD4_CLK__GPIO7_IO10 0x2f8 0x6e0 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_D0__NAND_DATA00 0x2fc 0x6e4 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_D0__SD1_DATA4 0x2fc 0x6e4 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_D0__GPIO2_IO00 0x2fc 0x6e4 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_D1__NAND_DATA01 0x300 0x6e8 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_D1__SD1_DATA5 0x300 0x6e8 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_D1__GPIO2_IO01 0x300 0x6e8 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_D2__NAND_DATA02 0x304 0x6ec 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_D2__SD1_DATA6 0x304 0x6ec 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_D2__GPIO2_IO02 0x304 0x6ec 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_D3__NAND_DATA03 0x308 0x6f0 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_D3__SD1_DATA7 0x308 0x6f0 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_D3__GPIO2_IO03 0x308 0x6f0 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_D4__NAND_DATA04 0x30c 0x6f4 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_D4__SD2_DATA4 0x30c 0x6f4 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_D4__GPIO2_IO04 0x30c 0x6f4 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_D5__NAND_DATA05 0x310 0x6f8 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_D5__SD2_DATA5 0x310 0x6f8 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_D5__GPIO2_IO05 0x310 0x6f8 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_D6__NAND_DATA06 0x314 0x6fc 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_D6__SD2_DATA6 0x314 0x6fc 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_D6__GPIO2_IO06 0x314 0x6fc 0x000 0x5 0x0 +-#define MX6Q_PAD_NANDF_D7__NAND_DATA07 0x318 0x700 0x000 0x0 0x0 +-#define MX6Q_PAD_NANDF_D7__SD2_DATA7 0x318 0x700 0x000 0x1 0x0 +-#define MX6Q_PAD_NANDF_D7__GPIO2_IO07 0x318 0x700 0x000 0x5 0x0 +-#define MX6Q_PAD_SD4_DAT0__SD4_DATA0 0x31c 0x704 0x000 0x1 0x0 +-#define MX6Q_PAD_SD4_DAT0__NAND_DQS 0x31c 0x704 0x000 0x2 0x0 +-#define MX6Q_PAD_SD4_DAT0__GPIO2_IO08 0x31c 0x704 0x000 0x5 0x0 +-#define MX6Q_PAD_SD4_DAT1__SD4_DATA1 0x320 0x708 0x000 0x1 0x0 +-#define MX6Q_PAD_SD4_DAT1__PWM3_OUT 0x320 0x708 0x000 0x2 0x0 +-#define MX6Q_PAD_SD4_DAT1__GPIO2_IO09 0x320 0x708 0x000 0x5 0x0 +-#define MX6Q_PAD_SD4_DAT2__SD4_DATA2 0x324 0x70c 0x000 0x1 0x0 +-#define MX6Q_PAD_SD4_DAT2__PWM4_OUT 0x324 0x70c 0x000 0x2 0x0 +-#define MX6Q_PAD_SD4_DAT2__GPIO2_IO10 0x324 0x70c 0x000 0x5 0x0 +-#define MX6Q_PAD_SD4_DAT3__SD4_DATA3 0x328 0x710 0x000 0x1 0x0 +-#define MX6Q_PAD_SD4_DAT3__GPIO2_IO11 0x328 0x710 0x000 0x5 0x0 +-#define MX6Q_PAD_SD4_DAT4__SD4_DATA4 0x32c 0x714 0x000 0x1 0x0 +-#define MX6Q_PAD_SD4_DAT4__UART2_RX_DATA 0x32c 0x714 0x928 0x2 0x6 +-#define MX6Q_PAD_SD4_DAT4__UART2_TX_DATA 0x32c 0x714 0x000 0x2 0x0 +-#define MX6Q_PAD_SD4_DAT4__GPIO2_IO12 0x32c 0x714 0x000 0x5 0x0 +-#define MX6Q_PAD_SD4_DAT5__SD4_DATA5 0x330 0x718 0x000 0x1 0x0 +-#define MX6Q_PAD_SD4_DAT5__UART2_RTS_B 0x330 0x718 0x924 0x2 0x4 +-#define MX6Q_PAD_SD4_DAT5__UART2_CTS_B 0x330 0x718 0x000 0x2 0x0 +-#define MX6Q_PAD_SD4_DAT5__GPIO2_IO13 0x330 0x718 0x000 0x5 0x0 +-#define MX6Q_PAD_SD4_DAT6__SD4_DATA6 0x334 0x71c 0x000 0x1 0x0 +-#define MX6Q_PAD_SD4_DAT6__UART2_CTS_B 0x334 0x71c 0x000 0x2 0x0 +-#define MX6Q_PAD_SD4_DAT6__UART2_RTS_B 0x334 0x71c 0x924 0x2 0x5 +-#define MX6Q_PAD_SD4_DAT6__GPIO2_IO14 0x334 0x71c 0x000 0x5 0x0 +-#define MX6Q_PAD_SD4_DAT7__SD4_DATA7 0x338 0x720 0x000 0x1 0x0 +-#define MX6Q_PAD_SD4_DAT7__UART2_TX_DATA 0x338 0x720 0x000 0x2 0x0 +-#define MX6Q_PAD_SD4_DAT7__UART2_RX_DATA 0x338 0x720 0x928 0x2 0x7 +-#define MX6Q_PAD_SD4_DAT7__GPIO2_IO15 0x338 0x720 0x000 0x5 0x0 +-#define MX6Q_PAD_SD1_DAT1__SD1_DATA1 0x33c 0x724 0x000 0x0 0x0 +-#define MX6Q_PAD_SD1_DAT1__ECSPI5_SS0 0x33c 0x724 0x834 0x1 0x1 +-#define MX6Q_PAD_SD1_DAT1__PWM3_OUT 0x33c 0x724 0x000 0x2 0x0 +-#define MX6Q_PAD_SD1_DAT1__GPT_CAPTURE2 0x33c 0x724 0x000 0x3 0x0 +-#define MX6Q_PAD_SD1_DAT1__GPIO1_IO17 0x33c 0x724 0x000 0x5 0x0 +-#define MX6Q_PAD_SD1_DAT0__SD1_DATA0 0x340 0x728 0x000 0x0 0x0 +-#define MX6Q_PAD_SD1_DAT0__ECSPI5_MISO 0x340 0x728 0x82c 0x1 0x1 +-#define MX6Q_PAD_SD1_DAT0__GPT_CAPTURE1 0x340 0x728 0x000 0x3 0x0 +-#define MX6Q_PAD_SD1_DAT0__GPIO1_IO16 0x340 0x728 0x000 0x5 0x0 +-#define MX6Q_PAD_SD1_DAT3__SD1_DATA3 0x344 0x72c 0x000 0x0 0x0 +-#define MX6Q_PAD_SD1_DAT3__ECSPI5_SS2 0x344 0x72c 0x000 0x1 0x0 +-#define MX6Q_PAD_SD1_DAT3__GPT_COMPARE3 0x344 0x72c 0x000 0x2 0x0 +-#define MX6Q_PAD_SD1_DAT3__PWM1_OUT 0x344 0x72c 0x000 0x3 0x0 +-#define MX6Q_PAD_SD1_DAT3__WDOG2_B 0x344 0x72c 0x000 0x4 0x0 +-#define MX6Q_PAD_SD1_DAT3__GPIO1_IO21 0x344 0x72c 0x000 0x5 0x0 +-#define MX6Q_PAD_SD1_DAT3__WDOG2_RESET_B_DEB 0x344 0x72c 0x000 0x6 0x0 +-#define MX6Q_PAD_SD1_CMD__SD1_CMD 0x348 0x730 0x000 0x0 0x0 +-#define MX6Q_PAD_SD1_CMD__ECSPI5_MOSI 0x348 0x730 0x830 0x1 0x0 +-#define MX6Q_PAD_SD1_CMD__PWM4_OUT 0x348 0x730 0x000 0x2 0x0 +-#define MX6Q_PAD_SD1_CMD__GPT_COMPARE1 0x348 0x730 0x000 0x3 0x0 +-#define MX6Q_PAD_SD1_CMD__GPIO1_IO18 0x348 0x730 0x000 0x5 0x0 +-#define MX6Q_PAD_SD1_DAT2__SD1_DATA2 0x34c 0x734 0x000 0x0 0x0 +-#define MX6Q_PAD_SD1_DAT2__ECSPI5_SS1 0x34c 0x734 0x838 0x1 0x1 +-#define MX6Q_PAD_SD1_DAT2__GPT_COMPARE2 0x34c 0x734 0x000 0x2 0x0 +-#define MX6Q_PAD_SD1_DAT2__PWM2_OUT 0x34c 0x734 0x000 0x3 0x0 +-#define MX6Q_PAD_SD1_DAT2__WDOG1_B 0x34c 0x734 0x000 0x4 0x0 +-#define MX6Q_PAD_SD1_DAT2__GPIO1_IO19 0x34c 0x734 0x000 0x5 0x0 +-#define MX6Q_PAD_SD1_DAT2__WDOG1_RESET_B_DEB 0x34c 0x734 0x000 0x6 0x0 +-#define MX6Q_PAD_SD1_CLK__SD1_CLK 0x350 0x738 0x000 0x0 0x0 +-#define MX6Q_PAD_SD1_CLK__ECSPI5_SCLK 0x350 0x738 0x828 0x1 0x0 +-#define MX6Q_PAD_SD1_CLK__GPT_CLKIN 0x350 0x738 0x000 0x3 0x0 +-#define MX6Q_PAD_SD1_CLK__GPIO1_IO20 0x350 0x738 0x000 0x5 0x0 +-#define MX6Q_PAD_SD2_CLK__SD2_CLK 0x354 0x73c 0x000 0x0 0x0 +-#define MX6Q_PAD_SD2_CLK__ECSPI5_SCLK 0x354 0x73c 0x828 0x1 0x1 +-#define MX6Q_PAD_SD2_CLK__KEY_COL5 0x354 0x73c 0x8e8 0x2 0x3 +-#define MX6Q_PAD_SD2_CLK__AUD4_RXFS 0x354 0x73c 0x7c0 0x3 0x1 +-#define MX6Q_PAD_SD2_CLK__GPIO1_IO10 0x354 0x73c 0x000 0x5 0x0 +-#define MX6Q_PAD_SD2_CMD__SD2_CMD 0x358 0x740 0x000 0x0 0x0 +-#define MX6Q_PAD_SD2_CMD__ECSPI5_MOSI 0x358 0x740 0x830 0x1 0x1 +-#define MX6Q_PAD_SD2_CMD__KEY_ROW5 0x358 0x740 0x8f4 0x2 0x2 +-#define MX6Q_PAD_SD2_CMD__AUD4_RXC 0x358 0x740 0x7bc 0x3 0x1 +-#define MX6Q_PAD_SD2_CMD__GPIO1_IO11 0x358 0x740 0x000 0x5 0x0 +-#define MX6Q_PAD_SD2_DAT3__SD2_DATA3 0x35c 0x744 0x000 0x0 0x0 +-#define MX6Q_PAD_SD2_DAT3__ECSPI5_SS3 0x35c 0x744 0x000 0x1 0x0 +-#define MX6Q_PAD_SD2_DAT3__KEY_COL6 0x35c 0x744 0x8ec 0x2 0x2 +-#define MX6Q_PAD_SD2_DAT3__AUD4_TXC 0x35c 0x744 0x7c4 0x3 0x1 +-#define MX6Q_PAD_SD2_DAT3__GPIO1_IO12 0x35c 0x744 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x04c 0x360 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD2_DAT1__ECSPI5_SS0 0x04c 0x360 0x834 0x1 0x0 ++#define MX6QDL_PAD_SD2_DAT1__EIM_CS2_B 0x04c 0x360 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x04c 0x360 0x7c8 0x3 0x0 ++#define MX6QDL_PAD_SD2_DAT1__KEY_COL7 0x04c 0x360 0x8f0 0x4 0x0 ++#define MX6QDL_PAD_SD2_DAT1__GPIO1_IO14 0x04c 0x360 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x050 0x364 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD2_DAT2__ECSPI5_SS1 0x050 0x364 0x838 0x1 0x0 ++#define MX6QDL_PAD_SD2_DAT2__EIM_CS3_B 0x050 0x364 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x050 0x364 0x7b8 0x3 0x0 ++#define MX6QDL_PAD_SD2_DAT2__KEY_ROW6 0x050 0x364 0x8f8 0x4 0x0 ++#define MX6QDL_PAD_SD2_DAT2__GPIO1_IO13 0x050 0x364 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x054 0x368 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD2_DAT0__ECSPI5_MISO 0x054 0x368 0x82c 0x1 0x0 ++#define MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x054 0x368 0x7b4 0x3 0x0 ++#define MX6QDL_PAD_SD2_DAT0__KEY_ROW7 0x054 0x368 0x8fc 0x4 0x0 ++#define MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x054 0x368 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_DAT0__DCIC2_OUT 0x054 0x368 0x000 0x6 0x0 ++#define MX6QDL_PAD_RGMII_TXC__USB_H2_DATA 0x058 0x36c 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x058 0x36c 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TXC__SPDIF_EXT_CLK 0x058 0x36c 0x918 0x2 0x0 ++#define MX6QDL_PAD_RGMII_TXC__GPIO6_IO19 0x058 0x36c 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TXC__XTALOSC_REF_CLK_24M 0x058 0x36c 0x000 0x7 0x0 ++#define MX6QDL_PAD_RGMII_TD0__HSI_TX_READY 0x05c 0x370 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x05c 0x370 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TD0__GPIO6_IO20 0x05c 0x370 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TD1__HSI_RX_FLAG 0x060 0x374 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x060 0x374 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TD1__GPIO6_IO21 0x060 0x374 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TD2__HSI_RX_DATA 0x064 0x378 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x064 0x378 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TD2__GPIO6_IO22 0x064 0x378 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TD3__HSI_RX_WAKE 0x068 0x37c 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x068 0x37c 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TD3__GPIO6_IO23 0x068 0x37c 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_RX_CTL__USB_H3_DATA 0x06c 0x380 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x06c 0x380 0x858 0x1 0x0 ++#define MX6QDL_PAD_RGMII_RX_CTL__GPIO6_IO24 0x06c 0x380 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_RD0__HSI_RX_READY 0x070 0x384 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x070 0x384 0x848 0x1 0x0 ++#define MX6QDL_PAD_RGMII_RD0__GPIO6_IO25 0x070 0x384 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TX_CTL__USB_H2_STROBE 0x074 0x388 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x074 0x388 0x000 0x1 0x0 ++#define MX6QDL_PAD_RGMII_TX_CTL__GPIO6_IO26 0x074 0x388 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_TX_CTL__ENET_REF_CLK 0x074 0x388 0x83c 0x7 0x0 ++#define MX6QDL_PAD_RGMII_RD1__HSI_TX_FLAG 0x078 0x38c 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x078 0x38c 0x84c 0x1 0x0 ++#define MX6QDL_PAD_RGMII_RD1__GPIO6_IO27 0x078 0x38c 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_RD2__HSI_TX_DATA 0x07c 0x390 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x07c 0x390 0x850 0x1 0x0 ++#define MX6QDL_PAD_RGMII_RD2__GPIO6_IO28 0x07c 0x390 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_RD3__HSI_TX_WAKE 0x080 0x394 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x080 0x394 0x854 0x1 0x0 ++#define MX6QDL_PAD_RGMII_RD3__GPIO6_IO29 0x080 0x394 0x000 0x5 0x0 ++#define MX6QDL_PAD_RGMII_RXC__USB_H3_STROBE 0x084 0x398 0x000 0x0 0x0 ++#define MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x084 0x398 0x844 0x1 0x0 ++#define MX6QDL_PAD_RGMII_RXC__GPIO6_IO30 0x084 0x398 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A25__EIM_ADDR25 0x088 0x39c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A25__ECSPI4_SS1 0x088 0x39c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A25__ECSPI2_RDY 0x088 0x39c 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_A25__IPU1_DI1_PIN12 0x088 0x39c 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_A25__IPU1_DI0_D1_CS 0x088 0x39c 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x088 0x39c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x088 0x39c 0x88c 0x6 0x0 ++#define MX6QDL_PAD_EIM_EB2__EIM_EB2_B 0x08c 0x3a0 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_EB2__ECSPI1_SS0 0x08c 0x3a0 0x800 0x1 0x0 ++#define MX6QDL_PAD_EIM_EB2__IPU2_CSI1_DATA19 0x08c 0x3a0 0x8d4 0x3 0x0 ++#define MX6QDL_PAD_EIM_EB2__HDMI_TX_DDC_SCL 0x08c 0x3a0 0x890 0x4 0x0 ++#define MX6QDL_PAD_EIM_EB2__GPIO2_IO30 0x08c 0x3a0 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x08c 0x3a0 0x8a0 0x6 0x0 ++#define MX6QDL_PAD_EIM_EB2__SRC_BOOT_CFG30 0x08c 0x3a0 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D16__EIM_DATA16 0x090 0x3a4 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x090 0x3a4 0x7f4 0x1 0x0 ++#define MX6QDL_PAD_EIM_D16__IPU1_DI0_PIN05 0x090 0x3a4 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D16__IPU2_CSI1_DATA18 0x090 0x3a4 0x8d0 0x3 0x0 ++#define MX6QDL_PAD_EIM_D16__HDMI_TX_DDC_SDA 0x090 0x3a4 0x894 0x4 0x0 ++#define MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x090 0x3a4 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D16__I2C2_SDA 0x090 0x3a4 0x8a4 0x6 0x0 ++#define MX6QDL_PAD_EIM_D17__EIM_DATA17 0x094 0x3a8 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x094 0x3a8 0x7f8 0x1 0x0 ++#define MX6QDL_PAD_EIM_D17__IPU1_DI0_PIN06 0x094 0x3a8 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D17__IPU2_CSI1_PIXCLK 0x094 0x3a8 0x8e0 0x3 0x0 ++#define MX6QDL_PAD_EIM_D17__DCIC1_OUT 0x094 0x3a8 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D17__GPIO3_IO17 0x094 0x3a8 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D17__I2C3_SCL 0x094 0x3a8 0x8a8 0x6 0x0 ++#define MX6QDL_PAD_EIM_D18__EIM_DATA18 0x098 0x3ac 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x098 0x3ac 0x7fc 0x1 0x0 ++#define MX6QDL_PAD_EIM_D18__IPU1_DI0_PIN07 0x098 0x3ac 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D18__IPU2_CSI1_DATA17 0x098 0x3ac 0x8cc 0x3 0x0 ++#define MX6QDL_PAD_EIM_D18__IPU1_DI1_D0_CS 0x098 0x3ac 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D18__GPIO3_IO18 0x098 0x3ac 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D18__I2C3_SDA 0x098 0x3ac 0x8ac 0x6 0x0 ++#define MX6QDL_PAD_EIM_D19__EIM_DATA19 0x09c 0x3b0 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D19__ECSPI1_SS1 0x09c 0x3b0 0x804 0x1 0x0 ++#define MX6QDL_PAD_EIM_D19__IPU1_DI0_PIN08 0x09c 0x3b0 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D19__IPU2_CSI1_DATA16 0x09c 0x3b0 0x8c8 0x3 0x0 ++#define MX6QDL_PAD_EIM_D19__UART1_CTS_B 0x09c 0x3b0 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D19__UART1_RTS_B 0x09c 0x3b0 0x91c 0x4 0x0 ++#define MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x09c 0x3b0 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D19__EPIT1_OUT 0x09c 0x3b0 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D20__EIM_DATA20 0x0a0 0x3b4 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D20__ECSPI4_SS0 0x0a0 0x3b4 0x824 0x1 0x0 ++#define MX6QDL_PAD_EIM_D20__IPU1_DI0_PIN16 0x0a0 0x3b4 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D20__IPU2_CSI1_DATA15 0x0a0 0x3b4 0x8c4 0x3 0x0 ++#define MX6QDL_PAD_EIM_D20__UART1_RTS_B 0x0a0 0x3b4 0x91c 0x4 0x1 ++#define MX6QDL_PAD_EIM_D20__UART1_CTS_B 0x0a0 0x3b4 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x0a0 0x3b4 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D20__EPIT2_OUT 0x0a0 0x3b4 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D21__EIM_DATA21 0x0a4 0x3b8 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D21__ECSPI4_SCLK 0x0a4 0x3b8 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D21__IPU1_DI0_PIN17 0x0a4 0x3b8 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D21__IPU2_CSI1_DATA11 0x0a4 0x3b8 0x8b4 0x3 0x0 ++#define MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x0a4 0x3b8 0x944 0x4 0x0 ++#define MX6QDL_PAD_EIM_D21__GPIO3_IO21 0x0a4 0x3b8 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D21__I2C1_SCL 0x0a4 0x3b8 0x898 0x6 0x0 ++#define MX6QDL_PAD_EIM_D21__SPDIF_IN 0x0a4 0x3b8 0x914 0x7 0x0 ++#define MX6QDL_PAD_EIM_D22__EIM_DATA22 0x0a8 0x3bc 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D22__ECSPI4_MISO 0x0a8 0x3bc 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D22__IPU1_DI0_PIN01 0x0a8 0x3bc 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D22__IPU2_CSI1_DATA10 0x0a8 0x3bc 0x8b0 0x3 0x0 ++#define MX6QDL_PAD_EIM_D22__USB_OTG_PWR 0x0a8 0x3bc 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x0a8 0x3bc 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D22__SPDIF_OUT 0x0a8 0x3bc 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D23__EIM_DATA23 0x0ac 0x3c0 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D23__IPU1_DI0_D0_CS 0x0ac 0x3c0 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x0ac 0x3c0 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D23__UART3_RTS_B 0x0ac 0x3c0 0x92c 0x2 0x0 ++#define MX6QDL_PAD_EIM_D23__UART1_DCD_B 0x0ac 0x3c0 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_D23__IPU2_CSI1_DATA_EN 0x0ac 0x3c0 0x8d8 0x4 0x0 ++#define MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x0ac 0x3c0 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D23__IPU1_DI1_PIN02 0x0ac 0x3c0 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D23__IPU1_DI1_PIN14 0x0ac 0x3c0 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_EB3__EIM_EB3_B 0x0b0 0x3c4 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_EB3__ECSPI4_RDY 0x0b0 0x3c4 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_EB3__UART3_RTS_B 0x0b0 0x3c4 0x92c 0x2 0x1 ++#define MX6QDL_PAD_EIM_EB3__UART3_CTS_B 0x0b0 0x3c4 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_EB3__UART1_RI_B 0x0b0 0x3c4 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_EB3__IPU2_CSI1_HSYNC 0x0b0 0x3c4 0x8dc 0x4 0x0 ++#define MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x0b0 0x3c4 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_EB3__IPU1_DI1_PIN03 0x0b0 0x3c4 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_EB3__SRC_BOOT_CFG31 0x0b0 0x3c4 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D24__EIM_DATA24 0x0b4 0x3c8 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D24__ECSPI4_SS2 0x0b4 0x3c8 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x0b4 0x3c8 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D24__UART3_RX_DATA 0x0b4 0x3c8 0x930 0x2 0x0 ++#define MX6QDL_PAD_EIM_D24__ECSPI1_SS2 0x0b4 0x3c8 0x808 0x3 0x0 ++#define MX6QDL_PAD_EIM_D24__ECSPI2_SS2 0x0b4 0x3c8 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D24__GPIO3_IO24 0x0b4 0x3c8 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D24__AUD5_RXFS 0x0b4 0x3c8 0x7d8 0x6 0x0 ++#define MX6QDL_PAD_EIM_D24__UART1_DTR_B 0x0b4 0x3c8 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D25__EIM_DATA25 0x0b8 0x3cc 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D25__ECSPI4_SS3 0x0b8 0x3cc 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x0b8 0x3cc 0x930 0x2 0x1 ++#define MX6QDL_PAD_EIM_D25__UART3_TX_DATA 0x0b8 0x3cc 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D25__ECSPI1_SS3 0x0b8 0x3cc 0x80c 0x3 0x0 ++#define MX6QDL_PAD_EIM_D25__ECSPI2_SS3 0x0b8 0x3cc 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D25__GPIO3_IO25 0x0b8 0x3cc 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D25__AUD5_RXC 0x0b8 0x3cc 0x7d4 0x6 0x0 ++#define MX6QDL_PAD_EIM_D25__UART1_DSR_B 0x0b8 0x3cc 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D26__EIM_DATA26 0x0bc 0x3d0 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D26__IPU1_DI1_PIN11 0x0bc 0x3d0 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D26__IPU1_CSI0_DATA01 0x0bc 0x3d0 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D26__IPU2_CSI1_DATA14 0x0bc 0x3d0 0x8c0 0x3 0x0 ++#define MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x0bc 0x3d0 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D26__UART2_RX_DATA 0x0bc 0x3d0 0x928 0x4 0x0 ++#define MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x0bc 0x3d0 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D26__IPU1_SISG2 0x0bc 0x3d0 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D26__IPU1_DISP1_DATA22 0x0bc 0x3d0 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D27__EIM_DATA27 0x0c0 0x3d4 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D27__IPU1_DI1_PIN13 0x0c0 0x3d4 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D27__IPU1_CSI0_DATA00 0x0c0 0x3d4 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D27__IPU2_CSI1_DATA13 0x0c0 0x3d4 0x8bc 0x3 0x0 ++#define MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x0c0 0x3d4 0x928 0x4 0x1 ++#define MX6QDL_PAD_EIM_D27__UART2_TX_DATA 0x0c0 0x3d4 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D27__GPIO3_IO27 0x0c0 0x3d4 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D27__IPU1_SISG3 0x0c0 0x3d4 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D27__IPU1_DISP1_DATA23 0x0c0 0x3d4 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D28__EIM_DATA28 0x0c4 0x3d8 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D28__I2C1_SDA 0x0c4 0x3d8 0x89c 0x1 0x0 ++#define MX6QDL_PAD_EIM_D28__ECSPI4_MOSI 0x0c4 0x3d8 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D28__IPU2_CSI1_DATA12 0x0c4 0x3d8 0x8b8 0x3 0x0 ++#define MX6QDL_PAD_EIM_D28__UART2_CTS_B 0x0c4 0x3d8 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D28__UART2_RTS_B 0x0c4 0x3d8 0x924 0x4 0x0 ++#define MX6QDL_PAD_EIM_D28__UART2_DTE_CTS_B 0x0c4 0x3d8 0x924 0x4 0x0 ++#define MX6QDL_PAD_EIM_D28__UART2_DTE_RTS_B 0x0c4 0x3d8 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x0c4 0x3d8 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D28__IPU1_EXT_TRIG 0x0c4 0x3d8 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_D28__IPU1_DI0_PIN13 0x0c4 0x3d8 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D29__EIM_DATA29 0x0c8 0x3dc 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D29__IPU1_DI1_PIN15 0x0c8 0x3dc 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D29__ECSPI4_SS0 0x0c8 0x3dc 0x824 0x2 0x1 ++#define MX6QDL_PAD_EIM_D29__UART2_RTS_B 0x0c8 0x3dc 0x924 0x4 0x1 ++#define MX6QDL_PAD_EIM_D29__UART2_CTS_B 0x0c8 0x3dc 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D29__UART2_DTE_RTS_B 0x0c8 0x3dc 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D29__UART2_DTE_CTS_B 0x0c8 0x3dc 0x924 0x4 0x1 ++#define MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x0c8 0x3dc 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D29__IPU2_CSI1_VSYNC 0x0c8 0x3dc 0x8e4 0x6 0x0 ++#define MX6QDL_PAD_EIM_D29__IPU1_DI0_PIN14 0x0c8 0x3dc 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_D30__EIM_DATA30 0x0cc 0x3e0 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D30__IPU1_DISP1_DATA21 0x0cc 0x3e0 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D30__IPU1_DI0_PIN11 0x0cc 0x3e0 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D30__IPU1_CSI0_DATA03 0x0cc 0x3e0 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_D30__UART3_CTS_B 0x0cc 0x3e0 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D30__UART3_RTS_B 0x0cc 0x3e0 0x92c 0x4 0x2 ++#define MX6QDL_PAD_EIM_D30__GPIO3_IO30 0x0cc 0x3e0 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D30__USB_H1_OC 0x0cc 0x3e0 0x948 0x6 0x0 ++#define MX6QDL_PAD_EIM_D31__EIM_DATA31 0x0d0 0x3e4 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_D31__IPU1_DISP1_DATA20 0x0d0 0x3e4 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_D31__IPU1_DI0_PIN12 0x0d0 0x3e4 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_D31__IPU1_CSI0_DATA02 0x0d0 0x3e4 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x0d0 0x3e4 0x92c 0x4 0x3 ++#define MX6QDL_PAD_EIM_D31__UART3_CTS_B 0x0d0 0x3e4 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x0d0 0x3e4 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_D31__USB_H1_PWR 0x0d0 0x3e4 0x000 0x6 0x0 ++#define MX6QDL_PAD_EIM_A24__EIM_ADDR24 0x0d4 0x3e8 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A24__IPU1_DISP1_DATA19 0x0d4 0x3e8 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A24__IPU2_CSI1_DATA19 0x0d4 0x3e8 0x8d4 0x2 0x1 ++#define MX6QDL_PAD_EIM_A24__IPU2_SISG2 0x0d4 0x3e8 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_A24__IPU1_SISG2 0x0d4 0x3e8 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x0d4 0x3e8 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A24__SRC_BOOT_CFG24 0x0d4 0x3e8 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A23__EIM_ADDR23 0x0d8 0x3ec 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A23__IPU1_DISP1_DATA18 0x0d8 0x3ec 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A23__IPU2_CSI1_DATA18 0x0d8 0x3ec 0x8d0 0x2 0x1 ++#define MX6QDL_PAD_EIM_A23__IPU2_SISG3 0x0d8 0x3ec 0x000 0x3 0x0 ++#define MX6QDL_PAD_EIM_A23__IPU1_SISG3 0x0d8 0x3ec 0x000 0x4 0x0 ++#define MX6QDL_PAD_EIM_A23__GPIO6_IO06 0x0d8 0x3ec 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A23__SRC_BOOT_CFG23 0x0d8 0x3ec 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A22__EIM_ADDR22 0x0dc 0x3f0 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A22__IPU1_DISP1_DATA17 0x0dc 0x3f0 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A22__IPU2_CSI1_DATA17 0x0dc 0x3f0 0x8cc 0x2 0x1 ++#define MX6QDL_PAD_EIM_A22__GPIO2_IO16 0x0dc 0x3f0 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A22__SRC_BOOT_CFG22 0x0dc 0x3f0 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A21__EIM_ADDR21 0x0e0 0x3f4 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A21__IPU1_DISP1_DATA16 0x0e0 0x3f4 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A21__IPU2_CSI1_DATA16 0x0e0 0x3f4 0x8c8 0x2 0x1 ++#define MX6QDL_PAD_EIM_A21__GPIO2_IO17 0x0e0 0x3f4 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A21__SRC_BOOT_CFG21 0x0e0 0x3f4 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A20__EIM_ADDR20 0x0e4 0x3f8 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A20__IPU1_DISP1_DATA15 0x0e4 0x3f8 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A20__IPU2_CSI1_DATA15 0x0e4 0x3f8 0x8c4 0x2 0x1 ++#define MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x0e4 0x3f8 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A20__SRC_BOOT_CFG20 0x0e4 0x3f8 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A19__EIM_ADDR19 0x0e8 0x3fc 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A19__IPU1_DISP1_DATA14 0x0e8 0x3fc 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A19__IPU2_CSI1_DATA14 0x0e8 0x3fc 0x8c0 0x2 0x1 ++#define MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x0e8 0x3fc 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A19__SRC_BOOT_CFG19 0x0e8 0x3fc 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A18__EIM_ADDR18 0x0ec 0x400 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A18__IPU1_DISP1_DATA13 0x0ec 0x400 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A18__IPU2_CSI1_DATA13 0x0ec 0x400 0x8bc 0x2 0x1 ++#define MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x0ec 0x400 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A18__SRC_BOOT_CFG18 0x0ec 0x400 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A17__EIM_ADDR17 0x0f0 0x404 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A17__IPU1_DISP1_DATA12 0x0f0 0x404 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A17__IPU2_CSI1_DATA12 0x0f0 0x404 0x8b8 0x2 0x1 ++#define MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x0f0 0x404 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A17__SRC_BOOT_CFG17 0x0f0 0x404 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_A16__EIM_ADDR16 0x0f4 0x408 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_A16__IPU1_DI1_DISP_CLK 0x0f4 0x408 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_A16__IPU2_CSI1_PIXCLK 0x0f4 0x408 0x8e0 0x2 0x1 ++#define MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x0f4 0x408 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_A16__SRC_BOOT_CFG16 0x0f4 0x408 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_CS0__EIM_CS0_B 0x0f8 0x40c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_CS0__IPU1_DI1_PIN05 0x0f8 0x40c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x0f8 0x40c 0x810 0x2 0x0 ++#define MX6QDL_PAD_EIM_CS0__GPIO2_IO23 0x0f8 0x40c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_CS1__EIM_CS1_B 0x0fc 0x410 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_CS1__IPU1_DI1_PIN06 0x0fc 0x410 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x0fc 0x410 0x818 0x2 0x0 ++#define MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x0fc 0x410 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_OE__EIM_OE_B 0x100 0x414 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_OE__IPU1_DI1_PIN07 0x100 0x414 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100 0x414 0x814 0x2 0x0 ++#define MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x100 0x414 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_RW__EIM_RW 0x104 0x418 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_RW__IPU1_DI1_PIN08 0x104 0x418 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_RW__ECSPI2_SS0 0x104 0x418 0x81c 0x2 0x0 ++#define MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x104 0x418 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_RW__SRC_BOOT_CFG29 0x104 0x418 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_LBA__EIM_LBA_B 0x108 0x41c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_LBA__IPU1_DI1_PIN17 0x108 0x41c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_LBA__ECSPI2_SS1 0x108 0x41c 0x820 0x2 0x0 ++#define MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x108 0x41c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_LBA__SRC_BOOT_CFG26 0x108 0x41c 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_EB0__EIM_EB0_B 0x10c 0x420 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_EB0__IPU1_DISP1_DATA11 0x10c 0x420 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_EB0__IPU2_CSI1_DATA11 0x10c 0x420 0x8b4 0x2 0x1 ++#define MX6QDL_PAD_EIM_EB0__CCM_PMIC_READY 0x10c 0x420 0x7f0 0x4 0x0 ++#define MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x10c 0x420 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_EB0__SRC_BOOT_CFG27 0x10c 0x420 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_EB1__EIM_EB1_B 0x110 0x424 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_EB1__IPU1_DISP1_DATA10 0x110 0x424 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_EB1__IPU2_CSI1_DATA10 0x110 0x424 0x8b0 0x2 0x1 ++#define MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x110 0x424 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_EB1__SRC_BOOT_CFG28 0x110 0x424 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA0__EIM_AD00 0x114 0x428 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA0__IPU1_DISP1_DATA09 0x114 0x428 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA0__IPU2_CSI1_DATA09 0x114 0x428 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA0__GPIO3_IO00 0x114 0x428 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA0__SRC_BOOT_CFG00 0x114 0x428 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA1__EIM_AD01 0x118 0x42c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA1__IPU1_DISP1_DATA08 0x118 0x42c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA1__IPU2_CSI1_DATA08 0x118 0x42c 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA1__GPIO3_IO01 0x118 0x42c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA1__SRC_BOOT_CFG01 0x118 0x42c 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA2__EIM_AD02 0x11c 0x430 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA2__IPU1_DISP1_DATA07 0x11c 0x430 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA2__IPU2_CSI1_DATA07 0x11c 0x430 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA2__GPIO3_IO02 0x11c 0x430 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA2__SRC_BOOT_CFG02 0x11c 0x430 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA3__EIM_AD03 0x120 0x434 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA3__IPU1_DISP1_DATA06 0x120 0x434 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA3__IPU2_CSI1_DATA06 0x120 0x434 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA3__GPIO3_IO03 0x120 0x434 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA3__SRC_BOOT_CFG03 0x120 0x434 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA4__EIM_AD04 0x124 0x438 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA4__IPU1_DISP1_DATA05 0x124 0x438 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA4__IPU2_CSI1_DATA05 0x124 0x438 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x124 0x438 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA4__SRC_BOOT_CFG04 0x124 0x438 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA5__EIM_AD05 0x128 0x43c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA5__IPU1_DISP1_DATA04 0x128 0x43c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA5__IPU2_CSI1_DATA04 0x128 0x43c 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x128 0x43c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA5__SRC_BOOT_CFG05 0x128 0x43c 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA6__EIM_AD06 0x12c 0x440 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA6__IPU1_DISP1_DATA03 0x12c 0x440 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA6__IPU2_CSI1_DATA03 0x12c 0x440 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA6__GPIO3_IO06 0x12c 0x440 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA6__SRC_BOOT_CFG06 0x12c 0x440 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA7__EIM_AD07 0x130 0x444 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA7__IPU1_DISP1_DATA02 0x130 0x444 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA7__IPU2_CSI1_DATA02 0x130 0x444 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x130 0x444 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA7__SRC_BOOT_CFG07 0x130 0x444 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA8__EIM_AD08 0x134 0x448 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA8__IPU1_DISP1_DATA01 0x134 0x448 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA8__IPU2_CSI1_DATA01 0x134 0x448 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x134 0x448 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA8__SRC_BOOT_CFG08 0x134 0x448 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA9__EIM_AD09 0x138 0x44c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA9__IPU1_DISP1_DATA00 0x138 0x44c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA9__IPU2_CSI1_DATA00 0x138 0x44c 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x138 0x44c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA9__SRC_BOOT_CFG09 0x138 0x44c 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA10__EIM_AD10 0x13c 0x450 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA10__IPU1_DI1_PIN15 0x13c 0x450 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA10__IPU2_CSI1_DATA_EN 0x13c 0x450 0x8d8 0x2 0x1 ++#define MX6QDL_PAD_EIM_DA10__GPIO3_IO10 0x13c 0x450 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA10__SRC_BOOT_CFG10 0x13c 0x450 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA11__EIM_AD11 0x140 0x454 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA11__IPU1_DI1_PIN02 0x140 0x454 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA11__IPU2_CSI1_HSYNC 0x140 0x454 0x8dc 0x2 0x1 ++#define MX6QDL_PAD_EIM_DA11__GPIO3_IO11 0x140 0x454 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA11__SRC_BOOT_CFG11 0x140 0x454 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA12__EIM_AD12 0x144 0x458 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA12__IPU1_DI1_PIN03 0x144 0x458 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA12__IPU2_CSI1_VSYNC 0x144 0x458 0x8e4 0x2 0x1 ++#define MX6QDL_PAD_EIM_DA12__GPIO3_IO12 0x144 0x458 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA12__SRC_BOOT_CFG12 0x144 0x458 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA13__EIM_AD13 0x148 0x45c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA13__IPU1_DI1_D0_CS 0x148 0x45c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA13__GPIO3_IO13 0x148 0x45c 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA13__SRC_BOOT_CFG13 0x148 0x45c 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA14__EIM_AD14 0x14c 0x460 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA14__IPU1_DI1_D1_CS 0x14c 0x460 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA14__GPIO3_IO14 0x14c 0x460 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA14__SRC_BOOT_CFG14 0x14c 0x460 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_DA15__EIM_AD15 0x150 0x464 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_DA15__IPU1_DI1_PIN01 0x150 0x464 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_DA15__IPU1_DI1_PIN04 0x150 0x464 0x000 0x2 0x0 ++#define MX6QDL_PAD_EIM_DA15__GPIO3_IO15 0x150 0x464 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_DA15__SRC_BOOT_CFG15 0x150 0x464 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_WAIT__EIM_WAIT_B 0x154 0x468 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_WAIT__EIM_DTACK_B 0x154 0x468 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_WAIT__GPIO5_IO00 0x154 0x468 0x000 0x5 0x0 ++#define MX6QDL_PAD_EIM_WAIT__SRC_BOOT_CFG25 0x154 0x468 0x000 0x7 0x0 ++#define MX6QDL_PAD_EIM_BCLK__EIM_BCLK 0x158 0x46c 0x000 0x0 0x0 ++#define MX6QDL_PAD_EIM_BCLK__IPU1_DI1_PIN16 0x158 0x46c 0x000 0x1 0x0 ++#define MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x158 0x46c 0x000 0x5 0x0 ++#define MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x15c 0x470 0x000 0x0 0x0 ++#define MX6QDL_PAD_DI0_DISP_CLK__IPU2_DI0_DISP_CLK 0x15c 0x470 0x000 0x1 0x0 ++#define MX6QDL_PAD_DI0_DISP_CLK__GPIO4_IO16 0x15c 0x470 0x000 0x5 0x0 ++#define MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x160 0x474 0x000 0x0 0x0 ++#define MX6QDL_PAD_DI0_PIN15__IPU2_DI0_PIN15 0x160 0x474 0x000 0x1 0x0 ++#define MX6QDL_PAD_DI0_PIN15__AUD6_TXC 0x160 0x474 0x000 0x2 0x0 ++#define MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x160 0x474 0x000 0x5 0x0 ++#define MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x164 0x478 0x000 0x0 0x0 ++#define MX6QDL_PAD_DI0_PIN2__IPU2_DI0_PIN02 0x164 0x478 0x000 0x1 0x0 ++#define MX6QDL_PAD_DI0_PIN2__AUD6_TXD 0x164 0x478 0x000 0x2 0x0 ++#define MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x164 0x478 0x000 0x5 0x0 ++#define MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x168 0x47c 0x000 0x0 0x0 ++#define MX6QDL_PAD_DI0_PIN3__IPU2_DI0_PIN03 0x168 0x47c 0x000 0x1 0x0 ++#define MX6QDL_PAD_DI0_PIN3__AUD6_TXFS 0x168 0x47c 0x000 0x2 0x0 ++#define MX6QDL_PAD_DI0_PIN3__GPIO4_IO19 0x168 0x47c 0x000 0x5 0x0 ++#define MX6QDL_PAD_DI0_PIN4__IPU1_DI0_PIN04 0x16c 0x480 0x000 0x0 0x0 ++#define MX6QDL_PAD_DI0_PIN4__IPU2_DI0_PIN04 0x16c 0x480 0x000 0x1 0x0 ++#define MX6QDL_PAD_DI0_PIN4__AUD6_RXD 0x16c 0x480 0x000 0x2 0x0 ++#define MX6QDL_PAD_DI0_PIN4__SD1_WP 0x16c 0x480 0x94c 0x3 0x0 ++#define MX6QDL_PAD_DI0_PIN4__GPIO4_IO20 0x16c 0x480 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x170 0x484 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT0__IPU2_DISP0_DATA00 0x170 0x484 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x170 0x484 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT0__GPIO4_IO21 0x170 0x484 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x174 0x488 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT1__IPU2_DISP0_DATA01 0x174 0x488 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x174 0x488 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT1__GPIO4_IO22 0x174 0x488 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x178 0x48c 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT2__IPU2_DISP0_DATA02 0x178 0x48c 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x178 0x48c 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT2__GPIO4_IO23 0x178 0x48c 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x17c 0x490 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT3__IPU2_DISP0_DATA03 0x17c 0x490 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT3__ECSPI3_SS0 0x17c 0x490 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x17c 0x490 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x180 0x494 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT4__IPU2_DISP0_DATA04 0x180 0x494 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT4__ECSPI3_SS1 0x180 0x494 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT4__GPIO4_IO25 0x180 0x494 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x184 0x498 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT5__IPU2_DISP0_DATA05 0x184 0x498 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT5__ECSPI3_SS2 0x184 0x498 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT5__AUD6_RXFS 0x184 0x498 0x000 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT5__GPIO4_IO26 0x184 0x498 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x188 0x49c 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT6__IPU2_DISP0_DATA06 0x188 0x49c 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT6__ECSPI3_SS3 0x188 0x49c 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT6__AUD6_RXC 0x188 0x49c 0x000 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT6__GPIO4_IO27 0x188 0x49c 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x18c 0x4a0 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT7__IPU2_DISP0_DATA07 0x18c 0x4a0 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT7__ECSPI3_RDY 0x18c 0x4a0 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT7__GPIO4_IO28 0x18c 0x4a0 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x190 0x4a4 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT8__IPU2_DISP0_DATA08 0x190 0x4a4 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x190 0x4a4 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT8__WDOG1_B 0x190 0x4a4 0x000 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT8__GPIO4_IO29 0x190 0x4a4 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x194 0x4a8 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT9__IPU2_DISP0_DATA09 0x194 0x4a8 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT9__PWM2_OUT 0x194 0x4a8 0x000 0x2 0x0 ++#define MX6QDL_PAD_DISP0_DAT9__WDOG2_B 0x194 0x4a8 0x000 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT9__GPIO4_IO30 0x194 0x4a8 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x198 0x4ac 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT10__IPU2_DISP0_DATA10 0x198 0x4ac 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT10__GPIO4_IO31 0x198 0x4ac 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x19c 0x4b0 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT11__IPU2_DISP0_DATA11 0x19c 0x4b0 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x19c 0x4b0 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x1a0 0x4b4 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT12__IPU2_DISP0_DATA12 0x1a0 0x4b4 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT12__GPIO5_IO06 0x1a0 0x4b4 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x1a4 0x4b8 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT13__IPU2_DISP0_DATA13 0x1a4 0x4b8 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT13__AUD5_RXFS 0x1a4 0x4b8 0x7d8 0x3 0x1 ++#define MX6QDL_PAD_DISP0_DAT13__GPIO5_IO07 0x1a4 0x4b8 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x1a8 0x4bc 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT14__IPU2_DISP0_DATA14 0x1a8 0x4bc 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT14__AUD5_RXC 0x1a8 0x4bc 0x7d4 0x3 0x1 ++#define MX6QDL_PAD_DISP0_DAT14__GPIO5_IO08 0x1a8 0x4bc 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x1ac 0x4c0 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT15__IPU2_DISP0_DATA15 0x1ac 0x4c0 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT15__ECSPI1_SS1 0x1ac 0x4c0 0x804 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT15__ECSPI2_SS1 0x1ac 0x4c0 0x820 0x3 0x1 ++#define MX6QDL_PAD_DISP0_DAT15__GPIO5_IO09 0x1ac 0x4c0 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x1b0 0x4c4 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT16__IPU2_DISP0_DATA16 0x1b0 0x4c4 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT16__ECSPI2_MOSI 0x1b0 0x4c4 0x818 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT16__AUD5_TXC 0x1b0 0x4c4 0x7dc 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT16__SDMA_EXT_EVENT0 0x1b0 0x4c4 0x90c 0x4 0x0 ++#define MX6QDL_PAD_DISP0_DAT16__GPIO5_IO10 0x1b0 0x4c4 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x1b4 0x4c8 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT17__IPU2_DISP0_DATA17 0x1b4 0x4c8 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT17__ECSPI2_MISO 0x1b4 0x4c8 0x814 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT17__AUD5_TXD 0x1b4 0x4c8 0x7d0 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT17__SDMA_EXT_EVENT1 0x1b4 0x4c8 0x910 0x4 0x0 ++#define MX6QDL_PAD_DISP0_DAT17__GPIO5_IO11 0x1b4 0x4c8 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x1b8 0x4cc 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__IPU2_DISP0_DATA18 0x1b8 0x4cc 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__ECSPI2_SS0 0x1b8 0x4cc 0x81c 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS 0x1b8 0x4cc 0x7e0 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__AUD4_RXFS 0x1b8 0x4cc 0x7c0 0x4 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__GPIO5_IO12 0x1b8 0x4cc 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT18__EIM_CS2_B 0x1b8 0x4cc 0x000 0x7 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x1bc 0x4d0 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__IPU2_DISP0_DATA19 0x1bc 0x4d0 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__ECSPI2_SCLK 0x1bc 0x4d0 0x810 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x1bc 0x4d0 0x7cc 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__AUD4_RXC 0x1bc 0x4d0 0x7bc 0x4 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__GPIO5_IO13 0x1bc 0x4d0 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT19__EIM_CS3_B 0x1bc 0x4d0 0x000 0x7 0x0 ++#define MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x1c0 0x4d4 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT20__IPU2_DISP0_DATA20 0x1c0 0x4d4 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT20__ECSPI1_SCLK 0x1c0 0x4d4 0x7f4 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT20__AUD4_TXC 0x1c0 0x4d4 0x7c4 0x3 0x0 ++#define MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14 0x1c0 0x4d4 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x1c4 0x4d8 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT21__IPU2_DISP0_DATA21 0x1c4 0x4d8 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT21__ECSPI1_MOSI 0x1c4 0x4d8 0x7fc 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT21__AUD4_TXD 0x1c4 0x4d8 0x7b8 0x3 0x1 ++#define MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15 0x1c4 0x4d8 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x1c8 0x4dc 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT22__IPU2_DISP0_DATA22 0x1c8 0x4dc 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT22__ECSPI1_MISO 0x1c8 0x4dc 0x7f8 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT22__AUD4_TXFS 0x1c8 0x4dc 0x7c8 0x3 0x1 ++#define MX6QDL_PAD_DISP0_DAT22__GPIO5_IO16 0x1c8 0x4dc 0x000 0x5 0x0 ++#define MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x1cc 0x4e0 0x000 0x0 0x0 ++#define MX6QDL_PAD_DISP0_DAT23__IPU2_DISP0_DATA23 0x1cc 0x4e0 0x000 0x1 0x0 ++#define MX6QDL_PAD_DISP0_DAT23__ECSPI1_SS0 0x1cc 0x4e0 0x800 0x2 0x1 ++#define MX6QDL_PAD_DISP0_DAT23__AUD4_RXD 0x1cc 0x4e0 0x7b4 0x3 0x1 ++#define MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x1cc 0x4e0 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1d0 0x4e4 0x840 0x1 0x0 ++#define MX6QDL_PAD_ENET_MDIO__ESAI_RX_CLK 0x1d0 0x4e4 0x86c 0x2 0x0 ++#define MX6QDL_PAD_ENET_MDIO__ENET_1588_EVENT1_OUT 0x1d0 0x4e4 0x000 0x4 0x0 ++#define MX6QDL_PAD_ENET_MDIO__GPIO1_IO22 0x1d0 0x4e4 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_MDIO__SPDIF_LOCK 0x1d0 0x4e4 0x000 0x6 0x0 ++#define MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1d4 0x4e8 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_REF_CLK__ESAI_RX_FS 0x1d4 0x4e8 0x85c 0x2 0x0 ++#define MX6QDL_PAD_ENET_REF_CLK__GPIO1_IO23 0x1d4 0x4e8 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_REF_CLK__SPDIF_SR_CLK 0x1d4 0x4e8 0x000 0x6 0x0 ++#define MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x1d8 0x4ec 0x004 0x0 0xff0d0100 ++#define MX6QDL_PAD_ENET_RX_ER__ENET_RX_ER 0x1d8 0x4ec 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_RX_ER__ESAI_RX_HF_CLK 0x1d8 0x4ec 0x864 0x2 0x0 ++#define MX6QDL_PAD_ENET_RX_ER__SPDIF_IN 0x1d8 0x4ec 0x914 0x3 0x1 ++#define MX6QDL_PAD_ENET_RX_ER__ENET_1588_EVENT2_OUT 0x1d8 0x4ec 0x000 0x4 0x0 ++#define MX6QDL_PAD_ENET_RX_ER__GPIO1_IO24 0x1d8 0x4ec 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_CRS_DV__ENET_RX_EN 0x1dc 0x4f0 0x858 0x1 0x1 ++#define MX6QDL_PAD_ENET_CRS_DV__ESAI_TX_CLK 0x1dc 0x4f0 0x870 0x2 0x0 ++#define MX6QDL_PAD_ENET_CRS_DV__SPDIF_EXT_CLK 0x1dc 0x4f0 0x918 0x3 0x1 ++#define MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1dc 0x4f0 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_RXD1__MLB_SIG 0x1e0 0x4f4 0x908 0x0 0x0 ++#define MX6QDL_PAD_ENET_RXD1__ENET_RX_DATA1 0x1e0 0x4f4 0x84c 0x1 0x1 ++#define MX6QDL_PAD_ENET_RXD1__ESAI_TX_FS 0x1e0 0x4f4 0x860 0x2 0x0 ++#define MX6QDL_PAD_ENET_RXD1__ENET_1588_EVENT3_OUT 0x1e0 0x4f4 0x000 0x4 0x0 ++#define MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x1e0 0x4f4 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_RXD0__ENET_RX_DATA0 0x1e4 0x4f8 0x848 0x1 0x1 ++#define MX6QDL_PAD_ENET_RXD0__ESAI_TX_HF_CLK 0x1e4 0x4f8 0x868 0x2 0x0 ++#define MX6QDL_PAD_ENET_RXD0__SPDIF_OUT 0x1e4 0x4f8 0x000 0x3 0x0 ++#define MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x1e4 0x4f8 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1e8 0x4fc 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_TX_EN__ESAI_TX3_RX2 0x1e8 0x4fc 0x880 0x2 0x0 ++#define MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1e8 0x4fc 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_TXD1__MLB_CLK 0x1ec 0x500 0x900 0x0 0x0 ++#define MX6QDL_PAD_ENET_TXD1__ENET_TX_DATA1 0x1ec 0x500 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_TXD1__ESAI_TX2_RX3 0x1ec 0x500 0x87c 0x2 0x0 ++#define MX6QDL_PAD_ENET_TXD1__ENET_1588_EVENT0_IN 0x1ec 0x500 0x000 0x4 0x0 ++#define MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x1ec 0x500 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_TXD0__ENET_TX_DATA0 0x1f0 0x504 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_TXD0__ESAI_TX4_RX1 0x1f0 0x504 0x884 0x2 0x0 ++#define MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x1f0 0x504 0x000 0x5 0x0 ++#define MX6QDL_PAD_ENET_MDC__MLB_DATA 0x1f4 0x508 0x904 0x0 0x0 ++#define MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1f4 0x508 0x000 0x1 0x0 ++#define MX6QDL_PAD_ENET_MDC__ESAI_TX5_RX0 0x1f4 0x508 0x888 0x2 0x0 ++#define MX6QDL_PAD_ENET_MDC__ENET_1588_EVENT1_IN 0x1f4 0x508 0x000 0x4 0x0 ++#define MX6QDL_PAD_ENET_MDC__GPIO1_IO31 0x1f4 0x508 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x1f8 0x5c8 0x7f4 0x0 0x2 ++#define MX6QDL_PAD_KEY_COL0__ENET_RX_DATA3 0x1f8 0x5c8 0x854 0x1 0x1 ++#define MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x1f8 0x5c8 0x7dc 0x2 0x1 ++#define MX6QDL_PAD_KEY_COL0__KEY_COL0 0x1f8 0x5c8 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1f8 0x5c8 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_COL0__UART4_RX_DATA 0x1f8 0x5c8 0x938 0x4 0x0 ++#define MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x1f8 0x5c8 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_COL0__DCIC1_OUT 0x1f8 0x5c8 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x1fc 0x5cc 0x7fc 0x0 0x2 ++#define MX6QDL_PAD_KEY_ROW0__ENET_TX_DATA3 0x1fc 0x5cc 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x1fc 0x5cc 0x7d0 0x2 0x1 ++#define MX6QDL_PAD_KEY_ROW0__KEY_ROW0 0x1fc 0x5cc 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1fc 0x5cc 0x938 0x4 0x1 ++#define MX6QDL_PAD_KEY_ROW0__UART4_TX_DATA 0x1fc 0x5cc 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x1fc 0x5cc 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_ROW0__DCIC2_OUT 0x1fc 0x5cc 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x200 0x5d0 0x7f8 0x0 0x2 ++#define MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x200 0x5d0 0x840 0x1 0x1 ++#define MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x200 0x5d0 0x7e0 0x2 0x1 ++#define MX6QDL_PAD_KEY_COL1__KEY_COL1 0x200 0x5d0 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x200 0x5d0 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_COL1__UART5_RX_DATA 0x200 0x5d0 0x940 0x4 0x0 ++#define MX6QDL_PAD_KEY_COL1__GPIO4_IO08 0x200 0x5d0 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_COL1__SD1_VSELECT 0x200 0x5d0 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_ROW1__ECSPI1_SS0 0x204 0x5d4 0x800 0x0 0x2 ++#define MX6QDL_PAD_KEY_ROW1__ENET_COL 0x204 0x5d4 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_ROW1__AUD5_RXD 0x204 0x5d4 0x7cc 0x2 0x1 ++#define MX6QDL_PAD_KEY_ROW1__KEY_ROW1 0x204 0x5d4 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x204 0x5d4 0x940 0x4 0x1 ++#define MX6QDL_PAD_KEY_ROW1__UART5_TX_DATA 0x204 0x5d4 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x204 0x5d4 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x204 0x5d4 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_COL2__ECSPI1_SS1 0x208 0x5d8 0x804 0x0 0x2 ++#define MX6QDL_PAD_KEY_COL2__ENET_RX_DATA2 0x208 0x5d8 0x850 0x1 0x1 ++#define MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x208 0x5d8 0x000 0x2 0x0 ++#define MX6QDL_PAD_KEY_COL2__KEY_COL2 0x208 0x5d8 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_COL2__ENET_MDC 0x208 0x5d8 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x208 0x5d8 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_COL2__USB_H1_PWR_CTL_WAKE 0x208 0x5d8 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_ROW2__ECSPI1_SS2 0x20c 0x5dc 0x808 0x0 0x1 ++#define MX6QDL_PAD_KEY_ROW2__ENET_TX_DATA2 0x20c 0x5dc 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x20c 0x5dc 0x7e4 0x2 0x0 ++#define MX6QDL_PAD_KEY_ROW2__KEY_ROW2 0x20c 0x5dc 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_ROW2__SD2_VSELECT 0x20c 0x5dc 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_ROW2__GPIO4_IO11 0x20c 0x5dc 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x20c 0x5dc 0x88c 0x6 0x1 ++#define MX6QDL_PAD_KEY_COL3__ECSPI1_SS3 0x210 0x5e0 0x80c 0x0 0x1 ++#define MX6QDL_PAD_KEY_COL3__ENET_CRS 0x210 0x5e0 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_COL3__HDMI_TX_DDC_SCL 0x210 0x5e0 0x890 0x2 0x1 ++#define MX6QDL_PAD_KEY_COL3__KEY_COL3 0x210 0x5e0 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x210 0x5e0 0x8a0 0x4 0x1 ++#define MX6QDL_PAD_KEY_COL3__GPIO4_IO12 0x210 0x5e0 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x210 0x5e0 0x914 0x6 0x2 ++#define MX6QDL_PAD_KEY_ROW3__ASRC_EXT_CLK 0x214 0x5e4 0x7b0 0x1 0x0 ++#define MX6QDL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 0x214 0x5e4 0x894 0x2 0x1 ++#define MX6QDL_PAD_KEY_ROW3__KEY_ROW3 0x214 0x5e4 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x214 0x5e4 0x8a4 0x4 0x1 ++#define MX6QDL_PAD_KEY_ROW3__GPIO4_IO13 0x214 0x5e4 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_ROW3__SD1_VSELECT 0x214 0x5e4 0x000 0x6 0x0 ++#define MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x218 0x5e8 0x000 0x0 0x0 ++#define MX6QDL_PAD_KEY_COL4__IPU1_SISG4 0x218 0x5e8 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x218 0x5e8 0x944 0x2 0x1 ++#define MX6QDL_PAD_KEY_COL4__KEY_COL4 0x218 0x5e8 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_COL4__UART5_RTS_B 0x218 0x5e8 0x93c 0x4 0x0 ++#define MX6QDL_PAD_KEY_COL4__UART5_CTS_B 0x218 0x5e8 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x218 0x5e8 0x000 0x5 0x0 ++#define MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x21c 0x5ec 0x7e8 0x0 0x0 ++#define MX6QDL_PAD_KEY_ROW4__IPU1_SISG5 0x21c 0x5ec 0x000 0x1 0x0 ++#define MX6QDL_PAD_KEY_ROW4__USB_OTG_PWR 0x21c 0x5ec 0x000 0x2 0x0 ++#define MX6QDL_PAD_KEY_ROW4__KEY_ROW4 0x21c 0x5ec 0x000 0x3 0x0 ++#define MX6QDL_PAD_KEY_ROW4__UART5_CTS_B 0x21c 0x5ec 0x000 0x4 0x0 ++#define MX6QDL_PAD_KEY_ROW4__UART5_RTS_B 0x21c 0x5ec 0x93c 0x4 0x1 ++#define MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x21c 0x5ec 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x220 0x5f0 0x000 0x0 0x0 ++#define MX6QDL_PAD_GPIO_0__KEY_COL5 0x220 0x5f0 0x8e8 0x2 0x0 ++#define MX6QDL_PAD_GPIO_0__ASRC_EXT_CLK 0x220 0x5f0 0x7b0 0x3 0x1 ++#define MX6QDL_PAD_GPIO_0__EPIT1_OUT 0x220 0x5f0 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x220 0x5f0 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_0__USB_H1_PWR 0x220 0x5f0 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_0__SNVS_VIO_5 0x220 0x5f0 0x000 0x7 0x0 ++#define MX6QDL_PAD_GPIO_1__ESAI_RX_CLK 0x224 0x5f4 0x86c 0x0 0x1 ++#define MX6QDL_PAD_GPIO_1__WDOG2_B 0x224 0x5f4 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_1__KEY_ROW5 0x224 0x5f4 0x8f4 0x2 0x0 ++#define MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x224 0x5f4 0x004 0x3 0xff0d0101 ++#define MX6QDL_PAD_GPIO_1__PWM2_OUT 0x224 0x5f4 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_1__GPIO1_IO01 0x224 0x5f4 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_1__SD1_CD_B 0x224 0x5f4 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_9__ESAI_RX_FS 0x228 0x5f8 0x85c 0x0 0x1 ++#define MX6QDL_PAD_GPIO_9__WDOG1_B 0x228 0x5f8 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_9__KEY_COL6 0x228 0x5f8 0x8ec 0x2 0x0 ++#define MX6QDL_PAD_GPIO_9__CCM_REF_EN_B 0x228 0x5f8 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_9__PWM1_OUT 0x228 0x5f8 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x228 0x5f8 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_9__SD1_WP 0x228 0x5f8 0x94c 0x6 0x1 ++#define MX6QDL_PAD_GPIO_3__ESAI_RX_HF_CLK 0x22c 0x5fc 0x864 0x0 0x1 ++#define MX6QDL_PAD_GPIO_3__I2C3_SCL 0x22c 0x5fc 0x8a8 0x2 0x1 ++#define MX6QDL_PAD_GPIO_3__XTALOSC_REF_CLK_24M 0x22c 0x5fc 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_3__CCM_CLKO2 0x22c 0x5fc 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x22c 0x5fc 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_3__USB_H1_OC 0x22c 0x5fc 0x948 0x6 0x1 ++#define MX6QDL_PAD_GPIO_3__MLB_CLK 0x22c 0x5fc 0x900 0x7 0x1 ++#define MX6QDL_PAD_GPIO_6__ESAI_TX_CLK 0x230 0x600 0x870 0x0 0x1 ++#define MX6QDL_PAD_GPIO_6__I2C3_SDA 0x230 0x600 0x8ac 0x2 0x1 ++#define MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x230 0x600 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_6__SD2_LCTL 0x230 0x600 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_6__MLB_SIG 0x230 0x600 0x908 0x7 0x1 ++#define MX6QDL_PAD_GPIO_2__ESAI_TX_FS 0x234 0x604 0x860 0x0 0x1 ++#define MX6QDL_PAD_GPIO_2__KEY_ROW6 0x234 0x604 0x8f8 0x2 0x1 ++#define MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x234 0x604 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_2__SD2_WP 0x234 0x604 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_2__MLB_DATA 0x234 0x604 0x904 0x7 0x1 ++#define MX6QDL_PAD_GPIO_4__ESAI_TX_HF_CLK 0x238 0x608 0x868 0x0 0x1 ++#define MX6QDL_PAD_GPIO_4__KEY_COL7 0x238 0x608 0x8f0 0x2 0x1 ++#define MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x238 0x608 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_4__SD2_CD_B 0x238 0x608 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_5__ESAI_TX2_RX3 0x23c 0x60c 0x87c 0x0 0x1 ++#define MX6QDL_PAD_GPIO_5__KEY_ROW7 0x23c 0x60c 0x8fc 0x2 0x1 ++#define MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x23c 0x60c 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x23c 0x60c 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_5__I2C3_SCL 0x23c 0x60c 0x8a8 0x6 0x2 ++#define MX6QDL_PAD_GPIO_5__ARM_EVENTI 0x23c 0x60c 0x000 0x7 0x0 ++#define MX6QDL_PAD_GPIO_7__ESAI_TX4_RX1 0x240 0x610 0x884 0x0 0x1 ++#define MX6QDL_PAD_GPIO_7__ECSPI5_RDY 0x240 0x610 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_7__EPIT1_OUT 0x240 0x610 0x000 0x2 0x0 ++#define MX6QDL_PAD_GPIO_7__FLEXCAN1_TX 0x240 0x610 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_7__UART2_TX_DATA 0x240 0x610 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_7__UART2_RX_DATA 0x240 0x610 0x928 0x4 0x2 ++#define MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x240 0x610 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_7__SPDIF_LOCK 0x240 0x610 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_7__USB_OTG_HOST_MODE 0x240 0x610 0x000 0x7 0x0 ++#define MX6QDL_PAD_GPIO_8__ESAI_TX5_RX0 0x244 0x614 0x888 0x0 0x1 ++#define MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x244 0x614 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_8__EPIT2_OUT 0x244 0x614 0x000 0x2 0x0 ++#define MX6QDL_PAD_GPIO_8__FLEXCAN1_RX 0x244 0x614 0x7e4 0x3 0x1 ++#define MX6QDL_PAD_GPIO_8__UART2_RX_DATA 0x244 0x614 0x928 0x4 0x3 ++#define MX6QDL_PAD_GPIO_8__UART2_TX_DATA 0x244 0x614 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x244 0x614 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_8__SPDIF_SR_CLK 0x244 0x614 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_8__USB_OTG_PWR_CTL_WAKE 0x244 0x614 0x000 0x7 0x0 ++#define MX6QDL_PAD_GPIO_16__ESAI_TX3_RX2 0x248 0x618 0x880 0x0 0x1 ++#define MX6QDL_PAD_GPIO_16__ENET_1588_EVENT2_IN 0x248 0x618 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x248 0x618 0x83c 0x2 0x1 ++#define MX6QDL_PAD_GPIO_16__SD1_LCTL 0x248 0x618 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_16__SPDIF_IN 0x248 0x618 0x914 0x4 0x3 ++#define MX6QDL_PAD_GPIO_16__GPIO7_IO11 0x248 0x618 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_16__I2C3_SDA 0x248 0x618 0x8ac 0x6 0x2 ++#define MX6QDL_PAD_GPIO_16__JTAG_DE_B 0x248 0x618 0x000 0x7 0x0 ++#define MX6QDL_PAD_GPIO_17__ESAI_TX0 0x24c 0x61c 0x874 0x0 0x0 ++#define MX6QDL_PAD_GPIO_17__ENET_1588_EVENT3_IN 0x24c 0x61c 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_17__CCM_PMIC_READY 0x24c 0x61c 0x7f0 0x2 0x1 ++#define MX6QDL_PAD_GPIO_17__SDMA_EXT_EVENT0 0x24c 0x61c 0x90c 0x3 0x1 ++#define MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x24c 0x61c 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x24c 0x61c 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_18__ESAI_TX1 0x250 0x620 0x878 0x0 0x0 ++#define MX6QDL_PAD_GPIO_18__ENET_RX_CLK 0x250 0x620 0x844 0x1 0x1 ++#define MX6QDL_PAD_GPIO_18__SD3_VSELECT 0x250 0x620 0x000 0x2 0x0 ++#define MX6QDL_PAD_GPIO_18__SDMA_EXT_EVENT1 0x250 0x620 0x910 0x3 0x1 ++#define MX6QDL_PAD_GPIO_18__ASRC_EXT_CLK 0x250 0x620 0x7b0 0x4 0x2 ++#define MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x250 0x620 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_18__SNVS_VIO_5_CTL 0x250 0x620 0x000 0x6 0x0 ++#define MX6QDL_PAD_GPIO_19__KEY_COL5 0x254 0x624 0x8e8 0x0 0x1 ++#define MX6QDL_PAD_GPIO_19__ENET_1588_EVENT0_OUT 0x254 0x624 0x000 0x1 0x0 ++#define MX6QDL_PAD_GPIO_19__SPDIF_OUT 0x254 0x624 0x000 0x2 0x0 ++#define MX6QDL_PAD_GPIO_19__CCM_CLKO1 0x254 0x624 0x000 0x3 0x0 ++#define MX6QDL_PAD_GPIO_19__ECSPI1_RDY 0x254 0x624 0x000 0x4 0x0 ++#define MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x254 0x624 0x000 0x5 0x0 ++#define MX6QDL_PAD_GPIO_19__ENET_TX_ER 0x254 0x624 0x000 0x6 0x0 ++#define MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x258 0x628 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_PIXCLK__GPIO5_IO18 0x258 0x628 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_PIXCLK__ARM_EVENTO 0x258 0x628 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x25c 0x62c 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_MCLK__CCM_CLKO1 0x25c 0x62c 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_MCLK__GPIO5_IO19 0x25c 0x62c 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_MCLK__ARM_TRACE_CTL 0x25c 0x62c 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN 0x260 0x630 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DATA_EN__EIM_DATA00 0x260 0x630 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x260 0x630 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DATA_EN__ARM_TRACE_CLK 0x260 0x630 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x264 0x634 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_VSYNC__EIM_DATA01 0x264 0x634 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_VSYNC__GPIO5_IO21 0x264 0x634 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_VSYNC__ARM_TRACE00 0x264 0x634 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__IPU1_CSI0_DATA04 0x268 0x638 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__EIM_DATA02 0x268 0x638 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__ECSPI1_SCLK 0x268 0x638 0x7f4 0x2 0x3 ++#define MX6QDL_PAD_CSI0_DAT4__KEY_COL5 0x268 0x638 0x8e8 0x3 0x2 ++#define MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x268 0x638 0x000 0x4 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__GPIO5_IO22 0x268 0x638 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT4__ARM_TRACE01 0x268 0x638 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__IPU1_CSI0_DATA05 0x26c 0x63c 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__EIM_DATA03 0x26c 0x63c 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__ECSPI1_MOSI 0x26c 0x63c 0x7fc 0x2 0x3 ++#define MX6QDL_PAD_CSI0_DAT5__KEY_ROW5 0x26c 0x63c 0x8f4 0x3 0x1 ++#define MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x26c 0x63c 0x000 0x4 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__GPIO5_IO23 0x26c 0x63c 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT5__ARM_TRACE02 0x26c 0x63c 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__IPU1_CSI0_DATA06 0x270 0x640 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__EIM_DATA04 0x270 0x640 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__ECSPI1_MISO 0x270 0x640 0x7f8 0x2 0x3 ++#define MX6QDL_PAD_CSI0_DAT6__KEY_COL6 0x270 0x640 0x8ec 0x3 0x1 ++#define MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x270 0x640 0x000 0x4 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__GPIO5_IO24 0x270 0x640 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT6__ARM_TRACE03 0x270 0x640 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__IPU1_CSI0_DATA07 0x274 0x644 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__EIM_DATA05 0x274 0x644 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__ECSPI1_SS0 0x274 0x644 0x800 0x2 0x3 ++#define MX6QDL_PAD_CSI0_DAT7__KEY_ROW6 0x274 0x644 0x8f8 0x3 0x2 ++#define MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x274 0x644 0x000 0x4 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__GPIO5_IO25 0x274 0x644 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT7__ARM_TRACE04 0x274 0x644 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT8__IPU1_CSI0_DATA08 0x278 0x648 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT8__EIM_DATA06 0x278 0x648 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT8__ECSPI2_SCLK 0x278 0x648 0x810 0x2 0x2 ++#define MX6QDL_PAD_CSI0_DAT8__KEY_COL7 0x278 0x648 0x8f0 0x3 0x2 ++#define MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x278 0x648 0x89c 0x4 0x1 ++#define MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x278 0x648 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT8__ARM_TRACE05 0x278 0x648 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT9__IPU1_CSI0_DATA09 0x27c 0x64c 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT9__EIM_DATA07 0x27c 0x64c 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT9__ECSPI2_MOSI 0x27c 0x64c 0x818 0x2 0x2 ++#define MX6QDL_PAD_CSI0_DAT9__KEY_ROW7 0x27c 0x64c 0x8fc 0x3 0x2 ++#define MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x27c 0x64c 0x898 0x4 0x1 ++#define MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x27c 0x64c 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT9__ARM_TRACE06 0x27c 0x64c 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__IPU1_CSI0_DATA10 0x280 0x650 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__AUD3_RXC 0x280 0x650 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__ECSPI2_MISO 0x280 0x650 0x814 0x2 0x2 ++#define MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x280 0x650 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__UART1_RX_DATA 0x280 0x650 0x920 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__GPIO5_IO28 0x280 0x650 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT10__ARM_TRACE07 0x280 0x650 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT11__IPU1_CSI0_DATA11 0x284 0x654 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT11__AUD3_RXFS 0x284 0x654 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT11__ECSPI2_SS0 0x284 0x654 0x81c 0x2 0x2 ++#define MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x284 0x654 0x920 0x3 0x1 ++#define MX6QDL_PAD_CSI0_DAT11__UART1_TX_DATA 0x284 0x654 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT11__GPIO5_IO29 0x284 0x654 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT11__ARM_TRACE08 0x284 0x654 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x288 0x658 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT12__EIM_DATA08 0x288 0x658 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x288 0x658 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT12__UART4_RX_DATA 0x288 0x658 0x938 0x3 0x2 ++#define MX6QDL_PAD_CSI0_DAT12__GPIO5_IO30 0x288 0x658 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT12__ARM_TRACE09 0x288 0x658 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x28c 0x65c 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT13__EIM_DATA09 0x28c 0x65c 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x28c 0x65c 0x938 0x3 0x3 ++#define MX6QDL_PAD_CSI0_DAT13__UART4_TX_DATA 0x28c 0x65c 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31 0x28c 0x65c 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT13__ARM_TRACE10 0x28c 0x65c 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x290 0x660 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT14__EIM_DATA10 0x290 0x660 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT14__UART5_TX_DATA 0x290 0x660 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT14__UART5_RX_DATA 0x290 0x660 0x940 0x3 0x2 ++#define MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x290 0x660 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT14__ARM_TRACE11 0x290 0x660 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x294 0x664 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT15__EIM_DATA11 0x294 0x664 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT15__UART5_RX_DATA 0x294 0x664 0x940 0x3 0x3 ++#define MX6QDL_PAD_CSI0_DAT15__UART5_TX_DATA 0x294 0x664 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 0x294 0x664 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT15__ARM_TRACE12 0x294 0x664 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x298 0x668 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__EIM_DATA12 0x298 0x668 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x298 0x668 0x934 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__UART4_CTS_B 0x298 0x668 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__GPIO6_IO02 0x298 0x668 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT16__ARM_TRACE13 0x298 0x668 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x29c 0x66c 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT17__EIM_DATA13 0x29c 0x66c 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x29c 0x66c 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT17__UART4_RTS_B 0x29c 0x66c 0x934 0x3 0x1 ++#define MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 0x29c 0x66c 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT17__ARM_TRACE14 0x29c 0x66c 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x2a0 0x670 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT18__EIM_DATA14 0x2a0 0x670 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT18__UART5_RTS_B 0x2a0 0x670 0x93c 0x3 0x2 ++#define MX6QDL_PAD_CSI0_DAT18__UART5_CTS_B 0x2a0 0x670 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x2a0 0x670 0x000 0x5 0x0 ++#define MX6QDL_PAD_CSI0_DAT18__ARM_TRACE15 0x2a0 0x670 0x000 0x7 0x0 ++#define MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x2a4 0x674 0x000 0x0 0x0 ++#define MX6QDL_PAD_CSI0_DAT19__EIM_DATA15 0x2a4 0x674 0x000 0x1 0x0 ++#define MX6QDL_PAD_CSI0_DAT19__UART5_CTS_B 0x2a4 0x674 0x000 0x3 0x0 ++#define MX6QDL_PAD_CSI0_DAT19__UART5_RTS_B 0x2a4 0x674 0x93c 0x3 0x3 ++#define MX6QDL_PAD_CSI0_DAT19__GPIO6_IO05 0x2a4 0x674 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x2a8 0x690 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x2a8 0x690 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT7__UART1_RX_DATA 0x2a8 0x690 0x920 0x1 0x2 ++#define MX6QDL_PAD_SD3_DAT7__GPIO6_IO17 0x2a8 0x690 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x2ac 0x694 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x2ac 0x694 0x920 0x1 0x3 ++#define MX6QDL_PAD_SD3_DAT6__UART1_TX_DATA 0x2ac 0x694 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT6__GPIO6_IO18 0x2ac 0x694 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x2b0 0x698 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT5__UART2_TX_DATA 0x2b0 0x698 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT5__UART2_RX_DATA 0x2b0 0x698 0x928 0x1 0x4 ++#define MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x2b0 0x698 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x2b4 0x69c 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT4__UART2_RX_DATA 0x2b4 0x69c 0x928 0x1 0x5 ++#define MX6QDL_PAD_SD3_DAT4__UART2_TX_DATA 0x2b4 0x69c 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x2b4 0x69c 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_CMD__SD3_CMD 0x2b8 0x6a0 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_CMD__UART2_CTS_B 0x2b8 0x6a0 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_CMD__UART2_RTS_B 0x2b8 0x6a0 0x924 0x1 0x2 ++#define MX6QDL_PAD_SD3_CMD__FLEXCAN1_TX 0x2b8 0x6a0 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD3_CMD__GPIO7_IO02 0x2b8 0x6a0 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_CLK__SD3_CLK 0x2bc 0x6a4 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_CLK__UART2_RTS_B 0x2bc 0x6a4 0x924 0x1 0x3 ++#define MX6QDL_PAD_SD3_CLK__UART2_CTS_B 0x2bc 0x6a4 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_CLK__FLEXCAN1_RX 0x2bc 0x6a4 0x7e4 0x2 0x2 ++#define MX6QDL_PAD_SD3_CLK__GPIO7_IO03 0x2bc 0x6a4 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x2c0 0x6a8 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT0__UART1_CTS_B 0x2c0 0x6a8 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT0__UART1_RTS_B 0x2c0 0x6a8 0x91c 0x1 0x2 ++#define MX6QDL_PAD_SD3_DAT0__FLEXCAN2_TX 0x2c0 0x6a8 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD3_DAT0__GPIO7_IO04 0x2c0 0x6a8 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x2c4 0x6ac 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT1__UART1_RTS_B 0x2c4 0x6ac 0x91c 0x1 0x3 ++#define MX6QDL_PAD_SD3_DAT1__UART1_CTS_B 0x2c4 0x6ac 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT1__FLEXCAN2_RX 0x2c4 0x6ac 0x7e8 0x2 0x1 ++#define MX6QDL_PAD_SD3_DAT1__GPIO7_IO05 0x2c4 0x6ac 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x2c8 0x6b0 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT2__GPIO7_IO06 0x2c8 0x6b0 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x2cc 0x6b4 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_DAT3__UART3_CTS_B 0x2cc 0x6b4 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_DAT3__UART3_RTS_B 0x2cc 0x6b4 0x92c 0x1 0x4 ++#define MX6QDL_PAD_SD3_DAT3__GPIO7_IO07 0x2cc 0x6b4 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD3_RST__SD3_RESET 0x2d0 0x6b8 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD3_RST__UART3_RTS_B 0x2d0 0x6b8 0x92c 0x1 0x5 ++#define MX6QDL_PAD_SD3_RST__UART3_CTS_B 0x2d0 0x6b8 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x2d0 0x6b8 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CLE__NAND_CLE 0x2d4 0x6bc 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_CLE__IPU2_SISG4 0x2d4 0x6bc 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x2d4 0x6bc 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_ALE__NAND_ALE 0x2d8 0x6c0 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_ALE__SD4_RESET 0x2d8 0x6c0 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x2d8 0x6c0 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0x2dc 0x6c4 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_WP_B__IPU2_SISG5 0x2dc 0x6c4 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x2dc 0x6c4 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0x2e0 0x6c8 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_RB0__IPU2_DI0_PIN01 0x2e0 0x6c8 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_RB0__GPIO6_IO10 0x2e0 0x6c8 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0x2e4 0x6cc 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x2e4 0x6cc 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0x2e8 0x6d0 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_CS1__SD4_VSELECT 0x2e8 0x6d0 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_CS1__SD3_VSELECT 0x2e8 0x6d0 0x000 0x2 0x0 ++#define MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x2e8 0x6d0 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CS2__NAND_CE2_B 0x2ec 0x6d4 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_CS2__IPU1_SISG0 0x2ec 0x6d4 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_CS2__ESAI_TX0 0x2ec 0x6d4 0x874 0x2 0x1 ++#define MX6QDL_PAD_NANDF_CS2__EIM_CRE 0x2ec 0x6d4 0x000 0x3 0x0 ++#define MX6QDL_PAD_NANDF_CS2__CCM_CLKO2 0x2ec 0x6d4 0x000 0x4 0x0 ++#define MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x2ec 0x6d4 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CS2__IPU2_SISG0 0x2ec 0x6d4 0x000 0x6 0x0 ++#define MX6QDL_PAD_NANDF_CS3__NAND_CE3_B 0x2f0 0x6d8 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_CS3__IPU1_SISG1 0x2f0 0x6d8 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_CS3__ESAI_TX1 0x2f0 0x6d8 0x878 0x2 0x1 ++#define MX6QDL_PAD_NANDF_CS3__EIM_ADDR26 0x2f0 0x6d8 0x000 0x3 0x0 ++#define MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x2f0 0x6d8 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_CS3__IPU2_SISG1 0x2f0 0x6d8 0x000 0x6 0x0 ++#define MX6QDL_PAD_SD4_CMD__SD4_CMD 0x2f4 0x6dc 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD4_CMD__NAND_RE_B 0x2f4 0x6dc 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_CMD__UART3_TX_DATA 0x2f4 0x6dc 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_CMD__UART3_RX_DATA 0x2f4 0x6dc 0x930 0x2 0x2 ++#define MX6QDL_PAD_SD4_CMD__GPIO7_IO09 0x2f4 0x6dc 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_CLK__SD4_CLK 0x2f8 0x6e0 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD4_CLK__NAND_WE_B 0x2f8 0x6e0 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_CLK__UART3_RX_DATA 0x2f8 0x6e0 0x930 0x2 0x3 ++#define MX6QDL_PAD_SD4_CLK__UART3_TX_DATA 0x2f8 0x6e0 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_CLK__GPIO7_IO10 0x2f8 0x6e0 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D0__NAND_DATA00 0x2fc 0x6e4 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D0__SD1_DATA4 0x2fc 0x6e4 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x2fc 0x6e4 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D1__NAND_DATA01 0x300 0x6e8 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D1__SD1_DATA5 0x300 0x6e8 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x300 0x6e8 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D2__NAND_DATA02 0x304 0x6ec 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D2__SD1_DATA6 0x304 0x6ec 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x304 0x6ec 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D3__NAND_DATA03 0x308 0x6f0 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D3__SD1_DATA7 0x308 0x6f0 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x308 0x6f0 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D4__NAND_DATA04 0x30c 0x6f4 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D4__SD2_DATA4 0x30c 0x6f4 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x30c 0x6f4 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D5__NAND_DATA05 0x310 0x6f8 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D5__SD2_DATA5 0x310 0x6f8 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x310 0x6f8 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D6__NAND_DATA06 0x314 0x6fc 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D6__SD2_DATA6 0x314 0x6fc 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x314 0x6fc 0x000 0x5 0x0 ++#define MX6QDL_PAD_NANDF_D7__NAND_DATA07 0x318 0x700 0x000 0x0 0x0 ++#define MX6QDL_PAD_NANDF_D7__SD2_DATA7 0x318 0x700 0x000 0x1 0x0 ++#define MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x318 0x700 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x31c 0x704 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x31c 0x704 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT0__GPIO2_IO08 0x31c 0x704 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x320 0x708 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x320 0x708 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT1__GPIO2_IO09 0x320 0x708 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x324 0x70c 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT2__PWM4_OUT 0x324 0x70c 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT2__GPIO2_IO10 0x324 0x70c 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x328 0x710 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x328 0x710 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x32c 0x714 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x32c 0x714 0x928 0x2 0x6 ++#define MX6QDL_PAD_SD4_DAT4__UART2_TX_DATA 0x32c 0x714 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT4__GPIO2_IO12 0x32c 0x714 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x330 0x718 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT5__UART2_RTS_B 0x330 0x718 0x924 0x2 0x4 ++#define MX6QDL_PAD_SD4_DAT5__UART2_CTS_B 0x330 0x718 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT5__GPIO2_IO13 0x330 0x718 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x334 0x71c 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT6__UART2_CTS_B 0x334 0x71c 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT6__UART2_RTS_B 0x334 0x71c 0x924 0x2 0x5 ++#define MX6QDL_PAD_SD4_DAT6__GPIO2_IO14 0x334 0x71c 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x338 0x720 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x338 0x720 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD4_DAT7__UART2_RX_DATA 0x338 0x720 0x928 0x2 0x7 ++#define MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x338 0x720 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x33c 0x724 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD1_DAT1__ECSPI5_SS0 0x33c 0x724 0x834 0x1 0x1 ++#define MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x33c 0x724 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD1_DAT1__GPT_CAPTURE2 0x33c 0x724 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x33c 0x724 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x340 0x728 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD1_DAT0__ECSPI5_MISO 0x340 0x728 0x82c 0x1 0x1 ++#define MX6QDL_PAD_SD1_DAT0__GPT_CAPTURE1 0x340 0x728 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x340 0x728 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x344 0x72c 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD1_DAT3__ECSPI5_SS2 0x344 0x72c 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD1_DAT3__GPT_COMPARE3 0x344 0x72c 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x344 0x72c 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_DAT3__WDOG2_B 0x344 0x72c 0x000 0x4 0x0 ++#define MX6QDL_PAD_SD1_DAT3__GPIO1_IO21 0x344 0x72c 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_DAT3__WDOG2_RESET_B_DEB 0x344 0x72c 0x000 0x6 0x0 ++#define MX6QDL_PAD_SD1_CMD__SD1_CMD 0x348 0x730 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD1_CMD__ECSPI5_MOSI 0x348 0x730 0x830 0x1 0x0 ++#define MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x348 0x730 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD1_CMD__GPT_COMPARE1 0x348 0x730 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_CMD__GPIO1_IO18 0x348 0x730 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x34c 0x734 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD1_DAT2__ECSPI5_SS1 0x34c 0x734 0x838 0x1 0x1 ++#define MX6QDL_PAD_SD1_DAT2__GPT_COMPARE2 0x34c 0x734 0x000 0x2 0x0 ++#define MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x34c 0x734 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_DAT2__WDOG1_B 0x34c 0x734 0x000 0x4 0x0 ++#define MX6QDL_PAD_SD1_DAT2__GPIO1_IO19 0x34c 0x734 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD1_DAT2__WDOG1_RESET_B_DEB 0x34c 0x734 0x000 0x6 0x0 ++#define MX6QDL_PAD_SD1_CLK__SD1_CLK 0x350 0x738 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD1_CLK__ECSPI5_SCLK 0x350 0x738 0x828 0x1 0x0 ++#define MX6QDL_PAD_SD1_CLK__GPT_CLKIN 0x350 0x738 0x000 0x3 0x0 ++#define MX6QDL_PAD_SD1_CLK__GPIO1_IO20 0x350 0x738 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_CLK__SD2_CLK 0x354 0x73c 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD2_CLK__ECSPI5_SCLK 0x354 0x73c 0x828 0x1 0x1 ++#define MX6QDL_PAD_SD2_CLK__KEY_COL5 0x354 0x73c 0x8e8 0x2 0x3 ++#define MX6QDL_PAD_SD2_CLK__AUD4_RXFS 0x354 0x73c 0x7c0 0x3 0x1 ++#define MX6QDL_PAD_SD2_CLK__GPIO1_IO10 0x354 0x73c 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_CMD__SD2_CMD 0x358 0x740 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD2_CMD__ECSPI5_MOSI 0x358 0x740 0x830 0x1 0x1 ++#define MX6QDL_PAD_SD2_CMD__KEY_ROW5 0x358 0x740 0x8f4 0x2 0x2 ++#define MX6QDL_PAD_SD2_CMD__AUD4_RXC 0x358 0x740 0x7bc 0x3 0x1 ++#define MX6QDL_PAD_SD2_CMD__GPIO1_IO11 0x358 0x740 0x000 0x5 0x0 ++#define MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x35c 0x744 0x000 0x0 0x0 ++#define MX6QDL_PAD_SD2_DAT3__ECSPI5_SS3 0x35c 0x744 0x000 0x1 0x0 ++#define MX6QDL_PAD_SD2_DAT3__KEY_COL6 0x35c 0x744 0x8ec 0x2 0x2 ++#define MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x35c 0x744 0x7c4 0x3 0x1 ++#define MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x35c 0x744 0x000 0x5 0x0 + + #endif /* __DTS_IMX6Q_PINFUNC_H */ +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q-sabreauto-ecspi.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabreauto-ecspi.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6q-sabreauto-ecspi.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabreauto-ecspi.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "imx6q-sabreauto.dts" ++ ++&ecspi1 { ++ status = "okay"; ++}; ++ ++&flexcan2 { ++ /* max7310_c on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&i2c3 { ++ /* pin conflict with ecspi1 */ ++ status = "disabled"; ++}; ++ ++&uart3 { ++ /* the uart3 depends on the i2c3, so disable it too. */ ++ status = "disabled"; ++}; ++ ++&usbh1 { ++ /* max7310_b on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&usbotg { ++ /* max7310_c on i2c3 is gone */ ++ status = "okay"; ++ dr_mode = "peripheral"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q-sabreauto-flexcan1.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabreauto-flexcan1.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6q-sabreauto-flexcan1.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabreauto-flexcan1.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "imx6q-sabreauto.dts" ++ ++&flexcan1{ ++ status = "okay"; ++}; ++ ++&fec { ++ /* pin conflict with flexcan1 */ ++ status = "disabled"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q-sabreauto-gpmi-weim.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabreauto-gpmi-weim.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6q-sabreauto-gpmi-weim.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabreauto-gpmi-weim.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "imx6q-sabreauto.dts" ++ ++&ecspi1 { ++ /* pin conflict with weim */ ++ status = "disabled"; ++}; ++ ++&flexcan2 { ++ /* max7310_c on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&gpmi { ++ status = "okay"; ++}; ++ ++&i2c3 { ++ /* pin conflict with weim */ ++ status = "disabled"; ++}; ++ ++&uart3 { ++ /* pin conflict with gpmi and weim */ ++ status = "disabled"; ++}; ++ ++&usbh1 { ++ /* max7310_b on i2c3 is gone */ ++ status = "disabled"; ++}; ++ ++&usbotg { ++ /* max7310_c on i2c3 is gone */ ++ status = "okay"; ++ dr_mode = "peripheral"; ++}; ++ ++&weim { ++ status = "okay"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q-sabreauto.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabreauto.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6q-sabreauto.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabreauto.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -20,16 +20,22 @@ + compatible = "fsl,imx6q-sabreauto", "fsl,imx6q"; + }; + +-&iomuxc { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_hog>; ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; ++ ++&mxcfb3 { ++ status = "okay"; ++}; ++ ++&mxcfb4 { ++ status = "okay"; ++}; + +- hog { +- pinctrl_hog: hoggrp { +- fsl,pins = < +- MX6Q_PAD_NANDF_CS2__GPIO6_IO15 0x80000000 +- MX6Q_PAD_SD2_DAT2__GPIO1_IO13 0x80000000 +- >; +- }; +- }; ++&sata { ++ status = "okay"; + }; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q-sabrelite.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabrelite.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6q-sabrelite.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabrelite.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -65,6 +65,12 @@ + }; + }; + ++&audmux { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux_1>; ++}; ++ + &ecspi1 { + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio3 19 0>; +@@ -79,9 +85,27 @@ + }; + }; + +-&ssi1 { +- fsl,mode = "i2s-slave"; ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet_1>; ++ phy-mode = "rgmii"; ++ phy-reset-gpios = <&gpio3 23 0>; ++ status = "okay"; ++}; ++ ++&i2c1 { + status = "okay"; ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1_1>; ++ ++ codec: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&clks 201>; ++ VDDA-supply = <®_2p5v>; ++ VDDIO-supply = <®_3p3v>; ++ }; + }; + + &iomuxc { +@@ -91,36 +115,69 @@ + hog { + pinctrl_hog: hoggrp { + fsl,pins = < +- MX6Q_PAD_NANDF_D6__GPIO2_IO06 0x80000000 +- MX6Q_PAD_NANDF_D7__GPIO2_IO07 0x80000000 +- MX6Q_PAD_EIM_D19__GPIO3_IO19 0x80000000 +- MX6Q_PAD_EIM_D22__GPIO3_IO22 0x80000000 +- MX6Q_PAD_EIM_D23__GPIO3_IO23 0x80000000 +- MX6Q_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 +- MX6Q_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 +- MX6Q_PAD_GPIO_0__CCM_CLKO1 0x80000000 ++ MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x80000000 ++ MX6QDL_PAD_NANDF_D7__GPIO2_IO07 0x80000000 ++ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 ++ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 ++ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 ++ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 ++ MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 ++ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x80000000 ++ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 + >; + }; + }; + }; + +-&usbotg { +- vbus-supply = <®_usb_otg_vbus>; +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usbotg_1>; +- disable-over-current; ++&ldb { ++ status = "okay"; ++ ++ lvds-channel@0 { ++ fsl,data-mapping = "spwg"; ++ fsl,data-width = <18>; ++ status = "okay"; ++ ++ display-timings { ++ native-mode = <&timing0>; ++ timing0: hsd100pxn1 { ++ clock-frequency = <65000000>; ++ hactive = <1024>; ++ vactive = <768>; ++ hback-porch = <220>; ++ hfront-porch = <40>; ++ vback-porch = <21>; ++ vfront-porch = <7>; ++ hsync-len = <60>; ++ vsync-len = <10>; ++ }; ++ }; ++ }; ++}; ++ ++&sata { + status = "okay"; + }; + ++&ssi1 { ++ fsl,mode = "i2s-slave"; ++ status = "okay"; ++}; ++ ++&uart2 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2_1>; ++}; ++ + &usbh1 { + status = "okay"; + }; + +-&fec { ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_1>; +- phy-mode = "rgmii"; +- phy-reset-gpios = <&gpio3 23 0>; ++ pinctrl-0 = <&pinctrl_usbotg_1>; ++ disable-over-current; + status = "okay"; + }; + +@@ -141,30 +198,3 @@ + vmmc-supply = <®_3p3v>; + status = "okay"; + }; +- +-&audmux { +- status = "okay"; +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_audmux_1>; +-}; +- +-&uart2 { +- status = "okay"; +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart2_1>; +-}; +- +-&i2c1 { +- status = "okay"; +- clock-frequency = <100000>; +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_i2c1_1>; +- +- codec: sgtl5000@0a { +- compatible = "fsl,sgtl5000"; +- reg = <0x0a>; +- clocks = <&clks 169>; +- VDDA-supply = <®_2p5v>; +- VDDIO-supply = <®_3p3v>; +- }; +-}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright 2012-2013 Freescale Semiconductor, Inc. ++ * Copyright 2011 Linaro Ltd. ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include "imx6q-sabresd.dts" ++ ++&hdmi_video { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hdmi_hdcp_1>; ++ fsl,hdcp; ++}; ++ ++&i2c2 { ++ status = "disable"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q-sabresd-ldo.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabresd-ldo.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6q-sabresd-ldo.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabresd-ldo.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,34 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor, Inc. ++ * Copyright 2011 Linaro Ltd. ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++ ++#include "imx6q-sabresd.dts" ++ ++&cpu0 { ++ arm-supply = <®_arm>; ++ soc-supply = <®_soc>; ++ pu-supply = <®_pu>; /* use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&gpc { ++ fsl,ldo-bypass = <0>; /* use ldo-bypass, u-boot will check it and configure */ ++ fsl,wdog-reset = <1>; /* watchdog select of reset source */ ++ pu-supply = <®_pu>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&gpu { ++ pu-supply = <®_pu>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&vpu { ++ pu-supply = <®_pu>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q-sabresd.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabresd.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6q-sabresd.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q-sabresd.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -20,20 +20,32 @@ + compatible = "fsl,imx6q-sabresd", "fsl,imx6q"; + }; + +-&iomuxc { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_hog>; +- +- hog { +- pinctrl_hog: hoggrp { +- fsl,pins = < +- MX6Q_PAD_GPIO_4__GPIO1_IO04 0x80000000 +- MX6Q_PAD_GPIO_5__GPIO1_IO05 0x80000000 +- MX6Q_PAD_NANDF_D0__GPIO2_IO00 0x80000000 +- MX6Q_PAD_NANDF_D1__GPIO2_IO01 0x80000000 +- MX6Q_PAD_NANDF_D2__GPIO2_IO02 0x80000000 +- MX6Q_PAD_NANDF_D3__GPIO2_IO03 0x80000000 +- >; +- }; +- }; ++&imx_drm { ++ crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; ++}; ++ ++&sata { ++ status = "okay"; ++}; ++ ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; ++ ++&mxcfb3 { ++ status = "okay"; ++}; ++ ++&mxcfb4 { ++ status = "okay"; ++}; ++ ++&battery { ++ offset-charger = <1900>; ++ offset-discharger = <1694>; ++ offset-usb-charger = <1685>; + }; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6q.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx6q.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6q.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -8,15 +8,19 @@ + * + */ + +-#include "imx6qdl.dtsi" + #include "imx6q-pinfunc.h" ++#include "imx6qdl.dtsi" + + / { ++ aliases { ++ ipu1 = &ipu2; ++ }; ++ + cpus { + #address-cells = <1>; + #size-cells = <0>; + +- cpu@0 { ++ cpu0: cpu@0 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <0>; +@@ -25,8 +29,17 @@ + /* kHz uV */ + 1200000 1275000 + 996000 1250000 ++ 852000 1250000 + 792000 1150000 +- 396000 950000 ++ 396000 975000 ++ >; ++ fsl,soc-operating-points = < ++ /* ARM kHz SOC-PU uV */ ++ 1200000 1275000 ++ 996000 1250000 ++ 852000 1250000 ++ 792000 1175000 ++ 396000 1175000 + >; + clock-latency = <61036>; /* two CLK32 periods */ + clocks = <&clks 104>, <&clks 6>, <&clks 16>, +@@ -61,6 +74,77 @@ + }; + + soc { ++ ++ busfreq { /* BUSFREQ */ ++ compatible = "fsl,imx6_busfreq"; ++ clocks = <&clks 171>, <&clks 6>, <&clks 11>, <&clks 104>, <&clks 172>, <&clks 58>, ++ <&clks 18>, <&clks 60>, <&clks 20>, <&clks 3>; ++ clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", "periph", ++ "periph_pre", "periph_clk2", "periph_clk2_sel", "osc"; ++ interrupts = <0 107 0x04>, <0 112 0x4>, <0 113 0x4>, <0 114 0x4>; ++ interrupt-names = "irq_busfreq_0", "irq_busfreq_1", "irq_busfreq_2", "irq_busfreq_3"; ++ fsl,max_ddr_freq = <528000000>; ++ }; ++ ++ gpu: gpu@00130000 { ++ compatible = "fsl,imx6q-gpu"; ++ reg = <0x00130000 0x4000>, <0x00134000 0x4000>, ++ <0x02204000 0x4000>, <0x0 0x0>; ++ reg-names = "iobase_3d", "iobase_2d", ++ "iobase_vg", "phys_baseaddr"; ++ interrupts = <0 9 0x04>, <0 10 0x04>,<0 11 0x04>; ++ interrupt-names = "irq_3d", "irq_2d", "irq_vg"; ++ clocks = <&clks 26>, <&clks 143>, ++ <&clks 27>, <&clks 121>, ++ <&clks 122>, <&clks 74>; ++ clock-names = "gpu2d_axi_clk", "openvg_axi_clk", ++ "gpu3d_axi_clk", "gpu2d_clk", ++ "gpu3d_clk", "gpu3d_shader_clk"; ++ resets = <&src 0>, <&src 3>, <&src 3>; ++ reset-names = "gpu3d", "gpu2d", "gpuvg"; ++ pu-supply = <®_pu>; ++ }; ++ ++ ocram: sram@00900000 { ++ compatible = "mmio-sram"; ++ reg = <0x00900000 0x40000>; ++ clocks = <&clks 142>; ++ }; ++ ++ hdmi_core: hdmi_core@00120000 { ++ compatible = "fsl,imx6q-hdmi-core"; ++ reg = <0x00120000 0x9000>; ++ clocks = <&clks 124>, <&clks 123>; ++ clock-names = "hdmi_isfr", "hdmi_iahb"; ++ status = "disabled"; ++ }; ++ ++ hdmi_video: hdmi_video@020e0000 { ++ compatible = "fsl,imx6q-hdmi-video"; ++ reg = <0x020e0000 0x1000>; ++ reg-names = "hdmi_gpr"; ++ interrupts = <0 115 0x04>; ++ clocks = <&clks 124>, <&clks 123>; ++ clock-names = "hdmi_isfr", "hdmi_iahb"; ++ status = "disabled"; ++ }; ++ ++ hdmi_audio: hdmi_audio@00120000 { ++ compatible = "fsl,imx6q-hdmi-audio"; ++ clocks = <&clks 124>, <&clks 123>; ++ clock-names = "hdmi_isfr", "hdmi_iahb"; ++ dmas = <&sdma 2 22 0>; ++ dma-names = "tx"; ++ status = "disabled"; ++ }; ++ ++ hdmi_cec: hdmi_cec@00120000 { ++ compatible = "fsl,imx6q-hdmi-cec"; ++ interrupts = <0 115 0x04>; ++ status = "disabled"; ++ }; ++ ++ + aips-bus@02000000 { /* AIPS1 */ + spba-bus@02000000 { + ecspi5: ecspi@02018000 { +@@ -75,288 +159,91 @@ + }; + }; + ++ vpu@02040000 { ++ status = "okay"; ++ }; ++ + iomuxc: iomuxc@020e0000 { + compatible = "fsl,imx6q-iomuxc"; +- reg = <0x020e0000 0x4000>; +- +- /* shared pinctrl settings */ +- audmux { +- pinctrl_audmux_1: audmux-1 { +- fsl,pins = < +- MX6Q_PAD_SD2_DAT0__AUD4_RXD 0x80000000 +- MX6Q_PAD_SD2_DAT3__AUD4_TXC 0x80000000 +- MX6Q_PAD_SD2_DAT2__AUD4_TXD 0x80000000 +- MX6Q_PAD_SD2_DAT1__AUD4_TXFS 0x80000000 +- >; +- }; +- +- pinctrl_audmux_2: audmux-2 { +- fsl,pins = < +- MX6Q_PAD_CSI0_DAT7__AUD3_RXD 0x80000000 +- MX6Q_PAD_CSI0_DAT4__AUD3_TXC 0x80000000 +- MX6Q_PAD_CSI0_DAT5__AUD3_TXD 0x80000000 +- MX6Q_PAD_CSI0_DAT6__AUD3_TXFS 0x80000000 +- >; +- }; +- }; +- +- ecspi1 { +- pinctrl_ecspi1_1: ecspi1grp-1 { +- fsl,pins = < +- MX6Q_PAD_EIM_D17__ECSPI1_MISO 0x100b1 +- MX6Q_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 +- MX6Q_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 +- >; +- }; +- }; +- +- ecspi3 { +- pinctrl_ecspi3_1: ecspi3grp-1 { +- fsl,pins = < +- MX6Q_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 +- MX6Q_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 +- MX6Q_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 +- >; +- }; +- }; +- +- enet { +- pinctrl_enet_1: enetgrp-1 { +- fsl,pins = < +- MX6Q_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 +- MX6Q_PAD_ENET_MDC__ENET_MDC 0x1b0b0 +- MX6Q_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 +- MX6Q_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 +- MX6Q_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 +- MX6Q_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 +- MX6Q_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 +- MX6Q_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 +- MX6Q_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 +- MX6Q_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 +- MX6Q_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 +- MX6Q_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 +- MX6Q_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 +- MX6Q_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 +- MX6Q_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 +- MX6Q_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 +- >; +- }; +- +- pinctrl_enet_2: enetgrp-2 { +- fsl,pins = < +- MX6Q_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 +- MX6Q_PAD_KEY_COL2__ENET_MDC 0x1b0b0 +- MX6Q_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 +- MX6Q_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 +- MX6Q_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 +- MX6Q_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 +- MX6Q_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 +- MX6Q_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 +- MX6Q_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 +- MX6Q_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 +- MX6Q_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 +- MX6Q_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 +- MX6Q_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 +- MX6Q_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 +- MX6Q_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 +- >; +- }; +- }; +- +- gpmi-nand { +- pinctrl_gpmi_nand_1: gpmi-nand-1 { +- fsl,pins = < +- MX6Q_PAD_NANDF_CLE__NAND_CLE 0xb0b1 +- MX6Q_PAD_NANDF_ALE__NAND_ALE 0xb0b1 +- MX6Q_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 +- MX6Q_PAD_NANDF_RB0__NAND_READY_B 0xb000 +- MX6Q_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 +- MX6Q_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 +- MX6Q_PAD_NANDF_CS2__NAND_CE2_B 0xb0b1 +- MX6Q_PAD_NANDF_CS3__NAND_CE3_B 0xb0b1 +- MX6Q_PAD_SD4_CMD__NAND_RE_B 0xb0b1 +- MX6Q_PAD_SD4_CLK__NAND_WE_B 0xb0b1 +- MX6Q_PAD_NANDF_D0__NAND_DATA00 0xb0b1 +- MX6Q_PAD_NANDF_D1__NAND_DATA01 0xb0b1 +- MX6Q_PAD_NANDF_D2__NAND_DATA02 0xb0b1 +- MX6Q_PAD_NANDF_D3__NAND_DATA03 0xb0b1 +- MX6Q_PAD_NANDF_D4__NAND_DATA04 0xb0b1 +- MX6Q_PAD_NANDF_D5__NAND_DATA05 0xb0b1 +- MX6Q_PAD_NANDF_D6__NAND_DATA06 0xb0b1 +- MX6Q_PAD_NANDF_D7__NAND_DATA07 0xb0b1 +- MX6Q_PAD_SD4_DAT0__NAND_DQS 0x00b1 +- >; +- }; +- }; +- +- i2c1 { +- pinctrl_i2c1_1: i2c1grp-1 { +- fsl,pins = < +- MX6Q_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 +- MX6Q_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 +- >; +- }; +- }; +- +- i2c2 { +- pinctrl_i2c2_1: i2c2grp-1 { +- fsl,pins = < +- MX6Q_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 +- MX6Q_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 +- >; +- }; +- }; +- +- i2c3 { +- pinctrl_i2c3_1: i2c3grp-1 { +- fsl,pins = < +- MX6Q_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 +- MX6Q_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 +- >; +- }; +- }; +- +- uart1 { +- pinctrl_uart1_1: uart1grp-1 { +- fsl,pins = < +- MX6Q_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 +- MX6Q_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 +- >; +- }; +- }; +- +- uart2 { +- pinctrl_uart2_1: uart2grp-1 { +- fsl,pins = < +- MX6Q_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 +- MX6Q_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 +- >; +- }; +- }; +- +- uart4 { +- pinctrl_uart4_1: uart4grp-1 { +- fsl,pins = < +- MX6Q_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 +- MX6Q_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 +- >; +- }; +- }; +- +- usbotg { +- pinctrl_usbotg_1: usbotggrp-1 { +- fsl,pins = < +- MX6Q_PAD_GPIO_1__USB_OTG_ID 0x17059 +- >; +- }; +- +- pinctrl_usbotg_2: usbotggrp-2 { +- fsl,pins = < +- MX6Q_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 +- >; +- }; +- }; +- +- usdhc2 { +- pinctrl_usdhc2_1: usdhc2grp-1 { +- fsl,pins = < +- MX6Q_PAD_SD2_CMD__SD2_CMD 0x17059 +- MX6Q_PAD_SD2_CLK__SD2_CLK 0x10059 +- MX6Q_PAD_SD2_DAT0__SD2_DATA0 0x17059 +- MX6Q_PAD_SD2_DAT1__SD2_DATA1 0x17059 +- MX6Q_PAD_SD2_DAT2__SD2_DATA2 0x17059 +- MX6Q_PAD_SD2_DAT3__SD2_DATA3 0x17059 +- MX6Q_PAD_NANDF_D4__SD2_DATA4 0x17059 +- MX6Q_PAD_NANDF_D5__SD2_DATA5 0x17059 +- MX6Q_PAD_NANDF_D6__SD2_DATA6 0x17059 +- MX6Q_PAD_NANDF_D7__SD2_DATA7 0x17059 +- >; +- }; +- }; +- +- usdhc3 { +- pinctrl_usdhc3_1: usdhc3grp-1 { +- fsl,pins = < +- MX6Q_PAD_SD3_CMD__SD3_CMD 0x17059 +- MX6Q_PAD_SD3_CLK__SD3_CLK 0x10059 +- MX6Q_PAD_SD3_DAT0__SD3_DATA0 0x17059 +- MX6Q_PAD_SD3_DAT1__SD3_DATA1 0x17059 +- MX6Q_PAD_SD3_DAT2__SD3_DATA2 0x17059 +- MX6Q_PAD_SD3_DAT3__SD3_DATA3 0x17059 +- MX6Q_PAD_SD3_DAT4__SD3_DATA4 0x17059 +- MX6Q_PAD_SD3_DAT5__SD3_DATA5 0x17059 +- MX6Q_PAD_SD3_DAT6__SD3_DATA6 0x17059 +- MX6Q_PAD_SD3_DAT7__SD3_DATA7 0x17059 +- >; +- }; +- +- pinctrl_usdhc3_2: usdhc3grp-2 { +- fsl,pins = < +- MX6Q_PAD_SD3_CMD__SD3_CMD 0x17059 +- MX6Q_PAD_SD3_CLK__SD3_CLK 0x10059 +- MX6Q_PAD_SD3_DAT0__SD3_DATA0 0x17059 +- MX6Q_PAD_SD3_DAT1__SD3_DATA1 0x17059 +- MX6Q_PAD_SD3_DAT2__SD3_DATA2 0x17059 +- MX6Q_PAD_SD3_DAT3__SD3_DATA3 0x17059 +- >; +- }; +- }; ++ }; ++ }; + +- usdhc4 { +- pinctrl_usdhc4_1: usdhc4grp-1 { +- fsl,pins = < +- MX6Q_PAD_SD4_CMD__SD4_CMD 0x17059 +- MX6Q_PAD_SD4_CLK__SD4_CLK 0x10059 +- MX6Q_PAD_SD4_DAT0__SD4_DATA0 0x17059 +- MX6Q_PAD_SD4_DAT1__SD4_DATA1 0x17059 +- MX6Q_PAD_SD4_DAT2__SD4_DATA2 0x17059 +- MX6Q_PAD_SD4_DAT3__SD4_DATA3 0x17059 +- MX6Q_PAD_SD4_DAT4__SD4_DATA4 0x17059 +- MX6Q_PAD_SD4_DAT5__SD4_DATA5 0x17059 +- MX6Q_PAD_SD4_DAT6__SD4_DATA6 0x17059 +- MX6Q_PAD_SD4_DAT7__SD4_DATA7 0x17059 +- >; +- }; +- +- pinctrl_usdhc4_2: usdhc4grp-2 { +- fsl,pins = < +- MX6Q_PAD_SD4_CMD__SD4_CMD 0x17059 +- MX6Q_PAD_SD4_CLK__SD4_CLK 0x10059 +- MX6Q_PAD_SD4_DAT0__SD4_DATA0 0x17059 +- MX6Q_PAD_SD4_DAT1__SD4_DATA1 0x17059 +- MX6Q_PAD_SD4_DAT2__SD4_DATA2 0x17059 +- MX6Q_PAD_SD4_DAT3__SD4_DATA3 0x17059 +- >; +- }; +- }; ++ aips-bus@02100000 { /* AIPS2 */ ++ mipi_dsi: mipi@021e0000 { ++ compatible = "fsl,imx6q-mipi-dsi"; ++ reg = <0x021e0000 0x4000>; ++ interrupts = <0 102 0x04>; ++ gpr = <&gpr>; ++ clocks = <&clks 138>, <&clks 204>; ++ clock-names = "mipi_pllref_clk", "mipi_cfg_clk"; ++ status = "disabled"; + }; + }; + ++ sata: sata@02200000 { ++ compatible = "fsl,imx6q-ahci"; ++ reg = <0x02200000 0x4000>; ++ interrupts = <0 39 0x04>; ++ clocks = <&clks 154>, <&clks 187>, <&clks 105>; ++ clock-names = "sata", "sata_ref", "ahb"; ++ status = "disabled"; ++ }; ++ + ipu2: ipu@02800000 { +- #crtc-cells = <1>; + compatible = "fsl,imx6q-ipu"; + reg = <0x02800000 0x400000>; + interrupts = <0 8 0x4 0 7 0x4>; +- clocks = <&clks 133>, <&clks 134>, <&clks 137>; +- clock-names = "bus", "di0", "di1"; ++ clocks = <&clks 133>, <&clks 134>, <&clks 137>, ++ <&clks 41>, <&clks 42>, ++ <&clks 135>, <&clks 136>; ++ clock-names = "bus", "di0", "di1", ++ "di0_sel", "di1_sel", ++ "ldb_di0", "ldb_di1"; + resets = <&src 4>; ++ bypass_reset = <0>; + }; + }; + }; + +-&ldb { +- clocks = <&clks 33>, <&clks 34>, +- <&clks 39>, <&clks 40>, <&clks 41>, <&clks 42>, +- <&clks 135>, <&clks 136>; +- clock-names = "di0_pll", "di1_pll", +- "di0_sel", "di1_sel", "di2_sel", "di3_sel", +- "di0", "di1"; +- +- lvds-channel@0 { +- crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; ++&iomuxc { ++ ipu2 { ++ pinctrl_ipu2_1: ipu2grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_DI0_DISP_CLK__IPU2_DI0_DISP_CLK 0x10 ++ MX6QDL_PAD_DI0_PIN15__IPU2_DI0_PIN15 0x10 ++ MX6QDL_PAD_DI0_PIN2__IPU2_DI0_PIN02 0x10 ++ MX6QDL_PAD_DI0_PIN3__IPU2_DI0_PIN03 0x10 ++ MX6QDL_PAD_DI0_PIN4__IPU2_DI0_PIN04 0x80000000 ++ MX6QDL_PAD_DISP0_DAT0__IPU2_DISP0_DATA00 0x10 ++ MX6QDL_PAD_DISP0_DAT1__IPU2_DISP0_DATA01 0x10 ++ MX6QDL_PAD_DISP0_DAT2__IPU2_DISP0_DATA02 0x10 ++ MX6QDL_PAD_DISP0_DAT3__IPU2_DISP0_DATA03 0x10 ++ MX6QDL_PAD_DISP0_DAT4__IPU2_DISP0_DATA04 0x10 ++ MX6QDL_PAD_DISP0_DAT5__IPU2_DISP0_DATA05 0x10 ++ MX6QDL_PAD_DISP0_DAT6__IPU2_DISP0_DATA06 0x10 ++ MX6QDL_PAD_DISP0_DAT7__IPU2_DISP0_DATA07 0x10 ++ MX6QDL_PAD_DISP0_DAT8__IPU2_DISP0_DATA08 0x10 ++ MX6QDL_PAD_DISP0_DAT9__IPU2_DISP0_DATA09 0x10 ++ MX6QDL_PAD_DISP0_DAT10__IPU2_DISP0_DATA10 0x10 ++ MX6QDL_PAD_DISP0_DAT11__IPU2_DISP0_DATA11 0x10 ++ MX6QDL_PAD_DISP0_DAT12__IPU2_DISP0_DATA12 0x10 ++ MX6QDL_PAD_DISP0_DAT13__IPU2_DISP0_DATA13 0x10 ++ MX6QDL_PAD_DISP0_DAT14__IPU2_DISP0_DATA14 0x10 ++ MX6QDL_PAD_DISP0_DAT15__IPU2_DISP0_DATA15 0x10 ++ MX6QDL_PAD_DISP0_DAT16__IPU2_DISP0_DATA16 0x10 ++ MX6QDL_PAD_DISP0_DAT17__IPU2_DISP0_DATA17 0x10 ++ MX6QDL_PAD_DISP0_DAT18__IPU2_DISP0_DATA18 0x10 ++ MX6QDL_PAD_DISP0_DAT19__IPU2_DISP0_DATA19 0x10 ++ MX6QDL_PAD_DISP0_DAT20__IPU2_DISP0_DATA20 0x10 ++ MX6QDL_PAD_DISP0_DAT21__IPU2_DISP0_DATA21 0x10 ++ MX6QDL_PAD_DISP0_DAT22__IPU2_DISP0_DATA22 0x10 ++ MX6QDL_PAD_DISP0_DAT23__IPU2_DISP0_DATA23 0x10 ++ >; ++ }; + }; ++}; + +- lvds-channel@1 { +- crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; +- }; ++&hdmi { ++ compatible = "fsl,imx6q-hdmi"; ++ crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; + }; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,289 @@ ++/* ++ * Copyright (C) 2014 Russell King ++ */ ++#include "imx6qdl-microsom.dtsi" ++#include "imx6qdl-microsom-ar8035.dtsi" ++ ++/ { ++ aliases { ++ mxcfb0 = &mxcfb1; ++ }; ++ ++ ir_recv: ir-receiver { ++ compatible = "gpio-ir-receiver"; ++ gpios = <&gpio3 9 1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_ir>; ++ }; ++ ++ pwmleds { ++ compatible = "pwm-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_pwm1>; ++ ++ front { ++ active-low; ++ default-brightness = <128>; ++ label = "imx6:red:front"; ++ max-brightness = <248>; ++ pwms = <&pwm1 0 50000>; ++ }; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_3p3v: 3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_usbh1_vbus: usb-h1-vbus { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio1 0 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_usbh1_vbus>; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ }; ++ ++ reg_usbotg_vbus: usb-otg-vbus { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio3 22 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_usbotg_vbus>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ }; ++ }; ++ ++ codec: spdif-transmitter { ++ compatible = "linux,spdif-dit"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_spdif>; ++ }; ++ ++ imx-drm { ++ compatible = "fsl,imx-drm"; ++ crtcs = <&ipu1 0>, <&ipu1 1>; ++ connectors = <&hdmi>; ++ }; ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-out; ++ }; ++ ++ sound-hdmi { ++ compatible = "fsl,imx6q-audio-hdmi", ++ "fsl,imx-audio-hdmi"; ++ model = "imx-audio-hdmi"; ++ hdmi-controller = <&hdmi_audio>; ++ }; ++ ++ mxcfb1: mxc_sdc_fb@0 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "hdmi"; ++ interface_pix_fmt = "RGB24"; ++ mode_str ="1280x720@60"; ++ default_bpp = <32>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_cap_0 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <0>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_cap_1 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++}; ++ ++&hdmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_hdmi>; ++ ddc = <&i2c2>; ++ status = "okay"; ++ crtcs = <&ipu1 0>; ++}; ++ ++&hdmi_audio { ++ status = "okay"; ++}; ++ ++&hdmi_cec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_hdmi>; ++ status = "okay"; ++}; ++ ++&hdmi_core { ++ ipu_id = <1>; ++ disp_id = <0>; ++ status = "okay"; ++}; ++ ++&hdmi_video { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hdmi_hdcp_1>; ++ fsl,phy_reg_vlev = <0x0294>; ++ fsl,phy_reg_cksymtx = <0x800d>; ++ fsl,hdcp; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2_2>; ++ status = "disable"; ++}; ++ ++&i2c3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3_1>; ++ ++ status = "okay"; ++ ++ rtc: pcf8523@68 { ++ compatible = "nxp,pcf8523"; ++ reg = <0x68>; ++ }; ++}; ++ ++&iomuxc { ++ cubox_i { ++ pinctrl_cubox_i_ir: cubox-i-ir { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 ++ >; ++ }; ++ ++ pinctrl_cubox_i_hdmi: cubox-i-hdmi { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ ++ pinctrl_cubox_i_pwm1: cubox-i-pwm1-front-led { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_cubox_i_spdif: cubox-i-spdif { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_cubox_i_usbotg_vbus: cubox-i-usbotg-vbus { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_cubox_i_usdhc2_aux: cubox-i-usdhc2-aux { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1f071 ++ MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071 ++ >; ++ }; ++ ++ pinctrl_cubox_i_usdhc2: cubox-i-usdhc2 { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 ++ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 ++ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 ++ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 ++ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 ++ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059 ++ >; ++ }; ++ ++ pinctrl_cubox_i_usdhc2_100mhz: cubox-i-usdhc2-100mhz { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9 ++ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9 ++ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 ++ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 ++ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 ++ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130b9 ++ >; ++ }; ++ ++ pinctrl_cubox_i_usdhc2_200mhz: cubox-i-usdhc2-200mhz { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9 ++ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9 ++ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 ++ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 ++ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 ++ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130f9 ++ >; ++ }; ++ }; ++}; ++ ++&spdif { ++ status = "okay"; ++}; ++ ++&usbh1 { ++ vbus-supply = <®_usbh1_vbus>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usbotg_vbus>; ++ status = "okay"; ++}; ++ ++&uart4 { ++ status = "okay"; ++}; ++ ++&usdhc1 { ++ status = "disabled"; ++}; ++ ++&uart4 { ++ status = "okay"; ++}; ++ ++&usdhc1 { ++ status = "okay"; ++}; ++ ++&usdhc2 { ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>; ++ pinctrl-1 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_100mhz>; ++ pinctrl-2 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_200mhz>; ++ vmmc-supply = <®_3p3v>; ++ cd-gpios = <&gpio1 4 0>; ++ no-1-8-v; ++ status = "okay"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,58 @@ ++/* ++ * Copyright 2013 Russell King ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License version 2. ++ * ++ * This describes the hookup for an AR8035 to the IMX6 on the Cubox-i ++ * MicroSOM. ++ * ++ * FIXME: we need to configure PLL_ENET to produce 25MHz, but there ++ * doesn't seem to be a way to do that yet from DT. (Writing 0x2000 ++ * to 0x020c80e0 phys will do this.) ++ */ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_enet_ar8035>; ++ phy-mode = "rgmii"; ++ phy-reset-duration = <2>; ++ phy-reset-gpios = <&gpio4 15 0>; ++ status = "okay"; ++}; ++ ++&iomuxc { ++ enet { ++ pinctrl_microsom_enet_ar8035: microsom-enet-ar8035 { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ /* AR8035 reset */ ++ MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x130b0 ++ /* AR8035 interrupt */ ++ MX6QDL_PAD_DI0_PIN2__GPIO4_IO18 0x80000000 ++ /* GPIO16 -> AR8035 25MHz */ ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0xc0000000 ++ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x80000000 ++ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 ++ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 ++ /* AR8035 CLK_25M --> ENET_REF_CLK (V22) */ ++ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x0a0b1 ++ /* AR8035 pin strapping: IO voltage: pull up */ ++ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 ++ /* AR8035 pin strapping: PHYADDR#0: pull down */ ++ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x130b0 ++ /* AR8035 pin strapping: PHYADDR#1: pull down */ ++ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x130b0 ++ /* AR8035 pin strapping: MODE#1: pull up */ ++ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 ++ /* AR8035 pin strapping: MODE#3: pull up */ ++ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 ++ /* AR8035 pin strapping: MODE#0: pull down */ ++ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x130b0 ++ >; ++ }; ++ }; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6qdl-microsom.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl-microsom.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx6qdl-microsom.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,120 @@ ++/* ++ * Copyright (C) 2013,2014 Russell King ++ */ ++#include ++/ { ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_brcm_osc: brcm-osc-reg { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio5 5 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_brcm_osc_reg>; ++ regulator-name = "brcm_osc_reg"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ regulator-boot-on; ++ }; ++ ++ reg_brcm: brcm-reg { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio3 19 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_brcm_reg>; ++ regulator-name = "brcm_reg"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ startup-delay-us = <200000>; ++ }; ++ }; ++}; ++ ++&iomuxc { ++ microsom { ++ pinctrl_microsom_brcm_osc_reg: microsom-brcm-osc-reg { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070 ++ >; ++ }; ++ ++ pinctrl_microsom_brcm_reg: microsom-brcm-reg { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x40013070 ++ >; ++ }; ++ ++ pinctrl_microsom_brcm_wifi: microsom-brcm-wifi { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x1b0b0 ++ MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x40013070 ++ MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x40013070 ++ MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x40013070 ++ >; ++ }; ++ ++ pinctrl_microsom_brcm_bt: microsom-brcm-bt { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x40013070 ++ MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 0x40013070 ++ MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40013070 ++ >; ++ }; ++ ++ pinctrl_microsom_uart1: microsom-uart1 { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_microsom_uart4_1: microsom-uart4 { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_microsom_usbotg: microsom-usbotg { ++ /* ++ * Similar to pinctrl_usbotg_2, but we want it ++ * pulled down for a fixed host connection. ++ */ ++ fsl,pins = ; ++ }; ++ }; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_uart1>; ++ status = "okay"; ++}; ++ ++/* UART4 - Connected to optional BRCM Wifi/BT/FM */ ++&uart4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_brcm_bt &pinctrl_microsom_uart4_1>; ++ fsl,uart-has-rtscts; ++}; ++ ++&usbotg { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_usbotg>; ++}; ++ ++/* USDHC1 - Connected to optional BRCM Wifi/BT/FM */ ++&usdhc1 { ++ card-external-vcc-supply = <®_brcm>; ++ card-reset-gpios = <&gpio5 26 GPIO_ACTIVE_LOW>, <&gpio6 0 GPIO_ACTIVE_LOW>; ++ keep-power-in-suspend; ++ non-removable; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_microsom_brcm_wifi &pinctrl_usdhc1_2>; ++ vmmc-supply = <®_brcm>; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -11,9 +11,282 @@ + */ + + / { ++ aliases { ++ mxcfb0 = &mxcfb1; ++ mxcfb1 = &mxcfb2; ++ mxcfb2 = &mxcfb3; ++ mxcfb3 = &mxcfb4; ++ }; ++ + memory { + reg = <0x10000000 0x80000000>; + }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ home { ++ label = "Home"; ++ gpios = <&gpio1 11 0>; ++ linux,code = <102>; /* KEY_HOME */ ++ gpio-key,wakeup; ++ }; ++ ++ back { ++ label = "Back"; ++ gpios = <&gpio1 12 0>; ++ linux,code = <158>; /* KEY_BACK */ ++ gpio-key,wakeup; ++ }; ++ ++ program { ++ label = "Program"; ++ gpios = <&gpio2 12 0>; ++ linux,code = <362>; /* KEY_PROGRAM */ ++ gpio-key,wakeup; ++ }; ++ ++ volume-up { ++ label = "Volume Up"; ++ gpios = <&gpio2 15 0>; ++ linux,code = <115>; /* KEY_VOLUMEUP */ ++ gpio-key,wakeup; ++ }; ++ ++ volume-down { ++ label = "Volume Down"; ++ gpios = <&gpio5 14 0>; ++ linux,code = <114>; /* KEY_VOLUMEDOWN */ ++ gpio-key,wakeup; ++ }; ++ }; ++ ++ max7310_reset: max7310-reset { ++ compatible = "gpio-reset"; ++ reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; ++ reset-delay-us = <1>; ++ #reset-cells = <0>; ++ }; ++ ++ mxcfb1: fb@0 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "ldb"; ++ interface_pix_fmt = "RGB666"; ++ mode_str ="LDB-XGA"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ mxcfb2: fb@1 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "hdmi"; ++ interface_pix_fmt = "RGB24"; ++ mode_str ="1920x1080M@60"; ++ default_bpp = <24>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ mxcfb3: fb@2 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "lcd"; ++ interface_pix_fmt = "RGB565"; ++ mode_str ="CLAA-WVGA"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ mxcfb4: fb@3 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "ldb"; ++ interface_pix_fmt = "RGB666"; ++ mode_str ="LDB-XGA"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm3 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ reg_audio: cs42888_supply { ++ compatible = "regulator-fixed"; ++ regulator-name = "cs42888_supply"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ si4763_vio1: vio1_tnr { ++ compatible = "regulator-fixed"; ++ regulator-name = "vio1"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ si4763_vio2: vio2_tnr { ++ compatible = "regulator-fixed"; ++ regulator-name = "vio2"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ si4763_vd: f3v3_tnr { ++ compatible = "regulator-fixed"; ++ regulator-name = "vd"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ si4763_va: f5v_tnr { ++ compatible = "regulator-fixed"; ++ regulator-name = "va"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_h1_vbus: usb_h1_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&max7310_b 7 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ reg_usb_otg_vbus: usb_otg_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&max7310_c 1 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ reg_3p3v: 3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ }; ++ ++ sound-cs42888 { ++ compatible = "fsl,imx6-sabreauto-cs42888", ++ "fsl,imx-audio-cs42888"; ++ model = "imx-cs42888"; ++ esai-controller = <&esai>; ++ asrc-controller = <&asrc_p2p>; ++ audio-codec = <&codec>; ++ }; ++ ++ clocks { ++ codec_osc: codec_osc { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24576000>; ++ }; ++ }; ++ ++ sound-fm { ++ compatible = "fsl,imx-audio-si476x", ++ "fsl,imx-tuner-si476x"; ++ model = "imx-radio-si4763"; ++ ++ ssi-controller = <&ssi2>; ++ fm-controller = <&si4763>; ++ mux-int-port = <2>; ++ mux-ext-port = <5>; ++ }; ++ ++ sound-hdmi { ++ compatible = "fsl,imx6q-audio-hdmi", ++ "fsl,imx-audio-hdmi"; ++ model = "imx-audio-hdmi"; ++ hdmi-controller = <&hdmi_audio>; ++ }; ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif", ++ "fsl,imx-sabreauto-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-in; ++ }; ++ ++ v4l2_cap_0 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <0>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_cap_1 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux_3>; ++ status = "okay"; ++}; ++ ++&ecspi1 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio3 19 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi1_1 &pinctrl_ecspi1_sabreauto>; ++ status = "disabled"; /* pin conflict with WEIM NOR */ ++ ++ flash: m25p80@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p32"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++&ecspi1 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio3 19 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi1_1>; ++ ++ flash: m25p80@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p32"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; + }; + + &fec { +@@ -23,16 +296,409 @@ + status = "okay"; + }; + ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand_1>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2_3>; ++ status = "okay"; ++ ++ egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ interrupt-parent = <&gpio2>; ++ interrupts = <28 2>; ++ wakeup-gpios = <&gpio2 28 0>; ++ }; ++ ++ pmic: pfuze100@08 { ++ compatible = "fsl,pfuze100"; ++ reg = <0x08>; ++ ++ regulators { ++ sw1a_reg: sw1ab { ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1875000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-ramp-delay = <6250>; ++ }; ++ ++ sw1c_reg: sw1c { ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1875000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-ramp-delay = <6250>; ++ }; ++ ++ sw2_reg: sw2 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw3a_reg: sw3a { ++ regulator-min-microvolt = <400000>; ++ regulator-max-microvolt = <1975000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw3b_reg: sw3b { ++ regulator-min-microvolt = <400000>; ++ regulator-max-microvolt = <1975000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw4_reg: sw4 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ swbst_reg: swbst { ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5150000>; ++ }; ++ ++ snvs_reg: vsnvs { ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <3000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vref_reg: vrefddr { ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vgen1_reg: vgen1 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <1550000>; ++ }; ++ ++ vgen2_reg: vgen2 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <1550000>; ++ }; ++ ++ vgen3_reg: vgen3 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ vgen4_reg: vgen4 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vgen5_reg: vgen5 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vgen6_reg: vgen6 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ }; ++ }; ++ ++ codec: cs42888@048 { ++ compatible = "cirrus,cs42888"; ++ reg = <0x048>; ++ clocks = <&codec_osc 0>; ++ clock-names = "codec_osc"; ++ VA-supply = <®_audio>; ++ VD-supply = <®_audio>; ++ VLS-supply = <®_audio>; ++ VLC-supply = <®_audio>; ++ }; ++ ++ hdmi: edid@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; ++ ++ si4763: si4763@63 { ++ compatible = "si4761"; ++ reg = <0x63>; ++ va-supply = <&si4763_va>; ++ vd-supply = <&si4763_vd>; ++ vio1-supply = <&si4763_vio1>; ++ vio2-supply = <&si4763_vio2>; ++ }; ++}; ++ ++&i2c3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3_4>; ++ pinctrl-assert-gpios = <&gpio5 4 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++ ++ max7310_a: gpio@30 { ++ compatible = "maxim,max7310"; ++ reg = <0x30>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ resets = <&max7310_reset>; ++ }; ++ ++ max7310_b: gpio@32 { ++ compatible = "maxim,max7310"; ++ reg = <0x32>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ max7310_c: gpio@34 { ++ compatible = "maxim,max7310"; ++ reg = <0x34>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ mma8451@1c { ++ compatible = "fsl,mma8451"; ++ reg = <0x1c>; ++ position = <3>; ++ }; ++ ++ mag3110@0e { ++ compatible = "fsl,mag3110"; ++ reg = <0x0e>; ++ position = <2>; ++ interrupt-parent = <&gpio2>; ++ interrupts = <29 2>; ++ }; ++ ++ isl29023@44 { ++ compatible = "fsl,isl29023"; ++ reg = <0x44>; ++ rext = <499>; ++ interrupt-parent = <&gpio5>; ++ interrupts = <17 2>; ++ }; ++ ++ adv7180: adv7180@21 { ++ compatible = "adv,adv7180"; ++ reg = <0x21>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ipu1_3>; ++ clocks = <&clks 201>; ++ clock-names = "csi_mclk"; ++ DOVDD-supply = <®_3p3v>; /* 3.3v, enabled via 2.8 VGEN6 */ ++ AVDD-supply = <®_3p3v>; /* 1.8v */ ++ DVDD-supply = <®_3p3v>; /* 1.8v */ ++ PVDD-supply = <®_3p3v>; /* 1.8v */ ++ pwn-gpios = <&max7310_b 2 0>; ++ csi_id = <0>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ cvbs = <1>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ hog { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000 ++ MX6QDL_PAD_SD2_DAT2__GPIO1_IO13 0x80000000 ++ MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x80000000 ++ MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x80000000 ++ MX6QDL_PAD_EIM_EB0__GPIO2_IO28 0x80000000 ++ MX6QDL_PAD_EIM_EB1__GPIO2_IO29 0x80000000 ++ MX6QDL_PAD_DISP0_DAT23__GPIO5_IO17 0x80000000 ++ MX6QDL_PAD_SD2_CMD__GPIO1_IO11 0x80000000 ++ MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x80000000 ++ MX6QDL_PAD_SD4_DAT4__GPIO2_IO12 0x80000000 ++ MX6QDL_PAD_SD4_DAT7__GPIO2_IO15 0x80000000 ++ MX6QDL_PAD_DISP0_DAT20__GPIO5_IO14 0x80000000 ++ MX6QDL_PAD_GPIO_18__SD3_VSELECT 0x17059 ++ >; ++ }; ++ }; ++ ++ ecspi1 { ++ pinctrl_ecspi1_sabreauto: ecspi1-sabreauto { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 ++ >; ++ }; ++ }; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_spdif_1>; ++ status = "okay"; ++}; ++ ++&ssi2 { ++ fsl,mode = "i2s-master"; ++ status = "okay"; ++}; ++ ++&uart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart3_1>; ++ pinctrl-assert-gpios = <&max7310_b 4 GPIO_ACTIVE_HIGH>, /* CTS */ ++ <&max7310_c 3 GPIO_ACTIVE_HIGH>; /* RXD and TXD */ ++ fsl,uart-has-rtscts; ++ status = "okay"; ++}; ++ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand_1>; ++ status = "disabled"; /* pin conflict with uart3 */ ++}; ++ + &uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4_1>; + status = "okay"; + }; + +-&usdhc3 { ++&usbh1 { ++ vbus-supply = <®_usb_h1_vbus>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg_2>; ++ imx6-usb-charger-detection; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3_1>; ++ pinctrl-1 = <&pinctrl_usdhc3_1_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc3_1_200mhz>; + cd-gpios = <&gpio6 15 0>; + wp-gpios = <&gpio1 13 0>; + status = "okay"; + }; ++ ++&weim { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_weim_nor_1 &pinctrl_weim_cs0_1>; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0 0 0x08000000 0x08000000>; ++ status = "disabled"; /* pin conflict with ecspi1, i2c3 and uart3 */ ++ ++ nor@0,0 { ++ compatible = "cfi-flash"; ++ reg = <0 0 0x02000000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ bank-width = <2>; ++ fsl,weim-cs-timing = <0x00620081 0x00000001 0x1c022000 ++ 0x0000c000 0x1404a38e 0x00000000>; ++ }; ++}; ++ ++&flexcan1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan1_1>; ++ pinctrl-assert-gpios = <&max7310_b 3 GPIO_ACTIVE_HIGH>; /* TX */ ++ trx-en-gpio = <&max7310_b 6 GPIO_ACTIVE_HIGH>; ++ trx-stby-gpio = <&max7310_b 5 GPIO_ACTIVE_HIGH>; ++ status = "disabled"; /* pin conflict with fec */ ++}; ++ ++&flexcan2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan2_1>; ++ trx-en-gpio = <&max7310_c 6 GPIO_ACTIVE_HIGH>; ++ trx-stby-gpio = <&max7310_c 5 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&ldb { ++ ipu_id = <1>; ++ disp_id = <0>; ++ ext_ref = <1>; ++ mode = "sep0"; ++ sec_ipu_id = <1>; ++ sec_disp_id = <1>; ++ status = "okay"; ++}; ++ ++&mipi_csi { ++ status = "okay"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ v_channel = <0>; ++ lanes = <1>; ++}; ++ ++&mlb { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_mlb_2>; ++ status = "okay"; ++}; ++ ++&pcie { ++ status = "okay"; ++}; ++ ++&pwm3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm3_1>; ++ status = "okay"; ++}; ++ ++&esai { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_esai_2>; ++ status = "okay"; ++}; ++ ++&hdmi_core { ++ ipu_id = <0>; ++ disp_id = <1>; ++ status = "okay"; ++}; ++ ++&hdmi_video { ++ fsl,phy_reg_vlev = <0x0294>; ++ fsl,phy_reg_cksymtx = <0x800d>; ++ status = "okay"; ++}; ++ ++&hdmi_audio { ++ status = "okay"; ++}; ++ ++&hdmi_cec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hdmi_cec_1>; ++ status = "okay"; ++}; ++ ++&gpc { ++ fsl,cpu_pupscr_sw2iso = <0xf>; ++ fsl,cpu_pupscr_sw = <0xf>; ++ fsl,cpu_pdnscr_iso2sw = <0x1>; ++ fsl,cpu_pdnscr_iso = <0x1>; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6qdl-sabresd.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx6qdl-sabresd.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl-sabresd.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -11,10 +11,30 @@ + */ + + / { ++ aliases { ++ mxcfb0 = &mxcfb1; ++ mxcfb1 = &mxcfb2; ++ mxcfb2 = &mxcfb3; ++ mxcfb3 = &mxcfb4; ++ }; ++ + memory { + reg = <0x10000000 0x40000000>; + }; + ++ battery: max8903@0 { ++ compatible = "fsl,max8903-charger"; ++ pinctrl-names = "default"; ++ dok_input = <&gpio2 24 1>; ++ uok_input = <&gpio1 27 1>; ++ chg_input = <&gpio3 23 1>; ++ flt_input = <&gpio5 2 1>; ++ fsl,dcm_always_high; ++ fsl,dc_valid; ++ fsl,usb_valid; ++ status = "okay"; ++ }; ++ + regulators { + compatible = "simple-bus"; + +@@ -26,29 +46,605 @@ + gpio = <&gpio3 22 0>; + enable-active-high; + }; ++ ++ reg_usb_h1_vbus: usb_h1_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 29 0>; ++ enable-active-high; ++ }; ++ ++ reg_usb_h1_vbus: usb_h1_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 29 0>; ++ enable-active-high; ++ }; ++ ++ reg_audio: wm8962_supply { ++ compatible = "regulator-fixed"; ++ regulator-name = "wm8962-supply"; ++ gpio = <&gpio4 10 0>; ++ enable-active-high; ++ }; ++ ++ reg_mipi_dsi_pwr_on: mipi_dsi_pwr_on { ++ compatible = "regulator-fixed"; ++ regulator-name = "mipi_dsi_pwr_on"; ++ gpio = <&gpio6 14 0>; ++ enable-active-high; ++ }; ++ ++ reg_sensor: sensor_supply { ++ compatible = "regulator-fixed"; ++ regulator-name = "sensor-supply"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio2 31 0>; ++ startup-delay-us = <500>; ++ enable-active-high; ++ }; + }; + + gpio-keys { + compatible = "gpio-keys"; ++ power { ++ label = "Power Button"; ++ gpios = <&gpio3 29 0>; ++ linux,code = <116>; /* KEY_POWER */ ++ gpio-key,wakeup; ++ }; + + volume-up { + label = "Volume Up"; + gpios = <&gpio1 4 0>; ++ gpio-key,wakeup; + linux,code = <115>; /* KEY_VOLUMEUP */ + }; + + volume-down { + label = "Volume Down"; + gpios = <&gpio1 5 0>; ++ gpio-key,wakeup; + linux,code = <114>; /* KEY_VOLUMEDOWN */ + }; + }; ++ ++ imx_drm: imx-drm { ++ compatible = "fsl,imx-drm"; ++ crtcs = <&ipu1 0>, <&ipu1 1>; ++ connectors = <&ldb>; ++ }; ++ ++ sound { ++ compatible = "fsl,imx6q-sabresd-wm8962", ++ "fsl,imx-audio-wm8962"; ++ model = "wm8962-audio"; ++ ssi-controller = <&ssi2>; ++ audio-codec = <&codec>; ++ audio-routing = ++ "Headphone Jack", "HPOUTL", ++ "Headphone Jack", "HPOUTR", ++ "Ext Spk", "SPKOUTL", ++ "Ext Spk", "SPKOUTR", ++ "MICBIAS", "AMIC", ++ "IN3R", "MICBIAS", ++ "DMIC", "MICBIAS", ++ "DMICDAT", "DMIC"; ++ mux-int-port = <2>; ++ mux-ext-port = <3>; ++ hp-det-gpios = <&gpio7 8 1>; ++ mic-det-gpios = <&gpio1 9 1>; ++ }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm1 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ status = "okay"; ++ }; ++ ++ sound-hdmi { ++ compatible = "fsl,imx6q-audio-hdmi", ++ "fsl,imx-audio-hdmi"; ++ model = "imx-audio-hdmi"; ++ hdmi-controller = <&hdmi_audio>; ++ }; ++ ++ mxcfb1: fb@0 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "ldb"; ++ interface_pix_fmt = "RGB666"; ++ mode_str ="LDB-XGA"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ mxcfb2: fb@1 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "hdmi"; ++ interface_pix_fmt = "RGB24"; ++ mode_str ="1920x1080M@60"; ++ default_bpp = <24>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ mxcfb3: fb@2 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "lcd"; ++ interface_pix_fmt = "RGB565"; ++ mode_str ="CLAA-WVGA"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ mxcfb4: fb@3 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "ldb"; ++ interface_pix_fmt = "RGB666"; ++ mode_str ="LDB-XGA"; ++ default_bpp = <16>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "disabled"; ++ }; ++ ++ lcd@0 { ++ compatible = "fsl,lcd"; ++ ipu_id = <0>; ++ disp_id = <0>; ++ default_ifmt = "RGB565"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ipu1_1>; ++ status = "okay"; ++ }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm1 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ }; ++ ++ v4l2_cap_0 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <0>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_cap_1 { ++ compatible = "fsl,imx6q-v4l2-capture"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ mclk_source = <0>; ++ status = "okay"; ++ }; ++ ++ v4l2_out { ++ compatible = "fsl,mxc_v4l2_output"; ++ status = "okay"; ++ }; ++ ++ lvds_cabc_ctrl { ++ lvds0-gpios = <&gpio6 15 0>; ++ lvds1-gpios = <&gpio6 16 0>; ++ }; ++ ++ mipi_dsi_reset: mipi-dsi-reset { ++ compatible = "gpio-reset"; ++ reset-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>; ++ reset-delay-us = <50>; ++ #reset-cells = <0>; ++ }; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux_2>; ++ status = "okay"; ++}; ++ ++&cpu0 { ++ arm-supply = <&sw1a_reg>; ++ soc-supply = <&sw1c_reg>; ++ pu-supply = <&pu_dummy>; /* use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&ecspi1 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio4 9 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi1_2>; ++ status = "okay"; ++ ++ flash: m25p80@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p32"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; + }; + + &fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_enet_1>; + phy-mode = "rgmii"; ++ phy-reset-gpios = <&gpio1 25 0>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1_2>; ++ status = "okay"; ++ ++ codec: wm8962@1a { ++ compatible = "wlf,wm8962"; ++ reg = <0x1a>; ++ clocks = <&clks 201>; ++ DCVDD-supply = <®_audio>; ++ DBVDD-supply = <®_audio>; ++ AVDD-supply = <®_audio>; ++ CPVDD-supply = <®_audio>; ++ MICVDD-supply = <®_audio>; ++ PLLVDD-supply = <®_audio>; ++ SPKVDD1-supply = <®_audio>; ++ SPKVDD2-supply = <®_audio>; ++ amic-mono; ++ gpio-cfg = < ++ 0x0000 /* 0:Default */ ++ 0x0000 /* 1:Default */ ++ 0x0013 /* 2:FN_DMICCLK */ ++ 0x0000 /* 3:Default */ ++ 0x8014 /* 4:FN_DMICCDAT */ ++ 0x0000 /* 5:Default */ ++ >; ++ }; ++ ++ ov564x: ov564x@3c { ++ compatible = "ovti,ov564x"; ++ reg = <0x3c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ipu1_2>; ++ clocks = <&clks 201>; ++ clock-names = "csi_mclk"; ++ DOVDD-supply = <&vgen4_reg>; /* 1.8v */ ++ AVDD-supply = <&vgen3_reg>; /* 2.8v, on rev C board is VGEN3, ++ on rev B board is VGEN5 */ ++ DVDD-supply = <&vgen2_reg>; /* 1.5v*/ ++ pwn-gpios = <&gpio1 16 1>; /* active low: SD1_DAT0 */ ++ rst-gpios = <&gpio1 17 0>; /* active high: SD1_DAT1 */ ++ csi_id = <0>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ }; ++ ++ mma8451@1c { ++ compatible = "fsl,mma8451"; ++ reg = <0x1c>; ++ position = <1>; ++ vdd-supply = <®_sensor>; ++ vddio-supply = <®_sensor>; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3_2>; ++ status = "okay"; ++ ++ egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ interrupt-parent = <&gpio6>; ++ interrupts = <7 2>; ++ wakeup-gpios = <&gpio6 7 0>; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2_2>; ++ status = "okay"; ++ ++ hdmi: edid@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; ++ ++ max11801@48 { ++ compatible = "maxim,max11801"; ++ reg = <0x48>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <26 2>; ++ work-mode = <1>;/*DCM mode*/ ++ }; ++ ++ ov5640_mipi: ov5640_mipi@3c { /* i2c2 driver */ ++ compatible = "ovti,ov5640_mipi"; ++ reg = <0x3c>; ++ clocks = <&clks 201>; ++ clock-names = "csi_mclk"; ++ DOVDD-supply = <&vgen4_reg>; /* 1.8v */ ++ AVDD-supply = <&vgen3_reg>; /* 2.8v, rev C board is VGEN3 ++ rev B board is VGEN5 */ ++ DVDD-supply = <&vgen2_reg>; /* 1.5v*/ ++ pwn-gpios = <&gpio1 19 1>; /* active low: SD1_CLK */ ++ rst-gpios = <&gpio1 20 0>; /* active high: SD1_DAT2 */ ++ csi_id = <1>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ }; ++ ++ pmic: pfuze100@08 { ++ compatible = "fsl,pfuze100"; ++ reg = <0x08>; ++ ++ regulators { ++ sw1a_reg: sw1ab { ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1875000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-ramp-delay = <6250>; ++ }; ++ ++ sw1c_reg: sw1c { ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1875000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-ramp-delay = <6250>; ++ }; ++ ++ sw2_reg: sw2 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw3a_reg: sw3a { ++ regulator-min-microvolt = <400000>; ++ regulator-max-microvolt = <1975000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw3b_reg: sw3b { ++ regulator-min-microvolt = <400000>; ++ regulator-max-microvolt = <1975000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw4_reg: sw4 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ swbst_reg: swbst { ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5150000>; ++ }; ++ ++ snvs_reg: vsnvs { ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <3000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vref_reg: vrefddr { ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vgen1_reg: vgen1 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <1550000>; ++ }; ++ ++ vgen2_reg: vgen2 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <1550000>; ++ }; ++ ++ vgen3_reg: vgen3 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ vgen4_reg: vgen4 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vgen5_reg: vgen5 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vgen6_reg: vgen6 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ }; ++ }; ++ ++ egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ interrupt-parent = <&gpio6>; ++ interrupts = <8 2>; ++ wakeup-gpios = <&gpio6 8 0>; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3_2>; ++ status = "okay"; ++ ++ egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ interrupt-parent = <&gpio6>; ++ interrupts = <7 2>; ++ wakeup-gpios = <&gpio6 7 0>; ++ }; ++ ++ mag3110@0e { ++ compatible = "fsl,mag3110"; ++ reg = <0x0e>; ++ position = <2>; ++ vdd-supply = <®_sensor>; ++ vddio-supply = <®_sensor>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <16 2>; ++ }; ++ ++ elan@10 { ++ compatible = "elan,elan-touch"; ++ reg = <0x10>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <28 3>; ++ gpio_elan_cs = <&gpio2 18 0>; ++ gpio_elan_rst = <&gpio3 8 0>; ++ gpio_intr = <&gpio3 28 0>; ++ status = "okay"; ++ }; ++ ++ isl29023@44 { ++ compatible = "fsl,isl29023"; ++ reg = <0x44>; ++ rext = <499>; ++ vdd-supply = <®_sensor>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <9 2>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog_1>; ++ ++ hog { ++ pinctrl_hog_1: hoggrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x80000000 ++ MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x80000000 ++ MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x80000000 ++ MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x80000000 ++ MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x80000000 ++ MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x80000000 ++ MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x80000000 ++ MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x80000000 ++ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 ++ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000 ++ MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x80000000 ++ MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x80000000 ++ MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x80000000 ++ MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 ++ MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x80000000 ++ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 ++ MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x80000000 ++ MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 ++ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 ++ MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x80000000 ++ MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x80000000 ++ MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x80000000 ++ MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x80000000 ++ MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000 ++ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x80000000 ++ MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x80000000 ++ MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x80000000 ++ MX6QDL_PAD_SD3_RST__GPIO7_IO08 0x80000000 ++ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x80000000 ++ MX6QDL_PAD_GPIO_1__WDOG2_B 0x80000000 ++ MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x80000000 ++ >; ++ }; ++ }; ++}; ++ ++&ldb { ++ status = "okay"; ++ ++ lvds-channel@1 { ++ fsl,data-mapping = "spwg"; ++ fsl,data-width = <18>; ++ status = "okay"; ++ ++ display-timings { ++ native-mode = <&timing0>; ++ timing0: hsd100pxn1 { ++ clock-frequency = <65000000>; ++ hactive = <1024>; ++ vactive = <768>; ++ hback-porch = <220>; ++ hfront-porch = <40>; ++ vback-porch = <21>; ++ vfront-porch = <7>; ++ hsync-len = <60>; ++ vsync-len = <10>; ++ }; ++ }; ++ }; ++}; ++ ++&pwm1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm0_1>; ++ status = "okay"; ++}; ++ ++&ldb { ++ ipu_id = <1>; ++ disp_id = <1>; ++ ext_ref = <1>; ++ mode = "sep1"; ++ sec_ipu_id = <1>; ++ sec_disp_id = <0>; ++ status = "okay"; ++}; ++ ++&pcie { ++ power-on-gpio = <&gpio3 19 0>; ++ reset-gpio = <&gpio7 12 0>; ++ status = "okay"; ++}; ++ ++ ++&pwm1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm1_1>; ++ status = "okay"; ++}; ++ ++&ssi2 { ++ fsl,mode = "i2s-slave"; + status = "okay"; + }; + +@@ -58,7 +654,25 @@ + status = "okay"; + }; + ++&mipi_csi { ++ status = "okay"; ++ ipu_id = <0>; ++ csi_id = <1>; ++ v_channel = <0>; ++ lanes = <2>; ++}; ++ ++&mipi_dsi { ++ dev_id = <0>; ++ disp_id = <0>; ++ lcd_panel = "TRULY-WVGA"; ++ disp-power-on-supply = <®_mipi_dsi_pwr_on>; ++ resets = <&mipi_dsi_reset>; ++ status = "okay"; ++}; ++ + &usbh1 { ++ vbus-supply = <®_usb_h1_vbus>; + status = "okay"; + }; + +@@ -73,15 +687,68 @@ + &usdhc2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc2_1>; ++ bus-width = <8>; + cd-gpios = <&gpio2 2 0>; + wp-gpios = <&gpio2 3 0>; ++ no-1-8-v; + status = "okay"; + }; + + &usdhc3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc3_1>; ++ bus-width = <8>; + cd-gpios = <&gpio2 0 0>; + wp-gpios = <&gpio2 1 0>; ++ no-1-8-v; ++ status = "okay"; ++}; ++ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4_1>; ++ bus-width = <8>; ++ non-removable; ++ no-1-8-v; ++ status = "okay"; ++}; ++ ++&vpu { ++ pu-supply = <&pu_dummy>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&hdmi_core { ++ ipu_id = <0>; ++ disp_id = <0>; ++ status = "okay"; ++}; ++ ++&hdmi_video { ++ fsl,phy_reg_vlev = <0x0294>; ++ fsl,phy_reg_cksymtx = <0x800d>; ++ status = "okay"; ++}; ++ ++&hdmi_audio { ++ status = "okay"; ++}; ++ ++&hdmi_cec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hdmi_cec_2>; + status = "okay"; + }; ++ ++&gpc { ++ fsl,cpu_pupscr_sw2iso = <0xf>; ++ fsl,cpu_pupscr_sw = <0xf>; ++ fsl,cpu_pdnscr_iso2sw = <0x1>; ++ fsl,cpu_pdnscr_iso = <0x1>; ++ fsl,ldo-bypass = <1>; /* use ldo-bypass, u-boot will check it and configure */ ++ fsl,wdog-reset = <2>; /* watchdog select of reset source */ ++ pu-supply = <&pu_dummy>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&gpu { ++ pu-supply = <&pu_dummy>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6qdl.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx6qdl.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6qdl.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -11,14 +11,12 @@ + */ + + #include "skeleton.dtsi" ++#include + + / { + aliases { +- serial0 = &uart1; +- serial1 = &uart2; +- serial2 = &uart3; +- serial3 = &uart4; +- serial4 = &uart5; ++ flexcan0 = &flexcan1; ++ flexcan1 = &flexcan2; + gpio0 = &gpio1; + gpio1 = &gpio2; + gpio2 = &gpio3; +@@ -26,6 +24,21 @@ + gpio4 = &gpio5; + gpio5 = &gpio6; + gpio6 = &gpio7; ++ i2c0 = &i2c1; ++ i2c1 = &i2c2; ++ i2c2 = &i2c3; ++ ipu0 = &ipu1; ++ serial0 = &uart1; ++ serial1 = &uart2; ++ serial2 = &uart3; ++ serial3 = &uart4; ++ serial4 = &uart5; ++ spi0 = &ecspi1; ++ spi1 = &ecspi2; ++ spi2 = &ecspi3; ++ spi3 = &ecspi4; ++ usbphy0 = &usbphy1; ++ usbphy1 = &usbphy2; + }; + + intc: interrupt-controller@00a01000 { +@@ -58,6 +71,10 @@ + }; + }; + ++ pu_dummy: pudummy_reg { ++ compatible = "fsl,imx6-dummy-pureg"; /* only used in ldo-bypass */ ++ }; ++ + soc { + #address-cells = <1>; + #size-cells = <1>; +@@ -65,6 +82,11 @@ + interrupt-parent = <&intc>; + ranges; + ++ caam_sm: caam-sm@00100000 { ++ compatible = "fsl,imx6q-caam-sm"; ++ reg = <0x00100000 0x3fff>; ++ }; ++ + dma_apbh: dma-apbh@00110000 { + compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh"; + reg = <0x00110000 0x2000>; +@@ -75,24 +97,35 @@ + clocks = <&clks 106>; + }; + ++ irq_sec_vio: caam_secvio { ++ compatible = "fsl,imx6q-caam-secvio"; ++ interrupts = <0 20 0x04>; ++ secvio_src = <0x8000001d>; ++ }; ++ + gpmi: gpmi-nand@00112000 { + compatible = "fsl,imx6q-gpmi-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x00112000 0x2000>, <0x00114000 0x2000>; + reg-names = "gpmi-nand", "bch"; +- interrupts = <0 13 0x04>, <0 15 0x04>; +- interrupt-names = "gpmi-dma", "bch"; ++ interrupts = <0 15 0x04>; ++ interrupt-names = "bch"; + clocks = <&clks 152>, <&clks 153>, <&clks 151>, + <&clks 150>, <&clks 149>; + clock-names = "gpmi_io", "gpmi_apb", "gpmi_bch", + "gpmi_bch_apb", "per1_bch"; + dmas = <&dma_apbh 0>; + dma-names = "rx-tx"; +- fsl,gpmi-dma-channel = <0>; + status = "disabled"; + }; + ++ ocram: sram@00900000 { ++ compatible = "mmio-sram"; ++ reg = <0x00900000 0x3f000>; ++ clocks = <&clks 142>; ++ }; ++ + timer@00a00600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0x00a00600 0x20>; +@@ -106,6 +139,24 @@ + interrupts = <0 92 0x04>; + cache-unified; + cache-level = <2>; ++ arm,tag-latency = <4 2 3>; ++ arm,data-latency = <4 2 3>; ++ }; ++ ++ pcie: pcie@0x01000000 { ++ compatible = "fsl,imx6q-pcie", "snps,dw-pcie"; ++ reg = <0x01ffc000 0x4000>; /* DBI */ ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000 /* configuration space */ ++ 0x81000000 0 0 0x01f80000 0 0x00010000 /* downstream I/O */ ++ 0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */ ++ num-lanes = <1>; ++ interrupts = <0 123 0x04>; ++ clocks = <&clks 189>, <&clks 187>, <&clks 144>, <&clks 212>; ++ clock-names = "pcie_ref_125m", "sata_ref_100m", "pcie_axi", "lvds_gate"; ++ status = "disabled"; + }; + + pmu { +@@ -128,8 +179,24 @@ + ranges; + + spdif: spdif@02004000 { ++ compatible = "fsl,imx6q-spdif", ++ "fsl,imx35-spdif"; + reg = <0x02004000 0x4000>; + interrupts = <0 52 0x04>; ++ dmas = <&sdma 14 18 0>, ++ <&sdma 15 18 0>; ++ dma-names = "rx", "tx"; ++ clocks = <&clks 197>, <&clks 3>, ++ <&clks 197>, <&clks 107>, ++ <&clks 0>, <&clks 118>, ++ <&clks 0>, <&clks 139>, ++ <&clks 0>, <&clks 156>; ++ clock-names = "core", "rxtx0", ++ "rxtx1", "rxtx2", ++ "rxtx3", "rxtx4", ++ "rxtx5", "rxtx6", ++ "rxtx7", "dma"; ++ status = "disabled"; + }; + + ecspi1: ecspi@02008000 { +@@ -182,19 +249,31 @@ + interrupts = <0 26 0x04>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; ++ dmas = <&sdma 25 4 0>, <&sdma 26 4 0>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + + esai: esai@02024000 { ++ compatible = "fsl,imx6q-esai"; + reg = <0x02024000 0x4000>; + interrupts = <0 51 0x04>; ++ clocks = <&clks 118>, <&clks 156>; ++ clock-names = "core", "dma"; ++ fsl,esai-dma-events = <24 23>; ++ fsl,flags = <1>; ++ status = "disabled"; + }; + + ssi1: ssi@02028000 { + compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + reg = <0x02028000 0x4000>; + interrupts = <0 46 0x04>; +- clocks = <&clks 178>; ++ clocks = <&clks 178>, <&clks 157>; ++ clock-names = "ipg", "baud"; ++ dmas = <&sdma 37 1 0>, ++ <&sdma 38 1 0>; ++ dma-names = "rx", "tx"; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <38 37>; + status = "disabled"; +@@ -204,7 +283,11 @@ + compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + reg = <0x0202c000 0x4000>; + interrupts = <0 47 0x04>; +- clocks = <&clks 179>; ++ clocks = <&clks 179>, <&clks 158>; ++ clock-names = "ipg", "baud"; ++ dmas = <&sdma 41 1 0>, ++ <&sdma 42 1 0>; ++ dma-names = "rx", "tx"; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <42 41>; + status = "disabled"; +@@ -214,15 +297,36 @@ + compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; + reg = <0x02030000 0x4000>; + interrupts = <0 48 0x04>; +- clocks = <&clks 180>; ++ clocks = <&clks 180>, <&clks 159>; ++ clock-names = "ipg", "baud"; ++ dmas = <&sdma 45 1 0>, ++ <&sdma 46 1 0>; ++ dma-names = "rx", "tx"; + fsl,fifo-depth = <15>; + fsl,ssi-dma-events = <46 45>; + status = "disabled"; + }; + + asrc: asrc@02034000 { ++ compatible = "fsl,imx53-asrc"; + reg = <0x02034000 0x4000>; + interrupts = <0 50 0x04>; ++ clocks = <&clks 107>, <&clks 156>; ++ clock-names = "core", "dma"; ++ dmas = <&sdma 17 20 1>, <&sdma 18 20 1>, <&sdma 19 20 1>, ++ <&sdma 20 20 1>, <&sdma 21 20 1>, <&sdma 22 20 1>; ++ dma-names = "rxa", "rxb", "rxc", ++ "txa", "txb", "txc"; ++ status = "okay"; ++ }; ++ ++ asrc_p2p: asrc_p2p { ++ compatible = "fsl,imx6q-asrc-p2p"; ++ fsl,output-rate = <48000>; ++ fsl,output-width = <16>; ++ fsl,asrc-dma-rx-events = <17 18 19>; ++ fsl,asrc-dma-tx-events = <20 21 22>; ++ status = "okay"; + }; + + spba@0203c000 { +@@ -231,8 +335,18 @@ + }; + + vpu: vpu@02040000 { ++ compatible = "fsl,imx6-vpu"; + reg = <0x02040000 0x3c000>; +- interrupts = <0 3 0x04 0 12 0x04>; ++ reg-names = "vpu_regs"; ++ interrupts = <0 3 0x01>, <0 12 0x04>; ++ interrupt-names = "vpu_jpu_irq", "vpu_ipi_irq"; ++ clocks = <&clks 168>, <&clks 140>, <&clks 142>; ++ clock-names = "vpu_clk", "mmdc_ch0_axi", "ocram"; ++ iramsize = <0x21000>; ++ iram = <&ocram>; ++ resets = <&src 1>; ++ pu-supply = <®_pu>; ++ status = "disabled"; + }; + + aipstz@0207c000 { /* AIPSTZ1 */ +@@ -275,18 +389,28 @@ + clock-names = "ipg", "per"; + }; + +- can1: flexcan@02090000 { ++ flexcan1: flexcan@02090000 { ++ compatible = "fsl,imx6q-flexcan"; + reg = <0x02090000 0x4000>; + interrupts = <0 110 0x04>; ++ clocks = <&clks 108>, <&clks 109>; ++ clock-names = "ipg", "per"; ++ gpr = <&gpr>; ++ status = "disabled"; + }; + +- can2: flexcan@02094000 { ++ flexcan2: flexcan@02094000 { ++ compatible = "fsl,imx6q-flexcan"; + reg = <0x02094000 0x4000>; + interrupts = <0 111 0x04>; ++ clocks = <&clks 110>, <&clks 111>; ++ clock-names = "ipg", "per"; ++ gpr = <&gpr>; ++ status = "disabled"; + }; + + gpt: gpt@02098000 { +- compatible = "fsl,imx6q-gpt"; ++ compatible = "fsl,imx6q-gpt", "fsl,imx31-gpt"; + reg = <0x02098000 0x4000>; + interrupts = <0 55 0x04>; + clocks = <&clks 119>, <&clks 120>; +@@ -459,7 +583,6 @@ + regulator-name = "vddpu"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1450000>; +- regulator-always-on; + anatop-reg-offset = <0x140>; + anatop-vol-bit-shift = <9>; + anatop-vol-bit-width = <5>; +@@ -489,11 +612,20 @@ + }; + }; + ++ tempmon: tempmon { ++ compatible = "fsl,imx6q-tempmon"; ++ interrupts = <0 49 0x04>; ++ fsl,tempmon = <&anatop>; ++ fsl,tempmon-data = <&ocotp>; ++ clocks = <&clks 172>; ++ }; ++ + usbphy1: usbphy@020c9000 { + compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; + reg = <0x020c9000 0x1000>; + interrupts = <0 44 0x04>; + clocks = <&clks 182>; ++ fsl,anatop = <&anatop>; + }; + + usbphy2: usbphy@020ca000 { +@@ -501,6 +633,12 @@ + reg = <0x020ca000 0x1000>; + interrupts = <0 45 0x04>; + clocks = <&clks 183>; ++ fsl,anatop = <&anatop>; ++ }; ++ ++ caam_snvs: caam-snvs@020cc000 { ++ compatible = "fsl,imx6q-caam-snvs"; ++ reg = <0x020cc000 0x4000>; + }; + + snvs@020cc000 { +@@ -537,6 +675,11 @@ + compatible = "fsl,imx6q-gpc"; + reg = <0x020dc000 0x4000>; + interrupts = <0 89 0x04 0 90 0x04>; ++ clocks = <&clks 122>, <&clks 74>, <&clks 121>, ++ <&clks 26>, <&clks 143>, <&clks 168>, <&clks 62>; ++ clock-names = "gpu3d_core", "gpu3d_shader", "gpu2d_core", ++ "gpu2d_axi", "openvg_axi", "vpu_axi", "ipg"; ++ pu-supply = <®_pu>; + }; + + gpr: iomuxc-gpr@020e0000 { +@@ -544,24 +687,775 @@ + reg = <0x020e0000 0x38>; + }; + ++ iomuxc: iomuxc@020e0000 { ++ compatible = "fsl,imx6dl-iomuxc", "fsl,imx6q-iomuxc"; ++ reg = <0x020e0000 0x4000>; ++ ++ audmux { ++ pinctrl_audmux_1: audmux-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 ++ MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 ++ MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x130b0 ++ MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 ++ >; ++ }; ++ ++ pinctrl_audmux_2: audmux-2 { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 ++ MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 ++ MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x130b0 ++ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 ++ >; ++ }; ++ ++ pinctrl_audmux_3: audmux-3 { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT16__AUD5_TXC 0x130b0 ++ MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS 0x130b0 ++ MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 ++ >; ++ }; ++ }; ++ ++ ecspi1 { ++ pinctrl_ecspi1_1: ecspi1grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 ++ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 ++ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 ++ >; ++ }; ++ ++ pinctrl_ecspi1_2: ecspi1grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x100b1 ++ MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x100b1 ++ MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x100b1 ++ >; ++ }; ++ }; ++ ++ ecspi3 { ++ pinctrl_ecspi3_1: ecspi3grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 ++ MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 ++ MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 ++ >; ++ }; ++ }; ++ ++ enet { ++ pinctrl_enet_1: enetgrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 ++ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 ++ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 ++ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 ++ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_enet_2: enetgrp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL1__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_KEY_COL2__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 ++ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 ++ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 ++ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 ++ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_enet_3: enetgrp-3 { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0 ++ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0 ++ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0 ++ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0 ++ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 ++ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0 ++ MX6QDL_PAD_ENET_TX_EN__ENET_TX_EN 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ esai { ++ pinctrl_esai_1: esaigrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_RXD0__ESAI_TX_HF_CLK 0x1b030 ++ MX6QDL_PAD_ENET_CRS_DV__ESAI_TX_CLK 0x1b030 ++ MX6QDL_PAD_ENET_RXD1__ESAI_TX_FS 0x1b030 ++ MX6QDL_PAD_ENET_TX_EN__ESAI_TX3_RX2 0x1b030 ++ MX6QDL_PAD_ENET_TXD1__ESAI_TX2_RX3 0x1b030 ++ MX6QDL_PAD_ENET_TXD0__ESAI_TX4_RX1 0x1b030 ++ MX6QDL_PAD_ENET_MDC__ESAI_TX5_RX0 0x1b030 ++ MX6QDL_PAD_NANDF_CS2__ESAI_TX0 0x1b030 ++ MX6QDL_PAD_NANDF_CS3__ESAI_TX1 0x1b030 ++ >; ++ }; ++ ++ pinctrl_esai_2: esaigrp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_CRS_DV__ESAI_TX_CLK 0x1b030 ++ MX6QDL_PAD_ENET_RXD1__ESAI_TX_FS 0x1b030 ++ MX6QDL_PAD_ENET_TX_EN__ESAI_TX3_RX2 0x1b030 ++ MX6QDL_PAD_GPIO_5__ESAI_TX2_RX3 0x1b030 ++ MX6QDL_PAD_ENET_TXD0__ESAI_TX4_RX1 0x1b030 ++ MX6QDL_PAD_ENET_MDC__ESAI_TX5_RX0 0x1b030 ++ MX6QDL_PAD_GPIO_17__ESAI_TX0 0x1b030 ++ MX6QDL_PAD_NANDF_CS3__ESAI_TX1 0x1b030 ++ MX6QDL_PAD_ENET_MDIO__ESAI_RX_CLK 0x1b030 ++ MX6QDL_PAD_GPIO_9__ESAI_RX_FS 0x1b030 ++ >; ++ }; ++ }; ++ ++ flexcan1 { ++ pinctrl_flexcan1_1: flexcan1grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x80000000 ++ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x80000000 ++ >; ++ }; ++ ++ pinctrl_flexcan1_2: flexcan1grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_7__FLEXCAN1_TX 0x80000000 ++ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x80000000 ++ >; ++ }; ++ }; ++ ++ flexcan2 { ++ pinctrl_flexcan2_1: flexcan2grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL4__FLEXCAN2_TX 0x80000000 ++ MX6QDL_PAD_KEY_ROW4__FLEXCAN2_RX 0x80000000 ++ >; ++ }; ++ }; ++ ++ gpmi-nand { ++ pinctrl_gpmi_nand_1: gpmi-nand-1 { ++ fsl,pins = < ++ MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 ++ MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1 ++ MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1 ++ MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000 ++ MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1 ++ MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1 ++ MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1 ++ MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1 ++ MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1 ++ MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1 ++ MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1 ++ MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1 ++ MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1 ++ MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1 ++ MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1 ++ MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1 ++ MX6QDL_PAD_SD4_DAT0__NAND_DQS 0x00b1 ++ >; ++ }; ++ }; ++ ++ hdmi_hdcp { ++ pinctrl_hdmi_hdcp_1: hdmihdcpgrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__HDMI_TX_DDC_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_hdmi_hdcp_2: hdmihdcpgrp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_EB2__HDMI_TX_DDC_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D16__HDMI_TX_DDC_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_hdmi_hdcp_3: hdmihdcpgrp-3 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_EB2__HDMI_TX_DDC_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ hdmi_cec { ++ pinctrl_hdmi_cec_1: hdmicecgrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_A25__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ ++ pinctrl_hdmi_cec_2: hdmicecgrp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ }; ++ ++ i2c1 { ++ pinctrl_i2c1_1: i2c1grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c1_2: i2c1grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 ++ MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ i2c2 { ++ pinctrl_i2c2_1: i2c2grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c2_2: i2c2grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c2_3: i2c2grp-3 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ i2c3 { ++ pinctrl_i2c3_1: i2c3grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3_2: i2c3grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3_3: i2c3grp-3 { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3_4: i2c3grp-4 { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ ipu1 { ++ pinctrl_ipu1_1: ipu1grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10 ++ MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10 ++ MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10 ++ MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10 ++ MX6QDL_PAD_DI0_PIN4__IPU1_DI0_PIN04 0x80000000 ++ MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10 ++ MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10 ++ MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10 ++ MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10 ++ MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10 ++ MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10 ++ MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10 ++ MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10 ++ MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10 ++ MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10 ++ MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10 ++ MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10 ++ MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10 ++ MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10 ++ MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10 ++ MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10 ++ MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10 ++ MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10 ++ MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10 ++ MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10 ++ MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10 ++ MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10 ++ MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10 ++ MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10 ++ >; ++ }; ++ ++ pinctrl_ipu1_2: ipu1grp-2 { /* parallel camera */ ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x80000000 ++ MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x80000000 ++ MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x80000000 ++ MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x80000000 ++ MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x80000000 ++ MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x80000000 ++ MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x80000000 ++ MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x80000000 ++ MX6QDL_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN 0x80000000 ++ MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x80000000 ++ MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x80000000 ++ MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x80000000 ++ >; ++ }; ++ ++ pinctrl_ipu1_3: ipu1grp-3 { /* parallel port 16-bit */ ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT4__IPU1_CSI0_DATA04 0x80000000 ++ MX6QDL_PAD_CSI0_DAT5__IPU1_CSI0_DATA05 0x80000000 ++ MX6QDL_PAD_CSI0_DAT6__IPU1_CSI0_DATA06 0x80000000 ++ MX6QDL_PAD_CSI0_DAT7__IPU1_CSI0_DATA07 0x80000000 ++ MX6QDL_PAD_CSI0_DAT8__IPU1_CSI0_DATA08 0x80000000 ++ MX6QDL_PAD_CSI0_DAT9__IPU1_CSI0_DATA09 0x80000000 ++ MX6QDL_PAD_CSI0_DAT10__IPU1_CSI0_DATA10 0x80000000 ++ MX6QDL_PAD_CSI0_DAT11__IPU1_CSI0_DATA11 0x80000000 ++ MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x80000000 ++ MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x80000000 ++ MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x80000000 ++ MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x80000000 ++ MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x80000000 ++ MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x80000000 ++ MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x80000000 ++ MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x80000000 ++ MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x80000000 ++ MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x80000000 ++ MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x80000000 ++ >; ++ }; ++ }; ++ ++ mlb { ++ pinctrl_mlb_1: mlbgrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__MLB_CLK 0x71 ++ MX6QDL_PAD_GPIO_6__MLB_SIG 0x71 ++ MX6QDL_PAD_GPIO_2__MLB_DATA 0x71 ++ >; ++ }; ++ ++ pinctrl_mlb_2: mlbgrp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_TXD1__MLB_CLK 0x80000000 ++ MX6QDL_PAD_GPIO_6__MLB_SIG 0x80000000 ++ MX6QDL_PAD_GPIO_2__MLB_DATA 0x80000000 ++ >; ++ }; ++ }; ++ ++ pwm1 { ++ pinctrl_pwm1_1: pwm1grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ pwm3 { ++ pinctrl_pwm3_1: pwm3grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ spdif { ++ pinctrl_spdif_1: spdifgrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_spdif_2: spdifgrp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_16__SPDIF_IN 0x1b0b0 ++ MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_spdif_3: spdifgrp-3 { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_RXD0__SPDIF_OUT 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ uart1 { ++ pinctrl_uart1_1: uart1grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ uart2 { ++ pinctrl_uart2_1: uart2grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2_2: uart2grp-2 { /* DTE mode */ ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D26__UART2_RX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D27__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D28__UART2_DTE_CTS_B 0x1b0b1 ++ MX6QDL_PAD_EIM_D29__UART2_DTE_RTS_B 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ uart3 { ++ pinctrl_uart3_1: uart3grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_CLK__UART3_RX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD4_CMD__UART3_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D30__UART3_CTS_B 0x1b0b1 ++ MX6QDL_PAD_EIM_EB3__UART3_RTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart3_2: uart3grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b1 ++ MX6QDL_PAD_EIM_EB3__UART3_RTS_B 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ uart4 { ++ pinctrl_uart4_1: uart4grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ usbotg { ++ pinctrl_usbotg_1: usbotggrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg_2: usbotggrp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 ++ >; ++ }; ++ }; ++ ++ usbh2 { ++ pinctrl_usbh2_1: usbh2grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_RGMII_TXC__USB_H2_DATA 0x40013030 ++ MX6QDL_PAD_RGMII_TX_CTL__USB_H2_STROBE 0x40013030 ++ >; ++ }; ++ ++ pinctrl_usbh2_2: usbh2grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_RGMII_TX_CTL__USB_H2_STROBE 0x40017030 ++ >; ++ }; ++ }; ++ ++ usbh3 { ++ pinctrl_usbh3_1: usbh3grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_RGMII_RX_CTL__USB_H3_DATA 0x40013030 ++ MX6QDL_PAD_RGMII_RXC__USB_H3_STROBE 0x40013030 ++ >; ++ }; ++ ++ pinctrl_usbh3_2: usbh3grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_RGMII_RXC__USB_H3_STROBE 0x40017030 ++ >; ++ }; ++ }; ++ ++ usdhc1 { ++ pinctrl_usdhc1_1: usdhc1grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 ++ MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 ++ MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 ++ MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 ++ MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 ++ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 ++ MX6QDL_PAD_NANDF_D0__SD1_DATA4 0x17059 ++ MX6QDL_PAD_NANDF_D1__SD1_DATA5 0x17059 ++ MX6QDL_PAD_NANDF_D2__SD1_DATA6 0x17059 ++ MX6QDL_PAD_NANDF_D3__SD1_DATA7 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc1_2: usdhc1grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059 ++ MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059 ++ MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059 ++ MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059 ++ MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059 ++ MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059 ++ >; ++ }; ++ }; ++ ++ usdhc2 { ++ pinctrl_usdhc2_1: usdhc2grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 ++ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 ++ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 ++ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 ++ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 ++ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 ++ MX6QDL_PAD_NANDF_D4__SD2_DATA4 0x17059 ++ MX6QDL_PAD_NANDF_D5__SD2_DATA5 0x17059 ++ MX6QDL_PAD_NANDF_D6__SD2_DATA6 0x17059 ++ MX6QDL_PAD_NANDF_D7__SD2_DATA7 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc2_2: usdhc2grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059 ++ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059 ++ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059 ++ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059 ++ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059 ++ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059 ++ >; ++ }; ++ }; ++ ++ usdhc3 { ++ pinctrl_usdhc3_1: usdhc3grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 ++ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 ++ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 ++ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 ++ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 ++ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 ++ MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x17059 ++ MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x17059 ++ MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x17059 ++ MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz { /* 100Mhz */ ++ fsl,pins = < ++ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170b9 ++ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100b9 ++ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 ++ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 ++ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 ++ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 ++ MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170b9 ++ MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170b9 ++ MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170b9 ++ MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz { /* 200Mhz */ ++ fsl,pins = < ++ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x170f9 ++ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x100f9 ++ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 ++ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 ++ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 ++ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 ++ MX6QDL_PAD_SD3_DAT4__SD3_DATA4 0x170f9 ++ MX6QDL_PAD_SD3_DAT5__SD3_DATA5 0x170f9 ++ MX6QDL_PAD_SD3_DAT6__SD3_DATA6 0x170f9 ++ MX6QDL_PAD_SD3_DAT7__SD3_DATA7 0x170f9 ++ >; ++ }; ++ ++ pinctrl_usdhc3_2: usdhc3grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059 ++ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059 ++ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059 ++ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059 ++ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059 ++ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059 ++ >; ++ }; ++ }; ++ ++ usdhc4 { ++ pinctrl_usdhc4_1: usdhc4grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 ++ MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 ++ MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 ++ MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 ++ MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 ++ MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 ++ MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 ++ MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 ++ MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 ++ MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc4_2: usdhc4grp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 ++ MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 ++ MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 ++ MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 ++ MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 ++ MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 ++ >; ++ }; ++ }; ++ ++ weim { ++ pinctrl_weim_cs0_1: weim_cs0grp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_CS0__EIM_CS0_B 0xb0b1 ++ >; ++ }; ++ ++ pinctrl_weim_nor_1: weim_norgrp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_OE__EIM_OE_B 0xb0b1 ++ MX6QDL_PAD_EIM_RW__EIM_RW 0xb0b1 ++ MX6QDL_PAD_EIM_WAIT__EIM_WAIT_B 0xb060 ++ /* data */ ++ MX6QDL_PAD_EIM_D16__EIM_DATA16 0x1b0b0 ++ MX6QDL_PAD_EIM_D17__EIM_DATA17 0x1b0b0 ++ MX6QDL_PAD_EIM_D18__EIM_DATA18 0x1b0b0 ++ MX6QDL_PAD_EIM_D19__EIM_DATA19 0x1b0b0 ++ MX6QDL_PAD_EIM_D20__EIM_DATA20 0x1b0b0 ++ MX6QDL_PAD_EIM_D21__EIM_DATA21 0x1b0b0 ++ MX6QDL_PAD_EIM_D22__EIM_DATA22 0x1b0b0 ++ MX6QDL_PAD_EIM_D23__EIM_DATA23 0x1b0b0 ++ MX6QDL_PAD_EIM_D24__EIM_DATA24 0x1b0b0 ++ MX6QDL_PAD_EIM_D25__EIM_DATA25 0x1b0b0 ++ MX6QDL_PAD_EIM_D26__EIM_DATA26 0x1b0b0 ++ MX6QDL_PAD_EIM_D27__EIM_DATA27 0x1b0b0 ++ MX6QDL_PAD_EIM_D28__EIM_DATA28 0x1b0b0 ++ MX6QDL_PAD_EIM_D29__EIM_DATA29 0x1b0b0 ++ MX6QDL_PAD_EIM_D30__EIM_DATA30 0x1b0b0 ++ MX6QDL_PAD_EIM_D31__EIM_DATA31 0x1b0b0 ++ /* address */ ++ MX6QDL_PAD_EIM_A23__EIM_ADDR23 0xb0b1 ++ MX6QDL_PAD_EIM_A22__EIM_ADDR22 0xb0b1 ++ MX6QDL_PAD_EIM_A21__EIM_ADDR21 0xb0b1 ++ MX6QDL_PAD_EIM_A20__EIM_ADDR20 0xb0b1 ++ MX6QDL_PAD_EIM_A19__EIM_ADDR19 0xb0b1 ++ MX6QDL_PAD_EIM_A18__EIM_ADDR18 0xb0b1 ++ MX6QDL_PAD_EIM_A17__EIM_ADDR17 0xb0b1 ++ MX6QDL_PAD_EIM_A16__EIM_ADDR16 0xb0b1 ++ MX6QDL_PAD_EIM_DA15__EIM_AD15 0xb0b1 ++ MX6QDL_PAD_EIM_DA14__EIM_AD14 0xb0b1 ++ MX6QDL_PAD_EIM_DA13__EIM_AD13 0xb0b1 ++ MX6QDL_PAD_EIM_DA12__EIM_AD12 0xb0b1 ++ MX6QDL_PAD_EIM_DA11__EIM_AD11 0xb0b1 ++ MX6QDL_PAD_EIM_DA10__EIM_AD10 0xb0b1 ++ MX6QDL_PAD_EIM_DA9__EIM_AD09 0xb0b1 ++ MX6QDL_PAD_EIM_DA8__EIM_AD08 0xb0b1 ++ MX6QDL_PAD_EIM_DA7__EIM_AD07 0xb0b1 ++ MX6QDL_PAD_EIM_DA6__EIM_AD06 0xb0b1 ++ MX6QDL_PAD_EIM_DA5__EIM_AD05 0xb0b1 ++ MX6QDL_PAD_EIM_DA4__EIM_AD04 0xb0b1 ++ MX6QDL_PAD_EIM_DA3__EIM_AD03 0xb0b1 ++ MX6QDL_PAD_EIM_DA2__EIM_AD02 0xb0b1 ++ MX6QDL_PAD_EIM_DA1__EIM_AD01 0xb0b1 ++ MX6QDL_PAD_EIM_DA0__EIM_AD00 0xb0b1 ++ >; ++ }; ++ }; ++ }; ++ + ldb: ldb@020e0008 { +- #address-cells = <1>; +- #size-cells = <0>; + compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb"; +- gpr = <&gpr>; ++ reg = <0x020e0000 0x4000>; ++ clocks = <&clks 135>, <&clks 136>, ++ <&clks 39>, <&clks 40>, ++ <&clks 41>, <&clks 42>, ++ <&clks 184>, <&clks 185>, ++ <&clks 205>, <&clks 206>, ++ <&clks 207>, <&clks 208>; ++ clock-names = "ldb_di0", "ldb_di1", ++ "ipu1_di0_sel", "ipu1_di1_sel", ++ "ipu2_di0_sel", "ipu2_di1_sel", ++ "di0_div_3_5", "di1_div_3_5", ++ "di0_div_7", "di1_div_7", ++ "di0_div_sel", "di1_div_sel"; + status = "disabled"; ++ }; + +- lvds-channel@0 { +- reg = <0>; +- crtcs = <&ipu1 0>; +- status = "disabled"; +- }; +- +- lvds-channel@1 { +- reg = <1>; +- crtcs = <&ipu1 1>; +- status = "disabled"; +- }; ++ hdmi: hdmi@0120000 { ++ reg = <0x00120000 0x9000>; ++ interrupts = <0 115 0x04>; ++ gpr = <&gpr>; ++ clocks = <&clks 123>, <&clks 124>; ++ clock-names = "iahb", "isfr"; ++ status = "disabled"; + }; + + dcic1: dcic@020e4000 { +@@ -580,6 +1474,8 @@ + interrupts = <0 2 0x04>; + clocks = <&clks 155>, <&clks 155>; + clock-names = "ipg", "ahb"; ++ #dma-cells = <3>; ++ iram = <&ocram>; + fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q.bin"; + }; + }; +@@ -591,9 +1487,29 @@ + reg = <0x02100000 0x100000>; + ranges; + +- caam@02100000 { +- reg = <0x02100000 0x40000>; +- interrupts = <0 105 0x04 0 106 0x04>; ++ crypto: caam@2100000 { ++ compatible = "fsl,sec-v4.0"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x2100000 0x40000>; ++ ranges = <0 0x2100000 0x40000>; ++ interrupt-parent = <&intc>; /* interrupts = <0 92 0x4>; */ ++ clocks = <&clks 213>, <&clks 214>, <&clks 215>; ++ clock-names = "caam_mem", "caam_aclk", "caam_ipg"; ++ ++ sec_jr0: jr0@1000 { ++ compatible = "fsl,sec-v4.0-job-ring"; ++ reg = <0x1000 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <0 105 0x4>; ++ }; ++ ++ sec_jr1: jr1@2000 { ++ compatible = "fsl,sec-v4.0-job-ring"; ++ reg = <0x2000 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <0 106 0x4>; ++ }; + }; + + aipstz@0217c000 { /* AIPSTZ2 */ +@@ -607,6 +1523,7 @@ + clocks = <&clks 162>; + fsl,usbphy = <&usbphy1>; + fsl,usbmisc = <&usbmisc 0>; ++ fsl,anatop = <&anatop>; + status = "disabled"; + }; + +@@ -638,7 +1555,7 @@ + status = "disabled"; + }; + +- usbmisc: usbmisc: usbmisc@02184800 { ++ usbmisc: usbmisc@02184800 { + #index-cells = <1>; + compatible = "fsl,imx6q-usbmisc"; + reg = <0x02184800 0x200>; +@@ -654,9 +1571,14 @@ + status = "disabled"; + }; + +- mlb@0218c000 { ++ mlb: mlb@0218c000 { ++ compatible = "fsl,imx6q-mlb150"; + reg = <0x0218c000 0x4000>; + interrupts = <0 53 0x04 0 117 0x04 0 126 0x04>; ++ clocks = <&clks 139>, <&clks 175>; ++ clock-names = "mlb", "pll8_mlb"; ++ iram = <&ocram>; ++ status = "disabled"; + }; + + usdhc1: usdhc@02190000 { +@@ -733,6 +1655,11 @@ + reg = <0x021ac000 0x4000>; + }; + ++ mmdc0-1@021b0000 { /* MMDC0-1 */ ++ compatible = "fsl,imx6q-mmdc-combine"; ++ reg = <0x021b0000 0x8000>; ++ }; ++ + mmdc0: mmdc@021b0000 { /* MMDC0 */ + compatible = "fsl,imx6q-mmdc"; + reg = <0x021b0000 0x4000>; +@@ -742,20 +1669,23 @@ + reg = <0x021b4000 0x4000>; + }; + +- weim@021b8000 { ++ weim: weim@021b8000 { ++ compatible = "fsl,imx6q-weim"; + reg = <0x021b8000 0x4000>; + interrupts = <0 14 0x04>; ++ clocks = <&clks 196>; + }; + +- ocotp@021bc000 { +- compatible = "fsl,imx6q-ocotp"; ++ ocotp: ocotp-ctrl@021bc000 { ++ compatible = "syscon"; + reg = <0x021bc000 0x4000>; + }; + +- ocotp@021c0000 { +- reg = <0x021c0000 0x4000>; +- interrupts = <0 21 0x04>; +- }; ++ ocotp-fuse@021bc000 { ++ compatible = "fsl,imx6q-ocotp"; ++ reg = <0x021bc000 0x4000>; ++ clocks = <&clks 128>; ++ }; + + tzasc@021d0000 { /* TZASC1 */ + reg = <0x021d0000 0x4000>; +@@ -773,17 +1703,26 @@ + status = "disabled"; + }; + +- mipi@021dc000 { /* MIPI-CSI */ ++ mipi_csi: mipi_csi@021dc000 { ++ compatible = "fsl,imx6q-mipi-csi2"; + reg = <0x021dc000 0x4000>; +- }; +- +- mipi@021e0000 { /* MIPI-DSI */ +- reg = <0x021e0000 0x4000>; ++ interrupts = <0 100 0x04>, <0 101 0x04>; ++ clocks = <&clks 138>, <&clks 53>; ++ /* Note: clks 138 is hsi_tx, however, the dphy_c ++ * hsi_tx and pll_refclk use the same clk gate. ++ * In current clk driver, open/close clk gate do ++ * use hsi_tx for a temporary debug purpose. ++ */ ++ clock-names = "dphy_clk", "pixel_clk"; ++ status = "disabled"; + }; + + vdoa@021e4000 { ++ compatible = "fsl,imx6q-vdoa"; + reg = <0x021e4000 0x4000>; + interrupts = <0 18 0x04>; ++ clocks = <&clks 202>; ++ iram = <&ocram>; + }; + + uart2: serial@021e8000 { +@@ -792,6 +1731,8 @@ + interrupts = <0 27 0x04>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; ++ dmas = <&sdma 27 4 0>, <&sdma 28 4 0>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -801,6 +1742,8 @@ + interrupts = <0 28 0x04>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; ++ dmas = <&sdma 29 4 0>, <&sdma 30 4 0>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -810,6 +1753,8 @@ + interrupts = <0 29 0x04>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; ++ dmas = <&sdma 31 4 0>, <&sdma 32 4 0>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -819,18 +1764,24 @@ + interrupts = <0 30 0x04>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; ++ dmas = <&sdma 33 4 0>, <&sdma 34 4 0>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + }; + + ipu1: ipu@02400000 { +- #crtc-cells = <1>; + compatible = "fsl,imx6q-ipu"; + reg = <0x02400000 0x400000>; + interrupts = <0 6 0x4 0 5 0x4>; +- clocks = <&clks 130>, <&clks 131>, <&clks 132>; +- clock-names = "bus", "di0", "di1"; ++ clocks = <&clks 130>, <&clks 131>, <&clks 132>, ++ <&clks 39>, <&clks 40>, ++ <&clks 135>, <&clks 136>; ++ clock-names = "bus", "di0", "di1", ++ "di0_sel", "di1_sel", ++ "ldb_di0", "ldb_di1"; + resets = <&src 2>; ++ bypass_reset = <0>; + }; + }; + }; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6sl-evk-csi.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6sl-evk-csi.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6sl-evk-csi.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6sl-evk-csi.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "imx6sl-evk.dts" ++ ++/ { ++ csi_v4l2_cap { ++ status = "okay"; ++ }; ++}; ++ ++&csi { ++ status = "okay"; ++}; ++ ++&i2c3 { ++ status = "okay"; ++}; ++ ++&epdc { ++ status = "disabled"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6sl-evk-ldo.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6sl-evk-ldo.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6sl-evk-ldo.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6sl-evk-ldo.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "imx6sl-evk.dts" ++ ++&cpu0 { ++ arm-supply = <®_arm>; ++ soc-supply = <®_soc>; ++ pu-supply = <®_pu>; /* use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&gpc { ++ fsl,ldo-bypass = <0>; /* use ldo-bypass, u-boot will check it and configure */ ++ fsl,wdog-reset = <1>; /* watchdog select of reset source */ ++ pu-supply = <®_pu>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&gpu { ++ pu-supply = <®_pu>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6sl-evk.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6sl-evk.dts +--- linux-3.10.30/arch/arm/boot/dts/imx6sl-evk.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6sl-evk.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,604 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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. ++ */ ++ ++/dts-v1/; ++ ++#include "imx6sl.dtsi" ++ ++/ { ++ model = "Freescale i.MX6 SoloLite EVK Board"; ++ compatible = "fsl,imx6sl-evk", "fsl,imx6sl"; ++ ++ memory { ++ reg = <0x80000000 0x40000000>; ++ }; ++ ++ battery: max8903@0 { ++ compatible = "fsl,max8903-charger"; ++ pinctrl-names = "default"; ++ dok_input = <&gpio4 13 1>; ++ uok_input = <&gpio4 13 1>; ++ chg_input = <&gpio4 15 1>; ++ flt_input = <&gpio4 14 1>; ++ fsl,dcm_always_high; ++ fsl,dc_valid; ++ fsl,adc_disable; ++ status = "okay"; ++ }; ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_lcd_3v3: lcd-3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "lcd-3v3"; ++ gpio = <&gpio4 3 0>; ++ enable-active-high; ++ }; ++ ++ reg_aud3v: wm8962_supply_3v15 { ++ compatible = "regulator-fixed"; ++ regulator-name = "wm8962-supply-3v15"; ++ regulator-min-microvolt = <3150000>; ++ regulator-max-microvolt = <3150000>; ++ regulator-boot-on; ++ }; ++ ++ reg_aud4v: wm8962_supply_4v2 { ++ compatible = "regulator-fixed"; ++ regulator-name = "wm8962-supply-4v2"; ++ regulator-min-microvolt = <4325000>; ++ regulator-max-microvolt = <4325000>; ++ regulator-boot-on; ++ }; ++ ++ reg_usb_otg1_vbus: usb_otg1_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_otg1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio4 0 0>; ++ enable-active-high; ++ }; ++ ++ reg_usb_otg2_vbus: usb_otg2_vbus { ++ compatible = "regulator-fixed"; ++ regulator-name = "usb_otg2_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio4 2 0>; ++ enable-active-high; ++ }; ++ }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm1 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <6>; ++ }; ++ ++ csi_v4l2_cap { ++ compatible = "fsl,imx6sl-csi-v4l2"; ++ status = "disabled"; ++ }; ++ ++ pxp_v4l2_out { ++ compatible = "fsl,imx6sl-pxp-v4l2"; ++ status = "okay"; ++ }; ++ ++ sound { ++ compatible = "fsl,imx6q-sabresd-wm8962", ++ "fsl,imx-audio-wm8962"; ++ model = "wm8962-audio"; ++ ssi-controller = <&ssi2>; ++ audio-codec = <&codec>; ++ audio-routing = ++ "Headphone Jack", "HPOUTL", ++ "Headphone Jack", "HPOUTR", ++ "Ext Spk", "SPKOUTL", ++ "Ext Spk", "SPKOUTR", ++ "AMIC", "MICBIAS", ++ "IN3R", "AMIC"; ++ amic-mono; ++ mux-int-port = <2>; ++ mux-ext-port = <3>; ++ hp-det-gpios = <&gpio4 19 1>; ++ }; ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif", ++ "fsl,imx6sl-evk-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-out; ++ }; ++ ++ sii902x_reset: sii902x-reset { ++ compatible = "gpio-reset"; ++ reset-gpios = <&gpio2 19 1>; ++ reset-delay-us = <100000>; ++ #reset-cells = <0>; ++ }; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux_1>; ++ status = "okay"; ++}; ++ ++&csi { ++ status = "disabled"; ++}; ++ ++&ecspi1 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio4 11 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi1_1>; ++ status = "okay"; ++ ++ flash: m25p80@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p32"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++&epdc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_epdc_0>; ++ V3P3-supply = <&V3P3_reg>; ++ VCOM-supply = <&VCOM_reg>; ++ DISPLAY-supply = <&DISPLAY_reg>; ++ status = "okay"; ++}; ++ ++&cpu0 { ++ arm-supply = <&sw1a_reg>; ++ soc-supply = <&sw1c_reg>; ++ pu-supply = <&pu_dummy>; /* use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&fec { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&pinctrl_fec_1>; ++ pinctrl-1 = <&pinctrl_fec_1_sleep>; ++ phy-mode = "rmii"; ++ phy-reset-gpios = <&gpio4 21 0>; /* GPIO4_21 */ ++ phy-reset-duration = <1>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1_1>; ++ status = "okay"; ++ ++ pmic: pfuze100@08 { ++ compatible = "fsl,pfuze100"; ++ reg = <0x08>; ++ ++ regulators { ++ sw1a_reg: sw1ab { ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1875000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-ramp-delay = <6250>; ++ }; ++ ++ sw1c_reg: sw1c { ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1875000>; ++ regulator-boot-on; ++ regulator-always-on; ++ regulator-ramp-delay = <6250>; ++ }; ++ ++ sw2_reg: sw2 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw3a_reg: sw3a { ++ regulator-min-microvolt = <400000>; ++ regulator-max-microvolt = <1975000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw3b_reg: sw3b { ++ regulator-min-microvolt = <400000>; ++ regulator-max-microvolt = <1975000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw4_reg: sw4 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ swbst_reg: swbst { ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5150000>; ++ }; ++ ++ snvs_reg: vsnvs { ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <3000000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vref_reg: vrefddr { ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vgen1_reg: vgen1 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <1550000>; ++ }; ++ ++ vgen2_reg: vgen2 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <1550000>; ++ }; ++ ++ vgen3_reg: vgen3 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vgen4_reg: vgen4 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vgen5_reg: vgen5 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vgen6_reg: vgen6 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ }; ++ }; ++ ++ elan@10 { ++ compatible = "elan,elan-touch"; ++ reg = <0x10>; ++ interrupt-parent = <&gpio2>; ++ interrupts = <10 2>; ++ gpio_elan_cs = <&gpio2 9 0>; ++ gpio_elan_rst = <&gpio4 4 0>; ++ gpio_intr = <&gpio2 10 0>; ++ status = "okay"; ++ }; ++ ++ max17135@48 { ++ compatible = "maxim,max17135"; ++ reg = <0x48>; ++ vneg_pwrup = <1>; ++ gvee_pwrup = <2>; ++ vpos_pwrup = <10>; ++ gvdd_pwrup = <12>; ++ gvdd_pwrdn = <1>; ++ vpos_pwrdn = <2>; ++ gvee_pwrdn = <8>; ++ vneg_pwrdn = <10>; ++ gpio_pmic_pwrgood = <&gpio2 13 0>; ++ gpio_pmic_vcom_ctrl = <&gpio2 3 0>; ++ gpio_pmic_wakeup = <&gpio2 14 0>; ++ gpio_pmic_v3p3 = <&gpio2 7 0>; ++ gpio_pmic_intr = <&gpio2 12 0>; ++ ++ regulators { ++ DISPLAY_reg: DISPLAY { ++ regulator-name = "DISPLAY"; ++ }; ++ ++ GVDD_reg: GVDD { ++ /* 20v */ ++ regulator-name = "GVDD"; ++ }; ++ ++ GVEE_reg: GVEE { ++ /* -22v */ ++ regulator-name = "GVEE"; ++ }; ++ ++ HVINN_reg: HVINN { ++ /* -22v */ ++ regulator-name = "HVINN"; ++ }; ++ ++ HVINP_reg: HVINP { ++ /* 20v */ ++ regulator-name = "HVINP"; ++ }; ++ ++ VCOM_reg: VCOM { ++ regulator-name = "VCOM"; ++ /* 2's-compliment, -4325000 */ ++ regulator-min-microvolt = <0xffbe0178>; ++ /* 2's-compliment, -500000 */ ++ regulator-max-microvolt = <0xfff85ee0>; ++ }; ++ ++ VNEG_reg: VNEG { ++ /* -15v */ ++ regulator-name = "VNEG"; ++ }; ++ ++ VPOS_reg: VPOS { ++ /* 15v */ ++ regulator-name = "VPOS"; ++ }; ++ ++ V3P3_reg: V3P3 { ++ regulator-name = "V3P3"; ++ }; ++ }; ++ }; ++ ++ mma8450@1c { ++ compatible = "fsl,mma8450"; ++ reg = <0x1c>; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2_1>; ++ status = "okay"; ++ ++ codec: wm8962@1a { ++ compatible = "wlf,wm8962"; ++ reg = <0x1a>; ++ clocks = <&clks IMX6SL_CLK_EXTERN_AUDIO>; ++ DCVDD-supply = <&vgen3_reg>; ++ DBVDD-supply = <®_aud3v>; ++ AVDD-supply = <&vgen3_reg>; ++ CPVDD-supply = <&vgen3_reg>; ++ MICVDD-supply = <®_aud3v>; ++ PLLVDD-supply = <&vgen3_reg>; ++ SPKVDD1-supply = <®_aud4v>; ++ SPKVDD2-supply = <®_aud4v>; ++ amic-mono; ++ }; ++ ++ sii902x@39 { ++ compatible = "SiI,sii902x"; ++ interrupt-parent = <&gpio2>; ++ interrupts = <10 2>; ++ mode_str ="1280x720M@60"; ++ bits-per-pixel = <32>; ++ resets = <&sii902x_reset>; ++ reg = <0x39>; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3_1>; ++ status = "disabled"; ++ ++ ov564x: ov564x@3c { ++ compatible = "ovti,ov564x"; ++ reg = <0x3c>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_csi_0>; ++ clocks = <&clks IMX6SL_CLK_CSI>; ++ clock-names = "csi_mclk"; ++ AVDD-supply = <&vgen6_reg>; /* 2.8v */ ++ DVDD-supply = <&vgen2_reg>; /* 1.5v*/ ++ pwn-gpios = <&gpio1 25 1>; ++ rst-gpios = <&gpio1 26 0>; ++ csi_id = <0>; ++ mclk = <24000000>; ++ mclk_source = <0>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&pinctrl_hog>; ++ pinctrl-1 = <&pinctrl_hog_sleep>; ++ ++ hog { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6SL_PAD_KEY_ROW7__GPIO4_IO07 0x17059 ++ MX6SL_PAD_KEY_COL7__GPIO4_IO06 0x17059 ++ MX6SL_PAD_SD2_DAT7__GPIO5_IO00 0x17059 ++ MX6SL_PAD_SD2_DAT6__GPIO4_IO29 0x17059 ++ MX6SL_PAD_REF_CLK_32K__GPIO3_IO22 0x17059 ++ MX6SL_PAD_FEC_TX_CLK__GPIO4_IO21 0x80000000 ++ MX6SL_PAD_KEY_ROW5__GPIO4_IO03 0x110b0 ++ MX6SL_PAD_EPDC_VCOM0__GPIO2_IO03 0x80000000 ++ MX6SL_PAD_EPDC_PWRSTAT__GPIO2_IO13 0x80000000 ++ MX6SL_PAD_EPDC_PWRCTRL0__GPIO2_IO07 0x80000000 ++ MX6SL_PAD_EPDC_PWRWAKEUP__GPIO2_IO14 0x80000000 ++ MX6SL_PAD_EPDC_PWRINT__GPIO2_IO12 0x80000000 ++ MX6SL_PAD_EPDC_PWRCTRL3__GPIO2_IO10 0x170b0 ++ MX6SL_PAD_EPDC_PWRCTRL2__GPIO2_IO09 0x80000000 ++ MX6SL_PAD_KEY_COL6__GPIO4_IO04 0x110b0 ++ MX6SL_PAD_ECSPI2_MISO__GPIO4_IO14 0x17000 ++ MX6SL_PAD_ECSPI2_MOSI__GPIO4_IO13 0x17000 ++ MX6SL_PAD_ECSPI2_SS0__GPIO4_IO15 0x17000 ++ MX6SL_PAD_FEC_RX_ER__GPIO4_IO19 0x1b0b0 ++ MX6SL_PAD_LCD_RESET__GPIO2_IO19 0x1b0b0 ++ MX6SL_PAD_KEY_COL4__GPIO4_IO00 0x80000000 ++ MX6SL_PAD_KEY_COL5__GPIO4_IO02 0x80000000 ++ >; ++ }; ++ ++ pinctrl_hog_sleep: hoggrp_sleep { ++ fsl,pins = < ++ MX6SL_PAD_KEY_ROW5__GPIO4_IO03 0x3080 ++ MX6SL_PAD_KEY_COL6__GPIO4_IO04 0x3080 ++ MX6SL_PAD_LCD_RESET__GPIO2_IO19 0x3080 ++ >; ++ }; ++ }; ++}; ++ ++&kpp { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&pinctrl_kpp_1>; ++ pinctrl-1 = <&pinctrl_kpp_1_sleep>; ++ linux,keymap = < ++ 0x00000067 /* KEY_UP */ ++ 0x0001006c /* KEY_DOWN */ ++ 0x0002001c /* KEY_ENTER */ ++ 0x01000066 /* KEY_HOME */ ++ 0x0101006a /* KEY_RIGHT */ ++ 0x01020069 /* KEY_LEFT */ ++ 0x02000072 /* KEY_VOLUMEDOWN */ ++ 0x02010073 /* KEY_VOLUMEUP */ ++ >; ++ status = "okay"; ++}; ++ ++&lcdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_lcdif_dat_0 ++ &pinctrl_lcdif_ctrl_0>; ++ lcd-supply = <®_lcd_3v3>; ++ display = <&display>; ++ status = "okay"; ++ ++ display: display { ++ bits-per-pixel = <16>; ++ bus-width = <24>; ++ ++ display-timings { ++ native-mode = <&timing0>; ++ timing0: timing0 { ++ clock-frequency = <33500000>; ++ hactive = <800>; ++ vactive = <480>; ++ hback-porch = <89>; ++ hfront-porch = <164>; ++ vback-porch = <23>; ++ vfront-porch = <10>; ++ hsync-len = <10>; ++ vsync-len = <10>; ++ hsync-active = <0>; ++ vsync-active = <0>; ++ de-active = <1>; ++ pixelclk-active = <0>; ++ }; ++ }; ++ }; ++}; ++ ++&pwm1 { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&pinctrl_pwm1_0>; ++ pinctrl-1 = <&pinctrl_pwm1_0_sleep>; ++ status = "okay"; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_spdif_1>; ++ status = "okay"; ++}; ++ ++&ssi2 { ++ fsl,mode = "i2s-slave"; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1_1>; ++ status = "okay"; ++}; ++ ++&usbotg1 { ++ vbus-supply = <®_usb_otg1_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg1_1>; ++ disable-over-current; ++ imx6-usb-charger-detection; ++ status = "okay"; ++}; ++ ++&usbotg2 { ++ vbus-supply = <®_usb_otg2_vbus>; ++ dr_mode = "host"; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usdhc1 { ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ pinctrl-0 = <&pinctrl_usdhc1_1>; ++ pinctrl-1 = <&pinctrl_usdhc1_1_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc1_1_200mhz>; ++ bus-width = <8>; ++ cd-gpios = <&gpio4 7 0>; ++ wp-gpios = <&gpio4 6 0>; ++ status = "okay"; ++}; ++ ++&usdhc2 { ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ pinctrl-0 = <&pinctrl_usdhc2_1>; ++ pinctrl-1 = <&pinctrl_usdhc2_1_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc2_1_200mhz>; ++ cd-gpios = <&gpio5 0 0>; ++ wp-gpios = <&gpio4 29 0>; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default", "state_100mhz", "state_200mhz"; ++ pinctrl-0 = <&pinctrl_usdhc3_1>; ++ pinctrl-1 = <&pinctrl_usdhc3_1_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc3_1_200mhz>; ++ cd-gpios = <&gpio3 22 0>; ++ status = "okay"; ++}; ++ ++&pxp { ++ status = "okay"; ++}; ++ ++&gpc { ++ fsl,cpu_pupscr_sw2iso = <0xf>; ++ fsl,cpu_pupscr_sw = <0xf>; ++ fsl,cpu_pdnscr_iso2sw = <0x1>; ++ fsl,cpu_pdnscr_iso = <0x1>; ++ fsl,ldo-bypass = <1>; /* use ldo-bypass, u-boot will check it and configure */ ++ fsl,wdog-reset = <1>; /* watchdog select of reset source */ ++ pu-supply = <&pu_dummy>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; ++ ++&gpu { ++ pu-supply = <&pu_dummy>; /* ldo-bypass:use pu_dummy if VDDSOC share with VDDPU */ ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/imx6sl.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6sl.dtsi +--- linux-3.10.30/arch/arm/boot/dts/imx6sl.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/imx6sl.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,1255 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "skeleton.dtsi" ++#include "imx6sl-pinfunc.h" ++#include ++ ++/ { ++ aliases { ++ serial0 = &uart1; ++ serial1 = &uart2; ++ serial2 = &uart3; ++ serial3 = &uart4; ++ serial4 = &uart5; ++ gpio0 = &gpio1; ++ gpio1 = &gpio2; ++ gpio2 = &gpio3; ++ gpio3 = &gpio4; ++ gpio4 = &gpio5; ++ usbphy0 = &usbphy1; ++ usbphy1 = &usbphy2; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ compatible = "arm,cortex-a9"; ++ device_type = "cpu"; ++ reg = <0x0>; ++ next-level-cache = <&L2>; ++ operating-points = < ++ /* kHz uV */ ++ 996000 1275000 ++ 792000 1175000 ++ 396000 975000 ++ >; ++ fsl,soc-operating-points = < ++ /* ARM kHz SOC-PU uV */ ++ 996000 1225000 ++ 792000 1175000 ++ 396000 1175000 ++ >; ++ clock-latency = <61036>; /* two CLK32 periods */ ++ clocks = <&clks IMX6SL_CLK_ARM>, <&clks IMX6SL_CLK_PLL2_PFD2>, ++ <&clks IMX6SL_CLK_STEP>, <&clks IMX6SL_CLK_PLL1_SW>, ++ <&clks IMX6SL_CLK_PLL1_SYS>; ++ clock-names = "arm", "pll2_pfd2_396m", "step", ++ "pll1_sw", "pll1_sys"; ++ arm-supply = <®_arm>; ++ pu-supply = <®_pu>; ++ soc-supply = <®_soc>; ++ }; ++ }; ++ ++ intc: interrupt-controller@00a01000 { ++ compatible = "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ interrupt-controller; ++ reg = <0x00a01000 0x1000>, ++ <0x00a00100 0x100>; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ckil { ++ compatible = "fixed-clock"; ++ clock-frequency = <32768>; ++ }; ++ ++ osc { ++ compatible = "fixed-clock"; ++ clock-frequency = <24000000>; ++ }; ++ }; ++ ++ pu_dummy: pudummy_reg { ++ compatible = "fsl,imx6-dummy-pureg"; /* only used in ldo-bypass */ ++ }; ++ ++ soc { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "simple-bus"; ++ interrupt-parent = <&intc>; ++ ranges; ++ ++ busfreq { /* BUSFREQ */ ++ compatible = "fsl,imx6_busfreq"; ++ clocks = <&clks IMX6SL_CLK_PLL2_BUS>, <&clks IMX6SL_CLK_PLL2_PFD2>, ++ <&clks IMX6SL_CLK_PLL2_198M>, <&clks IMX6SL_CLK_ARM>, ++ <&clks IMX6SL_CLK_PLL3_USB_OTG>, <&clks IMX6SL_CLK_PERIPH>, ++ <&clks IMX6SL_CLK_PRE_PERIPH_SEL>, <&clks IMX6SL_CLK_PERIPH_CLK2>, ++ <&clks IMX6SL_CLK_PERIPH_CLK2_SEL>, <&clks IMX6SL_CLK_OSC>, ++ <&clks IMX6SL_CLK_PLL1_SYS>, <&clks IMX6SL_CLK_PERIPH2>, ++ <&clks IMX6SL_CLK_AHB>, <&clks IMX6SL_CLK_OCRAM>, ++ <&clks IMX6SL_CLK_PLL1_SW>, <&clks IMX6SL_CLK_PRE_PERIPH2_SEL>, ++ <&clks IMX6SL_CLK_PERIPH2_CLK2_SEL>, <&clks IMX6SL_CLK_PERIPH2_CLK2>, ++ <&clks IMX6SL_CLK_STEP>; ++ clock-names = "pll2_bus", "pll2_pfd2_396m", "pll2_198m", "arm", "pll3_usb_otg", "periph", ++ "periph_pre", "periph_clk2", "periph_clk2_sel", "osc", "pll1_sys", "periph2", "ahb", "ocram", "pll1_sw", ++ "periph2_pre", "periph2_clk2_sel", "periph2_clk2", "step"; ++ fsl,max_ddr_freq = <400000000>; ++ }; ++ ++ L2: l2-cache@00a02000 { ++ compatible = "arm,pl310-cache"; ++ reg = <0x00a02000 0x1000>; ++ interrupts = <0 92 0x04>; ++ cache-unified; ++ cache-level = <2>; ++ arm,tag-latency = <4 2 3>; ++ arm,data-latency = <4 2 3>; ++ }; ++ ++ pmu { ++ compatible = "arm,cortex-a9-pmu"; ++ interrupts = <0 94 0x04>; ++ }; ++ ++ aips1: aips-bus@02000000 { ++ compatible = "fsl,aips-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x02000000 0x100000>; ++ ranges; ++ ++ spba: spba-bus@02000000 { ++ compatible = "fsl,spba-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x02000000 0x40000>; ++ ranges; ++ ++ spdif: spdif@02004000 { ++ compatible = "fsl,imx6sl-spdif", ++ "fsl,imx35-spdif"; ++ reg = <0x02004000 0x4000>; ++ interrupts = <0 52 0x04>; ++ dmas = <&sdma 14 18 0>, ++ <&sdma 15 18 0>; ++ dma-names = "rx", "tx"; ++ clocks = <&clks IMX6SL_CLK_SPDIF>, ++ <&clks IMX6SL_CLK_OSC>, ++ <&clks IMX6SL_CLK_SPDIF>, ++ <&clks 0>, <&clks 0>, <&clks 0>, ++ <&clks IMX6SL_CLK_IPG>, ++ <&clks 0>, <&clks 0>, ++ <&clks IMX6SL_CLK_SPBA>; ++ clock-names = "core", "rxtx0", ++ "rxtx1", "rxtx2", ++ "rxtx3", "rxtx4", ++ "rxtx5", "rxtx6", ++ "rxtx7", "dma"; ++ status = "disabled"; ++ }; ++ ++ ecspi1: ecspi@02008000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; ++ reg = <0x02008000 0x4000>; ++ interrupts = <0 31 0x04>; ++ clocks = <&clks IMX6SL_CLK_ECSPI1>, ++ <&clks IMX6SL_CLK_ECSPI1>; ++ clock-names = "ipg", "per"; ++ status = "disabled"; ++ }; ++ ++ ecspi2: ecspi@0200c000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; ++ reg = <0x0200c000 0x4000>; ++ interrupts = <0 32 0x04>; ++ clocks = <&clks IMX6SL_CLK_ECSPI2>, ++ <&clks IMX6SL_CLK_ECSPI2>; ++ clock-names = "ipg", "per"; ++ status = "disabled"; ++ }; ++ ++ ecspi3: ecspi@02010000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; ++ reg = <0x02010000 0x4000>; ++ interrupts = <0 33 0x04>; ++ clocks = <&clks IMX6SL_CLK_ECSPI3>, ++ <&clks IMX6SL_CLK_ECSPI3>; ++ clock-names = "ipg", "per"; ++ status = "disabled"; ++ }; ++ ++ ecspi4: ecspi@02014000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; ++ reg = <0x02014000 0x4000>; ++ interrupts = <0 34 0x04>; ++ clocks = <&clks IMX6SL_CLK_ECSPI4>, ++ <&clks IMX6SL_CLK_ECSPI4>; ++ clock-names = "ipg", "per"; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@02018000 { ++ compatible = "fsl,imx6sl-uart", "fsl,imx21-uart"; ++ reg = <0x02018000 0x4000>; ++ interrupts = <0 30 0x04>; ++ clocks = <&clks IMX6SL_CLK_UART>, ++ <&clks IMX6SL_CLK_UART_SERIAL>; ++ clock-names = "ipg", "per"; ++ status = "disabled"; ++ }; ++ ++ uart1: serial@02020000 { ++ compatible = "fsl,imx6sl-uart", "fsl,imx21-uart"; ++ reg = <0x02020000 0x4000>; ++ interrupts = <0 26 0x04>; ++ clocks = <&clks IMX6SL_CLK_UART>, ++ <&clks IMX6SL_CLK_UART_SERIAL>; ++ clock-names = "ipg", "per"; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@02024000 { ++ compatible = "fsl,imx6sl-uart", "fsl,imx21-uart"; ++ reg = <0x02024000 0x4000>; ++ interrupts = <0 27 0x04>; ++ clocks = <&clks IMX6SL_CLK_UART>, ++ <&clks IMX6SL_CLK_UART_SERIAL>; ++ clock-names = "ipg", "per"; ++ status = "disabled"; ++ }; ++ ++ ssi1: ssi@02028000 { ++ compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; ++ reg = <0x02028000 0x4000>; ++ interrupts = <0 46 0x04>; ++ clocks = <&clks IMX6SL_CLK_SSI1>, <&clks IMX6SL_CLK_SSI1>; ++ clock-names = "ipg", "baud"; ++ status = "disabled"; ++ }; ++ ++ ssi2: ssi@0202c000 { ++ compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; ++ reg = <0x0202c000 0x4000>; ++ interrupts = <0 47 0x04>; ++ clocks = <&clks IMX6SL_CLK_SSI2>, <&clks IMX6SL_CLK_SSI2>; ++ clock-names = "ipg", "baud"; ++ status = "disabled"; ++ }; ++ ++ ssi3: ssi@02030000 { ++ compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; ++ reg = <0x02030000 0x4000>; ++ interrupts = <0 48 0x04>; ++ clocks = <&clks IMX6SL_CLK_SSI3>, <&clks IMX6SL_CLK_SSI3>; ++ clock-names = "ipg", "baud"; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@02034000 { ++ compatible = "fsl,imx6sl-uart", "fsl,imx21-uart"; ++ reg = <0x02034000 0x4000>; ++ interrupts = <0 28 0x04>; ++ clocks = <&clks IMX6SL_CLK_UART>, ++ <&clks IMX6SL_CLK_UART_SERIAL>; ++ clock-names = "ipg", "per"; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@02038000 { ++ compatible = "fsl,imx6sl-uart", "fsl,imx21-uart"; ++ reg = <0x02038000 0x4000>; ++ interrupts = <0 29 0x04>; ++ clocks = <&clks IMX6SL_CLK_UART>, ++ <&clks IMX6SL_CLK_UART_SERIAL>; ++ clock-names = "ipg", "per"; ++ status = "disabled"; ++ }; ++ }; ++ ++ pwm1: pwm@02080000 { ++ #pwm-cells = <2>; ++ compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; ++ reg = <0x02080000 0x4000>; ++ interrupts = <0 83 0x04>; ++ clocks = <&clks IMX6SL_CLK_PWM1>, ++ <&clks IMX6SL_CLK_PWM1>; ++ clock-names = "ipg", "per"; ++ }; ++ ++ pwm2: pwm@02084000 { ++ #pwm-cells = <2>; ++ compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; ++ reg = <0x02084000 0x4000>; ++ interrupts = <0 84 0x04>; ++ clocks = <&clks IMX6SL_CLK_PWM2>, ++ <&clks IMX6SL_CLK_PWM2>; ++ clock-names = "ipg", "per"; ++ }; ++ ++ pwm3: pwm@02088000 { ++ #pwm-cells = <2>; ++ compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; ++ reg = <0x02088000 0x4000>; ++ interrupts = <0 85 0x04>; ++ clocks = <&clks IMX6SL_CLK_PWM3>, ++ <&clks IMX6SL_CLK_PWM3>; ++ clock-names = "ipg", "per"; ++ }; ++ ++ pwm4: pwm@0208c000 { ++ #pwm-cells = <2>; ++ compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; ++ reg = <0x0208c000 0x4000>; ++ interrupts = <0 86 0x04>; ++ clocks = <&clks IMX6SL_CLK_PWM4>, ++ <&clks IMX6SL_CLK_PWM4>; ++ clock-names = "ipg", "per"; ++ }; ++ ++ gpt: gpt@02098000 { ++ compatible = "fsl,imx6sl-gpt"; ++ reg = <0x02098000 0x4000>; ++ interrupts = <0 55 0x04>; ++ clocks = <&clks IMX6SL_CLK_GPT>, ++ <&clks IMX6SL_CLK_GPT_SERIAL>; ++ clock-names = "ipg", "per"; ++ }; ++ ++ gpio1: gpio@0209c000 { ++ compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; ++ reg = <0x0209c000 0x4000>; ++ interrupts = <0 66 0x04 0 67 0x04>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio2: gpio@020a0000 { ++ compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; ++ reg = <0x020a0000 0x4000>; ++ interrupts = <0 68 0x04 0 69 0x04>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio3: gpio@020a4000 { ++ compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; ++ reg = <0x020a4000 0x4000>; ++ interrupts = <0 70 0x04 0 71 0x04>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio4: gpio@020a8000 { ++ compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; ++ reg = <0x020a8000 0x4000>; ++ interrupts = <0 72 0x04 0 73 0x04>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio5: gpio@020ac000 { ++ compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; ++ reg = <0x020ac000 0x4000>; ++ interrupts = <0 74 0x04 0 75 0x04>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ kpp: kpp@020b8000 { ++ compatible = "fsl,imx6sl-kpp", "fsl,imx21-kpp"; ++ reg = <0x020b8000 0x4000>; ++ interrupts = <0 82 0x04>; ++ clocks = <&clks IMX6SL_CLK_DUMMY>; ++ }; ++ ++ wdog1: wdog@020bc000 { ++ compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt"; ++ reg = <0x020bc000 0x4000>; ++ interrupts = <0 80 0x04>; ++ clocks = <&clks IMX6SL_CLK_DUMMY>; ++ }; ++ ++ wdog2: wdog@020c0000 { ++ compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt"; ++ reg = <0x020c0000 0x4000>; ++ interrupts = <0 81 0x04>; ++ clocks = <&clks IMX6SL_CLK_DUMMY>; ++ status = "disabled"; ++ }; ++ ++ clks: ccm@020c4000 { ++ compatible = "fsl,imx6sl-ccm"; ++ reg = <0x020c4000 0x4000>; ++ interrupts = <0 87 0x04 0 88 0x04>; ++ #clock-cells = <1>; ++ }; ++ ++ anatop: anatop@020c8000 { ++ compatible = "fsl,imx6sl-anatop", ++ "fsl,imx6q-anatop", ++ "syscon", "simple-bus"; ++ reg = <0x020c8000 0x1000>; ++ interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>; ++ ++ regulator-1p1@110 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "vdd1p1"; ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <1375000>; ++ regulator-always-on; ++ anatop-reg-offset = <0x110>; ++ anatop-vol-bit-shift = <8>; ++ anatop-vol-bit-width = <5>; ++ anatop-min-bit-val = <4>; ++ anatop-min-voltage = <800000>; ++ anatop-max-voltage = <1375000>; ++ }; ++ ++ regulator-3p0@120 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "vdd3p0"; ++ regulator-min-microvolt = <2800000>; ++ regulator-max-microvolt = <3150000>; ++ regulator-always-on; ++ anatop-reg-offset = <0x120>; ++ anatop-vol-bit-shift = <8>; ++ anatop-vol-bit-width = <5>; ++ anatop-min-bit-val = <0>; ++ anatop-min-voltage = <2625000>; ++ anatop-max-voltage = <3400000>; ++ }; ++ ++ regulator-2p5@130 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "vdd2p5"; ++ regulator-min-microvolt = <2100000>; ++ regulator-max-microvolt = <2850000>; ++ regulator-always-on; ++ anatop-reg-offset = <0x130>; ++ anatop-vol-bit-shift = <8>; ++ anatop-vol-bit-width = <5>; ++ anatop-min-bit-val = <0>; ++ anatop-min-voltage = <2100000>; ++ anatop-max-voltage = <2850000>; ++ }; ++ ++ reg_arm: regulator-vddcore@140 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "cpu"; ++ regulator-min-microvolt = <725000>; ++ regulator-max-microvolt = <1450000>; ++ regulator-always-on; ++ anatop-reg-offset = <0x140>; ++ anatop-vol-bit-shift = <0>; ++ anatop-vol-bit-width = <5>; ++ anatop-delay-reg-offset = <0x170>; ++ anatop-delay-bit-shift = <24>; ++ anatop-delay-bit-width = <2>; ++ anatop-min-bit-val = <1>; ++ anatop-min-voltage = <725000>; ++ anatop-max-voltage = <1450000>; ++ }; ++ ++ reg_pu: regulator-vddpu@140 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "vddpu"; ++ regulator-min-microvolt = <725000>; ++ regulator-max-microvolt = <1450000>; ++ anatop-reg-offset = <0x140>; ++ anatop-vol-bit-shift = <9>; ++ anatop-vol-bit-width = <5>; ++ anatop-delay-reg-offset = <0x170>; ++ anatop-delay-bit-shift = <26>; ++ anatop-delay-bit-width = <2>; ++ anatop-min-bit-val = <1>; ++ anatop-min-voltage = <725000>; ++ anatop-max-voltage = <1450000>; ++ }; ++ ++ reg_soc: regulator-vddsoc@140 { ++ compatible = "fsl,anatop-regulator"; ++ regulator-name = "vddsoc"; ++ regulator-min-microvolt = <725000>; ++ regulator-max-microvolt = <1450000>; ++ regulator-always-on; ++ anatop-reg-offset = <0x140>; ++ anatop-vol-bit-shift = <18>; ++ anatop-vol-bit-width = <5>; ++ anatop-delay-reg-offset = <0x170>; ++ anatop-delay-bit-shift = <28>; ++ anatop-delay-bit-width = <2>; ++ anatop-min-bit-val = <1>; ++ anatop-min-voltage = <725000>; ++ anatop-max-voltage = <1450000>; ++ }; ++ }; ++ ++ tempmon: tempmon { ++ compatible = "fsl,imx6sl-tempmon", "fsl,imx6q-tempmon"; ++ interrupts = <0 49 0x04>; ++ fsl,tempmon = <&anatop>; ++ fsl,tempmon-data = <&ocotp>; ++ clocks = <&clks IMX6SL_CLK_PLL3_USB_OTG>; ++ }; ++ ++ usbphy1: usbphy@020c9000 { ++ compatible = "fsl,imx6sl-usbphy", "fsl,imx23-usbphy"; ++ reg = <0x020c9000 0x1000>; ++ interrupts = <0 44 0x04>; ++ clocks = <&clks IMX6SL_CLK_USBPHY1>; ++ fsl,anatop = <&anatop>; ++ }; ++ ++ usbphy2: usbphy@020ca000 { ++ compatible = "fsl,imx6sl-usbphy", "fsl,imx23-usbphy"; ++ reg = <0x020ca000 0x1000>; ++ interrupts = <0 45 0x04>; ++ clocks = <&clks IMX6SL_CLK_USBPHY2>; ++ fsl,anatop = <&anatop>; ++ }; ++ ++ snvs@020cc000 { ++ compatible = "fsl,sec-v4.0-mon", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0x020cc000 0x4000>; ++ ++ snvs-rtc-lp@34 { ++ compatible = "fsl,sec-v4.0-mon-rtc-lp"; ++ reg = <0x34 0x58>; ++ interrupts = <0 19 0x04 0 20 0x04>; ++ }; ++ }; ++ ++ epit1: epit@020d0000 { ++ reg = <0x020d0000 0x4000>; ++ interrupts = <0 56 0x04>; ++ }; ++ ++ epit2: epit@020d4000 { ++ reg = <0x020d4000 0x4000>; ++ interrupts = <0 57 0x04>; ++ }; ++ ++ src: src@020d8000 { ++ compatible = "fsl,imx6sl-src", "fsl,imx51-src"; ++ reg = <0x020d8000 0x4000>; ++ interrupts = <0 91 0x04 0 96 0x04>; ++ #reset-cells = <1>; ++ }; ++ ++ ocram: sram@00900000 { ++ compatible = "mmio-sram"; ++ reg = <0x00900000 0x20000>; ++ clocks = <&clks IMX6SL_CLK_OCRAM>; ++ }; ++ ++ gpc: gpc@020dc000 { ++ compatible = "fsl,imx6sl-gpc", "fsl,imx6q-gpc"; ++ reg = <0x020dc000 0x4000>; ++ interrupts = <0 89 0x04>; ++ clocks = <&clks IMX6SL_CLK_GPU2D_PODF>, <&clks IMX6SL_CLK_GPU2D_OVG>, ++ <&clks IMX6SL_CLK_IPG>, <&clks IMX6SL_CLK_LCDIF_AXI>, ++ <&clks IMX6SL_CLK_LCDIF_PIX>, <&clks IMX6SL_CLK_EPDC_AXI>, ++ <&clks IMX6SL_CLK_EPDC_PIX>, <&clks IMX6SL_CLK_PXP_AXI>; ++ clock-names = "gpu2d_podf", "gpu2d_ovg", "ipg", "lcd_axi", ++ "lcd_pix", "epdc_axi", "epdc_pix", "pxp_axi"; ++ pu-supply = <®_pu>; ++ }; ++ ++ gpr: iomuxc-gpr@020e0000 { ++ compatible = "fsl,imx6sl-iomuxc-gpr", "syscon"; ++ reg = <0x020e0000 0x38>; ++ }; ++ ++ iomuxc: iomuxc@020e0000 { ++ compatible = "fsl,imx6sl-iomuxc"; ++ reg = <0x020e0000 0x4000>; ++ ++ audmux { ++ pinctrl_audmux_1: audmux-1 { ++ fsl,pins = < ++ MX6SL_PAD_AUD_RXD__AUD3_RXD 0x4130B0 ++ MX6SL_PAD_AUD_TXC__AUD3_TXC 0x4130B0 ++ MX6SL_PAD_AUD_TXD__AUD3_TXD 0x4110B0 ++ MX6SL_PAD_AUD_TXFS__AUD3_TXFS 0x4130B0 ++ MX6SL_PAD_AUD_MCLK__AUDIO_CLK_OUT 0x4130B0 ++ >; ++ }; ++ }; ++ ++ csi { ++ pinctrl_csi_0: csigrp-0 { ++ fsl,pins = < ++ MX6SL_PAD_EPDC_GDRL__CSI_MCLK 0x110b0 ++ MX6SL_PAD_EPDC_GDCLK__CSI_PIXCLK 0x110b0 ++ MX6SL_PAD_EPDC_GDSP__CSI_VSYNC 0x110b0 ++ MX6SL_PAD_EPDC_GDOE__CSI_HSYNC 0x110b0 ++ MX6SL_PAD_EPDC_SDLE__CSI_DATA09 0x110b0 ++ MX6SL_PAD_EPDC_SDCLK__CSI_DATA08 0x110b0 ++ MX6SL_PAD_EPDC_D7__CSI_DATA07 0x110b0 ++ MX6SL_PAD_EPDC_D6__CSI_DATA06 0x110b0 ++ MX6SL_PAD_EPDC_D5__CSI_DATA05 0x110b0 ++ MX6SL_PAD_EPDC_D4__CSI_DATA04 0x110b0 ++ MX6SL_PAD_EPDC_D3__CSI_DATA03 0x110b0 ++ MX6SL_PAD_EPDC_D2__CSI_DATA02 0x110b0 ++ MX6SL_PAD_EPDC_D1__CSI_DATA01 0x110b0 ++ MX6SL_PAD_EPDC_D0__CSI_DATA00 0x110b0 ++ MX6SL_PAD_EPDC_SDSHR__GPIO1_IO26 0x80000000 ++ MX6SL_PAD_EPDC_SDOE__GPIO1_IO25 0x80000000 ++ >; ++ }; ++ }; ++ ++ ecspi1 { ++ pinctrl_ecspi1_1: ecspi1grp-1 { ++ fsl,pins = < ++ MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO 0x100b1 ++ MX6SL_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x100b1 ++ MX6SL_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x100b1 ++ >; ++ }; ++ }; ++ ++ epdc { ++ pinctrl_epdc_0: epdcgrp-0 { ++ fsl,pins = < ++ MX6SL_PAD_EPDC_D0__EPDC_DATA00 0x80000000 ++ MX6SL_PAD_EPDC_D1__EPDC_DATA01 0x80000000 ++ MX6SL_PAD_EPDC_D2__EPDC_DATA02 0x80000000 ++ MX6SL_PAD_EPDC_D3__EPDC_DATA03 0x80000000 ++ MX6SL_PAD_EPDC_D4__EPDC_DATA04 0x80000000 ++ MX6SL_PAD_EPDC_D5__EPDC_DATA05 0x80000000 ++ MX6SL_PAD_EPDC_D6__EPDC_DATA06 0x80000000 ++ MX6SL_PAD_EPDC_D7__EPDC_DATA07 0x80000000 ++ MX6SL_PAD_EPDC_D8__EPDC_DATA08 0x80000000 ++ MX6SL_PAD_EPDC_D9__EPDC_DATA09 0x80000000 ++ MX6SL_PAD_EPDC_D10__EPDC_DATA10 0x80000000 ++ MX6SL_PAD_EPDC_D11__EPDC_DATA11 0x80000000 ++ MX6SL_PAD_EPDC_D12__EPDC_DATA12 0x80000000 ++ MX6SL_PAD_EPDC_D13__EPDC_DATA13 0x80000000 ++ MX6SL_PAD_EPDC_D14__EPDC_DATA14 0x80000000 ++ MX6SL_PAD_EPDC_D15__EPDC_DATA15 0x80000000 ++ MX6SL_PAD_EPDC_GDCLK__EPDC_GDCLK 0x80000000 ++ MX6SL_PAD_EPDC_GDSP__EPDC_GDSP 0x80000000 ++ MX6SL_PAD_EPDC_GDOE__EPDC_GDOE 0x80000000 ++ MX6SL_PAD_EPDC_GDRL__EPDC_GDRL 0x80000000 ++ MX6SL_PAD_EPDC_SDCLK__EPDC_SDCLK_P 0x80000000 ++ MX6SL_PAD_EPDC_SDOE__EPDC_SDOE 0x80000000 ++ MX6SL_PAD_EPDC_SDLE__EPDC_SDLE 0x80000000 ++ MX6SL_PAD_EPDC_SDSHR__EPDC_SDSHR 0x80000000 ++ MX6SL_PAD_EPDC_BDR0__EPDC_BDR0 0x80000000 ++ MX6SL_PAD_EPDC_SDCE0__EPDC_SDCE0 0x80000000 ++ MX6SL_PAD_EPDC_SDCE1__EPDC_SDCE1 0x80000000 ++ MX6SL_PAD_EPDC_SDCE2__EPDC_SDCE2 0x80000000 ++ >; ++ }; ++ }; ++ ++ fec { ++ pinctrl_fec_1: fecgrp-1 { ++ fsl,pins = < ++ MX6SL_PAD_FEC_MDC__FEC_MDC 0x1b0b0 ++ MX6SL_PAD_FEC_MDIO__FEC_MDIO 0x1b0b0 ++ MX6SL_PAD_FEC_CRS_DV__FEC_RX_DV 0x1b0b0 ++ MX6SL_PAD_FEC_RXD0__FEC_RX_DATA0 0x1b0b0 ++ MX6SL_PAD_FEC_RXD1__FEC_RX_DATA1 0x1b0b0 ++ MX6SL_PAD_FEC_TX_EN__FEC_TX_EN 0x1b0b0 ++ MX6SL_PAD_FEC_TXD0__FEC_TX_DATA0 0x1b0b0 ++ MX6SL_PAD_FEC_TXD1__FEC_TX_DATA1 0x1b0b0 ++ MX6SL_PAD_FEC_REF_CLK__FEC_REF_OUT 0x4001b0a8 ++ >; ++ }; ++ }; ++ ++ spdif { ++ pinctrl_spdif_1: spdifgrp-1 { ++ fsl,pins = < ++ MX6SL_PAD_SD2_DAT4__SPDIF_OUT 0x80000000 ++ >; ++ }; ++ }; ++ ++ uart1 { ++ pinctrl_uart1_1: uart1grp-1 { ++ fsl,pins = < ++ MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1 ++ MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1 ++ >; ++ }; ++ }; ++ ++ usbotg1 { ++ pinctrl_usbotg1_1: usbotg1grp-1 { ++ fsl,pins = < ++ MX6SL_PAD_EPDC_PWRCOM__USB_OTG1_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg1_2: usbotg1grp-2 { ++ fsl,pins = < ++ MX6SL_PAD_FEC_RXD0__USB_OTG1_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg1_3: usbotg1grp-3 { ++ fsl,pins = < ++ MX6SL_PAD_LCD_DAT1__USB_OTG1_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg1_4: usbotg1grp-4 { ++ fsl,pins = < ++ MX6SL_PAD_REF_CLK_32K__USB_OTG1_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg1_5: usbotg1grp-5 { ++ fsl,pins = < ++ MX6SL_PAD_SD3_DAT0__USB_OTG1_ID 0x17059 ++ >; ++ }; ++ }; ++ ++ usbotg2 { ++ pinctrl_usbotg2_1: usbotg2grp-1 { ++ fsl,pins = < ++ MX6SL_PAD_ECSPI1_SCLK__USB_OTG2_OC 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg2_2: usbotg2grp-2 { ++ fsl,pins = < ++ MX6SL_PAD_ECSPI2_SCLK__USB_OTG2_OC 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg2_3: usbotg2grp-3 { ++ fsl,pins = < ++ MX6SL_PAD_KEY_ROW5__USB_OTG2_OC 0x17059 ++ >; ++ }; ++ ++ pinctrl_usbotg2_4: usbotg2grp-4 { ++ fsl,pins = < ++ MX6SL_PAD_SD3_DAT2__USB_OTG2_OC 0x17059 ++ >; ++ }; ++ }; ++ ++ usdhc1 { ++ pinctrl_usdhc1_1: usdhc1grp-1 { ++ fsl,pins = < ++ MX6SL_PAD_SD1_CMD__SD1_CMD 0x17059 ++ MX6SL_PAD_SD1_CLK__SD1_CLK 0x10059 ++ MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x17059 ++ MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x17059 ++ MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x17059 ++ MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x17059 ++ MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x17059 ++ MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x17059 ++ MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x17059 ++ MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x17059 ++ >; ++ }; ++ }; ++ ++ usdhc2 { ++ pinctrl_usdhc2_1: usdhc2grp-1 { ++ fsl,pins = < ++ MX6SL_PAD_SD2_CMD__SD2_CMD 0x17059 ++ MX6SL_PAD_SD2_CLK__SD2_CLK 0x10059 ++ MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x17059 ++ MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x17059 ++ MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x17059 ++ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc2_1_100mhz: usdhc2grp-1-100mhz { ++ fsl,pins = < ++ MX6SL_PAD_SD2_CMD__SD2_CMD 0x170b9 ++ MX6SL_PAD_SD2_CLK__SD2_CLK 0x100b9 ++ MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170b9 ++ MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170b9 ++ MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170b9 ++ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc2_1_200mhz: usdhc2grp-1-200mhz { ++ fsl,pins = < ++ MX6SL_PAD_SD2_CMD__SD2_CMD 0x170f9 ++ MX6SL_PAD_SD2_CLK__SD2_CLK 0x100f9 ++ MX6SL_PAD_SD2_DAT0__SD2_DATA0 0x170f9 ++ MX6SL_PAD_SD2_DAT1__SD2_DATA1 0x170f9 ++ MX6SL_PAD_SD2_DAT2__SD2_DATA2 0x170f9 ++ MX6SL_PAD_SD2_DAT3__SD2_DATA3 0x170f9 ++ >; ++ }; ++ }; ++ ++ usdhc3 { ++ pinctrl_usdhc3_1: usdhc3grp-1 { ++ fsl,pins = < ++ MX6SL_PAD_SD3_CMD__SD3_CMD 0x17059 ++ MX6SL_PAD_SD3_CLK__SD3_CLK 0x10059 ++ MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x17059 ++ MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x17059 ++ MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x17059 ++ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3_1_100mhz: usdhc3grp-1-100mhz { ++ fsl,pins = < ++ MX6SL_PAD_SD3_CMD__SD3_CMD 0x170b9 ++ MX6SL_PAD_SD3_CLK__SD3_CLK 0x100b9 ++ MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170b9 ++ MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170b9 ++ MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170b9 ++ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc3_1_200mhz: usdhc3grp-1-200mhz { ++ fsl,pins = < ++ MX6SL_PAD_SD3_CMD__SD3_CMD 0x170f9 ++ MX6SL_PAD_SD3_CLK__SD3_CLK 0x100f9 ++ MX6SL_PAD_SD3_DAT0__SD3_DATA0 0x170f9 ++ MX6SL_PAD_SD3_DAT1__SD3_DATA1 0x170f9 ++ MX6SL_PAD_SD3_DAT2__SD3_DATA2 0x170f9 ++ MX6SL_PAD_SD3_DAT3__SD3_DATA3 0x170f9 ++ >; ++ }; ++ }; ++ ++ i2c1 { ++ pinctrl_i2c1_1: i2c1grp-1 { ++ fsl,pins = < ++ MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x4001b8b1 ++ MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ i2c2 { ++ pinctrl_i2c2_1: i2c2grp-1 { ++ fsl,pins = < ++ MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x4001b8b1 ++ MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ i2c3 { ++ pinctrl_i2c3_1: i2c3grp-1 { ++ fsl,pins = < ++ MX6SL_PAD_EPDC_SDCE2__I2C3_SCL 0x4001b8b1 ++ MX6SL_PAD_EPDC_SDCE3__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ }; ++ ++ kpp { ++ pinctrl_kpp_1: kpp_grp_1 { ++ fsl,pins = < ++ MX6SL_PAD_KEY_ROW0__KEY_ROW0 0x1b010 ++ MX6SL_PAD_KEY_ROW1__KEY_ROW1 0x1b010 ++ MX6SL_PAD_KEY_ROW2__KEY_ROW2 0x1b0b0 ++ MX6SL_PAD_KEY_COL0__KEY_COL0 0x1b0b0 ++ MX6SL_PAD_KEY_COL1__KEY_COL1 0x1b0b0 ++ MX6SL_PAD_KEY_COL2__KEY_COL2 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_kpp_1_sleep: kpp_grp_1_sleep { ++ fsl,pins = < ++ MX6SL_PAD_KEY_ROW0__GPIO3_IO25 0x3080 ++ MX6SL_PAD_KEY_ROW1__GPIO3_IO27 0x3080 ++ MX6SL_PAD_KEY_ROW2__GPIO3_IO29 0x3080 ++ MX6SL_PAD_KEY_COL0__GPIO3_IO24 0x3080 ++ MX6SL_PAD_KEY_COL1__GPIO3_IO26 0x3080 ++ MX6SL_PAD_KEY_COL2__GPIO3_IO28 0x3080 ++ >; ++ }; ++ }; ++ ++ lcdif { ++ pinctrl_lcdif_dat_0: lcdifdatgrp-0 { ++ fsl,pins = < ++ MX6SL_PAD_LCD_DAT0__LCD_DATA00 0x1b0b0 ++ MX6SL_PAD_LCD_DAT1__LCD_DATA01 0x1b0b0 ++ MX6SL_PAD_LCD_DAT2__LCD_DATA02 0x1b0b0 ++ MX6SL_PAD_LCD_DAT3__LCD_DATA03 0x1b0b0 ++ MX6SL_PAD_LCD_DAT4__LCD_DATA04 0x1b0b0 ++ MX6SL_PAD_LCD_DAT5__LCD_DATA05 0x1b0b0 ++ MX6SL_PAD_LCD_DAT6__LCD_DATA06 0x1b0b0 ++ MX6SL_PAD_LCD_DAT7__LCD_DATA07 0x1b0b0 ++ MX6SL_PAD_LCD_DAT8__LCD_DATA08 0x1b0b0 ++ MX6SL_PAD_LCD_DAT9__LCD_DATA09 0x1b0b0 ++ MX6SL_PAD_LCD_DAT10__LCD_DATA10 0x1b0b0 ++ MX6SL_PAD_LCD_DAT11__LCD_DATA11 0x1b0b0 ++ MX6SL_PAD_LCD_DAT12__LCD_DATA12 0x1b0b0 ++ MX6SL_PAD_LCD_DAT13__LCD_DATA13 0x1b0b0 ++ MX6SL_PAD_LCD_DAT14__LCD_DATA14 0x1b0b0 ++ MX6SL_PAD_LCD_DAT15__LCD_DATA15 0x1b0b0 ++ MX6SL_PAD_LCD_DAT16__LCD_DATA16 0x1b0b0 ++ MX6SL_PAD_LCD_DAT17__LCD_DATA17 0x1b0b0 ++ MX6SL_PAD_LCD_DAT18__LCD_DATA18 0x1b0b0 ++ MX6SL_PAD_LCD_DAT19__LCD_DATA19 0x1b0b0 ++ MX6SL_PAD_LCD_DAT20__LCD_DATA20 0x1b0b0 ++ MX6SL_PAD_LCD_DAT21__LCD_DATA21 0x1b0b0 ++ MX6SL_PAD_LCD_DAT22__LCD_DATA22 0x1b0b0 ++ MX6SL_PAD_LCD_DAT23__LCD_DATA23 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_lcdif_ctrl_0: lcdifctrlgrp-0 { ++ fsl,pins = < ++ MX6SL_PAD_LCD_CLK__LCD_CLK 0x1b0b0 ++ MX6SL_PAD_LCD_ENABLE__LCD_ENABLE 0x1b0b0 ++ MX6SL_PAD_LCD_HSYNC__LCD_HSYNC 0x1b0b0 ++ MX6SL_PAD_LCD_VSYNC__LCD_VSYNC 0x1b0b0 ++ >; ++ }; ++ }; ++ ++ pwm1 { ++ pinctrl_pwm1_0: pwm1grp-0 { ++ fsl,pins = < ++ MX6SL_PAD_PWM1__PWM1_OUT 0x110b0 ++ >; ++ }; ++ }; ++ }; ++ ++ csi: csi@020e4000 { ++ compatible = "fsl,imx6sl-csi"; ++ reg = <0x020e4000 0x4000>; ++ interrupts = <0 7 0x04>; ++ status = "disabled"; ++ }; ++ ++ spdc: spdc@020e8000 { ++ reg = <0x020e8000 0x4000>; ++ interrupts = <0 6 0x04>; ++ }; ++ ++ sdma: sdma@020ec000 { ++ compatible = "fsl,imx6sl-sdma", "fsl,imx35-sdma"; ++ reg = <0x020ec000 0x4000>; ++ interrupts = <0 2 0x04>; ++ clocks = <&clks IMX6SL_CLK_SDMA>, ++ <&clks IMX6SL_CLK_SDMA>; ++ clock-names = "ipg", "ahb"; ++ iram = <&ocram>; ++ /* imx6sl reuses imx6q sdma firmware */ ++ fsl,sdma-ram-script-name = "imx/sdma/sdma-imx6q.bin"; ++ }; ++ ++ pxp: pxp@020f0000 { ++ compatible = "fsl,imx6sl-pxp-dma", "fsl,imx6dl-pxp-dma"; ++ reg = <0x020f0000 0x4000>; ++ interrupts = <0 98 0x04>; ++ clocks = <&clks 111>; ++ clock-names = "pxp-axi"; ++ status = "disabled"; ++ }; ++ ++ epdc: epdc@020f4000 { ++ compatible = "fsl,imx6sl-epdc", "fsl,imx6dl-epdc"; ++ reg = <0x020f4000 0x4000>; ++ interrupts = <0 97 0x04>; ++ clocks = <&clks IMX6SL_CLK_EPDC_AXI>, ++ <&clks IMX6SL_CLK_EPDC_PIX>; ++ clock-names = "epdc_axi", "epdc_pix"; ++ }; ++ ++ lcdif: lcdif@020f8000 { ++ compatible = "fsl,imx6sl-lcdif", "fsl,imx28-lcdif"; ++ reg = <0x020f8000 0x4000>; ++ interrupts = <0 39 0x04>; ++ clocks = <&clks IMX6SL_CLK_LCDIF_PIX>, ++ <&clks IMX6SL_CLK_LCDIF_AXI>; ++ clock-names = "pix", "axi"; ++ status = "disabled"; ++ }; ++ ++ dcp: dcp@020fc000 { ++ reg = <0x020fc000 0x4000>; ++ interrupts = <0 99 0x04>; ++ }; ++ }; ++ ++ aips2: aips-bus@02100000 { ++ compatible = "fsl,aips-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x02100000 0x100000>; ++ ranges; ++ ++ usbotg1: usb@02184000 { ++ compatible = "fsl,imx6sl-usb", "fsl,imx27-usb"; ++ reg = <0x02184000 0x200>; ++ interrupts = <0 43 0x04>; ++ clocks = <&clks IMX6SL_CLK_USBOH3>; ++ fsl,usbphy = <&usbphy1>; ++ fsl,usbmisc = <&usbmisc 0>; ++ fsl,anatop = <&anatop>; ++ status = "disabled"; ++ }; ++ ++ usbotg2: usb@02184200 { ++ compatible = "fsl,imx6sl-usb", "fsl,imx27-usb"; ++ reg = <0x02184200 0x200>; ++ interrupts = <0 42 0x04>; ++ clocks = <&clks IMX6SL_CLK_USBOH3>; ++ fsl,usbphy = <&usbphy2>; ++ fsl,usbmisc = <&usbmisc 1>; ++ status = "disabled"; ++ }; ++ ++ usbh: usb@02184400 { ++ compatible = "fsl,imx6sl-usb", "fsl,imx27-usb"; ++ reg = <0x02184400 0x200>; ++ interrupts = <0 40 0x04>; ++ clocks = <&clks IMX6SL_CLK_USBOH3>; ++ fsl,usbmisc = <&usbmisc 2>; ++ status = "disabled"; ++ }; ++ ++ usbmisc: usbmisc@02184800 { ++ #index-cells = <1>; ++ compatible = "fsl,imx6sl-usbmisc", "fsl,imx6q-usbmisc"; ++ reg = <0x02184800 0x200>; ++ clocks = <&clks IMX6SL_CLK_USBOH3>; ++ }; ++ ++ fec: ethernet@02188000 { ++ compatible = "fsl,imx6sl-fec", "fsl,imx25-fec"; ++ reg = <0x02188000 0x4000>; ++ interrupts = <0 114 0x04>; ++ clocks = <&clks IMX6SL_CLK_ENET>, ++ <&clks IMX6SL_CLK_ENET_REF>; ++ clock-names = "ipg", "ahb"; ++ status = "disabled"; ++ }; ++ ++ usdhc1: usdhc@02190000 { ++ compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; ++ reg = <0x02190000 0x4000>; ++ interrupts = <0 22 0x04>; ++ clocks = <&clks IMX6SL_CLK_USDHC1>, ++ <&clks IMX6SL_CLK_USDHC1>, ++ <&clks IMX6SL_CLK_USDHC1>; ++ clock-names = "ipg", "ahb", "per"; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ usdhc2: usdhc@02194000 { ++ compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; ++ reg = <0x02194000 0x4000>; ++ interrupts = <0 23 0x04>; ++ clocks = <&clks IMX6SL_CLK_USDHC2>, ++ <&clks IMX6SL_CLK_USDHC2>, ++ <&clks IMX6SL_CLK_USDHC2>; ++ clock-names = "ipg", "ahb", "per"; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ usdhc3: usdhc@02198000 { ++ compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; ++ reg = <0x02198000 0x4000>; ++ interrupts = <0 24 0x04>; ++ clocks = <&clks IMX6SL_CLK_USDHC3>, ++ <&clks IMX6SL_CLK_USDHC3>, ++ <&clks IMX6SL_CLK_USDHC3>; ++ clock-names = "ipg", "ahb", "per"; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ usdhc4: usdhc@0219c000 { ++ compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; ++ reg = <0x0219c000 0x4000>; ++ interrupts = <0 25 0x04>; ++ clocks = <&clks IMX6SL_CLK_USDHC4>, ++ <&clks IMX6SL_CLK_USDHC4>, ++ <&clks IMX6SL_CLK_USDHC4>; ++ clock-names = "ipg", "ahb", "per"; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ i2c1: i2c@021a0000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c"; ++ reg = <0x021a0000 0x4000>; ++ interrupts = <0 36 0x04>; ++ clocks = <&clks IMX6SL_CLK_I2C1>; ++ status = "disabled"; ++ }; ++ ++ i2c2: i2c@021a4000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c"; ++ reg = <0x021a4000 0x4000>; ++ interrupts = <0 37 0x04>; ++ clocks = <&clks IMX6SL_CLK_I2C2>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@021a8000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c"; ++ reg = <0x021a8000 0x4000>; ++ interrupts = <0 38 0x04>; ++ clocks = <&clks IMX6SL_CLK_I2C3>; ++ status = "disabled"; ++ }; ++ ++ mmdc: mmdc@021b0000 { ++ compatible = "fsl,imx6sl-mmdc", "fsl,imx6q-mmdc"; ++ reg = <0x021b0000 0x4000>; ++ }; ++ ++ rngb: rngb@021b4000 { ++ reg = <0x021b4000 0x4000>; ++ interrupts = <0 5 0x04>; ++ }; ++ ++ weim: weim@021b8000 { ++ reg = <0x021b8000 0x4000>; ++ interrupts = <0 14 0x04>; ++ }; ++ ++ ocotp: ocotp-ctrl@021bc000 { ++ compatible = "syscon"; ++ reg = <0x021bc000 0x4000>; ++ }; ++ ++ ocotp-fuse@021bc000 { ++ compatible = "fsl,imx6sl-ocotp", "fsl,imx6q-ocotp"; ++ reg = <0x021bc000 0x4000>; ++ clocks = <&clks IMX6SL_CLK_OCOTP>; ++ }; ++ ++ audmux: audmux@021d8000 { ++ compatible = "fsl,imx6sl-audmux", "fsl,imx31-audmux"; ++ reg = <0x021d8000 0x4000>; ++ status = "disabled"; ++ }; ++ ++ gpu: gpu@02200000 { ++ compatible = "fsl,imx6sl-gpu", "fsl,imx6q-gpu"; ++ reg = <0x02200000 0x4000>, <0x02204000 0x4000>, ++ <0x80000000 0x0>; ++ reg-names = "iobase_2d", "iobase_vg", ++ "phys_baseaddr"; ++ interrupts = <0 10 0x04>, <0 11 0x04>; ++ interrupt-names = "irq_2d", "irq_vg"; ++ clocks = <&clks IMX6SL_CLK_MMDC_ROOT>, ++ <&clks IMX6SL_CLK_MMDC_ROOT>, ++ <&clks IMX6SL_CLK_GPU2D_OVG>; ++ clock-names = "gpu2d_axi_clk", "openvg_axi_clk", ++ "gpu2d_clk"; ++ resets = <&src 3>, <&src 3>; ++ reset-names = "gpu2d", "gpuvg"; ++ pu-supply = <®_pu>; ++ }; ++ ++ }; ++ ++ pinctrl_fec_1_sleep: fecgrp-1-sleep { ++ fsl,pins = < ++ MX6SL_PAD_FEC_MDC__GPIO4_IO23 0x3080 ++ MX6SL_PAD_FEC_CRS_DV__GPIO4_IO25 0x3080 ++ MX6SL_PAD_FEC_RXD0__GPIO4_IO17 0x3080 ++ MX6SL_PAD_FEC_RXD1__GPIO4_IO18 0x3080 ++ MX6SL_PAD_FEC_TX_EN__GPIO4_IO22 0x3080 ++ MX6SL_PAD_FEC_TXD0__GPIO4_IO24 0x3080 ++ MX6SL_PAD_FEC_TXD1__GPIO4_IO16 0x3080 ++ MX6SL_PAD_FEC_REF_CLK__GPIO4_IO26 0x3080 ++ >; ++ }; ++ ++ pinctrl_pwm1_0_sleep: pwm1grp-0-sleep { ++ fsl,pins = < ++ MX6SL_PAD_PWM1__GPIO3_IO23 0x3080 ++ >; ++ }; ++ ++ pinctrl_usdhc1_1_100mhz: usdhc1grp-1-100mhz { ++ fsl,pins = < ++ MX6SL_PAD_SD1_CMD__SD1_CMD 0x170b9 ++ MX6SL_PAD_SD1_CLK__SD1_CLK 0x100b9 ++ MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170b9 ++ MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170b9 ++ MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170b9 ++ MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170b9 ++ MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170b9 ++ MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170b9 ++ MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170b9 ++ MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170b9 ++ >; ++ }; ++ ++ pinctrl_usdhc1_1_200mhz: usdhc1grp-1-200mhz { ++ fsl,pins = < ++ MX6SL_PAD_SD1_CMD__SD1_CMD 0x170f9 ++ MX6SL_PAD_SD1_CLK__SD1_CLK 0x100f9 ++ MX6SL_PAD_SD1_DAT0__SD1_DATA0 0x170f9 ++ MX6SL_PAD_SD1_DAT1__SD1_DATA1 0x170f9 ++ MX6SL_PAD_SD1_DAT2__SD1_DATA2 0x170f9 ++ MX6SL_PAD_SD1_DAT3__SD1_DATA3 0x170f9 ++ MX6SL_PAD_SD1_DAT4__SD1_DATA4 0x170f9 ++ MX6SL_PAD_SD1_DAT5__SD1_DATA5 0x170f9 ++ MX6SL_PAD_SD1_DAT6__SD1_DATA6 0x170f9 ++ MX6SL_PAD_SD1_DAT7__SD1_DATA7 0x170f9 ++ >; ++ }; ++ ++ }; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/include/dt-bindings/clock/imx6sl-clock.h linux-3.10.30-cubox-i/arch/arm/boot/dts/include/dt-bindings/clock/imx6sl-clock.h +--- linux-3.10.30/arch/arm/boot/dts/include/dt-bindings/clock/imx6sl-clock.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/include/dt-bindings/clock/imx6sl-clock.h 2014-03-08 20:34:36.000000000 +0100 +@@ -0,0 +1,152 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 __DT_BINDINGS_CLOCK_IMX6SL_H ++#define __DT_BINDINGS_CLOCK_IMX6SL_H ++ ++#define IMX6SL_CLK_DUMMY 0 ++#define IMX6SL_CLK_CKIL 1 ++#define IMX6SL_CLK_OSC 2 ++#define IMX6SL_CLK_PLL1_SYS 3 ++#define IMX6SL_CLK_PLL2_BUS 4 ++#define IMX6SL_CLK_PLL3_USB_OTG 5 ++#define IMX6SL_CLK_PLL4_AUDIO 6 ++#define IMX6SL_CLK_PLL5_VIDEO 7 ++#define IMX6SL_CLK_PLL6_ENET 8 ++#define IMX6SL_CLK_PLL7_USB_HOST 9 ++#define IMX6SL_CLK_USBPHY1 10 ++#define IMX6SL_CLK_USBPHY2 11 ++#define IMX6SL_CLK_USBPHY1_GATE 12 ++#define IMX6SL_CLK_USBPHY2_GATE 13 ++#define IMX6SL_CLK_PLL4_POST_DIV 14 ++#define IMX6SL_CLK_PLL5_POST_DIV 15 ++#define IMX6SL_CLK_PLL5_VIDEO_DIV 16 ++#define IMX6SL_CLK_ENET_REF 17 ++#define IMX6SL_CLK_PLL2_PFD0 18 ++#define IMX6SL_CLK_PLL2_PFD1 19 ++#define IMX6SL_CLK_PLL2_PFD2 20 ++#define IMX6SL_CLK_PLL3_PFD0 21 ++#define IMX6SL_CLK_PLL3_PFD1 22 ++#define IMX6SL_CLK_PLL3_PFD2 23 ++#define IMX6SL_CLK_PLL3_PFD3 24 ++#define IMX6SL_CLK_PLL2_198M 25 ++#define IMX6SL_CLK_PLL3_120M 26 ++#define IMX6SL_CLK_PLL3_80M 27 ++#define IMX6SL_CLK_PLL3_60M 28 ++#define IMX6SL_CLK_STEP 29 ++#define IMX6SL_CLK_PLL1_SW 30 ++#define IMX6SL_CLK_OCRAM_ALT_SEL 31 ++#define IMX6SL_CLK_OCRAM_SEL 32 ++#define IMX6SL_CLK_PRE_PERIPH2_SEL 33 ++#define IMX6SL_CLK_PRE_PERIPH_SEL 34 ++#define IMX6SL_CLK_PERIPH2_CLK2_SEL 35 ++#define IMX6SL_CLK_PERIPH_CLK2_SEL 36 ++#define IMX6SL_CLK_CSI_SEL 37 ++#define IMX6SL_CLK_LCDIF_AXI_SEL 38 ++#define IMX6SL_CLK_USDHC1_SEL 39 ++#define IMX6SL_CLK_USDHC2_SEL 40 ++#define IMX6SL_CLK_USDHC3_SEL 41 ++#define IMX6SL_CLK_USDHC4_SEL 42 ++#define IMX6SL_CLK_SSI1_SEL 43 ++#define IMX6SL_CLK_SSI2_SEL 44 ++#define IMX6SL_CLK_SSI3_SEL 45 ++#define IMX6SL_CLK_PERCLK_SEL 46 ++#define IMX6SL_CLK_PXP_AXI_SEL 47 ++#define IMX6SL_CLK_EPDC_AXI_SEL 48 ++#define IMX6SL_CLK_GPU2D_OVG_SEL 49 ++#define IMX6SL_CLK_GPU2D_SEL 50 ++#define IMX6SL_CLK_LCDIF_PIX_SEL 51 ++#define IMX6SL_CLK_EPDC_PIX_SEL 52 ++#define IMX6SL_CLK_SPDIF0_SEL 53 ++#define IMX6SL_CLK_SPDIF1_SEL 54 ++#define IMX6SL_CLK_EXTERN_AUDIO_SEL 55 ++#define IMX6SL_CLK_ECSPI_SEL 56 ++#define IMX6SL_CLK_UART_SEL 57 ++#define IMX6SL_CLK_PERIPH 58 ++#define IMX6SL_CLK_PERIPH2 59 ++#define IMX6SL_CLK_OCRAM_PODF 60 ++#define IMX6SL_CLK_PERIPH_CLK2 61 ++#define IMX6SL_CLK_PERIPH2_CLK2 62 ++#define IMX6SL_CLK_IPG 63 ++#define IMX6SL_CLK_CSI_PODF 64 ++#define IMX6SL_CLK_LCDIF_AXI_PODF 65 ++#define IMX6SL_CLK_USDHC1_PODF 66 ++#define IMX6SL_CLK_USDHC2_PODF 67 ++#define IMX6SL_CLK_USDHC3_PODF 68 ++#define IMX6SL_CLK_USDHC4_PODF 69 ++#define IMX6SL_CLK_SSI1_PRED 70 ++#define IMX6SL_CLK_SSI1_PODF 71 ++#define IMX6SL_CLK_SSI2_PRED 72 ++#define IMX6SL_CLK_SSI2_PODF 73 ++#define IMX6SL_CLK_SSI3_PRED 74 ++#define IMX6SL_CLK_SSI3_PODF 75 ++#define IMX6SL_CLK_PERCLK 76 ++#define IMX6SL_CLK_PXP_AXI_PODF 77 ++#define IMX6SL_CLK_EPDC_AXI_PODF 78 ++#define IMX6SL_CLK_GPU2D_OVG_PODF 79 ++#define IMX6SL_CLK_GPU2D_PODF 80 ++#define IMX6SL_CLK_LCDIF_PIX_PRED 81 ++#define IMX6SL_CLK_EPDC_PIX_PRED 82 ++#define IMX6SL_CLK_LCDIF_PIX_PODF 83 ++#define IMX6SL_CLK_EPDC_PIX_PODF 84 ++#define IMX6SL_CLK_SPDIF0_PRED 85 ++#define IMX6SL_CLK_SPDIF0_PODF 86 ++#define IMX6SL_CLK_SPDIF1_PRED 87 ++#define IMX6SL_CLK_SPDIF1_PODF 88 ++#define IMX6SL_CLK_EXTERN_AUDIO_PRED 89 ++#define IMX6SL_CLK_EXTERN_AUDIO_PODF 90 ++#define IMX6SL_CLK_ECSPI_ROOT 91 ++#define IMX6SL_CLK_UART_ROOT 92 ++#define IMX6SL_CLK_AHB 93 ++#define IMX6SL_CLK_MMDC_ROOT 94 ++#define IMX6SL_CLK_ARM 95 ++#define IMX6SL_CLK_ECSPI1 96 ++#define IMX6SL_CLK_ECSPI2 97 ++#define IMX6SL_CLK_ECSPI3 98 ++#define IMX6SL_CLK_ECSPI4 99 ++#define IMX6SL_CLK_EPIT1 100 ++#define IMX6SL_CLK_EPIT2 101 ++#define IMX6SL_CLK_EXTERN_AUDIO 102 ++#define IMX6SL_CLK_GPT 103 ++#define IMX6SL_CLK_GPT_SERIAL 104 ++#define IMX6SL_CLK_GPU2D_OVG 105 ++#define IMX6SL_CLK_I2C1 106 ++#define IMX6SL_CLK_I2C2 107 ++#define IMX6SL_CLK_I2C3 108 ++#define IMX6SL_CLK_OCOTP 109 ++#define IMX6SL_CLK_CSI 110 ++#define IMX6SL_CLK_PXP_AXI 111 ++#define IMX6SL_CLK_EPDC_AXI 112 ++#define IMX6SL_CLK_LCDIF_AXI 113 ++#define IMX6SL_CLK_LCDIF_PIX 114 ++#define IMX6SL_CLK_EPDC_PIX 115 ++#define IMX6SL_CLK_OCRAM 116 ++#define IMX6SL_CLK_PWM1 117 ++#define IMX6SL_CLK_PWM2 118 ++#define IMX6SL_CLK_PWM3 119 ++#define IMX6SL_CLK_PWM4 120 ++#define IMX6SL_CLK_SDMA 121 ++#define IMX6SL_CLK_SPDIF 122 ++#define IMX6SL_CLK_SSI1 123 ++#define IMX6SL_CLK_SSI2 124 ++#define IMX6SL_CLK_SSI3 125 ++#define IMX6SL_CLK_UART 126 ++#define IMX6SL_CLK_UART_SERIAL 127 ++#define IMX6SL_CLK_USBOH3 128 ++#define IMX6SL_CLK_USDHC1 129 ++#define IMX6SL_CLK_USDHC2 130 ++#define IMX6SL_CLK_USDHC3 131 ++#define IMX6SL_CLK_USDHC4 132 ++#define IMX6SL_CLK_PLL4_AUDIO_DIV 133 ++#define IMX6SL_CLK_ENET 134 ++#define IMX6SL_CLK_UART_OSC_4M 135 ++#define IMX6SL_CLK_SPBA 136 ++#define IMX6SL_CLK_CLK_END 137 ++ ++#endif /* __DT_BINDINGS_CLOCK_IMX6SL_H */ +diff -Nur linux-3.10.30/arch/arm/boot/dts/include/dt-bindings/clock/vf610-clock.h linux-3.10.30-cubox-i/arch/arm/boot/dts/include/dt-bindings/clock/vf610-clock.h +--- linux-3.10.30/arch/arm/boot/dts/include/dt-bindings/clock/vf610-clock.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/include/dt-bindings/clock/vf610-clock.h 2014-03-08 20:34:36.000000000 +0100 +@@ -0,0 +1,165 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#ifndef __DT_BINDINGS_CLOCK_VF610_H ++#define __DT_BINDINGS_CLOCK_VF610_H ++ ++#define VF610_CLK_DUMMY 0 ++#define VF610_CLK_SIRC_128K 1 ++#define VF610_CLK_SIRC_32K 2 ++#define VF610_CLK_FIRC 3 ++#define VF610_CLK_SXOSC 4 ++#define VF610_CLK_FXOSC 5 ++#define VF610_CLK_FXOSC_HALF 6 ++#define VF610_CLK_SLOW_CLK_SEL 7 ++#define VF610_CLK_FASK_CLK_SEL 8 ++#define VF610_CLK_AUDIO_EXT 9 ++#define VF610_CLK_ENET_EXT 10 ++#define VF610_CLK_PLL1_MAIN 11 ++#define VF610_CLK_PLL1_PFD1 12 ++#define VF610_CLK_PLL1_PFD2 13 ++#define VF610_CLK_PLL1_PFD3 14 ++#define VF610_CLK_PLL1_PFD4 15 ++#define VF610_CLK_PLL2_MAIN 16 ++#define VF610_CLK_PLL2_PFD1 17 ++#define VF610_CLK_PLL2_PFD2 18 ++#define VF610_CLK_PLL2_PFD3 19 ++#define VF610_CLK_PLL2_PFD4 20 ++#define VF610_CLK_PLL3_MAIN 21 ++#define VF610_CLK_PLL3_PFD1 22 ++#define VF610_CLK_PLL3_PFD2 23 ++#define VF610_CLK_PLL3_PFD3 24 ++#define VF610_CLK_PLL3_PFD4 25 ++#define VF610_CLK_PLL4_MAIN 26 ++#define VF610_CLK_PLL5_MAIN 27 ++#define VF610_CLK_PLL6_MAIN 28 ++#define VF610_CLK_PLL3_MAIN_DIV 29 ++#define VF610_CLK_PLL4_MAIN_DIV 30 ++#define VF610_CLK_PLL6_MAIN_DIV 31 ++#define VF610_CLK_PLL1_PFD_SEL 32 ++#define VF610_CLK_PLL2_PFD_SEL 33 ++#define VF610_CLK_SYS_SEL 34 ++#define VF610_CLK_DDR_SEL 35 ++#define VF610_CLK_SYS_BUS 36 ++#define VF610_CLK_PLATFORM_BUS 37 ++#define VF610_CLK_IPG_BUS 38 ++#define VF610_CLK_UART0 39 ++#define VF610_CLK_UART1 40 ++#define VF610_CLK_UART2 41 ++#define VF610_CLK_UART3 42 ++#define VF610_CLK_UART4 43 ++#define VF610_CLK_UART5 44 ++#define VF610_CLK_PIT 45 ++#define VF610_CLK_I2C0 46 ++#define VF610_CLK_I2C1 47 ++#define VF610_CLK_I2C2 48 ++#define VF610_CLK_I2C3 49 ++#define VF610_CLK_FTM0_EXT_SEL 50 ++#define VF610_CLK_FTM0_FIX_SEL 51 ++#define VF610_CLK_FTM0_EXT_FIX_EN 52 ++#define VF610_CLK_FTM1_EXT_SEL 53 ++#define VF610_CLK_FTM1_FIX_SEL 54 ++#define VF610_CLK_FTM1_EXT_FIX_EN 55 ++#define VF610_CLK_FTM2_EXT_SEL 56 ++#define VF610_CLK_FTM2_FIX_SEL 57 ++#define VF610_CLK_FTM2_EXT_FIX_EN 58 ++#define VF610_CLK_FTM3_EXT_SEL 59 ++#define VF610_CLK_FTM3_FIX_SEL 60 ++#define VF610_CLK_FTM3_EXT_FIX_EN 61 ++#define VF610_CLK_FTM0 62 ++#define VF610_CLK_FTM1 63 ++#define VF610_CLK_FTM2 64 ++#define VF610_CLK_FTM3 65 ++#define VF610_CLK_ENET_50M 66 ++#define VF610_CLK_ENET_25M 67 ++#define VF610_CLK_ENET_SEL 68 ++#define VF610_CLK_ENET 69 ++#define VF610_CLK_ENET_TS_SEL 70 ++#define VF610_CLK_ENET_TS 71 ++#define VF610_CLK_DSPI0 72 ++#define VF610_CLK_DSPI1 73 ++#define VF610_CLK_DSPI2 74 ++#define VF610_CLK_DSPI3 75 ++#define VF610_CLK_WDT 76 ++#define VF610_CLK_ESDHC0_SEL 77 ++#define VF610_CLK_ESDHC0_EN 78 ++#define VF610_CLK_ESDHC0_DIV 79 ++#define VF610_CLK_ESDHC0 80 ++#define VF610_CLK_ESDHC1_SEL 81 ++#define VF610_CLK_ESDHC1_EN 82 ++#define VF610_CLK_ESDHC1_DIV 83 ++#define VF610_CLK_ESDHC1 84 ++#define VF610_CLK_DCU0_SEL 85 ++#define VF610_CLK_DCU0_EN 86 ++#define VF610_CLK_DCU0_DIV 87 ++#define VF610_CLK_DCU0 88 ++#define VF610_CLK_DCU1_SEL 89 ++#define VF610_CLK_DCU1_EN 90 ++#define VF610_CLK_DCU1_DIV 91 ++#define VF610_CLK_DCU1 92 ++#define VF610_CLK_ESAI_SEL 93 ++#define VF610_CLK_ESAI_EN 94 ++#define VF610_CLK_ESAI_DIV 95 ++#define VF610_CLK_ESAI 96 ++#define VF610_CLK_SAI0_SEL 97 ++#define VF610_CLK_SAI0_EN 98 ++#define VF610_CLK_SAI0_DIV 99 ++#define VF610_CLK_SAI0 100 ++#define VF610_CLK_SAI1_SEL 101 ++#define VF610_CLK_SAI1_EN 102 ++#define VF610_CLK_SAI1_DIV 103 ++#define VF610_CLK_SAI1 104 ++#define VF610_CLK_SAI2_SEL 105 ++#define VF610_CLK_SAI2_EN 106 ++#define VF610_CLK_SAI2_DIV 107 ++#define VF610_CLK_SAI2 108 ++#define VF610_CLK_SAI3_SEL 109 ++#define VF610_CLK_SAI3_EN 110 ++#define VF610_CLK_SAI3_DIV 111 ++#define VF610_CLK_SAI3 112 ++#define VF610_CLK_USBC0 113 ++#define VF610_CLK_USBC1 114 ++#define VF610_CLK_QSPI0_SEL 115 ++#define VF610_CLK_QSPI0_EN 116 ++#define VF610_CLK_QSPI0_X4_DIV 117 ++#define VF610_CLK_QSPI0_X2_DIV 118 ++#define VF610_CLK_QSPI0_X1_DIV 119 ++#define VF610_CLK_QSPI1_SEL 120 ++#define VF610_CLK_QSPI1_EN 121 ++#define VF610_CLK_QSPI1_X4_DIV 122 ++#define VF610_CLK_QSPI1_X2_DIV 123 ++#define VF610_CLK_QSPI1_X1_DIV 124 ++#define VF610_CLK_QSPI0 125 ++#define VF610_CLK_QSPI1 126 ++#define VF610_CLK_NFC_SEL 127 ++#define VF610_CLK_NFC_EN 128 ++#define VF610_CLK_NFC_PRE_DIV 129 ++#define VF610_CLK_NFC_FRAC_DIV 130 ++#define VF610_CLK_NFC_INV 131 ++#define VF610_CLK_NFC 132 ++#define VF610_CLK_VADC_SEL 133 ++#define VF610_CLK_VADC_EN 134 ++#define VF610_CLK_VADC_DIV 135 ++#define VF610_CLK_VADC_DIV_HALF 136 ++#define VF610_CLK_VADC 137 ++#define VF610_CLK_ADC0 138 ++#define VF610_CLK_ADC1 139 ++#define VF610_CLK_DAC0 140 ++#define VF610_CLK_DAC1 141 ++#define VF610_CLK_FLEXCAN0 142 ++#define VF610_CLK_FLEXCAN1 143 ++#define VF610_CLK_ASRC 144 ++#define VF610_CLK_GPU_SEL 145 ++#define VF610_CLK_GPU_EN 146 ++#define VF610_CLK_GPU2D 147 ++#define VF610_CLK_ENET0 148 ++#define VF610_CLK_ENET1 149 ++#define VF610_CLK_END 150 ++ ++#endif /* __DT_BINDINGS_CLOCK_VF610_H */ +diff -Nur linux-3.10.30/arch/arm/boot/dts/rtsm_ve-cortex_a15x1.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-cortex_a15x1.dts +--- linux-3.10.30/arch/arm/boot/dts/rtsm_ve-cortex_a15x1.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-cortex_a15x1.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,159 @@ ++/* ++ * ARM Ltd. Fast Models ++ * ++ * Versatile Express (VE) system model ++ * ARMCortexA15x1CT ++ * ++ * RTSM_VE_Cortex_A15x1.lisa ++ */ ++ ++/dts-v1/; ++ ++/ { ++ model = "RTSM_VE_CortexA15x1"; ++ arm,vexpress,site = <0xf>; ++ compatible = "arm,rtsm_ve,cortex_a15x1", "arm,vexpress"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ chosen { }; ++ ++ aliases { ++ serial0 = &v2m_serial0; ++ serial1 = &v2m_serial1; ++ serial2 = &v2m_serial2; ++ serial3 = &v2m_serial3; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <0>; ++ }; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0 0x80000000 0 0x80000000>; ++ }; ++ ++ gic: interrupt-controller@2c001000 { ++ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ interrupt-controller; ++ reg = <0 0x2c001000 0 0x1000>, ++ <0 0x2c002000 0 0x1000>, ++ <0 0x2c004000 0 0x2000>, ++ <0 0x2c006000 0 0x2000>; ++ interrupts = <1 9 0xf04>; ++ }; ++ ++ timer { ++ compatible = "arm,armv7-timer"; ++ interrupts = <1 13 0xf08>, ++ <1 14 0xf08>, ++ <1 11 0xf08>, ++ <1 10 0xf08>; ++ }; ++ ++ dcc { ++ compatible = "arm,vexpress,config-bus"; ++ arm,vexpress,config-bridge = <&v2m_sysreg>; ++ ++ osc@0 { ++ /* ACLK clock to the AXI master port on the test chip */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 0>; ++ freq-range = <30000000 50000000>; ++ #clock-cells = <0>; ++ clock-output-names = "extsaxiclk"; ++ }; ++ ++ oscclk1: osc@1 { ++ /* Reference clock for the CLCD */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 1>; ++ freq-range = <10000000 80000000>; ++ #clock-cells = <0>; ++ clock-output-names = "clcdclk"; ++ }; ++ ++ smbclk: oscclk2: osc@2 { ++ /* Reference clock for the test chip internal PLLs */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 2>; ++ freq-range = <33000000 100000000>; ++ #clock-cells = <0>; ++ clock-output-names = "tcrefclk"; ++ }; ++ }; ++ ++ smb { ++ compatible = "simple-bus"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0 0 0 0x08000000 0x04000000>, ++ <1 0 0 0x14000000 0x04000000>, ++ <2 0 0 0x18000000 0x04000000>, ++ <3 0 0 0x1c000000 0x04000000>, ++ <4 0 0 0x0c000000 0x04000000>, ++ <5 0 0 0x10000000 0x04000000>; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 63>; ++ interrupt-map = <0 0 0 &gic 0 0 4>, ++ <0 0 1 &gic 0 1 4>, ++ <0 0 2 &gic 0 2 4>, ++ <0 0 3 &gic 0 3 4>, ++ <0 0 4 &gic 0 4 4>, ++ <0 0 5 &gic 0 5 4>, ++ <0 0 6 &gic 0 6 4>, ++ <0 0 7 &gic 0 7 4>, ++ <0 0 8 &gic 0 8 4>, ++ <0 0 9 &gic 0 9 4>, ++ <0 0 10 &gic 0 10 4>, ++ <0 0 11 &gic 0 11 4>, ++ <0 0 12 &gic 0 12 4>, ++ <0 0 13 &gic 0 13 4>, ++ <0 0 14 &gic 0 14 4>, ++ <0 0 15 &gic 0 15 4>, ++ <0 0 16 &gic 0 16 4>, ++ <0 0 17 &gic 0 17 4>, ++ <0 0 18 &gic 0 18 4>, ++ <0 0 19 &gic 0 19 4>, ++ <0 0 20 &gic 0 20 4>, ++ <0 0 21 &gic 0 21 4>, ++ <0 0 22 &gic 0 22 4>, ++ <0 0 23 &gic 0 23 4>, ++ <0 0 24 &gic 0 24 4>, ++ <0 0 25 &gic 0 25 4>, ++ <0 0 26 &gic 0 26 4>, ++ <0 0 27 &gic 0 27 4>, ++ <0 0 28 &gic 0 28 4>, ++ <0 0 29 &gic 0 29 4>, ++ <0 0 30 &gic 0 30 4>, ++ <0 0 31 &gic 0 31 4>, ++ <0 0 32 &gic 0 32 4>, ++ <0 0 33 &gic 0 33 4>, ++ <0 0 34 &gic 0 34 4>, ++ <0 0 35 &gic 0 35 4>, ++ <0 0 36 &gic 0 36 4>, ++ <0 0 37 &gic 0 37 4>, ++ <0 0 38 &gic 0 38 4>, ++ <0 0 39 &gic 0 39 4>, ++ <0 0 40 &gic 0 40 4>, ++ <0 0 41 &gic 0 41 4>, ++ <0 0 42 &gic 0 42 4>; ++ ++ /include/ "rtsm_ve-motherboard.dtsi" ++ }; ++}; ++ ++/include/ "clcd-panels.dtsi" +diff -Nur linux-3.10.30/arch/arm/boot/dts/rtsm_ve-cortex_a15x2.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-cortex_a15x2.dts +--- linux-3.10.30/arch/arm/boot/dts/rtsm_ve-cortex_a15x2.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-cortex_a15x2.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,165 @@ ++/* ++ * ARM Ltd. Fast Models ++ * ++ * Versatile Express (VE) system model ++ * ARMCortexA15x2CT ++ * ++ * RTSM_VE_Cortex_A15x2.lisa ++ */ ++ ++/dts-v1/; ++ ++/ { ++ model = "RTSM_VE_CortexA15x2"; ++ arm,vexpress,site = <0xf>; ++ compatible = "arm,rtsm_ve,cortex_a15x2", "arm,vexpress"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ chosen { }; ++ ++ aliases { ++ serial0 = &v2m_serial0; ++ serial1 = &v2m_serial1; ++ serial2 = &v2m_serial2; ++ serial3 = &v2m_serial3; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <0>; ++ }; ++ ++ cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <1>; ++ }; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0 0x80000000 0 0x80000000>; ++ }; ++ ++ gic: interrupt-controller@2c001000 { ++ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ interrupt-controller; ++ reg = <0 0x2c001000 0 0x1000>, ++ <0 0x2c002000 0 0x1000>, ++ <0 0x2c004000 0 0x2000>, ++ <0 0x2c006000 0 0x2000>; ++ interrupts = <1 9 0xf04>; ++ }; ++ ++ timer { ++ compatible = "arm,armv7-timer"; ++ interrupts = <1 13 0xf08>, ++ <1 14 0xf08>, ++ <1 11 0xf08>, ++ <1 10 0xf08>; ++ }; ++ ++ dcc { ++ compatible = "arm,vexpress,config-bus"; ++ arm,vexpress,config-bridge = <&v2m_sysreg>; ++ ++ osc@0 { ++ /* ACLK clock to the AXI master port on the test chip */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 0>; ++ freq-range = <30000000 50000000>; ++ #clock-cells = <0>; ++ clock-output-names = "extsaxiclk"; ++ }; ++ ++ oscclk1: osc@1 { ++ /* Reference clock for the CLCD */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 1>; ++ freq-range = <10000000 80000000>; ++ #clock-cells = <0>; ++ clock-output-names = "clcdclk"; ++ }; ++ ++ smbclk: oscclk2: osc@2 { ++ /* Reference clock for the test chip internal PLLs */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 2>; ++ freq-range = <33000000 100000000>; ++ #clock-cells = <0>; ++ clock-output-names = "tcrefclk"; ++ }; ++ }; ++ ++ smb { ++ compatible = "simple-bus"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0 0 0 0x08000000 0x04000000>, ++ <1 0 0 0x14000000 0x04000000>, ++ <2 0 0 0x18000000 0x04000000>, ++ <3 0 0 0x1c000000 0x04000000>, ++ <4 0 0 0x0c000000 0x04000000>, ++ <5 0 0 0x10000000 0x04000000>; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 63>; ++ interrupt-map = <0 0 0 &gic 0 0 4>, ++ <0 0 1 &gic 0 1 4>, ++ <0 0 2 &gic 0 2 4>, ++ <0 0 3 &gic 0 3 4>, ++ <0 0 4 &gic 0 4 4>, ++ <0 0 5 &gic 0 5 4>, ++ <0 0 6 &gic 0 6 4>, ++ <0 0 7 &gic 0 7 4>, ++ <0 0 8 &gic 0 8 4>, ++ <0 0 9 &gic 0 9 4>, ++ <0 0 10 &gic 0 10 4>, ++ <0 0 11 &gic 0 11 4>, ++ <0 0 12 &gic 0 12 4>, ++ <0 0 13 &gic 0 13 4>, ++ <0 0 14 &gic 0 14 4>, ++ <0 0 15 &gic 0 15 4>, ++ <0 0 16 &gic 0 16 4>, ++ <0 0 17 &gic 0 17 4>, ++ <0 0 18 &gic 0 18 4>, ++ <0 0 19 &gic 0 19 4>, ++ <0 0 20 &gic 0 20 4>, ++ <0 0 21 &gic 0 21 4>, ++ <0 0 22 &gic 0 22 4>, ++ <0 0 23 &gic 0 23 4>, ++ <0 0 24 &gic 0 24 4>, ++ <0 0 25 &gic 0 25 4>, ++ <0 0 26 &gic 0 26 4>, ++ <0 0 27 &gic 0 27 4>, ++ <0 0 28 &gic 0 28 4>, ++ <0 0 29 &gic 0 29 4>, ++ <0 0 30 &gic 0 30 4>, ++ <0 0 31 &gic 0 31 4>, ++ <0 0 32 &gic 0 32 4>, ++ <0 0 33 &gic 0 33 4>, ++ <0 0 34 &gic 0 34 4>, ++ <0 0 35 &gic 0 35 4>, ++ <0 0 36 &gic 0 36 4>, ++ <0 0 37 &gic 0 37 4>, ++ <0 0 38 &gic 0 38 4>, ++ <0 0 39 &gic 0 39 4>, ++ <0 0 40 &gic 0 40 4>, ++ <0 0 41 &gic 0 41 4>, ++ <0 0 42 &gic 0 42 4>; ++ ++ /include/ "rtsm_ve-motherboard.dtsi" ++ }; ++}; ++ ++/include/ "clcd-panels.dtsi" +diff -Nur linux-3.10.30/arch/arm/boot/dts/rtsm_ve-cortex_a15x4.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-cortex_a15x4.dts +--- linux-3.10.30/arch/arm/boot/dts/rtsm_ve-cortex_a15x4.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-cortex_a15x4.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,177 @@ ++/* ++ * ARM Ltd. Fast Models ++ * ++ * Versatile Express (VE) system model ++ * ARMCortexA15x4CT ++ * ++ * RTSM_VE_Cortex_A15x4.lisa ++ */ ++ ++/dts-v1/; ++ ++/ { ++ model = "RTSM_VE_CortexA15x4"; ++ arm,vexpress,site = <0xf>; ++ compatible = "arm,rtsm_ve,cortex_a15x4", "arm,vexpress"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ chosen { }; ++ ++ aliases { ++ serial0 = &v2m_serial0; ++ serial1 = &v2m_serial1; ++ serial2 = &v2m_serial2; ++ serial3 = &v2m_serial3; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <0>; ++ }; ++ ++ cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <1>; ++ }; ++ ++ cpu@2 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <2>; ++ }; ++ ++ cpu@3 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <3>; ++ }; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0 0x80000000 0 0x80000000>; ++ }; ++ ++ gic: interrupt-controller@2c001000 { ++ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ interrupt-controller; ++ reg = <0 0x2c001000 0 0x1000>, ++ <0 0x2c002000 0 0x1000>, ++ <0 0x2c004000 0 0x2000>, ++ <0 0x2c006000 0 0x2000>; ++ interrupts = <1 9 0xf04>; ++ }; ++ ++ timer { ++ compatible = "arm,armv7-timer"; ++ interrupts = <1 13 0xf08>, ++ <1 14 0xf08>, ++ <1 11 0xf08>, ++ <1 10 0xf08>; ++ }; ++ ++ dcc { ++ compatible = "arm,vexpress,config-bus"; ++ arm,vexpress,config-bridge = <&v2m_sysreg>; ++ ++ osc@0 { ++ /* ACLK clock to the AXI master port on the test chip */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 0>; ++ freq-range = <30000000 50000000>; ++ #clock-cells = <0>; ++ clock-output-names = "extsaxiclk"; ++ }; ++ ++ oscclk1: osc@1 { ++ /* Reference clock for the CLCD */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 1>; ++ freq-range = <10000000 80000000>; ++ #clock-cells = <0>; ++ clock-output-names = "clcdclk"; ++ }; ++ ++ smbclk: oscclk2: osc@2 { ++ /* Reference clock for the test chip internal PLLs */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 2>; ++ freq-range = <33000000 100000000>; ++ #clock-cells = <0>; ++ clock-output-names = "tcrefclk"; ++ }; ++ }; ++ ++ smb { ++ compatible = "simple-bus"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0 0 0 0x08000000 0x04000000>, ++ <1 0 0 0x14000000 0x04000000>, ++ <2 0 0 0x18000000 0x04000000>, ++ <3 0 0 0x1c000000 0x04000000>, ++ <4 0 0 0x0c000000 0x04000000>, ++ <5 0 0 0x10000000 0x04000000>; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 63>; ++ interrupt-map = <0 0 0 &gic 0 0 4>, ++ <0 0 1 &gic 0 1 4>, ++ <0 0 2 &gic 0 2 4>, ++ <0 0 3 &gic 0 3 4>, ++ <0 0 4 &gic 0 4 4>, ++ <0 0 5 &gic 0 5 4>, ++ <0 0 6 &gic 0 6 4>, ++ <0 0 7 &gic 0 7 4>, ++ <0 0 8 &gic 0 8 4>, ++ <0 0 9 &gic 0 9 4>, ++ <0 0 10 &gic 0 10 4>, ++ <0 0 11 &gic 0 11 4>, ++ <0 0 12 &gic 0 12 4>, ++ <0 0 13 &gic 0 13 4>, ++ <0 0 14 &gic 0 14 4>, ++ <0 0 15 &gic 0 15 4>, ++ <0 0 16 &gic 0 16 4>, ++ <0 0 17 &gic 0 17 4>, ++ <0 0 18 &gic 0 18 4>, ++ <0 0 19 &gic 0 19 4>, ++ <0 0 20 &gic 0 20 4>, ++ <0 0 21 &gic 0 21 4>, ++ <0 0 22 &gic 0 22 4>, ++ <0 0 23 &gic 0 23 4>, ++ <0 0 24 &gic 0 24 4>, ++ <0 0 25 &gic 0 25 4>, ++ <0 0 26 &gic 0 26 4>, ++ <0 0 27 &gic 0 27 4>, ++ <0 0 28 &gic 0 28 4>, ++ <0 0 29 &gic 0 29 4>, ++ <0 0 30 &gic 0 30 4>, ++ <0 0 31 &gic 0 31 4>, ++ <0 0 32 &gic 0 32 4>, ++ <0 0 33 &gic 0 33 4>, ++ <0 0 34 &gic 0 34 4>, ++ <0 0 35 &gic 0 35 4>, ++ <0 0 36 &gic 0 36 4>, ++ <0 0 37 &gic 0 37 4>, ++ <0 0 38 &gic 0 38 4>, ++ <0 0 39 &gic 0 39 4>, ++ <0 0 40 &gic 0 40 4>, ++ <0 0 41 &gic 0 41 4>, ++ <0 0 42 &gic 0 42 4>; ++ ++ /include/ "rtsm_ve-motherboard.dtsi" ++ }; ++}; ++ ++/include/ "clcd-panels.dtsi" +diff -Nur linux-3.10.30/arch/arm/boot/dts/rtsm_ve-cortex_a9x2.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-cortex_a9x2.dts +--- linux-3.10.30/arch/arm/boot/dts/rtsm_ve-cortex_a9x2.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-cortex_a9x2.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,171 @@ ++/* ++ * ARM Ltd. Fast Models ++ * ++ * Versatile Express (VE) system model ++ * ARMCortexA9MPx2CT ++ * ++ * RTSM_VE_Cortex_A9x2.lisa ++ */ ++ ++/dts-v1/; ++ ++/ { ++ model = "RTSM_VE_CortexA9x2"; ++ arm,vexpress,site = <0xf>; ++ compatible = "arm,rtsm_ve,cortex_a9x2", "arm,vexpress"; ++ interrupt-parent = <&gic>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ chosen { }; ++ ++ aliases { ++ serial0 = &v2m_serial0; ++ serial1 = &v2m_serial1; ++ serial2 = &v2m_serial2; ++ serial3 = &v2m_serial3; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ reg = <0>; ++ }; ++ ++ cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ reg = <1>; ++ }; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0x80000000 0x80000000>; ++ }; ++ ++ scu@2c000000 { ++ compatible = "arm,cortex-a9-scu"; ++ reg = <0x2c000000 0x58>; ++ }; ++ ++ timer@2c000600 { ++ compatible = "arm,cortex-a9-twd-timer"; ++ reg = <0x2c000600 0x20>; ++ interrupts = <1 13 0xf04>; ++ }; ++ ++ watchdog@2c000620 { ++ compatible = "arm,cortex-a9-twd-wdt"; ++ reg = <0x2c000620 0x20>; ++ interrupts = <1 14 0xf04>; ++ }; ++ ++ gic: interrupt-controller@2c001000 { ++ compatible = "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ interrupt-controller; ++ reg = <0x2c001000 0x1000>, ++ <0x2c000100 0x100>; ++ }; ++ ++ dcc { ++ compatible = "arm,vexpress,config-bus"; ++ arm,vexpress,config-bridge = <&v2m_sysreg>; ++ ++ osc@0 { ++ /* ACLK clock to the AXI master port on the test chip */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 0>; ++ freq-range = <30000000 50000000>; ++ #clock-cells = <0>; ++ clock-output-names = "extsaxiclk"; ++ }; ++ ++ oscclk1: osc@1 { ++ /* Reference clock for the CLCD */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 1>; ++ freq-range = <10000000 80000000>; ++ #clock-cells = <0>; ++ clock-output-names = "clcdclk"; ++ }; ++ ++ smbclk: oscclk2: osc@2 { ++ /* Reference clock for the test chip internal PLLs */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 2>; ++ freq-range = <33000000 100000000>; ++ #clock-cells = <0>; ++ clock-output-names = "tcrefclk"; ++ }; ++ }; ++ ++ smb { ++ compatible = "simple-bus"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0 0 0x08000000 0x04000000>, ++ <1 0 0x14000000 0x04000000>, ++ <2 0 0x18000000 0x04000000>, ++ <3 0 0x1c000000 0x04000000>, ++ <4 0 0x0c000000 0x04000000>, ++ <5 0 0x10000000 0x04000000>; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 63>; ++ interrupt-map = <0 0 0 &gic 0 0 4>, ++ <0 0 1 &gic 0 1 4>, ++ <0 0 2 &gic 0 2 4>, ++ <0 0 3 &gic 0 3 4>, ++ <0 0 4 &gic 0 4 4>, ++ <0 0 5 &gic 0 5 4>, ++ <0 0 6 &gic 0 6 4>, ++ <0 0 7 &gic 0 7 4>, ++ <0 0 8 &gic 0 8 4>, ++ <0 0 9 &gic 0 9 4>, ++ <0 0 10 &gic 0 10 4>, ++ <0 0 11 &gic 0 11 4>, ++ <0 0 12 &gic 0 12 4>, ++ <0 0 13 &gic 0 13 4>, ++ <0 0 14 &gic 0 14 4>, ++ <0 0 15 &gic 0 15 4>, ++ <0 0 16 &gic 0 16 4>, ++ <0 0 17 &gic 0 17 4>, ++ <0 0 18 &gic 0 18 4>, ++ <0 0 19 &gic 0 19 4>, ++ <0 0 20 &gic 0 20 4>, ++ <0 0 21 &gic 0 21 4>, ++ <0 0 22 &gic 0 22 4>, ++ <0 0 23 &gic 0 23 4>, ++ <0 0 24 &gic 0 24 4>, ++ <0 0 25 &gic 0 25 4>, ++ <0 0 26 &gic 0 26 4>, ++ <0 0 27 &gic 0 27 4>, ++ <0 0 28 &gic 0 28 4>, ++ <0 0 29 &gic 0 29 4>, ++ <0 0 30 &gic 0 30 4>, ++ <0 0 31 &gic 0 31 4>, ++ <0 0 32 &gic 0 32 4>, ++ <0 0 33 &gic 0 33 4>, ++ <0 0 34 &gic 0 34 4>, ++ <0 0 35 &gic 0 35 4>, ++ <0 0 36 &gic 0 36 4>, ++ <0 0 37 &gic 0 37 4>, ++ <0 0 38 &gic 0 38 4>, ++ <0 0 39 &gic 0 39 4>, ++ <0 0 40 &gic 0 40 4>, ++ <0 0 41 &gic 0 41 4>, ++ <0 0 42 &gic 0 42 4>; ++ ++ /include/ "rtsm_ve-motherboard.dtsi" ++ }; ++}; ++ ++/include/ "clcd-panels.dtsi" +diff -Nur linux-3.10.30/arch/arm/boot/dts/rtsm_ve-cortex_a9x4.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-cortex_a9x4.dts +--- linux-3.10.30/arch/arm/boot/dts/rtsm_ve-cortex_a9x4.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-cortex_a9x4.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,183 @@ ++/* ++ * ARM Ltd. Fast Models ++ * ++ * Versatile Express (VE) system model ++ * ARMCortexA9MPx4CT ++ * ++ * RTSM_VE_Cortex_A9x4.lisa ++ */ ++ ++/dts-v1/; ++ ++/ { ++ model = "RTSM_VE_CortexA9x4"; ++ arm,vexpress,site = <0xf>; ++ compatible = "arm,rtsm_ve,cortex_a9x4", "arm,vexpress"; ++ interrupt-parent = <&gic>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ chosen { }; ++ ++ aliases { ++ serial0 = &v2m_serial0; ++ serial1 = &v2m_serial1; ++ serial2 = &v2m_serial2; ++ serial3 = &v2m_serial3; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ reg = <0>; ++ }; ++ ++ cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ reg = <1>; ++ }; ++ ++ cpu@2 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ reg = <2>; ++ }; ++ ++ cpu@3 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a9"; ++ reg = <3>; ++ }; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0x80000000 0x80000000>; ++ }; ++ ++ scu@2c000000 { ++ compatible = "arm,cortex-a9-scu"; ++ reg = <0x2c000000 0x58>; ++ }; ++ ++ timer@2c000600 { ++ compatible = "arm,cortex-a9-twd-timer"; ++ reg = <0x2c000600 0x20>; ++ interrupts = <1 13 0xf04>; ++ }; ++ ++ watchdog@2c000620 { ++ compatible = "arm,cortex-a9-twd-wdt"; ++ reg = <0x2c000620 0x20>; ++ interrupts = <1 14 0xf04>; ++ }; ++ ++ gic: interrupt-controller@2c001000 { ++ compatible = "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ interrupt-controller; ++ reg = <0x2c001000 0x1000>, ++ <0x2c000100 0x100>; ++ }; ++ ++ dcc { ++ compatible = "arm,vexpress,config-bus"; ++ arm,vexpress,config-bridge = <&v2m_sysreg>; ++ ++ osc@0 { ++ /* ACLK clock to the AXI master port on the test chip */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 0>; ++ freq-range = <30000000 50000000>; ++ #clock-cells = <0>; ++ clock-output-names = "extsaxiclk"; ++ }; ++ ++ oscclk1: osc@1 { ++ /* Reference clock for the CLCD */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 1>; ++ freq-range = <10000000 80000000>; ++ #clock-cells = <0>; ++ clock-output-names = "clcdclk"; ++ }; ++ ++ smbclk: oscclk2: osc@2 { ++ /* Reference clock for the test chip internal PLLs */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 2>; ++ freq-range = <33000000 100000000>; ++ #clock-cells = <0>; ++ clock-output-names = "tcrefclk"; ++ }; ++ }; ++ ++ smb { ++ compatible = "simple-bus"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0 0 0x08000000 0x04000000>, ++ <1 0 0x14000000 0x04000000>, ++ <2 0 0x18000000 0x04000000>, ++ <3 0 0x1c000000 0x04000000>, ++ <4 0 0x0c000000 0x04000000>, ++ <5 0 0x10000000 0x04000000>; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 63>; ++ interrupt-map = <0 0 0 &gic 0 0 4>, ++ <0 0 1 &gic 0 1 4>, ++ <0 0 2 &gic 0 2 4>, ++ <0 0 3 &gic 0 3 4>, ++ <0 0 4 &gic 0 4 4>, ++ <0 0 5 &gic 0 5 4>, ++ <0 0 6 &gic 0 6 4>, ++ <0 0 7 &gic 0 7 4>, ++ <0 0 8 &gic 0 8 4>, ++ <0 0 9 &gic 0 9 4>, ++ <0 0 10 &gic 0 10 4>, ++ <0 0 11 &gic 0 11 4>, ++ <0 0 12 &gic 0 12 4>, ++ <0 0 13 &gic 0 13 4>, ++ <0 0 14 &gic 0 14 4>, ++ <0 0 15 &gic 0 15 4>, ++ <0 0 16 &gic 0 16 4>, ++ <0 0 17 &gic 0 17 4>, ++ <0 0 18 &gic 0 18 4>, ++ <0 0 19 &gic 0 19 4>, ++ <0 0 20 &gic 0 20 4>, ++ <0 0 21 &gic 0 21 4>, ++ <0 0 22 &gic 0 22 4>, ++ <0 0 23 &gic 0 23 4>, ++ <0 0 24 &gic 0 24 4>, ++ <0 0 25 &gic 0 25 4>, ++ <0 0 26 &gic 0 26 4>, ++ <0 0 27 &gic 0 27 4>, ++ <0 0 28 &gic 0 28 4>, ++ <0 0 29 &gic 0 29 4>, ++ <0 0 30 &gic 0 30 4>, ++ <0 0 31 &gic 0 31 4>, ++ <0 0 32 &gic 0 32 4>, ++ <0 0 33 &gic 0 33 4>, ++ <0 0 34 &gic 0 34 4>, ++ <0 0 35 &gic 0 35 4>, ++ <0 0 36 &gic 0 36 4>, ++ <0 0 37 &gic 0 37 4>, ++ <0 0 38 &gic 0 38 4>, ++ <0 0 39 &gic 0 39 4>, ++ <0 0 40 &gic 0 40 4>, ++ <0 0 41 &gic 0 41 4>, ++ <0 0 42 &gic 0 42 4>; ++ ++ /include/ "rtsm_ve-motherboard.dtsi" ++ }; ++}; ++ ++/include/ "clcd-panels.dtsi" +diff -Nur linux-3.10.30/arch/arm/boot/dts/rtsm_ve-motherboard.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-motherboard.dtsi +--- linux-3.10.30/arch/arm/boot/dts/rtsm_ve-motherboard.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-motherboard.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,231 @@ ++/* ++ * ARM Ltd. Fast Models ++ * ++ * Versatile Express (VE) system model ++ * Motherboard component ++ * ++ * VEMotherBoard.lisa ++ */ ++ ++ motherboard { ++ compatible = "arm,vexpress,v2m-p1", "simple-bus"; ++ arm,hbi = <0x190>; ++ arm,vexpress,site = <0>; ++ arm,v2m-memory-map = "rs1"; ++ #address-cells = <2>; /* SMB chipselect number and offset */ ++ #size-cells = <1>; ++ #interrupt-cells = <1>; ++ ranges; ++ ++ flash@0,00000000 { ++ compatible = "arm,vexpress-flash", "cfi-flash"; ++ reg = <0 0x00000000 0x04000000>, ++ <4 0x00000000 0x04000000>; ++ bank-width = <4>; ++ }; ++ ++ vram@2,00000000 { ++ compatible = "arm,vexpress-vram"; ++ reg = <2 0x00000000 0x00800000>; ++ }; ++ ++ ethernet@2,02000000 { ++ compatible = "smsc,lan91c111"; ++ reg = <2 0x02000000 0x10000>; ++ interrupts = <15>; ++ }; ++ ++ iofpga@3,00000000 { ++ compatible = "arm,amba-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 3 0 0x200000>; ++ ++ v2m_sysreg: sysreg@010000 { ++ compatible = "arm,vexpress-sysreg"; ++ reg = <0x010000 0x1000>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ v2m_sysctl: sysctl@020000 { ++ compatible = "arm,sp810", "arm,primecell"; ++ reg = <0x020000 0x1000>; ++ clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>; ++ clock-names = "refclk", "timclk", "apb_pclk"; ++ #clock-cells = <1>; ++ clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3"; ++ }; ++ ++ aaci@040000 { ++ compatible = "arm,pl041", "arm,primecell"; ++ reg = <0x040000 0x1000>; ++ interrupts = <11>; ++ clocks = <&smbclk>; ++ clock-names = "apb_pclk"; ++ }; ++ ++ mmci@050000 { ++ compatible = "arm,pl180", "arm,primecell"; ++ reg = <0x050000 0x1000>; ++ interrupts = <9 10>; ++ cd-gpios = <&v2m_sysreg 0 0>; ++ wp-gpios = <&v2m_sysreg 1 0>; ++ max-frequency = <12000000>; ++ vmmc-supply = <&v2m_fixed_3v3>; ++ clocks = <&v2m_clk24mhz>, <&smbclk>; ++ clock-names = "mclk", "apb_pclk"; ++ }; ++ ++ kmi@060000 { ++ compatible = "arm,pl050", "arm,primecell"; ++ reg = <0x060000 0x1000>; ++ interrupts = <12>; ++ clocks = <&v2m_clk24mhz>, <&smbclk>; ++ clock-names = "KMIREFCLK", "apb_pclk"; ++ }; ++ ++ kmi@070000 { ++ compatible = "arm,pl050", "arm,primecell"; ++ reg = <0x070000 0x1000>; ++ interrupts = <13>; ++ clocks = <&v2m_clk24mhz>, <&smbclk>; ++ clock-names = "KMIREFCLK", "apb_pclk"; ++ }; ++ ++ v2m_serial0: uart@090000 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x090000 0x1000>; ++ interrupts = <5>; ++ clocks = <&v2m_clk24mhz>, <&smbclk>; ++ clock-names = "uartclk", "apb_pclk"; ++ }; ++ ++ v2m_serial1: uart@0a0000 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x0a0000 0x1000>; ++ interrupts = <6>; ++ clocks = <&v2m_clk24mhz>, <&smbclk>; ++ clock-names = "uartclk", "apb_pclk"; ++ }; ++ ++ v2m_serial2: uart@0b0000 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x0b0000 0x1000>; ++ interrupts = <7>; ++ clocks = <&v2m_clk24mhz>, <&smbclk>; ++ clock-names = "uartclk", "apb_pclk"; ++ }; ++ ++ v2m_serial3: uart@0c0000 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x0c0000 0x1000>; ++ interrupts = <8>; ++ clocks = <&v2m_clk24mhz>, <&smbclk>; ++ clock-names = "uartclk", "apb_pclk"; ++ }; ++ ++ wdt@0f0000 { ++ compatible = "arm,sp805", "arm,primecell"; ++ reg = <0x0f0000 0x1000>; ++ interrupts = <0>; ++ clocks = <&v2m_refclk32khz>, <&smbclk>; ++ clock-names = "wdogclk", "apb_pclk"; ++ }; ++ ++ v2m_timer01: timer@110000 { ++ compatible = "arm,sp804", "arm,primecell"; ++ reg = <0x110000 0x1000>; ++ interrupts = <2>; ++ clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&smbclk>; ++ clock-names = "timclken1", "timclken2", "apb_pclk"; ++ }; ++ ++ v2m_timer23: timer@120000 { ++ compatible = "arm,sp804", "arm,primecell"; ++ reg = <0x120000 0x1000>; ++ interrupts = <3>; ++ clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&smbclk>; ++ clock-names = "timclken1", "timclken2", "apb_pclk"; ++ }; ++ ++ rtc@170000 { ++ compatible = "arm,pl031", "arm,primecell"; ++ reg = <0x170000 0x1000>; ++ interrupts = <4>; ++ clocks = <&smbclk>; ++ clock-names = "apb_pclk"; ++ }; ++ ++ clcd@1f0000 { ++ compatible = "arm,pl111", "arm,primecell"; ++ reg = <0x1f0000 0x1000>; ++ interrupts = <14>; ++ clocks = <&v2m_oscclk1>, <&smbclk>; ++ clock-names = "v2m:oscclk1", "apb_pclk"; ++ mode = "VGA"; ++ use_dma = <0>; ++ framebuffer = <0x18000000 0x00180000>; ++ }; ++ ++ virtio_block@0130000 { ++ compatible = "virtio,mmio"; ++ reg = <0x130000 0x200>; ++ interrupts = <42>; ++ }; ++ ++ }; ++ ++ v2m_fixed_3v3: fixedregulator@0 { ++ compatible = "regulator-fixed"; ++ regulator-name = "3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ v2m_clk24mhz: clk24mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ clock-output-names = "v2m:clk24mhz"; ++ }; ++ ++ v2m_refclk1mhz: refclk1mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <1000000>; ++ clock-output-names = "v2m:refclk1mhz"; ++ }; ++ ++ v2m_refclk32khz: refclk32khz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ clock-output-names = "v2m:refclk32khz"; ++ }; ++ ++ mcc { ++ compatible = "simple-bus"; ++ arm,vexpress,config-bridge = <&v2m_sysreg>; ++ ++ v2m_oscclk1: osc@1 { ++ /* CLCD clock */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 1>; ++ freq-range = <23750000 63500000>; ++ #clock-cells = <0>; ++ clock-output-names = "v2m:oscclk1"; ++ }; ++ ++ muxfpga@0 { ++ compatible = "arm,vexpress-muxfpga"; ++ arm,vexpress-sysreg,func = <7 0>; ++ }; ++ ++ shutdown@0 { ++ compatible = "arm,vexpress-shutdown"; ++ arm,vexpress-sysreg,func = <8 0>; ++ }; ++ }; ++ }; +diff -Nur linux-3.10.30/arch/arm/boot/dts/rtsm_ve-v2p-ca15x1-ca7x1.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-v2p-ca15x1-ca7x1.dts +--- linux-3.10.30/arch/arm/boot/dts/rtsm_ve-v2p-ca15x1-ca7x1.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-v2p-ca15x1-ca7x1.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,244 @@ ++/* ++ * ARM Ltd. Fast Models ++ * ++ * Versatile Express (VE) system model ++ * ARMCortexA15x4CT ++ * ARMCortexA7x4CT ++ * RTSM_VE_Cortex_A15x1_A7x1.lisa ++ */ ++ ++/dts-v1/; ++ ++/memreserve/ 0xff000000 0x01000000; ++ ++/ { ++ model = "RTSM_VE_CortexA15x1-A7x1"; ++ arm,vexpress,site = <0xf>; ++ compatible = "arm,rtsm_ve,cortex_a15x1_a7x1", "arm,vexpress"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ chosen { }; ++ ++ aliases { ++ serial0 = &v2m_serial0; ++ serial1 = &v2m_serial1; ++ serial2 = &v2m_serial2; ++ serial3 = &v2m_serial3; ++ }; ++ ++ clusters { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cluster0: cluster@0 { ++ reg = <0>; ++// freqs = <500000000 600000000 700000000 800000000 900000000 1000000000 1100000000 1200000000>; ++ cores { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ core0: core@0 { ++ reg = <0>; ++ }; ++ ++ }; ++ }; ++ ++ cluster1: cluster@1 { ++ reg = <1>; ++// freqs = <350000000 400000000 500000000 600000000 700000000 800000000 900000000 1000000000>; ++ cores { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ core1: core@0 { ++ reg = <0>; ++ }; ++ ++ }; ++ }; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <0>; ++ cluster = <&cluster0>; ++ core = <&core0>; ++// clock-frequency = <1000000000>; ++ cci-control-port = <&cci_control1>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a7"; ++ reg = <0x100>; ++ cluster = <&cluster1>; ++ core = <&core1>; ++// clock-frequency = <800000000>; ++ cci-control-port = <&cci_control2>; ++ }; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0 0x80000000 0 0x80000000>; ++ }; ++ ++ cci@2c090000 { ++ compatible = "arm,cci-400", "arm,cci"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0 0x2c090000 0 0x1000>; ++ ranges = <0x0 0x0 0x2c090000 0x10000>; ++ ++ cci_control1: slave-if@4000 { ++ compatible = "arm,cci-400-ctrl-if"; ++ interface-type = "ace"; ++ reg = <0x4000 0x1000>; ++ }; ++ ++ cci_control2: slave-if@5000 { ++ compatible = "arm,cci-400-ctrl-if"; ++ interface-type = "ace"; ++ reg = <0x5000 0x1000>; ++ }; ++ }; ++ ++ dcscb@60000000 { ++ compatible = "arm,rtsm,dcscb"; ++ reg = <0 0x60000000 0 0x1000>; ++ }; ++ ++ gic: interrupt-controller@2c001000 { ++ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ interrupt-controller; ++ reg = <0 0x2c001000 0 0x1000>, ++ <0 0x2c002000 0 0x1000>, ++ <0 0x2c004000 0 0x2000>, ++ <0 0x2c006000 0 0x2000>; ++ interrupts = <1 9 0xf04>; ++ ++ gic-cpuif@0 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <0>; ++ cpu = <&cpu0>; ++ }; ++ gic-cpuif@1 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <1>; ++ cpu = <&cpu1>; ++ }; ++ }; ++ ++ timer { ++ compatible = "arm,armv7-timer"; ++ interrupts = <1 13 0xf08>, ++ <1 14 0xf08>, ++ <1 11 0xf08>, ++ <1 10 0xf08>; ++ }; ++ ++ dcc { ++ compatible = "arm,vexpress,config-bus"; ++ arm,vexpress,config-bridge = <&v2m_sysreg>; ++ ++ osc@0 { ++ /* ACLK clock to the AXI master port on the test chip */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 0>; ++ freq-range = <30000000 50000000>; ++ #clock-cells = <0>; ++ clock-output-names = "extsaxiclk"; ++ }; ++ ++ oscclk1: osc@1 { ++ /* Reference clock for the CLCD */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 1>; ++ freq-range = <10000000 80000000>; ++ #clock-cells = <0>; ++ clock-output-names = "clcdclk"; ++ }; ++ ++ smbclk: oscclk2: osc@2 { ++ /* Reference clock for the test chip internal PLLs */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 2>; ++ freq-range = <33000000 100000000>; ++ #clock-cells = <0>; ++ clock-output-names = "tcrefclk"; ++ }; ++ }; ++ ++ smb { ++ compatible = "simple-bus"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0 0 0 0x08000000 0x04000000>, ++ <1 0 0 0x14000000 0x04000000>, ++ <2 0 0 0x18000000 0x04000000>, ++ <3 0 0 0x1c000000 0x04000000>, ++ <4 0 0 0x0c000000 0x04000000>, ++ <5 0 0 0x10000000 0x04000000>; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 63>; ++ interrupt-map = <0 0 0 &gic 0 0 4>, ++ <0 0 1 &gic 0 1 4>, ++ <0 0 2 &gic 0 2 4>, ++ <0 0 3 &gic 0 3 4>, ++ <0 0 4 &gic 0 4 4>, ++ <0 0 5 &gic 0 5 4>, ++ <0 0 6 &gic 0 6 4>, ++ <0 0 7 &gic 0 7 4>, ++ <0 0 8 &gic 0 8 4>, ++ <0 0 9 &gic 0 9 4>, ++ <0 0 10 &gic 0 10 4>, ++ <0 0 11 &gic 0 11 4>, ++ <0 0 12 &gic 0 12 4>, ++ <0 0 13 &gic 0 13 4>, ++ <0 0 14 &gic 0 14 4>, ++ <0 0 15 &gic 0 15 4>, ++ <0 0 16 &gic 0 16 4>, ++ <0 0 17 &gic 0 17 4>, ++ <0 0 18 &gic 0 18 4>, ++ <0 0 19 &gic 0 19 4>, ++ <0 0 20 &gic 0 20 4>, ++ <0 0 21 &gic 0 21 4>, ++ <0 0 22 &gic 0 22 4>, ++ <0 0 23 &gic 0 23 4>, ++ <0 0 24 &gic 0 24 4>, ++ <0 0 25 &gic 0 25 4>, ++ <0 0 26 &gic 0 26 4>, ++ <0 0 27 &gic 0 27 4>, ++ <0 0 28 &gic 0 28 4>, ++ <0 0 29 &gic 0 29 4>, ++ <0 0 30 &gic 0 30 4>, ++ <0 0 31 &gic 0 31 4>, ++ <0 0 32 &gic 0 32 4>, ++ <0 0 33 &gic 0 33 4>, ++ <0 0 34 &gic 0 34 4>, ++ <0 0 35 &gic 0 35 4>, ++ <0 0 36 &gic 0 36 4>, ++ <0 0 37 &gic 0 37 4>, ++ <0 0 38 &gic 0 38 4>, ++ <0 0 39 &gic 0 39 4>, ++ <0 0 40 &gic 0 40 4>, ++ <0 0 41 &gic 0 41 4>, ++ <0 0 42 &gic 0 42 4>; ++ ++ /include/ "rtsm_ve-motherboard.dtsi" ++ }; ++}; ++ ++/include/ "clcd-panels.dtsi" +diff -Nur linux-3.10.30/arch/arm/boot/dts/rtsm_ve-v2p-ca15x4-ca7x4.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-v2p-ca15x4-ca7x4.dts +--- linux-3.10.30/arch/arm/boot/dts/rtsm_ve-v2p-ca15x4-ca7x4.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/rtsm_ve-v2p-ca15x4-ca7x4.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,358 @@ ++/* ++ * ARM Ltd. Fast Models ++ * ++ * Versatile Express (VE) system model ++ * ARMCortexA15x4CT ++ * ARMCortexA7x4CT ++ * RTSM_VE_Cortex_A15x4_A7x4.lisa ++ */ ++ ++/dts-v1/; ++ ++/memreserve/ 0xff000000 0x01000000; ++ ++/ { ++ model = "RTSM_VE_CortexA15x4-A7x4"; ++ arm,vexpress,site = <0xf>; ++ compatible = "arm,rtsm_ve,cortex_a15x4_a7x4", "arm,vexpress"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ chosen { }; ++ ++ aliases { ++ serial0 = &v2m_serial0; ++ serial1 = &v2m_serial1; ++ serial2 = &v2m_serial2; ++ serial3 = &v2m_serial3; ++ }; ++ ++ clusters { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cluster0: cluster@0 { ++ reg = <0>; ++// freqs = <500000000 600000000 700000000 800000000 900000000 1000000000 1100000000 1200000000>; ++ cores { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ core0: core@0 { ++ reg = <0>; ++ }; ++ ++ core1: core@1 { ++ reg = <1>; ++ }; ++ ++ core2: core@2 { ++ reg = <2>; ++ }; ++ ++ core3: core@3 { ++ reg = <3>; ++ }; ++ ++ }; ++ }; ++ ++ cluster1: cluster@1 { ++ reg = <1>; ++// freqs = <350000000 400000000 500000000 600000000 700000000 800000000 900000000 1000000000>; ++ cores { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ core4: core@0 { ++ reg = <0>; ++ }; ++ ++ core5: core@1 { ++ reg = <1>; ++ }; ++ ++ core6: core@2 { ++ reg = <2>; ++ }; ++ ++ core7: core@3 { ++ reg = <3>; ++ }; ++ ++ }; ++ }; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <0>; ++ cluster = <&cluster0>; ++ core = <&core0>; ++// clock-frequency = <1000000000>; ++ cci-control-port = <&cci_control1>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <1>; ++ cluster = <&cluster0>; ++ core = <&core1>; ++// clock-frequency = <1000000000>; ++ cci-control-port = <&cci_control1>; ++ }; ++ ++ cpu2: cpu@2 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <2>; ++ cluster = <&cluster0>; ++ core = <&core2>; ++// clock-frequency = <1000000000>; ++ cci-control-port = <&cci_control1>; ++ }; ++ ++ cpu3: cpu@3 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <3>; ++ cluster = <&cluster0>; ++ core = <&core3>; ++// clock-frequency = <1000000000>; ++ cci-control-port = <&cci_control1>; ++ }; ++ ++ cpu4: cpu@4 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a7"; ++ reg = <0x100>; ++ cluster = <&cluster1>; ++ core = <&core4>; ++// clock-frequency = <800000000>; ++ cci-control-port = <&cci_control2>; ++ }; ++ ++ cpu5: cpu@5 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a7"; ++ reg = <0x101>; ++ cluster = <&cluster1>; ++ core = <&core5>; ++// clock-frequency = <800000000>; ++ cci-control-port = <&cci_control2>; ++ }; ++ ++ cpu6: cpu@6 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a7"; ++ reg = <0x102>; ++ cluster = <&cluster1>; ++ core = <&core6>; ++// clock-frequency = <800000000>; ++ cci-control-port = <&cci_control2>; ++ }; ++ ++ cpu7: cpu@7 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a7"; ++ reg = <0x103>; ++ cluster = <&cluster1>; ++ core = <&core7>; ++// clock-frequency = <800000000>; ++ cci-control-port = <&cci_control2>; ++ }; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0 0x80000000 0 0x80000000>; ++ }; ++ ++ cci@2c090000 { ++ compatible = "arm,cci-400", "arm,cci"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0 0x2c090000 0 0x1000>; ++ ranges = <0x0 0x0 0x2c090000 0x10000>; ++ ++ cci_control1: slave-if@4000 { ++ compatible = "arm,cci-400-ctrl-if"; ++ interface-type = "ace"; ++ reg = <0x4000 0x1000>; ++ }; ++ ++ cci_control2: slave-if@5000 { ++ compatible = "arm,cci-400-ctrl-if"; ++ interface-type = "ace"; ++ reg = <0x5000 0x1000>; ++ }; ++ }; ++ ++ dcscb@60000000 { ++ compatible = "arm,rtsm,dcscb"; ++ reg = <0 0x60000000 0 0x1000>; ++ }; ++ ++ gic: interrupt-controller@2c001000 { ++ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ interrupt-controller; ++ reg = <0 0x2c001000 0 0x1000>, ++ <0 0x2c002000 0 0x1000>, ++ <0 0x2c004000 0 0x2000>, ++ <0 0x2c006000 0 0x2000>; ++ interrupts = <1 9 0xf04>; ++ ++ gic-cpuif@0 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <0>; ++ cpu = <&cpu0>; ++ }; ++ gic-cpuif@1 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <1>; ++ cpu = <&cpu1>; ++ }; ++ gic-cpuif@2 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <2>; ++ cpu = <&cpu2>; ++ }; ++ gic-cpuif@3 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <3>; ++ cpu = <&cpu3>; ++ }; ++ gic-cpuif@4 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <4>; ++ cpu = <&cpu4>; ++ }; ++ gic-cpuif@5 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <5>; ++ cpu = <&cpu5>; ++ }; ++ gic-cpuif@6 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <6>; ++ cpu = <&cpu6>; ++ }; ++ gic-cpuif@7 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <7>; ++ cpu = <&cpu7>; ++ }; ++ }; ++ ++ timer { ++ compatible = "arm,armv7-timer"; ++ interrupts = <1 13 0xf08>, ++ <1 14 0xf08>, ++ <1 11 0xf08>, ++ <1 10 0xf08>; ++ }; ++ ++ dcc { ++ compatible = "arm,vexpress,config-bus"; ++ arm,vexpress,config-bridge = <&v2m_sysreg>; ++ ++ osc@0 { ++ /* ACLK clock to the AXI master port on the test chip */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 0>; ++ freq-range = <30000000 50000000>; ++ #clock-cells = <0>; ++ clock-output-names = "extsaxiclk"; ++ }; ++ ++ oscclk1: osc@1 { ++ /* Reference clock for the CLCD */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 1>; ++ freq-range = <10000000 80000000>; ++ #clock-cells = <0>; ++ clock-output-names = "clcdclk"; ++ }; ++ ++ smbclk: oscclk2: osc@2 { ++ /* Reference clock for the test chip internal PLLs */ ++ compatible = "arm,vexpress-osc"; ++ arm,vexpress-sysreg,func = <1 2>; ++ freq-range = <33000000 100000000>; ++ #clock-cells = <0>; ++ clock-output-names = "tcrefclk"; ++ }; ++ }; ++ ++ smb { ++ compatible = "simple-bus"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0 0 0 0x08000000 0x04000000>, ++ <1 0 0 0x14000000 0x04000000>, ++ <2 0 0 0x18000000 0x04000000>, ++ <3 0 0 0x1c000000 0x04000000>, ++ <4 0 0 0x0c000000 0x04000000>, ++ <5 0 0 0x10000000 0x04000000>; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 63>; ++ interrupt-map = <0 0 0 &gic 0 0 4>, ++ <0 0 1 &gic 0 1 4>, ++ <0 0 2 &gic 0 2 4>, ++ <0 0 3 &gic 0 3 4>, ++ <0 0 4 &gic 0 4 4>, ++ <0 0 5 &gic 0 5 4>, ++ <0 0 6 &gic 0 6 4>, ++ <0 0 7 &gic 0 7 4>, ++ <0 0 8 &gic 0 8 4>, ++ <0 0 9 &gic 0 9 4>, ++ <0 0 10 &gic 0 10 4>, ++ <0 0 11 &gic 0 11 4>, ++ <0 0 12 &gic 0 12 4>, ++ <0 0 13 &gic 0 13 4>, ++ <0 0 14 &gic 0 14 4>, ++ <0 0 15 &gic 0 15 4>, ++ <0 0 16 &gic 0 16 4>, ++ <0 0 17 &gic 0 17 4>, ++ <0 0 18 &gic 0 18 4>, ++ <0 0 19 &gic 0 19 4>, ++ <0 0 20 &gic 0 20 4>, ++ <0 0 21 &gic 0 21 4>, ++ <0 0 22 &gic 0 22 4>, ++ <0 0 23 &gic 0 23 4>, ++ <0 0 24 &gic 0 24 4>, ++ <0 0 25 &gic 0 25 4>, ++ <0 0 26 &gic 0 26 4>, ++ <0 0 27 &gic 0 27 4>, ++ <0 0 28 &gic 0 28 4>, ++ <0 0 29 &gic 0 29 4>, ++ <0 0 30 &gic 0 30 4>, ++ <0 0 31 &gic 0 31 4>, ++ <0 0 32 &gic 0 32 4>, ++ <0 0 33 &gic 0 33 4>, ++ <0 0 34 &gic 0 34 4>, ++ <0 0 35 &gic 0 35 4>, ++ <0 0 36 &gic 0 36 4>, ++ <0 0 37 &gic 0 37 4>, ++ <0 0 38 &gic 0 38 4>, ++ <0 0 39 &gic 0 39 4>, ++ <0 0 40 &gic 0 40 4>, ++ <0 0 41 &gic 0 41 4>, ++ <0 0 42 &gic 0 42 4>; ++ ++ /include/ "rtsm_ve-motherboard.dtsi" ++ }; ++}; ++ ++/include/ "clcd-panels.dtsi" +diff -Nur linux-3.10.30/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +--- linux-3.10.30/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -228,6 +228,7 @@ + }; + + clcd@1f0000 { ++ status = "disabled"; + compatible = "arm,pl111", "arm,primecell"; + reg = <0x1f0000 0x1000>; + interrupts = <14>; +diff -Nur linux-3.10.30/arch/arm/boot/dts/vexpress-v2m.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2m.dtsi +--- linux-3.10.30/arch/arm/boot/dts/vexpress-v2m.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2m.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -227,6 +227,7 @@ + }; + + clcd@1f000 { ++ status = "disabled"; + compatible = "arm,pl111", "arm,primecell"; + reg = <0x1f000 0x1000>; + interrupts = <14>; +diff -Nur linux-3.10.30/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts +--- linux-3.10.30/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -9,6 +9,8 @@ + + /dts-v1/; + ++/memreserve/ 0xbf000000 0x01000000; ++ + / { + model = "V2P-CA15"; + arm,hbi = <0x237>; +@@ -57,6 +59,8 @@ + interrupts = <0 85 4>; + clocks = <&oscclk5>; + clock-names = "pxlclk"; ++ mode = "1024x768-16@60"; ++ framebuffer = <0 0xff000000 0 0x01000000>; + }; + + memory-controller@2b0a0000 { +diff -Nur linux-3.10.30/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts +--- linux-3.10.30/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -9,11 +9,13 @@ + + /dts-v1/; + ++/memreserve/ 0xff000000 0x01000000; ++ + / { + model = "V2P-CA15_CA7"; + arm,hbi = <0x249>; + arm,vexpress,site = <0xf>; +- compatible = "arm,vexpress,v2p-ca15_a7", "arm,vexpress"; ++ compatible = "arm,vexpress,v2p-ca15_a7", "arm,vexpress", "arm,generic"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; +@@ -29,44 +31,106 @@ + i2c1 = &v2m_i2c_pcie; + }; + +- cpus { ++ clusters { + #address-cells = <1>; + #size-cells = <0>; + +- cpu0: cpu@0 { +- device_type = "cpu"; +- compatible = "arm,cortex-a15"; ++ cluster0: cluster@0 { + reg = <0>; ++ cores { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ core0: core@0 { ++ reg = <0>; ++ }; ++ ++ core1: core@1 { ++ reg = <1>; ++ }; ++ ++ }; + }; + +- cpu1: cpu@1 { +- device_type = "cpu"; +- compatible = "arm,cortex-a15"; ++ cluster1: cluster@1 { + reg = <1>; ++ cores { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ core2: core@0 { ++ reg = <0>; ++ }; ++ ++ core3: core@1 { ++ reg = <1>; ++ }; ++ ++ core4: core@2 { ++ reg = <2>; ++ }; ++ }; + }; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x100>; ++ cluster = <&cluster1>; ++ core = <&core2>; ++ clock-frequency = <800000000>; ++ cci-control-port = <&cci_control2>; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x101>; ++ cluster = <&cluster1>; ++ core = <&core3>; ++ clock-frequency = <800000000>; ++ cci-control-port = <&cci_control2>; + }; + + cpu4: cpu@4 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x102>; ++ cluster = <&cluster1>; ++ core = <&core4>; ++ clock-frequency = <800000000>; ++ cci-control-port = <&cci_control2>; ++ }; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <0>; ++ cluster = <&cluster0>; ++ core = <&core0>; ++ clock-frequency = <1000000000>; ++ cci-control-port = <&cci_control1>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <1>; ++ cluster = <&cluster0>; ++ core = <&core1>; ++ clock-frequency = <1000000000>; ++ cci-control-port = <&cci_control1>; + }; + }; + + memory@80000000 { + device_type = "memory"; +- reg = <0 0x80000000 0 0x40000000>; ++ reg = <0 0x80000000 0 0x80000000>; + }; + + wdt@2a490000 { +@@ -81,6 +145,8 @@ + compatible = "arm,hdlcd"; + reg = <0 0x2b000000 0 0x1000>; + interrupts = <0 85 4>; ++ mode = "1024x768-16@60"; ++ framebuffer = <0 0xff000000 0 0x01000000>; + clocks = <&oscclk5>; + clock-names = "pxlclk"; + }; +@@ -102,6 +168,64 @@ + <0 0x2c004000 0 0x2000>, + <0 0x2c006000 0 0x2000>; + interrupts = <1 9 0xf04>; ++ ++ gic-cpuif@0 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <0>; ++ cpu = <&cpu0>; ++ }; ++ gic-cpuif@1 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <1>; ++ cpu = <&cpu1>; ++ }; ++ gic-cpuif@2 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <2>; ++ cpu = <&cpu2>; ++ }; ++ ++ gic-cpuif@3 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <3>; ++ cpu = <&cpu3>; ++ }; ++ ++ gic-cpuif@4 { ++ compatible = "arm,gic-cpuif"; ++ cpuif-id = <4>; ++ cpu = <&cpu4>; ++ }; ++ }; ++ ++ cci@2c090000 { ++ compatible = "arm,cci-400"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0 0x2c090000 0 0x1000>; ++ ranges = <0x0 0x0 0x2c090000 0x10000>; ++ ++ cci_control1: slave-if@4000 { ++ compatible = "arm,cci-400-ctrl-if"; ++ interface-type = "ace"; ++ reg = <0x4000 0x1000>; ++ }; ++ ++ cci_control2: slave-if@5000 { ++ compatible = "arm,cci-400-ctrl-if"; ++ interface-type = "ace"; ++ reg = <0x5000 0x1000>; ++ }; ++ }; ++ ++ cci-pmu@2c099000 { ++ compatible = "arm,cci-400-pmu"; ++ reg = <0 0x2c099000 0 0x6000>; ++ interrupts = <0 101 4>, ++ <0 102 4>, ++ <0 103 4>, ++ <0 104 4>, ++ <0 105 4>; + }; + + memory-controller@7ffd0000 { +@@ -125,6 +249,12 @@ + clock-names = "apb_pclk"; + }; + ++ spc@7fff0000 { ++ compatible = "arm,vexpress-spc,v2p-ca15_a7","arm,vexpress-spc"; ++ reg = <0 0x7fff0000 0 0x1000>; ++ interrupts = <0 95 4>; ++ }; ++ + timer { + compatible = "arm,armv7-timer"; + interrupts = <1 13 0xf08>, +@@ -133,12 +263,21 @@ + <1 10 0xf08>; + }; + +- pmu { ++ pmu_a15 { + compatible = "arm,cortex-a15-pmu"; ++ cluster = <&cluster0>; + interrupts = <0 68 4>, + <0 69 4>; + }; + ++ pmu_a7 { ++ compatible = "arm,cortex-a7-pmu"; ++ cluster = <&cluster1>; ++ interrupts = <0 128 4>, ++ <0 129 4>, ++ <0 130 4>; ++ }; ++ + oscclk6a: oscclk6a { + /* Reference 24MHz clock */ + compatible = "fixed-clock"; +@@ -147,6 +286,15 @@ + clock-output-names = "oscclk6a"; + }; + ++ psci { ++ compatible = "arm,psci"; ++ method = "smc"; ++ cpu_suspend = <0x80100001>; ++ cpu_off = <0x80100002>; ++ cpu_on = <0x80100003>; ++ migrate = <0x80100004>; ++ }; ++ + dcc { + compatible = "arm,vexpress,config-bus"; + arm,vexpress,config-bridge = <&v2m_sysreg>; +diff -Nur linux-3.10.30/arch/arm/boot/dts/vexpress-v2p-ca5s.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2p-ca5s.dts +--- linux-3.10.30/arch/arm/boot/dts/vexpress-v2p-ca5s.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2p-ca5s.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -9,6 +9,8 @@ + + /dts-v1/; + ++/memreserve/ 0xbf000000 0x01000000; ++ + / { + model = "V2P-CA5s"; + arm,hbi = <0x225>; +@@ -59,6 +61,8 @@ + interrupts = <0 85 4>; + clocks = <&oscclk3>; + clock-names = "pxlclk"; ++ mode = "640x480-16@60"; ++ framebuffer = <0xbf000000 0x01000000>; + }; + + memory-controller@2a150000 { +diff -Nur linux-3.10.30/arch/arm/boot/dts/vexpress-v2p-ca9.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2p-ca9.dts +--- linux-3.10.30/arch/arm/boot/dts/vexpress-v2p-ca9.dts 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/vexpress-v2p-ca9.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -9,6 +9,8 @@ + + /dts-v1/; + ++/include/ "clcd-panels.dtsi" ++ + / { + model = "V2P-CA9"; + arm,hbi = <0x191>; +@@ -73,6 +75,8 @@ + interrupts = <0 44 4>; + clocks = <&oscclk1>, <&oscclk2>; + clock-names = "clcdclk", "apb_pclk"; ++ mode = "XVGA"; ++ use_dma = <1>; + }; + + memory-controller@100e0000 { +diff -Nur linux-3.10.30/arch/arm/boot/dts/vf610-pinfunc.h linux-3.10.30-cubox-i/arch/arm/boot/dts/vf610-pinfunc.h +--- linux-3.10.30/arch/arm/boot/dts/vf610-pinfunc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/vf610-pinfunc.h 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,810 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 __DTS_VF610_PINFUNC_H ++#define __DTS_VF610_PINFUNC_H ++ ++/* ++ * The pin function ID for VF610 is a tuple of: ++ * ++ */ ++ ++#define ALT0 0x0 ++#define ALT1 0x1 ++#define ALT2 0x2 ++#define ALT3 0x3 ++#define ALT4 0x4 ++#define ALT5 0x5 ++#define ALT6 0x6 ++#define ALT7 0x7 ++ ++ ++#define VF610_PAD_PTA6__GPIO_0 0x000 0x000 ALT0 0x0 ++#define VF610_PAD_PTA6__RMII_CLKOUT 0x000 0x000 ALT1 0x0 ++#define VF610_PAD_PTA6__RMII_CLKIN 0x000 0x2F0 ALT2 0x0 ++#define VF610_PAD_PTA6__DCU1_TCON11 0x000 0x000 ALT4 0x0 ++#define VF610_PAD_PTA6__DCU1_R2 0x000 0x000 ALT7 0x0 ++#define VF610_PAD_PTA8__GPIO_1 0x004 0x000 ALT0 0x0 ++#define VF610_PAD_PTA8__TCLK 0x004 0x000 ALT1 0x0 ++#define VF610_PAD_PTA8__DCU0_R0 0x004 0x000 ALT4 0x0 ++#define VF610_PAD_PTA8__MLB_CLK 0x004 0x354 ALT7 0x0 ++#define VF610_PAD_PTA9__GPIO_2 0x008 0x000 ALT0 0x0 ++#define VF610_PAD_PTA9__TDI 0x008 0x000 ALT1 0x0 ++#define VF610_PAD_PTA9__RMII_CLKOUT 0x008 0x000 ALT2 0x0 ++#define VF610_PAD_PTA9__RMII_CLKIN 0x008 0x2F0 ALT3 0x1 ++#define VF610_PAD_PTA9__DCU0_R1 0x008 0x000 ALT4 0x0 ++#define VF610_PAD_PTA9__WDOG_B 0x008 0x000 ALT6 0x0 ++#define VF610_PAD_PTA10__GPIO_3 0x00C 0x000 ALT0 0x0 ++#define VF610_PAD_PTA10__TDO 0x00C 0x000 ALT1 0x0 ++#define VF610_PAD_PTA10__EXT_AUDIO_MCLK 0x00C 0x2EC ALT2 0x0 ++#define VF610_PAD_PTA10__DCU0_G0 0x00C 0x000 ALT4 0x0 ++#define VF610_PAD_PTA10__ENET_TS_CLKIN 0x00C 0x2F4 ALT6 0x0 ++#define VF610_PAD_PTA10__MLB_SIGNAL 0x00C 0x35C ALT7 0x0 ++#define VF610_PAD_PTA11__GPIO_4 0x010 0x000 ALT0 0x0 ++#define VF610_PAD_PTA11__TMS 0x010 0x000 ALT1 0x0 ++#define VF610_PAD_PTA11__DCU0_G1 0x010 0x000 ALT4 0x0 ++#define VF610_PAD_PTA11__MLB_DATA 0x010 0x358 ALT7 0x0 ++#define VF610_PAD_PTA12__GPIO_5 0x014 0x000 ALT0 0x0 ++#define VF610_PAD_PTA12__TRACECK 0x014 0x000 ALT1 0x0 ++#define VF610_PAD_PTA12__EXT_AUDIO_MCLK 0x014 0x2EC ALT2 0x1 ++#define VF610_PAD_PTA12__VIU_DATA13 0x014 0x000 ALT6 0x0 ++#define VF610_PAD_PTA12__I2C0_SCL 0x014 0x33C ALT7 0x0 ++#define VF610_PAD_PTA16__GPIO_6 0x018 0x000 ALT0 0x0 ++#define VF610_PAD_PTA16__TRACED0 0x018 0x000 ALT1 0x0 ++#define VF610_PAD_PTA16__USB0_VBUS_EN 0x018 0x000 ALT2 0x0 ++#define VF610_PAD_PTA16__ADC1_SE0 0x018 0x000 ALT3 0x0 ++#define VF610_PAD_PTA16__LCD29 0x018 0x000 ALT4 0x0 ++#define VF610_PAD_PTA16__SAI2_TX_BCLK 0x018 0x370 ALT5 0x0 ++#define VF610_PAD_PTA16__VIU_DATA14 0x018 0x000 ALT6 0x0 ++#define VF610_PAD_PTA16__I2C0_SDA 0x018 0x340 ALT7 0x0 ++#define VF610_PAD_PTA17__GPIO_7 0x01C 0x000 ALT0 0x0 ++#define VF610_PAD_PTA17__TRACED1 0x01C 0x000 ALT1 0x0 ++#define VF610_PAD_PTA17__USB0_VBUS_OC 0x01C 0x000 ALT2 0x0 ++#define VF610_PAD_PTA17__ADC1_SE1 0x01C 0x000 ALT3 0x0 ++#define VF610_PAD_PTA17__LCD30 0x01C 0x000 ALT4 0x0 ++#define VF610_PAD_PTA17__USB0_SOF_PULSE 0x01C 0x000 ALT5 0x0 ++#define VF610_PAD_PTA17__VIU_DATA15 0x01C 0x000 ALT6 0x0 ++#define VF610_PAD_PTA17__I2C1_SCL 0x01C 0x344 ALT7 0x0 ++#define VF610_PAD_PTA18__GPIO_8 0x020 0x000 ALT0 0x0 ++#define VF610_PAD_PTA18__TRACED2 0x020 0x000 ALT1 0x0 ++#define VF610_PAD_PTA18__ADC0_SE0 0x020 0x000 ALT2 0x0 ++#define VF610_PAD_PTA18__FTM1_QD_PHA 0x020 0x334 ALT3 0x0 ++#define VF610_PAD_PTA18__LCD31 0x020 0x000 ALT4 0x0 ++#define VF610_PAD_PTA18__SAI2_TX_DATA 0x020 0x000 ALT5 0x0 ++#define VF610_PAD_PTA18__VIU_DATA16 0x020 0x000 ALT6 0x0 ++#define VF610_PAD_PTA18__I2C1_SDA 0x020 0x348 ALT7 0x0 ++#define VF610_PAD_PTA19__GPIO_9 0x024 0x000 ALT0 0x0 ++#define VF610_PAD_PTA19__TRACED3 0x024 0x000 ALT1 0x0 ++#define VF610_PAD_PTA19__ADC0_SE1 0x024 0x000 ALT2 0x0 ++#define VF610_PAD_PTA19__FTM1_QD_PHB 0x024 0x338 ALT3 0x0 ++#define VF610_PAD_PTA19__LCD32 0x024 0x000 ALT4 0x0 ++#define VF610_PAD_PTA19__SAI2_TX_SYNC 0x024 0x000 ALT5 0x0 ++#define VF610_PAD_PTA19__VIU_DATA17 0x024 0x000 ALT6 0x0 ++#define VF610_PAD_PTA19__QSPI1_A_QSCK 0x024 0x374 ALT7 0x0 ++#define VF610_PAD_PTA20__GPIO_10 0x028 0x000 ALT0 0x0 ++#define VF610_PAD_PTA20__TRACED4 0x028 0x000 ALT1 0x0 ++#define VF610_PAD_PTA20__LCD33 0x028 0x000 ALT4 0x0 ++#define VF610_PAD_PTA20__UART3_TX 0x028 0x394 ALT6 0x0 ++#define VF610_PAD_PTA20__DCU1_HSYNC 0x028 0x000 ALT7 0x0 ++#define VF610_PAD_PTA21__GPIO_11 0x02C 0x000 ALT0 0x0 ++#define VF610_PAD_PTA21__TRACED5 0x02C 0x000 ALT1 0x0 ++#define VF610_PAD_PTA21__SAI2_RX_BCLK 0x02C 0x364 ALT5 0x0 ++#define VF610_PAD_PTA21__UART3_RX 0x02C 0x390 ALT6 0x0 ++#define VF610_PAD_PTA21__DCU1_VSYNC 0x02C 0x000 ALT7 0x0 ++#define VF610_PAD_PTA22__GPIO_12 0x030 0x000 ALT0 0x0 ++#define VF610_PAD_PTA22__TRACED6 0x030 0x000 ALT1 0x0 ++#define VF610_PAD_PTA22__SAI2_RX_DATA 0x030 0x368 ALT5 0x0 ++#define VF610_PAD_PTA22__I2C2_SCL 0x030 0x34C ALT6 0x0 ++#define VF610_PAD_PTA22__DCU1_TAG 0x030 0x000 ALT7 0x0 ++#define VF610_PAD_PTA23__GPIO_13 0x034 0x000 ALT0 0x0 ++#define VF610_PAD_PTA23__TRACED7 0x034 0x000 ALT1 0x0 ++#define VF610_PAD_PTA23__SAI2_RX_SYNC 0x034 0x36C ALT5 0x0 ++#define VF610_PAD_PTA23__I2C2_SDA 0x034 0x350 ALT6 0x0 ++#define VF610_PAD_PTA23__DCU1_DE 0x034 0x000 ALT7 0x0 ++#define VF610_PAD_PTA24__GPIO_14 0x038 0x000 ALT0 0x0 ++#define VF610_PAD_PTA24__TRACED8 0x038 0x000 ALT1 0x0 ++#define VF610_PAD_PTA24__USB1_VBUS_EN 0x038 0x000 ALT2 0x0 ++#define VF610_PAD_PTA24__ESDHC1_CLK 0x038 0x000 ALT5 0x0 ++#define VF610_PAD_PTA24__DCU1_TCON4 0x038 0x000 ALT6 0x0 ++#define VF610_PAD_PTA24__DDR_TEST_PAD_CTRL 0x038 0x000 ALT7 0x0 ++#define VF610_PAD_PTA25__GPIO_15 0x03C 0x000 ALT0 0x0 ++#define VF610_PAD_PTA25__TRACED9 0x03C 0x000 ALT1 0x0 ++#define VF610_PAD_PTA25__USB1_VBUS_OC 0x03C 0x000 ALT2 0x0 ++#define VF610_PAD_PTA25__ESDHC1_CMD 0x03C 0x000 ALT5 0x0 ++#define VF610_PAD_PTA25__DCU1_TCON5 0x03C 0x000 ALT6 0x0 ++#define VF610_PAD_PTA26__GPIO_16 0x040 0x000 ALT0 0x0 ++#define VF610_PAD_PTA26__TRACED10 0x040 0x000 ALT1 0x0 ++#define VF610_PAD_PTA26__SAI3_TX_BCLK 0x040 0x000 ALT2 0x0 ++#define VF610_PAD_PTA26__ESDHC1_DAT0 0x040 0x000 ALT5 0x0 ++#define VF610_PAD_PTA26__DCU1_TCON6 0x040 0x000 ALT6 0x0 ++#define VF610_PAD_PTA27__GPIO_17 0x044 0x000 ALT0 0x0 ++#define VF610_PAD_PTA27__TRACED11 0x044 0x000 ALT1 0x0 ++#define VF610_PAD_PTA27__SAI3_RX_BCLK 0x044 0x000 ALT2 0x0 ++#define VF610_PAD_PTA27__ESDHC1_DAT1 0x044 0x000 ALT5 0x0 ++#define VF610_PAD_PTA27__DCU1_TCON7 0x044 0x000 ALT6 0x0 ++#define VF610_PAD_PTA28__GPIO_18 0x048 0x000 ALT0 0x0 ++#define VF610_PAD_PTA28__TRACED12 0x048 0x000 ALT1 0x0 ++#define VF610_PAD_PTA28__SAI3_RX_DATA 0x048 0x000 ALT2 0x0 ++#define VF610_PAD_PTA28__ENET1_1588_TMR0 0x048 0x000 ALT3 0x0 ++#define VF610_PAD_PTA28__UART4_TX 0x048 0x000 ALT4 0x0 ++#define VF610_PAD_PTA28__ESDHC1_DATA2 0x048 0x000 ALT5 0x0 ++#define VF610_PAD_PTA28__DCU1_TCON8 0x048 0x000 ALT6 0x0 ++#define VF610_PAD_PTA29__GPIO_19 0x04C 0x000 ALT0 0x0 ++#define VF610_PAD_PTA29__TRACED13 0x04C 0x000 ALT1 0x0 ++#define VF610_PAD_PTA29__SAI3_TX_DATA 0x04C 0x000 ALT2 0x0 ++#define VF610_PAD_PTA29__ENET1_1588_TMR1 0x04C 0x000 ALT3 0x0 ++#define VF610_PAD_PTA29__UART4_RX 0x04C 0x000 ALT4 0x0 ++#define VF610_PAD_PTA29__ESDHC1_DAT3 0x04C 0x000 ALT5 0x0 ++#define VF610_PAD_PTA29__DCU1_TCON9 0x04C 0x000 ALT6 0x0 ++#define VF610_PAD_PTA30__GPIO_20 0x050 0x000 ALT0 0x0 ++#define VF610_PAD_PTA30__TRACED14 0x050 0x000 ALT1 0x0 ++#define VF610_PAD_PTA30__SAI3_RX_SYNC 0x050 0x000 ALT2 0x0 ++#define VF610_PAD_PTA30__ENET1_1588_TMR2 0x050 0x000 ALT3 0x0 ++#define VF610_PAD_PTA30__UART4_RTS 0x050 0x000 ALT4 0x0 ++#define VF610_PAD_PTA30__I2C3_SCL 0x050 0x000 ALT5 0x0 ++#define VF610_PAD_PTA30__UART3_TX 0x050 0x394 ALT7 0x1 ++#define VF610_PAD_PTA31__GPIO_21 0x054 0x000 ALT0 0x0 ++#define VF610_PAD_PTA31__TRACED15 0x054 0x000 ALT1 0x0 ++#define VF610_PAD_PTA31__SAI3_TX_SYNC 0x054 0x000 ALT2 0x0 ++#define VF610_PAD_PTA31__ENET1_1588_TMR3 0x054 0x000 ALT3 0x0 ++#define VF610_PAD_PTA31__UART4_CTS 0x054 0x000 ALT4 0x0 ++#define VF610_PAD_PTA31__I2C3_SDA 0x054 0x000 ALT5 0x0 ++#define VF610_PAD_PTA31__UART3_RX 0x054 0x390 ALT7 0x1 ++#define VF610_PAD_PTB0__GPIO_22 0x058 0x000 ALT0 0x0 ++#define VF610_PAD_PTB0__FTM0_CH0 0x058 0x000 ALT1 0x0 ++#define VF610_PAD_PTB0__ADC0_SE2 0x058 0x000 ALT2 0x0 ++#define VF610_PAD_PTB0__TRACE_CTL 0x058 0x000 ALT3 0x0 ++#define VF610_PAD_PTB0__LCD34 0x058 0x000 ALT4 0x0 ++#define VF610_PAD_PTB0__SAI2_RX_BCLK 0x058 0x364 ALT5 0x1 ++#define VF610_PAD_PTB0__VIU_DATA18 0x058 0x000 ALT6 0x0 ++#define VF610_PAD_PTB0__QSPI1_A_QPCS0 0x058 0x000 ALT7 0x0 ++#define VF610_PAD_PTB1__GPIO_23 0x05C 0x000 ALT0 0x0 ++#define VF610_PAD_PTB1__FTM0_CH1 0x05C 0x000 ALT1 0x0 ++#define VF610_PAD_PTB1__ADC0_SE3 0x05C 0x000 ALT2 0x0 ++#define VF610_PAD_PTB1__SRC_RCON30 0x05C 0x000 ALT3 0x0 ++#define VF610_PAD_PTB1__LCD35 0x05C 0x000 ALT4 0x0 ++#define VF610_PAD_PTB1__SAI2_RX_DATA 0x05C 0x368 ALT5 0x1 ++#define VF610_PAD_PTB1__VIU_DATA19 0x05C 0x000 ALT6 0x0 ++#define VF610_PAD_PTB1__QSPI1_A_DATA3 0x05C 0x000 ALT7 0x0 ++#define VF610_PAD_PTB2__GPIO_24 0x060 0x000 ALT0 0x0 ++#define VF610_PAD_PTB2__FTM0_CH2 0x060 0x000 ALT1 0x0 ++#define VF610_PAD_PTB2__ADC1_SE2 0x060 0x000 ALT2 0x0 ++#define VF610_PAD_PTB2__SRC_RCON31 0x060 0x000 ALT3 0x0 ++#define VF610_PAD_PTB2__LCD36 0x060 0x000 ALT4 0x0 ++#define VF610_PAD_PTB2__SAI2_RX_SYNC 0x060 0x36C ALT5 0x1 ++#define VF610_PAD_PTB2__VIDEO_IN0_DATA20 0x060 0x000 ALT6 0x0 ++#define VF610_PAD_PTB2__QSPI1_A_DATA2 0x060 0x000 ALT7 0x0 ++#define VF610_PAD_PTB3__GPIO_25 0x064 0x000 ALT0 0x0 ++#define VF610_PAD_PTB3__FTM0_CH3 0x064 0x000 ALT1 0x0 ++#define VF610_PAD_PTB3__ADC1_SE3 0x064 0x000 ALT2 0x0 ++#define VF610_PAD_PTB3__PDB_EXTRIG 0x064 0x000 ALT3 0x0 ++#define VF610_PAD_PTB3__LCD37 0x064 0x000 ALT4 0x0 ++#define VF610_PAD_PTB3__VIU_DATA21 0x064 0x000 ALT6 0x0 ++#define VF610_PAD_PTB3__QSPI1_A_DATA1 0x064 0x000 ALT7 0x0 ++#define VF610_PAD_PTB4__GPIO_26 0x068 0x000 ALT0 0x0 ++#define VF610_PAD_PTB4__FTM0_CH4 0x068 0x000 ALT1 0x0 ++#define VF610_PAD_PTB4__UART1_TX 0x068 0x380 ALT2 0x0 ++#define VF610_PAD_PTB4__ADC0_SE4 0x068 0x000 ALT3 0x0 ++#define VF610_PAD_PTB4__LCD38 0x068 0x000 ALT4 0x0 ++#define VF610_PAD_PTB4__VIU_FID 0x068 0x3A8 ALT5 0x0 ++#define VF610_PAD_PTB4__VIU_DATA22 0x068 0x000 ALT6 0x0 ++#define VF610_PAD_PTB4__QSPI1_A_DATA0 0x068 0x000 ALT7 0x0 ++#define VF610_PAD_PTB5__GPIO_27 0x06C 0x000 ALT0 0x0 ++#define VF610_PAD_PTB5__FTM0_CH5 0x06C 0x000 ALT1 0x0 ++#define VF610_PAD_PTB5__UART1_RX 0x06C 0x37C ALT2 0x0 ++#define VF610_PAD_PTB5__ADC1_SE4 0x06C 0x000 ALT3 0x0 ++#define VF610_PAD_PTB5__LCD39 0x06C 0x000 ALT4 0x0 ++#define VF610_PAD_PTB5__VIU_DE 0x06C 0x3A4 ALT5 0x0 ++#define VF610_PAD_PTB5__QSPI1_A_DQS 0x06C 0x000 ALT7 0x0 ++#define VF610_PAD_PTB6__GPIO_28 0x070 0x000 ALT0 0x0 ++#define VF610_PAD_PTB6__FTM0_CH6 0x070 0x000 ALT1 0x0 ++#define VF610_PAD_PTB6__UART1_RTS 0x070 0x000 ALT2 0x0 ++#define VF610_PAD_PTB6__QSPI0_QPCS1_A 0x070 0x000 ALT3 0x0 ++#define VF610_PAD_PTB6__LCD_LCD40 0x070 0x000 ALT4 0x0 ++#define VF610_PAD_PTB6__FB_CLKOUT 0x070 0x000 ALT5 0x0 ++#define VF610_PAD_PTB6__VIU_HSYNC 0x070 0x000 ALT6 0x0 ++#define VF610_PAD_PTB6__UART2_TX 0x070 0x38C ALT7 0x0 ++#define VF610_PAD_PTB7__GPIO_29 0x074 0x000 ALT0 0x0 ++#define VF610_PAD_PTB7__FTM0_CH7 0x074 0x000 ALT1 0x0 ++#define VF610_PAD_PTB7__UART1_CTS 0x074 0x378 ALT2 0x0 ++#define VF610_PAD_PTB7__QSPI0_B_QPCS1 0x074 0x000 ALT3 0x0 ++#define VF610_PAD_PTB7__LCD41 0x074 0x000 ALT4 0x0 ++#define VF610_PAD_PTB7__VIU_VSYNC 0x074 0x000 ALT6 0x0 ++#define VF610_PAD_PTB7__UART2_RX 0x074 0x388 ALT7 0x0 ++#define VF610_PAD_PTB8__GPIO_30 0x078 0x000 ALT0 0x0 ++#define VF610_PAD_PTB8__FTM1_CH0 0x078 0x32C ALT1 0x0 ++#define VF610_PAD_PTB8__FTM1_QD_PHA 0x078 0x334 ALT3 0x1 ++#define VF610_PAD_PTB8__VIU_DE 0x078 0x3A4 ALT5 0x1 ++#define VF610_PAD_PTB8__DCU1_R6 0x078 0x000 ALT7 0x0 ++#define VF610_PAD_PTB9__GPIO_31 0x07C 0x000 ALT0 0x0 ++#define VF610_PAD_PTB9__FTM1_CH1 0x07C 0x330 ALT1 0x0 ++#define VF610_PAD_PTB9__FTM1_QD_PHB 0x07C 0x338 ALT3 0x1 ++#define VF610_PAD_PTB9__DCU1_R7 0x07C 0x000 ALT7 0x0 ++#define VF610_PAD_PTB10__GPIO_32 0x080 0x000 ALT0 0x0 ++#define VF610_PAD_PTB10__UART0_TX 0x080 0x000 ALT1 0x0 ++#define VF610_PAD_PTB10__DCU0_TCON4 0x080 0x000 ALT4 0x0 ++#define VF610_PAD_PTB10__VIU_DE 0x080 0x3A4 ALT5 0x2 ++#define VF610_PAD_PTB10__CKO1 0x080 0x000 ALT6 0x0 ++#define VF610_PAD_PTB10__ENET_TS_CLKIN 0x080 0x2F4 ALT7 0x1 ++#define VF610_PAD_PTB11__GPIO_33 0x084 0x000 ALT0 0x0 ++#define VF610_PAD_PTB11__UART0_RX 0x084 0x000 ALT1 0x0 ++#define VF610_PAD_PTB11__DCU0_TCON5 0x084 0x000 ALT4 0x0 ++#define VF610_PAD_PTB11__SNVS_ALARM_OUT_B 0x084 0x000 ALT5 0x0 ++#define VF610_PAD_PTB11__CKO2 0x084 0x000 ALT6 0x0 ++#define VF610_PAD_PTB11_ENET0_1588_TMR0 0x084 0x304 ALT7 0x0 ++#define VF610_PAD_PTB12__GPIO_34 0x088 0x000 ALT0 0x0 ++#define VF610_PAD_PTB12__UART0_RTS 0x088 0x000 ALT1 0x0 ++#define VF610_PAD_PTB12__DSPI0_CS5 0x088 0x000 ALT3 0x0 ++#define VF610_PAD_PTB12__DCU0_TCON6 0x088 0x000 ALT4 0x0 ++#define VF610_PAD_PTB12__FB_AD1 0x088 0x000 ALT5 0x0 ++#define VF610_PAD_PTB12__NMI 0x088 0x000 ALT6 0x0 ++#define VF610_PAD_PTB12__ENET0_1588_TMR1 0x088 0x308 ALT7 0x0 ++#define VF610_PAD_PTB13__GPIO_35 0x08C 0x000 ALT0 0x0 ++#define VF610_PAD_PTB13__UART0_CTS 0x08C 0x000 ALT1 0x0 ++#define VF610_PAD_PTB13__DSPI0_CS4 0x08C 0x000 ALT3 0x0 ++#define VF610_PAD_PTB13__DCU0_TCON7 0x08C 0x000 ALT4 0x0 ++#define VF610_PAD_PTB13__FB_AD0 0x08C 0x000 ALT5 0x0 ++#define VF610_PAD_PTB13__TRACE_CTL 0x08C 0x000 ALT6 0x0 ++#define VF610_PAD_PTB14__GPIO_36 0x090 0x000 ALT0 0x0 ++#define VF610_PAD_PTB14__CAN0_RX 0x090 0x000 ALT1 0x0 ++#define VF610_PAD_PTB14__I2C0_SCL 0x090 0x33C ALT2 0x1 ++#define VF610_PAD_PTB14__DCU0_TCON8 0x090 0x000 ALT4 0x0 ++#define VF610_PAD_PTB14__DCU1_PCLK 0x090 0x000 ALT7 0x0 ++#define VF610_PAD_PTB15__GPIO_37 0x094 0x000 ALT0 0x0 ++#define VF610_PAD_PTB15__CAN0_TX 0x094 0x000 ALT1 0x0 ++#define VF610_PAD_PTB15__I2C0_SDA 0x094 0x340 ALT2 0x1 ++#define VF610_PAD_PTB15__DCU0_TCON9 0x094 0x000 ALT4 0x0 ++#define VF610_PAD_PTB15__VIU_PIX_CLK 0x094 0x3AC ALT7 0x0 ++#define VF610_PAD_PTB16__GPIO_38 0x098 0x000 ALT0 0x0 ++#define VF610_PAD_PTB16__CAN1_RX 0x098 0x000 ALT1 0x0 ++#define VF610_PAD_PTB16__I2C1_SCL 0x098 0x344 ALT2 0x1 ++#define VF610_PAD_PTB16__DCU0_TCON10 0x098 0x000 ALT4 0x0 ++#define VF610_PAD_PTB17__GPIO_39 0x09C 0x000 ALT0 0x0 ++#define VF610_PAD_PTB17__CAN1_TX 0x09C 0x000 ALT1 0x0 ++#define VF610_PAD_PTB17__I2C1_SDA 0x09C 0x348 ALT2 0x1 ++#define VF610_PAD_PTB17__DCU0_TCON11 0x09C 0x000 ALT4 0x0 ++#define VF610_PAD_PTB18__GPIO_40 0x0A0 0x000 ALT0 0x0 ++#define VF610_PAD_PTB18__DSPI0_CS1 0x0A0 0x000 ALT1 0x0 ++#define VF610_PAD_PTB18__EXT_AUDIO_MCLK 0x0A0 0x2EC ALT2 0x2 ++#define VF610_PAD_PTB18__VIU_DATA9 0x0A0 0x000 ALT6 0x0 ++#define VF610_PAD_PTB19__GPIO_41 0x0A4 0x000 ALT0 0x0 ++#define VF610_PAD_PTB19__DSPI0_CS0 0x0A4 0x000 ALT1 0x0 ++#define VF610_PAD_PTB19__VIU_DATA10 0x0A4 0x000 ALT6 0x0 ++#define VF610_PAD_PTB20__GPIO_42 0x0A8 0x000 ALT0 0x0 ++#define VF610_PAD_PTB20__DSPI0_SIN 0x0A8 0x000 ALT1 0x0 ++#define VF610_PAD_PTB20__LCD42 0x0A8 0x000 ALT4 0x0 ++#define VF610_PAD_PTB20__VIU_DATA11 0x0A8 0x000 ALT6 0x0 ++#define VF610_PAD_PTB21__GPIO_43 0x0AC 0x000 ALT0 0x0 ++#define VF610_PAD_PTB21__DSPI0_SOUT 0x0AC 0x000 ALT1 0x0 ++#define VF610_PAD_PTB21__LCD43 0x0AC 0x000 ALT4 0x0 ++#define VF610_PAD_PTB21__VIU_DATA12 0x0AC 0x000 ALT6 0x0 ++#define VF610_PAD_PTB21__DCU1_PCLK 0x0AC 0x000 ALT7 0x0 ++#define VF610_PAD_PTB22__GPIO_44 0x0B0 0x000 ALT0 0x0 ++#define VF610_PAD_PTB22__DSPI0_SCK 0x0B0 0x000 ALT1 0x0 ++#define VF610_PAD_PTB22__VLCD 0x0B0 0x000 ALT4 0x0 ++#define VF610_PAD_PTB22__VIU_FID 0x0B0 0x3A8 ALT5 0x1 ++#define VF610_PAD_PTC0__GPIO_45 0x0B4 0x000 ALT0 0x0 ++#define VF610_PAD_PTC0__ENET_RMII0_MDC 0x0B4 0x000 ALT1 0x0 ++#define VF610_PAD_PTC0__FTM1_CH0 0x0B4 0x32C ALT2 0x1 ++#define VF610_PAD_PTC0__DSPI0_CS3 0x0B4 0x000 ALT3 0x0 ++#define VF610_PAD_PTC0__ESAI_SCKT 0x0B4 0x310 ALT4 0x0 ++#define VF610_PAD_PTC0__ESDHC0_CLK 0x0B4 0x000 ALT5 0x0 ++#define VF610_PAD_PTC0__VIU_DATA0 0x0B4 0x000 ALT6 0x0 ++#define VF610_PAD_PTC0__SRC_RCON18 0x0B4 0x398 ALT7 0x0 ++#define VF610_PAD_PTC1__GPIO_46 0x0B8 0x000 ALT0 0x0 ++#define VF610_PAD_PTC1__ENET_RMII0_MDIO 0x0B8 0x000 ALT1 0x0 ++#define VF610_PAD_PTC1__FTM1_CH1 0x0B8 0x330 ALT2 0x1 ++#define VF610_PAD_PTC1__DSPI0_CS2 0x0B8 0x000 ALT3 0x0 ++#define VF610_PAD_PTC1__ESAI_FST 0x0B8 0x30C ALT4 0x0 ++#define VF610_PAD_PTC1__ESDHC0_CMD 0x0B8 0x000 ALT5 0x0 ++#define VF610_PAD_PTC1__VIU_DATA1 0x0B8 0x000 ALT6 0x0 ++#define VF610_PAD_PTC1__SRC_RCON19 0x0B8 0x39C ALT7 0x0 ++#define VF610_PAD_PTC2__GPIO_47 0x0BC 0x000 ALT0 0x0 ++#define VF610_PAD_PTC2__ENET_RMII0_CRS 0x0BC 0x000 ALT1 0x0 ++#define VF610_PAD_PTC2__UART1_TX 0x0BC 0x380 ALT2 0x1 ++#define VF610_PAD_PTC2__ESAI_SDO0 0x0BC 0x314 ALT4 0x0 ++#define VF610_PAD_PTC2__ESDHC0_DAT0 0x0BC 0x000 ALT5 0x0 ++#define VF610_PAD_PTC2__VIU_DATA2 0x0BC 0x000 ALT6 0x0 ++#define VF610_PAD_PTC2__SRC_RCON20 0x0BC 0x3A0 ALT7 0x0 ++#define VF610_PAD_PTC3__GPIO_48 0x0C0 0x000 ALT0 0x0 ++#define VF610_PAD_PTC3__ENET_RMII0_RXD1 0x0C0 0x000 ALT1 0x0 ++#define VF610_PAD_PTC3__UART1_RX 0x0C0 0x37C ALT2 0x1 ++#define VF610_PAD_PTC3__ESAI_SDO1 0x0C0 0x318 ALT4 0x0 ++#define VF610_PAD_PTC3__ESDHC0_DAT1 0x0C0 0x000 ALT5 0x0 ++#define VF610_PAD_PTC3__VIU_DATA3 0x0C0 0x000 ALT6 0x0 ++#define VF610_PAD_PTC3__DCU0_R0 0x0C0 0x000 ALT7 0x0 ++#define VF610_PAD_PTC4__GPIO_49 0x0C4 0x000 ALT0 0x0 ++#define VF610_PAD_PTC4__ENET_RMII0_RXD0 0x0C4 0x000 ALT1 0x0 ++#define VF610_PAD_PTC4__UART1_RTS 0x0C4 0x000 ALT2 0x0 ++#define VF610_PAD_PTC4__DSPI1_CS1 0x0C4 0x000 ALT3 0x0 ++#define VF610_PAD_PTC4__ESAI_SDO2 0x0C4 0x31C ALT4 0x0 ++#define VF610_PAD_PTC4__ESDHC0_DAT2 0x0C4 0x000 ALT5 0x0 ++#define VF610_PAD_PTC4__VIU_DATA4 0x0C4 0x000 ALT6 0x0 ++#define VF610_PAD_PTC4__DCU0_R1 0x0C4 0x000 ALT7 0x0 ++#define VF610_PAD_PTC5__GPIO_50 0x0C8 0x000 ALT0 0x0 ++#define VF610_PAD_PTC5__ENET_RMII0_RXER 0x0C8 0x000 ALT1 0x0 ++#define VF610_PAD_PTC5__UART1_CTS 0x0C8 0x378 ALT2 0x1 ++#define VF610_PAD_PTC5__DSPI1_CS0 0x0C8 0x300 ALT3 0x0 ++#define VF610_PAD_PTC5__ESAI_SDO3 0x0C8 0x320 ALT4 0x0 ++#define VF610_PAD_PTC5__ESDHC0_DAT3 0x0C8 0x000 ALT5 0x0 ++#define VF610_PAD_PTC5__VIU_DATA5 0x0C8 0x000 ALT6 0x0 ++#define VF610_PAD_PTC5__DCU0_G0 0x0C8 0x000 ALT7 0x0 ++#define VF610_PAD_PTC6__GPIO_51 0x0CC 0x000 ALT0 0x0 ++#define VF610_PAD_PTC6__ENET_RMII0_TXD1 0x0CC 0x000 ALT1 0x0 ++#define VF610_PAD_PTC6__DSPI1_SIN 0x0CC 0x2FC ALT3 0x0 ++#define VF610_PAD_PTC6__ESAI_SDI0 0x0CC 0x328 ALT4 0x0 ++#define VF610_PAD_PTC6__ESDHC0_WP 0x0CC 0x000 ALT5 0x0 ++#define VF610_PAD_PTC6__VIU_DATA6 0x0CC 0x000 ALT6 0x0 ++#define VF610_PAD_PTC6__DCU0_G1 0x0CC 0x000 ALT7 0x0 ++#define VF610_PAD_PTC7__GPIO_52 0x0D0 0x000 ALT0 0x0 ++#define VF610_PAD_PTC7__ENET_RMII0_TXD0 0x0D0 0x000 ALT1 0x0 ++#define VF610_PAD_PTC7__DSPI1_SOUT 0x0D0 0x000 ALT3 0x0 ++#define VF610_PAD_PTC7__ESAI_SDI1 0x0D0 0x324 ALT4 0x0 ++#define VF610_PAD_PTC7__VIU_DATA7 0x0D0 0x000 ALT6 0x0 ++#define VF610_PAD_PTC7__DCU0_B0 0x0D0 0x000 ALT7 0x0 ++#define VF610_PAD_PTC8__GPIO_53 0x0D4 0x000 ALT0 0x0 ++#define VF610_PAD_PTC8__ENET_RMII0_TXEN 0x0D4 0x000 ALT1 0x0 ++#define VF610_PAD_PTC8__DSPI1_SCK 0x0D4 0x2F8 ALT3 0x0 ++#define VF610_PAD_PTC8__VIU_DATA8 0x0D4 0x000 ALT6 0x0 ++#define VF610_PAD_PTC8__DCU0_B1 0x0D4 0x000 ALT7 0x0 ++#define VF610_PAD_PTC9__GPIO_54 0x0D8 0x000 ALT0 0x0 ++#define VF610_PAD_PTC9__ENET_RMII1_MDC 0x0D8 0x000 ALT1 0x0 ++#define VF610_PAD_PTC9__ESAI_SCKT 0x0D8 0x310 ALT3 0x1 ++#define VF610_PAD_PTC9__MLB_CLK 0x0D8 0x354 ALT6 0x1 ++#define VF610_PAD_PTC9__DEBUG_OUT0 0x0D8 0x000 ALT7 0x0 ++#define VF610_PAD_PTC10__GPIO_55 0x0DC 0x000 ALT0 0x0 ++#define VF610_PAD_PTC10__ENET_RMII1_MDIO 0x0DC 0x000 ALT1 0x0 ++#define VF610_PAD_PTC10__ESAI_FST 0x0DC 0x30C ALT3 0x1 ++#define VF610_PAD_PTC10__MLB_SIGNAL 0x0DC 0x35C ALT6 0x1 ++#define VF610_PAD_PTC10__DEBUG_OUT1 0x0DC 0x000 ALT7 0x0 ++#define VF610_PAD_PTC11__GPIO_56 0x0E0 0x000 ALT0 0x0 ++#define VF610_PAD_PTC11__ENET_RMII1_CRS 0x0E0 0x000 ALT1 0x0 ++#define VF610_PAD_PTC11__ESAI_SDO0 0x0E0 0x314 ALT3 0x1 ++#define VF610_PAD_PTC11__MLB_DATA 0x0E0 0x358 ALT6 0x1 ++#define VF610_PAD_PTC11__DEBUG_OUT 0x0E0 0x000 ALT7 0x0 ++#define VF610_PAD_PTC12__GPIO_57 0x0E4 0x000 ALT0 0x0 ++#define VF610_PAD_PTC12__ENET_RMII_RXD1 0x0E4 0x000 ALT1 0x0 ++#define VF610_PAD_PTC12__ESAI_SDO1 0x0E4 0x318 ALT3 0x1 ++#define VF610_PAD_PTC12__SAI2_TX_BCLK 0x0E4 0x370 ALT5 0x1 ++#define VF610_PAD_PTC12__DEBUG_OUT3 0x0E4 0x000 ALT7 0x0 ++#define VF610_PAD_PTC13__GPIO_58 0x0E8 0x000 ALT0 0x0 ++#define VF610_PAD_PTC13__ENET_RMII1_RXD0 0x0E8 0x000 ALT1 0x0 ++#define VF610_PAD_PTC13__ESAI_SDO2 0x0E8 0x31C ALT3 0x1 ++#define VF610_PAD_PTC13__SAI2_RX_BCLK 0x0E8 0x364 ALT5 0x2 ++#define VF610_PAD_PTC13__DEBUG_OUT4 0x0E8 0x000 ALT7 0x0 ++#define VF610_PAD_PTC14__GPIO_59 0x0EC 0x000 ALT0 0x0 ++#define VF610_PAD_PTC14__ENET_RMII1_RXER 0x0EC 0x000 ALT1 0x0 ++#define VF610_PAD_PTC14__ESAI_SDO3 0x0EC 0x320 ALT3 0x1 ++#define VF610_PAD_PTC14__UART5_TX 0x0EC 0x000 ALT4 0x0 ++#define VF610_PAD_PTC14__SAI2_RX_DATA 0x0EC 0x368 ALT5 0x2 ++#define VF610_PAD_PTC14__ADC0_SE6 0x0EC 0x000 ALT6 0x0 ++#define VF610_PAD_PTC14__DEBUG_OUT5 0x0EC 0x000 ALT7 0x0 ++#define VF610_PAD_PTC15__GPIO_60 0x0F0 0x000 ALT0 0x0 ++#define VF610_PAD_PTC15__ENET_RMII1_TXD1 0x0F0 0x000 ALT1 0x0 ++#define VF610_PAD_PTC15__ESAI_SDI0 0x0F0 0x328 ALT3 0x1 ++#define VF610_PAD_PTC15__UART5_RX 0x0F0 0x000 ALT4 0x0 ++#define VF610_PAD_PTC15__SAI2_TX_DATA 0x0F0 0x000 ALT5 0x0 ++#define VF610_PAD_PTC15__ADC0_SE7 0x0F0 0x000 ALT6 0x0 ++#define VF610_PAD_PTC15__DEBUG_OUT6 0x0F0 0x000 ALT7 0x0 ++#define VF610_PAD_PTC16__GPIO_61 0x0F4 0x000 ALT0 0x0 ++#define VF610_PAD_PTC16__ENET_RMII1_TXD0 0x0F4 0x000 ALT1 0x0 ++#define VF610_PAD_PTC16__ESAI_SDI1 0x0F4 0x324 ALT3 0x1 ++#define VF610_PAD_PTC16__UART5_RTS 0x0F4 0x000 ALT4 0x0 ++#define VF610_PAD_PTC16__SAI2_RX_SYNC 0x0F4 0x36C ALT5 0x2 ++#define VF610_PAD_PTC16__ADC1_SE6 0x0F4 0x000 ALT6 0x0 ++#define VF610_PAD_PTC16__DEBUG_OUT7 0x0F4 0x000 ALT7 0x0 ++#define VF610_PAD_PTC17__GPIO_62 0x0F8 0x000 ALT0 0x0 ++#define VF610_PAD_PTC17__ENET_RMII1_TXEN 0x0F8 0x000 ALT1 0x0 ++#define VF610_PAD_PTC17__ADC1_SE7 0x0F8 0x000 ALT3 0x0 ++#define VF610_PAD_PTC17__UART5_CTS 0x0F8 0x000 ALT4 0x0 ++#define VF610_PAD_PTC17__SAI2_TX_SYNC 0x0F8 0x374 ALT5 0x1 ++#define VF610_PAD_PTC17__USB1_SOF_PULSE 0x0F8 0x000 ALT6 0x0 ++#define VF610_PAD_PTC17__DEBUG_OUT8 0x0F8 0x000 ALT7 0x0 ++#define VF610_PAD_PTD31__GPIO_63 0x0FC 0x000 ALT0 0x0 ++#define VF610_PAD_PTD31__FB_AD31 0x0FC 0x000 ALT1 0x0 ++#define VF610_PAD_PTD31__NF_IO15 0x0FC 0x000 ALT2 0x0 ++#define VF610_PAD_PTD31__FTM3_CH0 0x0FC 0x000 ALT4 0x0 ++#define VF610_PAD_PTD31__DSPI2_CS1 0x0FC 0x000 ALT5 0x0 ++#define VF610_PAD_PTD31__DEBUG_OUT9 0x0FC 0x000 ALT7 0x0 ++#define VF610_PAD_PTD30__GPIO_64 0x100 0x000 ALT0 0x0 ++#define VF610_PAD_PTD30__FB_AD30 0x100 0x000 ALT1 0x0 ++#define VF610_PAD_PTD30__NF_IO14 0x100 0x000 ALT2 0x0 ++#define VF610_PAD_PTD30__FTM3_CH1 0x100 0x000 ALT4 0x0 ++#define VF610_PAD_PTD30__DSPI2_CS0 0x100 0x000 ALT5 0x0 ++#define VF610_PAD_PTD30__DEBUG_OUT10 0x100 0x000 ALT7 0x0 ++#define VF610_PAD_PTD29__GPIO_65 0x104 0x000 ALT0 0x0 ++#define VF610_PAD_PTD29__FB_AD29 0x104 0x000 ALT1 0x0 ++#define VF610_PAD_PTD29__NF_IO13 0x104 0x000 ALT2 0x0 ++#define VF610_PAD_PTD29__FTM3_CH2 0x104 0x000 ALT4 0x0 ++#define VF610_PAD_PTD29__DSPI2_SIN 0x104 0x000 ALT5 0x0 ++#define VF610_PAD_PTD29__DEBUG_OUT11 0x104 0x000 ALT7 0x0 ++#define VF610_PAD_PTD28__GPIO_66 0x108 0x000 ALT0 0x0 ++#define VF610_PAD_PTD28__FB_AD28 0x108 0x000 ALT1 0x0 ++#define VF610_PAD_PTD28__NF_IO12 0x108 0x000 ALT2 0x0 ++#define VF610_PAD_PTD28__I2C2_SCL 0x108 0x34C ALT3 0x1 ++#define VF610_PAD_PTD28__FTM3_CH3 0x108 0x000 ALT4 0x0 ++#define VF610_PAD_PTD28__DSPI2_SOUT 0x108 0x000 ALT5 0x0 ++#define VF610_PAD_PTD28__DEBUG_OUT12 0x108 0x000 ALT7 0x0 ++#define VF610_PAD_PTD27__GPIO_67 0x10C 0x000 ALT0 0x0 ++#define VF610_PAD_PTD27__FB_AD27 0x10C 0x000 ALT1 0x0 ++#define VF610_PAD_PTD27__NF_IO11 0x10C 0x000 ALT2 0x0 ++#define VF610_PAD_PTD27__I2C2_SDA 0x10C 0x350 ALT3 0x1 ++#define VF610_PAD_PTD27__FTM3_CH4 0x10C 0x000 ALT4 0x0 ++#define VF610_PAD_PTD27__DSPI2_SCK 0x10C 0x000 ALT5 0x0 ++#define VF610_PAD_PTD27__DEBUG_OUT13 0x10C 0x000 ALT7 0x0 ++#define VF610_PAD_PTD26__GPIO_68 0x110 0x000 ALT0 0x0 ++#define VF610_PAD_PTD26__FB_AD26 0x110 0x000 ALT1 0x0 ++#define VF610_PAD_PTD26__NF_IO10 0x110 0x000 ALT2 0x0 ++#define VF610_PAD_PTD26__FTM3_CH5 0x110 0x000 ALT4 0x0 ++#define VF610_PAD_PTD26__ESDHC1_WP 0x110 0x000 ALT5 0x0 ++#define VF610_PAD_PTD26__DEBUG_OUT14 0x110 0x000 ALT7 0x0 ++#define VF610_PAD_PTD25__GPIO_69 0x114 0x000 ALT0 0x0 ++#define VF610_PAD_PTD25__FB_AD25 0x114 0x000 ALT1 0x0 ++#define VF610_PAD_PTD25__NF_IO9 0x114 0x000 ALT2 0x0 ++#define VF610_PAD_PTD25__FTM3_CH6 0x114 0x000 ALT4 0x0 ++#define VF610_PAD_PTD25__DEBUG_OUT15 0x114 0x000 ALT7 0x0 ++#define VF610_PAD_PTD24__GPIO_70 0x118 0x000 ALT0 0x0 ++#define VF610_PAD_PTD24__FB_AD24 0x118 0x000 ALT1 0x0 ++#define VF610_PAD_PTD24__NF_IO8 0x118 0x000 ALT2 0x0 ++#define VF610_PAD_PTD24__FTM3_CH7 0x118 0x000 ALT4 0x0 ++#define VF610_PAD_PTD24__DEBUG_OUT16 0x118 0x000 ALT7 0x0 ++#define VF610_PAD_PTD23__GPIO_71 0x11C 0x000 ALT0 0x0 ++#define VF610_PAD_PTD23__FB_AD23 0x11C 0x000 ALT1 0x0 ++#define VF610_PAD_PTD23__NF_IO7 0x11C 0x000 ALT2 0x0 ++#define VF610_PAD_PTD23__FTM2_CH0 0x11C 0x000 ALT3 0x0 ++#define VF610_PAD_PTD23__ENET0_1588_TMR0 0x11C 0x304 ALT4 0x1 ++#define VF610_PAD_PTD23__ESDHC0_DAT4 0x11C 0x000 ALT5 0x0 ++#define VF610_PAD_PTD23__UART2_TX 0x11C 0x38C ALT6 0x1 ++#define VF610_PAD_PTD23__DCU1_R3 0x11C 0x000 ALT7 0x0 ++#define VF610_PAD_PTD22__GPIO_72 0x120 0x000 ALT0 0x0 ++#define VF610_PAD_PTD22__FB_AD22 0x120 0x000 ALT1 0x0 ++#define VF610_PAD_PTD22__NF_IO6 0x120 0x000 ALT2 0x0 ++#define VF610_PAD_PTD22__FTM2_CH1 0x120 0x000 ALT3 0x0 ++#define VF610_PAD_PTD22__ENET0_1588_TMR1 0x120 0x308 ALT4 0x1 ++#define VF610_PAD_PTD22__ESDHC0_DAT5 0x120 0x000 ALT5 0x0 ++#define VF610_PAD_PTD22__UART2_RX 0x120 0x388 ALT6 0x1 ++#define VF610_PAD_PTD22__DCU1_R4 0x120 0x000 ALT7 0x0 ++#define VF610_PAD_PTD21__GPIO_73 0x124 0x000 ALT0 0x0 ++#define VF610_PAD_PTD21__FB_AD21 0x124 0x000 ALT1 0x0 ++#define VF610_PAD_PTD21__NF_IO5 0x124 0x000 ALT2 0x0 ++#define VF610_PAD_PTD21__ENET0_1588_TMR2 0x124 0x000 ALT4 0x0 ++#define VF610_PAD_PTD21__ESDHC0_DAT6 0x124 0x000 ALT5 0x0 ++#define VF610_PAD_PTD21__UART2_RTS 0x124 0x000 ALT6 0x0 ++#define VF610_PAD_PTD21__DCU1_R5 0x124 0x000 ALT7 0x0 ++#define VF610_PAD_PTD20__GPIO_74 0x128 0x000 ALT0 0x0 ++#define VF610_PAD_PTD20__FB_AD20 0x128 0x000 ALT1 0x0 ++#define VF610_PAD_PTD20__NF_IO4 0x128 0x000 ALT2 0x0 ++#define VF610_PAD_PTD20__ENET0_1588_TMR3 0x128 0x000 ALT4 0x0 ++#define VF610_PAD_PTD20__ESDHC0_DAT7 0x128 0x000 ALT5 0x0 ++#define VF610_PAD_PTD20__UART2_CTS 0x128 0x384 ALT6 0x0 ++#define VF610_PAD_PTD20__DCU1_R0 0x128 0x000 ALT7 0x0 ++#define VF610_PAD_PTD19__GPIO_75 0x12C 0x000 ALT0 0x0 ++#define VF610_PAD_PTD19__FB_AD19 0x12C 0x000 ALT1 0x0 ++#define VF610_PAD_PTD19__NF_IO3 0x12C 0x000 ALT2 0x0 ++#define VF610_PAD_PTD19__ESAI_SCKR 0x12C 0x000 ALT3 0x0 ++#define VF610_PAD_PTD19__I2C0_SCL 0x12C 0x33C ALT4 0x2 ++#define VF610_PAD_PTD19__FTM2_QD_PHA 0x12C 0x000 ALT5 0x0 ++#define VF610_PAD_PTD19__DCU1_R1 0x12C 0x000 ALT7 0x0 ++#define VF610_PAD_PTD18__GPIO_76 0x130 0x000 ALT0 0x0 ++#define VF610_PAD_PTD18__FB_AD18 0x130 0x000 ALT1 0x0 ++#define VF610_PAD_PTD18__NF_IO2 0x130 0x000 ALT2 0x0 ++#define VF610_PAD_PTD18__ESAI_FSR 0x130 0x000 ALT3 0x0 ++#define VF610_PAD_PTD18__I2C0_SDA 0x130 0x340 ALT4 0x2 ++#define VF610_PAD_PTD18__FTM2_QD_PHB 0x130 0x000 ALT5 0x0 ++#define VF610_PAD_PTD18__DCU1_G0 0x130 0x000 ALT7 0x0 ++#define VF610_PAD_PTD17__GPIO_77 0x134 0x000 ALT0 0x0 ++#define VF610_PAD_PTD17__FB_AD17 0x134 0x000 ALT1 0x0 ++#define VF610_PAD_PTD17__NF_IO1 0x134 0x000 ALT2 0x0 ++#define VF610_PAD_PTD17__ESAI_HCKR 0x134 0x000 ALT3 0x0 ++#define VF610_PAD_PTD17__I2C1_SCL 0x134 0x344 ALT4 0x2 ++#define VF610_PAD_PTD17__DCU1_G1 0x134 0x000 ALT7 0x0 ++#define VF610_PAD_PTD16__GPIO_78 0x138 0x000 ALT0 0x0 ++#define VF610_PAD_PTD16__FB_AD16 0x138 0x000 ALT1 0x0 ++#define VF610_PAD_PTD16__NF_IO0 0x138 0x000 ALT2 0x0 ++#define VF610_PAD_PTD16__ESAI_HCKT 0x138 0x000 ALT3 0x0 ++#define VF610_PAD_PTD16__I2C1_SDA 0x138 0x348 ALT4 0x2 ++#define VF610_PAD_PTD16__DCU1_G2 0x138 0x000 ALT7 0x0 ++#define VF610_PAD_PTD0__GPIO_79 0x13C 0x000 ALT0 0x0 ++#define VF610_PAD_PTD0__QSPI0_A_QSCK 0x13C 0x000 ALT1 0x0 ++#define VF610_PAD_PTD0__UART2_TX 0x13C 0x38C ALT2 0x2 ++#define VF610_PAD_PTD0__FB_AD15 0x13C 0x000 ALT4 0x0 ++#define VF610_PAD_PTD0__SPDIF_EXTCLK 0x13C 0x000 ALT5 0x0 ++#define VF610_PAD_PTD0__DEBUG_OUT17 0x13C 0x000 ALT7 0x0 ++#define VF610_PAD_PTD1__GPIO_80 0x140 0x000 ALT0 0x0 ++#define VF610_PAD_PTD1__QSPI0_A_CS0 0x140 0x000 ALT1 0x0 ++#define VF610_PAD_PTD1__UART2_RX 0x140 0x388 ALT2 0x2 ++#define VF610_PAD_PTD1__FB_AD14 0x140 0x000 ALT4 0x0 ++#define VF610_PAD_PTD1__SPDIF_IN1 0x140 0x000 ALT5 0x0 ++#define VF610_PAD_PTD1__DEBUG_OUT18 0x140 0x000 ALT7 0x0 ++#define VF610_PAD_PTD2__GPIO_81 0x144 0x000 ALT0 0x0 ++#define VF610_PAD_PTD2__QSPI0_A_DATA3 0x144 0x000 ALT1 0x0 ++#define VF610_PAD_PTD2__UART2_RTS 0x144 0x000 ALT2 0x0 ++#define VF610_PAD_PTD2__DSPI1_CS3 0x144 0x000 ALT3 0x0 ++#define VF610_PAD_PTD2__FB_AD13 0x144 0x000 ALT4 0x0 ++#define VF610_PAD_PTD2__SPDIF_OUT1 0x144 0x000 ALT5 0x0 ++#define VF610_PAD_PTD2__DEBUG_OUT19 0x144 0x000 ALT7 0x0 ++#define VF610_PAD_PTD3__GPIO_82 0x148 0x000 ALT0 0x0 ++#define VF610_PAD_PTD3__QSPI0_A_DATA2 0x148 0x000 ALT1 0x0 ++#define VF610_PAD_PTD3__UART2_CTS 0x148 0x384 ALT2 0x1 ++#define VF610_PAD_PTD3__DSPI1_CS2 0x148 0x000 ALT3 0x0 ++#define VF610_PAD_PTD3__FB_AD12 0x148 0x000 ALT4 0x0 ++#define VF610_PAD_PTD3__SPDIF_PLOCK 0x148 0x000 ALT5 0x0 ++#define VF610_PAD_PTD3__DEBUG_OUT20 0x148 0x000 ALT7 0x0 ++#define VF610_PAD_PTD4__GPIO_83 0x14C 0x000 ALT0 0x0 ++#define VF610_PAD_PTD4__QSPI0_A_DATA1 0x14C 0x000 ALT1 0x0 ++#define VF610_PAD_PTD4__DSPI1_CS1 0x14C 0x000 ALT3 0x0 ++#define VF610_PAD_PTD4__FB_AD11 0x14C 0x000 ALT4 0x0 ++#define VF610_PAD_PTD4__SPDIF_SRCLK 0x14C 0x000 ALT5 0x0 ++#define VF610_PAD_PTD4__DEBUG_OUT21 0x14C 0x000 ALT7 0x0 ++#define VF610_PAD_PTD5__GPIO_84 0x150 0x000 ALT0 0x0 ++#define VF610_PAD_PTD5__QSPI0_A_DATA0 0x150 0x000 ALT1 0x0 ++#define VF610_PAD_PTD5__DSPI1_CS0 0x150 0x300 ALT3 0x1 ++#define VF610_PAD_PTD5__FB_AD10 0x150 0x000 ALT4 0x0 ++#define VF610_PAD_PTD5__DEBUG_OUT22 0x150 0x000 ALT7 0x0 ++#define VF610_PAD_PTD6__GPIO_85 0x154 0x000 ALT0 0x0 ++#define VF610_PAD_PTD6__QSPI1_A_DQS 0x154 0x000 ALT1 0x0 ++#define VF610_PAD_PTD6__DSPI1_SIN 0x154 0x2FC ALT3 0x1 ++#define VF610_PAD_PTD6__FB_AD9 0x154 0x000 ALT4 0x0 ++#define VF610_PAD_PTD6__DEBUG_OUT23 0x154 0x000 ALT7 0x0 ++#define VF610_PAD_PTD7__GPIO_86 0x158 0x000 ALT0 0x0 ++#define VF610_PAD_PTD7__QSPI0_B_QSCK 0x158 0x000 ALT1 0x0 ++#define VF610_PAD_PTD7__DSPI1_SOUT 0x158 0x000 ALT3 0x0 ++#define VF610_PAD_PTD7__FB_AD8 0x158 0x000 ALT4 0x0 ++#define VF610_PAD_PTD7__DEBUG_OUT24 0x158 0x000 ALT7 0x0 ++#define VF610_PAD_PTD8__GPIO_87 0x15C 0x000 ALT0 0x0 ++#define VF610_PAD_PTD8__QSPI0_B_CS0 0x15C 0x000 ALT1 0x0 ++#define VF610_PAD_PTD8__FB_CLKOUT 0x15C 0x000 ALT2 0x0 ++#define VF610_PAD_PTD8__DSPI1_SCK 0x15C 0x2F8 ALT3 0x1 ++#define VF610_PAD_PTD8__FB_AD7 0x15C 0x000 ALT4 0x0 ++#define VF610_PAD_PTD8__DEBUG_OUT25 0x15C 0x000 ALT7 0x0 ++#define VF610_PAD_PTD9__GPIO_88 0x160 0x000 ALT0 0x0 ++#define VF610_PAD_PTD9__QSPI0_B_DATA3 0x160 0x000 ALT1 0x0 ++#define VF610_PAD_PTD9__DSPI3_CS1 0x160 0x000 ALT2 0x0 ++#define VF610_PAD_PTD9__FB_AD6 0x160 0x000 ALT4 0x0 ++#define VF610_PAD_PTD9__SAI1_TX_SYNC 0x160 0x360 ALT6 0x0 ++#define VF610_PAD_PTD9__DCU1_B0 0x160 0x000 ALT7 0x0 ++#define VF610_PAD_PTD10__GPIO_89 0x164 0x000 ALT0 0x0 ++#define VF610_PAD_PTD10__QSPI0_B_DATA2 0x164 0x000 ALT1 0x0 ++#define VF610_PAD_PTD10__DSPI3_CS0 0x164 0x000 ALT2 0x0 ++#define VF610_PAD_PTD10__FB_AD5 0x164 0x000 ALT4 0x0 ++#define VF610_PAD_PTD10__DCU1_B1 0x164 0x000 ALT7 0x0 ++#define VF610_PAD_PTD11__GPIO_90 0x168 0x000 ALT0 0x0 ++#define VF610_PAD_PTD11__QSPI0_B_DATA1 0x168 0x000 ALT1 0x0 ++#define VF610_PAD_PTD11__DSPI3_SIN 0x168 0x000 ALT2 0x0 ++#define VF610_PAD_PTD11__FB_AD4 0x168 0x000 ALT4 0x0 ++#define VF610_PAD_PTD11__DEBUG_OUT26 0x168 0x000 ALT7 0x0 ++#define VF610_PAD_PTD12__GPIO_91 0x16C 0x000 ALT0 0x0 ++#define VF610_PAD_PTD12__QSPI0_B_DATA0 0x16C 0x000 ALT1 0x0 ++#define VF610_PAD_PTD12__DSPI3_SOUT 0x16C 0x000 ALT2 0x0 ++#define VF610_PAD_PTD12__FB_AD3 0x16C 0x000 ALT4 0x0 ++#define VF610_PAD_PTD12__DEBUG_OUT27 0x16C 0x000 ALT7 0x0 ++#define VF610_PAD_PTD13__GPIO_92 0x170 0x000 ALT0 0x0 ++#define VF610_PAD_PTD13__QSPI0_B_DQS 0x170 0x000 ALT1 0x0 ++#define VF610_PAD_PTD13__DSPI3_SCK 0x170 0x000 ALT2 0x0 ++#define VF610_PAD_PTD13__FB_AD2 0x170 0x000 ALT4 0x0 ++#define VF610_PAD_PTD13__DEBUG_OUT28 0x170 0x000 ALT7 0x0 ++#define VF610_PAD_PTB23__GPIO_93 0x174 0x000 ALT0 0x0 ++#define VF610_PAD_PTB23__SAI0_TX_BCLK 0x174 0x000 ALT1 0x0 ++#define VF610_PAD_PTB23__UART1_TX 0x174 0x380 ALT2 0x2 ++#define VF610_PAD_PTB23__SRC_RCON18 0x174 0x398 ALT3 0x1 ++#define VF610_PAD_PTB23__FB_MUXED_ALE 0x174 0x000 ALT4 0x0 ++#define VF610_PAD_PTB23__FB_TS_B 0x174 0x000 ALT5 0x0 ++#define VF610_PAD_PTB23__UART3_RTS 0x174 0x000 ALT6 0x0 ++#define VF610_PAD_PTB23__DCU1_G3 0x174 0x000 ALT7 0x0 ++#define VF610_PAD_PTB24__GPIO_94 0x178 0x000 ALT0 0x0 ++#define VF610_PAD_PTB24__SAI0_RX_BCLK 0x178 0x000 ALT1 0x0 ++#define VF610_PAD_PTB24__UART1_RX 0x178 0x37C ALT2 0x2 ++#define VF610_PAD_PTB24__SRC_RCON19 0x178 0x39C ALT3 0x1 ++#define VF610_PAD_PTB24__FB_MUXED_TSIZ0 0x178 0x000 ALT4 0x0 ++#define VF610_PAD_PTB24__NF_WE_B 0x178 0x000 ALT5 0x0 ++#define VF610_PAD_PTB24__UART3_CTS 0x178 0x000 ALT6 0x0 ++#define VF610_PAD_PTB24__DCU1_G4 0x178 0x000 ALT7 0x0 ++#define VF610_PAD_PTB25__GPIO_95 0x17C 0x000 ALT0 0x0 ++#define VF610_PAD_PTB25__SAI0_RX_DATA 0x17C 0x000 ALT1 0x0 ++#define VF610_PAD_PTB25__UART1_RTS 0x17C 0x000 ALT2 0x0 ++#define VF610_PAD_PTB25__SRC_RCON20 0x17C 0x3A0 ALT3 0x1 ++#define VF610_PAD_PTB25__FB_CS1_B 0x17C 0x000 ALT4 0x0 ++#define VF610_PAD_PTB25__NF_CE0_B 0x17C 0x000 ALT5 0x0 ++#define VF610_PAD_PTB25__DCU1_G5 0x17C 0x000 ALT7 0x0 ++#define VF610_PAD_PTB26__GPIO_96 0x180 0x000 ALT0 0x0 ++#define VF610_PAD_PTB26__SAI0_TX_DATA 0x180 0x000 ALT1 0x0 ++#define VF610_PAD_PTB26__UART1_CTS 0x180 0x378 ALT2 0x2 ++#define VF610_PAD_PTB26__SRC_RCON21 0x180 0x000 ALT3 0x0 ++#define VF610_PAD_PTB26__FB_CS0_B 0x180 0x000 ALT4 0x0 ++#define VF610_PAD_PTB26__NF_CE1_B 0x180 0x000 ALT5 0x0 ++#define VF610_PAD_PTB26__DCU1_G6 0x180 0x000 ALT7 0x0 ++#define VF610_PAD_PTB27__GPIO_97 0x184 0x000 ALT0 0x0 ++#define VF610_PAD_PTB27__SAI0_RX_SYNC 0x184 0x000 ALT1 0x0 ++#define VF610_PAD_PTB27__SRC_RCON22 0x184 0x000 ALT3 0x0 ++#define VF610_PAD_PTB27__FB_OE_B 0x184 0x000 ALT4 0x0 ++#define VF610_PAD_PTB27__FB_MUXED_TBST_B 0x184 0x000 ALT5 0x0 ++#define VF610_PAD_PTB27__NF_RE_B 0x184 0x000 ALT6 0x0 ++#define VF610_PAD_PTB27__DCU1_G7 0x184 0x000 ALT7 0x0 ++#define VF610_PAD_PTB28__GPIO_98 0x188 0x000 ALT0 0x0 ++#define VF610_PAD_PTB28__SAI0_TX_SYNC 0x188 0x000 ALT1 0x0 ++#define VF610_PAD_PTB28__SRC_RCON23 0x188 0x000 ALT3 0x0 ++#define VF610_PAD_PTB28__FB_RW_B 0x188 0x000 ALT4 0x0 ++#define VF610_PAD_PTB28__DCU1_B6 0x188 0x000 ALT7 0x0 ++#define VF610_PAD_PTC26__GPIO_99 0x18C 0x000 ALT0 0x0 ++#define VF610_PAD_PTC26__SAI1_TX_BCLK 0x18C 0x000 ALT1 0x0 ++#define VF610_PAD_PTC26__DSPI0_CS5 0x18C 0x000 ALT2 0x0 ++#define VF610_PAD_PTC26__SRC_RCON24 0x18C 0x000 ALT3 0x0 ++#define VF610_PAD_PTC26__FB_TA_B 0x18C 0x000 ALT4 0x0 ++#define VF610_PAD_PTC26__NF_RB_B 0x18C 0x000 ALT5 0x0 ++#define VF610_PAD_PTC26__DCU1_B7 0x18C 0x000 ALT7 0x0 ++#define VF610_PAD_PTC27__GPIO_100 0x190 0x000 ALT0 0x0 ++#define VF610_PAD_PTC27__SAI1_RX_BCLK 0x190 0x000 ALT1 0x0 ++#define VF610_PAD_PTC27__DSPI0_CS4 0x190 0x000 ALT2 0x0 ++#define VF610_PAD_PTC27__SRC_RCON25 0x190 0x000 ALT3 0x0 ++#define VF610_PAD_PTC27__FB_BE3_B 0x190 0x000 ALT4 0x0 ++#define VF610_PAD_PTC27__FB_CS3_B 0x190 0x000 ALT5 0x0 ++#define VF610_PAD_PTC27__NF_ALE 0x190 0x000 ALT6 0x0 ++#define VF610_PAD_PTC27__DCU1_B2 0x190 0x000 ALT7 0x0 ++#define VF610_PAD_PTC28__GPIO_101 0x194 0x000 ALT0 0x0 ++#define VF610_PAD_PTC28__SAI1_RX_DATA 0x194 0x000 ALT1 0x0 ++#define VF610_PAD_PTC28__DSPI0_CS3 0x194 0x000 ALT2 0x0 ++#define VF610_PAD_PTC28__SRC_RCON26 0x194 0x000 ALT3 0x0 ++#define VF610_PAD_PTC28__FB_BE2_B 0x194 0x000 ALT4 0x0 ++#define VF610_PAD_PTC28__FB_CS2_B 0x194 0x000 ALT5 0x0 ++#define VF610_PAD_PTC28__NF_CLE 0x194 0x000 ALT6 0x0 ++#define VF610_PAD_PTC28__DCU1_B3 0x194 0x000 ALT7 0x0 ++#define VF610_PAD_PTC29__GPIO_102 0x198 0x000 ALT0 0x0 ++#define VF610_PAD_PTC29__SAI1_TX_DATA 0x198 0x000 ALT1 0x0 ++#define VF610_PAD_PTC29__DSPI0_CS2 0x198 0x000 ALT2 0x0 ++#define VF610_PAD_PTC29__SRC_RCON27 0x198 0x000 ALT3 0x0 ++#define VF610_PAD_PTC29__FB_BE1_B 0x198 0x000 ALT4 0x0 ++#define VF610_PAD_PTC29__FB_MUXED_TSIZE1 0x198 0x000 ALT5 0x0 ++#define VF610_PAD_PTC29__DCU1_B4 0x198 0x000 ALT7 0x0 ++#define VF610_PAD_PTC30__GPIO_103 0x19C 0x000 ALT0 0x0 ++#define VF610_PAD_PTC30__SAI1_RX_SYNC 0x19C 0x000 ALT1 0x0 ++#define VF610_PAD_PTC30__DSPI1_CS2 0x19C 0x000 ALT2 0x0 ++#define VF610_PAD_PTC30__SRC_RCON28 0x19C 0x000 ALT3 0x0 ++#define VF610_PAD_PTC30__FB_MUXED_BE0_B 0x19C 0x000 ALT4 0x0 ++#define VF610_PAD_PTC30__FB_TSIZ0 0x19C 0x000 ALT5 0x0 ++#define VF610_PAD_PTC30__ADC0_SE5 0x19C 0x000 ALT6 0x0 ++#define VF610_PAD_PTC30__DCU1_B5 0x19C 0x000 ALT7 0x0 ++#define VF610_PAD_PTC31__GPIO_104 0x1A0 0x000 ALT0 0x0 ++#define VF610_PAD_PTC31__SAI1_TX_SYNC 0x1A0 0x360 ALT1 0x1 ++#define VF610_PAD_PTC31__SRC_RCON29 0x1A0 0x000 ALT3 0x0 ++#define VF610_PAD_PTC31__ADC1_SE5 0x1A0 0x000 ALT6 0x0 ++#define VF610_PAD_PTC31__DCU1_B6 0x1A0 0x000 ALT7 0x0 ++#define VF610_PAD_PTE0__GPIO_105 0x1A4 0x000 ALT0 0x0 ++#define VF610_PAD_PTE0__DCU0_HSYNC 0x1A4 0x000 ALT1 0x0 ++#define VF610_PAD_PTE0__SRC_BMODE1 0x1A4 0x000 ALT2 0x0 ++#define VF610_PAD_PTE0__LCD0 0x1A4 0x000 ALT4 0x0 ++#define VF610_PAD_PTE0__DEBUG_OUT29 0x1A4 0x000 ALT7 0x0 ++#define VF610_PAD_PTE1__GPIO_106 0x1A8 0x000 ALT0 0x0 ++#define VF610_PAD_PTE1__DCU0_VSYNC 0x1A8 0x000 ALT1 0x0 ++#define VF610_PAD_PTE1__SRC_BMODE0 0x1A8 0x000 ALT2 0x0 ++#define VF610_PAD_PTE1__LCD1 0x1A8 0x000 ALT4 0x0 ++#define VF610_PAD_PTE1__DEBUG_OUT30 0x1A8 0x000 ALT7 0x0 ++#define VF610_PAD_PTE2__GPIO_107 0x1AC 0x000 ALT0 0x0 ++#define VF610_PAD_PTE2__DCU0_PCLK 0x1AC 0x000 ALT1 0x0 ++#define VF610_PAD_PTE2__LCD2 0x1AC 0x000 ALT4 0x0 ++#define VF610_PAD_PTE2__DEBUG_OUT31 0x1AC 0x000 ALT7 0x0 ++#define VF610_PAD_PTE3__GPIO_108 0x1B0 0x000 ALT0 0x0 ++#define VF610_PAD_PTE3__DCU0_TAG 0x1B0 0x000 ALT1 0x0 ++#define VF610_PAD_PTE3__LCD3 0x1B0 0x000 ALT4 0x0 ++#define VF610_PAD_PTE3__DEBUG_OUT32 0x1B0 0x000 ALT7 0x0 ++#define VF610_PAD_PTE4__GPIO_109 0x1B4 0x000 ALT0 0x0 ++#define VF610_PAD_PTE4__DCU0_DE 0x1B4 0x000 ALT1 0x0 ++#define VF610_PAD_PTE4__LCD4 0x1B4 0x000 ALT4 0x0 ++#define VF610_PAD_PTE4__DEBUG_OUT33 0x1B4 0x000 ALT7 0x0 ++#define VF610_PAD_PTE5__GPIO_110 0x1B8 0x000 ALT0 0x0 ++#define VF610_PAD_PTE5__DCU0_R0 0x1B8 0x000 ALT1 0x0 ++#define VF610_PAD_PTE5__LCD5 0x1B8 0x000 ALT4 0x0 ++#define VF610_PAD_PTE5__DEBUG_OUT34 0x1B8 0x000 ALT7 0x0 ++#define VF610_PAD_PTE6__GPIO_111 0x1BC 0x000 ALT0 0x0 ++#define VF610_PAD_PTE6__DCU0_R1 0x1BC 0x000 ALT1 0x0 ++#define VF610_PAD_PTE6__LCD6 0x1BC 0x000 ALT4 0x0 ++#define VF610_PAD_PTE6__DEBUG_OUT35 0x1BC 0x000 ALT7 0x0 ++#define VF610_PAD_PTE7__GPIO_112 0x1C0 0x000 ALT0 0x0 ++#define VF610_PAD_PTE7__DCU0_R2 0x1C0 0x000 ALT1 0x0 ++#define VF610_PAD_PTE7__SRC_RCON0 0x1C0 0x000 ALT3 0x0 ++#define VF610_PAD_PTE7__LCD7 0x1C0 0x000 ALT4 0x0 ++#define VF610_PAD_PTE7__DEBUG_OUT36 0x1C0 0x000 ALT7 0x0 ++#define VF610_PAD_PTE8__GPIO_113 0x1C4 0x000 ALT0 0x0 ++#define VF610_PAD_PTE8__DCU0_R3 0x1C4 0x000 ALT1 0x0 ++#define VF610_PAD_PTE8__SRC_RCON1 0x1C4 0x000 ALT3 0x0 ++#define VF610_PAD_PTE8__LCD8 0x1C4 0x000 ALT4 0x0 ++#define VF610_PAD_PTE8__DEBUG_OUT37 0x1C4 0x000 ALT7 0x0 ++#define VF610_PAD_PTE9__GPIO_114 0x1C8 0x000 ALT0 0x0 ++#define VF610_PAD_PTE9__DCU0_R4 0x1C8 0x000 ALT1 0x0 ++#define VF610_PAD_PTE9__SRC_RCON2 0x1C8 0x000 ALT3 0x0 ++#define VF610_PAD_PTE9__LCD9 0x1C8 0x000 ALT4 0x0 ++#define VF610_PAD_PTE9__DEBUG_OUT38 0x1C8 0x000 ALT7 0x0 ++#define VF610_PAD_PTE10__GPIO_115 0x1CC 0x000 ALT0 0x0 ++#define VF610_PAD_PTE10__DCU0_R5 0x1CC 0x000 ALT1 0x0 ++#define VF610_PAD_PTE10__SRC_RCON3 0x1CC 0x000 ALT3 0x0 ++#define VF610_PAD_PTE10__LCD10 0x1CC 0x000 ALT4 0x0 ++#define VF610_PAD_PTE10__DEBUG_OUT39 0x1CC 0x000 ALT7 0x0 ++#define VF610_PAD_PTE11__GPIO_116 0x1D0 0x000 ALT0 0x0 ++#define VF610_PAD_PTE11__DCU0_R6 0x1D0 0x000 ALT1 0x0 ++#define VF610_PAD_PTE11__SRC_RCON4 0x1D0 0x000 ALT3 0x0 ++#define VF610_PAD_PTE11__LCD11 0x1D0 0x000 ALT4 0x0 ++#define VF610_PAD_PTE11__DEBUG_OUT40 0x1D0 0x000 ALT7 0x0 ++#define VF610_PAD_PTE12__GPIO_117 0x1D4 0x000 ALT0 0x0 ++#define VF610_PAD_PTE12__DCU0_R7 0x1D4 0x000 ALT1 0x0 ++#define VF610_PAD_PTE12__DSPI1_CS3 0x1D4 0x000 ALT2 0x0 ++#define VF610_PAD_PTE12__SRC_RCON5 0x1D4 0x000 ALT3 0x0 ++#define VF610_PAD_PTE12__LCD12 0x1D4 0x000 ALT4 0x0 ++#define VF610_PAD_PTE12__LPT_ALT0 0x1D4 0x000 ALT7 0x0 ++#define VF610_PAD_PTE13__GPIO_118 0x1D8 0x000 ALT0 0x0 ++#define VF610_PAD_PTE13__DCU0_G0 0x1D8 0x000 ALT1 0x0 ++#define VF610_PAD_PTE13__LCD13 0x1D8 0x000 ALT4 0x0 ++#define VF610_PAD_PTE13__DEBUG_OUT41 0x1D8 0x000 ALT7 0x0 ++#define VF610_PAD_PTE14__GPIO_119 0x1DC 0x000 ALT0 0x0 ++#define VF610_PAD_PTE14__DCU0_G1 0x1DC 0x000 ALT1 0x0 ++#define VF610_PAD_PTE14__LCD14 0x1DC 0x000 ALT4 0x0 ++#define VF610_PAD_PTE14__DEBUG_OUT42 0x1DC 0x000 ALT7 0x0 ++#define VF610_PAD_PTE15__GPIO_120 0x1E0 0x000 ALT0 0x0 ++#define VF610_PAD_PTE15__DCU0_G2 0x1E0 0x000 ALT1 0x0 ++#define VF610_PAD_PTE15__SRC_RCON6 0x1E0 0x000 ALT3 0x0 ++#define VF610_PAD_PTE15__LCD15 0x1E0 0x000 ALT4 0x0 ++#define VF610_PAD_PTE15__DEBUG_OUT43 0x1E0 0x000 ALT7 0x0 ++#define VF610_PAD_PTE16__GPIO_121 0x1E4 0x000 ALT0 0x0 ++#define VF610_PAD_PTE16__DCU0_G3 0x1E4 0x000 ALT1 0x0 ++#define VF610_PAD_PTE16__SRC_RCON7 0x1E4 0x000 ALT3 0x0 ++#define VF610_PAD_PTE16__LCD16 0x1E4 0x000 ALT4 0x0 ++#define VF610_PAD_PTE17__GPIO_122 0x1E8 0x000 ALT0 0x0 ++#define VF610_PAD_PTE17__DCU0_G4 0x1E8 0x000 ALT1 0x0 ++#define VF610_PAD_PTE17__SRC_RCON8 0x1E8 0x000 ALT3 0x0 ++#define VF610_PAD_PTE17__LCD17 0x1E8 0x000 ALT4 0x0 ++#define VF610_PAD_PTE18__GPIO_123 0x1EC 0x000 ALT0 0x0 ++#define VF610_PAD_PTE18__DCU0_G5 0x1EC 0x000 ALT1 0x0 ++#define VF610_PAD_PTE18__SRC_RCON9 0x1EC 0x000 ALT3 0x0 ++#define VF610_PAD_PTE18__LCD18 0x1EC 0x000 ALT4 0x0 ++#define VF610_PAD_PTE19__GPIO_124 0x1F0 0x000 ALT0 0x0 ++#define VF610_PAD_PTE19__DCU0_G6 0x1F0 0x000 ALT1 0x0 ++#define VF610_PAD_PTE19__SRC_RCON10 0x1F0 0x000 ALT3 0x0 ++#define VF610_PAD_PTE19__LCD19 0x1F0 0x000 ALT4 0x0 ++#define VF610_PAD_PTE19__I2C0_SCL 0x1F0 0x33C ALT5 0x3 ++#define VF610_PAD_PTE20__GPIO_125 0x1F4 0x000 ALT0 0x0 ++#define VF610_PAD_PTE20__DCU0_G7 0x1F4 0x000 ALT1 0x0 ++#define VF610_PAD_PTE20__SRC_RCON11 0x1F4 0x000 ALT3 0x0 ++#define VF610_PAD_PTE20__LCD20 0x1F4 0x000 ALT4 0x0 ++#define VF610_PAD_PTE20__I2C0_SDA 0x1F4 0x340 ALT5 0x3 ++#define VF610_PAD_PTE20__EWM_IN 0x1F4 0x000 ALT7 0x0 ++#define VF610_PAD_PTE21__GPIO_126 0x1F8 0x000 ALT0 0x0 ++#define VF610_PAD_PTE21__DCU0_B0 0x1F8 0x000 ALT1 0x0 ++#define VF610_PAD_PTE21__LCD21 0x1F8 0x000 ALT4 0x0 ++#define VF610_PAD_PTE22__GPIO_127 0x1FC 0x000 ALT0 0x0 ++#define VF610_PAD_PTE22__DCU0_B1 0x1FC 0x000 ALT1 0x0 ++#define VF610_PAD_PTE22__LCD22 0x1FC 0x000 ALT4 0x0 ++#define VF610_PAD_PTE23__GPIO_128 0x200 0x000 ALT0 0x0 ++#define VF610_PAD_PTE23__DCU0_B2 0x200 0x000 ALT1 0x0 ++#define VF610_PAD_PTE23__SRC_RCON12 0x200 0x000 ALT3 0x0 ++#define VF610_PAD_PTE23__LCD23 0x200 0x000 ALT4 0x0 ++#define VF610_PAD_PTE24__GPIO_129 0x204 0x000 ALT0 0x0 ++#define VF610_PAD_PTE24__DCU0_B3 0x204 0x000 ALT1 0x0 ++#define VF610_PAD_PTE24__SRC_RCON13 0x204 0x000 ALT3 0x0 ++#define VF610_PAD_PTE24__LCD24 0x204 0x000 ALT4 0x0 ++#define VF610_PAD_PTE25__GPIO_130 0x208 0x000 ALT0 0x0 ++#define VF610_PAD_PTE25__DCU0_B4 0x208 0x000 ALT1 0x0 ++#define VF610_PAD_PTE25__SRC_RCON14 0x208 0x000 ALT3 0x0 ++#define VF610_PAD_PTE25__LCD25 0x208 0x000 ALT4 0x0 ++#define VF610_PAD_PTE26__GPIO_131 0x20C 0x000 ALT0 0x0 ++#define VF610_PAD_PTE26__DCU0_B5 0x20C 0x000 ALT1 0x0 ++#define VF610_PAD_PTE26__SRC_RCON15 0x20C 0x000 ALT3 0x0 ++#define VF610_PAD_PTE26__LCD26 0x20C 0x000 ALT4 0x0 ++#define VF610_PAD_PTE27__GPIO_132 0x210 0x000 ALT0 0x0 ++#define VF610_PAD_PTE27__DCU0_B6 0x210 0x000 ALT1 0x0 ++#define VF610_PAD_PTE27__SRC_RCON16 0x210 0x000 ALT3 0x0 ++#define VF610_PAD_PTE27__LCD27 0x210 0x000 ALT4 0x0 ++#define VF610_PAD_PTE27__I2C1_SCL 0x210 0x344 ALT5 0x3 ++#define VF610_PAD_PTE28__GPIO_133 0x214 0x000 ALT0 0x0 ++#define VF610_PAD_PTE28__DCU0_B7 0x214 0x000 ALT1 0x0 ++#define VF610_PAD_PTE28__SRC_RCON17 0x214 0x000 ALT3 0x0 ++#define VF610_PAD_PTE28__LCD28 0x214 0x000 ALT4 0x0 ++#define VF610_PAD_PTE28__I2C1_SDA 0x214 0x348 ALT5 0x3 ++#define VF610_PAD_PTE28__EWM_OUT 0x214 0x000 ALT7 0x0 ++#define VF610_PAD_PTA7__GPIO_134 0x218 0x000 ALT0 0x0 ++#define VF610_PAD_PTA7__VIU_PIX_CLK 0x218 0x3AC ALT1 0x1 ++ ++#endif +diff -Nur linux-3.10.30/arch/arm/boot/dts/vf610-twr.dts linux-3.10.30-cubox-i/arch/arm/boot/dts/vf610-twr.dts +--- linux-3.10.30/arch/arm/boot/dts/vf610-twr.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/vf610-twr.dts 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,57 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++/dts-v1/; ++#include "vf610.dtsi" ++ ++/ { ++ model = "VF610 Tower Board"; ++ compatible = "fsl,vf610-twr", "fsl,vf610"; ++ ++ chosen { ++ bootargs = "console=ttyLP1,115200"; ++ }; ++ ++ memory { ++ reg = <0x80000000 0x8000000>; ++ }; ++ ++ clocks { ++ audio_ext { ++ compatible = "fixed-clock"; ++ clock-frequency = <24576000>; ++ }; ++ ++ enet_ext { ++ compatible = "fixed-clock"; ++ clock-frequency = <50000000>; ++ }; ++ }; ++ ++}; ++ ++&fec0 { ++ phy-mode = "rmii"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_fec0_1>; ++ status = "okay"; ++}; ++ ++&fec1 { ++ phy-mode = "rmii"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_fec1_1>; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1_1>; ++ status = "okay"; ++}; +diff -Nur linux-3.10.30/arch/arm/boot/dts/vf610.dtsi linux-3.10.30-cubox-i/arch/arm/boot/dts/vf610.dtsi +--- linux-3.10.30/arch/arm/boot/dts/vf610.dtsi 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/boot/dts/vf610.dtsi 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,464 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include "skeleton.dtsi" ++#include "vf610-pinfunc.h" ++#include ++ ++/ { ++ aliases { ++ serial0 = &uart0; ++ serial1 = &uart1; ++ serial2 = &uart2; ++ serial3 = &uart3; ++ serial4 = &uart4; ++ serial5 = &uart5; ++ gpio0 = &gpio1; ++ gpio1 = &gpio2; ++ gpio2 = &gpio3; ++ gpio3 = &gpio4; ++ gpio4 = &gpio5; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu@0 { ++ compatible = "arm,cortex-a5"; ++ device_type = "cpu"; ++ reg = <0x0>; ++ next-level-cache = <&L2>; ++ }; ++ }; ++ ++ clocks { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ sxosc { ++ compatible = "fixed-clock"; ++ clock-frequency = <32768>; ++ }; ++ ++ fxosc { ++ compatible = "fixed-clock"; ++ clock-frequency = <24000000>; ++ }; ++ }; ++ ++ soc { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "simple-bus"; ++ interrupt-parent = <&intc>; ++ ranges; ++ ++ aips0: aips-bus@40000000 { ++ compatible = "fsl,aips-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ interrupt-parent = <&intc>; ++ reg = <0x40000000 0x70000>; ++ ranges; ++ ++ intc: interrupt-controller@40002000 { ++ compatible = "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ interrupt-controller; ++ reg = <0x40003000 0x1000>, ++ <0x40002100 0x100>; ++ }; ++ ++ L2: l2-cache@40006000 { ++ compatible = "arm,pl310-cache"; ++ reg = <0x40006000 0x1000>; ++ cache-unified; ++ cache-level = <2>; ++ arm,data-latency = <1 1 1>; ++ arm,tag-latency = <2 2 2>; ++ }; ++ ++ uart0: serial@40027000 { ++ compatible = "fsl,vf610-lpuart"; ++ reg = <0x40027000 0x1000>; ++ interrupts = <0 61 0x00>; ++ clocks = <&clks VF610_CLK_UART0>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ uart1: serial@40028000 { ++ compatible = "fsl,vf610-lpuart"; ++ reg = <0x40028000 0x1000>; ++ interrupts = <0 62 0x04>; ++ clocks = <&clks VF610_CLK_UART1>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@40029000 { ++ compatible = "fsl,vf610-lpuart"; ++ reg = <0x40029000 0x1000>; ++ interrupts = <0 63 0x04>; ++ clocks = <&clks VF610_CLK_UART2>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@4002a000 { ++ compatible = "fsl,vf610-lpuart"; ++ reg = <0x4002a000 0x1000>; ++ interrupts = <0 64 0x04>; ++ clocks = <&clks VF610_CLK_UART3>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ sai2: sai@40031000 { ++ compatible = "fsl,vf610-sai"; ++ reg = <0x40031000 0x1000>; ++ interrupts = <0 86 0x04>; ++ clocks = <&clks VF610_CLK_SAI2>; ++ clock-names = "sai"; ++ status = "disabled"; ++ }; ++ ++ pit: pit@40037000 { ++ compatible = "fsl,vf610-pit"; ++ reg = <0x40037000 0x1000>; ++ interrupts = <0 39 0x04>; ++ clocks = <&clks VF610_CLK_PIT>; ++ clock-names = "pit"; ++ }; ++ ++ wdog@4003e000 { ++ compatible = "fsl,vf610-wdt", "fsl,imx21-wdt"; ++ reg = <0x4003e000 0x1000>; ++ clocks = <&clks VF610_CLK_WDT>; ++ clock-names = "wdog"; ++ }; ++ ++ qspi0: quadspi@40044000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,vf610-qspi"; ++ reg = <0x40044000 0x1000>; ++ interrupts = <0 24 0x04>; ++ clocks = <&clks VF610_CLK_QSPI0_EN>, ++ <&clks VF610_CLK_QSPI0>; ++ clock-names = "qspi_en", "qspi"; ++ status = "disabled"; ++ }; ++ ++ iomuxc: iomuxc@40048000 { ++ compatible = "fsl,vf610-iomuxc"; ++ reg = <0x40048000 0x1000>; ++ #gpio-range-cells = <2>; ++ ++ /* functions and groups pins */ ++ ++ dcu0 { ++ pinctrl_dcu0_1: dcu0grp_1 { ++ fsl,pins = < ++ VF610_PAD_PTB8__GPIO_30 0x42 ++ VF610_PAD_PTE0__DCU0_HSYNC 0x42 ++ VF610_PAD_PTE1__DCU0_VSYNC 0x42 ++ VF610_PAD_PTE2__DCU0_PCLK 0x42 ++ VF610_PAD_PTE4__DCU0_DE 0x42 ++ VF610_PAD_PTE5__DCU0_R0 0x42 ++ VF610_PAD_PTE6__DCU0_R1 0x42 ++ VF610_PAD_PTE7__DCU0_R2 0x42 ++ VF610_PAD_PTE8__DCU0_R3 0x42 ++ VF610_PAD_PTE9__DCU0_R4 0x42 ++ VF610_PAD_PTE10__DCU0_R5 0x42 ++ VF610_PAD_PTE11__DCU0_R6 0x42 ++ VF610_PAD_PTE12__DCU0_R7 0x42 ++ VF610_PAD_PTE13__DCU0_G0 0x42 ++ VF610_PAD_PTE14__DCU0_G1 0x42 ++ VF610_PAD_PTE15__DCU0_G2 0x42 ++ VF610_PAD_PTE16__DCU0_G3 0x42 ++ VF610_PAD_PTE17__DCU0_G4 0x42 ++ VF610_PAD_PTE18__DCU0_G5 0x42 ++ VF610_PAD_PTE19__DCU0_G6 0x42 ++ VF610_PAD_PTE20__DCU0_G7 0x42 ++ VF610_PAD_PTE21__DCU0_B0 0x42 ++ VF610_PAD_PTE22__DCU0_B1 0x42 ++ VF610_PAD_PTE23__DCU0_B2 0x42 ++ VF610_PAD_PTE24__DCU0_B3 0x42 ++ VF610_PAD_PTE25__DCU0_B4 0x42 ++ VF610_PAD_PTE26__DCU0_B5 0x42 ++ VF610_PAD_PTE27__DCU0_B6 0x42 ++ VF610_PAD_PTE28__DCU0_B7 0x42 ++ >; ++ }; ++ }; ++ ++ dspi0 { ++ pinctrl_dspi0_1: dspi0grp_1 { ++ fsl,pins = < ++ VF610_PAD_PTB19__DSPI0_CS0 0x1182 ++ VF610_PAD_PTB20__DSPI0_SIN 0x1181 ++ VF610_PAD_PTB21__DSPI0_SOUT 0x1182 ++ VF610_PAD_PTB22__DSPI0_SCK 0x1182 ++ >; ++ }; ++ }; ++ ++ esdhc1 { ++ pinctrl_esdhc1_1: esdhc1grp_1 { ++ fsl,pins = < ++ VF610_PAD_PTA24__ESDHC1_CLK 0x31ef ++ VF610_PAD_PTA25__ESDHC1_CMD 0x31ef ++ VF610_PAD_PTA26__ESDHC1_DAT0 0x31ef ++ VF610_PAD_PTA27__ESDHC1_DAT1 0x31ef ++ VF610_PAD_PTA28__ESDHC1_DATA2 0x31ef ++ VF610_PAD_PTA29__ESDHC1_DAT3 0x31ef ++ VF610_PAD_PTA7__GPIO_134 0x219d ++ >; ++ }; ++ }; ++ ++ fec0 { ++ pinctrl_fec0_1: fec0grp_1 { ++ fsl,pins = < ++ VF610_PAD_PTA6__RMII_CLKIN 0x30d1 ++ VF610_PAD_PTC0__ENET_RMII0_MDC 0x30d3 ++ VF610_PAD_PTC1__ENET_RMII0_MDIO 0x30d1 ++ VF610_PAD_PTC2__ENET_RMII0_CRS 0x30d1 ++ VF610_PAD_PTC3__ENET_RMII0_RXD1 0x30d1 ++ VF610_PAD_PTC4__ENET_RMII0_RXD0 0x30d1 ++ VF610_PAD_PTC5__ENET_RMII0_RXER 0x30d1 ++ VF610_PAD_PTC6__ENET_RMII0_TXD1 0x30d2 ++ VF610_PAD_PTC7__ENET_RMII0_TXD0 0x30d2 ++ VF610_PAD_PTC8__ENET_RMII0_TXEN 0x30d2 ++ >; ++ }; ++ }; ++ ++ fec1 { ++ pinctrl_fec1_1: fec1grp_1 { ++ fsl,pins = < ++ VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2 ++ VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3 ++ VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1 ++ VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1 ++ VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1 ++ VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1 ++ VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2 ++ VF610_PAD_PTC16__ENET_RMII1_TXD0 0x30d2 ++ VF610_PAD_PTC17__ENET_RMII1_TXEN 0x30d2 ++ >; ++ }; ++ }; ++ ++ i2c0 { ++ pinctrl_i2c0_1: i2c0grp_1 { ++ fsl,pins = < ++ VF610_PAD_PTB14__I2C0_SCL 0x30d3 ++ VF610_PAD_PTB15__I2C0_SDA 0x30d3 ++ >; ++ }; ++ }; ++ ++ pwm0 { ++ pinctrl_pwm0_1: pwm0grp_1 { ++ fsl,pins = < ++ VF610_PAD_PTB0__FTM0_CH0 0x1582 ++ VF610_PAD_PTB1__FTM0_CH1 0x1582 ++ VF610_PAD_PTB2__FTM0_CH2 0x1582 ++ VF610_PAD_PTB3__FTM0_CH3 0x1582 ++ VF610_PAD_PTB6__FTM0_CH6 0x1582 ++ VF610_PAD_PTB7__FTM0_CH7 0x1582 ++ >; ++ }; ++ }; ++ ++ qspi0 { ++ pinctrl_qspi0_1: qspi0grp_1 { ++ fsl,pins = < ++ VF610_PAD_PTD0__QSPI0_A_QSCK 0x307b ++ VF610_PAD_PTD1__QSPI0_A_CS0 0x307f ++ VF610_PAD_PTD2__QSPI0_A_DATA3 0x3073 ++ VF610_PAD_PTD3__QSPI0_A_DATA2 0x3073 ++ VF610_PAD_PTD4__QSPI0_A_DATA1 0x3073 ++ VF610_PAD_PTD5__QSPI0_A_DATA0 0x307b ++ VF610_PAD_PTD7__QSPI0_B_QSCK 0x307b ++ VF610_PAD_PTD8__QSPI0_B_CS0 0x307f ++ VF610_PAD_PTD9__QSPI0_B_DATA3 0x3073 ++ VF610_PAD_PTD10__QSPI0_B_DATA2 0x3073 ++ VF610_PAD_PTD11__QSPI0_B_DATA1 0x3073 ++ VF610_PAD_PTD12__QSPI0_B_DATA0 0x307b ++ >; ++ }; ++ }; ++ ++ sai2 { ++ pinctrl_sai2_1: sai2grp_1 { ++ fsl,pins = < ++ VF610_PAD_PTA16__SAI2_TX_BCLK 0x02ed ++ VF610_PAD_PTA18__SAI2_TX_DATA 0x02ee ++ VF610_PAD_PTA19__SAI2_TX_SYNC 0x02ed ++ VF610_PAD_PTA21__SAI2_RX_BCLK 0x02ed ++ VF610_PAD_PTA22__SAI2_RX_DATA 0x02ed ++ VF610_PAD_PTA23__SAI2_RX_SYNC 0x02ed ++ VF610_PAD_PTB18__EXT_AUDIO_MCLK 0x02ed ++ >; ++ }; ++ }; ++ ++ uart1 { ++ pinctrl_uart1_1: uart1grp_1 { ++ fsl,pins = < ++ VF610_PAD_PTB4__UART1_TX 0x21a2 ++ VF610_PAD_PTB5__UART1_RX 0x21a1 ++ >; ++ }; ++ }; ++ ++ usbvbus { ++ pinctrl_usbvbus_1: usbvbusgrp_1 { ++ fsl,pins = < ++ VF610_PAD_PTA24__USB1_VBUS_EN 0x219c ++ VF610_PAD_PTA16__USB0_VBUS_EN 0x219c ++ >; ++ }; ++ }; ++ ++ }; ++ ++ gpio1: gpio@40049000 { ++ compatible = "fsl,vf610-gpio"; ++ reg = <0x40049000 0x1000 0x400ff000 0x40>; ++ interrupts = <0 107 0x04>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-ranges = <&iomuxc 0 32>; ++ }; ++ ++ gpio2: gpio@4004a000 { ++ compatible = "fsl,vf610-gpio"; ++ reg = <0x4004a000 0x1000 0x400ff040 0x40>; ++ interrupts = <0 108 0x04>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-ranges = <&iomuxc 32 32>; ++ }; ++ ++ gpio3: gpio@4004b000 { ++ compatible = "fsl,vf610-gpio"; ++ reg = <0x4004b000 0x1000 0x400ff080 0x40>; ++ interrupts = <0 109 0x04>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-ranges = <&iomuxc 64 32>; ++ }; ++ ++ gpio4: gpio@4004c000 { ++ compatible = "fsl,vf610-gpio"; ++ reg = <0x4004c000 0x1000 0x400ff0c0 0x40>; ++ interrupts = <0 110 0x04>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-ranges = <&iomuxc 96 32>; ++ }; ++ ++ gpio5: gpio@4004d000 { ++ compatible = "fsl,vf610-gpio"; ++ reg = <0x4004d000 0x1000 0x400ff100 0x40>; ++ interrupts = <0 111 0x04>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-ranges = <&iomuxc 128 7>; ++ }; ++ ++ anatop@40050000 { ++ compatible = "fsl,vf610-anatop"; ++ reg = <0x40050000 0x1000>; ++ }; ++ ++ i2c0: i2c@40066000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,vf610-i2c"; ++ reg = <0x40066000 0x1000>; ++ interrupts =<0 71 0x04>; ++ clocks = <&clks VF610_CLK_I2C0>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ clks: ccm@4006b000 { ++ compatible = "fsl,vf610-ccm"; ++ reg = <0x4006b000 0x1000>; ++ #clock-cells = <1>; ++ }; ++ }; ++ ++ aips1: aips-bus@40080000 { ++ compatible = "fsl,aips-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x40080000 0x80000>; ++ ranges; ++ ++ uart4: serial@400a9000 { ++ compatible = "fsl,vf610-lpuart"; ++ reg = <0x400a9000 0x1000>; ++ interrupts = <0 65 0x04>; ++ clocks = <&clks VF610_CLK_UART4>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ uart5: serial@400aa000 { ++ compatible = "fsl,vf610-lpuart"; ++ reg = <0x400aa000 0x1000>; ++ interrupts = <0 66 0x04>; ++ clocks = <&clks VF610_CLK_UART5>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ fec0: ethernet@400d0000 { ++ compatible = "fsl,mvf600-fec"; ++ reg = <0x400d0000 0x1000>; ++ interrupts = <0 78 0x04>; ++ clocks = <&clks VF610_CLK_ENET0>, ++ <&clks VF610_CLK_ENET0>, ++ <&clks VF610_CLK_ENET>; ++ clock-names = "ipg", "ahb", "ptp"; ++ status = "disabled"; ++ }; ++ ++ fec1: ethernet@400d1000 { ++ compatible = "fsl,mvf600-fec"; ++ reg = <0x400d1000 0x1000>; ++ interrupts = <0 79 0x04>; ++ clocks = <&clks VF610_CLK_ENET1>, ++ <&clks VF610_CLK_ENET1>, ++ <&clks VF610_CLK_ENET>; ++ clock-names = "ipg", "ahb", "ptp"; ++ status = "disabled"; ++ }; ++ }; ++ }; ++}; +diff -Nur linux-3.10.30/arch/arm/common/Makefile linux-3.10.30-cubox-i/arch/arm/common/Makefile +--- linux-3.10.30/arch/arm/common/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/common/Makefile 2014-03-08 20:32:53.000000000 +0100 +@@ -14,5 +14,9 @@ + obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o + obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o + obj-$(CONFIG_MCPM) += mcpm_head.o mcpm_entry.o mcpm_platsmp.o vlock.o ++obj-$(CONFIG_BL_SWITCHER) += bL_switcher.o ++obj-$(CONFIG_BL_SWITCHER_DUMMY_IF) += bL_switcher_dummy_if.o ++ + AFLAGS_mcpm_head.o := -march=armv7-a + AFLAGS_vlock.o := -march=armv7-a ++CFLAGS_REMOVE_mcpm_entry.o = -pg +diff -Nur linux-3.10.30/arch/arm/common/bL_switcher.c linux-3.10.30-cubox-i/arch/arm/common/bL_switcher.c +--- linux-3.10.30/arch/arm/common/bL_switcher.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/common/bL_switcher.c 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,864 @@ ++/* ++ * arch/arm/common/bL_switcher.c -- big.LITTLE cluster switcher core driver ++ * ++ * Created by: Nicolas Pitre, March 2012 ++ * Copyright: (C) 2012 Linaro Limited ++ * ++ * This program 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 ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CREATE_TRACE_POINTS ++#include ++ ++ ++/* ++ * Use our own MPIDR accessors as the generic ones in asm/cputype.h have ++ * __attribute_const__ and we don't want the compiler to assume any ++ * constness here as the value _does_ change along some code paths. ++ */ ++ ++static int read_mpidr(void) ++{ ++ unsigned int id; ++ asm volatile ("mrc\tp15, 0, %0, c0, c0, 5" : "=r" (id)); ++ return id & MPIDR_HWID_BITMASK; ++} ++ ++/* ++ * Get a global nanosecond time stamp for tracing. ++ */ ++static s64 get_ns(void) ++{ ++ struct timespec ts; ++ getnstimeofday(&ts); ++ return timespec_to_ns(&ts); ++} ++ ++/* ++ * bL switcher core code. ++ */ ++ ++static void bL_do_switch(void *_arg) ++{ ++ unsigned ib_mpidr, ib_cpu, ib_cluster; ++ long volatile handshake, **handshake_ptr = _arg; ++ ++ pr_debug("%s\n", __func__); ++ ++ ib_mpidr = cpu_logical_map(smp_processor_id()); ++ ib_cpu = MPIDR_AFFINITY_LEVEL(ib_mpidr, 0); ++ ib_cluster = MPIDR_AFFINITY_LEVEL(ib_mpidr, 1); ++ ++ /* Advertise our handshake location */ ++ if (handshake_ptr) { ++ handshake = 0; ++ *handshake_ptr = &handshake; ++ } else ++ handshake = -1; ++ ++ /* ++ * Our state has been saved at this point. Let's release our ++ * inbound CPU. ++ */ ++ mcpm_set_entry_vector(ib_cpu, ib_cluster, cpu_resume); ++ sev(); ++ ++ /* ++ * From this point, we must assume that our counterpart CPU might ++ * have taken over in its parallel world already, as if execution ++ * just returned from cpu_suspend(). It is therefore important to ++ * be very careful not to make any change the other guy is not ++ * expecting. This is why we need stack isolation. ++ * ++ * Fancy under cover tasks could be performed here. For now ++ * we have none. ++ */ ++ ++ /* ++ * Let's wait until our inbound is alive. ++ */ ++ while (!handshake) { ++ wfe(); ++ smp_mb(); ++ } ++ ++ /* Let's put ourself down. */ ++ mcpm_cpu_power_down(); ++ ++ /* should never get here */ ++ BUG(); ++} ++ ++/* ++ * Stack isolation. To ensure 'current' remains valid, we just use another ++ * piece of our thread's stack space which should be fairly lightly used. ++ * The selected area starts just above the thread_info structure located ++ * at the very bottom of the stack, aligned to a cache line, and indexed ++ * with the cluster number. ++ */ ++#define STACK_SIZE 512 ++extern void call_with_stack(void (*fn)(void *), void *arg, void *sp); ++static int bL_switchpoint(unsigned long _arg) ++{ ++ unsigned int mpidr = read_mpidr(); ++ unsigned int clusterid = MPIDR_AFFINITY_LEVEL(mpidr, 1); ++ void *stack = current_thread_info() + 1; ++ stack = PTR_ALIGN(stack, L1_CACHE_BYTES); ++ stack += clusterid * STACK_SIZE + STACK_SIZE; ++ call_with_stack(bL_do_switch, (void *)_arg, stack); ++ BUG(); ++} ++ ++/* ++ * Generic switcher interface ++ */ ++ ++static unsigned int bL_gic_id[MAX_CPUS_PER_CLUSTER][MAX_NR_CLUSTERS]; ++static int bL_switcher_cpu_pairing[NR_CPUS]; ++ ++/* ++ * bL_switch_to - Switch to a specific cluster for the current CPU ++ * @new_cluster_id: the ID of the cluster to switch to. ++ * ++ * This function must be called on the CPU to be switched. ++ * Returns 0 on success, else a negative status code. ++ */ ++static int bL_switch_to(unsigned int new_cluster_id) ++{ ++ unsigned int mpidr, this_cpu, that_cpu; ++ unsigned int ob_mpidr, ob_cpu, ob_cluster, ib_mpidr, ib_cpu, ib_cluster; ++ struct completion inbound_alive; ++ struct tick_device *tdev; ++ enum clock_event_mode tdev_mode; ++ long volatile *handshake_ptr; ++ int ipi_nr, ret; ++ ++ this_cpu = smp_processor_id(); ++ ob_mpidr = read_mpidr(); ++ ob_cpu = MPIDR_AFFINITY_LEVEL(ob_mpidr, 0); ++ ob_cluster = MPIDR_AFFINITY_LEVEL(ob_mpidr, 1); ++ BUG_ON(cpu_logical_map(this_cpu) != ob_mpidr); ++ ++ if (new_cluster_id == ob_cluster) ++ return 0; ++ ++ that_cpu = bL_switcher_cpu_pairing[this_cpu]; ++ ib_mpidr = cpu_logical_map(that_cpu); ++ ib_cpu = MPIDR_AFFINITY_LEVEL(ib_mpidr, 0); ++ ib_cluster = MPIDR_AFFINITY_LEVEL(ib_mpidr, 1); ++ ++ pr_debug("before switch: CPU %d MPIDR %#x -> %#x\n", ++ this_cpu, ob_mpidr, ib_mpidr); ++ ++ this_cpu = smp_processor_id(); ++ ++ /* Close the gate for our entry vectors */ ++ mcpm_set_entry_vector(ob_cpu, ob_cluster, NULL); ++ mcpm_set_entry_vector(ib_cpu, ib_cluster, NULL); ++ ++ /* Install our "inbound alive" notifier. */ ++ init_completion(&inbound_alive); ++ ipi_nr = register_ipi_completion(&inbound_alive, this_cpu); ++ ipi_nr |= ((1 << 16) << bL_gic_id[ob_cpu][ob_cluster]); ++ mcpm_set_early_poke(ib_cpu, ib_cluster, gic_get_sgir_physaddr(), ipi_nr); ++ ++ /* ++ * Let's wake up the inbound CPU now in case it requires some delay ++ * to come online, but leave it gated in our entry vector code. ++ */ ++ ret = mcpm_cpu_power_up(ib_cpu, ib_cluster); ++ if (ret) { ++ pr_err("%s: mcpm_cpu_power_up() returned %d\n", __func__, ret); ++ return ret; ++ } ++ ++ /* ++ * Raise a SGI on the inbound CPU to make sure it doesn't stall ++ * in a possible WFI, such as in bL_power_down(). ++ */ ++ gic_send_sgi(bL_gic_id[ib_cpu][ib_cluster], 0); ++ ++ /* ++ * Wait for the inbound to come up. This allows for other ++ * tasks to be scheduled in the mean time. ++ */ ++ wait_for_completion(&inbound_alive); ++ mcpm_set_early_poke(ib_cpu, ib_cluster, 0, 0); ++ ++ /* ++ * From this point we are entering the switch critical zone ++ * and can't sleep/schedule anymore. ++ */ ++ local_irq_disable(); ++ local_fiq_disable(); ++ trace_cpu_migrate_begin(get_ns(), ob_mpidr); ++ ++ /* redirect GIC's SGIs to our counterpart */ ++ gic_migrate_target(bL_gic_id[ib_cpu][ib_cluster]); ++ ++ tdev = tick_get_device(this_cpu); ++ if (tdev && !cpumask_equal(tdev->evtdev->cpumask, cpumask_of(this_cpu))) ++ tdev = NULL; ++ if (tdev) { ++ tdev_mode = tdev->evtdev->mode; ++ clockevents_set_mode(tdev->evtdev, CLOCK_EVT_MODE_SHUTDOWN); ++ } ++ ++ ret = cpu_pm_enter(); ++ ++ /* we can not tolerate errors at this point */ ++ if (ret) ++ panic("%s: cpu_pm_enter() returned %d\n", __func__, ret); ++ ++ /* ++ * Swap the physical CPUs in the logical map for this logical CPU. ++ * This must be flushed to RAM as the resume code ++ * needs to access it while the caches are still disabled. ++ */ ++ cpu_logical_map(this_cpu) = ib_mpidr; ++ cpu_logical_map(that_cpu) = ob_mpidr; ++ sync_cache_w(&cpu_logical_map(this_cpu)); ++ ++ /* Let's do the actual CPU switch. */ ++ ret = cpu_suspend((unsigned long)&handshake_ptr, bL_switchpoint); ++ if (ret > 0) ++ panic("%s: cpu_suspend() returned %d\n", __func__, ret); ++ ++ /* We are executing on the inbound CPU at this point */ ++ mpidr = read_mpidr(); ++ pr_debug("after switch: CPU %d MPIDR %#x\n", this_cpu, mpidr); ++ BUG_ON(mpidr != ib_mpidr); ++ ++ mcpm_cpu_powered_up(); ++ ++ ret = cpu_pm_exit(); ++ ++ if (tdev) { ++ clockevents_set_mode(tdev->evtdev, tdev_mode); ++ clockevents_program_event(tdev->evtdev, ++ tdev->evtdev->next_event, 1); ++ } ++ ++ trace_cpu_migrate_finish(get_ns(), ib_mpidr); ++ local_fiq_enable(); ++ local_irq_enable(); ++ ++ *handshake_ptr = 1; ++ dsb_sev(); ++ ++ if (ret) ++ pr_err("%s exiting with error %d\n", __func__, ret); ++ return ret; ++} ++ ++struct bL_thread { ++ spinlock_t lock; ++ struct task_struct *task; ++ wait_queue_head_t wq; ++ int wanted_cluster; ++ struct completion started; ++ bL_switch_completion_handler completer; ++ void *completer_cookie; ++}; ++ ++static struct bL_thread bL_threads[NR_CPUS]; ++ ++static int bL_switcher_thread(void *arg) ++{ ++ struct bL_thread *t = arg; ++ struct sched_param param = { .sched_priority = 1 }; ++ int cluster; ++ bL_switch_completion_handler completer; ++ void *completer_cookie; ++ ++ sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m); ++ complete(&t->started); ++ ++ do { ++ if (signal_pending(current)) ++ flush_signals(current); ++ wait_event_interruptible(t->wq, ++ t->wanted_cluster != -1 || ++ kthread_should_stop()); ++ ++ spin_lock(&t->lock); ++ cluster = t->wanted_cluster; ++ completer = t->completer; ++ completer_cookie = t->completer_cookie; ++ t->wanted_cluster = -1; ++ t->completer = NULL; ++ spin_unlock(&t->lock); ++ ++ if (cluster != -1) { ++ bL_switch_to(cluster); ++ ++ if (completer) ++ completer(completer_cookie); ++ } ++ } while (!kthread_should_stop()); ++ ++ return 0; ++} ++ ++static struct task_struct * bL_switcher_thread_create(int cpu, void *arg) ++{ ++ struct task_struct *task; ++ ++ task = kthread_create_on_node(bL_switcher_thread, arg, ++ cpu_to_node(cpu), "kswitcher_%d", cpu); ++ if (!IS_ERR(task)) { ++ kthread_bind(task, cpu); ++ wake_up_process(task); ++ } else ++ pr_err("%s failed for CPU %d\n", __func__, cpu); ++ return task; ++} ++ ++/* ++ * bL_switch_request_cb - Switch to a specific cluster for the given CPU, ++ * with completion notification via a callback ++ * ++ * @cpu: the CPU to switch ++ * @new_cluster_id: the ID of the cluster to switch to. ++ * @completer: switch completion callback. if non-NULL, ++ * @completer(@completer_cookie) will be called on completion of ++ * the switch, in non-atomic context. ++ * @completer_cookie: opaque context argument for @completer. ++ * ++ * This function causes a cluster switch on the given CPU by waking up ++ * the appropriate switcher thread. This function may or may not return ++ * before the switch has occurred. ++ * ++ * If a @completer callback function is supplied, it will be called when ++ * the switch is complete. This can be used to determine asynchronously ++ * when the switch is complete, regardless of when bL_switch_request() ++ * returns. When @completer is supplied, no new switch request is permitted ++ * for the affected CPU until after the switch is complete, and @completer ++ * has returned. ++ */ ++int bL_switch_request_cb(unsigned int cpu, unsigned int new_cluster_id, ++ bL_switch_completion_handler completer, ++ void *completer_cookie) ++{ ++ struct bL_thread *t; ++ ++ if (cpu >= ARRAY_SIZE(bL_threads)) { ++ pr_err("%s: cpu %d out of bounds\n", __func__, cpu); ++ return -EINVAL; ++ } ++ ++ t = &bL_threads[cpu]; ++ ++ if (IS_ERR(t->task)) ++ return PTR_ERR(t->task); ++ if (!t->task) ++ return -ESRCH; ++ ++ spin_lock(&t->lock); ++ if (t->completer) { ++ spin_unlock(&t->lock); ++ return -EBUSY; ++ } ++ t->completer = completer; ++ t->completer_cookie = completer_cookie; ++ t->wanted_cluster = new_cluster_id; ++ spin_unlock(&t->lock); ++ wake_up(&t->wq); ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(bL_switch_request_cb); ++ ++/* ++ * Detach an outstanding switch request. ++ * ++ * The switcher will continue with the switch request in the background, ++ * but the completer function will not be called. ++ * ++ * This may be necessary if the completer is in a kernel module which is ++ * about to be unloaded. ++ */ ++void bL_switch_request_detach(unsigned int cpu, ++ bL_switch_completion_handler completer) ++{ ++ struct bL_thread *t; ++ ++ if (cpu >= ARRAY_SIZE(bL_threads)) { ++ pr_err("%s: cpu %d out of bounds\n", __func__, cpu); ++ return; ++ } ++ ++ t = &bL_threads[cpu]; ++ ++ if (IS_ERR(t->task) || !t->task) ++ return; ++ ++ spin_lock(&t->lock); ++ if (t->completer == completer) ++ t->completer = NULL; ++ spin_unlock(&t->lock); ++} ++ ++EXPORT_SYMBOL_GPL(bL_switch_request_detach); ++ ++/* ++ * Activation and configuration code. ++ */ ++ ++static DEFINE_MUTEX(bL_switcher_activation_lock); ++static BLOCKING_NOTIFIER_HEAD(bL_activation_notifier); ++static unsigned int bL_switcher_active; ++static unsigned int bL_switcher_cpu_original_cluster[NR_CPUS]; ++static cpumask_t bL_switcher_removed_logical_cpus; ++ ++int bL_switcher_register_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register(&bL_activation_notifier, nb); ++} ++EXPORT_SYMBOL_GPL(bL_switcher_register_notifier); ++ ++int bL_switcher_unregister_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_unregister(&bL_activation_notifier, nb); ++} ++EXPORT_SYMBOL_GPL(bL_switcher_unregister_notifier); ++ ++static int bL_activation_notify(unsigned long val) ++{ ++ int ret; ++ ++ ret = blocking_notifier_call_chain(&bL_activation_notifier, val, NULL); ++ if (ret & NOTIFY_STOP_MASK) ++ pr_err("%s: notifier chain failed with status 0x%x\n", ++ __func__, ret); ++ return notifier_to_errno(ret); ++} ++ ++static void bL_switcher_restore_cpus(void) ++{ ++ int i; ++ ++ for_each_cpu(i, &bL_switcher_removed_logical_cpus) ++ cpu_up(i); ++} ++ ++static int bL_switcher_halve_cpus(void) ++{ ++ int i, j, cluster_0, gic_id, ret; ++ unsigned int cpu, cluster, mask; ++ cpumask_t available_cpus; ++ ++ /* First pass to validate what we have */ ++ mask = 0; ++ for_each_online_cpu(i) { ++ cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 0); ++ cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1); ++ if (cluster >= 2) { ++ pr_err("%s: only dual cluster systems are supported\n", __func__); ++ return -EINVAL; ++ } ++ if (WARN_ON(cpu >= MAX_CPUS_PER_CLUSTER)) ++ return -EINVAL; ++ mask |= (1 << cluster); ++ } ++ if (mask != 3) { ++ pr_err("%s: no CPU pairing possible\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* ++ * Now let's do the pairing. We match each CPU with another CPU ++ * from a different cluster. To get a uniform scheduling behavior ++ * without fiddling with CPU topology and compute capacity data, ++ * we'll use logical CPUs initially belonging to the same cluster. ++ */ ++ memset(bL_switcher_cpu_pairing, -1, sizeof(bL_switcher_cpu_pairing)); ++ cpumask_copy(&available_cpus, cpu_online_mask); ++ cluster_0 = -1; ++ for_each_cpu(i, &available_cpus) { ++ int match = -1; ++ cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1); ++ if (cluster_0 == -1) ++ cluster_0 = cluster; ++ if (cluster != cluster_0) ++ continue; ++ cpumask_clear_cpu(i, &available_cpus); ++ for_each_cpu(j, &available_cpus) { ++ cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(j), 1); ++ /* ++ * Let's remember the last match to create "odd" ++ * pairing on purpose in order for other code not ++ * to assume any relation between physical and ++ * logical CPU numbers. ++ */ ++ if (cluster != cluster_0) ++ match = j; ++ } ++ if (match != -1) { ++ bL_switcher_cpu_pairing[i] = match; ++ cpumask_clear_cpu(match, &available_cpus); ++ pr_info("CPU%d paired with CPU%d\n", i, match); ++ } ++ } ++ ++ /* ++ * Now we disable the unwanted CPUs i.e. everything that has no ++ * pairing information (that includes the pairing counterparts). ++ */ ++ cpumask_clear(&bL_switcher_removed_logical_cpus); ++ for_each_online_cpu(i) { ++ cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 0); ++ cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(i), 1); ++ ++ /* Let's take note of the GIC ID for this CPU */ ++ gic_id = gic_get_cpu_id(i); ++ if (gic_id < 0) { ++ pr_err("%s: bad GIC ID for CPU %d\n", __func__, i); ++ bL_switcher_restore_cpus(); ++ return -EINVAL; ++ } ++ bL_gic_id[cpu][cluster] = gic_id; ++ pr_info("GIC ID for CPU %u cluster %u is %u\n", ++ cpu, cluster, gic_id); ++ ++ if (bL_switcher_cpu_pairing[i] != -1) { ++ bL_switcher_cpu_original_cluster[i] = cluster; ++ continue; ++ } ++ ++ ret = cpu_down(i); ++ if (ret) { ++ bL_switcher_restore_cpus(); ++ return ret; ++ } ++ cpumask_set_cpu(i, &bL_switcher_removed_logical_cpus); ++ } ++ ++ return 0; ++} ++ ++/* Determine the logical CPU a given physical CPU is grouped on. */ ++int bL_switcher_get_logical_index(u32 mpidr) ++{ ++ int cpu; ++ ++ if (!bL_switcher_active) ++ return -EUNATCH; ++ ++ mpidr &= MPIDR_HWID_BITMASK; ++ for_each_online_cpu(cpu) { ++ int pairing = bL_switcher_cpu_pairing[cpu]; ++ if (pairing == -1) ++ continue; ++ if ((mpidr == cpu_logical_map(cpu)) || ++ (mpidr == cpu_logical_map(pairing))) ++ return cpu; ++ } ++ return -EINVAL; ++} ++ ++static void bL_switcher_trace_trigger_cpu(void *__always_unused info) ++{ ++ trace_cpu_migrate_current(get_ns(), read_mpidr()); ++} ++ ++int bL_switcher_trace_trigger(void) ++{ ++ int ret; ++ ++ preempt_disable(); ++ ++ bL_switcher_trace_trigger_cpu(NULL); ++ ret = smp_call_function(bL_switcher_trace_trigger_cpu, NULL, true); ++ ++ preempt_enable(); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(bL_switcher_trace_trigger); ++ ++static int bL_switcher_enable(void) ++{ ++ int cpu, ret; ++ ++ mutex_lock(&bL_switcher_activation_lock); ++ cpu_hotplug_driver_lock(); ++ if (bL_switcher_active) { ++ cpu_hotplug_driver_unlock(); ++ mutex_unlock(&bL_switcher_activation_lock); ++ return 0; ++ } ++ ++ pr_info("big.LITTLE switcher initializing\n"); ++ ++ ret = bL_activation_notify(BL_NOTIFY_PRE_ENABLE); ++ if (ret) ++ goto error; ++ ++ ret = bL_switcher_halve_cpus(); ++ if (ret) ++ goto error; ++ ++ bL_switcher_trace_trigger(); ++ ++ for_each_online_cpu(cpu) { ++ struct bL_thread *t = &bL_threads[cpu]; ++ spin_lock_init(&t->lock); ++ init_waitqueue_head(&t->wq); ++ init_completion(&t->started); ++ t->wanted_cluster = -1; ++ t->task = bL_switcher_thread_create(cpu, t); ++ } ++ ++ bL_switcher_active = 1; ++ bL_activation_notify(BL_NOTIFY_POST_ENABLE); ++ pr_info("big.LITTLE switcher initialized\n"); ++ goto out; ++ ++error: ++ pr_warning("big.LITTLE switcher initialization failed\n"); ++ bL_activation_notify(BL_NOTIFY_POST_DISABLE); ++ ++out: ++ cpu_hotplug_driver_unlock(); ++ mutex_unlock(&bL_switcher_activation_lock); ++ return ret; ++} ++ ++#ifdef CONFIG_SYSFS ++ ++static void bL_switcher_disable(void) ++{ ++ unsigned int cpu, cluster; ++ struct bL_thread *t; ++ struct task_struct *task; ++ ++ mutex_lock(&bL_switcher_activation_lock); ++ cpu_hotplug_driver_lock(); ++ ++ if (!bL_switcher_active) ++ goto out; ++ ++ if (bL_activation_notify(BL_NOTIFY_PRE_DISABLE) != 0) { ++ bL_activation_notify(BL_NOTIFY_POST_ENABLE); ++ goto out; ++ } ++ ++ bL_switcher_active = 0; ++ ++ /* ++ * To deactivate the switcher, we must shut down the switcher ++ * threads to prevent any other requests from being accepted. ++ * Then, if the final cluster for given logical CPU is not the ++ * same as the original one, we'll recreate a switcher thread ++ * just for the purpose of switching the CPU back without any ++ * possibility for interference from external requests. ++ */ ++ for_each_online_cpu(cpu) { ++ t = &bL_threads[cpu]; ++ task = t->task; ++ t->task = NULL; ++ if (!task || IS_ERR(task)) ++ continue; ++ kthread_stop(task); ++ /* no more switch may happen on this CPU at this point */ ++ cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 1); ++ if (cluster == bL_switcher_cpu_original_cluster[cpu]) ++ continue; ++ init_completion(&t->started); ++ t->wanted_cluster = bL_switcher_cpu_original_cluster[cpu]; ++ task = bL_switcher_thread_create(cpu, t); ++ if (!IS_ERR(task)) { ++ wait_for_completion(&t->started); ++ kthread_stop(task); ++ cluster = MPIDR_AFFINITY_LEVEL(cpu_logical_map(cpu), 1); ++ if (cluster == bL_switcher_cpu_original_cluster[cpu]) ++ continue; ++ } ++ /* If execution gets here, we're in trouble. */ ++ pr_crit("%s: unable to restore original cluster for CPU %d\n", ++ __func__, cpu); ++ pr_crit("%s: CPU %d can't be restored\n", ++ __func__, bL_switcher_cpu_pairing[cpu]); ++ cpumask_clear_cpu(bL_switcher_cpu_pairing[cpu], ++ &bL_switcher_removed_logical_cpus); ++ } ++ ++ bL_switcher_restore_cpus(); ++ bL_switcher_trace_trigger(); ++ ++ bL_activation_notify(BL_NOTIFY_POST_DISABLE); ++ ++out: ++ cpu_hotplug_driver_unlock(); ++ mutex_unlock(&bL_switcher_activation_lock); ++} ++ ++static ssize_t bL_switcher_active_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%u\n", bL_switcher_active); ++} ++ ++static ssize_t bL_switcher_active_store(struct kobject *kobj, ++ struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ int ret; ++ ++ switch (buf[0]) { ++ case '0': ++ bL_switcher_disable(); ++ ret = 0; ++ break; ++ case '1': ++ ret = bL_switcher_enable(); ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ ++ return (ret >= 0) ? count : ret; ++} ++ ++static ssize_t bL_switcher_trace_trigger_store(struct kobject *kobj, ++ struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ int ret = bL_switcher_trace_trigger(); ++ ++ return ret ? ret : count; ++} ++ ++static struct kobj_attribute bL_switcher_active_attr = ++ __ATTR(active, 0644, bL_switcher_active_show, bL_switcher_active_store); ++ ++static struct kobj_attribute bL_switcher_trace_trigger_attr = ++ __ATTR(trace_trigger, 0200, NULL, bL_switcher_trace_trigger_store); ++ ++static struct attribute *bL_switcher_attrs[] = { ++ &bL_switcher_active_attr.attr, ++ &bL_switcher_trace_trigger_attr.attr, ++ NULL, ++}; ++ ++static struct attribute_group bL_switcher_attr_group = { ++ .attrs = bL_switcher_attrs, ++}; ++ ++static struct kobject *bL_switcher_kobj; ++ ++static int __init bL_switcher_sysfs_init(void) ++{ ++ int ret; ++ ++ bL_switcher_kobj = kobject_create_and_add("bL_switcher", kernel_kobj); ++ if (!bL_switcher_kobj) ++ return -ENOMEM; ++ ret = sysfs_create_group(bL_switcher_kobj, &bL_switcher_attr_group); ++ if (ret) ++ kobject_put(bL_switcher_kobj); ++ return ret; ++} ++ ++#endif /* CONFIG_SYSFS */ ++ ++bool bL_switcher_get_enabled(void) ++{ ++ mutex_lock(&bL_switcher_activation_lock); ++ ++ return bL_switcher_active; ++} ++EXPORT_SYMBOL_GPL(bL_switcher_get_enabled); ++ ++void bL_switcher_put_enabled(void) ++{ ++ mutex_unlock(&bL_switcher_activation_lock); ++} ++EXPORT_SYMBOL_GPL(bL_switcher_put_enabled); ++ ++/* ++ * Veto any CPU hotplug operation while the switcher is active. ++ * We're just not ready to deal with that given the trickery involved. ++ */ ++static int bL_switcher_hotplug_callback(struct notifier_block *nfb, ++ unsigned long action, void *hcpu) ++{ ++ switch (action) { ++ case CPU_UP_PREPARE: ++ case CPU_DOWN_PREPARE: ++ if (bL_switcher_active) ++ return NOTIFY_BAD; ++ } ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block bL_switcher_hotplug_notifier = ++ { &bL_switcher_hotplug_callback, NULL, 0 }; ++ ++#ifdef CONFIG_SCHED_HMP ++static bool no_bL_switcher = true; ++#else ++static bool no_bL_switcher; ++#endif ++core_param(no_bL_switcher, no_bL_switcher, bool, 0644); ++ ++static int __init bL_switcher_init(void) ++{ ++ int ret; ++ ++ if (MAX_NR_CLUSTERS != 2) { ++ pr_err("%s: only dual cluster systems are supported\n", __func__); ++ return -EINVAL; ++ } ++ ++ register_cpu_notifier(&bL_switcher_hotplug_notifier); ++ ++ if (!no_bL_switcher) { ++ ret = bL_switcher_enable(); ++ if (ret) ++ return ret; ++ } ++ ++#ifdef CONFIG_SYSFS ++ ret = bL_switcher_sysfs_init(); ++ if (ret) ++ pr_err("%s: unable to create sysfs entry\n", __func__); ++#endif ++ ++ return 0; ++} ++ ++late_initcall(bL_switcher_init); +diff -Nur linux-3.10.30/arch/arm/common/bL_switcher_dummy_if.c linux-3.10.30-cubox-i/arch/arm/common/bL_switcher_dummy_if.c +--- linux-3.10.30/arch/arm/common/bL_switcher_dummy_if.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/common/bL_switcher_dummy_if.c 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,71 @@ ++/* ++ * arch/arm/common/bL_switcher_dummy_if.c -- b.L switcher dummy interface ++ * ++ * Created by: Nicolas Pitre, November 2012 ++ * Copyright: (C) 2012 Linaro Limited ++ * ++ * Dummy interface to user space for debugging purpose only. ++ * ++ * This program 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 ssize_t bL_switcher_write(struct file *file, const char __user *buf, ++ size_t len, loff_t *pos) ++{ ++ unsigned char val[3]; ++ unsigned int cpu, cluster; ++ int ret; ++ ++ pr_debug("%s\n", __func__); ++ ++ if (len < 3) ++ return -EINVAL; ++ ++ if (copy_from_user(val, buf, 3)) ++ return -EFAULT; ++ ++ /* format: , */ ++ if (val[0] < '0' || val[0] > '4' || ++ val[1] != ',' || ++ val[2] < '0' || val[2] > '1') ++ return -EINVAL; ++ ++ cpu = val[0] - '0'; ++ cluster = val[2] - '0'; ++ ret = bL_switch_request(cpu, cluster); ++ ++ return ret ? : len; ++} ++ ++static const struct file_operations bL_switcher_fops = { ++ .write = bL_switcher_write, ++ .owner = THIS_MODULE, ++}; ++ ++static struct miscdevice bL_switcher_device = { ++ MISC_DYNAMIC_MINOR, ++ "b.L_switcher", ++ &bL_switcher_fops ++}; ++ ++static int __init bL_switcher_dummy_if_init(void) ++{ ++ return misc_register(&bL_switcher_device); ++} ++ ++static void __exit bL_switcher_dummy_if_exit(void) ++{ ++ misc_deregister(&bL_switcher_device); ++} ++ ++module_init(bL_switcher_dummy_if_init); ++module_exit(bL_switcher_dummy_if_exit); +diff -Nur linux-3.10.30/arch/arm/common/mcpm_entry.c linux-3.10.30-cubox-i/arch/arm/common/mcpm_entry.c +--- linux-3.10.30/arch/arm/common/mcpm_entry.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/common/mcpm_entry.c 2014-03-08 20:32:53.000000000 +0100 +@@ -27,6 +27,18 @@ + sync_cache_w(&mcpm_entry_vectors[cluster][cpu]); + } + ++extern unsigned long mcpm_entry_early_pokes[MAX_NR_CLUSTERS][MAX_CPUS_PER_CLUSTER][2]; ++ ++void mcpm_set_early_poke(unsigned cpu, unsigned cluster, ++ unsigned long poke_phys_addr, unsigned long poke_val) ++{ ++ unsigned long *poke = &mcpm_entry_early_pokes[cluster][cpu][0]; ++ poke[0] = poke_phys_addr; ++ poke[1] = poke_val; ++ __cpuc_flush_dcache_area((void *)poke, 8); ++ outer_clean_range(__pa(poke), __pa(poke + 2)); ++} ++ + static const struct mcpm_platform_ops *platform_ops; + + int __init mcpm_platform_register(const struct mcpm_platform_ops *ops) +diff -Nur linux-3.10.30/arch/arm/common/mcpm_head.S linux-3.10.30-cubox-i/arch/arm/common/mcpm_head.S +--- linux-3.10.30/arch/arm/common/mcpm_head.S 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/common/mcpm_head.S 2014-03-08 20:32:53.000000000 +0100 +@@ -71,12 +71,19 @@ + * position independent way. + */ + adr r5, 3f +- ldmia r5, {r6, r7, r8, r11} ++ ldmia r5, {r0, r6, r7, r8, r11} ++ add r0, r5, r0 @ r0 = mcpm_entry_early_pokes + add r6, r5, r6 @ r6 = mcpm_entry_vectors + ldr r7, [r5, r7] @ r7 = mcpm_power_up_setup_phys + add r8, r5, r8 @ r8 = mcpm_sync + add r11, r5, r11 @ r11 = first_man_locks + ++ @ Perform an early poke, if any ++ add r0, r0, r4, lsl #3 ++ ldmia r0, {r0, r1} ++ teq r0, #0 ++ strne r1, [r0] ++ + mov r0, #MCPM_SYNC_CLUSTER_SIZE + mla r8, r0, r10, r8 @ r8 = sync cluster base + +@@ -195,7 +202,8 @@ + + .align 2 + +-3: .word mcpm_entry_vectors - . ++3: .word mcpm_entry_early_pokes - . ++ .word mcpm_entry_vectors - 3b + .word mcpm_power_up_setup_phys - 3b + .word mcpm_sync - 3b + .word first_man_locks - 3b +@@ -214,6 +222,10 @@ + ENTRY(mcpm_entry_vectors) + .space 4 * MAX_NR_CLUSTERS * MAX_CPUS_PER_CLUSTER + ++ .type mcpm_entry_early_pokes, #object ++ENTRY(mcpm_entry_early_pokes) ++ .space 8 * MAX_NR_CLUSTERS * MAX_CPUS_PER_CLUSTER ++ + .type mcpm_power_up_setup_phys, #object + ENTRY(mcpm_power_up_setup_phys) + .space 4 @ set by mcpm_sync_init() +diff -Nur linux-3.10.30/arch/arm/configs/imx_v6_v7_defconfig linux-3.10.30-cubox-i/arch/arm/configs/imx_v6_v7_defconfig +--- linux-3.10.30/arch/arm/configs/imx_v6_v7_defconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/configs/imx_v6_v7_defconfig 2014-03-08 20:32:53.000000000 +0100 +@@ -1,4 +1,3 @@ +-CONFIG_EXPERIMENTAL=y + # CONFIG_LOCALVERSION_AUTO is not set + CONFIG_KERNEL_LZO=y + CONFIG_SYSVIPC=y +@@ -17,10 +16,9 @@ + CONFIG_MODVERSIONS=y + CONFIG_MODULE_SRCVERSION_ALL=y + # CONFIG_BLK_DEV_BSG is not set +-CONFIG_ARCH_MXC=y + CONFIG_ARCH_MULTI_V6=y +-CONFIG_ARCH_MULTI_V7=y +-CONFIG_MACH_IMX31_DT=y ++CONFIG_GPIO_PCA953X=y ++CONFIG_ARCH_MXC=y + CONFIG_MACH_MX31LILLY=y + CONFIG_MACH_MX31LITE=y + CONFIG_MACH_PCM037=y +@@ -30,6 +28,7 @@ + CONFIG_MACH_QONG=y + CONFIG_MACH_ARMADILLO5X0=y + CONFIG_MACH_KZM_ARM11_01=y ++CONFIG_MACH_IMX31_DT=y + CONFIG_MACH_PCM043=y + CONFIG_MACH_MX35_3DS=y + CONFIG_MACH_VPR200=y +@@ -37,16 +36,26 @@ + CONFIG_MACH_EUKREA_CPUIMX51SD=y + CONFIG_SOC_IMX53=y + CONFIG_SOC_IMX6Q=y +-CONFIG_MXC_PWM=y ++CONFIG_SOC_IMX6SL=y ++CONFIG_SOC_VF610=y + CONFIG_SMP=y + CONFIG_VMSPLIT_2G=y + CONFIG_PREEMPT_VOLUNTARY=y + CONFIG_AEABI=y + # CONFIG_OABI_COMPAT is not set + CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" ++CONFIG_CPU_FREQ=y ++CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y ++CONFIG_CPU_FREQ_GOV_POWERSAVE=y ++CONFIG_CPU_FREQ_GOV_USERSPACE=y ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y ++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y ++CONFIG_ARM_IMX6_CPUFREQ=y ++CONFIG_CPU_IDLE=y + CONFIG_VFP=y + CONFIG_NEON=y + CONFIG_BINFMT_MISC=m ++CONFIG_PM_RUNTIME=y + CONFIG_PM_DEBUG=y + CONFIG_PM_TEST_SUSPEND=y + CONFIG_NET=y +@@ -65,16 +74,19 @@ + CONFIG_DEVTMPFS=y + CONFIG_DEVTMPFS_MOUNT=y + # CONFIG_STANDALONE is not set ++CONFIG_CMA=y ++CONFIG_CMA_SIZE_MBYTES=256 ++CONFIG_IMX_WEIM=y + CONFIG_CONNECTOR=y + CONFIG_MTD=y + CONFIG_MTD_CMDLINE_PARTS=y +-CONFIG_MTD_CHAR=y + CONFIG_MTD_BLOCK=y + CONFIG_MTD_CFI=y + CONFIG_MTD_JEDECPROBE=y + CONFIG_MTD_CFI_INTELEXT=y + CONFIG_MTD_CFI_AMDSTD=y + CONFIG_MTD_CFI_STAA=y ++CONFIG_MTD_PHYSMAP_OF=y + CONFIG_MTD_DATAFLASH=y + CONFIG_MTD_M25P80=y + CONFIG_MTD_SST25L=y +@@ -95,10 +107,11 @@ + CONFIG_SCSI_SCAN_ASYNC=y + # CONFIG_SCSI_LOWLEVEL is not set + CONFIG_ATA=y ++CONFIG_SATA_AHCI_PLATFORM=y ++CONFIG_AHCI_IMX=y + CONFIG_PATA_IMX=y + CONFIG_NETDEVICES=y + # CONFIG_NET_VENDOR_BROADCOM is not set +-# CONFIG_NET_VENDOR_CHELSIO is not set + CONFIG_CS89x0=y + CONFIG_CS89x0_PLATFORM=y + # CONFIG_NET_VENDOR_FARADAY is not set +@@ -112,6 +125,7 @@ + CONFIG_SMC911X=y + CONFIG_SMSC911X=y + # CONFIG_NET_VENDOR_STMICRO is not set ++CONFIG_AT803X_PHY=y + # CONFIG_WLAN is not set + # CONFIG_INPUT_MOUSEDEV_PSAUX is not set + CONFIG_INPUT_EVDEV=y +@@ -121,22 +135,26 @@ + CONFIG_MOUSE_PS2=m + CONFIG_MOUSE_PS2_ELANTECH=y + CONFIG_INPUT_TOUCHSCREEN=y ++CONFIG_TOUCHSCREEN_EGALAX=y ++CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH=y ++CONFIG_TOUCHSCREEN_MAX11801=y + CONFIG_TOUCHSCREEN_MC13783=y + CONFIG_INPUT_MISC=y + CONFIG_INPUT_MMA8450=y ++CONFIG_INPUT_ISL29023=y + CONFIG_SERIO_SERPORT=m + CONFIG_VT_HW_CONSOLE_BINDING=y + # CONFIG_LEGACY_PTYS is not set + # CONFIG_DEVKMEM is not set + CONFIG_SERIAL_IMX=y + CONFIG_SERIAL_IMX_CONSOLE=y ++CONFIG_SERIAL_FSL_LPUART=y ++CONFIG_SERIAL_FSL_LPUART_CONSOLE=y + CONFIG_HW_RANDOM=y + CONFIG_HW_RANDOM_MXC_RNGA=y +-CONFIG_I2C=y + # CONFIG_I2C_COMPAT is not set + CONFIG_I2C_CHARDEV=y + # CONFIG_I2C_HELPER_AUTO is not set +-CONFIG_I2C_ALGOBIT=m + CONFIG_I2C_ALGOPCF=m + CONFIG_I2C_ALGOPCA=m + CONFIG_I2C_IMX=y +@@ -144,7 +162,13 @@ + CONFIG_SPI_IMX=y + CONFIG_GPIO_SYSFS=y + CONFIG_GPIO_MC9S08DZ60=y +-# CONFIG_HWMON is not set ++CONFIG_POWER_SUPPLY=y ++CONFIG_SABRESD_MAX8903=y ++CONFIG_SENSORS_MAG3110=y ++CONFIG_THERMAL=y ++CONFIG_CPU_THERMAL=y ++CONFIG_IMX_THERMAL=y ++CONFIG_DEVICE_THERMAL=y + CONFIG_WATCHDOG=y + CONFIG_IMX2_WDT=y + CONFIG_MFD_DA9052_I2C=y +@@ -156,20 +180,35 @@ + CONFIG_REGULATOR_ANATOP=y + CONFIG_REGULATOR_MC13783=y + CONFIG_REGULATOR_MC13892=y ++CONFIG_REGULATOR_PFUZE100=y + CONFIG_MEDIA_SUPPORT=y +-CONFIG_VIDEO_DEV=y +-CONFIG_V4L_PLATFORM_DRIVERS=y + CONFIG_MEDIA_CAMERA_SUPPORT=y ++CONFIG_MEDIA_USB_SUPPORT=y ++CONFIG_USB_VIDEO_CLASS=m ++CONFIG_MEDIA_RC_SUPPORT=y ++CONFIG_RC_DEVICES=y ++CONFIG_IR_GPIO_CIR=y ++CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MXC_OUTPUT=y ++CONFIG_VIDEO_MXC_IPU_OUTPUT=y + CONFIG_SOC_CAMERA=y ++CONFIG_VIDEO_MX3=y + CONFIG_SOC_CAMERA_OV2640=y + CONFIG_DRM=y +-CONFIG_VIDEO_MX3=y ++CONFIG_DRM_VIVANTE=y + CONFIG_FB=y +-CONFIG_LCD_PLATFORM=y ++CONFIG_FB_MXS=y + CONFIG_BACKLIGHT_LCD_SUPPORT=y + CONFIG_LCD_CLASS_DEVICE=y + CONFIG_LCD_L4F00242T03=y ++CONFIG_LCD_PLATFORM=y + CONFIG_BACKLIGHT_CLASS_DEVICE=y ++CONFIG_BACKLIGHT_PWM=y ++CONFIG_FB_MXC_SYNC_PANEL=y ++CONFIG_FB_MXC_LDB=y ++CONFIG_FB_MXC_MIPI_DSI=y ++CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL=y ++CONFIG_FB_MXC_HDMI=y + CONFIG_FRAMEBUFFER_CONSOLE=y + CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y + CONFIG_FONTS=y +@@ -178,24 +217,36 @@ + CONFIG_LOGO=y + CONFIG_SOUND=y + CONFIG_SND=y ++CONFIG_SND_USB_AUDIO=m + CONFIG_SND_SOC=y + CONFIG_SND_IMX_SOC=y + CONFIG_SND_SOC_PHYCORE_AC97=y + CONFIG_SND_SOC_EUKREA_TLV320=y ++CONFIG_SND_SOC_IMX_CS42888=y ++CONFIG_SND_SOC_IMX_WM8962=y + CONFIG_SND_SOC_IMX_SGTL5000=y + CONFIG_SND_SOC_IMX_MC13783=y + CONFIG_USB=y + CONFIG_USB_EHCI_HCD=y +-CONFIG_USB_EHCI_MXC=y ++CONFIG_USB_STORAGE=y + CONFIG_USB_CHIPIDEA=y ++CONFIG_USB_CHIPIDEA_UDC=y + CONFIG_USB_CHIPIDEA_HOST=y + CONFIG_USB_PHY=y + CONFIG_USB_MXS_PHY=y +-CONFIG_USB_STORAGE=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_ZERO=m ++CONFIG_USB_ETH=m ++CONFIG_USB_MASS_STORAGE=m ++CONFIG_USB_G_SERIAL=m + CONFIG_MMC=y ++CONFIG_MMC_UNSAFE_RESUME=y + CONFIG_MMC_SDHCI=y + CONFIG_MMC_SDHCI_PLTFM=y + CONFIG_MMC_SDHCI_ESDHC_IMX=y ++CONFIG_MXC_IPU=y ++CONFIG_MXC_GPU_VIV=y ++CONFIG_MXC_ASRC=y + CONFIG_NEW_LEDS=y + CONFIG_LEDS_CLASS=y + CONFIG_RTC_CLASS=y +@@ -204,14 +255,14 @@ + CONFIG_RTC_DRV_MXC=y + CONFIG_RTC_DRV_SNVS=y + CONFIG_DMADEVICES=y ++CONFIG_MXC_PXP_V2=y + CONFIG_IMX_SDMA=y + CONFIG_MXS_DMA=y + CONFIG_STAGING=y +-CONFIG_DRM_IMX=y +-CONFIG_DRM_IMX_IPUV3_CORE=y +-CONFIG_DRM_IMX_IPUV3=y + CONFIG_COMMON_CLK_DEBUG=y + # CONFIG_IOMMU_SUPPORT is not set ++CONFIG_PWM=y ++CONFIG_PWM_IMX=y + CONFIG_EXT2_FS=y + CONFIG_EXT2_FS_XATTR=y + CONFIG_EXT2_FS_POSIX_ACL=y +@@ -234,7 +285,6 @@ + CONFIG_MSDOS_FS=m + CONFIG_VFAT_FS=y + CONFIG_TMPFS=y +-CONFIG_CONFIGFS_FS=m + CONFIG_JFFS2_FS=y + CONFIG_UBIFS_FS=y + CONFIG_NFS_FS=y +diff -Nur linux-3.10.30/arch/arm/configs/imx_v7_cubox-i_hummingboard_defconfig linux-3.10.30-cubox-i/arch/arm/configs/imx_v7_cubox-i_hummingboard_defconfig +--- linux-3.10.30/arch/arm/configs/imx_v7_cubox-i_hummingboard_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/configs/imx_v7_cubox-i_hummingboard_defconfig 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,384 @@ ++CONFIG_KERNEL_LZO=y ++CONFIG_SYSVIPC=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=18 ++CONFIG_CGROUPS=y ++CONFIG_RELAY=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_EXPERT=y ++CONFIG_PERF_EVENTS=y ++# CONFIG_SLUB_DEBUG is not set ++# CONFIG_COMPAT_BRK is not set ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_MODVERSIONS=y ++CONFIG_MODULE_SRCVERSION_ALL=y ++# CONFIG_BLK_DEV_BSG is not set ++CONFIG_GPIO_PCA953X=y ++CONFIG_ARCH_MXC=y ++CONFIG_MXC_DEBUG_BOARD=y ++CONFIG_HAVE_IMX_ANATOP=y ++CONFIG_HAVE_IMX_GPC=y ++CONFIG_HAVE_IMX_MMDC=y ++CONFIG_HAVE_IMX_SRC=y ++CONFIG_ARCH_MXC_IOMUX_V3=y ++CONFIG_SOC_IMX6Q=y ++CONFIG_SOC_IMX6SL=y ++CONFIG_IMX_HAVE_PLATFORM_FEC=y ++CONFIG_IMX_HAVE_PLATFORM_FSL_USB2_UDC=y ++CONFIG_IMX_HAVE_PLATFORM_GPIO_KEYS=y ++CONFIG_IMX_HAVE_PLATFORM_IMX2_WDT=y ++CONFIG_IMX_HAVE_PLATFORM_IMX_I2C=y ++CONFIG_IMX_HAVE_PLATFORM_IMX_SSI=y ++CONFIG_IMX_HAVE_PLATFORM_IMX_UART=y ++CONFIG_IMX_HAVE_PLATFORM_MXC_EHCI=y ++CONFIG_IMX_HAVE_PLATFORM_MXC_NAND=y ++CONFIG_IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX=y ++CONFIG_IMX_HAVE_PLATFORM_SPI_IMX=y ++CONFIG_PCI=y ++CONFIG_PCI_IMX6=y ++# CONFIG_SWP_EMULATE is not set ++CONFIG_SMP=y ++CONFIG_VMSPLIT_2G=y ++CONFIG_PREEMPT_VOLUNTARY=y ++CONFIG_AEABI=y ++# CONFIG_OABI_COMPAT is not set ++CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" ++CONFIG_CPU_FREQ=y ++CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y ++CONFIG_CPU_FREQ_GOV_POWERSAVE=y ++CONFIG_CPU_FREQ_GOV_USERSPACE=y ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y ++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y ++CONFIG_ARM_IMX6_CPUFREQ=y ++CONFIG_CPU_IDLE=y ++CONFIG_VFP=y ++CONFIG_NEON=y ++CONFIG_BINFMT_MISC=m ++CONFIG_PM_RUNTIME=y ++CONFIG_PM_DEBUG=y ++CONFIG_PM_TEST_SUSPEND=y ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++CONFIG_IPV6=y ++CONFIG_NETFILTER=y ++CONFIG_VLAN_8021Q=y ++CONFIG_CAN=y ++CONFIG_CAN_FLEXCAN=y ++CONFIG_BT=y ++CONFIG_BT_L2CAP=y ++CONFIG_BT_SCO=y ++CONFIG_BT_RFCOMM=y ++CONFIG_BT_RFCOMM_TTY=y ++CONFIG_BT_BNEP=y ++CONFIG_BT_BNEP_MC_FILTER=y ++CONFIG_BT_BNEP_PROTO_FILTER=y ++CONFIG_BT_HIDP=y ++ ++# ++# Bluetooth device drivers ++# ++CONFIG_BT_HCIBTUSB=y ++CONFIG_BT_HCIUART=y ++CONFIG_BT_HCIUART_ATH3K=y ++CONFIG_BT_HCIVHCI=y ++CONFIG_WIRELESS=y ++CONFIG_WIRELESS_EXT=y ++CONFIG_WEXT_CORE=y ++CONFIG_WEXT_PROC=y ++CONFIG_WEXT_SPY=y ++CONFIG_WEXT_PRIV=y ++CONFIG_CFG80211=y ++CONFIG_CFG80211_DEFAULT_PS=y ++CONFIG_CFG80211_WEXT=y ++CONFIG_WIRELESS_EXT_SYSFS=y ++CONFIG_LIB80211=y ++CONFIG_LIB80211_CRYPT_WEP=y ++CONFIG_LIB80211_CRYPT_CCMP=y ++CONFIG_LIB80211_CRYPT_TKIP=y ++CONFIG_RFKILL=y ++CONFIG_RFKILL_LEDS=y ++CONFIG_RFKILL_INPUT=y ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++CONFIG_CMA=y ++CONFIG_CMA_SIZE_MBYTES=256 ++CONFIG_IMX_WEIM=y ++CONFIG_CONNECTOR=y ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_CFI=y ++CONFIG_MTD_JEDECPROBE=y ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_CFI_AMDSTD=y ++CONFIG_MTD_CFI_STAA=y ++CONFIG_MTD_PHYSMAP_OF=y ++CONFIG_MTD_DATAFLASH=y ++CONFIG_MTD_M25P80=y ++CONFIG_MTD_SST25L=y ++CONFIG_MTD_NAND=y ++CONFIG_MTD_NAND_GPMI_NAND=y ++CONFIG_MTD_NAND_MXC=y ++CONFIG_MTD_UBI=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=65536 ++CONFIG_EEPROM_AT24=y ++CONFIG_EEPROM_AT25=y ++# CONFIG_SCSI_PROC_FS is not set ++CONFIG_BLK_DEV_SD=y ++CONFIG_SCSI_MULTI_LUN=y ++CONFIG_SCSI_CONSTANTS=y ++CONFIG_SCSI_LOGGING=y ++CONFIG_SCSI_SCAN_ASYNC=y ++# CONFIG_SCSI_LOWLEVEL is not set ++CONFIG_ATA=y ++CONFIG_SATA_AHCI_PLATFORM=y ++CONFIG_AHCI_IMX=y ++CONFIG_PATA_IMX=y ++CONFIG_NETDEVICES=y ++CONFIG_NET_VENDOR_FREESCALE=y ++CONFIG_FEC=y ++CONFIG_PHYLIB=y ++CONFIG_AT803X_PHY=y ++# CONFIG_NET_VENDOR_BROADCOM is not set ++CONFIG_CS89x0=y ++CONFIG_CS89x0_PLATFORM=y ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_MICROCHIP is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++CONFIG_SMC91X=y ++CONFIG_SMC911X=y ++CONFIG_SMSC911X=y ++# CONFIG_NET_VENDOR_STMICRO is not set ++CONFIG_ATH_CARDS=y ++CONFIG_ATH6KL=m ++CONFIG_ATH6KL_SDIO=m ++CONFIG_BRCMUTIL=y ++# CONFIG_BRCMSMAC is not set ++CONFIG_BRCMFMAC=m ++CONFIG_BRCMFMAC_SDIO=y ++CONFIG_HOSTAP=y ++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set ++CONFIG_INPUT_EVDEV=y ++CONFIG_INPUT_EVBUG=m ++CONFIG_KEYBOARD_GPIO=y ++CONFIG_KEYBOARD_IMX=y ++CONFIG_MOUSE_PS2=m ++CONFIG_MOUSE_PS2_ELANTECH=y ++CONFIG_INPUT_MISC=y ++CONFIG_INPUT_MMA8450=y ++CONFIG_INPUT_ISL29023=y ++CONFIG_SERIO_SERPORT=m ++CONFIG_VT_HW_CONSOLE_BINDING=y ++# CONFIG_LEGACY_PTYS is not set ++# CONFIG_DEVKMEM is not set ++CONFIG_SERIAL_IMX=y ++CONFIG_SERIAL_IMX_CONSOLE=y ++# CONFIG_I2C_COMPAT is not set ++CONFIG_I2C_CHARDEV=y ++# CONFIG_I2C_HELPER_AUTO is not set ++CONFIG_I2C_ALGOPCF=m ++CONFIG_I2C_ALGOPCA=m ++CONFIG_I2C_IMX=y ++CONFIG_SPI=y ++CONFIG_SPI_IMX=y ++CONFIG_GPIO_SYSFS=y ++CONFIG_POWER_SUPPLY=y ++CONFIG_MXC_MMA8451=y ++CONFIG_THERMAL=y ++CONFIG_CPU_THERMAL=y ++CONFIG_IMX_THERMAL=y ++CONFIG_DEVICE_THERMAL=y ++CONFIG_WATCHDOG=y ++CONFIG_IMX2_WDT=y ++CONFIG_MFD_DA9052_I2C=y ++CONFIG_MFD_MC13XXX_SPI=y ++CONFIG_MFD_MC13XXX_I2C=y ++CONFIG_MFD_SI476X_CORE=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=y ++CONFIG_REGULATOR_DA9052=y ++CONFIG_REGULATOR_ANATOP=y ++CONFIG_REGULATOR_MC13783=y ++CONFIG_REGULATOR_MC13892=y ++CONFIG_REGULATOR_PFUZE100=y ++CONFIG_VIDEO_V4L2=y ++CONFIG_VIDEO_CAPTURE_DRIVERS=y ++CONFIG_MEDIA_SUPPORT=y ++CONFIG_MEDIA_CAMERA_SUPPORT=y ++CONFIG_MEDIA_RC_SUPPORT=y ++CONFIG_VIDEO_DEV=y ++CONFIG_VIDEO_V4L2_COMMON=y ++CONFIG_VIDEO_MEDIA=y ++CONFIG_VIDEOBUF_GEN=y ++CONFIG_VIDEOBUF_DMA_CONTIG=y ++CONFIG_VIDEOBUF2_CORE=y ++CONFIG_VIDEOBUF2_MEMOPS=y ++CONFIG_VIDEOBUF2_DMA_CONTIG=y ++CONFIG_VIDEOBUF2_VMALLOC=m ++CONFIG_VIDEO_V4L2_INT_DEVICE=y ++CONFIG_RC_CORE=y ++CONFIG_RC_MAP=y ++CONFIG_RC_DECODERS=y ++CONFIG_LIRC=y ++CONFIG_IR_LIRC_CODEC=y ++CONFIG_IR_NEC_DECODER=y ++CONFIG_IR_RC5_DECODER=y ++CONFIG_IR_RC6_DECODER=y ++CONFIG_IR_JVC_DECODER=y ++CONFIG_IR_SONY_DECODER=y ++CONFIG_IR_RC5_SZ_DECODER=y ++CONFIG_IR_SANYO_DECODER=y ++CONFIG_IR_MCE_KBD_DECODER=y ++CONFIG_RC_DEVICES=y ++CONFIG_IR_GPIO_CIR=y ++CONFIG_MEDIA_USB_SUPPORT=y ++CONFIG_USB_VIDEO_CLASS=m ++CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y ++CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MXC_OUTPUT=y ++CONFIG_VIDEO_MXC_CAPTURE=m ++CONFIG_VIDEO_MXC_CSI_CAMERA=m ++CONFIG_MXC_CAMERA_OV5640=m ++CONFIG_MXC_CAMERA_OV5642=m ++CONFIG_MXC_CAMERA_OV5640_MIPI=m ++CONFIG_MXC_TVIN_ADV7180=m ++CONFIG_MXC_IPU_DEVICE_QUEUE_SDC=m ++CONFIG_VIDEO_MXC_IPU_OUTPUT=y ++CONFIG_VIDEO_MXC_PXP_V4L2=y ++CONFIG_SOC_CAMERA=y ++CONFIG_VIDEO_MX3=y ++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y ++CONFIG_VIDEO_IR_I2C=y ++CONFIG_DRM=y ++CONFIG_DRM_VIVANTE=y ++CONFIG_FB=y ++CONFIG_FB_MXS=y ++CONFIG_FB_MXC_SYNC_PANEL=y ++CONFIG_FB_MXC_HDMI=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y ++CONFIG_SOUND=y ++CONFIG_SND=y ++CONFIG_SND_USB_AUDIO=m ++CONFIG_SND_SOC=y ++CONFIG_SND_IMX_SOC=y ++CONFIG_SND_SOC_IMX_SPDIF=y ++CONFIG_SND_SOC_IMX_HDMI=y ++CONFIG_SND_SOC_FSL_SPDIF=y ++CONFIG_SND_SOC_FSL_HDMI=y ++CONFIG_USB=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_STORAGE=y ++CONFIG_USB_CHIPIDEA=y ++CONFIG_USB_CHIPIDEA_UDC=y ++CONFIG_USB_CHIPIDEA_HOST=y ++CONFIG_USB_PHY=y ++CONFIG_USB_MXS_PHY=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_ZERO=m ++CONFIG_USB_ETH=m ++CONFIG_USB_MASS_STORAGE=m ++CONFIG_USB_G_SERIAL=m ++CONFIG_MMC=y ++CONFIG_MMC_UNSAFE_RESUME=y ++CONFIG_MMC_SDHCI=y ++CONFIG_MMC_SDHCI_PLTFM=y ++CONFIG_MMC_SDHCI_ESDHC_IMX=y ++CONFIG_MXC_IPU=y ++CONFIG_MXC_GPU_VIV=y ++CONFIG_MXC_ASRC=y ++CONFIG_MXC_HDMI_CEC=y ++CONFIG_MXC_VPU=y ++CONFIG_MXC_MIPI_CSI2=y ++CONFIG_MXC_MLB150=m ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_PWM=y ++CONFIG_LEDS_REGULATOR=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_INTF_DEV_UIE_EMUL=y ++CONFIG_RTC_DRV_MC13XXX=y ++CONFIG_RTC_DRV_MXC=y ++CONFIG_RTC_DRV_SNVS=y ++CONFIG_RTC_DRV_PCF8523=y ++CONFIG_DMADEVICES=y ++CONFIG_MXC_PXP_V2=y ++CONFIG_IMX_SDMA=y ++CONFIG_MXS_DMA=y ++CONFIG_STAGING=y ++CONFIG_STAGING_MEDIA=y ++CONFIG_LIRC_STAGING=y ++CONFIG_LIRC_SERIAL=y ++CONFIG_LIRC_SERIAL_TRANSMITTER=y ++CONFIG_COMMON_CLK_DEBUG=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_PWM=y ++CONFIG_PWM_IMX=y ++CONFIG_EXT4_FS=y ++CONFIG_EXT4_USE_FOR_EXT23=y ++CONFIG_EXT4_FS_POSIX_ACL=y ++CONFIG_EXT4_FS_SECURITY=y ++CONFIG_QUOTA=y ++CONFIG_QUOTA_NETLINK_INTERFACE=y ++# CONFIG_PRINT_QUOTA_WARNING is not set ++CONFIG_AUTOFS4_FS=y ++CONFIG_FUSE_FS=y ++CONFIG_ISO9660_FS=m ++CONFIG_JOLIET=y ++CONFIG_ZISOFS=y ++CONFIG_UDF_FS=m ++CONFIG_MSDOS_FS=m ++CONFIG_VFAT_FS=y ++CONFIG_TMPFS=y ++CONFIG_JFFS2_FS=y ++CONFIG_UBIFS_FS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3_ACL=y ++CONFIG_NFS_V4=y ++CONFIG_ROOT_NFS=y ++CONFIG_NLS_DEFAULT="cp437" ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_ASCII=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_NLS_ISO8859_15=m ++CONFIG_NLS_UTF8=y ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_SCHED_DEBUG is not set ++# CONFIG_DEBUG_BUGVERBOSE is not set ++# CONFIG_FTRACE is not set ++CONFIG_SECURITYFS=y ++CONFIG_CRYPTO_USER=y ++CONFIG_CRYPTO_CCM=y ++CONFIG_CRYPTO_GCM=y ++CONFIG_CRYPTO_CBC=y ++CONFIG_CRYPTO_CTS=y ++CONFIG_CRYPTO_ECB=y ++CONFIG_CRYPTO_LRW=y ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++CONFIG_CRYPTO_DEV_FSL_CAAM=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y ++CONFIG_CRC_CCITT=m ++CONFIG_CRC_T10DIF=y ++CONFIG_CRC7=m ++CONFIG_LIBCRC32C=m +diff -Nur linux-3.10.30/arch/arm/configs/imx_v7_defconfig linux-3.10.30-cubox-i/arch/arm/configs/imx_v7_defconfig +--- linux-3.10.30/arch/arm/configs/imx_v7_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/configs/imx_v7_defconfig 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,332 @@ ++CONFIG_KERNEL_LZO=y ++CONFIG_SYSVIPC=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=18 ++CONFIG_CGROUPS=y ++CONFIG_RELAY=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_EXPERT=y ++CONFIG_PERF_EVENTS=y ++# CONFIG_SLUB_DEBUG is not set ++# CONFIG_COMPAT_BRK is not set ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_MODVERSIONS=y ++CONFIG_MODULE_SRCVERSION_ALL=y ++# CONFIG_BLK_DEV_BSG is not set ++CONFIG_GPIO_PCA953X=y ++CONFIG_ARCH_MXC=y ++CONFIG_MXC_DEBUG_BOARD=y ++CONFIG_MACH_IMX51_DT=y ++CONFIG_MACH_EUKREA_CPUIMX51SD=y ++CONFIG_SOC_IMX53=y ++CONFIG_SOC_IMX6Q=y ++CONFIG_SOC_IMX6SL=y ++CONFIG_SOC_VF610=y ++# CONFIG_SWP_EMULATE is not set ++CONFIG_SMP=y ++CONFIG_VMSPLIT_2G=y ++CONFIG_PREEMPT_VOLUNTARY=y ++CONFIG_AEABI=y ++# CONFIG_OABI_COMPAT is not set ++CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" ++CONFIG_CPU_FREQ=y ++CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y ++CONFIG_CPU_FREQ_GOV_POWERSAVE=y ++CONFIG_CPU_FREQ_GOV_USERSPACE=y ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y ++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y ++CONFIG_ARM_IMX6_CPUFREQ=y ++CONFIG_CPU_IDLE=y ++CONFIG_VFP=y ++CONFIG_NEON=y ++CONFIG_BINFMT_MISC=m ++CONFIG_PM_RUNTIME=y ++CONFIG_PM_DEBUG=y ++CONFIG_PM_TEST_SUSPEND=y ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++CONFIG_IPV6=y ++CONFIG_NETFILTER=y ++CONFIG_VLAN_8021Q=y ++CONFIG_CAN=y ++CONFIG_CAN_FLEXCAN=y ++CONFIG_CFG80211=y ++CONFIG_CFG80211_WEXT=y ++CONFIG_MAC80211=y ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++CONFIG_CMA=y ++CONFIG_CMA_SIZE_MBYTES=256 ++CONFIG_IMX_WEIM=y ++CONFIG_CONNECTOR=y ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_CFI=y ++CONFIG_MTD_JEDECPROBE=y ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_CFI_AMDSTD=y ++CONFIG_MTD_CFI_STAA=y ++CONFIG_MTD_PHYSMAP_OF=y ++CONFIG_MTD_DATAFLASH=y ++CONFIG_MTD_M25P80=y ++CONFIG_MTD_SST25L=y ++CONFIG_MTD_NAND=y ++CONFIG_MTD_NAND_GPMI_NAND=y ++CONFIG_MTD_NAND_MXC=y ++CONFIG_MTD_UBI=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=65536 ++CONFIG_EEPROM_AT24=y ++CONFIG_EEPROM_AT25=y ++# CONFIG_SCSI_PROC_FS is not set ++CONFIG_BLK_DEV_SD=y ++CONFIG_SCSI_MULTI_LUN=y ++CONFIG_SCSI_CONSTANTS=y ++CONFIG_SCSI_LOGGING=y ++CONFIG_SCSI_SCAN_ASYNC=y ++# CONFIG_SCSI_LOWLEVEL is not set ++CONFIG_ATA=y ++CONFIG_SATA_AHCI_PLATFORM=y ++CONFIG_AHCI_IMX=y ++CONFIG_PATA_IMX=y ++CONFIG_NETDEVICES=y ++# CONFIG_NET_VENDOR_BROADCOM is not set ++CONFIG_CS89x0=y ++CONFIG_CS89x0_PLATFORM=y ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_MICROCHIP is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++CONFIG_SMC91X=y ++CONFIG_SMC911X=y ++CONFIG_SMSC911X=y ++# CONFIG_NET_VENDOR_STMICRO is not set ++CONFIG_ATH_CARDS=y ++CONFIG_ATH6KL=m ++CONFIG_ATH6KL_SDIO=m ++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set ++CONFIG_INPUT_EVDEV=y ++CONFIG_INPUT_EVBUG=m ++CONFIG_KEYBOARD_GPIO=y ++CONFIG_KEYBOARD_IMX=y ++CONFIG_MOUSE_PS2=m ++CONFIG_MOUSE_PS2_ELANTECH=y ++CONFIG_INPUT_TOUCHSCREEN=y ++CONFIG_TOUCHSCREEN_EGALAX=y ++CONFIG_TOUCHSCREEN_ELAN=y ++CONFIG_TOUCHSCREEN_MAX11801=y ++CONFIG_TOUCHSCREEN_MC13783=y ++CONFIG_INPUT_MISC=y ++CONFIG_INPUT_MMA8450=y ++CONFIG_INPUT_ISL29023=y ++CONFIG_SERIO_SERPORT=m ++CONFIG_VT_HW_CONSOLE_BINDING=y ++# CONFIG_LEGACY_PTYS is not set ++# CONFIG_DEVKMEM is not set ++CONFIG_SERIAL_IMX=y ++CONFIG_SERIAL_IMX_CONSOLE=y ++CONFIG_SERIAL_FSL_LPUART=y ++CONFIG_SERIAL_FSL_LPUART_CONSOLE=y ++CONFIG_FSL_OTP=y ++# CONFIG_I2C_COMPAT is not set ++CONFIG_I2C_CHARDEV=y ++# CONFIG_I2C_HELPER_AUTO is not set ++CONFIG_I2C_ALGOPCF=m ++CONFIG_I2C_ALGOPCA=m ++CONFIG_I2C_IMX=y ++CONFIG_SPI=y ++CONFIG_SPI_IMX=y ++CONFIG_GPIO_SYSFS=y ++CONFIG_POWER_SUPPLY=y ++CONFIG_SABRESD_MAX8903=y ++CONFIG_IMX6_USB_CHARGER=y ++CONFIG_SENSORS_MAX17135=y ++CONFIG_SENSORS_MAG3110=y ++CONFIG_THERMAL=y ++CONFIG_CPU_THERMAL=y ++CONFIG_IMX_THERMAL=y ++CONFIG_DEVICE_THERMAL=y ++CONFIG_WATCHDOG=y ++CONFIG_IMX2_WDT=y ++CONFIG_MFD_DA9052_I2C=y ++CONFIG_MFD_MC13XXX_SPI=y ++CONFIG_MFD_MC13XXX_I2C=y ++CONFIG_MFD_MAX17135=y ++CONFIG_MFD_SI476X_CORE=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=y ++CONFIG_REGULATOR_DA9052=y ++CONFIG_REGULATOR_ANATOP=y ++CONFIG_REGULATOR_MC13783=y ++CONFIG_REGULATOR_MC13892=y ++CONFIG_REGULATOR_MAX17135=y ++CONFIG_REGULATOR_PFUZE100=y ++CONFIG_MEDIA_SUPPORT=y ++CONFIG_MEDIA_CAMERA_SUPPORT=y ++CONFIG_MEDIA_RADIO_SUPPORT=y ++CONFIG_VIDEO_V4L2_INT_DEVICE=y ++CONFIG_MEDIA_USB_SUPPORT=y ++CONFIG_USB_VIDEO_CLASS=m ++CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MXC_OUTPUT=y ++CONFIG_VIDEO_MXC_CAPTURE=m ++CONFIG_VIDEO_MXC_CSI_CAMERA=m ++CONFIG_MXC_CAMERA_OV5640=m ++CONFIG_MXC_CAMERA_OV5642=m ++CONFIG_MXC_CAMERA_OV5640_MIPI=m ++CONFIG_MXC_TVIN_ADV7180=m ++CONFIG_MXC_IPU_DEVICE_QUEUE_SDC=m ++CONFIG_VIDEO_MXC_IPU_OUTPUT=y ++CONFIG_VIDEO_MXC_PXP_V4L2=y ++CONFIG_SOC_CAMERA=y ++CONFIG_VIDEO_MX3=y ++CONFIG_RADIO_SI476X=y ++CONFIG_SOC_CAMERA_OV2640=y ++CONFIG_DRM=y ++CONFIG_DRM_VIVANTE=y ++CONFIG_FB=y ++CONFIG_FB_MXS=y ++CONFIG_BACKLIGHT_LCD_SUPPORT=y ++CONFIG_LCD_CLASS_DEVICE=y ++CONFIG_LCD_L4F00242T03=y ++CONFIG_LCD_PLATFORM=y ++CONFIG_BACKLIGHT_CLASS_DEVICE=y ++CONFIG_BACKLIGHT_PWM=y ++CONFIG_FB_MXC_SYNC_PANEL=y ++CONFIG_FB_MXC_LDB=y ++CONFIG_FB_MXC_MIPI_DSI=y ++CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL=y ++CONFIG_FB_MXC_HDMI=y ++CONFIG_FB_MXC_EINK_PANEL=y ++CONFIG_FB_MXS_SII902X=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y ++CONFIG_FONTS=y ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++CONFIG_LOGO=y ++CONFIG_SOUND=y ++CONFIG_SND=y ++CONFIG_SND_USB_AUDIO=m ++CONFIG_SND_SOC=y ++CONFIG_SND_IMX_SOC=y ++CONFIG_SND_SOC_EUKREA_TLV320=y ++CONFIG_SND_SOC_IMX_CS42888=y ++CONFIG_SND_SOC_IMX_WM8962=y ++CONFIG_SND_SOC_IMX_SGTL5000=y ++CONFIG_SND_SOC_IMX_SPDIF=y ++CONFIG_SND_SOC_IMX_MC13783=y ++CONFIG_SND_SOC_IMX_HDMI=y ++CONFIG_SND_SOC_IMX_SI476X=y ++CONFIG_USB=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_STORAGE=y ++CONFIG_USB_CHIPIDEA=y ++CONFIG_USB_CHIPIDEA_UDC=y ++CONFIG_USB_CHIPIDEA_HOST=y ++CONFIG_USB_PHY=y ++CONFIG_USB_MXS_PHY=y ++CONFIG_USB_GADGET=y ++CONFIG_USB_ZERO=m ++CONFIG_USB_ETH=m ++CONFIG_USB_MASS_STORAGE=m ++CONFIG_USB_G_SERIAL=m ++CONFIG_MMC=y ++CONFIG_MMC_UNSAFE_RESUME=y ++CONFIG_MMC_SDHCI=y ++CONFIG_MMC_SDHCI_PLTFM=y ++CONFIG_MMC_SDHCI_ESDHC_IMX=y ++CONFIG_MXC_IPU=y ++CONFIG_MXC_GPU_VIV=y ++CONFIG_MXC_ASRC=y ++CONFIG_MXC_MIPI_CSI2=y ++CONFIG_MXC_MLB150=m ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_INTF_DEV_UIE_EMUL=y ++CONFIG_RTC_DRV_MC13XXX=y ++CONFIG_RTC_DRV_MXC=y ++CONFIG_RTC_DRV_SNVS=y ++CONFIG_DMADEVICES=y ++CONFIG_MXC_PXP_V2=y ++CONFIG_IMX_SDMA=y ++CONFIG_MXS_DMA=y ++CONFIG_STAGING=y ++CONFIG_COMMON_CLK_DEBUG=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_PWM=y ++CONFIG_PWM_IMX=y ++CONFIG_EXT2_FS=y ++CONFIG_EXT2_FS_XATTR=y ++CONFIG_EXT2_FS_POSIX_ACL=y ++CONFIG_EXT2_FS_SECURITY=y ++CONFIG_EXT3_FS=y ++CONFIG_EXT3_FS_POSIX_ACL=y ++CONFIG_EXT3_FS_SECURITY=y ++CONFIG_EXT4_FS=y ++CONFIG_EXT4_FS_POSIX_ACL=y ++CONFIG_EXT4_FS_SECURITY=y ++CONFIG_QUOTA=y ++CONFIG_QUOTA_NETLINK_INTERFACE=y ++# CONFIG_PRINT_QUOTA_WARNING is not set ++CONFIG_AUTOFS4_FS=y ++CONFIG_FUSE_FS=y ++CONFIG_ISO9660_FS=m ++CONFIG_JOLIET=y ++CONFIG_ZISOFS=y ++CONFIG_UDF_FS=m ++CONFIG_MSDOS_FS=m ++CONFIG_VFAT_FS=y ++CONFIG_TMPFS=y ++CONFIG_JFFS2_FS=y ++CONFIG_UBIFS_FS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3_ACL=y ++CONFIG_NFS_V4=y ++CONFIG_ROOT_NFS=y ++CONFIG_NLS_DEFAULT="cp437" ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_ASCII=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_NLS_ISO8859_15=m ++CONFIG_NLS_UTF8=y ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_SCHED_DEBUG is not set ++# CONFIG_DEBUG_BUGVERBOSE is not set ++# CONFIG_FTRACE is not set ++CONFIG_SECURITYFS=y ++CONFIG_CRYPTO_USER=y ++CONFIG_CRYPTO_CCM=y ++CONFIG_CRYPTO_GCM=y ++CONFIG_CRYPTO_CBC=y ++CONFIG_CRYPTO_CTS=y ++CONFIG_CRYPTO_ECB=y ++CONFIG_CRYPTO_LRW=y ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++CONFIG_CRYPTO_DEV_FSL_CAAM=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y ++CONFIG_CRC_CCITT=m ++CONFIG_CRC_T10DIF=y ++CONFIG_CRC7=m ++CONFIG_LIBCRC32C=m +diff -Nur linux-3.10.30/arch/arm/configs/imx_v7_mfg_defconfig linux-3.10.30-cubox-i/arch/arm/configs/imx_v7_mfg_defconfig +--- linux-3.10.30/arch/arm/configs/imx_v7_mfg_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/configs/imx_v7_mfg_defconfig 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,341 @@ ++CONFIG_KERNEL_LZO=y ++CONFIG_SYSVIPC=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=18 ++CONFIG_CGROUPS=y ++CONFIG_RELAY=y ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_EXPERT=y ++CONFIG_PERF_EVENTS=y ++# CONFIG_SLUB_DEBUG is not set ++# CONFIG_COMPAT_BRK is not set ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++CONFIG_MODVERSIONS=y ++CONFIG_MODULE_SRCVERSION_ALL=y ++# CONFIG_BLK_DEV_BSG is not set ++CONFIG_GPIO_PCA953X=y ++CONFIG_ARCH_MXC=y ++CONFIG_MXC_DEBUG_BOARD=y ++CONFIG_MACH_IMX51_DT=y ++CONFIG_MACH_EUKREA_CPUIMX51SD=y ++CONFIG_SOC_IMX53=y ++CONFIG_SOC_IMX6Q=y ++CONFIG_SOC_IMX6SL=y ++CONFIG_SOC_VF610=y ++# CONFIG_SWP_EMULATE is not set ++CONFIG_SMP=y ++CONFIG_VMSPLIT_2G=y ++CONFIG_PREEMPT_VOLUNTARY=y ++CONFIG_AEABI=y ++# CONFIG_OABI_COMPAT is not set ++CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" ++CONFIG_CPU_FREQ=y ++CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y ++CONFIG_CPU_FREQ_GOV_POWERSAVE=y ++CONFIG_CPU_FREQ_GOV_USERSPACE=y ++CONFIG_CPU_FREQ_GOV_ONDEMAND=y ++CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y ++CONFIG_ARM_IMX6_CPUFREQ=y ++CONFIG_CPU_IDLE=y ++CONFIG_VFP=y ++CONFIG_NEON=y ++CONFIG_BINFMT_MISC=m ++CONFIG_PM_RUNTIME=y ++CONFIG_PM_DEBUG=y ++CONFIG_PM_TEST_SUSPEND=y ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++CONFIG_IPV6=y ++CONFIG_NETFILTER=y ++CONFIG_VLAN_8021Q=y ++CONFIG_CFG80211=y ++CONFIG_CFG80211_WEXT=y ++CONFIG_MAC80211=y ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++CONFIG_CMA=y ++CONFIG_CMA_SIZE_MBYTES=256 ++CONFIG_IMX_WEIM=y ++CONFIG_CONNECTOR=y ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_CFI=y ++CONFIG_MTD_JEDECPROBE=y ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_CFI_AMDSTD=y ++CONFIG_MTD_CFI_STAA=y ++CONFIG_MTD_PHYSMAP_OF=y ++CONFIG_MTD_DATAFLASH=y ++CONFIG_MTD_M25P80=y ++CONFIG_MTD_SST25L=y ++CONFIG_MTD_NAND=y ++CONFIG_MTD_NAND_GPMI_NAND=y ++CONFIG_MTD_NAND_MXC=y ++CONFIG_MTD_UBI=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=65536 ++CONFIG_EEPROM_AT24=y ++CONFIG_EEPROM_AT25=y ++# CONFIG_SCSI_PROC_FS is not set ++CONFIG_BLK_DEV_SD=y ++CONFIG_SCSI_MULTI_LUN=y ++CONFIG_SCSI_CONSTANTS=y ++CONFIG_SCSI_LOGGING=y ++CONFIG_SCSI_SCAN_ASYNC=y ++# CONFIG_SCSI_LOWLEVEL is not set ++CONFIG_ATA=y ++CONFIG_SATA_AHCI_PLATFORM=y ++CONFIG_AHCI_IMX=y ++CONFIG_PATA_IMX=y ++CONFIG_NETDEVICES=y ++# CONFIG_NET_VENDOR_BROADCOM is not set ++CONFIG_CS89x0=y ++CONFIG_CS89x0_PLATFORM=y ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_INTEL is not set ++# CONFIG_NET_VENDOR_MARVELL is not set ++# CONFIG_NET_VENDOR_MICREL is not set ++# CONFIG_NET_VENDOR_MICROCHIP is not set ++# CONFIG_NET_VENDOR_NATSEMI is not set ++# CONFIG_NET_VENDOR_SEEQ is not set ++CONFIG_SMC91X=y ++CONFIG_SMC911X=y ++CONFIG_SMSC911X=y ++# CONFIG_NET_VENDOR_STMICRO is not set ++CONFIG_ATH_CARDS=y ++CONFIG_ATH6KL=m ++CONFIG_ATH6KL_SDIO=m ++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set ++CONFIG_INPUT_EVDEV=y ++CONFIG_INPUT_EVBUG=m ++CONFIG_KEYBOARD_GPIO=y ++CONFIG_KEYBOARD_IMX=y ++CONFIG_MOUSE_PS2=m ++CONFIG_MOUSE_PS2_ELANTECH=y ++CONFIG_INPUT_TOUCHSCREEN=y ++CONFIG_TOUCHSCREEN_EGALAX=y ++CONFIG_TOUCHSCREEN_ELAN=y ++CONFIG_TOUCHSCREEN_MAX11801=y ++CONFIG_TOUCHSCREEN_MC13783=y ++CONFIG_INPUT_MISC=y ++CONFIG_INPUT_MMA8450=y ++CONFIG_INPUT_ISL29023=y ++CONFIG_SERIO_SERPORT=m ++CONFIG_VT_HW_CONSOLE_BINDING=y ++# CONFIG_LEGACY_PTYS is not set ++# CONFIG_DEVKMEM is not set ++CONFIG_SERIAL_IMX=y ++CONFIG_SERIAL_IMX_CONSOLE=y ++CONFIG_SERIAL_FSL_LPUART=y ++CONFIG_SERIAL_FSL_LPUART_CONSOLE=y ++CONFIG_FSL_OTP=y ++# CONFIG_I2C_COMPAT is not set ++CONFIG_I2C_CHARDEV=y ++# CONFIG_I2C_HELPER_AUTO is not set ++CONFIG_I2C_ALGOPCF=m ++CONFIG_I2C_ALGOPCA=m ++CONFIG_I2C_IMX=y ++CONFIG_SPI=y ++CONFIG_SPI_IMX=y ++CONFIG_GPIO_SYSFS=y ++CONFIG_POWER_SUPPLY=y ++CONFIG_SABRESD_MAX8903=y ++CONFIG_SENSORS_MAX17135=y ++CONFIG_SENSORS_MAG3110=y ++CONFIG_THERMAL=y ++CONFIG_CPU_THERMAL=y ++CONFIG_IMX_THERMAL=y ++CONFIG_DEVICE_THERMAL=y ++CONFIG_WATCHDOG=y ++CONFIG_IMX2_WDT=y ++CONFIG_MFD_DA9052_I2C=y ++CONFIG_MFD_MC13XXX_SPI=y ++CONFIG_MFD_MC13XXX_I2C=y ++CONFIG_MFD_MAX17135=y ++CONFIG_MFD_SI476X_CORE=y ++CONFIG_REGULATOR=y ++CONFIG_REGULATOR_FIXED_VOLTAGE=y ++CONFIG_REGULATOR_DA9052=y ++CONFIG_REGULATOR_ANATOP=y ++CONFIG_REGULATOR_MC13783=y ++CONFIG_REGULATOR_MC13892=y ++CONFIG_REGULATOR_MAX17135=y ++CONFIG_REGULATOR_PFUZE100=y ++CONFIG_MEDIA_SUPPORT=y ++CONFIG_MEDIA_CAMERA_SUPPORT=y ++CONFIG_MEDIA_RADIO_SUPPORT=y ++CONFIG_VIDEO_V4L2_INT_DEVICE=y ++CONFIG_MEDIA_USB_SUPPORT=y ++CONFIG_USB_VIDEO_CLASS=m ++CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MXC_OUTPUT=y ++CONFIG_VIDEO_MXC_CAPTURE=m ++CONFIG_VIDEO_MXC_CSI_CAMERA=m ++CONFIG_MXC_CAMERA_OV5640=m ++CONFIG_MXC_CAMERA_OV5642=m ++CONFIG_MXC_CAMERA_OV5640_MIPI=m ++CONFIG_MXC_TVIN_ADV7180=m ++CONFIG_MXC_IPU_DEVICE_QUEUE_SDC=m ++CONFIG_VIDEO_MXC_IPU_OUTPUT=y ++CONFIG_VIDEO_MXC_PXP_V4L2=y ++CONFIG_SOC_CAMERA=y ++CONFIG_VIDEO_MX3=y ++CONFIG_RADIO_SI476X=y ++CONFIG_SOC_CAMERA_OV2640=y ++CONFIG_DRM=y ++CONFIG_DRM_VIVANTE=y ++CONFIG_FB=y ++CONFIG_FB_MXS=y ++CONFIG_BACKLIGHT_LCD_SUPPORT=y ++CONFIG_LCD_CLASS_DEVICE=y ++CONFIG_LCD_L4F00242T03=y ++CONFIG_LCD_PLATFORM=y ++CONFIG_BACKLIGHT_CLASS_DEVICE=y ++CONFIG_BACKLIGHT_PWM=y ++CONFIG_FB_MXC_SYNC_PANEL=y ++CONFIG_FB_MXC_LDB=y ++CONFIG_FB_MXC_MIPI_DSI=y ++CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL=y ++CONFIG_FB_MXC_HDMI=y ++CONFIG_FB_MXC_EINK_PANEL=y ++CONFIG_FB_MXS_SII902X=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y ++CONFIG_FONTS=y ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++CONFIG_LOGO=y ++CONFIG_SOUND=y ++CONFIG_SND=y ++CONFIG_SND_USB_AUDIO=m ++CONFIG_SND_SOC=y ++CONFIG_SND_IMX_SOC=y ++CONFIG_SND_SOC_EUKREA_TLV320=y ++CONFIG_SND_SOC_IMX_CS42888=y ++CONFIG_SND_SOC_IMX_WM8962=y ++CONFIG_SND_SOC_IMX_SGTL5000=y ++CONFIG_SND_SOC_IMX_SPDIF=y ++CONFIG_SND_SOC_IMX_MC13783=y ++CONFIG_SND_SOC_IMX_HDMI=y ++CONFIG_SND_SOC_IMX_SI476X=y ++CONFIG_USB=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB_STORAGE=y ++CONFIG_USB_CHIPIDEA=y ++CONFIG_USB_CHIPIDEA_UDC=y ++CONFIG_USB_CHIPIDEA_HOST=y ++CONFIG_USB_PHY=y ++CONFIG_USB_MXS_PHY=y ++CONFIG_USB_GADGET=y ++# CONFIG_USB_ZERO is not set ++# CONFIG_USB_AUDIO is not set ++# CONFIG_USB_ETH is not set ++# CONFIG_USB_G_NCM is not set ++# CONFIG_USB_GADGETFS is not set ++# CONFIG_USB_FUNCTIONFS is not set ++CONFIG_USB_MASS_STORAGE=y ++CONFIG_FSL_UTP=y ++# CONFIG_USB_G_SERIAL is not set ++# CONFIG_USB_MIDI_GADGET is not set ++# CONFIG_USB_G_PRINTER is not set ++# CONFIG_USB_CDC_COMPOSITE is not set ++# CONFIG_USB_G_ACM_MS is not set ++# CONFIG_USB_G_MULTI is not set ++# CONFIG_USB_G_HID is not set ++# CONFIG_USB_G_DBGP is not set ++# CONFIG_USB_G_WEBCAM is not set ++CONFIG_MMC=y ++CONFIG_MMC_UNSAFE_RESUME=y ++CONFIG_MMC_SDHCI=y ++CONFIG_MMC_SDHCI_PLTFM=y ++CONFIG_MMC_SDHCI_ESDHC_IMX=y ++CONFIG_MXC_IPU=y ++CONFIG_MXC_GPU_VIV=y ++CONFIG_MXC_ASRC=y ++CONFIG_MXC_MIPI_CSI2=y ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_INTF_DEV_UIE_EMUL=y ++CONFIG_RTC_DRV_MC13XXX=y ++CONFIG_RTC_DRV_MXC=y ++CONFIG_RTC_DRV_SNVS=y ++CONFIG_DMADEVICES=y ++CONFIG_MXC_PXP_V2=y ++CONFIG_IMX_SDMA=y ++CONFIG_MXS_DMA=y ++CONFIG_STAGING=y ++CONFIG_COMMON_CLK_DEBUG=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_PWM=y ++CONFIG_PWM_IMX=y ++CONFIG_EXT2_FS=y ++CONFIG_EXT2_FS_XATTR=y ++CONFIG_EXT2_FS_POSIX_ACL=y ++CONFIG_EXT2_FS_SECURITY=y ++CONFIG_EXT3_FS=y ++CONFIG_EXT3_FS_POSIX_ACL=y ++CONFIG_EXT3_FS_SECURITY=y ++CONFIG_EXT4_FS=y ++CONFIG_EXT4_FS_POSIX_ACL=y ++CONFIG_EXT4_FS_SECURITY=y ++CONFIG_QUOTA=y ++CONFIG_QUOTA_NETLINK_INTERFACE=y ++# CONFIG_PRINT_QUOTA_WARNING is not set ++CONFIG_AUTOFS4_FS=y ++CONFIG_FUSE_FS=y ++CONFIG_ISO9660_FS=m ++CONFIG_JOLIET=y ++CONFIG_ZISOFS=y ++CONFIG_UDF_FS=m ++CONFIG_MSDOS_FS=m ++CONFIG_VFAT_FS=y ++CONFIG_TMPFS=y ++CONFIG_JFFS2_FS=y ++CONFIG_UBIFS_FS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3_ACL=y ++CONFIG_NFS_V4=y ++CONFIG_ROOT_NFS=y ++CONFIG_NLS_DEFAULT="cp437" ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_ASCII=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_NLS_ISO8859_15=m ++CONFIG_NLS_UTF8=y ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_SCHED_DEBUG is not set ++# CONFIG_DEBUG_BUGVERBOSE is not set ++# CONFIG_FTRACE is not set ++CONFIG_SECURITYFS=y ++CONFIG_CRYPTO_USER=y ++CONFIG_CRYPTO_CCM=y ++CONFIG_CRYPTO_GCM=y ++CONFIG_CRYPTO_CBC=y ++CONFIG_CRYPTO_CTS=y ++CONFIG_CRYPTO_ECB=y ++CONFIG_CRYPTO_LRW=y ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++CONFIG_CRYPTO_DEV_FSL_CAAM=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST=y ++CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y ++CONFIG_CRC_CCITT=m ++CONFIG_CRC_T10DIF=y ++CONFIG_CRC7=m ++CONFIG_LIBCRC32C=m +diff -Nur linux-3.10.30/arch/arm/include/asm/arch_timer.h linux-3.10.30-cubox-i/arch/arm/include/asm/arch_timer.h +--- linux-3.10.30/arch/arm/include/asm/arch_timer.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/arch_timer.h 2014-03-08 20:32:53.000000000 +0100 +@@ -96,7 +96,7 @@ + asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl)); + + /* disable user access to everything */ +- cntkctl &= ~((3 << 8) | (7 << 0)); ++ cntkctl &= ~((3 << 8) | (3 << 0)); + + asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); + } +diff -Nur linux-3.10.30/arch/arm/include/asm/bL_switcher.h linux-3.10.30-cubox-i/arch/arm/include/asm/bL_switcher.h +--- linux-3.10.30/arch/arm/include/asm/bL_switcher.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/bL_switcher.h 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,83 @@ ++/* ++ * arch/arm/include/asm/bL_switcher.h ++ * ++ * Created by: Nicolas Pitre, April 2012 ++ * Copyright: (C) 2012 Linaro Limited ++ * ++ * This program 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_BL_SWITCHER_H ++#define ASM_BL_SWITCHER_H ++ ++#include ++#include ++ ++typedef void (*bL_switch_completion_handler)(void *cookie); ++ ++int bL_switch_request_cb(unsigned int cpu, unsigned int new_cluster_id, ++ bL_switch_completion_handler completer, ++ void *completer_cookie); ++static inline int bL_switch_request(unsigned int cpu, unsigned int new_cluster_id) ++{ ++ return bL_switch_request_cb(cpu, new_cluster_id, NULL, NULL); ++} ++ ++/* ++ * Register here to be notified about runtime enabling/disabling of ++ * the switcher. ++ * ++ * The notifier chain is called with the switcher activation lock held: ++ * the switcher will not be enabled or disabled during callbacks. ++ * Callbacks must not call bL_switcher_{get,put}_enabled(). ++ */ ++#define BL_NOTIFY_PRE_ENABLE 0 ++#define BL_NOTIFY_POST_ENABLE 1 ++#define BL_NOTIFY_PRE_DISABLE 2 ++#define BL_NOTIFY_POST_DISABLE 3 ++ ++#ifdef CONFIG_BL_SWITCHER ++ ++void bL_switch_request_detach(unsigned int cpu, ++ bL_switch_completion_handler completer); ++ ++int bL_switcher_register_notifier(struct notifier_block *nb); ++int bL_switcher_unregister_notifier(struct notifier_block *nb); ++ ++/* ++ * Use these functions to temporarily prevent enabling/disabling of ++ * the switcher. ++ * bL_switcher_get_enabled() returns true if the switcher is currently ++ * enabled. Each call to bL_switcher_get_enabled() must be followed ++ * by a call to bL_switcher_put_enabled(). These functions are not ++ * recursive. ++ */ ++bool bL_switcher_get_enabled(void); ++void bL_switcher_put_enabled(void); ++ ++int bL_switcher_trace_trigger(void); ++int bL_switcher_get_logical_index(u32 mpidr); ++ ++#else ++static void bL_switch_request_detach(unsigned int cpu, ++ bL_switch_completion_handler completer) { } ++ ++static inline int bL_switcher_register_notifier(struct notifier_block *nb) ++{ ++ return 0; ++} ++ ++static inline int bL_switcher_unregister_notifier(struct notifier_block *nb) ++{ ++ return 0; ++} ++ ++static inline bool bL_switcher_get_enabled(void) { return false; } ++static inline void bL_switcher_put_enabled(void) { } ++static inline int bL_switcher_trace_trigger(void) { return 0; } ++static inline int bL_switcher_get_logical_index(u32 mpidr) { return -EUNATCH; } ++#endif /* CONFIG_BL_SWITCHER */ ++ ++#endif +diff -Nur linux-3.10.30/arch/arm/include/asm/cacheflush.h linux-3.10.30-cubox-i/arch/arm/include/asm/cacheflush.h +--- linux-3.10.30/arch/arm/include/asm/cacheflush.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/cacheflush.h 2014-03-08 20:32:53.000000000 +0100 +@@ -436,4 +436,50 @@ + #define sync_cache_w(ptr) __sync_cache_range_w(ptr, sizeof *(ptr)) + #define sync_cache_r(ptr) __sync_cache_range_r(ptr, sizeof *(ptr)) + ++/* ++ * Disabling cache access for one CPU in an ARMv7 SMP system is tricky. ++ * To do so we must: ++ * ++ * - Clear the SCTLR.C bit to prevent further cache allocations ++ * - Flush the desired level of cache ++ * - Clear the ACTLR "SMP" bit to disable local coherency ++ * ++ * ... and so without any intervening memory access in between those steps, ++ * not even to the stack. ++ * ++ * WARNING -- After this has been called: ++ * ++ * - No ldrex/strex (and similar) instructions must be used. ++ * - The CPU is obviously no longer coherent with the other CPUs. ++ * - This is unlikely to work as expected if Linux is running non-secure. ++ * ++ * Note: ++ * ++ * - This is known to apply to several ARMv7 processor implementations, ++ * however some exceptions may exist. Caveat emptor. ++ * ++ * - The clobber list is dictated by the call to v7_flush_dcache_*. ++ * fp is preserved to the stack explicitly prior disabling the cache ++ * since adding it to the clobber list is incompatible with having ++ * CONFIG_FRAME_POINTER=y. ip is saved as well if ever r12-clobbering ++ * trampoline are inserted by the linker and to keep sp 64-bit aligned. ++ */ ++#define v7_exit_coherency_flush(level) \ ++ asm volatile( \ ++ "stmfd sp!, {fp, ip} \n\t" \ ++ "mrc p15, 0, r0, c1, c0, 0 @ get SCTLR \n\t" \ ++ "bic r0, r0, #"__stringify(CR_C)" \n\t" \ ++ "mcr p15, 0, r0, c1, c0, 0 @ set SCTLR \n\t" \ ++ "isb \n\t" \ ++ "bl v7_flush_dcache_"__stringify(level)" \n\t" \ ++ "clrex \n\t" \ ++ "mrc p15, 0, r0, c1, c0, 1 @ get ACTLR \n\t" \ ++ "bic r0, r0, #(1 << 6) @ disable local coherency \n\t" \ ++ "mcr p15, 0, r0, c1, c0, 1 @ set ACTLR \n\t" \ ++ "isb \n\t" \ ++ "dsb \n\t" \ ++ "ldmfd sp!, {fp, ip}" \ ++ : : : "r0","r1","r2","r3","r4","r5","r6","r7", \ ++ "r9","r10","lr","memory" ) ++ + #endif +diff -Nur linux-3.10.30/arch/arm/include/asm/cp15.h linux-3.10.30-cubox-i/arch/arm/include/asm/cp15.h +--- linux-3.10.30/arch/arm/include/asm/cp15.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/cp15.h 2014-03-08 20:32:53.000000000 +0100 +@@ -61,6 +61,20 @@ + isb(); + } + ++static inline unsigned int get_auxcr(void) ++{ ++ unsigned int val; ++ asm("mrc p15, 0, %0, c1, c0, 1 @ get AUXCR" : "=r" (val)); ++ return val; ++} ++ ++static inline void set_auxcr(unsigned int val) ++{ ++ asm volatile("mcr p15, 0, %0, c1, c0, 1 @ set AUXCR" ++ : : "r" (val)); ++ isb(); ++} ++ + #ifndef CONFIG_SMP + extern void adjust_cr(unsigned long mask, unsigned long set); + #endif +diff -Nur linux-3.10.30/arch/arm/include/asm/glue-cache.h linux-3.10.30-cubox-i/arch/arm/include/asm/glue-cache.h +--- linux-3.10.30/arch/arm/include/asm/glue-cache.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/glue-cache.h 2014-03-08 20:32:53.000000000 +0100 +@@ -102,19 +102,19 @@ + #endif + + #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) +-# ifdef _CACHE ++//# ifdef _CACHE + # define MULTI_CACHE 1 +-# else +-# define _CACHE v6 +-# endif ++//# else ++//# define _CACHE v6 ++//# endif + #endif + + #if defined(CONFIG_CPU_V7) +-# ifdef _CACHE ++//# ifdef _CACHE + # define MULTI_CACHE 1 +-# else +-# define _CACHE v7 +-# endif ++//# else ++//# define _CACHE v7 ++//# endif + #endif + + #if !defined(_CACHE) && !defined(MULTI_CACHE) +diff -Nur linux-3.10.30/arch/arm/include/asm/hardirq.h linux-3.10.30-cubox-i/arch/arm/include/asm/hardirq.h +--- linux-3.10.30/arch/arm/include/asm/hardirq.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/hardirq.h 2014-03-08 20:32:53.000000000 +0100 +@@ -5,7 +5,7 @@ + #include + #include + +-#define NR_IPI 6 ++#define NR_IPI 7 + + typedef struct { + unsigned int __softirq_pending; +diff -Nur linux-3.10.30/arch/arm/include/asm/mach/arch.h linux-3.10.30-cubox-i/arch/arm/include/asm/mach/arch.h +--- linux-3.10.30/arch/arm/include/asm/mach/arch.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/mach/arch.h 2014-03-08 20:32:53.000000000 +0100 +@@ -8,6 +8,8 @@ + * published by the Free Software Foundation. + */ + ++#include ++ + #ifndef __ASSEMBLY__ + + struct tag; +@@ -16,8 +18,10 @@ + struct smp_operations; + #ifdef CONFIG_SMP + #define smp_ops(ops) (&(ops)) ++#define smp_init_ops(ops) (&(ops)) + #else + #define smp_ops(ops) (struct smp_operations *)NULL ++#define smp_init_ops(ops) (bool (*)(void))NULL + #endif + + struct machine_desc { +@@ -41,6 +45,7 @@ + unsigned char reserve_lp2 :1; /* never has lp2 */ + char restart_mode; /* default restart mode */ + struct smp_operations *smp; /* SMP operations */ ++ bool (*smp_init)(void); + void (*fixup)(struct tag *, char **, + struct meminfo *); + void (*reserve)(void);/* reserve mem blocks */ +diff -Nur linux-3.10.30/arch/arm/include/asm/mach/pci.h linux-3.10.30-cubox-i/arch/arm/include/asm/mach/pci.h +--- linux-3.10.30/arch/arm/include/asm/mach/pci.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/mach/pci.h 2014-03-08 20:32:53.000000000 +0100 +@@ -35,6 +35,8 @@ + resource_size_t start, + resource_size_t size, + resource_size_t align); ++ void (*add_bus)(struct pci_bus *bus); ++ void (*remove_bus)(struct pci_bus *bus); + }; + + /* +@@ -62,6 +64,8 @@ + resource_size_t start, + resource_size_t size, + resource_size_t align); ++ void (*add_bus)(struct pci_bus *bus); ++ void (*remove_bus)(struct pci_bus *bus); + void *private_data; /* platform controller private data */ + }; + +@@ -96,9 +100,4 @@ + extern int via82c505_setup(int nr, struct pci_sys_data *); + extern void via82c505_init(void *sysdata); + +-extern struct pci_ops pci_v3_ops; +-extern int pci_v3_setup(int nr, struct pci_sys_data *); +-extern void pci_v3_preinit(void); +-extern void pci_v3_postinit(void); +- + #endif /* __ASM_MACH_PCI_H */ +diff -Nur linux-3.10.30/arch/arm/include/asm/mcpm.h linux-3.10.30-cubox-i/arch/arm/include/asm/mcpm.h +--- linux-3.10.30/arch/arm/include/asm/mcpm.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/mcpm.h 2014-03-08 20:32:53.000000000 +0100 +@@ -42,6 +42,14 @@ + void mcpm_set_entry_vector(unsigned cpu, unsigned cluster, void *ptr); + + /* ++ * This sets an early poke i.e a value to be poked into some address ++ * from very early assembly code before the CPU is ungated. The ++ * address must be physical, and if 0 then nothing will happen. ++ */ ++void mcpm_set_early_poke(unsigned cpu, unsigned cluster, ++ unsigned long poke_phys_addr, unsigned long poke_val); ++ ++/* + * CPU/cluster power operations API for higher subsystems to use. + */ + +diff -Nur linux-3.10.30/arch/arm/include/asm/pmu.h linux-3.10.30-cubox-i/arch/arm/include/asm/pmu.h +--- linux-3.10.30/arch/arm/include/asm/pmu.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/pmu.h 2014-03-08 20:32:53.000000000 +0100 +@@ -62,9 +62,19 @@ + raw_spinlock_t pmu_lock; + }; + ++struct cpupmu_regs { ++ u32 pmc; ++ u32 pmcntenset; ++ u32 pmuseren; ++ u32 pmintenset; ++ u32 pmxevttype[8]; ++ u32 pmxevtcnt[8]; ++}; ++ + struct arm_pmu { + struct pmu pmu; + cpumask_t active_irqs; ++ cpumask_t valid_cpus; + char *name; + irqreturn_t (*handle_irq)(int irq_num, void *dev); + void (*enable)(struct perf_event *event); +@@ -81,6 +91,8 @@ + int (*request_irq)(struct arm_pmu *, irq_handler_t handler); + void (*free_irq)(struct arm_pmu *); + int (*map_event)(struct perf_event *event); ++ void (*save_regs)(struct arm_pmu *, struct cpupmu_regs *); ++ void (*restore_regs)(struct arm_pmu *, struct cpupmu_regs *); + int num_events; + atomic_t active_events; + struct mutex reserve_mutex; +diff -Nur linux-3.10.30/arch/arm/include/asm/psci.h linux-3.10.30-cubox-i/arch/arm/include/asm/psci.h +--- linux-3.10.30/arch/arm/include/asm/psci.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/psci.h 2014-03-08 20:32:53.000000000 +0100 +@@ -16,6 +16,10 @@ + + #define PSCI_POWER_STATE_TYPE_STANDBY 0 + #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 ++#define PSCI_POWER_STATE_AFFINITY_LEVEL0 0 ++#define PSCI_POWER_STATE_AFFINITY_LEVEL1 1 ++#define PSCI_POWER_STATE_AFFINITY_LEVEL2 2 ++#define PSCI_POWER_STATE_AFFINITY_LEVEL3 3 + + struct psci_power_state { + u16 id; +@@ -32,5 +36,22 @@ + }; + + extern struct psci_operations psci_ops; ++extern struct smp_operations psci_smp_ops; + ++#ifdef CONFIG_ARM_PSCI ++void psci_init(void); ++bool psci_smp_available(void); ++#else ++static inline void psci_init(void) { } ++static inline bool psci_smp_available(void) { return false; } ++#endif ++ ++#ifdef CONFIG_ARM_PSCI ++extern int __init psci_probe(void); ++#else ++static inline int psci_probe(void) ++{ ++ return -ENODEV; ++} ++#endif + #endif /* __ASM_ARM_PSCI_H */ +diff -Nur linux-3.10.30/arch/arm/include/asm/smp.h linux-3.10.30-cubox-i/arch/arm/include/asm/smp.h +--- linux-3.10.30/arch/arm/include/asm/smp.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/smp.h 2014-03-08 20:32:53.000000000 +0100 +@@ -81,6 +81,8 @@ + extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); + extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask); + ++extern int register_ipi_completion(struct completion *completion, int cpu); ++ + struct smp_operations { + #ifdef CONFIG_SMP + /* +diff -Nur linux-3.10.30/arch/arm/include/asm/topology.h linux-3.10.30-cubox-i/arch/arm/include/asm/topology.h +--- linux-3.10.30/arch/arm/include/asm/topology.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/asm/topology.h 2014-03-08 20:32:53.000000000 +0100 +@@ -26,11 +26,45 @@ + void init_cpu_topology(void); + void store_cpu_topology(unsigned int cpuid); + const struct cpumask *cpu_coregroup_mask(int cpu); ++int cluster_to_logical_mask(unsigned int socket_id, cpumask_t *cluster_mask); ++ ++#ifdef CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE ++/* Common values for CPUs */ ++#ifndef SD_CPU_INIT ++#define SD_CPU_INIT (struct sched_domain) { \ ++ .min_interval = 1, \ ++ .max_interval = 4, \ ++ .busy_factor = 64, \ ++ .imbalance_pct = 125, \ ++ .cache_nice_tries = 1, \ ++ .busy_idx = 2, \ ++ .idle_idx = 1, \ ++ .newidle_idx = 0, \ ++ .wake_idx = 0, \ ++ .forkexec_idx = 0, \ ++ \ ++ .flags = 0*SD_LOAD_BALANCE \ ++ | 1*SD_BALANCE_NEWIDLE \ ++ | 1*SD_BALANCE_EXEC \ ++ | 1*SD_BALANCE_FORK \ ++ | 0*SD_BALANCE_WAKE \ ++ | 1*SD_WAKE_AFFINE \ ++ | 0*SD_SHARE_CPUPOWER \ ++ | 0*SD_SHARE_PKG_RESOURCES \ ++ | 0*SD_SERIALIZE \ ++ , \ ++ .last_balance = jiffies, \ ++ .balance_interval = 1, \ ++} ++#endif ++#endif /* CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE */ + + #else + + static inline void init_cpu_topology(void) { } + static inline void store_cpu_topology(unsigned int cpuid) { } ++static inline int cluster_to_logical_mask(unsigned int socket_id, ++ cpumask_t *cluster_mask) { return -EINVAL; } + + #endif + +diff -Nur linux-3.10.30/arch/arm/include/debug/imx-uart.h linux-3.10.30-cubox-i/arch/arm/include/debug/imx-uart.h +--- linux-3.10.30/arch/arm/include/debug/imx-uart.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/debug/imx-uart.h 2014-03-08 20:32:53.000000000 +0100 +@@ -65,6 +65,14 @@ + #define IMX6Q_UART_BASE_ADDR(n) IMX6Q_UART##n##_BASE_ADDR + #define IMX6Q_UART_BASE(n) IMX6Q_UART_BASE_ADDR(n) + ++#define IMX6SL_UART1_BASE_ADDR 0x02020000 ++#define IMX6SL_UART2_BASE_ADDR 0x02024000 ++#define IMX6SL_UART3_BASE_ADDR 0x02034000 ++#define IMX6SL_UART4_BASE_ADDR 0x02038000 ++#define IMX6SL_UART5_BASE_ADDR 0x02018000 ++#define IMX6SL_UART_BASE_ADDR(n) IMX6SL_UART##n##_BASE_ADDR ++#define IMX6SL_UART_BASE(n) IMX6SL_UART_BASE_ADDR(n) ++ + #define IMX_DEBUG_UART_BASE(soc) soc##_UART_BASE(CONFIG_DEBUG_IMX_UART_PORT) + + #ifdef CONFIG_DEBUG_IMX1_UART +@@ -83,6 +91,8 @@ + #define UART_PADDR IMX_DEBUG_UART_BASE(IMX53) + #elif defined(CONFIG_DEBUG_IMX6Q_UART) + #define UART_PADDR IMX_DEBUG_UART_BASE(IMX6Q) ++#elif defined(CONFIG_DEBUG_IMX6SL_UART) ++#define UART_PADDR IMX_DEBUG_UART_BASE(IMX6SL) + #endif + + #endif /* __DEBUG_IMX_UART_H */ +diff -Nur linux-3.10.30/arch/arm/include/debug/vf.S linux-3.10.30-cubox-i/arch/arm/include/debug/vf.S +--- linux-3.10.30/arch/arm/include/debug/vf.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/include/debug/vf.S 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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. ++ * ++ */ ++ ++ .macro addruart, rp, rv, tmp ++ ldr \rp, =0x40028000 @ physical ++ ldr \rv, =0xfe028000 @ virtual ++ .endm ++ ++ .macro senduart, rd, rx ++ strb \rd, [\rx, #0x7] @ Data Register ++ .endm ++ ++ .macro busyuart, rd, rx ++1001: ldrb \rd, [\rx, #0x4] @ Status Register 1 ++ tst \rd, #1 << 6 @ TC ++ beq 1001b @ wait until transmit done ++ .endm ++ ++ .macro waituart,rd,rx ++ .endm +diff -Nur linux-3.10.30/arch/arm/kernel/Makefile linux-3.10.30-cubox-i/arch/arm/kernel/Makefile +--- linux-3.10.30/arch/arm/kernel/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/Makefile 2014-03-08 20:32:53.000000000 +0100 +@@ -82,6 +82,9 @@ + obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + + obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o +-obj-$(CONFIG_ARM_PSCI) += psci.o ++ifeq ($(CONFIG_ARM_PSCI),y) ++obj-y += psci.o ++obj-$(CONFIG_SMP) += psci_smp.o ++endif + + extra-y := $(head-y) vmlinux.lds +diff -Nur linux-3.10.30/arch/arm/kernel/bios32.c linux-3.10.30-cubox-i/arch/arm/kernel/bios32.c +--- linux-3.10.30/arch/arm/kernel/bios32.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/bios32.c 2014-03-08 20:32:53.000000000 +0100 +@@ -363,6 +363,20 @@ + } + EXPORT_SYMBOL(pcibios_fixup_bus); + ++void pcibios_add_bus(struct pci_bus *bus) ++{ ++ struct pci_sys_data *sys = bus->sysdata; ++ if (sys->add_bus) ++ sys->add_bus(bus); ++} ++ ++void pcibios_remove_bus(struct pci_bus *bus) ++{ ++ struct pci_sys_data *sys = bus->sysdata; ++ if (sys->remove_bus) ++ sys->remove_bus(bus); ++} ++ + /* + * Swizzle the device pin each time we cross a bridge. If a platform does + * not provide a swizzle function, we perform the standard PCI swizzling. +@@ -463,6 +477,8 @@ + sys->swizzle = hw->swizzle; + sys->map_irq = hw->map_irq; + sys->align_resource = hw->align_resource; ++ sys->add_bus = hw->add_bus; ++ sys->remove_bus = hw->remove_bus; + INIT_LIST_HEAD(&sys->resources); + + if (hw->private_data) +diff -Nur linux-3.10.30/arch/arm/kernel/head.S linux-3.10.30-cubox-i/arch/arm/kernel/head.S +--- linux-3.10.30/arch/arm/kernel/head.S 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/head.S 2014-03-08 20:32:53.000000000 +0100 +@@ -342,7 +342,6 @@ + .long __turn_mmu_on_end + + #if defined(CONFIG_SMP) +- __CPUINIT + ENTRY(secondary_startup) + /* + * Common entry point for secondary CPUs. +diff -Nur linux-3.10.30/arch/arm/kernel/hw_breakpoint.c linux-3.10.30-cubox-i/arch/arm/kernel/hw_breakpoint.c +--- linux-3.10.30/arch/arm/kernel/hw_breakpoint.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/hw_breakpoint.c 2014-03-08 20:32:53.000000000 +0100 +@@ -1049,7 +1049,8 @@ + + static void __init pm_init(void) + { +- cpu_pm_register_notifier(&dbg_cpu_pm_nb); ++ if (has_ossr) ++ cpu_pm_register_notifier(&dbg_cpu_pm_nb); + } + #else + static inline void pm_init(void) +diff -Nur linux-3.10.30/arch/arm/kernel/perf_event.c linux-3.10.30-cubox-i/arch/arm/kernel/perf_event.c +--- linux-3.10.30/arch/arm/kernel/perf_event.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/perf_event.c 2014-03-08 20:32:53.000000000 +0100 +@@ -12,6 +12,7 @@ + */ + #define pr_fmt(fmt) "hw perfevents: " fmt + ++#include + #include + #include + #include +@@ -86,6 +87,9 @@ + return armpmu_map_cache_event(cache_map, config); + case PERF_TYPE_RAW: + return armpmu_map_raw_event(raw_event_mask, config); ++ default: ++ if (event->attr.type >= PERF_TYPE_MAX) ++ return armpmu_map_raw_event(raw_event_mask, config); + } + + return -ENOENT; +@@ -163,6 +167,8 @@ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + ++ if (!cpumask_test_cpu(smp_processor_id(), &armpmu->valid_cpus)) ++ return; + /* + * ARM pmu always has to update the counter, so ignore + * PERF_EF_UPDATE, see comments in armpmu_start(). +@@ -179,6 +185,8 @@ + struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + ++ if (!cpumask_test_cpu(smp_processor_id(), &armpmu->valid_cpus)) ++ return; + /* + * ARM pmu always has to reprogram the period, so ignore + * PERF_EF_RELOAD, see the comment below. +@@ -206,6 +214,9 @@ + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + ++ if (!cpumask_test_cpu(smp_processor_id(), &armpmu->valid_cpus)) ++ return; ++ + armpmu_stop(event, PERF_EF_UPDATE); + hw_events->events[idx] = NULL; + clear_bit(idx, hw_events->used_mask); +@@ -222,6 +233,10 @@ + int idx; + int err = 0; + ++ /* An event following a process won't be stopped earlier */ ++ if (!cpumask_test_cpu(smp_processor_id(), &armpmu->valid_cpus)) ++ return 0; ++ + perf_pmu_disable(event->pmu); + + /* If we don't have a space for the counter then finish early. */ +@@ -424,6 +439,10 @@ + int err = 0; + atomic_t *active_events = &armpmu->active_events; + ++ if (event->cpu != -1 && ++ !cpumask_test_cpu(event->cpu, &armpmu->valid_cpus)) ++ return -ENOENT; ++ + /* does not support taken branch sampling */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; +diff -Nur linux-3.10.30/arch/arm/kernel/perf_event_cpu.c linux-3.10.30-cubox-i/arch/arm/kernel/perf_event_cpu.c +--- linux-3.10.30/arch/arm/kernel/perf_event_cpu.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/perf_event_cpu.c 2014-03-08 20:32:53.000000000 +0100 +@@ -19,6 +19,7 @@ + #define pr_fmt(fmt) "CPU PMU: " fmt + + #include ++#include + #include + #include + #include +@@ -31,33 +32,36 @@ + #include + + /* Set at runtime when we know what CPU type we are. */ +-static struct arm_pmu *cpu_pmu; ++static DEFINE_PER_CPU(struct arm_pmu *, cpu_pmu); + + static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events); + static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask); + static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events); + ++static DEFINE_PER_CPU(struct cpupmu_regs, cpu_pmu_regs); ++ + /* + * Despite the names, these two functions are CPU-specific and are used + * by the OProfile/perf code. + */ + const char *perf_pmu_name(void) + { +- if (!cpu_pmu) ++ struct arm_pmu *pmu = per_cpu(cpu_pmu, 0); ++ if (!pmu) + return NULL; + +- return cpu_pmu->name; ++ return pmu->name; + } + EXPORT_SYMBOL_GPL(perf_pmu_name); + + int perf_num_counters(void) + { +- int max_events = 0; ++ struct arm_pmu *pmu = per_cpu(cpu_pmu, 0); + +- if (cpu_pmu != NULL) +- max_events = cpu_pmu->num_events; ++ if (!pmu) ++ return 0; + +- return max_events; ++ return pmu->num_events; + } + EXPORT_SYMBOL_GPL(perf_num_counters); + +@@ -75,11 +79,13 @@ + { + int i, irq, irqs; + struct platform_device *pmu_device = cpu_pmu->plat_device; ++ int cpu = -1; + + irqs = min(pmu_device->num_resources, num_possible_cpus()); + + for (i = 0; i < irqs; ++i) { +- if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs)) ++ cpu = cpumask_next(cpu, &cpu_pmu->valid_cpus); ++ if (!cpumask_test_and_clear_cpu(cpu, &cpu_pmu->active_irqs)) + continue; + irq = platform_get_irq(pmu_device, i); + if (irq >= 0) +@@ -91,6 +97,7 @@ + { + int i, err, irq, irqs; + struct platform_device *pmu_device = cpu_pmu->plat_device; ++ int cpu = -1; + + if (!pmu_device) + return -ENODEV; +@@ -103,6 +110,7 @@ + + for (i = 0; i < irqs; ++i) { + err = 0; ++ cpu = cpumask_next(cpu, &cpu_pmu->valid_cpus); + irq = platform_get_irq(pmu_device, i); + if (irq < 0) + continue; +@@ -112,7 +120,7 @@ + * assume that we're running on a uniprocessor machine and + * continue. Otherwise, continue without this interrupt. + */ +- if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { ++ if (irq_set_affinity(irq, cpumask_of(cpu)) && irqs > 1) { + pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", + irq, i); + continue; +@@ -126,7 +134,7 @@ + return err; + } + +- cpumask_set_cpu(i, &cpu_pmu->active_irqs); ++ cpumask_set_cpu(cpu, &cpu_pmu->active_irqs); + } + + return 0; +@@ -135,7 +143,7 @@ + static void cpu_pmu_init(struct arm_pmu *cpu_pmu) + { + int cpu; +- for_each_possible_cpu(cpu) { ++ for_each_cpu_mask(cpu, cpu_pmu->valid_cpus) { + struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu); + events->events = per_cpu(hw_events, cpu); + events->used_mask = per_cpu(used_mask, cpu); +@@ -148,7 +156,7 @@ + + /* Ensure the PMU has sane values out of reset. */ + if (cpu_pmu->reset) +- on_each_cpu(cpu_pmu->reset, cpu_pmu, 1); ++ on_each_cpu_mask(&cpu_pmu->valid_cpus, cpu_pmu->reset, cpu_pmu, 1); + } + + /* +@@ -160,21 +168,46 @@ + static int __cpuinit cpu_pmu_notify(struct notifier_block *b, + unsigned long action, void *hcpu) + { ++ struct arm_pmu *pmu = per_cpu(cpu_pmu, (long)hcpu); ++ + if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) + return NOTIFY_DONE; + +- if (cpu_pmu && cpu_pmu->reset) +- cpu_pmu->reset(cpu_pmu); ++ if (pmu && pmu->reset) ++ pmu->reset(pmu); + else + return NOTIFY_DONE; + + return NOTIFY_OK; + } + ++static int cpu_pmu_pm_notify(struct notifier_block *b, ++ unsigned long action, void *hcpu) ++{ ++ int cpu = smp_processor_id(); ++ struct arm_pmu *pmu = per_cpu(cpu_pmu, cpu); ++ struct cpupmu_regs *pmuregs = &per_cpu(cpu_pmu_regs, cpu); ++ ++ if (!pmu) ++ return NOTIFY_DONE; ++ ++ if (action == CPU_PM_ENTER && pmu->save_regs) { ++ pmu->save_regs(pmu, pmuregs); ++ } else if (action == CPU_PM_EXIT && pmu->restore_regs) { ++ pmu->restore_regs(pmu, pmuregs); ++ } ++ ++ return NOTIFY_OK; ++} ++ + static struct notifier_block __cpuinitdata cpu_pmu_hotplug_notifier = { + .notifier_call = cpu_pmu_notify, + }; + ++static struct notifier_block __cpuinitdata cpu_pmu_pm_notifier = { ++ .notifier_call = cpu_pmu_pm_notify, ++}; ++ + /* + * PMU platform driver and devicetree bindings. + */ +@@ -246,6 +279,9 @@ + } + } + ++ /* assume PMU support all the CPUs in this case */ ++ cpumask_setall(&pmu->valid_cpus); ++ + put_cpu(); + return ret; + } +@@ -253,15 +289,10 @@ + static int cpu_pmu_device_probe(struct platform_device *pdev) + { + const struct of_device_id *of_id; +- int (*init_fn)(struct arm_pmu *); + struct device_node *node = pdev->dev.of_node; + struct arm_pmu *pmu; +- int ret = -ENODEV; +- +- if (cpu_pmu) { +- pr_info("attempt to register multiple PMU devices!"); +- return -ENOSPC; +- } ++ int ret = 0; ++ int cpu; + + pmu = kzalloc(sizeof(struct arm_pmu), GFP_KERNEL); + if (!pmu) { +@@ -270,8 +301,28 @@ + } + + if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) { +- init_fn = of_id->data; +- ret = init_fn(pmu); ++ smp_call_func_t init_fn = (smp_call_func_t)of_id->data; ++ struct device_node *ncluster; ++ int cluster = -1; ++ cpumask_t sibling_mask; ++ ++ ncluster = of_parse_phandle(node, "cluster", 0); ++ if (ncluster) { ++ int len; ++ const u32 *hwid; ++ hwid = of_get_property(ncluster, "reg", &len); ++ if (hwid && len == 4) ++ cluster = be32_to_cpup(hwid); ++ } ++ /* set sibling mask to all cpu mask if socket is not specified */ ++ if (cluster == -1 || ++ cluster_to_logical_mask(cluster, &sibling_mask)) ++ cpumask_setall(&sibling_mask); ++ ++ smp_call_function_any(&sibling_mask, init_fn, pmu, 1); ++ ++ /* now set the valid_cpus after init */ ++ cpumask_copy(&pmu->valid_cpus, &sibling_mask); + } else { + ret = probe_current_pmu(pmu); + } +@@ -281,10 +332,12 @@ + goto out_free; + } + +- cpu_pmu = pmu; +- cpu_pmu->plat_device = pdev; +- cpu_pmu_init(cpu_pmu); +- ret = armpmu_register(cpu_pmu, PERF_TYPE_RAW); ++ for_each_cpu_mask(cpu, pmu->valid_cpus) ++ per_cpu(cpu_pmu, cpu) = pmu; ++ ++ pmu->plat_device = pdev; ++ cpu_pmu_init(pmu); ++ ret = armpmu_register(pmu, -1); + + if (!ret) + return 0; +@@ -313,9 +366,17 @@ + if (err) + return err; + ++ err = cpu_pm_register_notifier(&cpu_pmu_pm_notifier); ++ if (err) { ++ unregister_cpu_notifier(&cpu_pmu_hotplug_notifier); ++ return err; ++ } ++ + err = platform_driver_register(&cpu_pmu_driver); +- if (err) ++ if (err) { ++ cpu_pm_unregister_notifier(&cpu_pmu_pm_notifier); + unregister_cpu_notifier(&cpu_pmu_hotplug_notifier); ++ } + + return err; + } +diff -Nur linux-3.10.30/arch/arm/kernel/perf_event_v7.c linux-3.10.30-cubox-i/arch/arm/kernel/perf_event_v7.c +--- linux-3.10.30/arch/arm/kernel/perf_event_v7.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/perf_event_v7.c 2014-03-08 20:32:53.000000000 +0100 +@@ -950,6 +950,51 @@ + } + #endif + ++static void armv7pmu_save_regs(struct arm_pmu *cpu_pmu, ++ struct cpupmu_regs *regs) ++{ ++ unsigned int cnt; ++ asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (regs->pmc)); ++ if (!(regs->pmc & ARMV7_PMNC_E)) ++ return; ++ ++ asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (regs->pmcntenset)); ++ asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r" (regs->pmuseren)); ++ asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (regs->pmintenset)); ++ asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (regs->pmxevtcnt[0])); ++ for (cnt = ARMV7_IDX_COUNTER0; ++ cnt <= ARMV7_IDX_COUNTER_LAST(cpu_pmu); cnt++) { ++ armv7_pmnc_select_counter(cnt); ++ asm volatile("mrc p15, 0, %0, c9, c13, 1" ++ : "=r"(regs->pmxevttype[cnt])); ++ asm volatile("mrc p15, 0, %0, c9, c13, 2" ++ : "=r"(regs->pmxevtcnt[cnt])); ++ } ++ return; ++} ++ ++static void armv7pmu_restore_regs(struct arm_pmu *cpu_pmu, ++ struct cpupmu_regs *regs) ++{ ++ unsigned int cnt; ++ if (!(regs->pmc & ARMV7_PMNC_E)) ++ return; ++ ++ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (regs->pmcntenset)); ++ asm volatile("mcr p15, 0, %0, c9, c14, 0" : : "r" (regs->pmuseren)); ++ asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (regs->pmintenset)); ++ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (regs->pmxevtcnt[0])); ++ for (cnt = ARMV7_IDX_COUNTER0; ++ cnt <= ARMV7_IDX_COUNTER_LAST(cpu_pmu); cnt++) { ++ armv7_pmnc_select_counter(cnt); ++ asm volatile("mcr p15, 0, %0, c9, c13, 1" ++ : : "r"(regs->pmxevttype[cnt])); ++ asm volatile("mcr p15, 0, %0, c9, c13, 2" ++ : : "r"(regs->pmxevtcnt[cnt])); ++ } ++ asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (regs->pmc)); ++} ++ + static void armv7pmu_enable_event(struct perf_event *event) + { + unsigned long flags; +@@ -1223,6 +1268,8 @@ + cpu_pmu->start = armv7pmu_start; + cpu_pmu->stop = armv7pmu_stop; + cpu_pmu->reset = armv7pmu_reset; ++ cpu_pmu->save_regs = armv7pmu_save_regs; ++ cpu_pmu->restore_regs = armv7pmu_restore_regs; + cpu_pmu->max_period = (1LLU << 32) - 1; + }; + +@@ -1240,7 +1287,7 @@ + static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu) + { + armv7pmu_init(cpu_pmu); +- cpu_pmu->name = "ARMv7 Cortex-A8"; ++ cpu_pmu->name = "ARMv7_Cortex_A8"; + cpu_pmu->map_event = armv7_a8_map_event; + cpu_pmu->num_events = armv7_read_num_pmnc_events(); + return 0; +@@ -1249,7 +1296,7 @@ + static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu) + { + armv7pmu_init(cpu_pmu); +- cpu_pmu->name = "ARMv7 Cortex-A9"; ++ cpu_pmu->name = "ARMv7_Cortex_A9"; + cpu_pmu->map_event = armv7_a9_map_event; + cpu_pmu->num_events = armv7_read_num_pmnc_events(); + return 0; +@@ -1258,7 +1305,7 @@ + static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu) + { + armv7pmu_init(cpu_pmu); +- cpu_pmu->name = "ARMv7 Cortex-A5"; ++ cpu_pmu->name = "ARMv7_Cortex_A5"; + cpu_pmu->map_event = armv7_a5_map_event; + cpu_pmu->num_events = armv7_read_num_pmnc_events(); + return 0; +@@ -1267,7 +1314,7 @@ + static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu) + { + armv7pmu_init(cpu_pmu); +- cpu_pmu->name = "ARMv7 Cortex-A15"; ++ cpu_pmu->name = "ARMv7_Cortex_A15"; + cpu_pmu->map_event = armv7_a15_map_event; + cpu_pmu->num_events = armv7_read_num_pmnc_events(); + cpu_pmu->set_event_filter = armv7pmu_set_event_filter; +@@ -1277,7 +1324,7 @@ + static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) + { + armv7pmu_init(cpu_pmu); +- cpu_pmu->name = "ARMv7 Cortex-A7"; ++ cpu_pmu->name = "ARMv7_Cortex_A7"; + cpu_pmu->map_event = armv7_a7_map_event; + cpu_pmu->num_events = armv7_read_num_pmnc_events(); + cpu_pmu->set_event_filter = armv7pmu_set_event_filter; +diff -Nur linux-3.10.30/arch/arm/kernel/process.c linux-3.10.30-cubox-i/arch/arm/kernel/process.c +--- linux-3.10.30/arch/arm/kernel/process.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/process.c 2014-03-08 20:32:53.000000000 +0100 +@@ -170,8 +170,10 @@ + */ + void arch_cpu_idle(void) + { ++ idle_notifier_call_chain(IDLE_START); + if (cpuidle_idle_call()) + default_idle(); ++ idle_notifier_call_chain(IDLE_END); + } + + static char reboot_mode = 'h'; +diff -Nur linux-3.10.30/arch/arm/kernel/psci.c linux-3.10.30-cubox-i/arch/arm/kernel/psci.c +--- linux-3.10.30/arch/arm/kernel/psci.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/psci.c 2014-03-08 20:32:53.000000000 +0100 +@@ -17,6 +17,7 @@ + + #include + #include ++#include + + #include + #include +@@ -26,6 +27,11 @@ + + struct psci_operations psci_ops; + ++/* Type of psci support. Currently can only be enabled or disabled */ ++#define PSCI_SUP_DISABLED 0 ++#define PSCI_SUP_ENABLED 1 ++ ++static unsigned int psci; + static int (*invoke_psci_fn)(u32, u32, u32, u32); + + enum psci_function { +@@ -42,6 +48,7 @@ + #define PSCI_RET_EOPNOTSUPP -1 + #define PSCI_RET_EINVAL -2 + #define PSCI_RET_EPERM -3 ++#define PSCI_RET_EALREADYON -4 + + static int psci_to_linux_errno(int errno) + { +@@ -54,6 +61,8 @@ + return -EINVAL; + case PSCI_RET_EPERM: + return -EPERM; ++ case PSCI_RET_EALREADYON: ++ return -EAGAIN; + }; + + return -EINVAL; +@@ -158,15 +167,18 @@ + {}, + }; + +-static int __init psci_init(void) ++void __init psci_init(void) + { + struct device_node *np; + const char *method; + u32 id; + ++ if (psci == PSCI_SUP_DISABLED) ++ return; ++ + np = of_find_matching_node(NULL, psci_of_match); + if (!np) +- return 0; ++ return; + + pr_info("probing function IDs from device-tree\n"); + +@@ -206,6 +218,35 @@ + + out_put_node: + of_node_put(np); +- return 0; ++ return; ++} ++ ++int __init psci_probe(void) ++{ ++ struct device_node *np; ++ int ret = -ENODEV; ++ ++ if (psci == PSCI_SUP_ENABLED) { ++ np = of_find_matching_node(NULL, psci_of_match); ++ if (np) ++ ret = 0; ++ } ++ ++ of_node_put(np); ++ return ret; ++} ++ ++static int __init early_psci(char *val) ++{ ++ int ret = 0; ++ ++ if (strcmp(val, "enable") == 0) ++ psci = PSCI_SUP_ENABLED; ++ else if (strcmp(val, "disable") == 0) ++ psci = PSCI_SUP_DISABLED; ++ else ++ ret = -EINVAL; ++ ++ return ret; + } +-early_initcall(psci_init); ++early_param("psci", early_psci); +diff -Nur linux-3.10.30/arch/arm/kernel/psci_smp.c linux-3.10.30-cubox-i/arch/arm/kernel/psci_smp.c +--- linux-3.10.30/arch/arm/kernel/psci_smp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/psci_smp.c 2014-03-08 20:32:53.000000000 +0100 +@@ -0,0 +1,84 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * Copyright (C) 2012 ARM Limited ++ * ++ * Author: Will Deacon ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* ++ * psci_smp assumes that the following is true about PSCI: ++ * ++ * cpu_suspend Suspend the execution on a CPU ++ * @state we don't currently describe affinity levels, so just pass 0. ++ * @entry_point the first instruction to be executed on return ++ * returns 0 success, < 0 on failure ++ * ++ * cpu_off Power down a CPU ++ * @state we don't currently describe affinity levels, so just pass 0. ++ * no return on successful call ++ * ++ * cpu_on Power up a CPU ++ * @cpuid cpuid of target CPU, as from MPIDR ++ * @entry_point the first instruction to be executed on return ++ * returns 0 success, < 0 on failure ++ * ++ * migrate Migrate the context to a different CPU ++ * @cpuid cpuid of target CPU, as from MPIDR ++ * returns 0 success, < 0 on failure ++ * ++ */ ++ ++extern void secondary_startup(void); ++ ++static int __cpuinit psci_boot_secondary(unsigned int cpu, ++ struct task_struct *idle) ++{ ++ if (psci_ops.cpu_on) ++ return psci_ops.cpu_on(cpu_logical_map(cpu), ++ __pa(secondary_startup)); ++ return -ENODEV; ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++void __ref psci_cpu_die(unsigned int cpu) ++{ ++ const struct psci_power_state ps = { ++ .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, ++ }; ++ ++ if (psci_ops.cpu_off) ++ psci_ops.cpu_off(ps); ++ ++ /* We should never return */ ++ panic("psci: cpu %d failed to shutdown\n", cpu); ++} ++#else ++#define psci_cpu_die NULL ++#endif ++ ++bool __init psci_smp_available(void) ++{ ++ /* is cpu_on available at least? */ ++ return (psci_ops.cpu_on != NULL); ++} ++ ++struct smp_operations __initdata psci_smp_ops = { ++ .smp_boot_secondary = psci_boot_secondary, ++ .cpu_die = psci_cpu_die, ++}; +diff -Nur linux-3.10.30/arch/arm/kernel/setup.c linux-3.10.30-cubox-i/arch/arm/kernel/setup.c +--- linux-3.10.30/arch/arm/kernel/setup.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/setup.c 2014-03-08 20:32:53.000000000 +0100 +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -261,6 +262,19 @@ + int aliasing_icache; + unsigned int id_reg, num_sets, line_size; + ++#ifdef CONFIG_BIG_LITTLE ++ /* ++ * We expect a combination of Cortex-A15 and Cortex-A7 cores. ++ * A7 = VIPT aliasing I-cache ++ * A15 = PIPT (non-aliasing) I-cache ++ * To cater for this discrepancy, let's assume aliasing I-cache ++ * all the time. This means unneeded extra work on the A15 but ++ * only ptrace is affected which is not performance critical. ++ */ ++ if ((read_cpuid_id() & 0xff0ffff0) == 0x410fc0f0) ++ return 1; ++#endif ++ + /* PIPT caches never alias. */ + if (icache_is_pipt()) + return 0; +@@ -796,9 +810,15 @@ + unflatten_device_tree(); + + arm_dt_init_cpu_maps(); ++ psci_init(); + #ifdef CONFIG_SMP + if (is_smp()) { +- smp_set_ops(mdesc->smp); ++ if (!mdesc->smp_init || !mdesc->smp_init()) { ++ if (psci_smp_available()) ++ smp_set_ops(&psci_smp_ops); ++ else if (mdesc->smp) ++ smp_set_ops(mdesc->smp); ++ } + smp_init_cpus(); + } + #endif +diff -Nur linux-3.10.30/arch/arm/kernel/sleep.S linux-3.10.30-cubox-i/arch/arm/kernel/sleep.S +--- linux-3.10.30/arch/arm/kernel/sleep.S 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/sleep.S 2014-03-08 20:32:53.000000000 +0100 +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include "entry-header.S" + .text + + /* +@@ -30,9 +31,8 @@ + mov r2, r5 @ virtual SP + ldr r3, =sleep_save_sp + #ifdef CONFIG_SMP +- ALT_SMP(mrc p15, 0, lr, c0, c0, 5) +- ALT_UP(mov lr, #0) +- and lr, lr, #15 ++ get_thread_info r5 ++ ldr lr, [r5, #TI_CPU] @ cpu logical index + add r3, r3, lr, lsl #2 + #endif + bl __cpu_suspend_save +@@ -82,10 +82,13 @@ + .align + ENTRY(cpu_resume) + #ifdef CONFIG_SMP ++ mov r1, #0 @ fall-back logical index for UP ++ ALT_SMP(mrc p15, 0, r0, c0, c0, 5) ++ ALT_UP_B(1f) ++ bic r0, #0xff000000 ++ bl cpu_logical_index @ return logical index in r1 ++1: + adr r0, sleep_save_sp +- ALT_SMP(mrc p15, 0, r1, c0, c0, 5) +- ALT_UP(mov r1, #0) +- and r1, r1, #15 + ldr r0, [r0, r1, lsl #2] @ stack phys addr + #else + ldr r0, sleep_save_sp @ stack phys addr +@@ -102,3 +105,20 @@ + .rept CONFIG_NR_CPUS + .long 0 @ preserve stack phys ptr here + .endr ++ ++#ifdef CONFIG_SMP ++cpu_logical_index: ++ adr r3, cpu_map_ptr ++ ldr r2, [r3] ++ add r3, r3, r2 @ virt_to_phys(__cpu_logical_map) ++ mov r1, #0 ++1: ++ ldr r2, [r3, r1, lsl #2] ++ cmp r2, r0 ++ moveq pc, lr ++ add r1, r1, #1 ++ b 1b ++ ++cpu_map_ptr: ++ .long __cpu_logical_map - . ++#endif +diff -Nur linux-3.10.30/arch/arm/kernel/smp.c linux-3.10.30-cubox-i/arch/arm/kernel/smp.c +--- linux-3.10.30/arch/arm/kernel/smp.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/smp.c 2014-03-08 20:32:53.000000000 +0100 +@@ -46,6 +46,9 @@ + #include + #include + ++#define CREATE_TRACE_POINTS ++#include ++ + /* + * as from 2.5, kernels no longer have an init_tasks structure + * so we need some other way of telling a new secondary core +@@ -57,7 +60,7 @@ + * control for which core is the next to come out of the secondary + * boot "holding pen" + */ +-volatile int __cpuinitdata pen_release = -1; ++volatile int pen_release = -1; + + enum ipi_msg_type { + IPI_WAKEUP, +@@ -66,6 +69,7 @@ + IPI_CALL_FUNC, + IPI_CALL_FUNC_SINGLE, + IPI_CPU_STOP, ++ IPI_COMPLETION, + }; + + static DECLARE_COMPLETION(cpu_running); +@@ -463,6 +467,7 @@ + S(IPI_CALL_FUNC, "Function call interrupts"), + S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), + S(IPI_CPU_STOP, "CPU stop interrupts"), ++ S(IPI_COMPLETION, "completion interrupts"), + }; + + void show_ipi_list(struct seq_file *p, int prec) +@@ -588,6 +593,19 @@ + cpu_relax(); + } + ++static DEFINE_PER_CPU(struct completion *, cpu_completion); ++ ++int register_ipi_completion(struct completion *completion, int cpu) ++{ ++ per_cpu(cpu_completion, cpu) = completion; ++ return IPI_COMPLETION; ++} ++ ++static void ipi_complete(unsigned int cpu) ++{ ++ complete(per_cpu(cpu_completion, cpu)); ++} ++ + /* + * Main handler for inter-processor interrupts + */ +@@ -604,6 +622,7 @@ + if (ipinr < NR_IPI) + __inc_irq_stat(cpu, ipi_irqs[ipinr]); + ++ trace_arm_ipi_entry(ipinr); + switch (ipinr) { + case IPI_WAKEUP: + break; +@@ -638,11 +657,18 @@ + irq_exit(); + break; + ++ case IPI_COMPLETION: ++ irq_enter(); ++ ipi_complete(cpu); ++ irq_exit(); ++ break; ++ + default: + printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n", + cpu, ipinr); + break; + } ++ trace_arm_ipi_exit(ipinr); + set_irq_regs(old_regs); + } + +diff -Nur linux-3.10.30/arch/arm/kernel/topology.c linux-3.10.30-cubox-i/arch/arm/kernel/topology.c +--- linux-3.10.30/arch/arm/kernel/topology.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/topology.c 2014-03-08 20:32:53.000000000 +0100 +@@ -23,6 +23,7 @@ + #include + + #include ++#include + #include + + /* +@@ -289,6 +290,140 @@ + cpu_topology[cpuid].socket_id, mpidr); + } + ++ ++#ifdef CONFIG_SCHED_HMP ++ ++static const char * const little_cores[] = { ++ "arm,cortex-a7", ++ NULL, ++}; ++ ++static bool is_little_cpu(struct device_node *cn) ++{ ++ const char * const *lc; ++ for (lc = little_cores; *lc; lc++) ++ if (of_device_is_compatible(cn, *lc)) ++ return true; ++ return false; ++} ++ ++void __init arch_get_fast_and_slow_cpus(struct cpumask *fast, ++ struct cpumask *slow) ++{ ++ struct device_node *cn = NULL; ++ int cpu; ++ ++ cpumask_clear(fast); ++ cpumask_clear(slow); ++ ++ /* ++ * Use the config options if they are given. This helps testing ++ * HMP scheduling on systems without a big.LITTLE architecture. ++ */ ++ if (strlen(CONFIG_HMP_FAST_CPU_MASK) && strlen(CONFIG_HMP_SLOW_CPU_MASK)) { ++ if (cpulist_parse(CONFIG_HMP_FAST_CPU_MASK, fast)) ++ WARN(1, "Failed to parse HMP fast cpu mask!\n"); ++ if (cpulist_parse(CONFIG_HMP_SLOW_CPU_MASK, slow)) ++ WARN(1, "Failed to parse HMP slow cpu mask!\n"); ++ return; ++ } ++ ++ /* ++ * Else, parse device tree for little cores. ++ */ ++ while ((cn = of_find_node_by_type(cn, "cpu"))) { ++ ++ const u32 *mpidr; ++ int len; ++ ++ mpidr = of_get_property(cn, "reg", &len); ++ if (!mpidr || len != 4) { ++ pr_err("* %s missing reg property\n", cn->full_name); ++ continue; ++ } ++ ++ cpu = get_logical_index(be32_to_cpup(mpidr)); ++ if (cpu == -EINVAL) { ++ pr_err("couldn't get logical index for mpidr %x\n", ++ be32_to_cpup(mpidr)); ++ break; ++ } ++ ++ if (is_little_cpu(cn)) ++ cpumask_set_cpu(cpu, slow); ++ else ++ cpumask_set_cpu(cpu, fast); ++ } ++ ++ if (!cpumask_empty(fast) && !cpumask_empty(slow)) ++ return; ++ ++ /* ++ * We didn't find both big and little cores so let's call all cores ++ * fast as this will keep the system running, with all cores being ++ * treated equal. ++ */ ++ cpumask_setall(fast); ++ cpumask_clear(slow); ++} ++ ++struct cpumask hmp_slow_cpu_mask; ++ ++void __init arch_get_hmp_domains(struct list_head *hmp_domains_list) ++{ ++ struct cpumask hmp_fast_cpu_mask; ++ struct hmp_domain *domain; ++ ++ arch_get_fast_and_slow_cpus(&hmp_fast_cpu_mask, &hmp_slow_cpu_mask); ++ ++ /* ++ * Initialize hmp_domains ++ * Must be ordered with respect to compute capacity. ++ * Fastest domain at head of list. ++ */ ++ if(!cpumask_empty(&hmp_slow_cpu_mask)) { ++ domain = (struct hmp_domain *) ++ kmalloc(sizeof(struct hmp_domain), GFP_KERNEL); ++ cpumask_copy(&domain->possible_cpus, &hmp_slow_cpu_mask); ++ cpumask_and(&domain->cpus, cpu_online_mask, &domain->possible_cpus); ++ list_add(&domain->hmp_domains, hmp_domains_list); ++ } ++ domain = (struct hmp_domain *) ++ kmalloc(sizeof(struct hmp_domain), GFP_KERNEL); ++ cpumask_copy(&domain->possible_cpus, &hmp_fast_cpu_mask); ++ cpumask_and(&domain->cpus, cpu_online_mask, &domain->possible_cpus); ++ list_add(&domain->hmp_domains, hmp_domains_list); ++} ++#endif /* CONFIG_SCHED_HMP */ ++ ++ ++/* ++ * cluster_to_logical_mask - return cpu logical mask of CPUs in a cluster ++ * @socket_id: cluster HW identifier ++ * @cluster_mask: the cpumask location to be initialized, modified by the ++ * function only if return value == 0 ++ * ++ * Return: ++ * ++ * 0 on success ++ * -EINVAL if cluster_mask is NULL or there is no record matching socket_id ++ */ ++int cluster_to_logical_mask(unsigned int socket_id, cpumask_t *cluster_mask) ++{ ++ int cpu; ++ ++ if (!cluster_mask) ++ return -EINVAL; ++ ++ for_each_online_cpu(cpu) ++ if (socket_id == topology_physical_package_id(cpu)) { ++ cpumask_copy(cluster_mask, topology_core_cpumask(cpu)); ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ + /* + * init_cpu_topology is called at boot when only one cpu is running + * which prevent simultaneous write access to cpu_topology array +diff -Nur linux-3.10.30/arch/arm/kernel/traps.c linux-3.10.30-cubox-i/arch/arm/kernel/traps.c +--- linux-3.10.30/arch/arm/kernel/traps.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/kernel/traps.c 2014-03-08 20:32:53.000000000 +0100 +@@ -61,7 +61,7 @@ + void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) + { + #ifdef CONFIG_KALLSYMS +- printk("[<%08lx>] (%pS) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from); ++ printk("[<%08lx>] (%ps) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from); + #else + printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); + #endif +diff -Nur linux-3.10.30/arch/arm/lib/backtrace.S linux-3.10.30-cubox-i/arch/arm/lib/backtrace.S +--- linux-3.10.30/arch/arm/lib/backtrace.S 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/lib/backtrace.S 2014-03-08 20:32:53.000000000 +0100 +@@ -80,14 +80,14 @@ + + ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists, + ldr r3, .Ldsi+4 +- teq r3, r1, lsr #10 ++ teq r3, r1, lsr #11 + ldreq r0, [frame, #-8] @ get sp + subeq r0, r0, #4 @ point at the last arg + bleq .Ldumpstm @ dump saved registers + + 1004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc} + ldr r3, .Ldsi @ instruction exists, +- teq r3, r1, lsr #10 ++ teq r3, r1, lsr #11 + subeq r0, frame, #16 + bleq .Ldumpstm @ dump saved registers + +@@ -128,11 +128,11 @@ + beq 2f + add r7, r7, #1 + teq r7, #6 +- moveq r7, #1 +- moveq r1, #'\n' +- movne r1, #' ' +- ldr r3, [stack], #-4 +- mov r2, reg ++ moveq r7, #0 ++ adr r3, .Lcr ++ addne r3, r3, #1 @ skip newline ++ ldr r2, [stack], #-4 ++ mov r1, reg + adr r0, .Lfp + bl printk + 2: subs reg, reg, #1 +@@ -142,11 +142,11 @@ + blne printk + ldmfd sp!, {instr, reg, stack, r7, pc} + +-.Lfp: .asciz "%cr%d:%08x" ++.Lfp: .asciz " r%d:%08x%s" + .Lcr: .asciz "\n" + .Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" + .align +-.Ldsi: .word 0xe92dd800 >> 10 @ stmfd sp!, {... fp, ip, lr, pc} +- .word 0xe92d0000 >> 10 @ stmfd sp!, {} ++.Ldsi: .word 0xe92dd800 >> 11 @ stmfd sp!, {... fp, ip, lr, pc} ++ .word 0xe92d0000 >> 11 @ stmfd sp!, {} + + #endif +diff -Nur linux-3.10.30/arch/arm/mach-exynos/mach-exynos5-dt.c linux-3.10.30-cubox-i/arch/arm/mach-exynos/mach-exynos5-dt.c +--- linux-3.10.30/arch/arm/mach-exynos/mach-exynos5-dt.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-exynos/mach-exynos5-dt.c 2014-03-08 20:32:54.000000000 +0100 +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -23,11 +24,31 @@ + + #include "common.h" + ++static u64 dma_mask64 = DMA_BIT_MASK(64); ++ + static void __init exynos5_dt_map_io(void) + { + exynos_init_io(NULL, 0); + } + ++static int exynos5250_platform_notifier(struct notifier_block *nb, ++ unsigned long event, void *__dev) ++{ ++ struct device *dev = __dev; ++ ++ if (event != BUS_NOTIFY_ADD_DEVICE) ++ return NOTIFY_DONE; ++ ++ dev->dma_mask = &dma_mask64; ++ dev->coherent_dma_mask = DMA_BIT_MASK(64); ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block exynos5250_platform_nb = { ++ .notifier_call = exynos5250_platform_notifier, ++}; ++ + static void __init exynos5_dt_machine_init(void) + { + struct device_node *i2c_np; +@@ -52,6 +73,11 @@ + } + } + ++ if (config_enabled(CONFIG_ARM_LPAE) && ++ of_machine_is_compatible("samsung,exynos5250")) ++ bus_register_notifier(&platform_bus_type, ++ &exynos5250_platform_nb); ++ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + } + +diff -Nur linux-3.10.30/arch/arm/mach-imx/Kconfig linux-3.10.30-cubox-i/arch/arm/mach-imx/Kconfig +--- linux-3.10.30/arch/arm/mach-imx/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/Kconfig 2014-03-08 20:32:54.000000000 +0100 +@@ -1,5 +1,6 @@ + config ARCH_MXC + bool "Freescale i.MX family" if ARCH_MULTI_V4_V5 || ARCH_MULTI_V6_V7 ++ select ARCH_HAS_RESET_CONTROLLER + select ARCH_REQUIRE_GPIOLIB + select ARM_PATCH_PHYS_VIRT + select AUTO_ZRELADDR if !ZBOOT_ROM +@@ -8,8 +9,11 @@ + select GENERIC_ALLOCATOR + select GENERIC_CLOCKEVENTS + select GENERIC_IRQ_CHIP ++ select MIGHT_HAVE_CACHE_L2X0 if ARCH_MULTI_V6_V7 + select MULTI_IRQ_HANDLER ++ select SOC_BUS + select SPARSE_IRQ ++ select SRAM + select USE_OF + help + Support for Freescale MXC/iMX-based family of processors +@@ -73,7 +77,6 @@ + + config HAVE_IMX_SRC + def_bool y if SMP +- select ARCH_HAS_RESET_CONTROLLER + + config IMX_HAVE_IOMUX_V1 + bool +@@ -806,16 +809,54 @@ + select HAVE_IMX_SRC + select HAVE_SMP + select MFD_SYSCON ++ select MIGHT_HAVE_PCI ++ select PCI_DOMAINS if PCI ++ select ARCH_SUPPORTS_MSI + select PINCTRL + select PINCTRL_IMX6Q + select PL310_ERRATA_588369 if CACHE_PL310 + select PL310_ERRATA_727915 if CACHE_PL310 + select PL310_ERRATA_769419 if CACHE_PL310 + select PM_OPP if PM ++ select ZONE_DMA + + help + This enables support for Freescale i.MX6 Quad processor. + ++config SOC_IMX6SL ++ bool "i.MX6 SoloLite support" ++ select ARM_ERRATA_754322 ++ select ARM_ERRATA_775420 ++ select ARM_GIC ++ select CPU_V7 ++ select HAVE_IMX_ANATOP ++ select HAVE_IMX_GPC ++ select HAVE_IMX_MMDC ++ select HAVE_IMX_SRC ++ select PINCTRL ++ select PINCTRL_IMX6SL ++ select PL310_ERRATA_588369 if CACHE_PL310 ++ select PL310_ERRATA_727915 if CACHE_PL310 ++ select PL310_ERRATA_769419 if CACHE_PL310 ++ ++ help ++ This enables support for Freescale i.MX6 SoloLite processor. ++ ++config SOC_VF610 ++ bool "Vybrid Family VF610 support" ++ select CPU_V7 ++ select ARM_GIC ++ select CLKSRC_OF ++ select PINCTRL ++ select PINCTRL_VF610 ++ select VF_PIT_TIMER ++ select PL310_ERRATA_588369 if CACHE_PL310 ++ select PL310_ERRATA_727915 if CACHE_PL310 ++ select PL310_ERRATA_769419 if CACHE_PL310 ++ ++ help ++ This enable support for Freescale Vybrid VF610 processor. ++ + endif + + source "arch/arm/mach-imx/devices/Kconfig" +diff -Nur linux-3.10.30/arch/arm/mach-imx/Makefile linux-3.10.30-cubox-i/arch/arm/mach-imx/Makefile +--- linux-3.10.30/arch/arm/mach-imx/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/Makefile 2014-03-08 20:32:54.000000000 +0100 +@@ -15,7 +15,8 @@ + obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clk-imx51-imx53.o ehci-imx5.o $(imx5-pm-y) + + obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \ +- clk-pfd.o clk-busy.o clk.o ++ clk-pfd.o clk-busy.o clk.o \ ++ clk-fixup-div.o clk-fixup-mux.o + + obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o + obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o +@@ -30,6 +31,7 @@ + ifeq ($(CONFIG_CPU_IDLE),y) + obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o + obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o ++obj-$(CONFIG_SOC_IMX6SL) += cpuidle-imx6sl.o + endif + + ifdef CONFIG_SND_IMX_SOC +@@ -98,11 +100,20 @@ + obj-$(CONFIG_SMP) += headsmp.o platsmp.o + obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o + obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o ++obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o + +-ifeq ($(CONFIG_PM),y) +-obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o ++AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a ++obj-$(CONFIG_PM) += pm-imx6.o headsmp.o suspend-imx6.o ++ ++ifeq ($(CONFIG_ARM_IMX6_CPUFREQ),y) ++obj-y += busfreq-imx6.o ++obj-$(CONFIG_SOC_IMX6Q) += ddr3_freq_imx6.o busfreq_ddr3.o ++AFLAGS_lpddr2_freq_imx6.o := -march=armv7-a ++AFLAGS_imx6sl_wfi.o := -march=armv7-a ++obj-$(CONFIG_SOC_IMX6SL) += lpddr2_freq_imx6.o busfreq_lpddr2.o imx6sl_wfi.o + endif + ++ + # i.MX5 based machines + obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o + obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += mach-cpuimx51sd.o +@@ -111,4 +122,6 @@ + obj-$(CONFIG_MACH_IMX51_DT) += imx51-dt.o + obj-$(CONFIG_SOC_IMX53) += mach-imx53.o + ++obj-$(CONFIG_SOC_VF610) += clk-vf610.o mach-vf610.o ++ + obj-y += devices/ +diff -Nur linux-3.10.30/arch/arm/mach-imx/anatop.c linux-3.10.30-cubox-i/arch/arm/mach-imx/anatop.c +--- linux-3.10.30/arch/arm/mach-imx/anatop.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/anatop.c 2014-03-08 20:32:54.000000000 +0100 +@@ -9,6 +9,7 @@ + * http://www.gnu.org/copyleft/gpl.html + */ + ++#include + #include + #include + #include +@@ -16,6 +17,7 @@ + #include + #include + #include "common.h" ++#include "hardware.h" + + #define REG_SET 0x4 + #define REG_CLR 0x8 +@@ -26,13 +28,20 @@ + #define ANADIG_USB1_CHRG_DETECT 0x1b0 + #define ANADIG_USB2_CHRG_DETECT 0x210 + #define ANADIG_DIGPROG 0x260 ++#define ANADIG_DIGPROG_IMX6SL 0x280 + + #define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000 ++#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x8 + #define BM_ANADIG_REG_CORE_FET_ODRIVE 0x20000000 + #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG 0x1000 ++#define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS 0x2000 + #define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x80000 + #define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x100000 + ++#define ANADIG_REG_TARG_MASK 0x1f ++#define ANADIG_REG1_TARG_SHIFT 9 /* VDDPU */ ++#define ANADIG_REG2_TARG_SHIFT 18 /* VDDSOC */ ++ + static struct regmap *anatop; + + static void imx_anatop_enable_weak2p5(bool enable) +@@ -48,25 +57,48 @@ + regmap_write(anatop, reg, BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG); + } + +-static void imx_anatop_enable_fet_odrive(bool enable) ++static inline void imx_anatop_enable_2p5_pulldown(bool enable) ++{ ++ regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR), ++ BM_ANADIG_REG_2P5_ENABLE_PULLDOWN); ++} ++ ++static inline void imx_anatop_enable_fet_odrive(bool enable) + { + regmap_write(anatop, ANADIG_REG_CORE + (enable ? REG_SET : REG_CLR), + BM_ANADIG_REG_CORE_FET_ODRIVE); + } + ++static inline void imx_anatop_disconnect_high_snvs(bool enable) ++{ ++ regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR), ++ BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS); ++} ++ + void imx_anatop_pre_suspend(void) + { +- imx_anatop_enable_weak2p5(true); ++ if (cpu_is_imx6sl()) { ++ imx_anatop_enable_2p5_pulldown(true); ++ imx_anatop_disconnect_high_snvs(true); ++ } else { ++ imx_anatop_enable_weak2p5(true); ++ } ++ + imx_anatop_enable_fet_odrive(true); + } + + void imx_anatop_post_resume(void) + { + imx_anatop_enable_fet_odrive(false); +- imx_anatop_enable_weak2p5(false); ++ if (cpu_is_imx6sl()) { ++ imx_anatop_enable_2p5_pulldown(false); ++ imx_anatop_disconnect_high_snvs(false); ++ } else { ++ imx_anatop_enable_weak2p5(false); ++ } + } + +-void imx_anatop_usb_chrg_detect_disable(void) ++static void imx_anatop_usb_chrg_detect_disable(void) + { + regmap_write(anatop, ANADIG_USB1_CHRG_DETECT, + BM_ANADIG_USB_CHRG_DETECT_EN_B +@@ -76,21 +108,70 @@ + BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); + } + +-u32 imx_anatop_get_digprog(void) ++void imx_anatop_pu_enable(bool enable) ++{ ++ u32 val; ++ ++ regmap_read(anatop, ANADIG_REG_CORE, &val); ++ val &= ANADIG_REG_TARG_MASK << ANADIG_REG2_TARG_SHIFT; ++ /* ++ * set pu regulator only in LDO_BYPASS mode(know by VDDSOC reg 0x1f), ++ * else handled by anatop regulator driver. ++ */ ++ if (((val >> (ANADIG_REG2_TARG_SHIFT)) & ANADIG_REG_TARG_MASK) ++ == ANADIG_REG_TARG_MASK) { ++ if (enable) { ++ regmap_write(anatop, ANADIG_REG_CORE + REG_SET, ++ ANADIG_REG_TARG_MASK << ANADIG_REG1_TARG_SHIFT); ++ udelay(70); /* bypass need 70us to be stable */ ++ } else { ++ regmap_write(anatop, ANADIG_REG_CORE + REG_CLR, ++ ANADIG_REG_TARG_MASK << ANADIG_REG1_TARG_SHIFT); ++ } ++ } ++} ++void __init imx_init_revision_from_anatop(void) + { + struct device_node *np; + void __iomem *anatop_base; +- static u32 digprog; +- +- if (digprog) +- return digprog; ++ unsigned int revision; ++ u32 digprog; ++ u16 offset = ANADIG_DIGPROG; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); + anatop_base = of_iomap(np, 0); + WARN_ON(!anatop_base); +- digprog = readl_relaxed(anatop_base + ANADIG_DIGPROG); ++ if (of_device_is_compatible(np, "fsl,imx6sl-anatop")) ++ offset = ANADIG_DIGPROG_IMX6SL; ++ digprog = readl_relaxed(anatop_base + offset); ++ iounmap(anatop_base); ++ ++ switch (digprog & 0xff) { ++ case 0: ++ revision = IMX_CHIP_REVISION_1_0; ++ break; ++ case 1: ++ revision = IMX_CHIP_REVISION_1_1; ++ break; ++ case 2: ++ revision = IMX_CHIP_REVISION_1_2; ++ break; ++ case 3: ++ revision = IMX_CHIP_REVISION_1_3; ++ break; ++ case 4: ++ revision = IMX_CHIP_REVISION_1_4; ++ break; ++ case 5: ++ revision = IMX_CHIP_REVISION_1_5; ++ break; ++ default: ++ revision = IMX_CHIP_REVISION_UNKNOWN; ++ } + +- return digprog; ++ mxc_set_cpu_type(digprog >> 16 & 0xff); ++ mxc_set_system_rev(((digprog >> 16 & 0xff) << 12) | ((digprog & 0xff) + 0x10)); ++ imx_set_soc_revision(revision); + } + + void __init imx_anatop_init(void) +@@ -100,4 +181,6 @@ + pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__); + return; + } ++ ++ imx_anatop_usb_chrg_detect_disable(); + } +diff -Nur linux-3.10.30/arch/arm/mach-imx/busfreq-imx6.c linux-3.10.30-cubox-i/arch/arm/mach-imx/busfreq-imx6.c +--- linux-3.10.30/arch/arm/mach-imx/busfreq-imx6.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/busfreq-imx6.c 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,938 @@ ++/* ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++/*! ++ * @file busfreq-imx6.c ++ * ++ * @brief A common API for the Freescale Semiconductor iMX6 Busfreq API ++ * ++ * The APIs are for setting bus frequency to different values based on the ++ * highest freqeuncy requested. ++ * ++ * @ingroup PM ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "hardware.h" ++ ++#define LPAPM_CLK 24000000 ++#define DDR3_AUDIO_CLK 50000000 ++#define LPDDR2_AUDIO_CLK 100000000 ++ ++int high_bus_freq_mode; ++int med_bus_freq_mode; ++int audio_bus_freq_mode; ++int low_bus_freq_mode; ++int ultra_low_bus_freq_mode; ++unsigned int ddr_med_rate; ++unsigned int ddr_normal_rate; ++ ++static int bus_freq_scaling_initialized; ++static struct device *busfreq_dev; ++static int busfreq_suspended; ++static u32 org_arm_rate; ++static int bus_freq_scaling_is_active; ++static int high_bus_count, med_bus_count, audio_bus_count, low_bus_count; ++static unsigned int ddr_low_rate; ++ ++extern int init_mmdc_lpddr2_settings(struct platform_device *dev); ++extern int init_mmdc_ddr3_settings(struct platform_device *dev); ++extern int update_ddr_freq(int ddr_rate); ++extern int update_lpddr2_freq(int ddr_rate); ++ ++DEFINE_MUTEX(bus_freq_mutex); ++static DEFINE_SPINLOCK(freq_lock); ++ ++static struct clk *pll2_400; ++static struct clk *periph_clk; ++static struct clk *periph_pre_clk; ++static struct clk *periph_clk2_sel; ++static struct clk *periph_clk2; ++static struct clk *osc_clk; ++static struct clk *cpu_clk; ++static struct clk *pll3; ++static struct clk *pll2; ++static struct clk *pll2_200; ++static struct clk *pll1_sys; ++static struct clk *periph2_clk; ++static struct clk *ocram_clk; ++static struct clk *ahb_clk; ++static struct clk *pll1_sw_clk; ++static struct clk *periph2_pre_clk; ++static struct clk *periph2_clk2_sel; ++static struct clk *periph2_clk2; ++static struct clk *step_clk; ++static struct clk *axi_sel_clk; ++static struct clk *pll3_pfd1_540m; ++ ++static u32 pll2_org_rate; ++static struct delayed_work low_bus_freq_handler; ++static struct delayed_work bus_freq_daemon; ++ ++static void enter_lpm_imx6sl(void) ++{ ++ unsigned long flags; ++ ++ if (high_bus_freq_mode) { ++ pll2_org_rate = clk_get_rate(pll2); ++ /* Set periph_clk to be sourced from OSC_CLK */ ++ clk_set_parent(periph_clk2_sel, osc_clk); ++ clk_set_parent(periph_clk, periph_clk2); ++ /* Ensure AHB/AXI clks are at 24MHz. */ ++ clk_set_rate(ahb_clk, LPAPM_CLK); ++ clk_set_rate(ocram_clk, LPAPM_CLK); ++ } ++ if (audio_bus_count) { ++ /* Set AHB to 8MHz to lower pwer.*/ ++ clk_set_rate(ahb_clk, LPAPM_CLK / 3); ++ ++ /* Set up DDR to 100MHz. */ ++ spin_lock_irqsave(&freq_lock, flags); ++ update_lpddr2_freq(LPDDR2_AUDIO_CLK); ++ spin_unlock_irqrestore(&freq_lock, flags); ++ ++ /* Fix the clock tree in kernel */ ++ clk_set_rate(pll2, pll2_org_rate); ++ clk_set_parent(periph2_pre_clk, pll2_200); ++ clk_set_parent(periph2_clk, periph2_pre_clk); ++ ++ if (low_bus_freq_mode || ultra_low_bus_freq_mode) { ++ /* ++ * Swtich ARM to run off PLL2_PFD2_400MHz ++ * since DDR is anyway at 100MHz. ++ */ ++ clk_set_parent(step_clk, pll2_400); ++ clk_set_parent(pll1_sw_clk, step_clk); ++ /* ++ * Ensure that the clock will be ++ * at original speed. ++ */ ++ clk_set_rate(cpu_clk, org_arm_rate); ++ } ++ low_bus_freq_mode = 0; ++ ultra_low_bus_freq_mode = 0; ++ audio_bus_freq_mode = 1; ++ } else { ++ u32 arm_div, pll1_rate; ++ org_arm_rate = clk_get_rate(cpu_clk); ++ if (low_bus_freq_mode && low_bus_count == 0) { ++ /* ++ * We are already in DDR @ 24MHz state, but ++ * no one but ARM needs the DDR. In this case, ++ * we can lower the DDR freq to 1MHz when ARM ++ * enters WFI in this state. Keep track of this state. ++ */ ++ ultra_low_bus_freq_mode = 1; ++ low_bus_freq_mode = 0; ++ audio_bus_freq_mode = 0; ++ } else { ++ if (!ultra_low_bus_freq_mode && !low_bus_freq_mode) { ++ /* ++ * Set DDR to 24MHz. ++ * Since we are going to bypass PLL2, ++ * we need to move ARM clk off PLL2_PFD2 ++ * to PLL1. Make sure the PLL1 is running ++ * at the lowest possible freq. ++ */ ++ clk_set_rate(pll1_sys, ++ clk_round_rate(pll1_sys, org_arm_rate)); ++ pll1_rate = clk_get_rate(pll1_sys); ++ arm_div = pll1_rate / org_arm_rate + 1; ++ /* ++ * Ensure ARM CLK is lower before ++ * changing the parent. ++ */ ++ clk_set_rate(cpu_clk, org_arm_rate / arm_div); ++ /* Now set the ARM clk parent to PLL1_SYS. */ ++ clk_set_parent(pll1_sw_clk, pll1_sys); ++ ++ /* ++ * Set STEP_CLK back to OSC to save power and ++ * also to maintain the parent.The WFI iram code ++ * will switch step_clk to osc, but the clock API ++ * is not aware of the change and when a new request ++ * to change the step_clk parent to pll2_pfd2_400M ++ * is requested sometime later, the change is ignored. ++ */ ++ clk_set_parent(step_clk, osc_clk); ++ /* Now set DDR to 24MHz. */ ++ spin_lock_irqsave(&freq_lock, flags); ++ update_lpddr2_freq(LPAPM_CLK); ++ spin_unlock_irqrestore(&freq_lock, flags); ++ ++ /* ++ * Fix the clock tree in kernel. ++ * Make sure PLL2 rate is updated as it gets ++ * bypassed in the DDR freq change code. ++ */ ++ clk_set_rate(pll2, LPAPM_CLK); ++ clk_set_parent(periph2_clk2_sel, pll2); ++ clk_set_parent(periph2_clk, periph2_clk2_sel); ++ ++ } ++ if (low_bus_count == 0) { ++ ultra_low_bus_freq_mode = 1; ++ low_bus_freq_mode = 0; ++ } else { ++ ultra_low_bus_freq_mode = 0; ++ low_bus_freq_mode = 1; ++ } ++ audio_bus_freq_mode = 0; ++ } ++ } ++} ++ ++static void exit_lpm_imx6sl(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&freq_lock, flags); ++ /* Change DDR freq in IRAM. */ ++ update_lpddr2_freq(ddr_normal_rate); ++ spin_unlock_irqrestore(&freq_lock, flags); ++ ++ /* ++ * Fix the clock tree in kernel. ++ * Make sure PLL2 rate is updated as it gets ++ * un-bypassed in the DDR freq change code. ++ */ ++ clk_set_rate(pll2, pll2_org_rate); ++ clk_set_parent(periph2_pre_clk, pll2_400); ++ clk_set_parent(periph2_clk, periph2_pre_clk); ++ ++ /* Ensure that periph_clk is sourced from PLL2_400. */ ++ clk_set_parent(periph_pre_clk, pll2_400); ++ /* ++ * Before switching the perhiph_clk, ensure that the ++ * AHB/AXI will not be too fast. ++ */ ++ clk_set_rate(ahb_clk, LPAPM_CLK / 3); ++ clk_set_rate(ocram_clk, LPAPM_CLK / 2); ++ clk_set_parent(periph_clk, periph_pre_clk); ++ ++ if (low_bus_freq_mode || ultra_low_bus_freq_mode) { ++ /* Move ARM from PLL1_SW_CLK to PLL2_400. */ ++ clk_set_parent(step_clk, pll2_400); ++ clk_set_parent(pll1_sw_clk, step_clk); ++ clk_set_rate(cpu_clk, org_arm_rate); ++ ultra_low_bus_freq_mode = 0; ++ } ++} ++ ++int reduce_bus_freq(void) ++{ ++ int ret = 0; ++ clk_prepare_enable(pll3); ++ if (cpu_is_imx6sl()) ++ enter_lpm_imx6sl(); ++ else { ++ if (cpu_is_imx6dl() && (clk_get_parent(axi_sel_clk) ++ != periph_clk)) ++ /* Set axi to periph_clk */ ++ clk_set_parent(axi_sel_clk, periph_clk); ++ ++ if (audio_bus_count) { ++ /* Need to ensure that PLL2_PFD_400M is kept ON. */ ++ clk_prepare_enable(pll2_400); ++ update_ddr_freq(DDR3_AUDIO_CLK); ++ /* Make sure periph clk's parent also got updated */ ++ ret = clk_set_parent(periph_clk2_sel, pll3); ++ if (ret) ++ dev_WARN(busfreq_dev, ++ "%s: %d: clk set parent fail!\n", ++ __func__, __LINE__); ++ ret = clk_set_parent(periph_pre_clk, pll2_200); ++ if (ret) ++ dev_WARN(busfreq_dev, ++ "%s: %d: clk set parent fail!\n", ++ __func__, __LINE__); ++ ret = clk_set_parent(periph_clk, periph_pre_clk); ++ if (ret) ++ dev_WARN(busfreq_dev, ++ "%s: %d: clk set parent fail!\n", ++ __func__, __LINE__); ++ audio_bus_freq_mode = 1; ++ low_bus_freq_mode = 0; ++ } else { ++ update_ddr_freq(LPAPM_CLK); ++ /* Make sure periph clk's parent also got updated */ ++ ret = clk_set_parent(periph_clk2_sel, osc_clk); ++ if (ret) ++ dev_WARN(busfreq_dev, ++ "%s: %d: clk set parent fail!\n", ++ __func__, __LINE__); ++ /* Set periph_clk parent to OSC via periph_clk2_sel */ ++ ret = clk_set_parent(periph_clk, periph_clk2); ++ if (ret) ++ dev_WARN(busfreq_dev, ++ "%s: %d: clk set parent fail!\n", ++ __func__, __LINE__); ++ if (audio_bus_freq_mode) ++ clk_disable_unprepare(pll2_400); ++ low_bus_freq_mode = 1; ++ audio_bus_freq_mode = 0; ++ } ++ } ++ clk_disable_unprepare(pll3); ++ ++ med_bus_freq_mode = 0; ++ high_bus_freq_mode = 0; ++ ++ if (audio_bus_freq_mode) ++ dev_dbg(busfreq_dev, "Bus freq set to audio mode. Count:\ ++ high %d, med %d, audio %d\n", ++ high_bus_count, med_bus_count, audio_bus_count); ++ if (low_bus_freq_mode) ++ dev_dbg(busfreq_dev, "Bus freq set to low mode. Count:\ ++ high %d, med %d, audio %d\n", ++ high_bus_count, med_bus_count, audio_bus_count); ++ ++ return ret; ++} ++ ++static void reduce_bus_freq_handler(struct work_struct *work) ++{ ++ mutex_lock(&bus_freq_mutex); ++ ++ reduce_bus_freq(); ++ ++ mutex_unlock(&bus_freq_mutex); ++} ++ ++/* ++ * Set the DDR, AHB to 24MHz. ++ * This mode will be activated only when none of the modules that ++ * need a higher DDR or AHB frequency are active. ++ */ ++int set_low_bus_freq(void) ++{ ++ if (busfreq_suspended) ++ return 0; ++ ++ if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) ++ return 0; ++ ++ /* ++ * Check to see if we need to got from ++ * low bus freq mode to audio bus freq mode. ++ * If so, the change needs to be done immediately. ++ */ ++ if (audio_bus_count && (low_bus_freq_mode || ultra_low_bus_freq_mode)) ++ reduce_bus_freq(); ++ else ++ /* ++ * Don't lower the frequency immediately. Instead ++ * scheduled a delayed work and drop the freq if ++ * the conditions still remain the same. ++ */ ++ schedule_delayed_work(&low_bus_freq_handler, ++ usecs_to_jiffies(3000000)); ++ return 0; ++} ++ ++/* ++ * Set the DDR to either 528MHz or 400MHz for iMX6qd ++ * or 400MHz for iMX6dl. ++ */ ++int set_high_bus_freq(int high_bus_freq) ++{ ++ int ret = 0; ++ struct clk *periph_clk_parent; ++ ++ if (bus_freq_scaling_initialized && bus_freq_scaling_is_active) ++ cancel_delayed_work_sync(&low_bus_freq_handler); ++ ++ if (busfreq_suspended) ++ return 0; ++ ++ if (cpu_is_imx6q()) ++ periph_clk_parent = pll2; ++ else ++ periph_clk_parent = pll2_400; ++ ++ if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) ++ return 0; ++ ++ if (high_bus_freq_mode) ++ return 0; ++ ++ /* medium bus freq is only supported for MX6DQ */ ++ if (med_bus_freq_mode && !high_bus_freq) ++ return 0; ++ ++ clk_prepare_enable(pll3); ++ if (cpu_is_imx6sl()) ++ exit_lpm_imx6sl(); ++ else { ++ if (high_bus_freq) { ++ update_ddr_freq(ddr_normal_rate); ++ /* Make sure periph clk's parent also got updated */ ++ ret = clk_set_parent(periph_clk2_sel, pll3); ++ if (ret) ++ dev_WARN(busfreq_dev, ++ "%s: %d: clk set parent fail!\n", ++ __func__, __LINE__); ++ ret = clk_set_parent(periph_pre_clk, periph_clk_parent); ++ if (ret) ++ dev_WARN(busfreq_dev, ++ "%s: %d: clk set parent fail!\n", ++ __func__, __LINE__); ++ ret = clk_set_parent(periph_clk, periph_pre_clk); ++ if (ret) ++ dev_WARN(busfreq_dev, ++ "%s: %d: clk set parent fail!\n", ++ __func__, __LINE__); ++ if (cpu_is_imx6dl() && (clk_get_parent(axi_sel_clk) ++ != pll3_pfd1_540m)) ++ /* Set axi to pll3_pfd1_540m */ ++ clk_set_parent(axi_sel_clk, pll3_pfd1_540m); ++ } else { ++ update_ddr_freq(ddr_med_rate); ++ /* Make sure periph clk's parent also got updated */ ++ ret = clk_set_parent(periph_clk2_sel, pll3); ++ if (ret) ++ dev_WARN(busfreq_dev, ++ "%s: %d: clk set parent fail!\n", ++ __func__, __LINE__); ++ ret = clk_set_parent(periph_pre_clk, pll2_400); ++ if (ret) ++ dev_WARN(busfreq_dev, ++ "%s: %d: clk set parent fail!\n", ++ __func__, __LINE__); ++ ret = clk_set_parent(periph_clk, periph_pre_clk); ++ if (ret) ++ dev_WARN(busfreq_dev, ++ "%s: %d: clk set parent fail!\n", ++ __func__, __LINE__); ++ } ++ if (audio_bus_freq_mode) ++ clk_disable_unprepare(pll2_400); ++ } ++ ++ high_bus_freq_mode = 1; ++ med_bus_freq_mode = 0; ++ low_bus_freq_mode = 0; ++ audio_bus_freq_mode = 0; ++ ++ clk_disable_unprepare(pll3); ++ ++ if (high_bus_freq_mode) ++ dev_dbg(busfreq_dev, "Bus freq set to high mode. Count:\ ++ high %d, med %d, audio %d\n", ++ high_bus_count, med_bus_count, audio_bus_count); ++ if (med_bus_freq_mode) ++ dev_dbg(busfreq_dev, "Bus freq set to med mode. Count:\ ++ high %d, med %d, audio %d\n", ++ high_bus_count, med_bus_count, audio_bus_count); ++ ++ return 0; ++} ++ ++void request_bus_freq(enum bus_freq_mode mode) ++{ ++ mutex_lock(&bus_freq_mutex); ++ ++ if (mode == BUS_FREQ_HIGH) ++ high_bus_count++; ++ else if (mode == BUS_FREQ_MED) ++ med_bus_count++; ++ else if (mode == BUS_FREQ_AUDIO) ++ audio_bus_count++; ++ else if (mode == BUS_FREQ_LOW) ++ low_bus_count++; ++ ++ if (busfreq_suspended || !bus_freq_scaling_initialized || ++ !bus_freq_scaling_is_active) { ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ cancel_delayed_work_sync(&low_bus_freq_handler); ++ ++ if (cpu_is_imx6dl()) { ++ /* No support for medium setpoint on MX6DL. */ ++ if (mode == BUS_FREQ_MED) { ++ high_bus_count++; ++ mode = BUS_FREQ_HIGH; ++ } ++ } ++ ++ if ((mode == BUS_FREQ_HIGH) && (!high_bus_freq_mode)) { ++ set_high_bus_freq(1); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ ++ if ((mode == BUS_FREQ_MED) && (!high_bus_freq_mode) && ++ (!med_bus_freq_mode)) { ++ set_high_bus_freq(0); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ if ((mode == BUS_FREQ_AUDIO) && (!high_bus_freq_mode) && ++ (!med_bus_freq_mode) && (!audio_bus_freq_mode)) { ++ set_low_bus_freq(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ mutex_unlock(&bus_freq_mutex); ++ return; ++} ++EXPORT_SYMBOL(request_bus_freq); ++ ++void release_bus_freq(enum bus_freq_mode mode) ++{ ++ mutex_lock(&bus_freq_mutex); ++ ++ if (mode == BUS_FREQ_HIGH) { ++ if (high_bus_count == 0) { ++ dev_err(busfreq_dev, "high bus count mismatch!\n"); ++ dump_stack(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ high_bus_count--; ++ } else if (mode == BUS_FREQ_MED) { ++ if (med_bus_count == 0) { ++ dev_err(busfreq_dev, "med bus count mismatch!\n"); ++ dump_stack(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ med_bus_count--; ++ } else if (mode == BUS_FREQ_AUDIO) { ++ if (audio_bus_count == 0) { ++ dev_err(busfreq_dev, "audio bus count mismatch!\n"); ++ dump_stack(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ audio_bus_count--; ++ } else if (mode == BUS_FREQ_LOW) { ++ if (low_bus_count == 0) { ++ dev_err(busfreq_dev, "low bus count mismatch!\n"); ++ dump_stack(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ low_bus_count--; ++ } ++ ++ if (busfreq_suspended || !bus_freq_scaling_initialized || ++ !bus_freq_scaling_is_active) { ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ ++ if (cpu_is_imx6dl()) { ++ /* No support for medium setpoint on MX6DL. */ ++ if (mode == BUS_FREQ_MED) { ++ high_bus_count--; ++ mode = BUS_FREQ_HIGH; ++ } ++ } ++ ++ if ((!audio_bus_freq_mode) && (high_bus_count == 0) && ++ (med_bus_count == 0) && (audio_bus_count != 0)) { ++ set_low_bus_freq(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ if ((!low_bus_freq_mode) && (high_bus_count == 0) && ++ (med_bus_count == 0) && (audio_bus_count == 0) && ++ (low_bus_count != 0)) { ++ set_low_bus_freq(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ if ((!ultra_low_bus_freq_mode) && (high_bus_count == 0) && ++ (med_bus_count == 0) && (audio_bus_count == 0) && ++ (low_bus_count == 0)) { ++ set_low_bus_freq(); ++ mutex_unlock(&bus_freq_mutex); ++ return; ++ } ++ ++ mutex_unlock(&bus_freq_mutex); ++ return; ++} ++EXPORT_SYMBOL(release_bus_freq); ++ ++static void bus_freq_daemon_handler(struct work_struct *work) ++{ ++ mutex_lock(&bus_freq_mutex); ++ if ((!low_bus_freq_mode) && (high_bus_count == 0) && ++ (med_bus_count == 0) && (audio_bus_count == 0)) ++ set_low_bus_freq(); ++ mutex_unlock(&bus_freq_mutex); ++} ++ ++static ssize_t bus_freq_scaling_enable_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ if (bus_freq_scaling_is_active) ++ return sprintf(buf, "Bus frequency scaling is enabled\n"); ++ else ++ return sprintf(buf, "Bus frequency scaling is disabled\n"); ++} ++ ++static ssize_t bus_freq_scaling_enable_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t size) ++{ ++ if (strncmp(buf, "1", 1) == 0) { ++ bus_freq_scaling_is_active = 1; ++ set_high_bus_freq(1); ++ /* ++ * We set bus freq to highest at the beginning, ++ * so we use this daemon thread to make sure system ++ * can enter low bus mode if ++ * there is no high bus request pending ++ */ ++ schedule_delayed_work(&bus_freq_daemon, ++ usecs_to_jiffies(5000000)); ++ } else if (strncmp(buf, "0", 1) == 0) { ++ if (bus_freq_scaling_is_active) ++ set_high_bus_freq(1); ++ bus_freq_scaling_is_active = 0; ++ } ++ return size; ++} ++ ++static int bus_freq_pm_notify(struct notifier_block *nb, unsigned long event, ++ void *dummy) ++{ ++ mutex_lock(&bus_freq_mutex); ++ ++ if (event == PM_SUSPEND_PREPARE) { ++ high_bus_count++; ++ set_high_bus_freq(1); ++ busfreq_suspended = 1; ++ } else if (event == PM_POST_SUSPEND) { ++ busfreq_suspended = 0; ++ high_bus_count--; ++ schedule_delayed_work(&bus_freq_daemon, ++ usecs_to_jiffies(5000000)); ++ } ++ ++ mutex_unlock(&bus_freq_mutex); ++ ++ return NOTIFY_OK; ++} ++ ++static int busfreq_reboot_notifier_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ /* System is rebooting. Set the system into high_bus_freq_mode. */ ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ return 0; ++} ++ ++static struct notifier_block imx_bus_freq_pm_notifier = { ++ .notifier_call = bus_freq_pm_notify, ++}; ++ ++static struct notifier_block imx_busfreq_reboot_notifier = { ++ .notifier_call = busfreq_reboot_notifier_event, ++}; ++ ++ ++static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show, ++ bus_freq_scaling_enable_store); ++ ++/*! ++ * This is the probe routine for the bus frequency driver. ++ * ++ * @param pdev The platform device structure ++ * ++ * @return The function returns 0 on success ++ * ++ */ ++ ++static int busfreq_probe(struct platform_device *pdev) ++{ ++ u32 err; ++ ++ busfreq_dev = &pdev->dev; ++ ++ pll2_400 = devm_clk_get(&pdev->dev, "pll2_pfd2_396m"); ++ if (IS_ERR(pll2_400)) { ++ dev_err(busfreq_dev, "%s: failed to get pll2_pfd2_396m\n", ++ __func__); ++ return PTR_ERR(pll2_400); ++ } ++ ++ pll2_200 = devm_clk_get(&pdev->dev, "pll2_198m"); ++ if (IS_ERR(pll2_200)) { ++ dev_err(busfreq_dev, "%s: failed to get pll2_198m\n", ++ __func__); ++ return PTR_ERR(pll2_200); ++ } ++ ++ pll2 = devm_clk_get(&pdev->dev, "pll2_bus"); ++ if (IS_ERR(pll2)) { ++ dev_err(busfreq_dev, "%s: failed to get pll2_bus\n", ++ __func__); ++ return PTR_ERR(pll2); ++ } ++ ++ cpu_clk = devm_clk_get(&pdev->dev, "arm"); ++ if (IS_ERR(cpu_clk)) { ++ dev_err(busfreq_dev, "%s: failed to get cpu_clk\n", ++ __func__); ++ return PTR_ERR(cpu_clk); ++ } ++ ++ pll3 = devm_clk_get(&pdev->dev, "pll3_usb_otg"); ++ if (IS_ERR(pll3)) { ++ dev_err(busfreq_dev, "%s: failed to get pll3_usb_otg\n", ++ __func__); ++ return PTR_ERR(pll3); ++ } ++ ++ periph_clk = devm_clk_get(&pdev->dev, "periph"); ++ if (IS_ERR(periph_clk)) { ++ dev_err(busfreq_dev, "%s: failed to get periph\n", ++ __func__); ++ return PTR_ERR(periph_clk); ++ } ++ ++ periph_pre_clk = devm_clk_get(&pdev->dev, "periph_pre"); ++ if (IS_ERR(periph_pre_clk)) { ++ dev_err(busfreq_dev, "%s: failed to get periph_pre\n", ++ __func__); ++ return PTR_ERR(periph_pre_clk); ++ } ++ ++ periph_clk2 = devm_clk_get(&pdev->dev, "periph_clk2"); ++ if (IS_ERR(periph_clk2)) { ++ dev_err(busfreq_dev, "%s: failed to get periph_clk2\n", ++ __func__); ++ return PTR_ERR(periph_clk2); ++ } ++ ++ periph_clk2_sel = devm_clk_get(&pdev->dev, "periph_clk2_sel"); ++ if (IS_ERR(periph_clk2_sel)) { ++ dev_err(busfreq_dev, "%s: failed to get periph_clk2_sel\n", ++ __func__); ++ return PTR_ERR(periph_clk2_sel); ++ } ++ ++ osc_clk = devm_clk_get(&pdev->dev, "osc"); ++ if (IS_ERR(osc_clk)) { ++ dev_err(busfreq_dev, "%s: failed to get osc_clk\n", ++ __func__); ++ return PTR_ERR(osc_clk); ++ } ++ ++ if (cpu_is_imx6dl()) { ++ axi_sel_clk = devm_clk_get(&pdev->dev, "axi_sel"); ++ if (IS_ERR(axi_sel_clk)) { ++ dev_err(busfreq_dev, "%s: failed to get axi_sel_clk\n", ++ __func__); ++ return PTR_ERR(axi_sel_clk); ++ } ++ ++ pll3_pfd1_540m = devm_clk_get(&pdev->dev, "pll3_pfd1_540m"); ++ if (IS_ERR(pll3_pfd1_540m)) { ++ dev_err(busfreq_dev, ++ "%s: failed to get pll3_pfd1_540m\n", __func__); ++ return PTR_ERR(pll3_pfd1_540m); ++ } ++ } ++ ++ if (cpu_is_imx6sl()) { ++ pll1_sys = devm_clk_get(&pdev->dev, "pll1_sys"); ++ if (IS_ERR(pll1_sys)) { ++ dev_err(busfreq_dev, "%s: failed to get pll1_sys\n", ++ __func__); ++ return PTR_ERR(pll1_sys); ++ } ++ ++ ahb_clk = devm_clk_get(&pdev->dev, "ahb"); ++ if (IS_ERR(ahb_clk)) { ++ dev_err(busfreq_dev, "%s: failed to get ahb_clk\n", ++ __func__); ++ return PTR_ERR(ahb_clk); ++ } ++ ++ ocram_clk = devm_clk_get(&pdev->dev, "ocram"); ++ if (IS_ERR(ocram_clk)) { ++ dev_err(busfreq_dev, "%s: failed to get ocram_clk\n", ++ __func__); ++ return PTR_ERR(ocram_clk); ++ } ++ ++ pll1_sw_clk = devm_clk_get(&pdev->dev, "pll1_sw"); ++ if (IS_ERR(pll1_sw_clk)) { ++ dev_err(busfreq_dev, "%s: failed to get pll1_sw_clk\n", ++ __func__); ++ return PTR_ERR(pll1_sw_clk); ++ } ++ ++ periph2_clk = devm_clk_get(&pdev->dev, "periph2"); ++ if (IS_ERR(periph2_clk)) { ++ dev_err(busfreq_dev, "%s: failed to get periph2\n", ++ __func__); ++ return PTR_ERR(periph2_clk); ++ } ++ ++ periph2_pre_clk = devm_clk_get(&pdev->dev, "periph2_pre"); ++ if (IS_ERR(periph2_pre_clk)) { ++ dev_err(busfreq_dev, ++ "%s: failed to get periph2_pre_clk\n", ++ __func__); ++ return PTR_ERR(periph2_pre_clk); ++ } ++ ++ periph2_clk2 = devm_clk_get(&pdev->dev, "periph2_clk2"); ++ if (IS_ERR(periph2_clk2)) { ++ dev_err(busfreq_dev, ++ "%s: failed to get periph2_clk2\n", ++ __func__); ++ return PTR_ERR(periph2_clk2); ++ } ++ ++ periph2_clk2_sel = devm_clk_get(&pdev->dev, "periph2_clk2_sel"); ++ if (IS_ERR(periph2_clk2_sel)) { ++ dev_err(busfreq_dev, ++ "%s: failed to get periph2_clk2_sel\n", ++ __func__); ++ return PTR_ERR(periph2_clk2_sel); ++ } ++ ++ step_clk = devm_clk_get(&pdev->dev, "step"); ++ if (IS_ERR(step_clk)) { ++ dev_err(busfreq_dev, ++ "%s: failed to get step_clk\n", ++ __func__); ++ return PTR_ERR(periph2_clk2_sel); ++ } ++ ++ } ++ ++ err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr); ++ if (err) { ++ dev_err(busfreq_dev, ++ "Unable to register sysdev entry for BUSFREQ"); ++ return err; ++ } ++ ++ if (of_property_read_u32(pdev->dev.of_node, "fsl,max_ddr_freq", ++ &ddr_normal_rate)) { ++ dev_err(busfreq_dev, "max_ddr_freq entry missing\n"); ++ return -EINVAL; ++ } ++ ++ high_bus_freq_mode = 1; ++ med_bus_freq_mode = 0; ++ low_bus_freq_mode = 0; ++ audio_bus_freq_mode = 0; ++ ultra_low_bus_freq_mode = 0; ++ ++ bus_freq_scaling_is_active = 1; ++ bus_freq_scaling_initialized = 1; ++ ++ ddr_low_rate = LPAPM_CLK; ++ if (cpu_is_imx6q()) { ++ if (of_property_read_u32(pdev->dev.of_node, "fsl,med_ddr_freq", ++ &ddr_med_rate)) { ++ dev_info(busfreq_dev, ++ "DDR medium rate not supported.\n"); ++ ddr_med_rate = ddr_normal_rate; ++ } ++ } ++ ++ INIT_DELAYED_WORK(&low_bus_freq_handler, reduce_bus_freq_handler); ++ INIT_DELAYED_WORK(&bus_freq_daemon, bus_freq_daemon_handler); ++ register_pm_notifier(&imx_bus_freq_pm_notifier); ++ register_reboot_notifier(&imx_busfreq_reboot_notifier); ++ ++ if (cpu_is_imx6sl()) ++ err = init_mmdc_lpddr2_settings(pdev); ++ else ++ err = init_mmdc_ddr3_settings(pdev); ++ if (err) { ++ dev_err(busfreq_dev, "Busfreq init of MMDC failed\n"); ++ return err; ++ } ++ return 0; ++} ++ ++static const struct of_device_id imx6_busfreq_ids[] = { ++ { .compatible = "fsl,imx6_busfreq", }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver busfreq_driver = { ++ .driver = { ++ .name = "imx6_busfreq", ++ .owner = THIS_MODULE, ++ .of_match_table = imx6_busfreq_ids, ++ }, ++ .probe = busfreq_probe, ++}; ++ ++/*! ++ * Initialise the busfreq_driver. ++ * ++ * @return The function always returns 0. ++ */ ++ ++static int __init busfreq_init(void) ++{ ++ if (platform_driver_register(&busfreq_driver) != 0) ++ return -ENODEV; ++ ++ printk(KERN_INFO "Bus freq driver module loaded\n"); ++ ++ return 0; ++} ++ ++static void __exit busfreq_cleanup(void) ++{ ++ sysfs_remove_file(&busfreq_dev->kobj, &dev_attr_enable.attr); ++ ++ /* Unregister the device structure */ ++ platform_driver_unregister(&busfreq_driver); ++ bus_freq_scaling_initialized = 0; ++} ++ ++module_init(busfreq_init); ++module_exit(busfreq_cleanup); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("BusFreq driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/arch/arm/mach-imx/busfreq_ddr3.c linux-3.10.30-cubox-i/arch/arm/mach-imx/busfreq_ddr3.c +--- linux-3.10.30/arch/arm/mach-imx/busfreq_ddr3.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/busfreq_ddr3.c 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,476 @@ ++/* ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file busfreq_ddr3.c ++ * ++ * @brief iMX6 DDR3 frequency change specific file. ++ * ++ * @ingroup PM ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "hardware.h" ++ ++/* DDR settings */ ++static unsigned long (*iram_ddr_settings)[2]; ++static unsigned long (*normal_mmdc_settings)[2]; ++static unsigned long (*iram_iomux_settings)[2]; ++ ++static void __iomem *mmdc_base; ++static void __iomem *iomux_base; ++static void __iomem *ccm_base; ++static void __iomem *l2_base; ++static void __iomem *gic_dist_base; ++static u32 *irqs_used; ++ ++static void *ddr_freq_change_iram_base; ++static int ddr_settings_size; ++static int iomux_settings_size; ++static volatile unsigned int cpus_in_wfe; ++static volatile bool wait_for_ddr_freq_update; ++static int curr_ddr_rate; ++ ++void (*mx6_change_ddr_freq)(u32 freq, void *ddr_settings, ++ bool dll_mode, void *iomux_offsets) = NULL; ++ ++extern unsigned int ddr_med_rate; ++extern unsigned int ddr_normal_rate; ++extern int low_bus_freq_mode; ++extern int audio_bus_freq_mode; ++extern void mx6_ddr3_freq_change(u32 freq, void *ddr_settings, ++ bool dll_mode, void *iomux_offsets); ++ ++#define MIN_DLL_ON_FREQ 333000000 ++#define MAX_DLL_OFF_FREQ 125000000 ++#define DDR_FREQ_CHANGE_SIZE 0x2000 ++ ++unsigned long ddr3_dll_mx6q[][2] = { ++ {0x0c, 0x0}, ++ {0x10, 0x0}, ++ {0x1C, 0x04088032}, ++ {0x1C, 0x0408803a}, ++ {0x1C, 0x08408030}, ++ {0x1C, 0x08408038}, ++ {0x818, 0x0}, ++}; ++ ++unsigned long ddr3_calibration[][2] = { ++ {0x83c, 0x0}, ++ {0x840, 0x0}, ++ {0x483c, 0x0}, ++ {0x4840, 0x0}, ++ {0x848, 0x0}, ++ {0x4848, 0x0}, ++ {0x850, 0x0}, ++ {0x4850, 0x0}, ++}; ++ ++unsigned long ddr3_dll_mx6dl[][2] = { ++ {0x0c, 0x0}, ++ {0x10, 0x0}, ++ {0x1C, 0x04008032}, ++ {0x1C, 0x0400803a}, ++ {0x1C, 0x07208030}, ++ {0x1C, 0x07208038}, ++ {0x818, 0x0}, ++}; ++ ++unsigned long iomux_offsets_mx6q[][2] = { ++ {0x5A8, 0x0}, ++ {0x5B0, 0x0}, ++ {0x524, 0x0}, ++ {0x51C, 0x0}, ++ {0x518, 0x0}, ++ {0x50C, 0x0}, ++ {0x5B8, 0x0}, ++ {0x5C0, 0x0}, ++}; ++ ++unsigned long iomux_offsets_mx6dl[][2] = { ++ {0x4BC, 0x0}, ++ {0x4C0, 0x0}, ++ {0x4C4, 0x0}, ++ {0x4C8, 0x0}, ++ {0x4CC, 0x0}, ++ {0x4D0, 0x0}, ++ {0x4D4, 0x0}, ++ {0x4D8, 0x0}, ++}; ++ ++unsigned long ddr3_400[][2] = { ++ {0x83c, 0x42490249}, ++ {0x840, 0x02470247}, ++ {0x483c, 0x42570257}, ++ {0x4840, 0x02400240}, ++ {0x848, 0x4039363C}, ++ {0x4848, 0x3A39333F}, ++ {0x850, 0x38414441}, ++ {0x4850, 0x472D4833} ++}; ++ ++int can_change_ddr_freq(void) ++{ ++ return 1; ++} ++ ++/* ++ * each active core apart from the one changing ++ * the DDR frequency will execute this function. ++ * the rest of the cores have to remain in WFE ++ * state until the frequency is changed. ++ */ ++irqreturn_t wait_in_wfe_irq(int irq, void *dev_id) ++{ ++ u32 me = smp_processor_id(); ++ ++ *((char *)(&cpus_in_wfe) + (u8)me) = 0xff; ++ ++ while (wait_for_ddr_freq_update) ++ wfe(); ++ ++ *((char *)(&cpus_in_wfe) + (u8)me) = 0; ++ ++ return IRQ_HANDLED; ++} ++ ++/* change the DDR frequency. */ ++int update_ddr_freq(int ddr_rate) ++{ ++ int i, j; ++ unsigned int reg; ++ bool dll_off = false; ++ unsigned int online_cpus = 0; ++ int cpu = 0; ++ int me; ++ ++ if (!can_change_ddr_freq()) ++ return -1; ++ ++ if (ddr_rate == curr_ddr_rate) ++ return 0; ++ ++ printk(KERN_DEBUG "\nBus freq set to %d start...\n", ddr_rate); ++ ++ if (low_bus_freq_mode || audio_bus_freq_mode) ++ dll_off = true; ++ ++ iram_ddr_settings[0][0] = ddr_settings_size; ++ iram_iomux_settings[0][0] = iomux_settings_size; ++ if (ddr_rate == ddr_med_rate && cpu_is_imx6q()) { ++ for (i = 0; i < ARRAY_SIZE(ddr3_dll_mx6q); i++) { ++ iram_ddr_settings[i + 1][0] = ++ normal_mmdc_settings[i][0]; ++ iram_ddr_settings[i + 1][1] = ++ normal_mmdc_settings[i][1]; ++ } ++ for (j = 0, i = ARRAY_SIZE(ddr3_dll_mx6q); ++ i < iram_ddr_settings[0][0]; j++, i++) { ++ iram_ddr_settings[i + 1][0] = ++ ddr3_400[j][0]; ++ iram_ddr_settings[i + 1][1] = ++ ddr3_400[j][1]; ++ } ++ } else if (ddr_rate == ddr_normal_rate) { ++ for (i = 0; i < iram_ddr_settings[0][0]; i++) { ++ iram_ddr_settings[i + 1][0] = ++ normal_mmdc_settings[i][0]; ++ iram_ddr_settings[i + 1][1] = ++ normal_mmdc_settings[i][1]; ++ } ++ } ++ ++ /* ensure that all Cores are in WFE. */ ++ local_irq_disable(); ++ ++ me = smp_processor_id(); ++ ++ *((char *)(&cpus_in_wfe) + (u8)me) = 0xff; ++ wait_for_ddr_freq_update = true; ++ for_each_online_cpu(cpu) { ++ *((char *)(&online_cpus) + (u8)cpu) = 0xff; ++ if (cpu != me) { ++ /* set the interrupt to be pending in the GIC. */ ++ reg = 1 << (irqs_used[cpu] % 32); ++ writel_relaxed(reg, gic_dist_base + GIC_DIST_PENDING_SET ++ + (irqs_used[cpu] / 32) * 4); ++ } ++ } ++ while (cpus_in_wfe != online_cpus) ++ udelay(5); ++ ++ /* ++ * Flush the TLB, to ensure no TLB maintenance occurs ++ * when DDR is in self-refresh. ++ */ ++ local_flush_tlb_all(); ++ /* Now we can change the DDR frequency. */ ++ mx6_change_ddr_freq(ddr_rate, iram_ddr_settings, ++ dll_off, iram_iomux_settings); ++ ++ curr_ddr_rate = ddr_rate; ++ ++ /* DDR frequency change is done . */ ++ wait_for_ddr_freq_update = false; ++ ++ /* wake up all the cores. */ ++ sev(); ++ ++ *((char *)(&cpus_in_wfe) + (u8)me) = 0; ++ ++ local_irq_enable(); ++ ++ printk(KERN_DEBUG "Bus freq set to %d done!\n", ddr_rate); ++ ++ return 0; ++} ++ ++int init_mmdc_ddr3_settings(struct platform_device *busfreq_pdev) ++{ ++ struct device *dev = &busfreq_pdev->dev; ++ struct platform_device *ocram_dev; ++ unsigned int iram_paddr; ++ int i, err; ++ u32 cpu; ++ struct device_node *node; ++ struct gen_pool *iram_pool; ++ void *iram_addr; ++ ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc-combine"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6q-mmdc device tree data!\n"); ++ return -EINVAL; ++ } ++ mmdc_base = of_iomap(node, 0); ++ WARN(!mmdc_base, "unable to map mmdc registers\n"); ++ ++ node = NULL; ++ if (cpu_is_imx6q()) ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-iomuxc"); ++ if (cpu_is_imx6dl()) ++ node = of_find_compatible_node(NULL, NULL, ++ "fsl,imx6dl-iomuxc"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6q-iomux device tree data!\n"); ++ return -EINVAL; ++ } ++ iomux_base = of_iomap(node, 0); ++ WARN(!iomux_base, "unable to map iomux registers\n"); ++ ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ccm"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6q-ccm device tree data!\n"); ++ return -EINVAL; ++ } ++ ccm_base = of_iomap(node, 0); ++ WARN(!ccm_base, "unable to map mmdc registers\n"); ++ ++ node = of_find_compatible_node(NULL, NULL, "arm,pl310-cache"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6q-pl310-cache device tree data!\n"); ++ return -EINVAL; ++ } ++ l2_base = of_iomap(node, 0); ++ WARN(!ccm_base, "unable to map mmdc registers\n"); ++ ++ node = NULL; ++ node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-gic"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6q-a9-gic device tree data!\n"); ++ return -EINVAL; ++ } ++ gic_dist_base = of_iomap(node, 0); ++ WARN(!gic_dist_base, "unable to map gic dist registers\n"); ++ ++ if (cpu_is_imx6q()) ++ ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6q) + ++ ARRAY_SIZE(ddr3_calibration); ++ if (cpu_is_imx6dl()) ++ ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6dl) + ++ ARRAY_SIZE(ddr3_calibration); ++ ++ normal_mmdc_settings = kmalloc((ddr_settings_size * 8), GFP_KERNEL); ++ if (cpu_is_imx6q()) { ++ memcpy(normal_mmdc_settings, ddr3_dll_mx6q, ++ sizeof(ddr3_dll_mx6q)); ++ memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6q)), ++ ddr3_calibration, sizeof(ddr3_calibration)); ++ } ++ if (cpu_is_imx6dl()) { ++ memcpy(normal_mmdc_settings, ddr3_dll_mx6dl, ++ sizeof(ddr3_dll_mx6dl)); ++ memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6dl)), ++ ddr3_calibration, sizeof(ddr3_calibration)); ++ } ++ /* store the original DDR settings at boot. */ ++ for (i = 0; i < ddr_settings_size; i++) { ++ /* ++ * writes via command mode register cannot be read back. ++ * hence hardcode them in the initial static array. ++ * this may require modification on a per customer basis. ++ */ ++ if (normal_mmdc_settings[i][0] != 0x1C) ++ normal_mmdc_settings[i][1] = ++ readl_relaxed(mmdc_base ++ + normal_mmdc_settings[i][0]); ++ } ++ ++ irqs_used = devm_kzalloc(dev, sizeof(u32) * num_present_cpus(), ++ GFP_KERNEL); ++ ++ for_each_online_cpu(cpu) { ++ int irq; ++ ++ /* ++ * set up a reserved interrupt to get all ++ * the active cores into a WFE state ++ * before changing the DDR frequency. ++ */ ++ irq = platform_get_irq(busfreq_pdev, cpu); ++ err = request_irq(irq, wait_in_wfe_irq, ++ IRQF_PERCPU, "mmdc_1", NULL); ++ if (err) { ++ dev_err(dev, ++ "Busfreq:request_irq failed %d, err = %d\n", ++ irq, err); ++ return err; ++ } ++ err = irq_set_affinity(irq, cpumask_of(cpu)); ++ if (err) { ++ dev_err(dev, ++ "Busfreq: Cannot set irq affinity irq=%d,\n", ++ irq); ++ return err; ++ } ++ irqs_used[cpu] = irq; ++ } ++ ++ node = NULL; ++ node = of_find_compatible_node(NULL, NULL, "mmio-sram"); ++ if (!node) { ++ dev_err(dev, "%s: failed to find ocram node\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ ocram_dev = of_find_device_by_node(node); ++ if (!ocram_dev) { ++ dev_err(dev, "failed to find ocram device!\n"); ++ return -EINVAL; ++ } ++ ++ iram_pool = dev_get_gen_pool(&ocram_dev->dev); ++ if (!iram_pool) { ++ dev_err(dev, "iram pool unavailable!\n"); ++ return -EINVAL; ++ } ++ ++ iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6q); ++ iram_addr = (void *)gen_pool_alloc(iram_pool, ++ (iomux_settings_size * 8) + 8); ++ iram_iomux_settings = iram_addr; ++ if (!iram_iomux_settings) { ++ dev_err(dev, "unable to alloc iram for IOMUX settings!\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Allocate extra space to store the number of entries in the ++ * ddr_settings plus 4 extra regsiter information that needs ++ * to be passed to the frequency change code. ++ * sizeof(iram_ddr_settings) = sizeof(ddr_settings) + ++ * entries in ddr_settings + 16. ++ * The last 4 enties store the addresses of the registers: ++ * CCM_BASE_ADDR ++ * MMDC_BASE_ADDR ++ * IOMUX_BASE_ADDR ++ * L2X0_BASE_ADDR ++ */ ++ iram_addr = (void *)gen_pool_alloc(iram_pool, ++ (ddr_settings_size * 8) + 8 + 32); ++ iram_ddr_settings = iram_addr; ++ if (!iram_ddr_settings) { ++ dev_err(dev, "unable to alloc iram for ddr settings!\n"); ++ return -ENOMEM; ++ } ++ ++ i = ddr_settings_size + 1; ++ iram_ddr_settings[i][0] = (unsigned long)mmdc_base; ++ iram_ddr_settings[i+1][0] = (unsigned long)ccm_base; ++ iram_ddr_settings[i+2][0] = (unsigned long)iomux_base; ++ iram_ddr_settings[i+3][0] = (unsigned long)l2_base; ++ ++ if (cpu_is_imx6q()) { ++ /* store the IOMUX settings at boot. */ ++ for (i = 0; i < iomux_settings_size; i++) { ++ iomux_offsets_mx6q[i][1] = ++ readl_relaxed(iomux_base + ++ iomux_offsets_mx6q[i][0]); ++ iram_iomux_settings[i+1][0] = iomux_offsets_mx6q[i][0]; ++ iram_iomux_settings[i+1][1] = iomux_offsets_mx6q[i][1]; ++ } ++ } ++ ++ if (cpu_is_imx6dl()) { ++ for (i = 0; i < iomux_settings_size; i++) { ++ iomux_offsets_mx6dl[i][1] = ++ readl_relaxed(iomux_base + ++ iomux_offsets_mx6dl[i][0]); ++ iram_iomux_settings[i+1][0] = iomux_offsets_mx6dl[i][0]; ++ iram_iomux_settings[i+1][1] = iomux_offsets_mx6dl[i][1]; ++ } ++ } ++ ++ ddr_freq_change_iram_base = (void *)gen_pool_alloc(iram_pool, ++ DDR_FREQ_CHANGE_SIZE); ++ if (!ddr_freq_change_iram_base) { ++ dev_err(dev, "Cannot alloc iram for ddr freq change code!\n"); ++ return -ENOMEM; ++ } ++ ++ iram_paddr = gen_pool_virt_to_phys(iram_pool, ++ (unsigned long)ddr_freq_change_iram_base); ++ /* ++ * Need to remap the area here since we want ++ * the memory region to be executable. ++ */ ++ ddr_freq_change_iram_base = __arm_ioremap(iram_paddr, ++ DDR_FREQ_CHANGE_SIZE, ++ MT_MEMORY_NONCACHED); ++ mx6_change_ddr_freq = (void *)fncpy(ddr_freq_change_iram_base, ++ &mx6_ddr3_freq_change, DDR_FREQ_CHANGE_SIZE); ++ ++ curr_ddr_rate = ddr_normal_rate; ++ ++ return 0; ++} +diff -Nur linux-3.10.30/arch/arm/mach-imx/busfreq_lpddr2.c linux-3.10.30-cubox-i/arch/arm/mach-imx/busfreq_lpddr2.c +--- linux-3.10.30/arch/arm/mach-imx/busfreq_lpddr2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/busfreq_lpddr2.c 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,183 @@ ++/* ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file busfreq_lpddr2.c ++ * ++ * @brief iMX6 LPDDR2 frequency change specific file. ++ * ++ * @ingroup PM ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "hardware.h" ++ ++/* DDR settings */ ++static void __iomem *mmdc_base; ++static void __iomem *anatop_base; ++static void __iomem *ccm_base; ++static void __iomem *l2_base; ++static struct device *busfreq_dev; ++static void *ddr_freq_change_iram_base; ++static int curr_ddr_rate; ++ ++unsigned long reg_addrs[4]; ++ ++void (*mx6_change_lpddr2_freq)(u32 ddr_freq, int bus_freq_mode, ++ void *iram_addr) = NULL; ++ ++extern unsigned int ddr_normal_rate; ++extern int low_bus_freq_mode; ++extern int ultra_low_bus_freq_mode; ++extern void mx6_lpddr2_freq_change(u32 freq, int bus_freq_mode, ++ void *iram_addr); ++ ++ ++#define LPDDR2_FREQ_CHANGE_SIZE 0x1000 ++ ++ ++/* change the DDR frequency. */ ++int update_lpddr2_freq(int ddr_rate) ++{ ++ if (ddr_rate == curr_ddr_rate) ++ return 0; ++ ++ dev_dbg(busfreq_dev, "\nBus freq set to %d start...\n", ddr_rate); ++ ++ /* ++ * Flush the TLB, to ensure no TLB maintenance occurs ++ * when DDR is in self-refresh. ++ */ ++ local_flush_tlb_all(); ++ /* Now change DDR frequency. */ ++ mx6_change_lpddr2_freq(ddr_rate, ++ (low_bus_freq_mode | ultra_low_bus_freq_mode), ++ reg_addrs); ++ ++ curr_ddr_rate = ddr_rate; ++ ++ dev_dbg(busfreq_dev, "\nBus freq set to %d done...\n", ddr_rate); ++ ++ return 0; ++} ++ ++int init_mmdc_lpddr2_settings(struct platform_device *busfreq_pdev) ++{ ++ struct platform_device *ocram_dev; ++ unsigned int iram_paddr; ++ struct device_node *node; ++ struct gen_pool *iram_pool; ++ ++ busfreq_dev = &busfreq_pdev->dev; ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-mmdc"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6sl-mmdc device tree data!\n"); ++ return -EINVAL; ++ } ++ mmdc_base = of_iomap(node, 0); ++ WARN(!mmdc_base, "unable to map mmdc registers\n"); ++ ++ node = NULL; ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-ccm"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6sl-ccm device tree data!\n"); ++ return -EINVAL; ++ } ++ ccm_base = of_iomap(node, 0); ++ WARN(!ccm_base, "unable to map ccm registers\n"); ++ ++ node = of_find_compatible_node(NULL, NULL, "arm,pl310-cache"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6sl-pl310-cache device tree data!\n"); ++ return -EINVAL; ++ } ++ l2_base = of_iomap(node, 0); ++ WARN(!l2_base, "unable to map PL310 registers\n"); ++ ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop"); ++ if (!node) { ++ printk(KERN_ERR "failed to find imx6sl-pl310-cache device tree data!\n"); ++ return -EINVAL; ++ } ++ anatop_base = of_iomap(node, 0); ++ WARN(!anatop_base, "unable to map anatop registers\n"); ++ ++ node = NULL; ++ node = of_find_compatible_node(NULL, NULL, "mmio-sram"); ++ if (!node) { ++ dev_err(busfreq_dev, "%s: failed to find ocram node\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ ocram_dev = of_find_device_by_node(node); ++ if (!ocram_dev) { ++ dev_err(busfreq_dev, "failed to find ocram device!\n"); ++ return -EINVAL; ++ } ++ ++ iram_pool = dev_get_gen_pool(&ocram_dev->dev); ++ if (!iram_pool) { ++ dev_err(busfreq_dev, "iram pool unavailable!\n"); ++ return -EINVAL; ++ } ++ ++ reg_addrs[0] = (unsigned long)anatop_base; ++ reg_addrs[1] = (unsigned long)ccm_base; ++ reg_addrs[2] = (unsigned long)mmdc_base; ++ reg_addrs[3] = (unsigned long)l2_base; ++ ++ ddr_freq_change_iram_base = (void *)gen_pool_alloc(iram_pool, ++ LPDDR2_FREQ_CHANGE_SIZE); ++ if (!ddr_freq_change_iram_base) { ++ dev_err(busfreq_dev, ++ "Cannot alloc iram for ddr freq change code!\n"); ++ return -ENOMEM; ++ } ++ ++ iram_paddr = gen_pool_virt_to_phys(iram_pool, ++ (unsigned long)ddr_freq_change_iram_base); ++ /* ++ * Need to remap the area here since we want ++ * the memory region to be executable. ++ */ ++ ddr_freq_change_iram_base = __arm_ioremap(iram_paddr, ++ LPDDR2_FREQ_CHANGE_SIZE, ++ MT_MEMORY_NONCACHED); ++ mx6_change_lpddr2_freq = (void *)fncpy(ddr_freq_change_iram_base, ++ &mx6_lpddr2_freq_change, LPDDR2_FREQ_CHANGE_SIZE); ++ ++ curr_ddr_rate = ddr_normal_rate; ++ ++ return 0; ++} +diff -Nur linux-3.10.30/arch/arm/mach-imx/clk-fixup-div.c linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-fixup-div.c +--- linux-3.10.30/arch/arm/mach-imx/clk-fixup-div.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-fixup-div.c 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,129 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include "clk.h" ++ ++#define to_clk_div(_hw) container_of(_hw, struct clk_divider, hw) ++#define div_mask(d) ((1 << (d->width)) - 1) ++ ++/** ++ * struct clk_fixup_div - imx integer fixup divider clock ++ * @divider: the parent class ++ * @ops: pointer to clk_ops of parent class ++ * @fixup: a hook to fixup the write value ++ * ++ * The imx fixup divider clock is a subclass of basic clk_divider ++ * with an addtional fixup hook. ++ */ ++struct clk_fixup_div { ++ struct clk_divider divider; ++ const struct clk_ops *ops; ++ void (*fixup)(u32 *val); ++}; ++ ++static inline struct clk_fixup_div *to_clk_fixup_div(struct clk_hw *hw) ++{ ++ struct clk_divider *divider = to_clk_div(hw); ++ ++ return container_of(divider, struct clk_fixup_div, divider); ++} ++ ++static unsigned long clk_fixup_div_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw); ++ ++ return fixup_div->ops->recalc_rate(&fixup_div->divider.hw, parent_rate); ++} ++ ++static long clk_fixup_div_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw); ++ ++ return fixup_div->ops->round_rate(&fixup_div->divider.hw, rate, prate); ++} ++ ++static int clk_fixup_div_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_fixup_div *fixup_div = to_clk_fixup_div(hw); ++ struct clk_divider *div = to_clk_div(hw); ++ unsigned int divider, value; ++ unsigned long flags = 0; ++ u32 val; ++ ++ divider = parent_rate / rate; ++ ++ /* Zero based divider */ ++ value = divider - 1; ++ ++ if (value > div_mask(div)) ++ value = div_mask(div); ++ ++ spin_lock_irqsave(div->lock, flags); ++ ++ val = readl(div->reg); ++ val &= ~(div_mask(div) << div->shift); ++ val |= value << div->shift; ++ fixup_div->fixup(&val); ++ writel(val, div->reg); ++ ++ spin_unlock_irqrestore(div->lock, flags); ++ ++ return 0; ++} ++ ++static const struct clk_ops clk_fixup_div_ops = { ++ .recalc_rate = clk_fixup_div_recalc_rate, ++ .round_rate = clk_fixup_div_round_rate, ++ .set_rate = clk_fixup_div_set_rate, ++}; ++ ++struct clk *imx_clk_fixup_divider(const char *name, const char *parent, ++ void __iomem *reg, u8 shift, u8 width, ++ void (*fixup)(u32 *val)) ++{ ++ struct clk_fixup_div *fixup_div; ++ struct clk *clk; ++ struct clk_init_data init; ++ ++ if (!fixup) ++ return ERR_PTR(-EINVAL); ++ ++ fixup_div = kzalloc(sizeof(*fixup_div), GFP_KERNEL); ++ if (!fixup_div) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ init.ops = &clk_fixup_div_ops; ++ init.flags = CLK_SET_RATE_PARENT; ++ init.parent_names = parent ? &parent : NULL; ++ init.num_parents = parent ? 1 : 0; ++ ++ fixup_div->divider.reg = reg; ++ fixup_div->divider.shift = shift; ++ fixup_div->divider.width = width; ++ fixup_div->divider.lock = &imx_ccm_lock; ++ fixup_div->divider.hw.init = &init; ++ fixup_div->ops = &clk_divider_ops; ++ fixup_div->fixup = fixup; ++ ++ clk = clk_register(NULL, &fixup_div->divider.hw); ++ if (IS_ERR(clk)) ++ kfree(fixup_div); ++ ++ return clk; ++} +diff -Nur linux-3.10.30/arch/arm/mach-imx/clk-fixup-mux.c linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-fixup-mux.c +--- linux-3.10.30/arch/arm/mach-imx/clk-fixup-mux.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-fixup-mux.c 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,107 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include "clk.h" ++ ++#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) ++ ++/** ++ * struct clk_fixup_mux - imx integer fixup multiplexer clock ++ * @mux: the parent class ++ * @ops: pointer to clk_ops of parent class ++ * @fixup: a hook to fixup the write value ++ * ++ * The imx fixup multiplexer clock is a subclass of basic clk_mux ++ * with an addtional fixup hook. ++ */ ++struct clk_fixup_mux { ++ struct clk_mux mux; ++ const struct clk_ops *ops; ++ void (*fixup)(u32 *val); ++}; ++ ++static inline struct clk_fixup_mux *to_clk_fixup_mux(struct clk_hw *hw) ++{ ++ struct clk_mux *mux = to_clk_mux(hw); ++ ++ return container_of(mux, struct clk_fixup_mux, mux); ++} ++ ++static u8 clk_fixup_mux_get_parent(struct clk_hw *hw) ++{ ++ struct clk_fixup_mux *fixup_mux = to_clk_fixup_mux(hw); ++ ++ return fixup_mux->ops->get_parent(&fixup_mux->mux.hw); ++} ++ ++static int clk_fixup_mux_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct clk_fixup_mux *fixup_mux = to_clk_fixup_mux(hw); ++ struct clk_mux *mux = to_clk_mux(hw); ++ unsigned long flags = 0; ++ u32 val; ++ ++ spin_lock_irqsave(mux->lock, flags); ++ ++ val = readl(mux->reg); ++ val &= ~(mux->mask << mux->shift); ++ val |= index << mux->shift; ++ fixup_mux->fixup(&val); ++ writel(val, mux->reg); ++ ++ spin_unlock_irqrestore(mux->lock, flags); ++ ++ return 0; ++} ++ ++static const struct clk_ops clk_fixup_mux_ops = { ++ .get_parent = clk_fixup_mux_get_parent, ++ .set_parent = clk_fixup_mux_set_parent, ++}; ++ ++struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, ++ u8 shift, u8 width, const char **parents, ++ int num_parents, void (*fixup)(u32 *val)) ++{ ++ struct clk_fixup_mux *fixup_mux; ++ struct clk *clk; ++ struct clk_init_data init; ++ ++ if (!fixup) ++ return ERR_PTR(-EINVAL); ++ ++ fixup_mux = kzalloc(sizeof(*fixup_mux), GFP_KERNEL); ++ if (!fixup_mux) ++ return ERR_PTR(-ENOMEM); ++ ++ init.name = name; ++ init.ops = &clk_fixup_mux_ops; ++ init.parent_names = parents; ++ init.num_parents = num_parents; ++ ++ fixup_mux->mux.reg = reg; ++ fixup_mux->mux.shift = shift; ++ fixup_mux->mux.mask = BIT(width) - 1; ++ fixup_mux->mux.lock = &imx_ccm_lock; ++ fixup_mux->mux.hw.init = &init; ++ fixup_mux->ops = &clk_mux_ops; ++ fixup_mux->fixup = fixup; ++ ++ clk = clk_register(NULL, &fixup_mux->mux.hw); ++ if (IS_ERR(clk)) ++ kfree(fixup_mux); ++ ++ return clk; ++} +diff -Nur linux-3.10.30/arch/arm/mach-imx/clk-gate2.c linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-gate2.c +--- linux-3.10.30/arch/arm/mach-imx/clk-gate2.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-gate2.c 2014-03-08 20:32:54.000000000 +0100 +@@ -1,6 +1,7 @@ + /* + * Copyright (C) 2010-2011 Canonical Ltd + * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -72,7 +73,7 @@ + + reg = readl(gate->reg); + +- if (((reg >> gate->bit_idx) & 3) == 3) ++ if (((reg >> gate->bit_idx) & 1) == 1) + return 1; + + return 0; +diff -Nur linux-3.10.30/arch/arm/mach-imx/clk-imx51-imx53.c linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-imx51-imx53.c +--- linux-3.10.30/arch/arm/mach-imx/clk-imx51-imx53.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-imx51-imx53.c 2014-03-08 20:32:54.000000000 +0100 +@@ -123,11 +123,13 @@ + { + int i; + ++ of_clk_init(NULL); ++ + clk[dummy] = imx_clk_fixed("dummy", 0); +- clk[ckil] = imx_clk_fixed("ckil", rate_ckil); +- clk[osc] = imx_clk_fixed("osc", rate_osc); +- clk[ckih1] = imx_clk_fixed("ckih1", rate_ckih1); +- clk[ckih2] = imx_clk_fixed("ckih2", rate_ckih2); ++ clk[ckil] = imx_obtain_fixed_clock("ckil", rate_ckil); ++ clk[osc] = imx_obtain_fixed_clock("osc", rate_osc); ++ clk[ckih1] = imx_obtain_fixed_clock("ckih1", rate_ckih1); ++ clk[ckih2] = imx_obtain_fixed_clock("ckih2", rate_ckih2); + + clk[lp_apm] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 9, 1, + lp_apm_sel, ARRAY_SIZE(lp_apm_sel)); +@@ -542,42 +544,12 @@ + return 0; + } + +-#ifdef CONFIG_OF +-static void __init clk_get_freq_dt(unsigned long *ckil, unsigned long *osc, +- unsigned long *ckih1, unsigned long *ckih2) +-{ +- struct device_node *np; +- +- /* retrieve the freqency of fixed clocks from device tree */ +- for_each_compatible_node(np, NULL, "fixed-clock") { +- u32 rate; +- if (of_property_read_u32(np, "clock-frequency", &rate)) +- continue; +- +- if (of_device_is_compatible(np, "fsl,imx-ckil")) +- *ckil = rate; +- else if (of_device_is_compatible(np, "fsl,imx-osc")) +- *osc = rate; +- else if (of_device_is_compatible(np, "fsl,imx-ckih1")) +- *ckih1 = rate; +- else if (of_device_is_compatible(np, "fsl,imx-ckih2")) +- *ckih2 = rate; +- } +-} +- + int __init mx51_clocks_init_dt(void) + { +- unsigned long ckil, osc, ckih1, ckih2; +- +- clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); +- return mx51_clocks_init(ckil, osc, ckih1, ckih2); ++ return mx51_clocks_init(0, 0, 0, 0); + } + + int __init mx53_clocks_init_dt(void) + { +- unsigned long ckil, osc, ckih1, ckih2; +- +- clk_get_freq_dt(&ckil, &osc, &ckih1, &ckih2); +- return mx53_clocks_init(ckil, osc, ckih1, ckih2); ++ return mx53_clocks_init(0, 0, 0, 0); + } +-#endif +diff -Nur linux-3.10.30/arch/arm/mach-imx/clk-imx6q.c linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-imx6q.c +--- linux-3.10.30/arch/arm/mach-imx/clk-imx6q.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-imx6q.c 2014-03-08 20:32:54.000000000 +0100 +@@ -14,7 +14,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -25,154 +24,7 @@ + #include "common.h" + #include "hardware.h" + +-#define CCR 0x0 +-#define BM_CCR_WB_COUNT (0x7 << 16) +-#define BM_CCR_RBC_BYPASS_COUNT (0x3f << 21) +-#define BM_CCR_RBC_EN (0x1 << 27) +- +-#define CCGR0 0x68 +-#define CCGR1 0x6c +-#define CCGR2 0x70 +-#define CCGR3 0x74 +-#define CCGR4 0x78 +-#define CCGR5 0x7c +-#define CCGR6 0x80 +-#define CCGR7 0x84 +- +-#define CLPCR 0x54 +-#define BP_CLPCR_LPM 0 +-#define BM_CLPCR_LPM (0x3 << 0) +-#define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) +-#define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) +-#define BM_CLPCR_SBYOS (0x1 << 6) +-#define BM_CLPCR_DIS_REF_OSC (0x1 << 7) +-#define BM_CLPCR_VSTBY (0x1 << 8) +-#define BP_CLPCR_STBY_COUNT 9 +-#define BM_CLPCR_STBY_COUNT (0x3 << 9) +-#define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) +-#define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) +-#define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) +-#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) +-#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) +-#define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) +-#define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) +-#define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) +-#define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) +-#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) +-#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) +- +-#define CGPR 0x64 +-#define BM_CGPR_CHICKEN_BIT (0x1 << 17) +- +-static void __iomem *ccm_base; +- +-void imx6q_set_chicken_bit(void) +-{ +- u32 val = readl_relaxed(ccm_base + CGPR); +- +- val |= BM_CGPR_CHICKEN_BIT; +- writel_relaxed(val, ccm_base + CGPR); +-} +- +-static void imx6q_enable_rbc(bool enable) +-{ +- u32 val; +- static bool last_rbc_mode; +- +- if (last_rbc_mode == enable) +- return; +- /* +- * need to mask all interrupts in GPC before +- * operating RBC configurations +- */ +- imx_gpc_mask_all(); +- +- /* configure RBC enable bit */ +- val = readl_relaxed(ccm_base + CCR); +- val &= ~BM_CCR_RBC_EN; +- val |= enable ? BM_CCR_RBC_EN : 0; +- writel_relaxed(val, ccm_base + CCR); +- +- /* configure RBC count */ +- val = readl_relaxed(ccm_base + CCR); +- val &= ~BM_CCR_RBC_BYPASS_COUNT; +- val |= enable ? BM_CCR_RBC_BYPASS_COUNT : 0; +- writel(val, ccm_base + CCR); +- +- /* +- * need to delay at least 2 cycles of CKIL(32K) +- * due to hardware design requirement, which is +- * ~61us, here we use 65us for safe +- */ +- udelay(65); +- +- /* restore GPC interrupt mask settings */ +- imx_gpc_restore_all(); +- +- last_rbc_mode = enable; +-} +- +-static void imx6q_enable_wb(bool enable) +-{ +- u32 val; +- static bool last_wb_mode; +- +- if (last_wb_mode == enable) +- return; +- +- /* configure well bias enable bit */ +- val = readl_relaxed(ccm_base + CLPCR); +- val &= ~BM_CLPCR_WB_PER_AT_LPM; +- val |= enable ? BM_CLPCR_WB_PER_AT_LPM : 0; +- writel_relaxed(val, ccm_base + CLPCR); +- +- /* configure well bias count */ +- val = readl_relaxed(ccm_base + CCR); +- val &= ~BM_CCR_WB_COUNT; +- val |= enable ? BM_CCR_WB_COUNT : 0; +- writel_relaxed(val, ccm_base + CCR); +- +- last_wb_mode = enable; +-} +- +-int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) +-{ +- u32 val = readl_relaxed(ccm_base + CLPCR); +- +- val &= ~BM_CLPCR_LPM; +- switch (mode) { +- case WAIT_CLOCKED: +- imx6q_enable_wb(false); +- imx6q_enable_rbc(false); +- break; +- case WAIT_UNCLOCKED: +- val |= 0x1 << BP_CLPCR_LPM; +- val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM; +- break; +- case STOP_POWER_ON: +- val |= 0x2 << BP_CLPCR_LPM; +- break; +- case WAIT_UNCLOCKED_POWER_OFF: +- val |= 0x1 << BP_CLPCR_LPM; +- val &= ~BM_CLPCR_VSTBY; +- val &= ~BM_CLPCR_SBYOS; +- break; +- case STOP_POWER_OFF: +- val |= 0x2 << BP_CLPCR_LPM; +- val |= 0x3 << BP_CLPCR_STBY_COUNT; +- val |= BM_CLPCR_VSTBY; +- val |= BM_CLPCR_SBYOS; +- imx6q_enable_wb(true); +- imx6q_enable_rbc(true); +- break; +- default: +- return -EINVAL; +- } +- +- writel_relaxed(val, ccm_base + CLPCR); +- +- return 0; +-} ++#define CCM_CCGR_OFFSET(index) (index * 2) + + static const char *step_sels[] = { "osc", "pll2_pfd2_396m", }; + static const char *pll1_sw_sels[] = { "pll1_sys", "step", }; +@@ -182,13 +34,15 @@ + static const char *periph_sels[] = { "periph_pre", "periph_clk2", }; + static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", }; + static const char *axi_sels[] = { "periph", "pll2_pfd2_396m", "periph", "pll3_pfd1_540m", }; +-static const char *audio_sels[] = { "pll4_post_div", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", }; ++static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", }; + static const char *gpu_axi_sels[] = { "axi", "ahb", }; + static const char *gpu2d_core_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", }; + static const char *gpu3d_core_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd2_396m", }; + static const char *gpu3d_shader_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll3_pfd0_720m", }; + static const char *ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", }; + static const char *ldb_di_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "mmdc_ch1_axi", "pll3_usb_otg", }; ++static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", }; ++static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", }; + static const char *ipu_di_pre_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", }; + static const char *ipu1_di0_sels[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; + static const char *ipu1_di1_sels[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; +@@ -196,15 +50,29 @@ + static const char *ipu2_di1_sels[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", }; + static const char *hsi_tx_sels[] = { "pll3_120m", "pll2_pfd2_396m", }; + static const char *pcie_axi_sels[] = { "axi", "ahb", }; +-static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_post_div", }; ++static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio_div", }; + static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; + static const char *enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", }; +-static const char *emi_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", }; ++static const char *emi_sels[] = { "pll2_pfd2_396m", "pll3_usb_otg", "axi", "pll2_pfd0_352m", }; ++static const char *emi_slow_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd2_396m", "pll2_pfd0_352m", }; + static const char *vdo_axi_sels[] = { "axi", "ahb", }; + static const char *vpu_axi_sels[] = { "axi", "pll2_pfd2_396m", "pll2_pfd0_352m", }; + static const char *cko1_sels[] = { "pll3_usb_otg", "pll2_bus", "pll1_sys", "pll5_video_div", + "dummy", "axi", "enfc", "ipu1_di0", "ipu1_di1", "ipu2_di0", +- "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_post_div", }; ++ "ipu2_di1", "ahb", "ipg", "ipg_per", "ckil", "pll4_audio_div", }; ++static const char *cko2_sels[] = { ++ "mmdc_ch0_axi", "mmdc_ch1_axi", "usdhc4", "usdhc1", ++ "gpu2d_axi", "dummy", "ecspi_root", "gpu3d_axi", ++ "usdhc3", "dummy", "arm", "ipu1", ++ "ipu2", "vdo_axi", "osc", "gpu2d_core", ++ "gpu3d_core", "usdhc2", "ssi1", "ssi2", ++ "ssi3", "gpu3d_shader", "vpu_axi", "can_root", ++ "ldb_di0", "ldb_di1", "esai", "eim_slow", ++ "uart_serial", "spdif", "asrc", "hsi_tx", ++}; ++static const char *cko_sels[] = { "cko1", "cko2", }; ++static const char *lvds_sels[] = { "arm", "pll1_sys", "dummy", "dummy", "dummy", "dummy", "dummy", "pll5_video_div", ++ "dummy", "dummy", "pcie_ref", "sata_ref", "usbphy1", "usbphy2", }; + + enum mx6q_clks { + dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m, +@@ -221,11 +89,11 @@ + periph_clk2, periph2_clk2, ipg, ipg_per, esai_pred, esai_podf, + asrc_pred, asrc_podf, spdif_pred, spdif_podf, can_root, ecspi_root, + gpu2d_core_podf, gpu3d_core_podf, gpu3d_shader, ipu1_podf, ipu2_podf, +- ldb_di0_podf, ldb_di1_podf, ipu1_di0_pre, ipu1_di1_pre, ipu2_di0_pre, +- ipu2_di1_pre, hsi_tx_podf, ssi1_pred, ssi1_podf, ssi2_pred, ssi2_podf, +- ssi3_pred, ssi3_podf, uart_serial_podf, usdhc1_podf, usdhc2_podf, +- usdhc3_podf, usdhc4_podf, enfc_pred, enfc_podf, emi_podf, +- emi_slow_podf, vpu_axi_podf, cko1_podf, axi, mmdc_ch0_axi_podf, ++ ldb_di0_podf_unused, ldb_di1_podf_unused, ipu1_di0_pre, ipu1_di1_pre, ++ ipu2_di0_pre, ipu2_di1_pre, hsi_tx_podf, ssi1_pred, ssi1_podf, ++ ssi2_pred, ssi2_podf, ssi3_pred, ssi3_podf, uart_serial_podf, ++ usdhc1_podf, usdhc2_podf, usdhc3_podf, usdhc4_podf, enfc_pred, enfc_podf, ++ emi_podf, emi_slow_podf, vpu_axi_podf, cko1_podf, axi, mmdc_ch0_axi_podf, + mmdc_ch1_axi_podf, arm, ahb, apbh_dma, asrc, can1_ipg, can1_serial, + can2_ipg, can2_serial, ecspi1, ecspi2, ecspi3, ecspi4, ecspi5, enet, + esai, gpt_ipg, gpt_ipg_per, gpu2d_core, gpu3d_core, hdmi_iahb, +@@ -238,14 +106,18 @@ + pll4_audio, pll5_video, pll8_mlb, pll7_usb_host, pll6_enet, ssi1_ipg, + ssi2_ipg, ssi3_ipg, rom, usbphy1, usbphy2, ldb_di0_div_3_5, ldb_di1_div_3_5, + sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate, +- usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, clk_max ++ usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow, ++ spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, gpt_3m, video_27m, ++ ldb_di0_div_7, ldb_di1_div_7, ldb_di0_div_sel, ldb_di1_div_sel, ++ pll4_audio_div, lvds1_sel, lvds1_in, lvds1_out, caam_mem, caam_aclk, ++ caam_ipg, epit1, epit2, tzasc2, clk_max + }; + + static struct clk *clk[clk_max]; + static struct clk_onecell_data clk_data; + + static enum mx6q_clks const clks_init_on[] __initconst = { +- mmdc_ch0_axi, rom, pll1_sys, ++ mmdc_ch0_axi, rom, arm, + }; + + static struct clk_div_table clk_enet_ref_table[] = { +@@ -270,34 +142,24 @@ + { } + }; + +-int __init mx6q_clocks_init(void) ++static void __init imx6q_clocks_init(struct device_node *ccm_node) + { + struct device_node *np; + void __iomem *base; + int i, irq; ++ int ret; + + clk[dummy] = imx_clk_fixed("dummy", 0); +- +- /* retrieve the freqency of fixed clocks from device tree */ +- for_each_compatible_node(np, NULL, "fixed-clock") { +- u32 rate; +- if (of_property_read_u32(np, "clock-frequency", &rate)) +- continue; +- +- if (of_device_is_compatible(np, "fsl,imx-ckil")) +- clk[ckil] = imx_clk_fixed("ckil", rate); +- else if (of_device_is_compatible(np, "fsl,imx-ckih1")) +- clk[ckih] = imx_clk_fixed("ckih", rate); +- else if (of_device_is_compatible(np, "fsl,imx-osc")) +- clk[osc] = imx_clk_fixed("osc", rate); +- } ++ clk[ckil] = imx_obtain_fixed_clock("ckil", 0); ++ clk[ckih] = imx_obtain_fixed_clock("ckih1", 0); ++ clk[osc] = imx_obtain_fixed_clock("osc", 0); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); + base = of_iomap(np, 0); + WARN_ON(!base); + + /* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */ +- if (cpu_is_imx6q() && imx6q_revision() == IMX_CHIP_REVISION_1_0) { ++ if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) { + post_div_table[1].div = 1; + post_div_table[2].div = 1; + video_div_table[1].div = 1; +@@ -305,14 +167,16 @@ + }; + + /* type name parent_name base div_mask */ +- clk[pll1_sys] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f); +- clk[pll2_bus] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc", base + 0x30, 0x1); +- clk[pll3_usb_otg] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc", base + 0x10, 0x3); +- clk[pll4_audio] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4_audio", "osc", base + 0x70, 0x7f); +- clk[pll5_video] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "osc", base + 0xa0, 0x7f); +- clk[pll6_enet] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6_enet", "osc", base + 0xe0, 0x3); +- clk[pll7_usb_host] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host","osc", base + 0x20, 0x3); +- clk[pll8_mlb] = imx_clk_pllv3(IMX_PLLV3_MLB, "pll8_mlb", "osc", base + 0xd0, 0x0); ++ clk[pll1_sys] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f, false); ++ clk[pll2_bus] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc", base + 0x30, 0x1, false); ++ clk[pll3_usb_otg] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc", base + 0x10, 0x3, false); ++ clk[pll4_audio] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4_audio", "osc", base + 0x70, 0x7f, false); ++ clk[pll5_video] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "osc", base + 0xa0, 0x7f, false); ++ clk[pll6_enet] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6_enet", "osc", base + 0xe0, 0x3, false); ++ clk[pll7_usb_host] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host", "osc", base + 0x20, 0x3, false); ++ ++ /* name reg shift width parent_names num_parents */ ++ clk[lvds1_sel] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); + + /* + * Bit 20 is the reserved and read-only bit, we do this only for: +@@ -332,6 +196,9 @@ + + clk[sata_ref] = imx_clk_fixed_factor("sata_ref", "pll6_enet", 1, 5); + clk[pcie_ref] = imx_clk_fixed_factor("pcie_ref", "pll6_enet", 1, 4); ++ /* NOTICE: The gate of the lvds1 in/out is used to select the clk direction */ ++ clk[lvds1_in] = imx_clk_gate("lvds1_in", NULL, base + 0x160, 12); ++ clk[lvds1_out] = imx_clk_gate("lvds1_out", "lvds1_sel", base + 0x160, 10); + + clk[sata_ref_100m] = imx_clk_gate("sata_ref_100m", "sata_ref", base + 0xe0, 20); + clk[pcie_ref_125m] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19); +@@ -355,15 +222,18 @@ + clk[pll3_80m] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); + clk[pll3_60m] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); + clk[twd] = imx_clk_fixed_factor("twd", "arm", 1, 2); ++ clk[gpt_3m] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); ++ clk[video_27m] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20); + + clk[pll4_post_div] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); ++ clk[pll4_audio_div] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock); + clk[pll5_post_div] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); + clk[pll5_video_div] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); + +- np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ccm"); ++ np = ccm_node; + base = of_iomap(np, 0); + WARN_ON(!base); +- ccm_base = base; ++ imx6_pm_set_ccm_base(base); + + /* name reg shift width parent_names num_parents */ + clk[step] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); +@@ -385,29 +255,33 @@ + clk[ipu2_sel] = imx_clk_mux("ipu2_sel", base + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels)); + clk[ldb_di0_sel] = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT); + clk[ldb_di1_sel] = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT); +- clk[ipu1_di0_pre_sel] = imx_clk_mux("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); +- clk[ipu1_di1_pre_sel] = imx_clk_mux("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); +- clk[ipu2_di0_pre_sel] = imx_clk_mux("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); +- clk[ipu2_di1_pre_sel] = imx_clk_mux("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels)); +- clk[ipu1_di0_sel] = imx_clk_mux("ipu1_di0_sel", base + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels)); +- clk[ipu1_di1_sel] = imx_clk_mux("ipu1_di1_sel", base + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels)); +- clk[ipu2_di0_sel] = imx_clk_mux("ipu2_di0_sel", base + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels)); +- clk[ipu2_di1_sel] = imx_clk_mux("ipu2_di1_sel", base + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels)); ++ clk[ldb_di0_div_sel] = imx_clk_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT); ++ clk[ldb_di1_div_sel] = imx_clk_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT); ++ clk[ipu1_di0_pre_sel] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); ++ clk[ipu1_di1_pre_sel] = imx_clk_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); ++ clk[ipu2_di0_pre_sel] = imx_clk_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); ++ clk[ipu2_di1_pre_sel] = imx_clk_mux_flags("ipu2_di1_pre_sel", base + 0x38, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT); ++ clk[ipu1_di0_sel] = imx_clk_mux_flags("ipu1_di0_sel", base + 0x34, 0, 3, ipu1_di0_sels, ARRAY_SIZE(ipu1_di0_sels), CLK_SET_RATE_PARENT); ++ clk[ipu1_di1_sel] = imx_clk_mux_flags("ipu1_di1_sel", base + 0x34, 9, 3, ipu1_di1_sels, ARRAY_SIZE(ipu1_di1_sels), CLK_SET_RATE_PARENT); ++ clk[ipu2_di0_sel] = imx_clk_mux_flags("ipu2_di0_sel", base + 0x38, 0, 3, ipu2_di0_sels, ARRAY_SIZE(ipu2_di0_sels), CLK_SET_RATE_PARENT); ++ clk[ipu2_di1_sel] = imx_clk_mux_flags("ipu2_di1_sel", base + 0x38, 9, 3, ipu2_di1_sels, ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT); + clk[hsi_tx_sel] = imx_clk_mux("hsi_tx_sel", base + 0x30, 28, 1, hsi_tx_sels, ARRAY_SIZE(hsi_tx_sels)); + clk[pcie_axi_sel] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels)); +- clk[ssi1_sel] = imx_clk_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); +- clk[ssi2_sel] = imx_clk_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); +- clk[ssi3_sel] = imx_clk_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels)); +- clk[usdhc1_sel] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); +- clk[usdhc2_sel] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); +- clk[usdhc3_sel] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); +- clk[usdhc4_sel] = imx_clk_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels)); ++ clk[ssi1_sel] = imx_clk_fixup_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); ++ clk[ssi2_sel] = imx_clk_fixup_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); ++ clk[ssi3_sel] = imx_clk_fixup_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); ++ clk[usdhc1_sel] = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); ++ clk[usdhc2_sel] = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); ++ clk[usdhc3_sel] = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); ++ clk[usdhc4_sel] = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); + clk[enfc_sel] = imx_clk_mux("enfc_sel", base + 0x2c, 16, 2, enfc_sels, ARRAY_SIZE(enfc_sels)); +- clk[emi_sel] = imx_clk_mux("emi_sel", base + 0x1c, 27, 2, emi_sels, ARRAY_SIZE(emi_sels)); +- clk[emi_slow_sel] = imx_clk_mux("emi_slow_sel", base + 0x1c, 29, 2, emi_sels, ARRAY_SIZE(emi_sels)); ++ clk[emi_sel] = imx_clk_fixup_mux("emi_sel", base + 0x1c, 27, 2, emi_sels, ARRAY_SIZE(emi_sels), imx_cscmr1_fixup); ++ clk[emi_slow_sel] = imx_clk_fixup_mux("emi_slow_sel", base + 0x1c, 29, 2, emi_slow_sels, ARRAY_SIZE(emi_slow_sels), imx_cscmr1_fixup); + clk[vdo_axi_sel] = imx_clk_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels)); + clk[vpu_axi_sel] = imx_clk_mux("vpu_axi_sel", base + 0x18, 14, 2, vpu_axi_sels, ARRAY_SIZE(vpu_axi_sels)); + clk[cko1_sel] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels)); ++ clk[cko2_sel] = imx_clk_mux("cko2_sel", base + 0x60, 16, 5, cko2_sels, ARRAY_SIZE(cko2_sels)); ++ clk[cko] = imx_clk_mux("cko", base + 0x60, 8, 1, cko_sels, ARRAY_SIZE(cko_sels)); + + /* name reg shift width busy: reg, shift parent_names num_parents */ + clk[periph] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); +@@ -417,7 +291,7 @@ + clk[periph_clk2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); + clk[periph2_clk2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); + clk[ipg] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); +- clk[ipg_per] = imx_clk_divider("ipg_per", "ipg", base + 0x1c, 0, 6); ++ clk[ipg_per] = imx_clk_fixup_divider("ipg_per", "ipg", base + 0x1c, 0, 6, imx_cscmr1_fixup); + clk[esai_pred] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3); + clk[esai_podf] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3); + clk[asrc_pred] = imx_clk_divider("asrc_pred", "asrc_sel", base + 0x30, 12, 3); +@@ -432,9 +306,9 @@ + clk[ipu1_podf] = imx_clk_divider("ipu1_podf", "ipu1_sel", base + 0x3c, 11, 3); + clk[ipu2_podf] = imx_clk_divider("ipu2_podf", "ipu2_sel", base + 0x3c, 16, 3); + clk[ldb_di0_div_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7); +- clk[ldb_di0_podf] = imx_clk_divider_flags("ldb_di0_podf", "ldb_di0_div_3_5", base + 0x20, 10, 1, 0); ++ clk[ldb_di0_div_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7); + clk[ldb_di1_div_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7); +- clk[ldb_di1_podf] = imx_clk_divider_flags("ldb_di1_podf", "ldb_di1_div_3_5", base + 0x20, 11, 1, 0); ++ clk[ldb_di1_div_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7); + clk[ipu1_di0_pre] = imx_clk_divider("ipu1_di0_pre", "ipu1_di0_pre_sel", base + 0x34, 3, 3); + clk[ipu1_di1_pre] = imx_clk_divider("ipu1_di1_pre", "ipu1_di1_pre_sel", base + 0x34, 12, 3); + clk[ipu2_di0_pre] = imx_clk_divider("ipu2_di0_pre", "ipu2_di0_pre_sel", base + 0x38, 3, 3); +@@ -453,10 +327,11 @@ + clk[usdhc4_podf] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); + clk[enfc_pred] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3); + clk[enfc_podf] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6); +- clk[emi_podf] = imx_clk_divider("emi_podf", "emi_sel", base + 0x1c, 20, 3); +- clk[emi_slow_podf] = imx_clk_divider("emi_slow_podf", "emi_slow_sel", base + 0x1c, 23, 3); ++ clk[emi_podf] = imx_clk_fixup_divider("emi_podf", "emi_sel", base + 0x1c, 20, 3, imx_cscmr1_fixup); ++ clk[emi_slow_podf] = imx_clk_fixup_divider("emi_slow_podf", "emi_slow_sel", base + 0x1c, 23, 3, imx_cscmr1_fixup); + clk[vpu_axi_podf] = imx_clk_divider("vpu_axi_podf", "vpu_axi_sel", base + 0x24, 25, 3); + clk[cko1_podf] = imx_clk_divider("cko1_podf", "cko1_sel", base + 0x60, 4, 3); ++ clk[cko2_podf] = imx_clk_divider("cko2_podf", "cko2_sel", base + 0x60, 21, 3); + + /* name parent_name reg shift width busy: reg, shift */ + clk[axi] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0); +@@ -468,6 +343,9 @@ + /* name parent_name reg shift */ + clk[apbh_dma] = imx_clk_gate2("apbh_dma", "usdhc3", base + 0x68, 4); + clk[asrc] = imx_clk_gate2("asrc", "asrc_podf", base + 0x68, 6); ++ clk[caam_mem] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8); ++ clk[caam_aclk] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10); ++ clk[caam_ipg] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12); + clk[can1_ipg] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14); + clk[can1_serial] = imx_clk_gate2("can1_serial", "can_root", base + 0x68, 16); + clk[can2_ipg] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18); +@@ -478,10 +356,19 @@ + clk[ecspi4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6); + clk[ecspi5] = imx_clk_gate2("ecspi5", "ecspi_root", base + 0x6c, 8); + clk[enet] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10); ++ clk[epit1] = imx_clk_gate2("epit1", "ipg", base + 0x6c, 12); ++ clk[epit2] = imx_clk_gate2("epit2", "ipg", base + 0x6c, 14); + clk[esai] = imx_clk_gate2("esai", "esai_podf", base + 0x6c, 16); + clk[gpt_ipg] = imx_clk_gate2("gpt_ipg", "ipg", base + 0x6c, 20); + clk[gpt_ipg_per] = imx_clk_gate2("gpt_ipg_per", "ipg_per", base + 0x6c, 22); +- clk[gpu2d_core] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); ++ if (cpu_is_imx6dl()) ++ /* ++ * The multiplexer and divider of imx6q clock gpu3d_shader get ++ * redefined/reused as gpu2d_core_sel and gpu2d_core_podf on imx6dl. ++ */ ++ clk[gpu2d_core] = imx_clk_gate2("gpu2d_core", "gpu3d_shader", base + 0x6c, 24); ++ else ++ clk[gpu2d_core] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); + clk[gpu3d_core] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26); + clk[hdmi_iahb] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0); + clk[hdmi_isfr] = imx_clk_gate2("hdmi_isfr", "pll3_pfd1_540m", base + 0x70, 4); +@@ -490,16 +377,25 @@ + clk[i2c3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10); + clk[iim] = imx_clk_gate2("iim", "ipg", base + 0x70, 12); + clk[enfc] = imx_clk_gate2("enfc", "enfc_podf", base + 0x70, 14); ++ clk[tzasc2] = imx_clk_gate2("tzasc2", "mmdc_ch0_axi_podf", base + 0x70, 24); ++ clk[vdoa] = imx_clk_gate2("vdoa", "vdo_axi", base + 0x70, 26); + clk[ipu1] = imx_clk_gate2("ipu1", "ipu1_podf", base + 0x74, 0); + clk[ipu1_di0] = imx_clk_gate2("ipu1_di0", "ipu1_di0_sel", base + 0x74, 2); + clk[ipu1_di1] = imx_clk_gate2("ipu1_di1", "ipu1_di1_sel", base + 0x74, 4); + clk[ipu2] = imx_clk_gate2("ipu2", "ipu2_podf", base + 0x74, 6); + clk[ipu2_di0] = imx_clk_gate2("ipu2_di0", "ipu2_di0_sel", base + 0x74, 8); +- clk[ldb_di0] = imx_clk_gate2("ldb_di0", "ldb_di0_podf", base + 0x74, 12); +- clk[ldb_di1] = imx_clk_gate2("ldb_di1", "ldb_di1_podf", base + 0x74, 14); + clk[ipu2_di1] = imx_clk_gate2("ipu2_di1", "ipu2_di1_sel", base + 0x74, 10); ++ clk[ldb_di0] = imx_clk_gate2("ldb_di0", "ldb_di0_div_sel", base + 0x74, 12); ++ clk[ldb_di1] = imx_clk_gate2("ldb_di1", "ldb_di1_div_sel", base + 0x74, 14); + clk[hsi_tx] = imx_clk_gate2("hsi_tx", "hsi_tx_podf", base + 0x74, 16); +- clk[mlb] = imx_clk_gate2("mlb", "axi", base + 0x74, 18); ++ if (cpu_is_imx6dl()) ++ /* ++ * The multiplexer and divider of the imx6q clock gpu2d get ++ * redefined/reused as mlb_sys_sel and mlb_sys_clk_podf on imx6dl. ++ */ ++ clk[mlb] = imx_clk_gate2("mlb", "gpu2d_core_podf", base + 0x74, 18); ++ else ++ clk[mlb] = imx_clk_gate2("mlb", "axi", base + 0x74, 18); + clk[mmdc_ch0_axi] = imx_clk_gate2("mmdc_ch0_axi", "mmdc_ch0_axi_podf", base + 0x74, 20); + clk[mmdc_ch1_axi] = imx_clk_gate2("mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22); + clk[ocram] = imx_clk_gate2("ocram", "ahb", base + 0x74, 28); +@@ -518,9 +414,13 @@ + clk[sata] = imx_clk_gate2("sata", "ipg", base + 0x7c, 4); + clk[sdma] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); + clk[spba] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); ++ clk[spdif] = imx_clk_gate2("spdif", "spdif_podf", base + 0x7c, 14); + clk[ssi1_ipg] = imx_clk_gate2("ssi1_ipg", "ipg", base + 0x7c, 18); + clk[ssi2_ipg] = imx_clk_gate2("ssi2_ipg", "ipg", base + 0x7c, 20); + clk[ssi3_ipg] = imx_clk_gate2("ssi3_ipg", "ipg", base + 0x7c, 22); ++ clk[ssi1] = imx_clk_gate2("ssi1", "ssi1_podf", base + 0x7c, 18); ++ clk[ssi2] = imx_clk_gate2("ssi2", "ssi2_podf", base + 0x7c, 20); ++ clk[ssi3] = imx_clk_gate2("ssi3", "ssi3_podf", base + 0x7c, 22); + clk[uart_ipg] = imx_clk_gate2("uart_ipg", "ipg", base + 0x7c, 24); + clk[uart_serial] = imx_clk_gate2("uart_serial", "uart_serial_podf", base + 0x7c, 26); + clk[usboh3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); +@@ -528,31 +428,63 @@ + clk[usdhc2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); + clk[usdhc3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); + clk[usdhc4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8); ++ clk[eim_slow] = imx_clk_gate2("eim_slow", "emi_slow_podf", base + 0x80, 10); + clk[vdo_axi] = imx_clk_gate2("vdo_axi", "vdo_axi_sel", base + 0x80, 12); + clk[vpu_axi] = imx_clk_gate2("vpu_axi", "vpu_axi_podf", base + 0x80, 14); + clk[cko1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7); ++ clk[cko2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24); + + for (i = 0; i < ARRAY_SIZE(clk); i++) + if (IS_ERR(clk[i])) + pr_err("i.MX6q clk %d: register failed with %ld\n", + i, PTR_ERR(clk[i])); + ++ /* Initialize clock gate status */ ++ writel_relaxed(1 << CCM_CCGR_OFFSET(11) | ++ 3 << CCM_CCGR_OFFSET(1) | ++ 3 << CCM_CCGR_OFFSET(0), base + 0x68); ++ if (cpu_is_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) ++ writel_relaxed(3 << CCM_CCGR_OFFSET(11) | ++ 3 << CCM_CCGR_OFFSET(10), base + 0x6c); ++ else ++ writel_relaxed(3 << CCM_CCGR_OFFSET(10), base + 0x6c); ++ writel_relaxed(1 << CCM_CCGR_OFFSET(12) | ++ 3 << CCM_CCGR_OFFSET(11) | ++ 3 << CCM_CCGR_OFFSET(10) | ++ 3 << CCM_CCGR_OFFSET(9) | ++ 3 << CCM_CCGR_OFFSET(8), base + 0x70); ++ writel_relaxed(3 << CCM_CCGR_OFFSET(14) | ++ 1 << CCM_CCGR_OFFSET(13) | ++ 3 << CCM_CCGR_OFFSET(12) | ++ 1 << CCM_CCGR_OFFSET(11) | ++ 3 << CCM_CCGR_OFFSET(10), base + 0x74); ++ writel_relaxed(3 << CCM_CCGR_OFFSET(7) | ++ 3 << CCM_CCGR_OFFSET(6) | ++ 3 << CCM_CCGR_OFFSET(4), base + 0x78); ++ writel_relaxed(1 << CCM_CCGR_OFFSET(0), base + 0x7c); ++ writel_relaxed(0, base + 0x80); ++ + clk_data.clks = clk; + clk_data.clk_num = ARRAY_SIZE(clk); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + clk_register_clkdev(clk[gpt_ipg], "ipg", "imx-gpt.0"); + clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0"); ++ clk_register_clkdev(clk[gpt_3m], "gpt_3m", "imx-gpt.0"); + clk_register_clkdev(clk[cko1_sel], "cko1_sel", NULL); + clk_register_clkdev(clk[ahb], "ahb", NULL); + clk_register_clkdev(clk[cko1], "cko1", NULL); + clk_register_clkdev(clk[arm], NULL, "cpu0"); + +- if (imx6q_revision() != IMX_CHIP_REVISION_1_0) { ++ if ((imx_get_soc_revision() != IMX_CHIP_REVISION_1_0) || cpu_is_imx6dl()) { + clk_set_parent(clk[ldb_di0_sel], clk[pll5_video_div]); + clk_set_parent(clk[ldb_di1_sel], clk[pll5_video_div]); + } + ++ if (cpu_is_imx6dl()) { ++ clk_set_parent(clk[ipu1_sel], clk[pll3_pfd1_540m]); ++ } ++ + /* + * The gpmi needs 100MHz frequency in the EDO/Sync mode, + * We can not get the 100MHz from the pll2_pfd0_352m. +@@ -560,6 +492,20 @@ + */ + clk_set_parent(clk[enfc_sel], clk[pll2_pfd2_396m]); + ++ /* Set the parent clks of PCIe lvds1 and pcie_axi to be sata ref, axi */ ++ if (clk_set_parent(clk[lvds1_sel], clk[sata_ref])) ++ pr_err("Failed to set PCIe bus parent clk.\n"); ++ if (clk_set_parent(clk[pcie_axi_sel], clk[axi])) ++ pr_err("Failed to set PCIe parent clk.\n"); ++ ++ ++ /* gpu clock initilazation */ ++ clk_set_parent(clk[gpu3d_shader_sel], clk[pll2_pfd1_594m]); ++ clk_set_rate(clk[gpu3d_shader], 594000000); ++ clk_set_parent(clk[gpu3d_core_sel], clk[mmdc_ch0_axi]); ++ clk_set_rate(clk[gpu3d_core], 528000000); ++ clk_set_parent(clk[gpu2d_core_sel], clk[pll3_usb_otg]); ++ + for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) + clk_prepare_enable(clk[clks_init_on[i]]); + +@@ -568,14 +514,57 @@ + clk_prepare_enable(clk[usbphy2_gate]); + } + ++ /* ipu clock initialization */ ++ clk_set_parent(clk[ldb_di0_sel], clk[pll2_pfd0_352m]); ++ clk_set_parent(clk[ldb_di1_sel], clk[pll2_pfd0_352m]); ++ clk_set_parent(clk[ipu1_di0_pre_sel], clk[pll5_video_div]); ++ clk_set_parent(clk[ipu1_di1_pre_sel], clk[pll5_video_div]); ++ clk_set_parent(clk[ipu2_di0_pre_sel], clk[pll5_video_div]); ++ clk_set_parent(clk[ipu2_di1_pre_sel], clk[pll5_video_div]); ++ clk_set_parent(clk[ipu1_di0_sel], clk[ipu1_di0_pre]); ++ clk_set_parent(clk[ipu1_di1_sel], clk[ipu1_di1_pre]); ++ clk_set_parent(clk[ipu2_di0_sel], clk[ipu2_di0_pre]); ++ clk_set_parent(clk[ipu2_di1_sel], clk[ipu2_di1_pre]); ++ if (cpu_is_imx6dl()) { ++ clk_set_rate(clk[pll3_pfd1_540m], 540000000); ++ clk_set_parent(clk[ipu1_sel], clk[pll3_pfd1_540m]); ++ clk_set_parent(clk[axi_sel], clk[pll3_pfd1_540m]); ++ /* set epdc/pxp axi clock to 200Mhz */ ++ clk_set_parent(clk[ipu2_sel], clk[pll2_pfd2_396m]); ++ clk_set_rate(clk[ipu2], 200000000); ++ } else if (cpu_is_imx6q()) { ++ clk_set_parent(clk[ipu1_sel], clk[mmdc_ch0_axi]); ++ clk_set_parent(clk[ipu2_sel], clk[mmdc_ch0_axi]); ++ } ++ ++ /* ++ * Let's initially set up CLKO with OSC24M, since this configuration ++ * is widely used by imx6q board designs to clock audio codec. ++ */ ++ ret = clk_set_parent(clk[cko2_sel], clk[osc]); ++ if (!ret) ++ ret = clk_set_parent(clk[cko], clk[cko2]); ++ if (ret) ++ pr_warn("failed to set up CLKO: %d\n", ret); ++ ++ /* Audio clocks */ ++ clk_set_parent(clk[ssi1_sel], clk[pll4_audio_div]); ++ clk_set_parent(clk[ssi2_sel], clk[pll4_audio_div]); ++ clk_set_parent(clk[ssi3_sel], clk[pll4_audio_div]); ++ clk_set_parent(clk[spdif_sel], clk[pll3_pfd3_454m]); ++ clk_set_parent(clk[asrc_sel], clk[pll3_usb_otg]); ++ clk_set_rate(clk[asrc_sel], 7500000); ++ ++ /* Set pll4_audio to a value that can derive 5K-88.2KHz and 8K-96KHz */ ++ clk_set_rate(clk[pll4_audio_div], 541900800); ++ + /* Set initial power mode */ +- imx6q_set_lpm(WAIT_CLOCKED); ++ imx6_set_lpm(WAIT_CLOCKED); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); + base = of_iomap(np, 0); + WARN_ON(!base); + irq = irq_of_parse_and_map(np, 0); + mxc_timer_init(base, irq); +- +- return 0; + } ++CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init); +diff -Nur linux-3.10.30/arch/arm/mach-imx/clk-imx6sl.c linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-imx6sl.c +--- linux-3.10.30/arch/arm/mach-imx/clk-imx6sl.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-imx6sl.c 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,493 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#define CCM_CCDR_OFFSET 0x4 ++#define ANATOP_PLL_USB1 0x10 ++#define ANATOP_PLL_USB2 0x20 ++#define ANATOP_PLL_ENET 0xE0 ++#define ANATOP_PLL_BYPASS_OFFSET (1 << 16) ++#define ANATOP_PLL_ENABLE_OFFSET (1 << 13) ++#define ANATOP_PLL_POWER_OFFSET (1 << 12) ++#define ANATOP_PFD_480n_OFFSET 0xf0 ++#define ANATOP_PFD_528n_OFFSET 0x100 ++#define PFD0_CLKGATE (1 << 7) ++#define PFD1_CLK_GATE (1 << 15) ++#define PFD2_CLK_GATE (1 << 23) ++#define PFD3_CLK_GATE (1 << 31) ++#define CCDR_CH0_HS_BYP 17 ++#define OSC_RATE 24000000 ++ ++#define CCM_CCGR_OFFSET(index) (index * 2) ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "clk.h" ++#include "common.h" ++ ++static bool uart_from_osc; ++static const char const *step_sels[] = { "osc", "pll2_pfd2", }; ++static const char const *pll1_sw_sels[] = { "pll1_sys", "step", }; ++static const char const *ocram_alt_sels[] = { "pll2_pfd2", "pll3_pfd1", }; ++static const char const *ocram_sels[] = { "periph", "ocram_alt_sels", }; ++static const char const *pre_periph_sels[] = { "pll2_bus", "pll2_pfd2", "pll2_pfd0", "pll2_198m", }; ++static const char const *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy", }; ++static const char const *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", }; ++static const char const *periph_sels[] = { "pre_periph_sel", "periph_clk2", }; ++static const char const *periph2_sels[] = { "pre_periph2_sel", "periph2_clk2", }; ++static const char const *csi_sels[] = { "osc", "pll2_pfd2", "pll3_120m", "pll3_pfd1", }; ++static const char const *lcdif_axi_sels[] = { "pll2_bus", "pll2_pfd2", "pll3_usb_otg", "pll3_pfd1", }; ++static const char const *usdhc_sels[] = { "pll2_pfd2", "pll2_pfd0", }; ++static const char const *ssi_sels[] = { "pll3_pfd2", "pll3_pfd3", "pll4_audio_div", "dummy", }; ++static const char const *perclk_sels[] = { "ipg", "osc", }; ++static const char const *epdc_axi_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd2", "pll3_pfd2", }; ++static const char const *pxp_axi_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd2", "pll3_pfd3", }; ++static const char const *gpu2d_ovg_sels[] = { "pll3_pfd1", "pll3_usb_otg", "pll2_bus", "pll2_pfd2", }; ++static const char const *gpu2d_sels[] = { "pll2_pfd2", "pll3_usb_otg", "pll3_pfd1", "pll2_bus", }; ++static const char const *lcdif_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll3_pfd0", "pll3_pfd1", }; ++static const char const *epdc_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd1", "pll3_pfd1", }; ++static const char const *audio_sels[] = { "pll4_audio_div", "pll3_pfd2", "pll3_pfd3", "pll3_usb_otg", }; ++static const char const *ecspi_sels[] = { "pll3_60m", "osc", }; ++static const char const *uart_sels[] = { "pll3_80m", "uart_osc_4M", }; ++ ++static struct clk_div_table clk_enet_ref_table[] = { ++ { .val = 0, .div = 20, }, ++ { .val = 1, .div = 10, }, ++ { .val = 2, .div = 5, }, ++ { .val = 3, .div = 4, }, ++ { } ++}; ++ ++static struct clk_div_table post_div_table[] = { ++ { .val = 2, .div = 1, }, ++ { .val = 1, .div = 2, }, ++ { .val = 0, .div = 4, }, ++ { } ++}; ++ ++static struct clk_div_table video_div_table[] = { ++ { .val = 0, .div = 1, }, ++ { .val = 1, .div = 2, }, ++ { .val = 2, .div = 1, }, ++ { .val = 3, .div = 4, }, ++ { } ++}; ++ ++static struct clk *clks[IMX6SL_CLK_CLK_END]; ++static struct clk_onecell_data clk_data; ++static u32 cur_arm_podf; ++static u32 pll1_org_rate; ++ ++extern int low_bus_freq_mode; ++extern int audio_bus_freq_mode; ++ ++/* ++ * On MX6SL, need to ensure that the ARM:IPG clock ratio is maintained ++ * within 12:5 when the clocks to ARM are gated when the SOC enters ++ * WAIT mode. This is necessary to avoid WAIT mode issue (an early ++ * interrupt waking up the ARM). ++ * This function will set the ARM clk to max value within the 12:5 limit. ++ */ ++void imx6sl_set_wait_clk(bool enter) ++{ ++ u32 parent_rate; ++ ++ if (enter) { ++ u32 wait_podf; ++ u32 new_parent_rate = OSC_RATE; ++ u32 ipg_rate = clk_get_rate(clks[IMX6SL_CLK_IPG]); ++ u32 max_arm_wait_clk = (12 * ipg_rate) / 5; ++ parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]); ++ cur_arm_podf = parent_rate / clk_get_rate(clks[IMX6SL_CLK_ARM]); ++ if (low_bus_freq_mode) { ++ /* ++ * IPG clk is at 12MHz at this point, we can only run ++ * ARM at a max of 28.8MHz. So we need to set ARM ++ * to run from the 24MHz OSC, as there is no way to ++ * get 28.8MHz when ARM is sourced from PLL1. ++ */ ++ clk_set_parent(clks[IMX6SL_CLK_STEP], ++ clks[IMX6SL_CLK_OSC]); ++ clk_set_parent(clks[IMX6SL_CLK_PLL1_SW], ++ clks[IMX6SL_CLK_STEP]); ++ } else if (audio_bus_freq_mode) { ++ /* ++ * In this mode ARM is from PLL2_PFD2 (396MHz), ++ * but IPG is at 12MHz. Need to switch ARM to run ++ * from the bypassed PLL1 clocks so that we can run ++ * ARM at 24MHz. ++ */ ++ pll1_org_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SYS]); ++ /* Ensure PLL1 is at 24MHz. */ ++ clk_set_rate(clks[IMX6SL_CLK_PLL1_SYS], OSC_RATE); ++ clk_set_parent(clks[IMX6SL_CLK_PLL1_SW], clks[IMX6SL_CLK_PLL1_SYS]); ++ } else ++ new_parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]); ++ wait_podf = (new_parent_rate + max_arm_wait_clk - 1) / ++ max_arm_wait_clk; ++ ++ clk_set_rate(clks[IMX6SL_CLK_ARM], new_parent_rate / wait_podf); ++ } else { ++ if (low_bus_freq_mode) ++ /* Move ARM back to PLL1. */ ++ clk_set_parent(clks[IMX6SL_CLK_PLL1_SW], ++ clks[IMX6SL_CLK_PLL1_SYS]); ++ else if (audio_bus_freq_mode) { ++ /* Move ARM back to PLL2_PFD2 via STEP_CLK. */ ++ clk_set_parent(clks[IMX6SL_CLK_PLL1_SW], clks[IMX6SL_CLK_STEP]); ++ clk_set_rate(clks[IMX6SL_CLK_PLL1_SYS], pll1_org_rate); ++ } ++ parent_rate = clk_get_rate(clks[IMX6SL_CLK_PLL1_SW]); ++ clk_set_rate(clks[IMX6SL_CLK_ARM], parent_rate / cur_arm_podf); ++ } ++} ++ ++static int __init setup_uart_clk(char *uart_rate) ++{ ++ uart_from_osc = true; ++ return 1; ++} ++ ++__setup("uart_at_4M", setup_uart_clk); ++ ++static void __init imx6sl_clocks_init(struct device_node *ccm_node) ++{ ++ struct device_node *np; ++ void __iomem *base; ++ int irq; ++ int ret; ++ int i; ++ u32 reg; ++ ++ clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); ++ clks[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0); ++ clks[IMX6SL_CLK_OSC] = imx_obtain_fixed_clock("osc", 0); ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-anatop"); ++ base = of_iomap(np, 0); ++ WARN_ON(!base); ++ ++ /* type name parent base div_mask */ ++ clks[IMX6SL_CLK_PLL1_SYS] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_sys", "osc", base, 0x7f, true); ++ clks[IMX6SL_CLK_PLL2_BUS] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc", base + 0x30, 0x1, true); ++ clks[IMX6SL_CLK_PLL3_USB_OTG] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc", base + 0x10, 0x3, false); ++ clks[IMX6SL_CLK_PLL4_AUDIO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4_audio", "osc", base + 0x70, 0x7f, false); ++ clks[IMX6SL_CLK_PLL5_VIDEO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "osc", base + 0xa0, 0x7f, false); ++ clks[IMX6SL_CLK_PLL6_ENET] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6_enet", "osc", base + 0xe0, 0x3, false); ++ clks[IMX6SL_CLK_PLL7_USB_HOST] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host", "osc", base + 0x20, 0x3, false); ++ ++ /* ++ * usbphy1 and usbphy2 are implemented as dummy gates using reserve ++ * bit 20. They are used by phy driver to keep the refcount of ++ * parent PLL correct. usbphy1_gate and usbphy2_gate only needs to be ++ * turned on during boot, and software will not need to control it ++ * anymore after that. ++ */ ++ clks[IMX6SL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20); ++ clks[IMX6SL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20); ++ clks[IMX6SL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6); ++ clks[IMX6SL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6); ++ ++ /* dev name parent_name flags reg shift width div: flags, div_table lock */ ++ clks[IMX6SL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock); ++ clks[IMX6SL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock); ++ clks[IMX6SL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock); ++ clks[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock); ++ clks[IMX6SL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0, base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock); ++ ++ /* name parent_name reg idx */ ++ clks[IMX6SL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0", "pll2_bus", base + 0x100, 0); ++ clks[IMX6SL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1", "pll2_bus", base + 0x100, 1); ++ clks[IMX6SL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2", "pll2_bus", base + 0x100, 2); ++ clks[IMX6SL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0", "pll3_usb_otg", base + 0xf0, 0); ++ clks[IMX6SL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1", "pll3_usb_otg", base + 0xf0, 1); ++ clks[IMX6SL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2", "pll3_usb_otg", base + 0xf0, 2); ++ clks[IMX6SL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3", "pll3_usb_otg", base + 0xf0, 3); ++ ++ /* name parent_name mult div */ ++ clks[IMX6SL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2", 1, 2); ++ clks[IMX6SL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4); ++ clks[IMX6SL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6); ++ clks[IMX6SL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8); ++ clks[IMX6SL_CLK_UART_OSC_4M] = imx_clk_fixed_factor("uart_osc_4M", "osc", 1, 6); ++ ++ /* Ensure all PFDs but PLL2_PFD2 are disabled. */ ++ reg = readl_relaxed(base + ANATOP_PFD_480n_OFFSET); ++ reg |= (PFD0_CLKGATE | PFD1_CLK_GATE | PFD2_CLK_GATE | PFD3_CLK_GATE); ++ writel_relaxed(reg, base + ANATOP_PFD_480n_OFFSET); ++ reg = readl_relaxed(base + ANATOP_PFD_528n_OFFSET); ++ reg |= (PFD0_CLKGATE | PFD1_CLK_GATE); ++ writel_relaxed(reg, base + ANATOP_PFD_528n_OFFSET); ++ ++ /* Ensure Unused PLLs are disabled. */ ++ reg = readl_relaxed(base + ANATOP_PLL_USB1); ++ reg |= ANATOP_PLL_BYPASS_OFFSET; ++ reg &= ~(ANATOP_PLL_ENABLE_OFFSET | ANATOP_PLL_POWER_OFFSET); ++ writel_relaxed(reg, base + ANATOP_PLL_USB1); ++ ++ reg = readl_relaxed(base + ANATOP_PLL_USB2); ++ reg |= ANATOP_PLL_BYPASS_OFFSET; ++ reg &= ~(ANATOP_PLL_ENABLE_OFFSET | ANATOP_PLL_POWER_OFFSET); ++ writel_relaxed(reg, base + ANATOP_PLL_USB2); ++ ++ reg = readl_relaxed(base + ANATOP_PLL_ENET); ++ reg |= (ANATOP_PLL_BYPASS_OFFSET | ANATOP_PLL_POWER_OFFSET); ++ reg &= ~ANATOP_PLL_ENABLE_OFFSET; ++ writel_relaxed(reg, base + ANATOP_PLL_ENET); ++ ++ np = ccm_node; ++ base = of_iomap(np, 0); ++ WARN_ON(!base); ++ imx6_pm_set_ccm_base(base); ++ ++ /* name reg shift width parent_names num_parents */ ++ clks[IMX6SL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels)); ++ clks[IMX6SL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels)); ++ clks[IMX6SL_CLK_OCRAM_ALT_SEL] = imx_clk_mux("ocram_alt_sel", base + 0x14, 7, 1, ocram_alt_sels, ARRAY_SIZE(ocram_alt_sels)); ++ clks[IMX6SL_CLK_OCRAM_SEL] = imx_clk_mux("ocram_sel", base + 0x14, 6, 1, ocram_sels, ARRAY_SIZE(ocram_sels)); ++ clks[IMX6SL_CLK_PRE_PERIPH2_SEL] = imx_clk_mux("pre_periph2_sel", base + 0x18, 21, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels)); ++ clks[IMX6SL_CLK_PRE_PERIPH_SEL] = imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels)); ++ clks[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels)); ++ clks[IMX6SL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels)); ++ clks[IMX6SL_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels)); ++ clks[IMX6SL_CLK_LCDIF_AXI_SEL] = imx_clk_mux("lcdif_axi_sel", base + 0x3c, 14, 2, lcdif_axi_sels, ARRAY_SIZE(lcdif_axi_sels)); ++ clks[IMX6SL_CLK_USDHC1_SEL] = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); ++ clks[IMX6SL_CLK_USDHC2_SEL] = imx_clk_fixup_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); ++ clks[IMX6SL_CLK_USDHC3_SEL] = imx_clk_fixup_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); ++ clks[IMX6SL_CLK_USDHC4_SEL] = imx_clk_fixup_mux("usdhc4_sel", base + 0x1c, 19, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup); ++ clks[IMX6SL_CLK_SSI1_SEL] = imx_clk_fixup_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); ++ clks[IMX6SL_CLK_SSI2_SEL] = imx_clk_fixup_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); ++ clks[IMX6SL_CLK_SSI3_SEL] = imx_clk_fixup_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); ++ clks[IMX6SL_CLK_PERCLK_SEL] = imx_clk_fixup_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels), imx_cscmr1_fixup); ++ clks[IMX6SL_CLK_PXP_AXI_SEL] = imx_clk_mux("pxp_axi_sel", base + 0x34, 6, 3, pxp_axi_sels, ARRAY_SIZE(pxp_axi_sels)); ++ clks[IMX6SL_CLK_EPDC_AXI_SEL] = imx_clk_mux("epdc_axi_sel", base + 0x34, 15, 3, epdc_axi_sels, ARRAY_SIZE(epdc_axi_sels)); ++ clks[IMX6SL_CLK_GPU2D_OVG_SEL] = imx_clk_mux("gpu2d_ovg_sel", base + 0x18, 4, 2, gpu2d_ovg_sels, ARRAY_SIZE(gpu2d_ovg_sels)); ++ clks[IMX6SL_CLK_GPU2D_SEL] = imx_clk_mux("gpu2d_sel", base + 0x18, 8, 2, gpu2d_sels, ARRAY_SIZE(gpu2d_sels)); ++ clks[IMX6SL_CLK_LCDIF_PIX_SEL] = imx_clk_mux_flags("lcdif_pix_sel", base + 0x38, 6, 3, lcdif_pix_sels, ARRAY_SIZE(lcdif_pix_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SL_CLK_EPDC_PIX_SEL] = imx_clk_mux_flags("epdc_pix_sel", base + 0x38, 15, 3, epdc_pix_sels, ARRAY_SIZE(epdc_pix_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SL_CLK_SPDIF0_SEL] = imx_clk_mux("spdif0_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels)); ++ clks[IMX6SL_CLK_SPDIF1_SEL] = imx_clk_mux("spdif1_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels)); ++ clks[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux_flags("extern_audio_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels), CLK_SET_RATE_PARENT); ++ clks[IMX6SL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels)); ++ clks[IMX6SL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels)); ++ ++ /* name reg shift width busy: reg, shift parent_names num_parents */ ++ clks[IMX6SL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels)); ++ clks[IMX6SL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels)); ++ ++ /* name parent_name reg shift width */ ++ clks[IMX6SL_CLK_OCRAM_PODF] = imx_clk_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3); ++ clks[IMX6SL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3); ++ clks[IMX6SL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3); ++ clks[IMX6SL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2); ++ clks[IMX6SL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3); ++ clks[IMX6SL_CLK_LCDIF_AXI_PODF] = imx_clk_divider("lcdif_axi_podf", "lcdif_axi_sel", base + 0x3c, 16, 3); ++ clks[IMX6SL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3); ++ clks[IMX6SL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3); ++ clks[IMX6SL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3); ++ clks[IMX6SL_CLK_USDHC4_PODF] = imx_clk_divider("usdhc4_podf", "usdhc4_sel", base + 0x24, 22, 3); ++ clks[IMX6SL_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3); ++ clks[IMX6SL_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6); ++ clks[IMX6SL_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3); ++ clks[IMX6SL_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6); ++ clks[IMX6SL_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3); ++ clks[IMX6SL_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6); ++ clks[IMX6SL_CLK_PERCLK] = imx_clk_fixup_divider("perclk", "perclk_sel", base + 0x1c, 0, 6, imx_cscmr1_fixup); ++ clks[IMX6SL_CLK_PXP_AXI_PODF] = imx_clk_divider("pxp_axi_podf", "pxp_axi_sel", base + 0x34, 3, 3); ++ clks[IMX6SL_CLK_EPDC_AXI_PODF] = imx_clk_divider("epdc_axi_podf", "epdc_axi_sel", base + 0x34, 12, 3); ++ clks[IMX6SL_CLK_GPU2D_OVG_PODF] = imx_clk_divider("gpu2d_ovg_podf", "gpu2d_ovg_sel", base + 0x18, 26, 3); ++ clks[IMX6SL_CLK_GPU2D_PODF] = imx_clk_divider("gpu2d_podf", "gpu2d_sel", base + 0x18, 29, 3); ++ clks[IMX6SL_CLK_LCDIF_PIX_PRED] = imx_clk_divider("lcdif_pix_pred", "lcdif_pix_sel", base + 0x38, 3, 3); ++ clks[IMX6SL_CLK_EPDC_PIX_PRED] = imx_clk_divider("epdc_pix_pred", "epdc_pix_sel", base + 0x38, 12, 3); ++ clks[IMX6SL_CLK_LCDIF_PIX_PODF] = imx_clk_fixup_divider("lcdif_pix_podf", "lcdif_pix_pred", base + 0x1c, 20, 3, imx_cscmr1_fixup); ++ clks[IMX6SL_CLK_EPDC_PIX_PODF] = imx_clk_divider("epdc_pix_podf", "epdc_pix_pred", base + 0x18, 23, 3); ++ clks[IMX6SL_CLK_SPDIF0_PRED] = imx_clk_divider("spdif0_pred", "spdif0_sel", base + 0x30, 25, 3); ++ clks[IMX6SL_CLK_SPDIF0_PODF] = imx_clk_divider("spdif0_podf", "spdif0_pred", base + 0x30, 22, 3); ++ clks[IMX6SL_CLK_SPDIF1_PRED] = imx_clk_divider("spdif1_pred", "spdif1_sel", base + 0x30, 12, 3); ++ clks[IMX6SL_CLK_SPDIF1_PODF] = imx_clk_divider("spdif1_podf", "spdif1_pred", base + 0x30, 9, 3); ++ clks[IMX6SL_CLK_EXTERN_AUDIO_PRED] = imx_clk_divider("extern_audio_pred", "extern_audio_sel", base + 0x28, 9, 3); ++ clks[IMX6SL_CLK_EXTERN_AUDIO_PODF] = imx_clk_divider("extern_audio_podf", "extern_audio_pred", base + 0x28, 25, 3); ++ clks[IMX6SL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "ecspi_sel", base + 0x38, 19, 6); ++ clks[IMX6SL_CLK_UART_ROOT] = imx_clk_divider("uart_root", "uart_sel", base + 0x24, 0, 6); ++ ++ /* name parent_name reg shift width busy: reg, shift */ ++ clks[IMX6SL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); ++ clks[IMX6SL_CLK_MMDC_ROOT] = imx_clk_busy_divider("mmdc", "periph2", base + 0x14, 3, 3, base + 0x48, 2); ++ clks[IMX6SL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16); ++ ++ /* name parent_name reg shift */ ++ clks[IMX6SL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0); ++ clks[IMX6SL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2); ++ clks[IMX6SL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4); ++ clks[IMX6SL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_root", base + 0x6c, 6); ++ clks[IMX6SL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x6c, 10); ++ clks[IMX6SL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12); ++ clks[IMX6SL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14); ++ clks[IMX6SL_CLK_EXTERN_AUDIO] = imx_clk_gate2("extern_audio", "extern_audio_podf", base + 0x6c, 16); ++ clks[IMX6SL_CLK_GPT] = imx_clk_gate2("gpt", "perclk", base + 0x6c, 20); ++ clks[IMX6SL_CLK_GPT_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x6c, 22); ++ clks[IMX6SL_CLK_GPU2D_OVG] = imx_clk_gate2("gpu2d_ovg", "gpu2d_ovg_podf", base + 0x6c, 26); ++ clks[IMX6SL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6); ++ clks[IMX6SL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8); ++ clks[IMX6SL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); ++ clks[IMX6SL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); ++ clks[IMX6SL_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x74, 0); ++ clks[IMX6SL_CLK_PXP_AXI] = imx_clk_gate2("pxp_axi", "pxp_axi_podf", base + 0x74, 2); ++ clks[IMX6SL_CLK_EPDC_AXI] = imx_clk_gate2("epdc_axi", "epdc_axi_podf", base + 0x74, 4); ++ clks[IMX6SL_CLK_LCDIF_AXI] = imx_clk_gate2("lcdif_axi", "lcdif_axi_podf", base + 0x74, 6); ++ clks[IMX6SL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_pix_podf", base + 0x74, 8); ++ clks[IMX6SL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_pix_podf", base + 0x74, 10); ++ clks[IMX6SL_CLK_OCRAM] = imx_clk_gate2("ocram", "ocram_podf", base + 0x74, 28); ++ clks[IMX6SL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16); ++ clks[IMX6SL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18); ++ clks[IMX6SL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20); ++ clks[IMX6SL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22); ++ clks[IMX6SL_CLK_SDMA] = imx_clk_gate2("sdma", "ipg", base + 0x7c, 6); ++ clks[IMX6SL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12); ++ clks[IMX6SL_CLK_SPDIF] = imx_clk_gate2("spdif", "spdif0_podf", base + 0x7c, 14); ++ clks[IMX6SL_CLK_SSI1] = imx_clk_gate2("ssi1", "ssi1_podf", base + 0x7c, 18); ++ clks[IMX6SL_CLK_SSI2] = imx_clk_gate2("ssi2", "ssi2_podf", base + 0x7c, 20); ++ clks[IMX6SL_CLK_SSI3] = imx_clk_gate2("ssi3", "ssi3_podf", base + 0x7c, 22); ++ clks[IMX6SL_CLK_UART] = imx_clk_gate2("uart", "ipg", base + 0x7c, 24); ++ clks[IMX6SL_CLK_UART_SERIAL] = imx_clk_gate2("uart_serial", "uart_root", base + 0x7c, 26); ++ clks[IMX6SL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0); ++ clks[IMX6SL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2); ++ clks[IMX6SL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4); ++ clks[IMX6SL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6); ++ clks[IMX6SL_CLK_USDHC4] = imx_clk_gate2("usdhc4", "usdhc4_podf", base + 0x80, 8); ++ ++ for (i = 0; i < ARRAY_SIZE(clks); i++) ++ if (IS_ERR(clks[i])) ++ pr_err("i.MX6SL clk %d: register failed with %ld\n", ++ i, PTR_ERR(clks[i])); ++ ++ /* Initialize clock gate status */ ++ writel_relaxed(1 << CCM_CCGR_OFFSET(11) | ++ 3 << CCM_CCGR_OFFSET(1) | ++ 3 << CCM_CCGR_OFFSET(0), base + 0x68); ++ writel_relaxed(3 << CCM_CCGR_OFFSET(10), base + 0x6c); ++ writel_relaxed(1 << CCM_CCGR_OFFSET(11) | ++ 3 << CCM_CCGR_OFFSET(10) | ++ 3 << CCM_CCGR_OFFSET(9) | ++ 3 << CCM_CCGR_OFFSET(8), base + 0x70); ++ writel_relaxed(3 << CCM_CCGR_OFFSET(14) | ++ 3 << CCM_CCGR_OFFSET(13) | ++ 3 << CCM_CCGR_OFFSET(12) | ++ 3 << CCM_CCGR_OFFSET(11) | ++ 3 << CCM_CCGR_OFFSET(10), base + 0x74); ++ writel_relaxed(3 << CCM_CCGR_OFFSET(7) | ++ 3 << CCM_CCGR_OFFSET(4), base + 0x78); ++ writel_relaxed(1 << CCM_CCGR_OFFSET(0), base + 0x7c); ++ writel_relaxed(0, base + 0x80); ++ ++ clk_data.clks = clks; ++ clk_data.clk_num = ARRAY_SIZE(clks); ++ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); ++ ++ clk_register_clkdev(clks[IMX6SL_CLK_GPT], "ipg", "imx-gpt.0"); ++ clk_register_clkdev(clks[IMX6SL_CLK_GPT_SERIAL], "per", "imx-gpt.0"); ++ ++ /* Ensure the AHB clk is at 132MHz. */ ++ ret = clk_set_rate(clks[IMX6SL_CLK_AHB], 132000000); ++ if (ret) ++ pr_warn("%s: failed to set AHB clock rate %d\n", __func__, ret); ++ ++ /* ++ * To prevent the bus clock from being disabled accidently when ++ * clk_disable() gets called on child clock, let's increment the use ++ * count of IPG clock by initially calling clk_prepare_enable() on it. ++ */ ++ ret = clk_prepare_enable(clks[IMX6SL_CLK_IPG]); ++ if (ret) ++ pr_warn("%s: failed to enable IPG clock %d\n", __func__, ret); ++ ++ /* ++ * Make sure the ARM clk is enabled to maintain the correct usecount ++ * and enabling/disabling of parent PLLs. ++ */ ++ ret = clk_prepare_enable(clks[IMX6SL_CLK_ARM]); ++ if (ret) ++ pr_warn("%s: failed to enable ARM core clock %d\n", ++ __func__, ret); ++ ++ /* ++ * Make sure the MMDC clk is enabled to maintain the correct usecount ++ * and enabling/disabling of parent PLLs. ++ */ ++ ret = clk_prepare_enable(clks[IMX6SL_CLK_MMDC_ROOT]); ++ if (ret) ++ pr_warn("%s: failed to enable MMDC clock %d\n", ++ __func__, ret); ++ ++ if (IS_ENABLED(CONFIG_USB_MXS_PHY)) { ++ clk_prepare_enable(clks[IMX6SL_CLK_USBPHY1_GATE]); ++ clk_prepare_enable(clks[IMX6SL_CLK_USBPHY2_GATE]); ++ } ++ ++ clk_set_parent(clks[IMX6SL_CLK_GPU2D_OVG_SEL], ++ clks[IMX6SL_CLK_PLL2_BUS]); ++ clk_set_parent(clks[IMX6SL_CLK_GPU2D_SEL], clks[IMX6SL_CLK_PLL2_BUS]); ++ ++ /* Initialize Video PLLs to valid frequency (650MHz). */ ++ clk_set_rate(clks[IMX6SL_CLK_PLL5_VIDEO], 650000000); ++ /* set PLL5 video as lcdif pix parent clock */ ++ clk_set_parent(clks[IMX6SL_CLK_LCDIF_PIX_SEL], ++ clks[IMX6SL_CLK_PLL5_VIDEO_DIV]); ++ clk_set_parent(clks[IMX6SL_CLK_EPDC_PIX_SEL], ++ clks[IMX6SL_CLK_PLL5_VIDEO_DIV]); ++ ++ clk_set_parent(clks[IMX6SL_CLK_EPDC_AXI_SEL], clks[IMX6SL_CLK_PLL2_PFD2]); ++ clk_set_rate(clks[IMX6SL_CLK_EPDC_AXI], 200000000); ++ clk_set_parent(clks[IMX6SL_CLK_PXP_AXI_SEL], clks[IMX6SL_CLK_PLL2_PFD2]); ++ clk_set_rate(clks[IMX6SL_CLK_PXP_AXI], 200000000); ++ clk_set_parent(clks[IMX6SL_CLK_LCDIF_AXI_SEL], clks[IMX6SL_CLK_PLL2_PFD2]); ++ clk_set_rate(clks[IMX6SL_CLK_LCDIF_AXI], 200000000); ++ ++ /* Audio clocks */ ++ clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]); ++ ++ /* set extern_audio to be sourced from PLL4/audio PLL */ ++ clk_set_parent(clks[IMX6SL_CLK_EXTERN_AUDIO_SEL], clks[IMX6SL_CLK_PLL4_AUDIO_DIV]); ++ /* set extern_audio to 24MHz */ ++ clk_set_rate(clks[IMX6SL_CLK_PLL4_AUDIO], 24000000); ++ clk_set_rate(clks[IMX6SL_CLK_EXTERN_AUDIO], 24000000); ++ ++ /* set SSI2 parent to PLL4 */ ++ clk_set_parent(clks[IMX6SL_CLK_SSI2_SEL], clks[IMX6SL_CLK_PLL4_AUDIO_DIV]); ++ clk_set_rate(clks[IMX6SL_CLK_SSI2], 24000000); ++ ++ /* set perclk to source from OSC 24MHz */ ++ clk_set_parent(clks[IMX6SL_CLK_PERCLK_SEL], clks[IMX6SL_CLK_OSC]); ++ ++ /* Set initial power mode */ ++ imx6_set_lpm(WAIT_CLOCKED); ++ ++ /* Ensure that CH0 handshake is bypassed. */ ++ reg = readl_relaxed(base + CCM_CCDR_OFFSET); ++ reg |= 1 << CCDR_CH0_HS_BYP; ++ writel_relaxed(reg, base + CCM_CCDR_OFFSET); ++ ++ /* Set the UART parent if needed. */ ++ if (uart_from_osc) ++ ret = clk_set_parent(clks[IMX6SL_CLK_UART_SEL], clks[IMX6SL_CLK_UART_OSC_4M]); ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-gpt"); ++ base = of_iomap(np, 0); ++ WARN_ON(!base); ++ irq = irq_of_parse_and_map(np, 0); ++ mxc_timer_init(base, irq); ++} ++CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init); +diff -Nur linux-3.10.30/arch/arm/mach-imx/clk-pfd.c linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-pfd.c +--- linux-3.10.30/arch/arm/mach-imx/clk-pfd.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-pfd.c 2014-03-08 20:32:54.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2012 Freescale Semiconductor, Inc. ++ * Copyright 2012-2013 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -17,6 +17,8 @@ + #include + #include "clk.h" + ++#define BYPASS_RATE 24000000 ++ + /** + * struct clk_pfd - IMX PFD clock + * @clk_hw: clock source +@@ -62,9 +64,14 @@ + u64 tmp = parent_rate; + u8 frac = (readl_relaxed(pfd->reg) >> (pfd->idx * 8)) & 0x3f; + +- tmp *= 18; +- do_div(tmp, frac); +- ++ /* ++ * If the parent PLL is in bypass state, the PFDs ++ * are also in bypass state. ++ */ ++ if (tmp != BYPASS_RATE) { ++ tmp *= 18; ++ do_div(tmp, frac); ++ } + return tmp; + } + +@@ -74,17 +81,22 @@ + u64 tmp = *prate; + u8 frac; + +- tmp = tmp * 18 + rate / 2; +- do_div(tmp, rate); +- frac = tmp; +- if (frac < 12) +- frac = 12; +- else if (frac > 35) +- frac = 35; +- tmp = *prate; +- tmp *= 18; +- do_div(tmp, frac); +- ++ /* ++ * If the parent PLL is in bypass state, the PFDs ++ * are also in bypass state. ++ */ ++ if (tmp != BYPASS_RATE) { ++ tmp = tmp * 18 + rate / 2; ++ do_div(tmp, rate); ++ frac = tmp; ++ if (frac < 12) ++ frac = 12; ++ else if (frac > 35) ++ frac = 35; ++ tmp = *prate; ++ tmp *= 18; ++ do_div(tmp, frac); ++ } + return tmp; + } + +@@ -95,6 +107,9 @@ + u64 tmp = parent_rate; + u8 frac; + ++ if (tmp == BYPASS_RATE) ++ return 0; ++ + tmp = tmp * 18 + rate / 2; + do_div(tmp, rate); + frac = tmp; +@@ -109,12 +124,24 @@ + return 0; + } + ++static int clk_pfd_is_enabled(struct clk_hw *hw) ++{ ++ struct clk_pfd *pfd = to_clk_pfd(hw); ++ ++ if (readl_relaxed(pfd->reg) & ++ (1 << ((pfd->idx + 1) * 8 - 1))) ++ return 0; ++ ++ return 1; ++} ++ + static const struct clk_ops clk_pfd_ops = { + .enable = clk_pfd_enable, + .disable = clk_pfd_disable, + .recalc_rate = clk_pfd_recalc_rate, + .round_rate = clk_pfd_round_rate, + .set_rate = clk_pfd_set_rate, ++ .is_enabled = clk_pfd_is_enabled, + }; + + struct clk *imx_clk_pfd(const char *name, const char *parent_name, +diff -Nur linux-3.10.30/arch/arm/mach-imx/clk-pllv3.c linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-pllv3.c +--- linux-3.10.30/arch/arm/mach-imx/clk-pllv3.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-pllv3.c 2014-03-08 20:32:54.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2012 Freescale Semiconductor, Inc. ++ * Copyright 2012-2013 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -25,12 +25,15 @@ + #define BM_PLL_ENABLE (0x1 << 13) + #define BM_PLL_BYPASS (0x1 << 16) + #define BM_PLL_LOCK (0x1 << 31) ++#define BYPASS_RATE 24000000 ++#define BYPASS_MASK 0x10000 + + /** + * struct clk_pllv3 - IMX PLL clock version 3 + * @clk_hw: clock source + * @base: base address of PLL registers + * @powerup_set: set POWER bit to power up the PLL ++ * @always_on : Leave the PLL powered up all the time. + * @div_mask: mask of divider bits + * + * IMX PLL clock version 3, found on i.MX6 series. Divider for pllv3 +@@ -40,52 +43,72 @@ + struct clk_hw hw; + void __iomem *base; + bool powerup_set; ++ bool always_on; + u32 div_mask; ++ u32 rate_req; + }; + + #define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw) + +-static int clk_pllv3_prepare(struct clk_hw *hw) ++static int clk_pllv3_wait_for_lock(struct clk_pllv3 *pll, u32 timeout_ms) + { +- struct clk_pllv3 *pll = to_clk_pllv3(hw); +- unsigned long timeout = jiffies + msecs_to_jiffies(10); +- u32 val; ++ unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); ++ u32 val = readl_relaxed(pll->base) & BM_PLL_POWER; + +- val = readl_relaxed(pll->base); +- val &= ~BM_PLL_BYPASS; +- if (pll->powerup_set) +- val |= BM_PLL_POWER; +- else +- val &= ~BM_PLL_POWER; +- writel_relaxed(val, pll->base); ++ /* No need to wait for lock when pll is power down */ ++ if ((pll->powerup_set && !val) || (!pll->powerup_set && val)) ++ return 0; + + /* Wait for PLL to lock */ +- while (!(readl_relaxed(pll->base) & BM_PLL_LOCK)) ++ do { ++ if (readl_relaxed(pll->base) & BM_PLL_LOCK) ++ break; + if (time_after(jiffies, timeout)) +- return -ETIMEDOUT; ++ break; ++ } while (1); + +- return 0; ++ if (readl_relaxed(pll->base) & BM_PLL_LOCK) ++ return 0; ++ else ++ return -ETIMEDOUT; + } + +-static void clk_pllv3_unprepare(struct clk_hw *hw) ++static int clk_pllv3_power_up_down(struct clk_hw *hw, bool enable) + { + struct clk_pllv3 *pll = to_clk_pllv3(hw); +- u32 val; ++ u32 val, ret = 0; + +- val = readl_relaxed(pll->base); +- val |= BM_PLL_BYPASS; +- if (pll->powerup_set) +- val &= ~BM_PLL_POWER; +- else +- val |= BM_PLL_POWER; +- writel_relaxed(val, pll->base); ++ if (enable) { ++ val = readl_relaxed(pll->base); ++ val &= ~BM_PLL_BYPASS; ++ if (pll->powerup_set) ++ val |= BM_PLL_POWER; ++ else ++ val &= ~BM_PLL_POWER; ++ writel_relaxed(val, pll->base); ++ ++ ret = clk_pllv3_wait_for_lock(pll, 10); ++ } else { ++ val = readl_relaxed(pll->base); ++ val |= BM_PLL_BYPASS; ++ if (pll->powerup_set) ++ val &= ~BM_PLL_POWER; ++ else ++ val |= BM_PLL_POWER; ++ writel_relaxed(val, pll->base); ++ } ++ return ret; + } + ++ + static int clk_pllv3_enable(struct clk_hw *hw) + { + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val; + ++ if (pll->rate_req != BYPASS_RATE) ++ clk_pllv3_power_up_down(hw, true); ++ + val = readl_relaxed(pll->base); + val |= BM_PLL_ENABLE; + writel_relaxed(val, pll->base); +@@ -99,8 +122,12 @@ + u32 val; + + val = readl_relaxed(pll->base); +- val &= ~BM_PLL_ENABLE; ++ if (!pll->always_on) ++ val &= ~BM_PLL_ENABLE; + writel_relaxed(val, pll->base); ++ ++ if (pll->rate_req != BYPASS_RATE) ++ clk_pllv3_power_up_down(hw, false); + } + + static unsigned long clk_pllv3_recalc_rate(struct clk_hw *hw, +@@ -108,8 +135,15 @@ + { + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 div = readl_relaxed(pll->base) & pll->div_mask; ++ u32 bypass = readl_relaxed(pll->base) & BYPASS_MASK; ++ u32 rate; ++ ++ if (pll->rate_req == BYPASS_RATE && bypass) ++ rate = BYPASS_RATE; ++ else ++ rate = (div == 1) ? parent_rate * 22 : parent_rate * 20; + +- return (div == 1) ? parent_rate * 22 : parent_rate * 20; ++ return rate; + } + + static long clk_pllv3_round_rate(struct clk_hw *hw, unsigned long rate, +@@ -117,6 +151,10 @@ + { + unsigned long parent_rate = *prate; + ++ /* If the PLL is bypassed, its rate is 24MHz. */ ++ if (rate == BYPASS_RATE) ++ return BYPASS_RATE; ++ + return (rate >= parent_rate * 22) ? parent_rate * 22 : + parent_rate * 20; + } +@@ -127,6 +165,22 @@ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 val, div; + ++ pll->rate_req = rate; ++ val = readl_relaxed(pll->base); ++ ++ /* If the PLL is bypassed, its rate is 24MHz. */ ++ if (rate == BYPASS_RATE) { ++ /* Set the bypass bit. */ ++ val |= BM_PLL_BYPASS; ++ /* Power down the PLL. */ ++ if (pll->powerup_set) ++ val &= ~BM_PLL_POWER; ++ else ++ val |= BM_PLL_POWER; ++ writel_relaxed(val, pll->base); ++ ++ return 0; ++ } + if (rate == parent_rate * 22) + div = 1; + else if (rate == parent_rate * 20) +@@ -139,12 +193,10 @@ + val |= div; + writel_relaxed(val, pll->base); + +- return 0; ++ return clk_pllv3_wait_for_lock(pll, 10); + } + + static const struct clk_ops clk_pllv3_ops = { +- .prepare = clk_pllv3_prepare, +- .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_recalc_rate, +@@ -157,6 +209,10 @@ + { + struct clk_pllv3 *pll = to_clk_pllv3(hw); + u32 div = readl_relaxed(pll->base) & pll->div_mask; ++ u32 bypass = readl_relaxed(pll->base) & BYPASS_MASK; ++ ++ if (pll->rate_req == BYPASS_RATE && bypass) ++ return BYPASS_RATE; + + return parent_rate * div / 2; + } +@@ -169,6 +225,9 @@ + unsigned long max_rate = parent_rate * 108 / 2; + u32 div; + ++ if (rate == BYPASS_RATE) ++ return BYPASS_RATE; ++ + if (rate > max_rate) + rate = max_rate; + else if (rate < min_rate) +@@ -186,21 +245,36 @@ + unsigned long max_rate = parent_rate * 108 / 2; + u32 val, div; + +- if (rate < min_rate || rate > max_rate) ++ if (rate != BYPASS_RATE && (rate < min_rate || rate > max_rate)) + return -EINVAL; + ++ pll->rate_req = rate; ++ val = readl_relaxed(pll->base); ++ ++ if (rate == BYPASS_RATE) { ++ /* ++ * Set the PLL in bypass mode if rate requested is ++ * BYPASS_RATE. ++ */ ++ val |= BM_PLL_BYPASS; ++ /* Power down the PLL. */ ++ if (pll->powerup_set) ++ val &= ~BM_PLL_POWER; ++ else ++ val |= BM_PLL_POWER; ++ writel_relaxed(val, pll->base); ++ return 0; ++ } + div = rate * 2 / parent_rate; + val = readl_relaxed(pll->base); + val &= ~pll->div_mask; + val |= div; + writel_relaxed(val, pll->base); + +- return 0; ++ return clk_pllv3_wait_for_lock(pll, 10); + } + + static const struct clk_ops clk_pllv3_sys_ops = { +- .prepare = clk_pllv3_prepare, +- .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_sys_recalc_rate, +@@ -215,6 +289,10 @@ + u32 mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET); + u32 mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET); + u32 div = readl_relaxed(pll->base) & pll->div_mask; ++ u32 bypass = readl_relaxed(pll->base) & BYPASS_MASK; ++ ++ if (pll->rate_req == BYPASS_RATE && bypass) ++ return BYPASS_RATE; + + return (parent_rate * div) + ((parent_rate / mfd) * mfn); + } +@@ -229,6 +307,9 @@ + u32 mfn, mfd = 1000000; + s64 temp64; + ++ if (rate == BYPASS_RATE) ++ return BYPASS_RATE; ++ + if (rate > max_rate) + rate = max_rate; + else if (rate < min_rate) +@@ -249,13 +330,36 @@ + struct clk_pllv3 *pll = to_clk_pllv3(hw); + unsigned long min_rate = parent_rate * 27; + unsigned long max_rate = parent_rate * 54; +- u32 val, div; ++ u32 val, newval, div; + u32 mfn, mfd = 1000000; + s64 temp64; ++ int ret; + +- if (rate < min_rate || rate > max_rate) ++ if (rate != BYPASS_RATE && (rate < min_rate || rate > max_rate)) + return -EINVAL; + ++ pll->rate_req = rate; ++ val = readl_relaxed(pll->base); ++ ++ if (rate == BYPASS_RATE) { ++ /* ++ * Set the PLL in bypass mode if rate requested is ++ * BYPASS_RATE. ++ */ ++ /* Bypass the PLL */ ++ val |= BM_PLL_BYPASS; ++ /* Power down the PLL. */ ++ if (pll->powerup_set) ++ val &= ~BM_PLL_POWER; ++ else ++ val |= BM_PLL_POWER; ++ writel_relaxed(val, pll->base); ++ return 0; ++ } ++ /* Else clear the bypass bit. */ ++ val &= ~BM_PLL_BYPASS; ++ writel_relaxed(val, pll->base); ++ + div = rate / parent_rate; + temp64 = (u64) (rate - div * parent_rate); + temp64 *= mfd; +@@ -263,18 +367,30 @@ + mfn = temp64; + + val = readl_relaxed(pll->base); +- val &= ~pll->div_mask; +- val |= div; +- writel_relaxed(val, pll->base); ++ ++ /* set the PLL into bypass mode */ ++ newval = val | BM_PLL_BYPASS; ++ writel_relaxed(newval, pll->base); ++ ++ /* configure the new frequency */ ++ newval &= ~pll->div_mask; ++ newval |= div; ++ writel_relaxed(newval, pll->base); + writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET); +- writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET); ++ writel(mfd, pll->base + PLL_DENOM_OFFSET); + +- return 0; ++ ret = clk_pllv3_wait_for_lock(pll, 10); ++ if (ret == 0 && val & BM_PLL_POWER) { ++ /* only if it locked can we switch back to the PLL */ ++ newval &= ~BM_PLL_BYPASS; ++ newval |= val & BM_PLL_BYPASS; ++ writel(newval, pll->base); ++ } ++ ++ return ret; + } + + static const struct clk_ops clk_pllv3_av_ops = { +- .prepare = clk_pllv3_prepare, +- .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_av_recalc_rate, +@@ -289,23 +405,19 @@ + } + + static const struct clk_ops clk_pllv3_enet_ops = { +- .prepare = clk_pllv3_prepare, +- .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + .recalc_rate = clk_pllv3_enet_recalc_rate, + }; + + static const struct clk_ops clk_pllv3_mlb_ops = { +- .prepare = clk_pllv3_prepare, +- .unprepare = clk_pllv3_unprepare, + .enable = clk_pllv3_enable, + .disable = clk_pllv3_disable, + }; + + struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, + const char *parent_name, void __iomem *base, +- u32 div_mask) ++ u32 div_mask, bool always_on) + { + struct clk_pllv3 *pll; + const struct clk_ops *ops; +@@ -338,6 +450,7 @@ + } + pll->base = base; + pll->div_mask = div_mask; ++ pll->always_on = always_on; + + init.name = name; + init.ops = ops; +diff -Nur linux-3.10.30/arch/arm/mach-imx/clk-vf610.c linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-vf610.c +--- linux-3.10.30/arch/arm/mach-imx/clk-vf610.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/clk-vf610.c 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,321 @@ ++/* ++ * Copyright 2012-2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ */ ++ ++#include ++#include ++#include ++ ++#include "clk.h" ++ ++#define CCM_CCR (ccm_base + 0x00) ++#define CCM_CSR (ccm_base + 0x04) ++#define CCM_CCSR (ccm_base + 0x08) ++#define CCM_CACRR (ccm_base + 0x0c) ++#define CCM_CSCMR1 (ccm_base + 0x10) ++#define CCM_CSCDR1 (ccm_base + 0x14) ++#define CCM_CSCDR2 (ccm_base + 0x18) ++#define CCM_CSCDR3 (ccm_base + 0x1c) ++#define CCM_CSCMR2 (ccm_base + 0x20) ++#define CCM_CSCDR4 (ccm_base + 0x24) ++#define CCM_CLPCR (ccm_base + 0x2c) ++#define CCM_CISR (ccm_base + 0x30) ++#define CCM_CIMR (ccm_base + 0x34) ++#define CCM_CGPR (ccm_base + 0x3c) ++#define CCM_CCGR0 (ccm_base + 0x40) ++#define CCM_CCGR1 (ccm_base + 0x44) ++#define CCM_CCGR2 (ccm_base + 0x48) ++#define CCM_CCGR3 (ccm_base + 0x4c) ++#define CCM_CCGR4 (ccm_base + 0x50) ++#define CCM_CCGR5 (ccm_base + 0x54) ++#define CCM_CCGR6 (ccm_base + 0x58) ++#define CCM_CCGR7 (ccm_base + 0x5c) ++#define CCM_CCGR8 (ccm_base + 0x60) ++#define CCM_CCGR9 (ccm_base + 0x64) ++#define CCM_CCGR10 (ccm_base + 0x68) ++#define CCM_CCGR11 (ccm_base + 0x6c) ++#define CCM_CMEOR0 (ccm_base + 0x70) ++#define CCM_CMEOR1 (ccm_base + 0x74) ++#define CCM_CMEOR2 (ccm_base + 0x78) ++#define CCM_CMEOR3 (ccm_base + 0x7c) ++#define CCM_CMEOR4 (ccm_base + 0x80) ++#define CCM_CMEOR5 (ccm_base + 0x84) ++#define CCM_CPPDSR (ccm_base + 0x88) ++#define CCM_CCOWR (ccm_base + 0x8c) ++#define CCM_CCPGR0 (ccm_base + 0x90) ++#define CCM_CCPGR1 (ccm_base + 0x94) ++#define CCM_CCPGR2 (ccm_base + 0x98) ++#define CCM_CCPGR3 (ccm_base + 0x9c) ++ ++#define CCM_CCGRx_CGn(n) ((n) * 2) ++ ++#define PFD_PLL1_BASE (anatop_base + 0x2b0) ++#define PFD_PLL2_BASE (anatop_base + 0x100) ++#define PFD_PLL3_BASE (anatop_base + 0xf0) ++ ++static void __iomem *anatop_base; ++static void __iomem *ccm_base; ++ ++/* sources for multiplexer clocks, this is used multiple times */ ++static const char const *fast_sels[] = { "firc", "fxosc", }; ++static const char const *slow_sels[] = { "sirc_32k", "sxosc", }; ++static const char const *pll1_sels[] = { "pll1_main", "pll1_pfd1", "pll1_pfd2", "pll1_pfd3", "pll1_pfd4", }; ++static const char const *pll2_sels[] = { "pll2_main", "pll2_pfd1", "pll2_pfd2", "pll2_pfd3", "pll2_pfd4", }; ++static const char const *sys_sels[] = { "fast_clk_sel", "slow_clk_sel", "pll2_pfd_sel", "pll2_main", "pll1_pfd_sel", "pll3_main", }; ++static const char const *ddr_sels[] = { "pll2_pfd2", "sys_sel", }; ++static const char const *rmii_sels[] = { "enet_ext", "audio_ext", "enet_50m", "enet_25m", }; ++static const char const *enet_ts_sels[] = { "enet_ext", "fxosc", "audio_ext", "usb", "enet_ts", "enet_25m", "enet_50m", }; ++static const char const *esai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_main_div", }; ++static const char const *sai_sels[] = { "audio_ext", "mlb", "spdif_rx", "pll4_main_div", }; ++static const char const *nfc_sels[] = { "platform_bus", "pll1_pfd1", "pll3_pfd1", "pll3_pfd3", }; ++static const char const *qspi_sels[] = { "pll3_main", "pll3_pfd4", "pll2_pfd4", "pll1_pfd4", }; ++static const char const *esdhc_sels[] = { "pll3_main", "pll3_pfd3", "pll1_pfd3", "platform_bus", }; ++static const char const *dcu_sels[] = { "pll1_pfd2", "pll3_main", }; ++static const char const *gpu_sels[] = { "pll2_pfd2", "pll3_pfd2", }; ++static const char const *vadc_sels[] = { "pll6_main_div", "pll3_main_div", "pll3_main", }; ++/* FTM counter clock source, not module clock */ ++static const char const *ftm_ext_sels[] = {"sirc_128k", "sxosc", "fxosc_half", "audio_ext", }; ++static const char const *ftm_fix_sels[] = { "sxosc", "ipg_bus", }; ++ ++static struct clk_div_table pll4_main_div_table[] = { ++ { .val = 0, .div = 1 }, ++ { .val = 1, .div = 2 }, ++ { .val = 2, .div = 6 }, ++ { .val = 3, .div = 8 }, ++ { .val = 4, .div = 10 }, ++ { .val = 5, .div = 12 }, ++ { .val = 6, .div = 14 }, ++ { .val = 7, .div = 16 }, ++ { } ++}; ++ ++static struct clk *clk[VF610_CLK_END]; ++static struct clk_onecell_data clk_data; ++ ++static void __init vf610_clocks_init(struct device_node *ccm_node) ++{ ++ struct device_node *np; ++ ++ clk[VF610_CLK_DUMMY] = imx_clk_fixed("dummy", 0); ++ clk[VF610_CLK_SIRC_128K] = imx_clk_fixed("sirc_128k", 128000); ++ clk[VF610_CLK_SIRC_32K] = imx_clk_fixed("sirc_32k", 32000); ++ clk[VF610_CLK_FIRC] = imx_clk_fixed("firc", 24000000); ++ ++ clk[VF610_CLK_SXOSC] = imx_obtain_fixed_clock("sxosc", 0); ++ clk[VF610_CLK_FXOSC] = imx_obtain_fixed_clock("fxosc", 0); ++ clk[VF610_CLK_AUDIO_EXT] = imx_obtain_fixed_clock("audio_ext", 0); ++ clk[VF610_CLK_ENET_EXT] = imx_obtain_fixed_clock("enet_ext", 0); ++ ++ clk[VF610_CLK_FXOSC_HALF] = imx_clk_fixed_factor("fxosc_half", "fxosc", 1, 2); ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop"); ++ anatop_base = of_iomap(np, 0); ++ BUG_ON(!anatop_base); ++ ++ np = ccm_node; ++ ccm_base = of_iomap(np, 0); ++ BUG_ON(!ccm_base); ++ ++ clk[VF610_CLK_SLOW_CLK_SEL] = imx_clk_mux("slow_clk_sel", CCM_CCSR, 4, 1, slow_sels, ARRAY_SIZE(slow_sels)); ++ clk[VF610_CLK_FASK_CLK_SEL] = imx_clk_mux("fast_clk_sel", CCM_CCSR, 5, 1, fast_sels, ARRAY_SIZE(fast_sels)); ++ ++ clk[VF610_CLK_PLL1_MAIN] = imx_clk_fixed_factor("pll1_main", "fast_clk_sel", 22, 1); ++ clk[VF610_CLK_PLL1_PFD1] = imx_clk_pfd("pll1_pfd1", "pll1_main", PFD_PLL1_BASE, 0); ++ clk[VF610_CLK_PLL1_PFD2] = imx_clk_pfd("pll1_pfd2", "pll1_main", PFD_PLL1_BASE, 1); ++ clk[VF610_CLK_PLL1_PFD3] = imx_clk_pfd("pll1_pfd3", "pll1_main", PFD_PLL1_BASE, 2); ++ clk[VF610_CLK_PLL1_PFD4] = imx_clk_pfd("pll1_pfd4", "pll1_main", PFD_PLL1_BASE, 3); ++ ++ clk[VF610_CLK_PLL2_MAIN] = imx_clk_fixed_factor("pll2_main", "fast_clk_sel", 22, 1); ++ clk[VF610_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1", "pll2_main", PFD_PLL2_BASE, 0); ++ clk[VF610_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2", "pll2_main", PFD_PLL2_BASE, 1); ++ clk[VF610_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3", "pll2_main", PFD_PLL2_BASE, 2); ++ clk[VF610_CLK_PLL2_PFD4] = imx_clk_pfd("pll2_pfd4", "pll2_main", PFD_PLL2_BASE, 3); ++ ++ clk[VF610_CLK_PLL3_MAIN] = imx_clk_fixed_factor("pll3_main", "fast_clk_sel", 20, 1); ++ clk[VF610_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1", "pll3_main", PFD_PLL3_BASE, 0); ++ clk[VF610_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2", "pll3_main", PFD_PLL3_BASE, 1); ++ clk[VF610_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3", "pll3_main", PFD_PLL3_BASE, 2); ++ clk[VF610_CLK_PLL3_PFD4] = imx_clk_pfd("pll3_pfd4", "pll3_main", PFD_PLL3_BASE, 3); ++ ++ clk[VF610_CLK_PLL4_MAIN] = imx_clk_fixed_factor("pll4_main", "fast_clk_sel", 25, 1); ++ /* Enet pll: fixed 50Mhz */ ++ clk[VF610_CLK_PLL5_MAIN] = imx_clk_fixed_factor("pll5_main", "fast_clk_sel", 125, 6); ++ /* pll6: default 960Mhz */ ++ clk[VF610_CLK_PLL6_MAIN] = imx_clk_fixed_factor("pll6_main", "fast_clk_sel", 40, 1); ++ clk[VF610_CLK_PLL1_PFD_SEL] = imx_clk_mux("pll1_pfd_sel", CCM_CCSR, 16, 3, pll1_sels, 5); ++ clk[VF610_CLK_PLL2_PFD_SEL] = imx_clk_mux("pll2_pfd_sel", CCM_CCSR, 19, 3, pll2_sels, 5); ++ clk[VF610_CLK_SYS_SEL] = imx_clk_mux("sys_sel", CCM_CCSR, 0, 3, sys_sels, ARRAY_SIZE(sys_sels)); ++ clk[VF610_CLK_DDR_SEL] = imx_clk_mux("ddr_sel", CCM_CCSR, 6, 1, ddr_sels, ARRAY_SIZE(ddr_sels)); ++ clk[VF610_CLK_SYS_BUS] = imx_clk_divider("sys_bus", "sys_sel", CCM_CACRR, 0, 3); ++ clk[VF610_CLK_PLATFORM_BUS] = imx_clk_divider("platform_bus", "sys_bus", CCM_CACRR, 3, 3); ++ clk[VF610_CLK_IPG_BUS] = imx_clk_divider("ipg_bus", "platform_bus", CCM_CACRR, 11, 2); ++ ++ clk[VF610_CLK_PLL3_MAIN_DIV] = imx_clk_divider("pll3_main_div", "pll3_main", CCM_CACRR, 20, 1); ++ clk[VF610_CLK_PLL4_MAIN_DIV] = clk_register_divider_table(NULL, "pll4_main_div", "pll4_main", 0, CCM_CACRR, 6, 3, 0, pll4_main_div_table, &imx_ccm_lock); ++ clk[VF610_CLK_PLL6_MAIN_DIV] = imx_clk_divider("pll6_main_div", "pll6_main", CCM_CACRR, 21, 1); ++ ++ clk[VF610_CLK_USBC0] = imx_clk_gate2("usbc0", "pll3_main", CCM_CCGR1, CCM_CCGRx_CGn(4)); ++ clk[VF610_CLK_USBC1] = imx_clk_gate2("usbc1", "pll3_main", CCM_CCGR7, CCM_CCGRx_CGn(4)); ++ ++ clk[VF610_CLK_QSPI0_SEL] = imx_clk_mux("qspi0_sel", CCM_CSCMR1, 22, 2, qspi_sels, 4); ++ clk[VF610_CLK_QSPI0_EN] = imx_clk_gate("qspi0_en", "qspi0_sel", CCM_CSCDR3, 4); ++ clk[VF610_CLK_QSPI0_X4_DIV] = imx_clk_divider("qspi0_x4", "qspi0_en", CCM_CSCDR3, 0, 2); ++ clk[VF610_CLK_QSPI0_X2_DIV] = imx_clk_divider("qspi0_x2", "qspi0_x4", CCM_CSCDR3, 2, 1); ++ clk[VF610_CLK_QSPI0_X1_DIV] = imx_clk_divider("qspi0_x1", "qspi0_x2", CCM_CSCDR3, 3, 1); ++ clk[VF610_CLK_QSPI0] = imx_clk_gate2("qspi0", "qspi0_x1", CCM_CCGR2, CCM_CCGRx_CGn(4)); ++ ++ clk[VF610_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", CCM_CSCMR1, 24, 2, qspi_sels, 4); ++ clk[VF610_CLK_QSPI1_EN] = imx_clk_gate("qspi1_en", "qspi1_sel", CCM_CSCDR3, 12); ++ clk[VF610_CLK_QSPI1_X4_DIV] = imx_clk_divider("qspi1_x4", "qspi1_en", CCM_CSCDR3, 8, 2); ++ clk[VF610_CLK_QSPI1_X2_DIV] = imx_clk_divider("qspi1_x2", "qspi1_x4", CCM_CSCDR3, 10, 1); ++ clk[VF610_CLK_QSPI1_X1_DIV] = imx_clk_divider("qspi1_x1", "qspi1_x2", CCM_CSCDR3, 11, 1); ++ clk[VF610_CLK_QSPI1] = imx_clk_gate2("qspi1", "qspi1_x1", CCM_CCGR8, CCM_CCGRx_CGn(4)); ++ ++ clk[VF610_CLK_ENET_50M] = imx_clk_fixed_factor("enet_50m", "pll5_main", 1, 10); ++ clk[VF610_CLK_ENET_25M] = imx_clk_fixed_factor("enet_25m", "pll5_main", 1, 20); ++ clk[VF610_CLK_ENET_SEL] = imx_clk_mux("enet_sel", CCM_CSCMR2, 4, 2, rmii_sels, 4); ++ clk[VF610_CLK_ENET_TS_SEL] = imx_clk_mux("enet_ts_sel", CCM_CSCMR2, 0, 3, enet_ts_sels, 7); ++ clk[VF610_CLK_ENET] = imx_clk_gate("enet", "enet_sel", CCM_CSCDR1, 24); ++ clk[VF610_CLK_ENET_TS] = imx_clk_gate("enet_ts", "enet_ts_sel", CCM_CSCDR1, 23); ++ clk[VF610_CLK_ENET0] = imx_clk_gate2("enet0", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(0)); ++ clk[VF610_CLK_ENET1] = imx_clk_gate2("enet1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(1)); ++ ++ clk[VF610_CLK_PIT] = imx_clk_gate2("pit", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(7)); ++ ++ clk[VF610_CLK_UART0] = imx_clk_gate2("uart0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(7)); ++ clk[VF610_CLK_UART1] = imx_clk_gate2("uart1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(8)); ++ clk[VF610_CLK_UART2] = imx_clk_gate2("uart2", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(9)); ++ clk[VF610_CLK_UART3] = imx_clk_gate2("uart3", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(10)); ++ ++ clk[VF610_CLK_I2C0] = imx_clk_gate2("i2c0", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(6)); ++ clk[VF610_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(7)); ++ ++ clk[VF610_CLK_DSPI0] = imx_clk_gate2("dspi0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(12)); ++ clk[VF610_CLK_DSPI1] = imx_clk_gate2("dspi1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(13)); ++ clk[VF610_CLK_DSPI2] = imx_clk_gate2("dspi2", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(12)); ++ clk[VF610_CLK_DSPI3] = imx_clk_gate2("dspi3", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(13)); ++ ++ clk[VF610_CLK_WDT] = imx_clk_gate2("wdt", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(14)); ++ ++ clk[VF610_CLK_ESDHC0_SEL] = imx_clk_mux("esdhc0_sel", CCM_CSCMR1, 16, 2, esdhc_sels, 4); ++ clk[VF610_CLK_ESDHC0_EN] = imx_clk_gate("esdhc0_en", "esdhc0_sel", CCM_CSCDR2, 28); ++ clk[VF610_CLK_ESDHC0_DIV] = imx_clk_divider("esdhc0_div", "esdhc0_en", CCM_CSCDR2, 16, 4); ++ clk[VF610_CLK_ESDHC0] = imx_clk_gate2("eshc0", "esdhc0_div", CCM_CCGR7, CCM_CCGRx_CGn(1)); ++ ++ clk[VF610_CLK_ESDHC1_SEL] = imx_clk_mux("esdhc1_sel", CCM_CSCMR1, 18, 2, esdhc_sels, 4); ++ clk[VF610_CLK_ESDHC1_EN] = imx_clk_gate("esdhc1_en", "esdhc1_sel", CCM_CSCDR2, 29); ++ clk[VF610_CLK_ESDHC1_DIV] = imx_clk_divider("esdhc1_div", "esdhc1_en", CCM_CSCDR2, 20, 4); ++ clk[VF610_CLK_ESDHC1] = imx_clk_gate2("eshc1", "esdhc1_div", CCM_CCGR7, CCM_CCGRx_CGn(2)); ++ ++ /* ++ * ftm_ext_clk and ftm_fix_clk are FTM timer counter's ++ * selectable clock sources, both use a common enable bit ++ * in CCM_CSCDR1, selecting "dummy" clock as parent of ++ * "ftm0_ext_fix" make it serve only for enable/disable. ++ */ ++ clk[VF610_CLK_FTM0_EXT_SEL] = imx_clk_mux("ftm0_ext_sel", CCM_CSCMR2, 6, 2, ftm_ext_sels, 4); ++ clk[VF610_CLK_FTM0_FIX_SEL] = imx_clk_mux("ftm0_fix_sel", CCM_CSCMR2, 14, 1, ftm_fix_sels, 2); ++ clk[VF610_CLK_FTM0_EXT_FIX_EN] = imx_clk_gate("ftm0_ext_fix_en", "dummy", CCM_CSCDR1, 25); ++ clk[VF610_CLK_FTM1_EXT_SEL] = imx_clk_mux("ftm1_ext_sel", CCM_CSCMR2, 8, 2, ftm_ext_sels, 4); ++ clk[VF610_CLK_FTM1_FIX_SEL] = imx_clk_mux("ftm1_fix_sel", CCM_CSCMR2, 15, 1, ftm_fix_sels, 2); ++ clk[VF610_CLK_FTM1_EXT_FIX_EN] = imx_clk_gate("ftm1_ext_fix_en", "dummy", CCM_CSCDR1, 26); ++ clk[VF610_CLK_FTM2_EXT_SEL] = imx_clk_mux("ftm2_ext_sel", CCM_CSCMR2, 10, 2, ftm_ext_sels, 4); ++ clk[VF610_CLK_FTM2_FIX_SEL] = imx_clk_mux("ftm2_fix_sel", CCM_CSCMR2, 16, 1, ftm_fix_sels, 2); ++ clk[VF610_CLK_FTM2_EXT_FIX_EN] = imx_clk_gate("ftm2_ext_fix_en", "dummy", CCM_CSCDR1, 27); ++ clk[VF610_CLK_FTM3_EXT_SEL] = imx_clk_mux("ftm3_ext_sel", CCM_CSCMR2, 12, 2, ftm_ext_sels, 4); ++ clk[VF610_CLK_FTM3_FIX_SEL] = imx_clk_mux("ftm3_fix_sel", CCM_CSCMR2, 17, 1, ftm_fix_sels, 2); ++ clk[VF610_CLK_FTM3_EXT_FIX_EN] = imx_clk_gate("ftm3_ext_fix_en", "dummy", CCM_CSCDR1, 28); ++ ++ /* ftm(n)_clk are FTM module operation clock */ ++ clk[VF610_CLK_FTM0] = imx_clk_gate2("ftm0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(8)); ++ clk[VF610_CLK_FTM1] = imx_clk_gate2("ftm1", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(9)); ++ clk[VF610_CLK_FTM2] = imx_clk_gate2("ftm2", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(8)); ++ clk[VF610_CLK_FTM3] = imx_clk_gate2("ftm3", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(9)); ++ ++ clk[VF610_CLK_DCU0_SEL] = imx_clk_mux("dcu0_sel", CCM_CSCMR1, 28, 1, dcu_sels, 2); ++ clk[VF610_CLK_DCU0_EN] = imx_clk_gate("dcu0_en", "dcu0_sel", CCM_CSCDR3, 19); ++ clk[VF610_CLK_DCU0_DIV] = imx_clk_divider("dcu0_div", "dcu0_en", CCM_CSCDR3, 16, 3); ++ clk[VF610_CLK_DCU0] = imx_clk_gate2("dcu0", "dcu0_div", CCM_CCGR3, CCM_CCGRx_CGn(8)); ++ clk[VF610_CLK_DCU1_SEL] = imx_clk_mux("dcu1_sel", CCM_CSCMR1, 29, 1, dcu_sels, 2); ++ clk[VF610_CLK_DCU1_EN] = imx_clk_gate("dcu1_en", "dcu1_sel", CCM_CSCDR3, 23); ++ clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en", CCM_CSCDR3, 20, 3); ++ clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "dcu1_div", CCM_CCGR9, CCM_CCGRx_CGn(8)); ++ ++ clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", CCM_CSCMR1, 20, 2, esai_sels, 4); ++ clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel", CCM_CSCDR2, 30); ++ clk[VF610_CLK_ESAI_DIV] = imx_clk_divider("esai_div", "esai_en", CCM_CSCDR2, 24, 4); ++ clk[VF610_CLK_ESAI] = imx_clk_gate2("esai", "esai_div", CCM_CCGR4, CCM_CCGRx_CGn(2)); ++ ++ clk[VF610_CLK_SAI0_SEL] = imx_clk_mux("sai0_sel", CCM_CSCMR1, 0, 2, sai_sels, 4); ++ clk[VF610_CLK_SAI0_EN] = imx_clk_gate("sai0_en", "sai0_sel", CCM_CSCDR1, 16); ++ clk[VF610_CLK_SAI0_DIV] = imx_clk_divider("sai0_div", "sai0_en", CCM_CSCDR1, 0, 4); ++ clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "sai0_div", CCM_CCGR0, CCM_CCGRx_CGn(15)); ++ ++ clk[VF610_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", CCM_CSCMR1, 2, 2, sai_sels, 4); ++ clk[VF610_CLK_SAI1_EN] = imx_clk_gate("sai1_en", "sai1_sel", CCM_CSCDR1, 17); ++ clk[VF610_CLK_SAI1_DIV] = imx_clk_divider("sai1_div", "sai1_en", CCM_CSCDR1, 4, 4); ++ clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "sai1_div", CCM_CCGR1, CCM_CCGRx_CGn(0)); ++ ++ clk[VF610_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", CCM_CSCMR1, 4, 2, sai_sels, 4); ++ clk[VF610_CLK_SAI2_EN] = imx_clk_gate("sai2_en", "sai2_sel", CCM_CSCDR1, 18); ++ clk[VF610_CLK_SAI2_DIV] = imx_clk_divider("sai2_div", "sai2_en", CCM_CSCDR1, 8, 4); ++ clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "sai2_div", CCM_CCGR1, CCM_CCGRx_CGn(1)); ++ ++ clk[VF610_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", CCM_CSCMR1, 6, 2, sai_sels, 4); ++ clk[VF610_CLK_SAI3_EN] = imx_clk_gate("sai3_en", "sai3_sel", CCM_CSCDR1, 19); ++ clk[VF610_CLK_SAI3_DIV] = imx_clk_divider("sai3_div", "sai3_en", CCM_CSCDR1, 12, 4); ++ clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "sai3_div", CCM_CCGR1, CCM_CCGRx_CGn(2)); ++ ++ clk[VF610_CLK_NFC_SEL] = imx_clk_mux("nfc_sel", CCM_CSCMR1, 12, 2, nfc_sels, 4); ++ clk[VF610_CLK_NFC_EN] = imx_clk_gate("nfc_en", "nfc_sel", CCM_CSCDR2, 9); ++ clk[VF610_CLK_NFC_PRE_DIV] = imx_clk_divider("nfc_pre_div", "nfc_en", CCM_CSCDR3, 13, 3); ++ clk[VF610_CLK_NFC_FRAC_DIV] = imx_clk_divider("nfc_frac_div", "nfc_pre_div", CCM_CSCDR2, 4, 4); ++ clk[VF610_CLK_NFC] = imx_clk_gate2("nfc", "nfc_frac_div", CCM_CCGR10, CCM_CCGRx_CGn(0)); ++ ++ clk[VF610_CLK_GPU_SEL] = imx_clk_mux("gpu_sel", CCM_CSCMR1, 14, 1, gpu_sels, 2); ++ clk[VF610_CLK_GPU_EN] = imx_clk_gate("gpu_en", "gpu_sel", CCM_CSCDR2, 10); ++ clk[VF610_CLK_GPU2D] = imx_clk_gate2("gpu", "gpu_en", CCM_CCGR8, CCM_CCGRx_CGn(15)); ++ ++ clk[VF610_CLK_VADC_SEL] = imx_clk_mux("vadc_sel", CCM_CSCMR1, 8, 2, vadc_sels, 3); ++ clk[VF610_CLK_VADC_EN] = imx_clk_gate("vadc_en", "vadc_sel", CCM_CSCDR1, 22); ++ clk[VF610_CLK_VADC_DIV] = imx_clk_divider("vadc_div", "vadc_en", CCM_CSCDR1, 20, 2); ++ clk[VF610_CLK_VADC_DIV_HALF] = imx_clk_fixed_factor("vadc_div_half", "vadc_div", 1, 2); ++ clk[VF610_CLK_VADC] = imx_clk_gate2("vadc", "vadc_div", CCM_CCGR8, CCM_CCGRx_CGn(7)); ++ ++ clk[VF610_CLK_ADC0] = imx_clk_gate2("adc0", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(11)); ++ clk[VF610_CLK_ADC1] = imx_clk_gate2("adc1", "ipg_bus", CCM_CCGR7, CCM_CCGRx_CGn(11)); ++ clk[VF610_CLK_DAC0] = imx_clk_gate2("dac0", "ipg_bus", CCM_CCGR8, CCM_CCGRx_CGn(12)); ++ clk[VF610_CLK_DAC1] = imx_clk_gate2("dac1", "ipg_bus", CCM_CCGR8, CCM_CCGRx_CGn(13)); ++ ++ clk[VF610_CLK_ASRC] = imx_clk_gate2("asrc", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(1)); ++ ++ clk[VF610_CLK_FLEXCAN0] = imx_clk_gate2("flexcan0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(0)); ++ clk[VF610_CLK_FLEXCAN1] = imx_clk_gate2("flexcan1", "ipg_bus", CCM_CCGR9, CCM_CCGRx_CGn(4)); ++ ++ clk_set_parent(clk[VF610_CLK_QSPI0_SEL], clk[VF610_CLK_PLL1_PFD4]); ++ clk_set_rate(clk[VF610_CLK_QSPI0_X4_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_SEL]) / 2); ++ clk_set_rate(clk[VF610_CLK_QSPI0_X2_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_X4_DIV]) / 2); ++ clk_set_rate(clk[VF610_CLK_QSPI0_X1_DIV], clk_get_rate(clk[VF610_CLK_QSPI0_X2_DIV]) / 2); ++ ++ clk_set_parent(clk[VF610_CLK_QSPI1_SEL], clk[VF610_CLK_PLL1_PFD4]); ++ clk_set_rate(clk[VF610_CLK_QSPI1_X4_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_SEL]) / 2); ++ clk_set_rate(clk[VF610_CLK_QSPI1_X2_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_X4_DIV]) / 2); ++ clk_set_rate(clk[VF610_CLK_QSPI1_X1_DIV], clk_get_rate(clk[VF610_CLK_QSPI1_X2_DIV]) / 2); ++ ++ clk_set_parent(clk[VF610_CLK_SAI0_SEL], clk[VF610_CLK_AUDIO_EXT]); ++ clk_set_parent(clk[VF610_CLK_SAI1_SEL], clk[VF610_CLK_AUDIO_EXT]); ++ clk_set_parent(clk[VF610_CLK_SAI2_SEL], clk[VF610_CLK_AUDIO_EXT]); ++ clk_set_parent(clk[VF610_CLK_SAI3_SEL], clk[VF610_CLK_AUDIO_EXT]); ++ ++ /* Add the clocks to provider list */ ++ clk_data.clks = clk; ++ clk_data.clk_num = ARRAY_SIZE(clk); ++ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); ++} ++CLK_OF_DECLARE(vf610, "fsl,vf610-ccm", vf610_clocks_init); +diff -Nur linux-3.10.30/arch/arm/mach-imx/clk.c linux-3.10.30-cubox-i/arch/arm/mach-imx/clk.c +--- linux-3.10.30/arch/arm/mach-imx/clk.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/clk.c 2014-03-08 20:32:54.000000000 +0100 +@@ -1,4 +1,65 @@ ++#include ++#include ++#include ++#include + #include + #include "clk.h" + + DEFINE_SPINLOCK(imx_ccm_lock); ++ ++static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name) ++{ ++ struct of_phandle_args phandle = {0}; ++ struct clk *clk = ERR_PTR(-ENODEV); ++ char *path; ++ ++ path = kasprintf(GFP_KERNEL, "/clocks/%s", name); ++ if (!path) ++ return ERR_PTR(-ENOMEM); ++ ++ phandle.np = of_find_node_by_path(path); ++ kfree(path); ++ ++ if (phandle.np) { ++ clk = of_clk_get_from_provider(&phandle); ++ of_node_put(phandle.np); ++ } ++ return clk; ++} ++ ++struct clk * __init imx_obtain_fixed_clock( ++ const char *name, unsigned long rate) ++{ ++ struct clk *clk; ++ ++ clk = imx_obtain_fixed_clock_from_dt(name); ++ if (IS_ERR(clk)) ++ clk = imx_clk_fixed(name, rate); ++ return clk; ++} ++ ++/* ++ * This fixups the register CCM_CSCMR1 write value. ++ * The write/read/divider values of the aclk_podf field ++ * of that register have the relationship described by ++ * the following table: ++ * ++ * write value read value divider ++ * 3b'000 3b'110 7 ++ * 3b'001 3b'111 8 ++ * 3b'010 3b'100 5 ++ * 3b'011 3b'101 6 ++ * 3b'100 3b'010 3 ++ * 3b'101 3b'011 4 ++ * 3b'110 3b'000 1 ++ * 3b'111 3b'001 2(default) ++ * ++ * That's why we do the xor operation below. ++ */ ++#define CSCMR1_FIXUP 0x00600000 ++ ++void imx_cscmr1_fixup(u32 *val) ++{ ++ *val ^= CSCMR1_FIXUP; ++ return; ++} +diff -Nur linux-3.10.30/arch/arm/mach-imx/clk.h linux-3.10.30-cubox-i/arch/arm/mach-imx/clk.h +--- linux-3.10.30/arch/arm/mach-imx/clk.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/clk.h 2014-03-08 20:32:54.000000000 +0100 +@@ -6,6 +6,8 @@ + + extern spinlock_t imx_ccm_lock; + ++extern void imx_cscmr1_fixup(u32 *val); ++ + struct clk *imx_clk_pllv1(const char *name, const char *parent, + void __iomem *base); + +@@ -22,13 +24,17 @@ + }; + + struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, +- const char *parent_name, void __iomem *base, u32 div_mask); ++ const char *parent_name, void __iomem *base, ++ u32 div_mask, bool always_on); + + struct clk *clk_register_gate2(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock); + ++struct clk * imx_obtain_fixed_clock( ++ const char *name, unsigned long rate); ++ + static inline struct clk *imx_clk_gate2(const char *name, const char *parent, + void __iomem *reg, u8 shift) + { +@@ -47,6 +53,14 @@ + u8 width, void __iomem *busy_reg, u8 busy_shift, + const char **parent_names, int num_parents); + ++struct clk *imx_clk_fixup_divider(const char *name, const char *parent, ++ void __iomem *reg, u8 shift, u8 width, ++ void (*fixup)(u32 *val)); ++ ++struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg, ++ u8 shift, u8 width, const char **parents, ++ int num_parents, void (*fixup)(u32 *val)); ++ + static inline struct clk *imx_clk_fixed(const char *name, int rate) + { + return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate); +diff -Nur linux-3.10.30/arch/arm/mach-imx/common.h linux-3.10.30-cubox-i/arch/arm/mach-imx/common.h +--- linux-3.10.30/arch/arm/mach-imx/common.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/common.h 2014-03-08 20:32:54.000000000 +0100 +@@ -14,6 +14,7 @@ + struct platform_device; + struct pt_regs; + struct clk; ++struct irq_data; + enum mxc_cpu_pwr_mode; + + extern void mx1_map_io(void); +@@ -68,17 +69,21 @@ + extern int mx31_clocks_init_dt(void); + extern int mx51_clocks_init_dt(void); + extern int mx53_clocks_init_dt(void); +-extern int mx6q_clocks_init(void); + extern struct platform_device *mxc_register_gpio(char *name, int id, + resource_size_t iobase, resource_size_t iosize, int irq, int irq_high); + extern void mxc_set_cpu_type(unsigned int type); ++extern void mxc_set_system_rev(unsigned int sysrev); + extern void mxc_restart(char, const char *); + extern void mxc_arch_reset_init(void __iomem *); ++extern void mxc_arch_reset_init_dt(void); + extern int mx53_revision(void); +-extern int imx6q_revision(void); + extern int mx53_display_revision(void); + extern void imx_set_aips(void __iomem *); + extern int mxc_device_init(void); ++extern void imx_set_soc_revision(unsigned int rev); ++extern unsigned int imx_get_soc_revision(void); ++extern void imx_init_revision_from_anatop(void); ++extern struct device *imx_soc_device_init(void); + + enum mxc_cpu_pwr_mode { + WAIT_CLOCKED, /* wfi only */ +@@ -125,30 +130,41 @@ + static inline void imx_smp_prepare(void) {} + static inline void imx_scu_standby_enable(void) {} + #endif ++extern void imx6_pm_map_io(void); ++extern void imx6_suspend(void); + extern void imx_src_init(void); ++#ifdef CONFIG_HAVE_IMX_SRC + extern void imx_src_prepare_restart(void); ++#else ++static inline void imx_src_prepare_restart(void) {} ++#endif + extern void imx_gpc_init(void); +-extern void imx_gpc_pre_suspend(void); ++extern void imx_gpc_pre_suspend(bool arm_power_off); + extern void imx_gpc_post_resume(void); + extern void imx_gpc_mask_all(void); ++extern void imx_gpc_irq_mask(struct irq_data *d); ++extern void imx_gpc_irq_unmask(struct irq_data *d); + extern void imx_gpc_restore_all(void); + extern void imx_anatop_init(void); + extern void imx_anatop_pre_suspend(void); + extern void imx_anatop_post_resume(void); +-extern void imx_anatop_usb_chrg_detect_disable(void); +-extern u32 imx_anatop_get_digprog(void); +-extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); +-extern void imx6q_set_chicken_bit(void); ++extern void imx_anatop_pu_enable(bool enable); ++extern int imx6_set_lpm(enum mxc_cpu_pwr_mode mode); ++extern void imx6_set_cache_lpm_in_wait(bool enable); ++extern void imx6sl_set_wait_clk(bool enter); ++extern void imx6_enet_mac_init(const char *compatible); + + extern void imx_cpu_die(unsigned int cpu); + extern int imx_cpu_kill(unsigned int cpu); + + #ifdef CONFIG_PM +-extern void imx6q_pm_init(void); ++extern void imx6_pm_init(void); ++extern void imx6_pm_set_ccm_base(void __iomem *base); + extern void imx51_pm_init(void); + extern void imx53_pm_init(void); + #else +-static inline void imx6q_pm_init(void) {} ++static inline void imx6_pm_init(void) {} ++static inline void imx6_pm_set_ccm_base(void __iomem *base) {} + static inline void imx51_pm_init(void) {} + static inline void imx53_pm_init(void) {} + #endif +@@ -159,6 +175,12 @@ + static inline int mx51_neon_fixup(void) { return 0; } + #endif + ++#ifdef CONFIG_CACHE_L2X0 ++extern void imx_init_l2cache(void); ++#else ++static inline void imx_init_l2cache(void) {} ++#endif ++ + extern struct smp_operations imx_smp_ops; + + #endif +diff -Nur linux-3.10.30/arch/arm/mach-imx/cpu.c linux-3.10.30-cubox-i/arch/arm/mach-imx/cpu.c +--- linux-3.10.30/arch/arm/mach-imx/cpu.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/cpu.c 2014-03-08 20:32:54.000000000 +0100 +@@ -1,6 +1,9 @@ + + #include + #include ++#include ++#include ++#include + + #include "hardware.h" + #include "common.h" +@@ -8,11 +11,30 @@ + unsigned int __mxc_cpu_type; + EXPORT_SYMBOL(__mxc_cpu_type); + ++extern unsigned int system_rev; ++ ++static unsigned int imx_soc_revision; ++ + void mxc_set_cpu_type(unsigned int type) + { + __mxc_cpu_type = type; + } + ++void mxc_set_system_rev(unsigned int sysrev) ++{ ++ system_rev = sysrev; ++} ++ ++void imx_set_soc_revision(unsigned int rev) ++{ ++ imx_soc_revision = rev; ++} ++ ++unsigned int imx_get_soc_revision(void) ++{ ++ return imx_soc_revision; ++} ++ + void imx_print_silicon_rev(const char *cpu, int srev) + { + if (srev == IMX_CHIP_REVISION_UNKNOWN) +@@ -44,3 +66,80 @@ + reg = __raw_readl(base + 0x50) & 0x00FFFFFF; + __raw_writel(reg, base + 0x50); + } ++ ++struct device * __init imx_soc_device_init(void) ++{ ++ struct soc_device_attribute *soc_dev_attr; ++ struct soc_device *soc_dev; ++ struct device_node *root; ++ const char *soc_id; ++ int ret; ++ ++ soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); ++ if (!soc_dev_attr) ++ return NULL; ++ ++ soc_dev_attr->family = "Freescale i.MX"; ++ ++ root = of_find_node_by_path("/"); ++ ret = of_property_read_string(root, "model", &soc_dev_attr->machine); ++ if (ret) ++ goto free_soc; ++ ++ switch (__mxc_cpu_type) { ++ case MXC_CPU_MX1: ++ soc_id = "i.MX1"; ++ break; ++ case MXC_CPU_MX21: ++ soc_id = "i.MX21"; ++ break; ++ case MXC_CPU_MX25: ++ soc_id = "i.MX25"; ++ break; ++ case MXC_CPU_MX27: ++ soc_id = "i.MX27"; ++ break; ++ case MXC_CPU_MX31: ++ soc_id = "i.MX31"; ++ break; ++ case MXC_CPU_MX35: ++ soc_id = "i.MX35"; ++ break; ++ case MXC_CPU_MX51: ++ soc_id = "i.MX51"; ++ break; ++ case MXC_CPU_MX53: ++ soc_id = "i.MX53"; ++ break; ++ case MXC_CPU_IMX6SL: ++ soc_id = "i.MX6SL"; ++ break; ++ case MXC_CPU_IMX6DL: ++ soc_id = "i.MX6DL"; ++ break; ++ case MXC_CPU_IMX6Q: ++ soc_id = "i.MX6Q"; ++ break; ++ default: ++ soc_id = "Unknown"; ++ } ++ soc_dev_attr->soc_id = soc_id; ++ ++ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d", ++ (imx_soc_revision >> 4) & 0xf, ++ imx_soc_revision & 0xf); ++ if (!soc_dev_attr->revision) ++ goto free_soc; ++ ++ soc_dev = soc_device_register(soc_dev_attr); ++ if (IS_ERR(soc_dev)) ++ goto free_rev; ++ ++ return soc_device_to_device(soc_dev); ++ ++free_rev: ++ kfree(soc_dev_attr->revision); ++free_soc: ++ kfree(soc_dev_attr); ++ return NULL; ++} +diff -Nur linux-3.10.30/arch/arm/mach-imx/cpuidle-imx6q.c linux-3.10.30-cubox-i/arch/arm/mach-imx/cpuidle-imx6q.c +--- linux-3.10.30/arch/arm/mach-imx/cpuidle-imx6q.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/cpuidle-imx6q.c 2014-03-08 20:32:54.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2012 Freescale Semiconductor, Inc. ++ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -27,9 +27,9 @@ + */ + if (!spin_trylock(&master_lock)) + goto idle; +- imx6q_set_lpm(WAIT_UNCLOCKED); ++ imx6_set_lpm(WAIT_UNCLOCKED); + cpu_do_idle(); +- imx6q_set_lpm(WAIT_CLOCKED); ++ imx6_set_lpm(WAIT_CLOCKED); + spin_unlock(&master_lock); + goto done; + } +@@ -68,8 +68,8 @@ + /* Need to enable SCU standby for entering WAIT modes */ + imx_scu_standby_enable(); + +- /* Set chicken bit to get a reliable WAIT mode support */ +- imx6q_set_chicken_bit(); ++ /* Set cache lpm bit for reliable WAIT mode support */ ++ imx6_set_cache_lpm_in_wait(true); + + return cpuidle_register(&imx6q_cpuidle_driver, NULL); + } +diff -Nur linux-3.10.30/arch/arm/mach-imx/cpuidle-imx6sl.c linux-3.10.30-cubox-i/arch/arm/mach-imx/cpuidle-imx6sl.c +--- linux-3.10.30/arch/arm/mach-imx/cpuidle-imx6sl.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/cpuidle-imx6sl.c 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,145 @@ ++/* ++ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "common.h" ++#include "cpuidle.h" ++ ++extern u32 audio_bus_freq_mode; ++extern u32 ultra_low_bus_freq_mode; ++extern unsigned long reg_addrs[]; ++extern void imx6sl_low_power_wfi(void); ++ ++static void __iomem *iomux_base; ++static void *wfi_iram_base; ++ ++void (*imx6sl_wfi_in_iram_fn)(void *wfi_iram_base, ++ void *iomux_addr, void *regs_addr, u32 audio_mode) = NULL; ++ ++#define WFI_IN_IRAM_SIZE 0x1000 ++ ++static int imx6sl_enter_wait(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) ++{ ++ imx6_set_lpm(WAIT_UNCLOCKED); ++ if (ultra_low_bus_freq_mode || audio_bus_freq_mode) { ++ /* ++ * Flush the TLB, to ensure no TLB maintenance occurs ++ * when DDR is in self-refresh. ++ */ ++ local_flush_tlb_all(); ++ /* ++ * Run WFI code from IRAM. ++ * Drop the DDR freq to 1MHz and AHB to 3MHz ++ * Also float DDR IO pads. ++ */ ++ imx6sl_wfi_in_iram_fn(wfi_iram_base, iomux_base, reg_addrs, audio_bus_freq_mode); ++ } else { ++ imx6sl_set_wait_clk(true); ++ cpu_do_idle(); ++ imx6sl_set_wait_clk(false); ++ } ++ imx6_set_lpm(WAIT_CLOCKED); ++ ++ return index; ++} ++ ++static struct cpuidle_driver imx6sl_cpuidle_driver = { ++ .name = "imx6sl_cpuidle", ++ .owner = THIS_MODULE, ++ .states = { ++ /* WFI */ ++ ARM_CPUIDLE_WFI_STATE, ++ /* WAIT */ ++ { ++ .exit_latency = 50, ++ .target_residency = 75, ++ .flags = CPUIDLE_FLAG_TIME_VALID | ++ CPUIDLE_FLAG_TIMER_STOP, ++ .enter = imx6sl_enter_wait, ++ .name = "WAIT", ++ .desc = "Clock off", ++ }, ++ }, ++ .state_count = 2, ++ .safe_state_index = 0, ++}; ++ ++int __init imx6sl_cpuidle_init(void) ++{ ++ struct platform_device *ocram_dev; ++ unsigned int iram_paddr; ++ struct device_node *node; ++ struct gen_pool *iram_pool; ++ ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-iomuxc"); ++ if (!node) { ++ pr_err("failed to find imx6sl-iomuxc device tree data!\n"); ++ return -EINVAL; ++ } ++ iomux_base = of_iomap(node, 0); ++ WARN(!iomux_base, "unable to map iomux registers\n"); ++ ++ node = NULL; ++ node = of_find_compatible_node(NULL, NULL, "mmio-sram"); ++ if (!node) { ++ pr_err("%s: failed to find ocram node\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ ocram_dev = of_find_device_by_node(node); ++ if (!ocram_dev) { ++ pr_err("failed to find ocram device!\n"); ++ return -EINVAL; ++ } ++ ++ iram_pool = dev_get_gen_pool(&ocram_dev->dev); ++ if (!iram_pool) { ++ pr_err("iram pool unavailable!\n"); ++ return -EINVAL; ++ } ++ /* ++ * Allocate IRAM memory when ARM executes WFI in ++ * ultra_low_power_mode. ++ */ ++ wfi_iram_base = (void *)gen_pool_alloc(iram_pool, ++ WFI_IN_IRAM_SIZE); ++ if (!wfi_iram_base) { ++ pr_err("Cannot alloc iram for wfi code!\n"); ++ return -ENOMEM; ++ } ++ ++ iram_paddr = gen_pool_virt_to_phys(iram_pool, ++ (unsigned long)wfi_iram_base); ++ /* ++ * Need to remap the area here since we want ++ * the memory region to be executable. ++ */ ++ wfi_iram_base = __arm_ioremap(iram_paddr, ++ WFI_IN_IRAM_SIZE, ++ MT_MEMORY_NONCACHED); ++ if (!wfi_iram_base) ++ pr_err("wfi_ram_base NOT remapped\n"); ++ ++ imx6sl_wfi_in_iram_fn = (void *)fncpy(wfi_iram_base, ++ &imx6sl_low_power_wfi, WFI_IN_IRAM_SIZE); ++ ++ return cpuidle_register(&imx6sl_cpuidle_driver, NULL); ++} +diff -Nur linux-3.10.30/arch/arm/mach-imx/cpuidle.h linux-3.10.30-cubox-i/arch/arm/mach-imx/cpuidle.h +--- linux-3.10.30/arch/arm/mach-imx/cpuidle.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/cpuidle.h 2014-03-08 20:32:54.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2012 Freescale Semiconductor, Inc. ++ * Copyright 2012-2013 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -13,6 +13,7 @@ + #ifdef CONFIG_CPU_IDLE + extern int imx5_cpuidle_init(void); + extern int imx6q_cpuidle_init(void); ++extern int imx6sl_cpuidle_init(void); + #else + static inline int imx5_cpuidle_init(void) + { +@@ -22,4 +23,8 @@ + { + return 0; + } ++static inline int imx6sl_cpuidle_init(void) ++{ ++ return 0; ++} + #endif +diff -Nur linux-3.10.30/arch/arm/mach-imx/ddr3_freq_imx6.S linux-3.10.30-cubox-i/arch/arm/mach-imx/ddr3_freq_imx6.S +--- linux-3.10.30/arch/arm/mach-imx/ddr3_freq_imx6.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/ddr3_freq_imx6.S 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,893 @@ ++/* ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++ ++#define MMDC0_MDPDC 0x4 ++#define MMDC0_MDCF0 0x0c ++#define MMDC0_MDCF1 0x10 ++#define MMDC0_MDMISC 0x18 ++#define MMDC0_MDSCR 0x1c ++#define MMDC0_MAPSR 0x404 ++#define MMDC0_MADPCR0 0x410 ++#define MMDC0_MPZQHWCTRL 0x800 ++#define MMDC1_MPZQHWCTRL 0x4800 ++#define MMDC0_MPODTCTRL 0x818 ++#define MMDC1_MPODTCTRL 0x4818 ++#define MMDC0_MPDGCTRL0 0x83c ++#define MMDC1_MPDGCTRL0 0x483c ++#define MMDC0_MPMUR0 0x8b8 ++#define MMDC1_MPMUR0 0x48b8 ++ ++#define CCM_CBCDR 0x14 ++#define CCM_CBCMR 0x18 ++#define CCM_CSCMR1 0x1c ++#define CCM_CDHIPR 0x48 ++ ++#define L2_CACHE_SYNC 0x730 ++ ++ .align 3 ++ ++ .macro switch_to_528MHz ++ ++ /* check if periph_clk_sel is already set */ ++ ldr r0, [r6, #CCM_CBCDR] ++ and r0, r0, #(1 << 25) ++ cmp r0, #(1 << 25) ++ beq set_ahb_podf_before_switch ++ ++ /* change periph_clk to be sourced from pll3_clk. */ ++ ldr r0, [r6, #CCM_CBCMR] ++ bic r0, r0, #(3 << 12) ++ str r0, [r6, #CCM_CBCMR] ++ ++ ldr r0, [r6, #CCM_CBCDR] ++ bic r0, r0, #(0x38 << 20) ++ str r0, [r6, #CCM_CBCDR] ++ ++ /* ++ * set the AHB dividers before the switch, ++ * don't change AXI clock divider, ++ * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4, ++ */ ++ ldr r0, [r6, #CCM_CBCDR] ++ ldr r2, =0x3f1f00 ++ bic r0, r0, r2 ++ orr r0, r0, #0xd00 ++ orr r0, r0, #(1 << 16) ++ str r0, [r6, #CCM_CBCDR] ++ ++wait_div_update528: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne wait_div_update528 ++ ++ /* now switch periph_clk to pll3_main_clk. */ ++ ldr r0, [r6, #CCM_CBCDR] ++ orr r0, r0, #(1 << 25) ++ str r0, [r6, #CCM_CBCDR] ++ ++periph_clk_switch3: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne periph_clk_switch3 ++ ++ b switch_pre_periph_clk_528 ++ ++set_ahb_podf_before_switch: ++ /* ++ * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4, ++ */ ++ ldr r0, [r6, #CCM_CBCDR] ++ ldr r2, =0x3f1f00 ++ bic r0, r0, r2 ++ orr r0, r0, #0xd00 ++ orr r0, r0, #(1 << 16) ++ str r0, [r6, #CCM_CBCDR] ++ ++wait_div_update528_1: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne wait_div_update528_1 ++ ++switch_pre_periph_clk_528: ++ ++ /* now switch pre_periph_clk to PLL2_528MHz. */ ++ ldr r0, [r6, #CCM_CBCMR] ++ bic r0, r0, #(0xc << 16) ++ str r0, [r6, #CCM_CBCMR] ++ ++ /* now switch periph_clk back. */ ++ ldr r0, [r6, #CCM_CBCDR] ++ bic r0, r0, #(1 << 25) ++ str r0, [r6, #CCM_CBCDR] ++ ++periph_clk_switch4: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne periph_clk_switch4 ++ ++ .endm ++ ++ .macro switch_to_400MHz ++ ++ /* check if periph_clk_sel is already set. */ ++ ldr r0, [r6, #CCM_CBCDR] ++ and r0, r0, #(1 << 25) ++ cmp r0, #(1 << 25) ++ beq set_ahb_podf_before_switch1 ++ ++ /* change periph_clk to be sourced from pll3_clk. */ ++ ldr r0, [r6, #CCM_CBCMR] ++ bic r0, r0, #(3 << 12) ++ str r0, [r6, #CCM_CBCMR] ++ ++ ldr r0, [r6, #CCM_CBCDR] ++ bic r0, r0, #(0x38 << 24) ++ str r0, [r6, #CCM_CBCDR] ++ ++ /* now switch periph_clk to pll3_main_clk. */ ++ ldr r0, [r6, #CCM_CBCDR] ++ orr r0, r0, #(1 << 25) ++ str r0, [r6, #CCM_CBCDR] ++ ++periph_clk_switch5: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne periph_clk_switch5 ++ ++ b switch_pre_periph_clk_400 ++ ++set_ahb_podf_before_switch1: ++ /* ++ * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4, ++ */ ++ ldr r0, [r6, #CCM_CBCDR] ++ ldr r2, =0x3f1f00 ++ bic r0, r0, r2 ++ orr r0, r0, #(0x9 << 8) ++ orr r0, r0, #(1 << 16) ++ str r0, [r6, #CCM_CBCDR] ++ ++wait_div_update400_1: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne wait_div_update400_1 ++ ++switch_pre_periph_clk_400: ++ ++ /* now switch pre_periph_clk to PFD_400MHz. */ ++ ldr r0, [r6, #CCM_CBCMR] ++ bic r0, r0, #(0xc << 16) ++ orr r0, r0, #(0x4 << 16) ++ str r0, [r6, #CCM_CBCMR] ++ ++ /* now switch periph_clk back. */ ++ ldr r0, [r6, #CCM_CBCDR] ++ bic r0, r0, #(1 << 25) ++ str r0, [r6, #CCM_CBCDR] ++ ++periph_clk_switch6: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne periph_clk_switch6 ++ ++ /* ++ * change AHB divider so that we are at 400/3=133MHz. ++ * don't change AXI clock divider. ++ * set the MMDC_DIV=1, AXI_DIV=2, AHB_DIV=3, ++ */ ++ ldr r0, [r6, #CCM_CBCDR] ++ ldr r2, =0x3f1f00 ++ bic r0, r0, r2 ++ orr r0, r0, #(0x9 << 8) ++ orr r0, r0, #(1 << 16) ++ str r0, [r6, #CCM_CBCDR] ++ ++wait_div_update400_2: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne wait_div_update400_2 ++ ++ .endm ++ ++ .macro switch_to_50MHz ++ ++ /* check if periph_clk_sel is already set. */ ++ ldr r0, [r6, #CCM_CBCDR] ++ and r0, r0, #(1 << 25) ++ cmp r0, #(1 << 25) ++ beq switch_pre_periph_clk_50 ++ ++ /* ++ * set the periph_clk to be sourced from PLL2_PFD_200M ++ * change periph_clk to be sourced from pll3_clk. ++ * ensure PLL3 is the source and set the divider to 1. ++ */ ++ ldr r0, [r6, #CCM_CBCMR] ++ bic r0, r0, #(0x3 << 12) ++ str r0, [r6, #CCM_CBCMR] ++ ++ ldr r0, [r6, #CCM_CBCDR] ++ bic r0, r0, #(0x38 << 24) ++ str r0, [r6, #CCM_CBCDR] ++ ++ /* now switch periph_clk to pll3_main_clk. */ ++ ldr r0, [r6, #CCM_CBCDR] ++ orr r0, r0, #(1 << 25) ++ str r0, [r6, #CCM_CBCDR] ++ ++periph_clk_switch_50: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne periph_clk_switch_50 ++ ++switch_pre_periph_clk_50: ++ ++ /* now switch pre_periph_clk to PFD_200MHz. */ ++ ldr r0, [r6, #CCM_CBCMR] ++ orr r0, r0, #(0xc << 16) ++ str r0, [r6, #CCM_CBCMR] ++ ++ /* ++ * set the MMDC_DIV=4, AXI_DIV = 4, AHB_DIV=8, ++ */ ++ ldr r0, [r6, #CCM_CBCDR] ++ ldr r2, =0x3f1f00 ++ bic r0, r0, r2 ++ orr r0, r0, #(0x18 << 16) ++ orr r0, r0, #(0x3 << 16) ++ ++ /* ++ * if changing AHB divider remember to change ++ * the IPGPER divider too below. ++ */ ++ orr r0, r0, #0x1d00 ++ str r0, [r6, #CCM_CBCDR] ++ ++wait_div_update_50: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne wait_div_update_50 ++ ++ /* now switch periph_clk back. */ ++ ldr r0, [r6, #CCM_CBCDR] ++ bic r0, r0, #(1 << 25) ++ str r0, [r6, #CCM_CBCDR] ++ ++periph_clk_switch2: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne periph_clk_switch2 ++ ++ .endm ++ ++ .macro switch_to_24MHz ++ /* ++ * change the freq now try setting DDR to 24MHz. ++ * source it from the periph_clk2 ensure the ++ * periph_clk2 is sourced from 24MHz and the ++ * divider is 1. ++ */ ++ ++ ldr r0, [r6, #CCM_CBCMR] ++ bic r0, r0, #(0x3 << 12) ++ orr r0, r0, #(1 << 12) ++ str r0, [r6, #CCM_CBCMR] ++ ++ ldr r0, [r6, #CCM_CBCDR] ++ bic r0, r0, #(0x38 << 24) ++ str r0, [r6, #CCM_CBCDR] ++ ++ /* now switch periph_clk to 24MHz. */ ++ ldr r0, [r6, #CCM_CBCDR] ++ orr r0, r0, #(1 << 25) ++ str r0, [r6, #CCM_CBCDR] ++ ++periph_clk_switch1: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne periph_clk_switch1 ++ ++ /* change all the dividers to 1. */ ++ ldr r0, [r6, #CCM_CBCDR] ++ ldr r2, =0x3f1f00 ++ bic r0, r0, r2 ++ orr r0, r0, #(1 << 8) ++ str r0, [r6, #CCM_CBCDR] ++ ++ /* Wait for the divider to change. */ ++wait_div_update: ++ ldr r0, [r6, #CCM_CDHIPR] ++ cmp r0, #0 ++ bne wait_div_update ++ ++ .endm ++ ++/* ++ * mx6_ddr3_freq_change ++ * ++ * idle the processor (eg, wait for interrupt). ++ * make sure DDR is in self-refresh. ++ * IRQs are already disabled. ++ */ ++ENTRY(mx6_ddr3_freq_change) ++ ++ stmfd sp!, {r4-r12} ++ ++ /* ++ * r5 -> mmdc_base ++ * r6 -> ccm_base ++ * r7 -> iomux_base ++ * r12 -> l2_base ++ */ ++ mov r4, r0 ++ mov r8, r1 ++ mov r9, r2 ++ mov r11, r3 ++ ++ /* ++ * Get the addresses of the registers. ++ * They are last few entries in the ++ * ddr_settings parameter. ++ * The first entry contains the count, ++ * and each entry is 2 words. ++ */ ++ ldr r0, [r1] ++ add r0, r0, #1 ++ lsl r0, r0, #3 ++ add r1, r0, r1 ++ /* mmdc_base. */ ++ ldr r5, [r1] ++ add r1, #8 ++ /* ccm_base */ ++ ldr r6, [r1] ++ add r1, #8 ++ /*iomux_base */ ++ ldr r7, [r1] ++ add r1, #8 ++ /*l2_base */ ++ ldr r12, [r1] ++ ++ddr_freq_change: ++ /* ++ * make sure no TLB miss will occur when ++ * the DDR is in self refresh. invalidate ++ * TLB single entry to ensure that the ++ * address is not already in the TLB. ++ */ ++ ++ adr r10, ddr_freq_change ++ ++ ldr r2, [r6] ++ ldr r2, [r5] ++ ldr r2, [r7] ++ ldr r2, [r8] ++ ldr r2, [r10] ++ ldr r2, [r11] ++ ldr r2, [r12] ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* ++ * Make sure the L2 buffers are drained. ++ * Sync operation on L2 drains the buffers. ++ */ ++ mov r1, #0x0 ++ str r1, [r12, #L2_CACHE_SYNC] ++#endif ++ ++ /* disable automatic power saving. */ ++ ldr r0, [r5, #MMDC0_MAPSR] ++ orr r0, r0, #0x01 ++ str r0, [r5, #MMDC0_MAPSR] ++ ++ /* disable MMDC power down timer. */ ++ ldr r0, [r5, #MMDC0_MDPDC] ++ bic r0, r0, #(0xff << 8) ++ str r0, [r5, #MMDC0_MDPDC] ++ ++ /* delay for a while */ ++ ldr r1, =4 ++delay1: ++ ldr r2, =0 ++cont1: ++ ldr r0, [r5, r2] ++ add r2, r2, #4 ++ cmp r2, #16 ++ bne cont1 ++ sub r1, r1, #1 ++ cmp r1, #0 ++ bgt delay1 ++ ++ /* set CON_REG */ ++ ldr r0, =0x8000 ++ str r0, [r5, #MMDC0_MDSCR] ++poll_conreq_set_1: ++ ldr r0, [r5, #MMDC0_MDSCR] ++ and r0, r0, #(0x4 << 12) ++ cmp r0, #(0x4 << 12) ++ bne poll_conreq_set_1 ++ ++ ldr r0, =0x00008010 ++ str r0, [r5, #MMDC0_MDSCR] ++ ldr r0, =0x00008018 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ /* ++ * if requested frequency is greater than ++ * 300MHz go to DLL on mode. ++ */ ++ ldr r1, =300000000 ++ cmp r4, r1 ++ bge dll_on_mode ++ ++dll_off_mode: ++ ++ /* if DLL is currently on, turn it off. */ ++ cmp r9, #1 ++ beq continue_dll_off_1 ++ ++ ldr r0, =0x00018031 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r0, =0x00018039 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r1, =10 ++delay1a: ++ ldr r2, =0 ++cont1a: ++ ldr r0, [r5, r2] ++ add r2, r2, #4 ++ cmp r2, #16 ++ bne cont1a ++ sub r1, r1, #1 ++ cmp r1, #0 ++ bgt delay1a ++ ++continue_dll_off_1: ++ /* set DVFS - enter self refresh mode */ ++ ldr r0, [r5, #MMDC0_MAPSR] ++ orr r0, r0, #(1 << 21) ++ str r0, [r5, #MMDC0_MAPSR] ++ ++ /* de-assert con_req */ ++ mov r0, #0x0 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++poll_dvfs_set_1: ++ ldr r0, [r5, #MMDC0_MAPSR] ++ and r0, r0, #(1 << 25) ++ cmp r0, #(1 << 25) ++ bne poll_dvfs_set_1 ++ ++ ldr r1, =24000000 ++ cmp r4, r1 ++ beq switch_freq_24 ++ ++ switch_to_50MHz ++ b continue_dll_off_2 ++ ++switch_freq_24: ++ switch_to_24MHz ++ ++continue_dll_off_2: ++ ++ /* set SBS - block ddr accesses */ ++ ldr r0, [r5, #MMDC0_MADPCR0] ++ orr r0, r0, #(1 << 8) ++ str r0, [r5, #MMDC0_MADPCR0] ++ ++ /* clear DVFS - exit from self refresh mode */ ++ ldr r0, [r5, #MMDC0_MAPSR] ++ bic r0, r0, #(1 << 21) ++ str r0, [r5, #MMDC0_MAPSR] ++ ++poll_dvfs_clear_1: ++ ldr r0, [r5, #MMDC0_MAPSR] ++ and r0, r0, #(1 << 25) ++ cmp r0, #(1 << 25) ++ beq poll_dvfs_clear_1 ++ ++ /* if DLL was previously on, continue DLL off routine. */ ++ cmp r9, #1 ++ beq continue_dll_off_3 ++ ++ ldr r0, =0x00018031 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r0, =0x00018039 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r0, =0x08208030 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r0, =0x08208038 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r0, =0x00088032 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r0, =0x0008803A ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ /* delay for a while. */ ++ ldr r1, =4 ++delay_1: ++ ldr r2, =0 ++cont_1: ++ ldr r0, [r5, r2] ++ add r2, r2, #4 ++ cmp r2, #16 ++ bne cont_1 ++ sub r1, r1, #1 ++ cmp r1, #0 ++ bgt delay_1 ++ ++ ldr r0, [r5, #MMDC0_MDCF0] ++ bic r0, r0, #0xf ++ orr r0, r0, #0x3 ++ str r0, [r5, #MMDC0_MDCF0] ++ ++ ldr r0, [r5, #MMDC0_MDCF1] ++ bic r0, r0, #0x7 ++ orr r0, r0, #0x4 ++ str r0, [r5, #MMDC0_MDCF1] ++ ++ ldr r0, =0x00091680 ++ str r0, [r5, #MMDC0_MDMISC] ++ ++ /* enable dqs pull down in the IOMUX. */ ++ ldr r1, [r11] ++ add r11, r11, #8 ++ ldr r2, =0x3028 ++update_iomux: ++ ldr r0, [r11, #0x0] ++ ldr r3, [r7, r0] ++ bic r3, r3, r2 ++ orr r3, r3, #(0x3 << 12) ++ orr r3, r3, #0x28 ++ str r3, [r7, r0] ++ add r11, r11, #8 ++ sub r1, r1, #1 ++ cmp r1, #0 ++ bgt update_iomux ++ ++ /* ODT disabled. */ ++ ldr r0, =0x0 ++ ldr r2, =MMDC0_MPODTCTRL ++ str r0, [r5, r2] ++ ldr r2, =MMDC1_MPODTCTRL ++ str r0, [r5, r2] ++ ++ /* DQS gating disabled. */ ++ ldr r2, =MMDC0_MPDGCTRL0 ++ ldr r0, [r5, r2] ++ orr r0, r0, #(1 << 29) ++ str r0, [r5, r2] ++ ++ ldr r2, =MMDC1_MPDGCTRL0 ++ ldr r0, [r5, r2] ++ orr r0, r0, #(0x1 << 29) ++ str r0, [r5, r2] ++ ++ /* MMDC0_MAPSR adopt power down enable. */ ++ ldr r0, [r5, #MMDC0_MAPSR] ++ bic r0, r0, #0x01 ++ str r0, [r5, #MMDC0_MAPSR] ++ ++ /* frc_msr + mu bypass */ ++ ldr r0, =0x00000060 ++ str r0, [r5, #MMDC0_MPMUR0] ++ ldr r2, =MMDC1_MPMUR0 ++ str r0, [r5, r2] ++ ldr r0, =0x00000460 ++ str r0, [r5, #MMDC0_MPMUR0] ++ ldr r2, =MMDC1_MPMUR0 ++ str r0, [r5, r2] ++ ldr r0, =0x00000c60 ++ str r0, [r5, #MMDC0_MPMUR0] ++ ldr r2, =MMDC1_MPMUR0 ++ str r0, [r5, r2] ++ ++continue_dll_off_3: ++ /* clear SBS - unblock accesses to DDR. */ ++ ldr r0, [r5, #MMDC0_MADPCR0] ++ bic r0, r0, #(0x1 << 8) ++ str r0, [r5, #MMDC0_MADPCR0] ++ ++ mov r0, #0x0 ++ str r0, [r5, #MMDC0_MDSCR] ++poll_conreq_clear_1: ++ ldr r0, [r5, #MMDC0_MDSCR] ++ and r0, r0, #(0x4 << 12) ++ cmp r0, #(0x4 << 12) ++ beq poll_conreq_clear_1 ++ ++ b done ++ ++dll_on_mode: ++ /* assert DVFS - enter self refresh mode. */ ++ ldr r0, [r5, #MMDC0_MAPSR] ++ orr r0, r0, #(1 << 21) ++ str r0, [r5, #MMDC0_MAPSR] ++ ++ /* de-assert CON_REQ. */ ++ mov r0, #0x0 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ /* poll DVFS ack. */ ++poll_dvfs_set_2: ++ ldr r0, [r5, #MMDC0_MAPSR] ++ and r0, r0, #(1 << 25) ++ cmp r0, #(1 << 25) ++ bne poll_dvfs_set_2 ++ ++ ldr r1, =528000000 ++ cmp r4, r1 ++ beq switch_freq_528 ++ ++ switch_to_400MHz ++ ++ b continue_dll_on ++ ++switch_freq_528: ++ switch_to_528MHz ++ ++continue_dll_on: ++ ++ /* set SBS step-by-step mode. */ ++ ldr r0, [r5, #MMDC0_MADPCR0] ++ orr r0, r0, #( 1 << 8) ++ str r0, [r5, #MMDC0_MADPCR0] ++ ++ /* clear DVFS - exit self refresh mode. */ ++ ldr r0, [r5, #MMDC0_MAPSR] ++ bic r0, r0, #(1 << 21) ++ str r0, [r5, #MMDC0_MAPSR] ++ ++poll_dvfs_clear_2: ++ ldr r0, [r5, #MMDC0_MAPSR] ++ and r0, r0, #(1 << 25) ++ cmp r0, #(1 << 25) ++ beq poll_dvfs_clear_2 ++ ++ /* if DLL is currently off, turn it back on. */ ++ cmp r9, #0 ++ beq update_calibration_only ++ ++ ldr r0, =0xa5390003 ++ str r0, [r5, #MMDC0_MPZQHWCTRL] ++ ldr r2, =MMDC1_MPZQHWCTRL ++ str r0, [r5, r2] ++ ++ /* enable DQS gating. */ ++ ldr r2, =MMDC0_MPDGCTRL0 ++ ldr r0, [r5, r2] ++ bic r0, r0, #(1 << 29) ++ str r0, [r5, r2] ++ ++ ldr r2, =MMDC1_MPDGCTRL0 ++ ldr r0, [r5, r2] ++ bic r0, r0, #(1 << 29) ++ str r0, [r5, r2] ++ ++ /* force measure. */ ++ ldr r0, =0x00000800 ++ str r0, [r5, #MMDC0_MPMUR0] ++ ldr r2, =MMDC1_MPMUR0 ++ str r0, [r5, r2] ++ ++ /* delay for while. */ ++ ldr r1, =4 ++delay5: ++ ldr r2, =0 ++cont5: ++ ldr r0, [r5, r2] ++ add r2, r2, #4 ++ cmp r2, #16 ++ bne cont5 ++ sub r1, r1, #1 ++ cmp r1, #0 ++ bgt delay5 ++ ++ /* disable dqs pull down in the IOMUX. */ ++ ldr r1, [r11] ++ add r11, r11, #8 ++update_iomux1: ++ ldr r0, [r11, #0x0] ++ ldr r3, [r11, #0x4] ++ str r3, [r7, r0] ++ add r11, r11, #8 ++ sub r1, r1, #1 ++ cmp r1, #0 ++ bgt update_iomux1 ++ ++ /* config MMDC timings to 528MHz. */ ++ ldr r9, [r8] ++ add r8, r8, #8 ++ ldr r0, [r8, #0x0] ++ ldr r3, [r8, #0x4] ++ str r3, [r5, r0] ++ add r8, r8, #8 ++ ++ ldr r0, [r8, #0x0] ++ ldr r3, [r8, #0x4] ++ str r3, [r5, r0] ++ add r8, r8, #8 ++ ++ /* update MISC register: WALAT, RALAT */ ++ ldr r0, =0x00081740 ++ str r0, [r5, #MMDC0_MDMISC] ++ ++ /* configure ddr devices to dll on, odt. */ ++ ldr r0, =0x00028031 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r0, =0x00028039 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ /* delay for while. */ ++ ldr r1, =4 ++delay7: ++ ldr r2, =0 ++cont7: ++ ldr r0, [r5, r2] ++ add r2, r2, #4 ++ cmp r2, #16 ++ bne cont7 ++ sub r1, r1, #1 ++ cmp r1, #0 ++ bgt delay7 ++ ++ /* reset dll. */ ++ ldr r0, =0x09208030 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r0, =0x09208038 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ /* delay for while. */ ++ ldr r1, =100 ++delay8: ++ ldr r2, =0 ++cont8: ++ ldr r0, [r5, r2] ++ add r2, r2, #4 ++ cmp r2, #16 ++ bne cont8 ++ sub r1, r1, #1 ++ cmp r1, #0 ++ bgt delay8 ++ ++ ldr r0, [r8, #0x0] ++ ldr r3, [r8, #0x4] ++ str r3, [r5, r0] ++ add r8, r8, #8 ++ ++ ldr r0, [r8, #0x0] ++ ldr r3, [r8, #0x4] ++ str r3, [r5, r0] ++ add r8, r8, #8 ++ ++ ldr r0, =0x00428031 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r0, =0x00428039 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r0, [r8, #0x0] ++ ldr r3, [r8, #0x4] ++ str r3, [r5, r0] ++ add r8, r8, #8 ++ ++ ldr r0, [r8, #0x0] ++ ldr r3, [r8, #0x4] ++ str r3, [r5, r0] ++ add r8, r8, #8 ++ ++ /* issue a zq command. */ ++ ldr r0, =0x04008040 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ ldr r0, =0x04008048 ++ str r0, [r5, #MMDC0_MDSCR] ++ ++ /* MMDC ODT enable. */ ++ ldr r0, [r8, #0x0] ++ ldr r3, [r8, #0x4] ++ str r3, [r5, r0] ++ add r8, r8, #8 ++ ++ ldr r2, =0x4818 ++ str r0, [r5, r2] ++ ++ /* delay for while. */ ++ ldr r1, =40 ++delay15: ++ ldr r2, =0 ++cont15: ++ ldr r0, [r5, r2] ++ add r2, r2, #4 ++ cmp r2, #16 ++ bne cont15 ++ sub r1, r1, #1 ++ cmp r1, #0 ++ bgt delay15 ++ ++ /* MMDC0_MAPSR adopt power down enable. */ ++ ldr r0, [r5, #MMDC0_MAPSR] ++ bic r0, r0, #0x01 ++ str r0, [r5, #MMDC0_MAPSR] ++ ++ /* enable MMDC power down timer. */ ++ ldr r0, [r5, #MMDC0_MDPDC] ++ orr r0, r0, #(0x55 << 8) ++ str r0, [r5, #MMDC0_MDPDC] ++ ++ b update_calibration ++ ++update_calibration_only: ++ ldr r1, [r8] ++ sub r1, r1, #7 ++ add r8, r8, #64 ++ b update_calib ++ ++update_calibration: ++ /* write the new calibration values. */ ++ mov r1, r9 ++ sub r1, r1, #7 ++ ++update_calib: ++ ldr r0, [r8, #0x0] ++ ldr r3, [r8, #0x4] ++ str r3, [r5, r0] ++ add r8, r8, #8 ++ sub r1, r1, #1 ++ cmp r1, #0 ++ bgt update_calib ++ ++ /* perform a force measurement. */ ++ ldr r0, =0x800 ++ str r0, [r5, #MMDC0_MPMUR0] ++ ldr r2, =MMDC1_MPMUR0 ++ str r0, [r5, r2] ++ ++ /* clear SBS - unblock DDR accesses. */ ++ ldr r0, [r5, #MMDC0_MADPCR0] ++ bic r0, r0, #(1 << 8) ++ str r0, [r5, #MMDC0_MADPCR0] ++ ++ mov r0, #0x0 ++ str r0, [r5, #MMDC0_MDSCR] ++poll_conreq_clear_2: ++ ldr r0, [r5, #MMDC0_MDSCR] ++ and r0, r0, #(0x4 << 12) ++ cmp r0, #(0x4 << 12) ++ beq poll_conreq_clear_2 ++ ++done: ++ /* restore registers */ ++ ++ ldmfd sp!, {r4-r12} ++ mov pc, lr ++ ++ .type mx6_do_ddr3_freq_change, #object ++ENTRY(mx6_do_ddr_freq_change) ++ .word mx6_ddr3_freq_change ++ .size mx6_ddr3_freq_change, . - mx6_ddr3_freq_change +diff -Nur linux-3.10.30/arch/arm/mach-imx/gpc.c linux-3.10.30-cubox-i/arch/arm/mach-imx/gpc.c +--- linux-3.10.30/arch/arm/mach-imx/gpc.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/gpc.c 2014-03-08 20:32:54.000000000 +0100 +@@ -10,30 +10,127 @@ + * http://www.gnu.org/copyleft/gpl.html + */ + ++#include ++#include + #include + #include ++#include + #include + #include + #include ++#include + #include ++#include ++#include ++#include + #include "common.h" ++#include "hardware.h" + + #define GPC_IMR1 0x008 + #define GPC_PGC_CPU_PDN 0x2a0 ++#define GPC_PGC_GPU_PDN 0x260 ++#define GPC_PGC_GPU_PUPSCR 0x264 ++#define GPC_PGC_GPU_PDNSCR 0x268 ++#define GPC_PGC_DISP_PGCR_OFFSET 0x240 ++#define GPC_PGC_DISP_PUPSCR_OFFSET 0x244 ++#define GPC_PGC_DISP_PDNSCR_OFFSET 0x248 ++#define GPC_PGC_DISP_SR_OFFSET 0x24c ++#define GPC_PGC_GPU_SW_SHIFT 0 ++#define GPC_PGC_GPU_SW_MASK 0x3f ++#define GPC_PGC_GPU_SW2ISO_SHIFT 8 ++#define GPC_PGC_GPU_SW2ISO_MASK 0x3f ++#define GPC_PGC_CPU_PUPSCR 0x2a4 ++#define GPC_PGC_CPU_PDNSCR 0x2a8 ++#define GPC_PGC_CPU_SW_SHIFT 0 ++#define GPC_PGC_CPU_SW_MASK 0x3f ++#define GPC_PGC_CPU_SW2ISO_SHIFT 8 ++#define GPC_PGC_CPU_SW2ISO_MASK 0x3f ++#define GPC_CNTR 0x0 ++#define GPC_CNTR_PU_UP_REQ_SHIFT 0x1 ++#define GPC_CNTR_PU_DOWN_REQ_SHIFT 0x0 + + #define IMR_NUM 4 + + static void __iomem *gpc_base; + static u32 gpc_wake_irqs[IMR_NUM]; + static u32 gpc_saved_imrs[IMR_NUM]; ++static struct clk *gpu3d_clk, *gpu3d_shader_clk, *gpu2d_clk, *gpu2d_axi_clk; ++static struct clk *lcd_axi_clk, *lcd_pix_clk, *epdc_axi_clk, *epdc_pix_clk; ++static struct clk *pxp_axi_clk; ++static struct clk *openvg_axi_clk, *vpu_clk, *ipg_clk; ++static struct device *gpc_dev; ++struct regulator *pu_reg; ++struct notifier_block nb; ++static struct regulator_dev *pu_dummy_regulator_rdev; ++static struct regulator_init_data pu_dummy_initdata = { ++ .constraints = { ++ .max_uV = 1450000, /* allign with real max of anatop */ ++ .valid_ops_mask = REGULATOR_CHANGE_STATUS | ++ REGULATOR_CHANGE_VOLTAGE, ++ }, ++}; ++static int pu_dummy_enable; + +-void imx_gpc_pre_suspend(void) ++static void imx_disp_clk(bool enable) ++{ ++ if (enable) { ++ clk_prepare_enable(lcd_axi_clk); ++ clk_prepare_enable(lcd_pix_clk); ++ clk_prepare_enable(epdc_axi_clk); ++ clk_prepare_enable(epdc_pix_clk); ++ clk_prepare_enable(pxp_axi_clk); ++ } else { ++ clk_disable_unprepare(lcd_axi_clk); ++ clk_disable_unprepare(lcd_pix_clk); ++ clk_disable_unprepare(epdc_axi_clk); ++ clk_disable_unprepare(epdc_pix_clk); ++ clk_disable_unprepare(pxp_axi_clk); ++ } ++} ++ ++static void imx_gpc_dispmix_on(void) ++{ ++ if (cpu_is_imx6sl()) { ++ imx_disp_clk(true); ++ ++ writel_relaxed(0x0, gpc_base + GPC_PGC_DISP_PGCR_OFFSET); ++ writel_relaxed(0x20, gpc_base + GPC_CNTR); ++ while (readl_relaxed(gpc_base + GPC_CNTR) & 0x20) ++ ; ++ writel_relaxed(0x1, gpc_base + GPC_PGC_DISP_SR_OFFSET); ++ ++ imx_disp_clk(false); ++ } ++} ++ ++static void imx_gpc_dispmix_off(void) ++{ ++ if (cpu_is_imx6sl()) { ++ imx_disp_clk(true); ++ ++ writel_relaxed(0xFFFFFFFF, ++ gpc_base + GPC_PGC_DISP_PUPSCR_OFFSET); ++ writel_relaxed(0xFFFFFFFF, ++ gpc_base + GPC_PGC_DISP_PDNSCR_OFFSET); ++ writel_relaxed(0x1, gpc_base + GPC_PGC_DISP_PGCR_OFFSET); ++ writel_relaxed(0x10, gpc_base + GPC_CNTR); ++ while (readl_relaxed(gpc_base + GPC_CNTR) & 0x10) ++ ; ++ ++ imx_disp_clk(false); ++ } ++} ++ ++void imx_gpc_pre_suspend(bool arm_power_off) + { + void __iomem *reg_imr1 = gpc_base + GPC_IMR1; + int i; + +- /* Tell GPC to power off ARM core when suspend */ +- writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN); ++ imx_gpc_dispmix_off(); ++ ++ if (arm_power_off) ++ /* Tell GPC to power off ARM core when suspend */ ++ writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN); + + for (i = 0; i < IMR_NUM; i++) { + gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4); +@@ -51,6 +148,8 @@ + + for (i = 0; i < IMR_NUM; i++) + writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); ++ ++ imx_gpc_dispmix_on(); + } + + static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on) +@@ -90,7 +189,7 @@ + writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4); + } + +-static void imx_gpc_irq_unmask(struct irq_data *d) ++void imx_gpc_irq_unmask(struct irq_data *d) + { + void __iomem *reg; + u32 val; +@@ -105,7 +204,7 @@ + writel_relaxed(val, reg); + } + +-static void imx_gpc_irq_mask(struct irq_data *d) ++void imx_gpc_irq_mask(struct irq_data *d) + { + void __iomem *reg; + u32 val; +@@ -120,10 +219,119 @@ + writel_relaxed(val, reg); + } + ++static void imx_pu_clk(bool enable) ++{ ++ if (enable) { ++ if (cpu_is_imx6sl()) { ++ clk_prepare_enable(gpu2d_clk); ++ clk_prepare_enable(openvg_axi_clk); ++ } else { ++ clk_prepare_enable(gpu3d_clk); ++ clk_prepare_enable(gpu3d_shader_clk); ++ clk_prepare_enable(vpu_clk); ++ clk_prepare_enable(gpu2d_clk); ++ clk_prepare_enable(gpu2d_axi_clk); ++ clk_prepare_enable(openvg_axi_clk); ++ } ++ } else { ++ if (cpu_is_imx6sl()) { ++ clk_disable_unprepare(gpu2d_clk); ++ clk_disable_unprepare(openvg_axi_clk); ++ } else { ++ clk_disable_unprepare(gpu3d_clk); ++ clk_disable_unprepare(gpu3d_shader_clk); ++ clk_disable_unprepare(vpu_clk); ++ clk_disable_unprepare(gpu2d_clk); ++ clk_disable_unprepare(gpu2d_axi_clk); ++ clk_disable_unprepare(openvg_axi_clk); ++ } ++ } ++} ++ ++static void imx_gpc_pu_enable(bool enable) ++{ ++ u32 rate, delay_us; ++ u32 gpu_pupscr_sw2iso, gpu_pdnscr_iso2sw; ++ u32 gpu_pupscr_sw, gpu_pdnscr_iso; ++ ++ /* get ipg clk rate for PGC delay */ ++ rate = clk_get_rate(ipg_clk); ++ ++ if (enable) { ++ imx_anatop_pu_enable(true); ++ /* ++ * need to add necessary delay between powering up PU LDO and ++ * disabling PU isolation in PGC, the counter of PU isolation ++ * is based on ipg clk. ++ */ ++ gpu_pupscr_sw2iso = (readl_relaxed(gpc_base + ++ GPC_PGC_GPU_PUPSCR) >> GPC_PGC_GPU_SW2ISO_SHIFT) ++ & GPC_PGC_GPU_SW2ISO_MASK; ++ gpu_pupscr_sw = (readl_relaxed(gpc_base + ++ GPC_PGC_GPU_PUPSCR) >> GPC_PGC_GPU_SW_SHIFT) ++ & GPC_PGC_GPU_SW_MASK; ++ delay_us = (gpu_pupscr_sw2iso + gpu_pupscr_sw) * 1000000 ++ / rate + 1; ++ udelay(delay_us); ++ ++ imx_pu_clk(true); ++ writel_relaxed(1, gpc_base + GPC_PGC_GPU_PDN); ++ writel_relaxed(1 << GPC_CNTR_PU_UP_REQ_SHIFT, ++ gpc_base + GPC_CNTR); ++ while (readl_relaxed(gpc_base + GPC_CNTR) & ++ (1 << GPC_CNTR_PU_UP_REQ_SHIFT)) ++ ; ++ imx_pu_clk(false); ++ } else { ++ writel_relaxed(1, gpc_base + GPC_PGC_GPU_PDN); ++ writel_relaxed(1 << GPC_CNTR_PU_DOWN_REQ_SHIFT, ++ gpc_base + GPC_CNTR); ++ while (readl_relaxed(gpc_base + GPC_CNTR) & ++ (1 << GPC_CNTR_PU_DOWN_REQ_SHIFT)) ++ ; ++ /* ++ * need to add necessary delay between enabling PU isolation ++ * in PGC and powering down PU LDO , the counter of PU isolation ++ * is based on ipg clk. ++ */ ++ gpu_pdnscr_iso2sw = (readl_relaxed(gpc_base + ++ GPC_PGC_GPU_PDNSCR) >> GPC_PGC_GPU_SW2ISO_SHIFT) ++ & GPC_PGC_GPU_SW2ISO_MASK; ++ gpu_pdnscr_iso = (readl_relaxed(gpc_base + ++ GPC_PGC_GPU_PDNSCR) >> GPC_PGC_GPU_SW_SHIFT) ++ & GPC_PGC_GPU_SW_MASK; ++ delay_us = (gpu_pdnscr_iso2sw + gpu_pdnscr_iso) * 1000000 ++ / rate + 1; ++ udelay(delay_us); ++ imx_anatop_pu_enable(false); ++ } ++} ++ ++static int imx_gpc_regulator_notify(struct notifier_block *nb, ++ unsigned long event, ++ void *ignored) ++{ ++ switch (event) { ++ case REGULATOR_EVENT_PRE_DISABLE: ++ imx_gpc_pu_enable(false); ++ break; ++ case REGULATOR_EVENT_ENABLE: ++ imx_gpc_pu_enable(true); ++ break; ++ default: ++ break; ++ } ++ ++ return NOTIFY_OK; ++} ++ + void __init imx_gpc_init(void) + { + struct device_node *np; + int i; ++ u32 val; ++ u32 cpu_pupscr_sw2iso, cpu_pupscr_sw; ++ u32 cpu_pdnscr_iso2sw, cpu_pdnscr_iso; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc"); + gpc_base = of_iomap(np, 0); +@@ -137,4 +345,197 @@ + gic_arch_extn.irq_mask = imx_gpc_irq_mask; + gic_arch_extn.irq_unmask = imx_gpc_irq_unmask; + gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake; ++ ++ /* ++ * If there are CPU isolation timing settings in dts, ++ * update them according to dts, otherwise, keep them ++ * with default value in registers. ++ */ ++ cpu_pupscr_sw2iso = cpu_pupscr_sw = ++ cpu_pdnscr_iso2sw = cpu_pdnscr_iso = 0; ++ ++ /* Read CPU isolation setting for GPC */ ++ of_property_read_u32(np, "fsl,cpu_pupscr_sw2iso", &cpu_pupscr_sw2iso); ++ of_property_read_u32(np, "fsl,cpu_pupscr_sw", &cpu_pupscr_sw); ++ of_property_read_u32(np, "fsl,cpu_pdnscr_iso2sw", &cpu_pdnscr_iso2sw); ++ of_property_read_u32(np, "fsl,cpu_pdnscr_iso", &cpu_pdnscr_iso); ++ ++ /* Update CPU PUPSCR timing if it is defined in dts */ ++ val = readl_relaxed(gpc_base + GPC_PGC_CPU_PUPSCR); ++ if (cpu_pupscr_sw2iso) ++ val &= ~(GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT); ++ if (cpu_pupscr_sw) ++ val &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT); ++ val |= cpu_pupscr_sw2iso << GPC_PGC_CPU_SW2ISO_SHIFT; ++ val |= cpu_pupscr_sw << GPC_PGC_CPU_SW_SHIFT; ++ writel_relaxed(val, gpc_base + GPC_PGC_CPU_PUPSCR); ++ ++ /* Update CPU PDNSCR timing if it is defined in dts */ ++ val = readl_relaxed(gpc_base + GPC_PGC_CPU_PDNSCR); ++ if (cpu_pdnscr_iso2sw) ++ val &= ~(GPC_PGC_CPU_SW2ISO_MASK << GPC_PGC_CPU_SW2ISO_SHIFT); ++ if (cpu_pdnscr_iso) ++ val &= ~(GPC_PGC_CPU_SW_MASK << GPC_PGC_CPU_SW_SHIFT); ++ val |= cpu_pdnscr_iso2sw << GPC_PGC_CPU_SW2ISO_SHIFT; ++ val |= cpu_pdnscr_iso << GPC_PGC_CPU_SW_SHIFT; ++ writel_relaxed(val, gpc_base + GPC_PGC_CPU_PDNSCR); ++} ++ ++static int imx_pureg_set_voltage(struct regulator_dev *reg, int min_uV, ++ int max_uV, unsigned *selector) ++{ ++ return 0; ++} ++ ++static int imx_pureg_enable(struct regulator_dev *rdev) ++{ ++ pu_dummy_enable = 1; ++ ++ return 0; ++} ++ ++static int imx_pureg_disable(struct regulator_dev *rdev) ++{ ++ pu_dummy_enable = 0; ++ ++ return 0; ++} ++ ++static int imx_pureg_is_enable(struct regulator_dev *rdev) ++{ ++ return pu_dummy_enable; ++} ++ ++static int imx_pureg_list_voltage(struct regulator_dev *rdev, ++ unsigned int selector) ++{ ++ return 0; ++} ++ ++static struct regulator_ops pu_dummy_ops = { ++ .set_voltage = imx_pureg_set_voltage, ++ .enable = imx_pureg_enable, ++ .disable = imx_pureg_disable, ++ .is_enabled = imx_pureg_is_enable, ++ .list_voltage = imx_pureg_list_voltage, ++}; ++ ++static struct regulator_desc pu_dummy_desc = { ++ .name = "pureg-dummy", ++ .id = -1, ++ .type = REGULATOR_VOLTAGE, ++ .owner = THIS_MODULE, ++ .ops = &pu_dummy_ops, ++}; ++ ++static int pu_dummy_probe(struct platform_device *pdev) ++{ ++ struct regulator_config config = { }; ++ int ret; ++ ++ config.dev = &pdev->dev; ++ config.init_data = &pu_dummy_initdata; ++ config.of_node = pdev->dev.of_node; ++ ++ pu_dummy_regulator_rdev = regulator_register(&pu_dummy_desc, &config); ++ if (IS_ERR(pu_dummy_regulator_rdev)) { ++ ret = PTR_ERR(pu_dummy_regulator_rdev); ++ dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; + } ++ ++static const struct of_device_id imx_pudummy_ids[] = { ++ { .compatible = "fsl,imx6-dummy-pureg" }, ++}; ++MODULE_DEVICE_TABLE(of, imx_pudummy_ids); ++ ++static struct platform_driver pu_dummy_driver = { ++ .probe = pu_dummy_probe, ++ .driver = { ++ .name = "pu-dummy", ++ .owner = THIS_MODULE, ++ .of_match_table = imx_pudummy_ids, ++ }, ++}; ++ ++static int imx_gpc_probe(struct platform_device *pdev) ++{ ++ int ret; ++ ++ gpc_dev = &pdev->dev; ++ ++ pu_reg = devm_regulator_get(gpc_dev, "pu"); ++ if (IS_ERR(pu_reg)) { ++ ret = PTR_ERR(pu_reg); ++ dev_info(gpc_dev, "pu regulator not ready.\n"); ++ return ret; ++ } ++ nb.notifier_call = &imx_gpc_regulator_notify; ++ ++ /* Get gpu&vpu clk for power up PU by GPC */ ++ if (cpu_is_imx6sl()) { ++ gpu2d_clk = devm_clk_get(gpc_dev, "gpu2d_podf"); ++ openvg_axi_clk = devm_clk_get(gpc_dev, "gpu2d_ovg"); ++ ipg_clk = devm_clk_get(gpc_dev, "ipg"); ++ lcd_axi_clk = devm_clk_get(gpc_dev, "lcd_axi"); ++ lcd_pix_clk = devm_clk_get(gpc_dev, "lcd_pix"); ++ epdc_axi_clk = devm_clk_get(gpc_dev, "epdc_axi"); ++ epdc_pix_clk = devm_clk_get(gpc_dev, "epdc_pix"); ++ pxp_axi_clk = devm_clk_get(gpc_dev, "pxp_axi"); ++ if (IS_ERR(gpu2d_clk) || IS_ERR(openvg_axi_clk) ++ || IS_ERR(ipg_clk) || IS_ERR(lcd_axi_clk) ++ || IS_ERR(lcd_pix_clk) || IS_ERR(epdc_axi_clk) ++ || IS_ERR(epdc_pix_clk) || IS_ERR(pxp_axi_clk)) { ++ dev_err(gpc_dev, "failed to get clk!\n"); ++ return -ENOENT; ++ } ++ } else { ++ gpu3d_clk = devm_clk_get(gpc_dev, "gpu3d_core"); ++ gpu3d_shader_clk = devm_clk_get(gpc_dev, "gpu3d_shader"); ++ gpu2d_clk = devm_clk_get(gpc_dev, "gpu2d_core"); ++ gpu2d_axi_clk = devm_clk_get(gpc_dev, "gpu2d_axi"); ++ openvg_axi_clk = devm_clk_get(gpc_dev, "openvg_axi"); ++ vpu_clk = devm_clk_get(gpc_dev, "vpu_axi"); ++ ipg_clk = devm_clk_get(gpc_dev, "ipg"); ++ if (IS_ERR(gpu3d_clk) || IS_ERR(gpu3d_shader_clk) ++ || IS_ERR(gpu2d_clk) || IS_ERR(gpu2d_axi_clk) ++ || IS_ERR(openvg_axi_clk) || IS_ERR(vpu_clk) ++ || IS_ERR(ipg_clk)) { ++ dev_err(gpc_dev, "failed to get clk!\n"); ++ return -ENOENT; ++ } ++ } ++ ++ ret = regulator_register_notifier(pu_reg, &nb); ++ if (ret) { ++ dev_err(gpc_dev, ++ "regulator notifier request failed\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id imx_gpc_ids[] = { ++ { .compatible = "fsl,imx6q-gpc" }, ++}; ++MODULE_DEVICE_TABLE(of, imx_gpc_ids); ++ ++static struct platform_driver imx_gpc_platdrv = { ++ .driver = { ++ .name = "imx-gpc", ++ .owner = THIS_MODULE, ++ .of_match_table = imx_gpc_ids, ++ }, ++ .probe = imx_gpc_probe, ++}; ++module_platform_driver(imx_gpc_platdrv); ++ ++module_platform_driver(pu_dummy_driver); ++ ++MODULE_AUTHOR("Anson Huang "); ++MODULE_DESCRIPTION("Freescale i.MX GPC driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/arch/arm/mach-imx/hardware.h linux-3.10.30-cubox-i/arch/arm/mach-imx/hardware.h +--- linux-3.10.30/arch/arm/mach-imx/hardware.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/hardware.h 2014-03-08 20:32:54.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Juergen Beisert, kernel@pengutronix.de + * + * This program is free software; you can redistribute it and/or +@@ -20,6 +20,9 @@ + #ifndef __ASM_ARCH_MXC_HARDWARE_H__ + #define __ASM_ARCH_MXC_HARDWARE_H__ + ++#ifndef __ASSEMBLY__ ++#include ++#endif + #include + + #define addr_in_module(addr, mod) \ +@@ -104,6 +107,7 @@ + + #include "mx51.h" + #include "mx53.h" ++#include "mx6.h" + #include "mx3x.h" + #include "mx31.h" + #include "mx35.h" +diff -Nur linux-3.10.30/arch/arm/mach-imx/hotplug.c linux-3.10.30-cubox-i/arch/arm/mach-imx/hotplug.c +--- linux-3.10.30/arch/arm/mach-imx/hotplug.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/hotplug.c 2014-03-08 20:32:54.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011 Freescale Semiconductor, Inc. ++ * Copyright 2011, 2013 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -52,7 +52,8 @@ + * the register being cleared to kill the cpu. + */ + imx_set_cpu_arg(cpu, ~0); +- cpu_do_idle(); ++ for (;;) ++ cpu_do_idle(); + } + + int imx_cpu_kill(unsigned int cpu) +diff -Nur linux-3.10.30/arch/arm/mach-imx/imx25-dt.c linux-3.10.30-cubox-i/arch/arm/mach-imx/imx25-dt.c +--- linux-3.10.30/arch/arm/mach-imx/imx25-dt.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/imx25-dt.c 2014-03-08 20:32:54.000000000 +0100 +@@ -19,6 +19,8 @@ + + static void __init imx25_dt_init(void) + { ++ mxc_arch_reset_init_dt(); ++ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + } + +diff -Nur linux-3.10.30/arch/arm/mach-imx/imx27-dt.c linux-3.10.30-cubox-i/arch/arm/mach-imx/imx27-dt.c +--- linux-3.10.30/arch/arm/mach-imx/imx27-dt.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/imx27-dt.c 2014-03-08 20:32:54.000000000 +0100 +@@ -22,6 +22,8 @@ + { + struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; + ++ mxc_arch_reset_init_dt(); ++ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + + platform_device_register_full(&devinfo); +diff -Nur linux-3.10.30/arch/arm/mach-imx/imx31-dt.c linux-3.10.30-cubox-i/arch/arm/mach-imx/imx31-dt.c +--- linux-3.10.30/arch/arm/mach-imx/imx31-dt.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/imx31-dt.c 2014-03-08 20:32:54.000000000 +0100 +@@ -20,6 +20,8 @@ + + static void __init imx31_dt_init(void) + { ++ mxc_arch_reset_init_dt(); ++ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + } + +diff -Nur linux-3.10.30/arch/arm/mach-imx/imx51-dt.c linux-3.10.30-cubox-i/arch/arm/mach-imx/imx51-dt.c +--- linux-3.10.30/arch/arm/mach-imx/imx51-dt.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/imx51-dt.c 2014-03-08 20:32:54.000000000 +0100 +@@ -23,6 +23,8 @@ + { + struct platform_device_info devinfo = { .name = "cpufreq-cpu0", }; + ++ mxc_arch_reset_init_dt(); ++ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + platform_device_register_full(&devinfo); + } +diff -Nur linux-3.10.30/arch/arm/mach-imx/imx6sl_wfi.S linux-3.10.30-cubox-i/arch/arm/mach-imx/imx6sl_wfi.S +--- linux-3.10.30/arch/arm/mach-imx/imx6sl_wfi.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/imx6sl_wfi.S 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,639 @@ ++/* ++ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#define IRAM_WAIT_SIZE (1 << 11) ++ ++ .macro sl_ddr_io_save ++ ++ ldr r4, [r1, #0x30c] /* DRAM_DQM0 */ ++ ldr r5, [r1, #0x310] /* DRAM_DQM1 */ ++ ldr r6, [r1, #0x314] /* DRAM_DQM2 */ ++ ldr r7, [r1, #0x318] /* DRAM_DQM3 */ ++ stmfd r9!, {r4-r7} ++ ++ ldr r4, [r1, #0x5c4] /* GPR_B0DS */ ++ ldr r5, [r1, #0x5cc] /* GPR_B1DS */ ++ ldr r6, [r1, #0x5d4] /* GPR_B2DS */ ++ ldr r7, [r1, #0x5d8] /* GPR_B3DS */ ++ stmfd r9!, {r4-r7} ++ ++ ldr r4, [r1, #0x300] /* DRAM_CAS */ ++ ldr r5, [r1, #0x31c] /* DRAM_RAS */ ++ ldr r6, [r1, #0x338] /* DRAM_SDCLK_0 */ ++ ldr r7, [r1, #0x5ac] /* GPR_ADDS*/ ++ stmfd r9!, {r4-r7} ++ ++ ldr r4, [r1, #0x5b0] /* DDRMODE_CTL */ ++ ldr r5, [r1, #0x5c0] /* DDRMODE */ ++ ldr r6, [r1, #0x33c] /* DRAM_SODT0*/ ++ ldr r7, [r1, #0x340] /* DRAM_SODT1*/ ++ stmfd r9!, {r4-r7} ++ ++ ldr r4, [r1, #0x330] /* DRAM_SDCKE0 */ ++ ldr r5, [r1, #0x334] /* DRAM_SDCKE1 */ ++ ldr r6, [r1, #0x320] /* DRAM_RESET */ ++ stmfd r9!, {r4-r6} ++ ++ .endm ++ ++ .macro sl_ddr_io_restore ++ ++ /* ++ * r9 points to IRAM stack. ++ * r1 points to IOMUX base address. ++ * r8 points to MMDC base address. ++ */ ++ ldmea r9!, {r4-r7} ++ str r4, [r1, #0x30c] /* DRAM_DQM0 */ ++ str r5, [r1, #0x310] /* DRAM_DQM1 */ ++ str r6, [r1, #0x314] /* DRAM_DQM2 */ ++ str r7, [r1, #0x318] /* DRAM_DQM3 */ ++ ++ ldmea r9!, {r4-r7} ++ str r4, [r1, #0x5c4] /* GPR_B0DS */ ++ str r5, [r1, #0x5cc] /* GPR_B1DS */ ++ str r6, [r1, #0x5d4] /* GPR_B2DS */ ++ str r7, [r1, #0x5d8] /* GPR_B3DS */ ++ ++ ldmea r9!, {r4-r7} ++ str r4, [r1, #0x300] /* DRAM_CAS */ ++ str r5, [r1, #0x31c] /* DRAM_RAS */ ++ str r6, [r1, #0x338] /* DRAM_SDCLK_0 */ ++ str r7, [r1, #0x5ac] /* GPR_ADDS*/ ++ ++ ldmea r9!, {r4-r7} ++ str r4, [r1, #0x5b0] /* DDRMODE_CTL */ ++ str r5, [r1, #0x5c0] /* DDRMODE */ ++ str r6, [r1, #0x33c] /* DRAM_SODT0*/ ++ str r7, [r1, #0x340] /* DRAM_SODT1*/ ++ ++ ldmea r9!, {r4-r6} ++ str r4, [r1, #0x330] /* DRAM_SDCKE0 */ ++ str r5, [r1, #0x334] /* DRAM_SDCKE1 */ ++ str r6, [r1, #0x320] /* DRAM_RESET */ ++ ++ /* ++ * Need to reset the FIFO to avoid MMDC lockup ++ * caused because of floating/changing the ++ * configuration of many DDR IO pads. ++ */ ++ ldr r7, =0x83c ++ ldr r6, [r8, r7] ++ orr r6, r6, #0x80000000 ++ str r6, [r8, r7] ++fifo_reset1_wait: ++ ldr r6, [r8, r7] ++ and r6, r6, #0x80000000 ++ cmp r6, #0 ++ bne fifo_reset1_wait ++ ++ /* reset FIFO a second time */ ++ ldr r6, [r8, r7] ++ orr r6, r6, #0x80000000 ++ str r6, [r8, r7] ++fifo_reset2_wait: ++ ldr r6, [r8, r7] ++ and r6, r6, #0x80000000 ++ cmp r6, #0 ++ bne fifo_reset2_wait ++ ++ .endm ++ ++ .macro sl_ddr_io_set_lpm ++ ++ mov r4, #0 ++ str r4, [r1, #0x30c] /* DRAM_DQM0 */ ++ str r4, [r1, #0x310] /* DRAM_DQM1 */ ++ str r4, [r1, #0x314] /* DRAM_DQM2 */ ++ str r4, [r1, #0x318] /* DRAM_DQM3 */ ++ ++ str r4, [r1, #0x5c4] /* GPR_B0DS */ ++ str r4, [r1, #0x5cc] /* GPR_B1DS */ ++ str r4, [r1, #0x5d4] /* GPR_B2DS */ ++ str r4, [r1, #0x5d8] /* GPR_B3DS */ ++ ++ str r4, [r1, #0x300] /* DRAM_CAS */ ++ str r4, [r1, #0x31c] /* DRAM_RAS */ ++ str r4, [r1, #0x338] /* DRAM_SDCLK_0 */ ++ str r4, [r1, #0x5ac] /* GPR_ADDS*/ ++ ++ str r4, [r1, #0x5b0] /* DDRMODE_CTL */ ++ str r4, [r1, #0x5c0] /* DDRMODE */ ++ str r4, [r1, #0x33c] /* DRAM_SODT0*/ ++ str r4, [r1, #0x340] /* DRAM_SODT1*/ ++ ++ mov r4, #0x80000 ++ str r4, [r1, #0x320] /* DRAM_RESET */ ++ mov r4, #0x1000 ++ str r4, [r1, #0x330] /* DRAM_SDCKE0 */ ++ str r4, [r1, #0x334] /* DRAM_SDCKE1 */ ++ ++ .endm ++ ++/* ++ * imx6sl_low_power_wfi ++ * ++ * Idle the processor (eg, wait for interrupt). ++ * Make sure DDR is in self-refresh. ++ * IRQs are already disabled. ++ * r0: WFI IRAMcode base address. ++ * r1: IOMUX base address ++ * r2: Base address of CCM, ANATOP and MMDC ++ * r3: 1 if in audio_bus_freq_mode ++ */ ++ .align 3 ++ENTRY(imx6sl_low_power_wfi) ++ ++ push {r4-r11} ++ ++mx6sl_lpm_wfi: ++ /* Store audio_bus_freq_mode */ ++ mov r11, r3 ++ ++ mov r4,r2 ++ /* Get the IRAM data storage address. */ ++ mov r10, r0 ++ mov r9, r0 /* get suspend_iram_base */ ++ add r9, r9, #IRAM_WAIT_SIZE ++ ++ /* Anatop Base address in r3. */ ++ ldr r3, [r4] ++ /* CCM Base Address in r2 */ ++ ldr r2, [r4, #0x4] ++ /* MMDC Base Address in r8 */ ++ ldr r8, [r4, #0x8] ++ /* L2 Base Address in r7 */ ++ ldr r7, [r4, #0xC] ++ ++ ldr r6, [r8] ++ ldr r6, [r3] ++ ldr r6, [r2] ++ ldr r6, [r1] ++ ++ /* Store the original ARM PODF. */ ++ ldr r0, [r2, #0x10] ++ ++ /* Drain all the L1 buffers. */ ++ dsb ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* ++ * Need to make sure the buffers in L2 are drained. ++ * Performing a sync operation does this. ++ */ ++ mov r6, #0x0 ++ str r6, [r7, #0x730] ++#endif ++ ++ /* ++ * The second dsb might be needed to keep cache sync (device write) ++ * ordering with the memory accesses before it. ++ */ ++ dsb ++ isb ++ ++ /* Save the DDR IO state. */ ++ sl_ddr_io_save ++ ++ /* Disable Automatic power savings. */ ++ ldr r6, [r8, #0x404] ++ orr r6, r6, #0x01 ++ str r6, [r8, #0x404] ++ ++ /* Make the DDR explicitly enter self-refresh. */ ++ ldr r6, [r8, #0x404] ++ orr r6, r6, #0x200000 ++ str r6, [r8, #0x404] ++ ++poll_dvfs_set_1: ++ ldr r6, [r8, #0x404] ++ and r6, r6, #0x2000000 ++ cmp r6, #0x2000000 ++ bne poll_dvfs_set_1 ++ ++ /* set SBS step-by-step mode */ ++ ldr r6, [r8, #0x410] ++ orr r6, r6, #0x100 ++ str r6, [r8, #0x410] ++ ++ cmp r11, #1 ++ beq audio_mode ++ /* ++ * Now set DDR rate to 1MHz. ++ * DDR is from bypassed PLL2 on periph2_clk2 path. ++ * Set the periph2_clk2_podf to divide by 8. ++ */ ++ ldr r6, [r2, #0x14] ++ orr r6, r6, #0x07 ++ str r6, [r2, #0x14] ++ ++ /* Now set MMDC PODF to divide by 3. */ ++ ldr r6, [r2, #0x14] ++ bic r6, r6, #0x38 ++ orr r6, r6, #0x10 ++ str r6, [r2, #0x14] ++ b mmdc_podf ++ ++audio_mode: ++ /* MMDC is from PLL2_200M. ++ * Set the mmdc_podf to div by 8. ++ */ ++ ldr r6, [r2, #0x14] ++ orr r6, r6, #0x38 ++ str r6, [r2, #0x14] ++ ++ /* Loop till podf is accepted. */ ++mmdc_podf: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0x0 ++ bne mmdc_podf ++ ++ /* Set the DDR IO in LPM state. */ ++ sl_ddr_io_set_lpm ++ ++ cmp r11, #1 ++ beq do_audio_arm_clk ++ ++ /* ++ * Check if none of the PLLs are ++ * locked, except PLL1 which will get ++ * bypassed below. ++ * We should not be here if PLL2 is not ++ * bypassed. ++ */ ++ ldr r7, =1 ++ /* USB1 PLL3 */ ++ ldr r6, [r3, #0x10] ++ and r6, r6, #0x80000000 ++ cmp r6, #0x80000000 ++ beq no_analog_saving ++ ++ /* USB2 PLL7 */ ++ ldr r6, [r3, #0x20] ++ and r6, r6, #0x80000000 ++ cmp r6, #0x80000000 ++ beq no_analog_saving ++ ++ /* Audio PLL4 */ ++ ldr r6, [r3, #0x70] ++ and r6, r6, #0x80000000 ++ cmp r6, #0x80000000 ++ beq no_analog_saving ++ ++ /* Video PLL5 */ ++ ldr r6, [r3, #0xA0] ++ and r6, r6, #0x80000000 ++ cmp r6, #0x80000000 ++ beq no_analog_saving ++ ++ /* ENET PLL8 */ ++ ldr r6, [r3, #0xE0] ++ and r6, r6, #0x80000000 ++ cmp r6, #0x80000000 ++ beq no_analog_saving ++ ++ b cont ++ ++no_analog_saving: ++ ldr r7, =0 ++ ++cont: ++ /* Set the AHB to 3MHz. AXI to 3MHz. */ ++ ldr r9, [r2, #0x14] ++ mov r6, r9 ++ orr r6, r6, #0x1c00 ++ orr r6, r6, #0x70000 ++ str r6, [r2, #0x14] ++ ++ /* Loop till podf is accepted. */ ++ahb_podf: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0x0 ++ bne podf_loop ++ ++ /* ++ * Now set ARM to 24MHz. ++ * Move ARM to be sourced from STEP_CLK ++ * after setting STEP_CLK to 24MHz. ++ */ ++ ldr r6, [r2, #0xc] ++ bic r6, r6, #0x100 ++ str r6, [r2, #0x0c] ++ /* Now PLL1_SW_CLK to step_clk. */ ++ ldr r6, [r2, #0x0c] ++ orr r6, r6, #0x4 ++ str r6, [r2, #0x0c] ++ ++ /* Bypass PLL1 and power it down. */ ++ ldr r6, =(1 << 16) ++ orr r6, r6, #0x1000 ++ str r6, [r3, #0x04] ++ ++ /* ++ * Set the ARM PODF to divide by 8. ++ * IPG is at 1.5MHz here, we need ARM to ++ * run at the 12:5 ratio (WAIT mode issue). ++ */ ++ ldr r6, =0x7 ++ str r6, [r2, #0x10] ++ ++ /* Loop till podf is accepted. */ ++podf_loop: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0x0 ++ bne podf_loop ++ ++ /* ++ * Check if we can save some ++ * power in the Analog section. ++ */ ++ cmp r7, #0x1 ++ bne do_wfi ++ ++ /* Disable 1p1 brown out. */ ++ ldr r6, [r3, #0x110] ++ bic r6, r6, #0x2 ++ str r6, [r3, #0x110] ++ ++ /* Enable the weak 2P5 */ ++ ldr r6, [r3, #0x130] ++ orr r6, r6, #0x40000 ++ str r6, [r3, #0x130] ++ ++ /* Disable main 2p5. */ ++ ldr r6, [r3, #0x130] ++ bic r6, r6, #0x1 ++ str r6, [r3, #0x130] ++ ++ /* ++ * Set the OSC bias current to -37.5% ++ * to drop the power on VDDHIGH. ++ */ ++ ldr r6, [r3, #0x150] ++ orr r6, r6, #0xC000 ++ str r6, [r3, #0x150] ++ ++ /* Enable low power bandgap */ ++ ldr r6, [r3, #0x260] ++ orr r6, r6, #0x20 ++ str r6, [r3, #0x260] ++ ++ /* ++ * Turn off the bias current ++ * from the regular bandgap. ++ */ ++ ldr r6, [r3, #0x260] ++ orr r6, r6, #0x80 ++ str r6, [r3, #0x260] ++ ++ /* ++ * Clear the REFTOP_SELFBIASOFF, ++ * self-bias circuit of the band gap. ++ * Per RM, should be cleared when ++ * band gap is powered down. ++ */ ++ ldr r6, [r3, #0x150] ++ bic r6, r6, #0x8 ++ str r6, [r3, #0x150] ++ ++ /* Power down the regular bandgap. */ ++ ldr r6, [r3, #0x150] ++ orr r6, r6, #0x1 ++ str r6, [r3, #0x150] ++ ++ b do_wfi ++ ++do_audio_arm_clk: ++ /* ++ * ARM is from PLL2_PFD2_400M here. ++ * Switch ARM to bypassed PLL1. ++ */ ++ ldr r6, [r2, #0xC] ++ bic r6, r6, #0x4 ++ str r6, [r2, #0xC] ++ ++ /* ++ * Set the ARM_PODF to divide by 2 ++ * as IPG is at 4MHz, we cannot run ++ * ARM_CLK above 9.6MHz when ++ * system enters WAIT mode. ++ */ ++ ldr r6, =0x2 ++ str r6, [r2, #0x10] ++ ++ /* Loop till podf is accepted. */ ++podf_loop_audio: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0x0 ++ bne podf_loop_audio ++ ++do_wfi: ++ /* Now do WFI. */ ++ wfi ++ ++ /* Set original ARM PODF back. */ ++ str r0, [r2, #0x10] ++ ++ /* Loop till podf is accepted. */ ++podf_loop1: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0x0 ++ bne podf_loop1 ++ ++ cmp r11, #1 ++ beq audio_arm_clk_restore ++ ++ /* ++ * Check if powered down ++ * analog components. ++ */ ++ cmp r7, #0x1 ++ bne skip_analog_restore ++ ++ /* Power up the regular bandgap. */ ++ ldr r6, [r3, #0x150] ++ bic r6, r6, #0x1 ++ str r6, [r3, #0x150] ++ ++ /* ++ * Turn on the bias current ++ * from the regular bandgap. ++ */ ++ ldr r6, [r3, #0x260] ++ bic r6, r6, #0x80 ++ str r6, [r3, #0x260] ++ ++ /* Disable the low power bandgap */ ++ ldr r6, [r3, #0x260] ++ bic r6, r6, #0x20 ++ str r6, [r3, #0x260] ++ ++ /* ++ * Set the OSC bias current to max ++ * value for normal operation. ++ */ ++ ldr r6, [r3, #0x150] ++ bic r6, r6, #0xC000 ++ str r6, [r3, #0x150] ++ ++ /* Enable main 2p5. */ ++ ldr r6, [r3, #0x130] ++ orr r6, r6, #0x1 ++ str r6, [r3, #0x130] ++ ++ /* Ensure the 2P5 is up. */ ++loop_2p5: ++ ldr r6, [r3, #0x130] ++ and r6, r6, #0x20000 ++ cmp r6, #0x20000 ++ bne loop_2p5 ++ ++ /* Disable the weak 2P5 */ ++ ldr r6, [r3, #0x130] ++ bic r6, r6, #0x40000 ++ str r6, [r3, #0x130] ++ ++ /* Enable 1p1 brown out. */ ++ ldr r6, [r3, #0x110] ++ orr r6, r6, #0x2 ++ str r6, [r3, #0x110] ++ ++skip_analog_restore: ++ ++ /* Power up PLL1 and un-bypass it. */ ++ ldr r6, =(1 << 12) ++ str r6, [r3, #0x08] ++ ++ /* Wait for PLL1 to relock. */ ++wait_for_pll_lock: ++ ldr r6, [r3, #0x0] ++ and r6, r6, #0x80000000 ++ cmp r6, #0x80000000 ++ bne wait_for_pll_lock ++ ++ ldr r6, =(1 << 16) ++ str r6, [r3, #0x08] ++ ++ /* Set PLL1_sw_clk back to PLL1. */ ++ ldr r6, [r2, #0x0c] ++ bic r6, r6, #0x4 ++ str r6, [r2, #0xc] ++ ++ /* Restore AHB/AXI back. */ ++ str r9, [r2, #0x14] ++ ++ /* Loop till podf is accepted. */ ++ahb_podf1: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0x0 ++ bne podf_loop1 ++ ++ b wfi_restore ++ ++ audio_arm_clk_restore: ++ /* Move ARM back to PLL2_PFD2_400M */ ++ ldr r6, [r2, #0xC] ++ orr r6, r6, #0x4 ++ str r6, [r2, #0xC] ++ ++wfi_restore: ++ /* get suspend_iram_base */ ++ mov r9, r10 ++ add r9, r9, #IRAM_WAIT_SIZE ++ ++ /* Restore the DDR IO before exiting self-refresh. */ ++ sl_ddr_io_restore ++ ++ /* ++ * Set MMDC back to 24MHz. ++ * Set periph2_clk2_podf to divide by 1 ++ * Now set MMDC PODF to divide by 1. ++ */ ++ ldr r6, [r2, #0x14] ++ bic r6, r6, #0x3f ++ str r6, [r2, #0x14] ++ ++mmdc_podf1: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0x0 ++ bne mmdc_podf1 ++ ++ /* clear DVFS - exit from self refresh mode */ ++ ldr r6, [r8, #0x404] ++ bic r6, r6, #0x200000 ++ str r6, [r8, #0x404] ++ ++poll_dvfs_clear_1: ++ ldr r6, [r8, #0x404] ++ and r6, r6, #0x2000000 ++ cmp r6, #0x2000000 ++ beq poll_dvfs_clear_1 ++ ++ /* ++ * Add these nops so that the ++ * prefetcher will not try to get ++ * any instructions from DDR. ++ * The prefetch depth is about 23 ++ * on A9, so adding 25 nops. ++ */ ++ nop ++ nop ++ nop ++ nop ++ nop ++ ++ nop ++ nop ++ nop ++ nop ++ nop ++ ++ nop ++ nop ++ nop ++ nop ++ nop ++ ++ nop ++ nop ++ nop ++ nop ++ nop ++ ++ nop ++ nop ++ nop ++ nop ++ nop ++ ++ /* Enable Automatic power savings. */ ++ ldr r6, [r8, #0x404] ++ bic r6, r6, #0x01 ++ str r6, [r8, #0x404] ++ ++ /* clear SBS - unblock DDR accesses */ ++ ldr r6, [r8, #0x410] ++ bic r6, r6, #0x100 ++ str r6, [r8, #0x410] ++ ++ ++ pop {r4-r11} ++ ++ /* Restore registers */ ++ mov pc, lr +diff -Nur linux-3.10.30/arch/arm/mach-imx/lpddr2_freq_imx6.S linux-3.10.30-cubox-i/arch/arm/mach-imx/lpddr2_freq_imx6.S +--- linux-3.10.30/arch/arm/mach-imx/lpddr2_freq_imx6.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/lpddr2_freq_imx6.S 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,484 @@ ++/* ++ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++ ++ .macro mx6sl_switch_to_24MHz ++ ++ /* ++ * Set MMDC clock to be sourced from PLL3. ++ * Ensure first periph2_clk2 is sourced from PLL3. ++ * Set the PERIPH2_CLK2_PODF to divide by 2. ++ */ ++ ldr r6, [r2, #0x14] ++ bic r6, r6, #0x7 ++ orr r6, r6, #0x1 ++ str r6, [r2, #0x14] ++ ++ /* Select PLL3 to source MMDC. */ ++ ldr r6, [r2, #0x18] ++ bic r6, r6, #0x100000 ++ str r6, [r2, #0x18] ++ ++ /* Swtich periph2_clk_sel to run from PLL3. */ ++ ldr r6, [r2, #0x14] ++ orr r6, r6, #0x4000000 ++ str r6, [r2, #0x14] ++ ++periph2_clk_switch1: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0 ++ bne periph2_clk_switch1 ++ ++ /* ++ * Need to clock gate the 528 PFDs before ++ * powering down PLL2. ++ * Only the PLL2_PFD2_400M should be ON ++ * at this time, so only clock gate that one. ++ */ ++ ldr r6, [r3, #0x100] ++ orr r6, r6, #0x800000 ++ str r6, [r3, #0x100] ++ ++ /* ++ * Set PLL2 to bypass state. We should be here ++ * only if MMDC is not sourced from PLL2. ++ */ ++ ldr r6, [r3, #0x30] ++ orr r6, r6, #0x10000 ++ str r6, [r3, #0x30] ++ ++ ldr r6, [r3, #0x30] ++ orr r6, r6, #0x1000 ++ str r6, [r3, #0x30] ++ ++ /* Ensure pre_periph2_clk_mux is set to pll2 */ ++ ldr r6, [r2, #0x18] ++ bic r6, r6, #0x600000 ++ str r6, [r2, #0x18] ++ ++ /* Set MMDC clock to be sourced from the bypassed PLL2. */ ++ ldr r6, [r2, #0x14] ++ bic r6, r6, #0x4000000 ++ str r6, [r2, #0x14] ++ ++periph2_clk_switch2: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0 ++ bne periph2_clk_switch2 ++ ++ /* ++ * Now move MMDC back to periph2_clk2 source. ++ * after selecting PLL2 as the option. ++ * Select PLL2 as the source. ++ */ ++ ldr r6, [r2, #0x18] ++ orr r6, r6, #0x100000 ++ str r6, [r2, #0x18] ++ ++ /* set periph2_clk2_podf to divide by 1. */ ++ ldr r6, [r2, #0x14] ++ bic r6, r6, #0x7 ++ str r6, [r2, #0x14] ++ ++ /* Now move periph2_clk to periph2_clk2 source */ ++ ldr r6, [r2, #0x14] ++ orr r6, r6, #0x4000000 ++ str r6, [r2, #0x14] ++ ++periph2_clk_switch3: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0 ++ bne periph2_clk_switch3 ++ ++ /* Now set the MMDC PODF back to 1.*/ ++ ldr r6, [r2, #0x14] ++ bic r6, r6, #0x38 ++ str r6, [r2, #0x14] ++ ++mmdc_podf0: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0 ++ bne mmdc_podf0 ++ ++ .endm ++ ++ .macro ddr_switch_400MHz ++ ++ /* Set MMDC divider first, in case PLL3 is at 480MHz. */ ++ ldr r6, [r3, #0x10] ++ and r6, r6, #0x10000 ++ cmp r6, #0x10000 ++ beq pll3_in_bypass ++ ++ /* Set MMDC divder to divide by 2. */ ++ ldr r6, [r2, #0x14] ++ bic r6, r6, #0x38 ++ orr r6, r6, #0x8 ++ str r6, [r2, #0x14] ++ ++mmdc_podf: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0 ++ bne mmdc_podf ++ ++pll3_in_bypass: ++ /* ++ * Check if we are switching between ++ * 400Mhz <-> 100MHz.If so, we should ++ * try to source MMDC from PLL2_200M. ++ */ ++ cmp r1, #0 ++ beq not_low_bus_freq ++ ++ /* Ensure that MMDC is sourced from PLL2 mux first. */ ++ ldr r6, [r2, #0x14] ++ bic r6, r6, #0x4000000 ++ str r6, [r2, #0x14] ++ ++periph2_clk_switch4: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0 ++ bne periph2_clk_switch4 ++ ++not_low_bus_freq: ++ /* Now ensure periph2_clk2_sel mux is set to PLL3 */ ++ ldr r6, [r2, #0x18] ++ bic r6, r6, #0x100000 ++ str r6, [r2, #0x18] ++ ++ /* Now switch MMDC to PLL3. */ ++ ldr r6, [r2, #0x14] ++ orr r6, r6, #0x4000000 ++ str r6, [r2, #0x14] ++ ++periph2_clk_switch5: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0 ++ bne periph2_clk_switch5 ++ ++ /* ++ * Check if PLL2 is already unlocked. ++ * If so do nothing with PLL2. ++ */ ++ cmp r1, #0 ++ beq pll2_already_on ++ ++ /* Now power up PLL2 and unbypass it. */ ++ ldr r6, [r3, #0x30] ++ bic r6, r6, #0x1000 ++ str r6, [r3, #0x30] ++ ++ /* Make sure PLL2 has locked.*/ ++wait_for_pll_lock: ++ ldr r6, [r3, #0x30] ++ and r6, r6, #0x80000000 ++ cmp r6, #0x80000000 ++ bne wait_for_pll_lock ++ ++ ldr r6, [r3, #0x30] ++ bic r6, r6, #0x10000 ++ str r6, [r3, #0x30] ++ ++ /* ++ * Need to enable the 528 PFDs after ++ * powering up PLL2. ++ * Only the PLL2_PFD2_400M should be ON ++ * as it feeds the MMDC. Rest should have ++ * been managed by clock code. ++ */ ++ ldr r6, [r3, #0x100] ++ bic r6, r6, #0x800000 ++ str r6, [r3, #0x100] ++ ++pll2_already_on: ++ /* ++ * Now switch MMDC clk back to pll2_mux option. ++ * Ensure pre_periph2_clk2 is set to pll2_pfd_400M. ++ * If switching to audio DDR freq, set the ++ * pre_periph2_clk2 to PLL2_PFD_200M ++ */ ++ ldr r6, =400000000 ++ cmp r6, r0 ++ bne use_pll2_pfd_200M ++ ++ ldr r6, [r2, #0x18] ++ bic r6, r6, #0x600000 ++ orr r6, r6, #0x200000 ++ str r6, [r2, #0x18] ++ ldr r6, =400000000 ++ b cont2 ++ ++use_pll2_pfd_200M: ++ ldr r6, [r2, #0x18] ++ orr r6, r6, #0x600000 ++ str r6, [r2, #0x18] ++ ldr r6, =200000000 ++ ++cont2: ++ ldr r4, [r2, #0x14] ++ bic r4, r4, #0x4000000 ++ str r4, [r2, #0x14] ++ ++periph2_clk_switch6: ++ ldr r4, [r2, #0x48] ++ cmp r4, #0 ++ bne periph2_clk_switch6 ++ ++change_divider_only: ++ /* ++ * Calculate the MMDC divider ++ * based on the requested freq. ++ */ ++ ldr r4, =0 ++Loop2: ++ sub r6, r6, r0 ++ cmp r6, r0 ++ blt Div_Found ++ add r4, r4, #1 ++ bgt Loop2 ++ ++ /* Shift divider into correct offset. */ ++ lsl r4, r4, #3 ++Div_Found: ++ /* Set the MMDC PODF. */ ++ ldr r6, [r2, #0x14] ++ bic r6, r6, #0x38 ++ orr r6, r6, r4 ++ str r6, [r2, #0x14] ++ ++mmdc_podf1: ++ ldr r6, [r2, #0x48] ++ cmp r6, #0 ++ bne mmdc_podf1 ++ ++ .endm ++ ++ .macro mmdc_clk_lower_100MHz ++ ++ /* ++ * Prior to reducing the DDR frequency (at 528/400 MHz), ++ * read the Measure unit count bits (MU_UNIT_DEL_NUM) ++ */ ++ ldr r5, =0x8B8 ++ ldr r6, [r8, r5] ++ /* Original MU unit count */ ++ mov r6, r6, LSR #16 ++ ldr r4, =0x3FF ++ and r6, r6, r4 ++ /* Original MU unit count * 2 */ ++ mov r7, r6, LSL #1 ++ /* ++ * Bypass the automatic measure unit when below 100 MHz ++ * by setting the Measure unit bypass enable bit (MU_BYP_EN) ++ */ ++ ldr r6, [r8, r5] ++ orr r6, r6, #0x400 ++ str r6, [r8, r5] ++ /* ++ * Double the measure count value read in step 1 and program it in the ++ * measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit ++ * Register for the reduced frequency operation below 100 MHz ++ */ ++ ldr r6, [r8, r5] ++ ldr r4, =0x3FF ++ bic r6, r6, r4 ++ orr r6, r6, r7 ++ str r6, [r8, r5] ++ /* Now perform a Force Measurement. */ ++ ldr r6, [r8, r5] ++ orr r6, r6, #0x800 ++ str r6, [r8, r5] ++ /* Wait for FRC_MSR to clear. */ ++force_measure: ++ ldr r6, [r8, r5] ++ and r6, r6, #0x800 ++ cmp r6, #0x0 ++ bne force_measure ++ ++ .endm ++ ++ .macro mmdc_clk_above_100MHz ++ ++ /* Make sure that the PHY measurement unit is NOT in bypass mode */ ++ ldr r5, =0x8B8 ++ ldr r6, [r8, r5] ++ bic r6, r6, #0x400 ++ str r6, [r8, r5] ++ /* Now perform a Force Measurement. */ ++ ldr r6, [r8, r5] ++ orr r6, r6, #0x800 ++ str r6, [r8, r5] ++ /* Wait for FRC_MSR to clear. */ ++force_measure1: ++ ldr r6, [r8, r5] ++ and r6, r6, #0x800 ++ cmp r6, #0x0 ++ bne force_measure1 ++ .endm ++ ++/* ++ * mx6_lpddr2_freq_change ++ * ++ * Make sure DDR is in self-refresh. ++ * IRQs are already disabled. ++ * r0 : DDR freq. ++ * r1: low_bus_freq_mode flag ++ * r2: Pointer to array containing addresses of registers. ++ */ ++ .align 3 ++ENTRY(mx6_lpddr2_freq_change) ++ ++ push {r4-r10} ++ ++ mov r4, r2 ++ ldr r3, [r4] @ANATOP_BASE_ADDR ++ ldr r2, [r4, #0x4] @CCM_BASE_ADDR ++ ldr r8, [r4, #0x8] @MMDC_P0_BASE_ADDR ++ ldr r7, [r4, #0xC] @L2_BASE_ADDR ++ ++lpddr2_freq_change: ++ adr r9, lpddr2_freq_change ++ ++ /* Prime all TLB entries. */ ++ ldr r6, [r9] ++ ldr r6, [r8] ++ ldr r6, [r3] ++ ldr r6, [r2] ++ ++ /* Drain all the L1 buffers. */ ++ dsb ++ ++#ifdef CONFIG_CACHE_L2X0 ++ /* ++ * Need to make sure the buffers in L2 are drained. ++ * Performing a sync operation does this. ++ */ ++ mov r6, #0x0 ++ str r6, [r7, #0x730] ++#endif ++ ++ /* ++ * The second dsb might be needed to keep cache sync (device write) ++ * ordering with the memory accesses before it. ++ */ ++ dsb ++ isb ++ ++ /* Disable Automatic power savings. */ ++ ldr r6, [r8, #0x404] ++ orr r6, r6, #0x01 ++ str r6, [r8, #0x404] ++ ++ /* MMDC0_MDPDC disable power down timer */ ++ ldr r6, [r8, #0x4] ++ bic r6, r6, #0xff00 ++ str r6, [r8, #0x4] ++ ++ /* Delay for a while */ ++ ldr r10, =10 ++delay1: ++ ldr r7, =0 ++cont1: ++ ldr r6, [r8, r7] ++ add r7, r7, #4 ++ cmp r7, #16 ++ bne cont1 ++ sub r10, r10, #1 ++ cmp r10, #0 ++ bgt delay1 ++ ++ /* Make the DDR explicitly enter self-refresh. */ ++ ldr r6, [r8, #0x404] ++ orr r6, r6, #0x200000 ++ str r6, [r8, #0x404] ++ ++poll_dvfs_set_1: ++ ldr r6, [r8, #0x404] ++ and r6, r6, #0x2000000 ++ cmp r6, #0x2000000 ++ bne poll_dvfs_set_1 ++ ++ /* set SBS step-by-step mode */ ++ ldr r6, [r8, #0x410] ++ orr r6, r6, #0x100 ++ str r6, [r8, #0x410] ++ ++ ldr r10, =100000000 ++ cmp r0, r10 ++ bgt set_ddr_mu_above_100 ++ mmdc_clk_lower_100MHz ++ ++set_ddr_mu_above_100: ++ ldr r10, =24000000 ++ cmp r0, r10 ++ beq set_to_24MHz ++ ++ ddr_switch_400MHz ++ ++ ldr r10,=100000000 ++ cmp r0, r10 ++ blt done ++ mmdc_clk_above_100MHz ++ ++ b done ++ ++set_to_24MHz: ++ mx6sl_switch_to_24MHz ++ ++done: ++ /* clear DVFS - exit from self refresh mode */ ++ ldr r6, [r8, #0x404] ++ bic r6, r6, #0x200000 ++ str r6, [r8, #0x404] ++ ++poll_dvfs_clear_1: ++ ldr r6, [r8, #0x404] ++ and r6, r6, #0x2000000 ++ cmp r6, #0x2000000 ++ beq poll_dvfs_clear_1 ++ ++ /* Enable Automatic power savings. */ ++ ldr r6, [r8, #0x404] ++ bic r6, r6, #0x01 ++ str r6, [r8, #0x404] ++ ++ ldr r10, =24000000 ++ cmp r0, r10 ++ beq skip_power_down ++ ++ /* Enable MMDC power down timer. */ ++ ldr r6, [r8, #0x4] ++ orr r6, r6, #0x5500 ++ str r6, [r8, #0x4] ++ ++skip_power_down: ++ /* clear SBS - unblock DDR accesses */ ++ ldr r6, [r8, #0x410] ++ bic r6, r6, #0x100 ++ str r6, [r8, #0x410] ++ ++ pop {r4-r10} ++ ++ /* Restore registers */ ++ mov pc, lr ++ ++ .type mx6_lpddr2_do_iram, #object ++ENTRY(mx6_lpddr2_do_iram) ++ .word mx6_lpddr2_freq_change ++ .size mx6_lpddr2_freq_change, . - mx6_lpddr2_freq_change +diff -Nur linux-3.10.30/arch/arm/mach-imx/mach-imx53.c linux-3.10.30-cubox-i/arch/arm/mach-imx/mach-imx53.c +--- linux-3.10.30/arch/arm/mach-imx/mach-imx53.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mach-imx53.c 2014-03-08 20:32:54.000000000 +0100 +@@ -21,6 +21,7 @@ + #include + + #include "common.h" ++#include "hardware.h" + #include "mx53.h" + + static void __init imx53_qsb_init(void) +@@ -38,6 +39,8 @@ + + static void __init imx53_dt_init(void) + { ++ mxc_arch_reset_init_dt(); ++ + if (of_machine_is_compatible("fsl,imx53-qsb")) + imx53_qsb_init(); + +diff -Nur linux-3.10.30/arch/arm/mach-imx/mach-imx6q.c linux-3.10.30-cubox-i/arch/arm/mach-imx/mach-imx6q.c +--- linux-3.10.30/arch/arm/mach-imx/mach-imx6q.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mach-imx6q.c 2014-03-08 20:32:54.000000000 +0100 +@@ -10,12 +10,14 @@ + * http://www.gnu.org/copyleft/gpl.html + */ + ++#include + #include ++#include + #include + #include + #include +-#include + #include ++#include + #include + #include + #include +@@ -23,13 +25,15 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include + #include +-#include ++#include ++#include + #include + #include + #include +@@ -38,62 +42,67 @@ + #include "cpuidle.h" + #include "hardware.h" + +-static u32 chip_revision; ++static struct flexcan_platform_data flexcan_pdata[2]; ++static int flexcan_en_gpio; ++static int flexcan_stby_gpio; ++static int flexcan0_en; ++static int flexcan1_en; ++static void mx6q_flexcan_switch(void) ++{ ++ if (flexcan0_en || flexcan1_en) { ++ /* ++ * The transceiver TJA1041A on sabreauto RevE baseboard will ++ * fail to transit to Normal state if EN/STBY is high by default ++ * after board power up. So we set the EN/STBY initial state to low ++ * first then to high to guarantee the state transition successfully. ++ */ ++ gpio_set_value_cansleep(flexcan_en_gpio, 0); ++ gpio_set_value_cansleep(flexcan_stby_gpio, 0); ++ ++ gpio_set_value_cansleep(flexcan_en_gpio, 1); ++ gpio_set_value_cansleep(flexcan_stby_gpio, 1); ++ } else { ++ /* ++ * avoid to disable CAN xcvr if any of the CAN interfaces ++ * are down. XCRV will be disabled only if both CAN2 ++ * interfaces are DOWN. ++ */ ++ gpio_set_value_cansleep(flexcan_en_gpio, 0); ++ gpio_set_value_cansleep(flexcan_stby_gpio, 0); ++ } ++} + +-int imx6q_revision(void) ++static void imx6q_flexcan0_switch_auto(int enable) + { +- return chip_revision; ++ flexcan0_en = enable; ++ mx6q_flexcan_switch(); + } + +-static void __init imx6q_init_revision(void) ++static void imx6q_flexcan1_switch_auto(int enable) + { +- u32 rev = imx_anatop_get_digprog(); +- +- switch (rev & 0xff) { +- case 0: +- chip_revision = IMX_CHIP_REVISION_1_0; +- break; +- case 1: +- chip_revision = IMX_CHIP_REVISION_1_1; +- break; +- case 2: +- chip_revision = IMX_CHIP_REVISION_1_2; +- break; +- default: +- chip_revision = IMX_CHIP_REVISION_UNKNOWN; +- } +- +- mxc_set_cpu_type(rev >> 16 & 0xff); ++ flexcan1_en = enable; ++ mx6q_flexcan_switch(); + } + +-static void imx6q_restart(char mode, const char *cmd) ++static int __init imx6q_flexcan_fixup_auto(void) + { + struct device_node *np; +- void __iomem *wdog_base; +- +- np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-wdt"); +- wdog_base = of_iomap(np, 0); +- if (!wdog_base) +- goto soft; +- +- imx_src_prepare_restart(); + +- /* enable wdog */ +- writew_relaxed(1 << 2, wdog_base); +- /* write twice to ensure the request will not get ignored */ +- writew_relaxed(1 << 2, wdog_base); +- +- /* wait for reset to assert ... */ +- mdelay(500); +- +- pr_err("Watchdog reset failed to assert reset\n"); +- +- /* delay to allow the serial port to show the message */ +- mdelay(50); ++ np = of_find_node_by_path("/soc/aips-bus@02000000/can@02090000"); ++ if (!np) ++ return -ENODEV; ++ ++ flexcan_en_gpio = of_get_named_gpio(np, "trx-en-gpio", 0); ++ flexcan_stby_gpio = of_get_named_gpio(np, "trx-stby-gpio", 0); ++ if (gpio_is_valid(flexcan_en_gpio) && gpio_is_valid(flexcan_stby_gpio) && ++ !gpio_request_one(flexcan_en_gpio, GPIOF_DIR_OUT, "flexcan-trx-en") && ++ !gpio_request_one(flexcan_stby_gpio, GPIOF_DIR_OUT, "flexcan-trx-stby")) { ++ /* flexcan 0 & 1 are using the same GPIOs for transceiver */ ++ flexcan_pdata[0].transceiver_switch = imx6q_flexcan0_switch_auto; ++ flexcan_pdata[1].transceiver_switch = imx6q_flexcan1_switch_auto; ++ } + +-soft: +- /* we'll take a jump through zero as a poor second */ +- soft_restart(0); ++ return 0; + } + + /* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */ +@@ -113,36 +122,105 @@ + return 0; + } + +-static void __init imx6q_sabrelite_cko1_setup(void) ++static void mmd_write_reg(struct phy_device *dev, int device, int reg, int val) + { +- struct clk *cko1_sel, *ahb, *cko1; +- unsigned long rate; ++ phy_write(dev, 0x0d, device); ++ phy_write(dev, 0x0e, reg); ++ phy_write(dev, 0x0d, (1 << 14) | device); ++ phy_write(dev, 0x0e, val); ++} + +- cko1_sel = clk_get_sys(NULL, "cko1_sel"); +- ahb = clk_get_sys(NULL, "ahb"); +- cko1 = clk_get_sys(NULL, "cko1"); +- if (IS_ERR(cko1_sel) || IS_ERR(ahb) || IS_ERR(cko1)) { +- pr_err("cko1 setup failed!\n"); +- goto put_clk; +- } +- clk_set_parent(cko1_sel, ahb); +- rate = clk_round_rate(cko1, 16000000); +- clk_set_rate(cko1, rate); +-put_clk: +- if (!IS_ERR(cko1_sel)) +- clk_put(cko1_sel); +- if (!IS_ERR(ahb)) +- clk_put(ahb); +- if (!IS_ERR(cko1)) +- clk_put(cko1); ++static int ksz9031rn_phy_fixup(struct phy_device *dev) ++{ ++ /* ++ * min rx data delay, max rx/tx clock delay, ++ * min rx/tx control delay ++ */ ++ mmd_write_reg(dev, 2, 4, 0); ++ mmd_write_reg(dev, 2, 5, 0); ++ mmd_write_reg(dev, 2, 8, 0x003ff); ++ ++ return 0; ++} ++ ++static int ar8031_phy_fixup(struct phy_device *dev) ++{ ++ u16 val; ++ ++ /* disable phy AR8031 SmartEEE function. */ ++ phy_write(dev, 0xd, 0x3); ++ phy_write(dev, 0xe, 0x805d); ++ phy_write(dev, 0xd, 0x4003); ++ val = phy_read(dev, 0xe); ++ val &= ~(0x1 << 8); ++ phy_write(dev, 0xe, val); ++ ++ /* To enable AR8031 output a 125MHz clk from CLK_25M */ ++ phy_write(dev, 0xd, 0x7); ++ phy_write(dev, 0xe, 0x8016); ++ phy_write(dev, 0xd, 0x4007); ++ ++ val = phy_read(dev, 0xe); ++ val &= 0xffe3; ++ val |= 0x18; ++ phy_write(dev, 0xe, val); ++ ++ /* introduce tx clock delay */ ++ phy_write(dev, 0x1d, 0x5); ++ val = phy_read(dev, 0x1e); ++ val |= 0x0100; ++ phy_write(dev, 0x1e, val); ++ ++ return 0; + } + +-static void __init imx6q_sabrelite_init(void) ++#define PHY_ID_AR8031 0x004dd074 ++ ++static int ar8035_phy_fixup(struct phy_device *dev) + { +- if (IS_BUILTIN(CONFIG_PHYLIB)) ++ u16 val; ++ ++ /* Ar803x phy SmartEEE feature cause link status generates glitch, ++ * which cause ethernet link down/up issue, so disable SmartEEE ++ */ ++ phy_write(dev, 0xd, 0x3); ++ phy_write(dev, 0xe, 0x805d); ++ phy_write(dev, 0xd, 0x4003); ++ ++ val = phy_read(dev, 0xe); ++ phy_write(dev, 0xe, val & ~(1 << 8)); ++ ++ /* ++ * Enable 125MHz clock from CLK_25M on the AR8031. This ++ * is fed in to the IMX6 on the ENET_REF_CLK (V22) pad. ++ * Also, introduce a tx clock delay. ++ * ++ * This is the same as is the AR8031 fixup. ++ */ ++ ar8031_phy_fixup(dev); ++ ++ /*check phy power*/ ++ val = phy_read(dev, 0x0); ++ if (val & BMCR_PDOWN) ++ phy_write(dev, 0x0, val & ~BMCR_PDOWN); ++ ++ return 0; ++} ++ ++#define PHY_ID_AR8035 0x004dd072 ++ ++static void __init imx6q_enet_phy_init(void) ++{ ++ if (IS_BUILTIN(CONFIG_PHYLIB)) { + phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK, + ksz9021rn_phy_fixup); +- imx6q_sabrelite_cko1_setup(); ++ phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK, ++ ksz9031rn_phy_fixup); ++ phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff, ++ ar8031_phy_fixup); ++ phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef, ++ ar8035_phy_fixup); ++ } + } + + static void __init imx6q_1588_init(void) +@@ -151,34 +229,175 @@ + + gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); + if (!IS_ERR(gpr)) +- regmap_update_bits(gpr, 0x4, 1 << 21, 1 << 21); ++ regmap_update_bits(gpr, IOMUXC_GPR1, ++ IMX6Q_GPR1_ENET_CLK_SEL_MASK, ++ IMX6Q_GPR1_ENET_CLK_SEL_ANATOP); + else + pr_err("failed to find fsl,imx6q-iomux-gpr regmap\n"); + + } +-static void __init imx6q_usb_init(void) ++ ++static void __init imx6q_csi_mux_init(void) + { +- imx_anatop_usb_chrg_detect_disable(); ++ /* ++ * MX6Q SabreSD board: ++ * IPU1 CSI0 connects to parallel interface. ++ * Set GPR1 bit 19 to 0x1. ++ * ++ * MX6DL SabreSD board: ++ * IPU1 CSI0 connects to parallel interface. ++ * Set GPR13 bit 0-2 to 0x4. ++ * IPU1 CSI1 connects to MIPI CSI2 virtual channel 1. ++ * Set GPR13 bit 3-5 to 0x1. ++ */ ++ struct regmap *gpr; ++ ++ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); ++ if (!IS_ERR(gpr)) { ++ if (of_machine_is_compatible("fsl,imx6q-sabresd") || ++ of_machine_is_compatible("fsl,imx6q-sabreauto")) ++ regmap_update_bits(gpr, IOMUXC_GPR1, 1 << 19, 1 << 19); ++ else if (of_machine_is_compatible("fsl,imx6dl-sabresd") || ++ of_machine_is_compatible("fsl,imx6dl-sabreauto")) ++ regmap_update_bits(gpr, IOMUXC_GPR13, 0x3F, 0x0C); ++ } else { ++ pr_err("%s(): failed to find fsl,imx6q-iomux-gpr regmap\n", ++ __func__); ++ } + } + ++/* ++ * Disable Hannstar LVDS panel CABC function. ++ * This function turns the panel's backlight density automatically ++ * according to the content shown on the panel which may cause ++ * annoying unstable backlight issue. ++ */ ++static void __init imx6q_lvds_cabc_init(void) ++{ ++ struct device_node *np = NULL; ++ int ret, lvds0_gpio, lvds1_gpio; ++ ++ np = of_find_node_by_name(NULL, "lvds_cabc_ctrl"); ++ if (!np) ++ return; ++ ++ lvds0_gpio = of_get_named_gpio(np, "lvds0-gpios", 0); ++ if (gpio_is_valid(lvds0_gpio)) { ++ ret = gpio_request_one(lvds0_gpio, GPIOF_OUT_INIT_LOW, ++ "LVDS0 CABC enable"); ++ if (ret) ++ pr_warn("failed to request LVDS0 CABC gpio\n"); ++ } ++ ++ lvds1_gpio = of_get_named_gpio(np, "lvds1-gpios", 0); ++ if (gpio_is_valid(lvds1_gpio)) { ++ ret = gpio_request_one(lvds1_gpio, GPIOF_OUT_INIT_LOW, ++ "LVDS1 CABC enable"); ++ if (ret) ++ pr_warn("failed to request LVDS1 CABC gpio\n"); ++ } ++} ++ ++#define OCOTP_MACn(n) (0x00000620 + (n) * 0x10) ++void __init imx6_enet_mac_init(const char *compatible) ++{ ++ struct device_node *ocotp_np, *enet_np; ++ void __iomem *base; ++ struct property *newmac; ++ u32 macaddr_low, macaddr_high; ++ u8 *macaddr; ++ ++ enet_np = of_find_compatible_node(NULL, NULL, compatible); ++ if (!enet_np) ++ return; ++ ++ if (of_get_mac_address(enet_np)) ++ goto put_enet_node; ++ ++ ocotp_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp"); ++ if (!ocotp_np) { ++ pr_warn("failed to find ocotp node\n"); ++ goto put_enet_node; ++ } ++ ++ base = of_iomap(ocotp_np, 0); ++ if (!base) { ++ pr_warn("failed to map ocotp\n"); ++ goto put_ocotp_node; ++ } ++ ++ macaddr_high = readl_relaxed(base + OCOTP_MACn(0)); ++ macaddr_low = readl_relaxed(base + OCOTP_MACn(1)); ++ ++ newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL); ++ if (!newmac) ++ goto put_ocotp_node; ++ ++ newmac->value = newmac + 1; ++ newmac->length = 6; ++ newmac->name = kstrdup("local-mac-address", GFP_KERNEL); ++ if (!newmac->name) { ++ kfree(newmac); ++ goto put_ocotp_node; ++ } ++ ++ macaddr = newmac->value; ++ macaddr[5] = macaddr_high & 0xff; ++ macaddr[4] = (macaddr_high >> 8) & 0xff; ++ macaddr[3] = (macaddr_high >> 16) & 0xff; ++ macaddr[2] = (macaddr_high >> 24) & 0xff; ++ macaddr[1] = macaddr_low & 0xff; ++ macaddr[0] = (macaddr_low >> 8) & 0xff; ++ ++ of_update_property(enet_np, newmac); ++ ++put_ocotp_node: ++ of_node_put(ocotp_np); ++put_enet_node: ++ of_node_put(enet_np); ++} ++ ++static inline void imx6q_enet_init(void) ++{ ++ imx6_enet_mac_init("fsl,imx6q-fec"); ++ imx6q_enet_phy_init(); ++ imx6q_1588_init(); ++} ++ ++/* Add auxdata to pass platform data */ ++static const struct of_dev_auxdata imx6q_auxdata_lookup[] __initconst = { ++ OF_DEV_AUXDATA("fsl,imx6q-flexcan", 0x02090000, NULL, &flexcan_pdata[0]), ++ OF_DEV_AUXDATA("fsl,imx6q-flexcan", 0x02094000, NULL, &flexcan_pdata[1]), ++ { /* sentinel */ } ++}; ++ + static void __init imx6q_init_machine(void) + { +- if (of_machine_is_compatible("fsl,imx6q-sabrelite")) +- imx6q_sabrelite_init(); ++ struct device *parent; ++ ++ mxc_arch_reset_init_dt(); ++ parent = imx_soc_device_init(); ++ if (parent == NULL) ++ pr_warn("failed to initialize soc device\n"); + +- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); ++ of_platform_populate(NULL, of_default_bus_match_table, ++ imx6q_auxdata_lookup, parent); + ++ imx6q_enet_init(); + imx_anatop_init(); +- imx6q_pm_init(); +- imx6q_usb_init(); +- imx6q_1588_init(); ++ imx6_pm_init(); ++ imx6q_csi_mux_init(); ++ imx6q_lvds_cabc_init(); + } + + #define OCOTP_CFG3 0x440 + #define OCOTP_CFG3_SPEED_SHIFT 16 + #define OCOTP_CFG3_SPEED_1P2GHZ 0x3 ++#define OCOTP_CFG3_SPEED_1GHZ 0x2 ++#define OCOTP_CFG3_SPEED_850MHZ 0x1 ++#define OCOTP_CFG3_SPEED_800MHZ 0x0 + +-static void __init imx6q_opp_check_1p2ghz(struct device *cpu_dev) ++static void __init imx6q_opp_check_speed_grading(struct device *cpu_dev) + { + struct device_node *np; + void __iomem *base; +@@ -196,11 +415,36 @@ + goto put_node; + } + ++ /* ++ * SPEED_GRADING[1:0] defines the max speed of ARM: ++ * 2b'11: 1200000000Hz; -- i.MX6Q only. ++ * 2b'10: 1000000000Hz; ++ * 2b'01: 850000000Hz; -- i.MX6Q Only, exclusive with 1GHz. ++ * 2b'00: 800000000Hz; ++ * We need to set the max speed of ARM according to fuse map. ++ */ + val = readl_relaxed(base + OCOTP_CFG3); + val >>= OCOTP_CFG3_SPEED_SHIFT; +- if ((val & 0x3) != OCOTP_CFG3_SPEED_1P2GHZ) +- if (opp_disable(cpu_dev, 1200000000)) +- pr_warn("failed to disable 1.2 GHz OPP\n"); ++ val &= 3; ++ if (cpu_is_imx6q()) { ++ if (!val) { ++ /* fuses not set for IMX_CHIP_REVISION_1_0 */ ++ if (imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) ++ val = OCOTP_CFG3_SPEED_1GHZ; ++ } ++ if (val < OCOTP_CFG3_SPEED_1P2GHZ) ++ if (opp_disable(cpu_dev, 1200000000)) ++ pr_warn("failed to disable 1.2 GHz OPP\n"); ++ } ++ if (val < OCOTP_CFG3_SPEED_1GHZ) ++ if (opp_disable(cpu_dev, 996000000)) ++ pr_warn("failed to disable 1 GHz OPP\n"); ++ if (cpu_is_imx6q()) { ++ if (val < OCOTP_CFG3_SPEED_850MHZ || ++ val == OCOTP_CFG3_SPEED_1GHZ) ++ if (opp_disable(cpu_dev, 852000000)) ++ pr_warn("failed to disable 850 MHz OPP\n"); ++ } + + put_node: + of_node_put(np); +@@ -222,41 +466,60 @@ + goto put_node; + } + +- imx6q_opp_check_1p2ghz(cpu_dev); ++ imx6q_opp_check_speed_grading(cpu_dev); + + put_node: + of_node_put(np); + } + + static struct platform_device imx6q_cpufreq_pdev = { +- .name = "imx6q-cpufreq", ++ .name = "imx6-cpufreq", + }; + + static void __init imx6q_init_late(void) + { ++ struct regmap *gpr; ++ ++ /* ++ * Need to force IOMUXC irq pending to meet CCM low power mode ++ * restriction, this is recommended by hardware team. ++ */ ++ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); ++ if (!IS_ERR(gpr)) ++ regmap_update_bits(gpr, IOMUXC_GPR1, ++ IMX6Q_GPR1_GINT_MASK, ++ IMX6Q_GPR1_GINT_ASSERT); ++ + /* + * WAIT mode is broken on TO 1.0 and 1.1, so there is no point + * to run cpuidle on them. + */ +- if (imx6q_revision() > IMX_CHIP_REVISION_1_1) ++ if ((cpu_is_imx6q() && imx_get_soc_revision() > IMX_CHIP_REVISION_1_1) ++ || (cpu_is_imx6dl() && imx_get_soc_revision() > ++ IMX_CHIP_REVISION_1_0)) + imx6q_cpuidle_init(); + +- if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) { ++ if (IS_ENABLED(CONFIG_ARM_IMX6_CPUFREQ)) { + imx6q_opp_init(&imx6q_cpufreq_pdev.dev); + platform_device_register(&imx6q_cpufreq_pdev); + } ++ ++ if (of_machine_is_compatible("fsl,imx6q-sabreauto") ++ || of_machine_is_compatible("fsl,imx6dl-sabreauto")) ++ imx6q_flexcan_fixup_auto(); + } + + static void __init imx6q_map_io(void) + { + debug_ll_io_init(); + imx_scu_map_io(); ++ imx6_pm_map_io(); + } + + static void __init imx6q_init_irq(void) + { +- imx6q_init_revision(); +- l2x0_of_init(0, ~0UL); ++ imx_init_revision_from_anatop(); ++ imx_init_l2cache(); + imx_src_init(); + imx_gpc_init(); + irqchip_init(); +@@ -264,10 +527,10 @@ + + static void __init imx6q_timer_init(void) + { +- mx6q_clocks_init(); ++ of_clk_init(NULL); + clocksource_of_init(); + imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q", +- imx6q_revision()); ++ imx_get_soc_revision()); + } + + static const char *imx6q_dt_compat[] __initdata = { +@@ -277,6 +540,12 @@ + }; + + DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)") ++ /* ++ * i.MX6Q/DL maps system memory at 0x10000000 (offset 256MiB), and ++ * GPU has a limit on physical address that it accesses, which must ++ * be below 2GiB. ++ */ ++ .dma_zone_size = (SZ_2G - SZ_256M), + .smp = smp_ops(imx_smp_ops), + .map_io = imx6q_map_io, + .init_irq = imx6q_init_irq, +@@ -284,5 +553,5 @@ + .init_machine = imx6q_init_machine, + .init_late = imx6q_init_late, + .dt_compat = imx6q_dt_compat, +- .restart = imx6q_restart, ++ .restart = mxc_restart, + MACHINE_END +diff -Nur linux-3.10.30/arch/arm/mach-imx/mach-imx6sl.c linux-3.10.30-cubox-i/arch/arm/mach-imx/mach-imx6sl.c +--- linux-3.10.30/arch/arm/mach-imx/mach-imx6sl.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mach-imx6sl.c 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,149 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 "common.h" ++#include "cpuidle.h" ++#include "hardware.h" ++ ++static struct platform_device imx6sl_cpufreq_pdev = { ++ .name = "imx6-cpufreq", ++}; ++ ++static void __init imx6sl_fec_clk_init(void) ++{ ++ struct regmap *gpr; ++ ++ /* set FEC clock from internal PLL clock source */ ++ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sl-iomuxc-gpr"); ++ if (!IS_ERR(gpr)) { ++ regmap_update_bits(gpr, IOMUXC_GPR1, ++ IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK, 0); ++ regmap_update_bits(gpr, IOMUXC_GPR1, ++ IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK, 0); ++ } else ++ pr_err("failed to find fsl,imx6sl-iomux-gpr regmap\n"); ++} ++ ++static inline void imx6sl_fec_init(void) ++{ ++ imx6sl_fec_clk_init(); ++ imx6_enet_mac_init("fsl,imx6sl-fec"); ++} ++ ++static void __init imx6sl_init_machine(void) ++{ ++ struct device *parent; ++ ++ mxc_arch_reset_init_dt(); ++ ++ parent = imx_soc_device_init(); ++ if (parent == NULL) ++ pr_warn("failed to initialize soc device\n"); ++ ++ of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); ++ ++ imx6sl_fec_init(); ++ imx_anatop_init(); ++ imx6_pm_init(); ++} ++ ++static void __init imx6sl_opp_init(struct device *cpu_dev) ++{ ++ struct device_node *np; ++ ++ np = of_find_node_by_path("/cpus/cpu@0"); ++ if (!np) { ++ pr_warn("failed to find cpu0 node\n"); ++ return; ++ } ++ ++ cpu_dev->of_node = np; ++ if (of_init_opp_table(cpu_dev)) { ++ pr_warn("failed to init OPP table\n"); ++ goto put_node; ++ } ++ ++put_node: ++ of_node_put(np); ++} ++ ++static void __init imx6sl_init_late(void) ++{ ++ struct regmap *gpr; ++ ++ /* ++ * Need to force IOMUXC irq pending to meet CCM low power mode ++ * restriction, this is recommended by hardware team. ++ */ ++ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sl-iomuxc-gpr"); ++ if (!IS_ERR(gpr)) ++ regmap_update_bits(gpr, IOMUXC_GPR1, ++ IMX6Q_GPR1_GINT_MASK, ++ IMX6Q_GPR1_GINT_ASSERT); ++ else ++ pr_err("failed to find fsl,imx6sl-iomux-gpr regmap\n"); ++ ++ /* Init CPUIDLE */ ++ imx6sl_cpuidle_init(); ++ ++ if (IS_ENABLED(CONFIG_ARM_IMX6_CPUFREQ)) { ++ imx6sl_opp_init(&imx6sl_cpufreq_pdev.dev); ++ platform_device_register(&imx6sl_cpufreq_pdev); ++ } ++ ++} ++ ++static void __init imx6sl_map_io(void) ++{ ++ debug_ll_io_init(); ++ imx6_pm_map_io(); ++} ++ ++static void __init imx6sl_init_irq(void) ++{ ++ imx_init_revision_from_anatop(); ++ imx_init_l2cache(); ++ imx_src_init(); ++ imx_gpc_init(); ++ irqchip_init(); ++} ++ ++static void __init imx6sl_timer_init(void) ++{ ++ of_clk_init(NULL); ++} ++ ++static const char *imx6sl_dt_compat[] __initdata = { ++ "fsl,imx6sl", ++ NULL, ++}; ++ ++DT_MACHINE_START(IMX6SL, "Freescale i.MX6 SoloLite (Device Tree)") ++ .map_io = imx6sl_map_io, ++ .init_irq = imx6sl_init_irq, ++ .init_time = imx6sl_timer_init, ++ .init_machine = imx6sl_init_machine, ++ .init_late = imx6sl_init_late, ++ .dt_compat = imx6sl_dt_compat, ++ .restart = mxc_restart, ++MACHINE_END +diff -Nur linux-3.10.30/arch/arm/mach-imx/mach-vf610.c linux-3.10.30-cubox-i/arch/arm/mach-imx/mach-vf610.c +--- linux-3.10.30/arch/arm/mach-imx/mach-vf610.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mach-vf610.c 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,50 @@ ++/* ++ * Copyright 2012-2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++ ++static void __init vf610_init_machine(void) ++{ ++ mxc_arch_reset_init_dt(); ++ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); ++} ++ ++static void __init vf610_init_irq(void) ++{ ++ l2x0_of_init(0, ~0UL); ++ irqchip_init(); ++} ++ ++static void __init vf610_init_time(void) ++{ ++ of_clk_init(NULL); ++ clocksource_of_init(); ++} ++ ++static const char *vf610_dt_compat[] __initdata = { ++ "fsl,vf610", ++ NULL, ++}; ++ ++DT_MACHINE_START(VYBRID_VF610, "Freescale Vybrid VF610 (Device Tree)") ++ .map_io = debug_ll_io_init, ++ .init_irq = vf610_init_irq, ++ .init_time = vf610_init_time, ++ .init_machine = vf610_init_machine, ++ .dt_compat = vf610_dt_compat, ++ .restart = mxc_restart, ++MACHINE_END +diff -Nur linux-3.10.30/arch/arm/mach-imx/mm-imx1.c linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx1.c +--- linux-3.10.30/arch/arm/mach-imx/mm-imx1.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx1.c 2014-03-08 20:32:54.000000000 +0100 +@@ -39,7 +39,6 @@ + void __init imx1_init_early(void) + { + mxc_set_cpu_type(MXC_CPU_MX1); +- mxc_arch_reset_init(MX1_IO_ADDRESS(MX1_WDT_BASE_ADDR)); + imx_iomuxv1_init(MX1_IO_ADDRESS(MX1_GPIO_BASE_ADDR), + MX1_NUM_GPIO_PORT); + } +@@ -51,6 +50,7 @@ + + void __init imx1_soc_init(void) + { ++ mxc_arch_reset_init(MX1_IO_ADDRESS(MX1_WDT_BASE_ADDR)); + mxc_device_init(); + + mxc_register_gpio("imx1-gpio", 0, MX1_GPIO1_BASE_ADDR, SZ_256, +diff -Nur linux-3.10.30/arch/arm/mach-imx/mm-imx21.c linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx21.c +--- linux-3.10.30/arch/arm/mach-imx/mm-imx21.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx21.c 2014-03-08 20:32:54.000000000 +0100 +@@ -66,7 +66,6 @@ + void __init imx21_init_early(void) + { + mxc_set_cpu_type(MXC_CPU_MX21); +- mxc_arch_reset_init(MX21_IO_ADDRESS(MX21_WDOG_BASE_ADDR)); + imx_iomuxv1_init(MX21_IO_ADDRESS(MX21_GPIO_BASE_ADDR), + MX21_NUM_GPIO_PORT); + } +@@ -82,6 +81,7 @@ + + void __init imx21_soc_init(void) + { ++ mxc_arch_reset_init(MX21_IO_ADDRESS(MX21_WDOG_BASE_ADDR)); + mxc_device_init(); + + mxc_register_gpio("imx21-gpio", 0, MX21_GPIO1_BASE_ADDR, SZ_256, MX21_INT_GPIO, 0); +diff -Nur linux-3.10.30/arch/arm/mach-imx/mm-imx25.c linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx25.c +--- linux-3.10.30/arch/arm/mach-imx/mm-imx25.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx25.c 2014-03-08 20:32:54.000000000 +0100 +@@ -54,7 +54,6 @@ + { + mxc_set_cpu_type(MXC_CPU_MX25); + mxc_iomux_v3_init(MX25_IO_ADDRESS(MX25_IOMUXC_BASE_ADDR)); +- mxc_arch_reset_init(MX25_IO_ADDRESS(MX25_WDOG_BASE_ADDR)); + } + + void __init mx25_init_irq(void) +@@ -89,6 +88,7 @@ + + void __init imx25_soc_init(void) + { ++ mxc_arch_reset_init(MX25_IO_ADDRESS(MX25_WDOG_BASE_ADDR)); + mxc_device_init(); + + /* i.mx25 has the i.mx35 type gpio */ +diff -Nur linux-3.10.30/arch/arm/mach-imx/mm-imx27.c linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx27.c +--- linux-3.10.30/arch/arm/mach-imx/mm-imx27.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx27.c 2014-03-08 20:32:54.000000000 +0100 +@@ -66,7 +66,6 @@ + void __init imx27_init_early(void) + { + mxc_set_cpu_type(MXC_CPU_MX27); +- mxc_arch_reset_init(MX27_IO_ADDRESS(MX27_WDOG_BASE_ADDR)); + imx_iomuxv1_init(MX27_IO_ADDRESS(MX27_GPIO_BASE_ADDR), + MX27_NUM_GPIO_PORT); + } +@@ -82,6 +81,7 @@ + + void __init imx27_soc_init(void) + { ++ mxc_arch_reset_init(MX27_IO_ADDRESS(MX27_WDOG_BASE_ADDR)); + mxc_device_init(); + + /* i.mx27 has the i.mx21 type gpio */ +diff -Nur linux-3.10.30/arch/arm/mach-imx/mm-imx3.c linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx3.c +--- linux-3.10.30/arch/arm/mach-imx/mm-imx3.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx3.c 2014-03-08 20:32:54.000000000 +0100 +@@ -138,7 +138,6 @@ + void __init imx31_init_early(void) + { + mxc_set_cpu_type(MXC_CPU_MX31); +- mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR)); + arch_ioremap_caller = imx3_ioremap_caller; + arm_pm_idle = imx3_idle; + mx3_ccm_base = MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR); +@@ -174,6 +173,7 @@ + + imx3_init_l2x0(); + ++ mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR)); + mxc_device_init(); + + mxc_register_gpio("imx31-gpio", 0, MX31_GPIO1_BASE_ADDR, SZ_16K, MX31_INT_GPIO1, 0); +@@ -216,7 +216,6 @@ + { + mxc_set_cpu_type(MXC_CPU_MX35); + mxc_iomux_v3_init(MX35_IO_ADDRESS(MX35_IOMUXC_BASE_ADDR)); +- mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR)); + arm_pm_idle = imx3_idle; + arch_ioremap_caller = imx3_ioremap_caller; + mx3_ccm_base = MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR); +@@ -272,6 +271,7 @@ + + imx3_init_l2x0(); + ++ mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR)); + mxc_device_init(); + + mxc_register_gpio("imx35-gpio", 0, MX35_GPIO1_BASE_ADDR, SZ_16K, MX35_INT_GPIO1, 0); +diff -Nur linux-3.10.30/arch/arm/mach-imx/mm-imx5.c linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx5.c +--- linux-3.10.30/arch/arm/mach-imx/mm-imx5.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mm-imx5.c 2014-03-08 20:32:54.000000000 +0100 +@@ -83,7 +83,6 @@ + imx51_ipu_mipi_setup(); + mxc_set_cpu_type(MXC_CPU_MX51); + mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR)); +- mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG1_BASE_ADDR)); + imx_src_init(); + } + +@@ -91,7 +90,6 @@ + { + mxc_set_cpu_type(MXC_CPU_MX53); + mxc_iomux_v3_init(MX53_IO_ADDRESS(MX53_IOMUXC_BASE_ADDR)); +- mxc_arch_reset_init(MX53_IO_ADDRESS(MX53_WDOG1_BASE_ADDR)); + imx_src_init(); + } + +@@ -129,6 +127,7 @@ + + void __init imx51_soc_init(void) + { ++ mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG1_BASE_ADDR)); + mxc_device_init(); + + /* i.mx51 has the i.mx35 type gpio */ +diff -Nur linux-3.10.30/arch/arm/mach-imx/mx6.h linux-3.10.30-cubox-i/arch/arm/mach-imx/mx6.h +--- linux-3.10.30/arch/arm/mach-imx/mx6.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mx6.h 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,35 @@ ++/* ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * This program 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_ARCH_MXC_IOMAP_H__ ++#define __ASM_ARCH_MXC_IOMAP_H__ ++ ++#define MX6Q_IO_P2V(x) IMX_IO_P2V(x) ++#define MX6Q_IO_ADDRESS(x) IOMEM(MX6Q_IO_P2V(x)) ++ ++#define MX6Q_L2_BASE_ADDR 0x00a02000 ++#define MX6Q_L2_SIZE 0x1000 ++#define MX6Q_IOMUXC_BASE_ADDR 0x020e0000 ++#define MX6Q_IOMUXC_SIZE 0x4000 ++#define MX6Q_SRC_BASE_ADDR 0x020d8000 ++#define MX6Q_SRC_SIZE 0x4000 ++#define MX6Q_CCM_BASE_ADDR 0x020c4000 ++#define MX6Q_CCM_SIZE 0x4000 ++#define MX6Q_ANATOP_BASE_ADDR 0x020c8000 ++#define MX6Q_ANATOP_SIZE 0x1000 ++#define MX6Q_GPC_BASE_ADDR 0x020dc000 ++#define MX6Q_GPC_SIZE 0x4000 ++#define MX6Q_MMDC_P0_BASE_ADDR 0x021b0000 ++#define MX6Q_MMDC_P0_SIZE 0x4000 ++#define MX6Q_MMDC_P1_BASE_ADDR 0x021b4000 ++#define MX6Q_MMDC_P1_SIZE 0x4000 ++ ++#define MX6_SUSPEND_IRAM_SIZE 0x1000 ++#endif +diff -Nur linux-3.10.30/arch/arm/mach-imx/mxc.h linux-3.10.30-cubox-i/arch/arm/mach-imx/mxc.h +--- linux-3.10.30/arch/arm/mach-imx/mxc.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/mxc.h 2014-03-08 20:32:54.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2004-2007, 2010 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright 2004-2007, 2010, 2013 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * + * This program is free software; you can redistribute it and/or +@@ -34,6 +34,7 @@ + #define MXC_CPU_MX35 35 + #define MXC_CPU_MX51 51 + #define MXC_CPU_MX53 53 ++#define MXC_CPU_IMX6SL 0x60 + #define MXC_CPU_IMX6DL 0x61 + #define MXC_CPU_IMX6Q 0x63 + +@@ -41,6 +42,8 @@ + #define IMX_CHIP_REVISION_1_1 0x11 + #define IMX_CHIP_REVISION_1_2 0x12 + #define IMX_CHIP_REVISION_1_3 0x13 ++#define IMX_CHIP_REVISION_1_4 0x14 ++#define IMX_CHIP_REVISION_1_5 0x15 + #define IMX_CHIP_REVISION_2_0 0x20 + #define IMX_CHIP_REVISION_2_1 0x21 + #define IMX_CHIP_REVISION_2_2 0x22 +@@ -152,6 +155,11 @@ + #endif + + #ifndef __ASSEMBLY__ ++static inline bool cpu_is_imx6sl(void) ++{ ++ return __mxc_cpu_type == MXC_CPU_IMX6SL; ++} ++ + static inline bool cpu_is_imx6dl(void) + { + return __mxc_cpu_type == MXC_CPU_IMX6DL; +@@ -171,6 +179,7 @@ + extern struct cpu_op *(*get_cpu_op)(int *op); + #endif + ++#define cpu_is_imx6() (cpu_is_imx6q() || cpu_is_imx6dl() || cpu_is_imx6sl()) + #define cpu_is_mx3() (cpu_is_mx31() || cpu_is_mx35()) + #define cpu_is_mx2() (cpu_is_mx21() || cpu_is_mx27()) + +diff -Nur linux-3.10.30/arch/arm/mach-imx/pm-imx6.c linux-3.10.30-cubox-i/arch/arm/mach-imx/pm-imx6.c +--- linux-3.10.30/arch/arm/mach-imx/pm-imx6.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/pm-imx6.c 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,379 @@ ++/* ++ * Copyright 2011-2013 Freescale Semiconductor, Inc. ++ * Copyright 2011 Linaro Ltd. ++ * ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++#include "hardware.h" ++ ++#define CCR 0x0 ++#define BM_CCR_WB_COUNT (0x7 << 16) ++#define BM_CCR_RBC_BYPASS_COUNT (0x3f << 21) ++#define BM_CCR_RBC_EN (0x1 << 27) ++ ++#define CLPCR 0x54 ++#define BP_CLPCR_LPM 0 ++#define BM_CLPCR_LPM (0x3 << 0) ++#define BM_CLPCR_BYPASS_PMIC_READY (0x1 << 2) ++#define BM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) ++#define BM_CLPCR_SBYOS (0x1 << 6) ++#define BM_CLPCR_DIS_REF_OSC (0x1 << 7) ++#define BM_CLPCR_VSTBY (0x1 << 8) ++#define BP_CLPCR_STBY_COUNT 9 ++#define BM_CLPCR_STBY_COUNT (0x3 << 9) ++#define BM_CLPCR_COSC_PWRDOWN (0x1 << 11) ++#define BM_CLPCR_WB_PER_AT_LPM (0x1 << 16) ++#define BM_CLPCR_WB_CORE_AT_LPM (0x1 << 17) ++#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS (0x1 << 19) ++#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS (0x1 << 21) ++#define BM_CLPCR_MASK_CORE0_WFI (0x1 << 22) ++#define BM_CLPCR_MASK_CORE1_WFI (0x1 << 23) ++#define BM_CLPCR_MASK_CORE2_WFI (0x1 << 24) ++#define BM_CLPCR_MASK_CORE3_WFI (0x1 << 25) ++#define BM_CLPCR_MASK_SCU_IDLE (0x1 << 26) ++#define BM_CLPCR_MASK_L2CC_IDLE (0x1 << 27) ++ ++#define CGPR 0x64 ++#define BM_CGPR_INT_MEM_CLK_LPM (0x1 << 17) ++ ++#define MX6_INT_IOMUXC 32 ++ ++static struct gen_pool *iram_pool; ++static void *suspend_iram_base; ++static unsigned long iram_size, iram_paddr; ++static int (*suspend_in_iram_fn)(void *iram_vbase, ++ unsigned long iram_pbase, unsigned int cpu_type); ++static unsigned int cpu_type; ++static void __iomem *ccm_base; ++ ++void imx6_set_cache_lpm_in_wait(bool enable) ++{ ++ if ((cpu_is_imx6q() && imx_get_soc_revision() > ++ IMX_CHIP_REVISION_1_1) || ++ (cpu_is_imx6dl() && imx_get_soc_revision() > ++ IMX_CHIP_REVISION_1_0)) { ++ u32 val; ++ ++ val = readl_relaxed(ccm_base + CGPR); ++ if (enable) ++ val |= BM_CGPR_INT_MEM_CLK_LPM; ++ else ++ val &= ~BM_CGPR_INT_MEM_CLK_LPM; ++ writel_relaxed(val, ccm_base + CGPR); ++ } ++} ++ ++static void imx6_enable_rbc(bool enable) ++{ ++ u32 val; ++ ++ /* ++ * need to mask all interrupts in GPC before ++ * operating RBC configurations ++ */ ++ imx_gpc_mask_all(); ++ ++ /* configure RBC enable bit */ ++ val = readl_relaxed(ccm_base + CCR); ++ val &= ~BM_CCR_RBC_EN; ++ val |= enable ? BM_CCR_RBC_EN : 0; ++ writel_relaxed(val, ccm_base + CCR); ++ ++ /* configure RBC count */ ++ val = readl_relaxed(ccm_base + CCR); ++ val &= ~BM_CCR_RBC_BYPASS_COUNT; ++ val |= enable ? BM_CCR_RBC_BYPASS_COUNT : 0; ++ writel(val, ccm_base + CCR); ++ ++ /* ++ * need to delay at least 2 cycles of CKIL(32K) ++ * due to hardware design requirement, which is ++ * ~61us, here we use 65us for safe ++ */ ++ udelay(65); ++ ++ /* restore GPC interrupt mask settings */ ++ imx_gpc_restore_all(); ++} ++ ++static void imx6_enable_wb(bool enable) ++{ ++ u32 val; ++ ++ /* configure well bias enable bit */ ++ val = readl_relaxed(ccm_base + CLPCR); ++ val &= ~BM_CLPCR_WB_PER_AT_LPM; ++ val |= enable ? BM_CLPCR_WB_PER_AT_LPM : 0; ++ writel_relaxed(val, ccm_base + CLPCR); ++ ++ /* configure well bias count */ ++ val = readl_relaxed(ccm_base + CCR); ++ val &= ~BM_CCR_WB_COUNT; ++ val |= enable ? BM_CCR_WB_COUNT : 0; ++ writel_relaxed(val, ccm_base + CCR); ++} ++ ++int imx6_set_lpm(enum mxc_cpu_pwr_mode mode) ++{ ++ u32 val = readl_relaxed(ccm_base + CLPCR); ++ struct irq_desc *desc = irq_to_desc(MX6_INT_IOMUXC); ++ ++ /* ++ * CCM state machine has restriction, before enabling ++ * LPM mode, need to make sure last LPM mode is waked up ++ * by dsm_wakeup_signal, which means the wakeup source ++ * must be seen by GPC, then CCM will clean its state machine ++ * and re-sample necessary signal to decide whether it can ++ * enter LPM mode. We force irq #32 to be always pending, ++ * unmask it before we enable LPM mode and mask it after LPM ++ * is enabled, this flow will make sure CCM state machine in ++ * reliable status before entering LPM mode. Otherwise, CCM ++ * may enter LPM mode by mistake which will cause system bus ++ * locked by CPU access not finished, as when CCM enter ++ * LPM mode, CPU will stop running. ++ */ ++ imx_gpc_irq_unmask(&desc->irq_data); ++ ++ val &= ~BM_CLPCR_LPM; ++ switch (mode) { ++ case WAIT_CLOCKED: ++ break; ++ case WAIT_UNCLOCKED: ++ val |= 0x1 << BP_CLPCR_LPM; ++ val |= BM_CLPCR_ARM_CLK_DIS_ON_LPM; ++ val &= ~BM_CLPCR_VSTBY; ++ val &= ~BM_CLPCR_SBYOS; ++ if (cpu_is_imx6sl()) ++ val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS; ++ else ++ val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; ++ break; ++ case STOP_POWER_ON: ++ val |= 0x2 << BP_CLPCR_LPM; ++ val &= ~BM_CLPCR_VSTBY; ++ val &= ~BM_CLPCR_SBYOS; ++ if (cpu_is_imx6sl()) { ++ val |= BM_CLPCR_BYPASS_PMIC_READY; ++ val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS; ++ } else { ++ val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; ++ } ++ break; ++ case WAIT_UNCLOCKED_POWER_OFF: ++ val |= 0x1 << BP_CLPCR_LPM; ++ val &= ~BM_CLPCR_VSTBY; ++ val &= ~BM_CLPCR_SBYOS; ++ break; ++ case STOP_POWER_OFF: ++ val |= 0x2 << BP_CLPCR_LPM; ++ val |= 0x3 << BP_CLPCR_STBY_COUNT; ++ val |= BM_CLPCR_VSTBY; ++ val |= BM_CLPCR_SBYOS; ++ if (cpu_is_imx6sl()) { ++ val |= BM_CLPCR_BYPASS_PMIC_READY; ++ val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS; ++ } else { ++ val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS; ++ } ++ break; ++ default: ++ imx_gpc_irq_mask(&desc->irq_data); ++ return -EINVAL; ++ } ++ ++ writel_relaxed(val, ccm_base + CLPCR); ++ imx_gpc_irq_mask(&desc->irq_data); ++ ++ return 0; ++} ++ ++static int imx6_suspend_finish(unsigned long val) ++{ ++ /* ++ * call low level suspend function in iram, ++ * as we need to float DDR IO. ++ */ ++ local_flush_tlb_all(); ++ suspend_in_iram_fn(suspend_iram_base, iram_paddr, cpu_type); ++ return 0; ++} ++ ++static int imx6_pm_enter(suspend_state_t state) ++{ ++ struct regmap *g; ++ ++ /* ++ * L2 can exit by 'reset' or Inband beacon (from remote EP) ++ * toggling phy_powerdown has same effect as 'inband beacon' ++ * So, toggle bit18 of GPR1, used as a workaround of errata ++ * "PCIe PCIe does not support L2 Power Down" ++ */ ++ if (IS_ENABLED(CONFIG_PCI_IMX6)) { ++ g = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); ++ if (IS_ERR(g)) { ++ pr_err("failed to find fsl,imx6q-iomux-gpr regmap\n"); ++ return PTR_ERR(g); ++ } ++ regmap_update_bits(g, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD, ++ IMX6Q_GPR1_PCIE_TEST_PD); ++ } ++ ++ switch (state) { ++ case PM_SUSPEND_STANDBY: ++ imx6_set_lpm(STOP_POWER_ON); ++ imx6_set_cache_lpm_in_wait(true); ++ imx_gpc_pre_suspend(false); ++ if (cpu_is_imx6sl()) ++ imx6sl_set_wait_clk(true); ++ /* Zzz ... */ ++ cpu_do_idle(); ++ if (cpu_is_imx6sl()) ++ imx6sl_set_wait_clk(false); ++ imx_gpc_post_resume(); ++ imx6_set_lpm(WAIT_CLOCKED); ++ break; ++ case PM_SUSPEND_MEM: ++ imx6_enable_wb(true); ++ imx6_set_cache_lpm_in_wait(false); ++ imx6_set_lpm(STOP_POWER_OFF); ++ imx_gpc_pre_suspend(true); ++ imx_anatop_pre_suspend(); ++ imx_set_cpu_jump(0, v7_cpu_resume); ++ /* Zzz ... */ ++ cpu_suspend(0, imx6_suspend_finish); ++ if (!cpu_is_imx6sl()) ++ imx_smp_prepare(); ++ imx_anatop_post_resume(); ++ imx_gpc_post_resume(); ++ imx6_enable_rbc(false); ++ imx6_enable_wb(false); ++ imx6_set_cache_lpm_in_wait(true); ++ imx6_set_lpm(WAIT_CLOCKED); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* ++ * L2 can exit by 'reset' or Inband beacon (from remote EP) ++ * toggling phy_powerdown has same effect as 'inband beacon' ++ * So, toggle bit18 of GPR1, used as a workaround of errata ++ * "PCIe PCIe does not support L2 Power Down" ++ */ ++ if (IS_ENABLED(CONFIG_PCI_IMX6)) { ++ regmap_update_bits(g, IOMUXC_GPR1, IMX6Q_GPR1_PCIE_TEST_PD, ++ !IMX6Q_GPR1_PCIE_TEST_PD); ++ } ++ ++ return 0; ++} ++ ++static struct map_desc imx6_pm_io_desc[] __initdata = { ++ imx_map_entry(MX6Q, MMDC_P0, MT_DEVICE), ++ imx_map_entry(MX6Q, MMDC_P1, MT_DEVICE), ++ imx_map_entry(MX6Q, SRC, MT_DEVICE), ++ imx_map_entry(MX6Q, IOMUXC, MT_DEVICE), ++ imx_map_entry(MX6Q, CCM, MT_DEVICE), ++ imx_map_entry(MX6Q, ANATOP, MT_DEVICE), ++ imx_map_entry(MX6Q, GPC, MT_DEVICE), ++ imx_map_entry(MX6Q, L2, MT_DEVICE), ++}; ++ ++void __init imx6_pm_map_io(void) ++{ ++ iotable_init(imx6_pm_io_desc, ARRAY_SIZE(imx6_pm_io_desc)); ++} ++ ++static int imx6_pm_valid(suspend_state_t state) ++{ ++ return (state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM); ++} ++ ++static const struct platform_suspend_ops imx6_pm_ops = { ++ .enter = imx6_pm_enter, ++ .valid = imx6_pm_valid, ++}; ++ ++void imx6_pm_set_ccm_base(void __iomem *base) ++{ ++ if (!base) ++ pr_warn("ccm base is NULL!\n"); ++ ccm_base = base; ++} ++ ++void __init imx6_pm_init(void) ++{ ++ struct device_node *node; ++ unsigned long iram_base; ++ struct platform_device *pdev; ++ ++ node = of_find_compatible_node(NULL, NULL, "mmio-sram"); ++ if (!node) { ++ pr_err("failed to find ocram node!\n"); ++ return; ++ } ++ ++ pdev = of_find_device_by_node(node); ++ if (!pdev) { ++ pr_err("failed to find ocram device!\n"); ++ return; ++ } ++ ++ iram_pool = dev_get_gen_pool(&pdev->dev); ++ if (!iram_pool) { ++ pr_err("iram pool unavailable!\n"); ++ return; ++ } ++ ++ iram_size = MX6_SUSPEND_IRAM_SIZE; ++ ++ iram_base = gen_pool_alloc(iram_pool, iram_size); ++ if (!iram_base) { ++ pr_err("unable to alloc iram!\n"); ++ return; ++ } ++ ++ iram_paddr = gen_pool_virt_to_phys(iram_pool, iram_base); ++ ++ suspend_iram_base = __arm_ioremap(iram_paddr, iram_size, ++ MT_MEMORY_NONCACHED); ++ ++ suspend_in_iram_fn = (void *)fncpy(suspend_iram_base, ++ &imx6_suspend, iram_size); ++ ++ suspend_set_ops(&imx6_pm_ops); ++ ++ /* Set cpu_type for DSM */ ++ if (cpu_is_imx6q()) ++ cpu_type = MXC_CPU_IMX6Q; ++ else if (cpu_is_imx6dl()) ++ cpu_type = MXC_CPU_IMX6DL; ++ else ++ cpu_type = MXC_CPU_IMX6SL; ++} +diff -Nur linux-3.10.30/arch/arm/mach-imx/pm-imx6q.c linux-3.10.30-cubox-i/arch/arm/mach-imx/pm-imx6q.c +--- linux-3.10.30/arch/arm/mach-imx/pm-imx6q.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/pm-imx6q.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,61 +0,0 @@ +-/* +- * Copyright 2011-2013 Freescale Semiconductor, Inc. +- * Copyright 2011 Linaro Ltd. +- * +- * The code contained herein is licensed under the GNU General Public +- * License. You may obtain a copy of the GNU General Public License +- * Version 2 or later at the following locations: +- * +- * http://www.opensource.org/licenses/gpl-license.html +- * http://www.gnu.org/copyleft/gpl.html +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "common.h" +-#include "hardware.h" +- +-static int imx6q_suspend_finish(unsigned long val) +-{ +- cpu_do_idle(); +- return 0; +-} +- +-static int imx6q_pm_enter(suspend_state_t state) +-{ +- switch (state) { +- case PM_SUSPEND_MEM: +- imx6q_set_lpm(STOP_POWER_OFF); +- imx_gpc_pre_suspend(); +- imx_anatop_pre_suspend(); +- imx_set_cpu_jump(0, v7_cpu_resume); +- /* Zzz ... */ +- cpu_suspend(0, imx6q_suspend_finish); +- imx_smp_prepare(); +- imx_anatop_post_resume(); +- imx_gpc_post_resume(); +- imx6q_set_lpm(WAIT_CLOCKED); +- break; +- default: +- return -EINVAL; +- } +- +- return 0; +-} +- +-static const struct platform_suspend_ops imx6q_pm_ops = { +- .enter = imx6q_pm_enter, +- .valid = suspend_valid_only_mem, +-}; +- +-void __init imx6q_pm_init(void) +-{ +- suspend_set_ops(&imx6q_pm_ops); +-} +diff -Nur linux-3.10.30/arch/arm/mach-imx/src.c linux-3.10.30-cubox-i/arch/arm/mach-imx/src.c +--- linux-3.10.30/arch/arm/mach-imx/src.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/src.c 2014-03-08 20:32:54.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011 Freescale Semiconductor, Inc. ++ * Copyright 2011, 2013 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -91,6 +91,7 @@ + spin_lock(&scr_lock); + val = readl_relaxed(src_base + SRC_SCR); + val = enable ? val | mask : val & ~mask; ++ val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); + writel_relaxed(val, src_base + SRC_SCR); + spin_unlock(&scr_lock); + } +@@ -114,21 +115,6 @@ + writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4); + } + +-void imx_src_prepare_restart(void) +-{ +- u32 val; +- +- /* clear enable bits of secondary cores */ +- spin_lock(&scr_lock); +- val = readl_relaxed(src_base + SRC_SCR); +- val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE); +- writel_relaxed(val, src_base + SRC_SCR); +- spin_unlock(&scr_lock); +- +- /* clear persistent entry register of primary core */ +- writel_relaxed(0, src_base + SRC_GPR1); +-} +- + void __init imx_src_init(void) + { + struct device_node *np; +diff -Nur linux-3.10.30/arch/arm/mach-imx/suspend-imx6.S linux-3.10.30-cubox-i/arch/arm/mach-imx/suspend-imx6.S +--- linux-3.10.30/arch/arm/mach-imx/suspend-imx6.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/suspend-imx6.S 2014-03-08 20:32:54.000000000 +0100 +@@ -0,0 +1,801 @@ ++/* ++ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++#include "hardware.h" ++ ++#define MX6Q_SRC_GPR1 0x20 ++#define MX6Q_SRC_GPR2 0x24 ++#define MX6Q_MMDC_MAPSR 0x404 ++#define MX6Q_MMDC_MPDGCTRL0 0x83c ++#define MX6Q_GPC_IMR1 0x08 ++#define MX6Q_GPC_IMR2 0x0c ++#define MX6Q_GPC_IMR3 0x10 ++#define MX6Q_GPC_IMR4 0x14 ++#define MX6Q_CCM_CCR 0x0 ++#define MX6Q_ANATOP_CORE 0x140 ++ ++ .align 3 ++ ++ .macro imx6sl_ddr_io_save ++ ++ ldr r4, [r8, #0x30c] /* DRAM_DQM0 */ ++ ldr r5, [r8, #0x310] /* DRAM_DQM1 */ ++ ldr r6, [r8, #0x314] /* DRAM_DQM2 */ ++ ldr r7, [r8, #0x318] /* DRAM_DQM3 */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x5c4] /* GPR_B0DS */ ++ ldr r5, [r8, #0x5cc] /* GPR_B1DS */ ++ ldr r6, [r8, #0x5d4] /* GPR_B2DS */ ++ ldr r7, [r8, #0x5d8] /* GPR_B3DS */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x300] /* DRAM_CAS */ ++ ldr r5, [r8, #0x31c] /* DRAM_RAS */ ++ ldr r6, [r8, #0x338] /* DRAM_SDCLK_0 */ ++ ldr r7, [r8, #0x5ac] /* GPR_ADDS*/ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x5b0] /* DDRMODE_CTL */ ++ ldr r5, [r8, #0x5c0] /* DDRMODE */ ++ ldr r6, [r8, #0x33c] /* DRAM_SODT0*/ ++ ldr r7, [r8, #0x340] /* DRAM_SODT1*/ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x330] /* DRAM_SDCKE0 */ ++ ldr r5, [r8, #0x334] /* DRAM_SDCKE1 */ ++ ldr r6, [r8, #0x320] /* DRAM_RESET */ ++ stmfd r10!, {r4-r6} ++ ++ .endm ++ ++ .macro imx6sl_ddr_io_restore ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x30c] /* DRAM_DQM0 */ ++ str r5, [r8, #0x310] /* DRAM_DQM1 */ ++ str r6, [r8, #0x314] /* DRAM_DQM2 */ ++ str r7, [r8, #0x318] /* DRAM_DQM3 */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x5c4] /* GPR_B0DS */ ++ str r5, [r8, #0x5cc] /* GPR_B1DS */ ++ str r6, [r8, #0x5d4] /* GPR_B2DS */ ++ str r7, [r8, #0x5d8] /* GPR_B3DS */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x300] /* DRAM_CAS */ ++ str r5, [r8, #0x31c] /* DRAM_RAS */ ++ str r6, [r8, #0x338] /* DRAM_SDCLK_0 */ ++ str r7, [r8, #0x5ac] /* GPR_ADDS*/ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x5b0] /* DDRMODE_CTL */ ++ str r5, [r8, #0x5c0] /* DDRMODE */ ++ str r6, [r8, #0x33c] /* DRAM_SODT0*/ ++ str r7, [r8, #0x340] /* DRAM_SODT1*/ ++ ++ ldmea r10!, {r4-r6} ++ str r4, [r8, #0x330] /* DRAM_SDCKE0 */ ++ str r5, [r8, #0x334] /* DRAM_SDCKE1 */ ++ str r6, [r8, #0x320] /* DRAM_RESET */ ++ ++ .endm ++ ++ .macro imx6sl_ddr_io_set_lpm ++ ++ mov r10, #0 ++ str r10, [r8, #0x30c] /* DRAM_DQM0 */ ++ str r10, [r8, #0x310] /* DRAM_DQM1 */ ++ str r10, [r8, #0x314] /* DRAM_DQM2 */ ++ str r10, [r8, #0x318] /* DRAM_DQM3 */ ++ ++ str r10, [r8, #0x5c4] /* GPR_B0DS */ ++ str r10, [r8, #0x5cc] /* GPR_B1DS */ ++ str r10, [r8, #0x5d4] /* GPR_B2DS */ ++ str r10, [r8, #0x5d8] /* GPR_B3DS */ ++ ++ str r10, [r8, #0x300] /* DRAM_CAS */ ++ str r10, [r8, #0x31c] /* DRAM_RAS */ ++ str r10, [r8, #0x338] /* DRAM_SDCLK_0 */ ++ str r10, [r8, #0x5ac] /* GPR_ADDS*/ ++ ++ str r10, [r8, #0x5b0] /* DDRMODE_CTL */ ++ str r10, [r8, #0x5c0] /* DDRMODE */ ++ str r10, [r8, #0x33c] /* DRAM_SODT0*/ ++ str r10, [r8, #0x340] /* DRAM_SODT1*/ ++ ++ mov r10, #0x80000 ++ str r10, [r8, #0x320] /* DRAM_RESET */ ++ mov r10, #0x1000 ++ str r10, [r8, #0x330] /* DRAM_SDCKE0 */ ++ str r10, [r8, #0x334] /* DRAM_SDCKE1 */ ++ ++ .endm ++ ++ .macro imx6dl_ddr_io_save ++ ++ ldr r4, [r8, #0x470] /* DRAM_DQM0 */ ++ ldr r5, [r8, #0x474] /* DRAM_DQM1 */ ++ ldr r6, [r8, #0x478] /* DRAM_DQM2 */ ++ ldr r7, [r8, #0x47c] /* DRAM_DQM3 */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x480] /* DRAM_DQM4 */ ++ ldr r5, [r8, #0x484] /* DRAM_DQM5 */ ++ ldr r6, [r8, #0x488] /* DRAM_DQM6 */ ++ ldr r7, [r8, #0x48c] /* DRAM_DQM7 */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x464] /* DRAM_CAS */ ++ ldr r5, [r8, #0x490] /* DRAM_RAS */ ++ ldr r6, [r8, #0x4ac] /* DRAM_SDCLK_0 */ ++ ldr r7, [r8, #0x4b0] /* DRAM_SDCLK_1 */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r5, [r8, #0x750] /* DDRMODE_CTL */ ++ ldr r6, [r8, #0x760] /* DDRMODE */ ++ stmfd r10!, {r5-r6} ++ ++ ldr r4, [r8, #0x4bc] /* DRAM_SDQS0 */ ++ ldr r5, [r8, #0x4c0] /* DRAM_SDQS1 */ ++ ldr r6, [r8, #0x4c4] /* DRAM_SDQS2 */ ++ ldr r7, [r8, #0x4c8] /* DRAM_SDQS3 */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x4cc] /* DRAM_SDQS4 */ ++ ldr r5, [r8, #0x4d0] /* DRAM_SDQS5 */ ++ ldr r6, [r8, #0x4d4] /* DRAM_SDQS6 */ ++ ldr r7, [r8, #0x4d8] /* DRAM_SDQS7 */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x764] /* GPR_B0DS */ ++ ldr r5, [r8, #0x770] /* GPR_B1DS */ ++ ldr r6, [r8, #0x778] /* GPR_B2DS */ ++ ldr r7, [r8, #0x77c] /* GPR_B3DS */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x780] /* GPR_B4DS */ ++ ldr r5, [r8, #0x784] /* GPR_B5DS */ ++ ldr r6, [r8, #0x78c] /* GPR_B6DS */ ++ ldr r7, [r8, #0x748] /* GPR_B7DS */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r5, [r8, #0x74c] /* GPR_ADDS*/ ++ ldr r6, [r8, #0x4b4] /* DRAM_SODT0*/ ++ ldr r7, [r8, #0x4b8] /* DRAM_SODT1*/ ++ stmfd r10!, {r5-r7} ++ ++ .endm ++ ++ .macro imx6dl_ddr_io_restore ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x470] /* DRAM_DQM0 */ ++ str r5, [r8, #0x474] /* DRAM_DQM1 */ ++ str r6, [r8, #0x478] /* DRAM_DQM2 */ ++ str r7, [r8, #0x47c] /* DRAM_DQM3 */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x480] /* DRAM_DQM4 */ ++ str r5, [r8, #0x484] /* DRAM_DQM5 */ ++ str r6, [r8, #0x488] /* DRAM_DQM6 */ ++ str r7, [r8, #0x48c] /* DRAM_DQM7 */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x464] /* DRAM_CAS */ ++ str r5, [r8, #0x490] /* DRAM_RAS */ ++ str r6, [r8, #0x4ac] /* DRAM_SDCLK_0 */ ++ str r7, [r8, #0x4b0] /* DRAM_SDCLK_1 */ ++ ++ ldmea r10!, {r5-r6} ++ str r5, [r8, #0x750] /* DDRMODE_CTL */ ++ str r6, [r8, #0x760] /* DDRMODE */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x4bc] /* DRAM_SDQS0 */ ++ str r5, [r8, #0x4c0] /* DRAM_SDQS1 */ ++ str r6, [r8, #0x4c4] /* DRAM_SDQS2 */ ++ str r7, [r8, #0x4c8] /* DRAM_SDQS3 */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x4cc] /* DRAM_SDQS4 */ ++ str r5, [r8, #0x4d0] /* DRAM_SDQS5 */ ++ str r6, [r8, #0x4d4] /* DRAM_SDQS6 */ ++ str r7, [r8, #0x4d8] /* DRAM_SDQS7 */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x764] /* GPR_B0DS */ ++ str r5, [r8, #0x770] /* GPR_B1DS */ ++ str r6, [r8, #0x778] /* GPR_B2DS */ ++ str r7, [r8, #0x77c] /* GPR_B3DS */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x780] /* GPR_B4DS */ ++ str r5, [r8, #0x784] /* GPR_B5DS */ ++ str r6, [r8, #0x78c] /* GPR_B6DS */ ++ str r7, [r8, #0x748] /* GPR_B7DS */ ++ ++ ldmea r10!, {r5-r7} ++ str r5, [r8, #0x74c] /* GPR_ADDS*/ ++ str r6, [r8, #0x4b4] /* DRAM_SODT0*/ ++ str r7, [r8, #0x4b8] /* DRAM_SODT1*/ ++ ++ .endm ++ ++ .macro imx6dl_ddr_io_set_lpm ++ ++ mov r10, #0 ++ str r10, [r8, #0x470] /* DRAM_DQM0 */ ++ str r10, [r8, #0x474] /* DRAM_DQM1 */ ++ str r10, [r8, #0x478] /* DRAM_DQM2 */ ++ str r10, [r8, #0x47c] /* DRAM_DQM3 */ ++ ++ str r10, [r8, #0x480] /* DRAM_DQM4 */ ++ str r10, [r8, #0x484] /* DRAM_DQM5 */ ++ str r10, [r8, #0x488] /* DRAM_DQM6 */ ++ str r10, [r8, #0x48c] /* DRAM_DQM7 */ ++ ++ str r10, [r8, #0x464] /* DRAM_CAS */ ++ str r10, [r8, #0x490] /* DRAM_RAS */ ++ str r10, [r8, #0x4ac] /* DRAM_SDCLK_0 */ ++ str r10, [r8, #0x4b0] /* DRAM_SDCLK_1 */ ++ ++ str r10, [r8, #0x750] /* DDRMODE_CTL */ ++ str r10, [r8, #0x760] /* DDRMODE */ ++ ++ str r10, [r8, #0x4bc] /* DRAM_SDQS0 */ ++ str r10, [r8, #0x4c0] /* DRAM_SDQS1 */ ++ str r10, [r8, #0x4c4] /* DRAM_SDQS2 */ ++ str r10, [r8, #0x4c8] /* DRAM_SDQS3 */ ++ ++ str r10, [r8, #0x4cc] /* DRAM_SDQS4 */ ++ str r10, [r8, #0x4d0] /* DRAM_SDQS5 */ ++ str r10, [r8, #0x4d4] /* DRAM_SDQS6 */ ++ str r10, [r8, #0x4d8] /* DRAM_SDQS7 */ ++ ++ str r10, [r8, #0x764] /* GPR_B0DS */ ++ str r10, [r8, #0x770] /* GPR_B1DS */ ++ str r10, [r8, #0x778] /* GPR_B2DS */ ++ str r10, [r8, #0x77c] /* GPR_B3DS */ ++ ++ str r10, [r8, #0x780] /* GPR_B4DS */ ++ str r10, [r8, #0x784] /* GPR_B5DS */ ++ str r10, [r8, #0x78c] /* GPR_B6DS */ ++ str r10, [r8, #0x748] /* GPR_B7DS */ ++ ++ str r10, [r8, #0x74c] /* GPR_ADDS*/ ++ str r10, [r8, #0x4b4] /* DRAM_SODT0*/ ++ str r10, [r8, #0x4b8] /* DRAM_SODT1*/ ++ ++ .endm ++ ++ .macro imx6dq_ddr_io_save ++ ++ ldr r4, [r8, #0x5ac] /* DRAM_DQM0 */ ++ ldr r5, [r8, #0x5b4] /* DRAM_DQM1 */ ++ ldr r6, [r8, #0x528] /* DRAM_DQM2 */ ++ ldr r7, [r8, #0x520] /* DRAM_DQM3 */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x514] /* DRAM_DQM4 */ ++ ldr r5, [r8, #0x510] /* DRAM_DQM5 */ ++ ldr r6, [r8, #0x5bc] /* DRAM_DQM6 */ ++ ldr r7, [r8, #0x5c4] /* DRAM_DQM7 */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x56c] /* DRAM_CAS */ ++ ldr r5, [r8, #0x578] /* DRAM_RAS */ ++ ldr r6, [r8, #0x588] /* DRAM_SDCLK_0 */ ++ ldr r7, [r8, #0x594] /* DRAM_SDCLK_1 */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r5, [r8, #0x750] /* DDRMODE_CTL */ ++ ldr r6, [r8, #0x774] /* DDRMODE */ ++ stmfd r10!, {r5-r6} ++ ++ ldr r4, [r8, #0x5a8] /* DRAM_SDQS0 */ ++ ldr r5, [r8, #0x5b0] /* DRAM_SDQS1 */ ++ ldr r6, [r8, #0x524] /* DRAM_SDQS2 */ ++ ldr r7, [r8, #0x51c] /* DRAM_SDQS3 */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x518] /* DRAM_SDQS4 */ ++ ldr r5, [r8, #0x50c] /* DRAM_SDQS5 */ ++ ldr r6, [r8, #0x5b8] /* DRAM_SDQS6 */ ++ ldr r7, [r8, #0x5c0] /* DRAM_SDQS7 */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x784] /* GPR_B0DS */ ++ ldr r5, [r8, #0x788] /* GPR_B1DS */ ++ ldr r6, [r8, #0x794] /* GPR_B2DS */ ++ ldr r7, [r8, #0x79c] /* GPR_B3DS */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r4, [r8, #0x7a0] /* GPR_B4DS */ ++ ldr r5, [r8, #0x7a4] /* GPR_B5DS */ ++ ldr r6, [r8, #0x7a8] /* GPR_B6DS */ ++ ldr r7, [r8, #0x748] /* GPR_B7DS */ ++ stmfd r10!, {r4-r7} ++ ++ ldr r5, [r8, #0x74c] /* GPR_ADDS*/ ++ ldr r6, [r8, #0x59c] /* DRAM_SODT0*/ ++ ldr r7, [r8, #0x5a0] /* DRAM_SODT1*/ ++ stmfd r10!, {r5-r7} ++ ++ .endm ++ ++ .macro imx6dq_ddr_io_restore ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x5ac] /* DRAM_DQM0 */ ++ str r5, [r8, #0x5b4] /* DRAM_DQM1 */ ++ str r6, [r8, #0x528] /* DRAM_DQM2 */ ++ str r7, [r8, #0x520] /* DRAM_DQM3 */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x514] /* DRAM_DQM4 */ ++ str r5, [r8, #0x510] /* DRAM_DQM5 */ ++ str r6, [r8, #0x5bc] /* DRAM_DQM6 */ ++ str r7, [r8, #0x5c4] /* DRAM_DQM7 */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x56c] /* DRAM_CAS */ ++ str r5, [r8, #0x578] /* DRAM_RAS */ ++ str r6, [r8, #0x588] /* DRAM_SDCLK_0 */ ++ str r7, [r8, #0x594] /* DRAM_SDCLK_1 */ ++ ++ ldmea r10!, {r5-r6} ++ str r5, [r8, #0x750] /* DDRMODE_CTL */ ++ str r6, [r8, #0x774] /* DDRMODE */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x5a8] /* DRAM_SDQS0 */ ++ str r5, [r8, #0x5b0] /* DRAM_SDQS1 */ ++ str r6, [r8, #0x524] /* DRAM_SDQS2 */ ++ str r7, [r8, #0x51c] /* DRAM_SDQS3 */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x518] /* DRAM_SDQS4 */ ++ str r5, [r8, #0x50c] /* DRAM_SDQS5 */ ++ str r6, [r8, #0x5b8] /* DRAM_SDQS6 */ ++ str r7, [r8, #0x5c0] /* DRAM_SDQS7 */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x784] /* GPR_B0DS */ ++ str r5, [r8, #0x788] /* GPR_B1DS */ ++ str r6, [r8, #0x794] /* GPR_B2DS */ ++ str r7, [r8, #0x79c] /* GPR_B3DS */ ++ ++ ldmea r10!, {r4-r7} ++ str r4, [r8, #0x7a0] /* GPR_B4DS */ ++ str r5, [r8, #0x7a4] /* GPR_B5DS */ ++ str r6, [r8, #0x7a8] /* GPR_B6DS */ ++ str r7, [r8, #0x748] /* GPR_B7DS */ ++ ++ ldmea r10!, {r5-r7} ++ str r5, [r8, #0x74c] /* GPR_ADDS*/ ++ str r6, [r8, #0x59c] /* DRAM_SODT0*/ ++ str r7, [r8, #0x5a0] /* DRAM_SODT1*/ ++ ++ .endm ++ ++ .macro imx6dq_ddr_io_set_lpm ++ ++ mov r10, #0 ++ str r10, [r8, #0x5ac] /* DRAM_DQM0 */ ++ str r10, [r8, #0x5b4] /* DRAM_DQM1 */ ++ str r10, [r8, #0x528] /* DRAM_DQM2 */ ++ str r10, [r8, #0x520] /* DRAM_DQM3 */ ++ ++ str r10, [r8, #0x514] /* DRAM_DQM4 */ ++ str r10, [r8, #0x510] /* DRAM_DQM5 */ ++ str r10, [r8, #0x5bc] /* DRAM_DQM6 */ ++ str r10, [r8, #0x5c4] /* DRAM_DQM7 */ ++ ++ str r10, [r8, #0x56c] /* DRAM_CAS */ ++ str r10, [r8, #0x578] /* DRAM_RAS */ ++ str r10, [r8, #0x588] /* DRAM_SDCLK_0 */ ++ str r10, [r8, #0x594] /* DRAM_SDCLK_1 */ ++ ++ str r10, [r8, #0x750] /* DDRMODE_CTL */ ++ str r10, [r8, #0x774] /* DDRMODE */ ++ ++ str r10, [r8, #0x5a8] /* DRAM_SDQS0 */ ++ str r10, [r8, #0x5b0] /* DRAM_SDQS1 */ ++ str r10, [r8, #0x524] /* DRAM_SDQS2 */ ++ str r10, [r8, #0x51c] /* DRAM_SDQS3 */ ++ ++ str r10, [r8, #0x518] /* DRAM_SDQS4 */ ++ str r10, [r8, #0x50c] /* DRAM_SDQS5 */ ++ str r10, [r8, #0x5b8] /* DRAM_SDQS6 */ ++ str r10, [r8, #0x5c0] /* DRAM_SDQS7 */ ++ ++ str r10, [r8, #0x784] /* GPR_B0DS */ ++ str r10, [r8, #0x788] /* GPR_B1DS */ ++ str r10, [r8, #0x794] /* GPR_B2DS */ ++ str r10, [r8, #0x79c] /* GPR_B3DS */ ++ ++ str r10, [r8, #0x7a0] /* GPR_B4DS */ ++ str r10, [r8, #0x7a4] /* GPR_B5DS */ ++ str r10, [r8, #0x7a8] /* GPR_B6DS */ ++ str r10, [r8, #0x748] /* GPR_B7DS */ ++ ++ str r10, [r8, #0x74c] /* GPR_ADDS*/ ++ str r10, [r8, #0x59c] /* DRAM_SODT0*/ ++ str r10, [r8, #0x5a0] /* DRAM_SODT1*/ ++ ++ .endm ++ ++ .macro sync_l2_cache ++ ++ /* sync L2 cache to drain L2's buffers to DRAM. */ ++#ifdef CONFIG_CACHE_L2X0 ++ ldr r8, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR) ++ mov r5, #0x0 ++ str r5, [r8, #L2X0_CACHE_SYNC] ++1: ++ ldr r5, [r8, #L2X0_CACHE_SYNC] ++ ands r5, r5, #0x1 ++ bne 1b ++#endif ++ .endm ++ ++ENTRY(imx6_suspend) ++ ++ /* ++ * counting the resume address in iram ++ * to set it in SRC register. ++ */ ++ ldr r4, =imx6_suspend ++ ldr r5, =resume ++ sub r5, r5, r4 ++ add r9, r1, r5 ++ ++ /* ++ * make sure TLB contain the addr we want, ++ * as we will access after DDR IO floated. ++ */ ++ ++ ldr r8, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR) ++ ldr r7, [r8, #MX6Q_ANATOP_CORE] ++ ldr r8, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) ++ ldr r7, [r8, #0x0] ++ ldr r8, =IMX_IO_P2V(MX6Q_GPC_BASE_ADDR) ++ ldr r7, [r8, #0x0] ++ ++ /* use r8 to store the IO address */ ++ ldr r8, =IMX_IO_P2V(MX6Q_SRC_BASE_ADDR) ++ ++ /* ++ * read previous resume address from SRC ++ * register, which is v7_cpu_resume, this ++ * is for the jump when we finish DDR IO ++ * restore. ++ */ ++ ldr r5, [r8, #MX6Q_SRC_GPR1] ++ add r10, r0, #MX6_SUSPEND_IRAM_SIZE ++ stmfd r10!, {r5} ++ ++ /* save cpu type */ ++ stmfd r10!, {r2} ++ ++ str r9, [r8, #MX6Q_SRC_GPR1] ++ add r3, r1, #MX6_SUSPEND_IRAM_SIZE ++ str r3, [r8, #MX6Q_SRC_GPR2] ++ ++ ldr r8, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR) ++ ++ cmp r2, #MXC_CPU_IMX6Q ++ bne dl_io_dsm_save ++ imx6dq_ddr_io_save ++ b ddr_io_save_dsm_done ++dl_io_dsm_save: ++ cmp r2, #MXC_CPU_IMX6DL ++ bne sl_io_save ++ imx6dl_ddr_io_save ++ b ddr_io_save_dsm_done ++sl_io_save: ++ imx6sl_ddr_io_save ++ddr_io_save_dsm_done: ++ ++ /* need to sync L2 cache before DSM. */ ++ sync_l2_cache ++ ++ ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) ++ /* ++ * put DDR explicitly into self-refresh and ++ * disable Automatic power savings. ++ */ ++ ldr r7, [r8, #MX6Q_MMDC_MAPSR] ++ orr r7, r7, #0x01 ++ str r7, [r8, #MX6Q_MMDC_MAPSR] ++ ++ /* make the DDR explicitly enter self-refresh. */ ++ ldr r7, [r8, #MX6Q_MMDC_MAPSR] ++ orr r7, r7, #(1 << 21) ++ str r7, [r8, #MX6Q_MMDC_MAPSR] ++ ++poll_dvfs_set_1: ++ ldr r7, [r8, #0x404] ++ ands r7, r7, #(1 << 25) ++ beq poll_dvfs_set_1 ++ ++ ldr r8, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR) ++ ++ cmp r2, #MXC_CPU_IMX6Q ++ bne dl_io_dsm_set_lpm ++ imx6dq_ddr_io_set_lpm ++ b ddr_io_set_lpm_dsm_done ++dl_io_dsm_set_lpm: ++ cmp r2, #MXC_CPU_IMX6DL ++ bne sl_io_dsm_set_lpm ++ imx6dl_ddr_io_set_lpm ++ b ddr_io_set_lpm_dsm_done ++sl_io_dsm_set_lpm: ++ imx6sl_ddr_io_set_lpm ++ddr_io_set_lpm_dsm_done: ++ ++ /* ++ * mask all GPC interrupts before ++ * enabling the RBC counters to ++ * avoid the counter starting too ++ * early if an interupt is already ++ * pending. ++ */ ++ ldr r8, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR) ++ /* save CCM base in r9 */ ++ mov r9, r8 ++ ldr r8, =IMX_IO_P2V(MX6Q_GPC_BASE_ADDR) ++ ldr r4, [r8, #MX6Q_GPC_IMR1] ++ ldr r5, [r8, #MX6Q_GPC_IMR2] ++ ldr r6, [r8, #MX6Q_GPC_IMR3] ++ ldr r7, [r8, #MX6Q_GPC_IMR4] ++ ++ ldr r3, =0xffffffff ++ str r3, [r8, #MX6Q_GPC_IMR1] ++ str r3, [r8, #MX6Q_GPC_IMR2] ++ str r3, [r8, #MX6Q_GPC_IMR3] ++ str r3, [r8, #MX6Q_GPC_IMR4] ++ ++ /* ++ * enable the RBC bypass counter here ++ * to hold off the interrupts. RBC counter ++ * = 32 (1ms), Minimum RBC delay should be ++ * 400us for the analog LDOs to power down. ++ */ ++ ldr r3, [r9, #MX6Q_CCM_CCR] ++ bic r3, r3, #(0x3f << 21) ++ orr r3, r3, #(0x20 << 21) ++ str r3, [r9, #MX6Q_CCM_CCR] ++ ++ /* enable the counter. */ ++ ldr r3, [r9, #MX6Q_CCM_CCR] ++ orr r3, r3, #(0x1 << 27) ++ str r3, [r9, #MX6Q_CCM_CCR] ++ ++ /* unmask all the GPC interrupts. */ ++ str r4, [r8, #MX6Q_GPC_IMR1] ++ str r5, [r8, #MX6Q_GPC_IMR2] ++ str r6, [r8, #MX6Q_GPC_IMR3] ++ str r7, [r8, #MX6Q_GPC_IMR4] ++ ++ /* ++ * now delay for a short while (3usec) ++ * ARM is at 1GHz at this point ++ * so a short loop should be enough. ++ * this delay is required to ensure that ++ * the RBC counter can start counting in ++ * case an interrupt is already pending ++ * or in case an interrupt arrives just ++ * as ARM is about to assert DSM_request. ++ */ ++ ldr r4, =2000 ++rbc_loop: ++ sub r4, r4, #0x1 ++ cmp r4, #0x0 ++ bne rbc_loop ++ ++ /* ++ * if internal ldo(VDDARM) bypassed,analog bypass ++ * it for DSM(0x1e) and restore it when resume(0x1f). ++ */ ++ ldr r8, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR) ++ ldr r7, [r8, #MX6Q_ANATOP_CORE] ++ and r7, r7, #0x1f ++ cmp r7, #0x1f ++ bne ldo_check_done1 ++ldo_analog_bypass: ++ ldr r7, [r8, #MX6Q_ANATOP_CORE] ++ bic r7, r7, #0x1f ++ orr r7, r7, #0x1e ++ str r7, [r8, #MX6Q_ANATOP_CORE] ++ldo_check_done1: ++ ++ /* Zzz, enter stop mode */ ++ wfi ++ nop ++ nop ++ nop ++ nop ++ ++ /* ++ * run to here means there is pending ++ * wakeup source, system should auto ++ * resume, we need to restore DDR IO first ++ */ ++ ++ /* restore it with 0x1f if use ldo bypass mode.*/ ++ ldr r8, =IMX_IO_P2V(MX6Q_ANATOP_BASE_ADDR) ++ ldr r7, [r8, #MX6Q_ANATOP_CORE] ++ and r7, r7, #0x1f ++ cmp r7, #0x1e ++ bne ldo_check_done2 ++ldo_bypass_restore: ++ ldr r7, [r8, #MX6Q_ANATOP_CORE] ++ orr r7, r7, #0x1f ++ str r7, [r8, #MX6Q_ANATOP_CORE] ++ldo_check_done2: ++ ++ add r10, r0, #MX6_SUSPEND_IRAM_SIZE ++ /* skip the lr saved in iram */ ++ sub r10, r10, #0x4 ++ /* skip the cpu type saved in iram */ ++ sub r10, r10, #0x4 ++ ++ ldr r8, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR) ++ ++ cmp r2, #MXC_CPU_IMX6Q ++ bne dl_io_restore ++ imx6dq_ddr_io_restore ++ b ddr_io_restore_done ++dl_io_restore: ++ cmp r2, #MXC_CPU_IMX6DL ++ bne sl_io_restore ++ imx6dl_ddr_io_restore ++ b ddr_io_restore_done ++sl_io_restore: ++ imx6sl_ddr_io_restore ++ ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) ++ /* reset read FIFO, RST_RD_FIFO */ ++ ldr r7, =MX6Q_MMDC_MPDGCTRL0 ++ ldr r6, [r8, r7] ++ orr r6, r6, #(1 << 31) ++ str r6, [r8, r7] ++fifo_reset1_wait: ++ ldr r6, [r8, r7] ++ and r6, r6, #(1 << 31) ++ cmp r6, #0 ++ bne fifo_reset1_wait ++ ++ /* reset FIFO a second time */ ++ ldr r6, [r8, r7] ++ orr r6, r6, #(1 << 31) ++ str r6, [r8, r7] ++fifo_reset2_wait: ++ ldr r6, [r8, r7] ++ and r6, r6, #(1 << 31) ++ cmp r6, #0 ++ bne fifo_reset2_wait ++ddr_io_restore_done: ++ ++ ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR) ++ /* let DDR out of self-refresh. */ ++ ldr r7, [r8, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #(1 << 21) ++ str r7, [r8, #MX6Q_MMDC_MAPSR] ++ ++poll_dvfs_clear_2: ++ ldr r7, [r8, #MX6Q_MMDC_MAPSR] ++ ands r7, r7, #(1 << 25) ++ bne poll_dvfs_clear_2 ++ /* enable DDR auto power saving */ ++ ldr r7, [r8, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #0x1 ++ str r7, [r8, #MX6Q_MMDC_MAPSR] ++ /* return to suspend finish */ ++ mov pc, lr ++ ++resume: ++ /* invalidate L1 I-cache first */ ++ mov r1, #0x0 ++ mcr p15, 0, r1, c7, c5, 0 ++ mcr p15, 0, r1, c7, c5, 0 ++ mcr p15, 0, r1, c7, c5, 6 ++ /* enable the Icache and branch prediction */ ++ mov r1, #0x1800 ++ mcr p15, 0, r1, c1, c0, 0 ++ isb ++ ++ /* restore it with 0x1f if use ldo bypass mode.*/ ++ ldr r8, =MX6Q_ANATOP_BASE_ADDR ++ ldr r7, [r8, #MX6Q_ANATOP_CORE] ++ and r7, r7, #0x1f ++ cmp r7, #0x1e ++ bne ldo_check_done3 ++ ldr r7, [r8, #MX6Q_ANATOP_CORE] ++ orr r7, r7, #0x1f ++ str r7, [r8, #MX6Q_ANATOP_CORE] ++ldo_check_done3: ++ ++ ldr r5, =MX6Q_SRC_BASE_ADDR ++ ldr r10, [r5, #MX6Q_SRC_GPR2] ++ ldmea r10!, {lr} ++ ++ /* get cpu tpye */ ++ ldmea r10!, {r2} ++ ++ /* clear core0's entry and parameter */ ++ ldr r8, =MX6Q_SRC_BASE_ADDR ++ mov r7, #0 ++ str r7, [r8, #MX6Q_SRC_GPR1] ++ str r7, [r8, #MX6Q_SRC_GPR2] ++ ++ ldr r8, =MX6Q_IOMUXC_BASE_ADDR ++ ++ cmp r2, #MXC_CPU_IMX6Q ++ bne dl_io_dsm_restore ++ imx6dq_ddr_io_restore ++ b ddr_io_restore_dsm_done ++dl_io_dsm_restore: ++ cmp r2, #MXC_CPU_IMX6DL ++ bne sl_io_dsm_restore ++ imx6dl_ddr_io_restore ++ b ddr_io_restore_dsm_done ++sl_io_dsm_restore: ++ imx6sl_ddr_io_restore ++ ldr r8, =MX6Q_MMDC_P0_BASE_ADDR ++ /* reset read FIFO, RST_RD_FIFO */ ++ ldr r7, =MX6Q_MMDC_MPDGCTRL0 ++ ldr r6, [r8, r7] ++ orr r6, r6, #(1 << 31) ++ str r6, [r8, r7] ++dsm_fifo_reset1_wait: ++ ldr r6, [r8, r7] ++ and r6, r6, #(1 << 31) ++ cmp r6, #0 ++ bne dsm_fifo_reset1_wait ++ ++ /* reset FIFO a second time */ ++ ldr r6, [r8, r7] ++ orr r6, r6, #(1 << 31) ++ str r6, [r8, r7] ++dsm_fifo_reset2_wait: ++ ldr r6, [r8, r7] ++ and r6, r6, #(1 << 31) ++ cmp r6, #0 ++ bne dsm_fifo_reset2_wait ++ddr_io_restore_dsm_done: ++ ++ ldr r8, =MX6Q_MMDC_P0_BASE_ADDR ++ /* let DDR out of self-refresh */ ++ ldr r7, [r8, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #(1 << 21) ++ str r7, [r8, #MX6Q_MMDC_MAPSR] ++ ++poll_dvfs_clear_1: ++ ldr r7, [r8, #MX6Q_MMDC_MAPSR] ++ ands r7, r7, #(1 << 25) ++ bne poll_dvfs_clear_1 ++ /* enable DDR auto power saving */ ++ ldr r7, [r8, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #0x1 ++ str r7, [r8, #MX6Q_MMDC_MAPSR] ++ mov pc, lr +diff -Nur linux-3.10.30/arch/arm/mach-imx/system.c linux-3.10.30-cubox-i/arch/arm/mach-imx/system.c +--- linux-3.10.30/arch/arm/mach-imx/system.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/system.c 2014-03-08 20:32:54.000000000 +0100 +@@ -1,7 +1,7 @@ + /* + * Copyright (C) 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd +- * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2006-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Juergen Beisert, kernel@pengutronix.de + * Copyright 2009 Ilya Yanok, Emcraft Systems Ltd, yanok@emcraft.com + * +@@ -21,15 +21,20 @@ + #include + #include + #include ++#include ++#include + + #include + #include + #include ++#include + + #include "common.h" + #include "hardware.h" + + static void __iomem *wdog_base; ++static struct clk *wdog_clk; ++static u32 wdog_source = 1; /* use WDOG1 default */ + + /* + * Reset the system. It is called by machine_restart(). +@@ -38,24 +43,32 @@ + { + unsigned int wcr_enable; + +- if (cpu_is_mx1()) { +- wcr_enable = (1 << 0); +- } else { +- struct clk *clk; ++ if (wdog_clk) ++ clk_enable(wdog_clk); + +- clk = clk_get_sys("imx2-wdt.0", NULL); +- if (!IS_ERR(clk)) +- clk_prepare_enable(clk); ++ if (cpu_is_mx1()) ++ wcr_enable = (1 << 0); ++ /* ++ * Some i.MX6 boards use WDOG2 to reset external pmic in bypass mode, ++ * so do WDOG2 reset here. Do not set SRS, since we will ++ * trigger external POR later. Use WDOG1 to reset in ldo-enable ++ * mode. You can set it by "fsl,wdog-reset" in dts. ++ */ ++ else if (wdog_source == 2 && (cpu_is_imx6q() || cpu_is_imx6dl() || ++ cpu_is_imx6sl())) ++ wcr_enable = 0x14; ++ else + wcr_enable = (1 << 2); +- } + + /* Assert SRS signal */ + __raw_writew(wcr_enable, wdog_base); ++ /* write twice to ensure the request will not get ignored */ ++ __raw_writew(wcr_enable, wdog_base); + + /* wait for reset to assert... */ + mdelay(500); + +- printk(KERN_ERR "Watchdog reset failed to assert reset\n"); ++ pr_err("%s: Watchdog reset failed to assert reset\n", __func__); + + /* delay to allow the serial port to show the message */ + mdelay(50); +@@ -64,7 +77,94 @@ + soft_restart(0); + } + +-void mxc_arch_reset_init(void __iomem *base) ++void __init mxc_arch_reset_init(void __iomem *base) + { + wdog_base = base; ++ ++ wdog_clk = clk_get_sys("imx2-wdt.0", NULL); ++ if (IS_ERR(wdog_clk)) { ++ pr_warn("%s: failed to get wdog clock\n", __func__); ++ wdog_clk = NULL; ++ return; ++ } ++ ++ clk_prepare(wdog_clk); ++} ++ ++void __init mxc_arch_reset_init_dt(void) ++{ ++ struct device_node *np = NULL; ++ ++ if (cpu_is_imx6q() || cpu_is_imx6dl()) ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc"); ++ else if (cpu_is_imx6sl()) ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-gpc"); ++ ++ if (np) ++ of_property_read_u32(np, "fsl,wdog-reset", &wdog_source); ++ pr_info("Use WDOG%d as reset source\n", wdog_source); ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx21-wdt"); ++ wdog_base = of_iomap(np, 0); ++ WARN_ON(!wdog_base); ++ ++ /* Some i.MX6 boards use WDOG2 to reset board in ldo-bypass mode */ ++ if (wdog_source == 2 && (cpu_is_imx6q() || cpu_is_imx6dl() || ++ cpu_is_imx6sl())) { ++ np = of_find_compatible_node(np, NULL, "fsl,imx21-wdt"); ++ wdog_base = of_iomap(np, 0); ++ WARN_ON(!wdog_base); ++ } ++ ++ wdog_clk = of_clk_get(np, 0); ++ if (IS_ERR(wdog_clk)) { ++ pr_warn("%s: failed to get wdog clock\n", __func__); ++ wdog_clk = NULL; ++ return; ++ } ++ ++ clk_prepare(wdog_clk); ++} ++ ++#ifdef CONFIG_CACHE_L2X0 ++void __init imx_init_l2cache(void) ++{ ++ void __iomem *l2x0_base; ++ struct device_node *np; ++ unsigned int val; ++ ++ np = of_find_compatible_node(NULL, NULL, "arm,pl310-cache"); ++ if (!np) ++ goto out; ++ ++ l2x0_base = of_iomap(np, 0); ++ if (!l2x0_base) { ++ of_node_put(np); ++ goto out; ++ } ++ ++ /* Configure the L2 PREFETCH and POWER registers */ ++ val = readl_relaxed(l2x0_base + L2X0_PREFETCH_CTRL); ++ val |= 0x30000000; ++ /* ++ * The L2 cache controller(PL310) version on the i.MX6D/Q is r3p1-50rel0 ++ * The L2 cache controller(PL310) version on the i.MX6DL/SOLO/SL is r3p2 ++ * But according to ARM PL310 errata: 752271 ++ * ID: 752271: Double linefill feature can cause data corruption ++ * Fault Status: Present in: r3p0, r3p1, r3p1-50rel0. Fixed in r3p2 ++ * Workaround: The only workaround to this erratum is to disable the ++ * double linefill feature. This is the default behavior. ++ */ ++ if (!of_machine_is_compatible("fsl,imx6q")) ++ val |= 0x40800000; ++ writel_relaxed(val, l2x0_base + L2X0_PREFETCH_CTRL); ++ val = L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN; ++ writel_relaxed(val, l2x0_base + L2X0_POWER_CTRL); ++ ++ iounmap(l2x0_base); ++ of_node_put(np); ++ ++out: ++ l2x0_of_init(0, ~0UL); + } ++#endif +diff -Nur linux-3.10.30/arch/arm/mach-imx/time.c linux-3.10.30-cubox-i/arch/arm/mach-imx/time.c +--- linux-3.10.30/arch/arm/mach-imx/time.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-imx/time.c 2014-03-08 20:32:54.000000000 +0100 +@@ -60,7 +60,11 @@ + #define V2_TCTL_WAITEN (1 << 3) /* Wait enable mode */ + #define V2_TCTL_CLK_IPG (1 << 6) + #define V2_TCTL_CLK_PER (2 << 6) ++#define V2_TCTL_CLK_OSC_DIV8 (5 << 6) ++#define V2_TCTL_CLK_OSC (7 << 6) ++#define V2_TCTL_24MEN (1 << 10) + #define V2_TCTL_FRR (1 << 9) ++#define V2_TPRER_PRE24M 12 + #define V2_IR 0x0c + #define V2_TSTAT 0x08 + #define V2_TSTAT_OF1 (1 << 0) +@@ -277,11 +281,20 @@ + + void __init mxc_timer_init(void __iomem *base, int irq) + { +- uint32_t tctl_val; ++ uint32_t tctl_val, tprer_val; + struct clk *timer_clk; + struct clk *timer_ipg_clk; + +- timer_clk = clk_get_sys("imx-gpt.0", "per"); ++ /* ++ * gpt clk source from 24M OSC on imx6q > TO1.0 and ++ * imx6dl, others from per clk. ++ */ ++ if ((cpu_is_imx6q() && imx_get_soc_revision() > IMX_CHIP_REVISION_1_0) ++ || cpu_is_imx6dl()) ++ timer_clk = clk_get_sys("imx-gpt.0", "gpt_3m"); ++ else ++ timer_clk = clk_get_sys("imx-gpt.0", "per"); ++ + if (IS_ERR(timer_clk)) { + pr_err("i.MX timer: unable to get clk\n"); + return; +@@ -302,10 +315,24 @@ + __raw_writel(0, timer_base + MXC_TCTL); + __raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */ + +- if (timer_is_v2()) +- tctl_val = V2_TCTL_CLK_PER | V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN; +- else ++ if (timer_is_v2()) { ++ if ((cpu_is_imx6q() && imx_get_soc_revision() > ++ IMX_CHIP_REVISION_1_0) || cpu_is_imx6dl()) { ++ tctl_val = V2_TCTL_CLK_OSC_DIV8 | V2_TCTL_FRR | ++ V2_TCTL_WAITEN | MXC_TCTL_TEN; ++ if (cpu_is_imx6dl()) { ++ /* 24 / 8 = 3 MHz */ ++ tprer_val = 7 << V2_TPRER_PRE24M; ++ __raw_writel(tprer_val, timer_base + MXC_TPRER); ++ tctl_val |= V2_TCTL_24MEN; ++ } ++ } else { ++ tctl_val = V2_TCTL_CLK_PER | V2_TCTL_FRR | ++ V2_TCTL_WAITEN | MXC_TCTL_TEN; ++ } ++ } else { + tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN; ++ } + + __raw_writel(tctl_val, timer_base + MXC_TCTL); + +diff -Nur linux-3.10.30/arch/arm/mach-integrator/Makefile linux-3.10.30-cubox-i/arch/arm/mach-integrator/Makefile +--- linux-3.10.30/arch/arm/mach-integrator/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-integrator/Makefile 2014-03-08 20:32:54.000000000 +0100 +@@ -8,5 +8,5 @@ + obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o + obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o + +-obj-$(CONFIG_PCI) += pci_v3.o pci.o ++obj-$(CONFIG_PCI) += pci_v3.o + obj-$(CONFIG_INTEGRATOR_IMPD1) += impd1.o +diff -Nur linux-3.10.30/arch/arm/mach-integrator/pci.c linux-3.10.30-cubox-i/arch/arm/mach-integrator/pci.c +--- linux-3.10.30/arch/arm/mach-integrator/pci.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-integrator/pci.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,113 +0,0 @@ +-/* +- * linux/arch/arm/mach-integrator/pci-integrator.c +- * +- * Copyright (C) 1999 ARM Limited +- * Copyright (C) 2000 Deep Blue Solutions Ltd +- * +- * 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 +- * +- * +- * PCI functions for Integrator +- */ +-#include +-#include +-#include +-#include +- +-#include +-#include +- +-#include +- +-/* +- * A small note about bridges and interrupts. The DECchip 21050 (and +- * later) adheres to the PCI-PCI bridge specification. This says that +- * the interrupts on the other side of a bridge are swizzled in the +- * following manner: +- * +- * Dev Interrupt Interrupt +- * Pin on Pin on +- * Device Connector +- * +- * 4 A A +- * B B +- * C C +- * D D +- * +- * 5 A B +- * B C +- * C D +- * D A +- * +- * 6 A C +- * B D +- * C A +- * D B +- * +- * 7 A D +- * B A +- * C B +- * D C +- * +- * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. +- * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 +- */ +- +-/* +- * This routine handles multiple bridges. +- */ +-static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp) +-{ +- if (*pinp == 0) +- *pinp = 1; +- +- return pci_common_swizzle(dev, pinp); +-} +- +-static int irq_tab[4] __initdata = { +- IRQ_AP_PCIINT0, IRQ_AP_PCIINT1, IRQ_AP_PCIINT2, IRQ_AP_PCIINT3 +-}; +- +-/* +- * map the specified device/slot/pin to an IRQ. This works out such +- * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1. +- */ +-static int __init integrator_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +-{ +- int intnr = ((slot - 9) + (pin - 1)) & 3; +- +- return irq_tab[intnr]; +-} +- +-extern void pci_v3_init(void *); +- +-static struct hw_pci integrator_pci __initdata = { +- .swizzle = integrator_swizzle, +- .map_irq = integrator_map_irq, +- .setup = pci_v3_setup, +- .nr_controllers = 1, +- .ops = &pci_v3_ops, +- .preinit = pci_v3_preinit, +- .postinit = pci_v3_postinit, +-}; +- +-static int __init integrator_pci_init(void) +-{ +- if (machine_is_integrator()) +- pci_common_init(&integrator_pci); +- return 0; +-} +- +-subsys_initcall(integrator_pci_init); +diff -Nur linux-3.10.30/arch/arm/mach-integrator/pci_v3.c linux-3.10.30-cubox-i/arch/arm/mach-integrator/pci_v3.c +--- linux-3.10.30/arch/arm/mach-integrator/pci_v3.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-integrator/pci_v3.c 2014-03-08 20:32:54.000000000 +0100 +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + #include + +@@ -337,7 +338,7 @@ + return PCIBIOS_SUCCESSFUL; + } + +-struct pci_ops pci_v3_ops = { ++static struct pci_ops pci_v3_ops = { + .read = v3_read_config, + .write = v3_write_config, + }; +@@ -471,7 +472,7 @@ + return IRQ_HANDLED; + } + +-int __init pci_v3_setup(int nr, struct pci_sys_data *sys) ++static int __init pci_v3_setup(int nr, struct pci_sys_data *sys) + { + int ret = 0; + +@@ -490,7 +491,7 @@ + * V3_LB_BASE? - local bus address + * V3_LB_MAP? - pci bus address + */ +-void __init pci_v3_preinit(void) ++static void __init pci_v3_preinit(void) + { + unsigned long flags; + unsigned int temp; +@@ -589,7 +590,7 @@ + raw_spin_unlock_irqrestore(&v3_lock, flags); + } + +-void __init pci_v3_postinit(void) ++static void __init pci_v3_postinit(void) + { + unsigned int pci_cmd; + +@@ -610,3 +611,82 @@ + + register_isa_ports(PHYS_PCI_MEM_BASE, PHYS_PCI_IO_BASE, 0); + } ++ ++/* ++ * A small note about bridges and interrupts. The DECchip 21050 (and ++ * later) adheres to the PCI-PCI bridge specification. This says that ++ * the interrupts on the other side of a bridge are swizzled in the ++ * following manner: ++ * ++ * Dev Interrupt Interrupt ++ * Pin on Pin on ++ * Device Connector ++ * ++ * 4 A A ++ * B B ++ * C C ++ * D D ++ * ++ * 5 A B ++ * B C ++ * C D ++ * D A ++ * ++ * 6 A C ++ * B D ++ * C A ++ * D B ++ * ++ * 7 A D ++ * B A ++ * C B ++ * D C ++ * ++ * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. ++ * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 ++ */ ++ ++/* ++ * This routine handles multiple bridges. ++ */ ++static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp) ++{ ++ if (*pinp == 0) ++ *pinp = 1; ++ ++ return pci_common_swizzle(dev, pinp); ++} ++ ++static int irq_tab[4] __initdata = { ++ IRQ_AP_PCIINT0, IRQ_AP_PCIINT1, IRQ_AP_PCIINT2, IRQ_AP_PCIINT3 ++}; ++ ++/* ++ * map the specified device/slot/pin to an IRQ. This works out such ++ * that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1. ++ */ ++static int __init integrator_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ int intnr = ((slot - 9) + (pin - 1)) & 3; ++ ++ return irq_tab[intnr]; ++} ++ ++static struct hw_pci integrator_pci __initdata = { ++ .swizzle = integrator_swizzle, ++ .map_irq = integrator_map_irq, ++ .setup = pci_v3_setup, ++ .nr_controllers = 1, ++ .ops = &pci_v3_ops, ++ .preinit = pci_v3_preinit, ++ .postinit = pci_v3_postinit, ++}; ++ ++static int __init integrator_pci_init(void) ++{ ++ if (machine_is_integrator()) ++ pci_common_init(&integrator_pci); ++ return 0; ++} ++ ++subsys_initcall(integrator_pci_init); +diff -Nur linux-3.10.30/arch/arm/mach-vexpress/Kconfig linux-3.10.30-cubox-i/arch/arm/mach-vexpress/Kconfig +--- linux-3.10.30/arch/arm/mach-vexpress/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-vexpress/Kconfig 2014-03-08 20:32:56.000000000 +0100 +@@ -1,5 +1,7 @@ + config ARCH_VEXPRESS + bool "ARM Ltd. Versatile Express family" if ARCH_MULTI_V7 ++ select ARCH_HAS_CPUFREQ ++ select ARCH_HAS_OPP + select ARCH_REQUIRE_GPIOLIB + select ARM_AMBA + select ARM_GIC +@@ -56,5 +58,23 @@ + + config ARCH_VEXPRESS_CA9X4 + bool "Versatile Express Cortex-A9x4 tile" ++ select ARM_ERRATA_643719 ++ ++config ARCH_VEXPRESS_DCSCB ++ bool "Dual Cluster System Control Block (DCSCB) support" ++ depends on MCPM ++ select ARM_CCI ++ help ++ Support for the Dual Cluster System Configuration Block (DCSCB). ++ This is needed to provide CPU and cluster power management ++ on RTSM implementing big.LITTLE. ++ ++config ARCH_VEXPRESS_TC2 ++ bool "TC2 cluster management" ++ depends on MCPM ++ select VEXPRESS_SPC ++ select ARM_CCI ++ help ++ Support for CPU and cluster power management on TC2. + + endmenu +diff -Nur linux-3.10.30/arch/arm/mach-vexpress/Makefile linux-3.10.30-cubox-i/arch/arm/mach-vexpress/Makefile +--- linux-3.10.30/arch/arm/mach-vexpress/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-vexpress/Makefile 2014-03-08 20:32:56.000000000 +0100 +@@ -6,5 +6,13 @@ + + obj-y := v2m.o + obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o ++obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o ++CFLAGS_REMOVE_dcscb.o = -pg ++obj-$(CONFIG_ARCH_VEXPRESS_TC2) += tc2_pm.o tc2_pm_setup.o ++CFLAGS_REMOVE_tc2_pm.o = -pg ++ifeq ($(CONFIG_ARCH_VEXPRESS_TC2),y) ++obj-$(CONFIG_ARM_PSCI) += tc2_pm_psci.o ++CFLAGS_REMOVE_tc2_pm_psci.o = -pg ++endif + obj-$(CONFIG_SMP) += platsmp.o + obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o +diff -Nur linux-3.10.30/arch/arm/mach-vexpress/core.h linux-3.10.30-cubox-i/arch/arm/mach-vexpress/core.h +--- linux-3.10.30/arch/arm/mach-vexpress/core.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-vexpress/core.h 2014-03-08 20:32:56.000000000 +0100 +@@ -6,6 +6,8 @@ + + void vexpress_dt_smp_map_io(void); + ++bool vexpress_smp_init_ops(void); ++ + extern struct smp_operations vexpress_smp_ops; + + extern void vexpress_cpu_die(unsigned int cpu); +diff -Nur linux-3.10.30/arch/arm/mach-vexpress/dcscb.c linux-3.10.30-cubox-i/arch/arm/mach-vexpress/dcscb.c +--- linux-3.10.30/arch/arm/mach-vexpress/dcscb.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-vexpress/dcscb.c 2014-03-08 20:32:56.000000000 +0100 +@@ -0,0 +1,236 @@ ++/* ++ * arch/arm/mach-vexpress/dcscb.c - Dual Cluster System Configuration Block ++ * ++ * Created by: Nicolas Pitre, May 2012 ++ * Copyright: (C) 2012-2013 Linaro Limited ++ * ++ * This program 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 ++ ++ ++#define RST_HOLD0 0x0 ++#define RST_HOLD1 0x4 ++#define SYS_SWRESET 0x8 ++#define RST_STAT0 0xc ++#define RST_STAT1 0x10 ++#define EAG_CFG_R 0x20 ++#define EAG_CFG_W 0x24 ++#define KFC_CFG_R 0x28 ++#define KFC_CFG_W 0x2c ++#define DCS_CFG_R 0x30 ++ ++/* ++ * We can't use regular spinlocks. In the switcher case, it is possible ++ * for an outbound CPU to call power_down() while its inbound counterpart ++ * is already live using the same logical CPU number which trips lockdep ++ * debugging. ++ */ ++static arch_spinlock_t dcscb_lock = __ARCH_SPIN_LOCK_UNLOCKED; ++ ++static void __iomem *dcscb_base; ++static int dcscb_use_count[4][2]; ++static int dcscb_allcpus_mask[2]; ++ ++static int dcscb_power_up(unsigned int cpu, unsigned int cluster) ++{ ++ unsigned int rst_hold, cpumask = (1 << cpu); ++ unsigned int all_mask = dcscb_allcpus_mask[cluster]; ++ ++ pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); ++ if (cpu >= 4 || cluster >= 2) ++ return -EINVAL; ++ ++ /* ++ * Since this is called with IRQs enabled, and no arch_spin_lock_irq ++ * variant exists, we need to disable IRQs manually here. ++ */ ++ local_irq_disable(); ++ arch_spin_lock(&dcscb_lock); ++ ++ dcscb_use_count[cpu][cluster]++; ++ if (dcscb_use_count[cpu][cluster] == 1) { ++ rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); ++ if (rst_hold & (1 << 8)) { ++ /* remove cluster reset and add individual CPU's reset */ ++ rst_hold &= ~(1 << 8); ++ rst_hold |= all_mask; ++ } ++ rst_hold &= ~(cpumask | (cpumask << 4)); ++ writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); ++ } else if (dcscb_use_count[cpu][cluster] != 2) { ++ /* ++ * The only possible values are: ++ * 0 = CPU down ++ * 1 = CPU (still) up ++ * 2 = CPU requested to be up before it had a chance ++ * to actually make itself down. ++ * Any other value is a bug. ++ */ ++ BUG(); ++ } ++ ++ arch_spin_unlock(&dcscb_lock); ++ local_irq_enable(); ++ ++ return 0; ++} ++ ++static void dcscb_power_down(void) ++{ ++ unsigned int mpidr, cpu, cluster, rst_hold, cpumask, all_mask; ++ bool last_man = false, skip_wfi = false; ++ ++ mpidr = read_cpuid_mpidr(); ++ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); ++ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); ++ cpumask = (1 << cpu); ++ all_mask = dcscb_allcpus_mask[cluster]; ++ ++ pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); ++ BUG_ON(cpu >= 4 || cluster >= 2); ++ ++ __mcpm_cpu_going_down(cpu, cluster); ++ ++ arch_spin_lock(&dcscb_lock); ++ BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP); ++ dcscb_use_count[cpu][cluster]--; ++ if (dcscb_use_count[cpu][cluster] == 0) { ++ rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4); ++ rst_hold |= cpumask; ++ if (((rst_hold | (rst_hold >> 4)) & all_mask) == all_mask) { ++ rst_hold |= (1 << 8); ++ last_man = true; ++ } ++ writel_relaxed(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4); ++ } else if (dcscb_use_count[cpu][cluster] == 1) { ++ /* ++ * A power_up request went ahead of us. ++ * Even if we do not want to shut this CPU down, ++ * the caller expects a certain state as if the WFI ++ * was aborted. So let's continue with cache cleaning. ++ */ ++ skip_wfi = true; ++ } else ++ BUG(); ++ ++ if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) { ++ arch_spin_unlock(&dcscb_lock); ++ ++ /* Flush all cache levels for this cluster. */ ++ v7_exit_coherency_flush(all); ++ ++ /* ++ * This is a harmless no-op. On platforms with a real ++ * outer cache this might either be needed or not, ++ * depending on where the outer cache sits. ++ */ ++ outer_flush_all(); ++ ++ /* ++ * Disable cluster-level coherency by masking ++ * incoming snoops and DVM messages: ++ */ ++ cci_disable_port_by_cpu(mpidr); ++ ++ __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN); ++ } else { ++ arch_spin_unlock(&dcscb_lock); ++ ++ /* Disable and flush the local CPU cache. */ ++ v7_exit_coherency_flush(louis); ++ } ++ ++ __mcpm_cpu_down(cpu, cluster); ++ ++ /* Now we are prepared for power-down, do it: */ ++ dsb(); ++ if (!skip_wfi) ++ wfi(); ++ ++ /* Not dead at this point? Let our caller cope. */ ++} ++ ++static const struct mcpm_platform_ops dcscb_power_ops = { ++ .power_up = dcscb_power_up, ++ .power_down = dcscb_power_down, ++}; ++ ++static void __init dcscb_usage_count_init(void) ++{ ++ unsigned int mpidr, cpu, cluster; ++ ++ mpidr = read_cpuid_mpidr(); ++ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); ++ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); ++ ++ pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); ++ BUG_ON(cpu >= 4 || cluster >= 2); ++ dcscb_use_count[cpu][cluster] = 1; ++} ++ ++extern void dcscb_power_up_setup(unsigned int affinity_level); ++ ++static int __init dcscb_init(void) ++{ ++ struct device_node *node; ++ unsigned int cfg; ++ int ret; ++ ++ ret = psci_probe(); ++ if (!ret) { ++ pr_debug("psci found. Aborting native init\n"); ++ return -ENODEV; ++ } ++ ++ if (!cci_probed()) ++ return -ENODEV; ++ ++ node = of_find_compatible_node(NULL, NULL, "arm,rtsm,dcscb"); ++ if (!node) ++ return -ENODEV; ++ dcscb_base = of_iomap(node, 0); ++ if (!dcscb_base) ++ return -EADDRNOTAVAIL; ++ cfg = readl_relaxed(dcscb_base + DCS_CFG_R); ++ dcscb_allcpus_mask[0] = (1 << (((cfg >> 16) >> (0 << 2)) & 0xf)) - 1; ++ dcscb_allcpus_mask[1] = (1 << (((cfg >> 16) >> (1 << 2)) & 0xf)) - 1; ++ dcscb_usage_count_init(); ++ ++ ret = mcpm_platform_register(&dcscb_power_ops); ++ if (!ret) ++ ret = mcpm_sync_init(dcscb_power_up_setup); ++ if (ret) { ++ iounmap(dcscb_base); ++ return ret; ++ } ++ ++ pr_info("VExpress DCSCB support installed\n"); ++ ++ /* ++ * Future entries into the kernel can now go ++ * through the cluster entry vectors. ++ */ ++ vexpress_flags_set(virt_to_phys(mcpm_entry_point)); ++ ++ return 0; ++} ++ ++early_initcall(dcscb_init); +diff -Nur linux-3.10.30/arch/arm/mach-vexpress/dcscb_setup.S linux-3.10.30-cubox-i/arch/arm/mach-vexpress/dcscb_setup.S +--- linux-3.10.30/arch/arm/mach-vexpress/dcscb_setup.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-vexpress/dcscb_setup.S 2014-03-08 20:32:56.000000000 +0100 +@@ -0,0 +1,38 @@ ++/* ++ * arch/arm/include/asm/dcscb_setup.S ++ * ++ * Created by: Dave Martin, 2012-06-22 ++ * Copyright: (C) 2012-2013 Linaro Limited ++ * ++ * This program 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 ++ ++ ++ENTRY(dcscb_power_up_setup) ++ ++ cmp r0, #0 @ check affinity level ++ beq 2f ++ ++/* ++ * Enable cluster-level coherency, in preparation for turning on the MMU. ++ * The ACTLR SMP bit does not need to be set here, because cpu_resume() ++ * already restores that. ++ * ++ * A15/A7 may not require explicit L2 invalidation on reset, dependent ++ * on hardware integration decisions. ++ * For now, this code assumes that L2 is either already invalidated, ++ * or invalidation is not required. ++ */ ++ ++ b cci_enable_port_for_self ++ ++2: @ Implementation-specific local CPU setup operations should go here, ++ @ if any. In this case, there is nothing to do. ++ ++ bx lr ++ ++ENDPROC(dcscb_power_up_setup) +diff -Nur linux-3.10.30/arch/arm/mach-vexpress/include/mach/tc2.h linux-3.10.30-cubox-i/arch/arm/mach-vexpress/include/mach/tc2.h +--- linux-3.10.30/arch/arm/mach-vexpress/include/mach/tc2.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-vexpress/include/mach/tc2.h 2014-03-08 20:32:56.000000000 +0100 +@@ -0,0 +1,10 @@ ++#ifndef __MACH_TC2_H ++#define __MACH_TC2_H ++ ++/* ++ * cpu and cluster limits ++ */ ++#define TC2_MAX_CPUS 3 ++#define TC2_MAX_CLUSTERS 2 ++ ++#endif +diff -Nur linux-3.10.30/arch/arm/mach-vexpress/platsmp.c linux-3.10.30-cubox-i/arch/arm/mach-vexpress/platsmp.c +--- linux-3.10.30/arch/arm/mach-vexpress/platsmp.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-vexpress/platsmp.c 2014-03-08 20:32:56.000000000 +0100 +@@ -12,9 +12,11 @@ + #include + #include + #include ++#include + #include + #include + ++#include + #include + #include + +@@ -203,3 +205,21 @@ + .cpu_die = vexpress_cpu_die, + #endif + }; ++ ++bool __init vexpress_smp_init_ops(void) ++{ ++#ifdef CONFIG_MCPM ++ /* ++ * The best way to detect a multi-cluster configuration at the moment ++ * is to look for the presence of a CCI in the system. ++ * Override the default vexpress_smp_ops if so. ++ */ ++ struct device_node *node; ++ node = of_find_compatible_node(NULL, NULL, "arm,cci-400"); ++ if (node && of_device_is_available(node)) { ++ mcpm_smp_set_ops(); ++ return true; ++ } ++#endif ++ return false; ++} +diff -Nur linux-3.10.30/arch/arm/mach-vexpress/tc2_pm.c linux-3.10.30-cubox-i/arch/arm/mach-vexpress/tc2_pm.c +--- linux-3.10.30/arch/arm/mach-vexpress/tc2_pm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-vexpress/tc2_pm.c 2014-03-08 20:32:56.000000000 +0100 +@@ -0,0 +1,277 @@ ++/* ++ * arch/arm/mach-vexpress/tc2_pm.c - TC2 power management support ++ * ++ * Created by: Nicolas Pitre, October 2012 ++ * Copyright: (C) 2012 Linaro Limited ++ * ++ * Some portions of this file were originally written by Achin Gupta ++ * Copyright: (C) 2012 ARM Limited ++ * ++ * This program 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 ++ ++/* ++ * We can't use regular spinlocks. In the switcher case, it is possible ++ * for an outbound CPU to call power_down() after its inbound counterpart ++ * is already live using the same logical CPU number which trips lockdep ++ * debugging. ++ */ ++static arch_spinlock_t tc2_pm_lock = __ARCH_SPIN_LOCK_UNLOCKED; ++ ++static int tc2_pm_use_count[TC2_MAX_CPUS][TC2_MAX_CLUSTERS]; ++ ++static int tc2_pm_power_up(unsigned int cpu, unsigned int cluster) ++{ ++ pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); ++ if (cluster >= TC2_MAX_CLUSTERS || ++ cpu >= vexpress_spc_get_nb_cpus(cluster)) ++ return -EINVAL; ++ ++ /* ++ * Since this is called with IRQs enabled, and no arch_spin_lock_irq ++ * variant exists, we need to disable IRQs manually here. ++ */ ++ local_irq_disable(); ++ arch_spin_lock(&tc2_pm_lock); ++ ++ if (!tc2_pm_use_count[0][cluster] && ++ !tc2_pm_use_count[1][cluster] && ++ !tc2_pm_use_count[2][cluster]) ++ vexpress_spc_powerdown_enable(cluster, 0); ++ ++ tc2_pm_use_count[cpu][cluster]++; ++ if (tc2_pm_use_count[cpu][cluster] == 1) { ++ vexpress_spc_write_resume_reg(cluster, cpu, ++ virt_to_phys(mcpm_entry_point)); ++ vexpress_spc_set_cpu_wakeup_irq(cpu, cluster, 1); ++ } else if (tc2_pm_use_count[cpu][cluster] != 2) { ++ /* ++ * The only possible values are: ++ * 0 = CPU down ++ * 1 = CPU (still) up ++ * 2 = CPU requested to be up before it had a chance ++ * to actually make itself down. ++ * Any other value is a bug. ++ */ ++ BUG(); ++ } ++ ++ arch_spin_unlock(&tc2_pm_lock); ++ local_irq_enable(); ++ ++ return 0; ++} ++ ++static void tc2_pm_down(u64 residency) ++{ ++ unsigned int mpidr, cpu, cluster; ++ bool last_man = false, skip_wfi = false; ++ ++ mpidr = read_cpuid_mpidr(); ++ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); ++ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); ++ ++ pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); ++ BUG_ON(cluster >= TC2_MAX_CLUSTERS || ++ cpu >= vexpress_spc_get_nb_cpus(cluster)); ++ ++ __mcpm_cpu_going_down(cpu, cluster); ++ ++ arch_spin_lock(&tc2_pm_lock); ++ BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP); ++ tc2_pm_use_count[cpu][cluster]--; ++ if (tc2_pm_use_count[cpu][cluster] == 0) { ++ vexpress_spc_set_cpu_wakeup_irq(cpu, cluster, 1); ++ if (!tc2_pm_use_count[0][cluster] && ++ !tc2_pm_use_count[1][cluster] && ++ !tc2_pm_use_count[2][cluster] && ++ (!residency || residency > 5000)) { ++ vexpress_spc_powerdown_enable(cluster, 1); ++ vexpress_spc_set_global_wakeup_intr(1); ++ last_man = true; ++ } ++ } else if (tc2_pm_use_count[cpu][cluster] == 1) { ++ /* ++ * A power_up request went ahead of us. ++ * Even if we do not want to shut this CPU down, ++ * the caller expects a certain state as if the WFI ++ * was aborted. So let's continue with cache cleaning. ++ */ ++ skip_wfi = true; ++ } else ++ BUG(); ++ ++ /* ++ * If the CPU is committed to power down, make sure ++ * the power controller will be in charge of waking it ++ * up upon IRQ, ie IRQ lines are cut from GIC CPU IF ++ * to the CPU by disabling the GIC CPU IF to prevent wfi ++ * from completing execution behind power controller back ++ */ ++ if (!skip_wfi) ++ gic_cpu_if_down(); ++ ++ if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) { ++ arch_spin_unlock(&tc2_pm_lock); ++ ++ if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A15) { ++ /* ++ * On the Cortex-A15 we need to disable ++ * L2 prefetching before flushing the cache. ++ */ ++ asm volatile( ++ "mcr p15, 1, %0, c15, c0, 3 \n\t" ++ "isb \n\t" ++ "dsb " ++ : : "r" (0x400) ); ++ } ++ ++ v7_exit_coherency_flush(all); ++ ++ cci_disable_port_by_cpu(mpidr); ++ ++ __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN); ++ } else { ++ /* ++ * If last man then undo any setup done previously. ++ */ ++ if (last_man) { ++ vexpress_spc_powerdown_enable(cluster, 0); ++ vexpress_spc_set_global_wakeup_intr(0); ++ } ++ ++ arch_spin_unlock(&tc2_pm_lock); ++ ++ v7_exit_coherency_flush(louis); ++ } ++ ++ __mcpm_cpu_down(cpu, cluster); ++ ++ /* Now we are prepared for power-down, do it: */ ++ if (!skip_wfi) ++ wfi(); ++ ++ /* Not dead at this point? Let our caller cope. */ ++} ++ ++static void tc2_pm_power_down(void) ++{ ++ tc2_pm_down(0); ++} ++ ++static void tc2_pm_suspend(u64 residency) ++{ ++ extern void tc2_resume(void); ++ unsigned int mpidr, cpu, cluster; ++ ++ mpidr = read_cpuid_mpidr(); ++ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); ++ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); ++ vexpress_spc_write_resume_reg(cluster, cpu, ++ virt_to_phys(tc2_resume)); ++ ++ tc2_pm_down(residency); ++} ++ ++static void tc2_pm_powered_up(void) ++{ ++ unsigned int mpidr, cpu, cluster; ++ unsigned long flags; ++ ++ mpidr = read_cpuid_mpidr(); ++ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); ++ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); ++ ++ pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); ++ BUG_ON(cluster >= TC2_MAX_CLUSTERS || ++ cpu >= vexpress_spc_get_nb_cpus(cluster)); ++ ++ local_irq_save(flags); ++ arch_spin_lock(&tc2_pm_lock); ++ ++ if (!tc2_pm_use_count[0][cluster] && ++ !tc2_pm_use_count[1][cluster] && ++ !tc2_pm_use_count[2][cluster]) { ++ vexpress_spc_powerdown_enable(cluster, 0); ++ vexpress_spc_set_global_wakeup_intr(0); ++ } ++ ++ if (!tc2_pm_use_count[cpu][cluster]) ++ tc2_pm_use_count[cpu][cluster] = 1; ++ ++ vexpress_spc_set_cpu_wakeup_irq(cpu, cluster, 0); ++ vexpress_spc_write_resume_reg(cluster, cpu, 0); ++ ++ arch_spin_unlock(&tc2_pm_lock); ++ local_irq_restore(flags); ++} ++ ++static const struct mcpm_platform_ops tc2_pm_power_ops = { ++ .power_up = tc2_pm_power_up, ++ .power_down = tc2_pm_power_down, ++ .suspend = tc2_pm_suspend, ++ .powered_up = tc2_pm_powered_up, ++}; ++ ++static void __init tc2_pm_usage_count_init(void) ++{ ++ unsigned int mpidr, cpu, cluster; ++ ++ mpidr = read_cpuid_mpidr(); ++ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); ++ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); ++ ++ pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); ++ BUG_ON(cluster >= TC2_MAX_CLUSTERS || ++ cpu >= vexpress_spc_get_nb_cpus(cluster)); ++ ++ tc2_pm_use_count[cpu][cluster] = 1; ++} ++ ++extern void tc2_pm_power_up_setup(unsigned int affinity_level); ++ ++static int __init tc2_pm_init(void) ++{ ++ int ret; ++ ++ ret = psci_probe(); ++ if (!ret) { ++ pr_debug("psci found. Aborting native init\n"); ++ return -ENODEV; ++ } ++ ++ if (!vexpress_spc_check_loaded()) ++ return -ENODEV; ++ ++ tc2_pm_usage_count_init(); ++ ++ ret = mcpm_platform_register(&tc2_pm_power_ops); ++ if (!ret) ++ ret = mcpm_sync_init(tc2_pm_power_up_setup); ++ if (!ret) ++ pr_info("TC2 power management initialized\n"); ++ return ret; ++} ++ ++early_initcall(tc2_pm_init); +diff -Nur linux-3.10.30/arch/arm/mach-vexpress/tc2_pm_psci.c linux-3.10.30-cubox-i/arch/arm/mach-vexpress/tc2_pm_psci.c +--- linux-3.10.30/arch/arm/mach-vexpress/tc2_pm_psci.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-vexpress/tc2_pm_psci.c 2014-03-08 20:32:56.000000000 +0100 +@@ -0,0 +1,173 @@ ++/* ++ * arch/arm/mach-vexpress/tc2_pm_psci.c - TC2 PSCI support ++ * ++ * Created by: Achin Gupta, December 2012 ++ * Copyright: (C) 2012 ARM Limited ++ * ++ * Some portions of this file were originally written by Nicolas Pitre ++ * Copyright: (C) 2012 Linaro Limited ++ * ++ * This program 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 ++ ++/* ++ * Platform specific state id understood by the firmware and used to ++ * program the power controller ++ */ ++#define PSCI_POWER_STATE_ID 0 ++ ++static atomic_t tc2_pm_use_count[TC2_MAX_CPUS][TC2_MAX_CLUSTERS]; ++ ++static int tc2_pm_psci_power_up(unsigned int cpu, unsigned int cluster) ++{ ++ unsigned int mpidr = (cluster << 8) | cpu; ++ int ret = 0; ++ ++ BUG_ON(!psci_ops.cpu_on); ++ ++ switch (atomic_inc_return(&tc2_pm_use_count[cpu][cluster])) { ++ case 1: ++ /* ++ * This is a request to power up a cpu that linux thinks has ++ * been powered down. Retries are needed if the firmware has ++ * seen the power down request as yet. ++ */ ++ do ++ ret = psci_ops.cpu_on(mpidr, ++ virt_to_phys(mcpm_entry_point)); ++ while (ret == -EAGAIN); ++ ++ return ret; ++ case 2: ++ /* This power up request has overtaken a power down request */ ++ return ret; ++ default: ++ /* Any other value is a bug */ ++ BUG(); ++ } ++} ++ ++static void tc2_pm_psci_power_down(void) ++{ ++ struct psci_power_state power_state; ++ unsigned int mpidr, cpu, cluster; ++ ++ mpidr = read_cpuid_mpidr(); ++ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); ++ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); ++ ++ BUG_ON(!psci_ops.cpu_off); ++ ++ switch (atomic_dec_return(&tc2_pm_use_count[cpu][cluster])) { ++ case 1: ++ /* ++ * Overtaken by a power up. Flush caches, exit coherency, ++ * return & fake a reset ++ */ ++ set_cr(get_cr() & ~CR_C); ++ ++ flush_cache_louis(); ++ ++ asm volatile ("clrex"); ++ set_auxcr(get_auxcr() & ~(1 << 6)); ++ ++ return; ++ case 0: ++ /* A normal request to possibly power down the cluster */ ++ power_state.id = PSCI_POWER_STATE_ID; ++ power_state.type = PSCI_POWER_STATE_TYPE_POWER_DOWN; ++ power_state.affinity_level = PSCI_POWER_STATE_AFFINITY_LEVEL1; ++ ++ psci_ops.cpu_off(power_state); ++ ++ /* On success this function never returns */ ++ default: ++ /* Any other value is a bug */ ++ BUG(); ++ } ++} ++ ++static void tc2_pm_psci_suspend(u64 unused) ++{ ++ struct psci_power_state power_state; ++ ++ BUG_ON(!psci_ops.cpu_suspend); ++ ++ /* On TC2 always attempt to power down the cluster */ ++ power_state.id = PSCI_POWER_STATE_ID; ++ power_state.type = PSCI_POWER_STATE_TYPE_POWER_DOWN; ++ power_state.affinity_level = PSCI_POWER_STATE_AFFINITY_LEVEL1; ++ ++ psci_ops.cpu_suspend(power_state, virt_to_phys(mcpm_entry_point)); ++ ++ /* On success this function never returns */ ++ BUG(); ++} ++ ++static const struct mcpm_platform_ops tc2_pm_power_ops = { ++ .power_up = tc2_pm_psci_power_up, ++ .power_down = tc2_pm_psci_power_down, ++ .suspend = tc2_pm_psci_suspend, ++}; ++ ++static void __init tc2_pm_usage_count_init(void) ++{ ++ unsigned int mpidr, cpu, cluster; ++ ++ mpidr = read_cpuid_mpidr(); ++ cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); ++ cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); ++ ++ pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); ++ BUG_ON(cluster >= TC2_MAX_CLUSTERS || ++ cpu >= vexpress_spc_get_nb_cpus(cluster)); ++ ++ atomic_set(&tc2_pm_use_count[cpu][cluster], 1); ++} ++ ++static int __init tc2_pm_psci_init(void) ++{ ++ int ret; ++ ++ ret = psci_probe(); ++ if (ret) { ++ pr_debug("psci not found. Aborting psci init\n"); ++ return -ENODEV; ++ } ++ ++ if (!vexpress_spc_check_loaded()) { ++ pr_debug("spc not found. Aborting psci init\n"); ++ return -ENODEV; ++ } ++ ++ tc2_pm_usage_count_init(); ++ ++ ret = mcpm_platform_register(&tc2_pm_power_ops); ++ if (!ret) ++ ret = mcpm_sync_init(NULL); ++ if (!ret) ++ pr_info("TC2 power management initialized\n"); ++ return ret; ++} ++ ++early_initcall(tc2_pm_psci_init); +diff -Nur linux-3.10.30/arch/arm/mach-vexpress/tc2_pm_setup.S linux-3.10.30-cubox-i/arch/arm/mach-vexpress/tc2_pm_setup.S +--- linux-3.10.30/arch/arm/mach-vexpress/tc2_pm_setup.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-vexpress/tc2_pm_setup.S 2014-03-08 20:32:56.000000000 +0100 +@@ -0,0 +1,68 @@ ++/* ++ * arch/arm/include/asm/tc2_pm_setup.S ++ * ++ * Created by: Nicolas Pitre, October 2012 ++ ( (based on dcscb_setup.S by Dave Martin) ++ * Copyright: (C) 2012 Linaro Limited ++ * ++ * This program 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 SPC_PHYS_BASE 0x7FFF0000 ++#define SPC_WAKE_INT_STAT 0xb2c ++ ++#define SNOOP_CTL_A15 0x404 ++#define SNOOP_CTL_A7 0x504 ++ ++#define A15_SNOOP_MASK (0x3 << 7) ++#define A7_SNOOP_MASK (0x1 << 13) ++ ++#define A15_BX_ADDR0 0xB68 ++ ++ ++ENTRY(tc2_resume) ++ mrc p15, 0, r0, c0, c0, 5 ++ ubfx r1, r0, #0, #4 @ r1 = cpu ++ ubfx r2, r0, #8, #4 @ r2 = cluster ++ add r1, r1, r2, lsl #2 @ r1 = index of CPU in WAKE_INT_STAT ++ ldr r3, =SPC_PHYS_BASE + SPC_WAKE_INT_STAT ++ ldr r3, [r3] ++ lsr r3, r1 ++ tst r3, #1 ++ wfieq @ if no pending IRQ reenters wfi ++ b mcpm_entry_point ++ENDPROC(tc2_resume) ++ ++/* ++ * Enable cluster-level coherency, in preparation for turning on the MMU. ++ * The ACTLR SMP bit does not need to be set here, because cpu_resume() ++ * already restores that. ++ */ ++ ++ENTRY(tc2_pm_power_up_setup) ++ ++ cmp r0, #0 ++ beq 2f ++ ++ b cci_enable_port_for_self ++ ++2: @ Clear the BX addr register ++ ldr r3, =SPC_PHYS_BASE + A15_BX_ADDR0 ++ mrc p15, 0, r0, c0, c0, 5 @ MPIDR ++ ubfx r1, r0, #8, #4 @ cluster ++ ubfx r0, r0, #0, #4 @ cpu ++ add r3, r3, r1, lsl #4 ++ mov r1, #0 ++ str r1, [r3, r0, lsl #2] ++ dsb ++ ++ bx lr ++ ++ENDPROC(tc2_pm_power_up_setup) +diff -Nur linux-3.10.30/arch/arm/mach-vexpress/v2m.c linux-3.10.30-cubox-i/arch/arm/mach-vexpress/v2m.c +--- linux-3.10.30/arch/arm/mach-vexpress/v2m.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-vexpress/v2m.c 2014-03-08 20:32:56.000000000 +0100 +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -373,6 +374,31 @@ + .init_machine = v2m_init, + MACHINE_END + ++static void __init v2m_dt_hdlcd_init(void) ++{ ++ struct device_node *node; ++ int len, na, ns; ++ const __be32 *prop; ++ phys_addr_t fb_base, fb_size; ++ ++ node = of_find_compatible_node(NULL, NULL, "arm,hdlcd"); ++ if (!node) ++ return; ++ ++ na = of_n_addr_cells(node); ++ ns = of_n_size_cells(node); ++ ++ prop = of_get_property(node, "framebuffer", &len); ++ if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop))) ++ return; ++ ++ fb_base = of_read_number(prop, na); ++ fb_size = of_read_number(prop + na, ns); ++ ++ if (WARN_ON(memblock_remove(fb_base, fb_size))) ++ return; ++}; ++ + static struct map_desc v2m_rs1_io_desc __initdata = { + .virtual = V2M_PERIPH, + .pfn = __phys_to_pfn(0x1c000000), +@@ -423,6 +449,8 @@ + pr_warning("vexpress: DT HBI (%x) is not matching " + "hardware (%x)!\n", dt_hbi, hbi); + } ++ ++ v2m_dt_hdlcd_init(); + } + + static void __init v2m_dt_timer_init(void) +@@ -456,6 +484,7 @@ + DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express") + .dt_compat = v2m_dt_match, + .smp = smp_ops(vexpress_smp_ops), ++ .smp_init = smp_init_ops(vexpress_smp_init_ops), + .map_io = v2m_dt_map_io, + .init_early = v2m_dt_init_early, + .init_irq = irqchip_init, +diff -Nur linux-3.10.30/arch/arm/mach-virt/Makefile linux-3.10.30-cubox-i/arch/arm/mach-virt/Makefile +--- linux-3.10.30/arch/arm/mach-virt/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-virt/Makefile 2014-03-08 20:32:56.000000000 +0100 +@@ -3,4 +3,3 @@ + # + + obj-y := virt.o +-obj-$(CONFIG_SMP) += platsmp.o +diff -Nur linux-3.10.30/arch/arm/mach-virt/platsmp.c linux-3.10.30-cubox-i/arch/arm/mach-virt/platsmp.c +--- linux-3.10.30/arch/arm/mach-virt/platsmp.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-virt/platsmp.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,50 +0,0 @@ +-/* +- * Dummy Virtual Machine - does what it says on the tin. +- * +- * Copyright (C) 2012 ARM Ltd +- * Author: Will Deacon +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program. If not, see . +- */ +- +-#include +-#include +-#include +- +-#include +-#include +- +-extern void secondary_startup(void); +- +-static void __init virt_smp_init_cpus(void) +-{ +-} +- +-static void __init virt_smp_prepare_cpus(unsigned int max_cpus) +-{ +-} +- +-static int __cpuinit virt_boot_secondary(unsigned int cpu, +- struct task_struct *idle) +-{ +- if (psci_ops.cpu_on) +- return psci_ops.cpu_on(cpu_logical_map(cpu), +- __pa(secondary_startup)); +- return -ENODEV; +-} +- +-struct smp_operations __initdata virt_smp_ops = { +- .smp_init_cpus = virt_smp_init_cpus, +- .smp_prepare_cpus = virt_smp_prepare_cpus, +- .smp_boot_secondary = virt_boot_secondary, +-}; +diff -Nur linux-3.10.30/arch/arm/mach-virt/virt.c linux-3.10.30-cubox-i/arch/arm/mach-virt/virt.c +--- linux-3.10.30/arch/arm/mach-virt/virt.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mach-virt/virt.c 2014-03-08 20:32:56.000000000 +0100 +@@ -36,11 +36,8 @@ + NULL + }; + +-extern struct smp_operations virt_smp_ops; +- + DT_MACHINE_START(VIRT, "Dummy Virtual Machine") + .init_irq = irqchip_init, + .init_machine = virt_init, +- .smp = smp_ops(virt_smp_ops), + .dt_compat = virt_dt_match, + MACHINE_END +diff -Nur linux-3.10.30/arch/arm/mm/cache-v7.S linux-3.10.30-cubox-i/arch/arm/mm/cache-v7.S +--- linux-3.10.30/arch/arm/mm/cache-v7.S 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mm/cache-v7.S 2014-03-08 20:32:56.000000000 +0100 +@@ -146,18 +146,18 @@ + ldr r7, =0x7fff + ands r7, r7, r1, lsr #13 @ extract max number of the index size + loop1: +- mov r9, r4 @ create working copy of max way size ++ mov r9, r7 @ create working copy of max index + loop2: +- ARM( orr r11, r10, r9, lsl r5 ) @ factor way and cache number into r11 +- THUMB( lsl r6, r9, r5 ) ++ ARM( orr r11, r10, r4, lsl r5 ) @ factor way and cache number into r11 ++ THUMB( lsl r6, r4, r5 ) + THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11 +- ARM( orr r11, r11, r7, lsl r2 ) @ factor index number into r11 +- THUMB( lsl r6, r7, r2 ) ++ ARM( orr r11, r11, r9, lsl r2 ) @ factor index number into r11 ++ THUMB( lsl r6, r9, r2 ) + THUMB( orr r11, r11, r6 ) @ factor index number into r11 + mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way +- subs r9, r9, #1 @ decrement the way ++ subs r9, r9, #1 @ decrement the index + bge loop2 +- subs r7, r7, #1 @ decrement the index ++ subs r4, r4, #1 @ decrement the way + bge loop1 + skip: + add r10, r10, #2 @ increment cache number +diff -Nur linux-3.10.30/arch/arm/mm/fault.c linux-3.10.30-cubox-i/arch/arm/mm/fault.c +--- linux-3.10.30/arch/arm/mm/fault.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/mm/fault.c 2014-03-08 20:32:56.000000000 +0100 +@@ -446,8 +446,16 @@ + + if (pud_none(*pud_k)) + goto bad_area; +- if (!pud_present(*pud)) ++ if (!pud_present(*pud)) { + set_pud(pud, *pud_k); ++ /* ++ * There is a small window during free_pgtables() where the ++ * user *pud entry is 0 but the TLB has not been invalidated ++ * and we get a level 2 (pmd) translation fault caused by the ++ * intermediate TLB caching of the old level 1 (pud) entry. ++ */ ++ flush_tlb_kernel_page(addr); ++ } + + pmd = pmd_offset(pud, addr); + pmd_k = pmd_offset(pud_k, addr); +@@ -470,8 +478,9 @@ + #endif + if (pmd_none(pmd_k[index])) + goto bad_area; ++ if (!pmd_present(pmd[index])) ++ copy_pmd(pmd, pmd_k); + +- copy_pmd(pmd, pmd_k); + return 0; + + bad_area: +diff -Nur linux-3.10.30/arch/arm/plat-versatile/headsmp.S linux-3.10.30-cubox-i/arch/arm/plat-versatile/headsmp.S +--- linux-3.10.30/arch/arm/plat-versatile/headsmp.S 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm/plat-versatile/headsmp.S 2014-03-08 20:32:56.000000000 +0100 +@@ -11,8 +11,6 @@ + #include + #include + +- __INIT +- + /* + * Realview/Versatile Express specific entry point for secondary CPUs. + * This provides a "holding pen" into which all secondary cores are held +diff -Nur linux-3.10.30/arch/arm64/Kconfig linux-3.10.30-cubox-i/arch/arm64/Kconfig +--- linux-3.10.30/arch/arm64/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/Kconfig 2014-03-08 20:32:56.000000000 +0100 +@@ -144,12 +144,139 @@ + + If you don't know what to do here, say N. + ++config ARM_CPU_TOPOLOGY ++ bool "Support CPU topology definition" ++ depends on SMP ++ default y ++ help ++ Support CPU topology definition, based on configuration ++ provided by the firmware. ++ ++config SCHED_MC ++ bool "Multi-core scheduler support" ++ depends on ARM_CPU_TOPOLOGY ++ help ++ Multi-core scheduler support improves the CPU scheduler's decision ++ making when dealing with multi-core CPU chips at a cost of slightly ++ increased overhead in some places. If unsure say N here. ++ ++config SCHED_SMT ++ bool "SMT scheduler support" ++ depends on ARM_CPU_TOPOLOGY ++ help ++ Improves the CPU scheduler's decision making when dealing with ++ MultiThreading at a cost of slightly increased overhead in some ++ places. If unsure say N here. ++ ++config DISABLE_CPU_SCHED_DOMAIN_BALANCE ++ bool "(EXPERIMENTAL) Disable CPU level scheduler load-balancing" ++ help ++ Disables scheduler load-balancing at CPU sched domain level. ++ ++config SCHED_HMP ++ bool "(EXPERIMENTAL) Heterogenous multiprocessor scheduling" ++ depends on DISABLE_CPU_SCHED_DOMAIN_BALANCE && SCHED_MC && FAIR_GROUP_SCHED && !SCHED_AUTOGROUP ++ help ++ Experimental scheduler optimizations for heterogeneous platforms. ++ Attempts to introspectively select task affinity to optimize power ++ and performance. Basic support for multiple (>2) cpu types is in place, ++ but it has only been tested with two types of cpus. ++ There is currently no support for migration of task groups, hence ++ !SCHED_AUTOGROUP. Furthermore, normal load-balancing must be disabled ++ between cpus of different type (DISABLE_CPU_SCHED_DOMAIN_BALANCE). ++ ++config SCHED_HMP_PRIO_FILTER ++ bool "(EXPERIMENTAL) Filter HMP migrations by task priority" ++ depends on SCHED_HMP ++ help ++ Enables task priority based HMP migration filter. Any task with ++ a NICE value above the threshold will always be on low-power cpus ++ with less compute capacity. ++ ++config SCHED_HMP_PRIO_FILTER_VAL ++ int "NICE priority threshold" ++ default 5 ++ depends on SCHED_HMP_PRIO_FILTER ++ ++config HMP_FAST_CPU_MASK ++ string "HMP scheduler fast CPU mask" ++ depends on SCHED_HMP ++ help ++ Leave empty to use device tree information. ++ Specify the cpuids of the fast CPUs in the system as a list string, ++ e.g. cpuid 0+1 should be specified as 0-1. ++ ++config HMP_SLOW_CPU_MASK ++ string "HMP scheduler slow CPU mask" ++ depends on SCHED_HMP ++ help ++ Leave empty to use device tree information. ++ Specify the cpuids of the slow CPUs in the system as a list string, ++ e.g. cpuid 0+1 should be specified as 0-1. ++ ++config HMP_VARIABLE_SCALE ++ bool "Allows changing the load tracking scale through sysfs" ++ depends on SCHED_HMP ++ help ++ When turned on, this option exports the thresholds and load average ++ period value for the load tracking patches through sysfs. ++ The values can be modified to change the rate of load accumulation ++ and the thresholds used for HMP migration. ++ The load_avg_period_ms is the time in ms to reach a load average of ++ 0.5 for an idle task of 0 load average ratio that start a busy loop. ++ The up_threshold and down_threshold is the value to go to a faster ++ CPU or to go back to a slower cpu. ++ The {up,down}_threshold are devided by 1024 before being compared ++ to the load average. ++ For examples, with load_avg_period_ms = 128 and up_threshold = 512, ++ a running task with a load of 0 will be migrated to a bigger CPU after ++ 128ms, because after 128ms its load_avg_ratio is 0.5 and the real ++ up_threshold is 0.5. ++ This patch has the same behavior as changing the Y of the load ++ average computation to ++ (1002/1024)^(LOAD_AVG_PERIOD/load_avg_period_ms) ++ but it remove intermadiate overflows in computation. ++ ++config HMP_FREQUENCY_INVARIANT_SCALE ++ bool "(EXPERIMENTAL) Frequency-Invariant Tracked Load for HMP" ++ depends on HMP_VARIABLE_SCALE && CPU_FREQ ++ help ++ Scales the current load contribution in line with the frequency ++ of the CPU that the task was executed on. ++ In this version, we use a simple linear scale derived from the ++ maximum frequency reported by CPUFreq. ++ Restricting tracked load to be scaled by the CPU's frequency ++ represents the consumption of possible compute capacity ++ (rather than consumption of actual instantaneous capacity as ++ normal) and allows the HMP migration's simple threshold ++ migration strategy to interact more predictably with CPUFreq's ++ asynchronous compute capacity changes. ++ ++config SCHED_HMP_LITTLE_PACKING ++ bool "Small task packing for HMP" ++ depends on SCHED_HMP ++ default n ++ help ++ Allows the HMP Scheduler to pack small tasks into CPUs in the ++ smallest HMP domain. ++ Controlled by two sysfs files in sys/kernel/hmp. ++ packing_enable: 1 to enable, 0 to disable packing. Default 1. ++ packing_limit: runqueue load ratio where a RQ is considered ++ to be full. Default is NICE_0_LOAD * 9/8. ++ + config NR_CPUS + int "Maximum number of CPUs (2-32)" + range 2 32 + depends on SMP + default "4" + ++config HOTPLUG_CPU ++ bool "Support for hot-pluggable CPUs" ++ depends on SMP ++ help ++ Say Y here to experiment with turning CPUs off and on. CPUs ++ can be controlled through /sys/devices/system/cpu. ++ + source kernel/Kconfig.preempt + + config HZ +@@ -229,6 +356,14 @@ + + endmenu + ++menu "Power management options" ++ ++source "kernel/power/Kconfig" ++ ++source "drivers/cpufreq/Kconfig" ++ ++endmenu ++ + source "net/Kconfig" + + source "drivers/Kconfig" +diff -Nur linux-3.10.30/arch/arm64/boot/dts/Makefile linux-3.10.30-cubox-i/arch/arm64/boot/dts/Makefile +--- linux-3.10.30/arch/arm64/boot/dts/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/boot/dts/Makefile 2014-03-08 20:32:56.000000000 +0100 +@@ -1,4 +1,5 @@ +-dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb ++dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb \ ++ fvp-base-gicv2-psci.dtb + + targets += dtbs + targets += $(dtb-y) +diff -Nur linux-3.10.30/arch/arm64/boot/dts/fvp-base-gicv2-psci.dts linux-3.10.30-cubox-i/arch/arm64/boot/dts/fvp-base-gicv2-psci.dts +--- linux-3.10.30/arch/arm64/boot/dts/fvp-base-gicv2-psci.dts 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/boot/dts/fvp-base-gicv2-psci.dts 2014-03-08 20:32:56.000000000 +0100 +@@ -0,0 +1,287 @@ ++/* ++ * Copyright (c) 2013, ARM Limited. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * ++ * Redistributions of source code must retain the above copyright notice, this ++ * list of conditions and the following disclaimer. ++ * ++ * Redistributions in binary form must reproduce the above copyright notice, ++ * this list of conditions and the following disclaimer in the documentation ++ * and/or other materials provided with the distribution. ++ * ++ * Neither the name of ARM nor the names of its contributors may be used ++ * to endorse or promote products derived from this software without specific ++ * prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/dts-v1/; ++ ++/memreserve/ 0x80000000 0x00010000; ++ ++/ { ++}; ++ ++/ { ++ model = "FVP Base"; ++ compatible = "arm,vfp-base", "arm,vexpress"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ chosen { }; ++ ++ aliases { ++ serial0 = &v2m_serial0; ++ serial1 = &v2m_serial1; ++ serial2 = &v2m_serial2; ++ serial3 = &v2m_serial3; ++ }; ++ ++ psci { ++ compatible = "arm,psci"; ++ method = "smc"; ++ cpu_suspend = <0xc4000001>; ++ cpu_off = <0x84000002>; ++ cpu_on = <0xc4000003>; ++ }; ++ ++ cpus { ++ #address-cells = <2>; ++ #size-cells = <0>; ++ ++ big0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57", "arm,armv8"; ++ reg = <0x0 0x0>; ++ enable-method = "psci"; ++ clock-frequency = <1000000>; ++ }; ++ big1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57", "arm,armv8"; ++ reg = <0x0 0x1>; ++ enable-method = "psci"; ++ clock-frequency = <1000000>; ++ }; ++ big2: cpu@2 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57", "arm,armv8"; ++ reg = <0x0 0x2>; ++ enable-method = "psci"; ++ clock-frequency = <1000000>; ++ }; ++ big3: cpu@3 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57", "arm,armv8"; ++ reg = <0x0 0x3>; ++ enable-method = "psci"; ++ clock-frequency = <1000000>; ++ }; ++ little0: cpu@100 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53", "arm,armv8"; ++ reg = <0x0 0x100>; ++ enable-method = "psci"; ++ clock-frequency = <1000000>; ++ }; ++ little1: cpu@101 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53", "arm,armv8"; ++ reg = <0x0 0x101>; ++ enable-method = "psci"; ++ clock-frequency = <1000000>; ++ }; ++ little2: cpu@102 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53", "arm,armv8"; ++ reg = <0x0 0x102>; ++ enable-method = "psci"; ++ clock-frequency = <1000000>; ++ }; ++ little3: cpu@103 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53", "arm,armv8"; ++ reg = <0x0 0x103>; ++ enable-method = "psci"; ++ clock-frequency = <1000000>; ++ }; ++ ++ cpu-map { ++ cluster0 { ++ core0 { ++ cpu = <&big0>; ++ }; ++ core1 { ++ cpu = <&big1>; ++ }; ++ core2 { ++ cpu = <&big2>; ++ }; ++ core3 { ++ cpu = <&big3>; ++ }; ++ }; ++ cluster1 { ++ core0 { ++ cpu = <&little0>; ++ }; ++ core1 { ++ cpu = <&little1>; ++ }; ++ core2 { ++ cpu = <&little2>; ++ }; ++ core3 { ++ cpu = <&little3>; ++ }; ++ }; ++ }; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0x00000000 0x80000000 0 0x80000000>, ++ <0x00000008 0x80000000 0 0x80000000>; ++ }; ++ ++ gic: interrupt-controller@2f000000 { ++ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ interrupt-controller; ++ reg = <0x0 0x2f000000 0 0x10000>, ++ <0x0 0x2c000000 0 0x2000>, ++ <0x0 0x2c010000 0 0x2000>, ++ <0x0 0x2c02F000 0 0x2000>; ++ interrupts = <1 9 0xf04>; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = <1 13 0xff01>, ++ <1 14 0xff01>, ++ <1 11 0xff01>, ++ <1 10 0xff01>; ++ clock-frequency = <100000000>; ++ }; ++ ++ timer@2a810000 { ++ compatible = "arm,armv7-timer-mem"; ++ reg = <0x0 0x2a810000 0x0 0x10000>; ++ clock-frequency = <100000000>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ frame@2a820000 { ++ frame-number = <0>; ++ interrupts = <0 25 4>; ++ reg = <0x0 0x2a820000 0x0 0x10000>; ++ }; ++ }; ++ ++ pmu { ++ compatible = "arm,armv8-pmuv3"; ++ interrupts = <0 60 4>, ++ <0 61 4>, ++ <0 62 4>, ++ <0 63 4>; ++ }; ++ ++ smb { ++ compatible = "simple-bus"; ++ ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0 0 0 0x08000000 0x04000000>, ++ <1 0 0 0x14000000 0x04000000>, ++ <2 0 0 0x18000000 0x04000000>, ++ <3 0 0 0x1c000000 0x04000000>, ++ <4 0 0 0x0c000000 0x04000000>, ++ <5 0 0 0x10000000 0x04000000>; ++ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 63>; ++ interrupt-map = <0 0 0 &gic 0 0 4>, ++ <0 0 1 &gic 0 1 4>, ++ <0 0 2 &gic 0 2 4>, ++ <0 0 3 &gic 0 3 4>, ++ <0 0 4 &gic 0 4 4>, ++ <0 0 5 &gic 0 5 4>, ++ <0 0 6 &gic 0 6 4>, ++ <0 0 7 &gic 0 7 4>, ++ <0 0 8 &gic 0 8 4>, ++ <0 0 9 &gic 0 9 4>, ++ <0 0 10 &gic 0 10 4>, ++ <0 0 11 &gic 0 11 4>, ++ <0 0 12 &gic 0 12 4>, ++ <0 0 13 &gic 0 13 4>, ++ <0 0 14 &gic 0 14 4>, ++ <0 0 15 &gic 0 15 4>, ++ <0 0 16 &gic 0 16 4>, ++ <0 0 17 &gic 0 17 4>, ++ <0 0 18 &gic 0 18 4>, ++ <0 0 19 &gic 0 19 4>, ++ <0 0 20 &gic 0 20 4>, ++ <0 0 21 &gic 0 21 4>, ++ <0 0 22 &gic 0 22 4>, ++ <0 0 23 &gic 0 23 4>, ++ <0 0 24 &gic 0 24 4>, ++ <0 0 25 &gic 0 25 4>, ++ <0 0 26 &gic 0 26 4>, ++ <0 0 27 &gic 0 27 4>, ++ <0 0 28 &gic 0 28 4>, ++ <0 0 29 &gic 0 29 4>, ++ <0 0 30 &gic 0 30 4>, ++ <0 0 31 &gic 0 31 4>, ++ <0 0 32 &gic 0 32 4>, ++ <0 0 33 &gic 0 33 4>, ++ <0 0 34 &gic 0 34 4>, ++ <0 0 35 &gic 0 35 4>, ++ <0 0 36 &gic 0 36 4>, ++ <0 0 37 &gic 0 37 4>, ++ <0 0 38 &gic 0 38 4>, ++ <0 0 39 &gic 0 39 4>, ++ <0 0 40 &gic 0 40 4>, ++ <0 0 41 &gic 0 41 4>, ++ <0 0 42 &gic 0 42 4>; ++ ++ /include/ "rtsm_ve-motherboard.dtsi" ++ }; ++ ++ panels { ++ panel@0 { ++ compatible = "panel"; ++ mode = "XVGA"; ++ refresh = <60>; ++ xres = <1024>; ++ yres = <768>; ++ pixclock = <15748>; ++ left_margin = <152>; ++ right_margin = <48>; ++ upper_margin = <23>; ++ lower_margin = <3>; ++ hsync_len = <104>; ++ vsync_len = <4>; ++ sync = <0>; ++ vmode = "FB_VMODE_NONINTERLACED"; ++ tim2 = "TIM2_BCD", "TIM2_IPC"; ++ cntl = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)"; ++ caps = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888"; ++ bpp = <16>; ++ }; ++ }; ++}; +diff -Nur linux-3.10.30/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi linux-3.10.30-cubox-i/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi +--- linux-3.10.30/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi 2014-03-08 20:32:56.000000000 +0100 +@@ -182,6 +182,15 @@ + interrupts = <14>; + clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>; + clock-names = "clcdclk", "apb_pclk"; ++ mode = "XVGA"; ++ use_dma = <0>; ++ framebuffer = <0x18000000 0x00180000>; ++ }; ++ ++ virtio_block@0130000 { ++ compatible = "virtio,mmio"; ++ reg = <0x130000 0x200>; ++ interrupts = <42>; + }; + }; + +diff -Nur linux-3.10.30/arch/arm64/include/asm/cmpxchg.h linux-3.10.30-cubox-i/arch/arm64/include/asm/cmpxchg.h +--- linux-3.10.30/arch/arm64/include/asm/cmpxchg.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/include/asm/cmpxchg.h 2014-03-08 20:32:56.000000000 +0100 +@@ -158,17 +158,23 @@ + return ret; + } + +-#define cmpxchg(ptr,o,n) \ +- ((__typeof__(*(ptr)))__cmpxchg_mb((ptr), \ +- (unsigned long)(o), \ +- (unsigned long)(n), \ +- sizeof(*(ptr)))) ++#define cmpxchg(ptr, o, n) \ ++({ \ ++ __typeof__(*(ptr)) __ret; \ ++ __ret = (__typeof__(*(ptr))) \ ++ __cmpxchg_mb((ptr), (unsigned long)(o), (unsigned long)(n), \ ++ sizeof(*(ptr))); \ ++ __ret; \ ++}) + +-#define cmpxchg_local(ptr,o,n) \ +- ((__typeof__(*(ptr)))__cmpxchg((ptr), \ +- (unsigned long)(o), \ +- (unsigned long)(n), \ +- sizeof(*(ptr)))) ++#define cmpxchg_local(ptr, o, n) \ ++({ \ ++ __typeof__(*(ptr)) __ret; \ ++ __ret = (__typeof__(*(ptr))) \ ++ __cmpxchg((ptr), (unsigned long)(o), \ ++ (unsigned long)(n), sizeof(*(ptr))); \ ++ __ret; \ ++}) + + #define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n)) + #define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n)) +diff -Nur linux-3.10.30/arch/arm64/include/asm/cpu_ops.h linux-3.10.30-cubox-i/arch/arm64/include/asm/cpu_ops.h +--- linux-3.10.30/arch/arm64/include/asm/cpu_ops.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/include/asm/cpu_ops.h 2014-03-08 20:32:56.000000000 +0100 +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (C) 2013 ARM Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++#ifndef __ASM_CPU_OPS_H ++#define __ASM_CPU_OPS_H ++ ++#include ++#include ++ ++struct device_node; ++ ++/** ++ * struct cpu_operations - Callback operations for hotplugging CPUs. ++ * ++ * @name: Name of the property as appears in a devicetree cpu node's ++ * enable-method property. ++ * @cpu_init: Reads any data necessary for a specific enable-method from the ++ * devicetree, for a given cpu node and proposed logical id. ++ * @cpu_prepare: Early one-time preparation step for a cpu. If there is a ++ * mechanism for doing so, tests whether it is possible to boot ++ * the given CPU. ++ * @cpu_boot: Boots a cpu into the kernel. ++ * @cpu_postboot: Optionally, perform any post-boot cleanup or necesary ++ * synchronisation. Called from the cpu being booted. ++ * @cpu_disable: Prepares a cpu to die. May fail for some mechanism-specific ++ * reason, which will cause the hot unplug to be aborted. Called ++ * from the cpu to be killed. ++ * @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the ++ * cpu being killed. ++ */ ++struct cpu_operations { ++ const char *name; ++ int (*cpu_init)(struct device_node *, unsigned int); ++ int (*cpu_prepare)(unsigned int); ++ int (*cpu_boot)(unsigned int); ++ void (*cpu_postboot)(void); ++#ifdef CONFIG_HOTPLUG_CPU ++ int (*cpu_disable)(unsigned int cpu); ++ void (*cpu_die)(unsigned int cpu); ++#endif ++}; ++ ++extern const struct cpu_operations *cpu_ops[NR_CPUS]; ++extern int __init cpu_read_ops(struct device_node *dn, int cpu); ++extern void __init cpu_read_bootcpu_ops(void); ++ ++#endif /* ifndef __ASM_CPU_OPS_H */ +diff -Nur linux-3.10.30/arch/arm64/include/asm/irq.h linux-3.10.30-cubox-i/arch/arm64/include/asm/irq.h +--- linux-3.10.30/arch/arm64/include/asm/irq.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/include/asm/irq.h 2014-03-08 20:32:56.000000000 +0100 +@@ -4,6 +4,7 @@ + #include + + extern void (*handle_arch_irq)(struct pt_regs *); ++extern void migrate_irqs(void); + extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); + + #endif +diff -Nur linux-3.10.30/arch/arm64/include/asm/pgtable-3level-types.h linux-3.10.30-cubox-i/arch/arm64/include/asm/pgtable-3level-types.h +--- linux-3.10.30/arch/arm64/include/asm/pgtable-3level-types.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/include/asm/pgtable-3level-types.h 2014-03-08 20:32:56.000000000 +0100 +@@ -16,6 +16,8 @@ + #ifndef __ASM_PGTABLE_3LEVEL_TYPES_H + #define __ASM_PGTABLE_3LEVEL_TYPES_H + ++#include ++ + typedef u64 pteval_t; + typedef u64 pmdval_t; + typedef u64 pgdval_t; +diff -Nur linux-3.10.30/arch/arm64/include/asm/psci.h linux-3.10.30-cubox-i/arch/arm64/include/asm/psci.h +--- linux-3.10.30/arch/arm64/include/asm/psci.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/include/asm/psci.h 2014-03-08 20:32:56.000000000 +0100 +@@ -14,25 +14,6 @@ + #ifndef __ASM_PSCI_H + #define __ASM_PSCI_H + +-#define PSCI_POWER_STATE_TYPE_STANDBY 0 +-#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 +- +-struct psci_power_state { +- u16 id; +- u8 type; +- u8 affinity_level; +-}; +- +-struct psci_operations { +- int (*cpu_suspend)(struct psci_power_state state, +- unsigned long entry_point); +- int (*cpu_off)(struct psci_power_state state); +- int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); +- int (*migrate)(unsigned long cpuid); +-}; +- +-extern struct psci_operations psci_ops; +- + int psci_init(void); + + #endif /* __ASM_PSCI_H */ +diff -Nur linux-3.10.30/arch/arm64/include/asm/smp.h linux-3.10.30-cubox-i/arch/arm64/include/asm/smp.h +--- linux-3.10.30/arch/arm64/include/asm/smp.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/include/asm/smp.h 2014-03-08 20:32:56.000000000 +0100 +@@ -60,21 +60,14 @@ + void *stack; + }; + extern struct secondary_data secondary_data; +-extern void secondary_holding_pen(void); +-extern volatile unsigned long secondary_holding_pen_release; ++extern void secondary_entry(void); + + extern void arch_send_call_function_single_ipi(int cpu); + extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); + +-struct device_node; ++extern int __cpu_disable(void); + +-struct smp_enable_ops { +- const char *name; +- int (*init_cpu)(struct device_node *, int); +- int (*prepare_cpu)(int); +-}; +- +-extern const struct smp_enable_ops smp_spin_table_ops; +-extern const struct smp_enable_ops smp_psci_ops; ++extern void __cpu_die(unsigned int cpu); ++extern void cpu_die(void); + + #endif /* ifndef __ASM_SMP_H */ +diff -Nur linux-3.10.30/arch/arm64/include/asm/topology.h linux-3.10.30-cubox-i/arch/arm64/include/asm/topology.h +--- linux-3.10.30/arch/arm64/include/asm/topology.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/include/asm/topology.h 2014-03-08 20:32:56.000000000 +0100 +@@ -0,0 +1,73 @@ ++#ifndef _ASM_ARM_TOPOLOGY_H ++#define _ASM_ARM_TOPOLOGY_H ++ ++#ifdef CONFIG_ARM_CPU_TOPOLOGY ++ ++#include ++ ++struct cputopo_arm { ++ int thread_id; ++ int core_id; ++ int socket_id; ++ cpumask_t thread_sibling; ++ cpumask_t core_sibling; ++}; ++ ++extern struct cputopo_arm cpu_topology[NR_CPUS]; ++ ++#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id) ++#define topology_core_id(cpu) (cpu_topology[cpu].core_id) ++#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling) ++#define topology_thread_cpumask(cpu) (&cpu_topology[cpu].thread_sibling) ++ ++#define mc_capable() (cpu_topology[0].socket_id != -1) ++#define smt_capable() (cpu_topology[0].thread_id != -1) ++ ++void init_cpu_topology(void); ++void store_cpu_topology(unsigned int cpuid); ++const struct cpumask *cpu_coregroup_mask(int cpu); ++int cluster_to_logical_mask(unsigned int socket_id, cpumask_t *cluster_mask); ++ ++#ifdef CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE ++/* Common values for CPUs */ ++#ifndef SD_CPU_INIT ++#define SD_CPU_INIT (struct sched_domain) { \ ++ .min_interval = 1, \ ++ .max_interval = 4, \ ++ .busy_factor = 64, \ ++ .imbalance_pct = 125, \ ++ .cache_nice_tries = 1, \ ++ .busy_idx = 2, \ ++ .idle_idx = 1, \ ++ .newidle_idx = 0, \ ++ .wake_idx = 0, \ ++ .forkexec_idx = 0, \ ++ \ ++ .flags = 0*SD_LOAD_BALANCE \ ++ | 1*SD_BALANCE_NEWIDLE \ ++ | 1*SD_BALANCE_EXEC \ ++ | 1*SD_BALANCE_FORK \ ++ | 0*SD_BALANCE_WAKE \ ++ | 1*SD_WAKE_AFFINE \ ++ | 0*SD_SHARE_CPUPOWER \ ++ | 0*SD_SHARE_PKG_RESOURCES \ ++ | 0*SD_SERIALIZE \ ++ , \ ++ .last_balance = jiffies, \ ++ .balance_interval = 1, \ ++} ++#endif ++#endif /* CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE */ ++ ++#else ++ ++static inline void init_cpu_topology(void) { } ++static inline void store_cpu_topology(unsigned int cpuid) { } ++static inline int cluster_to_logical_mask(unsigned int socket_id, ++ cpumask_t *cluster_mask) { return -EINVAL; } ++ ++#endif ++ ++#include ++ ++#endif /* _ASM_ARM_TOPOLOGY_H */ +diff -Nur linux-3.10.30/arch/arm64/kernel/Makefile linux-3.10.30-cubox-i/arch/arm64/kernel/Makefile +--- linux-3.10.30/arch/arm64/kernel/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/Makefile 2014-03-08 20:32:56.000000000 +0100 +@@ -9,15 +9,16 @@ + arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ + entry-fpsimd.o process.o ptrace.o setup.o signal.o \ + sys.o stacktrace.o time.o traps.o io.o vdso.o \ +- hyp-stub.o psci.o ++ hyp-stub.o psci.o cpu_ops.o + + arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ + sys_compat.o + arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o +-arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o smp_psci.o ++arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o + arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o + arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o + arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o ++arm64-obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o + + obj-y += $(arm64-obj-y) vdso/ + obj-m += $(arm64-obj-m) +diff -Nur linux-3.10.30/arch/arm64/kernel/cpu_ops.c linux-3.10.30-cubox-i/arch/arm64/kernel/cpu_ops.c +--- linux-3.10.30/arch/arm64/kernel/cpu_ops.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/cpu_ops.c 2014-03-08 20:32:56.000000000 +0100 +@@ -0,0 +1,99 @@ ++/* ++ * CPU kernel entry/exit control ++ * ++ * Copyright (C) 2013 ARM Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++extern const struct cpu_operations smp_spin_table_ops; ++extern const struct cpu_operations cpu_psci_ops; ++ ++const struct cpu_operations *cpu_ops[NR_CPUS]; ++ ++static const struct cpu_operations *supported_cpu_ops[] __initconst = { ++#ifdef CONFIG_SMP ++ &smp_spin_table_ops, ++ &cpu_psci_ops, ++#endif ++ NULL, ++}; ++ ++static const struct cpu_operations * __init cpu_get_ops(const char *name) ++{ ++ const struct cpu_operations **ops = supported_cpu_ops; ++ ++ while (*ops) { ++ if (!strcmp(name, (*ops)->name)) ++ return *ops; ++ ++ ops++; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Read a cpu's enable method from the device tree and record it in cpu_ops. ++ */ ++int __init cpu_read_ops(struct device_node *dn, int cpu) ++{ ++ const char *enable_method = of_get_property(dn, "enable-method", NULL); ++ if (!enable_method) { ++ /* ++ * The boot CPU may not have an enable method (e.g. when ++ * spin-table is used for secondaries). Don't warn spuriously. ++ */ ++ if (cpu != 0) ++ pr_err("%s: missing enable-method property\n", ++ dn->full_name); ++ return -ENOENT; ++ } ++ ++ cpu_ops[cpu] = cpu_get_ops(enable_method); ++ if (!cpu_ops[cpu]) { ++ pr_warn("%s: unsupported enable-method property: %s\n", ++ dn->full_name, enable_method); ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++void __init cpu_read_bootcpu_ops(void) ++{ ++ struct device_node *dn = NULL; ++ u64 mpidr = cpu_logical_map(0); ++ ++ while ((dn = of_find_node_by_type(dn, "cpu"))) { ++ u64 hwid; ++ const __be32 *prop; ++ ++ prop = of_get_property(dn, "reg", NULL); ++ if (!prop) ++ continue; ++ ++ hwid = of_read_number(prop, of_n_addr_cells(dn)); ++ if (hwid == mpidr) { ++ cpu_read_ops(dn, 0); ++ of_node_put(dn); ++ return; ++ } ++ } ++} +diff -Nur linux-3.10.30/arch/arm64/kernel/cputable.c linux-3.10.30-cubox-i/arch/arm64/kernel/cputable.c +--- linux-3.10.30/arch/arm64/kernel/cputable.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/cputable.c 2014-03-08 20:32:56.000000000 +0100 +@@ -22,7 +22,7 @@ + + extern unsigned long __cpu_setup(void); + +-struct cpu_info __initdata cpu_table[] = { ++struct cpu_info cpu_table[] = { + { + .cpu_id_val = 0x000f0000, + .cpu_id_mask = 0x000f0000, +diff -Nur linux-3.10.30/arch/arm64/kernel/head.S linux-3.10.30-cubox-i/arch/arm64/kernel/head.S +--- linux-3.10.30/arch/arm64/kernel/head.S 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/head.S 2014-03-08 20:32:56.000000000 +0100 +@@ -217,7 +217,6 @@ + .quad PAGE_OFFSET + + #ifdef CONFIG_SMP +- .pushsection .smp.pen.text, "ax" + .align 3 + 1: .quad . + .quad secondary_holding_pen_release +@@ -242,7 +241,16 @@ + wfe + b pen + ENDPROC(secondary_holding_pen) +- .popsection ++ ++ /* ++ * Secondary entry point that jumps straight into the kernel. Only to ++ * be used where CPUs are brought online dynamically by the kernel. ++ */ ++ENTRY(secondary_entry) ++ bl __calc_phys_offset // x2=phys offset ++ bl el2_setup // Drop to EL1 ++ b secondary_startup ++ENDPROC(secondary_entry) + + ENTRY(secondary_startup) + /* +diff -Nur linux-3.10.30/arch/arm64/kernel/irq.c linux-3.10.30-cubox-i/arch/arm64/kernel/irq.c +--- linux-3.10.30/arch/arm64/kernel/irq.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/irq.c 2014-03-08 20:32:56.000000000 +0100 +@@ -81,3 +81,64 @@ + if (!handle_arch_irq) + panic("No interrupt controller found."); + } ++ ++#ifdef CONFIG_HOTPLUG_CPU ++static bool migrate_one_irq(struct irq_desc *desc) ++{ ++ struct irq_data *d = irq_desc_get_irq_data(desc); ++ const struct cpumask *affinity = d->affinity; ++ struct irq_chip *c; ++ bool ret = false; ++ ++ /* ++ * If this is a per-CPU interrupt, or the affinity does not ++ * include this CPU, then we have nothing to do. ++ */ ++ if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity)) ++ return false; ++ ++ if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { ++ affinity = cpu_online_mask; ++ ret = true; ++ } ++ ++ c = irq_data_get_irq_chip(d); ++ if (!c->irq_set_affinity) ++ pr_debug("IRQ%u: unable to set affinity\n", d->irq); ++ else if (c->irq_set_affinity(d, affinity, true) == IRQ_SET_MASK_OK && ret) ++ cpumask_copy(d->affinity, affinity); ++ ++ return ret; ++} ++ ++/* ++ * The current CPU has been marked offline. Migrate IRQs off this CPU. ++ * If the affinity settings do not allow other CPUs, force them onto any ++ * available CPU. ++ * ++ * Note: we must iterate over all IRQs, whether they have an attached ++ * action structure or not, as we need to get chained interrupts too. ++ */ ++void migrate_irqs(void) ++{ ++ unsigned int i; ++ struct irq_desc *desc; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ for_each_irq_desc(i, desc) { ++ bool affinity_broken; ++ ++ raw_spin_lock(&desc->lock); ++ affinity_broken = migrate_one_irq(desc); ++ raw_spin_unlock(&desc->lock); ++ ++ if (affinity_broken) ++ pr_warn_ratelimited("IRQ%u no longer affine to CPU%u\n", ++ i, smp_processor_id()); ++ } ++ ++ local_irq_restore(flags); ++} ++#endif /* CONFIG_HOTPLUG_CPU */ +diff -Nur linux-3.10.30/arch/arm64/kernel/process.c linux-3.10.30-cubox-i/arch/arm64/kernel/process.c +--- linux-3.10.30/arch/arm64/kernel/process.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/process.c 2014-03-08 20:32:56.000000000 +0100 +@@ -102,6 +102,13 @@ + local_irq_enable(); + } + ++#ifdef CONFIG_HOTPLUG_CPU ++void arch_cpu_idle_dead(void) ++{ ++ cpu_die(); ++} ++#endif ++ + void machine_shutdown(void) + { + #ifdef CONFIG_SMP +diff -Nur linux-3.10.30/arch/arm64/kernel/psci.c linux-3.10.30-cubox-i/arch/arm64/kernel/psci.c +--- linux-3.10.30/arch/arm64/kernel/psci.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/psci.c 2014-03-08 20:32:56.000000000 +0100 +@@ -17,12 +17,32 @@ + + #include + #include ++#include + + #include ++#include + #include + #include ++#include + +-struct psci_operations psci_ops; ++#define PSCI_POWER_STATE_TYPE_STANDBY 0 ++#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 ++ ++struct psci_power_state { ++ u16 id; ++ u8 type; ++ u8 affinity_level; ++}; ++ ++struct psci_operations { ++ int (*cpu_suspend)(struct psci_power_state state, ++ unsigned long entry_point); ++ int (*cpu_off)(struct psci_power_state state); ++ int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); ++ int (*migrate)(unsigned long cpuid); ++}; ++ ++static struct psci_operations psci_ops; + + static int (*invoke_psci_fn)(u64, u64, u64, u64); + +@@ -209,3 +229,68 @@ + of_node_put(np); + return err; + } ++ ++#ifdef CONFIG_SMP ++ ++static int __init cpu_psci_cpu_init(struct device_node *dn, unsigned int cpu) ++{ ++ return 0; ++} ++ ++static int __init cpu_psci_cpu_prepare(unsigned int cpu) ++{ ++ if (!psci_ops.cpu_on) { ++ pr_err("no cpu_on method, not booting CPU%d\n", cpu); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int cpu_psci_cpu_boot(unsigned int cpu) ++{ ++ int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_entry)); ++ if (err) ++ pr_err("psci: failed to boot CPU%d (%d)\n", cpu, err); ++ ++ return err; ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++static int cpu_psci_cpu_disable(unsigned int cpu) ++{ ++ /* Fail early if we don't have CPU_OFF support */ ++ if (!psci_ops.cpu_off) ++ return -EOPNOTSUPP; ++ return 0; ++} ++ ++static void cpu_psci_cpu_die(unsigned int cpu) ++{ ++ int ret; ++ /* ++ * There are no known implementations of PSCI actually using the ++ * power state field, pass a sensible default for now. ++ */ ++ struct psci_power_state state = { ++ .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, ++ }; ++ ++ ret = psci_ops.cpu_off(state); ++ ++ pr_crit("psci: unable to power off CPU%u (%d)\n", cpu, ret); ++} ++#endif ++ ++const struct cpu_operations cpu_psci_ops = { ++ .name = "psci", ++ .cpu_init = cpu_psci_cpu_init, ++ .cpu_prepare = cpu_psci_cpu_prepare, ++ .cpu_boot = cpu_psci_cpu_boot, ++#ifdef CONFIG_HOTPLUG_CPU ++ .cpu_disable = cpu_psci_cpu_disable, ++ .cpu_die = cpu_psci_cpu_die, ++#endif ++}; ++ ++#endif +diff -Nur linux-3.10.30/arch/arm64/kernel/setup.c linux-3.10.30-cubox-i/arch/arm64/kernel/setup.c +--- linux-3.10.30/arch/arm64/kernel/setup.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/setup.c 2014-03-08 20:32:56.000000000 +0100 +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -97,6 +98,11 @@ + printk("%s", buf); + } + ++bool arch_match_cpu_phys_id(int cpu, u64 phys_id) ++{ ++ return phys_id == cpu_logical_map(cpu); ++} ++ + static void __init setup_processor(void) + { + struct cpu_info *cpu_info; +@@ -269,6 +275,7 @@ + psci_init(); + + cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; ++ cpu_read_bootcpu_ops(); + #ifdef CONFIG_SMP + smp_init_cpus(); + #endif +diff -Nur linux-3.10.30/arch/arm64/kernel/smp.c linux-3.10.30-cubox-i/arch/arm64/kernel/smp.c +--- linux-3.10.30/arch/arm64/kernel/smp.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/smp.c 2014-03-08 20:32:56.000000000 +0100 +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -48,13 +49,15 @@ + #include + #include + ++#define CREATE_TRACE_POINTS ++#include ++ + /* + * as from 2.5, kernels no longer have an init_tasks structure + * so we need some other way of telling a new secondary core + * where to place its SVC stack + */ + struct secondary_data secondary_data; +-volatile unsigned long secondary_holding_pen_release = INVALID_HWID; + + enum ipi_msg_type { + IPI_RESCHEDULE, +@@ -63,61 +66,16 @@ + IPI_CPU_STOP, + }; + +-static DEFINE_RAW_SPINLOCK(boot_lock); +- +-/* +- * Write secondary_holding_pen_release in a way that is guaranteed to be +- * visible to all observers, irrespective of whether they're taking part +- * in coherency or not. This is necessary for the hotplug code to work +- * reliably. +- */ +-static void __cpuinit write_pen_release(u64 val) +-{ +- void *start = (void *)&secondary_holding_pen_release; +- unsigned long size = sizeof(secondary_holding_pen_release); +- +- secondary_holding_pen_release = val; +- __flush_dcache_area(start, size); +-} +- + /* + * Boot a secondary CPU, and assign it the specified idle task. + * This also gives us the initial stack to use for this CPU. + */ + static int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) + { +- unsigned long timeout; ++ if (cpu_ops[cpu]->cpu_boot) ++ return cpu_ops[cpu]->cpu_boot(cpu); + +- /* +- * Set synchronisation state between this boot processor +- * and the secondary one +- */ +- raw_spin_lock(&boot_lock); +- +- /* +- * Update the pen release flag. +- */ +- write_pen_release(cpu_logical_map(cpu)); +- +- /* +- * Send an event, causing the secondaries to read pen_release. +- */ +- sev(); +- +- timeout = jiffies + (1 * HZ); +- while (time_before(jiffies, timeout)) { +- if (secondary_holding_pen_release == INVALID_HWID) +- break; +- udelay(10); +- } +- +- /* +- * Now the secondary core is starting up let it run its +- * calibrations, then wait for it to finish +- */ +- raw_spin_unlock(&boot_lock); +- +- return secondary_holding_pen_release != INVALID_HWID ? -ENOSYS : 0; ++ return -EOPNOTSUPP; + } + + static DECLARE_COMPLETION(cpu_running); +@@ -158,6 +116,11 @@ + return ret; + } + ++static void __cpuinit smp_store_cpu_info(unsigned int cpuid) ++{ ++ store_cpu_topology(cpuid); ++} ++ + /* + * This is the secondary CPU boot entry. We're using this CPUs + * idle thread stack, but a set of temporary page tables. +@@ -187,17 +150,15 @@ + preempt_disable(); + trace_hardirqs_off(); + +- /* +- * Let the primary processor know we're out of the +- * pen, then head off into the C entry point +- */ +- write_pen_release(INVALID_HWID); ++ if (cpu_ops[cpu]->cpu_postboot) ++ cpu_ops[cpu]->cpu_postboot(); ++ ++ smp_store_cpu_info(cpu); + + /* +- * Synchronise with the boot thread. ++ * Enable GIC and timers. + */ +- raw_spin_lock(&boot_lock); +- raw_spin_unlock(&boot_lock); ++ notify_cpu_starting(cpu); + + /* + * OK, now it's safe to let the boot CPU continue. Wait for +@@ -207,11 +168,6 @@ + set_cpu_online(cpu, true); + complete(&cpu_running); + +- /* +- * Enable GIC and timers. +- */ +- notify_cpu_starting(cpu); +- + local_irq_enable(); + local_fiq_enable(); + +@@ -221,43 +177,117 @@ + cpu_startup_entry(CPUHP_ONLINE); + } + +-void __init smp_cpus_done(unsigned int max_cpus) ++#ifdef CONFIG_HOTPLUG_CPU ++static int op_cpu_disable(unsigned int cpu) + { +- unsigned long bogosum = loops_per_jiffy * num_online_cpus(); ++ /* ++ * If we don't have a cpu_die method, abort before we reach the point ++ * of no return. CPU0 may not have an cpu_ops, so test for it. ++ */ ++ if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_die) ++ return -EOPNOTSUPP; + +- pr_info("SMP: Total of %d processors activated (%lu.%02lu BogoMIPS).\n", +- num_online_cpus(), bogosum / (500000/HZ), +- (bogosum / (5000/HZ)) % 100); ++ /* ++ * We may need to abort a hot unplug for some other mechanism-specific ++ * reason. ++ */ ++ if (cpu_ops[cpu]->cpu_disable) ++ return cpu_ops[cpu]->cpu_disable(cpu); ++ ++ return 0; + } + +-void __init smp_prepare_boot_cpu(void) ++/* ++ * __cpu_disable runs on the processor to be shutdown. ++ */ ++int __cpu_disable(void) + { +-} ++ unsigned int cpu = smp_processor_id(); ++ int ret; + +-static void (*smp_cross_call)(const struct cpumask *, unsigned int); ++ ret = op_cpu_disable(cpu); ++ if (ret) ++ return ret; + +-static const struct smp_enable_ops *enable_ops[] __initconst = { +- &smp_spin_table_ops, +- &smp_psci_ops, +- NULL, +-}; ++ /* ++ * Take this CPU offline. Once we clear this, we can't return, ++ * and we must not schedule until we're ready to give up the cpu. ++ */ ++ set_cpu_online(cpu, false); + +-static const struct smp_enable_ops *smp_enable_ops[NR_CPUS]; ++ /* ++ * OK - migrate IRQs away from this CPU ++ */ ++ migrate_irqs(); + +-static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name) +-{ +- const struct smp_enable_ops **ops = enable_ops; ++ /* ++ * Remove this CPU from the vm mask set of all processes. ++ */ ++ clear_tasks_mm_cpumask(cpu); ++ ++ return 0; ++} + +- while (*ops) { +- if (!strcmp(name, (*ops)->name)) +- return *ops; ++static DECLARE_COMPLETION(cpu_died); + +- ops++; ++/* ++ * called on the thread which is asking for a CPU to be shutdown - ++ * waits until shutdown has completed, or it is timed out. ++ */ ++void __cpu_die(unsigned int cpu) ++{ ++ if (!wait_for_completion_timeout(&cpu_died, msecs_to_jiffies(5000))) { ++ pr_crit("CPU%u: cpu didn't die\n", cpu); ++ return; + } ++ pr_notice("CPU%u: shutdown\n", cpu); ++} ++ ++/* ++ * Called from the idle thread for the CPU which has been shutdown. ++ * ++ * Note that we disable IRQs here, but do not re-enable them ++ * before returning to the caller. This is also the behaviour ++ * of the other hotplug-cpu capable cores, so presumably coming ++ * out of idle fixes this. ++ */ ++void cpu_die(void) ++{ ++ unsigned int cpu = smp_processor_id(); + +- return NULL; ++ idle_task_exit(); ++ ++ local_irq_disable(); ++ ++ /* Tell __cpu_die() that this CPU is now safe to dispose of */ ++ complete(&cpu_died); ++ ++ /* ++ * Actually shutdown the CPU. This must never fail. The specific hotplug ++ * mechanism must perform all required cache maintenance to ensure that ++ * no dirty lines are lost in the process of shutting down the CPU. ++ */ ++ cpu_ops[cpu]->cpu_die(cpu); ++ ++ BUG(); ++} ++#endif ++ ++void __init smp_cpus_done(unsigned int max_cpus) ++{ ++ unsigned long bogosum = loops_per_jiffy * num_online_cpus(); ++ ++ pr_info("SMP: Total of %d processors activated (%lu.%02lu BogoMIPS).\n", ++ num_online_cpus(), bogosum / (500000/HZ), ++ (bogosum / (5000/HZ)) % 100); ++} ++ ++void __init smp_prepare_boot_cpu(void) ++{ + } + ++static void (*smp_cross_call)(const struct cpumask *, unsigned int); ++ + /* + * Enumerate the possible CPU set from the device tree and build the + * cpu logical map array containing MPIDR values related to logical +@@ -265,9 +295,8 @@ + */ + void __init smp_init_cpus(void) + { +- const char *enable_method; + struct device_node *dn = NULL; +- int i, cpu = 1; ++ unsigned int i, cpu = 1; + bool bootcpu_valid = false; + + while ((dn = of_find_node_by_type(dn, "cpu"))) { +@@ -336,25 +365,10 @@ + if (cpu >= NR_CPUS) + goto next; + +- /* +- * We currently support only the "spin-table" enable-method. +- */ +- enable_method = of_get_property(dn, "enable-method", NULL); +- if (!enable_method) { +- pr_err("%s: missing enable-method property\n", +- dn->full_name); ++ if (cpu_read_ops(dn, cpu) != 0) + goto next; +- } +- +- smp_enable_ops[cpu] = smp_get_enable_ops(enable_method); + +- if (!smp_enable_ops[cpu]) { +- pr_err("%s: invalid enable-method property: %s\n", +- dn->full_name, enable_method); +- goto next; +- } +- +- if (smp_enable_ops[cpu]->init_cpu(dn, cpu)) ++ if (cpu_ops[cpu]->cpu_init(dn, cpu)) + goto next; + + pr_debug("cpu logical map 0x%llx\n", hwid); +@@ -384,8 +398,13 @@ + + void __init smp_prepare_cpus(unsigned int max_cpus) + { +- int cpu, err; +- unsigned int ncores = num_possible_cpus(); ++ int err; ++ unsigned int cpu, ncores = num_possible_cpus(); ++ ++ init_cpu_topology(); ++ ++ smp_store_cpu_info(smp_processor_id()); ++ + + /* + * are we trying to boot more cores than exist? +@@ -412,10 +431,10 @@ + if (cpu == smp_processor_id()) + continue; + +- if (!smp_enable_ops[cpu]) ++ if (!cpu_ops[cpu]) + continue; + +- err = smp_enable_ops[cpu]->prepare_cpu(cpu); ++ err = cpu_ops[cpu]->cpu_prepare(cpu); + if (err) + continue; + +diff -Nur linux-3.10.30/arch/arm64/kernel/smp_psci.c linux-3.10.30-cubox-i/arch/arm64/kernel/smp_psci.c +--- linux-3.10.30/arch/arm64/kernel/smp_psci.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/smp_psci.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,53 +0,0 @@ +-/* +- * PSCI SMP initialisation +- * +- * Copyright (C) 2013 ARM Ltd. +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program. If not, see . +- */ +- +-#include +-#include +-#include +- +-#include +-#include +- +-static int __init smp_psci_init_cpu(struct device_node *dn, int cpu) +-{ +- return 0; +-} +- +-static int __init smp_psci_prepare_cpu(int cpu) +-{ +- int err; +- +- if (!psci_ops.cpu_on) { +- pr_err("psci: no cpu_on method, not booting CPU%d\n", cpu); +- return -ENODEV; +- } +- +- err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_holding_pen)); +- if (err) { +- pr_err("psci: failed to boot CPU%d (%d)\n", cpu, err); +- return err; +- } +- +- return 0; +-} +- +-const struct smp_enable_ops smp_psci_ops __initconst = { +- .name = "psci", +- .init_cpu = smp_psci_init_cpu, +- .prepare_cpu = smp_psci_prepare_cpu, +-}; +diff -Nur linux-3.10.30/arch/arm64/kernel/smp_spin_table.c linux-3.10.30-cubox-i/arch/arm64/kernel/smp_spin_table.c +--- linux-3.10.30/arch/arm64/kernel/smp_spin_table.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/smp_spin_table.c 2014-03-08 20:32:56.000000000 +0100 +@@ -16,15 +16,39 @@ + * along with this program. If not, see . + */ + ++#include + #include + #include + #include + + #include ++#include ++#include ++#include ++ ++extern void secondary_holding_pen(void); ++volatile unsigned long secondary_holding_pen_release = INVALID_HWID; + + static phys_addr_t cpu_release_addr[NR_CPUS]; ++static DEFINE_RAW_SPINLOCK(boot_lock); + +-static int __init smp_spin_table_init_cpu(struct device_node *dn, int cpu) ++/* ++ * Write secondary_holding_pen_release in a way that is guaranteed to be ++ * visible to all observers, irrespective of whether they're taking part ++ * in coherency or not. This is necessary for the hotplug code to work ++ * reliably. ++ */ ++static void write_pen_release(u64 val) ++{ ++ void *start = (void *)&secondary_holding_pen_release; ++ unsigned long size = sizeof(secondary_holding_pen_release); ++ ++ secondary_holding_pen_release = val; ++ __flush_dcache_area(start, size); ++} ++ ++ ++static int smp_spin_table_cpu_init(struct device_node *dn, unsigned int cpu) + { + /* + * Determine the address from which the CPU is polling. +@@ -40,7 +64,7 @@ + return 0; + } + +-static int __init smp_spin_table_prepare_cpu(int cpu) ++static int smp_spin_table_cpu_prepare(unsigned int cpu) + { + void **release_addr; + +@@ -59,8 +83,60 @@ + return 0; + } + +-const struct smp_enable_ops smp_spin_table_ops __initconst = { ++static int smp_spin_table_cpu_boot(unsigned int cpu) ++{ ++ unsigned long timeout; ++ ++ /* ++ * Set synchronisation state between this boot processor ++ * and the secondary one ++ */ ++ raw_spin_lock(&boot_lock); ++ ++ /* ++ * Update the pen release flag. ++ */ ++ write_pen_release(cpu_logical_map(cpu)); ++ ++ /* ++ * Send an event, causing the secondaries to read pen_release. ++ */ ++ sev(); ++ ++ timeout = jiffies + (1 * HZ); ++ while (time_before(jiffies, timeout)) { ++ if (secondary_holding_pen_release == INVALID_HWID) ++ break; ++ udelay(10); ++ } ++ ++ /* ++ * Now the secondary core is starting up let it run its ++ * calibrations, then wait for it to finish ++ */ ++ raw_spin_unlock(&boot_lock); ++ ++ return secondary_holding_pen_release != INVALID_HWID ? -ENOSYS : 0; ++} ++ ++void smp_spin_table_cpu_postboot(void) ++{ ++ /* ++ * Let the primary processor know we're out of the pen. ++ */ ++ write_pen_release(INVALID_HWID); ++ ++ /* ++ * Synchronise with the boot thread. ++ */ ++ raw_spin_lock(&boot_lock); ++ raw_spin_unlock(&boot_lock); ++} ++ ++const struct cpu_operations smp_spin_table_ops = { + .name = "spin-table", +- .init_cpu = smp_spin_table_init_cpu, +- .prepare_cpu = smp_spin_table_prepare_cpu, ++ .cpu_init = smp_spin_table_cpu_init, ++ .cpu_prepare = smp_spin_table_cpu_prepare, ++ .cpu_boot = smp_spin_table_cpu_boot, ++ .cpu_postboot = smp_spin_table_cpu_postboot, + }; +diff -Nur linux-3.10.30/arch/arm64/kernel/topology.c linux-3.10.30-cubox-i/arch/arm64/kernel/topology.c +--- linux-3.10.30/arch/arm64/kernel/topology.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/topology.c 2014-03-08 20:32:56.000000000 +0100 +@@ -0,0 +1,537 @@ ++/* ++ * arch/arm64/kernel/topology.c ++ * ++ * Copyright (C) 2011,2013 Linaro Limited. ++ * Written by: Vincent Guittot ++ * ++ * based on arch/sh/kernel/topology.c ++ * ++ * 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* ++ * cpu power scale management ++ */ ++ ++/* ++ * cpu power table ++ * This per cpu data structure describes the relative capacity of each core. ++ * On a heteregenous system, cores don't have the same computation capacity ++ * and we reflect that difference in the cpu_power field so the scheduler can ++ * take this difference into account during load balance. A per cpu structure ++ * is preferred because each CPU updates its own cpu_power field during the ++ * load balance except for idle cores. One idle core is selected to run the ++ * rebalance_domains for all idle cores and the cpu_power can be updated ++ * during this sequence. ++ */ ++static DEFINE_PER_CPU(unsigned long, cpu_scale); ++ ++unsigned long arch_scale_freq_power(struct sched_domain *sd, int cpu) ++{ ++ return per_cpu(cpu_scale, cpu); ++} ++ ++static void set_power_scale(unsigned int cpu, unsigned long power) ++{ ++ per_cpu(cpu_scale, cpu) = power; ++} ++ ++#ifdef CONFIG_OF ++struct cpu_efficiency { ++ const char *compatible; ++ unsigned long efficiency; ++}; ++ ++/* ++ * Table of relative efficiency of each processors ++ * The efficiency value must fit in 20bit and the final ++ * cpu_scale value must be in the range ++ * 0 < cpu_scale < 3*SCHED_POWER_SCALE/2 ++ * in order to return at most 1 when DIV_ROUND_CLOSEST ++ * is used to compute the capacity of a CPU. ++ * Processors that are not defined in the table, ++ * use the default SCHED_POWER_SCALE value for cpu_scale. ++ */ ++static const struct cpu_efficiency table_efficiency[] = { ++ { "arm,cortex-a57", 3891 }, ++ { "arm,cortex-a53", 2048 }, ++ { NULL, }, ++}; ++ ++static unsigned long *__cpu_capacity; ++#define cpu_capacity(cpu) __cpu_capacity[cpu] ++ ++static unsigned long middle_capacity = 1; ++static int cluster_id; ++ ++static int __init get_cpu_for_node(struct device_node *node) ++{ ++ struct device_node *cpu_node; ++ int cpu; ++ ++ cpu_node = of_parse_phandle(node, "cpu", 0); ++ if (!cpu_node) { ++ pr_crit("%s: Unable to parse CPU phandle\n", node->full_name); ++ return -1; ++ } ++ ++ for_each_possible_cpu(cpu) { ++ if (of_get_cpu_node(cpu, NULL) == cpu_node) ++ return cpu; ++ } ++ ++ pr_crit("Unable to find CPU node for %s\n", cpu_node->full_name); ++ return -1; ++} ++ ++static void __init parse_core(struct device_node *core, int core_id) ++{ ++ char name[10]; ++ bool leaf = true; ++ int i, cpu; ++ struct device_node *t; ++ ++ i = 0; ++ do { ++ snprintf(name, sizeof(name), "thread%d", i); ++ t = of_get_child_by_name(core, name); ++ if (t) { ++ leaf = false; ++ cpu = get_cpu_for_node(t); ++ if (cpu) { ++ pr_info("CPU%d: socket %d core %d thread %d\n", ++ cpu, cluster_id, core_id, i); ++ cpu_topology[cpu].socket_id = cluster_id; ++ cpu_topology[cpu].core_id = core_id; ++ cpu_topology[cpu].thread_id = i; ++ } else { ++ pr_err("%s: Can't get CPU for thread\n", ++ t->full_name); ++ } ++ } ++ i++; ++ } while (t); ++ ++ cpu = get_cpu_for_node(core); ++ if (cpu >= 0) { ++ if (!leaf) { ++ pr_err("%s: Core has both threads and CPU\n", ++ core->full_name); ++ return; ++ } ++ ++ pr_info("CPU%d: socket %d core %d\n", ++ cpu, cluster_id, core_id); ++ cpu_topology[cpu].socket_id = cluster_id; ++ cpu_topology[cpu].core_id = core_id; ++ } else if (leaf) { ++ pr_err("%s: Can't get CPU for leaf core\n", core->full_name); ++ } ++} ++ ++static void __init parse_cluster(struct device_node *cluster) ++{ ++ char name[10]; ++ bool leaf = true; ++ bool has_cores = false; ++ struct device_node *c; ++ int core_id = 0; ++ int i; ++ ++ /* ++ * First check for child clusters; we currently ignore any ++ * information about the nesting of clusters and present the ++ * scheduler with a flat list of them. ++ */ ++ i = 0; ++ do { ++ snprintf(name, sizeof(name), "cluster%d", i); ++ c = of_get_child_by_name(cluster, name); ++ if (c) { ++ parse_cluster(c); ++ leaf = false; ++ } ++ i++; ++ } while (c); ++ ++ /* Now check for cores */ ++ i = 0; ++ do { ++ snprintf(name, sizeof(name), "core%d", i); ++ c = of_get_child_by_name(cluster, name); ++ if (c) { ++ has_cores = true; ++ ++ if (leaf) ++ parse_core(c, core_id++); ++ else ++ pr_err("%s: Non-leaf cluster with core %s\n", ++ cluster->full_name, name); ++ } ++ i++; ++ } while (c); ++ ++ if (leaf && !has_cores) ++ pr_warn("%s: empty cluster\n", cluster->full_name); ++ ++ if (leaf) ++ cluster_id++; ++} ++ ++/* ++ * Iterate all CPUs' descriptor in DT and compute the efficiency ++ * (as per table_efficiency). Also calculate a middle efficiency ++ * as close as possible to (max{eff_i} - min{eff_i}) / 2 ++ * This is later used to scale the cpu_power field such that an ++ * 'average' CPU is of middle power. Also see the comments near ++ * table_efficiency[] and update_cpu_power(). ++ */ ++static void __init parse_dt_topology(void) ++{ ++ const struct cpu_efficiency *cpu_eff; ++ struct device_node *cn = NULL; ++ unsigned long min_capacity = (unsigned long)(-1); ++ unsigned long max_capacity = 0; ++ unsigned long capacity = 0; ++ int alloc_size, cpu; ++ ++ alloc_size = nr_cpu_ids * sizeof(*__cpu_capacity); ++ __cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT); ++ ++ cn = of_find_node_by_path("/cpus"); ++ if (!cn) { ++ pr_err("No CPU information found in DT\n"); ++ return; ++ } ++ ++ /* ++ * If topology is provided as a cpu-map it is essentially a ++ * root cluster. ++ */ ++ cn = of_find_node_by_name(cn, "cpu-map"); ++ if (!cn) ++ return; ++ parse_cluster(cn); ++ ++ for_each_possible_cpu(cpu) { ++ const u32 *rate; ++ int len; ++ ++ /* Too early to use cpu->of_node */ ++ cn = of_get_cpu_node(cpu, NULL); ++ if (!cn) { ++ pr_err("Missing device node for CPU %d\n", cpu); ++ continue; ++ } ++ ++ /* check if the cpu is marked as "disabled", if so ignore */ ++ if (!of_device_is_available(cn)) ++ continue; ++ ++ for (cpu_eff = table_efficiency; cpu_eff->compatible; cpu_eff++) ++ if (of_device_is_compatible(cn, cpu_eff->compatible)) ++ break; ++ ++ if (cpu_eff->compatible == NULL) { ++ pr_warn("%s: Unknown CPU type\n", cn->full_name); ++ continue; ++ } ++ ++ rate = of_get_property(cn, "clock-frequency", &len); ++ if (!rate || len != 4) { ++ pr_err("%s: Missing clock-frequency property\n", ++ cn->full_name); ++ continue; ++ } ++ ++ capacity = ((be32_to_cpup(rate)) >> 20) * cpu_eff->efficiency; ++ ++ /* Save min capacity of the system */ ++ if (capacity < min_capacity) ++ min_capacity = capacity; ++ ++ /* Save max capacity of the system */ ++ if (capacity > max_capacity) ++ max_capacity = capacity; ++ ++ cpu_capacity(cpu) = capacity; ++ } ++ ++ /* If min and max capacities are equal we bypass the update of the ++ * cpu_scale because all CPUs have the same capacity. Otherwise, we ++ * compute a middle_capacity factor that will ensure that the capacity ++ * of an 'average' CPU of the system will be as close as possible to ++ * SCHED_POWER_SCALE, which is the default value, but with the ++ * constraint explained near table_efficiency[]. ++ */ ++ if (min_capacity == max_capacity) ++ return; ++ else if (4 * max_capacity < (3 * (max_capacity + min_capacity))) ++ middle_capacity = (min_capacity + max_capacity) ++ >> (SCHED_POWER_SHIFT+1); ++ else ++ middle_capacity = ((max_capacity / 3) ++ >> (SCHED_POWER_SHIFT-1)) + 1; ++ ++} ++ ++/* ++ * Look for a customed capacity of a CPU in the cpu_topo_data table during the ++ * boot. The update of all CPUs is in O(n^2) for heteregeneous system but the ++ * function returns directly for SMP system. ++ */ ++static void update_cpu_power(unsigned int cpu) ++{ ++ if (!cpu_capacity(cpu)) ++ return; ++ ++ set_power_scale(cpu, cpu_capacity(cpu) / middle_capacity); ++ ++ pr_info("CPU%u: update cpu_power %lu\n", ++ cpu, arch_scale_freq_power(NULL, cpu)); ++} ++ ++#else ++static inline void parse_dt_topology(void) {} ++static inline void update_cpu_power(unsigned int cpuid) {} ++#endif ++ ++/* ++ * cpu topology table ++ */ ++struct cputopo_arm cpu_topology[NR_CPUS]; ++EXPORT_SYMBOL_GPL(cpu_topology); ++ ++const struct cpumask *cpu_coregroup_mask(int cpu) ++{ ++ return &cpu_topology[cpu].core_sibling; ++} ++ ++static void update_siblings_masks(unsigned int cpuid) ++{ ++ struct cputopo_arm *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; ++ int cpu; ++ ++ /* update core and thread sibling masks */ ++ for_each_possible_cpu(cpu) { ++ cpu_topo = &cpu_topology[cpu]; ++ ++ if (cpuid_topo->socket_id != cpu_topo->socket_id) ++ continue; ++ ++ cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); ++ if (cpu != cpuid) ++ cpumask_set_cpu(cpu, &cpuid_topo->core_sibling); ++ ++ if (cpuid_topo->core_id != cpu_topo->core_id) ++ continue; ++ ++ cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling); ++ if (cpu != cpuid) ++ cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling); ++ } ++ smp_wmb(); ++} ++ ++void store_cpu_topology(unsigned int cpuid) ++{ ++ struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid]; ++ ++ /* DT should have been parsed by the time we get here */ ++ if (cpuid_topo->core_id == -1) ++ pr_info("CPU%u: No topology information configured\n", cpuid); ++ else ++ update_siblings_masks(cpuid); ++ ++ update_cpu_power(cpuid); ++} ++ ++#ifdef CONFIG_SCHED_HMP ++ ++/* ++ * Retrieve logical cpu index corresponding to a given MPIDR[23:0] ++ * - mpidr: MPIDR[23:0] to be used for the look-up ++ * ++ * Returns the cpu logical index or -EINVAL on look-up error ++ */ ++static inline int get_logical_index(u32 mpidr) ++{ ++ int cpu; ++ for (cpu = 0; cpu < nr_cpu_ids; cpu++) ++ if (cpu_logical_map(cpu) == mpidr) ++ return cpu; ++ return -EINVAL; ++} ++ ++static const char * const little_cores[] = { ++ "arm,cortex-a53", ++ NULL, ++}; ++ ++static bool is_little_cpu(struct device_node *cn) ++{ ++ const char * const *lc; ++ for (lc = little_cores; *lc; lc++) ++ if (of_device_is_compatible(cn, *lc)) ++ return true; ++ return false; ++} ++ ++void __init arch_get_fast_and_slow_cpus(struct cpumask *fast, ++ struct cpumask *slow) ++{ ++ struct device_node *cn = NULL; ++ int cpu; ++ ++ cpumask_clear(fast); ++ cpumask_clear(slow); ++ ++ /* ++ * Use the config options if they are given. This helps testing ++ * HMP scheduling on systems without a big.LITTLE architecture. ++ */ ++ if (strlen(CONFIG_HMP_FAST_CPU_MASK) && strlen(CONFIG_HMP_SLOW_CPU_MASK)) { ++ if (cpulist_parse(CONFIG_HMP_FAST_CPU_MASK, fast)) ++ WARN(1, "Failed to parse HMP fast cpu mask!\n"); ++ if (cpulist_parse(CONFIG_HMP_SLOW_CPU_MASK, slow)) ++ WARN(1, "Failed to parse HMP slow cpu mask!\n"); ++ return; ++ } ++ ++ /* ++ * Else, parse device tree for little cores. ++ */ ++ while ((cn = of_find_node_by_type(cn, "cpu"))) { ++ ++ const u32 *mpidr; ++ int len; ++ ++ mpidr = of_get_property(cn, "reg", &len); ++ if (!mpidr || len != 8) { ++ pr_err("%s missing reg property\n", cn->full_name); ++ continue; ++ } ++ ++ cpu = get_logical_index(be32_to_cpup(mpidr+1)); ++ if (cpu == -EINVAL) { ++ pr_err("couldn't get logical index for mpidr %x\n", ++ be32_to_cpup(mpidr+1)); ++ break; ++ } ++ ++ if (is_little_cpu(cn)) ++ cpumask_set_cpu(cpu, slow); ++ else ++ cpumask_set_cpu(cpu, fast); ++ } ++ ++ if (!cpumask_empty(fast) && !cpumask_empty(slow)) ++ return; ++ ++ /* ++ * We didn't find both big and little cores so let's call all cores ++ * fast as this will keep the system running, with all cores being ++ * treated equal. ++ */ ++ cpumask_setall(fast); ++ cpumask_clear(slow); ++} ++ ++struct cpumask hmp_slow_cpu_mask; ++ ++void __init arch_get_hmp_domains(struct list_head *hmp_domains_list) ++{ ++ struct cpumask hmp_fast_cpu_mask; ++ struct hmp_domain *domain; ++ ++ arch_get_fast_and_slow_cpus(&hmp_fast_cpu_mask, &hmp_slow_cpu_mask); ++ ++ /* ++ * Initialize hmp_domains ++ * Must be ordered with respect to compute capacity. ++ * Fastest domain at head of list. ++ */ ++ if(!cpumask_empty(&hmp_slow_cpu_mask)) { ++ domain = (struct hmp_domain *) ++ kmalloc(sizeof(struct hmp_domain), GFP_KERNEL); ++ cpumask_copy(&domain->possible_cpus, &hmp_slow_cpu_mask); ++ cpumask_and(&domain->cpus, cpu_online_mask, &domain->possible_cpus); ++ list_add(&domain->hmp_domains, hmp_domains_list); ++ } ++ domain = (struct hmp_domain *) ++ kmalloc(sizeof(struct hmp_domain), GFP_KERNEL); ++ cpumask_copy(&domain->possible_cpus, &hmp_fast_cpu_mask); ++ cpumask_and(&domain->cpus, cpu_online_mask, &domain->possible_cpus); ++ list_add(&domain->hmp_domains, hmp_domains_list); ++} ++#endif /* CONFIG_SCHED_HMP */ ++ ++/* ++ * cluster_to_logical_mask - return cpu logical mask of CPUs in a cluster ++ * @socket_id: cluster HW identifier ++ * @cluster_mask: the cpumask location to be initialized, modified by the ++ * function only if return value == 0 ++ * ++ * Return: ++ * ++ * 0 on success ++ * -EINVAL if cluster_mask is NULL or there is no record matching socket_id ++ */ ++int cluster_to_logical_mask(unsigned int socket_id, cpumask_t *cluster_mask) ++{ ++ int cpu; ++ ++ if (!cluster_mask) ++ return -EINVAL; ++ ++ for_each_online_cpu(cpu) { ++ if (socket_id == topology_physical_package_id(cpu)) { ++ cpumask_copy(cluster_mask, topology_core_cpumask(cpu)); ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++/* ++ * init_cpu_topology is called at boot when only one cpu is running ++ * which prevent simultaneous write access to cpu_topology array ++ */ ++void __init init_cpu_topology(void) ++{ ++ unsigned int cpu; ++ ++ /* init core mask and power*/ ++ for_each_possible_cpu(cpu) { ++ struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]); ++ ++ cpu_topo->thread_id = -1; ++ cpu_topo->core_id = -1; ++ cpu_topo->socket_id = -1; ++ cpumask_clear(&cpu_topo->core_sibling); ++ cpumask_clear(&cpu_topo->thread_sibling); ++ ++ set_power_scale(cpu, SCHED_POWER_SCALE); ++ } ++ smp_wmb(); ++ ++ parse_dt_topology(); ++} +diff -Nur linux-3.10.30/arch/arm64/kernel/vmlinux.lds.S linux-3.10.30-cubox-i/arch/arm64/kernel/vmlinux.lds.S +--- linux-3.10.30/arch/arm64/kernel/vmlinux.lds.S 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/arm64/kernel/vmlinux.lds.S 2014-03-08 20:32:56.000000000 +0100 +@@ -41,7 +41,6 @@ + } + .text : { /* Real text segment */ + _stext = .; /* Text and read-only data */ +- *(.smp.pen.text) + __exception_text_start = .; + *(.exception.text) + __exception_text_end = .; +diff -Nur linux-3.10.30/arch/mips/include/asm/pci.h linux-3.10.30-cubox-i/arch/mips/include/asm/pci.h +--- linux-3.10.30/arch/mips/include/asm/pci.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/mips/include/asm/pci.h 2014-03-08 20:33:02.000000000 +0100 +@@ -137,11 +137,6 @@ + return channel ? 15 : 14; + } + +-#ifdef CONFIG_CPU_CAVIUM_OCTEON +-/* MSI arch hook for OCTEON */ +-#define arch_setup_msi_irqs arch_setup_msi_irqs +-#endif +- + extern char * (*pcibios_plat_setup)(char *str); + + #ifdef CONFIG_OF +diff -Nur linux-3.10.30/arch/powerpc/include/asm/pci.h linux-3.10.30-cubox-i/arch/powerpc/include/asm/pci.h +--- linux-3.10.30/arch/powerpc/include/asm/pci.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/powerpc/include/asm/pci.h 2014-03-08 20:33:09.000000000 +0100 +@@ -113,11 +113,6 @@ + /* Decide whether to display the domain number in /proc */ + extern int pci_proc_domain(struct pci_bus *bus); + +-/* MSI arch hooks */ +-#define arch_setup_msi_irqs arch_setup_msi_irqs +-#define arch_teardown_msi_irqs arch_teardown_msi_irqs +-#define arch_msi_check_device arch_msi_check_device +- + struct vm_area_struct; + /* Map a range of PCI memory or I/O space for a device into user space */ + int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma, +diff -Nur linux-3.10.30/arch/powerpc/include/asm/prom.h linux-3.10.30-cubox-i/arch/powerpc/include/asm/prom.h +--- linux-3.10.30/arch/powerpc/include/asm/prom.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/powerpc/include/asm/prom.h 2014-03-08 20:33:09.000000000 +0100 +@@ -43,9 +43,6 @@ + + extern void kdump_move_device_tree(void); + +-/* CPU OF node matching */ +-struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); +- + /* cache lookup */ + struct device_node *of_find_next_cache_node(struct device_node *np); + +diff -Nur linux-3.10.30/arch/powerpc/kernel/prom.c linux-3.10.30-cubox-i/arch/powerpc/kernel/prom.c +--- linux-3.10.30/arch/powerpc/kernel/prom.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/powerpc/kernel/prom.c 2014-03-08 20:33:10.000000000 +0100 +@@ -827,49 +827,10 @@ + __initcall(prom_reconfig_setup); + #endif + +-/* Find the device node for a given logical cpu number, also returns the cpu +- * local thread number (index in ibm,interrupt-server#s) if relevant and +- * asked for (non NULL) +- */ +-struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) ++bool arch_match_cpu_phys_id(int cpu, u64 phys_id) + { +- int hardid; +- struct device_node *np; +- +- hardid = get_hard_smp_processor_id(cpu); +- +- for_each_node_by_type(np, "cpu") { +- const u32 *intserv; +- unsigned int plen, t; +- +- /* Check for ibm,ppc-interrupt-server#s. If it doesn't exist +- * fallback to "reg" property and assume no threads +- */ +- intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", +- &plen); +- if (intserv == NULL) { +- const u32 *reg = of_get_property(np, "reg", NULL); +- if (reg == NULL) +- continue; +- if (*reg == hardid) { +- if (thread) +- *thread = 0; +- return np; +- } +- } else { +- plen /= sizeof(u32); +- for (t = 0; t < plen; t++) { +- if (hardid == intserv[t]) { +- if (thread) +- *thread = t; +- return np; +- } +- } +- } +- } +- return NULL; ++ return (int)phys_id == get_hard_smp_processor_id(cpu); + } +-EXPORT_SYMBOL(of_get_cpu_node); + + #if defined(CONFIG_DEBUG_FS) && defined(DEBUG) + static struct debugfs_blob_wrapper flat_dt_blob; +diff -Nur linux-3.10.30/arch/s390/include/asm/pci.h linux-3.10.30-cubox-i/arch/s390/include/asm/pci.h +--- linux-3.10.30/arch/s390/include/asm/pci.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/s390/include/asm/pci.h 2014-03-08 20:33:12.000000000 +0100 +@@ -21,10 +21,6 @@ + int pci_domain_nr(struct pci_bus *); + int pci_proc_domain(struct pci_bus *); + +-/* MSI arch hooks */ +-#define arch_setup_msi_irqs arch_setup_msi_irqs +-#define arch_teardown_msi_irqs arch_teardown_msi_irqs +- + #define ZPCI_BUS_NR 0 /* default bus number */ + #define ZPCI_DEVFN 0 /* default device number */ + +diff -Nur linux-3.10.30/arch/x86/include/asm/pci.h linux-3.10.30-cubox-i/arch/x86/include/asm/pci.h +--- linux-3.10.30/arch/x86/include/asm/pci.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/x86/include/asm/pci.h 2014-03-08 20:33:20.000000000 +0100 +@@ -100,29 +100,6 @@ + extern void pci_iommu_alloc(void); + + #ifdef CONFIG_PCI_MSI +-/* MSI arch specific hooks */ +-static inline int x86_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +-{ +- return x86_msi.setup_msi_irqs(dev, nvec, type); +-} +- +-static inline void x86_teardown_msi_irqs(struct pci_dev *dev) +-{ +- x86_msi.teardown_msi_irqs(dev); +-} +- +-static inline void x86_teardown_msi_irq(unsigned int irq) +-{ +- x86_msi.teardown_msi_irq(irq); +-} +-static inline void x86_restore_msi_irqs(struct pci_dev *dev, int irq) +-{ +- x86_msi.restore_msi_irqs(dev, irq); +-} +-#define arch_setup_msi_irqs x86_setup_msi_irqs +-#define arch_teardown_msi_irqs x86_teardown_msi_irqs +-#define arch_teardown_msi_irq x86_teardown_msi_irq +-#define arch_restore_msi_irqs x86_restore_msi_irqs + /* implemented in arch/x86/kernel/apic/io_apic. */ + struct msi_desc; + int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); +@@ -130,16 +107,9 @@ + void native_restore_msi_irqs(struct pci_dev *dev, int irq); + int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, + unsigned int irq_base, unsigned int irq_offset); +-/* default to the implementation in drivers/lib/msi.c */ +-#define HAVE_DEFAULT_MSI_TEARDOWN_IRQS +-#define HAVE_DEFAULT_MSI_RESTORE_IRQS +-void default_teardown_msi_irqs(struct pci_dev *dev); +-void default_restore_msi_irqs(struct pci_dev *dev, int irq); + #else + #define native_setup_msi_irqs NULL + #define native_teardown_msi_irq NULL +-#define default_teardown_msi_irqs NULL +-#define default_restore_msi_irqs NULL + #endif + + #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys) +diff -Nur linux-3.10.30/arch/x86/kernel/x86_init.c linux-3.10.30-cubox-i/arch/x86/kernel/x86_init.c +--- linux-3.10.30/arch/x86/kernel/x86_init.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/arch/x86/kernel/x86_init.c 2014-03-08 20:33:22.000000000 +0100 +@@ -107,6 +107,8 @@ + }; + + EXPORT_SYMBOL_GPL(x86_platform); ++ ++#if defined(CONFIG_PCI_MSI) + struct x86_msi_ops x86_msi = { + .setup_msi_irqs = native_setup_msi_irqs, + .compose_msi_msg = native_compose_msi_msg, +@@ -116,6 +118,28 @@ + .setup_hpet_msi = default_setup_hpet_msi, + }; + ++/* MSI arch specific hooks */ ++int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ++{ ++ return x86_msi.setup_msi_irqs(dev, nvec, type); ++} ++ ++void arch_teardown_msi_irqs(struct pci_dev *dev) ++{ ++ x86_msi.teardown_msi_irqs(dev); ++} ++ ++void arch_teardown_msi_irq(unsigned int irq) ++{ ++ x86_msi.teardown_msi_irq(irq); ++} ++ ++void arch_restore_msi_irqs(struct pci_dev *dev, int irq) ++{ ++ x86_msi.restore_msi_irqs(dev, irq); ++} ++#endif ++ + struct x86_io_apic_ops x86_io_apic_ops = { + .init = native_io_apic_init_mappings, + .read = native_io_apic_read, +diff -Nur linux-3.10.30/block/blk-core.c linux-3.10.30-cubox-i/block/blk-core.c +--- linux-3.10.30/block/blk-core.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/block/blk-core.c 2014-03-08 20:33:23.000000000 +0100 +@@ -3191,7 +3191,8 @@ + + /* used for unplugging and affects IO latency/throughput - HIGHPRI */ + kblockd_workqueue = alloc_workqueue("kblockd", +- WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); ++ WQ_MEM_RECLAIM | WQ_HIGHPRI | ++ WQ_POWER_EFFICIENT, 0); + if (!kblockd_workqueue) + panic("Failed to create kblockd\n"); + +diff -Nur linux-3.10.30/block/blk-ioc.c linux-3.10.30-cubox-i/block/blk-ioc.c +--- linux-3.10.30/block/blk-ioc.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/block/blk-ioc.c 2014-03-08 20:33:23.000000000 +0100 +@@ -144,7 +144,8 @@ + if (atomic_long_dec_and_test(&ioc->refcount)) { + spin_lock_irqsave(&ioc->lock, flags); + if (!hlist_empty(&ioc->icq_list)) +- schedule_work(&ioc->release_work); ++ queue_work(system_power_efficient_wq, ++ &ioc->release_work); + else + free_ioc = true; + spin_unlock_irqrestore(&ioc->lock, flags); +diff -Nur linux-3.10.30/block/genhd.c linux-3.10.30-cubox-i/block/genhd.c +--- linux-3.10.30/block/genhd.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/block/genhd.c 2014-03-08 20:33:23.000000000 +0100 +@@ -1489,9 +1489,11 @@ + intv = disk_events_poll_jiffies(disk); + set_timer_slack(&ev->dwork.timer, intv / 4); + if (check_now) +- queue_delayed_work(system_freezable_wq, &ev->dwork, 0); ++ queue_delayed_work(system_freezable_power_efficient_wq, ++ &ev->dwork, 0); + else if (intv) +- queue_delayed_work(system_freezable_wq, &ev->dwork, intv); ++ queue_delayed_work(system_freezable_power_efficient_wq, ++ &ev->dwork, intv); + out_unlock: + spin_unlock_irqrestore(&ev->lock, flags); + } +@@ -1534,7 +1536,8 @@ + spin_lock_irq(&ev->lock); + ev->clearing |= mask; + if (!ev->block) +- mod_delayed_work(system_freezable_wq, &ev->dwork, 0); ++ mod_delayed_work(system_freezable_power_efficient_wq, ++ &ev->dwork, 0); + spin_unlock_irq(&ev->lock); + } + +@@ -1627,7 +1630,8 @@ + + intv = disk_events_poll_jiffies(disk); + if (!ev->block && intv) +- queue_delayed_work(system_freezable_wq, &ev->dwork, intv); ++ queue_delayed_work(system_freezable_power_efficient_wq, ++ &ev->dwork, intv); + + spin_unlock_irq(&ev->lock); + +diff -Nur linux-3.10.30/drivers/Kconfig linux-3.10.30-cubox-i/drivers/Kconfig +--- linux-3.10.30/drivers/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/Kconfig 2014-03-08 20:33:25.000000000 +0100 +@@ -98,6 +98,8 @@ + + source "drivers/memstick/Kconfig" + ++source "drivers/mxc/Kconfig" ++ + source "drivers/leds/Kconfig" + + source "drivers/accessibility/Kconfig" +@@ -166,4 +168,6 @@ + + source "drivers/reset/Kconfig" + ++source "drivers/gator/Kconfig" ++ + endmenu +diff -Nur linux-3.10.30/drivers/Makefile linux-3.10.30-cubox-i/drivers/Makefile +--- linux-3.10.30/drivers/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/Makefile 2014-03-08 20:33:25.000000000 +0100 +@@ -109,6 +109,7 @@ + obj-$(CONFIG_CPU_FREQ) += cpufreq/ + obj-$(CONFIG_CPU_IDLE) += cpuidle/ + obj-y += mmc/ ++obj-$(CONFIG_ARCH_MXC) += mxc/ + obj-$(CONFIG_MEMSTICK) += memstick/ + obj-y += leds/ + obj-$(CONFIG_INFINIBAND) += infiniband/ +@@ -152,3 +153,5 @@ + obj-$(CONFIG_VME_BUS) += vme/ + obj-$(CONFIG_IPACK_BUS) += ipack/ + obj-$(CONFIG_NTB) += ntb/ ++ ++obj-$(CONFIG_GATOR) += gator/ +diff -Nur linux-3.10.30/drivers/ata/Kconfig linux-3.10.30-cubox-i/drivers/ata/Kconfig +--- linux-3.10.30/drivers/ata/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/ata/Kconfig 2014-03-08 20:33:26.000000000 +0100 +@@ -97,6 +97,15 @@ + + If unsure, say N. + ++config AHCI_IMX ++ tristate "Freescale i.MX AHCI SATA support" ++ depends on SATA_AHCI_PLATFORM ++ help ++ This option enables support for the Freescale i.MX SoC's ++ onboard AHCI SATA. ++ ++ If unsure, say N. ++ + config SATA_FSL + tristate "Freescale 3.0Gbps SATA support" + depends on FSL_SOC +diff -Nur linux-3.10.30/drivers/ata/Makefile linux-3.10.30-cubox-i/drivers/ata/Makefile +--- linux-3.10.30/drivers/ata/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/ata/Makefile 2014-03-08 20:33:26.000000000 +0100 +@@ -10,6 +10,7 @@ + obj-$(CONFIG_SATA_SIL24) += sata_sil24.o + obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o + obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o ++obj-$(CONFIG_AHCI_IMX) += ahci_imx.o + + # SFF w/ custom DMA + obj-$(CONFIG_PDC_ADMA) += pdc_adma.o +diff -Nur linux-3.10.30/drivers/ata/ahci.h linux-3.10.30-cubox-i/drivers/ata/ahci.h +--- linux-3.10.30/drivers/ata/ahci.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/ata/ahci.h 2014-03-08 20:33:26.000000000 +0100 +@@ -337,6 +337,7 @@ + .sdev_attrs = ahci_sdev_attrs + + extern struct ata_port_operations ahci_ops; ++extern struct ata_port_operations ahci_platform_ops; + extern struct ata_port_operations ahci_pmp_retry_srst_ops; + + unsigned int ahci_dev_classify(struct ata_port *ap); +@@ -366,6 +367,7 @@ + irqreturn_t ahci_thread_fn(int irq, void *dev_instance); + void ahci_print_info(struct ata_host *host, const char *scc_s); + int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis); ++void ahci_error_handler(struct ata_port *ap); + + static inline void __iomem *__ahci_port_base(struct ata_host *host, + unsigned int port_no) +diff -Nur linux-3.10.30/drivers/ata/ahci_imx.c linux-3.10.30-cubox-i/drivers/ata/ahci_imx.c +--- linux-3.10.30/drivers/ata/ahci_imx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/ata/ahci_imx.c 2014-03-08 20:33:26.000000000 +0100 +@@ -0,0 +1,351 @@ ++/* ++ * copyright (c) 2013 Freescale Semiconductor, Inc. ++ * Freescale IMX AHCI SATA platform driver ++ * ++ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU General Public License, ++ * version 2, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for ++ * more details. ++ * ++ * You should have received a copy of the GNU General Public License along with ++ * this program. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ahci.h" ++ ++enum { ++ PORT_PHY_CTL = 0x178, /* Port0 PHY Control */ ++ PORT_PHY_CTL_PDDQ_LOC = 0x100000, /* PORT_PHY_CTL bits */ ++ HOST_TIMER1MS = 0xe0, /* Timer 1-ms */ ++}; ++ ++struct imx_ahci_priv { ++ struct platform_device *ahci_pdev; ++ struct clk *sata_ref_clk; ++ struct clk *ahb_clk; ++ struct regmap *gpr; ++ bool no_device; ++ bool first_time; ++}; ++ ++static int ahci_imx_hotplug; ++module_param_named(hotplug, ahci_imx_hotplug, int, 0644); ++MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)"); ++ ++static void ahci_imx_error_handler(struct ata_port *ap) ++{ ++ u32 reg_val; ++ struct ata_device *dev; ++ struct ata_host *host = dev_get_drvdata(ap->dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ void __iomem *mmio = hpriv->mmio; ++ struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent); ++ ++ ahci_error_handler(ap); ++ ++ if (!(imxpriv->first_time) || ahci_imx_hotplug) ++ return; ++ ++ imxpriv->first_time = false; ++ ++ ata_for_each_dev(dev, &ap->link, ENABLED) ++ return; ++ /* ++ * Disable link to save power. An imx ahci port can't be recovered ++ * without full reset once the pddq mode is enabled making it ++ * impossible to use as part of libata LPM. ++ */ ++ reg_val = readl(mmio + PORT_PHY_CTL); ++ writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL); ++ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, ++ IMX6Q_GPR13_SATA_MPLL_CLK_EN, ++ !IMX6Q_GPR13_SATA_MPLL_CLK_EN); ++ clk_disable_unprepare(imxpriv->sata_ref_clk); ++ release_bus_freq(BUS_FREQ_HIGH); ++ imxpriv->no_device = true; ++ ++ dev_info(ap->dev, "no device found, disabling link.\n"); ++ dev_info(ap->dev, "pass " MODULE_PARAM_PREFIX ++ ".hotplug=1 to enable hotplug\n"); ++} ++ ++static struct ata_port_operations ahci_imx_ops = { ++ .inherits = &ahci_platform_ops, ++ .error_handler = ahci_imx_error_handler, ++}; ++ ++static const struct ata_port_info ahci_imx_port_info = { ++ .flags = AHCI_FLAG_COMMON, ++ .pio_mask = ATA_PIO4, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &ahci_imx_ops, ++}; ++ ++static int imx6q_sata_init(struct device *dev, void __iomem *mmio) ++{ ++ int ret = 0; ++ unsigned int reg_val; ++ struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); ++ ++ imxpriv->gpr = ++ syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); ++ if (IS_ERR(imxpriv->gpr)) { ++ dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n"); ++ return PTR_ERR(imxpriv->gpr); ++ } ++ ++ ret = clk_prepare_enable(imxpriv->sata_ref_clk); ++ if (ret < 0) { ++ dev_err(dev, "prepare-enable sata_ref clock err:%d\n", ret); ++ return ret; ++ } ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ /* ++ * set PHY Paremeters, two steps to configure the GPR13, ++ * one write for rest of parameters, mask of first write ++ * is 0x07fffffd, and the other one write for setting ++ * the mpll_clk_en. ++ */ ++ regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK ++ | IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK ++ | IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK ++ | IMX6Q_GPR13_SATA_SPD_MODE_MASK ++ | IMX6Q_GPR13_SATA_MPLL_SS_EN ++ | IMX6Q_GPR13_SATA_TX_ATTEN_MASK ++ | IMX6Q_GPR13_SATA_TX_BOOST_MASK ++ | IMX6Q_GPR13_SATA_TX_LVL_MASK ++ | IMX6Q_GPR13_SATA_TX_EDGE_RATE ++ , IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB ++ | IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M ++ | IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F ++ | IMX6Q_GPR13_SATA_SPD_MODE_3P0G ++ | /* IMX6Q_GPR13_SATA_MPLL_SS_EN */ 0 ++ | IMX6Q_GPR13_SATA_TX_ATTEN_9_16 ++ | /* IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB ++ | IMX6Q_GPR13_SATA_TX_LVL_1_025_V */ ++ IMX6Q_GPR13_SATA_TX_LVL_1_104_V); ++ regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN, ++ IMX6Q_GPR13_SATA_MPLL_CLK_EN); ++ usleep_range(100, 200); ++ ++ /* ++ * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, ++ * and IP vendor specific register HOST_TIMER1MS. ++ * Configure CAP_SSS (support stagered spin up). ++ * Implement the port0. ++ * Get the ahb clock rate, and configure the TIMER1MS register. ++ */ ++ reg_val = readl(mmio + HOST_CAP); ++ if (!(reg_val & HOST_CAP_SSS)) { ++ reg_val |= HOST_CAP_SSS; ++ writel(reg_val, mmio + HOST_CAP); ++ } ++ reg_val = readl(mmio + HOST_PORTS_IMPL); ++ if (!(reg_val & 0x1)) { ++ reg_val |= 0x1; ++ writel(reg_val, mmio + HOST_PORTS_IMPL); ++ } ++ ++ reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; ++ writel(reg_val, mmio + HOST_TIMER1MS); ++ ++ return 0; ++} ++ ++static void imx6q_sata_exit(struct device *dev) ++{ ++ struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); ++ ++ if (!imxpriv->no_device) { ++ regmap_update_bits(imxpriv->gpr, 0x34, ++ IMX6Q_GPR13_SATA_MPLL_CLK_EN, ++ !IMX6Q_GPR13_SATA_MPLL_CLK_EN); ++ clk_disable_unprepare(imxpriv->sata_ref_clk); ++ release_bus_freq(BUS_FREQ_HIGH); ++ } ++} ++ ++static int imx_ahci_suspend(struct device *dev) ++{ ++ struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); ++ ++ /* ++ * If no_device is set, The CLKs had been gated off in the ++ * initialization so don't do it again here. ++ */ ++ if (!imxpriv->no_device) { ++ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, ++ IMX6Q_GPR13_SATA_MPLL_CLK_EN, ++ !IMX6Q_GPR13_SATA_MPLL_CLK_EN); ++ clk_disable_unprepare(imxpriv->sata_ref_clk); ++ release_bus_freq(BUS_FREQ_HIGH); ++ } ++ ++ return 0; ++} ++ ++static int imx_ahci_resume(struct device *dev) ++{ ++ struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); ++ int ret; ++ ++ if (!imxpriv->no_device) { ++ ret = clk_prepare_enable(imxpriv->sata_ref_clk); ++ if (ret < 0) { ++ dev_err(dev, "pre-enable sata_ref clock err:%d\n", ret); ++ return ret; ++ } ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, ++ IMX6Q_GPR13_SATA_MPLL_CLK_EN, ++ IMX6Q_GPR13_SATA_MPLL_CLK_EN); ++ usleep_range(1000, 2000); ++ } ++ ++ return 0; ++} ++ ++static struct ahci_platform_data imx6q_sata_pdata = { ++ .init = imx6q_sata_init, ++ .exit = imx6q_sata_exit, ++ .ata_port_info = &ahci_imx_port_info, ++ .suspend = imx_ahci_suspend, ++ .resume = imx_ahci_resume, ++}; ++ ++static const struct of_device_id imx_ahci_of_match[] = { ++ { .compatible = "fsl,imx6q-ahci", .data = &imx6q_sata_pdata}, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, imx_ahci_of_match); ++ ++static int imx_ahci_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct resource *mem, *irq, res[2]; ++ const struct of_device_id *of_id; ++ const struct ahci_platform_data *pdata = NULL; ++ struct imx_ahci_priv *imxpriv; ++ struct device *ahci_dev; ++ struct platform_device *ahci_pdev; ++ int ret; ++ ++ /* Prevent our child ahci device coming back to us */ ++ if (!strcmp(dev_name(&pdev->dev), "ahci")) ++ return -ENODEV; ++ ++ imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL); ++ if (!imxpriv) { ++ dev_err(dev, "can't alloc ahci_host_priv\n"); ++ return -ENOMEM; ++ } ++ ++ ahci_pdev = platform_device_alloc("ahci", -1); ++ if (!ahci_pdev) ++ return -ENODEV; ++ ++ ahci_dev = &ahci_pdev->dev; ++ ahci_dev->parent = dev; ++ ++ imxpriv->no_device = false; ++ imxpriv->first_time = true; ++ imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); ++ if (IS_ERR(imxpriv->ahb_clk)) { ++ dev_err(dev, "can't get ahb clock.\n"); ++ ret = PTR_ERR(imxpriv->ahb_clk); ++ goto err_out; ++ } ++ ++ imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref"); ++ if (IS_ERR(imxpriv->sata_ref_clk)) { ++ dev_err(dev, "can't get sata_ref clock.\n"); ++ ret = PTR_ERR(imxpriv->sata_ref_clk); ++ goto err_out; ++ } ++ ++ imxpriv->ahci_pdev = ahci_pdev; ++ platform_set_drvdata(pdev, imxpriv); ++ ++ of_id = of_match_device(imx_ahci_of_match, dev); ++ if (of_id) { ++ pdata = of_id->data; ++ } else { ++ ret = -EINVAL; ++ goto err_out; ++ } ++ ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (!mem || !irq) { ++ dev_err(dev, "no mmio/irq resource\n"); ++ ret = -ENOMEM; ++ goto err_out; ++ } ++ ++ res[0] = *mem; ++ res[1] = *irq; ++ ++ ahci_dev->coherent_dma_mask = DMA_BIT_MASK(32); ++ ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask; ++ ahci_dev->of_node = dev->of_node; ++ ++ ret = platform_device_add_resources(ahci_pdev, res, 2); ++ if (ret) ++ goto err_out; ++ ++ ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata)); ++ if (ret) ++ goto err_out; ++ ++ ret = platform_device_add(ahci_pdev); ++ if (ret) { ++err_out: ++ platform_device_put(ahci_pdev); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int imx_ahci_remove(struct platform_device *pdev) ++{ ++ struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev); ++ struct platform_device *ahci_pdev = imxpriv->ahci_pdev; ++ ++ platform_device_unregister(ahci_pdev); ++ return 0; ++} ++ ++static struct platform_driver imx_ahci_driver = { ++ .probe = imx_ahci_probe, ++ .remove = imx_ahci_remove, ++ .driver = { ++ .name = "ahci-imx", ++ .owner = THIS_MODULE, ++ .of_match_table = imx_ahci_of_match, ++ }, ++}; ++module_platform_driver(imx_ahci_driver); ++ ++MODULE_DESCRIPTION("Freescale i.MX AHCI SATA platform driver"); ++MODULE_AUTHOR("Richard Zhu "); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("ahci:imx"); +diff -Nur linux-3.10.30/drivers/ata/ahci_platform.c linux-3.10.30-cubox-i/drivers/ata/ahci_platform.c +--- linux-3.10.30/drivers/ata/ahci_platform.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/ata/ahci_platform.c 2014-03-08 20:33:26.000000000 +0100 +@@ -49,10 +49,11 @@ + }; + MODULE_DEVICE_TABLE(platform, ahci_devtype); + +-static struct ata_port_operations ahci_platform_ops = { ++struct ata_port_operations ahci_platform_ops = { + .inherits = &ahci_ops, + .host_stop = ahci_host_stop, + }; ++EXPORT_SYMBOL_GPL(ahci_platform_ops); + + static struct ata_port_operations ahci_platform_retry_srst_ops = { + .inherits = &ahci_pmp_retry_srst_ops, +diff -Nur linux-3.10.30/drivers/ata/libahci.c linux-3.10.30-cubox-i/drivers/ata/libahci.c +--- linux-3.10.30/drivers/ata/libahci.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/ata/libahci.c 2014-03-08 20:33:26.000000000 +0100 +@@ -89,7 +89,6 @@ + static int ahci_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); + static void ahci_postreset(struct ata_link *link, unsigned int *class); +-static void ahci_error_handler(struct ata_port *ap); + static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); + static void ahci_dev_config(struct ata_device *dev); + #ifdef CONFIG_PM +@@ -1996,7 +1995,7 @@ + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + } + +-static void ahci_error_handler(struct ata_port *ap) ++void ahci_error_handler(struct ata_port *ap) + { + if (!(ap->pflags & ATA_PFLAG_FROZEN)) { + /* restart engine */ +@@ -2009,6 +2008,7 @@ + if (!ata_dev_enabled(ap->link.device)) + ahci_stop_engine(ap); + } ++EXPORT_SYMBOL_GPL(ahci_error_handler); + + static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) + { +diff -Nur linux-3.10.30/drivers/base/Makefile linux-3.10.30-cubox-i/drivers/base/Makefile +--- linux-3.10.30/drivers/base/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/base/Makefile 2014-03-08 20:33:27.000000000 +0100 +@@ -1,6 +1,6 @@ + # Makefile for the Linux device tree + +-obj-y := core.o bus.o dd.o syscore.o \ ++obj-y := component.o core.o bus.o dd.o syscore.o \ + driver.o class.o platform.o \ + cpu.o firmware.o init.o map.o devres.o \ + attribute_container.o transport_class.o \ +diff -Nur linux-3.10.30/drivers/base/base.h linux-3.10.30-cubox-i/drivers/base/base.h +--- linux-3.10.30/drivers/base/base.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/base/base.h 2014-03-08 20:33:27.000000000 +0100 +@@ -119,6 +119,11 @@ + return drv->bus->match ? drv->bus->match(dev, drv) : 1; + } + ++extern int device_add_groups(struct device *dev, ++ const struct attribute_group **groups); ++extern void device_remove_groups(struct device *dev, ++ const struct attribute_group **groups); ++ + extern char *make_class_name(const char *name, struct kobject *kobj); + + extern int devres_release_all(struct device *dev); +diff -Nur linux-3.10.30/drivers/base/bus.c linux-3.10.30-cubox-i/drivers/base/bus.c +--- linux-3.10.30/drivers/base/bus.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/base/bus.c 2014-03-08 20:33:27.000000000 +0100 +@@ -499,6 +499,9 @@ + error = device_add_attrs(bus, dev); + if (error) + goto out_put; ++ error = device_add_groups(dev, bus->dev_groups); ++ if (error) ++ goto out_groups; + error = sysfs_create_link(&bus->p->devices_kset->kobj, + &dev->kobj, dev_name(dev)); + if (error) +@@ -513,6 +516,8 @@ + + out_subsys: + sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev)); ++out_groups: ++ device_remove_groups(dev, bus->dev_groups); + out_id: + device_remove_attrs(bus, dev); + out_put: +@@ -575,6 +580,7 @@ + sysfs_remove_link(&dev->bus->p->devices_kset->kobj, + dev_name(dev)); + device_remove_attrs(dev->bus, dev); ++ device_remove_groups(dev, dev->bus->dev_groups); + if (klist_node_attached(&dev->p->knode_bus)) + klist_del(&dev->p->knode_bus); + +diff -Nur linux-3.10.30/drivers/base/component.c linux-3.10.30-cubox-i/drivers/base/component.c +--- linux-3.10.30/drivers/base/component.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/base/component.c 2014-03-08 20:33:27.000000000 +0100 +@@ -0,0 +1,382 @@ ++/* ++ * Componentized device handling. ++ * ++ * This program 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 is work in progress. We gather up the component devices into a list, ++ * and bind them when instructed. At the moment, we're specific to the DRM ++ * subsystem, and only handles one master device, but this doesn't have to be ++ * the case. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct master { ++ struct list_head node; ++ struct list_head components; ++ bool bound; ++ ++ const struct component_master_ops *ops; ++ struct device *dev; ++}; ++ ++struct component { ++ struct list_head node; ++ struct list_head master_node; ++ struct master *master; ++ bool bound; ++ ++ const struct component_ops *ops; ++ struct device *dev; ++}; ++ ++static DEFINE_MUTEX(component_mutex); ++static LIST_HEAD(component_list); ++static LIST_HEAD(masters); ++ ++static struct master *__master_find(struct device *dev, ++ const struct component_master_ops *ops) ++{ ++ struct master *m; ++ ++ list_for_each_entry(m, &masters, node) ++ if (m->dev == dev && (!ops || m->ops == ops)) ++ return m; ++ ++ return NULL; ++} ++ ++/* Attach an unattached component to a master. */ ++static void component_attach_master(struct master *master, struct component *c) ++{ ++ c->master = master; ++ ++ list_add_tail(&c->master_node, &master->components); ++} ++ ++/* Detach a component from a master. */ ++static void component_detach_master(struct master *master, struct component *c) ++{ ++ list_del(&c->master_node); ++ ++ c->master = NULL; ++} ++ ++int component_master_add_child(struct master *master, ++ int (*compare)(struct device *, void *), void *compare_data) ++{ ++ struct component *c; ++ int ret = -ENXIO; ++ ++ list_for_each_entry(c, &component_list, node) { ++ if (c->master) ++ continue; ++ ++ if (compare(c->dev, compare_data)) { ++ component_attach_master(master, c); ++ ret = 0; ++ break; ++ } ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(component_master_add_child); ++ ++/* Detach all attached components from this master */ ++static void master_remove_components(struct master *master) ++{ ++ while (!list_empty(&master->components)) { ++ struct component *c = list_first_entry(&master->components, ++ struct component, master_node); ++ ++ WARN_ON(c->master != master); ++ ++ component_detach_master(master, c); ++ } ++} ++ ++/* ++ * Try to bring up a master. If component is NULL, we're interested in ++ * this master, otherwise it's a component which must be present to try ++ * and bring up the master. ++ * ++ * Returns 1 for successful bringup, 0 if not ready, or -ve errno. ++ */ ++static int try_to_bring_up_master(struct master *master, ++ struct component *component) ++{ ++ int ret = 0; ++ ++ if (!master->bound) { ++ /* ++ * Search the list of components, looking for components that ++ * belong to this master, and attach them to the master. ++ */ ++ if (master->ops->add_components(master->dev, master)) { ++ /* Failed to find all components */ ++ master_remove_components(master); ++ ret = 0; ++ goto out; ++ } ++ ++ if (component && component->master != master) { ++ master_remove_components(master); ++ ret = 0; ++ goto out; ++ } ++ ++ /* Found all components */ ++ ret = master->ops->bind(master->dev); ++ if (ret < 0) { ++ master_remove_components(master); ++ goto out; ++ } ++ ++ master->bound = true; ++ ret = 1; ++ } ++out: ++ ++ return ret; ++} ++ ++static int try_to_bring_up_masters(struct component *component) ++{ ++ struct master *m; ++ int ret = 0; ++ ++ list_for_each_entry(m, &masters, node) { ++ ret = try_to_bring_up_master(m, component); ++ if (ret != 0) ++ break; ++ } ++ ++ return ret; ++} ++ ++static void take_down_master(struct master *master) ++{ ++ if (master->bound) { ++ master->ops->unbind(master->dev); ++ master->bound = false; ++ } ++ ++ master_remove_components(master); ++} ++ ++int component_master_add(struct device *dev, ++ const struct component_master_ops *ops) ++{ ++ struct master *master; ++ int ret; ++ ++ master = kzalloc(sizeof(*master), GFP_KERNEL); ++ if (!master) ++ return -ENOMEM; ++ ++ master->dev = dev; ++ master->ops = ops; ++ INIT_LIST_HEAD(&master->components); ++ ++ /* Add to the list of available masters. */ ++ mutex_lock(&component_mutex); ++ list_add(&master->node, &masters); ++ ++ ret = try_to_bring_up_master(master, NULL); ++ ++ if (ret < 0) { ++ /* Delete off the list if we weren't successful */ ++ list_del(&master->node); ++ kfree(master); ++ } ++ mutex_unlock(&component_mutex); ++ ++ return ret < 0 ? ret : 0; ++} ++EXPORT_SYMBOL_GPL(component_master_add); ++ ++void component_master_del(struct device *dev, ++ const struct component_master_ops *ops) ++{ ++ struct master *master; ++ ++ mutex_lock(&component_mutex); ++ master = __master_find(dev, ops); ++ if (master) { ++ take_down_master(master); ++ ++ list_del(&master->node); ++ kfree(master); ++ } ++ mutex_unlock(&component_mutex); ++} ++EXPORT_SYMBOL_GPL(component_master_del); ++ ++static void component_unbind(struct component *component, ++ struct master *master, void *data) ++{ ++ WARN_ON(!component->bound); ++ ++ component->ops->unbind(component->dev, master->dev, data); ++ component->bound = false; ++ ++ /* Release all resources claimed in the binding of this component */ ++ devres_release_group(component->dev, component); ++} ++ ++void component_unbind_all(struct device *master_dev, void *data) ++{ ++ struct master *master; ++ struct component *c; ++ ++ WARN_ON(!mutex_is_locked(&component_mutex)); ++ ++ master = __master_find(master_dev, NULL); ++ if (!master) ++ return; ++ ++ list_for_each_entry_reverse(c, &master->components, master_node) ++ component_unbind(c, master, data); ++} ++EXPORT_SYMBOL_GPL(component_unbind_all); ++ ++static int component_bind(struct component *component, struct master *master, ++ void *data) ++{ ++ int ret; ++ ++ /* ++ * Each component initialises inside its own devres group. ++ * This allows us to roll-back a failed component without ++ * affecting anything else. ++ */ ++ if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) ++ return -ENOMEM; ++ ++ /* ++ * Also open a group for the device itself: this allows us ++ * to release the resources claimed against the sub-device ++ * at the appropriate moment. ++ */ ++ if (!devres_open_group(component->dev, component, GFP_KERNEL)) { ++ devres_release_group(master->dev, NULL); ++ return -ENOMEM; ++ } ++ ++ dev_dbg(master->dev, "binding %s (ops %ps)\n", ++ dev_name(component->dev), component->ops); ++ ++ ret = component->ops->bind(component->dev, master->dev, data); ++ if (!ret) { ++ component->bound = true; ++ ++ /* ++ * Close the component device's group so that resources ++ * allocated in the binding are encapsulated for removal ++ * at unbind. Remove the group on the DRM device as we ++ * can clean those resources up independently. ++ */ ++ devres_close_group(component->dev, NULL); ++ devres_remove_group(master->dev, NULL); ++ ++ dev_info(master->dev, "bound %s (ops %ps)\n", ++ dev_name(component->dev), component->ops); ++ } else { ++ devres_release_group(component->dev, NULL); ++ devres_release_group(master->dev, NULL); ++ ++ dev_err(master->dev, "failed to bind %s (ops %ps): %d\n", ++ dev_name(component->dev), component->ops, ret); ++ } ++ ++ return ret; ++} ++ ++int component_bind_all(struct device *master_dev, void *data) ++{ ++ struct master *master; ++ struct component *c; ++ int ret = 0; ++ ++ WARN_ON(!mutex_is_locked(&component_mutex)); ++ ++ master = __master_find(master_dev, NULL); ++ if (!master) ++ return -EINVAL; ++ ++ list_for_each_entry(c, &master->components, master_node) { ++ ret = component_bind(c, master, data); ++ if (ret) ++ break; ++ } ++ ++ if (ret != 0) { ++ list_for_each_entry_continue_reverse(c, &master->components, ++ master_node) ++ component_unbind(c, master, data); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(component_bind_all); ++ ++int component_add(struct device *dev, const struct component_ops *ops) ++{ ++ struct component *component; ++ int ret; ++ ++ component = kzalloc(sizeof(*component), GFP_KERNEL); ++ if (!component) ++ return -ENOMEM; ++ ++ component->ops = ops; ++ component->dev = dev; ++ ++ dev_dbg(dev, "adding component (ops %ps)\n", ops); ++ ++ mutex_lock(&component_mutex); ++ list_add_tail(&component->node, &component_list); ++ ++ ret = try_to_bring_up_masters(component); ++ if (ret < 0) { ++ list_del(&component->node); ++ ++ kfree(component); ++ } ++ mutex_unlock(&component_mutex); ++ ++ return ret < 0 ? ret : 0; ++} ++EXPORT_SYMBOL_GPL(component_add); ++ ++void component_del(struct device *dev, const struct component_ops *ops) ++{ ++ struct component *c, *component = NULL; ++ ++ mutex_lock(&component_mutex); ++ list_for_each_entry(c, &component_list, node) ++ if (c->dev == dev && c->ops == ops) { ++ list_del(&c->node); ++ component = c; ++ break; ++ } ++ ++ if (component && component->master) ++ take_down_master(component->master); ++ ++ mutex_unlock(&component_mutex); ++ ++ WARN_ON(!component); ++ kfree(component); ++} ++EXPORT_SYMBOL_GPL(component_del); ++ ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.10.30/drivers/base/core.c linux-3.10.30-cubox-i/drivers/base/core.c +--- linux-3.10.30/drivers/base/core.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/base/core.c 2014-03-08 20:33:27.000000000 +0100 +@@ -461,8 +461,7 @@ + device_remove_bin_file(dev, &attrs[i]); + } + +-static int device_add_groups(struct device *dev, +- const struct attribute_group **groups) ++int device_add_groups(struct device *dev, const struct attribute_group **groups) + { + int error = 0; + int i; +@@ -481,8 +480,8 @@ + return error; + } + +-static void device_remove_groups(struct device *dev, +- const struct attribute_group **groups) ++void device_remove_groups(struct device *dev, ++ const struct attribute_group **groups) + { + int i; + +diff -Nur linux-3.10.30/drivers/base/pinctrl.c linux-3.10.30-cubox-i/drivers/base/pinctrl.c +--- linux-3.10.30/drivers/base/pinctrl.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/base/pinctrl.c 2014-03-08 20:33:27.000000000 +0100 +@@ -48,6 +48,25 @@ + goto cleanup_get; + } + ++#ifdef CONFIG_PM ++ /* ++ * If power management is enabled, we also look for the optional ++ * sleep and idle pin states, with semantics as defined in ++ * ++ */ ++ dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p, ++ PINCTRL_STATE_SLEEP); ++ if (IS_ERR(dev->pins->sleep_state)) ++ /* Not supplying this state is perfectly legal */ ++ dev_dbg(dev, "no sleep pinctrl state\n"); ++ ++ dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p, ++ PINCTRL_STATE_IDLE); ++ if (IS_ERR(dev->pins->idle_state)) ++ /* Not supplying this state is perfectly legal */ ++ dev_dbg(dev, "no idle pinctrl state\n"); ++#endif ++ + return 0; + + /* +diff -Nur linux-3.10.30/drivers/base/regmap/internal.h linux-3.10.30-cubox-i/drivers/base/regmap/internal.h +--- linux-3.10.30/drivers/base/regmap/internal.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/base/regmap/internal.h 2014-03-08 20:33:27.000000000 +0100 +@@ -52,6 +52,7 @@ + struct regmap { + struct mutex mutex; + spinlock_t spinlock; ++ unsigned long spinlock_flags; + regmap_lock lock; + regmap_unlock unlock; + void *lock_arg; /* This is passed to lock/unlock functions */ +diff -Nur linux-3.10.30/drivers/base/regmap/regmap.c linux-3.10.30-cubox-i/drivers/base/regmap/regmap.c +--- linux-3.10.30/drivers/base/regmap/regmap.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/base/regmap/regmap.c 2014-03-08 20:33:27.000000000 +0100 +@@ -302,13 +302,16 @@ + static void regmap_lock_spinlock(void *__map) + { + struct regmap *map = __map; +- spin_lock(&map->spinlock); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&map->spinlock, flags); ++ map->spinlock_flags = flags; + } + + static void regmap_unlock_spinlock(void *__map) + { + struct regmap *map = __map; +- spin_unlock(&map->spinlock); ++ spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags); + } + + static void dev_get_regmap_release(struct device *dev, void *res) +diff -Nur linux-3.10.30/drivers/block/Kconfig linux-3.10.30-cubox-i/drivers/block/Kconfig +--- linux-3.10.30/drivers/block/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/Kconfig 2014-03-08 20:33:27.000000000 +0100 +@@ -541,4 +541,6 @@ + To compile this driver as a module, choose M here: the + module will be called rsxx. + ++source "drivers/block/enhanceio/Kconfig" ++ + endif # BLK_DEV +diff -Nur linux-3.10.30/drivers/block/Makefile linux-3.10.30-cubox-i/drivers/block/Makefile +--- linux-3.10.30/drivers/block/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/Makefile 2014-03-08 20:33:27.000000000 +0100 +@@ -42,5 +42,7 @@ + + obj-$(CONFIG_BLK_DEV_RSXX) += rsxx/ + ++obj-$(CONFIG_ENHANCEIO) += enhanceio/ ++ + nvme-y := nvme-core.o nvme-scsi.o + swim_mod-y := swim.o swim_asm.o +diff -Nur linux-3.10.30/drivers/block/enhanceio/Kconfig linux-3.10.30-cubox-i/drivers/block/enhanceio/Kconfig +--- linux-3.10.30/drivers/block/enhanceio/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/Kconfig 2014-03-08 20:33:27.000000000 +0100 +@@ -0,0 +1,21 @@ ++# ++# EnhanceIO caching solution by STEC INC. ++# ++ ++config ENHANCEIO ++ tristate "Enable EnhanceIO" ++ depends on PROC_FS ++ default m ++ ---help--- ++ Based on Facebook's open source Flashcache project developed by ++ Mohan Srinivasan and hosted at "http://github.com", EnhanceIO is ++ a collection of (currently three) loadable kernel modules for ++ using SSDs as cache devices for traditional rotating hard disk ++ ++ The caching engine is a loadable kernel module ("enhanceio.ko") ++ implemented as a device mapper target. The cache replacement ++ policies are implemented as loadable kernel modules ++ ("enhanceio_fifo.ko", "enhanceio_lru.ko") that register with ++ the caching engine module. ++ ++ If unsure, say N. +diff -Nur linux-3.10.30/drivers/block/enhanceio/Makefile linux-3.10.30-cubox-i/drivers/block/enhanceio/Makefile +--- linux-3.10.30/drivers/block/enhanceio/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/Makefile 2014-03-08 20:33:27.000000000 +0100 +@@ -0,0 +1,66 @@ ++# test ++# Makefile for EnhanceIO block device caching. ++# ++ ++COMMIT_REV ?= $(shell echo) ++KERNEL_SOURCE_VERSION ?= $(shell uname -r) ++KERNEL_TREE ?= /lib/modules/$(KERNEL_SOURCE_VERSION)/build ++EXTRA_CFLAGS += -I$(KERNEL_TREE)/drivers/md -I./ -DCOMMIT_REV="\"$(COMMIT_REV)\"" ++EXTRA_CFLAGS += -I$(KERNEL_TREE)/include/ -I$(KERNEL_TREE)/include/linux ++# Check for RHEL/CentOS ++RHEL5_VER ?= $(shell if [ -e /etc/redhat-release ]; then grep 5.[0-9] /etc/redhat-release; else false; fi) ++RHEL5_SETUP := ++ifneq "$(RHEL5_VER)" "" ++ RHEL5_SETUP := rhel5-setup ++ RHEL5_SPEC := /usr/src/redhat/SPECS/kernel.spec ++ RHEL5_TREE := /usr/src/redhat/BUILD/kernel-2.6.18/linux-$(shell uname -r).$(shell uname -i) ++ RHEL5_SRC := /usr/src/kernels/$(shell uname -r)-$(shell uname -i) ++ KERNEL_TREE := $(RHEL5_TREE) ++endif ++# Check for OpenVZ (/proc/vz) ++OPENVZ_VER ?= $(shell if [ -e /proc/vz ]; then grep 5.[0-9] /etc/redhat-release; else false; fi) ++ifneq "$(OPENVZ_VER)" "" ++ RHEL5_SPEC := /usr/src/redhat/SPECS/kernel-ovz.spec ++ RHEL5_TREE := /usr/src/redhat/BUILD/ovzkernel-2.6.18/linux-$(shell uname -r).$(shell uname -i) ++ KERNEL_TREE := $(RHEL5_TREE) ++endif ++obj-m += enhanceio.o enhanceio_lru.o enhanceio_fifo.o enhanceio_rand.o ++enhanceio-y += \ ++ eio_conf.o \ ++ eio_ioctl.o \ ++ eio_main.o \ ++ eio_mem.o \ ++ eio_policy.o \ ++ eio_procfs.o \ ++ eio_setlru.o \ ++ eio_subr.o \ ++ eio_ttc.o ++enhanceio_fifo-y += eio_fifo.o ++enhanceio_rand-y += eio_rand.o ++enhanceio_lru-y += eio_lru.o ++.PHONY: all ++all: modules ++.PHONY: modules ++modules: $(RHEL5_SETUP) ++ make -C $(KERNEL_TREE) M=$(PWD) modules V=0 ++.PHONY: modules_install ++modules_install: modules ++ install -o root -g root -m 0755 -d $(DESTDIR)/lib/modules/$(KERNEL_SOURCE_VERSION)/extra/enhanceio/ ++ install -o root -g root -m 0755 enhanceio.ko $(DESTDIR)/lib/modules/$(KERNEL_SOURCE_VERSION)/extra/enhanceio/ ++ install -o root -g root -m 0755 enhanceio_rand.ko $(DESTDIR)/lib/modules/$(KERNEL_SOURCE_VERSION)/extra/enhanceio/ ++ install -o root -g root -m 0755 enhanceio_fifo.ko $(DESTDIR)/lib/modules/$(KERNEL_SOURCE_VERSION)/extra/enhanceio/ ++ install -o root -g root -m 0755 enhanceio_lru.ko $(DESTDIR)/lib/modules/$(KERNEL_SOURCE_VERSION)/extra/enhanceio/ ++ depmod -a ++.PHONY: install ++install: modules_install ++.PHONY: clean ++clean: ++ make -C $(KERNEL_TREE) M=$(PWD) clean ++.PHONY: rhel5-setup ++rhel5-setup: $(RHEL5_TREE) ++ make -C $(RHEL5_TREE) oldconfig ; \ ++ make -C $(RHEL5_TREE) prepare modules_prepare ++ ln -s -f $(RHEL5_SRC)/Module.symvers $(RHEL5_TREE)/Module.symvers ++$(RHEL5_TREE): ++ rpmbuild -bp --target=`uname -m` $(RHEL5_SPEC) 2>&1 | tee `dirname $(RHEL5_SPEC)`/prep.log ++ +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio.h linux-3.10.30-cubox-i/drivers/block/enhanceio/eio.h +--- linux-3.10.30/drivers/block/enhanceio/eio.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio.h 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,1150 @@ ++/* ++ * eio.h ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Saied Kazemi ++ * Added EnhanceIO-specific code. ++ * Siddharth Choudhuri ++ * Common data structures and definitions between Windows and Linux. ++ * Amit Kale ++ * Restructured much of the io code to split bio within map function instead ++ * of letting dm do it. ++ * Amit Kale ++ * Harish Pujari ++ * Designed and implemented the writeback caching mode ++ * Copyright 2010 Facebook, Inc. ++ * Author: Mohan Srinivasan (mohan@facebook.com) ++ * ++ * Based on DM-Cache: ++ * Copyright (C) International Business Machines Corp., 2006 ++ * Author: Ming Zhao (mingzhao@ufl.edu) ++ * ++ * 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; under 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, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* required for eio_subr.c */ ++#include ++#include ++#include /* for sysinfo (mem) variables */ ++#include ++#include /* required for SSD failure handling */ ++/* resolve conflict with scsi/scsi_device.h */ ++#ifdef QUEUED ++#undef QUEUED ++#endif ++ ++#if defined(__KERNEL__) && !defined(CONFIG_PROC_FS) ++#error "EnhanceIO requires CONFIG_PROC_FS" ++#endif /* __KERNEL__ && !CONFIG_PROC_FS */ ++ ++#ifndef EIO_INC_H ++#define EIO_INC_H ++ ++/* Bit offsets for wait_on_bit_lock() */ ++#define EIO_UPDATE_LIST 0 ++#define EIO_HANDLE_REBOOT 1 ++ ++/* ++ * It is to carry out 64bit division ++ * on 32bit architecture. ++ */ ++static inline uint64_t ++EIO_CALCULATE_PERCENTAGE(uint64_t x64, uint64_t y64) ++{ ++ uint64_t result; ++ uint32_t h_y32 = y64 >> 32; ++ ++ result = x64 * 100; ++ ++ while (h_y32) { ++ h_y32 >>= 1; ++ y64 >>= 1; ++ result >>= 1; ++ } ++ do_div(result, y64); ++ return result; ++} ++ ++ ++static inline uint64_t ++EIO_DIV(uint64_t dividend_64, uint32_t divisor_32) ++{ ++ uint64_t result; ++ ++ result = dividend_64; ++ do_div(result, divisor_32); ++ return result; ++} ++ ++ ++static inline uint32_t ++EIO_REM(uint64_t dividend_64, uint32_t divisor_32) ++{ ++ uint64_t temp; ++ ++ temp = dividend_64; ++ return do_div(temp, divisor_32); ++} ++ ++static inline sector_t ++eio_to_sector(uint64_t size_in_bytes) ++{ ++ return size_in_bytes >> 9; ++} ++ ++struct eio_control_s { ++ unsigned long synch_flags; ++}; ++ ++int eio_wait_schedule(void *unused); ++ ++struct eio_event { ++ struct task_struct *process; /* handle of the sleeping process */ ++}; ++ ++typedef long int index_t; ++ ++extern int eio_reboot_notified; ++extern mempool_t *_io_pool; ++extern struct eio_control_s *eio_control; ++extern struct work_struct _kcached_wq; ++extern int eio_force_warm_boot; ++extern atomic_t nr_cache_jobs; ++extern mempool_t *_job_pool; ++ ++/* ++ * This file has three sections as follows: ++ * ++ * Section 1: User space only ++ * Section 2: User space and kernel ++ * Section 3: Kernel only ++ * ++ * Each section may contain its own subsections. ++ */ ++ ++/* ++ * Begin Section 1: User space only. ++ */ ++ ++/* ++ * End Section 1: User space only. ++ */ ++ ++/* ++ * Begin Section 2: User space and kernel. ++ */ ++ ++/* States of a cache block */ ++#define INVALID 0x0001 ++#define VALID 0x0002 /* Valid */ ++#define DISKREADINPROG 0x0004 /* Read from disk in progress */ ++#define DISKWRITEINPROG 0x0008 /* Write to disk in progress */ ++#define CACHEREADINPROG 0x0010 /* Read from cache in progress */ ++#define CACHEWRITEINPROG 0x0020 /* Write to cache in progress */ ++#define DIRTY 0x0040 /* Dirty, needs writeback to disk */ ++#define QUEUED 0x0080 /* Other requests are queued for this block */ ++ ++#define BLOCK_IO_INPROG (DISKREADINPROG | DISKWRITEINPROG | \ ++ CACHEREADINPROG | CACHEWRITEINPROG) ++#define DIRTY_INPROG (VALID | DIRTY | CACHEWRITEINPROG) /* block being dirtied */ ++#define CLEAN_INPROG (VALID | DIRTY | DISKWRITEINPROG) /* ongoing clean */ ++#define ALREADY_DIRTY (VALID | DIRTY) /* block which is dirty to begin with for an I/O */ ++ ++/* ++ * This is a special state used only in the following scenario as ++ * part of device (SSD) failure handling: ++ * ++ * ------| dev fail |------| dev resume |------------ ++ * ...-<--- Tf --><- Td -><---- Tr ---><-- Tn ---... ++ * |---- Normal ----|-- Degraded -------|-- Normal ---| ++ * ++ * Tf: Time during device failure. ++ * Td: Time after failure when the cache is in degraded mode. ++ * Tr: Time when the SSD comes back online. ++ * ++ * When a failed SSD is added back again, it should be treated ++ * as a cold SSD. ++ * ++ * If Td is very small, then there can be IOs that were initiated ++ * before or during Tf, and did not finish until the end of Tr. From ++ * the IO's viewpoint, the SSD was there when the IO was initiated ++ * and it was there when the IO was finished. These IOs need special ++ * handling as described below. ++ * ++ * To add the SSD as a cold cache device, we initialize all blocks ++ * to INVALID, execept for the ones that had IOs in progress before ++ * or during Tf. We mark such blocks as both VALID and INVALID. ++ * These blocks will be marked INVALID when finished. ++ */ ++#define NO_SSD_IO_INPROG (VALID | INVALID) ++ ++/* ++ * On Flash (cache metadata) Structures ++ */ ++#define CACHE_MD_STATE_DIRTY 0x55daddee ++#define CACHE_MD_STATE_CLEAN 0xacceded1 ++#define CACHE_MD_STATE_FASTCLEAN 0xcafebabf ++#define CACHE_MD_STATE_UNSTABLE 0xdeaddeee ++ ++/* Do we have a read cache or a read-write cache */ ++#define CACHE_MODE_WB 1 ++#define CACHE_MODE_RO 2 ++#define CACHE_MODE_WT 3 ++#define CACHE_MODE_FIRST CACHE_MODE_WB ++#define CACHE_MODE_LAST CACHE_MODE_WT ++#define CACHE_MODE_DEFAULT CACHE_MODE_WT ++ ++#define DEV_PATHLEN 128 ++#define EIO_SUPERBLOCK_SIZE 4096 ++ ++#define EIO_CLEAN_ABORT 0x00000000 ++#define EIO_CLEAN_START 0x00000001 ++#define EIO_CLEAN_KEEP 0x00000002 ++ ++/* EIO magic number */ ++#define EIO_MAGIC 0xE10CAC6E ++#define EIO_BAD_MAGIC 0xBADCAC6E ++ ++/* EIO version */ ++#define EIO_SB_VERSION 3 /* kernel superblock version */ ++#define EIO_SB_MAGIC_VERSION 3 /* version in which magic number was introduced */ ++ ++union eio_superblock { ++ struct superblock_fields { ++ __le64 size; /* Cache size */ ++ __le32 block_size; /* Cache block size */ ++ __le32 assoc; /* Cache associativity */ ++ __le32 cache_sb_state; /* Clean shutdown ? */ ++ char cache_devname[DEV_PATHLEN]; ++ __le64 cache_devsize; ++ char disk_devname[DEV_PATHLEN]; ++ __le64 disk_devsize; ++ __le32 cache_version; ++ char cache_name[DEV_PATHLEN]; ++ __le32 mode; ++ __le32 repl_policy; ++ __le32 cache_flags; ++ __le32 magic; ++ __le32 cold_boot; /* cache to be started as cold after boot */ ++ char ssd_uuid[DEV_PATHLEN]; ++ __le64 cache_md_start_sect; /* cache metadata start (8K aligned) */ ++ __le64 cache_data_start_sect; /* cache data start (8K aligned) */ ++ __le32 dirty_high_threshold; ++ __le32 dirty_low_threshold; ++ __le32 dirty_set_high_threshold; ++ __le32 dirty_set_low_threshold; ++ __le32 time_based_clean_interval; ++ __le32 autoclean_threshold; ++ } sbf; ++ u_int8_t padding[EIO_SUPERBLOCK_SIZE]; ++}; ++ ++/* ++ * For EnhanceIO, we move the superblock from sector 0 to 128 ++ * and give it a full 4K. Also, in addition to the single ++ * "red-zone" buffer that separates metadata sectors from the ++ * data sectors, we allocate extra sectors so that we can ++ * align the data sectors on a 4K boundary. ++ * ++ * 64K 4K variable variable 8K variable variable ++ * +--------+--+--------+---------+---+--------+---------+ ++ * | unused |SB| align1 |metadata | Z | align2 | data... | ++ * +--------+--+--------+---------+---+--------+---------+ ++ * <------------- dmc->md_sectors ------------> ++ */ ++#define EIO_UNUSED_SECTORS 128 ++#define EIO_SUPERBLOCK_SECTORS 8 ++#define EIO_REDZONE_SECTORS 16 ++#define EIO_START 0 ++ ++#define EIO_ALIGN1_SECTORS(index) ((index % 16) ? (24 - (index % 16)) : 8) ++#define EIO_ALIGN2_SECTORS(index) ((index % 16) ? (16 - (index % 16)) : 0) ++#define EIO_SUPERBLOCK_START (EIO_START + EIO_UNUSED_SECTORS) ++#define EIO_METADATA_START(hd_start_sect) (EIO_SUPERBLOCK_START + \ ++ EIO_SUPERBLOCK_SECTORS + \ ++ EIO_ALIGN1_SECTORS(hd_start_sect)) ++ ++#define EIO_EXTRA_SECTORS(start_sect, md_sects) (EIO_METADATA_START(start_sect) + \ ++ EIO_REDZONE_SECTORS + \ ++ EIO_ALIGN2_SECTORS(md_sects)) ++ ++/* ++ * We do metadata updates only when a block trasitions from DIRTY -> CLEAN ++ * or from CLEAN -> DIRTY. Consequently, on an unclean shutdown, we only ++ * pick up blocks that are marked (DIRTY | CLEAN), we clean these and stick ++ * them in the cache. ++ * On a clean shutdown, we will sync the state for every block, and we will ++ * load every block back into cache on a restart. ++ */ ++struct flash_cacheblock { ++ __le64 dbn; /* Sector number of the cached block */ ++ __le64 cache_state; ++}; ++ ++/* blksize in terms of no. of sectors */ ++#define BLKSIZE_2K 4 ++#define BLKSIZE_4K 8 ++#define BLKSIZE_8K 16 ++ ++/* ++ * Give me number of pages to allocated for the ++ * iosize x specified in terms of bytes. ++ */ ++#define IO_PAGE_COUNT(x) (((x) + (PAGE_SIZE - 1)) / PAGE_SIZE) ++ ++/* ++ * Macro that calculates number of biovecs to be ++ * allocated depending on the iosize and cache ++ * block size. ++ */ ++#define IO_BVEC_COUNT(x, blksize) ({ \ ++ int count = IO_PAGE_COUNT(x); \ ++ switch ((blksize)) { \ ++ case BLKSIZE_2K: \ ++ count = count * 2; \ ++ break; \ ++ case BLKSIZE_4K: \ ++ case BLKSIZE_8K: \ ++ break; \ ++ } \ ++ count; \ ++ }) ++ ++#define MD_MAX_NR_PAGES 16 ++#define MD_BLOCKS_PER_PAGE ((PAGE_SIZE) / sizeof(struct flash_cacheblock)) ++#define INDEX_TO_MD_PAGE(INDEX) ((INDEX) / MD_BLOCKS_PER_PAGE) ++#define INDEX_TO_MD_PAGE_OFFSET(INDEX) ((INDEX) % MD_BLOCKS_PER_PAGE) ++ ++#define MD_BLOCKS_PER_SECTOR (512 / (sizeof(struct flash_cacheblock))) ++#define INDEX_TO_MD_SECTOR(INDEX) (EIO_DIV((INDEX), MD_BLOCKS_PER_SECTOR)) ++#define INDEX_TO_MD_SECTOR_OFFSET(INDEX) (EIO_REM((INDEX), MD_BLOCKS_PER_SECTOR)) ++#define MD_BLOCKS_PER_CBLOCK(dmc) (MD_BLOCKS_PER_SECTOR * (dmc)->block_size) ++ ++#define METADATA_IO_BLOCKSIZE (256 * 1024) ++#define METADATA_IO_BLOCKSIZE_SECT (METADATA_IO_BLOCKSIZE / 512) ++#define SECTORS_PER_PAGE ((PAGE_SIZE) / 512) ++ ++/* ++ * Cache persistence. ++ */ ++#define CACHE_RELOAD 1 ++#define CACHE_CREATE 2 ++#define CACHE_FORCECREATE 3 ++ ++/* ++ * Cache replacement policy. ++ */ ++#define CACHE_REPL_FIFO 1 ++#define CACHE_REPL_LRU 2 ++#define CACHE_REPL_RANDOM 3 ++#define CACHE_REPL_FIRST CACHE_REPL_FIFO ++#define CACHE_REPL_LAST CACHE_REPL_RANDOM ++#define CACHE_REPL_DEFAULT CACHE_REPL_FIFO ++ ++struct eio_policy_and_name { ++ u8 p; ++ char *n; ++}; ++ ++ ++static const struct eio_policy_and_name eio_policy_names[] = { ++ { CACHE_REPL_FIFO, "fifo" }, ++ { CACHE_REPL_LRU, "lru" }, ++ { CACHE_REPL_RANDOM, "rand" }, ++}; ++ ++ ++/* ++ * Default cache parameters. ++ */ ++#define DEFAULT_CACHE_ASSOC 512 ++#define DEFAULT_CACHE_BLKSIZE 8 /* 4 KB */ ++ ++/* ++ * Valid commands that can be written to "control". ++ * NOTE: Update CACHE_CONTROL_FLAG_MAX value whenever a new control flag is added ++ */ ++#define CACHE_CONTROL_FLAG_MAX 7 ++#define CACHE_VERBOSE_OFF 0 ++#define CACHE_VERBOSE_ON 1 ++#define CACHE_WRITEBACK_ON 2 /* register write back variables */ ++#define CACHE_WRITEBACK_OFF 3 ++#define CACHE_INVALIDATE_ON 4 /* register invalidate variables */ ++#define CACHE_INVALIDATE_OFF 5 ++#define CACHE_FAST_REMOVE_ON 6 /* do not write MD when destroying cache */ ++#define CACHE_FAST_REMOVE_OFF 7 ++ ++/* ++ * Bit definitions in "cache_flags". These are exported in Linux as ++ * hex in the "flags" output line of /proc/enhanceio//config. ++ */ ++ ++#define CACHE_FLAGS_VERBOSE (1 << 0) ++#define CACHE_FLAGS_INVALIDATE (1 << 1) ++#define CACHE_FLAGS_FAST_REMOVE (1 << 2) ++#define CACHE_FLAGS_DEGRADED (1 << 3) ++#define CACHE_FLAGS_SSD_ADD_INPROG (1 << 4) ++#define CACHE_FLAGS_MD8 (1 << 5) /* using 8-byte metadata (instead of 4-byte md) */ ++#define CACHE_FLAGS_FAILED (1 << 6) ++#define CACHE_FLAGS_STALE (1 << 7) ++#define CACHE_FLAGS_SHUTDOWN_INPROG (1 << 8) ++#define CACHE_FLAGS_MOD_INPROG (1 << 9) /* cache modification such as edit/delete in progress */ ++#define CACHE_FLAGS_DELETED (1 << 10) ++#define CACHE_FLAGS_INCORE_ONLY (CACHE_FLAGS_DEGRADED | \ ++ CACHE_FLAGS_SSD_ADD_INPROG | \ ++ CACHE_FLAGS_FAILED | \ ++ CACHE_FLAGS_SHUTDOWN_INPROG | \ ++ CACHE_FLAGS_MOD_INPROG | \ ++ CACHE_FLAGS_STALE | \ ++ CACHE_FLAGS_DELETED) /* need a proper definition */ ++ ++/* flags that govern cold/warm enable after reboot */ ++#define BOOT_FLAG_COLD_ENABLE (1 << 0) /* enable the cache as cold */ ++#define BOOT_FLAG_FORCE_WARM (1 << 1) /* override the cold enable flag */ ++ ++enum dev_notifier { ++ NOTIFY_INITIALIZER, ++ NOTIFY_SSD_ADD, ++ NOTIFY_SSD_REMOVED, ++ NOTIFY_SRC_REMOVED ++}; ++ ++/* ++ * End Section 2: User space and kernel. ++ */ ++ ++/* ++ * Begin Section 3: Kernel only. ++ */ ++#if defined(__KERNEL__) ++ ++/* ++ * Subsection 3.1: Definitions. ++ */ ++ ++#define EIO_SB_VERSION 3 /* kernel superblock version */ ++ ++/* kcached/pending job states */ ++#define READCACHE 1 ++#define WRITECACHE 2 ++#define READDISK 3 ++#define WRITEDISK 4 ++#define READFILL 5 /* Read Cache Miss Fill */ ++#define INVALIDATE 6 ++ ++/* Cache persistence */ ++#define CACHE_RELOAD 1 ++#define CACHE_CREATE 2 ++#define CACHE_FORCECREATE 3 ++ ++/* Sysctl defined */ ++#define MAX_CLEAN_IOS_SET 2 ++#define MAX_CLEAN_IOS_TOTAL 4 ++ ++/* ++ * TBD ++ * Rethink on max, min, default values ++ */ ++#define DIRTY_HIGH_THRESH_DEF 30 ++#define DIRTY_LOW_THRESH_DEF 10 ++#define DIRTY_SET_HIGH_THRESH_DEF 100 ++#define DIRTY_SET_LOW_THRESH_DEF 30 ++ ++#define CLEAN_FACTOR(sectors) ((sectors) >> 25) /* in 16 GB multiples */ ++#define TIME_BASED_CLEAN_INTERVAL_DEF(dmc) (uint32_t)(CLEAN_FACTOR((dmc)->cache_size) ? \ ++ CLEAN_FACTOR((dmc)->cache_size) : 1) ++#define TIME_BASED_CLEAN_INTERVAL_MAX 720 /* in minutes */ ++ ++#define AUTOCLEAN_THRESH_DEF 128 /* Number of I/Os which puts a hold on time based cleaning */ ++#define AUTOCLEAN_THRESH_MAX 1024 /* Number of I/Os which puts a hold on time based cleaning */ ++ ++/* Inject a 5s delay between cleaning blocks and metadata */ ++#define CLEAN_REMOVE_DELAY 5000 ++ ++/* ++ * Subsection 2: Data structures. ++ */ ++ ++typedef void (*eio_notify_fn)(int error, void *context); ++ ++/* ++ * 4-byte metadata support. ++ */ ++ ++#define EIO_MAX_SECTOR (((u_int64_t)1) << 40) ++#ifdef __BIG_ENDIAN ++struct md4 { ++ u_int8_t cache_state; ++ char dbn_bytes[3]; ++}; ++#else /* Little Endian */ ++struct md4 { ++ char dbn_bytes[3]; ++ u_int8_t cache_state; ++}; ++#endif ++ ++struct cacheblock { ++ union { ++ u_int32_t u_i_md4; ++ struct md4 u_s_md4; ++ } md4_u; ++}; ++ ++#define EIO_MD4_DBN_BITS (32 - 8) /* 8 bits for state */ ++#define EIO_MD4_DBN_MASK ((1 << EIO_MD4_DBN_BITS) - 1) ++#define EIO_MD4_INVALID (INVALID << EIO_MD4_DBN_BITS) ++ ++/* ++ * 8-byte metadata support. ++ */ ++#ifdef __BIG_ENDIAN ++struct md8 { ++ u_int8_t cache_state; ++ char dbn_bytes[7]; ++}; ++#else /* little endian*/ ++struct md8 { ++ char dbn_bytes[7]; ++ u_int8_t cache_state; ++}; ++#endif ++struct cacheblock_md8 { ++ union { ++ u_int64_t u_i_md8; ++ struct md8 u_s_md8; ++ } md8_u; ++}; ++ ++#define EIO_MD8_DBN_BITS (64 - 8) /* 8 bits for state */ ++#define EIO_MD8_DBN_MASK ((((u_int64_t)1) << EIO_MD8_DBN_BITS) - 1) ++#define EIO_MD8_INVALID (((u_int64_t)INVALID) << EIO_MD8_DBN_BITS) ++#define EIO_MD8(dmc) CACHE_MD8_IS_SET(dmc) ++ ++/* Structure used for metadata update on-disk and in-core for writeback cache */ ++struct mdupdate_request { ++ struct list_head list; /* to build mdrequest chain */ ++ struct work_struct work; /* work structure */ ++ struct cache_c *dmc; /* cache pointer */ ++ index_t set; /* set index */ ++ unsigned md_size; /* metadata size */ ++ unsigned mdbvec_count; /* count of bvecs allocated. */ ++ struct bio_vec *mdblk_bvecs; /* bvecs for updating md_blocks */ ++ atomic_t holdcount; /* I/O hold count */ ++ struct eio_bio *pending_mdlist; /* ebios pending for md update */ ++ struct eio_bio *inprog_mdlist; /* ebios processed for md update */ ++ int error; /* error during md update */ ++ struct mdupdate_request *next; /* next mdreq in the mdreq list .TBD. Deprecate */ ++}; ++ ++#define SETFLAG_CLEAN_INPROG 0x00000001 /* clean in progress on a set */ ++#define SETFLAG_CLEAN_WHOLE 0x00000002 /* clean the set fully */ ++ ++/* Structure used for doing operations and storing cache set level info */ ++struct cache_set { ++ struct list_head list; ++ u_int32_t nr_dirty; /* number of dirty blocks */ ++ spinlock_t cs_lock; /* spin lock to protect struct fields */ ++ struct rw_semaphore rw_lock; /* reader-writer lock used for clean */ ++ unsigned int flags; /* misc cache set specific flags */ ++ struct mdupdate_request *mdreq; /* metadata update request pointer */ ++}; ++ ++struct eio_errors { ++ int disk_read_errors; ++ int disk_write_errors; ++ int ssd_read_errors; ++ int ssd_write_errors; ++ int memory_alloc_errors; ++ int no_cache_dev; ++ int no_source_dev; ++}; ++ ++/* ++ * Stats. Note that everything should be "atomic64_t" as ++ * code relies on it. ++ */ ++#define SECTOR_STATS(statval, io_size) \ ++ atomic64_add(eio_to_sector(io_size), &statval); ++ ++struct eio_stats { ++ atomic64_t reads; /* Number of reads */ ++ atomic64_t writes; /* Number of writes */ ++ atomic64_t read_hits; /* Number of cache hits */ ++ atomic64_t write_hits; /* Number of write hits (includes dirty write hits) */ ++ atomic64_t dirty_write_hits; /* Number of "dirty" write hits */ ++ atomic64_t cached_blocks; /* Number of cached blocks */ ++ atomic64_t rd_replace; /* Number of read cache replacements. TBD modify def doc */ ++ atomic64_t wr_replace; /* Number of write cache replacements. TBD modify def doc */ ++ atomic64_t noroom; /* No room in set */ ++ atomic64_t cleanings; /* blocks cleaned TBD modify def doc */ ++ atomic64_t md_write_dirty; /* Metadata sector writes dirtying block */ ++ atomic64_t md_write_clean; /* Metadata sector writes cleaning block */ ++ atomic64_t md_ssd_writes; /* How many md ssd writes did we do ? */ ++ atomic64_t uncached_reads; ++ atomic64_t uncached_writes; ++ atomic64_t uncached_map_size; ++ atomic64_t uncached_map_uncacheable; ++ atomic64_t disk_reads; ++ atomic64_t disk_writes; ++ atomic64_t ssd_reads; ++ atomic64_t ssd_writes; ++ atomic64_t ssd_readfills; ++ atomic64_t ssd_readfill_unplugs; ++ atomic64_t readdisk; ++ atomic64_t writedisk; ++ atomic64_t readcache; ++ atomic64_t readfill; ++ atomic64_t writecache; ++ atomic64_t wrtime_ms; /* total write time in ms */ ++ atomic64_t rdtime_ms; /* total read time in ms */ ++ atomic64_t readcount; /* total reads received so far */ ++ atomic64_t writecount; /* total writes received so far */ ++}; ++ ++#define PENDING_JOB_HASH_SIZE 32 ++#define PENDING_JOB_HASH(index) ((index) % PENDING_JOB_HASH_SIZE) ++#define SIZE_HIST (128 + 1) ++#define EIO_COPY_PAGES 1024 /* Number of pages for I/O */ ++#define MIN_JOBS 1024 ++#define MIN_EIO_IO 4096 ++#define MIN_DMC_BIO_PAIR 8192 ++ ++/* Structure representing a sequence of sets(first to last set index) */ ++struct set_seq { ++ index_t first_set; ++ index_t last_set; ++ struct set_seq *next; ++}; ++ ++/* EIO system control variables(tunables) */ ++/* ++ * Adding synchonization is not worth the benefits. ++ */ ++struct eio_sysctl { ++ uint32_t error_inject; ++ int32_t fast_remove; ++ int32_t zerostats; ++ int32_t do_clean; ++ uint32_t dirty_high_threshold; ++ uint32_t dirty_low_threshold; ++ uint32_t dirty_set_high_threshold; ++ uint32_t dirty_set_low_threshold; ++ uint32_t time_based_clean_interval; /* time after which dirty sets should clean */ ++ int32_t autoclean_threshold; ++ int32_t mem_limit_pct; ++ int32_t control; ++ u_int64_t invalidate; ++}; ++ ++/* forward declaration */ ++struct lru_ls; ++ ++/* Replacement for 'struct dm_dev' */ ++struct eio_bdev { ++ struct block_device *bdev; ++ fmode_t mode; ++ char name[16]; ++}; ++ ++/* Replacement for 'struct dm_io_region */ ++struct eio_io_region { ++ struct block_device *bdev; ++ sector_t sector; ++ sector_t count; /* If zero the region is ignored */ ++}; ++ ++/* ++ * Cache context ++ */ ++struct cache_c { ++ struct list_head cachelist; ++ make_request_fn *origmfn; ++ char dev_info; /* partition or whole device */ ++ ++ sector_t dev_start_sect; ++ sector_t dev_end_sect; ++ int cache_rdonly; /* protected by ttc_write lock */ ++ struct eio_bdev *disk_dev; /* Source device */ ++ struct eio_bdev *cache_dev; /* Cache device */ ++ struct cacheblock *cache; /* Hash table for cache blocks */ ++ struct cache_set *cache_sets; ++ struct cache_c *next_cache; ++ struct kcached_job *readfill_queue; ++ struct work_struct readfill_wq; ++ ++ struct list_head cleanq; /* queue of sets to awaiting clean */ ++ struct eio_event clean_event; /* event to wait for, when cleanq is empty */ ++ spinlock_t clean_sl; /* spinlock to protect cleanq etc */ ++ void *clean_thread; /* OS specific thread object to handle cleanq */ ++ int clean_thread_running; /* to indicate that clean thread is running */ ++ atomic64_t clean_pendings; /* Number of sets pending to be cleaned */ ++ struct bio_vec *clean_dbvecs; /* Data bvecs for clean set */ ++ struct page **clean_mdpages; /* Metadata pages for clean set */ ++ int dbvec_count; ++ int mdpage_count; ++ int clean_excess_dirty; /* Clean in progress to bring cache dirty blocks in limits */ ++ atomic_t clean_index; /* set being cleaned, in case of force clean */ ++ ++ u_int64_t md_start_sect; /* Sector no. at which Metadata starts */ ++ u_int64_t md_sectors; /* Numbers of metadata sectors, including header */ ++ u_int64_t disk_size; /* Source size */ ++ u_int64_t size; /* Cache size */ ++ u_int32_t assoc; /* Cache associativity */ ++ u_int32_t block_size; /* Cache block size */ ++ u_int32_t block_shift; /* Cache block size in bits */ ++ u_int32_t block_mask; /* Cache block mask */ ++ u_int32_t consecutive_shift; /* Consecutive blocks size in bits */ ++ u_int32_t persistence; /* Create | Force create | Reload */ ++ u_int32_t mode; /* CACHE_MODE_{WB, RO, WT} */ ++ u_int32_t cold_boot; /* Cache should be started as cold after boot */ ++ u_int32_t bio_nr_pages; /* number of hardware sectors supported by SSD in terms of PAGE_SIZE */ ++ ++ spinlock_t cache_spin_lock; ++ long unsigned int cache_spin_lock_flags; /* See comments above spin_lock_irqsave_FLAGS */ ++ atomic_t nr_jobs; /* Number of I/O jobs */ ++ ++ u_int32_t cache_flags; ++ u_int32_t sb_state; /* Superblock state */ ++ u_int32_t sb_version; /* Superblock version */ ++ ++ int readfill_in_prog; ++ struct eio_stats eio_stats; /* Run time stats */ ++ struct eio_errors eio_errors; /* Error stats */ ++ int max_clean_ios_set; /* Max cleaning IOs per set */ ++ int max_clean_ios_total; /* Total max cleaning IOs */ ++ int clean_inprog; ++ atomic64_t nr_dirty; ++ atomic64_t nr_ios; ++ atomic64_t size_hist[SIZE_HIST]; ++ ++ void *sysctl_handle_common; ++ void *sysctl_handle_writeback; ++ void *sysctl_handle_invalidate; ++ ++ struct eio_sysctl sysctl_pending; /* sysctl values pending to become active */ ++ struct eio_sysctl sysctl_active; /* sysctl currently active */ ++ ++ char cache_devname[DEV_PATHLEN]; ++ char disk_devname[DEV_PATHLEN]; ++ char cache_name[DEV_PATHLEN]; ++ char cache_gendisk_name[DEV_PATHLEN]; /* Used for SSD failure checks */ ++ char cache_srcdisk_name[DEV_PATHLEN]; /* Used for SRC failure checks */ ++ char ssd_uuid[DEV_PATHLEN]; ++ ++ struct cacheblock_md8 *cache_md8; ++ sector_t cache_size; /* Cache size passed to ctr(), used by dmsetup info */ ++ sector_t cache_dev_start_sect; /* starting sector of cache device */ ++ u_int64_t index_zero; /* index of cache block with starting sector 0 */ ++ u_int32_t num_sets; /* number of cache sets */ ++ u_int32_t num_sets_bits; /* number of bits to encode "num_sets" */ ++ u_int64_t num_sets_mask; /* mask value for bits in "num_sets" */ ++ ++ struct eio_policy *policy_ops; /* Cache block Replacement policy */ ++ u_int32_t req_policy; /* Policy requested by the user */ ++ u_int32_t random; /* Use for random replacement policy */ ++ void *sp_cache_blk; /* Per cache-block data structure */ ++ void *sp_cache_set; /* Per cache-set data structure */ ++ struct lru_ls *dirty_set_lru; /* lru for dirty sets : lru_list_t */ ++ spinlock_t dirty_set_lru_lock; /* spinlock for dirty set lru */ ++ struct delayed_work clean_aged_sets_work; /* work item for clean_aged_sets */ ++ int is_clean_aged_sets_sched; /* to know whether clean aged sets is scheduled */ ++ struct workqueue_struct *mdupdate_q; /* Workqueue to handle md updates */ ++ struct workqueue_struct *callback_q; /* Workqueue to handle io callbacks */ ++}; ++ ++#define EIO_CACHE_IOSIZE 0 ++ ++#define EIO_ROUND_SECTOR(dmc, sector) (sector & (~(unsigned long)(dmc->block_size - 1))) ++#define EIO_ROUND_SET_SECTOR(dmc, sector) (sector & (~(unsigned long)((dmc->block_size * dmc->assoc) - 1))) ++ ++/* ++ * The bit definitions are exported to the user space and are in the very beginning of the file. ++ */ ++#define CACHE_VERBOSE_IS_SET(dmc) (((dmc)->cache_flags & CACHE_FLAGS_VERBOSE) ? 1 : 0) ++#define CACHE_INVALIDATE_IS_SET(dmc) (((dmc)->cache_flags & CACHE_FLAGS_INVALIDATE) ? 1 : 0) ++#define CACHE_FAST_REMOVE_IS_SET(dmc) (((dmc)->cache_flags & CACHE_FLAGS_FAST_REMOVE) ? 1 : 0) ++#define CACHE_DEGRADED_IS_SET(dmc) (((dmc)->cache_flags & CACHE_FLAGS_DEGRADED) ? 1 : 0) ++#define CACHE_SSD_ADD_INPROG_IS_SET(dmc) (((dmc)->cache_flags & CACHE_FLAGS_SSD_ADD_INPROG) ? 1 : 0) ++#define CACHE_MD8_IS_SET(dmc) (((dmc)->cache_flags & CACHE_FLAGS_MD8) ? 1 : 0) ++#define CACHE_FAILED_IS_SET(dmc) (((dmc)->cache_flags & CACHE_FLAGS_FAILED) ? 1 : 0) ++#define CACHE_STALE_IS_SET(dmc) (((dmc)->cache_flags & CACHE_FLAGS_STALE) ? 1 : 0) ++ ++/* Device failure handling. */ ++#define CACHE_SRC_IS_ABSENT(dmc) (((dmc)->eio_errors.no_source_dev == 1) ? 1 : 0) ++ ++#define AUTOCLEAN_THRESHOLD_CROSSED(dmc) \ ++ ((atomic64_read(&(dmc)->nr_ios) > (int64_t)(dmc)->sysctl_active.autoclean_threshold) || \ ++ ((dmc)->sysctl_active.autoclean_threshold == 0)) ++ ++#define DIRTY_CACHE_THRESHOLD_CROSSED(dmc) \ ++ ((atomic64_read(&(dmc)->nr_dirty) - atomic64_read(&(dmc)->clean_pendings)) >= \ ++ (int64_t)((dmc)->sysctl_active.dirty_high_threshold * EIO_DIV((dmc)->size, 100)) && \ ++ ((dmc)->sysctl_active.dirty_high_threshold > (dmc)->sysctl_active.dirty_low_threshold)) ++ ++#define DIRTY_SET_THRESHOLD_CROSSED(dmc, set) \ ++ (((dmc)->cache_sets[(set)].nr_dirty >= (u_int32_t)((dmc)->sysctl_active.dirty_set_high_threshold * (dmc)->assoc) / 100) && \ ++ ((dmc)->sysctl_active.dirty_set_high_threshold > (dmc)->sysctl_active.dirty_set_low_threshold)) ++ ++/* ++ * Do not reverse the order of disk and cache! Code ++ * relies on this ordering. (Eg: eio_dm_io_async_bvec()). ++ */ ++struct job_io_regions { ++ struct eio_io_region disk; /* has to be the first member */ ++ struct eio_io_region cache; /* has to be the second member */ ++}; ++ ++#define EB_MAIN_IO 1 ++#define EB_SUBORDINATE_IO 2 ++#define EB_INVAL 4 ++#define GET_BIO_FLAGS(ebio) ((ebio)->eb_bc->bc_bio->bi_rw) ++#define VERIFY_BIO_FLAGS(ebio) EIO_ASSERT((ebio) && (ebio)->eb_bc && (ebio)->eb_bc->bc_bio) ++ ++#define SET_BARRIER_FLAGS(rw_flags) (rw_flags |= (REQ_WRITE | REQ_FLUSH)) ++ ++struct eio_bio { ++ int eb_iotype; ++ struct bio_container *eb_bc; ++ unsigned eb_cacheset; ++ sector_t eb_sector; /*sector number*/ ++ unsigned eb_size; /*size in bytes*/ ++ struct bio_vec *eb_bv; /*bvec pointer*/ ++ unsigned eb_nbvec; /*number of bio_vecs*/ ++ int eb_dir; /* io direction*/ ++ struct eio_bio *eb_next; /*used for splitting reads*/ ++ index_t eb_index; /*for read bios*/ ++ atomic_t eb_holdcount; /* ebio hold count, currently used only for dirty block I/O */ ++ struct bio_vec eb_rbv[0]; ++}; ++ ++enum eio_io_dir { ++ EIO_IO_INVALID_DIR = 0, ++ CACHED_WRITE, ++ CACHED_READ, ++ UNCACHED_WRITE, ++ UNCACHED_READ, ++ UNCACHED_READ_AND_READFILL ++}; ++ ++/* ASK ++ * Container for all eio_bio corresponding to a given bio ++ */ ++struct bio_container { ++ spinlock_t bc_lock; /* lock protecting the bc fields */ ++ atomic_t bc_holdcount; /* number of ebios referencing bc */ ++ struct bio *bc_bio; /* bio for the bc */ ++ struct cache_c *bc_dmc; /* cache structure */ ++ struct eio_bio *bc_mdlist; /* ebios waiting for md update */ ++ int bc_mdwait; /* count of ebios that will do md update */ ++ struct mdupdate_request *mdreqs; /* mdrequest structures required for md update */ ++ struct set_seq *bc_setspan; /* sets spanned by the bc(used only for wb) */ ++ struct set_seq bc_singlesspan; /* used(by wb) if bc spans a single set sequence */ ++ enum eio_io_dir bc_dir; /* bc I/O direction */ ++ int bc_error; /* error encountered during processing bc */ ++ unsigned long bc_iotime; /* maintains i/o time in jiffies */ ++ struct bio_container *bc_next; /* next bc in the chain */ ++}; ++ ++/* structure used as callback context during synchronous I/O */ ++struct sync_io_context { ++ struct rw_semaphore sio_lock; ++ unsigned long sio_error; ++}; ++ ++struct kcached_job { ++ struct list_head list; ++ struct work_struct work; ++ struct cache_c *dmc; ++ struct eio_bio *ebio; ++ struct job_io_regions job_io_regions; ++ index_t index; ++ int action; ++ int error; ++ struct flash_cacheblock *md_sector; ++ struct bio_vec md_io_bvec; ++ struct kcached_job *next; ++}; ++ ++struct ssd_rm_list { ++ struct cache_c *dmc; ++ int action; ++ dev_t devt; ++ enum dev_notifier note; ++ struct list_head list; ++}; ++ ++struct dbn_index_pair { ++ sector_t dbn; ++ index_t index; ++}; ++ ++/* ++ * Subsection 3: Function prototypes and definitions. ++ */ ++ ++struct kcached_job *eio_alloc_cache_job(void); ++void eio_free_cache_job(struct kcached_job *job); ++struct kcached_job *pop(struct list_head *jobs); ++void push(struct list_head *jobs, struct kcached_job *job); ++void do_work(struct work_struct *unused); ++void update_job_cacheregion(struct kcached_job *job, struct cache_c *dmc, ++ struct eio_bio *bio); ++void push_io(struct kcached_job *job); ++void push_md_io(struct kcached_job *job); ++void push_md_complete(struct kcached_job *job); ++void push_uncached_io_complete(struct kcached_job *job); ++int eio_io_empty(void); ++int eio_md_io_empty(void); ++int eio_md_complete_empty(void); ++void eio_md_write_done(struct kcached_job *job); ++void eio_ssderror_diskread(struct kcached_job *job); ++void eio_md_write(struct kcached_job *job); ++void eio_md_write_kickoff(struct kcached_job *job); ++void eio_do_readfill(struct work_struct *work); ++void eio_comply_dirty_thresholds(struct cache_c *dmc, index_t set); ++void eio_clean_all(struct cache_c *dmc); ++void eio_clean_for_reboot(struct cache_c *dmc); ++void eio_clean_aged_sets(struct work_struct *work); ++void eio_comply_dirty_thresholds(struct cache_c *dmc, index_t set); ++#ifndef SSDCACHE ++void eio_reclaim_lru_movetail(struct cache_c *dmc, index_t index, ++ struct eio_policy *); ++#endif /* !SSDCACHE */ ++int eio_io_sync_vm(struct cache_c *dmc, struct eio_io_region *where, int rw, ++ struct bio_vec *bvec, int nbvec); ++int eio_io_sync_pages(struct cache_c *dmc, struct eio_io_region *where, int rw, ++ struct page **pages, int num_bvecs); ++void eio_update_sync_progress(struct cache_c *dmc); ++void eio_plug_cache_device(struct cache_c *dmc); ++void eio_unplug_cache_device(struct cache_c *dmc); ++void eio_plug_disk_device(struct cache_c *dmc); ++void eio_unplug_disk_device(struct cache_c *dmc); ++int dm_io_async_bvec(unsigned int num_regions, struct eio_io_region *where, ++ int rw, struct bio_vec *bvec, eio_notify_fn fn, ++ void *context); ++void eio_put_cache_device(struct cache_c *dmc); ++void eio_suspend_caching(struct cache_c *dmc, enum dev_notifier note); ++void eio_resume_caching(struct cache_c *dmc, char *dev); ++int eio_ctr_ssd_add(struct cache_c *dmc, char *dev); ++ ++/* procfs */ ++void eio_module_procfs_init(void); ++void eio_module_procfs_exit(void); ++void eio_procfs_ctr(struct cache_c *dmc); ++void eio_procfs_dtr(struct cache_c *dmc); ++ ++int eio_sb_store(struct cache_c *dmc); ++ ++int eio_md_destroy(struct dm_target *tip, char *namep, char *srcp, char *cachep, ++ int force); ++ ++/* eio_conf.c */ ++extern int eio_ctr(struct dm_target *ti, unsigned int argc, char **argv); ++extern void eio_dtr(struct dm_target *ti); ++extern int eio_md_destroy(struct dm_target *tip, char *namep, char *srcp, ++ char *cachep, int force); ++extern int eio_ctr_ssd_add(struct cache_c *dmc, char *dev); ++ ++/* thread related functions */ ++void *eio_create_thread(int (*func)(void *), void *context, char *name); ++void eio_thread_exit(long exit_code); ++void eio_wait_thread_exit(void *thrdptr, int *notifier); ++ ++/* eio_main.c */ ++extern int eio_map(struct cache_c *, struct request_queue *, struct bio *); ++extern void eio_md_write_done(struct kcached_job *job); ++extern void eio_ssderror_diskread(struct kcached_job *job); ++extern void eio_md_write(struct kcached_job *job); ++extern void eio_md_write_kickoff(struct kcached_job *job); ++extern void eio_do_readfill(struct work_struct *work); ++extern void eio_check_dirty_thresholds(struct cache_c *dmc, index_t set); ++extern void eio_clean_all(struct cache_c *dmc); ++extern int eio_clean_thread_proc(void *context); ++extern void eio_touch_set_lru(struct cache_c *dmc, index_t set); ++extern void eio_inval_range(struct cache_c *dmc, sector_t iosector, ++ unsigned iosize); ++extern int eio_invalidate_sanity_check(struct cache_c *dmc, u_int64_t iosector, ++ u_int64_t *iosize); ++/* ++ * Invalidates all cached blocks without waiting for them to complete ++ * Should be called with incoming IO suspended ++ */ ++extern int eio_invalidate_cache(struct cache_c *dmc); ++ ++/* eio_mem.c */ ++extern int eio_mem_init(struct cache_c *dmc); ++extern u_int32_t eio_hash_block(struct cache_c *dmc, sector_t dbn); ++extern unsigned int eio_shrink_dbn(struct cache_c *dmc, sector_t dbn); ++extern sector_t eio_expand_dbn(struct cache_c *dmc, u_int64_t index); ++extern void eio_invalidate_md(struct cache_c *dmc, u_int64_t index); ++extern void eio_md4_dbn_set(struct cache_c *dmc, u_int64_t index, ++ u_int32_t dbn_24); ++extern void eio_md8_dbn_set(struct cache_c *dmc, u_int64_t index, sector_t dbn); ++ ++/* eio_procfs.c */ ++extern void eio_module_procfs_init(void); ++extern void eio_module_procfs_exit(void); ++extern void eio_procfs_ctr(struct cache_c *dmc); ++extern void eio_procfs_dtr(struct cache_c *dmc); ++extern int eio_version_query(size_t buf_sz, char *bufp); ++ ++/* eio_subr.c */ ++extern void eio_free_cache_job(struct kcached_job *job); ++extern void eio_do_work(struct work_struct *unused); ++extern struct kcached_job *eio_new_job(struct cache_c *dmc, struct eio_bio *bio, ++ index_t index); ++extern void eio_push_ssdread_failures(struct kcached_job *job); ++extern void eio_push_md_io(struct kcached_job *job); ++extern void eio_push_md_complete(struct kcached_job *job); ++extern void eio_push_uncached_io_complete(struct kcached_job *job); ++extern int eio_io_empty(void); ++extern int eio_io_sync_vm(struct cache_c *dmc, struct eio_io_region *where, ++ int rw, struct bio_vec *bvec, int nbvec); ++extern void eio_unplug_cache_device(struct cache_c *dmc); ++extern void eio_put_cache_device(struct cache_c *dmc); ++extern void eio_suspend_caching(struct cache_c *dmc, enum dev_notifier note); ++extern void eio_resume_caching(struct cache_c *dmc, char *dev); ++ ++static inline void ++EIO_DBN_SET(struct cache_c *dmc, u_int64_t index, sector_t dbn) ++{ ++ if (EIO_MD8(dmc)) ++ eio_md8_dbn_set(dmc, index, dbn); ++ else ++ eio_md4_dbn_set(dmc, index, eio_shrink_dbn(dmc, dbn)); ++ if (dbn == 0) ++ dmc->index_zero = index; ++} ++ ++static inline u_int64_t EIO_DBN_GET(struct cache_c *dmc, u_int64_t index) ++{ ++ if (EIO_MD8(dmc)) ++ return dmc->cache_md8[index].md8_u.u_i_md8 & EIO_MD8_DBN_MASK; ++ ++ return eio_expand_dbn(dmc, index); ++} ++ ++static inline void ++EIO_CACHE_STATE_SET(struct cache_c *dmc, u_int64_t index, u_int8_t cache_state) ++{ ++ if (EIO_MD8(dmc)) ++ dmc->cache_md8[index].md8_u.u_s_md8.cache_state = cache_state; ++ else ++ dmc->cache[index].md4_u.u_s_md4.cache_state = cache_state; ++} ++ ++static inline u_int8_t ++EIO_CACHE_STATE_GET(struct cache_c *dmc, u_int64_t index) ++{ ++ u_int8_t cache_state; ++ ++ if (EIO_MD8(dmc)) ++ cache_state = dmc->cache_md8[index].md8_u.u_s_md8.cache_state; ++ else ++ cache_state = dmc->cache[index].md4_u.u_s_md4.cache_state; ++ return cache_state; ++} ++ ++static inline void ++EIO_CACHE_STATE_OFF(struct cache_c *dmc, index_t index, u_int8_t bitmask) ++{ ++ u_int8_t cache_state = EIO_CACHE_STATE_GET(dmc, index); ++ ++ cache_state &= ~bitmask; ++ EIO_CACHE_STATE_SET(dmc, index, cache_state); ++} ++ ++static inline void ++EIO_CACHE_STATE_ON(struct cache_c *dmc, index_t index, u_int8_t bitmask) ++{ ++ u_int8_t cache_state = EIO_CACHE_STATE_GET(dmc, index); ++ ++ cache_state |= bitmask; ++ EIO_CACHE_STATE_SET(dmc, index, cache_state); ++} ++ ++void eio_set_warm_boot(void); ++#endif /* defined(__KERNEL__) */ ++ ++#include "eio_ioctl.h" ++ ++/* resolve conflict with scsi/scsi_device.h */ ++#ifdef __KERNEL__ ++ ++#ifdef EIO_ASSERT ++#undef EIO_ASSERT ++#endif ++/*Always compiled in*/ ++#define EIO_ASSERT(x) BUG_ON(unlikely(!(x))) ++ ++extern sector_t eio_get_device_size(struct eio_bdev *); ++extern sector_t eio_get_device_start_sect(struct eio_bdev *); ++#endif /* __KERNEL__ */ ++ ++#define EIO_INIT_EVENT(ev) ((ev)->process = NULL) ++ ++/*Assumes that the macro gets called under the same spinlock as in wait event*/ ++#define EIO_SET_EVENT_AND_UNLOCK(ev, sl, flags) \ ++ do { \ ++ struct task_struct *p = NULL; \ ++ if ((ev)->process) { \ ++ (p) = (ev)->process; \ ++ (ev)->process = NULL; \ ++ } \ ++ spin_unlock_irqrestore((sl), flags); \ ++ if (p) { \ ++ (void)wake_up_process(p); \ ++ } \ ++ } while (0) ++ ++/*Assumes that the spin lock sl is taken while calling this macro*/ ++#define EIO_WAIT_EVENT(ev, sl, flags) \ ++ do { \ ++ (ev)->process = current; \ ++ set_current_state(TASK_INTERRUPTIBLE); \ ++ spin_unlock_irqrestore((sl), flags); \ ++ (void)schedule_timeout(10 * HZ); \ ++ spin_lock_irqsave((sl), flags); \ ++ (ev)->process = NULL; \ ++ } while (0) ++ ++#define EIO_CLEAR_EVENT(ev) ((ev)->process = NULL) ++ ++#include "eio_setlru.h" ++#include "eio_policy.h" ++#define EIO_CACHE(dmc) (EIO_MD8(dmc) ? (void *)dmc->cache_md8 : (void *)dmc->cache) ++ ++#endif /* !EIO_INC_H */ +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_conf.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_conf.c +--- linux-3.10.30/drivers/block/enhanceio/eio_conf.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_conf.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,2630 @@ ++/* ++ * eio_conf.c ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * Amit Kale ++ * Restructured much of the io code to split bio within map function instead ++ * of letting dm do it. ++ * Simplified queued logic for write through. ++ * Amit Kale ++ * Harish Pujari ++ * Designed and implemented the writeback caching mode ++ * ++ * Copyright 2010 Facebook, Inc. ++ * Author: Mohan Srinivasan (mohan@facebook.com) ++ * ++ * Based on DM-Cache: ++ * Copyright (C) International Business Machines Corp., 2006 ++ * Author: Ming Zhao (mingzhao@ufl.edu) ++ * ++ * 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; under 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, see . ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include "eio.h" ++#include "eio_ttc.h" ++ ++#define KMEM_CACHE_JOB "eio-kcached-jobs" ++#define KMEM_EIO_IO "eio-io-context" ++#define KMEM_DMC_BIO_PAIR "eio-dmc-bio-pair" ++/* #define KMEM_CACHE_PENDING_JOB "eio-pending-jobs" */ ++ ++static struct cache_c *cache_list_head; ++struct work_struct _kcached_wq; ++ ++static struct kmem_cache *_job_cache; ++struct kmem_cache *_io_cache; /* cache of eio_context objects */ ++mempool_t *_job_pool; ++mempool_t *_io_pool; /* pool of eio_context object */ ++ ++atomic_t nr_cache_jobs; ++ ++ ++LIST_HEAD(ssd_rm_list); ++int ssd_rm_list_not_empty; ++spinlock_t ssd_rm_list_lock; ++ ++struct eio_control_s *eio_control; ++ ++int eio_force_warm_boot; ++static int eio_notify_reboot(struct notifier_block *nb, unsigned long action, ++ void *x); ++void eio_stop_async_tasks(struct cache_c *dmc); ++static int eio_notify_ssd_rm(struct notifier_block *nb, unsigned long action, ++ void *x); ++ ++/* ++ * The notifiers are registered in descending order of priority and ++ * executed in descending order or priority. We should be run before ++ * any notifiers of ssd's or other block devices. Typically, devices ++ * use a priority of 0. ++ * XXX - If in the future we happen to use a md device as the cache ++ * block device, we have a problem because md uses a priority of ++ * INT_MAX as well. But we want to run before the md's reboot notifier ! ++ */ ++static struct notifier_block eio_reboot_notifier = { ++ .notifier_call = eio_notify_reboot, ++ .next = NULL, ++ .priority = INT_MAX, /* should be > ssd pri's and disk dev pri's */ ++}; ++ ++static struct notifier_block eio_ssd_rm_notifier = { ++ .notifier_call = eio_notify_ssd_rm, ++ .next = NULL, ++ .priority = 0, ++}; ++ ++int eio_wait_schedule(void *unused) ++{ ++ ++ schedule(); ++ return 0; ++} ++ ++/* ++ * Check if the System RAM threshold > requested memory, don't care ++ * if threshold is set to 0. Return value is 0 for fail and 1 for success. ++ */ ++static inline int eio_mem_available(struct cache_c *dmc, size_t size) ++{ ++ struct sysinfo si; ++ ++ if (unlikely ++ (dmc->sysctl_active.mem_limit_pct <= 0 ++ || dmc->sysctl_active.mem_limit_pct >= 100)) ++ return 1; ++ ++ si_meminfo(&si); ++ return (((si.freeram << PAGE_SHIFT) * ++ dmc->sysctl_active.mem_limit_pct) / 100) > size; ++} ++ ++/* create a new thread and call the specified function */ ++void *eio_create_thread(int (*func)(void *), void *context, char *name) ++{ ++ return kthread_run(func, context, "%s", name); ++} ++ ++/* wait for the given thread to exit */ ++void eio_wait_thread_exit(void *thrdptr, int *running) ++{ ++ while (*running) ++ msleep(1); ++ ++ /*do_exit() would be called within the thread func itself*/ ++ ++ return; ++} ++ ++/* thread exit self */ ++void eio_thread_exit(long exit_code) ++{ ++ do_exit(exit_code); ++} ++const char *eio_policy_to_name(u8 p) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(eio_policy_names); i++) ++ if (eio_policy_names[i].p == p) ++ return eio_policy_names[i].n; ++ ++ return NULL; ++} ++ ++ ++inline int eio_policy_init(struct cache_c *dmc) ++{ ++ ++ if (dmc->req_policy == 0) ++ dmc->req_policy = CACHE_REPL_DEFAULT; ++ dmc->policy_ops = eio_get_policy(dmc->req_policy); ++ if (dmc->policy_ops == NULL) { ++ pr_err("eio_policy_init: Failed to initialize %s(%d) policy", ++ eio_policy_to_name(dmc->req_policy), dmc->req_policy); ++ return -EINVAL; ++ } else { ++ /* Back pointer to reference dmc from policy_ops */ ++ dmc->policy_ops->sp_dmc = dmc; ++ pr_info("Setting replacement policy to %s (%d)", ++ eio_policy_to_name(dmc->policy_ops->sp_name), ++ dmc->policy_ops->sp_name); ++ return 0; ++ } ++} ++ ++static int eio_jobs_init(void) ++{ ++ ++ _job_cache = _io_cache = NULL; ++ _job_pool = _io_pool = NULL; ++ ++ _job_cache = kmem_cache_create(KMEM_CACHE_JOB, ++ sizeof(struct kcached_job), ++ __alignof__(struct kcached_job), ++ 0, NULL); ++ if (!_job_cache) ++ return -ENOMEM; ++ ++ _job_pool = mempool_create(MIN_JOBS, mempool_alloc_slab, ++ mempool_free_slab, _job_cache); ++ if (!_job_pool) ++ goto out; ++ ++ _io_cache = kmem_cache_create(KMEM_EIO_IO, ++ sizeof(struct eio_context), ++ __alignof__(struct eio_context), 0, NULL); ++ if (!_io_cache) ++ goto out; ++ ++ _io_pool = mempool_create(MIN_EIO_IO, mempool_alloc_slab, ++ mempool_free_slab, _io_cache); ++ if (!_io_pool) ++ goto out; ++ ++ return 0; ++ ++out: ++ if (_io_pool) ++ mempool_destroy(_io_pool); ++ if (_io_cache) ++ kmem_cache_destroy(_io_cache); ++ if (_job_pool) ++ mempool_destroy(_job_pool); ++ if (_job_cache) ++ kmem_cache_destroy(_job_cache); ++ ++ _job_pool = _io_pool = NULL; ++ _job_cache = _io_cache = NULL; ++ return -ENOMEM; ++} ++ ++static void eio_jobs_exit(void) ++{ ++ ++ mempool_destroy(_io_pool); ++ mempool_destroy(_job_pool); ++ kmem_cache_destroy(_io_cache); ++ kmem_cache_destroy(_job_cache); ++ ++ _job_pool = _io_pool = NULL; ++ _job_cache = _io_cache = NULL; ++} ++ ++static int eio_kcached_init(struct cache_c *dmc) ++{ ++ ++ /* init_waitqueue_head(&dmc->destroyq); */ ++ atomic_set(&dmc->nr_jobs, 0); ++ return 0; ++} ++ ++static void eio_kcached_client_destroy(struct cache_c *dmc) ++{ ++ ++ /* Wait for all IOs ++ /wait_event(dmc->destroyq, !atomic_read(&dmc->nr_jobs));*/ ++} ++ ++/* Store the cache superblock on ssd */ ++int eio_sb_store(struct cache_c *dmc) ++{ ++ union eio_superblock *sb = NULL; ++ struct eio_io_region where; ++ int error; ++ ++ struct bio_vec *sb_pages; ++ int nr_pages; ++ int page_count, page_index; ++ ++ if ((unlikely(CACHE_FAILED_IS_SET(dmc)) || CACHE_DEGRADED_IS_SET(dmc)) ++ && (!CACHE_SSD_ADD_INPROG_IS_SET(dmc))) { ++ pr_err ++ ("sb_store: Cannot write superblock for cache \"%s\", in degraded/failed mode.\n", ++ dmc->cache_name); ++ return -ENODEV; ++ } ++ ++ page_count = 0; ++ nr_pages = EIO_SUPERBLOCK_SIZE / PAGE_SIZE; ++ EIO_ASSERT(nr_pages != 0); ++ ++ sb_pages = eio_alloc_pages(nr_pages, &page_count); ++ if (sb_pages == NULL) { ++ pr_err("sb_store: System memory too low.\n"); ++ return -ENOMEM; ++ } ++ ++ EIO_ASSERT(page_count == nr_pages); ++ ++ nr_pages = page_count; ++ page_index = 0; ++ sb = (union eio_superblock *)kmap(sb_pages[page_index].bv_page); ++ ++ sb->sbf.cache_sb_state = cpu_to_le32(dmc->sb_state); ++ sb->sbf.block_size = cpu_to_le32(dmc->block_size); ++ sb->sbf.size = cpu_to_le32(dmc->size); ++ sb->sbf.assoc = cpu_to_le32(dmc->assoc); ++ sb->sbf.cache_md_start_sect = cpu_to_le64(dmc->md_start_sect); ++ sb->sbf.cache_data_start_sect = cpu_to_le64(dmc->md_sectors); ++ strncpy(sb->sbf.disk_devname, dmc->disk_devname, DEV_PATHLEN); ++ strncpy(sb->sbf.cache_devname, dmc->cache_devname, DEV_PATHLEN); ++ strncpy(sb->sbf.ssd_uuid, dmc->ssd_uuid, DEV_PATHLEN - 1); ++ sb->sbf.cache_devsize = cpu_to_le64(eio_to_sector(eio_get_device_size(dmc->cache_dev))); ++ sb->sbf.disk_devsize = cpu_to_le64(eio_to_sector(eio_get_device_size(dmc->disk_dev))); ++ sb->sbf.cache_version = cpu_to_le32(dmc->sb_version); ++ strncpy(sb->sbf.cache_name, dmc->cache_name, DEV_PATHLEN); ++ sb->sbf.cache_name[DEV_PATHLEN - 1] = '\0'; ++ sb->sbf.mode = cpu_to_le32(dmc->mode); ++ spin_lock_irqsave(&dmc->cache_spin_lock, dmc->cache_spin_lock_flags); ++ sb->sbf.repl_policy = cpu_to_le32(dmc->req_policy); ++ sb->sbf.cache_flags = cpu_to_le32(dmc->cache_flags & ~CACHE_FLAGS_INCORE_ONLY); ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ if (dmc->sb_version) ++ sb->sbf.magic = cpu_to_le32(EIO_MAGIC); ++ else ++ sb->sbf.magic = cpu_to_le32(EIO_BAD_MAGIC); ++ ++ sb->sbf.cold_boot = cpu_to_le32(dmc->cold_boot); ++ if (le32_to_cpu(sb->sbf.cold_boot) && eio_force_warm_boot) ++ sb->sbf.cold_boot = cpu_to_le32(le32_to_cpu(sb->sbf.cold_boot) | ++ BOOT_FLAG_FORCE_WARM); ++ ++ sb->sbf.dirty_high_threshold = cpu_to_le32(dmc->sysctl_active.dirty_high_threshold); ++ sb->sbf.dirty_low_threshold = cpu_to_le32(dmc->sysctl_active.dirty_low_threshold); ++ sb->sbf.dirty_set_high_threshold = ++ cpu_to_le32(dmc->sysctl_active.dirty_set_high_threshold); ++ sb->sbf.dirty_set_low_threshold = ++ cpu_to_le32(dmc->sysctl_active.dirty_set_low_threshold); ++ sb->sbf.time_based_clean_interval = ++ cpu_to_le32(dmc->sysctl_active.time_based_clean_interval); ++ sb->sbf.autoclean_threshold = cpu_to_le32(dmc->sysctl_active.autoclean_threshold); ++ ++ /* write out to ssd */ ++ where.bdev = dmc->cache_dev->bdev; ++ where.sector = EIO_SUPERBLOCK_START; ++ where.count = eio_to_sector(EIO_SUPERBLOCK_SIZE); ++ error = eio_io_sync_vm(dmc, &where, WRITE, sb_pages, nr_pages); ++ if (error) { ++ pr_err ++ ("sb_store: Could not write out superblock to sector %llu (error %d) for cache \"%s\".\n", ++ (unsigned long long)where.sector, error, dmc->cache_name); ++ } ++ ++ /* free the allocated pages here */ ++ if (sb_pages) { ++ kunmap(sb_pages[0].bv_page); ++ for (page_index = 0; page_index < nr_pages; page_index++) ++ put_page(sb_pages[page_index].bv_page); ++ kfree(sb_pages); ++ sb_pages = NULL; ++ } ++ ++ return error; ++} ++ ++/* ++ * Write out the metadata one sector at a time. ++ * Then dump out the superblock. ++ */ ++int eio_md_store(struct cache_c *dmc) ++{ ++ struct flash_cacheblock *next_ptr; ++ struct eio_io_region where; ++ sector_t i; ++ int j, k; ++ int num_valid = 0, num_dirty = 0; ++ int error; ++ int write_errors = 0; ++ sector_t sectors_written = 0, sectors_expected = 0; /* debug */ ++ int slots_written = 0; /* How many cache slots did we fill in this MD io block ? */ ++ ++ struct bio_vec *pages; ++ int nr_pages; ++ int page_count, page_index; ++ void **pg_virt_addr; ++ ++ if (unlikely(CACHE_FAILED_IS_SET(dmc)) ++ || unlikely(CACHE_DEGRADED_IS_SET(dmc))) { ++ pr_err ++ ("md_store: Cannot write metadata in failed/degraded mode for cache \"%s\".", ++ dmc->cache_name); ++ return -ENODEV; ++ } ++ ++ if (CACHE_FAST_REMOVE_IS_SET(dmc)) { ++ if (CACHE_VERBOSE_IS_SET(dmc)) ++ pr_info("Skipping writing out metadata to cache"); ++ if (!dmc->sb_version) { ++ ++ /* ++ * Incase of delete, flush the superblock ++ * irrespective of fast_remove being set. ++ */ ++ ++ goto sb_store; ++ } ++ return 0; ++ } ++ ++ if (!eio_mem_available(dmc, METADATA_IO_BLOCKSIZE_SECT)) { ++ pr_err ++ ("md_store: System memory too low for allocating metadata IO buffers"); ++ return -ENOMEM; ++ } ++ ++ page_count = 0; ++ pages = eio_alloc_pages(dmc->bio_nr_pages, &page_count); ++ if (pages == NULL) { ++ pr_err("eio_md_store: System memory too low."); ++ return -ENOMEM; ++ } ++ ++ /* get the exact number of pages allocated */ ++ nr_pages = page_count; ++ where.bdev = dmc->cache_dev->bdev; ++ where.sector = dmc->md_start_sect; ++ slots_written = 0; ++ page_index = 0; ++ ++ pg_virt_addr = kmalloc(nr_pages * (sizeof(void *)), GFP_KERNEL); ++ if (pg_virt_addr == NULL) { ++ pr_err("eio_md_store: System memory too low."); ++ for (k = 0; k < nr_pages; k++) ++ put_page(pages[k].bv_page); ++ kfree(pages); ++ return -ENOMEM; ++ } ++ ++ for (k = 0; k < nr_pages; k++) ++ pg_virt_addr[k] = kmap(pages[k].bv_page); ++ ++ next_ptr = (struct flash_cacheblock *)pg_virt_addr[page_index]; ++ j = MD_BLOCKS_PER_PAGE; ++ ++ pr_info("Writing out metadata to cache device. Please wait..."); ++ ++ for (i = 0; i < dmc->size; i++) { ++ if (EIO_CACHE_STATE_GET(dmc, (index_t)i) & VALID) ++ num_valid++; ++ if (EIO_CACHE_STATE_GET(dmc, (index_t)i) & DIRTY) ++ num_dirty++; ++ next_ptr->dbn = cpu_to_le64(EIO_DBN_GET(dmc, i)); ++ next_ptr->cache_state = cpu_to_le64(EIO_CACHE_STATE_GET(dmc, (index_t)i) & ++ (INVALID | VALID | DIRTY)); ++ ++ next_ptr++; ++ slots_written++; ++ j--; ++ if (j == 0) { ++ /* ++ * Filled the page, goto the next page. ++ */ ++ page_index++; ++ ++ if (slots_written == ++ (int)(MD_BLOCKS_PER_PAGE * nr_pages)) { ++ /* ++ * Wrote out an entire metadata IO block, write the block to the ssd. ++ */ ++ where.count = ++ slots_written / MD_BLOCKS_PER_SECTOR; ++ slots_written = 0; ++ page_index = 0; ++ sectors_written += where.count; /* debug */ ++ ++ error = ++ eio_io_sync_vm(dmc, &where, WRITE, pages, ++ nr_pages); ++ ++ if (error) { ++ write_errors++; ++ pr_err ++ ("md_store: Could not write out metadata to sector %llu (error %d)", ++ (unsigned long long)where.sector, error); ++ } ++ where.sector += where.count; /* Advance offset */ ++ } ++ /* Move next slot pointer into next sector */ ++ next_ptr = ++ (struct flash_cacheblock *)pg_virt_addr[page_index]; ++ j = MD_BLOCKS_PER_PAGE; ++ } ++ } ++ ++ if (next_ptr != (struct flash_cacheblock *)pg_virt_addr[0]) { ++ /* Write the remaining last page out */ ++ EIO_ASSERT(slots_written > 0); ++ ++ where.count = slots_written / MD_BLOCKS_PER_SECTOR; ++ ++ if (slots_written % MD_BLOCKS_PER_SECTOR) ++ where.count++; ++ ++ sectors_written += where.count; ++ ++ /* ++ * This may happen that we are at the beginning of the next page ++ * and did not fill up any slots in this page. Verify this condition ++ * and set page_index accordingly. ++ */ ++ ++ if (next_ptr != ++ (struct flash_cacheblock *)pg_virt_addr[page_index]) { ++ unsigned offset; ++ ++ slots_written = slots_written % MD_BLOCKS_PER_PAGE; ++ ++ /* ++ * We have some extra slots written at this page_index. ++ * Let us try to zero out the remaining page size before submitting ++ * this page. ++ */ ++ offset = ++ slots_written * (sizeof(struct flash_cacheblock)); ++ memset(pg_virt_addr[page_index] + offset, 0, ++ PAGE_SIZE - offset); ++ ++ page_index++; ++ } ++ ++ error = eio_io_sync_vm(dmc, &where, WRITE, pages, page_index); ++ /* XXX: should we call eio_sb_store() on error ?? */ ++ if (error) { ++ write_errors++; ++ pr_err ++ ("md_store: Could not write out metadata to sector %llu (error %d)", ++ (unsigned long long)where.sector, error); ++ } ++ } ++ ++ /* Debug Tests */ ++ sectors_expected = EIO_DIV(dmc->size, MD_BLOCKS_PER_SECTOR); ++ if (EIO_REM(dmc->size, MD_BLOCKS_PER_SECTOR)) ++ sectors_expected++; ++ EIO_ASSERT(sectors_expected == sectors_written); ++ /* XXX: should we call eio_sb_store() on error ?? */ ++ if (sectors_expected != sectors_written) { ++ pr_err ++ ("md_store: Sector mismatch! sectors_expected=%llu, sectors_written=%llu\n", ++ (unsigned long long)sectors_expected, (unsigned long long)sectors_written); ++ } ++ ++ for (k = 0; k < nr_pages; k++) ++ kunmap(pages[k].bv_page); ++ kfree(pg_virt_addr); ++ ++ if (pages) ++ for (k = 0; k < nr_pages; k++) ++ put_page(pages[k].bv_page); ++ kfree(pages); ++ pages = NULL; ++ ++ if (write_errors == 0) { ++ if (num_dirty == 0) ++ dmc->sb_state = CACHE_MD_STATE_CLEAN; ++ else ++ dmc->sb_state = CACHE_MD_STATE_FASTCLEAN; ++ } else ++ dmc->sb_state = CACHE_MD_STATE_UNSTABLE; ++ ++sb_store: ++ error = eio_sb_store(dmc); ++ if (error) { ++ /* TBD. should we return error */ ++ write_errors++; ++ pr_err("md_store: superblock store failed(error %d)", error); ++ } ++ if (!dmc->sb_version && CACHE_FAST_REMOVE_IS_SET(dmc)) ++ return 0; ++ ++ if (write_errors == 0) ++ pr_info("Metadata saved on the cache device"); ++ else { ++ pr_info ++ ("CRITICAL: There were %d errors in saving metadata on cache device", ++ write_errors); ++ if (num_dirty) ++ pr_info ++ ("CRITICAL: %d dirty blocks could not be written out", ++ num_dirty); ++ } ++ ++ pr_info("Valid blocks: %d, Dirty blocks: %d, Metadata sectors: %llu", ++ num_valid, num_dirty, (long long unsigned int)dmc->md_sectors); ++ ++ return 0; ++} ++ ++static int eio_md_create(struct cache_c *dmc, int force, int cold) ++{ ++ struct flash_cacheblock *next_ptr; ++ union eio_superblock *header; ++ struct eio_io_region where; ++ sector_t i; ++ int j, error; ++ uint64_t cache_size, dev_size; ++ sector_t order; ++ sector_t sectors_written = 0, sectors_expected = 0; /* debug */ ++ int slots_written = 0; /* How many cache slots did we fill in this MD io block ? */ ++ ++ struct bio_vec *header_page = NULL; /* Header page */ ++ struct bio_vec *pages = NULL; /* Metadata pages */ ++ int nr_pages = 0; ++ int page_count, page_index; ++ int ret = 0, k; ++ void **pg_virt_addr = NULL; ++ ++ /* Allocate single page for superblock header.*/ ++ page_count = 0; ++ header_page = eio_alloc_pages(1, &page_count); ++ if (header_page == NULL) { ++ pr_err("eio_md_create: System memory too low."); ++ return -ENOMEM; ++ } ++ ++ EIO_ASSERT(page_count = 1); ++ header = (union eio_superblock *)kmap(header_page[0].bv_page); ++ ++ /* ++ * Apart from normal cache creation, eio_md_create() is also called when ++ * the SSD is added as part of eio_resume_caching(). At this point, ++ * the CACHE_FLAGS_DEGRADED is set, but we do want to write to the md area. ++ * Therefore, if the CACHE_FLAGS_SSD_ADD_INPROG is set, then proceed instead ++ * of returning -ENODEV. ++ */ ++ if ((unlikely(CACHE_FAILED_IS_SET(dmc)) ++ || unlikely(CACHE_DEGRADED_IS_SET(dmc))) ++ && (!CACHE_SSD_ADD_INPROG_IS_SET(dmc))) { ++ pr_err ++ ("md_create: Cannot write metadata in failed/degraded mode for cache \"%s\".\n", ++ dmc->cache_name); ++ ret = -ENODEV; ++ goto free_header; ++ } ++ ++ where.bdev = dmc->cache_dev->bdev; ++ where.sector = EIO_SUPERBLOCK_START; ++ where.count = eio_to_sector(EIO_SUPERBLOCK_SIZE); ++ error = eio_io_sync_vm(dmc, &where, READ, header_page, 1); ++ if (error) { ++ pr_err ++ ("md_create: Could not read superblock sector %llu error %d for cache \"%s\".\n", ++ (unsigned long long)where.sector, error, dmc->cache_name); ++ ret = -EINVAL; ++ goto free_header; ++ } ++ ++ if (!force && ++ ((le32_to_cpu(header->sbf.cache_sb_state) == CACHE_MD_STATE_DIRTY) || ++ (le32_to_cpu(header->sbf.cache_sb_state) == CACHE_MD_STATE_CLEAN) || ++ (le32_to_cpu(header->sbf.cache_sb_state) == CACHE_MD_STATE_FASTCLEAN))) { ++ pr_err ++ ("md_create: Existing cache detected, use force to re-create.\n"); ++ ret = -EINVAL; ++ goto free_header; ++ } ++ ++ /* ++ * Compute the size of the metadata including header. ++ * and here we also are making sure that metadata and userdata ++ * on SSD is aligned at 8K boundary. ++ * ++ * Note dmc->size is in raw sectors ++ */ ++ dmc->md_start_sect = EIO_METADATA_START(dmc->cache_dev_start_sect); ++ dmc->md_sectors = ++ INDEX_TO_MD_SECTOR(EIO_DIV(dmc->size, (sector_t)dmc->block_size)); ++ dmc->md_sectors += ++ EIO_EXTRA_SECTORS(dmc->cache_dev_start_sect, dmc->md_sectors); ++ dmc->size -= dmc->md_sectors; /* total sectors available for cache */ ++ do_div(dmc->size, dmc->block_size); ++ dmc->size = EIO_DIV(dmc->size, dmc->assoc) * (sector_t)dmc->assoc; ++ /* Recompute since dmc->size was possibly trunc'ed down */ ++ dmc->md_sectors = INDEX_TO_MD_SECTOR(dmc->size); ++ dmc->md_sectors += ++ EIO_EXTRA_SECTORS(dmc->cache_dev_start_sect, dmc->md_sectors); ++ ++ error = eio_mem_init(dmc); ++ if (error == -1) { ++ ret = -EINVAL; ++ goto free_header; ++ } ++ if ((unlikely(CACHE_FAILED_IS_SET(dmc)) ++ || unlikely(CACHE_DEGRADED_IS_SET(dmc))) ++ && (!CACHE_SSD_ADD_INPROG_IS_SET(dmc))) { ++ pr_err ++ ("md_create: Cannot write metadata in failed/degraded mode for cache \"%s\".\n", ++ dmc->cache_name); ++ ret = -ENODEV; ++ goto free_header; ++ } ++ dev_size = eio_to_sector(eio_get_device_size(dmc->cache_dev)); ++ cache_size = dmc->md_sectors + (dmc->size * dmc->block_size); ++ if (cache_size > dev_size) { ++ pr_err ++ ("md_create: Requested cache size exceeds the cache device's capacity (%llu > %llu)", ++ (unsigned long long)cache_size, (unsigned long long)dev_size); ++ ret = -EINVAL; ++ goto free_header; ++ } ++ ++ order = ++ dmc->size * ++ (EIO_MD8(dmc) ? sizeof(struct cacheblock_md8) : ++ sizeof(struct cacheblock)); ++ i = EIO_MD8(dmc) ? sizeof(struct cacheblock_md8) : sizeof(struct ++ cacheblock); ++ pr_info("Allocate %lluKB (%lluB per) mem for %llu-entry cache " \ ++ "(capacity:%lluMB, associativity:%u, block size:%u bytes)", ++ (unsigned long long)order >> 10, (unsigned long long)i, ++ (long long unsigned int)dmc->size, ++ (unsigned long long)(cache_size >> (20 - SECTOR_SHIFT)), dmc->assoc, ++ dmc->block_size << SECTOR_SHIFT); ++ ++ if (!eio_mem_available(dmc, order) && !CACHE_SSD_ADD_INPROG_IS_SET(dmc)) { ++ pr_err ++ ("md_create: System memory too low for allocating cache metadata.\n"); ++ ret = -ENOMEM; ++ goto free_header; ++ } ++ ++ /* ++ * If we are called due to SSD add, the memory was already allocated ++ * as part of cache creation (i.e., eio_ctr()) in the past. ++ */ ++ if (!CACHE_SSD_ADD_INPROG_IS_SET(dmc)) { ++ if (EIO_MD8(dmc)) ++ dmc->cache_md8 = vmalloc((size_t)order); ++ else ++ dmc->cache = vmalloc((size_t)order); ++ if ((EIO_MD8(dmc) && !dmc->cache_md8) ++ || (!EIO_MD8(dmc) && !dmc->cache)) { ++ pr_err ++ ("md_create: Unable to allocate cache md for cache \"%s\".\n", ++ dmc->cache_name); ++ ret = -ENOMEM; ++ goto free_header; ++ } ++ } ++ if (eio_repl_blk_init(dmc->policy_ops) != 0) { ++ pr_err ++ ("md_create: Unable to allocate memory for policy cache block for cache \"%s\".\n", ++ dmc->cache_name); ++ ret = -ENOMEM; ++ goto free_header; ++ } ++ ++ if (cold) { ++ int retry = 0; ++ do { ++ for (i = 0; i < dmc->size; i++) { ++ if (CACHE_SSD_ADD_INPROG_IS_SET(dmc)) { ++ u_int8_t cache_state = ++ EIO_CACHE_STATE_GET(dmc, i); ++ if (cache_state & BLOCK_IO_INPROG) { ++ /* sleep for 1 sec and retry */ ++ msleep(1000); ++ break; ++ } ++ } ++ eio_invalidate_md(dmc, i); ++ } ++ } while ((retry++ < 10) && (i < dmc->size)); ++ ++ if (i < dmc->size) { ++ pr_err ++ ("md_create: Cache \"%s\" is not in quiesce state. Can't proceed to resume.\n", ++ dmc->cache_name); ++ ret = -EBUSY; ++ goto free_header; ++ } ++ ++ /* Allocate pages of the order dmc->bio_nr_pages */ ++ page_count = 0; ++ pages = eio_alloc_pages(dmc->bio_nr_pages, &page_count); ++ if (!pages) { ++ pr_err ++ ("md_create: Unable to allocate pages for cache \"%s\".\n", ++ dmc->cache_name); ++ pr_err ++ ("md_create: Could not write out cache metadata.\n"); ++ ret = -ENOMEM; ++ goto free_header; ++ } ++ ++ /* nr_pages is used for freeing the pages */ ++ nr_pages = page_count; ++ ++ where.bdev = dmc->cache_dev->bdev; ++ where.sector = dmc->md_start_sect; ++ slots_written = 0; ++ page_index = 0; ++ ++ pg_virt_addr = kmalloc(nr_pages * (sizeof(void *)), GFP_KERNEL); ++ if (pg_virt_addr == NULL) { ++ pr_err("md_create: System memory too low.\n"); ++ for (k = 0; k < nr_pages; k++) ++ put_page(pages[k].bv_page); ++ kfree(pages); ++ ret = -ENOMEM; ++ goto free_header; ++ } ++ ++ for (k = 0; k < nr_pages; k++) ++ pg_virt_addr[k] = kmap(pages[k].bv_page); ++ ++ next_ptr = (struct flash_cacheblock *)pg_virt_addr[page_index]; ++ j = MD_BLOCKS_PER_PAGE; ++ ++ for (i = 0; i < dmc->size; i++) { ++ next_ptr->dbn = cpu_to_le64(EIO_DBN_GET(dmc, i)); ++ next_ptr->cache_state = ++ cpu_to_le64(EIO_CACHE_STATE_GET(dmc, ++ (index_t)i) & (INVALID | VALID | DIRTY)); ++ next_ptr++; ++ slots_written++; ++ j--; ++ ++ if (j == 0) { ++ ++ page_index++; ++ ++ if ((unsigned)slots_written == ++ MD_BLOCKS_PER_PAGE * nr_pages) { ++ ++ where.count = ++ slots_written / ++ MD_BLOCKS_PER_SECTOR; ++ slots_written = 0; ++ page_index = 0; ++ sectors_written += where.count; /* debug */ ++ error = ++ eio_io_sync_vm(dmc, &where, WRITE, ++ pages, nr_pages); ++ ++ if (error) { ++ if (!CACHE_SSD_ADD_INPROG_IS_SET ++ (dmc)) ++ vfree(EIO_CACHE(dmc)); ++ pr_err ++ ("md_create: Could not write cache metadata sector %llu error %d.\n for cache \"%s\".\n", ++ (unsigned long long)where.sector, error, ++ dmc->cache_name); ++ ret = -EIO; ++ goto free_md; ++ } ++ where.sector += where.count; /* Advance offset */ ++ } ++ ++ /* Move next slot pointer into next page */ ++ next_ptr = ++ (struct flash_cacheblock *) ++ pg_virt_addr[page_index]; ++ j = MD_BLOCKS_PER_PAGE; ++ } ++ } ++ ++ if (next_ptr != (struct flash_cacheblock *)pg_virt_addr[0]) { ++ /* Write the remaining last page out */ ++ EIO_ASSERT(slots_written > 0); ++ ++ where.count = slots_written / MD_BLOCKS_PER_SECTOR; ++ ++ if (slots_written % MD_BLOCKS_PER_SECTOR) ++ where.count++; ++ ++ sectors_written += where.count; ++ ++ if (next_ptr != ++ (struct flash_cacheblock *)pg_virt_addr[page_index]) { ++ unsigned offset; ++ ++ slots_written = ++ slots_written % MD_BLOCKS_PER_PAGE; ++ ++ /* ++ * We have some extra slots written at this page_index. ++ * Let us try to zero out the remaining page size before submitting ++ * this page. ++ */ ++ offset = ++ slots_written * ++ (sizeof(struct flash_cacheblock)); ++ memset(pg_virt_addr[page_index] + offset, 0, ++ PAGE_SIZE - offset); ++ ++ page_index = page_index + 1; ++ } ++ ++ error = ++ eio_io_sync_vm(dmc, &where, WRITE, pages, ++ page_index); ++ if (error) { ++ if (!CACHE_SSD_ADD_INPROG_IS_SET(dmc)) ++ vfree((void *)EIO_CACHE(dmc)); ++ pr_err ++ ("md_create: Could not write cache metadata sector %llu error %d for cache \"%s\".\n", ++ (unsigned long long)where.sector, error, dmc->cache_name); ++ ret = -EIO; ++ goto free_md; ++ } ++ } ++ ++ /* Debug Tests */ ++ sectors_expected = EIO_DIV(dmc->size, MD_BLOCKS_PER_SECTOR); ++ if (EIO_REM(dmc->size, MD_BLOCKS_PER_SECTOR)) ++ sectors_expected++; ++ if (sectors_expected != sectors_written) { ++ pr_err ++ ("md_create: Sector mismatch! sectors_expected=%llu, sectors_written=%llu for cache \"%s\".\n", ++ (unsigned long long)sectors_expected, (unsigned long long)sectors_written, ++ dmc->cache_name); ++ ret = -EIO; ++ goto free_md; ++ } ++ } ++ ++ /* if cold ends here */ ++ /* Write the superblock */ ++ if ((unlikely(CACHE_FAILED_IS_SET(dmc)) ++ || unlikely(CACHE_DEGRADED_IS_SET(dmc))) ++ && (!CACHE_SSD_ADD_INPROG_IS_SET(dmc))) { ++ pr_err ++ ("md_create: Cannot write metadata in failed/degraded mode for cache \"%s\".\n", ++ dmc->cache_name); ++ vfree((void *)EIO_CACHE(dmc)); ++ ret = -ENODEV; ++ goto free_md; ++ } ++ ++ dmc->sb_state = CACHE_MD_STATE_DIRTY; ++ dmc->sb_version = EIO_SB_VERSION; ++ error = eio_sb_store(dmc); ++ if (error) { ++ if (!CACHE_SSD_ADD_INPROG_IS_SET(dmc)) ++ vfree((void *)EIO_CACHE(dmc)); ++ pr_err ++ ("md_create: Could not write cache superblock sector(error %d) for cache \"%s\"\n", ++ error, dmc->cache_name); ++ ret = -EIO; ++ goto free_md; ++ } ++ ++free_md: ++ for (k = 0; k < nr_pages; k++) ++ kunmap(pages[k].bv_page); ++ kfree(pg_virt_addr); ++ ++ /* Free metadata pages here. */ ++ if (pages) { ++ for (k = 0; k < nr_pages; k++) ++ put_page(pages[k].bv_page); ++ kfree(pages); ++ pages = NULL; ++ } ++ ++free_header: ++ /* Free header page here */ ++ if (header_page) { ++ kunmap(header_page[0].bv_page); ++ put_page(header_page[0].bv_page); ++ kfree(header_page); ++ header_page = NULL; ++ } ++ ++ return ret; ++} ++ ++static int eio_md_load(struct cache_c *dmc) ++{ ++ struct flash_cacheblock *meta_data_cacheblock, *next_ptr; ++ union eio_superblock *header; ++ struct eio_io_region where; ++ int i; ++ index_t j, slots_read; ++ sector_t size; ++ int clean_shutdown; ++ int dirty_loaded = 0; ++ sector_t order, data_size; ++ int num_valid = 0; ++ int error; ++ sector_t sectors_read = 0, sectors_expected = 0; /* Debug */ ++ int force_warm_boot = 0; ++ ++ struct bio_vec *header_page, *pages; ++ int nr_pages, page_count, page_index; ++ int ret = 0; ++ void **pg_virt_addr; ++ ++ page_count = 0; ++ header_page = eio_alloc_pages(1, &page_count); ++ if (header_page == NULL) { ++ pr_err("md_load: Unable to allocate memory"); ++ return -ENOMEM; ++ } ++ ++ EIO_ASSERT(page_count == 1); ++ header = (union eio_superblock *)kmap(header_page[0].bv_page); ++ ++ if (CACHE_FAILED_IS_SET(dmc) || CACHE_DEGRADED_IS_SET(dmc)) { ++ pr_err ++ ("md_load: Cannot load metadata in failed / degraded mode"); ++ ret = -ENODEV; ++ goto free_header; ++ } ++ ++ where.bdev = dmc->cache_dev->bdev; ++ where.sector = EIO_SUPERBLOCK_START; ++ where.count = eio_to_sector(EIO_SUPERBLOCK_SIZE); ++ error = eio_io_sync_vm(dmc, &where, READ, header_page, 1); ++ if (error) { ++ pr_err ++ ("md_load: Could not read cache superblock sector %llu error %d", ++ (unsigned long long)where.sector, error); ++ ret = -EINVAL; ++ goto free_header; ++ } ++ ++ /* check ondisk superblock version */ ++ if (le32_to_cpu(header->sbf.cache_version) != EIO_SB_VERSION) { ++ pr_info("md_load: Cache superblock mismatch detected." \ ++ " (current: %u, ondisk: %u)", EIO_SB_VERSION, ++ header->sbf.cache_version); ++ ++ if (le32_to_cpu(header->sbf.cache_version) == 0) { ++ pr_err("md_load: Can't enable cache %s. Either " \ ++ "superblock version is invalid or cache has" \ ++ " been deleted", header->sbf.cache_name); ++ ret = 1; ++ goto free_header; ++ } ++ ++ if (le32_to_cpu(header->sbf.cache_version) > EIO_SB_VERSION) { ++ pr_err("md_load: Can't enable cache %s with newer " \ ++ " superblock version.", header->sbf.cache_name); ++ ret = 1; ++ goto free_header; ++ } ++ ++ if (le32_to_cpu(header->sbf.mode) == CACHE_MODE_WB) { ++ pr_err("md_load: Can't enable write-back cache %s" \ ++ " with newer superblock version.", ++ header->sbf.cache_name); ++ ret = 1; ++ goto free_header; ++ } else if ((le32_to_cpu(header->sbf.mode) == CACHE_MODE_RO) || ++ (le32_to_cpu(header->sbf.mode) == CACHE_MODE_WT)) { ++ dmc->persistence = CACHE_FORCECREATE; ++ pr_info("md_load: Can't enable cache, recreating" \ ++ " cache %s with newer superblock version.", ++ header->sbf.cache_name); ++ ret = 0; ++ goto free_header; ++ } ++ } ++ ++ /* check ondisk magic number */ ++ ++ if (le32_to_cpu(header->sbf.cache_version) >= EIO_SB_MAGIC_VERSION && ++ le32_to_cpu(header->sbf.magic) != EIO_MAGIC) { ++ pr_err("md_load: Magic number mismatch in superblock detected." \ ++ " (current: %u, ondisk: %u)", EIO_MAGIC, ++ le32_to_cpu(header->sbf.magic)); ++ ret = 1; ++ goto free_header; ++ } ++ ++ dmc->sb_version = EIO_SB_VERSION; ++ ++ /* ++ * TBD ++ * For writeback, only when the dirty blocks are non-zero ++ * and header state is unexpected, we should treat it as md corrupted. ++ * Otherwise, a bad write in last shutdown, can lead to data inaccessible ++ * in writeback case. ++ */ ++ if (!((le32_to_cpu(header->sbf.cache_sb_state) == CACHE_MD_STATE_DIRTY) || ++ (le32_to_cpu(header->sbf.cache_sb_state) == CACHE_MD_STATE_CLEAN) || ++ (le32_to_cpu(header->sbf.cache_sb_state) == CACHE_MD_STATE_FASTCLEAN))) { ++ pr_err("md_load: Corrupt cache superblock"); ++ ret = -EINVAL; ++ goto free_header; ++ } ++ ++ if (le32_to_cpu(header->sbf.cold_boot) & BOOT_FLAG_FORCE_WARM) { ++ force_warm_boot = 1; ++ header->sbf.cold_boot = cpu_to_le32(le32_to_cpu(header->sbf.cold_boot) & ++ ~BOOT_FLAG_FORCE_WARM); ++ } ++ ++ /* ++ * Determine if we can start as cold or hot cache ++ * - if cold_boot is set(unless force_warm_boot), start as cold cache ++ * - else if it is unclean shutdown, start as cold cache ++ * cold cache will still treat the dirty blocks as hot ++ */ ++ if (dmc->cold_boot != le32_to_cpu(header->sbf.cold_boot)) { ++ pr_info ++ ("superblock(%u) and config(%u) cold boot values do not match. Relying on config", ++ le32_to_cpu(header->sbf.cold_boot), dmc->cold_boot); ++ } ++ if (dmc->cold_boot && !force_warm_boot) { ++ pr_info ++ ("Cold boot is set, starting as if unclean shutdown(only dirty blocks will be hot)"); ++ clean_shutdown = 0; ++ } else { ++ if (le32_to_cpu(header->sbf.cache_sb_state) == CACHE_MD_STATE_DIRTY) { ++ pr_info("Unclean shutdown detected"); ++ pr_info("Only dirty blocks exist in cache"); ++ clean_shutdown = 0; ++ } else if (le32_to_cpu(header->sbf.cache_sb_state) == CACHE_MD_STATE_CLEAN) { ++ pr_info("Slow (clean) shutdown detected"); ++ pr_info("Only clean blocks exist in cache"); ++ clean_shutdown = 1; ++ } else if (le32_to_cpu(header->sbf.cache_sb_state) == ++ CACHE_MD_STATE_FASTCLEAN) { ++ pr_info("Fast (clean) shutdown detected"); ++ pr_info("Both clean and dirty blocks exist in cache"); ++ clean_shutdown = 1; ++ } else { ++ /* Won't reach here, but TBD may change the previous if condition */ ++ pr_info ++ ("cache state is %d. Treating as unclean shutdown", ++ le32_to_cpu(header->sbf.cache_sb_state)); ++ pr_info("Only dirty blocks exist in cache"); ++ clean_shutdown = 0; ++ } ++ } ++ ++ if (!dmc->mode) ++ dmc->mode = le32_to_cpu(header->sbf.mode); ++ if (!dmc->req_policy) ++ dmc->req_policy = le32_to_cpu(header->sbf.repl_policy); ++ ++ if (!dmc->cache_flags) ++ dmc->cache_flags = le32_to_cpu(header->sbf.cache_flags); ++ ++ error = eio_policy_init(dmc); ++ if (error) ++ goto free_header; ++ ++ dmc->block_size = le64_to_cpu(header->sbf.block_size); ++ dmc->block_shift = ffs(dmc->block_size) - 1; ++ dmc->block_mask = dmc->block_size - 1; ++ dmc->size = le32_to_cpu(header->sbf.size); ++ dmc->cache_size = le64_to_cpu(header->sbf.cache_devsize); ++ dmc->assoc = le32_to_cpu(header->sbf.assoc); ++ dmc->consecutive_shift = ffs(dmc->assoc) - 1; ++ dmc->md_start_sect = le64_to_cpu(header->sbf.cache_md_start_sect); ++ dmc->md_sectors = le64_to_cpu(header->sbf.cache_data_start_sect); ++ dmc->sysctl_active.dirty_high_threshold = ++ le32_to_cpu(header->sbf.dirty_high_threshold); ++ dmc->sysctl_active.dirty_low_threshold = ++ le32_to_cpu(header->sbf.dirty_low_threshold); ++ dmc->sysctl_active.dirty_set_high_threshold = ++ le32_to_cpu(header->sbf.dirty_set_high_threshold); ++ dmc->sysctl_active.dirty_set_low_threshold = ++ le32_to_cpu(header->sbf.dirty_set_low_threshold); ++ dmc->sysctl_active.time_based_clean_interval = ++ le32_to_cpu(header->sbf.time_based_clean_interval); ++ dmc->sysctl_active.autoclean_threshold = ++ le32_to_cpu(header->sbf.autoclean_threshold); ++ ++ i = eio_mem_init(dmc); ++ if (i == -1) { ++ pr_err("eio_md_load: Failed to initialize memory."); ++ ret = -EINVAL; ++ goto free_header; ++ } ++ ++ order = ++ dmc->size * ++ ((i == ++ 1) ? sizeof(struct cacheblock_md8) : sizeof(struct cacheblock)); ++ data_size = dmc->size * dmc->block_size; ++ size = ++ EIO_MD8(dmc) ? sizeof(struct cacheblock_md8) : sizeof(struct ++ cacheblock); ++ pr_info("Allocate %lluKB (%lluB per) mem for %llu-entry cache " \ ++ "(capacity:%lluMB, associativity:%u, block size:%u bytes)", ++ (unsigned long long)order >> 10, (unsigned long long)size, ++ (long long unsigned int)dmc->size, ++ (long long unsigned int)(dmc->md_sectors + data_size) >> (20 - ++ SECTOR_SHIFT), ++ dmc->assoc, dmc->block_size << SECTOR_SHIFT); ++ ++ if (EIO_MD8(dmc)) ++ dmc->cache_md8 = vmalloc((size_t)order); ++ else ++ dmc->cache = vmalloc((size_t)order); ++ ++ if ((EIO_MD8(dmc) && !dmc->cache_md8) || (!EIO_MD8(dmc) && !dmc->cache)) { ++ pr_err("md_load: Unable to allocate memory"); ++ vfree((void *)header); ++ return 1; ++ } ++ ++ if (eio_repl_blk_init(dmc->policy_ops) != 0) { ++ vfree((void *)EIO_CACHE(dmc)); ++ pr_err ++ ("md_load: Unable to allocate memory for policy cache block"); ++ ret = -EINVAL; ++ goto free_header; ++ } ++ ++ /* Allocate pages of the order dmc->bio_nr_pages */ ++ page_count = 0; ++ pages = eio_alloc_pages(dmc->bio_nr_pages, &page_count); ++ if (!pages) { ++ pr_err("md_create: unable to allocate pages"); ++ pr_err("md_create: Could not write out cache metadata"); ++ vfree((void *)EIO_CACHE(dmc)); ++ ret = -ENOMEM; ++ goto free_header; ++ } ++ ++ /* nr_pages is used for freeing the pages */ ++ nr_pages = page_count; ++ ++ pg_virt_addr = kmalloc(nr_pages * (sizeof(void *)), GFP_KERNEL); ++ if (pg_virt_addr == NULL) { ++ pr_err("eio_md_store: System memory too low."); ++ for (i = 0; i < nr_pages; i++) ++ put_page(pages[i].bv_page); ++ kfree(pages); ++ ret = -ENOMEM; ++ goto free_header; ++ } ++ ++ for (i = 0; i < nr_pages; i++) ++ pg_virt_addr[i] = kmap(pages[i].bv_page); ++ ++ /* ++ * Read 1 PAGE of the metadata at a time and load up the ++ * incore metadata struct. ++ */ ++ ++ page_index = 0; ++ page_count = 0; ++ meta_data_cacheblock = ++ (struct flash_cacheblock *)pg_virt_addr[page_index]; ++ ++ where.bdev = dmc->cache_dev->bdev; ++ where.sector = dmc->md_start_sect; ++ size = dmc->size; ++ i = 0; ++ while (size > 0) { ++ slots_read = ++ min((long)size, ((long)MD_BLOCKS_PER_PAGE * nr_pages)); ++ ++ if (slots_read % MD_BLOCKS_PER_SECTOR) ++ where.count = 1 + (slots_read / MD_BLOCKS_PER_SECTOR); ++ else ++ where.count = slots_read / MD_BLOCKS_PER_SECTOR; ++ ++ if (slots_read % MD_BLOCKS_PER_PAGE) ++ page_count = 1 + (slots_read / MD_BLOCKS_PER_PAGE); ++ else ++ page_count = slots_read / MD_BLOCKS_PER_PAGE; ++ ++ sectors_read += where.count; /* Debug */ ++ error = eio_io_sync_vm(dmc, &where, READ, pages, page_count); ++ if (error) { ++ vfree((void *)EIO_CACHE(dmc)); ++ pr_err ++ ("md_load: Could not read cache metadata sector %llu error %d", ++ (unsigned long long)where.sector, error); ++ ret = -EIO; ++ goto free_md; ++ } ++ ++ where.sector += where.count; ++ next_ptr = meta_data_cacheblock; ++ ++ for (j = 0, page_index = 0; j < slots_read; j++) { ++ ++ if ((j % MD_BLOCKS_PER_PAGE) == 0) ++ next_ptr = ++ (struct flash_cacheblock *) ++ pg_virt_addr[page_index++]; ++ ++ /* If unclean shutdown, only the DIRTY blocks are loaded.*/ ++ if (clean_shutdown || (next_ptr->cache_state & DIRTY)) { ++ ++ if (next_ptr->cache_state & DIRTY) ++ dirty_loaded++; ++ ++ EIO_CACHE_STATE_SET(dmc, i, ++ (u_int8_t)le64_to_cpu(next_ptr-> ++ cache_state) & ~QUEUED); ++ ++ EIO_ASSERT((EIO_CACHE_STATE_GET(dmc, i) & ++ (VALID | INVALID)) ++ != (VALID | INVALID)); ++ ++ if (EIO_CACHE_STATE_GET(dmc, i) & VALID) ++ num_valid++; ++ EIO_DBN_SET(dmc, i, le64_to_cpu(next_ptr->dbn)); ++ } else ++ eio_invalidate_md(dmc, i); ++ next_ptr++; ++ i++; ++ } ++ size -= slots_read; ++ } ++ ++ /* ++ * If the cache contains dirty data, the only valid mode is write back. ++ */ ++ if (dirty_loaded && dmc->mode != CACHE_MODE_WB) { ++ vfree((void *)EIO_CACHE(dmc)); ++ pr_err ++ ("md_load: Cannot use %s mode because dirty data exists in the cache", ++ (dmc->mode == ++ CACHE_MODE_RO) ? "read only" : "write through"); ++ ret = -EINVAL; ++ goto free_md; ++ } ++ ++ /* Debug Tests */ ++ sectors_expected = EIO_DIV(dmc->size, MD_BLOCKS_PER_SECTOR); ++ if (EIO_REM(dmc->size, MD_BLOCKS_PER_SECTOR)) ++ sectors_expected++; ++ if (sectors_expected != sectors_read) { ++ pr_err ++ ("md_load: Sector mismatch! sectors_expected=%llu, sectors_read=%llu\n", ++ (unsigned long long)sectors_expected, (unsigned long long)sectors_read); ++ vfree((void *)EIO_CACHE(dmc)); ++ ret = -EIO; ++ goto free_md; ++ } ++ ++ /* Before we finish loading, we need to dirty the superblock and write it out */ ++ dmc->sb_state = CACHE_MD_STATE_DIRTY; ++ error = eio_sb_store(dmc); ++ if (error) { ++ vfree((void *)EIO_CACHE(dmc)); ++ pr_err ++ ("md_load: Could not write cache superblock sector(error %d)", ++ error); ++ ret = 1; ++ goto free_md; ++ } ++ ++free_md: ++ for (i = 0; i < nr_pages; i++) ++ kunmap(pages[i].bv_page); ++ kfree(pg_virt_addr); ++ ++ if (pages) { ++ for (i = 0; i < nr_pages; i++) ++ put_page(pages[i].bv_page); ++ kfree(pages); ++ pages = NULL; ++ } ++ ++free_header: ++ /* Free header page here */ ++ if (header_page) { ++ kunmap(header_page[0].bv_page); ++ put_page(header_page[0].bv_page); ++ kfree(header_page); ++ header_page = NULL; ++ } ++ ++ pr_info("Cache metadata loaded from disk with %d valid %d dirty blocks", ++ num_valid, dirty_loaded); ++ return ret; ++} ++ ++void eio_policy_free(struct cache_c *dmc) ++{ ++ ++ if (dmc->policy_ops != NULL) { ++ eio_put_policy(dmc->policy_ops); ++ vfree(dmc->policy_ops); ++ } ++ if (dmc->sp_cache_blk != NULL) ++ vfree(dmc->sp_cache_blk); ++ if (dmc->sp_cache_set != NULL) ++ vfree(dmc->sp_cache_set); ++ ++ dmc->policy_ops = NULL; ++ dmc->sp_cache_blk = dmc->sp_cache_set = NULL; ++ return; ++} ++ ++static int eio_clean_thread_init(struct cache_c *dmc) ++{ ++ INIT_LIST_HEAD(&dmc->cleanq); ++ spin_lock_init(&dmc->clean_sl); ++ EIO_INIT_EVENT(&dmc->clean_event); ++ return eio_start_clean_thread(dmc); ++} ++ ++int ++eio_handle_ssd_message(char *cache_name, char *ssd_name, enum dev_notifier note) ++{ ++ struct cache_c *dmc; ++ ++ dmc = eio_cache_lookup(cache_name); ++ if (NULL == dmc) { ++ pr_err("eio_handle_ssd_message: cache %s does not exist", ++ cache_name); ++ return -EINVAL; ++ } ++ ++ switch (note) { ++ ++ case NOTIFY_SSD_ADD: ++ /* Making sure that CACHE state is not active */ ++ if (CACHE_FAILED_IS_SET(dmc) || CACHE_DEGRADED_IS_SET(dmc)) ++ eio_resume_caching(dmc, ssd_name); ++ else ++ pr_err ++ ("eio_handle_ssd_message: SSD_ADD event called for ACTIVE cache \"%s\", ignoring!!!", ++ dmc->cache_name); ++ break; ++ ++ case NOTIFY_SSD_REMOVED: ++ eio_suspend_caching(dmc, note); ++ break; ++ ++ default: ++ pr_err("Wrong notifier passed for eio_handle_ssd_message\n"); ++ } ++ ++ return 0; ++} ++ ++static void eio_init_ssddev_props(struct cache_c *dmc) ++{ ++ struct request_queue *rq; ++ uint32_t max_hw_sectors, max_nr_pages; ++ uint32_t nr_pages = 0; ++ ++ rq = bdev_get_queue(dmc->cache_dev->bdev); ++ max_hw_sectors = to_bytes(queue_max_hw_sectors(rq)) / PAGE_SIZE; ++ max_nr_pages = (u_int32_t)bio_get_nr_vecs(dmc->cache_dev->bdev); ++ nr_pages = min_t(u_int32_t, max_hw_sectors, max_nr_pages); ++ dmc->bio_nr_pages = nr_pages; ++ ++ /* ++ * If the cache device is not a physical device (eg: lv), then ++ * driverfs_dev will be null and we make cache_gendisk_name a null ++ * string. The eio_notify_ssd_rm() function in this case, ++ * cannot detect device removal, and therefore, we will have to rely ++ * on user space udev for the notification. ++ */ ++ ++ if (dmc->cache_dev && dmc->cache_dev->bdev && ++ dmc->cache_dev->bdev->bd_disk && ++ dmc->cache_dev->bdev->bd_disk->driverfs_dev) { ++ strncpy(dmc->cache_gendisk_name, ++ dev_name(dmc->cache_dev->bdev->bd_disk->driverfs_dev), ++ DEV_PATHLEN); ++ } else ++ dmc->cache_gendisk_name[0] = '\0'; ++} ++ ++static void eio_init_srcdev_props(struct cache_c *dmc) ++{ ++ /* Same applies for source device as well. */ ++ if (dmc->disk_dev && dmc->disk_dev->bdev && ++ dmc->disk_dev->bdev->bd_disk && ++ dmc->disk_dev->bdev->bd_disk->driverfs_dev) { ++ strncpy(dmc->cache_srcdisk_name, ++ dev_name(dmc->disk_dev->bdev->bd_disk->driverfs_dev), ++ DEV_PATHLEN); ++ } else ++ dmc->cache_srcdisk_name[0] = '\0'; ++} ++ ++int eio_cache_create(struct cache_rec_short *cache) ++{ ++ struct cache_c *dmc; ++ struct cache_c **nodepp; ++ unsigned int consecutive_blocks; ++ u_int64_t i; ++ index_t prev_set; ++ index_t cur_set; ++ sector_t order; ++ int error = -EINVAL; ++ uint32_t persistence = 0; ++ fmode_t mode = (FMODE_READ | FMODE_WRITE); ++ char *strerr = NULL; ++ ++ dmc = kzalloc(sizeof(*dmc), GFP_KERNEL); ++ if (dmc == NULL) { ++ strerr = "Failed to allocate memory for cache context"; ++ error = -ENOMEM; ++ goto bad; ++ } ++ ++ /* ++ * Source device. ++ */ ++ ++ error = eio_ttc_get_device(cache->cr_src_devname, mode, &dmc->disk_dev); ++ if (error) { ++ strerr = "get_device for source device failed"; ++ goto bad1; ++ } ++ ++ dmc->disk_size = eio_to_sector(eio_get_device_size(dmc->disk_dev)); ++ if (dmc->disk_size >= EIO_MAX_SECTOR) { ++ strerr = "Source device too big to support"; ++ error = -EFBIG; ++ goto bad2; ++ } ++ strncpy(dmc->disk_devname, cache->cr_src_devname, DEV_PATHLEN); ++ ++ /* ++ * Cache device. ++ */ ++ ++ error = ++ eio_ttc_get_device(cache->cr_ssd_devname, mode | FMODE_EXCL, &dmc->cache_dev); ++ if (error) { ++ strerr = "get_device for cache device failed"; ++ goto bad2; ++ } ++ ++ if (dmc->disk_dev == dmc->cache_dev) { ++ error = -EINVAL; ++ strerr = "Same devices specified"; ++ goto bad3; ++ } ++ strncpy(dmc->cache_devname, cache->cr_ssd_devname, DEV_PATHLEN); ++ ++ if (cache->cr_name[0] != '\0') { ++ strncpy(dmc->cache_name, cache->cr_name, ++ sizeof(dmc->cache_name)); ++ /* make sure it is zero terminated */ ++ dmc->cache_name[sizeof(dmc->cache_name) - 1] = '\x00'; ++ } else { ++ strerr = "Need cache name"; ++ error = -EINVAL; ++ goto bad3; ++ } ++ ++ strncpy(dmc->ssd_uuid, cache->cr_ssd_uuid, DEV_PATHLEN - 1); ++ ++ dmc->cache_dev_start_sect = eio_get_device_start_sect(dmc->cache_dev); ++ error = eio_do_preliminary_checks(dmc); ++ if (error) { ++ if (error == -EINVAL) ++ strerr = "Either Source and Cache devices belong to " ++ "same device or a cache already exists on" ++ " specified source device"; ++ else if (error == -EEXIST) ++ strerr = "Cache already exists"; ++ goto bad3; ++ } ++ ++ eio_init_ssddev_props(dmc); ++ eio_init_srcdev_props(dmc); ++ ++ /* ++ * Initialize the io callback queue. ++ */ ++ ++ dmc->callback_q = create_singlethread_workqueue("eio_callback"); ++ if (!dmc->callback_q) { ++ error = -ENOMEM; ++ strerr = "Failed to initialize callback workqueue"; ++ goto bad4; ++ } ++ error = eio_kcached_init(dmc); ++ if (error) { ++ strerr = "Failed to initialize kcached"; ++ goto bad4; ++ } ++ ++ /* ++ * We read policy before reading other args. The reason is that ++ * if there is a policy module loaded, we first need dmc->p_ops to be ++ * allocated so that it is non NULL. Once p_ops is !NULL, cache_blk_init ++ * and cache_set_init can set their pointers to dmc->p_ops->xxx ++ * ++ * policy_ops == NULL is not really an error. It just means that there ++ * is no registered policy and therefore we use EIO_REPL_RANDOM (random) ++ * as the replacement policy. ++ */ ++ ++ /* We do a kzalloc for dmc, but being extra careful here */ ++ dmc->sp_cache_blk = NULL; ++ dmc->sp_cache_set = NULL; ++ dmc->policy_ops = NULL; ++ if (cache->cr_policy) { ++ dmc->req_policy = cache->cr_policy; ++ if (dmc->req_policy && (dmc->req_policy < CACHE_REPL_FIRST || ++ dmc->req_policy > CACHE_REPL_LAST)) { ++ strerr = "Invalid cache policy"; ++ error = -EINVAL; ++ goto bad5; ++ } ++ } ++ ++ /* ++ * We need to determine the requested cache mode before we call ++ * eio_md_load becuase it examines dmc->mode. The cache mode is ++ * set as follows: ++ * 1. For a "reload" operation: ++ * - if mode is not provided as an argument, ++ it is read from superblock. ++ * - if mode is provided as an argument, ++ eio_md_load verifies that it is valid. ++ * 2. For a "create" operation: ++ * - if mode is not provided, it is set to CACHE_MODE_DEFAULT. ++ * - if mode is provided, it is validate and set. ++ */ ++ if (cache->cr_mode) { ++ dmc->mode = cache->cr_mode; ++ if (dmc->mode && (dmc->mode < CACHE_MODE_FIRST || ++ dmc->mode > CACHE_MODE_LAST)) { ++ strerr = "Invalid cache mode"; ++ error = -EINVAL; ++ goto bad5; ++ } ++ } ++ ++ dmc->cold_boot = cache->cr_cold_boot; ++ if ((dmc->cold_boot != 0) && (dmc->cold_boot != BOOT_FLAG_COLD_ENABLE)) { ++ strerr = "Invalid cold boot option"; ++ error = -EINVAL; ++ goto bad5; ++ } ++ ++ if (cache->cr_persistence) { ++ persistence = cache->cr_persistence; ++ if (persistence < CACHE_RELOAD || ++ persistence > CACHE_FORCECREATE) { ++ pr_err("ctr: persistence = %d", persistence); ++ strerr = "Invalid cache persistence"; ++ error = -EINVAL; ++ goto bad5; ++ } ++ dmc->persistence = persistence; ++ } ++ if (persistence == CACHE_RELOAD) { ++ if (eio_md_load(dmc)) { ++ strerr = "Failed to reload cache"; ++ error = -EINVAL; ++ goto bad5; ++ } ++ ++ /* ++ * "eio_md_load" will reset "dmc->persistence" from ++ * CACHE_RELOAD to CACHE_FORCECREATE in the case of ++ * cache superblock version mismatch and cache mode ++ * is Read-Only or Write-Through. ++ */ ++ if (dmc->persistence != persistence) ++ persistence = dmc->persistence; ++ } ++ ++ /* ++ * Now that we're back from "eio_md_load" in the case of a reload, ++ * we're ready to finish setting up the mode and policy. ++ */ ++ if (dmc->mode == 0) { ++ dmc->mode = CACHE_MODE_DEFAULT; ++ pr_info("Setting mode to default"); ++ } else { ++ pr_info("Setting mode to %s ", ++ (dmc->mode == CACHE_MODE_WB) ? "write back" : ++ ((dmc->mode == CACHE_MODE_RO) ? "read only" : ++ "write through")); ++ } ++ ++ /* eio_policy_init() is already called from within eio_md_load() */ ++ if (persistence != CACHE_RELOAD) { ++ error = eio_policy_init(dmc); ++ if (error) { ++ strerr = "Failed to initialize policy"; ++ goto bad5; ++ } ++ } ++ ++ if (cache->cr_flags) { ++ int flags; ++ flags = cache->cr_flags; ++ if (flags == 0) ++ dmc->cache_flags &= ~CACHE_FLAGS_INVALIDATE; ++ else if (flags == 1) { ++ dmc->cache_flags |= CACHE_FLAGS_INVALIDATE; ++ pr_info("Enabling invalidate API"); ++ } else ++ pr_info("Ignoring unknown flags value: %u", flags); ++ } ++ ++ if (persistence == CACHE_RELOAD) ++ goto init; /* Skip reading cache parameters from command line */ ++ ++ if (cache->cr_blksize && cache->cr_ssd_sector_size) { ++ dmc->block_size = EIO_DIV(cache->cr_blksize, cache->cr_ssd_sector_size); ++ if (dmc->block_size & (dmc->block_size - 1)) { ++ strerr = "Invalid block size"; ++ error = -EINVAL; ++ goto bad5; ++ } ++ if (dmc->block_size == 0) ++ dmc->block_size = DEFAULT_CACHE_BLKSIZE; ++ } else ++ dmc->block_size = DEFAULT_CACHE_BLKSIZE; ++ dmc->block_shift = ffs(dmc->block_size) - 1; ++ dmc->block_mask = dmc->block_size - 1; ++ ++ /* ++ * dmc->size is specified in sectors here, and converted to blocks later ++ * ++ * Giving preference to kernel got cache size. ++ * Only when we can't get the cache size in kernel, we accept user passed size. ++ * User mode may be using a different API or could also do some rounding, so we ++ * prefer kernel getting the cache size. In case of device failure and coming back, we ++ * rely on the device size got in kernel and we hope that it is equal to the ++ * one we used for creating the cache, so we ideally should always use the kernel ++ * got cache size. ++ */ ++ dmc->size = eio_to_sector(eio_get_device_size(dmc->cache_dev)); ++ if (dmc->size == 0) { ++ if (cache->cr_ssd_dev_size && cache->cr_ssd_sector_size) ++ dmc->size = ++ EIO_DIV(cache->cr_ssd_dev_size, cache->cr_ssd_sector_size); ++ ++ if (dmc->size == 0) { ++ strerr = "Invalid cache size or can't be fetched"; ++ error = -EINVAL; ++ goto bad5; ++ } ++ } ++ ++ dmc->cache_size = dmc->size; ++ ++ if (cache->cr_assoc) { ++ dmc->assoc = cache->cr_assoc; ++ if ((dmc->assoc & (dmc->assoc - 1)) || ++ dmc->assoc > EIO_MAX_ASSOC || dmc->size < dmc->assoc) { ++ strerr = "Invalid cache associativity"; ++ error = -EINVAL; ++ goto bad5; ++ } ++ if (dmc->assoc == 0) ++ dmc->assoc = DEFAULT_CACHE_ASSOC; ++ } else ++ dmc->assoc = DEFAULT_CACHE_ASSOC; ++ ++ /* ++ * initialize to an invalid index ++ */ ++ ++ dmc->index_zero = dmc->assoc + 1; ++ ++ /* ++ * Although it's very unlikely, we need to make sure that ++ * for the given associativity and block size our source ++ * device will have less than 4 billion sets. ++ */ ++ ++ i = EIO_DIV(eio_to_sector(eio_get_device_size(dmc->disk_dev)), ++ (dmc->assoc * dmc->block_size)); ++ if (i >= (((u_int64_t)1) << 32)) { ++ strerr = "Too many cache sets to support"; ++ goto bad5; ++ } ++ ++ consecutive_blocks = dmc->assoc; ++ dmc->consecutive_shift = ffs(consecutive_blocks) - 1; ++ ++ /* Initialize persistent thresholds */ ++ dmc->sysctl_active.dirty_high_threshold = DIRTY_HIGH_THRESH_DEF; ++ dmc->sysctl_active.dirty_low_threshold = DIRTY_LOW_THRESH_DEF; ++ dmc->sysctl_active.dirty_set_high_threshold = DIRTY_SET_HIGH_THRESH_DEF; ++ dmc->sysctl_active.dirty_set_low_threshold = DIRTY_SET_LOW_THRESH_DEF; ++ dmc->sysctl_active.autoclean_threshold = AUTOCLEAN_THRESH_DEF; ++ dmc->sysctl_active.time_based_clean_interval = ++ TIME_BASED_CLEAN_INTERVAL_DEF(dmc); ++ ++ spin_lock_init(&dmc->cache_spin_lock); ++ if (persistence == CACHE_CREATE) { ++ error = eio_md_create(dmc, /* force */ 0, /* cold */ 1); ++ if (error) { ++ strerr = "Failed to create cache"; ++ goto bad5; ++ } ++ } else { ++ error = eio_md_create(dmc, /* force */ 1, /* cold */ 1); ++ if (error) { ++ strerr = "Failed to force create cache"; ++ goto bad5; ++ } ++ } ++ ++init: ++ order = (dmc->size >> dmc->consecutive_shift) * ++ sizeof(struct cache_set); ++ ++ if (!eio_mem_available(dmc, order)) { ++ strerr = "System memory too low" ++ " for allocating cache set metadata"; ++ error = -ENOMEM; ++ vfree((void *)EIO_CACHE(dmc)); ++ goto bad5; ++ } ++ ++ dmc->cache_sets = vmalloc((size_t)order); ++ if (!dmc->cache_sets) { ++ strerr = "Failed to allocate memory"; ++ error = -ENOMEM; ++ vfree((void *)EIO_CACHE(dmc)); ++ goto bad5; ++ } ++ ++ for (i = 0; i < (dmc->size >> dmc->consecutive_shift); i++) { ++ dmc->cache_sets[i].nr_dirty = 0; ++ spin_lock_init(&dmc->cache_sets[i].cs_lock); ++ init_rwsem(&dmc->cache_sets[i].rw_lock); ++ dmc->cache_sets[i].mdreq = NULL; ++ dmc->cache_sets[i].flags = 0; ++ } ++ error = eio_repl_sets_init(dmc->policy_ops); ++ if (error < 0) { ++ strerr = "Failed to allocate memory for cache policy"; ++ vfree((void *)dmc->cache_sets); ++ vfree((void *)EIO_CACHE(dmc)); ++ goto bad5; ++ } ++ eio_policy_lru_pushblks(dmc->policy_ops); ++ ++ if (dmc->mode == CACHE_MODE_WB) { ++ error = eio_allocate_wb_resources(dmc); ++ if (error) { ++ vfree((void *)dmc->cache_sets); ++ vfree((void *)EIO_CACHE(dmc)); ++ goto bad5; ++ } ++ } ++ ++ dmc->sysctl_active.error_inject = 0; ++ dmc->sysctl_active.fast_remove = 0; ++ dmc->sysctl_active.zerostats = 0; ++ dmc->sysctl_active.do_clean = 0; ++ ++ atomic_set(&dmc->clean_index, 0); ++ ++ atomic64_set(&dmc->nr_ios, 0); ++ ++ /* ++ * sysctl_mem_limit_pct [0 - 100]. Before doing a vmalloc() ++ * make sure that the allocation size requested is less than ++ * sysctl_mem_limit_pct percentage of the free RAM available ++ * in the system. This is to avoid OOM errors in Linux. ++ * 0 => do the vmalloc without checking system memory. ++ */ ++ ++ dmc->sysctl_active.mem_limit_pct = 75; ++ ++ (void)wait_on_bit_lock((void *)&eio_control->synch_flags, ++ EIO_UPDATE_LIST, eio_wait_schedule, ++ TASK_UNINTERRUPTIBLE); ++ dmc->next_cache = cache_list_head; ++ cache_list_head = dmc; ++ clear_bit(EIO_UPDATE_LIST, (void *)&eio_control->synch_flags); ++ smp_mb__after_clear_bit(); ++ wake_up_bit((void *)&eio_control->synch_flags, EIO_UPDATE_LIST); ++ ++ prev_set = -1; ++ for (i = 0; i < dmc->size; i++) { ++ if (EIO_CACHE_STATE_GET(dmc, i) & VALID) ++ atomic64_inc(&dmc->eio_stats.cached_blocks); ++ if (EIO_CACHE_STATE_GET(dmc, i) & DIRTY) { ++ dmc->cache_sets[EIO_DIV(i, dmc->assoc)].nr_dirty++; ++ atomic64_inc(&dmc->nr_dirty); ++ cur_set = EIO_DIV(i, dmc->assoc); ++ if (prev_set != cur_set) { ++ /* Move the given set at the head of the set LRU list */ ++ eio_touch_set_lru(dmc, cur_set); ++ prev_set = cur_set; ++ } ++ } ++ } ++ ++ INIT_WORK(&dmc->readfill_wq, eio_do_readfill); ++ ++ /* ++ * invalid index, but signifies cache successfully built ++ */ ++ ++ dmc->index_zero = dmc->assoc; ++ ++ eio_procfs_ctr(dmc); ++ ++ /* ++ * Activate Application Transparent Caching. ++ */ ++ ++ error = eio_ttc_activate(dmc); ++ if (error) ++ goto bad6; ++ ++ /* ++ * In future if anyone adds code here and something fails, ++ * do call eio_ttc_deactivate(dmc) as part of cleanup. ++ */ ++ ++ return 0; ++ ++bad6: ++ eio_procfs_dtr(dmc); ++ if (dmc->mode == CACHE_MODE_WB) { ++ eio_stop_async_tasks(dmc); ++ eio_free_wb_resources(dmc); ++ } ++ vfree((void *)dmc->cache_sets); ++ vfree((void *)EIO_CACHE(dmc)); ++ ++ (void)wait_on_bit_lock((void *)&eio_control->synch_flags, ++ EIO_UPDATE_LIST, eio_wait_schedule, ++ TASK_UNINTERRUPTIBLE); ++ nodepp = &cache_list_head; ++ while (*nodepp != NULL) { ++ if (*nodepp == dmc) { ++ *nodepp = dmc->next_cache; ++ break; ++ } ++ nodepp = &((*nodepp)->next_cache); ++ } ++ clear_bit(EIO_UPDATE_LIST, (void *)&eio_control->synch_flags); ++ smp_mb__after_clear_bit(); ++ wake_up_bit((void *)&eio_control->synch_flags, EIO_UPDATE_LIST); ++bad5: ++ eio_kcached_client_destroy(dmc); ++bad4: ++bad3: ++ eio_put_cache_device(dmc); ++bad2: ++ eio_ttc_put_device(&dmc->disk_dev); ++bad1: ++ eio_policy_free(dmc); ++ kfree(dmc); ++bad: ++ if (strerr) ++ pr_err("Cache creation failed: %s.\n", strerr); ++ return error; ++} ++ ++/* ++ * Destroy the cache mapping. ++ */ ++ ++int eio_cache_delete(char *cache_name, int do_delete) ++{ ++ struct cache_c *dmc; ++ struct cache_c **nodepp; ++ int ret, error; ++ int restart_async_task; ++ ++ ret = 0; ++ restart_async_task = 0; ++ ++ dmc = eio_cache_lookup(cache_name); ++ if (NULL == dmc) { ++ pr_err("cache delete: cache \"%s\" doesn't exist.", cache_name); ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&dmc->cache_spin_lock, dmc->cache_spin_lock_flags); ++ if (dmc->cache_flags & CACHE_FLAGS_SHUTDOWN_INPROG) { ++ pr_err("cache_delete: system shutdown in progress, cannot " \ ++ "delete cache %s", cache_name); ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ return -EINVAL; ++ } ++ if (dmc->cache_flags & CACHE_FLAGS_MOD_INPROG) { ++ pr_err ++ ("cache_delete: simultaneous edit/delete operation " \ ++ " on cache %s is not permitted", cache_name); ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ return -EINVAL; ++ } ++ dmc->cache_flags |= CACHE_FLAGS_MOD_INPROG; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ ++ /* ++ * Earlier attempt to delete failed. ++ * Allow force deletes only for FAILED caches. ++ */ ++ if (unlikely(CACHE_STALE_IS_SET(dmc))) { ++ if (likely(CACHE_FAILED_IS_SET(dmc))) { ++ pr_err ++ ("cache_delete: Cache \"%s\" is in STALE state. Force deleting!!!", ++ dmc->cache_name); ++ goto force_delete; ++ } else { ++ if (atomic64_read(&dmc->nr_dirty) != 0) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->cache_flags &= ~CACHE_FLAGS_MOD_INPROG; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc-> ++ cache_spin_lock_flags); ++ pr_err ++ ("cache_delete: Stale Cache detected with dirty blocks=%lld.\n", ++ (long long)atomic64_read(&dmc->nr_dirty)); ++ pr_err ++ ("cache_delete: Cache \"%s\" wont be deleted. Deleting will result in data corruption.\n", ++ dmc->cache_name); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ eio_stop_async_tasks(dmc); ++ ++ /* ++ * Deactivate Application Transparent Caching. ++ * For wb cache, finish_nr_dirty may take long time. ++ * It should be guaranteed that normal cache delete should succeed ++ * only when finish_nr_dirty is completely done. ++ */ ++ ++ if (eio_ttc_deactivate(dmc, 0)) { ++ ++ /* If deactivate fails; only option is to delete cache. */ ++ pr_err("cache_delete: Failed to deactivate the cache \"%s\".", ++ dmc->cache_name); ++ if (CACHE_FAILED_IS_SET(dmc)) ++ pr_err ++ ("cache_delete: Use -f option to delete the cache \"%s\".", ++ dmc->cache_name); ++ ret = -EPERM; ++ dmc->cache_flags |= CACHE_FLAGS_STALE; ++ ++ /* Restart async tasks. */ ++ restart_async_task = 1; ++ goto out; ++ } ++ ++ if (!CACHE_FAILED_IS_SET(dmc)) ++ EIO_ASSERT(dmc->sysctl_active.fast_remove ++ || (atomic64_read(&dmc->nr_dirty) == 0)); ++ ++ /* ++ * If ttc_deactivate succeeded... proceed with cache delete. ++ * Dont entertain device failure hereafter. ++ */ ++ if (unlikely(CACHE_FAILED_IS_SET(dmc)) || ++ unlikely(CACHE_DEGRADED_IS_SET(dmc))) { ++ pr_err ++ ("cache_delete: Cannot update metadata of cache \"%s\" in failed/degraded mode.", ++ dmc->cache_name); ++ } else ++ eio_md_store(dmc); ++ ++force_delete: ++ eio_procfs_dtr(dmc); ++ ++ if (CACHE_STALE_IS_SET(dmc)) { ++ pr_info("Force deleting cache \"%s\"!!!.", dmc->cache_name); ++ eio_ttc_deactivate(dmc, 1); ++ } ++ ++ eio_free_wb_resources(dmc); ++ vfree((void *)EIO_CACHE(dmc)); ++ vfree((void *)dmc->cache_sets); ++ eio_ttc_put_device(&dmc->disk_dev); ++ eio_put_cache_device(dmc); ++ (void)wait_on_bit_lock((void *)&eio_control->synch_flags, ++ EIO_UPDATE_LIST, eio_wait_schedule, ++ TASK_UNINTERRUPTIBLE); ++ nodepp = &cache_list_head; ++ while (*nodepp != NULL) { ++ if (*nodepp == dmc) { ++ *nodepp = dmc->next_cache; ++ break; ++ } ++ nodepp = &((*nodepp)->next_cache); ++ } ++ clear_bit(EIO_UPDATE_LIST, &eio_control->synch_flags); ++ smp_mb__after_clear_bit(); ++ wake_up_bit((void *)&eio_control->synch_flags, EIO_UPDATE_LIST); ++ ++out: ++ if (restart_async_task) { ++ EIO_ASSERT(dmc->clean_thread == NULL); ++ error = eio_start_clean_thread(dmc); ++ if (error) ++ pr_err ++ ("cache_delete: Failed to restart async tasks. error=%d\n", ++ error); ++ } ++ spin_lock_irqsave(&dmc->cache_spin_lock, dmc->cache_spin_lock_flags); ++ dmc->cache_flags &= ~CACHE_FLAGS_MOD_INPROG; ++ if (!ret) ++ dmc->cache_flags |= CACHE_FLAGS_DELETED; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ ++ if (!ret) { ++ eio_policy_free(dmc); ++ ++ /* ++ * We don't need synchronisation since at this point the dmc is ++ * no more accessible via lookup. ++ */ ++ ++ if (!(dmc->cache_flags & CACHE_FLAGS_SHUTDOWN_INPROG)) ++ kfree(dmc); ++ } ++ ++ return ret; ++} ++ ++/* ++ * Reconstruct a degraded cache after the SSD is added. ++ * This function mimics the constructor eio_ctr() except ++ * for code that does not require re-initialization. ++ */ ++int eio_ctr_ssd_add(struct cache_c *dmc, char *dev) ++{ ++ int r = 0; ++ struct eio_bdev *prev_cache_dev; ++ u_int32_t prev_persistence = dmc->persistence; ++ fmode_t mode = (FMODE_READ | FMODE_WRITE); ++ ++ /* verify if source device is present */ ++ EIO_ASSERT(dmc->eio_errors.no_source_dev == 0); ++ ++ /* mimic relevant portions from eio_ctr() */ ++ ++ prev_cache_dev = dmc->cache_dev; ++ r = eio_ttc_get_device(dev, mode, &dmc->cache_dev); ++ if (r) { ++ dmc->cache_dev = prev_cache_dev; ++ pr_err("ctr_ssd_add: Failed to lookup cache device %s", dev); ++ return -EINVAL; ++ } ++ /* ++ * For Linux, we have to put the old SSD device now because ++ * we did not do so during SSD removal. ++ */ ++ eio_ttc_put_device(&prev_cache_dev); ++ ++ /* sanity check */ ++ if (dmc->cache_size != eio_to_sector(eio_get_device_size(dmc->cache_dev))) { ++ pr_err("ctr_ssd_add: Cache device size has changed," \ ++ "expected (%llu) found (%llu)" \ ++ "continuing in degraded mode", ++ (unsigned long long)dmc->cache_size, ++ (unsigned long long)eio_to_sector( ++ eio_get_device_size(dmc->cache_dev))); ++ r = -EINVAL; ++ goto out; ++ } ++ ++ /* sanity check for cache device start sector */ ++ if (dmc->cache_dev_start_sect != ++ eio_get_device_start_sect(dmc->cache_dev)) { ++ pr_err("ctr_ssd_add: Cache device starting sector changed," \ ++ "expected (%llu) found (%llu) continuing in" \ ++ "degraded mode", (unsigned long long)dmc->cache_dev_start_sect, ++ (unsigned long long)eio_get_device_start_sect(dmc->cache_dev)); ++ r = -EINVAL; ++ goto out; ++ } ++ ++ strncpy(dmc->cache_devname, dev, DEV_PATHLEN); ++ eio_init_ssddev_props(dmc); ++ dmc->size = dmc->cache_size; /* dmc->size will be recalculated in eio_md_create() */ ++ ++ /* ++ * In case of writeback mode, trust the content of SSD and reload the MD. ++ */ ++ dmc->persistence = CACHE_FORCECREATE; ++ ++ eio_policy_free(dmc); ++ r = eio_policy_init(dmc); ++ if (r) { ++ pr_err("ctr_ssd_add: Failed to initialize policy"); ++ goto out; ++ } ++ ++ r = eio_md_create(dmc, /* force */ 1, /* cold */ ++ (dmc->mode != CACHE_MODE_WB)); ++ if (r) { ++ pr_err ++ ("ctr_ssd_add: Failed to create md, continuing in degraded mode"); ++ goto out; ++ } ++ ++ r = eio_repl_sets_init(dmc->policy_ops); ++ if (r < 0) { ++ pr_err ++ ("ctr_ssd_add: Failed to allocate memory for cache policy"); ++ goto out; ++ } ++ eio_policy_lru_pushblks(dmc->policy_ops); ++ if (dmc->mode != CACHE_MODE_WB) ++ /* Cold cache will reset the stats */ ++ memset(&dmc->eio_stats, 0, sizeof(dmc->eio_stats)); ++ ++ return 0; ++out: ++ dmc->persistence = prev_persistence; ++ ++ return r; ++} ++ ++/* ++ * Stop the async tasks for a cache(threads, scheduled works). ++ * Used during the cache remove ++ */ ++void eio_stop_async_tasks(struct cache_c *dmc) ++{ ++ unsigned long flags = 0; ++ ++ if (dmc->clean_thread) { ++ dmc->sysctl_active.fast_remove = 1; ++ spin_lock_irqsave(&dmc->clean_sl, flags); ++ EIO_SET_EVENT_AND_UNLOCK(&dmc->clean_event, &dmc->clean_sl, ++ flags); ++ eio_wait_thread_exit(dmc->clean_thread, ++ &dmc->clean_thread_running); ++ EIO_CLEAR_EVENT(&dmc->clean_event); ++ dmc->clean_thread = NULL; ++ } ++ ++ dmc->sysctl_active.fast_remove = CACHE_FAST_REMOVE_IS_SET(dmc) ? 1 : 0; ++ ++ if (dmc->mode == CACHE_MODE_WB) { ++ /* ++ * Prevent new I/Os to schedule the time based cleaning. ++ * Cancel existing delayed work ++ */ ++ dmc->sysctl_active.time_based_clean_interval = 0; ++ cancel_delayed_work_sync(&dmc->clean_aged_sets_work); ++ } ++} ++ ++int eio_start_clean_thread(struct cache_c *dmc) ++{ ++ EIO_ASSERT(dmc->clean_thread == NULL); ++ EIO_ASSERT(dmc->mode == CACHE_MODE_WB); ++ EIO_ASSERT(dmc->clean_thread_running == 0); ++ EIO_ASSERT(!(dmc->sysctl_active.do_clean & EIO_CLEAN_START)); ++ ++ dmc->clean_thread = eio_create_thread(eio_clean_thread_proc, ++ (void *)dmc, "eio_clean_thread"); ++ if (!dmc->clean_thread) ++ return -EFAULT; ++ return 0; ++} ++ ++int eio_allocate_wb_resources(struct cache_c *dmc) ++{ ++ int nr_bvecs, nr_pages; ++ unsigned iosize; ++ int ret; ++ ++ EIO_ASSERT(dmc->clean_dbvecs == NULL); ++ EIO_ASSERT(dmc->clean_mdpages == NULL); ++ EIO_ASSERT(dmc->dbvec_count == 0); ++ EIO_ASSERT(dmc->mdpage_count == 0); ++ ++ /* Data page allocations are done in terms of "bio_vec" structures */ ++ iosize = (dmc->block_size * dmc->assoc) << SECTOR_SHIFT; ++ nr_bvecs = IO_BVEC_COUNT(iosize, dmc->block_size); ++ dmc->clean_dbvecs = kmalloc(sizeof(struct bio_vec) * nr_bvecs, ++ GFP_KERNEL); ++ if (dmc->clean_dbvecs == NULL) { ++ pr_err("cache_create: Failed to allocated memory.\n"); ++ ret = -ENOMEM; ++ goto errout; ++ } ++ /* Allocate pages for each bio_vec */ ++ ret = eio_alloc_wb_bvecs(dmc->clean_dbvecs, nr_bvecs, dmc->block_size); ++ if (ret) ++ goto errout; ++ EIO_ASSERT(dmc->clean_dbvecs != NULL); ++ dmc->dbvec_count = nr_bvecs; ++ ++ /* Metadata page allocations are done in terms of pages only */ ++ iosize = dmc->assoc * sizeof(struct flash_cacheblock); ++ nr_pages = IO_PAGE_COUNT(iosize); ++ dmc->clean_mdpages = kmalloc(sizeof(struct page *) * nr_pages, ++ GFP_KERNEL); ++ if (dmc->clean_mdpages == NULL) { ++ pr_err("cache_create: Failed to allocated memory.\n"); ++ ret = -ENOMEM; ++ eio_free_wb_bvecs(dmc->clean_dbvecs, dmc->dbvec_count, ++ dmc->block_size); ++ goto errout; ++ } ++ ret = eio_alloc_wb_pages(dmc->clean_mdpages, nr_pages); ++ if (ret) { ++ eio_free_wb_bvecs(dmc->clean_dbvecs, dmc->dbvec_count, ++ dmc->block_size); ++ goto errout; ++ } ++ EIO_ASSERT(dmc->clean_mdpages != NULL); ++ dmc->mdpage_count = nr_pages; ++ ++ /* ++ * For writeback cache: ++ * 1. Initialize the time based clean work queue ++ * 2. Initialize the dirty set lru ++ * 3. Initialize clean thread ++ */ ++ ++ /* ++ * Reset dmc->is_clean_aged_sets_sched. ++ * Time based clean will be enabled in eio_touch_set_lru() ++ * only when dmc->is_clean_aged_sets_sched is zero and ++ * dmc->sysctl_active.time_based_clean_interval > 0. ++ */ ++ ++ dmc->is_clean_aged_sets_sched = 0; ++ INIT_DELAYED_WORK(&dmc->clean_aged_sets_work, eio_clean_aged_sets); ++ dmc->dirty_set_lru = NULL; ++ ret = ++ lru_init(&dmc->dirty_set_lru, ++ (dmc->size >> dmc->consecutive_shift)); ++ if (ret == 0) { ++ spin_lock_init(&dmc->dirty_set_lru_lock); ++ ret = eio_clean_thread_init(dmc); ++ } ++ EIO_ASSERT(dmc->mdupdate_q == NULL); ++ dmc->mdupdate_q = create_singlethread_workqueue("eio_mdupdate"); ++ if (!dmc->mdupdate_q) ++ ret = -ENOMEM; ++ ++ if (ret < 0) { ++ pr_err("cache_create: Failed to initialize dirty lru set or" \ ++ "clean/mdupdate thread for wb cache.\n"); ++ if (dmc->dirty_set_lru) { ++ lru_uninit(dmc->dirty_set_lru); ++ dmc->dirty_set_lru = NULL; ++ } ++ ++ eio_free_wb_pages(dmc->clean_mdpages, dmc->mdpage_count); ++ eio_free_wb_bvecs(dmc->clean_dbvecs, dmc->dbvec_count, ++ dmc->block_size); ++ goto errout; ++ } ++ ++ goto out; ++ ++errout: ++ if (dmc->clean_mdpages) { ++ kfree(dmc->clean_mdpages); ++ dmc->clean_mdpages = NULL; ++ dmc->mdpage_count = 0; ++ } ++ if (dmc->clean_dbvecs) { ++ kfree(dmc->clean_dbvecs); ++ dmc->clean_dbvecs = NULL; ++ dmc->dbvec_count = 0; ++ } ++ ++out: ++ return ret; ++} ++ ++void eio_free_wb_resources(struct cache_c *dmc) ++{ ++ ++ if (dmc->mdupdate_q) { ++ flush_workqueue(dmc->mdupdate_q); ++ destroy_workqueue(dmc->mdupdate_q); ++ dmc->mdupdate_q = NULL; ++ } ++ if (dmc->dirty_set_lru) { ++ lru_uninit(dmc->dirty_set_lru); ++ dmc->dirty_set_lru = NULL; ++ } ++ if (dmc->clean_mdpages) { ++ eio_free_wb_pages(dmc->clean_mdpages, dmc->mdpage_count); ++ kfree(dmc->clean_mdpages); ++ dmc->clean_mdpages = NULL; ++ } ++ if (dmc->clean_dbvecs) { ++ eio_free_wb_bvecs(dmc->clean_dbvecs, dmc->dbvec_count, ++ dmc->block_size); ++ kfree(dmc->clean_dbvecs); ++ dmc->clean_dbvecs = NULL; ++ } ++ ++ dmc->dbvec_count = dmc->mdpage_count = 0; ++ return; ++} ++ ++static int ++eio_notify_reboot(struct notifier_block *this, unsigned long code, void *x) ++{ ++ struct cache_c *dmc; ++ ++ if (eio_reboot_notified == EIO_REBOOT_HANDLING_DONE) ++ return NOTIFY_DONE; ++ ++ (void)wait_on_bit_lock((void *)&eio_control->synch_flags, ++ EIO_HANDLE_REBOOT, eio_wait_schedule, ++ TASK_UNINTERRUPTIBLE); ++ if (eio_reboot_notified == EIO_REBOOT_HANDLING_DONE) { ++ clear_bit(EIO_HANDLE_REBOOT, (void *)&eio_control->synch_flags); ++ smp_mb__after_clear_bit(); ++ wake_up_bit((void *)&eio_control->synch_flags, ++ EIO_HANDLE_REBOOT); ++ return NOTIFY_DONE; ++ } ++ EIO_ASSERT(eio_reboot_notified == 0); ++ eio_reboot_notified = EIO_REBOOT_HANDLING_INPROG; ++ ++ (void)wait_on_bit_lock((void *)&eio_control->synch_flags, ++ EIO_UPDATE_LIST, eio_wait_schedule, ++ TASK_UNINTERRUPTIBLE); ++ for (dmc = cache_list_head; dmc != NULL; dmc = dmc->next_cache) { ++ if (unlikely(CACHE_FAILED_IS_SET(dmc)) ++ || unlikely(CACHE_DEGRADED_IS_SET(dmc))) { ++ pr_err ++ ("notify_reboot: Cannot sync in failed / degraded mode"); ++ continue; ++ } ++ if (dmc->cold_boot && atomic64_read(&dmc->nr_dirty) ++ && !eio_force_warm_boot) { ++ pr_info ++ ("Cold boot set for cache %s: Draining dirty blocks: %lld", ++ dmc->cache_name, (long long)atomic64_read(&dmc->nr_dirty)); ++ eio_clean_for_reboot(dmc); ++ } ++ eio_md_store(dmc); ++ } ++ clear_bit(EIO_UPDATE_LIST, (void *)&eio_control->synch_flags); ++ smp_mb__after_clear_bit(); ++ wake_up_bit((void *)&eio_control->synch_flags, EIO_UPDATE_LIST); ++ ++ eio_reboot_notified = EIO_REBOOT_HANDLING_DONE; ++ clear_bit(EIO_HANDLE_REBOOT, (void *)&eio_control->synch_flags); ++ smp_mb__after_clear_bit(); ++ wake_up_bit((void *)&eio_control->synch_flags, EIO_HANDLE_REBOOT); ++ return NOTIFY_DONE; ++} ++ ++/* ++ * The SSD add/remove is handled using udev from the user space. The driver ++ * is notified from the user space via dmsetup message. Both device addition ++ * and removal events are handled in the driver by eio_handle_message(). ++ * ++ * The device remove has a special case. From the time the device is removed, ++ * until the time the driver gets notified from the user space could be a few msec ++ * or a couple of seconds. During this time, any IO to the SSD fails. While this ++ * is handled gracefully, the logs can get filled with IO error messages. ++ * ++ * In order to cover that gap, we handle the device removal within the kernel ++ * using this function. Note that using the scsi notifier function in the kernel ++ * (vs. receiving the message from user space) minimizes the notification delay ++ * between the time the SSD is removed until the driver is notified. This cannot, ++ * however, make this delay zero. Therefore, there will be a small window during ++ * which eio_io_callback() may fail on CACHEWRITE action. ++ * ++ * We still need the user space (udev) method of handling for the following ++ * reasons: ++ * (i) This notifier is only for a scsi device. ++ * (ii) The add/remove feature in user space can also be used to dynamically ++ * turn the cache on and off. ++ * ++ * This notifier is used only when SSD is removed. The add event can ++ * be caught using the BUS_NOTIFY_ADD_DEVICE in action. However, we only ++ * get a scsi handle and do not have a reference to our device pointer. ++ */ ++static int ++eio_notify_ssd_rm(struct notifier_block *nb, unsigned long action, void *data) ++{ ++ struct device *dev = data; ++ struct cache_c *dmc; ++ const char *device_name; ++ size_t len; ++ unsigned long int flags = 0; ++ struct ssd_rm_list *ssd_list_ptr; ++ unsigned check_src = 0, check_ssd = 0; ++ enum dev_notifier notify = NOTIFY_INITIALIZER; ++ ++ if (likely(action != BUS_NOTIFY_DEL_DEVICE)) ++ return 0; ++ ++ if (unlikely(dev == NULL)) { ++ pr_info("notify_cache_dev: device is NULL!"); ++ return 0; ++ } ++ ++ if (!scsi_is_sdev_device(dev)) ++ return 0; ++ device_name = dev_name(dev); ++ if (device_name == NULL) ++ return 0; ++ len = strlen(device_name); ++ ++ /* push to a list for future processing as we could be in an interrupt context */ ++ for (dmc = cache_list_head; dmc != NULL; dmc = dmc->next_cache) { ++ notify = NOTIFY_INITIALIZER; ++ check_src = ('\0' == dmc->cache_srcdisk_name[0] ? 0 : 1); ++ check_ssd = ('\0' == dmc->cache_gendisk_name[0] ? 0 : 1); ++ ++ if (check_src == 0 && check_ssd == 0) ++ continue; ++ ++ /*Check if source dev name or ssd dev name is available or not. */ ++ if (check_ssd ++ && 0 == strncmp(device_name, dmc->cache_gendisk_name, ++ len)) { ++ pr_info("SSD Removed for cache name %s", ++ dmc->cache_name); ++ notify = NOTIFY_SSD_REMOVED; ++ } ++ ++ if (check_src ++ && 0 == strncmp(device_name, dmc->cache_srcdisk_name, ++ len)) { ++ pr_info("SRC Removed for cache name %s", ++ dmc->cache_name); ++ notify = NOTIFY_SRC_REMOVED; ++ } ++ ++ if (notify == NOTIFY_INITIALIZER) ++ continue; ++ ++ ssd_list_ptr = kmalloc(sizeof(struct ssd_rm_list), GFP_ATOMIC); ++ if (unlikely(ssd_list_ptr == NULL)) { ++ pr_err("Cannot allocate memory for ssd_rm_list"); ++ return -ENOMEM; ++ } ++ ssd_list_ptr->dmc = dmc; ++ ssd_list_ptr->action = action; ++ ssd_list_ptr->devt = dev->devt; ++ ssd_list_ptr->note = notify; ++ spin_lock_irqsave(&ssd_rm_list_lock, flags); ++ list_add_tail(&ssd_list_ptr->list, &ssd_rm_list); ++ ssd_rm_list_not_empty = 1; ++ spin_unlock_irqrestore(&ssd_rm_list_lock, flags); ++ } ++ ++ spin_lock_irqsave(&ssd_rm_list_lock, flags); ++ if (ssd_rm_list_not_empty) { ++ spin_unlock_irqrestore(&ssd_rm_list_lock, flags); ++ schedule_work(&_kcached_wq); ++ } else ++ spin_unlock_irqrestore(&ssd_rm_list_lock, flags); ++ ++ return 0; ++} ++ ++/* ++ * Initiate a cache target. ++ */ ++static int __init eio_init(void) ++{ ++ int r; ++ extern struct bus_type scsi_bus_type; ++ ++ eio_ttc_init(); ++ r = eio_create_misc_device(); ++ if (r) ++ return r; ++ ++ r = eio_jobs_init(); ++ if (r) { ++ (void)eio_delete_misc_device(); ++ return r; ++ } ++ atomic_set(&nr_cache_jobs, 0); ++ INIT_WORK(&_kcached_wq, eio_do_work); ++ ++ eio_module_procfs_init(); ++ eio_control = kmalloc(sizeof(*eio_control), GFP_KERNEL); ++ if (eio_control == NULL) { ++ pr_err("init: Cannot allocate memory for eio_control"); ++ (void)eio_delete_misc_device(); ++ return -ENOMEM; ++ } ++ eio_control->synch_flags = 0; ++ ++ register_reboot_notifier(&eio_reboot_notifier); ++ r = bus_register_notifier(&scsi_bus_type, &eio_ssd_rm_notifier); ++ if (r) { ++ pr_err("init: bus register notifier failed %d", r); ++ (void)eio_delete_misc_device(); ++ } ++ return r; ++} ++ ++/* ++ * Destroy a cache target. ++ */ ++static void eio_exit(void) ++{ ++ int r; ++ extern struct bus_type scsi_bus_type; ++ ++ unregister_reboot_notifier(&eio_reboot_notifier); ++ r = bus_unregister_notifier(&scsi_bus_type, &eio_ssd_rm_notifier); ++ if (r) ++ pr_err("exit: Bus unregister notifier failed %d", r); ++ ++ eio_jobs_exit(); ++ eio_module_procfs_exit(); ++ if (eio_control) { ++ eio_control->synch_flags = 0; ++ kfree(eio_control); ++ eio_control = NULL; ++ } ++ (void)eio_delete_misc_device(); ++} ++ ++/* ++ * eio_get_device_size ++ */ ++sector_t eio_get_device_size(struct eio_bdev *dev) ++{ ++ ++ return dev->bdev->bd_inode->i_size; ++} ++ ++/* ++ * To get starting sector of the device ++ */ ++sector_t eio_get_device_start_sect(struct eio_bdev *dev) ++{ ++ ++ if (dev == NULL || dev->bdev == NULL || dev->bdev->bd_part == NULL) ++ return 0; ++ ++ return dev->bdev->bd_part->start_sect; ++} ++ ++module_init(eio_init); ++module_exit(eio_exit); ++ ++MODULE_DESCRIPTION(DM_NAME "STEC EnhanceIO target"); ++MODULE_AUTHOR("STEC, Inc. based on code by Facebook"); ++ ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_fifo.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_fifo.c +--- linux-3.10.30/drivers/block/enhanceio/eio_fifo.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_fifo.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,239 @@ ++/* ++ * eio_fifo.c ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * ++ * Copyright 2010 Facebook, Inc. ++ * Author: Mohan Srinivasan (mohan@facebook.com) ++ * ++ * Based on DM-Cache: ++ * Copyright (C) International Business Machines Corp., 2006 ++ * Author: Ming Zhao (mingzhao@ufl.edu) ++ * ++ * 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; under 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, see . ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include "eio.h" ++/* Generic policy functions prototypes */ ++int eio_fifo_init(struct cache_c *); ++void eio_fifo_exit(void); ++int eio_fifo_cache_sets_init(struct eio_policy *); ++int eio_fifo_cache_blk_init(struct eio_policy *); ++void eio_fifo_find_reclaim_dbn(struct eio_policy *, index_t, index_t *); ++int eio_fifo_clean_set(struct eio_policy *, index_t, int); ++ ++/* Per policy instance initialization */ ++struct eio_policy *eio_fifo_instance_init(void); ++ ++/* Per cache set data structure */ ++struct eio_fifo_cache_set { ++ index_t set_fifo_next; ++ index_t set_clean_next; ++}; ++ ++/* ++ * Context that captures the FIFO replacement policy ++ */ ++static struct eio_policy_header eio_fifo_ops = { ++ .sph_name = CACHE_REPL_FIFO, ++ .sph_instance_init = eio_fifo_instance_init, ++}; ++ ++/* ++ * Initialize FIFO policy. ++ */ ++int eio_fifo_init(struct cache_c *dmc) ++{ ++ return 0; ++} ++ ++/* ++ * Initialize FIFO data structure called from ctr. ++ */ ++int eio_fifo_cache_sets_init(struct eio_policy *p_ops) ++{ ++ int i; ++ sector_t order; ++ struct cache_c *dmc = p_ops->sp_dmc; ++ struct eio_fifo_cache_set *cache_sets; ++ ++ pr_info("Initializing fifo cache sets\n"); ++ order = (dmc->size >> dmc->consecutive_shift) * ++ sizeof(struct eio_fifo_cache_set); ++ ++ dmc->sp_cache_set = vmalloc((size_t)order); ++ if (dmc->sp_cache_set == NULL) ++ return -ENOMEM; ++ ++ cache_sets = (struct eio_fifo_cache_set *)dmc->sp_cache_set; ++ ++ for (i = 0; i < (int)(dmc->size >> dmc->consecutive_shift); i++) { ++ cache_sets[i].set_fifo_next = i * dmc->assoc; ++ cache_sets[i].set_clean_next = i * dmc->assoc; ++ } ++ ++ return 0; ++} ++ ++/* ++ * The actual function that returns a victim block in index. ++ */ ++void ++eio_fifo_find_reclaim_dbn(struct eio_policy *p_ops, index_t start_index, ++ index_t *index) ++{ ++ index_t end_index; ++ int slots_searched = 0; ++ index_t i; ++ index_t set; ++ struct eio_fifo_cache_set *cache_sets; ++ struct cache_c *dmc = p_ops->sp_dmc; ++ ++ set = start_index / dmc->assoc; ++ end_index = start_index + dmc->assoc; ++ cache_sets = (struct eio_fifo_cache_set *)dmc->sp_cache_set; ++ ++ i = cache_sets[set].set_fifo_next; ++ while (slots_searched < (int)dmc->assoc) { ++ EIO_ASSERT(i >= start_index); ++ EIO_ASSERT(i < end_index); ++ if (EIO_CACHE_STATE_GET(dmc, i) == VALID) { ++ *index = i; ++ break; ++ } ++ slots_searched++; ++ i++; ++ if (i == end_index) ++ i = start_index; ++ } ++ i++; ++ if (i == end_index) ++ i = start_index; ++ cache_sets[set].set_fifo_next = i; ++} ++ ++/* ++ * Go through the entire set and clean. ++ */ ++int eio_fifo_clean_set(struct eio_policy *p_ops, index_t set, int to_clean) ++{ ++ index_t i; ++ int scanned = 0, nr_writes = 0; ++ index_t start_index; ++ index_t end_index; ++ struct eio_fifo_cache_set *cache_sets; ++ struct cache_c *dmc; ++ ++ dmc = p_ops->sp_dmc; ++ cache_sets = (struct eio_fifo_cache_set *)dmc->sp_cache_set; ++ start_index = set * dmc->assoc; ++ end_index = start_index + dmc->assoc; ++ i = cache_sets[set].set_clean_next; ++ ++ while ((scanned < (int)dmc->assoc) && (nr_writes < to_clean)) { ++ if ((EIO_CACHE_STATE_GET(dmc, i) & (DIRTY | BLOCK_IO_INPROG)) == ++ DIRTY) { ++ EIO_CACHE_STATE_ON(dmc, i, DISKWRITEINPROG); ++ nr_writes++; ++ } ++ scanned++; ++ i++; ++ if (i == end_index) ++ i = start_index; ++ } ++ cache_sets[set].set_clean_next = i; ++ ++ return nr_writes; ++} ++ ++/* ++ * FIFO is per set, so do nothing on a per block init. ++ */ ++int eio_fifo_cache_blk_init(struct eio_policy *p_ops) ++{ ++ return 0; ++} ++ ++/* ++ * Allocate a new instance of eio_policy per dmc ++ */ ++struct eio_policy *eio_fifo_instance_init(void) ++{ ++ struct eio_policy *new_instance; ++ ++ new_instance = vmalloc(sizeof(struct eio_policy)); ++ if (new_instance == NULL) { ++ pr_err("ssdscache_fifo_instance_init: vmalloc failed"); ++ return NULL; ++ } ++ ++ /* Initialize the FIFO specific functions and variables */ ++ new_instance->sp_name = CACHE_REPL_FIFO; ++ new_instance->sp_policy.lru = NULL; ++ new_instance->sp_repl_init = eio_fifo_init; ++ new_instance->sp_repl_exit = eio_fifo_exit; ++ new_instance->sp_repl_sets_init = eio_fifo_cache_sets_init; ++ new_instance->sp_repl_blk_init = eio_fifo_cache_blk_init; ++ new_instance->sp_find_reclaim_dbn = eio_fifo_find_reclaim_dbn; ++ new_instance->sp_clean_set = eio_fifo_clean_set; ++ new_instance->sp_dmc = NULL; ++ ++ try_module_get(THIS_MODULE); ++ ++ pr_info("eio_fifo_instance_init: created new instance of FIFO"); ++ ++ return new_instance; ++} ++ ++/* ++ * Cleanup an instance of eio_policy (called from dtr). ++ */ ++void eio_fifo_exit(void) ++{ ++ module_put(THIS_MODULE); ++} ++ ++static ++int __init fifo_register(void) ++{ ++ int ret; ++ ++ ret = eio_register_policy(&eio_fifo_ops); ++ if (ret != 0) ++ pr_info("eio_fifo already registered"); ++ ++ return ret; ++} ++ ++static ++void __exit fifo_unregister(void) ++{ ++ int ret; ++ ++ ret = eio_unregister_policy(&eio_fifo_ops); ++ if (ret != 0) ++ pr_err("eio_fifo unregister failed"); ++} ++ ++module_init(fifo_register); ++module_exit(fifo_unregister); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("FIFO policy for EnhanceIO"); ++MODULE_AUTHOR("STEC, Inc. based on code by Facebook"); +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_ioctl.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_ioctl.c +--- linux-3.10.30/drivers/block/enhanceio/eio_ioctl.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_ioctl.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,157 @@ ++/* ++ * eio_ioctl.c ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * ++ * Copyright 2010 Facebook, Inc. ++ * Author: Mohan Srinivasan (mohan@facebook.com) ++ * ++ * Based on DM-Cache: ++ * Copyright (C) International Business Machines Corp., 2006 ++ * Author: Ming Zhao (mingzhao@ufl.edu) ++ * ++ * 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; under 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, see . ++ */ ++ ++#include "eio.h" ++#include "eio_ttc.h" ++ ++long eio_ioctl(struct file *filp, unsigned cmd, unsigned long arg) ++{ ++ int error = 0; ++ struct cache_rec_short *cache; ++ uint64_t ncaches; ++ enum dev_notifier note; ++ int do_delete = 0; ++ ++ switch (cmd) { ++ case EIO_IOC_CREATE: ++ case EIO_IOC_ENABLE: ++ ++ cache = vmalloc(sizeof(struct cache_rec_short)); ++ if (!cache) ++ return -ENOMEM; ++ ++ if (copy_from_user(cache, (void __user *)arg, ++ sizeof(struct cache_rec_short))) { ++ vfree(cache); ++ return -EFAULT; ++ } ++ error = eio_cache_create(cache); ++ vfree(cache); ++ break; ++ ++ case EIO_IOC_DELETE: ++ do_delete = 1; ++ ++ case EIO_IOC_DISABLE: ++ ++ cache = vmalloc(sizeof(struct cache_rec_short)); ++ if (!cache) ++ return -ENOMEM; ++ ++ if (copy_from_user(cache, (void __user *)arg, ++ sizeof(struct cache_rec_short))) { ++ vfree(cache); ++ return -EFAULT; ++ } ++ error = eio_cache_delete(cache->cr_name, do_delete); ++ vfree(cache); ++ break; ++ ++ case EIO_IOC_EDIT: ++ cache = vmalloc(sizeof(struct cache_rec_short)); ++ if (!cache) ++ return -ENOMEM; ++ ++ if (copy_from_user(cache, (void __user *)arg, ++ sizeof(struct cache_rec_short))) { ++ vfree(cache); ++ return -EFAULT; ++ } ++ error = eio_cache_edit(cache->cr_name, ++ (u_int32_t)cache->cr_mode, ++ (u_int32_t)cache->cr_policy); ++ vfree(cache); ++ break; ++ ++ case EIO_IOC_NCACHES: ++ ncaches = eio_get_cache_count(); ++ if (copy_to_user((uint64_t __user *)arg, &ncaches, ++ sizeof(uint64_t))) ++ return -EFAULT; ++ break; ++ ++ case EIO_IOC_CACHE_LIST: ++ error = eio_get_cache_list((unsigned long __user *)arg); ++ break; ++ ++ case EIO_IOC_SET_WARM_BOOT: ++ eio_set_warm_boot(); ++ break; ++ ++ case EIO_IOC_SSD_ADD: ++ cache = vmalloc(sizeof(struct cache_rec_short)); ++ if (!cache) ++ return -ENOMEM; ++ ++ if (copy_from_user(cache, (void __user *)arg, ++ sizeof(struct cache_rec_short))) { ++ vfree(cache); ++ return -EFAULT; ++ } ++ note = NOTIFY_SSD_ADD; ++ error = ++ eio_handle_ssd_message(cache->cr_name, ++ cache->cr_ssd_devname, note); ++ vfree(cache); ++ ++ break; ++ ++ case EIO_IOC_SSD_REMOVE: ++ cache = vmalloc(sizeof(struct cache_rec_short)); ++ if (!cache) ++ return -ENOMEM; ++ if (copy_from_user(cache, (void __user *)arg, ++ sizeof(struct cache_rec_short))) { ++ vfree(cache); ++ return -EFAULT; ++ } ++ note = NOTIFY_SSD_REMOVED; ++ error = ++ eio_handle_ssd_message(cache->cr_name, ++ cache->cr_ssd_devname, note); ++ vfree(cache); ++ break; ++ ++ case EIO_IOC_SRC_ADD: ++ break; ++ ++ case EIO_IOC_NOTIFY_REBOOT: ++ eio_reboot_handling(); ++ break; ++ ++ default: ++ error = EINVAL; ++ } ++ return error; ++} ++ ++long eio_compact_ioctl(struct file *filp, unsigned cmd, unsigned long arg) ++{ ++ return eio_ioctl(filp, cmd, arg); ++} +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_ioctl.h linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_ioctl.h +--- linux-3.10.30/drivers/block/enhanceio/eio_ioctl.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_ioctl.h 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,86 @@ ++/* ++ * eio_ioctl.h ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * ++ * Copyright 2010 Facebook, Inc. ++ * Author: Mohan Srinivasan (mohan@facebook.com) ++ * ++ * Based on DM-Cache: ++ * Copyright (C) International Business Machines Corp., 2006 ++ * Author: Ming Zhao (mingzhao@ufl.edu) ++ * ++ * 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; under 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, see . ++ ****************************************************************************/ ++ ++#ifndef EIO_IOCTL_H ++#define EIO_IOCTL_H ++ ++#define EIO_DEVPATH "/dev/eiodev" ++#define MISC_DEVICE "eiodev" ++ ++#define CACHE_NAME_LEN 31 ++#define CACHE_NAME_SZ (CACHE_NAME_LEN + 1) ++ ++#define NAME_LEN 127 ++#define NAME_SZ (NAME_LEN + 1) ++ ++#define EIO_IOC_CREATE _IOW('E', 0, struct cache_rec_short) ++#define EIO_IOC_DELETE _IOW('E', 1, struct cache_rec_short) ++#define EIO_IOC_ENABLE _IOW('E', 2, struct cache_rec_short) ++#define EIO_IOC_DISABLE _IOW('E', 3, struct cache_rec_short) ++#define EIO_IOC_EDIT _IOW('E', 4, struct cache_rec_short) ++#define EIO_IOC_NCACHES _IOR('E', 5, uint64_t) ++#define EIO_IOC_CACHE_LIST _IOWR('E', 6, struct cache_list) ++#define EIO_IOC_SSD_ADD _IOW('E', 7, struct cache_rec_short) ++#define EIO_IOC_SSD_REMOVE _IOW('E', 8, struct cache_rec_short) ++#define EIO_IOC_SRC_ADD _IOW('E', 9, struct cache_rec_short) ++#define EIO_IOC_SRC_REMOVE _IOW('E', 10, struct cache_rec_short) ++#define EIO_IOC_NOTIFY_REBOOT _IO('E', 11) ++#define EIO_IOC_SET_WARM_BOOT _IO('E', 12) ++#define EIO_IOC_UNUSED _IO('E', 13) ++ ++ ++struct cache_rec_short { ++ char cr_name[CACHE_NAME_SZ]; ++ char cr_src_devname[NAME_SZ]; ++ char cr_ssd_devname[NAME_SZ]; ++ char cr_ssd_uuid[NAME_SZ]; ++ uint64_t cr_src_dev_size; ++ uint64_t cr_ssd_dev_size; ++ uint32_t cr_src_sector_size; ++ uint32_t cr_ssd_sector_size; ++ uint32_t cr_flags; /* CACHE_FLAGS_INV* etc. */ ++ char cr_policy; ++ char cr_mode; ++ char cr_persistence; ++ char cr_cold_boot; ++ uint64_t cr_blksize; ++ uint64_t cr_assoc; ++}; ++ ++struct cache_list { ++ uint64_t ncaches; ++ struct cache_rec_short *cachelist; ++}; ++ ++#ifdef __KERNEL__ ++long eio_ioctl(struct file *filp, unsigned cmd, unsigned long arg); ++long eio_compact_ioctl(struct file *filp, unsigned cmd, unsigned long arg); ++#endif /* __KERNEL__ */ ++ ++#endif /* !EIO_IOCTL_H */ +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_lru.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_lru.c +--- linux-3.10.30/drivers/block/enhanceio/eio_lru.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_lru.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,322 @@ ++/* ++ * eio_lru.c ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * ++ * Copyright 2010 Facebook, Inc. ++ * Author: Mohan Srinivasan (mohan@facebook.com) ++ * ++ * Based on DM-Cache: ++ * Copyright (C) International Business Machines Corp., 2006 ++ * Author: Ming Zhao (mingzhao@ufl.edu) ++ * ++ * 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; under 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, see . ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include "eio.h" ++/* Generic policy functions prototyes */ ++int eio_lru_init(struct cache_c *); ++void eio_lru_exit(void); ++int eio_lru_cache_sets_init(struct eio_policy *); ++int eio_lru_cache_blk_init(struct eio_policy *); ++void eio_lru_find_reclaim_dbn(struct eio_policy *, index_t, index_t *); ++int eio_lru_clean_set(struct eio_policy *, index_t, int); ++/* Per policy instance initialization */ ++struct eio_policy *eio_lru_instance_init(void); ++ ++/* LRU specific policy functions prototype */ ++void eio_lru_pushblks(struct eio_policy *); ++void eio_reclaim_lru_movetail(struct cache_c *, index_t, struct eio_policy *); ++ ++/* Per cache set data structure */ ++struct eio_lru_cache_set { ++ u_int16_t lru_head, lru_tail; ++}; ++ ++/* Per cache block data structure */ ++struct eio_lru_cache_block { ++ u_int16_t lru_prev, lru_next; ++}; ++ ++/* LRU specifc data structures */ ++static struct eio_lru eio_lru = { ++ .sl_lru_pushblks = eio_lru_pushblks, ++ .sl_reclaim_lru_movetail = eio_reclaim_lru_movetail, ++}; ++ ++/* ++ * Context that captures the LRU replacement policy ++ */ ++static struct eio_policy_header eio_lru_ops = { ++ .sph_name = CACHE_REPL_LRU, ++ .sph_instance_init = eio_lru_instance_init, ++}; ++ ++/* ++ * Intialize LRU. Called from ctr. ++ */ ++int eio_lru_init(struct cache_c *dmc) ++{ ++ return 0; ++} ++ ++/* ++ * Initialize per set LRU data structures. ++ */ ++int eio_lru_cache_sets_init(struct eio_policy *p_ops) ++{ ++ sector_t order; ++ int i; ++ struct cache_c *dmc = p_ops->sp_dmc; ++ struct eio_lru_cache_set *cache_sets; ++ ++ order = ++ (dmc->size >> dmc->consecutive_shift) * ++ sizeof(struct eio_lru_cache_set); ++ ++ dmc->sp_cache_set = vmalloc((size_t)order); ++ if (dmc->sp_cache_set == NULL) ++ return -ENOMEM; ++ ++ cache_sets = (struct eio_lru_cache_set *)dmc->sp_cache_set; ++ ++ for (i = 0; i < (int)(dmc->size >> dmc->consecutive_shift); i++) { ++ cache_sets[i].lru_tail = EIO_LRU_NULL; ++ cache_sets[i].lru_head = EIO_LRU_NULL; ++ } ++ pr_info("Initialized %d sets in LRU", i); ++ ++ return 0; ++} ++ ++/* ++ * Initialize per block LRU data structures ++ */ ++int eio_lru_cache_blk_init(struct eio_policy *p_ops) ++{ ++ sector_t order; ++ struct cache_c *dmc = p_ops->sp_dmc; ++ ++ order = dmc->size * sizeof(struct eio_lru_cache_block); ++ ++ dmc->sp_cache_blk = vmalloc((size_t)order); ++ if (dmc->sp_cache_blk == NULL) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++/* ++ * Allocate a new instance of eio_policy per dmc ++ */ ++struct eio_policy *eio_lru_instance_init(void) ++{ ++ struct eio_policy *new_instance; ++ ++ new_instance = vmalloc(sizeof(struct eio_policy)); ++ if (new_instance == NULL) { ++ pr_err("eio_lru_instance_init: vmalloc failed"); ++ return NULL; ++ } ++ ++ /* Initialize the LRU specific functions and variables */ ++ new_instance->sp_name = CACHE_REPL_LRU; ++ new_instance->sp_policy.lru = &eio_lru; ++ new_instance->sp_repl_init = eio_lru_init; ++ new_instance->sp_repl_exit = eio_lru_exit; ++ new_instance->sp_repl_sets_init = eio_lru_cache_sets_init; ++ new_instance->sp_repl_blk_init = eio_lru_cache_blk_init; ++ new_instance->sp_find_reclaim_dbn = eio_lru_find_reclaim_dbn; ++ new_instance->sp_clean_set = eio_lru_clean_set; ++ new_instance->sp_dmc = NULL; ++ ++ try_module_get(THIS_MODULE); ++ ++ pr_info("eio_lru_instance_init: created new instance of LRU"); ++ ++ return new_instance; ++} ++ ++/* ++ * Cleanup an instance of eio_policy (called from dtr). ++ */ ++void eio_lru_exit(void) ++{ ++ module_put(THIS_MODULE); ++} ++ ++/* ++ * Find a victim block to evict and return it in index. ++ */ ++void ++eio_lru_find_reclaim_dbn(struct eio_policy *p_ops, ++ index_t start_index, index_t *index) ++{ ++ index_t lru_rel_index; ++ struct eio_lru_cache_set *lru_sets; ++ struct eio_lru_cache_block *lru_blk; ++ struct cache_c *dmc = p_ops->sp_dmc; ++ index_t set; ++ ++ set = start_index / dmc->assoc; ++ lru_sets = (struct eio_lru_cache_set *)(dmc->sp_cache_set); ++ ++ lru_rel_index = lru_sets[set].lru_head; ++ while (lru_rel_index != EIO_LRU_NULL) { ++ lru_blk = ++ ((struct eio_lru_cache_block *)dmc->sp_cache_blk + ++ lru_rel_index + start_index); ++ if (EIO_CACHE_STATE_GET(dmc, (lru_rel_index + start_index)) == ++ VALID) { ++ EIO_ASSERT((lru_blk - (struct eio_lru_cache_block *) ++ dmc->sp_cache_blk) == ++ (lru_rel_index + start_index)); ++ *index = lru_rel_index + start_index; ++ eio_reclaim_lru_movetail(dmc, *index, p_ops); ++ break; ++ } ++ lru_rel_index = lru_blk->lru_next; ++ } ++ ++ return; ++} ++ ++/* ++ * Go through the entire set and clean. ++ */ ++int eio_lru_clean_set(struct eio_policy *p_ops, index_t set, int to_clean) ++{ ++ struct cache_c *dmc = p_ops->sp_dmc; ++ index_t lru_rel_index; ++ int nr_writes = 0; ++ struct eio_lru_cache_set *lru_cache_sets; ++ struct eio_lru_cache_block *lru_cacheblk; ++ index_t dmc_idx; ++ index_t start_index; ++ ++ lru_cache_sets = (struct eio_lru_cache_set *)dmc->sp_cache_set; ++ start_index = set * dmc->assoc; ++ lru_rel_index = lru_cache_sets[set].lru_head; ++ ++ while ((lru_rel_index != EIO_LRU_NULL) && (nr_writes < to_clean)) { ++ dmc_idx = lru_rel_index + start_index; ++ lru_cacheblk = ++ ((struct eio_lru_cache_block *)dmc->sp_cache_blk + ++ lru_rel_index + start_index); ++ EIO_ASSERT((lru_cacheblk - ++ (struct eio_lru_cache_block *)dmc->sp_cache_blk) == ++ (lru_rel_index + start_index)); ++ if ((EIO_CACHE_STATE_GET(dmc, dmc_idx) & ++ (DIRTY | BLOCK_IO_INPROG)) == DIRTY) { ++ EIO_CACHE_STATE_ON(dmc, dmc_idx, DISKWRITEINPROG); ++ nr_writes++; ++ } ++ lru_rel_index = lru_cacheblk->lru_next; ++ } ++ ++ return nr_writes; ++} ++ ++/* ++ * LRU specific functions. ++ */ ++void ++eio_reclaim_lru_movetail(struct cache_c *dmc, index_t index, ++ struct eio_policy *p_ops) ++{ ++ index_t set = index / dmc->assoc; ++ index_t start_index = set * dmc->assoc; ++ index_t my_index = index - start_index; ++ struct eio_lru_cache_block *cacheblk; ++ struct eio_lru_cache_set *cache_sets; ++ struct eio_lru_cache_block *blkptr; ++ ++ cacheblk = ++ (((struct eio_lru_cache_block *)(dmc->sp_cache_blk)) + index); ++ cache_sets = (struct eio_lru_cache_set *)dmc->sp_cache_set; ++ blkptr = (struct eio_lru_cache_block *)(dmc->sp_cache_blk); ++ ++ /* Remove from LRU */ ++ if (likely((cacheblk->lru_prev != EIO_LRU_NULL) || ++ (cacheblk->lru_next != EIO_LRU_NULL))) { ++ if (cacheblk->lru_prev != EIO_LRU_NULL) ++ blkptr[cacheblk->lru_prev + start_index].lru_next = ++ cacheblk->lru_next; ++ else ++ cache_sets[set].lru_head = cacheblk->lru_next; ++ if (cacheblk->lru_next != EIO_LRU_NULL) ++ blkptr[cacheblk->lru_next + start_index].lru_prev = ++ cacheblk->lru_prev; ++ else ++ cache_sets[set].lru_tail = cacheblk->lru_prev; ++ } ++ /* And add it to LRU Tail */ ++ cacheblk->lru_next = EIO_LRU_NULL; ++ cacheblk->lru_prev = cache_sets[set].lru_tail; ++ if (cache_sets[set].lru_tail == EIO_LRU_NULL) ++ cache_sets[set].lru_head = (u_int16_t)my_index; ++ else ++ blkptr[cache_sets[set].lru_tail + start_index].lru_next = ++ (u_int16_t)my_index; ++ cache_sets[set].lru_tail = (u_int16_t)my_index; ++} ++ ++void eio_lru_pushblks(struct eio_policy *p_ops) ++{ ++ struct cache_c *dmc = p_ops->sp_dmc; ++ struct eio_lru_cache_block *cache_block; ++ int i; ++ ++ cache_block = dmc->sp_cache_blk; ++ for (i = 0; i < (int)dmc->size; i++) { ++ cache_block[i].lru_prev = EIO_LRU_NULL; ++ cache_block[i].lru_next = EIO_LRU_NULL; ++ eio_reclaim_lru_movetail(dmc, i, p_ops); ++ } ++ return; ++} ++ ++static ++int __init lru_register(void) ++{ ++ int ret; ++ ++ ret = eio_register_policy(&eio_lru_ops); ++ if (ret != 0) ++ pr_info("eio_lru already registered"); ++ ++ return ret; ++} ++ ++static ++void __exit lru_unregister(void) ++{ ++ int ret; ++ ++ ret = eio_unregister_policy(&eio_lru_ops); ++ if (ret != 0) ++ pr_err("eio_lru unregister failed"); ++} ++ ++module_init(lru_register); ++module_exit(lru_unregister); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("LRU policy for EnhanceIO"); ++MODULE_AUTHOR("STEC, Inc. based on code by Facebook"); +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_main.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_main.c +--- linux-3.10.30/drivers/block/enhanceio/eio_main.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_main.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,3546 @@ ++/* ++ * eio_main.c ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * Amit Kale ++ * Restructured much of the io code to split bio within map function instead ++ * of letting dm do it. ++ * Simplified queued logic for write through. ++ * Created per-cache spinlocks for reducing contention in IO codepath. ++ * Amit Kale ++ * Harish Pujari ++ * Designed and implemented the writeback caching mode ++ * Copyright 2010 Facebook, Inc. ++ * Author: Mohan Srinivasan (mohan@facebook.com) ++ * ++ * Based on DM-Cache: ++ * Copyright (C) International Business Machines Corp., 2006 ++ * Author: Ming Zhao (mingzhao@ufl.edu) ++ * ++ * 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; under 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, see . ++ */ ++ ++#include "eio.h" ++#include "eio_ttc.h" ++ ++#define CTRACE(X) { } ++ ++/* ++ * TODO List : ++ * 1) sysctls : Create per-cache device sysctls instead of global sysctls. ++ * 2) Management of non cache pids : Needs improvement. Remove registration ++ * on process exits (with a pseudo filesstem'ish approach perhaps) ? ++ * 3) Breaking up the cache spinlock : Right now contention on the spinlock ++ * is not a problem. Might need change in future. ++ * 4) Use the standard linked list manipulation macros instead rolling our own. ++ * 5) Fix a security hole : A malicious process with 'ro' access to a file can ++ * potentially corrupt file data. This can be fixed by copying the data on a ++ * cache read miss. ++ */ ++ ++static int eio_read_peek(struct cache_c *dmc, struct eio_bio *ebio); ++static int eio_write_peek(struct cache_c *dmc, struct eio_bio *ebio); ++static void eio_read(struct cache_c *dmc, struct bio_container *bc, ++ struct eio_bio *ebegin); ++static void eio_write(struct cache_c *dmc, struct bio_container *bc, ++ struct eio_bio *ebegin); ++static int eio_inval_block(struct cache_c *dmc, sector_t iosector); ++static void eio_enqueue_readfill(struct cache_c *dmc, struct kcached_job *job); ++static int eio_acquire_set_locks(struct cache_c *dmc, struct bio_container *bc); ++static int eio_release_io_resources(struct cache_c *dmc, ++ struct bio_container *bc); ++static void eio_clean_set(struct cache_c *dmc, index_t set, int whole, ++ int force); ++static void eio_do_mdupdate(struct work_struct *work); ++static void eio_mdupdate_callback(int error, void *context); ++static void eio_enq_mdupdate(struct bio_container *bc); ++static void eio_uncached_read_done(struct kcached_job *job); ++static void eio_addto_cleanq(struct cache_c *dmc, index_t set, int whole); ++static int eio_alloc_mdreqs(struct cache_c *, struct bio_container *); ++static void eio_check_dirty_set_thresholds(struct cache_c *dmc, index_t set); ++static void eio_check_dirty_cache_thresholds(struct cache_c *dmc); ++static void eio_post_mdupdate(struct work_struct *work); ++static void eio_post_io_callback(struct work_struct *work); ++ ++static void bc_addfb(struct bio_container *bc, struct eio_bio *ebio) ++{ ++ ++ atomic_inc(&bc->bc_holdcount); ++ ++ ebio->eb_bc = bc; ++} ++ ++static void bc_put(struct bio_container *bc, unsigned int doneio) ++{ ++ struct cache_c *dmc; ++ int data_dir; ++ long elapsed; ++ ++ if (atomic_dec_and_test(&bc->bc_holdcount)) { ++ if (bc->bc_dmc->mode == CACHE_MODE_WB) ++ eio_release_io_resources(bc->bc_dmc, bc); ++ bc->bc_bio->bi_size = 0; ++ dmc = bc->bc_dmc; ++ ++ /* update iotime for latency */ ++ data_dir = bio_data_dir(bc->bc_bio); ++ elapsed = (long)jiffies_to_msecs(jiffies - bc->bc_iotime); ++ ++ if (data_dir == READ) ++ atomic64_add(elapsed, &dmc->eio_stats.rdtime_ms); ++ else ++ atomic64_add(elapsed, &dmc->eio_stats.wrtime_ms); ++ ++ bio_endio(bc->bc_bio, bc->bc_error); ++ atomic64_dec(&bc->bc_dmc->nr_ios); ++ kfree(bc); ++ } ++} ++ ++static void eb_endio(struct eio_bio *ebio, int error) ++{ ++ ++ EIO_ASSERT(ebio->eb_bc); ++ ++ /*Propagate only main io errors and sizes*/ ++ if (ebio->eb_iotype == EB_MAIN_IO) { ++ if (error) ++ ebio->eb_bc->bc_error = error; ++ bc_put(ebio->eb_bc, ebio->eb_size); ++ } else ++ bc_put(ebio->eb_bc, 0); ++ ebio->eb_bc = NULL; ++ kfree(ebio); ++} ++ ++static int ++eio_io_async_bvec(struct cache_c *dmc, struct eio_io_region *where, int rw, ++ struct bio_vec *pages, unsigned nr_bvecs, eio_notify_fn fn, ++ void *context, int hddio) ++{ ++ struct eio_io_request req; ++ int error = 0; ++ ++ memset((char *)&req, 0, sizeof(req)); ++ ++ if (unlikely(CACHE_DEGRADED_IS_SET(dmc))) { ++ if (where->bdev != dmc->disk_dev->bdev) { ++ pr_err ++ ("eio_io_async_bvec: Cache is in degraded mode.\n"); ++ pr_err ++ ("eio_io_async_Bvec: Can not issue i/o to ssd device.\n"); ++ return -ENODEV; ++ } ++ } ++ ++ req.mtype = EIO_BVECS; ++ req.dptr.pages = pages; ++ req.num_bvecs = nr_bvecs; ++ req.notify = fn; ++ req.context = context; ++ req.hddio = hddio; ++ ++ error = eio_do_io(dmc, where, rw, &req); ++ ++ return error; ++} ++ ++static void ++eio_flag_abios(struct cache_c *dmc, struct eio_bio *abio, int invalidated) ++{ ++ struct eio_bio *nbio; ++ ++ while (abio) { ++ int invalidate; ++ unsigned long flags; ++ int cwip_on = 0; ++ int dirty_on = 0; ++ int callendio = 0; ++ nbio = abio->eb_next; ++ ++ EIO_ASSERT(!(abio->eb_iotype & EB_INVAL) || abio->eb_index == -1); ++ invalidate = !invalidated && (abio->eb_iotype & EB_INVAL); ++ ++ spin_lock_irqsave(&dmc->cache_sets[abio->eb_cacheset].cs_lock, ++ flags); ++ ++ if (abio->eb_index != -1) { ++ if (EIO_CACHE_STATE_GET(dmc, abio->eb_index) & DIRTY) ++ dirty_on = 1; ++ ++ if (unlikely ++ (EIO_CACHE_STATE_GET(dmc, abio->eb_index) & ++ CACHEWRITEINPROG)) ++ cwip_on = 1; ++ } ++ ++ if (dirty_on) { ++ /* ++ * For dirty blocks, we don't change the cache state flags. ++ * We however, need to end the ebio, if this was the last ++ * hold on it. ++ */ ++ if (atomic_dec_and_test(&abio->eb_holdcount)) { ++ callendio = 1; ++ /* We shouldn't reach here when the DIRTY_INPROG flag ++ * is set on the cache block. It should either have been ++ * cleared to become DIRTY or INVALID elsewhere. ++ */ ++ EIO_ASSERT(EIO_CACHE_STATE_GET(dmc, abio->eb_index) ++ != DIRTY_INPROG); ++ } ++ } else if (abio->eb_index != -1) { ++ if (invalidate) { ++ if (cwip_on) ++ EIO_CACHE_STATE_ON(dmc, abio->eb_index, ++ QUEUED); ++ else { ++ EIO_CACHE_STATE_SET(dmc, abio->eb_index, ++ INVALID); ++ atomic64_dec_if_positive(&dmc-> ++ eio_stats. ++ cached_blocks); ++ } ++ } else { ++ if (cwip_on) ++ EIO_CACHE_STATE_OFF(dmc, abio->eb_index, ++ DISKWRITEINPROG); ++ else { ++ if (EIO_CACHE_STATE_GET ++ (dmc, abio->eb_index) & QUEUED) { ++ EIO_CACHE_STATE_SET(dmc, ++ abio-> ++ eb_index, ++ INVALID); ++ atomic64_dec_if_positive(&dmc-> ++ eio_stats. ++ cached_blocks); ++ } else { ++ EIO_CACHE_STATE_SET(dmc, ++ abio-> ++ eb_index, ++ VALID); ++ } ++ } ++ } ++ } else { ++ EIO_ASSERT(invalidated || invalidate); ++ if (invalidate) ++ eio_inval_block(dmc, abio->eb_sector); ++ } ++ spin_unlock_irqrestore(&dmc->cache_sets[abio->eb_cacheset]. ++ cs_lock, flags); ++ if (!cwip_on && (!dirty_on || callendio)) ++ eb_endio(abio, 0); ++ abio = nbio; ++ } ++} ++ ++static void eio_disk_io_callback(int error, void *context) ++{ ++ struct kcached_job *job; ++ struct eio_bio *ebio; ++ struct cache_c *dmc; ++ unsigned long flags; ++ unsigned eb_cacheset; ++ ++ flags = 0; ++ job = (struct kcached_job *)context; ++ dmc = job->dmc; ++ ebio = job->ebio; ++ ++ EIO_ASSERT(ebio != NULL); ++ eb_cacheset = ebio->eb_cacheset; ++ ++ if (unlikely(error)) ++ dmc->eio_errors.disk_read_errors++; ++ ++ spin_lock_irqsave(&dmc->cache_sets[eb_cacheset].cs_lock, flags); ++ /* Invalidate the cache block */ ++ EIO_CACHE_STATE_SET(dmc, ebio->eb_index, INVALID); ++ atomic64_dec_if_positive(&dmc->eio_stats.cached_blocks); ++ spin_unlock_irqrestore(&dmc->cache_sets[eb_cacheset].cs_lock, flags); ++ ++ if (unlikely(error)) ++ pr_err("disk_io_callback: io error %d block %llu action %d", ++ error, ++ (unsigned long long)job->job_io_regions.disk.sector, ++ job->action); ++ ++ eb_endio(ebio, error); ++ ebio = NULL; ++ job->ebio = NULL; ++ eio_free_cache_job(job); ++ job = NULL; ++} ++ ++static void eio_uncached_read_done(struct kcached_job *job) ++{ ++ struct eio_bio *ebio = job->ebio; ++ struct cache_c *dmc = job->dmc; ++ struct eio_bio *iebio; ++ struct eio_bio *nebio; ++ unsigned long flags = 0; ++ ++ if (ebio->eb_bc->bc_dir == UNCACHED_READ) { ++ EIO_ASSERT(ebio != NULL); ++ iebio = ebio->eb_next; ++ while (iebio != NULL) { ++ nebio = iebio->eb_next; ++ if (iebio->eb_index != -1) { ++ spin_lock_irqsave(&dmc-> ++ cache_sets[iebio-> ++ eb_cacheset]. ++ cs_lock, flags); ++ if (unlikely ++ (EIO_CACHE_STATE_GET(dmc, iebio->eb_index) & ++ QUEUED)) { ++ EIO_CACHE_STATE_SET(dmc, ++ iebio->eb_index, ++ INVALID); ++ atomic64_dec_if_positive(&dmc-> ++ eio_stats. ++ cached_blocks); ++ } else ++ if (EIO_CACHE_STATE_GET ++ (dmc, ++ iebio->eb_index) & CACHEREADINPROG) { ++ /*turn off the cache read in prog flag*/ ++ EIO_CACHE_STATE_OFF(dmc, ++ iebio->eb_index, ++ BLOCK_IO_INPROG); ++ } else ++ /*Should never reach here*/ ++ EIO_ASSERT(0); ++ spin_unlock_irqrestore(&dmc-> ++ cache_sets[iebio-> ++ eb_cacheset]. ++ cs_lock, flags); ++ } ++ eb_endio(iebio, 0); ++ iebio = nebio; ++ } ++ eb_endio(ebio, 0); ++ eio_free_cache_job(job); ++ } else if (ebio->eb_bc->bc_dir == UNCACHED_READ_AND_READFILL) { ++ /* ++ * Kick off the READFILL. It will also do a read ++ * from SSD, in case of ALREADY_DIRTY block ++ */ ++ job->action = READFILL; ++ eio_enqueue_readfill(dmc, job); ++ } else ++ /* Should never reach here for uncached read */ ++ EIO_ASSERT(0); ++} ++ ++static void eio_io_callback(int error, void *context) ++{ ++ struct kcached_job *job = (struct kcached_job *)context; ++ struct cache_c *dmc = job->dmc; ++ ++ job->error = error; ++ INIT_WORK(&job->work, eio_post_io_callback); ++ queue_work(dmc->callback_q, &job->work); ++ return; ++} ++ ++static void eio_post_io_callback(struct work_struct *work) ++{ ++ struct kcached_job *job; ++ struct cache_c *dmc; ++ struct eio_bio *ebio; ++ unsigned long flags = 0; ++ index_t index; ++ unsigned eb_cacheset; ++ u_int8_t cstate; ++ int callendio = 0; ++ int error; ++ ++ job = container_of(work, struct kcached_job, work); ++ dmc = job->dmc; ++ index = job->index; ++ error = job->error; ++ ++ EIO_ASSERT(index != -1 || job->action == WRITEDISK ++ || job->action == READDISK); ++ ebio = job->ebio; ++ EIO_ASSERT(ebio != NULL); ++ EIO_ASSERT(ebio->eb_bc); ++ ++ eb_cacheset = ebio->eb_cacheset; ++ if (error) ++ pr_err("io_callback: io error %d block %llu action %d", ++ error, ++ (unsigned long long)job->job_io_regions.disk.sector, ++ job->action); ++ ++ switch (job->action) { ++ case WRITEDISK: ++ ++ atomic64_inc(&dmc->eio_stats.writedisk); ++ if (unlikely(error)) ++ dmc->eio_errors.disk_write_errors++; ++ if (unlikely(error) || (ebio->eb_iotype & EB_INVAL)) ++ eio_inval_range(dmc, ebio->eb_sector, ebio->eb_size); ++ if (ebio->eb_next) ++ eio_flag_abios(dmc, ebio->eb_next, ++ error || (ebio->eb_iotype & EB_INVAL)); ++ eb_endio(ebio, error); ++ job->ebio = NULL; ++ eio_free_cache_job(job); ++ return; ++ ++ case READDISK: ++ ++ if (unlikely(error) || unlikely(ebio->eb_iotype & EB_INVAL) ++ || CACHE_DEGRADED_IS_SET(dmc)) { ++ if (error) ++ dmc->eio_errors.disk_read_errors++; ++ eio_inval_range(dmc, ebio->eb_sector, ebio->eb_size); ++ eio_flag_abios(dmc, ebio->eb_next, 1); ++ } else if (ebio->eb_next) { ++ eio_uncached_read_done(job); ++ return; ++ } ++ eb_endio(ebio, error); ++ job->ebio = NULL; ++ eio_free_cache_job(job); ++ return; ++ ++ case READCACHE: ++ ++ /*atomic64_inc(&dmc->eio_stats.readcache);*/ ++ /*SECTOR_STATS(dmc->eio_stats.ssd_reads, ebio->eb_size);*/ ++ EIO_ASSERT(EIO_DBN_GET(dmc, index) == ++ EIO_ROUND_SECTOR(dmc, ebio->eb_sector)); ++ cstate = EIO_CACHE_STATE_GET(dmc, index); ++ /* We shouldn't reach here for DIRTY_INPROG blocks. */ ++ EIO_ASSERT(cstate != DIRTY_INPROG); ++ if (unlikely(error)) { ++ dmc->eio_errors.ssd_read_errors++; ++ /* Retry read from HDD for non-DIRTY blocks. */ ++ if (cstate != ALREADY_DIRTY) { ++ spin_lock_irqsave(&dmc->cache_sets[eb_cacheset]. ++ cs_lock, flags); ++ EIO_CACHE_STATE_OFF(dmc, ebio->eb_index, ++ CACHEREADINPROG); ++ EIO_CACHE_STATE_ON(dmc, ebio->eb_index, ++ DISKREADINPROG); ++ spin_unlock_irqrestore(&dmc-> ++ cache_sets[eb_cacheset]. ++ cs_lock, flags); ++ ++ eio_push_ssdread_failures(job); ++ schedule_work(&_kcached_wq); ++ ++ return; ++ } ++ } ++ callendio = 1; ++ break; ++ ++ case READFILL: ++ ++ /*atomic64_inc(&dmc->eio_stats.readfill);*/ ++ /*SECTOR_STATS(dmc->eio_stats.ssd_writes, ebio->eb_size);*/ ++ EIO_ASSERT(EIO_DBN_GET(dmc, index) == ebio->eb_sector); ++ if (unlikely(error)) ++ dmc->eio_errors.ssd_write_errors++; ++ if (!(EIO_CACHE_STATE_GET(dmc, index) & CACHEWRITEINPROG)) { ++ pr_debug("DISKWRITEINPROG absent in READFILL \ ++ sector %llu io size %u\n", ++ (unsigned long long)ebio->eb_sector, ++ ebio->eb_size); ++ } ++ callendio = 1; ++ break; ++ ++ case WRITECACHE: ++ ++ /*SECTOR_STATS(dmc->eio_stats.ssd_writes, ebio->eb_size);*/ ++ /*atomic64_inc(&dmc->eio_stats.writecache);*/ ++ cstate = EIO_CACHE_STATE_GET(dmc, index); ++ EIO_ASSERT(EIO_DBN_GET(dmc, index) == ++ EIO_ROUND_SECTOR(dmc, ebio->eb_sector)); ++ /* CWIP is a must for WRITECACHE, except when it is DIRTY */ ++ EIO_ASSERT(cstate & (CACHEWRITEINPROG | DIRTY)); ++ if (likely(error == 0)) { ++ /* If it is a DIRTY inprog block, proceed for metadata update */ ++ if (cstate == DIRTY_INPROG) { ++ eio_md_write(job); ++ return; ++ } ++ } else { ++ /* TODO: ask if this if condition is required */ ++ if (dmc->mode == CACHE_MODE_WT) ++ dmc->eio_errors.disk_write_errors++; ++ dmc->eio_errors.ssd_write_errors++; ++ } ++ job->ebio = NULL; ++ break; ++ ++ default: ++ pr_err("io_callback: invalid action %d", job->action); ++ return; ++ } ++ ++ spin_lock_irqsave(&dmc->cache_sets[eb_cacheset].cs_lock, flags); ++ ++ cstate = EIO_CACHE_STATE_GET(dmc, index); ++ EIO_ASSERT(!(cstate & INVALID)); ++ ++ if (unlikely ++ ((job->action == WRITECACHE) && !(cstate & DISKWRITEINPROG))) { ++ /* ++ * Can reach here in 2 cases: ++ * 1. Uncached write case, where WRITEDISK has finished first ++ * 2. Cached write case ++ * ++ * For DIRTY or DIRTY inprog cases, use eb holdcount to determine ++ * if end ebio can be called. This is because, we don't set DWIP etc ++ * flags on those and we have to avoid double end ebio call ++ */ ++ EIO_ASSERT((cstate != DIRTY_INPROG) || error); ++ callendio = 1; ++ if ((cstate & DIRTY) ++ && !atomic_dec_and_test(&ebio->eb_holdcount)) ++ callendio = 0; ++ } ++ ++ if (cstate & DISKWRITEINPROG) { ++ /* uncached write and WRITEDISK is not yet finished */ ++ EIO_ASSERT(!(cstate & DIRTY)); /* For dirty blocks, we can't have DWIP flag */ ++ if (error) ++ EIO_CACHE_STATE_ON(dmc, index, QUEUED); ++ EIO_CACHE_STATE_OFF(dmc, index, CACHEWRITEINPROG); ++ } else if (unlikely(error || (cstate & QUEUED))) { ++ /* Error or QUEUED is set: mark block as INVALID for non-DIRTY blocks */ ++ if (cstate != ALREADY_DIRTY) { ++ EIO_CACHE_STATE_SET(dmc, index, INVALID); ++ atomic64_dec_if_positive(&dmc->eio_stats.cached_blocks); ++ } ++ } else if (cstate & VALID) { ++ EIO_CACHE_STATE_OFF(dmc, index, BLOCK_IO_INPROG); ++ /* ++ * If we have NO_SSD_IO_INPROG flag set, then this block needs to be ++ * invalidated. There are three things that can happen -- (i) error, ++ * (ii) IOs are queued on this block, and (iii) success. ++ * ++ * If there was an error or if the QUEUED bit was set, then the logic ++ * in the if part will take care of setting the block to INVALID. ++ * Therefore, this is the success path where we invalidate if need be. ++ */ ++ ++ /* ++ * TBD ++ * NO_SSD_IO_INPROG need to be differently handled, in case block is DIRTY ++ */ ++ if ((cstate & NO_SSD_IO_INPROG) == NO_SSD_IO_INPROG) ++ EIO_CACHE_STATE_OFF(dmc, index, VALID); ++ } ++ ++ spin_unlock_irqrestore(&dmc->cache_sets[eb_cacheset].cs_lock, flags); ++ ++ if (callendio) ++ eb_endio(ebio, error); ++ ++ eio_free_cache_job(job); ++ job = NULL; ++ ++} ++ ++/* ++ * This function processes the kcached_job that ++ * needs to be scheduled on disk after ssd read failures. ++ */ ++void eio_ssderror_diskread(struct kcached_job *job) ++{ ++ struct cache_c *dmc; ++ struct eio_bio *ebio; ++ index_t index; ++ int error; ++ unsigned long flags = 0; ++ ++ dmc = job->dmc; ++ error = 0; ++ ++ /* ++ * 1. Extract the ebio which needs to be scheduled on disk. ++ * 2. Verify cache block state is VALID ++ * 3. Make sure that the cache state in not IOINPROG ++ */ ++ /* Reset the ssd read error in the job. */ ++ job->error = 0; ++ ebio = job->ebio; ++ index = ebio->eb_index; ++ ++ EIO_ASSERT(index != -1); ++ ++ spin_lock_irqsave(&dmc->cache_sets[index / dmc->assoc].cs_lock, flags); ++ EIO_ASSERT(EIO_CACHE_STATE_GET(dmc, index) & DISKREADINPROG); ++ spin_unlock_irqrestore(&dmc->cache_sets[index / dmc->assoc].cs_lock, ++ flags); ++ ++ EIO_ASSERT(ebio->eb_dir == READ); ++ ++ atomic64_inc(&dmc->eio_stats.readdisk); ++ SECTOR_STATS(dmc->eio_stats.disk_reads, ebio->eb_size); ++ job->action = READDISK; ++ ++ error = eio_io_async_bvec(dmc, &job->job_io_regions.disk, ebio->eb_dir, ++ ebio->eb_bv, ebio->eb_nbvec, ++ eio_disk_io_callback, job, 1); ++ ++ /* ++ * In case of disk i/o submission error clear ebio and kcached_job. ++ * This would return the actual read that was issued on ssd. ++ */ ++ if (error) ++ goto out; ++ ++ return; ++ ++out: ++ /* We failed to submit the I/O to dm layer. The corresponding ++ * block should be marked as INVALID by turning off already set ++ * flags. ++ */ ++ spin_lock_irqsave(&dmc->cache_sets[index / dmc->assoc].cs_lock, flags); ++ EIO_CACHE_STATE_SET(dmc, ebio->eb_index, INVALID); ++ spin_unlock_irqrestore(&dmc->cache_sets[index / dmc->assoc].cs_lock, ++ flags); ++ ++ atomic64_dec_if_positive(&dmc->eio_stats.cached_blocks); ++ ++ eb_endio(ebio, error); ++ ebio = NULL; ++ job->ebio = NULL; ++ eio_free_cache_job(job); ++} ++ ++/* Adds clean set request to clean queue. */ ++static void eio_addto_cleanq(struct cache_c *dmc, index_t set, int whole) ++{ ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&dmc->cache_sets[set].cs_lock, flags); ++ ++ if (dmc->cache_sets[set].flags & SETFLAG_CLEAN_INPROG) { ++ /* Clean already in progress, just add to clean pendings */ ++ spin_unlock_irqrestore(&dmc->cache_sets[set].cs_lock, flags); ++ return; ++ } ++ ++ dmc->cache_sets[set].flags |= SETFLAG_CLEAN_INPROG; ++ if (whole) ++ dmc->cache_sets[set].flags |= SETFLAG_CLEAN_WHOLE; ++ ++ spin_unlock_irqrestore(&dmc->cache_sets[set].cs_lock, flags); ++ ++ spin_lock_irqsave(&dmc->clean_sl, flags); ++ list_add_tail(&dmc->cache_sets[set].list, &dmc->cleanq); ++ atomic64_inc(&dmc->clean_pendings); ++ EIO_SET_EVENT_AND_UNLOCK(&dmc->clean_event, &dmc->clean_sl, flags); ++ return; ++} ++ ++/* ++ * Clean thread loops forever in this, waiting for ++ * new clean set requests in the clean queue. ++ */ ++int eio_clean_thread_proc(void *context) ++{ ++ struct cache_c *dmc = (struct cache_c *)context; ++ unsigned long flags = 0; ++ u_int64_t systime; ++ index_t index; ++ ++ /* Sync makes sense only for writeback cache */ ++ EIO_ASSERT(dmc->mode == CACHE_MODE_WB); ++ ++ dmc->clean_thread_running = 1; ++ ++ /* ++ * Using sysctl_fast_remove to stop the clean thread ++ * works for now. Should have another flag specifically ++ * for such notification. ++ */ ++ for (; !dmc->sysctl_active.fast_remove; ) { ++ LIST_HEAD(setlist); ++ struct cache_set *set; ++ ++ eio_comply_dirty_thresholds(dmc, -1); ++ ++ if (dmc->sysctl_active.do_clean) { ++ /* pause the periodic clean */ ++ cancel_delayed_work_sync(&dmc->clean_aged_sets_work); ++ ++ /* clean all the sets */ ++ eio_clean_all(dmc); ++ ++ /* resume the periodic clean */ ++ spin_lock_irqsave(&dmc->dirty_set_lru_lock, flags); ++ dmc->is_clean_aged_sets_sched = 0; ++ if (dmc->sysctl_active.time_based_clean_interval ++ && atomic64_read(&dmc->nr_dirty)) { ++ /* there is a potential race here, If a sysctl changes ++ the time_based_clean_interval to 0. However a strong ++ synchronisation is not necessary here ++ */ ++ schedule_delayed_work(&dmc-> ++ clean_aged_sets_work, ++ dmc->sysctl_active. ++ time_based_clean_interval ++ * 60 * HZ); ++ dmc->is_clean_aged_sets_sched = 1; ++ } ++ spin_unlock_irqrestore(&dmc->dirty_set_lru_lock, flags); ++ } ++ ++ if (dmc->sysctl_active.fast_remove) ++ break; ++ ++ spin_lock_irqsave(&dmc->clean_sl, flags); ++ ++ while (! ++ ((!list_empty(&dmc->cleanq)) ++ || dmc->sysctl_active.fast_remove ++ || dmc->sysctl_active.do_clean)) ++ EIO_WAIT_EVENT(&dmc->clean_event, &dmc->clean_sl, ++ flags); ++ ++ /* ++ * Move cleanq elements to a private list for processing. ++ */ ++ ++ list_add(&setlist, &dmc->cleanq); ++ list_del(&dmc->cleanq); ++ INIT_LIST_HEAD(&dmc->cleanq); ++ ++ spin_unlock_irqrestore(&dmc->clean_sl, flags); ++ ++ systime = jiffies; ++ while (!list_empty(&setlist)) { ++ set = ++ list_entry((&setlist)->next, struct cache_set, ++ list); ++ list_del(&set->list); ++ index = set - dmc->cache_sets; ++ if (!(dmc->sysctl_active.fast_remove)) { ++ eio_clean_set(dmc, index, ++ set->flags & SETFLAG_CLEAN_WHOLE, ++ 0); ++ } else { ++ ++ /* ++ * Since we are not cleaning the set, we should ++ * put the set back in the lru list so that ++ * it is picked up at a later point. ++ * We also need to clear the clean inprog flag ++ * otherwise this set would never be cleaned. ++ */ ++ ++ spin_lock_irqsave(&dmc->cache_sets[index]. ++ cs_lock, flags); ++ dmc->cache_sets[index].flags &= ++ ~(SETFLAG_CLEAN_INPROG | ++ SETFLAG_CLEAN_WHOLE); ++ spin_unlock_irqrestore(&dmc->cache_sets[index]. ++ cs_lock, flags); ++ spin_lock_irqsave(&dmc->dirty_set_lru_lock, ++ flags); ++ lru_touch(dmc->dirty_set_lru, index, systime); ++ spin_unlock_irqrestore(&dmc->dirty_set_lru_lock, ++ flags); ++ } ++ atomic64_dec(&dmc->clean_pendings); ++ } ++ } ++ ++ /* notifier for cache delete that the clean thread has stopped running */ ++ dmc->clean_thread_running = 0; ++ ++ eio_thread_exit(0); ++ ++ /*Should never reach here*/ ++ return 0; ++} ++ ++/* ++ * Cache miss support. We read the data from disk, write it to the ssd. ++ * To avoid doing 1 IO at a time to the ssd, when the IO is kicked off, ++ * we enqueue it to a "readfill" queue in the cache in cache sector order. ++ * The worker thread can then issue all of these IOs and do 1 unplug to ++ * start them all. ++ * ++ */ ++static void eio_enqueue_readfill(struct cache_c *dmc, struct kcached_job *job) ++{ ++ unsigned long flags = 0; ++ struct kcached_job **j1, *next; ++ int do_schedule = 0; ++ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ /* Insert job in sorted order of cache sector */ ++ j1 = &dmc->readfill_queue; ++ while (*j1 != NULL && (*j1)->job_io_regions.cache.sector < ++ job->job_io_regions.cache.sector) ++ j1 = &(*j1)->next; ++ next = *j1; ++ *j1 = job; ++ job->next = next; ++ do_schedule = (dmc->readfill_in_prog == 0); ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ if (do_schedule) ++ schedule_work(&dmc->readfill_wq); ++} ++ ++void eio_do_readfill(struct work_struct *work) ++{ ++ struct kcached_job *job, *joblist; ++ struct eio_bio *ebio; ++ unsigned long flags = 0; ++ struct kcached_job *nextjob = NULL; ++ struct cache_c *dmc = container_of(work, struct cache_c, readfill_wq); ++ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ if (dmc->readfill_in_prog) ++ goto out; ++ dmc->readfill_in_prog = 1; ++ while (dmc->readfill_queue != NULL) { ++ joblist = dmc->readfill_queue; ++ dmc->readfill_queue = NULL; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ for (job = joblist; job != NULL; job = nextjob) { ++ struct eio_bio *iebio; ++ struct eio_bio *next; ++ ++ nextjob = job->next; /* save for later because 'job' will be freed */ ++ EIO_ASSERT(job->action == READFILL); ++ /* Write to cache device */ ++ ebio = job->ebio; ++ iebio = ebio->eb_next; ++ EIO_ASSERT(iebio); ++ /* other iebios are anchored on this bio. Create ++ * jobs for them and then issue ios ++ */ ++ do { ++ struct kcached_job *job; ++ int err; ++ unsigned long flags; ++ index_t index; ++ next = iebio->eb_next; ++ index = iebio->eb_index; ++ if (index == -1) { ++ CTRACE("eio_do_readfill:1\n"); ++ /* Any INPROG(including DIRTY_INPROG) case would fall here */ ++ eb_endio(iebio, 0); ++ iebio = NULL; ++ } else { ++ spin_lock_irqsave(&dmc-> ++ cache_sets[iebio-> ++ eb_cacheset]. ++ cs_lock, flags); ++ /* If this block was already valid, we don't need to write it */ ++ if (unlikely ++ (EIO_CACHE_STATE_GET(dmc, index) & ++ QUEUED)) { ++ /*An invalidation request is queued. Can't do anything*/ ++ CTRACE("eio_do_readfill:2\n"); ++ EIO_CACHE_STATE_SET(dmc, index, ++ INVALID); ++ spin_unlock_irqrestore(&dmc-> ++ cache_sets ++ [iebio-> ++ eb_cacheset]. ++ cs_lock, ++ flags); ++ atomic64_dec_if_positive(&dmc-> ++ eio_stats. ++ cached_blocks); ++ eb_endio(iebio, 0); ++ iebio = NULL; ++ } else ++ if ((EIO_CACHE_STATE_GET(dmc, index) ++ & (VALID | DISKREADINPROG)) ++ == (VALID | DISKREADINPROG)) { ++ /* Do readfill. */ ++ EIO_CACHE_STATE_SET(dmc, index, ++ VALID | ++ CACHEWRITEINPROG); ++ EIO_ASSERT(EIO_DBN_GET(dmc, index) ++ == iebio->eb_sector); ++ spin_unlock_irqrestore(&dmc-> ++ cache_sets ++ [iebio-> ++ eb_cacheset]. ++ cs_lock, ++ flags); ++ job = ++ eio_new_job(dmc, iebio, ++ iebio-> ++ eb_index); ++ if (unlikely(job == NULL)) ++ err = -ENOMEM; ++ else { ++ err = 0; ++ job->action = READFILL; ++ atomic_inc(&dmc-> ++ nr_jobs); ++ SECTOR_STATS(dmc-> ++ eio_stats. ++ ssd_readfills, ++ iebio-> ++ eb_size); ++ SECTOR_STATS(dmc-> ++ eio_stats. ++ ssd_writes, ++ iebio-> ++ eb_size); ++ atomic64_inc(&dmc-> ++ eio_stats. ++ readfill); ++ atomic64_inc(&dmc-> ++ eio_stats. ++ writecache); ++ err = ++ eio_io_async_bvec ++ (dmc, ++ &job-> ++ job_io_regions. ++ cache, WRITE, ++ iebio->eb_bv, ++ iebio->eb_nbvec, ++ eio_io_callback, ++ job, 0); ++ } ++ if (err) { ++ pr_err ++ ("eio_do_readfill: IO submission failed, block %llu", ++ EIO_DBN_GET(dmc, ++ index)); ++ spin_lock_irqsave(&dmc-> ++ cache_sets ++ [iebio-> ++ eb_cacheset]. ++ cs_lock, ++ flags); ++ EIO_CACHE_STATE_SET(dmc, ++ iebio-> ++ eb_index, ++ INVALID); ++ spin_unlock_irqrestore ++ (&dmc-> ++ cache_sets[iebio-> ++ eb_cacheset]. ++ cs_lock, flags); ++ atomic64_dec_if_positive ++ (&dmc->eio_stats. ++ cached_blocks); ++ eb_endio(iebio, err); ++ ++ if (job) { ++ eio_free_cache_job ++ (job); ++ job = NULL; ++ } ++ } ++ } else ++ if (EIO_CACHE_STATE_GET(dmc, index) ++ == ALREADY_DIRTY) { ++ ++ spin_unlock_irqrestore(&dmc-> ++ cache_sets ++ [iebio-> ++ eb_cacheset]. ++ cs_lock, ++ flags); ++ ++ /* ++ * DIRTY block handling: ++ * Read the dirty data from the cache block to update ++ * the data buffer already read from the disk ++ */ ++ job = ++ eio_new_job(dmc, iebio, ++ iebio-> ++ eb_index); ++ if (unlikely(job == NULL)) ++ err = -ENOMEM; ++ else { ++ job->action = READCACHE; ++ SECTOR_STATS(dmc-> ++ eio_stats. ++ ssd_reads, ++ iebio-> ++ eb_size); ++ atomic64_inc(&dmc-> ++ eio_stats. ++ readcache); ++ err = ++ eio_io_async_bvec ++ (dmc, ++ &job-> ++ job_io_regions. ++ cache, READ, ++ iebio->eb_bv, ++ iebio->eb_nbvec, ++ eio_io_callback, ++ job, 0); ++ } ++ ++ if (err) { ++ pr_err ++ ("eio_do_readfill: dirty block read IO submission failed, block %llu", ++ EIO_DBN_GET(dmc, ++ index)); ++ /* can't invalidate the DIRTY block, just return error */ ++ eb_endio(iebio, err); ++ if (job) { ++ eio_free_cache_job ++ (job); ++ job = NULL; ++ } ++ } ++ } else ++ if ((EIO_CACHE_STATE_GET(dmc, index) ++ & (VALID | CACHEREADINPROG)) ++ == (VALID | CACHEREADINPROG)) { ++ /*turn off the cache read in prog flag ++ don't need to write the cache block*/ ++ CTRACE("eio_do_readfill:3\n"); ++ EIO_CACHE_STATE_OFF(dmc, index, ++ BLOCK_IO_INPROG); ++ spin_unlock_irqrestore(&dmc-> ++ cache_sets ++ [iebio-> ++ eb_cacheset]. ++ cs_lock, ++ flags); ++ eb_endio(iebio, 0); ++ iebio = NULL; ++ } else { ++ panic("Unknown condition"); ++ spin_unlock_irqrestore(&dmc-> ++ cache_sets ++ [iebio-> ++ eb_cacheset]. ++ cs_lock, ++ flags); ++ } ++ } ++ iebio = next; ++ } while (iebio); ++ eb_endio(ebio, 0); ++ ebio = NULL; ++ eio_free_cache_job(job); ++ } ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ } ++ dmc->readfill_in_prog = 0; ++out: ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ atomic64_inc(&dmc->eio_stats.ssd_readfill_unplugs); ++ eio_unplug_cache_device(dmc); ++} ++ ++/* ++ * Map a block from the source device to a block in the cache device. ++ */ ++static u_int32_t hash_block(struct cache_c *dmc, sector_t dbn) ++{ ++ u_int32_t set_number; ++ ++ set_number = eio_hash_block(dmc, dbn); ++ return set_number; ++} ++ ++static void ++find_valid_dbn(struct cache_c *dmc, sector_t dbn, ++ index_t start_index, index_t *index) ++{ ++ index_t i; ++ index_t end_index = start_index + dmc->assoc; ++ ++ for (i = start_index; i < end_index; i++) { ++ if ((EIO_CACHE_STATE_GET(dmc, i) & VALID) ++ && EIO_DBN_GET(dmc, i) == dbn) { ++ *index = i; ++ if ((EIO_CACHE_STATE_GET(dmc, i) & BLOCK_IO_INPROG) == ++ 0) ++ eio_policy_reclaim_lru_movetail(dmc, i, ++ dmc-> ++ policy_ops); ++ return; ++ } ++ } ++ *index = -1; ++} ++ ++static index_t find_invalid_dbn(struct cache_c *dmc, index_t start_index) ++{ ++ index_t i; ++ index_t end_index = start_index + dmc->assoc; ++ ++ /* Find INVALID slot that we can reuse */ ++ for (i = start_index; i < end_index; i++) { ++ if (EIO_CACHE_STATE_GET(dmc, i) == INVALID) { ++ eio_policy_reclaim_lru_movetail(dmc, i, ++ dmc->policy_ops); ++ return i; ++ } ++ } ++ return -1; ++} ++ ++/* Search for a slot that we can reclaim */ ++static void ++find_reclaim_dbn(struct cache_c *dmc, index_t start_index, index_t *index) ++{ ++ eio_find_reclaim_dbn(dmc->policy_ops, start_index, index); ++} ++ ++void eio_set_warm_boot(void) ++{ ++ eio_force_warm_boot = 1; ++ return; ++} ++ ++/* ++ * dbn is the starting sector. ++ */ ++static int ++eio_lookup(struct cache_c *dmc, struct eio_bio *ebio, index_t *index) ++{ ++ sector_t dbn = EIO_ROUND_SECTOR(dmc, ebio->eb_sector); ++ u_int32_t set_number; ++ index_t invalid, oldest_clean = -1; ++ index_t start_index; ++ ++ /*ASK it is assumed that the lookup is being done for a single block*/ ++ set_number = hash_block(dmc, dbn); ++ start_index = dmc->assoc * set_number; ++ find_valid_dbn(dmc, dbn, start_index, index); ++ if (*index >= 0) ++ /* We found the exact range of blocks we are looking for */ ++ return VALID; ++ ++ invalid = find_invalid_dbn(dmc, start_index); ++ if (invalid == -1) ++ /* We didn't find an invalid entry, search for oldest valid entry */ ++ find_reclaim_dbn(dmc, start_index, &oldest_clean); ++ /* ++ * Cache miss : ++ * We can't choose an entry marked INPROG, but choose the oldest ++ * INVALID or the oldest VALID entry. ++ */ ++ *index = start_index + dmc->assoc; ++ if (invalid != -1) { ++ *index = invalid; ++ return INVALID; ++ } else if (oldest_clean != -1) { ++ *index = oldest_clean; ++ return VALID; ++ } ++ return -1; ++} ++ ++/* Do metadata update for a set */ ++static void eio_do_mdupdate(struct work_struct *work) ++{ ++ struct mdupdate_request *mdreq; ++ struct cache_set *set; ++ struct cache_c *dmc; ++ unsigned long flags; ++ index_t i; ++ index_t start_index; ++ index_t end_index; ++ index_t min_index; ++ index_t max_index; ++ struct flash_cacheblock *md_blocks; ++ struct eio_bio *ebio; ++ u_int8_t cstate; ++ struct eio_io_region region; ++ unsigned pindex; ++ int error, j; ++ index_t blk_index; ++ int k; ++ void *pg_virt_addr[2] = { NULL }; ++ u_int8_t sector_bits[2] = { 0 }; ++ int startbit, endbit; ++ int rw_flags = 0; ++ ++ mdreq = container_of(work, struct mdupdate_request, work); ++ dmc = mdreq->dmc; ++ set = &dmc->cache_sets[mdreq->set]; ++ ++ mdreq->error = 0; ++ EIO_ASSERT(mdreq->mdblk_bvecs); ++ ++ /* ++ * md_size = dmc->assoc * sizeof(struct flash_cacheblock); ++ * Currently, md_size is 8192 bytes, mdpage_count is 2 pages maximum. ++ */ ++ ++ EIO_ASSERT(mdreq->mdbvec_count && mdreq->mdbvec_count <= 2); ++ EIO_ASSERT((dmc->assoc == 512) || mdreq->mdbvec_count == 1); ++ for (k = 0; k < (int)mdreq->mdbvec_count; k++) ++ pg_virt_addr[k] = kmap(mdreq->mdblk_bvecs[k].bv_page); ++ ++ spin_lock_irqsave(&set->cs_lock, flags); ++ ++ start_index = mdreq->set * dmc->assoc; ++ end_index = start_index + dmc->assoc; ++ ++ pindex = 0; ++ md_blocks = (struct flash_cacheblock *)pg_virt_addr[pindex]; ++ j = MD_BLOCKS_PER_PAGE; ++ ++ /* initialize the md blocks to write */ ++ for (i = start_index; i < end_index; i++) { ++ cstate = EIO_CACHE_STATE_GET(dmc, i); ++ md_blocks->dbn = cpu_to_le64(EIO_DBN_GET(dmc, i)); ++ if (cstate == ALREADY_DIRTY) ++ md_blocks->cache_state = cpu_to_le64((VALID | DIRTY)); ++ else ++ md_blocks->cache_state = cpu_to_le64(INVALID); ++ md_blocks++; ++ j--; ++ ++ if ((j == 0) && (++pindex < mdreq->mdbvec_count)) { ++ md_blocks = ++ (struct flash_cacheblock *)pg_virt_addr[pindex]; ++ j = MD_BLOCKS_PER_PAGE; ++ } ++ ++ } ++ ++ /* Update the md blocks with the pending mdlist */ ++ min_index = start_index; ++ max_index = start_index; ++ ++ pindex = 0; ++ md_blocks = (struct flash_cacheblock *)pg_virt_addr[pindex]; ++ ++ ebio = mdreq->pending_mdlist; ++ while (ebio) { ++ EIO_ASSERT(EIO_CACHE_STATE_GET(dmc, ebio->eb_index) == ++ DIRTY_INPROG); ++ ++ blk_index = ebio->eb_index - start_index; ++ pindex = INDEX_TO_MD_PAGE(blk_index); ++ blk_index = INDEX_TO_MD_PAGE_OFFSET(blk_index); ++ sector_bits[pindex] |= (1 << INDEX_TO_MD_SECTOR(blk_index)); ++ ++ md_blocks = (struct flash_cacheblock *)pg_virt_addr[pindex]; ++ md_blocks[blk_index].cache_state = (VALID | DIRTY); ++ ++ if (min_index > ebio->eb_index) ++ min_index = ebio->eb_index; ++ ++ if (max_index < ebio->eb_index) ++ max_index = ebio->eb_index; ++ ++ ebio = ebio->eb_next; ++ } ++ ++ /* ++ * Below code may be required when selective pages need to be ++ * submitted for metadata update. Currently avoiding the optimization ++ * for correctness validation. ++ */ ++ ++ /* ++ min_cboff = (min_index - start_index) / MD_BLOCKS_PER_CBLOCK(dmc); ++ max_cboff = (max_index - start_index) / MD_BLOCKS_PER_CBLOCK(dmc); ++ write_size = ((uint32_t)(max_cboff - min_cboff + 1)) << dmc->block_shift; ++ EIO_ASSERT(write_size && (write_size <= eio_to_sector(mdreq->md_size))); ++ */ ++ ++ /* Move the pending mdlist to inprog list */ ++ mdreq->inprog_mdlist = mdreq->pending_mdlist; ++ mdreq->pending_mdlist = NULL; ++ ++ spin_unlock_irqrestore(&set->cs_lock, flags); ++ ++ for (k = 0; k < (int)mdreq->mdbvec_count; k++) ++ kunmap(mdreq->mdblk_bvecs[k].bv_page); ++ ++ /* ++ * Initiate the I/O to SSD for on-disk md update. ++ * TBD. Optimize to write only the affected blocks ++ */ ++ ++ region.bdev = dmc->cache_dev->bdev; ++ /*region.sector = dmc->md_start_sect + INDEX_TO_MD_SECTOR(start_index) + ++ (min_cboff << dmc->block_shift); */ ++ ++ atomic_set(&mdreq->holdcount, 1); ++ for (i = 0; i < mdreq->mdbvec_count; i++) { ++ if (!sector_bits[i]) ++ continue; ++ startbit = -1; ++ j = 0; ++ while (startbit == -1) { ++ if (sector_bits[i] & (1 << j)) ++ startbit = j; ++ j++; ++ } ++ endbit = -1; ++ j = 7; ++ while (endbit == -1) { ++ if (sector_bits[i] & (1 << j)) ++ endbit = j; ++ j--; ++ } ++ EIO_ASSERT(startbit <= endbit && startbit >= 0 && startbit <= 7 && ++ endbit >= 0 && endbit <= 7); ++ EIO_ASSERT(dmc->assoc != 128 || endbit <= 3); ++ region.sector = ++ dmc->md_start_sect + INDEX_TO_MD_SECTOR(start_index) + ++ i * SECTORS_PER_PAGE + startbit; ++ region.count = endbit - startbit + 1; ++ mdreq->mdblk_bvecs[i].bv_offset = to_bytes(startbit); ++ mdreq->mdblk_bvecs[i].bv_len = to_bytes(region.count); ++ ++ EIO_ASSERT(region.sector <= ++ (dmc->md_start_sect + INDEX_TO_MD_SECTOR(end_index))); ++ atomic64_inc(&dmc->eio_stats.md_ssd_writes); ++ SECTOR_STATS(dmc->eio_stats.ssd_writes, to_bytes(region.count)); ++ atomic_inc(&mdreq->holdcount); ++ ++ /* ++ * Set SYNC for making metadata ++ * writes as high priority. ++ */ ++ rw_flags = WRITE | REQ_SYNC; ++ error = eio_io_async_bvec(dmc, ®ion, rw_flags, ++ &mdreq->mdblk_bvecs[i], 1, ++ eio_mdupdate_callback, work, 0); ++ if (error && !(mdreq->error)) ++ mdreq->error = error; ++ } ++ if (atomic_dec_and_test(&mdreq->holdcount)) { ++ INIT_WORK(&mdreq->work, eio_post_mdupdate); ++ queue_work(dmc->mdupdate_q, &mdreq->work); ++ } ++} ++ ++/* Callback function for ondisk metadata update */ ++static void eio_mdupdate_callback(int error, void *context) ++{ ++ struct work_struct *work = (struct work_struct *)context; ++ struct mdupdate_request *mdreq; ++ ++ mdreq = container_of(work, struct mdupdate_request, work); ++ if (error && !(mdreq->error)) ++ mdreq->error = error; ++ if (!atomic_dec_and_test(&mdreq->holdcount)) ++ return; ++ INIT_WORK(&mdreq->work, eio_post_mdupdate); ++ queue_work(mdreq->dmc->mdupdate_q, &mdreq->work); ++} ++ ++static void eio_post_mdupdate(struct work_struct *work) ++{ ++ struct mdupdate_request *mdreq; ++ struct cache_set *set; ++ struct cache_c *dmc; ++ unsigned long flags; ++ struct eio_bio *ebio; ++ struct eio_bio *nebio; ++ int more_pending_mdupdates = 0; ++ int error; ++ index_t set_index; ++ ++ mdreq = container_of(work, struct mdupdate_request, work); ++ ++ dmc = mdreq->dmc; ++ EIO_ASSERT(dmc); ++ set_index = mdreq->set; ++ set = &dmc->cache_sets[set_index]; ++ error = mdreq->error; ++ ++ /* Update in-core cache metadata */ ++ ++ spin_lock_irqsave(&set->cs_lock, flags); ++ ++ /* ++ * Update dirty inprog blocks. ++ * On error, convert them to INVALID ++ * On success, convert them to ALREADY_DIRTY ++ */ ++ ebio = mdreq->inprog_mdlist; ++ while (ebio) { ++ EIO_ASSERT(EIO_CACHE_STATE_GET(dmc, ebio->eb_index) == ++ DIRTY_INPROG); ++ if (unlikely(error)) { ++ EIO_CACHE_STATE_SET(dmc, ebio->eb_index, INVALID); ++ atomic64_dec_if_positive(&dmc->eio_stats.cached_blocks); ++ } else { ++ EIO_CACHE_STATE_SET(dmc, ebio->eb_index, ALREADY_DIRTY); ++ set->nr_dirty++; ++ atomic64_inc(&dmc->nr_dirty); ++ atomic64_inc(&dmc->eio_stats.md_write_dirty); ++ } ++ ebio = ebio->eb_next; ++ } ++ ++ /* ++ * If there are more pending requests for md update, ++ * need to pick up those using the current mdreq. ++ */ ++ if (mdreq->pending_mdlist) ++ more_pending_mdupdates = 1; ++ else ++ /* No request pending, we can free the mdreq */ ++ set->mdreq = NULL; ++ ++ /* ++ * After we unlock the set, we need to end the I/Os, ++ * which were processed as part of this md update ++ */ ++ ++ ebio = mdreq->inprog_mdlist; ++ mdreq->inprog_mdlist = NULL; ++ ++ spin_unlock_irqrestore(&set->cs_lock, flags); ++ ++ /* End the processed I/Os */ ++ while (ebio) { ++ nebio = ebio->eb_next; ++ eb_endio(ebio, error); ++ ebio = nebio; ++ } ++ ++ /* ++ * if dirty block was added ++ * 1. update the cache set lru list ++ * 2. check and initiate cleaning if thresholds are crossed ++ */ ++ if (!error) { ++ eio_touch_set_lru(dmc, set_index); ++ eio_comply_dirty_thresholds(dmc, set_index); ++ } ++ ++ if (more_pending_mdupdates) { ++ /* ++ * Schedule work to process the new ++ * pending mdupdate requests ++ */ ++ INIT_WORK(&mdreq->work, eio_do_mdupdate); ++ queue_work(dmc->mdupdate_q, &mdreq->work); ++ } else { ++ /* ++ * No more pending mdupdates. ++ * Free the mdreq. ++ */ ++ if (mdreq->mdblk_bvecs) { ++ eio_free_wb_bvecs(mdreq->mdblk_bvecs, ++ mdreq->mdbvec_count, ++ SECTORS_PER_PAGE); ++ kfree(mdreq->mdblk_bvecs); ++ } ++ ++ kfree(mdreq); ++ } ++} ++ ++/* Enqueue metadata update for marking dirty blocks on-disk/in-core */ ++static void eio_enq_mdupdate(struct bio_container *bc) ++{ ++ unsigned long flags = 0; ++ index_t set_index; ++ struct eio_bio *ebio; ++ struct cache_c *dmc = bc->bc_dmc; ++ struct cache_set *set = NULL; ++ struct mdupdate_request *mdreq; ++ int do_schedule; ++ ++ ebio = bc->bc_mdlist; ++ set_index = -1; ++ do_schedule = 0; ++ while (ebio) { ++ if (ebio->eb_cacheset != set_index) { ++ set_index = ebio->eb_cacheset; ++ set = &dmc->cache_sets[set_index]; ++ spin_lock_irqsave(&set->cs_lock, flags); ++ } ++ EIO_ASSERT(ebio->eb_cacheset == set_index); ++ ++ bc->bc_mdlist = ebio->eb_next; ++ ++ if (!set->mdreq) { ++ /* Pick up one mdreq from bc */ ++ mdreq = bc->mdreqs; ++ EIO_ASSERT(mdreq != NULL); ++ bc->mdreqs = bc->mdreqs->next; ++ mdreq->next = NULL; ++ mdreq->pending_mdlist = ebio; ++ mdreq->dmc = dmc; ++ mdreq->set = set_index; ++ set->mdreq = mdreq; ++ ebio->eb_next = NULL; ++ do_schedule = 1; ++ } else { ++ mdreq = set->mdreq; ++ EIO_ASSERT(mdreq != NULL); ++ ebio->eb_next = mdreq->pending_mdlist; ++ mdreq->pending_mdlist = ebio; ++ } ++ ++ ebio = bc->bc_mdlist; ++ if (!ebio || ebio->eb_cacheset != set_index) { ++ spin_unlock_irqrestore(&set->cs_lock, flags); ++ if (do_schedule) { ++ INIT_WORK(&mdreq->work, eio_do_mdupdate); ++ queue_work(dmc->mdupdate_q, &mdreq->work); ++ do_schedule = 0; ++ } ++ } ++ } ++ ++ EIO_ASSERT(bc->bc_mdlist == NULL); ++} ++ ++/* Kick-off a cache metadata update for marking the blocks dirty */ ++void eio_md_write(struct kcached_job *job) ++{ ++ struct eio_bio *ebio = job->ebio; ++ struct eio_bio *nebio; ++ struct eio_bio *pebio; ++ struct bio_container *bc = ebio->eb_bc; ++ unsigned long flags; ++ int enqueue = 0; ++ ++ /* ++ * ebios are stored in ascending order of cache sets. ++ */ ++ ++ spin_lock_irqsave(&bc->bc_lock, flags); ++ EIO_ASSERT(bc->bc_mdwait > 0); ++ nebio = bc->bc_mdlist; ++ pebio = NULL; ++ while (nebio) { ++ if (nebio->eb_cacheset > ebio->eb_cacheset) ++ break; ++ pebio = nebio; ++ nebio = nebio->eb_next; ++ } ++ ebio->eb_next = nebio; ++ if (!pebio) ++ bc->bc_mdlist = ebio; ++ else ++ pebio->eb_next = ebio; ++ bc->bc_mdwait--; ++ if (bc->bc_mdwait == 0) ++ enqueue = 1; ++ spin_unlock_irqrestore(&bc->bc_lock, flags); ++ ++ eio_free_cache_job(job); ++ ++ if (enqueue) ++ eio_enq_mdupdate(bc); ++} ++ ++/* Ensure cache level dirty thresholds compliance. If required, trigger cache-wide clean */ ++static void eio_check_dirty_cache_thresholds(struct cache_c *dmc) ++{ ++ if (DIRTY_CACHE_THRESHOLD_CROSSED(dmc)) { ++ int64_t required_cleans; ++ int64_t enqueued_cleans; ++ u_int64_t set_time; ++ index_t set_index; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dmc->clean_sl, flags); ++ if (atomic64_read(&dmc->clean_pendings) ++ || dmc->clean_excess_dirty) { ++ /* Already excess dirty block cleaning is in progress */ ++ spin_unlock_irqrestore(&dmc->clean_sl, flags); ++ return; ++ } ++ dmc->clean_excess_dirty = 1; ++ spin_unlock_irqrestore(&dmc->clean_sl, flags); ++ ++ /* Clean needs to be triggered on the cache */ ++ required_cleans = atomic64_read(&dmc->nr_dirty) - ++ (EIO_DIV((dmc->sysctl_active.dirty_low_threshold * dmc->size), ++ 100)); ++ enqueued_cleans = 0; ++ ++ spin_lock_irqsave(&dmc->dirty_set_lru_lock, flags); ++ do { ++ lru_rem_head(dmc->dirty_set_lru, &set_index, &set_time); ++ if (set_index == LRU_NULL) ++ break; ++ ++ enqueued_cleans += dmc->cache_sets[set_index].nr_dirty; ++ spin_unlock_irqrestore(&dmc->dirty_set_lru_lock, flags); ++ eio_addto_cleanq(dmc, set_index, 1); ++ spin_lock_irqsave(&dmc->dirty_set_lru_lock, flags); ++ } while (enqueued_cleans <= required_cleans); ++ spin_unlock_irqrestore(&dmc->dirty_set_lru_lock, flags); ++ spin_lock_irqsave(&dmc->clean_sl, flags); ++ dmc->clean_excess_dirty = 0; ++ spin_unlock_irqrestore(&dmc->clean_sl, flags); ++ } ++} ++ ++/* Ensure set level dirty thresholds compliance. If required, trigger set clean */ ++static void eio_check_dirty_set_thresholds(struct cache_c *dmc, index_t set) ++{ ++ if (DIRTY_SET_THRESHOLD_CROSSED(dmc, set)) { ++ eio_addto_cleanq(dmc, set, 0); ++ return; ++ } ++} ++ ++/* Ensure various cache thresholds compliance. If required trigger clean */ ++void eio_comply_dirty_thresholds(struct cache_c *dmc, index_t set) ++{ ++ /* ++ * 1. Don't trigger new cleanings if ++ * - cache is not wb ++ * - autoclean threshold is crossed ++ * - fast remove in progress is set ++ * - cache is in failed mode. ++ * 2. Initiate set-wide clean, if set level dirty threshold is crossed ++ * 3. Initiate cache-wide clean, if cache level dirty threshold is crossed ++ */ ++ ++ if (unlikely(CACHE_FAILED_IS_SET(dmc))) { ++ pr_debug ++ ("eio_comply_dirty_thresholds: Cache %s is in failed mode.\n", ++ dmc->cache_name); ++ return; ++ } ++ ++ if (AUTOCLEAN_THRESHOLD_CROSSED(dmc) || (dmc->mode != CACHE_MODE_WB)) ++ return; ++ ++ if (set != -1) ++ eio_check_dirty_set_thresholds(dmc, set); ++ eio_check_dirty_cache_thresholds(dmc); ++} ++ ++/* Do read from cache */ ++static void ++eio_cached_read(struct cache_c *dmc, struct eio_bio *ebio, int rw_flags) ++{ ++ struct kcached_job *job; ++ index_t index = ebio->eb_index; ++ int err = 0; ++ ++ job = eio_new_job(dmc, ebio, index); ++ ++ if (unlikely(job == NULL)) ++ err = -ENOMEM; ++ else { ++ job->action = READCACHE; /* Fetch data from cache */ ++ atomic_inc(&dmc->nr_jobs); ++ ++ SECTOR_STATS(dmc->eio_stats.read_hits, ebio->eb_size); ++ SECTOR_STATS(dmc->eio_stats.ssd_reads, ebio->eb_size); ++ atomic64_inc(&dmc->eio_stats.readcache); ++ err = ++ eio_io_async_bvec(dmc, &job->job_io_regions.cache, rw_flags, ++ ebio->eb_bv, ebio->eb_nbvec, ++ eio_io_callback, job, 0); ++ ++ } ++ if (err) { ++ unsigned long flags; ++ pr_err("eio_cached_read: IO submission failed, block %llu", ++ EIO_DBN_GET(dmc, index)); ++ spin_lock_irqsave(&dmc->cache_sets[ebio->eb_cacheset].cs_lock, ++ flags); ++ /* ++ * For already DIRTY block, invalidation is too costly, skip it. ++ * For others, mark the block as INVALID and return error. ++ */ ++ if (EIO_CACHE_STATE_GET(dmc, ebio->eb_index) != ALREADY_DIRTY) { ++ EIO_CACHE_STATE_SET(dmc, ebio->eb_index, INVALID); ++ atomic64_dec_if_positive(&dmc->eio_stats.cached_blocks); ++ } ++ spin_unlock_irqrestore(&dmc->cache_sets[ebio->eb_cacheset]. ++ cs_lock, flags); ++ eb_endio(ebio, err); ++ ebio = NULL; ++ if (job) { ++ job->ebio = NULL; ++ eio_free_cache_job(job); ++ job = NULL; ++ } ++ } ++} ++ ++/* ++ * Invalidate any colliding blocks if they are !BUSY and !DIRTY. In BUSY case, ++ * we need to wait until the underlying IO is finished, and then proceed with ++ * the invalidation, so a QUEUED flag is added. ++ */ ++static int ++eio_inval_block_set_range(struct cache_c *dmc, int set, sector_t iosector, ++ unsigned iosize, int multiblk) ++{ ++ int start_index, end_index, i; ++ sector_t endsector = iosector + eio_to_sector(iosize); ++ ++ start_index = dmc->assoc * set; ++ end_index = start_index + dmc->assoc; ++ for (i = start_index; i < end_index; i++) { ++ sector_t start_dbn; ++ sector_t end_dbn; ++ ++ if (EIO_CACHE_STATE_GET(dmc, i) & INVALID) ++ continue; ++ start_dbn = EIO_DBN_GET(dmc, i); ++ end_dbn = start_dbn + dmc->block_size; ++ ++ if (!(endsector <= start_dbn || iosector >= end_dbn)) { ++ ++ if (! ++ (EIO_CACHE_STATE_GET(dmc, i) & ++ (BLOCK_IO_INPROG | DIRTY | QUEUED))) { ++ EIO_CACHE_STATE_SET(dmc, i, INVALID); ++ atomic64_dec_if_positive(&dmc->eio_stats. ++ cached_blocks); ++ if (multiblk) ++ continue; ++ return 0; ++ } ++ ++ /* Skip queued flag for DIRTY(inprog or otherwise) blocks. */ ++ if (!(EIO_CACHE_STATE_GET(dmc, i) & (DIRTY | QUEUED))) ++ /* BLOCK_IO_INPROG is set. Set QUEUED flag */ ++ EIO_CACHE_STATE_ON(dmc, i, QUEUED); ++ ++ if (!multiblk) ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++int ++eio_invalidate_sanity_check(struct cache_c *dmc, u_int64_t iosector, ++ u_int64_t *num_sectors) ++{ ++ u_int64_t disk_size; ++ ++ /* ++ * Sanity check the arguements ++ */ ++ if (unlikely(*num_sectors == 0)) { ++ pr_info ++ ("invaldate_sector_range: nothing to do because number of sectors specified is zero"); ++ return -EINVAL; ++ } ++ ++ disk_size = eio_to_sector(eio_get_device_size(dmc->disk_dev)); ++ if (iosector >= disk_size) { ++ pr_err ++ ("eio_inval_range: nothing to do because starting sector is past last sector (%lu > %lu)", ++ (long unsigned int)iosector, (long unsigned int)disk_size); ++ return -EINVAL; ++ } ++ ++ if ((iosector + (*num_sectors)) > disk_size) { ++ pr_info ++ ("eio_inval_range: trimming range because there are less sectors to invalidate than requested. (%lu < %lu)", ++ (long unsigned int)(disk_size - iosector), ++ (long unsigned int)*num_sectors); ++ *num_sectors = (disk_size - iosector); ++ } ++ ++ return 0; ++} ++ ++void eio_inval_range(struct cache_c *dmc, sector_t iosector, unsigned iosize) ++{ ++ u_int32_t bset; ++ sector_t snum; ++ sector_t snext; ++ unsigned ioinset; ++ unsigned long flags; ++ int totalsshift = dmc->block_shift + dmc->consecutive_shift; ++ ++ snum = iosector; ++ while (iosize) { ++ bset = hash_block(dmc, snum); ++ snext = ((snum >> totalsshift) + 1) << totalsshift; ++ ioinset = (unsigned)to_bytes(snext - snum); ++ if (ioinset > iosize) ++ ioinset = iosize; ++ spin_lock_irqsave(&dmc->cache_sets[bset].cs_lock, flags); ++ eio_inval_block_set_range(dmc, bset, snum, ioinset, 1); ++ spin_unlock_irqrestore(&dmc->cache_sets[bset].cs_lock, flags); ++ snum = snext; ++ iosize -= ioinset; ++ } ++} ++ ++/* ++ * Invalidates all cached blocks without waiting for them to complete ++ * Should be called with incoming IO suspended ++ */ ++int eio_invalidate_cache(struct cache_c *dmc) ++{ ++ u_int64_t i = 0; ++ unsigned long flags = 0; ++ sector_t disk_dev_size = to_bytes(eio_get_device_size(dmc->disk_dev)); ++ ++ /* invalidate the whole cache */ ++ for (i = 0; i < (dmc->size >> dmc->consecutive_shift); i++) { ++ spin_lock_irqsave(&dmc->cache_sets[i].cs_lock, flags); ++ /* TBD. Apply proper fix for the cast to disk_dev_size */ ++ (void)eio_inval_block_set_range(dmc, (int)i, 0, ++ (unsigned)disk_dev_size, 0); ++ spin_unlock_irqrestore(&dmc->cache_sets[i].cs_lock, flags); ++ } /* end - for all cachesets (i) */ ++ ++ return 0; /* i suspect we may need to return different statuses in the future */ ++} /* eio_invalidate_cache */ ++ ++static int eio_inval_block(struct cache_c *dmc, sector_t iosector) ++{ ++ u_int32_t bset; ++ int queued; ++ ++ /*Chop lower bits of iosector*/ ++ iosector = EIO_ROUND_SECTOR(dmc, iosector); ++ bset = hash_block(dmc, iosector); ++ queued = eio_inval_block_set_range(dmc, bset, iosector, ++ (unsigned)to_bytes(dmc->block_size), ++ 0); ++ ++ return queued; ++} ++ ++/* Serving write I/Os, that involves both SSD and HDD */ ++static int eio_uncached_write(struct cache_c *dmc, struct eio_bio *ebio) ++{ ++ struct kcached_job *job; ++ int err = 0; ++ index_t index = ebio->eb_index; ++ unsigned long flags = 0; ++ u_int8_t cstate; ++ ++ if (index == -1) { ++ /* ++ * No work, if block is not allocated. ++ * Ensure, invalidation of the block at the end ++ */ ++ ebio->eb_iotype |= EB_INVAL; ++ return 0; ++ } ++ ++ spin_lock_irqsave(&dmc->cache_sets[ebio->eb_cacheset].cs_lock, flags); ++ cstate = EIO_CACHE_STATE_GET(dmc, index); ++ EIO_ASSERT(cstate & (DIRTY | CACHEWRITEINPROG)); ++ if (cstate == ALREADY_DIRTY) { ++ /* ++ * Treat the dirty block cache write failure as ++ * I/O failure for the entire I/O ++ * TBD ++ * Can we live without this restriction ++ */ ++ ebio->eb_iotype = EB_MAIN_IO; ++ ++ /* ++ * We don't set inprog flag on dirty block. ++ * In lieu of the inprog flag, we are using the ++ * eb_holdcount for dirty block, so that the ++ * endio can be called, only when the write to disk ++ * and the write to cache both complete for the ebio ++ */ ++ atomic_inc(&ebio->eb_holdcount); ++ } else ++ /* ensure DISKWRITEINPROG for uncached write on non-DIRTY blocks */ ++ EIO_CACHE_STATE_ON(dmc, index, DISKWRITEINPROG); ++ ++ spin_unlock_irqrestore(&dmc->cache_sets[ebio->eb_cacheset].cs_lock, ++ flags); ++ ++ job = eio_new_job(dmc, ebio, index); ++ if (unlikely(job == NULL)) ++ err = -ENOMEM; ++ else { ++ job->action = WRITECACHE; ++ SECTOR_STATS(dmc->eio_stats.ssd_writes, ebio->eb_size); ++ atomic64_inc(&dmc->eio_stats.writecache); ++ err = eio_io_async_bvec(dmc, &job->job_io_regions.cache, WRITE, ++ ebio->eb_bv, ebio->eb_nbvec, ++ eio_io_callback, job, 0); ++ } ++ ++ if (err) { ++ pr_err("eio_uncached_write: IO submission failed, block %llu", ++ EIO_DBN_GET(dmc, index)); ++ spin_lock_irqsave(&dmc->cache_sets[ebio->eb_cacheset].cs_lock, ++ flags); ++ if (EIO_CACHE_STATE_GET(dmc, ebio->eb_index) == ALREADY_DIRTY) ++ /* ++ * Treat I/O failure on a DIRTY block as failure of entire I/O. ++ * TBD ++ * Can do better error handling by invalidation of the dirty ++ * block, if the cache block write failed, but disk write succeeded ++ */ ++ ebio->eb_bc->bc_error = err; ++ else { ++ /* Mark the block as INVALID for non-DIRTY block. */ ++ EIO_CACHE_STATE_SET(dmc, ebio->eb_index, INVALID); ++ atomic64_dec_if_positive(&dmc->eio_stats.cached_blocks); ++ /* Set the INVAL flag to ensure block is marked invalid at the end */ ++ ebio->eb_iotype |= EB_INVAL; ++ ebio->eb_index = -1; ++ } ++ spin_unlock_irqrestore(&dmc->cache_sets[ebio->eb_cacheset]. ++ cs_lock, flags); ++ if (job) { ++ job->ebio = NULL; ++ eio_free_cache_job(job); ++ job = NULL; ++ } ++ } ++ ++ return err; ++} ++ ++/* Serving write I/Os that can be fulfilled just by SSD */ ++static int ++eio_cached_write(struct cache_c *dmc, struct eio_bio *ebio, int rw_flags) ++{ ++ struct kcached_job *job; ++ int err = 0; ++ index_t index = ebio->eb_index; ++ unsigned long flags = 0; ++ u_int8_t cstate; ++ ++ /* ++ * WRITE (I->DV) ++ * WRITE (V->DV) ++ * WRITE (V1->DV2) ++ * WRITE (DV->DV) ++ */ ++ ++ /* Possible only in writeback caching mode */ ++ EIO_ASSERT(dmc->mode == CACHE_MODE_WB); ++ ++ /* ++ * TBD ++ * Possibly don't need the spinlock-unlock here ++ */ ++ spin_lock_irqsave(&dmc->cache_sets[ebio->eb_cacheset].cs_lock, flags); ++ cstate = EIO_CACHE_STATE_GET(dmc, index); ++ if (!(cstate & DIRTY)) { ++ EIO_ASSERT(cstate & CACHEWRITEINPROG); ++ /* make sure the block is marked DIRTY inprogress */ ++ EIO_CACHE_STATE_SET(dmc, index, DIRTY_INPROG); ++ } ++ spin_unlock_irqrestore(&dmc->cache_sets[ebio->eb_cacheset].cs_lock, ++ flags); ++ ++ job = eio_new_job(dmc, ebio, index); ++ if (unlikely(job == NULL)) ++ err = -ENOMEM; ++ else { ++ job->action = WRITECACHE; ++ ++ SECTOR_STATS(dmc->eio_stats.ssd_writes, ebio->eb_size); ++ atomic64_inc(&dmc->eio_stats.writecache); ++ EIO_ASSERT((rw_flags & 1) == WRITE); ++ err = ++ eio_io_async_bvec(dmc, &job->job_io_regions.cache, rw_flags, ++ ebio->eb_bv, ebio->eb_nbvec, ++ eio_io_callback, job, 0); ++ ++ } ++ ++ if (err) { ++ pr_err("eio_cached_write: IO submission failed, block %llu", ++ EIO_DBN_GET(dmc, index)); ++ spin_lock_irqsave(&dmc->cache_sets[ebio->eb_cacheset].cs_lock, ++ flags); ++ cstate = EIO_CACHE_STATE_GET(dmc, index); ++ if (cstate == DIRTY_INPROG) { ++ /* A DIRTY(inprog) block should be invalidated on error */ ++ EIO_CACHE_STATE_SET(dmc, ebio->eb_index, INVALID); ++ atomic64_dec_if_positive(&dmc->eio_stats.cached_blocks); ++ } else ++ /* An already DIRTY block don't have an option but just return error. */ ++ EIO_ASSERT(cstate == ALREADY_DIRTY); ++ spin_unlock_irqrestore(&dmc->cache_sets[ebio->eb_cacheset]. ++ cs_lock, flags); ++ eb_endio(ebio, err); ++ ebio = NULL; ++ if (job) { ++ job->ebio = NULL; ++ eio_free_cache_job(job); ++ job = NULL; ++ } ++ } ++ ++ return err; ++} ++ ++static struct eio_bio *eio_new_ebio(struct cache_c *dmc, struct bio *bio, ++ unsigned *presidual_biovec, sector_t snum, ++ int iosize, struct bio_container *bc, ++ int iotype) ++{ ++ struct eio_bio *ebio; ++ int residual_biovec = *presidual_biovec; ++ int numbvecs = 0; ++ int ios; ++ ++ if (residual_biovec) { ++ int bvecindex = bio->bi_idx; ++ int rbvindex; ++ ++ /* Calculate the number of bvecs required */ ++ ios = iosize; ++ while (ios > 0) { ++ int len; ++ ++ if (ios == iosize) ++ len = ++ bio->bi_io_vec[bvecindex].bv_len - ++ residual_biovec; ++ else ++ len = bio->bi_io_vec[bvecindex].bv_len; ++ ++ numbvecs++; ++ if (len > ios) ++ len = ios; ++ ios -= len; ++ bvecindex++; ++ } ++ ebio = ++ kmalloc(sizeof(struct eio_bio) + ++ numbvecs * sizeof(struct bio_vec), GFP_NOWAIT); ++ ++ if (!ebio) ++ return ERR_PTR(-ENOMEM); ++ ++ rbvindex = 0; ++ ios = iosize; ++ while (ios > 0) { ++ ebio->eb_rbv[rbvindex].bv_page = ++ bio->bi_io_vec[bio->bi_idx].bv_page; ++ ebio->eb_rbv[rbvindex].bv_offset = ++ bio->bi_io_vec[bio->bi_idx].bv_offset + ++ residual_biovec; ++ ebio->eb_rbv[rbvindex].bv_len = ++ bio->bi_io_vec[bio->bi_idx].bv_len - ++ residual_biovec; ++ if (ebio->eb_rbv[rbvindex].bv_len > (unsigned)ios) { ++ residual_biovec += ios; ++ ebio->eb_rbv[rbvindex].bv_len = ios; ++ } else { ++ residual_biovec = 0; ++ bio->bi_idx++; ++ } ++ ios -= ebio->eb_rbv[rbvindex].bv_len; ++ rbvindex++; ++ } ++ EIO_ASSERT(rbvindex == numbvecs); ++ ebio->eb_bv = ebio->eb_rbv; ++ } else { ++ ebio = kmalloc(sizeof(struct eio_bio), GFP_NOWAIT); ++ ++ if (!ebio) ++ return ERR_PTR(-ENOMEM); ++ ebio->eb_bv = bio->bi_io_vec + bio->bi_idx; ++ ios = iosize; ++ while (ios > 0) { ++ numbvecs++; ++ if ((unsigned)ios < bio->bi_io_vec[bio->bi_idx].bv_len) { ++ residual_biovec = ios; ++ ios = 0; ++ } else { ++ ios -= bio->bi_io_vec[bio->bi_idx].bv_len; ++ bio->bi_idx++; ++ } ++ } ++ } ++ EIO_ASSERT(ios == 0); ++ EIO_ASSERT(numbvecs != 0); ++ *presidual_biovec = residual_biovec; ++ ++ ebio->eb_sector = snum; ++ ebio->eb_cacheset = hash_block(dmc, snum); ++ ebio->eb_size = iosize; ++ ebio->eb_dir = bio_data_dir(bio); ++ ebio->eb_next = NULL; ++ ebio->eb_index = -1; ++ ebio->eb_iotype = iotype; ++ ebio->eb_nbvec = numbvecs; ++ ++ bc_addfb(bc, ebio); ++ ++ /* Always set the holdcount for eb to 1, to begin with. */ ++ atomic_set(&ebio->eb_holdcount, 1); ++ ++ return ebio; ++} ++ ++/* Issues HDD I/O */ ++static void ++eio_disk_io(struct cache_c *dmc, struct bio *bio, ++ struct eio_bio *anchored_bios, struct bio_container *bc, ++ int force_inval) ++{ ++ struct eio_bio *ebio; ++ struct kcached_job *job; ++ int residual_biovec = 0; ++ int error = 0; ++ ++ /*disk io happens on whole bio. Reset bi_idx*/ ++ bio->bi_idx = 0; ++ ebio = ++ eio_new_ebio(dmc, bio, &residual_biovec, bio->bi_sector, ++ bio->bi_size, bc, EB_MAIN_IO); ++ ++ if (unlikely(IS_ERR(ebio))) { ++ bc->bc_error = error = PTR_ERR(ebio); ++ ebio = NULL; ++ goto errout; ++ } ++ ++ if (force_inval) ++ ebio->eb_iotype |= EB_INVAL; ++ ebio->eb_next = anchored_bios; /*Anchor the ebio list to this super bio*/ ++ job = eio_new_job(dmc, ebio, -1); ++ ++ if (unlikely(job == NULL)) { ++ error = -ENOMEM; ++ goto errout; ++ } ++ atomic_inc(&dmc->nr_jobs); ++ if (ebio->eb_dir == READ) { ++ job->action = READDISK; ++ SECTOR_STATS(dmc->eio_stats.disk_reads, bio->bi_size); ++ atomic64_inc(&dmc->eio_stats.readdisk); ++ } else { ++ job->action = WRITEDISK; ++ SECTOR_STATS(dmc->eio_stats.disk_writes, bio->bi_size); ++ atomic64_inc(&dmc->eio_stats.writedisk); ++ } ++ ++ /* ++ * Pass the original bio flags as is, while doing ++ * read / write to HDD. ++ */ ++ VERIFY_BIO_FLAGS(ebio); ++ error = eio_io_async_bvec(dmc, &job->job_io_regions.disk, ++ GET_BIO_FLAGS(ebio), ++ ebio->eb_bv, ebio->eb_nbvec, ++ eio_io_callback, job, 1); ++ ++ if (error) { ++ job->ebio = NULL; ++ eio_free_cache_job(job); ++ goto errout; ++ } ++ return; ++ ++errout: ++ eio_inval_range(dmc, bio->bi_sector, bio->bi_size); ++ eio_flag_abios(dmc, anchored_bios, error); ++ ++ if (ebio) ++ eb_endio(ebio, error); ++ return; ++} ++ ++/*Given a sector number and biosize, returns cache io size*/ ++static unsigned int ++eio_get_iosize(struct cache_c *dmc, sector_t snum, unsigned int biosize) ++{ ++ unsigned int iosize; ++ unsigned int swithinblock = snum & (dmc->block_size - 1); ++ ++ /*Check whether io starts at a cache block boundary*/ ++ if (swithinblock) ++ iosize = (unsigned int)to_bytes(dmc->block_size - swithinblock); ++ else ++ iosize = (unsigned int)to_bytes(dmc->block_size); ++ if (iosize > biosize) ++ iosize = biosize; ++ return iosize; ++} ++ ++/* Insert a new set sequence in sorted order to existing set sequence list */ ++static int ++insert_set_seq(struct set_seq **seq_list, index_t first_set, index_t last_set) ++{ ++ struct set_seq *cur_seq = NULL; ++ struct set_seq *prev_seq = NULL; ++ struct set_seq *new_seq = NULL; ++ ++ EIO_ASSERT((first_set != -1) && (last_set != -1) ++ && (last_set >= first_set)); ++ ++ for (cur_seq = *seq_list; cur_seq; ++ prev_seq = cur_seq, cur_seq = cur_seq->next) { ++ if (first_set > cur_seq->last_set) ++ /* go for the next seq in the sorted seq list */ ++ continue; ++ ++ if (last_set < cur_seq->first_set) ++ /* break here to insert the new seq to seq list at this point */ ++ break; ++ ++ /* ++ * There is an overlap of the new seq with the current seq. ++ * Adjust the first_set field of the current seq to consume ++ * the overlap. ++ */ ++ if (first_set < cur_seq->first_set) ++ cur_seq->first_set = first_set; ++ ++ if (last_set <= cur_seq->last_set) ++ /* The current seq now fully encompasses the first and last sets */ ++ return 0; ++ ++ /* Increment the first set so as to start from, where the current seq left */ ++ first_set = cur_seq->last_set + 1; ++ } ++ ++ new_seq = kmalloc(sizeof(struct set_seq), GFP_NOWAIT); ++ if (new_seq == NULL) ++ return -ENOMEM; ++ new_seq->first_set = first_set; ++ new_seq->last_set = last_set; ++ if (prev_seq) { ++ new_seq->next = prev_seq->next; ++ prev_seq->next = new_seq; ++ } else { ++ new_seq->next = *seq_list; ++ *seq_list = new_seq; ++ } ++ ++ return 0; ++} ++ ++/* Acquire read/shared lock for the sets covering the entire I/O range */ ++static int eio_acquire_set_locks(struct cache_c *dmc, struct bio_container *bc) ++{ ++ struct bio *bio = bc->bc_bio; ++ sector_t round_sector; ++ sector_t end_sector; ++ sector_t set_size; ++ index_t cur_set; ++ index_t first_set; ++ index_t last_set; ++ index_t i; ++ struct set_seq *cur_seq; ++ struct set_seq *next_seq; ++ int error; ++ ++ /* ++ * Find first set using start offset of the I/O and lock it. ++ * Find next sets by adding the set offsets to the previous set ++ * Identify all the sequences of set numbers that need locking. ++ * Keep the sequences in sorted list. ++ * For each set in each sequence ++ * - acquire read lock on the set. ++ */ ++ ++ round_sector = EIO_ROUND_SET_SECTOR(dmc, bio->bi_sector); ++ set_size = dmc->block_size * dmc->assoc; ++ end_sector = bio->bi_sector + eio_to_sector(bio->bi_size); ++ first_set = -1; ++ last_set = -1; ++ cur_set = -1; ++ bc->bc_setspan = NULL; ++ ++ while (round_sector < end_sector) { ++ cur_set = hash_block(dmc, round_sector); ++ if (first_set == -1) { ++ first_set = cur_set; ++ last_set = cur_set; ++ } else if (cur_set == (last_set + 1)) ++ last_set = cur_set; ++ else { ++ /* ++ * Add the seq of start, end set to sorted (first, last) seq list ++ * and reinit the first and last set ++ */ ++ error = ++ insert_set_seq(&bc->bc_setspan, first_set, ++ last_set); ++ if (error) ++ goto err_out; ++ first_set = cur_set; ++ last_set = cur_set; ++ } ++ ++ round_sector += set_size; ++ } ++ ++ /* Add the remaining first, last set sequence */ ++ ++ EIO_ASSERT((first_set != -1) && (last_set == cur_set)); ++ ++ if (bc->bc_setspan == NULL) { ++ /* No sequence was added, can use singlespan */ ++ cur_seq = &bc->bc_singlesspan; ++ cur_seq->first_set = first_set; ++ cur_seq->last_set = last_set; ++ cur_seq->next = NULL; ++ bc->bc_setspan = cur_seq; ++ } else { ++ error = insert_set_seq(&bc->bc_setspan, first_set, last_set); ++ if (error) ++ goto err_out; ++ } ++ ++ /* Acquire read locks on the sets in the set span */ ++ for (cur_seq = bc->bc_setspan; cur_seq; cur_seq = cur_seq->next) ++ for (i = cur_seq->first_set; i <= cur_seq->last_set; i++) ++ down_read(&dmc->cache_sets[i].rw_lock); ++ ++ return 0; ++ ++err_out: ++ ++ /* Free the seqs in the seq list, unless it is just the local seq */ ++ if (bc->bc_setspan != &bc->bc_singlesspan) { ++ for (cur_seq = bc->bc_setspan; cur_seq; cur_seq = next_seq) { ++ next_seq = cur_seq->next; ++ kfree(cur_seq); ++ } ++ } ++ return error; ++} ++ ++/* ++ * Allocate mdreq and md_blocks for each set. ++ */ ++static int eio_alloc_mdreqs(struct cache_c *dmc, struct bio_container *bc) ++{ ++ index_t i; ++ struct mdupdate_request *mdreq; ++ int nr_bvecs, ret; ++ struct set_seq *cur_seq; ++ ++ bc->mdreqs = NULL; ++ ++ for (cur_seq = bc->bc_setspan; cur_seq; cur_seq = cur_seq->next) { ++ for (i = cur_seq->first_set; i <= cur_seq->last_set; i++) { ++ mdreq = kzalloc(sizeof(*mdreq), GFP_NOWAIT); ++ if (mdreq) { ++ mdreq->md_size = ++ dmc->assoc * ++ sizeof(struct flash_cacheblock); ++ nr_bvecs = ++ IO_BVEC_COUNT(mdreq->md_size, ++ SECTORS_PER_PAGE); ++ ++ mdreq->mdblk_bvecs = ++ (struct bio_vec *) ++ kmalloc(sizeof(struct bio_vec) * nr_bvecs, ++ GFP_KERNEL); ++ if (mdreq->mdblk_bvecs) { ++ ++ ret = ++ eio_alloc_wb_bvecs(mdreq-> ++ mdblk_bvecs, ++ nr_bvecs, ++ SECTORS_PER_PAGE); ++ if (ret) { ++ pr_err ++ ("eio_alloc_mdreqs: failed to allocated pages\n"); ++ kfree(mdreq->mdblk_bvecs); ++ mdreq->mdblk_bvecs = NULL; ++ } ++ mdreq->mdbvec_count = nr_bvecs; ++ } ++ } ++ ++ if (unlikely ++ ((mdreq == NULL) || (mdreq->mdblk_bvecs == NULL))) { ++ struct mdupdate_request *nmdreq; ++ ++ mdreq = bc->mdreqs; ++ while (mdreq) { ++ nmdreq = mdreq->next; ++ if (mdreq->mdblk_bvecs) { ++ eio_free_wb_bvecs(mdreq-> ++ mdblk_bvecs, ++ mdreq-> ++ mdbvec_count, ++ SECTORS_PER_PAGE); ++ kfree(mdreq->mdblk_bvecs); ++ } ++ kfree(mdreq); ++ mdreq = nmdreq; ++ } ++ bc->mdreqs = NULL; ++ return -ENOMEM; ++ } else { ++ mdreq->next = bc->mdreqs; ++ bc->mdreqs = mdreq; ++ } ++ } ++ } ++ ++ return 0; ++ ++} ++ ++/* ++ * Release: ++ * 1. the set locks covering the entire I/O range ++ * 2. any previously allocated memory for md update ++ */ ++static int ++eio_release_io_resources(struct cache_c *dmc, struct bio_container *bc) ++{ ++ index_t i; ++ struct mdupdate_request *mdreq; ++ struct mdupdate_request *nmdreq; ++ struct set_seq *cur_seq; ++ struct set_seq *next_seq; ++ ++ /* Release read locks on the sets in the set span */ ++ for (cur_seq = bc->bc_setspan; cur_seq; cur_seq = cur_seq->next) ++ for (i = cur_seq->first_set; i <= cur_seq->last_set; i++) ++ up_read(&dmc->cache_sets[i].rw_lock); ++ ++ /* Free the seqs in the set span, unless it is single span */ ++ if (bc->bc_setspan != &bc->bc_singlesspan) { ++ for (cur_seq = bc->bc_setspan; cur_seq; cur_seq = next_seq) { ++ next_seq = cur_seq->next; ++ kfree(cur_seq); ++ } ++ } ++ ++ mdreq = bc->mdreqs; ++ while (mdreq) { ++ nmdreq = mdreq->next; ++ if (mdreq->mdblk_bvecs) { ++ eio_free_wb_bvecs(mdreq->mdblk_bvecs, ++ mdreq->mdbvec_count, ++ SECTORS_PER_PAGE); ++ kfree(mdreq->mdblk_bvecs); ++ } ++ kfree(mdreq); ++ mdreq = nmdreq; ++ } ++ bc->mdreqs = NULL; ++ ++ return 0; ++} ++ ++/* ++ * Decide the mapping and perform necessary cache operations for a bio request. ++ */ ++int eio_map(struct cache_c *dmc, struct request_queue *rq, struct bio *bio) ++{ ++ sector_t sectors = eio_to_sector(bio->bi_size); ++ struct eio_bio *ebio = NULL; ++ struct bio_container *bc; ++ sector_t snum; ++ unsigned int iosize; ++ unsigned int totalio; ++ unsigned int biosize; ++ unsigned int residual_biovec; ++ unsigned int force_uncached = 0; ++ int data_dir = bio_data_dir(bio); ++ ++ /*bio list*/ ++ struct eio_bio *ebegin = NULL; ++ struct eio_bio *eend = NULL; ++ struct eio_bio *enext = NULL; ++ ++ EIO_ASSERT(bio->bi_idx == 0); ++ ++ pr_debug("this needs to be removed immediately\n"); ++ ++ if (bio_rw_flagged(bio, REQ_DISCARD)) { ++ pr_debug ++ ("eio_map: Discard IO received. Invalidate incore start=%lu totalsectors=%d.\n", ++ (unsigned long)bio->bi_sector, ++ (int)eio_to_sector(bio->bi_size)); ++ bio_endio(bio, 0); ++ pr_err ++ ("eio_map: I/O with Discard flag received. Discard flag is not supported.\n"); ++ return 0; ++ } ++ ++ if (unlikely(dmc->cache_rdonly)) { ++ if (data_dir != READ) { ++ bio_endio(bio, -EPERM); ++ pr_debug ++ ("eio_map: cache is read only, write not permitted\n"); ++ return 0; ++ } ++ } ++ ++ if (sectors < SIZE_HIST) ++ atomic64_inc(&dmc->size_hist[sectors]); ++ ++ if (data_dir == READ) { ++ SECTOR_STATS(dmc->eio_stats.reads, bio->bi_size); ++ atomic64_inc(&dmc->eio_stats.readcount); ++ } else { ++ SECTOR_STATS(dmc->eio_stats.writes, bio->bi_size); ++ atomic64_inc(&dmc->eio_stats.writecount); ++ } ++ ++ /* ++ * Cache FAILED mode is like Hard failure. ++ * Dont allow I/Os to go through. ++ */ ++ if (unlikely(CACHE_FAILED_IS_SET(dmc))) { ++ /*ASK confirm that once failed is set, it's never reset*/ ++ /* Source device is not available. */ ++ CTRACE ++ ("eio_map:2 source device is not present. Cache is in Failed state\n"); ++ bio_endio(bio, -ENODEV); ++ bio = NULL; ++ return DM_MAPIO_SUBMITTED; ++ } ++ ++ /* WB cache will never be in degraded mode. */ ++ if (unlikely(CACHE_DEGRADED_IS_SET(dmc))) { ++ EIO_ASSERT(dmc->mode != CACHE_MODE_WB); ++ force_uncached = 1; ++ } ++ ++ /* ++ * Process zero sized bios by passing original bio flags ++ * to both HDD and SSD. ++ */ ++ if (bio->bi_size == 0) { ++ eio_process_zero_size_bio(dmc, bio); ++ return DM_MAPIO_SUBMITTED; ++ } ++ ++ /* Create a bio container */ ++ ++ bc = kzalloc(sizeof(struct bio_container), GFP_NOWAIT); ++ if (!bc) { ++ bio_endio(bio, -ENOMEM); ++ return DM_MAPIO_SUBMITTED; ++ } ++ bc->bc_iotime = jiffies; ++ bc->bc_bio = bio; ++ bc->bc_dmc = dmc; ++ spin_lock_init(&bc->bc_lock); ++ atomic_set(&bc->bc_holdcount, 1); ++ bc->bc_error = 0; ++ ++ snum = bio->bi_sector; ++ totalio = bio->bi_size; ++ biosize = bio->bi_size; ++ residual_biovec = 0; ++ ++ if (dmc->mode == CACHE_MODE_WB) { ++ int ret; ++ /* ++ * For writeback, the app I/O and the clean I/Os ++ * need to be exclusive for a cache set. Acquire shared ++ * lock on the cache set for app I/Os and exclusive ++ * lock on the cache set for clean I/Os. ++ */ ++ ret = eio_acquire_set_locks(dmc, bc); ++ if (ret) { ++ bio_endio(bio, ret); ++ kfree(bc); ++ return DM_MAPIO_SUBMITTED; ++ } ++ } ++ ++ atomic64_inc(&dmc->nr_ios); ++ ++ /* ++ * Prepare for I/O processing. ++ * - Allocate ebios. ++ * - For reads, identify if we need to do uncached read ++ * - If force uncached I/O is set, invalidate the cache blocks for the I/O ++ */ ++ ++ if (force_uncached) ++ eio_inval_range(dmc, snum, totalio); ++ else { ++ while (biosize) { ++ iosize = eio_get_iosize(dmc, snum, biosize); ++ ebio = eio_new_ebio(dmc, bio, &residual_biovec, snum, ++ iosize, bc, EB_SUBORDINATE_IO); ++ if (IS_ERR(ebio)) { ++ bc->bc_error = -ENOMEM; ++ break; ++ } ++ ++ /* Anchor this ebio on ebio list. Preserve the order */ ++ if (ebegin) ++ eend->eb_next = ebio; ++ else ++ ebegin = ebio; ++ eend = ebio; ++ ++ biosize -= iosize; ++ snum += eio_to_sector(iosize); ++ } ++ } ++ ++ if (bc->bc_error) { ++ /* Error. Do ebio and bc cleanup. */ ++ ebio = ebegin; ++ while (ebio) { ++ enext = ebio->eb_next; ++ eb_endio(ebio, bc->bc_error); ++ ebio = enext; ++ } ++ ++ /* By now, the bc_holdcount must be 1 */ ++ EIO_ASSERT(atomic_read(&bc->bc_holdcount) == 1); ++ ++ /* Goto out to cleanup the bc(in bc_put()) */ ++ goto out; ++ } ++ ++ /* ++ * Start processing of the ebios. ++ * ++ * Note: don't return error from this point on. ++ * Error handling would be done as part of ++ * the processing of the ebios internally. ++ */ ++ if (force_uncached) { ++ EIO_ASSERT(dmc->mode != CACHE_MODE_WB); ++ if (data_dir == READ) ++ atomic64_inc(&dmc->eio_stats.uncached_reads); ++ else ++ atomic64_inc(&dmc->eio_stats.uncached_writes); ++ eio_disk_io(dmc, bio, ebegin, bc, 1); ++ } else if (data_dir == READ) { ++ ++ /* read io processing */ ++ eio_read(dmc, bc, ebegin); ++ } else ++ /* write io processing */ ++ eio_write(dmc, bc, ebegin); ++ ++out: ++ ++ if (bc) ++ bc_put(bc, 0); ++ ++ return DM_MAPIO_SUBMITTED; ++} ++ ++/* ++ * Checks the cache block state, for deciding cached/uncached read. ++ * Also reserves/allocates the cache block, wherever necessary. ++ * ++ * Return values ++ * 1: cache hit ++ * 0: cache miss ++ */ ++static int eio_read_peek(struct cache_c *dmc, struct eio_bio *ebio) ++{ ++ index_t index; ++ int res; ++ int retval = 0; ++ unsigned long flags; ++ u_int8_t cstate; ++ ++ spin_lock_irqsave(&dmc->cache_sets[ebio->eb_cacheset].cs_lock, flags); ++ ++ res = eio_lookup(dmc, ebio, &index); ++ ebio->eb_index = -1; ++ ++ if (res < 0) { ++ atomic64_inc(&dmc->eio_stats.noroom); ++ goto out; ++ } ++ ++ cstate = EIO_CACHE_STATE_GET(dmc, index); ++ ++ if (cstate & (BLOCK_IO_INPROG | QUEUED)) ++ /* ++ * We found a valid or invalid block but an io is on, so we can't ++ * proceed. Don't invalidate it. This implies that we'll ++ * have to read from disk. ++ * Read on a DIRTY | INPROG block (block which is going to be DIRTY) ++ * is also redirected to read from disk. ++ */ ++ goto out; ++ ++ if (res == VALID) { ++ EIO_ASSERT(cstate & VALID); ++ if ((EIO_DBN_GET(dmc, index) == ++ EIO_ROUND_SECTOR(dmc, ebio->eb_sector))) { ++ /* ++ * Read/write should be done on already DIRTY block ++ * without any inprog flag. ++ * Ensure that a failure of DIRTY block read is propagated to app. ++ * non-DIRTY valid blocks should have inprog flag. ++ */ ++ if (cstate == ALREADY_DIRTY) { ++ ebio->eb_iotype = EB_MAIN_IO; ++ /* ++ * Set to uncached read and readfill for now. ++ * It may change to CACHED_READ later, if all ++ * the blocks are found to be cached ++ */ ++ ebio->eb_bc->bc_dir = ++ UNCACHED_READ_AND_READFILL; ++ } else ++ EIO_CACHE_STATE_ON(dmc, index, CACHEREADINPROG); ++ retval = 1; ++ ebio->eb_index = index; ++ goto out; ++ } ++ ++ /* cache is marked readonly. Do not allow READFILL on SSD */ ++ if (unlikely(dmc->cache_rdonly)) ++ goto out; ++ ++ /* ++ * Found a block to be recycled. ++ * Its guranteed that it will be a non-DIRTY block ++ */ ++ EIO_ASSERT(!(cstate & DIRTY)); ++ if (eio_to_sector(ebio->eb_size) == dmc->block_size) { ++ /*We can recycle and then READFILL only if iosize is block size*/ ++ atomic64_inc(&dmc->eio_stats.rd_replace); ++ EIO_CACHE_STATE_SET(dmc, index, VALID | DISKREADINPROG); ++ EIO_DBN_SET(dmc, index, (sector_t)ebio->eb_sector); ++ ebio->eb_index = index; ++ ebio->eb_bc->bc_dir = UNCACHED_READ_AND_READFILL; ++ } ++ goto out; ++ } ++ EIO_ASSERT(res == INVALID); ++ ++ /* cache is marked readonly. Do not allow READFILL on SSD */ ++ if (unlikely(dmc->cache_rdonly)) ++ goto out; ++ /* ++ * Found an invalid block to be used. ++ * Can recycle only if iosize is block size ++ */ ++ if (eio_to_sector(ebio->eb_size) == dmc->block_size) { ++ EIO_ASSERT(cstate & INVALID); ++ EIO_CACHE_STATE_SET(dmc, index, VALID | DISKREADINPROG); ++ atomic64_inc(&dmc->eio_stats.cached_blocks); ++ EIO_DBN_SET(dmc, index, (sector_t)ebio->eb_sector); ++ ebio->eb_index = index; ++ ebio->eb_bc->bc_dir = UNCACHED_READ_AND_READFILL; ++ } ++ ++out: ++ ++ spin_unlock_irqrestore(&dmc->cache_sets[ebio->eb_cacheset].cs_lock, ++ flags); ++ ++ /* ++ * Enqueue clean set if there is no room in the set ++ * TBD ++ * Ensure, a force clean ++ */ ++ if (res < 0) ++ eio_comply_dirty_thresholds(dmc, ebio->eb_cacheset); ++ ++ return retval; ++} ++ ++/* ++ * Checks the cache block state, for deciding cached/uncached write. ++ * Also reserves/allocates the cache block, wherever necessary. ++ * ++ * Return values ++ * 1: cache block is available or newly allocated ++ * 0: cache block could not be got for the ebio ++ */ ++static int eio_write_peek(struct cache_c *dmc, struct eio_bio *ebio) ++{ ++ index_t index; ++ int res; ++ int retval; ++ u_int8_t cstate; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dmc->cache_sets[ebio->eb_cacheset].cs_lock, flags); ++ ++ res = eio_lookup(dmc, ebio, &index); ++ ebio->eb_index = -1; ++ retval = 0; ++ ++ if (res < 0) { ++ /* cache block not found and new block couldn't be allocated */ ++ atomic64_inc(&dmc->eio_stats.noroom); ++ ebio->eb_iotype |= EB_INVAL; ++ goto out; ++ } ++ ++ cstate = EIO_CACHE_STATE_GET(dmc, index); ++ ++ if (cstate & (BLOCK_IO_INPROG | QUEUED)) { ++ ebio->eb_iotype |= EB_INVAL; ++ /* treat as if cache block is not available */ ++ goto out; ++ } ++ ++ if ((res == VALID) && (EIO_DBN_GET(dmc, index) == ++ EIO_ROUND_SECTOR(dmc, ebio->eb_sector))) { ++ /* ++ * Cache hit. ++ * All except an already DIRTY block should have an INPROG flag. ++ * If it is a cached write, a DIRTY flag would be added later. ++ */ ++ SECTOR_STATS(dmc->eio_stats.write_hits, ebio->eb_size); ++ if (cstate != ALREADY_DIRTY) ++ EIO_CACHE_STATE_ON(dmc, index, CACHEWRITEINPROG); ++ else ++ atomic64_inc(&dmc->eio_stats.dirty_write_hits); ++ ebio->eb_index = index; ++ /* ++ * A VALID block should get upgraded to DIRTY, only when we ++ * are updating the entire cache block(not partially). ++ * Otherwise, 2 sequential partial writes can lead to missing ++ * data when one write upgrades the cache block to DIRTY, while ++ * the other just writes to HDD. Subsequent read would be ++ * served from the cache block, which won't have the data from ++ * 2nd write. ++ */ ++ if ((cstate == ALREADY_DIRTY) || ++ (eio_to_sector(ebio->eb_size) == dmc->block_size)) ++ retval = 1; ++ else ++ retval = 0; ++ goto out; ++ ++ } ++ ++ /* ++ * cache miss with a new block allocated for recycle. ++ * Set INPROG flag, if the ebio size is equal to cache block size ++ */ ++ EIO_ASSERT(!(EIO_CACHE_STATE_GET(dmc, index) & DIRTY)); ++ if (eio_to_sector(ebio->eb_size) == dmc->block_size) { ++ if (res == VALID) ++ atomic64_inc(&dmc->eio_stats.wr_replace); ++ else ++ atomic64_inc(&dmc->eio_stats.cached_blocks); ++ EIO_CACHE_STATE_SET(dmc, index, VALID | CACHEWRITEINPROG); ++ EIO_DBN_SET(dmc, index, (sector_t)ebio->eb_sector); ++ ebio->eb_index = index; ++ retval = 1; ++ } else { ++ /* ++ * eb iosize smaller than cache block size shouldn't ++ * do cache write on a cache miss ++ */ ++ retval = 0; ++ ebio->eb_iotype |= EB_INVAL; ++ } ++ ++out: ++ if ((retval == 1) && (dmc->mode == CACHE_MODE_WB) && ++ (cstate != ALREADY_DIRTY)) ++ ebio->eb_bc->bc_mdwait++; ++ ++ spin_unlock_irqrestore(&dmc->cache_sets[ebio->eb_cacheset].cs_lock, ++ flags); ++ ++ /* ++ * Enqueue clean set if there is no room in the set ++ * TBD ++ * Ensure, a force clean ++ */ ++ if (res < 0) ++ eio_comply_dirty_thresholds(dmc, ebio->eb_cacheset); ++ ++ return retval; ++} ++ ++/* Top level read function, called from eio_map */ ++static void ++eio_read(struct cache_c *dmc, struct bio_container *bc, struct eio_bio *ebegin) ++{ ++ int ucread = 0; ++ struct eio_bio *ebio; ++ struct eio_bio *enext; ++ ++ bc->bc_dir = UNCACHED_READ; ++ ebio = ebegin; ++ while (ebio) { ++ enext = ebio->eb_next; ++ if (eio_read_peek(dmc, ebio) == 0) ++ ucread = 1; ++ ebio = enext; ++ } ++ ++ if (ucread) { ++ /* ++ * Uncached read. ++ * Start HDD I/O. Once that is finished ++ * readfill or dirty block re-read would start ++ */ ++ atomic64_inc(&dmc->eio_stats.uncached_reads); ++ eio_disk_io(dmc, bc->bc_bio, ebegin, bc, 0); ++ } else { ++ /* Cached read. Serve the read from SSD */ ++ ++ /* ++ * Pass all orig bio flags except UNPLUG. ++ * Unplug in the end if flagged. ++ */ ++ int rw_flags; ++ ++ rw_flags = 0; ++ ++ bc->bc_dir = CACHED_READ; ++ ebio = ebegin; ++ ++ VERIFY_BIO_FLAGS(ebio); ++ ++ EIO_ASSERT((rw_flags & 1) == READ); ++ while (ebio) { ++ enext = ebio->eb_next; ++ ebio->eb_iotype = EB_MAIN_IO; ++ ++ eio_cached_read(dmc, ebio, rw_flags); ++ ebio = enext; ++ } ++ } ++} ++ ++/* Top level write function called from eio_map */ ++static void ++eio_write(struct cache_c *dmc, struct bio_container *bc, struct eio_bio *ebegin) ++{ ++ int ucwrite = 0; ++ int error = 0; ++ struct eio_bio *ebio; ++ struct eio_bio *enext; ++ ++ if ((dmc->mode != CACHE_MODE_WB) || ++ (dmc->sysctl_active.do_clean & EIO_CLEAN_KEEP)) ++ ucwrite = 1; ++ ++ ebio = ebegin; ++ while (ebio) { ++ enext = ebio->eb_next; ++ if (eio_write_peek(dmc, ebio) == 0) ++ ucwrite = 1; ++ ebio = enext; ++ } ++ ++ if (ucwrite) { ++ /* ++ * Uncached write. ++ * Start both SSD and HDD writes ++ */ ++ atomic64_inc(&dmc->eio_stats.uncached_writes); ++ bc->bc_mdwait = 0; ++ bc->bc_dir = UNCACHED_WRITE; ++ ebio = ebegin; ++ while (ebio) { ++ enext = ebio->eb_next; ++ eio_uncached_write(dmc, ebio); ++ ebio = enext; ++ } ++ ++ eio_disk_io(dmc, bc->bc_bio, ebegin, bc, 0); ++ } else { ++ /* Cached write. Start writes to SSD blocks */ ++ ++ int rw_flags; ++ rw_flags = 0; ++ ++ bc->bc_dir = CACHED_WRITE; ++ if (bc->bc_mdwait) { ++ ++ /* ++ * mdreqs are required only if the write would cause a metadata ++ * update. ++ */ ++ ++ error = eio_alloc_mdreqs(dmc, bc); ++ } ++ ++ /* ++ * Pass all orig bio flags except UNPLUG. ++ * UNPLUG in the end if flagged. ++ */ ++ ebio = ebegin; ++ VERIFY_BIO_FLAGS(ebio); ++ ++ while (ebio) { ++ enext = ebio->eb_next; ++ ebio->eb_iotype = EB_MAIN_IO; ++ ++ if (!error) { ++ ++ eio_cached_write(dmc, ebio, WRITE | rw_flags); ++ ++ } else { ++ unsigned long flags; ++ u_int8_t cstate; ++ ++ pr_err ++ ("eio_write: IO submission failed, block %llu", ++ EIO_DBN_GET(dmc, ebio->eb_index)); ++ spin_lock_irqsave(&dmc-> ++ cache_sets[ebio->eb_cacheset]. ++ cs_lock, flags); ++ cstate = ++ EIO_CACHE_STATE_GET(dmc, ebio->eb_index); ++ if (cstate != ALREADY_DIRTY) { ++ ++ /* ++ * A DIRTY(inprog) block should be invalidated on error. ++ */ ++ ++ EIO_CACHE_STATE_SET(dmc, ebio->eb_index, ++ INVALID); ++ atomic64_dec_if_positive(&dmc-> ++ eio_stats. ++ cached_blocks); ++ } ++ spin_unlock_irqrestore(&dmc-> ++ cache_sets[ebio-> ++ eb_cacheset]. ++ cs_lock, flags); ++ eb_endio(ebio, error); ++ } ++ ebio = enext; ++ } ++ } ++} ++ ++/* ++ * Synchronous clean of all the cache sets. Callers of this function needs ++ * to handle the situation that clean operation was aborted midway. ++ */ ++ ++void eio_clean_all(struct cache_c *dmc) ++{ ++ unsigned long flags = 0; ++ ++ EIO_ASSERT(dmc->mode == CACHE_MODE_WB); ++ for (atomic_set(&dmc->clean_index, 0); ++ (atomic_read(&dmc->clean_index) < ++ (s32)(dmc->size >> dmc->consecutive_shift)) ++ && (dmc->sysctl_active.do_clean & EIO_CLEAN_START) ++ && (atomic64_read(&dmc->nr_dirty) > 0) ++ && (!(dmc->cache_flags & CACHE_FLAGS_SHUTDOWN_INPROG) ++ && !dmc->sysctl_active.fast_remove); ++ atomic_inc(&dmc->clean_index)) { ++ ++ if (unlikely(CACHE_FAILED_IS_SET(dmc))) { ++ pr_err("clean_all: CACHE \"%s\" is in FAILED state.", ++ dmc->cache_name); ++ break; ++ } ++ ++ eio_clean_set(dmc, (index_t)(atomic_read(&dmc->clean_index)), ++ /* whole */ 1, /* force */ 1); ++ } ++ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_active.do_clean &= ~EIO_CLEAN_START; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++} ++ ++/* ++ * Do unconditional clean of a cache. ++ * Useful for a cold enabled writeback cache. ++ */ ++void eio_clean_for_reboot(struct cache_c *dmc) ++{ ++ index_t i; ++ ++ for (i = 0; i < (index_t)(dmc->size >> dmc->consecutive_shift); i++) ++ eio_clean_set(dmc, i, /* whole */ 1, /* force */ 1); ++} ++ ++/* ++ * Used during the partial cache set clean. ++ * Uses reclaim policy(LRU/FIFO) information to ++ * identify the cache blocks that needs cleaning. ++ * The number of such cache blocks is determined ++ * by the high and low thresholds set. ++ */ ++static void ++eio_get_setblks_to_clean(struct cache_c *dmc, index_t set, int *ncleans) ++{ ++ int i = 0; ++ int max_clean; ++ index_t start_index; ++ int nr_writes = 0; ++ ++ *ncleans = 0; ++ ++ max_clean = dmc->cache_sets[set].nr_dirty - ++ ((dmc->sysctl_active.dirty_set_low_threshold * dmc->assoc) / 100); ++ if (max_clean <= 0) ++ /* Nothing to clean */ ++ return; ++ ++ start_index = set * dmc->assoc; ++ ++ /* ++ * Spinlock is not required here, as we assume that we have ++ * taken a write lock on the cache set, when we reach here ++ */ ++ if (dmc->policy_ops == NULL) { ++ /* Scan sequentially in the set and pick blocks to clean */ ++ while ((i < (int)dmc->assoc) && (nr_writes < max_clean)) { ++ if ((EIO_CACHE_STATE_GET(dmc, start_index + i) & ++ (DIRTY | BLOCK_IO_INPROG)) == DIRTY) { ++ EIO_CACHE_STATE_ON(dmc, start_index + i, ++ DISKWRITEINPROG); ++ nr_writes++; ++ } ++ i++; ++ } ++ } else ++ nr_writes = ++ eio_policy_clean_set(dmc->policy_ops, set, max_clean); ++ ++ *ncleans = nr_writes; ++} ++ ++/* Callback function, when synchronous I/O completes */ ++static void eio_sync_io_callback(int error, void *context) ++{ ++ struct sync_io_context *sioc = (struct sync_io_context *)context; ++ ++ if (error) ++ sioc->sio_error = error; ++ up_read(&sioc->sio_lock); ++} ++ ++/* ++ * Setup biovecs for preallocated biovecs per cache set. ++ */ ++ ++struct bio_vec *setup_bio_vecs(struct bio_vec *bvec, index_t block_index, ++ unsigned block_size, unsigned total, ++ unsigned *num_bvecs) ++{ ++ struct bio_vec *data = NULL; ++ index_t iovec_index; ++ ++ switch (block_size) { ++ case BLKSIZE_2K: ++ *num_bvecs = total; ++ iovec_index = block_index; ++ data = &bvec[iovec_index]; ++ break; ++ ++ case BLKSIZE_4K: ++ *num_bvecs = total; ++ iovec_index = block_index; ++ data = &bvec[iovec_index]; ++ break; ++ ++ case BLKSIZE_8K: ++ /* ++ * For 8k data block size, we need 2 bio_vecs ++ * per data block. ++ */ ++ *num_bvecs = total * 2; ++ iovec_index = block_index * 2; ++ data = &bvec[iovec_index]; ++ break; ++ } ++ ++ return data; ++} ++ ++/* Cleans a given cache set */ ++static void ++eio_clean_set(struct cache_c *dmc, index_t set, int whole, int force) ++{ ++ struct eio_io_region where; ++ int error; ++ index_t i; ++ index_t j; ++ index_t start_index; ++ index_t end_index; ++ struct sync_io_context sioc; ++ int ncleans = 0; ++ int alloc_size; ++ struct flash_cacheblock *md_blocks = NULL; ++ unsigned long flags; ++ ++ int pindex, k; ++ index_t blkindex; ++ struct bio_vec *bvecs; ++ unsigned nr_bvecs = 0, total; ++ void *pg_virt_addr[2] = { NULL }; ++ ++ /* Cache is failed mode, do nothing. */ ++ if (unlikely(CACHE_FAILED_IS_SET(dmc))) { ++ pr_debug("clean_set: CACHE \"%s\" is in FAILED state.", ++ dmc->cache_name); ++ goto err_out1; ++ } ++ ++ /* Nothing to clean, if there are no dirty blocks */ ++ if (dmc->cache_sets[set].nr_dirty == 0) ++ goto err_out1; ++ ++ /* If this is not the suitable time to clean, postpone it */ ++ if ((!force) && AUTOCLEAN_THRESHOLD_CROSSED(dmc)) { ++ eio_touch_set_lru(dmc, set); ++ goto err_out1; ++ } ++ ++ /* ++ * 1. Take exclusive lock on the cache set ++ * 2. Verify that there are dirty blocks to clean ++ * 3. Identify the cache blocks to clean ++ * 4. Read the cache blocks data from ssd ++ * 5. Write the cache blocks data to hdd ++ * 6. Update on-disk cache metadata ++ * 7. Update in-core cache metadata ++ */ ++ ++ start_index = set * dmc->assoc; ++ end_index = start_index + dmc->assoc; ++ ++ /* 1. exclusive lock. Let the ongoing writes to finish. Pause new writes */ ++ down_write(&dmc->cache_sets[set].rw_lock); ++ ++ /* 2. Return if there are no dirty blocks to clean */ ++ if (dmc->cache_sets[set].nr_dirty == 0) ++ goto err_out2; ++ ++ /* 3. identify and mark cache blocks to clean */ ++ if (!whole) ++ eio_get_setblks_to_clean(dmc, set, &ncleans); ++ else { ++ for (i = start_index; i < end_index; i++) { ++ if (EIO_CACHE_STATE_GET(dmc, i) == ALREADY_DIRTY) { ++ EIO_CACHE_STATE_SET(dmc, i, CLEAN_INPROG); ++ ncleans++; ++ } ++ } ++ } ++ ++ /* If nothing to clean, return */ ++ if (!ncleans) ++ goto err_out2; ++ ++ /* ++ * From this point onwards, make sure to reset ++ * the clean inflag on cache blocks before returning ++ */ ++ ++ /* 4. read cache set data */ ++ ++ init_rwsem(&sioc.sio_lock); ++ sioc.sio_error = 0; ++ ++ for (i = start_index; i < end_index; i++) { ++ if (EIO_CACHE_STATE_GET(dmc, i) == CLEAN_INPROG) { ++ ++ for (j = i; ((j < end_index) && ++ (EIO_CACHE_STATE_GET(dmc, j) == CLEAN_INPROG)); ++ j++); ++ ++ blkindex = (i - start_index); ++ total = (j - i); ++ ++ /* ++ * Get the correct index and number of bvecs ++ * setup from dmc->clean_dbvecs before issuing i/o. ++ */ ++ bvecs = ++ setup_bio_vecs(dmc->clean_dbvecs, blkindex, ++ dmc->block_size, total, &nr_bvecs); ++ EIO_ASSERT(bvecs != NULL); ++ EIO_ASSERT(nr_bvecs > 0); ++ ++ where.bdev = dmc->cache_dev->bdev; ++ where.sector = ++ (i << dmc->block_shift) + dmc->md_sectors; ++ where.count = total * dmc->block_size; ++ ++ SECTOR_STATS(dmc->eio_stats.ssd_reads, ++ to_bytes(where.count)); ++ down_read(&sioc.sio_lock); ++ error = ++ eio_io_async_bvec(dmc, &where, READ, bvecs, ++ nr_bvecs, eio_sync_io_callback, ++ &sioc, 0); ++ if (error) { ++ sioc.sio_error = error; ++ up_read(&sioc.sio_lock); ++ } ++ ++ bvecs = NULL; ++ i = j; ++ } ++ } ++ /* ++ * In above for loop, submit all READ I/Os to SSD ++ * and unplug the device for immediate submission to ++ * underlying device driver. ++ */ ++ eio_unplug_cache_device(dmc); ++ ++ /* wait for all I/Os to complete and release sync lock */ ++ down_write(&sioc.sio_lock); ++ up_write(&sioc.sio_lock); ++ ++ error = sioc.sio_error; ++ if (error) ++ goto err_out3; ++ ++ /* 5. write to hdd */ ++ /* ++ * While writing the data to HDD, explicitly enable ++ * BIO_RW_SYNC flag to hint higher priority for these ++ * I/Os. ++ */ ++ for (i = start_index; i < end_index; i++) { ++ if (EIO_CACHE_STATE_GET(dmc, i) == CLEAN_INPROG) { ++ ++ blkindex = (i - start_index); ++ total = 1; ++ ++ bvecs = ++ setup_bio_vecs(dmc->clean_dbvecs, blkindex, ++ dmc->block_size, total, &nr_bvecs); ++ EIO_ASSERT(bvecs != NULL); ++ EIO_ASSERT(nr_bvecs > 0); ++ ++ where.bdev = dmc->disk_dev->bdev; ++ where.sector = EIO_DBN_GET(dmc, i); ++ where.count = dmc->block_size; ++ ++ SECTOR_STATS(dmc->eio_stats.disk_writes, ++ to_bytes(where.count)); ++ down_read(&sioc.sio_lock); ++ error = eio_io_async_bvec(dmc, &where, WRITE | REQ_SYNC, ++ bvecs, nr_bvecs, ++ eio_sync_io_callback, &sioc, ++ 1); ++ ++ if (error) { ++ sioc.sio_error = error; ++ up_read(&sioc.sio_lock); ++ } ++ bvecs = NULL; ++ } ++ } ++ ++ /* wait for all I/Os to complete and release sync lock */ ++ down_write(&sioc.sio_lock); ++ up_write(&sioc.sio_lock); ++ ++ error = sioc.sio_error; ++ if (error) ++ goto err_out3; ++ ++ /* 6. update on-disk cache metadata */ ++ ++ /* TBD. Do we have to consider sector alignment here ? */ ++ ++ /* ++ * md_size = dmc->assoc * sizeof(struct flash_cacheblock); ++ * Currently, md_size is 8192 bytes, mdpage_count is 2 pages maximum. ++ */ ++ ++ EIO_ASSERT(dmc->mdpage_count <= 2); ++ for (k = 0; k < dmc->mdpage_count; k++) ++ pg_virt_addr[k] = kmap(dmc->clean_mdpages[k]); ++ ++ alloc_size = dmc->assoc * sizeof(struct flash_cacheblock); ++ pindex = 0; ++ md_blocks = (struct flash_cacheblock *)pg_virt_addr[pindex]; ++ k = MD_BLOCKS_PER_PAGE; ++ ++ for (i = start_index; i < end_index; i++) { ++ ++ md_blocks->dbn = cpu_to_le64(EIO_DBN_GET(dmc, i)); ++ ++ if (EIO_CACHE_STATE_GET(dmc, i) == CLEAN_INPROG) ++ md_blocks->cache_state = cpu_to_le64(INVALID); ++ else if (EIO_CACHE_STATE_GET(dmc, i) == ALREADY_DIRTY) ++ md_blocks->cache_state = cpu_to_le64((VALID | DIRTY)); ++ else ++ md_blocks->cache_state = cpu_to_le64(INVALID); ++ ++ /* This was missing earlier. */ ++ md_blocks++; ++ k--; ++ ++ if (k == 0) { ++ md_blocks = ++ (struct flash_cacheblock *)pg_virt_addr[++pindex]; ++ k = MD_BLOCKS_PER_PAGE; ++ } ++ } ++ ++ for (k = 0; k < dmc->mdpage_count; k++) ++ kunmap(dmc->clean_mdpages[k]); ++ ++ where.bdev = dmc->cache_dev->bdev; ++ where.sector = dmc->md_start_sect + INDEX_TO_MD_SECTOR(start_index); ++ where.count = eio_to_sector(alloc_size); ++ error = ++ eio_io_sync_pages(dmc, &where, WRITE, dmc->clean_mdpages, ++ dmc->mdpage_count); ++ ++ if (error) ++ goto err_out3; ++ ++err_out3: ++ ++ /* ++ * 7. update in-core cache metadata for clean_inprog blocks. ++ * If there was an error, set them back to ALREADY_DIRTY ++ * If no error, set them to VALID ++ */ ++ for (i = start_index; i < end_index; i++) { ++ if (EIO_CACHE_STATE_GET(dmc, i) == CLEAN_INPROG) { ++ if (error) ++ EIO_CACHE_STATE_SET(dmc, i, ALREADY_DIRTY); ++ else { ++ EIO_CACHE_STATE_SET(dmc, i, VALID); ++ EIO_ASSERT(dmc->cache_sets[set].nr_dirty > 0); ++ dmc->cache_sets[set].nr_dirty--; ++ atomic64_dec(&dmc->nr_dirty); ++ } ++ } ++ } ++ ++err_out2: ++ ++ up_write(&dmc->cache_sets[set].rw_lock); ++ ++err_out1: ++ ++ /* Reset clean flags on the set */ ++ ++ if (!force) { ++ spin_lock_irqsave(&dmc->cache_sets[set].cs_lock, flags); ++ dmc->cache_sets[set].flags &= ++ ~(SETFLAG_CLEAN_INPROG | SETFLAG_CLEAN_WHOLE); ++ spin_unlock_irqrestore(&dmc->cache_sets[set].cs_lock, flags); ++ } ++ ++ if (dmc->cache_sets[set].nr_dirty) ++ /* ++ * Lru touch the set, so that it can be picked ++ * up for whole set clean by clean thread later ++ */ ++ eio_touch_set_lru(dmc, set); ++ ++ return; ++} ++ ++/* ++ * Enqueues the dirty sets for clean, which had got dirtied long ++ * time back(aged). User tunable values to determine if a set has aged ++ */ ++void eio_clean_aged_sets(struct work_struct *work) ++{ ++ struct cache_c *dmc; ++ unsigned long flags = 0; ++ index_t set_index; ++ u_int64_t set_time; ++ u_int64_t cur_time; ++ ++ dmc = container_of(work, struct cache_c, clean_aged_sets_work.work); ++ ++ /* ++ * In FAILED state, dont schedule cleaning of sets. ++ */ ++ if (unlikely(CACHE_FAILED_IS_SET(dmc))) { ++ pr_debug("clean_aged_sets: Cache \"%s\" is in failed mode.\n", ++ dmc->cache_name); ++ /* ++ * This is to make sure that this thread is rescheduled ++ * once CACHE is ACTIVE again. ++ */ ++ spin_lock_irqsave(&dmc->dirty_set_lru_lock, flags); ++ dmc->is_clean_aged_sets_sched = 0; ++ spin_unlock_irqrestore(&dmc->dirty_set_lru_lock, flags); ++ ++ return; ++ } ++ ++ cur_time = jiffies; ++ ++ /* Use the set LRU list to pick up the most aged sets. */ ++ spin_lock_irqsave(&dmc->dirty_set_lru_lock, flags); ++ do { ++ lru_read_head(dmc->dirty_set_lru, &set_index, &set_time); ++ if (set_index == LRU_NULL) ++ break; ++ ++ if ((EIO_DIV((cur_time - set_time), HZ)) < ++ (dmc->sysctl_active.time_based_clean_interval * 60)) ++ break; ++ lru_rem(dmc->dirty_set_lru, set_index); ++ ++ if (dmc->cache_sets[set_index].nr_dirty > 0) { ++ spin_unlock_irqrestore(&dmc->dirty_set_lru_lock, flags); ++ eio_addto_cleanq(dmc, set_index, 1); ++ spin_lock_irqsave(&dmc->dirty_set_lru_lock, flags); ++ } ++ } while (1); ++ spin_unlock_irqrestore(&dmc->dirty_set_lru_lock, flags); ++ ++ /* Re-schedule the aged set clean, unless the clean has to stop now */ ++ ++ if (dmc->sysctl_active.time_based_clean_interval == 0) ++ goto out; ++ ++ schedule_delayed_work(&dmc->clean_aged_sets_work, ++ dmc->sysctl_active.time_based_clean_interval * ++ 60 * HZ); ++out: ++ return; ++} ++ ++/* Move the given set at the head of the set LRU list */ ++void eio_touch_set_lru(struct cache_c *dmc, index_t set) ++{ ++ u_int64_t systime; ++ unsigned long flags; ++ ++ systime = jiffies; ++ spin_lock_irqsave(&dmc->dirty_set_lru_lock, flags); ++ lru_touch(dmc->dirty_set_lru, set, systime); ++ ++ if ((dmc->sysctl_active.time_based_clean_interval > 0) && ++ (dmc->is_clean_aged_sets_sched == 0)) { ++ schedule_delayed_work(&dmc->clean_aged_sets_work, ++ dmc->sysctl_active. ++ time_based_clean_interval * 60 * HZ); ++ dmc->is_clean_aged_sets_sched = 1; ++ } ++ ++ spin_unlock_irqrestore(&dmc->dirty_set_lru_lock, flags); ++} +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_mem.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_mem.c +--- linux-3.10.30/drivers/block/enhanceio/eio_mem.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_mem.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,236 @@ ++/* ++ * eio_mem.c ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * ++ * 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; under 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, see . ++ */ ++ ++#include "eio.h" ++ ++#define SECTORS_PER_SET (dmc->assoc * dmc->block_size) ++#define SECTORS_PER_SET_SHIFT (dmc->consecutive_shift + dmc->block_shift) ++#define SECTORS_PER_SET_MASK (SECTORS_PER_SET - 1) ++ ++#define EIO_DBN_TO_SET(dmc, dbn, set_number, wrapped) do { \ ++ u_int64_t value; \ ++ u_int64_t mid_i; \ ++ value = (dbn) >> SECTORS_PER_SET_SHIFT; \ ++ mid_i = (value) & (dmc)->num_sets_mask; \ ++ if (mid_i >= (dmc)->num_sets) { \ ++ (wrapped) = 1; \ ++ (set_number) = mid_i - (dmc)->num_sets; \ ++ } else { \ ++ (wrapped) = 0; \ ++ (set_number) = mid_i; \ ++ } \ ++} while (0) ++ ++/* ++ * eio_mem_init ++ */ ++int eio_mem_init(struct cache_c *dmc) ++{ ++ u_int32_t lsb_bits; ++ u_int32_t msb_bits_24; /* most significant bits in shrunk dbn */ ++ u_int64_t max_dbn; ++ u_int64_t num_sets_64; ++ ++ /* ++ * Sanity check the number of sets. ++ */ ++ num_sets_64 = EIO_DIV(dmc->size, dmc->assoc); ++ if (num_sets_64 > UINT_MAX) { ++ pr_err("Number of cache sets (%lu) greater than maximum" \ ++ "allowed (%u)", ++ (long unsigned int)num_sets_64, UINT_MAX); ++ return -1; ++ } ++ ++ /* ++ * Find the number of bits required to encode the set number and ++ * its corresponding mask value. ++ */ ++ dmc->num_sets = (u_int32_t)num_sets_64; ++ for (dmc->num_sets_bits = 0; (dmc->num_sets >> dmc->num_sets_bits); ++ dmc->num_sets_bits++); ++ ++ dmc->num_sets_mask = ULLONG_MAX >> (64 - dmc->num_sets_bits); ++ ++ /* ++ * If we don't have at least 16 bits to save, ++ * we can't use small metadata. ++ */ ++ if (dmc->num_sets_bits < 16) { ++ dmc->cache_flags |= CACHE_FLAGS_MD8; ++ pr_info("Not enough sets to use small metadata"); ++ return 1; ++ } ++ ++ /* ++ * Now compute the largest sector number that we can shrink; then see ++ * if the source volume is smaller. ++ */ ++ lsb_bits = dmc->consecutive_shift + dmc->block_shift; ++ msb_bits_24 = 24 - 1 - lsb_bits; /* 1 for wrapped bit */ ++ max_dbn = ++ ((u_int64_t)1) << (msb_bits_24 + dmc->num_sets_bits + lsb_bits); ++ if (eio_to_sector(eio_get_device_size(dmc->disk_dev)) > max_dbn) { ++ dmc->cache_flags |= CACHE_FLAGS_MD8; ++ pr_info("Source volume too big to use small metadata"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * eio_hash_block ++ */ ++u_int32_t eio_hash_block(struct cache_c *dmc, sector_t dbn) ++{ ++ int wrapped; ++ u_int64_t set_number; ++ ++ EIO_DBN_TO_SET(dmc, dbn, set_number, wrapped); ++ EIO_ASSERT(set_number < dmc->num_sets); ++ ++ return (u_int32_t)set_number; ++} ++ ++/* ++ * eio_shrink_dbn ++ * ++ * Shrink a 5-byte "dbn" into a 3-byte "dbn" by eliminating 16 lower bits ++ * of the set number this "dbn" belongs to. ++ */ ++unsigned int eio_shrink_dbn(struct cache_c *dmc, sector_t dbn) ++{ ++ u_int32_t dbn_24; ++ sector_t lsb; ++ sector_t wrapped; ++ sector_t msb; ++ sector_t set_number; ++ ++ EIO_ASSERT(!EIO_MD8(dmc)); ++ if (unlikely(dbn == 0)) ++ return 0; ++ ++ lsb = dbn & SECTORS_PER_SET_MASK; ++ EIO_DBN_TO_SET(dmc, dbn, set_number, wrapped); ++ msb = dbn >> (dmc->num_sets_bits + SECTORS_PER_SET_SHIFT); ++ dbn_24 = ++ (unsigned int)(lsb | (wrapped << SECTORS_PER_SET_SHIFT) | ++ (msb << (SECTORS_PER_SET_SHIFT + 1))); ++ ++ return dbn_24; ++} ++ ++/* ++ * eio_expand_dbn ++ * ++ * Expand a 3-byte "dbn" into a 5-byte "dbn" by adding 16 lower bits ++ * of the set number this "dbn" belongs to. ++ */ ++sector_t eio_expand_dbn(struct cache_c *dmc, u_int64_t index) ++{ ++ u_int32_t dbn_24; ++ u_int64_t set_number; ++ sector_t lsb; ++ sector_t msb; ++ sector_t dbn_40; ++ ++ EIO_ASSERT(!EIO_MD8(dmc)); ++ /* ++ * Expanding "dbn" zero? ++ */ ++ if (index == dmc->index_zero && ++ dmc->index_zero < (u_int64_t)dmc->assoc) ++ return 0; ++ ++ dbn_24 = dmc->cache[index].md4_u.u_i_md4 & EIO_MD4_DBN_MASK; ++ if (dbn_24 == 0 && EIO_CACHE_STATE_GET(dmc, index) == INVALID) ++ return (sector_t)0; ++ ++ set_number = EIO_DIV(index, dmc->assoc); ++ lsb = dbn_24 & SECTORS_PER_SET_MASK; ++ msb = dbn_24 >> (SECTORS_PER_SET_SHIFT + 1); /* 1 for wrapped */ ++ /* had we wrapped? */ ++ if ((dbn_24 & SECTORS_PER_SET) != 0) { ++ dbn_40 = msb << (dmc->num_sets_bits + SECTORS_PER_SET_SHIFT); ++ dbn_40 |= (set_number + dmc->num_sets) << SECTORS_PER_SET_SHIFT; ++ dbn_40 |= lsb; ++ } else { ++ dbn_40 = msb << (dmc->num_sets_bits + SECTORS_PER_SET_SHIFT); ++ dbn_40 |= set_number << SECTORS_PER_SET_SHIFT; ++ dbn_40 |= lsb; ++ } ++ EIO_ASSERT(unlikely(dbn_40 < EIO_MAX_SECTOR)); ++ ++ return (sector_t)dbn_40; ++} ++EXPORT_SYMBOL(eio_expand_dbn); ++ ++/* ++ * eio_invalidate_md ++ */ ++void eio_invalidate_md(struct cache_c *dmc, u_int64_t index) ++{ ++ ++ if (EIO_MD8(dmc)) ++ dmc->cache_md8[index].md8_u.u_i_md8 = EIO_MD8_INVALID; ++ else ++ dmc->cache[index].md4_u.u_i_md4 = EIO_MD4_INVALID; ++} ++ ++/* ++ * eio_md4_dbn_set ++ */ ++void eio_md4_dbn_set(struct cache_c *dmc, u_int64_t index, u_int32_t dbn_24) ++{ ++ ++ EIO_ASSERT((dbn_24 & ~EIO_MD4_DBN_MASK) == 0); ++ ++ /* retain "cache_state" */ ++ dmc->cache[index].md4_u.u_i_md4 &= ~EIO_MD4_DBN_MASK; ++ dmc->cache[index].md4_u.u_i_md4 |= dbn_24; ++ ++ /* XXX excessive debugging */ ++ if (dmc->index_zero < (u_int64_t)dmc->assoc && /* sector 0 cached */ ++ index == dmc->index_zero && /* we're accessing sector 0 */ ++ dbn_24 != 0) /* we're replacing sector 0 */ ++ dmc->index_zero = dmc->assoc; ++} ++ ++/* ++ * eio_md8_dbn_set ++ */ ++void eio_md8_dbn_set(struct cache_c *dmc, u_int64_t index, sector_t dbn) ++{ ++ ++ EIO_ASSERT((dbn & ~EIO_MD8_DBN_MASK) == 0); ++ ++ /* retain "cache_state" */ ++ dmc->cache_md8[index].md8_u.u_i_md8 &= ~EIO_MD8_DBN_MASK; ++ dmc->cache_md8[index].md8_u.u_i_md8 |= dbn; ++ ++ /* XXX excessive debugging */ ++ if (dmc->index_zero < (u_int64_t)dmc->assoc && /* sector 0 cached */ ++ index == dmc->index_zero && /* we're accessing sector 0 */ ++ dbn != 0) /* we're replacing sector 0 */ ++ dmc->index_zero = dmc->assoc; ++} +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_policy.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_policy.c +--- linux-3.10.30/drivers/block/enhanceio/eio_policy.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_policy.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,146 @@ ++/* ++ * eio_policy.c ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * ++ * 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; under 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, see . ++ */ ++ ++#include "eio.h" ++ ++LIST_HEAD(eio_policy_list); ++ ++int eio_register_policy(struct eio_policy_header *new_policy) ++{ ++ struct list_head *ptr; ++ struct eio_policy_header *curr; ++ ++ list_for_each(ptr, &eio_policy_list) { ++ curr = list_entry(ptr, struct eio_policy_header, sph_list); ++ if (curr->sph_name == new_policy->sph_name) ++ return 1; ++ } ++ list_add_tail(&new_policy->sph_list, &eio_policy_list); ++ ++ pr_info("register_policy: policy %d added", new_policy->sph_name); ++ ++ return 0; ++} ++EXPORT_SYMBOL(eio_register_policy); ++ ++int eio_unregister_policy(struct eio_policy_header *p_ops) ++{ ++ struct list_head *ptr; ++ struct eio_policy_header *curr; ++ ++ list_for_each(ptr, &eio_policy_list) { ++ curr = list_entry(ptr, struct eio_policy_header, sph_list); ++ if (curr->sph_name == p_ops->sph_name) { ++ list_del(&curr->sph_list); ++ pr_info("unregister_policy: policy %d removed", ++ (int)p_ops->sph_name); ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++EXPORT_SYMBOL(eio_unregister_policy); ++ ++struct eio_policy *eio_get_policy(int policy) ++{ ++ struct list_head *ptr; ++ struct eio_policy_header *curr; ++ ++ list_for_each(ptr, &eio_policy_list) { ++ curr = list_entry(ptr, struct eio_policy_header, sph_list); ++ if (curr->sph_name == policy) { ++ pr_info("get_policy: policy %d found", policy); ++ return curr->sph_instance_init(); ++ } ++ } ++ pr_info("get_policy: cannot find policy %d", policy); ++ ++ return NULL; ++} ++ ++/* ++ * Decrement the reference count of the policy specific module ++ * and any other cleanup that is required when an instance of a ++ * policy is no longer required. ++ */ ++void eio_put_policy(struct eio_policy *p_ops) ++{ ++ ++ if (p_ops == NULL) { ++ pr_err("put_policy: Cannot decrement reference" \ ++ "count of NULL policy"); ++ return; ++ } ++ p_ops->sp_repl_exit(); ++} ++ ++/* ++ * Wrappers for policy specific functions. These default to nothing if the ++ * default policy is being used. ++ */ ++int eio_repl_sets_init(struct eio_policy *p_ops) ++{ ++ ++ return (p_ops && ++ p_ops->sp_repl_sets_init) ? p_ops->sp_repl_sets_init(p_ops) : 0; ++} ++ ++int eio_repl_blk_init(struct eio_policy *p_ops) ++{ ++ ++ return (p_ops && ++ p_ops->sp_repl_blk_init) ? p_ops->sp_repl_blk_init(p_ops) : 0; ++} ++ ++void ++eio_find_reclaim_dbn(struct eio_policy *p_ops, ++ index_t start_index, index_t *index) ++{ ++ ++ p_ops->sp_find_reclaim_dbn(p_ops, start_index, index); ++} ++ ++int eio_policy_clean_set(struct eio_policy *p_ops, index_t set, int to_clean) ++{ ++ ++ return p_ops->sp_clean_set(p_ops, set, to_clean); ++} ++ ++/* ++ * LRU Specific functions ++ */ ++void eio_policy_lru_pushblks(struct eio_policy *p_ops) ++{ ++ ++ if (p_ops && p_ops->sp_name == CACHE_REPL_LRU) ++ p_ops->sp_policy.lru->sl_lru_pushblks(p_ops); ++} ++ ++void ++eio_policy_reclaim_lru_movetail(struct cache_c *dmc, index_t i, ++ struct eio_policy *p_ops) ++{ ++ ++ if (p_ops && p_ops->sp_name == CACHE_REPL_LRU) ++ p_ops->sp_policy.lru->sl_reclaim_lru_movetail(dmc, i, p_ops); ++} +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_policy.h linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_policy.h +--- linux-3.10.30/drivers/block/enhanceio/eio_policy.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_policy.h 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,105 @@ ++/* ++ * eio_policy.h ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * ++ * 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; under 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, see . ++ */ ++ ++#ifndef EIO_POLICY_H ++#define EIO_POLICY_H ++ ++#include ++#include ++ ++/* ++ * Defines for policy types (EIO_REPL_XXX are in eio.h ++ * so that user space utilties can use those definitions. ++ */ ++ ++/* ++ * The LRU pointers are maintained as set-relative offsets, instead of ++ * pointers. This enables us to store the LRU pointers per cacheblock ++ * using 4 bytes instead of 16 bytes. The upshot of this is that we ++ * are required to clamp the associativity at an 8K max. ++ * ++ * XXX - The above comment is from the original code. Looks like an error, ++ * maximum associativity should be 32K (2^15) and not 8K. ++ */ ++#define EIO_MAX_ASSOC 8192 ++#define EIO_LRU_NULL 0xFFFF ++ ++/* Declerations to keep the compiler happy */ ++struct cache_c; ++struct eio_policy; ++struct eio_lru; ++ ++/* LRU specific data structures and functions */ ++struct eio_lru { ++ void (*sl_lru_pushblks)(struct eio_policy *); ++ void (*sl_reclaim_lru_movetail)(struct cache_c *, index_t, ++ struct eio_policy *); ++}; ++ ++/* Function prototypes for LRU wrappers in eio_policy.c */ ++void eio_policy_lru_pushblks(struct eio_policy *); ++void eio_policy_reclaim_lru_movetail(struct cache_c *, index_t, ++ struct eio_policy *); ++ ++/* ++ * Context that captures the cache block replacement policy. ++ * There is one instance of this struct per dmc (cache) ++ */ ++struct eio_policy { ++ int sp_name; ++ union { ++ struct eio_lru *lru; ++ } sp_policy; ++ int (*sp_repl_init)(struct cache_c *); ++ void (*sp_repl_exit)(void); ++ int (*sp_repl_sets_init)(struct eio_policy *); ++ int (*sp_repl_blk_init)(struct eio_policy *); ++ void (*sp_find_reclaim_dbn)(struct eio_policy *, ++ index_t start_index, index_t *index); ++ int (*sp_clean_set)(struct eio_policy *, index_t set, int); ++ struct cache_c *sp_dmc; ++}; ++ ++/* ++ * List of registered policies. There is one instance ++ * of this structure per policy type. ++ */ ++struct eio_policy_header { ++ int sph_name; ++ struct eio_policy *(*sph_instance_init)(void); ++ struct list_head sph_list; ++}; ++ ++/* Prototypes of generic functions in eio_policy */ ++int *eio_repl_init(struct cache_c *); ++int eio_repl_sets_init(struct eio_policy *); ++int eio_repl_blk_init(struct eio_policy *); ++void eio_find_reclaim_dbn(struct eio_policy *, index_t start_index, ++ index_t *index); ++int eio_policy_clean_set(struct eio_policy *, index_t, int); ++ ++int eio_register_policy(struct eio_policy_header *); ++int eio_unregister_policy(struct eio_policy_header *); ++struct eio_policy *eio_get_policy(int); ++void eio_put_policy(struct eio_policy *); ++ ++#endif /* EIO_POLICY_H */ +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_procfs.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_procfs.c +--- linux-3.10.30/drivers/block/enhanceio/eio_procfs.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_procfs.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,1932 @@ ++/* ++ * eio_procfs.c ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * ++ * Copyright 2010 Facebook, Inc. ++ * Author: Mohan Srinivasan (mohan@facebook.com) ++ * ++ * Based on DM-Cache: ++ * Copyright (C) International Business Machines Corp., 2006 ++ * Author: Ming Zhao (mingzhao@ufl.edu) ++ * ++ * 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; under 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, see . ++ */ ++ ++#include "eio.h" ++#define EIO_RELEASE "ENHANCEIO" ++ ++#ifndef ENHANCEIO_GIT_COMMIT_HASH ++#define ENHANCEIO_GIT_COMMIT_HASH "unknown-git-version" ++#endif /* !ENHANCEIO_GIT_COMMIT_HASH */ ++ ++int eio_version_query(size_t buf_sz, char *bufp) ++{ ++ if (unlikely(buf_sz == 0) || unlikely(bufp == NULL)) ++ return -EINVAL; ++ snprintf(bufp, buf_sz, "EnhanceIO Version: %s %s (checksum disabled)", ++ EIO_RELEASE, ENHANCEIO_GIT_COMMIT_HASH); ++ ++ bufp[buf_sz - 1] = '\0'; ++ ++ return 0; ++} ++ ++static struct sysctl_table_dir *sysctl_handle_dir; ++ ++/* ++ * eio_zerostats_sysctl ++ */ ++static int ++eio_zerostats_sysctl(ctl_table *table, int write, void __user *buffer, ++ size_t *length, loff_t *ppos) ++{ ++ struct cache_c *dmc = (struct cache_c *)table->extra1; ++ long long cached_blocks; ++ unsigned long flags = 0; ++ ++ /* fetch the new tunable value or post the existing value */ ++ ++ if (!write) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_pending.zerostats = dmc->sysctl_active.zerostats; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ } ++ ++ proc_dointvec(table, write, buffer, length, ppos); ++ ++ /* do write processing */ ++ ++ if (write) { ++ /* do sanity check */ ++ ++ if ((dmc->sysctl_pending.zerostats != 0) && ++ (dmc->sysctl_pending.zerostats != 1)) { ++ pr_err ++ ("0 or 1 are the only valid values for zerostats"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.zerostats == ++ dmc->sysctl_active.zerostats) ++ /* same value. Nothing to work */ ++ return 0; ++ ++ /* Copy to active */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_active.zerostats = dmc->sysctl_pending.zerostats; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ /* apply the new tunable value */ ++ ++ if (dmc->sysctl_active.zerostats) { ++ /* ++ * The number of cached blocks should not be zero'd since ++ * these blocks are already on cache dev. Making this zero ++ * may lead to -ve count during block invalidate, and also, ++ * incorrectly indicating how much data is cached. ++ * ++ * TODO - should have used an spinlock, but existing spinlocks ++ * are inadequate to fully protect this ++ */ ++ ++ cached_blocks = ++ atomic64_read(&dmc->eio_stats.cached_blocks); ++ memset(&dmc->eio_stats, 0, sizeof(struct eio_stats)); ++ atomic64_set(&dmc->eio_stats.cached_blocks, ++ cached_blocks); ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * eio_mem_limit_pct_sysctl ++ * - sets the eio sysctl mem_limit_pct value ++ */ ++static int ++eio_mem_limit_pct_sysctl(ctl_table *table, int write, void __user *buffer, ++ size_t *length, loff_t *ppos) ++{ ++ struct cache_c *dmc = (struct cache_c *)table->extra1; ++ unsigned long flags = 0; ++ ++ /* fetch the new tunable value or post the existing value */ ++ ++ if (!write) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_pending.mem_limit_pct = ++ dmc->sysctl_active.mem_limit_pct; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ } ++ ++ proc_dointvec(table, write, buffer, length, ppos); ++ ++ /* do write processing */ ++ ++ if (write) { ++ /* do sanity check */ ++ if ((dmc->sysctl_pending.mem_limit_pct < 0) || ++ (dmc->sysctl_pending.mem_limit_pct > 100)) { ++ pr_err ++ ("only valid percents are [0 - 100] for mem_limit_pct"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.mem_limit_pct == ++ dmc->sysctl_active.mem_limit_pct) ++ /* same value. Nothing more to do */ ++ return 0; ++ ++ /* Copy to active */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_active.mem_limit_pct = ++ dmc->sysctl_pending.mem_limit_pct; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ } ++ ++ return 0; ++} ++ ++/* ++ * eio_clean_sysctl ++ */ ++static int ++eio_clean_sysctl(ctl_table *table, int write, void __user *buffer, ++ size_t *length, loff_t *ppos) ++{ ++ struct cache_c *dmc = (struct cache_c *)table->extra1; ++ unsigned long flags = 0; ++ ++ /* fetch the new tunable value or post the existing value */ ++ ++ if (!write) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_pending.do_clean = dmc->sysctl_active.do_clean; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ } ++ ++ proc_dointvec(table, write, buffer, length, ppos); ++ ++ /* do write processing */ ++ ++ if (write) { ++ /* Do sanity check */ ++ ++ if (dmc->mode != CACHE_MODE_WB) { ++ /* do_clean is only valid for writeback cache */ ++ pr_err("do_clean is only valid for writeback cache"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending. ++ do_clean & ~(EIO_CLEAN_START | EIO_CLEAN_KEEP)) { ++ pr_err ++ ("do_clean should be either clean start/clean keep"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.do_clean == dmc->sysctl_active.do_clean) ++ /* New and old values are same. No work required */ ++ return 0; ++ ++ /* Copy to active and apply the new tunable value */ ++ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ ++ if (dmc->cache_flags & CACHE_FLAGS_MOD_INPROG) { ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ pr_err ++ ("do_clean called while cache modification in progress"); ++ return -EBUSY; ++ } else { ++ dmc->sysctl_active.do_clean = ++ dmc->sysctl_pending.do_clean; ++ ++ if (dmc->sysctl_active.do_clean) { ++ atomic_set(&dmc->clean_index, 0); ++ dmc->sysctl_active.do_clean |= EIO_CLEAN_START; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ flags); ++ ++ /* ++ * Wake up the clean thread. ++ * Sync thread will do the clean and once complete ++ * will reset the clean_start flag. ++ * The clean_keep flag will remain set(unless reset ++ * by user) and will prevent new I/Os from making ++ * the blocks dirty. ++ */ ++ ++ spin_lock_irqsave(&dmc->clean_sl, flags); ++ EIO_SET_EVENT_AND_UNLOCK(&dmc->clean_event, ++ &dmc->clean_sl, flags); ++ } else ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ flags); ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * eio_dirty_high_threshold_sysctl ++ */ ++static int ++eio_dirty_high_threshold_sysctl(ctl_table *table, int write, ++ void __user *buffer, size_t *length, ++ loff_t *ppos) ++{ ++ struct cache_c *dmc = (struct cache_c *)table->extra1; ++ unsigned long flags = 0; ++ ++ /* fetch the new tunable value or post the existing value */ ++ ++ if (!write) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_pending.dirty_high_threshold = ++ dmc->sysctl_active.dirty_high_threshold; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ } ++ ++ proc_dointvec(table, write, buffer, length, ppos); ++ ++ /* do write processing */ ++ ++ if (write) { ++ int error; ++ uint32_t old_value; ++ ++ /* do sanity check */ ++ ++ if (dmc->mode != CACHE_MODE_WB) { ++ pr_err ++ ("dirty_high_threshold is only valid for writeback cache"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_high_threshold > 100) { ++ pr_err ++ ("dirty_high_threshold percentage should be [0 - 100]"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_high_threshold < ++ dmc->sysctl_active.dirty_low_threshold) { ++ pr_err ++ ("dirty high shouldn't be less than dirty low threshold"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_high_threshold == ++ dmc->sysctl_active.dirty_high_threshold) ++ /* new is same as old value. No need to take any action */ ++ return 0; ++ ++ /* update the active value with the new tunable value */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ old_value = dmc->sysctl_active.dirty_high_threshold; ++ dmc->sysctl_active.dirty_high_threshold = ++ dmc->sysctl_pending.dirty_high_threshold; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ /* apply the new tunable value */ ++ ++ /* Store the change persistently */ ++ error = eio_sb_store(dmc); ++ if (error) { ++ /* restore back the old value and return error */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_active.dirty_high_threshold = old_value; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ return error; ++ } ++ ++ /* if we reduced the high threshold, check if we require cache cleaning */ ++ if (old_value > dmc->sysctl_active.dirty_high_threshold) ++ eio_comply_dirty_thresholds(dmc, -1); ++ } ++ ++ return 0; ++} ++ ++/* ++ * eio_dirty_low_threshold_sysctl ++ */ ++static int ++eio_dirty_low_threshold_sysctl(ctl_table *table, int write, ++ void __user *buffer, size_t *length, ++ loff_t *ppos) ++{ ++ struct cache_c *dmc = (struct cache_c *)table->extra1; ++ unsigned long flags = 0; ++ ++ /* fetch the new tunable value or post the existing value */ ++ ++ if (!write) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_pending.dirty_low_threshold = ++ dmc->sysctl_active.dirty_low_threshold; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ } ++ ++ proc_dointvec(table, write, buffer, length, ppos); ++ ++ /* do write processing */ ++ ++ if (write) { ++ int error; ++ uint32_t old_value; ++ ++ /* do sanity check */ ++ ++ if (dmc->mode != CACHE_MODE_WB) { ++ pr_err ++ ("dirty_low_threshold is valid for only writeback cache"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_low_threshold > 100) { ++ pr_err ++ ("dirty_low_threshold percentage should be [0 - 100]"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_low_threshold > ++ dmc->sysctl_active.dirty_high_threshold) { ++ pr_err ++ ("dirty low shouldn't be more than dirty high threshold"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_low_threshold == ++ dmc->sysctl_active.dirty_low_threshold) ++ /* new is same as old value. No need to take any action */ ++ return 0; ++ ++ /* update the active value with the new tunable value */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ old_value = dmc->sysctl_active.dirty_low_threshold; ++ dmc->sysctl_active.dirty_low_threshold = ++ dmc->sysctl_pending.dirty_low_threshold; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ /* apply the new tunable value */ ++ ++ /* Store the change persistently */ ++ error = eio_sb_store(dmc); ++ if (error) { ++ /* restore back the old value and return error */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_active.dirty_low_threshold = old_value; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ return error; ++ } ++ ++ if (old_value > dmc->sysctl_active.dirty_low_threshold) ++ /* ++ * Although the low threshold set shouldn't trigger new cleans, ++ * but because we set the tunables one at a time from user mode, ++ * it is possible that the high threshold value triggering clean ++ * did not happen and should get triggered now that the low value ++ * has been changed, so we are calling the comply function here ++ */ ++ eio_comply_dirty_thresholds(dmc, -1); ++ } ++ ++ return 0; ++} ++ ++/* ++ * eio_dirty_set_high_threshold_sysctl ++ */ ++static int ++eio_dirty_set_high_threshold_sysctl(ctl_table *table, int write, ++ void __user *buffer, size_t *length, ++ loff_t *ppos) ++{ ++ struct cache_c *dmc = (struct cache_c *)table->extra1; ++ unsigned long flags = 0; ++ ++ /* fetch the new tunable value or post the existing value */ ++ ++ if (!write) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_pending.dirty_set_high_threshold = ++ dmc->sysctl_active.dirty_set_high_threshold; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ } ++ ++ proc_dointvec(table, write, buffer, length, ppos); ++ ++ /* do write processing */ ++ ++ if (write) { ++ int error; ++ uint32_t old_value; ++ u_int64_t i; ++ ++ /* do sanity check */ ++ ++ if (dmc->mode != CACHE_MODE_WB) { ++ pr_err ++ ("dirty_set_high_threshold is valid only for writeback cache"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_set_high_threshold > 100) { ++ pr_err ++ ("dirty_set_high_threshold percentage should be [0 - 100]"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_set_high_threshold < ++ dmc->sysctl_active.dirty_set_low_threshold) { ++ pr_err ++ ("dirty_set_high_threshold shouldn't be less than dirty low threshold"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_set_high_threshold == ++ dmc->sysctl_active.dirty_set_high_threshold) ++ /* new is same as old value. No need to take any action */ ++ return 0; ++ ++ /* update the active value with the new tunable value */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ old_value = dmc->sysctl_active.dirty_set_high_threshold; ++ dmc->sysctl_active.dirty_set_high_threshold = ++ dmc->sysctl_pending.dirty_set_high_threshold; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ /* apply the new tunable value */ ++ ++ /* Store the change persistently */ ++ error = eio_sb_store(dmc); ++ if (error) { ++ /* restore back the old value and return error */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_active.dirty_set_high_threshold = old_value; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ return error; ++ } ++ ++ if (old_value > dmc->sysctl_active.dirty_set_high_threshold) { ++ /* Check each set for dirty blocks cleaning */ ++ for (i = 0; i < (dmc->size >> dmc->consecutive_shift); ++ i++) ++ eio_comply_dirty_thresholds(dmc, i); ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * eio_dirty_set_low_threshold_sysctl ++ */ ++static int ++eio_dirty_set_low_threshold_sysctl(ctl_table *table, int write, ++ void __user *buffer, size_t *length, ++ loff_t *ppos) ++{ ++ struct cache_c *dmc = (struct cache_c *)table->extra1; ++ unsigned long flags = 0; ++ ++ /* fetch the new tunable value or post the existing value */ ++ ++ if (!write) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_pending.dirty_set_low_threshold = ++ dmc->sysctl_active.dirty_set_low_threshold; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ } ++ ++ proc_dointvec(table, write, buffer, length, ppos); ++ ++ /* do write processing */ ++ ++ if (write) { ++ int error; ++ uint32_t old_value; ++ u_int64_t i; ++ ++ /* do sanity check */ ++ ++ if (dmc->mode != CACHE_MODE_WB) { ++ pr_err ++ ("dirty_set_low_threshold is valid only for writeback cache"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_set_low_threshold > 100) { ++ pr_err ++ ("dirty_set_low_threshold percentage should be [0 - 100]"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_set_low_threshold > ++ dmc->sysctl_active.dirty_set_high_threshold) { ++ pr_err ++ ("dirty_set_low_threshold shouldn't be more than dirty_set_high_threshold"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.dirty_set_low_threshold == ++ dmc->sysctl_active.dirty_set_low_threshold) ++ /* new is same as old value. No need to take any action */ ++ return 0; ++ ++ /* update the active value with the new tunable value */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ old_value = dmc->sysctl_active.dirty_set_low_threshold; ++ dmc->sysctl_active.dirty_set_low_threshold = ++ dmc->sysctl_pending.dirty_set_low_threshold; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ /* apply the new tunable value */ ++ ++ /* Store the change persistently */ ++ error = eio_sb_store(dmc); ++ if (error) { ++ /* restore back the old value and return error */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_active.dirty_set_low_threshold = old_value; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ return error; ++ } ++ ++ /* ++ * Although the low threshold value shouldn't trigger new cleans, ++ * but because we set the tunables one at a time from user mode, ++ * it is possible that the high threshold value triggering clean ++ * did not happen and should get triggered now that the low value ++ * has been changed, so we are calling the comply function again ++ */ ++ if (old_value > dmc->sysctl_active.dirty_set_low_threshold) { ++ /* Check each set for dirty blocks cleaning */ ++ for (i = 0; i < (dmc->size >> dmc->consecutive_shift); ++ i++) ++ eio_comply_dirty_thresholds(dmc, i); ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * eio_autoclean_threshold_sysctl ++ */ ++static int ++eio_autoclean_threshold_sysctl(ctl_table *table, int write, ++ void __user *buffer, size_t *length, ++ loff_t *ppos) ++{ ++ struct cache_c *dmc = (struct cache_c *)table->extra1; ++ unsigned long flags = 0; ++ ++ /* fetch the new tunable value or post existing value */ ++ ++ if (!write) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_pending.autoclean_threshold = ++ dmc->sysctl_active.autoclean_threshold; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ } ++ ++ proc_dointvec(table, write, buffer, length, ppos); ++ ++ /* do write processing */ ++ ++ if (write) { ++ int error; ++ int old_value; ++ ++ /* do sanity check */ ++ ++ if (dmc->mode != CACHE_MODE_WB) { ++ pr_err ++ ("autoclean_threshold is valid only for writeback cache"); ++ return -EINVAL; ++ } ++ ++ if ((dmc->sysctl_pending.autoclean_threshold < 0) || ++ (dmc->sysctl_pending.autoclean_threshold > ++ AUTOCLEAN_THRESH_MAX)) { ++ pr_err("autoclean_threshold is valid range is 0 to %d", ++ AUTOCLEAN_THRESH_MAX); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.autoclean_threshold == ++ dmc->sysctl_active.autoclean_threshold) ++ /* new is same as old value. No need to take any action */ ++ return 0; ++ ++ /* update the active value with the new tunable value */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ old_value = dmc->sysctl_active.autoclean_threshold; ++ dmc->sysctl_active.autoclean_threshold = ++ dmc->sysctl_pending.autoclean_threshold; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ /* apply the new tunable value */ ++ ++ /* Store the change persistently */ ++ error = eio_sb_store(dmc); ++ if (error) { ++ /* restore back the old value and return error */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_active.autoclean_threshold = old_value; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ return error; ++ } ++ ++ /* Ensure new thresholds are being complied */ ++ eio_comply_dirty_thresholds(dmc, -1); ++ } ++ ++ return 0; ++} ++ ++/* ++ * eio_time_based_clean_interval_sysctl ++ */ ++static int ++eio_time_based_clean_interval_sysctl(ctl_table *table, int write, ++ void __user *buffer, size_t *length, ++ loff_t *ppos) ++{ ++ struct cache_c *dmc = (struct cache_c *)table->extra1; ++ unsigned long flags = 0; ++ ++ /* fetch the new tunable value or post existing value */ ++ ++ if (!write) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_pending.time_based_clean_interval = ++ dmc->sysctl_active.time_based_clean_interval; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ } ++ ++ proc_dointvec(table, write, buffer, length, ppos); ++ ++ /* do write processing */ ++ ++ if (write) { ++ int error; ++ uint32_t old_value; ++ ++ /* do sanity check */ ++ ++ if (dmc->mode != CACHE_MODE_WB) { ++ pr_err ++ ("time_based_clean_interval is valid only for writeback cache"); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.time_based_clean_interval > ++ TIME_BASED_CLEAN_INTERVAL_MAX) { ++ /* valid values are 0 to TIME_BASED_CLEAN_INTERVAL_MAX */ ++ pr_err ++ ("time_based_clean_interval valid range is 0 to %u", ++ TIME_BASED_CLEAN_INTERVAL_MAX); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.time_based_clean_interval == ++ dmc->sysctl_active.time_based_clean_interval) ++ /* new is same as old value */ ++ return 0; ++ ++ /* update the active value with the new tunable value */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ old_value = dmc->sysctl_active.time_based_clean_interval; ++ dmc->sysctl_active.time_based_clean_interval = ++ dmc->sysctl_pending.time_based_clean_interval; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ /* apply the new tunable value */ ++ ++ /* Store the change persistently */ ++ error = eio_sb_store(dmc); ++ if (error) { ++ /* restore back the old value and return error */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_active.time_based_clean_interval = ++ old_value; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ return error; ++ } ++ ++ /* Reschedule the time based clean, based on new interval */ ++ cancel_delayed_work_sync(&dmc->clean_aged_sets_work); ++ spin_lock_irqsave(&dmc->dirty_set_lru_lock, flags); ++ dmc->is_clean_aged_sets_sched = 0; ++ if (dmc->sysctl_active.time_based_clean_interval ++ && atomic64_read(&dmc->nr_dirty)) { ++ schedule_delayed_work(&dmc->clean_aged_sets_work, ++ dmc->sysctl_active. ++ time_based_clean_interval * 60 * ++ HZ); ++ dmc->is_clean_aged_sets_sched = 1; ++ } ++ spin_unlock_irqrestore(&dmc->dirty_set_lru_lock, flags); ++ } ++ ++ return 0; ++} ++ ++static void eio_sysctl_register_writeback(struct cache_c *dmc); ++static void eio_sysctl_unregister_writeback(struct cache_c *dmc); ++static void eio_sysctl_register_invalidate(struct cache_c *dmc); ++static void eio_sysctl_unregister_invalidate(struct cache_c *dmc); ++ ++/* ++ * eio_control_sysctl ++ */ ++int ++eio_control_sysctl(ctl_table *table, int write, void __user *buffer, ++ size_t *length, loff_t *ppos) ++{ ++ int rv = 0; ++ struct cache_c *dmc = (struct cache_c *)table->extra1; ++ unsigned long flags = 0; ++ ++ /* fetch the new tunable value */ ++ ++ if (!write) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_pending.control = dmc->sysctl_active.control; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ } ++ ++ proc_dointvec(table, write, buffer, length, ppos); ++ ++ /* do write processing */ ++ ++ if (write) { ++ /* do sanity check */ ++ ++ if (dmc->sysctl_pending.control > CACHE_CONTROL_FLAG_MAX || ++ dmc->sysctl_pending.control < 0) { ++ /* valid values are from 0 till CACHE_CONTROL_FLAG_MAX */ ++ pr_err("control valid values are from 0 till %d", ++ CACHE_CONTROL_FLAG_MAX); ++ return -EINVAL; ++ } ++ ++ if (dmc->sysctl_pending.control == dmc->sysctl_active.control) ++ /* new is same as old value. No work required */ ++ return 0; ++ ++ /* update the active value with the new tunable value */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_active.control = dmc->sysctl_pending.control; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ /* apply the new tunable value */ ++ ++ switch (dmc->sysctl_active.control) { ++ case CACHE_VERBOSE_OFF: ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->cache_flags &= ~CACHE_FLAGS_VERBOSE; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ pr_info("Turning off verbose mode"); ++ break; ++ case CACHE_VERBOSE_ON: ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->cache_flags |= CACHE_FLAGS_VERBOSE; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ pr_info("Turning on verbose mode"); ++ break; ++ case CACHE_WRITEBACK_ON: ++ if (dmc->sysctl_handle_writeback == NULL) ++ eio_sysctl_register_writeback(dmc); ++ break; ++ case CACHE_WRITEBACK_OFF: ++ if (dmc->sysctl_handle_writeback) ++ eio_sysctl_unregister_writeback(dmc); ++ break; ++ case CACHE_INVALIDATE_ON: ++ if (dmc->sysctl_handle_invalidate == NULL) { ++ eio_sysctl_register_invalidate(dmc); ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->cache_flags |= CACHE_FLAGS_INVALIDATE; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc-> ++ cache_spin_lock_flags); ++ } else ++ pr_info("Invalidate API already registered"); ++ break; ++ case CACHE_INVALIDATE_OFF: ++ if (dmc->sysctl_handle_invalidate) { ++ eio_sysctl_unregister_invalidate(dmc); ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->cache_flags &= ~CACHE_FLAGS_INVALIDATE; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc-> ++ cache_spin_lock_flags); ++ } else ++ pr_info("Invalidate API not registered"); ++ break; ++ case CACHE_FAST_REMOVE_ON: ++ if (dmc->mode != CACHE_MODE_WB) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->cache_flags |= CACHE_FLAGS_FAST_REMOVE; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc-> ++ cache_spin_lock_flags); ++ if (CACHE_VERBOSE_IS_SET(dmc)) ++ pr_info("Turning on fast remove"); ++ } else { ++#ifdef EIO_DEBUG ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->cache_flags |= CACHE_FLAGS_FAST_REMOVE; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc-> ++ cache_spin_lock_flags); ++ if (CACHE_VERBOSE_IS_SET(dmc)) ++ pr_info("Turning on fast remove"); ++#else ++ pr_err("Invalid control value: 0x%x", ++ dmc->sysctl_active.control); ++ rv = -1; ++#endif /* EIO_DEBUG */ ++ } ++ break; ++ case CACHE_FAST_REMOVE_OFF: ++ if (dmc->mode != CACHE_MODE_WB) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->cache_flags &= ~CACHE_FLAGS_FAST_REMOVE; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc-> ++ cache_spin_lock_flags); ++ if (CACHE_VERBOSE_IS_SET(dmc)) ++ pr_info("Turning off fast remove"); ++ } else { ++#ifdef EIO_DEBUG ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->cache_flags &= ~CACHE_FLAGS_FAST_REMOVE; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc-> ++ cache_spin_lock_flags); ++ if (CACHE_VERBOSE_IS_SET(dmc)) ++ pr_info("Turning off fast remove"); ++#else ++ pr_err("Invalid control value: 0x%x", ++ dmc->sysctl_active.control); ++ rv = -1; ++#endif /* EIO_DEBUG */ ++ } ++ break; ++ default: ++ pr_err("Invalid control value: 0x%x", ++ dmc->sysctl_active.control); ++ rv = -1; ++ } ++ } ++ ++ return rv; ++} ++ ++#define PROC_STR "enhanceio" ++#define PROC_VER_STR "enhanceio/version" ++#define PROC_STATS "stats" ++#define PROC_ERRORS "errors" ++#define PROC_IOSZ_HIST "io_hist" ++#define PROC_CONFIG "config" ++ ++static int eio_invalidate_sysctl(ctl_table *table, int write, ++ void __user *buffer, size_t *length, ++ loff_t *ppos); ++static void *eio_find_sysctl_data(struct cache_c *dmc, ctl_table *vars); ++static char *eio_cons_sysctl_devname(struct cache_c *dmc); ++static char *eio_cons_procfs_cachename(struct cache_c *dmc, ++ char *path_component); ++static void eio_sysctl_register_common(struct cache_c *dmc); ++static void eio_sysctl_unregister_common(struct cache_c *dmc); ++static void eio_sysctl_register_dir(void); ++static void eio_sysctl_unregister_dir(void); ++static int eio_stats_show(struct seq_file *seq, void *v); ++static int eio_stats_open(struct inode *inode, struct file *file); ++static int eio_errors_show(struct seq_file *seq, void *v); ++static int eio_errors_open(struct inode *inode, struct file *file); ++static int eio_iosize_hist_show(struct seq_file *seq, void *v); ++static int eio_iosize_hist_open(struct inode *inode, struct file *file); ++static int eio_version_show(struct seq_file *seq, void *v); ++static int eio_version_open(struct inode *inode, struct file *file); ++static int eio_config_show(struct seq_file *seq, void *v); ++static int eio_config_open(struct inode *inode, struct file *file); ++ ++static const struct file_operations eio_version_operations = { ++ .open = eio_version_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static const struct file_operations eio_stats_operations = { ++ .open = eio_stats_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static const struct file_operations eio_errors_operations = { ++ .open = eio_errors_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static const struct file_operations eio_iosize_hist_operations = { ++ .open = eio_iosize_hist_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static const struct file_operations eio_config_operations = { ++ .open = eio_config_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++/* ++ * Each ctl_table array needs to be 1 more than the actual number of ++ * entries - zero padded at the end ! Therefore the NUM_*_SYSCTLS ++ * is 1 more than then number of sysctls. ++ */ ++ ++#define PROC_SYS_ROOT_NAME "dev" ++#define PROC_SYS_DIR_NAME "enhanceio" ++#define PROC_SYS_CACHE_NAME "enhanceio-dev" ++ ++/* ++ * The purpose of sysctl_table_dir is to create the "enhanceio" ++ * dir under /proc/sys/dev/. The creation is done during module ++ * load time and the dir is removed when module is removed. ++ * ++ * This was added because otherwise, the first cache instance ++ * falsely assumes that /proc/sys/kernel/ is its parent instead ++ * of /proc/sys/dev leading to an incorrect number of reference ++ * count. When you have multiple cache instances, removing the ++ * last one results in the kernel's reference count to be 0 ++ * leading to a kernel warning at runtime. Hopefully, this will ++ * be fixed in the kernel sometime. ++ */ ++static struct sysctl_table_dir { ++ struct ctl_table_header *sysctl_header; ++ ctl_table vars[0 + 1]; ++ ctl_table dev[0 + 1]; ++ ctl_table dir[1 + 1]; ++ ctl_table root[1 + 1]; ++} sysctl_template_dir = { ++ .vars = { ++ }, .dev = { ++ }, .dir = { ++ { ++ .procname = PROC_SYS_DIR_NAME, ++ .maxlen = 0, ++ .mode = S_IRUGO | S_IXUGO, ++ .child = sysctl_template_dir.dev, ++ }, ++ }, .root = { ++ { ++ .procname = PROC_SYS_ROOT_NAME, ++ .maxlen = 0, ++ .mode = 0555, ++ .child = sysctl_template_dir.dir, ++ }, ++ }, ++}; ++ ++#define NUM_COMMON_SYSCTLS 3 ++ ++static struct sysctl_table_common { ++ struct ctl_table_header *sysctl_header; ++ ctl_table vars[NUM_COMMON_SYSCTLS + 1]; ++ ctl_table dev[1 + 1]; ++ ctl_table dir[1 + 1]; ++ ctl_table root[1 + 1]; ++} sysctl_template_common = { ++ .vars = { ++ { /* 1 */ ++ .procname = "zero_stats", ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &eio_zerostats_sysctl, ++ }, { /* 2 */ ++ .procname = "mem_limit_pct", ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &eio_mem_limit_pct_sysctl, ++ }, { /* 3 */ ++ .procname = "control", ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &eio_control_sysctl, ++ }, ++ }, .dev = { ++ { ++ .procname = PROC_SYS_CACHE_NAME, ++ .maxlen = 0, ++ .mode = S_IRUGO | S_IXUGO, ++ .child = sysctl_template_common.vars, ++ }, ++ }, .dir = { ++ { ++ .procname = PROC_SYS_DIR_NAME, ++ .maxlen = 0, ++ .mode = S_IRUGO | S_IXUGO, ++ .child = sysctl_template_common.dev, ++ }, ++ }, .root = { ++ { ++ .procname = PROC_SYS_ROOT_NAME, ++ .maxlen = 0, ++ .mode = 0555, ++ .child = sysctl_template_common.dir, ++ }, ++ }, ++}; ++ ++#define NUM_WRITEBACK_SYSCTLS 7 ++ ++static struct sysctl_table_writeback { ++ struct ctl_table_header *sysctl_header; ++ ctl_table vars[NUM_WRITEBACK_SYSCTLS + 1]; ++ ctl_table dev[1 + 1]; ++ ctl_table dir[1 + 1]; ++ ctl_table root[1 + 1]; ++} sysctl_template_writeback = { ++ .vars = { ++ { /* 1 */ ++ .procname = "do_clean", ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &eio_clean_sysctl, ++ }, { /* 2 */ ++ .procname = "time_based_clean_interval", ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = &eio_time_based_clean_interval_sysctl, ++ }, { /* 3 */ ++ .procname = "autoclean_threshold", ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = &eio_autoclean_threshold_sysctl, ++ }, { /* 4 */ ++ .procname = "dirty_high_threshold", ++ .maxlen = sizeof(uint32_t), ++ .mode = 0644, ++ .proc_handler = &eio_dirty_high_threshold_sysctl, ++ } ++ , { /* 5 */ ++ .procname = "dirty_low_threshold", ++ .maxlen = sizeof(uint32_t), ++ .mode = 0644, ++ .proc_handler = &eio_dirty_low_threshold_sysctl, ++ } ++ , { /* 6 */ ++ .procname = "dirty_set_high_threshold", ++ .maxlen = sizeof(uint32_t), ++ .mode = 0644, ++ .proc_handler = &eio_dirty_set_high_threshold_sysctl, ++ } ++ , { /* 7 */ ++ .procname = "dirty_set_low_threshold", ++ .maxlen = sizeof(uint32_t), ++ .mode = 0644, ++ .proc_handler = &eio_dirty_set_low_threshold_sysctl, ++ } ++ , ++ } ++ , .dev = { ++ { ++ .procname = PROC_SYS_CACHE_NAME, ++ .maxlen = 0, ++ .mode = S_IRUGO | S_IXUGO, ++ .child = sysctl_template_writeback.vars, ++ } ++ , ++ } ++ , .dir = { ++ { ++ .procname = PROC_SYS_DIR_NAME, ++ .maxlen = 0, ++ .mode = S_IRUGO | S_IXUGO, ++ .child = sysctl_template_writeback.dev, ++ } ++ , ++ } ++ , .root = { ++ { ++ .procname = PROC_SYS_ROOT_NAME, ++ .maxlen = 0, ++ .mode = 0555, ++ .child = sysctl_template_writeback.dir, ++ } ++ , ++ } ++ , ++}; ++ ++#define NUM_INVALIDATE_SYSCTLS (1) ++static struct sysctl_table_invalidate { ++ struct ctl_table_header *sysctl_header; ++ ctl_table vars[NUM_INVALIDATE_SYSCTLS + 1]; ++ ctl_table dev[1 + 1]; ++ ctl_table dir[1 + 1]; ++ ctl_table root[1 + 1]; ++} sysctl_template_invalidate = { ++ .vars = { ++ { /* 1 */ ++ .procname = "invalidate", ++ .maxlen = sizeof(u_int64_t), ++ .mode = 0644, ++ .proc_handler = &eio_invalidate_sysctl, ++ } ++ , ++ } ++ , .dev = { ++ { ++ .procname = PROC_SYS_CACHE_NAME, ++ .maxlen = 0, ++ .mode = S_IRUGO | S_IXUGO, ++ .child = sysctl_template_invalidate.vars, ++ } ++ , ++ } ++ , .dir = { ++ { ++ .procname = PROC_SYS_DIR_NAME, ++ .maxlen = 0, ++ .mode = S_IRUGO | S_IXUGO, ++ .child = sysctl_template_invalidate.dev, ++ } ++ , ++ } ++ , .root = { ++ { ++ .procname = PROC_SYS_ROOT_NAME, ++ .maxlen = 0, ++ .mode = 0555, ++ .child = sysctl_template_invalidate.dir, ++ } ++ , ++ } ++ , ++}; ++ ++/* ++ * eio_module_procfs_init -- called from "eio_init()" ++ */ ++void eio_module_procfs_init(void) ++{ ++ struct proc_dir_entry *entry; ++ ++ if (proc_mkdir(PROC_STR, NULL)) { ++ entry = proc_create_data(PROC_VER_STR, 0, NULL, ++ &eio_version_operations, NULL); ++ } ++ eio_sysctl_register_dir(); ++} ++ ++/* ++ * eio_module_procfs_exit -- called from "eio_exit()" ++ */ ++void eio_module_procfs_exit(void) ++{ ++ (void)remove_proc_entry(PROC_VER_STR, NULL); ++ (void)remove_proc_entry(PROC_STR, NULL); ++ ++ eio_sysctl_unregister_dir(); ++} ++ ++/* ++ * eio_procfs_ctr -- called from "eio_ctr()" ++ */ ++void eio_procfs_ctr(struct cache_c *dmc) ++{ ++ char *s; ++ struct proc_dir_entry *entry; ++ ++ s = eio_cons_procfs_cachename(dmc, ""); ++ entry = proc_mkdir(s, NULL); ++ kfree(s); ++ if (entry == NULL) { ++ pr_err("Failed to create /proc/%s", s); ++ return; ++ } ++ ++ s = eio_cons_procfs_cachename(dmc, PROC_STATS); ++ entry = proc_create_data(s, 0, NULL, &eio_stats_operations, dmc); ++ kfree(s); ++ ++ s = eio_cons_procfs_cachename(dmc, PROC_ERRORS); ++ entry = proc_create_data(s, 0, NULL, &eio_errors_operations, dmc); ++ kfree(s); ++ ++ s = eio_cons_procfs_cachename(dmc, PROC_IOSZ_HIST); ++ entry = proc_create_data(s, 0, NULL, &eio_iosize_hist_operations, dmc); ++ kfree(s); ++ ++ s = eio_cons_procfs_cachename(dmc, PROC_CONFIG); ++ entry = proc_create_data(s, 0, NULL, &eio_config_operations, dmc); ++ kfree(s); ++ ++ eio_sysctl_register_common(dmc); ++ if (dmc->mode == CACHE_MODE_WB) ++ eio_sysctl_register_writeback(dmc); ++ if (CACHE_INVALIDATE_IS_SET(dmc)) ++ eio_sysctl_register_invalidate(dmc); ++} ++ ++/* ++ * eio_procfs_dtr -- called from "eio_dtr()" ++ */ ++void eio_procfs_dtr(struct cache_c *dmc) ++{ ++ char *s; ++ ++ s = eio_cons_procfs_cachename(dmc, PROC_STATS); ++ remove_proc_entry(s, NULL); ++ kfree(s); ++ ++ s = eio_cons_procfs_cachename(dmc, PROC_ERRORS); ++ remove_proc_entry(s, NULL); ++ kfree(s); ++ ++ s = eio_cons_procfs_cachename(dmc, PROC_IOSZ_HIST); ++ remove_proc_entry(s, NULL); ++ kfree(s); ++ ++ s = eio_cons_procfs_cachename(dmc, PROC_CONFIG); ++ remove_proc_entry(s, NULL); ++ kfree(s); ++ ++ s = eio_cons_procfs_cachename(dmc, ""); ++ remove_proc_entry(s, NULL); ++ kfree(s); ++ ++ if (dmc->sysctl_handle_invalidate) ++ eio_sysctl_unregister_invalidate(dmc); ++ if (dmc->sysctl_handle_writeback) ++ eio_sysctl_unregister_writeback(dmc); ++ eio_sysctl_unregister_common(dmc); ++} ++ ++static spinlock_t invalidate_spin_lock; ++ ++/* ++ * eio_invalidate_sysctl ++ */ ++static int ++eio_invalidate_sysctl(ctl_table *table, int write, void __user *buffer, ++ size_t *length, loff_t *ppos) ++{ ++ static int have_sector; ++ static u_int64_t sector; ++ static u_int64_t num_sectors; ++ int rv; ++ unsigned long int flags; ++ struct cache_c *dmc; ++ ++ spin_lock_irqsave(&invalidate_spin_lock, flags); ++ ++ dmc = (struct cache_c *)table->extra1; ++ if (dmc == NULL) { ++ pr_err ++ ("Cannot invalidate due to unexpected NULL cache pointer"); ++ spin_unlock_irqrestore(&invalidate_spin_lock, flags); ++ return -EBUSY; ++ } ++ ++ table->extra1 = NULL; ++ proc_doulongvec_minmax(table, write, buffer, length, ppos); ++ table->extra1 = dmc; ++ ++ spin_unlock_irqrestore(&invalidate_spin_lock, flags); ++ ++ rv = 0; ++ ++ if (write) { ++ /* TBD. Need to put appropriate sanity checks */ ++ ++ /* update the active value with the new tunable value */ ++ spin_lock_irqsave(&dmc->cache_spin_lock, flags); ++ dmc->sysctl_active.invalidate = dmc->sysctl_pending.invalidate; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, flags); ++ ++ /* apply the new tunable value */ ++ ++ if (have_sector) { ++ num_sectors = dmc->sysctl_active.invalidate; ++ ++ rv = eio_invalidate_sanity_check(dmc, sector, ++ &num_sectors); ++ ++ /* Invalidate only if sanity passes and reset the return value. */ ++ if (rv == 0) ++ eio_inval_range(dmc, sector, ++ (unsigned) ++ to_bytes(num_sectors)); ++ ++ rv = 0; ++ have_sector = 0; ++ ++ } else { ++ sector = dmc->sysctl_active.invalidate; ++ have_sector = 1; ++ num_sectors = 0; ++ } ++ } ++ ++ if (CACHE_VERBOSE_IS_SET(dmc) && num_sectors) { ++ pr_info ++ ("eio_inval_range: Invalidated sector range from sector=%lu to sector=%lu", ++ (long unsigned int)sector, (long unsigned int)num_sectors); ++ } ++ ++ return rv; ++} ++ ++/* ++ * eio_find_sysctl_data ++ */ ++static void *eio_find_sysctl_data(struct cache_c *dmc, ctl_table *vars) ++{ ++ ++ if (strcmp(vars->procname, "do_clean") == 0) ++ return (void *)&dmc->sysctl_pending.do_clean; ++ if (strcmp(vars->procname, "time_based_clean_interval") == 0) ++ return (void *)&dmc->sysctl_pending.time_based_clean_interval; ++ if (strcmp(vars->procname, "dirty_high_threshold") == 0) ++ return (void *)&dmc->sysctl_pending.dirty_high_threshold; ++ if (strcmp(vars->procname, "dirty_low_threshold") == 0) ++ return (void *)&dmc->sysctl_pending.dirty_low_threshold; ++ if (strcmp(vars->procname, "dirty_set_high_threshold") == 0) ++ return (void *)&dmc->sysctl_pending.dirty_set_high_threshold; ++ if (strcmp(vars->procname, "dirty_set_low_threshold") == 0) ++ return (void *)&dmc->sysctl_pending.dirty_set_low_threshold; ++ if (strcmp(vars->procname, "autoclean_threshold") == 0) ++ return (void *)&dmc->sysctl_pending.autoclean_threshold; ++ if (strcmp(vars->procname, "zero_stats") == 0) ++ return (void *)&dmc->sysctl_pending.zerostats; ++ if (strcmp(vars->procname, "mem_limit_pct") == 0) ++ return (void *)&dmc->sysctl_pending.mem_limit_pct; ++ if (strcmp(vars->procname, "control") == 0) ++ return (void *)&dmc->sysctl_pending.control; ++ if (strcmp(vars->procname, "invalidate") == 0) ++ return (void *)&dmc->sysctl_pending.invalidate; ++ ++ pr_err("Cannot find sysctl data for %s", vars->procname); ++ return NULL; ++} ++ ++/* ++ * eio_cons_sysctl_devname ++ */ ++static char *eio_cons_sysctl_devname(struct cache_c *dmc) ++{ ++ char *pathname; ++ ++ if (dmc->cache_name[0]) { ++ pathname = kzalloc(strlen(dmc->cache_name) + 1, GFP_KERNEL); ++ if (pathname) ++ strcpy(pathname, dmc->cache_name); ++ else ++ pr_err("Failed to allocate memory"); ++ } else { ++ pr_err("Cache name is NULL"); ++ pathname = NULL; ++ } ++ ++ return pathname; ++} ++ ++/* ++ * eio_cons_procfs_cachename ++ */ ++static char *eio_cons_procfs_cachename(struct cache_c *dmc, ++ char *path_component) ++{ ++ char *pathname; ++ ++ if (dmc->cache_name[0]) { ++ pathname = ++ kzalloc(strlen(PROC_SYS_DIR_NAME) + 1 + ++ strlen(dmc->cache_name) + 1 + ++ strlen(path_component) + 1, GFP_KERNEL); ++ if (pathname) { ++ strcpy(pathname, PROC_SYS_DIR_NAME); ++ strcat(pathname, "/"); ++ strcat(pathname, dmc->cache_name); ++ if (strcmp(path_component, "") != 0) { ++ strcat(pathname, "/"); ++ strcat(pathname, path_component); ++ } ++ } else ++ pr_err("Failed to allocate memory"); ++ } else { ++ pr_err("Cache name is NULL"); ++ pathname = NULL; ++ } ++ ++ return pathname; ++} ++ ++static void eio_sysctl_register_dir(void) ++{ ++ struct sysctl_table_dir *dir; ++ ++ dir = ++ kmemdup(&sysctl_template_dir, sizeof(sysctl_template_dir), ++ GFP_KERNEL); ++ if (unlikely(dir == NULL)) { ++ pr_err("Failed to allocate memory for dir sysctl"); ++ return; ++ } ++ ++ dir->dir[0].child = dir->dev; ++ dir->root[0].child = dir->dir; ++ dir->sysctl_header = register_sysctl_table(dir->root); ++ if (unlikely(dir->sysctl_header == NULL)) { ++ pr_err("Failed to register dir sysctl"); ++ goto out; ++ } ++ ++ sysctl_handle_dir = dir; ++ return; ++out: ++ kfree(dir); ++} ++ ++static void eio_sysctl_unregister_dir(void) ++{ ++ if (sysctl_handle_dir != NULL) { ++ unregister_sysctl_table(sysctl_handle_dir->sysctl_header); ++ kfree(sysctl_handle_dir); ++ sysctl_handle_dir = NULL; ++ } ++} ++ ++/* ++ * eio_sysctl_register_common ++ */ ++static void eio_sysctl_register_common(struct cache_c *dmc) ++{ ++ unsigned int i; ++ struct sysctl_table_common *common; ++ ++ common = ++ kmemdup(&sysctl_template_common, sizeof(sysctl_template_common), ++ GFP_KERNEL); ++ if (common == NULL) { ++ pr_err("Failed to allocate memory for common sysctl"); ++ return; ++ } ++ for (i = 0; i < ARRAY_SIZE(common->vars) - 1; i++) { ++ common->vars[i].data = ++ eio_find_sysctl_data(dmc, &common->vars[i]); ++ common->vars[i].extra1 = dmc; ++ } ++ ++ common->dev[0].procname = eio_cons_sysctl_devname(dmc); ++ common->dev[0].child = common->vars; ++ common->dir[0].child = common->dev; ++ common->root[0].child = common->dir; ++ common->sysctl_header = register_sysctl_table(common->root); ++ if (common->sysctl_header == NULL) { ++ pr_err("Failed to register common sysctl"); ++ goto out; ++ } ++ ++ dmc->sysctl_handle_common = common; ++ return; ++out: ++ kfree(common->dev[0].procname); ++ kfree(common); ++} ++ ++/* ++ * eio_sysctl_unregister_common ++ */ ++static void eio_sysctl_unregister_common(struct cache_c *dmc) ++{ ++ struct sysctl_table_common *common; ++ ++ common = dmc->sysctl_handle_common; ++ if (common != NULL) { ++ dmc->sysctl_handle_common = NULL; ++ unregister_sysctl_table(common->sysctl_header); ++ kfree(common->dev[0].procname); ++ kfree(common); ++ } ++} ++ ++/* ++ * eio_sysctl_register_writeback ++ */ ++static void eio_sysctl_register_writeback(struct cache_c *dmc) ++{ ++ unsigned int i; ++ struct sysctl_table_writeback *writeback; ++ ++ writeback = ++ kmemdup(&sysctl_template_writeback, ++ sizeof(sysctl_template_writeback), GFP_KERNEL); ++ if (writeback == NULL) { ++ pr_err("Failed to allocate memory for writeback sysctl"); ++ return; ++ } ++ for (i = 0; i < ARRAY_SIZE(writeback->vars) - 1; i++) { ++ writeback->vars[i].data = ++ eio_find_sysctl_data(dmc, &writeback->vars[i]); ++ writeback->vars[i].extra1 = dmc; ++ } ++ ++ writeback->dev[0].procname = eio_cons_sysctl_devname(dmc); ++ writeback->dev[0].child = writeback->vars; ++ writeback->dir[0].child = writeback->dev; ++ writeback->root[0].child = writeback->dir; ++ writeback->sysctl_header = register_sysctl_table(writeback->root); ++ if (writeback->sysctl_header == NULL) { ++ pr_err("Failed to register writeback sysctl"); ++ goto out; ++ } ++ ++ dmc->sysctl_handle_writeback = writeback; ++ return; ++out: ++ kfree(writeback->dev[0].procname); ++ kfree(writeback); ++} ++ ++/* ++ * eio_sysctl_unregister_writeback ++ */ ++static void eio_sysctl_unregister_writeback(struct cache_c *dmc) ++{ ++ struct sysctl_table_writeback *writeback; ++ ++ writeback = dmc->sysctl_handle_writeback; ++ if (writeback != NULL) { ++ dmc->sysctl_handle_writeback = NULL; ++ unregister_sysctl_table(writeback->sysctl_header); ++ kfree(writeback->dev[0].procname); ++ kfree(writeback); ++ } ++} ++ ++/* ++ * eio_sysctl_register_invalidate ++ */ ++static void eio_sysctl_register_invalidate(struct cache_c *dmc) ++{ ++ unsigned int i; ++ struct sysctl_table_invalidate *invalidate; ++ ++ invalidate = ++ kmemdup(&sysctl_template_invalidate, ++ sizeof(sysctl_template_invalidate), GFP_KERNEL); ++ if (invalidate == NULL) { ++ pr_err("Failed to allocate memory for invalidate sysctl"); ++ return; ++ } ++ for (i = 0; i < ARRAY_SIZE(invalidate->vars) - 1; i++) { ++ invalidate->vars[i].data = ++ eio_find_sysctl_data(dmc, &invalidate->vars[i]); ++ invalidate->vars[i].extra1 = dmc; ++ } ++ ++ invalidate->dev[0].procname = eio_cons_sysctl_devname(dmc); ++ invalidate->dev[0].child = invalidate->vars; ++ invalidate->dir[0].child = invalidate->dev; ++ invalidate->root[0].child = invalidate->dir; ++ invalidate->sysctl_header = register_sysctl_table(invalidate->root); ++ if (invalidate->sysctl_header == NULL) { ++ pr_err("Failed to register invalidate sysctl"); ++ goto out; ++ } ++ ++ dmc->sysctl_handle_invalidate = invalidate; ++ spin_lock_init(&invalidate_spin_lock); ++ return; ++out: ++ kfree(invalidate->dev[0].procname); ++ kfree(invalidate); ++} ++ ++/* ++ * eio_sysctl_unregister_invalidate ++ */ ++static void eio_sysctl_unregister_invalidate(struct cache_c *dmc) ++{ ++ struct sysctl_table_invalidate *invalidate; ++ ++ invalidate = dmc->sysctl_handle_invalidate; ++ if (invalidate != NULL) { ++ dmc->sysctl_handle_invalidate = NULL; ++ unregister_sysctl_table(invalidate->sysctl_header); ++ kfree(invalidate->dev[0].procname); ++ kfree(invalidate); ++ } ++} ++ ++/* ++ * eio_stats_show ++ */ ++static int eio_stats_show(struct seq_file *seq, void *v) ++{ ++ struct cache_c *dmc = seq->private; ++ struct eio_stats *stats = &dmc->eio_stats; ++ int read_hit_pct, write_hit_pct, dirty_write_hit_pct; ++ ++ if (atomic64_read(&stats->reads) > 0) ++ read_hit_pct = ++ EIO_CALCULATE_PERCENTAGE( ++ atomic64_read(&stats->read_hits), ++ atomic64_read(&stats->reads)); ++ else ++ read_hit_pct = 0; ++ ++ if (atomic64_read(&stats->writes) > 0) { ++ write_hit_pct = ++ EIO_CALCULATE_PERCENTAGE( ++ atomic64_read(&stats->write_hits), ++ atomic64_read(&stats->writes)); ++ dirty_write_hit_pct = ++ EIO_CALCULATE_PERCENTAGE( ++ atomic64_read(&stats->dirty_write_hits), ++ atomic64_read(&stats->writes)); ++ } else { ++ write_hit_pct = 0; ++ dirty_write_hit_pct = 0; ++ } ++ ++ seq_printf(seq, "%-26s %12lld\n", "reads", ++ (int64_t)atomic64_read(&stats->reads)); ++ seq_printf(seq, "%-26s %12lld\n", "writes", ++ (int64_t)atomic64_read(&stats->writes)); ++ ++ seq_printf(seq, "%-26s %12lld\n", "read_hits", ++ (int64_t)atomic64_read(&stats->read_hits)); ++ seq_printf(seq, "%-26s %12d\n", "read_hit_pct", read_hit_pct); ++ ++ seq_printf(seq, "%-26s %12lld\n", "write_hits", ++ (int64_t)atomic64_read(&stats->write_hits)); ++ seq_printf(seq, "%-26s %12u\n", "write_hit_pct", write_hit_pct); ++ ++ seq_printf(seq, "%-26s %12lld\n", "dirty_write_hits", ++ (int64_t)atomic64_read(&stats->dirty_write_hits)); ++ seq_printf(seq, "%-26s %12d\n", "dirty_write_hit_pct", ++ dirty_write_hit_pct); ++ ++ if ((int64_t)(atomic64_read(&stats->cached_blocks)) < 0) ++ atomic64_set(&stats->cached_blocks, 0); ++ seq_printf(seq, "%-26s %12lld\n", "cached_blocks", ++ (int64_t)atomic64_read(&stats->cached_blocks)); ++ ++ seq_printf(seq, "%-26s %12lld\n", "rd_replace", ++ (int64_t)atomic64_read(&stats->rd_replace)); ++ seq_printf(seq, "%-26s %12lld\n", "wr_replace", ++ (int64_t)atomic64_read(&stats->wr_replace)); ++ ++ seq_printf(seq, "%-26s %12lld\n", "noroom", ++ (int64_t)atomic64_read(&stats->noroom)); ++ ++ seq_printf(seq, "%-26s %12lld\n", "cleanings", ++ (int64_t)atomic64_read(&stats->cleanings)); ++ seq_printf(seq, "%-26s %12lld\n", "md_write_dirty", ++ (int64_t)atomic64_read(&stats->md_write_dirty)); ++ seq_printf(seq, "%-26s %12lld\n", "md_write_clean", ++ (int64_t)atomic64_read(&stats->md_write_clean)); ++ seq_printf(seq, "%-26s %12lld\n", "md_ssd_writes", ++ (int64_t)atomic64_read(&stats->md_ssd_writes)); ++ seq_printf(seq, "%-26s %12d\n", "do_clean", ++ dmc->sysctl_active.do_clean); ++ seq_printf(seq, "%-26s %12lld\n", "nr_blocks", dmc->size); ++ seq_printf(seq, "%-26s %12lld\n", "nr_dirty", ++ (int64_t)atomic64_read(&dmc->nr_dirty)); ++ seq_printf(seq, "%-26s %12u\n", "nr_sets", (uint32_t)dmc->num_sets); ++ seq_printf(seq, "%-26s %12d\n", "clean_index", ++ (uint32_t)atomic_read(&dmc->clean_index)); ++ ++ seq_printf(seq, "%-26s %12lld\n", "uncached_reads", ++ (int64_t)atomic64_read(&stats->uncached_reads)); ++ seq_printf(seq, "%-26s %12lld\n", "uncached_writes", ++ (int64_t)atomic64_read(&stats->uncached_writes)); ++ seq_printf(seq, "%-26s %12lld\n", "uncached_map_size", ++ (int64_t)atomic64_read(&stats->uncached_map_size)); ++ seq_printf(seq, "%-26s %12lld\n", "uncached_map_uncacheable", ++ (int64_t)atomic64_read(&stats->uncached_map_uncacheable)); ++ ++ seq_printf(seq, "%-26s %12lld\n", "disk_reads", ++ (int64_t)atomic64_read(&stats->disk_reads)); ++ seq_printf(seq, "%-26s %12lld\n", "disk_writes", ++ (int64_t)atomic64_read(&stats->disk_writes)); ++ seq_printf(seq, "%-26s %12lld\n", "ssd_reads", ++ (int64_t)atomic64_read(&stats->ssd_reads)); ++ seq_printf(seq, "%-26s %12lld\n", "ssd_writes", ++ (int64_t)atomic64_read(&stats->ssd_writes)); ++ seq_printf(seq, "%-26s %12lld\n", "ssd_readfills", ++ (int64_t)atomic64_read(&stats->ssd_readfills)); ++ seq_printf(seq, "%-26s %12lld\n", "ssd_readfill_unplugs", ++ (int64_t)atomic64_read(&stats->ssd_readfill_unplugs)); ++ ++ seq_printf(seq, "%-26s %12lld\n", "readdisk", ++ (int64_t)atomic64_read(&stats->readdisk)); ++ seq_printf(seq, "%-26s %12lld\n", "writedisk", ++ (int64_t)atomic64_read(&stats->readdisk)); ++ seq_printf(seq, "%-26s %12lld\n", "readcache", ++ (int64_t)atomic64_read(&stats->readcache)); ++ seq_printf(seq, "%-26s %12lld\n", "readfill", ++ (int64_t)atomic64_read(&stats->readfill)); ++ seq_printf(seq, "%-26s %12lld\n", "writecache", ++ (int64_t)atomic64_read(&stats->writecache)); ++ ++ seq_printf(seq, "%-26s %12lld\n", "readcount", ++ (int64_t)atomic64_read(&stats->readcount)); ++ seq_printf(seq, "%-26s %12lld\n", "writecount", ++ (int64_t)atomic64_read(&stats->writecount)); ++ seq_printf(seq, "%-26s %12lld\n", "kb_reads", ++ (int64_t)atomic64_read(&stats->reads) / 2); ++ seq_printf(seq, "%-26s %12lld\n", "kb_writes", ++ (int64_t)atomic64_read(&stats->writes) / 2); ++ seq_printf(seq, "%-26s %12lld\n", "rdtime_ms", ++ (int64_t)atomic64_read(&stats->rdtime_ms)); ++ seq_printf(seq, "%-26s %12lld\n", "wrtime_ms", ++ (int64_t)atomic64_read(&stats->wrtime_ms)); ++ return 0; ++} ++ ++/* ++ * eio_stats_open ++ */ ++static int eio_stats_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, &eio_stats_show, PDE_DATA(inode)); ++} ++ ++/* ++ * eio_errors_show ++ */ ++static int eio_errors_show(struct seq_file *seq, void *v) ++{ ++ struct cache_c *dmc = seq->private; ++ ++ seq_printf(seq, "disk_read_errors %4u\n", ++ dmc->eio_errors.disk_read_errors); ++ seq_printf(seq, "disk_write_errors %4u\n", ++ dmc->eio_errors.disk_write_errors); ++ seq_printf(seq, "ssd_read_errors %4u\n", ++ dmc->eio_errors.ssd_read_errors); ++ seq_printf(seq, "ssd_write_errors %4u\n", ++ dmc->eio_errors.ssd_write_errors); ++ seq_printf(seq, "memory_alloc_errors %4u\n", ++ dmc->eio_errors.memory_alloc_errors); ++ seq_printf(seq, "no_cache_dev %4u\n", ++ dmc->eio_errors.no_cache_dev); ++ seq_printf(seq, "no_source_dev %4u\n", ++ dmc->eio_errors.no_source_dev); ++ ++ return 0; ++} ++ ++/* ++ * eio_errors_open ++ */ ++static int eio_errors_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, &eio_errors_show, PDE_DATA(inode)); ++} ++ ++/* ++ * eio_iosize_hist_show ++ */ ++static int eio_iosize_hist_show(struct seq_file *seq, void *v) ++{ ++ int i; ++ struct cache_c *dmc = seq->private; ++ ++ for (i = 1; i <= SIZE_HIST - 1; i++) { ++ if (atomic64_read(&dmc->size_hist[i]) == 0) ++ continue; ++ ++ if (i == 1) ++ seq_printf(seq, "%u %12lld\n", i * 512, ++ (int64_t)atomic64_read(&dmc->size_hist[i])); ++ else if (i < 20) ++ seq_printf(seq, "%u %12lld\n", i * 512, ++ (int64_t)atomic64_read(&dmc->size_hist[i])); ++ else ++ seq_printf(seq, "%u %12lld\n", i * 512, ++ (int64_t)atomic64_read(&dmc->size_hist[i])); ++ } ++ ++ return 0; ++} ++ ++/* ++ * eio_iosize_hist_open ++ */ ++static int eio_iosize_hist_open(struct inode *inode, struct file *file) ++{ ++ ++ return single_open(file, &eio_iosize_hist_show, PDE_DATA(inode)); ++} ++ ++/* ++ * eio_version_show ++ */ ++static int eio_version_show(struct seq_file *seq, void *v) ++{ ++ char buf[128]; ++ ++ memset(buf, 0, sizeof(buf)); ++ eio_version_query(sizeof(buf), buf); ++ seq_printf(seq, "%s\n", buf); ++ ++ return 0; ++} ++ ++/* ++ * eio_version_open ++ */ ++static int eio_version_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, &eio_version_show, PDE_DATA(inode)); ++} ++ ++/* ++ * eio_config_show ++ */ ++static int eio_config_show(struct seq_file *seq, void *v) ++{ ++ struct cache_c *dmc = seq->private; ++ ++ seq_printf(seq, "src_name %s\n", dmc->disk_devname); ++ seq_printf(seq, "ssd_name %s\n", dmc->cache_devname); ++ seq_printf(seq, "src_size %lu\n", (long unsigned int)dmc->disk_size); ++ seq_printf(seq, "ssd_size %lu\n", (long unsigned int)dmc->size); ++ ++ seq_printf(seq, "set_size %10u\n", dmc->assoc); ++ seq_printf(seq, "block_size %10u\n", (dmc->block_size) << SECTOR_SHIFT); ++ seq_printf(seq, "mode %10u\n", dmc->mode); ++ seq_printf(seq, "eviction %10u\n", dmc->req_policy); ++ seq_printf(seq, "num_sets %10u\n", dmc->num_sets); ++ seq_printf(seq, "num_blocks %10lu\n", (long unsigned int)dmc->size); ++ seq_printf(seq, "metadata %s\n", ++ CACHE_MD8_IS_SET(dmc) ? "large" : "small"); ++ seq_printf(seq, "state %s\n", ++ CACHE_DEGRADED_IS_SET(dmc) ? "degraded" ++ : (CACHE_FAILED_IS_SET(dmc) ? "failed" : "normal")); ++ seq_printf(seq, "flags 0x%08x\n", dmc->cache_flags); ++ ++ return 0; ++} ++ ++/* ++ * eio_config_open ++ */ ++static int eio_config_open(struct inode *inode, struct file *file) ++{ ++ ++ return single_open(file, &eio_config_show, PDE_DATA(inode)); ++} +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_rand.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_rand.c +--- linux-3.10.30/drivers/block/enhanceio/eio_rand.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_rand.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,201 @@ ++/* ++ * eio_rand.c ++ * ++ * Copyright (C) 2013 ProfitBricks, GmbH. ++ * Jack Wang ++ * Dongsu Park ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * ++ * Copyright 2010 Facebook, Inc. ++ * Author: Mohan Srinivasan (mohan@facebook.com) ++ * ++ * Based on DM-Cache: ++ * Copyright (C) International Business Machines Corp., 2006 ++ * Author: Ming Zhao (mingzhao@ufl.edu) ++ * ++ * 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; under 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, see . ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include "eio.h" ++/* Generic policy functions prototypes */ ++int eio_rand_init(struct cache_c *); ++void eio_rand_exit(void); ++int eio_rand_cache_sets_init(struct eio_policy *); ++int eio_rand_cache_blk_init(struct eio_policy *); ++void eio_rand_find_reclaim_dbn(struct eio_policy *, index_t, index_t *); ++int eio_rand_clean_set(struct eio_policy *, index_t, int); ++ ++/* Per policy instance initialization */ ++struct eio_policy *eio_rand_instance_init(void); ++ ++ ++/* ++ * Context that captures the rand replacement policy ++ */ ++static struct eio_policy_header eio_rand_ops = { ++ .sph_name = CACHE_REPL_RANDOM, ++ .sph_instance_init = eio_rand_instance_init, ++}; ++ ++/* ++ * Initialize RAND policy. ++ */ ++int eio_rand_init(struct cache_c *dmc) ++{ ++ return 0; ++} ++ ++/* ++ * Initialize rand data structure called from ctr. ++ */ ++int eio_rand_cache_sets_init(struct eio_policy *p_ops) ++{ ++ return 0; ++} ++ ++/* ++ * The actual function that returns a victim block in index. ++ */ ++void ++eio_rand_find_reclaim_dbn(struct eio_policy *p_ops, index_t start_index, ++ index_t *index) ++{ ++ int i = 0; ++ index_t idx; ++ ++ struct cache_c *dmc = p_ops->sp_dmc; ++ ++ /* ++ * "start_index" should already be the beginning index of the set. ++ * We're just being cautious here. ++ */ ++ start_index = (start_index / dmc->assoc) * dmc->assoc; ++ for (i = 0; i < (int)dmc->assoc; i++) { ++ idx = dmc->random++ % dmc->assoc; ++ if (EIO_CACHE_STATE_GET(dmc, start_index + idx) == VALID) { ++ *index = start_index + idx; ++ return; ++ } ++ } ++} ++ ++/* ++ * Go through the entire set and clean. ++ */ ++int eio_rand_clean_set(struct eio_policy *p_ops, index_t set, int to_clean) ++{ ++ int i = 0, nr_writes = 0; ++ index_t start_index; ++ ++ struct cache_c *dmc; ++ ++ dmc = p_ops->sp_dmc; ++ ++ start_index = set * dmc->assoc; ++ ++ /* Scan sequentially in the set and pick blocks to clean */ ++ while ((i < (int)dmc->assoc) && (nr_writes < to_clean)) { ++ if ((EIO_CACHE_STATE_GET(dmc, start_index + i) & ++ (DIRTY | BLOCK_IO_INPROG)) == DIRTY) { ++ EIO_CACHE_STATE_ON(dmc, start_index + i, ++ DISKWRITEINPROG); ++ nr_writes++; ++ } ++ i++; ++ } ++ ++ return nr_writes; ++} ++ ++/* ++ * rand is per set, so do nothing on a per block init. ++ */ ++int eio_rand_cache_blk_init(struct eio_policy *p_ops) ++{ ++ return 0; ++} ++ ++/* ++ * Allocate a new instance of eio_policy per dmc ++ */ ++struct eio_policy *eio_rand_instance_init(void) ++{ ++ struct eio_policy *new_instance; ++ ++ new_instance = vmalloc(sizeof(struct eio_policy)); ++ if (new_instance == NULL) { ++ pr_err("ssdscache_rand_instance_init: vmalloc failed"); ++ return NULL; ++ } ++ ++ /* Initialize the rand specific functions and variables */ ++ new_instance->sp_name = CACHE_REPL_RANDOM; ++ new_instance->sp_policy.lru = NULL; ++ new_instance->sp_repl_init = eio_rand_init; ++ new_instance->sp_repl_exit = eio_rand_exit; ++ new_instance->sp_repl_sets_init = eio_rand_cache_sets_init; ++ new_instance->sp_repl_blk_init = eio_rand_cache_blk_init; ++ new_instance->sp_find_reclaim_dbn = eio_rand_find_reclaim_dbn; ++ new_instance->sp_clean_set = eio_rand_clean_set; ++ new_instance->sp_dmc = NULL; ++ ++ try_module_get(THIS_MODULE); ++ ++ pr_info("eio_rand_instance_init: created new instance of RAND"); ++ ++ return new_instance; ++} ++ ++/* ++ * Cleanup an instance of eio_policy (called from dtr). ++ */ ++void eio_rand_exit(void) ++{ ++ module_put(THIS_MODULE); ++} ++ ++static ++int __init rand_register(void) ++{ ++ int ret; ++ ++ ret = eio_register_policy(&eio_rand_ops); ++ if (ret != 0) ++ pr_info("eio_rand already registered"); ++ ++ return ret; ++} ++ ++static ++void __exit rand_unregister(void) ++{ ++ int ret; ++ ++ ret = eio_unregister_policy(&eio_rand_ops); ++ if (ret != 0) ++ pr_err("eio_rand unregister failed"); ++} ++ ++module_init(rand_register); ++module_exit(rand_unregister); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("RAND policy for EnhanceIO"); ++MODULE_AUTHOR("STEC, Inc. based on code by Facebook"); +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_setlru.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_setlru.c +--- linux-3.10.30/drivers/block/enhanceio/eio_setlru.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_setlru.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,170 @@ ++/* ++ * eio_setlru.c ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Amit Kale ++ * Harish Pujari ++ * Generic lru implementation used mainly for cache sets. ++ * ++ * 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; under 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 ++ */ ++ ++#include "eio.h" ++ ++/* Initialize the lru list */ ++int lru_init(struct lru_ls **llist, index_t max) ++{ ++ index_t i = 0; ++ ++ EIO_ASSERT(max > 0); ++ *llist = vmalloc((sizeof(struct lru_ls) + (max - 1) * sizeof(struct lru_elem))); ++ if (*llist == NULL) ++ return -ENOMEM; ++ ++ (*llist)->ll_head = LRU_NULL; ++ (*llist)->ll_tail = LRU_NULL; ++ (*llist)->ll_max = max; ++ (*llist)->ll_size = 0; ++ ++ for (i = 0; i < max; i++) { ++ (*llist)->ll_elem[i].le_next = LRU_NULL; ++ (*llist)->ll_elem[i].le_prev = LRU_NULL; ++ (*llist)->ll_elem[i].le_key = 0; ++ } ++ ++ return 0; ++} ++ ++/* Uninitialize the lru list */ ++void lru_uninit(struct lru_ls *llist) ++{ ++ if (llist) ++ vfree(llist); ++} ++ ++/* Add a new entry to lru list */ ++int lru_add(struct lru_ls *llist, index_t index, u_int64_t key) ++{ ++ if (!llist || (index >= llist->ll_max)) ++ return -EINVAL; ++ ++ llist->ll_elem[index].le_prev = llist->ll_tail; ++ llist->ll_elem[index].le_next = LRU_NULL; ++ llist->ll_elem[index].le_key = key; ++ ++ if (llist->ll_tail != LRU_NULL) ++ llist->ll_elem[llist->ll_tail].le_next = index; ++ else { ++ EIO_ASSERT(llist->ll_head == LRU_NULL); ++ llist->ll_head = index; ++ } ++ llist->ll_tail = index; ++ llist->ll_size++; ++ ++ return 0; ++} ++ ++/* Remove an entry from the lru list */ ++int lru_rem(struct lru_ls *llist, index_t index) ++{ ++ if (!llist || (index >= llist->ll_max) || (index == LRU_NULL)) ++ return -EINVAL; ++ ++ if (llist->ll_head == LRU_NULL && llist->ll_tail == LRU_NULL) ++ /* ++ * No element in the list. ++ */ ++ return -EINVAL; ++ ++ if (llist->ll_elem[index].le_prev == LRU_NULL && ++ llist->ll_elem[index].le_next == LRU_NULL && ++ llist->ll_head != index && llist->ll_tail != index) ++ /* ++ * Element not in list. ++ */ ++ return 0; ++ ++ if (llist->ll_elem[index].le_prev != LRU_NULL) ++ llist->ll_elem[llist->ll_elem[index].le_prev].le_next = ++ llist->ll_elem[index].le_next; ++ ++ if (llist->ll_elem[index].le_next != LRU_NULL) ++ llist->ll_elem[llist->ll_elem[index].le_next].le_prev = ++ llist->ll_elem[index].le_prev; ++ ++ if (llist->ll_head == index) ++ llist->ll_head = llist->ll_elem[index].le_next; ++ ++ if (llist->ll_tail == index) ++ llist->ll_tail = llist->ll_elem[index].le_prev; ++ ++ llist->ll_elem[index].le_prev = LRU_NULL; ++ llist->ll_elem[index].le_next = LRU_NULL; ++ EIO_ASSERT(llist->ll_size != 0); ++ llist->ll_size--; ++ ++ return 0; ++} ++ ++/* Move up the given lru element */ ++int lru_touch(struct lru_ls *llist, index_t index, u_int64_t key) ++{ ++ if (!llist || (index >= llist->ll_max)) ++ return -EINVAL; ++ ++ if (llist->ll_tail == index) ++ llist->ll_elem[index].le_key = key; ++ else { ++ lru_rem(llist, index); ++ lru_add(llist, index, key); ++ } ++ ++ return 0; ++} ++ ++/* Read the element at the head of the lru */ ++int lru_read_head(struct lru_ls *llist, index_t *index, u_int64_t *key) ++{ ++ if (!llist || !index || !key) ++ return -EINVAL; ++ ++ *index = llist->ll_head; ++ if (llist->ll_head == LRU_NULL) { ++ *index = LRU_NULL; ++ *key = 0; ++ } else { ++ *index = llist->ll_head; ++ *key = llist->ll_elem[*index].le_key; ++ } ++ ++ return 0; ++} ++ ++/* Remove the element at the head of the lru */ ++int lru_rem_head(struct lru_ls *llist, index_t *index, u_int64_t *key) ++{ ++ if (!llist || !index || !key) ++ return -EINVAL; ++ ++ *index = llist->ll_head; ++ if (llist->ll_head == LRU_NULL) { ++ *index = LRU_NULL; ++ *key = 0; ++ } else { ++ *index = llist->ll_head; ++ *key = llist->ll_elem[*index].le_key; ++ lru_rem(llist, *index); ++ } ++ ++ return 0; ++} +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_setlru.h linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_setlru.h +--- linux-3.10.30/drivers/block/enhanceio/eio_setlru.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_setlru.h 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,49 @@ ++/* ++ * eio_setlru.h ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Amit Kale ++ * Harish Pujari ++ * Generic lru implementation used mainly for cache sets ++ * ++ * 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; under 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 ++ */ ++ ++#ifndef _EIO_SETLRU_H_ ++#define _EIO_SETLRU_H_ ++ ++#define LRU_NULL -1 ++ ++struct lru_elem { ++ index_t le_next; ++ index_t le_prev; ++ u_int64_t le_key; ++}; ++ ++struct lru_ls { ++ index_t ll_head; ++ index_t ll_tail; ++ index_t ll_max; ++ u_int64_t ll_size; ++ struct lru_elem ll_elem[1]; ++}; ++ ++int lru_init(struct lru_ls **llist, index_t max); ++void lru_uninit(struct lru_ls *llist); ++int lru_add(struct lru_ls *llist, index_t index, u_int64_t key); ++int lru_rem(struct lru_ls *llist, index_t index); ++int lru_touch(struct lru_ls *llist, index_t index, u_int64_t key); ++int lru_read_head(struct lru_ls *llist, index_t *index, u_int64_t *key); ++int lru_rem_head(struct lru_ls *llist, index_t *index, u_int64_t *key); ++ ++#endif /* _EIO_SETLRU_H_ */ +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_subr.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_subr.c +--- linux-3.10.30/drivers/block/enhanceio/eio_subr.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_subr.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,444 @@ ++/* ++ * eio_subr.c ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * Made EnhanceIO specific changes. ++ * Saied Kazemi ++ * Siddharth Choudhuri ++ * ++ * Copyright 2010 Facebook, Inc. ++ * Author: Mohan Srinivasan (mohan@facebook.com) ++ * ++ * Based on DM-Cache: ++ * Copyright (C) International Business Machines Corp., 2006 ++ * Author: Ming Zhao (mingzhao@ufl.edu) ++ * ++ * 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; under 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, see . ++ */ ++ ++#include "eio.h" ++#include "eio_ttc.h" ++ ++static DEFINE_SPINLOCK(_job_lock); ++static LIST_HEAD(_io_jobs); ++static LIST_HEAD(_disk_read_jobs); ++ ++int eio_io_empty(void) ++{ ++ ++ return list_empty(&_io_jobs); ++} ++ ++struct kcached_job *eio_alloc_cache_job(void) ++{ ++ struct kcached_job *job; ++ ++ job = mempool_alloc(_job_pool, GFP_NOIO); ++ if (likely(job)) ++ atomic_inc(&nr_cache_jobs); ++ return job; ++} ++ ++void eio_free_cache_job(struct kcached_job *job) ++{ ++ ++ mempool_free(job, _job_pool); ++ atomic_dec(&nr_cache_jobs); ++} ++ ++/* ++ * Functions to push and pop a job onto the head of a given job list. ++ */ ++static struct kcached_job *eio_pop(struct list_head *jobs) ++{ ++ struct kcached_job *job = NULL; ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&_job_lock, flags); ++ if (!list_empty(jobs)) { ++ job = list_entry(jobs->next, struct kcached_job, list); ++ list_del(&job->list); ++ } ++ spin_unlock_irqrestore(&_job_lock, flags); ++ return job; ++} ++ ++static void eio_push(struct list_head *jobs, struct kcached_job *job) ++{ ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(&_job_lock, flags); ++ list_add_tail(&job->list, jobs); ++ spin_unlock_irqrestore(&_job_lock, flags); ++} ++ ++void eio_push_ssdread_failures(struct kcached_job *job) ++{ ++ ++ eio_push(&_disk_read_jobs, job); ++} ++ ++static void ++eio_process_jobs(struct list_head *jobs, void (*fn) (struct kcached_job *)) ++{ ++ struct kcached_job *job; ++ ++ while ((job = eio_pop(jobs)) != NULL) ++ (void)fn(job); ++} ++ ++static void eio_process_ssd_rm_list(void) ++{ ++ unsigned long int flags = 0; ++ struct ssd_rm_list *ssd_list_ptr; ++ extern int ssd_rm_list_not_empty; ++ extern spinlock_t ssd_rm_list_lock; ++ extern struct list_head ssd_rm_list; ++ ++ spin_lock_irqsave(&ssd_rm_list_lock, flags); ++ if (likely(list_empty(&ssd_rm_list))) { ++ spin_unlock_irqrestore(&ssd_rm_list_lock, flags); ++ return; ++ } ++ ++ while (!list_empty(&ssd_rm_list)) { ++ ssd_list_ptr = ++ list_entry(ssd_rm_list.next, struct ssd_rm_list, list); ++ if (ssd_list_ptr->action == BUS_NOTIFY_DEL_DEVICE) ++ eio_suspend_caching(ssd_list_ptr->dmc, ++ ssd_list_ptr->note); ++ else ++ pr_err("eio_process_ssd_rm_list:" ++ "Unknown status (0x%x)\n", ssd_list_ptr->action); ++ list_del(&ssd_list_ptr->list); ++ kfree(ssd_list_ptr); ++ } ++ ssd_rm_list_not_empty = 0; ++ spin_unlock_irqrestore(&ssd_rm_list_lock, flags); ++} ++ ++/* ++ * Entry point of the "events" kernel thread. ++ */ ++void eio_do_work(struct work_struct *unused) ++{ ++ extern int ssd_rm_list_not_empty; ++ ++ if (unlikely(ssd_rm_list_not_empty)) ++ eio_process_ssd_rm_list(); ++ eio_process_jobs(&_disk_read_jobs, eio_ssderror_diskread); ++} ++ ++struct kcached_job *eio_new_job(struct cache_c *dmc, struct eio_bio *bio, ++ index_t index) ++{ ++ struct kcached_job *job; ++ ++ EIO_ASSERT((bio != NULL) || (index != -1)); ++ ++ job = eio_alloc_cache_job(); ++ if (unlikely(job == NULL)) { ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->eio_errors.memory_alloc_errors++; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ return NULL; ++ } ++ job->dmc = dmc; ++ job->index = index; ++ job->error = 0; ++ job->ebio = bio; ++ if (index != -1) { ++ job->job_io_regions.cache.bdev = dmc->cache_dev->bdev; ++ if (bio) { ++ job->job_io_regions.cache.sector = ++ (index << dmc->block_shift) + dmc->md_sectors + ++ (bio->eb_sector - ++ EIO_ROUND_SECTOR(dmc, bio->eb_sector)); ++ EIO_ASSERT(eio_to_sector(bio->eb_size) <= ++ dmc->block_size); ++ job->job_io_regions.cache.count = ++ eio_to_sector(bio->eb_size); ++ } else { ++ job->job_io_regions.cache.sector = ++ (index << dmc->block_shift) + dmc->md_sectors; ++ job->job_io_regions.cache.count = dmc->block_size; ++ } ++ } ++ ++ job->job_io_regions.disk.bdev = dmc->disk_dev->bdev; ++ if (bio) { ++ job->job_io_regions.disk.sector = bio->eb_sector; ++ job->job_io_regions.disk.count = eio_to_sector(bio->eb_size); ++ } else { ++ job->job_io_regions.disk.sector = EIO_DBN_GET(dmc, index); ++ job->job_io_regions.disk.count = dmc->block_size; ++ } ++ job->next = NULL; ++ job->md_sector = NULL; ++ ++ return job; ++} ++ ++int ++eio_io_sync_pages(struct cache_c *dmc, struct eio_io_region *where, int rw, ++ struct page **pages, int num_bvecs) ++{ ++ struct eio_io_request req; ++ int error; ++ ++ req.mtype = EIO_PAGES; ++ req.dptr.plist = pages; ++ req.num_bvecs = num_bvecs; ++ req.notify = NULL; ++ req.context = NULL; ++ req.hddio = 0; ++ ++ if ((unlikely(CACHE_FAILED_IS_SET(dmc)) || ++ unlikely(CACHE_DEGRADED_IS_SET(dmc))) && ++ (!CACHE_SSD_ADD_INPROG_IS_SET(dmc))) ++ error = -ENODEV; ++ else ++ error = eio_do_io(dmc, where, rw, &req); ++ ++ if (error) ++ return error; ++ ++ return 0; ++} ++ ++int ++eio_io_sync_vm(struct cache_c *dmc, struct eio_io_region *where, int rw, ++ struct bio_vec *pages, int num_bvecs) ++{ ++ struct eio_io_request req; ++ int error; ++ ++ memset((char *)&req, 0, sizeof(req)); ++ /* Fill up the appropriate fields ++ * in eio_io_request */ ++ req.mtype = EIO_BVECS; ++ req.dptr.pages = pages; ++ req.num_bvecs = num_bvecs; ++ req.notify = NULL; ++ req.context = NULL; ++ req.hddio = 0; ++ if ((unlikely(CACHE_FAILED_IS_SET(dmc)) || ++ unlikely(CACHE_DEGRADED_IS_SET(dmc))) && ++ (!CACHE_SSD_ADD_INPROG_IS_SET(dmc))) ++ error = -ENODEV; ++ else ++ error = eio_do_io(dmc, where, rw, &req); ++ if (error) ++ return error; ++ return 0; ++} ++ ++void eio_unplug_cache_device(struct cache_c *dmc) ++{ ++ struct request_queue *q; ++ struct block_device *bdev; ++ ++ if (unlikely(CACHE_FAILED_IS_SET(dmc)) || ++ unlikely(CACHE_DEGRADED_IS_SET(dmc))) ++ return; ++ bdev = dmc->cache_dev->bdev; ++ q = bdev_get_queue(bdev); ++} ++ ++void eio_unplug_disk_device(struct cache_c *dmc) ++{ ++ struct request_queue *q; ++ struct block_device *bdev; ++ ++ if (unlikely(CACHE_DEGRADED_IS_SET(dmc))) ++ return; ++ bdev = dmc->disk_dev->bdev; ++ q = bdev_get_queue(bdev); ++} ++ ++void eio_plug_cache_device(struct cache_c *dmc) ++{ ++ struct block_device *bdev; ++ struct request_queue *q; ++ ++ if (unlikely(CACHE_FAILED_IS_SET(dmc)) || ++ unlikely(CACHE_DEGRADED_IS_SET(dmc))) ++ return; ++ bdev = dmc->cache_dev->bdev; ++ q = bdev_get_queue(bdev); ++} ++ ++void eio_plug_disk_device(struct cache_c *dmc) ++{ ++ struct block_device *bdev; ++ struct request_queue *q; ++ ++ if (unlikely(CACHE_DEGRADED_IS_SET(dmc))) ++ return; ++ bdev = dmc->disk_dev->bdev; ++ q = bdev_get_queue(bdev); ++} ++ ++/* ++ * For Linux, we do not do a dm_put_device() when the device underneath ++ * disappears. The logic to handle the IOs to a missing device is handled ++ * by the kernel proper. We will get an IO error if an IO is done on a ++ * device that does not exist. ++ */ ++void eio_suspend_caching(struct cache_c *dmc, enum dev_notifier note) ++{ ++ ++ spin_lock_irqsave(&dmc->cache_spin_lock, dmc->cache_spin_lock_flags); ++ if (dmc->mode != CACHE_MODE_WB && CACHE_FAILED_IS_SET(dmc)) { ++ pr_err("suspend caching: Cache " ++ "%s is already in FAILED state\n", dmc->cache_name); ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ return; ++ } ++ ++ switch (note) { ++ ++ case NOTIFY_SRC_REMOVED: ++ if (CACHE_DEGRADED_IS_SET(dmc)) ++ dmc->cache_flags &= ~CACHE_FLAGS_DEGRADED; ++ dmc->cache_flags |= CACHE_FLAGS_FAILED; ++ dmc->eio_errors.no_source_dev = 1; ++ atomic64_set(&dmc->eio_stats.cached_blocks, 0); ++ pr_info("suspend_caching: Source Device Removed." ++ "Cache \"%s\" is in Failed mode.\n", dmc->cache_name); ++ break; ++ case NOTIFY_SSD_REMOVED: ++ if (dmc->mode == CACHE_MODE_WB) { ++ /* ++ * For writeback ++ * - Cache should never be in degraded mode ++ * - ssd removal should result in FAILED state ++ * - the cached block should not be reset. ++ */ ++ EIO_ASSERT(!CACHE_DEGRADED_IS_SET(dmc)); ++ dmc->cache_flags |= CACHE_FLAGS_FAILED; ++ pr_info("suspend caching: SSD Device Removed.\ ++ Cache \"%s\" is in Failed mode.\n", dmc->cache_name); ++ } else { ++ if (CACHE_DEGRADED_IS_SET(dmc) || ++ CACHE_SSD_ADD_INPROG_IS_SET(dmc)) { ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc-> ++ cache_spin_lock_flags); ++ pr_err("suspend_caching: Cache \ ++ \"%s\" is either degraded \ ++ or device add in progress, exiting.\n", dmc->cache_name); ++ return; ++ } ++ dmc->cache_flags |= CACHE_FLAGS_DEGRADED; ++ atomic64_set(&dmc->eio_stats.cached_blocks, 0); ++ pr_info("suspend caching: Cache \"%s\" \ ++ is in Degraded mode.\n", dmc->cache_name); ++ } ++ dmc->eio_errors.no_cache_dev = 1; ++ break; ++ default: ++ pr_err("suspend_caching: incorrect notify message.\n"); ++ break; ++ } ++ ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++} ++ ++void eio_put_cache_device(struct cache_c *dmc) ++{ ++ ++ eio_ttc_put_device(&dmc->cache_dev); ++} ++ ++void eio_resume_caching(struct cache_c *dmc, char *dev) ++{ ++ int r; ++ ++ if (dmc == NULL || dev == NULL) { ++ pr_err("resume_caching: Null device or" ++ "cache instance when resuming caching.\n"); ++ return; ++ } ++ if (strlen(dev) >= DEV_PATHLEN) { ++ pr_err("resume_caching: Device name %s too long.\n", dev); ++ return; ++ } ++ ++ spin_lock_irqsave(&dmc->cache_spin_lock, dmc->cache_spin_lock_flags); ++ if (CACHE_STALE_IS_SET(dmc)) { ++ pr_err("eio_resume_caching: Hard Failure Detected!!" ++ "Cache \"%s\" can not be resumed.", dmc->cache_name); ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ return; ++ } ++ ++ /* sanity check for writeback */ ++ if (dmc->mode == CACHE_MODE_WB) { ++ if (!CACHE_FAILED_IS_SET(dmc) || CACHE_SRC_IS_ABSENT(dmc) || ++ CACHE_SSD_ADD_INPROG_IS_SET(dmc)) { ++ pr_debug("eio_resume_caching: Cache not in Failed " ++ "state or Source is absent" ++ "or SSD add already in progress for cache \"%s\".\n", ++ dmc->cache_name); ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ return; ++ } ++ } else { ++ /* sanity check for WT or RO cache. */ ++ if (CACHE_FAILED_IS_SET(dmc) || !CACHE_DEGRADED_IS_SET(dmc) || ++ CACHE_SSD_ADD_INPROG_IS_SET(dmc)) { ++ pr_err("resume_caching: Cache \"%s\" " ++ "is either in failed mode or " ++ "cache device add in progress, ignoring.\n ", ++ dmc->cache_name); ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ return; ++ } ++ } ++ ++ dmc->cache_flags |= CACHE_FLAGS_SSD_ADD_INPROG; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ r = eio_ctr_ssd_add(dmc, dev); ++ if (r) { ++ /* error */ ++ pr_debug(" resume caching: returned error: %d\n ", r); ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->cache_flags &= ~CACHE_FLAGS_SSD_ADD_INPROG; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ return; ++ } ++ ++ spin_lock_irqsave(&dmc->cache_spin_lock, dmc->cache_spin_lock_flags); ++ dmc->eio_errors.no_cache_dev = 0; ++ if (dmc->mode != CACHE_MODE_WB) ++ dmc->cache_flags &= ~CACHE_FLAGS_DEGRADED; ++ else ++ dmc->cache_flags &= ~CACHE_FLAGS_FAILED; ++ dmc->cache_flags &= ~CACHE_FLAGS_SSD_ADD_INPROG; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ pr_info(" resume_caching:cache %s is restored to ACTIVE mode.\n", ++ dmc->cache_name); ++} +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_ttc.c linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_ttc.c +--- linux-3.10.30/drivers/block/enhanceio/eio_ttc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_ttc.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,1665 @@ ++/* ++ * True Transparent Caching (TTC) code. ++ * eio_ttc.c ++ * ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved ++ * ++ * Made EIO fully transparent with respect to applications. A cache can be ++ * created or deleted while a filesystem or applications are online ++ * Amit Kale ++ * Ramprasad Chinthekindi ++ * Akhil Bhansali ++ * ++ * 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; under 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, see . ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "eio.h" ++#include "eio_ttc.h" ++static struct rw_semaphore eio_ttc_lock[EIO_HASHTBL_SIZE]; ++static struct list_head eio_ttc_list[EIO_HASHTBL_SIZE]; ++ ++int eio_reboot_notified; ++ ++static void eio_make_request_fn(struct request_queue *, struct bio *); ++static void eio_cache_rec_fill(struct cache_c *, struct cache_rec_short *); ++static void eio_bio_end_empty_barrier(struct bio *, int); ++static void eio_issue_empty_barrier_flush(struct block_device *, struct bio *, ++ int, make_request_fn *, int rw_flags); ++static int eio_finish_nrdirty(struct cache_c *); ++static int eio_mode_switch(struct cache_c *, u_int32_t); ++static int eio_policy_switch(struct cache_c *, u_int32_t); ++ ++static int eio_overlap_split_bio(struct request_queue *, struct bio *); ++static struct bio *eio_split_new_bio(struct bio *, struct bio_container *, ++ unsigned *, unsigned *, sector_t); ++static void eio_split_endio(struct bio *, int); ++ ++static int eio_open(struct inode *ip, struct file *filp) ++{ ++ __module_get(THIS_MODULE); ++ return 0; ++} ++ ++static int eio_release(struct inode *ip, struct file *filp) ++{ ++ module_put(THIS_MODULE); ++ return 0; ++} ++ ++static const struct file_operations eio_fops = { ++ .open = eio_open, ++ .release = eio_release, ++ .unlocked_ioctl = eio_ioctl, ++ .compat_ioctl = eio_compact_ioctl, ++ .owner = THIS_MODULE, ++}; ++ ++static struct miscdevice eio_misc = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = MISC_DEVICE, ++ .fops = &eio_fops, ++}; ++ ++int eio_create_misc_device() ++{ ++ return misc_register(&eio_misc); ++} ++ ++int eio_delete_misc_device() ++{ ++ return misc_deregister(&eio_misc); ++} ++ ++int eio_ttc_get_device(const char *path, fmode_t mode, struct eio_bdev **result) ++{ ++ struct block_device *bdev; ++ struct eio_bdev *eio_bdev; ++ ++ static char *eio_holder = "EnhanceIO"; ++ ++ bdev = blkdev_get_by_path(path, mode, eio_holder); ++ if (IS_ERR(bdev)) ++ return PTR_ERR(bdev); ++ ++ eio_bdev = kzalloc(sizeof(*eio_bdev), GFP_KERNEL); ++ if (eio_bdev == NULL) { ++ blkdev_put(bdev, mode); ++ return -ENOMEM; ++ } ++ ++ eio_bdev->bdev = bdev; ++ eio_bdev->mode = mode; ++ *result = eio_bdev; ++ return 0; ++} ++ ++void eio_ttc_put_device(struct eio_bdev **d) ++{ ++ struct eio_bdev *eio_bdev; ++ ++ eio_bdev = *d; ++ blkdev_put(eio_bdev->bdev, eio_bdev->mode); ++ kfree(eio_bdev); ++ *d = NULL; ++ return; ++} ++ ++struct cache_c *eio_cache_lookup(char *name) ++{ ++ struct cache_c *dmc = NULL; ++ int i; ++ ++ for (i = 0; i < EIO_HASHTBL_SIZE; i++) { ++ down_read(&eio_ttc_lock[i]); ++ list_for_each_entry(dmc, &eio_ttc_list[i], cachelist) { ++ if (!strcmp(name, dmc->cache_name)) { ++ up_read(&eio_ttc_lock[i]); ++ return dmc; ++ } ++ } ++ up_read(&eio_ttc_lock[i]); ++ } ++ return NULL; ++} ++ ++int eio_ttc_activate(struct cache_c *dmc) ++{ ++ struct block_device *bdev; ++ struct request_queue *rq; ++ make_request_fn *origmfn; ++ struct cache_c *dmc1; ++ int wholedisk; ++ int error; ++ int index; ++ int rw_flags = 0; ++ ++ bdev = dmc->disk_dev->bdev; ++ if (bdev == NULL) { ++ pr_err("cache_create: Source device not found\n"); ++ return -ENODEV; ++ } ++ rq = bdev->bd_disk->queue; ++ ++ wholedisk = 0; ++ if (bdev == bdev->bd_contains) ++ wholedisk = 1; ++ ++ dmc->dev_start_sect = bdev->bd_part->start_sect; ++ dmc->dev_end_sect = ++ bdev->bd_part->start_sect + bdev->bd_part->nr_sects - 1; ++ ++ pr_debug("eio_ttc_activate: Device/Partition" \ ++ " sector_start: %llu, end: %llu\n", ++ (uint64_t)dmc->dev_start_sect, (uint64_t)dmc->dev_end_sect); ++ ++ error = 0; ++ origmfn = NULL; ++ index = EIO_HASH_BDEV(bdev->bd_contains->bd_dev); ++ ++ down_write(&eio_ttc_lock[index]); ++ list_for_each_entry(dmc1, &eio_ttc_list[index], cachelist) { ++ if (dmc1->disk_dev->bdev->bd_contains != bdev->bd_contains) ++ continue; ++ ++ if ((wholedisk) || (dmc1->dev_info == EIO_DEV_WHOLE_DISK) || ++ (dmc1->disk_dev->bdev == bdev)) { ++ error = -EINVAL; ++ up_write(&eio_ttc_lock[index]); ++ goto out; ++ } ++ ++ /* some partition of same device already cached */ ++ EIO_ASSERT(dmc1->dev_info == EIO_DEV_PARTITION); ++ origmfn = dmc1->origmfn; ++ break; ++ } ++ ++ /* ++ * Save original make_request_fn. Switch make_request_fn only once. ++ */ ++ ++ if (origmfn) { ++ dmc->origmfn = origmfn; ++ dmc->dev_info = EIO_DEV_PARTITION; ++ EIO_ASSERT(wholedisk == 0); ++ } else { ++ dmc->origmfn = rq->make_request_fn; ++ rq->make_request_fn = eio_make_request_fn; ++ dmc->dev_info = ++ (wholedisk) ? EIO_DEV_WHOLE_DISK : EIO_DEV_PARTITION; ++ } ++ ++ list_add_tail(&dmc->cachelist, &eio_ttc_list[index]); ++ ++ /* ++ * Sleep for sometime, to allow previous I/Os to hit ++ * Issue a barrier I/O on Source device. ++ */ ++ ++ msleep(1); ++ SET_BARRIER_FLAGS(rw_flags); ++ eio_issue_empty_barrier_flush(dmc->disk_dev->bdev, NULL, ++ EIO_HDD_DEVICE, dmc->origmfn, rw_flags); ++ up_write(&eio_ttc_lock[index]); ++ ++out: ++ if (error == -EINVAL) { ++ if (wholedisk) ++ pr_err ++ ("cache_create: A partition of this device is already cached.\n"); ++ else ++ pr_err("cache_create: Device is already cached.\n"); ++ } ++ return error; ++} ++ ++int eio_ttc_deactivate(struct cache_c *dmc, int force) ++{ ++ struct block_device *bdev; ++ struct request_queue *rq; ++ struct cache_c *dmc1; ++ int found_partitions; ++ int index; ++ int ret; ++ ++ ret = 0; ++ bdev = dmc->disk_dev->bdev; ++ rq = bdev->bd_disk->queue; ++ ++ if (force) ++ goto deactivate; ++ ++ /* Process and wait for nr_dirty to drop to zero */ ++ if (dmc->mode == CACHE_MODE_WB) { ++ if (!CACHE_FAILED_IS_SET(dmc)) { ++ ret = eio_finish_nrdirty(dmc); ++ if (ret) { ++ pr_err ++ ("ttc_deactivate: nrdirty failed to finish for cache \"%s\".", ++ dmc->cache_name); ++ return ret; ++ } ++ } else ++ pr_debug ++ ("ttc_deactivate: Cache \"%s\" failed is already set. Continue with cache delete.", ++ dmc->cache_name); ++ } ++ ++ /* ++ * Traverse the list and see if other partitions of this device are ++ * cached. Switch mfn if this is the only partition of the device ++ * in the list. ++ */ ++deactivate: ++ index = EIO_HASH_BDEV(bdev->bd_contains->bd_dev); ++ found_partitions = 0; ++ ++ /* check if barrier QUEUE is empty or not */ ++ down_write(&eio_ttc_lock[index]); ++ ++ if (dmc->dev_info != EIO_DEV_WHOLE_DISK) ++ list_for_each_entry(dmc1, &eio_ttc_list[index], cachelist) { ++ if (dmc == dmc1) ++ continue; ++ ++ if (dmc1->disk_dev->bdev->bd_contains != bdev->bd_contains) ++ continue; ++ ++ EIO_ASSERT(dmc1->dev_info == EIO_DEV_PARTITION); ++ ++ /* ++ * There are still other partitions which are cached. ++ * Do not switch the make_request_fn. ++ */ ++ ++ found_partitions = 1; ++ break; ++ } ++ ++ if ((dmc->dev_info == EIO_DEV_WHOLE_DISK) || (found_partitions == 0)) ++ rq->make_request_fn = dmc->origmfn; ++ ++ list_del_init(&dmc->cachelist); ++ up_write(&eio_ttc_lock[index]); ++ ++ /* wait for nr_ios to drain-out */ ++ while (atomic64_read(&dmc->nr_ios) != 0) ++ schedule_timeout(msecs_to_jiffies(100)); ++ ++ return ret; ++} ++ ++void eio_ttc_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < EIO_HASHTBL_SIZE; i++) { ++ init_rwsem(&eio_ttc_lock[i]); ++ INIT_LIST_HEAD(&eio_ttc_list[i]); ++ } ++} ++ ++/* ++ * Cases:- ++ * 1. Full device cached. ++ * if (ENQUEUE || barrier(bio)) ++ * enqueue (dmc, bio) and return ++ * else ++ * call eio_map(dmc, bio) ++ * 2. Some partitions of the device cached. ++ * if (ENQUEUE || barrier(bio)) ++ * All I/Os (both on cached and uncached partitions) are enqueued. ++ * else ++ * if (I/O on cached partition) ++ * call eio_map(dmc, bio) ++ * else ++ * origmfn(bio); // uncached partition ++ * 3. q->mfn got switched back to original ++ * call origmfn(q, bio) ++ * 4. Race condition: ++ */ ++ ++static void eio_make_request_fn(struct request_queue *q, struct bio *bio) ++{ ++ int ret; ++ int overlap; ++ int index; ++ make_request_fn *origmfn; ++ struct cache_c *dmc, *dmc1; ++ struct block_device *bdev; ++ ++ bdev = bio->bi_bdev; ++ ++re_lookup: ++ dmc = NULL; ++ origmfn = NULL; ++ overlap = ret = 0; ++ ++ index = EIO_HASH_BDEV(bdev->bd_contains->bd_dev); ++ ++ down_read(&eio_ttc_lock[index]); ++ ++ list_for_each_entry(dmc1, &eio_ttc_list[index], cachelist) { ++ if (dmc1->disk_dev->bdev->bd_contains != bdev->bd_contains) ++ continue; ++ ++ if (dmc1->dev_info == EIO_DEV_WHOLE_DISK) { ++ dmc = dmc1; /* found cached device */ ++ break; ++ } ++ ++ /* Handle partitions */ ++ if (!origmfn) ++ origmfn = dmc1->origmfn; ++ ++ /* I/O perfectly fit within cached partition */ ++ if ((bio->bi_sector >= dmc1->dev_start_sect) && ++ ((bio->bi_sector + eio_to_sector(bio->bi_size) - 1) <= ++ dmc1->dev_end_sect)) { ++ EIO_ASSERT(overlap == 0); ++ dmc = dmc1; /* found cached partition */ ++ break; ++ } ++ ++ /* Check if I/O is overlapping with cached partitions */ ++ if (((bio->bi_sector >= dmc1->dev_start_sect) && ++ (bio->bi_sector <= dmc1->dev_end_sect)) || ++ ((bio->bi_sector + eio_to_sector(bio->bi_size) - 1 >= ++ dmc1->dev_start_sect) && ++ (bio->bi_sector + eio_to_sector(bio->bi_size) - 1 <= ++ dmc1->dev_end_sect))) { ++ overlap = 1; ++ pr_err ++ ("Overlapping I/O detected on %s cache at sector: %llu, size: %u\n", ++ dmc1->cache_name, (uint64_t)bio->bi_sector, ++ bio->bi_size); ++ break; ++ } ++ } ++ ++ if (unlikely(overlap)) { ++ up_read(&eio_ttc_lock[index]); ++ ++ if (bio_rw_flagged(bio, REQ_DISCARD)) { ++ pr_err ++ ("eio_mfn: Overlap I/O with Discard flag." \ ++ " Discard flag is not supported.\n"); ++ bio_endio(bio, -EOPNOTSUPP); ++ } else ++ ret = eio_overlap_split_bio(q, bio); ++ } else if (dmc) { /* found cached partition or device */ ++ /* ++ * Start sector of cached partition may or may not be ++ * aligned with cache blocksize. ++ * Map start of the partition to zero reference. ++ */ ++ ++ if (bio->bi_sector) { ++ EIO_ASSERT(bio->bi_sector >= dmc->dev_start_sect); ++ bio->bi_sector -= dmc->dev_start_sect; ++ } ++ ret = eio_map(dmc, q, bio); ++ if (ret) ++ /* Error case: restore the start sector of bio */ ++ bio->bi_sector += dmc->dev_start_sect; ++ } ++ ++ if (!overlap) ++ up_read(&eio_ttc_lock[index]); ++ ++ if (overlap || dmc) ++ return; ++ ++ /* ++ * Race condition:- ++ * origmfn can be NULL if all partitions or whole disk got uncached. ++ * We set origmfn = q->mfn if origmfn is NULL. ++ * The origmfn may now again be eio_make_request_fn because ++ * someone else switched the q->mfn because of a new ++ * partition or whole disk being cached. ++ * Since, we cannot protect q->make_request_fn() by any lock, ++ * this situation may occur. However, this is a very rare event. ++ * In this case restart the lookup. ++ */ ++ ++ if (origmfn == NULL) ++ origmfn = q->make_request_fn; ++ if (origmfn == eio_make_request_fn) ++ goto re_lookup; ++ ++ origmfn(q, bio); ++ return; ++} ++ ++uint64_t eio_get_cache_count(void) ++{ ++ struct cache_c *dmc; ++ uint64_t cnt = 0; ++ int i; ++ ++ for (i = 0; i < EIO_HASHTBL_SIZE; i++) { ++ down_read(&eio_ttc_lock[i]); ++ list_for_each_entry(dmc, &eio_ttc_list[i], cachelist) { ++ cnt++; ++ } ++ up_read(&eio_ttc_lock[i]); ++ } ++ return cnt; ++} ++ ++int eio_get_cache_list(unsigned long *arg) ++{ ++ int error = 0; ++ unsigned int size, i, j; ++ struct cache_list reclist; ++ struct cache_rec_short *cache_recs; ++ struct cache_c *dmc; ++ ++ if (copy_from_user(&reclist, (struct cache_list __user *)arg, ++ sizeof(struct cache_list))) { ++ error = -EFAULT; ++ goto out; ++ } ++ ++ size = reclist.ncaches * sizeof(struct cache_rec_short); ++ cache_recs = vmalloc(size); ++ if (!cache_recs) { ++ error = -ENOMEM; ++ goto out; ++ } ++ memset(cache_recs, 0, size); ++ ++ i = 0; ++ for (j = 0; j < EIO_HASHTBL_SIZE; j++) { ++ down_read(&eio_ttc_lock[j]); ++ list_for_each_entry(dmc, &eio_ttc_list[j], cachelist) { ++ eio_cache_rec_fill(dmc, &cache_recs[i]); ++ i++; ++ ++ if (i == reclist.ncaches) ++ break; ++ } ++ up_read(&eio_ttc_lock[j]); ++ ++ if (i == reclist.ncaches) ++ break; ++ } ++ ++ if (copy_to_user((char __user *)reclist.cachelist, ++ (char *)cache_recs, size)) { ++ error = -EFAULT; ++ goto out; ++ } ++ ++ if (copy_to_user((struct cache_list __user *)arg, &reclist, ++ sizeof(struct cache_list))) { ++ error = -EFAULT; ++ goto out; ++ } ++ ++out: ++ return error; ++} ++ ++static void eio_cache_rec_fill(struct cache_c *dmc, struct cache_rec_short *rec) ++{ ++ strncpy(rec->cr_name, dmc->cache_name, sizeof(rec->cr_name) - 1); ++ strncpy(rec->cr_src_devname, dmc->disk_devname, ++ sizeof(rec->cr_src_devname) - 1); ++ strncpy(rec->cr_ssd_devname, dmc->cache_devname, ++ sizeof(rec->cr_ssd_devname) - 1); ++ rec->cr_src_dev_size = eio_get_device_size(dmc->disk_dev); ++ rec->cr_ssd_dev_size = eio_get_device_size(dmc->cache_dev); ++ rec->cr_src_sector_size = 0; /* unused in userspace */ ++ rec->cr_ssd_sector_size = 0; /* unused in userspace */ ++ rec->cr_flags = dmc->cache_flags; ++ rec->cr_policy = dmc->req_policy; ++ rec->cr_mode = dmc->mode; ++ rec->cr_persistence = dmc->persistence; ++ rec->cr_blksize = dmc->block_size; /* In sectors */ ++ rec->cr_assoc = dmc->assoc; ++ return; ++} ++ ++/* ++ * Few sanity checks before cache creation. ++ */ ++ ++int eio_do_preliminary_checks(struct cache_c *dmc) ++{ ++ struct block_device *bdev, *ssd_bdev; ++ struct cache_c *dmc1; ++ int error; ++ int wholedisk; ++ int index; ++ ++ error = wholedisk = 0; ++ bdev = dmc->disk_dev->bdev; ++ ssd_bdev = dmc->cache_dev->bdev; ++ ++ /* ++ * Disallow cache creation if source and cache device ++ * belong to same device. ++ */ ++ ++ if (bdev->bd_contains == ssd_bdev->bd_contains) ++ return -EINVAL; ++ ++ /* ++ * Check if cache with same name exists. ++ */ ++ ++ if (eio_cache_lookup(dmc->cache_name)) ++ return -EEXIST; ++ ++ if (bdev == bdev->bd_contains) ++ wholedisk = 1; ++ ++ index = EIO_HASH_BDEV(bdev->bd_contains->bd_dev); ++ ++ down_read(&eio_ttc_lock[index]); ++ list_for_each_entry(dmc1, &eio_ttc_list[index], cachelist) { ++ if (dmc1->disk_dev->bdev->bd_contains != bdev->bd_contains) ++ continue; ++ ++ if ((wholedisk) || (dmc1->dev_info == EIO_DEV_WHOLE_DISK) || ++ (dmc1->disk_dev->bdev == bdev)) { ++ error = -EINVAL; ++ break; ++ } ++ } ++ up_read(&eio_ttc_lock[index]); ++ return error; ++} ++ ++/* Use mempool_alloc and free for io in sync_io as well */ ++static void eio_dec_count(struct eio_context *io, int error) ++{ ++ if (error) ++ io->error = error; ++ ++ if (atomic_dec_and_test(&io->count)) { ++ if (io->event) ++ complete(io->event); ++ else { ++ int err = io->error; ++ eio_notify_fn fn = io->callback; ++ void *context = io->context; ++ ++ mempool_free(io, _io_pool); ++ io = NULL; ++ fn(err, context); ++ } ++ } ++} ++ ++static void eio_endio(struct bio *bio, int error) ++{ ++ struct eio_context *io; ++ ++ io = bio->bi_private; ++ EIO_ASSERT(io != NULL); ++ ++ bio_put(bio); ++ ++ eio_dec_count(io, error); ++} ++ ++static int eio_dispatch_io_pages(struct cache_c *dmc, ++ struct eio_io_region *where, int rw, ++ struct page **pagelist, struct eio_context *io, ++ int hddio, int num_vecs, int sync) ++{ ++ struct bio *bio; ++ struct page *page; ++ unsigned long len; ++ unsigned offset; ++ int num_bvecs; ++ int remaining_bvecs = num_vecs; ++ int ret = 0; ++ int pindex = 0; ++ ++ sector_t remaining = where->count; ++ ++ do { ++ /* Verify that num_vecs should not cross the threshhold */ ++ /* Check how many max bvecs bdev supports */ ++ num_bvecs = ++ min_t(int, bio_get_nr_vecs(where->bdev), remaining_bvecs); ++ bio = bio_alloc(GFP_NOIO, num_bvecs); ++ bio->bi_bdev = where->bdev; ++ bio->bi_sector = where->sector + (where->count - remaining); ++ ++ /* Remap the start sector of partition */ ++ if (hddio) ++ bio->bi_sector += dmc->dev_start_sect; ++ bio->bi_rw |= rw; ++ bio->bi_end_io = eio_endio; ++ bio->bi_private = io; ++ ++ while (remaining) { ++ page = pagelist[pindex]; ++ len = ++ min_t(unsigned long, PAGE_SIZE, ++ to_bytes(remaining)); ++ offset = 0; ++ ++ if (!bio_add_page(bio, page, len, offset)) ++ break; ++ ++ remaining -= eio_to_sector(len); ++ pindex++; ++ remaining_bvecs--; ++ } ++ ++ atomic_inc(&io->count); ++ if (hddio) ++ dmc->origmfn(bdev_get_queue(bio->bi_bdev), bio); ++ ++ else ++ submit_bio(rw, bio); ++ ++ } while (remaining); ++ ++ EIO_ASSERT(remaining_bvecs == 0); ++ return ret; ++} ++ ++/* ++ * This function will dispatch the i/o. It also takes care of ++ * splitting the large I/O requets to smaller I/Os which may not ++ * fit into single bio. ++ */ ++ ++static int eio_dispatch_io(struct cache_c *dmc, struct eio_io_region *where, ++ int rw, struct bio_vec *bvec, struct eio_context *io, ++ int hddio, int num_vecs, int sync) ++{ ++ struct bio *bio; ++ struct page *page; ++ unsigned long len; ++ unsigned offset; ++ int num_bvecs; ++ int remaining_bvecs = num_vecs; ++ int ret = 0; ++ ++ sector_t remaining = where->count; ++ ++ do { ++ /* Verify that num_vecs should not cross the threshhold */ ++ /* Check how many max bvecs bdev supports */ ++ num_bvecs = ++ min_t(int, bio_get_nr_vecs(where->bdev), remaining_bvecs); ++ bio = bio_alloc(GFP_NOIO, num_bvecs); ++ bio->bi_bdev = where->bdev; ++ bio->bi_sector = where->sector + (where->count - remaining); ++ ++ /* Remap the start sector of partition */ ++ if (hddio) ++ bio->bi_sector += dmc->dev_start_sect; ++ bio->bi_rw |= rw; ++ bio->bi_end_io = eio_endio; ++ bio->bi_private = io; ++ ++ while (remaining) { ++ page = bvec->bv_page; ++ len = ++ min_t(unsigned long, bvec->bv_len, ++ to_bytes(remaining)); ++ offset = bvec->bv_offset; ++ ++ if (!bio_add_page(bio, page, len, offset)) ++ break; ++ ++ offset = 0; ++ remaining -= eio_to_sector(len); ++ bvec = bvec + 1; ++ remaining_bvecs--; ++ } ++ ++ atomic_inc(&io->count); ++ if (hddio) ++ dmc->origmfn(bdev_get_queue(bio->bi_bdev), bio); ++ else ++ submit_bio(rw, bio); ++ ++ } while (remaining); ++ ++ EIO_ASSERT(remaining_bvecs == 0); ++ return ret; ++} ++ ++static int eio_async_io(struct cache_c *dmc, struct eio_io_region *where, ++ int rw, struct eio_io_request *req) ++{ ++ struct eio_context *io; ++ int err = 0; ++ ++ io = mempool_alloc(_io_pool, GFP_NOIO); ++ if (unlikely(io == NULL)) { ++ pr_err("eio_async_io: failed to allocate eio_context.\n"); ++ return -ENOMEM; ++ } ++ memset((char *)io, 0, sizeof(struct eio_context)); ++ ++ atomic_set(&io->count, 1); ++ io->callback = req->notify; ++ io->context = req->context; ++ io->event = NULL; ++ ++ switch (req->mtype) { ++ case EIO_BVECS: ++ err = ++ eio_dispatch_io(dmc, where, rw, req->dptr.pages, io, ++ req->hddio, req->num_bvecs, 0); ++ break; ++ ++ case EIO_PAGES: ++ err = ++ eio_dispatch_io_pages(dmc, where, rw, req->dptr.plist, io, ++ req->hddio, req->num_bvecs, 0); ++ break; ++ } ++ ++ /* Check if i/o submission has returned any error */ ++ if (unlikely(err)) { ++ /* Wait for any i/os which are submitted, to end. */ ++retry: ++ if (atomic_read(&io->count) != 1) { ++ schedule_timeout(msecs_to_jiffies(1)); ++ goto retry; ++ } ++ ++ EIO_ASSERT(io != NULL); ++ mempool_free(io, _io_pool); ++ io = NULL; ++ return err; ++ } ++ ++ /* Drop the extra reference count here */ ++ eio_dec_count(io, err); ++ return err; ++} ++ ++static int eio_sync_io(struct cache_c *dmc, struct eio_io_region *where, ++ int rw, struct eio_io_request *req) ++{ ++ int ret = 0; ++ struct eio_context io; ++ ++ DECLARE_COMPLETION_ONSTACK(wait); ++ ++ memset((char *)&io, 0, sizeof(io)); ++ ++ atomic_set(&io.count, 1); ++ io.event = &wait; ++ io.callback = NULL; ++ io.context = NULL; ++ ++ /* For synchronous I/Os pass SYNC */ ++ rw |= REQ_SYNC; ++ ++ switch (req->mtype) { ++ case EIO_BVECS: ++ ret = eio_dispatch_io(dmc, where, rw, req->dptr.pages, ++ &io, req->hddio, req->num_bvecs, 1); ++ break; ++ case EIO_PAGES: ++ ret = eio_dispatch_io_pages(dmc, where, rw, req->dptr.plist, ++ &io, req->hddio, req->num_bvecs, 1); ++ break; ++ } ++ ++ /* Check if i/o submission has returned any error */ ++ if (unlikely(ret)) { ++ /* Wait for any i/os which are submitted, to end. */ ++retry: ++ if (atomic_read(&(io.count)) != 1) { ++ schedule_timeout(msecs_to_jiffies(1)); ++ goto retry; ++ } ++ ++ return ret; ++ } ++ ++ /* Drop extra reference count here */ ++ eio_dec_count(&io, ret); ++ wait_for_completion(&wait); ++ ++ if (io.error) ++ ret = io.error; ++ ++ return ret; ++} ++ ++int eio_do_io(struct cache_c *dmc, struct eio_io_region *where, int rw, ++ struct eio_io_request *io_req) ++{ ++ if (!io_req->notify) ++ return eio_sync_io(dmc, where, rw, io_req); ++ ++ return eio_async_io(dmc, where, rw, io_req); ++} ++ ++void eio_process_zero_size_bio(struct cache_c *dmc, struct bio *origbio) ++{ ++ unsigned long rw_flags = 0; ++ ++ /* Extract bio flags from original bio */ ++ rw_flags = origbio->bi_rw; ++ ++ EIO_ASSERT(origbio->bi_size == 0); ++ EIO_ASSERT(rw_flags != 0); ++ ++ eio_issue_empty_barrier_flush(dmc->cache_dev->bdev, NULL, ++ EIO_SSD_DEVICE, NULL, rw_flags); ++ eio_issue_empty_barrier_flush(dmc->disk_dev->bdev, origbio, ++ EIO_HDD_DEVICE, dmc->origmfn, rw_flags); ++} ++ ++static void eio_bio_end_empty_barrier(struct bio *bio, int err) ++{ ++ if (bio->bi_private) ++ bio_endio(bio->bi_private, err); ++ bio_put(bio); ++ return; ++} ++ ++static void eio_issue_empty_barrier_flush(struct block_device *bdev, ++ struct bio *orig_bio, int device, ++ make_request_fn *origmfn, ++ int rw_flags) ++{ ++ struct bio *bio; ++ ++ bio = bio_alloc(GFP_KERNEL, 0); ++ if (!bio) ++ if (orig_bio) ++ bio_endio(orig_bio, -ENOMEM); ++ bio->bi_end_io = eio_bio_end_empty_barrier; ++ bio->bi_private = orig_bio; ++ bio->bi_bdev = bdev; ++ bio->bi_rw |= rw_flags; ++ ++ bio_get(bio); ++ if (device == EIO_HDD_DEVICE) ++ origmfn(bdev_get_queue(bio->bi_bdev), bio); ++ ++ else ++ submit_bio(0, bio); ++ bio_put(bio); ++ return; ++} ++ ++static int eio_finish_nrdirty(struct cache_c *dmc) ++{ ++ int index; ++ int ret = 0; ++ int retry_count; ++ ++ /* ++ * Due to any transient errors, finish_nr_dirty may not drop ++ * to zero. Retry the clean operations for FINISH_NRDIRTY_RETRY_COUNT. ++ */ ++ retry_count = FINISH_NRDIRTY_RETRY_COUNT; ++ ++ index = EIO_HASH_BDEV(dmc->disk_dev->bdev->bd_contains->bd_dev); ++ down_write(&eio_ttc_lock[index]); ++ ++ /* Wait for the in-flight I/Os to drain out */ ++ while (atomic64_read(&dmc->nr_ios) != 0) { ++ pr_debug("finish_nrdirty: Draining I/O inflight\n"); ++ schedule_timeout(msecs_to_jiffies(1)); ++ } ++ EIO_ASSERT(!(dmc->sysctl_active.do_clean & EIO_CLEAN_START)); ++ ++ dmc->sysctl_active.do_clean |= EIO_CLEAN_KEEP | EIO_CLEAN_START; ++ up_write(&eio_ttc_lock[index]); ++ ++ /* ++ * In the process of cleaning CACHE if CACHE turns to FAILED state, ++ * its a severe error. ++ */ ++ do { ++ if (unlikely(CACHE_FAILED_IS_SET(dmc))) { ++ pr_err ++ ("finish_nrdirty: CACHE \"%s\" is in FAILED state.", ++ dmc->cache_name); ++ ret = -ENODEV; ++ break; ++ } ++ ++ if (!dmc->sysctl_active.fast_remove) ++ eio_clean_all(dmc); ++ } while (!dmc->sysctl_active.fast_remove && ++ (atomic64_read(&dmc->nr_dirty) > 0) ++ && (!(dmc->cache_flags & CACHE_FLAGS_SHUTDOWN_INPROG))); ++ dmc->sysctl_active.do_clean &= ~EIO_CLEAN_START; ++ ++ /* ++ * If all retry_count exhausted and nr_dirty is still not zero. ++ * Return error. ++ */ ++ if (((dmc->cache_flags & CACHE_FLAGS_SHUTDOWN_INPROG) || ++ (retry_count == 0)) && (atomic64_read(&dmc->nr_dirty) > 0)) ++ ret = -EINVAL; ++ if (ret) ++ pr_err ++ ("finish_nrdirty: Failed to finish %llu dirty blocks for cache \"%s\".", ++ (unsigned long long)atomic64_read(&dmc->nr_dirty), dmc->cache_name); ++ ++ return ret; ++} ++ ++int eio_cache_edit(char *cache_name, u_int32_t mode, u_int32_t policy) ++{ ++ int error = 0; ++ int index; ++ struct cache_c *dmc; ++ uint32_t old_time_thresh = 0; ++ int restart_async_task = 0; ++ int ret; ++ ++ EIO_ASSERT((mode != 0) || (policy != 0)); ++ ++ dmc = eio_cache_lookup(cache_name); ++ if (NULL == dmc) { ++ pr_err("cache_edit: cache %s do not exist", cache_name); ++ return -EINVAL; ++ } ++ ++ if ((dmc->mode == mode) && (dmc->req_policy == policy)) ++ return 0; ++ ++ if (unlikely(CACHE_FAILED_IS_SET(dmc)) || ++ unlikely(CACHE_DEGRADED_IS_SET(dmc))) { ++ pr_err("cache_edit: Cannot proceed with edit on cache \"%s\"" \ ++ ". Cache is in failed or degraded state.", ++ dmc->cache_name); ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&dmc->cache_spin_lock, dmc->cache_spin_lock_flags); ++ if (dmc->cache_flags & CACHE_FLAGS_SHUTDOWN_INPROG) { ++ pr_err("cache_edit: system shutdown in progress, cannot edit" \ ++ " cache %s", cache_name); ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ return -EINVAL; ++ } ++ if (dmc->cache_flags & CACHE_FLAGS_MOD_INPROG) { ++ pr_err("cache_edit: simultaneous edit/delete operation on " \ ++ "cache %s is not permitted", cache_name); ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ return -EINVAL; ++ } ++ dmc->cache_flags |= CACHE_FLAGS_MOD_INPROG; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ old_time_thresh = dmc->sysctl_active.time_based_clean_interval; ++ ++ if (dmc->mode == CACHE_MODE_WB) { ++ if (CACHE_FAILED_IS_SET(dmc)) { ++ pr_err ++ ("cache_edit: Can not proceed with edit for Failed cache \"%s\".", ++ dmc->cache_name); ++ error = -EINVAL; ++ goto out; ++ } ++ eio_stop_async_tasks(dmc); ++ restart_async_task = 1; ++ } ++ ++ /* Wait for nr_dirty to drop to zero */ ++ if (dmc->mode == CACHE_MODE_WB && mode != CACHE_MODE_WB) { ++ if (CACHE_FAILED_IS_SET(dmc)) { ++ pr_err ++ ("cache_edit: Can not proceed with edit for Failed cache \"%s\".", ++ dmc->cache_name); ++ error = -EINVAL; ++ goto out; ++ } ++ ++ error = eio_finish_nrdirty(dmc); ++ /* This error can mostly occur due to Device removal */ ++ if (unlikely(error)) { ++ pr_err ++ ("cache_edit: nr_dirty FAILED to finish for cache \"%s\".", ++ dmc->cache_name); ++ goto out; ++ } ++ EIO_ASSERT((dmc->sysctl_active.do_clean & EIO_CLEAN_KEEP) && ++ !(dmc->sysctl_active.do_clean & EIO_CLEAN_START)); ++ EIO_ASSERT(dmc->sysctl_active.fast_remove || ++ (atomic64_read(&dmc->nr_dirty) == 0)); ++ } ++ ++ index = EIO_HASH_BDEV(dmc->disk_dev->bdev->bd_contains->bd_dev); ++ down_write(&eio_ttc_lock[index]); ++ ++ /* Wait for the in-flight I/Os to drain out */ ++ while (atomic64_read(&dmc->nr_ios) != 0) { ++ pr_debug("cache_edit: Draining I/O inflight\n"); ++ schedule_timeout(msecs_to_jiffies(1)); ++ } ++ ++ pr_debug("cache_edit: Blocking application I/O\n"); ++ ++ EIO_ASSERT(atomic64_read(&dmc->nr_ios) == 0); ++ ++ /* policy change */ ++ if ((policy != 0) && (policy != dmc->req_policy)) { ++ error = eio_policy_switch(dmc, policy); ++ if (error) { ++ up_write(&eio_ttc_lock[index]); ++ goto out; ++ } ++ } ++ ++ /* mode change */ ++ if ((mode != 0) && (mode != dmc->mode)) { ++ error = eio_mode_switch(dmc, mode); ++ if (error) { ++ up_write(&eio_ttc_lock[index]); ++ goto out; ++ } ++ } ++ ++ dmc->sysctl_active.time_based_clean_interval = old_time_thresh; ++ /* write updated superblock */ ++ error = eio_sb_store(dmc); ++ if (error) { ++ /* XXX: In case of error put the cache in degraded mode. */ ++ pr_err("eio_cache_edit: superblock update failed(error %d)", ++ error); ++ goto out; ++ } ++ ++ eio_procfs_dtr(dmc); ++ eio_procfs_ctr(dmc); ++ ++ up_write(&eio_ttc_lock[index]); ++ ++out: ++ dmc->sysctl_active.time_based_clean_interval = old_time_thresh; ++ ++ /* ++ * Resetting EIO_CLEAN_START and EIO_CLEAN_KEEP flags. ++ * EIO_CLEAN_START flag should be restored if eio_stop_async_tasks() ++ * is not called in future. ++ */ ++ ++ dmc->sysctl_active.do_clean &= ~(EIO_CLEAN_START | EIO_CLEAN_KEEP); ++ ++ /* Restart async-task for "WB" cache. */ ++ if ((dmc->mode == CACHE_MODE_WB) && (restart_async_task == 1)) { ++ pr_debug("cache_edit: Restarting the clean_thread.\n"); ++ EIO_ASSERT(dmc->clean_thread == NULL); ++ ret = eio_start_clean_thread(dmc); ++ if (ret) { ++ error = ret; ++ pr_err ++ ("cache_edit: Failed to restart async tasks. error=%d.\n", ++ ret); ++ } ++ if (dmc->sysctl_active.time_based_clean_interval && ++ atomic64_read(&dmc->nr_dirty)) { ++ schedule_delayed_work(&dmc->clean_aged_sets_work, ++ dmc-> ++ sysctl_active.time_based_clean_interval ++ * 60 * HZ); ++ dmc->is_clean_aged_sets_sched = 1; ++ } ++ } ++ spin_lock_irqsave(&dmc->cache_spin_lock, dmc->cache_spin_lock_flags); ++ dmc->cache_flags &= ~CACHE_FLAGS_MOD_INPROG; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ pr_debug("eio_cache_edit: Allowing application I/O\n"); ++ return error; ++} ++ ++static int eio_mode_switch(struct cache_c *dmc, u_int32_t mode) ++{ ++ int error = 0; ++ u_int32_t orig_mode; ++ ++ EIO_ASSERT(dmc->mode != mode); ++ pr_debug("eio_mode_switch: mode switch from %u to %u\n", ++ dmc->mode, mode); ++ ++ if (mode == CACHE_MODE_WB) { ++ orig_mode = dmc->mode; ++ dmc->mode = mode; ++ ++ error = eio_allocate_wb_resources(dmc); ++ if (error) { ++ dmc->mode = orig_mode; ++ goto out; ++ } ++ } else if (dmc->mode == CACHE_MODE_WB) { ++ eio_free_wb_resources(dmc); ++ dmc->mode = mode; ++ } else { /* (RO -> WT) or (WT -> RO) */ ++ EIO_ASSERT(((dmc->mode == CACHE_MODE_RO) && (mode == CACHE_MODE_WT)) ++ || ((dmc->mode == CACHE_MODE_WT) && ++ (mode == CACHE_MODE_RO))); ++ dmc->mode = mode; ++ } ++ ++out: ++ if (error) ++ pr_err("mode_switch: Failed to switch mode, error: %d\n", ++ error); ++ return error; ++} ++ ++/* ++ * XXX: Error handling. ++ * In case of error put the cache in degraded mode. ++ */ ++ ++static int eio_policy_switch(struct cache_c *dmc, u_int32_t policy) ++{ ++ int error = -EINVAL; ++ struct eio_policy *old_policy_ops; ++ ++ EIO_ASSERT(dmc->req_policy != policy); ++ old_policy_ops = dmc->policy_ops; ++ ++ error = eio_policy_init(dmc); ++ if (error) ++ goto out; ++ ++ error = eio_repl_blk_init(dmc->policy_ops); ++ if (error) { ++ error = -ENOMEM; ++ pr_err ("eio_policy_swtich: Unable to allocate memory for policy cache block"); ++ goto out; ++ } ++ ++ error = eio_repl_sets_init(dmc->policy_ops); ++ if (error) { ++ error = -ENOMEM; ++ pr_err ("eio_policy_switch: Failed to allocate memory for cache policy"); ++ goto out; ++ } ++ ++ eio_policy_lru_pushblks(dmc->policy_ops); ++ dmc->req_policy = policy; ++ return 0; ++ ++out: ++ if (dmc->policy_ops != old_policy_ops) ++ eio_policy_free(dmc); ++ dmc->policy_ops = old_policy_ops; ++ return error; ++} ++ ++void eio_free_wb_pages(struct page **pages, int allocated) ++{ ++ /* Verify that allocated is never 0 or less that zero. */ ++ if (allocated <= 0) ++ return; ++ ++ do ++ put_page(pages[--allocated]); ++ while (allocated); ++ ++ *pages = NULL; ++} ++ ++void eio_free_wb_bvecs(struct bio_vec *bvec, int allocated, int blksize) ++{ ++ int i; ++ ++ if (allocated <= 0) ++ return; ++ ++ for (i = 0; i < allocated; i++) { ++ switch (blksize) { ++ case BLKSIZE_2K: ++ /* ++ * For 2k blocksize, each page is shared between two ++ * bio_vecs. Hence make sure to put_page only for even ++ * indexes. ++ */ ++ if (((i % 2) == 0) && bvec[i].bv_page) { ++ put_page(bvec[i].bv_page); ++ bvec[i].bv_page = NULL; ++ continue; ++ } ++ ++ /* For odd index page should already have been freed. */ ++ if ((i % 2)) ++ bvec[i].bv_page = NULL; ++ ++ continue; ++ ++ case BLKSIZE_4K: ++ case BLKSIZE_8K: ++ if (bvec[i].bv_page) { ++ put_page(bvec[i].bv_page); ++ bvec[i].bv_page = NULL; ++ } ++ ++ continue; ++ } ++ } ++} ++ ++/* ++ * This function allocates pages to array of bvecs allocated by caller. ++ * It has special handling of blocksize of 2k where single page is ++ * shared between two bio_vecs. ++ */ ++ ++int eio_alloc_wb_bvecs(struct bio_vec *bvec, int max, int blksize) ++{ ++ int i, ret; ++ struct bio_vec *iovec; ++ struct page *page; ++ ++ ret = 0; ++ iovec = bvec; ++ page = NULL; ++ ++ for (i = 0; i < max; i++) { ++ switch (blksize) { ++ case BLKSIZE_2K: ++ /* ++ * In case of 2k blocksize, two biovecs will be sharing ++ * same page address. This is handled below. ++ */ ++ ++ if ((i % 2) == 0) { ++ /* Allocate page only for even bio vector */ ++ page = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (unlikely(!page)) { ++ pr_err ++ ("eio_alloc_wb_bvecs: System memory too low.\n"); ++ goto err; ++ } ++ iovec[i].bv_page = page; ++ iovec[i].bv_len = to_bytes(blksize); ++ iovec[i].bv_offset = 0; ++ } else { ++ /* Let the odd biovec share page allocated earlier. */ ++ EIO_ASSERT(page != NULL); ++ iovec[i].bv_page = page; ++ iovec[i].bv_len = to_bytes(blksize); ++ iovec[i].bv_offset = ++ PAGE_SIZE - to_bytes(blksize); ++ ++ /* Mark page NULL here as it is not required anymore. */ ++ page = NULL; ++ } ++ ++ continue; ++ ++ case BLKSIZE_4K: ++ case BLKSIZE_8K: ++ page = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (unlikely(!page)) { ++ pr_err("eio_alloc_wb_bvecs:" \ ++ " System memory too low.\n"); ++ goto err; ++ } ++ iovec[i].bv_page = page; ++ iovec[i].bv_offset = 0; ++ iovec[i].bv_len = PAGE_SIZE; ++ ++ page = NULL; ++ continue; ++ } ++ } ++ ++ goto out; ++ ++err: ++ if (i != max) { ++ if (i > 0) ++ eio_free_wb_bvecs(bvec, i, blksize); ++ ret = -ENOMEM; ++ } ++ ++out: ++ return ret; ++} ++ ++int eio_alloc_wb_pages(struct page **pages, int max) ++{ ++ int i, ret = 0; ++ struct page *page; ++ ++ for (i = 0; i < max; i++) { ++ page = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (unlikely(!page)) { ++ pr_err("alloc_wb_pages: System memory too low.\n"); ++ break; ++ } ++ pages[i] = page; ++ } ++ ++ if (i != max) { ++ if (i > 0) ++ eio_free_wb_pages(pages, i); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ ++/* ++ **************************************************************************** ++ * struct bio_vec *eio_alloc_pages(int max_pages, int *page_count) ++ * dmc : cache object ++ * pages : bio_vec to be allocated for synchronous I/O. ++ * page_count : total number of pages allocated. ++ **************************************************************************** ++ * ++ * This function allocates pages capped to minimum of ++ * MD_MAX_NR_PAGES OR maximun number of pages supported by ++ * block device. ++ * This is to ensure that the pages allocated should fit ++ * into single bio request. ++ */ ++ ++struct bio_vec *eio_alloc_pages(u_int32_t max_pages, int *page_count) ++{ ++ int pcount, i; ++ struct bio_vec *pages; ++ int nr_pages; ++ ++ /* ++ * Find out no. of pages supported by block device max capped to ++ * MD_MAX_NR_PAGES; ++ */ ++ nr_pages = min_t(u_int32_t, max_pages, MD_MAX_NR_PAGES); ++ ++ pages = kzalloc(nr_pages * sizeof(struct bio_vec), GFP_NOIO); ++ if (unlikely(!pages)) { ++ pr_err("eio_alloc_pages: System memory too low.\n"); ++ return NULL; ++ } ++ ++ pcount = 0; ++ for (i = 0; i < nr_pages; i++) { ++ pages[i].bv_page = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (unlikely(!pages[i].bv_page)) { ++ pr_err("eio_alloc_pages: System memory too low.\n"); ++ break; ++ } else { ++ pages[i].bv_len = PAGE_SIZE; ++ pages[i].bv_offset = 0; ++ pcount++; ++ } ++ } ++ ++ if (pcount == 0) { ++ pr_err("Single page allocation failed. System memory too low."); ++ kfree(pages); ++ return NULL; ++ } ++ ++ /* following can be commented out later... ++ * we may have less pages allocated. ++ */ ++ EIO_ASSERT(pcount == nr_pages); ++ ++ /* Set the return values here */ ++ *page_count = pcount; ++ return pages; ++} ++ ++/* ++ * As part of reboot handling, stop all activies and mark the devices as ++ * read only. ++ */ ++ ++int eio_reboot_handling(void) ++{ ++ struct cache_c *dmc, *tempdmc = NULL; ++ int i, error; ++ uint32_t old_time_thresh; ++ ++ if (eio_reboot_notified == EIO_REBOOT_HANDLING_DONE) ++ return 0; ++ ++ (void)wait_on_bit_lock((void *)&eio_control->synch_flags, ++ EIO_HANDLE_REBOOT, eio_wait_schedule, ++ TASK_UNINTERRUPTIBLE); ++ if (eio_reboot_notified == EIO_REBOOT_HANDLING_DONE) { ++ clear_bit(EIO_HANDLE_REBOOT, (void *)&eio_control->synch_flags); ++ smp_mb__after_clear_bit(); ++ wake_up_bit((void *)&eio_control->synch_flags, ++ EIO_HANDLE_REBOOT); ++ return 0; ++ } ++ EIO_ASSERT(eio_reboot_notified == 0); ++ eio_reboot_notified = EIO_REBOOT_HANDLING_INPROG; ++ ++ for (i = 0; i < EIO_HASHTBL_SIZE; i++) { ++ down_write(&eio_ttc_lock[i]); ++ list_for_each_entry(dmc, &eio_ttc_list[i], cachelist) { ++ ++ kfree(tempdmc); ++ tempdmc = NULL; ++ if (unlikely(CACHE_FAILED_IS_SET(dmc)) || ++ unlikely(CACHE_DEGRADED_IS_SET(dmc))) { ++ pr_err ++ ("Cache \"%s\" is in failed/degraded " \ ++ "mode. Cannot mark cache read only.\n", ++ dmc->cache_name); ++ continue; ++ } ++ ++ while (atomic64_read(&dmc->nr_ios) != 0) { ++ pr_debug("rdonly: Draining I/O inflight\n"); ++ schedule_timeout(msecs_to_jiffies(10)); ++ } ++ ++ EIO_ASSERT(atomic64_read(&dmc->nr_ios) == 0); ++ EIO_ASSERT(dmc->cache_rdonly == 0); ++ ++ /* ++ * Shutdown processing has the highest priority. ++ * Stop all ongoing activities. ++ */ ++ ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ EIO_ASSERT(! ++ (dmc-> ++ cache_flags & CACHE_FLAGS_SHUTDOWN_INPROG)); ++ dmc->cache_flags |= CACHE_FLAGS_SHUTDOWN_INPROG; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ ++ /* ++ * Wait for ongoing edit/delete to complete. ++ */ ++ ++ while (dmc->cache_flags & CACHE_FLAGS_MOD_INPROG) { ++ up_write(&eio_ttc_lock[i]); ++ schedule_timeout(msecs_to_jiffies(1)); ++ down_write(&eio_ttc_lock[i]); ++ } ++ if (dmc->cache_flags & CACHE_FLAGS_DELETED) { ++ /* ++ * Cache got deleted. Free the dmc. ++ */ ++ ++ tempdmc = dmc; ++ continue; ++ } ++ old_time_thresh = ++ dmc->sysctl_active.time_based_clean_interval; ++ eio_stop_async_tasks(dmc); ++ dmc->sysctl_active.time_based_clean_interval = ++ old_time_thresh; ++ ++ dmc->cache_rdonly = 1; ++ pr_info("Cache \"%s\" marked read only\n", ++ dmc->cache_name); ++ up_write(&eio_ttc_lock[i]); ++ ++ if (dmc->cold_boot && atomic64_read(&dmc->nr_dirty) && ++ !eio_force_warm_boot) { ++ pr_info ++ ("Cold boot set for cache %s: Draining dirty blocks: %llu", ++ dmc->cache_name, ++ (unsigned long long)atomic64_read(&dmc->nr_dirty)); ++ eio_clean_for_reboot(dmc); ++ } ++ ++ error = eio_md_store(dmc); ++ if (error) ++ pr_err("Cannot mark cache \"%s\" read only\n", ++ dmc->cache_name); ++ ++ spin_lock_irqsave(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ dmc->cache_flags &= ~CACHE_FLAGS_SHUTDOWN_INPROG; ++ spin_unlock_irqrestore(&dmc->cache_spin_lock, ++ dmc->cache_spin_lock_flags); ++ ++ down_write(&eio_ttc_lock[i]); ++ } ++ kfree(tempdmc); ++ tempdmc = NULL; ++ up_write(&eio_ttc_lock[i]); ++ } ++ ++ eio_reboot_notified = EIO_REBOOT_HANDLING_DONE; ++ clear_bit(EIO_HANDLE_REBOOT, (void *)&eio_control->synch_flags); ++ smp_mb__after_clear_bit(); ++ wake_up_bit((void *)&eio_control->synch_flags, EIO_HANDLE_REBOOT); ++ return 0; ++} ++ ++static int eio_overlap_split_bio(struct request_queue *q, struct bio *bio) ++{ ++ int i, nbios; ++ void **bioptr; ++ sector_t snum; ++ struct bio_container *bc; ++ unsigned bvec_idx; ++ unsigned bvec_consumed; ++ ++ nbios = bio->bi_size >> SECTOR_SHIFT; ++ snum = bio->bi_sector; ++ ++ bioptr = kmalloc(nbios * (sizeof(void *)), GFP_KERNEL); ++ if (!bioptr) { ++ bio_endio(bio, -ENOMEM); ++ return 0; ++ } ++ bc = kmalloc(sizeof(struct bio_container), GFP_NOWAIT); ++ if (!bc) { ++ bio_endio(bio, -ENOMEM); ++ kfree(bioptr); ++ return 0; ++ } ++ ++ atomic_set(&bc->bc_holdcount, nbios); ++ bc->bc_bio = bio; ++ bc->bc_error = 0; ++ ++ bvec_idx = bio->bi_idx; ++ bvec_consumed = 0; ++ for (i = 0; i < nbios; i++) { ++ bioptr[i] = ++ eio_split_new_bio(bio, bc, &bvec_idx, ++ &bvec_consumed, snum); ++ if (!bioptr[i]) ++ break; ++ snum++; ++ } ++ ++ /* Error: cleanup */ ++ if (i < nbios) { ++ for (i--; i >= 0; i--) ++ bio_put(bioptr[i]); ++ bio_endio(bio, -ENOMEM); ++ kfree(bc); ++ goto out; ++ } ++ ++ for (i = 0; i < nbios; i++) ++ eio_make_request_fn(q, bioptr[i]); ++ ++out: ++ kfree(bioptr); ++ return 0; ++} ++ ++static struct bio *eio_split_new_bio(struct bio *bio, struct bio_container *bc, ++ unsigned *bvec_idx, ++ unsigned *bvec_consumed, sector_t snum) ++{ ++ struct bio *cbio; ++ unsigned iosize = 1 << SECTOR_SHIFT; ++ ++ cbio = bio_alloc(GFP_NOIO, 1); ++ if (!cbio) ++ return NULL; ++ ++ EIO_ASSERT(bio->bi_io_vec[*bvec_idx].bv_len >= iosize); ++ ++ if (bio->bi_io_vec[*bvec_idx].bv_len <= *bvec_consumed) { ++ EIO_ASSERT(bio->bi_io_vec[*bvec_idx].bv_len == *bvec_consumed); ++ (*bvec_idx)++; ++ EIO_ASSERT(bio->bi_vcnt > *bvec_idx); ++ *bvec_consumed = 0; ++ } ++ ++ cbio->bi_io_vec[0].bv_page = bio->bi_io_vec[*bvec_idx].bv_page; ++ cbio->bi_io_vec[0].bv_offset = ++ bio->bi_io_vec[*bvec_idx].bv_offset + *bvec_consumed; ++ cbio->bi_io_vec[0].bv_len = iosize; ++ *bvec_consumed += iosize; ++ ++ cbio->bi_sector = snum; ++ cbio->bi_size = iosize; ++ cbio->bi_bdev = bio->bi_bdev; ++ cbio->bi_rw = bio->bi_rw; ++ cbio->bi_vcnt = 1; ++ cbio->bi_idx = 0; ++ cbio->bi_end_io = eio_split_endio; ++ cbio->bi_private = bc; ++ return cbio; ++} ++ ++static void eio_split_endio(struct bio *bio, int error) ++{ ++ struct bio_container *bc = bio->bi_private; ++ ++ if (error) ++ bc->bc_error = error; ++ bio_put(bio); ++ if (atomic_dec_and_test(&bc->bc_holdcount)) { ++ bio_endio(bc->bc_bio, bc->bc_error); ++ kfree(bc); ++ } ++ return; ++} +diff -Nur linux-3.10.30/drivers/block/enhanceio/eio_ttc.h linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_ttc.h +--- linux-3.10.30/drivers/block/enhanceio/eio_ttc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/block/enhanceio/eio_ttc.h 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,152 @@ ++/* ++ * Copyright (C) 2012 STEC, Inc. All rights not specifically granted ++ * under a license included herein are reserved. ++ * ++ * 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; under 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 ++ */ ++ ++#ifndef EIO_TTC_H ++#define EIO_TTC_H ++ ++#ifdef __KERNEL__ ++#include ++#define curthread get_current() ++#else ++#include ++#endif /* __KERNEL__ */ ++ ++static inline bool bio_rw_flagged(struct bio *bio, int flag) ++{ ++ return (bio->bi_rw & flag) != 0; ++} ++ ++/* ++ * Whether the cached (source) device is a partition or a whole device. ++ * dmc->dev_info stores this info. ++ */ ++enum eio_io_mem_type { ++ EIO_BVECS, /* bio vectors */ ++ EIO_PAGES, /* array of pages */ ++}; ++ ++struct eio_io_request { ++ enum eio_io_mem_type mtype; ++ ++ union { ++ struct bio_vec *pages; ++ struct page **plist; ++ } dptr; ++ ++ unsigned num_bvecs; ++ eio_notify_fn notify; ++ void *context; ++ unsigned hddio; ++}; ++ ++struct eio_context { ++ atomic_t count; ++ int error; ++ struct completion *event; ++ eio_notify_fn callback; ++ void *context; ++}; ++ ++int eio_do_io(struct cache_c *dmc, struct eio_io_region *where, int rw, ++ struct eio_io_request *io_req); ++ ++enum eio_device { ++ EIO_HDD_DEVICE = 1, ++ EIO_SSD_DEVICE, ++}; ++ ++enum eio_dev_info { ++ EIO_DEV_PARTITION = 1, ++ EIO_DEV_WHOLE_DISK ++}; ++ ++enum eio_cache_state { ++ DMC_TTC_INITIALIZING = 1, ++ DMC_TTC_READY, ++ DMC_TTC_IO_FREEZE, ++ DMC_TTC_UNINITIALIZING, ++ DMC_TTC_UNINITIALIZED ++}; ++ ++#ifdef __KERNEL__ ++ ++#define EIO_HASHTBL_SIZE 1024 ++ ++/* ++ * In case of i/o errors while eio_clean_all, retry for ++ * finish_nrdirty_retry count. ++ */ ++#define FINISH_NRDIRTY_RETRY_COUNT 2 ++ ++#define EIO_HASH_BDEV(dev) \ ++ ((MAJOR(dev) * EIO_MAGIC + MINOR(dev)) % EIO_HASHTBL_SIZE) ++ ++/* ++ * Reboot status flags. ++ */ ++ ++#define EIO_REBOOT_HANDLING_INPROG 0x01 ++#define EIO_REBOOT_HANDLING_DONE 0x02 ++ ++/* ++ * kernel function prototypes. ++ */ ++ ++extern int eio_create_misc_device(void); ++extern int eio_delete_misc_device(void); ++ ++extern int eio_ttc_get_device(const char *, fmode_t, struct eio_bdev **); ++extern void eio_ttc_put_device(struct eio_bdev **); ++ ++extern struct cache_c *eio_cache_lookup(char *); ++extern int eio_ttc_activate(struct cache_c *); ++extern int eio_ttc_deactivate(struct cache_c *, int); ++extern void eio_ttc_init(void); ++ ++extern int eio_cache_create(struct cache_rec_short *); ++extern int eio_cache_delete(char *, int); ++extern uint64_t eio_get_cache_count(void); ++extern int eio_get_cache_list(unsigned long *); ++ ++extern int eio_handle_ssd_message(char *cache_name, char *ssd_name, ++ enum dev_notifier note); ++ ++int eio_do_preliminary_checks(struct cache_c *); ++ ++extern int eio_allocate_wb_resources(struct cache_c *); ++extern void eio_free_wb_resources(struct cache_c *); ++ ++extern int eio_cache_edit(char *, u_int32_t, u_int32_t); ++ ++extern void eio_stop_async_tasks(struct cache_c *dmc); ++extern int eio_start_clean_thread(struct cache_c *dmc); ++ ++extern int eio_policy_init(struct cache_c *); ++extern void eio_policy_free(struct cache_c *); ++extern int eio_alloc_wb_pages(struct page **pages, int max); ++extern void eio_free_wb_pages(struct page **pages, int allocated); ++extern int eio_alloc_wb_bvecs(struct bio_vec *bvec, int max, int blksize); ++extern void eio_free_wb_bvecs(struct bio_vec *bvec, int allocated, int blksize); ++extern struct bio_vec *eio_alloc_pages(u_int32_t max_pages, int *page_count); ++extern int eio_md_store(struct cache_c *); ++extern int eio_reboot_handling(void); ++extern void eio_process_zero_size_bio(struct cache_c *dmc, struct bio *origbio); ++extern long eio_ioctl(struct file *filp, unsigned cmd, unsigned long arg); ++extern long eio_compact_ioctl(struct file *filp, unsigned cmd, ++ unsigned long arg); ++#endif /* __KERNEL__ */ ++ ++#endif /* EIO_TTC_H */ +diff -Nur linux-3.10.30/drivers/bus/Kconfig linux-3.10.30-cubox-i/drivers/bus/Kconfig +--- linux-3.10.30/drivers/bus/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/bus/Kconfig 2014-03-08 20:33:28.000000000 +0100 +@@ -4,6 +4,15 @@ + + menu "Bus devices" + ++config IMX_WEIM ++ bool "Freescale EIM DRIVER" ++ depends on ARCH_MXC ++ help ++ Driver for i.MX6 WEIM controller. ++ The WEIM(Wireless External Interface Module) works like a bus. ++ You can attach many different devices on it, such as NOR, onenand. ++ But now, we only support the Parallel NOR. ++ + config MVEBU_MBUS + bool + depends on PLAT_ORION +@@ -26,4 +35,11 @@ + + help + Driver to enable OMAP interconnect error handling driver. ++ ++config ARM_CCI ++ bool "ARM CCI driver support" ++ depends on ARM ++ help ++ Driver supporting the CCI cache coherent interconnect for ARM ++ platforms. + endmenu +diff -Nur linux-3.10.30/drivers/bus/Makefile linux-3.10.30-cubox-i/drivers/bus/Makefile +--- linux-3.10.30/drivers/bus/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/bus/Makefile 2014-03-08 20:33:28.000000000 +0100 +@@ -2,8 +2,11 @@ + # Makefile for the bus drivers. + # + ++obj-$(CONFIG_IMX_WEIM) += imx-weim.o + obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o + obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o + + # Interconnect bus driver for OMAP SoCs. + obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o ++# CCI cache coherent interconnect for ARM platforms ++obj-$(CONFIG_ARM_CCI) += arm-cci.o +diff -Nur linux-3.10.30/drivers/bus/arm-cci.c linux-3.10.30-cubox-i/drivers/bus/arm-cci.c +--- linux-3.10.30/drivers/bus/arm-cci.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/bus/arm-cci.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,945 @@ ++/* ++ * CCI cache coherent interconnect driver ++ * ++ * Copyright (C) 2013 ARM Ltd. ++ * Author: Lorenzo Pieralisi ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define DRIVER_NAME "CCI" ++ ++#define CCI_PORT_CTRL 0x0 ++#define CCI_CTRL_STATUS 0xc ++ ++#define CCI_ENABLE_SNOOP_REQ 0x1 ++#define CCI_ENABLE_DVM_REQ 0x2 ++#define CCI_ENABLE_REQ (CCI_ENABLE_SNOOP_REQ | CCI_ENABLE_DVM_REQ) ++ ++struct cci_nb_ports { ++ unsigned int nb_ace; ++ unsigned int nb_ace_lite; ++}; ++ ++enum cci_ace_port_type { ++ ACE_INVALID_PORT = 0x0, ++ ACE_PORT, ++ ACE_LITE_PORT, ++}; ++ ++struct cci_ace_port { ++ void __iomem *base; ++ unsigned long phys; ++ enum cci_ace_port_type type; ++ struct device_node *dn; ++}; ++ ++static struct cci_ace_port *ports; ++static unsigned int nb_cci_ports; ++ ++static void __iomem *cci_ctrl_base; ++static unsigned long cci_ctrl_phys; ++ ++#ifdef CONFIG_HW_PERF_EVENTS ++ ++static void __iomem *cci_pmu_base; ++ ++#define CCI400_PMCR 0x0100 ++ ++#define CCI400_PMU_CYCLE_CNTR_BASE 0x0000 ++#define CCI400_PMU_CNTR_BASE(idx) (CCI400_PMU_CYCLE_CNTR_BASE + (idx) * 0x1000) ++ ++#define CCI400_PMCR_CEN 0x00000001 ++#define CCI400_PMCR_RST 0x00000002 ++#define CCI400_PMCR_CCR 0x00000004 ++#define CCI400_PMCR_CCD 0x00000008 ++#define CCI400_PMCR_EX 0x00000010 ++#define CCI400_PMCR_DP 0x00000020 ++#define CCI400_PMCR_NCNT_MASK 0x0000F800 ++#define CCI400_PMCR_NCNT_SHIFT 11 ++ ++#define CCI400_PMU_EVT_SEL 0x000 ++#define CCI400_PMU_CNTR 0x004 ++#define CCI400_PMU_CNTR_CTRL 0x008 ++#define CCI400_PMU_OVERFLOW 0x00C ++ ++#define CCI400_PMU_OVERFLOW_FLAG 1 ++ ++enum cci400_perf_events { ++ CCI400_PMU_CYCLES = 0xFF ++}; ++ ++#define CCI400_PMU_EVENT_MASK 0xff ++#define CCI400_PMU_EVENT_SOURCE(event) ((event >> 5) & 0x7) ++#define CCI400_PMU_EVENT_CODE(event) (event & 0x1f) ++ ++#define CCI400_PMU_EVENT_SOURCE_S0 0 ++#define CCI400_PMU_EVENT_SOURCE_S4 4 ++#define CCI400_PMU_EVENT_SOURCE_M0 5 ++#define CCI400_PMU_EVENT_SOURCE_M2 7 ++ ++#define CCI400_PMU_EVENT_SLAVE_MIN 0x0 ++#define CCI400_PMU_EVENT_SLAVE_MAX 0x13 ++ ++#define CCI400_PMU_EVENT_MASTER_MIN 0x14 ++#define CCI400_PMU_EVENT_MASTER_MAX 0x1A ++ ++#define CCI400_PMU_MAX_HW_EVENTS 5 /* CCI PMU has 4 counters + 1 cycle counter */ ++ ++#define CCI400_PMU_CYCLE_COUNTER_IDX 0 ++#define CCI400_PMU_COUNTER0_IDX 1 ++#define CCI400_PMU_COUNTER_LAST(cci_pmu) (CCI400_PMU_CYCLE_COUNTER_IDX + cci_pmu->num_events - 1) ++ ++ ++static struct perf_event *events[CCI400_PMU_MAX_HW_EVENTS]; ++static unsigned long used_mask[BITS_TO_LONGS(CCI400_PMU_MAX_HW_EVENTS)]; ++static struct pmu_hw_events cci_hw_events = { ++ .events = events, ++ .used_mask = used_mask, ++}; ++ ++static int cci_pmu_validate_hw_event(u8 hw_event) ++{ ++ u8 ev_source = CCI400_PMU_EVENT_SOURCE(hw_event); ++ u8 ev_code = CCI400_PMU_EVENT_CODE(hw_event); ++ ++ if (ev_source <= CCI400_PMU_EVENT_SOURCE_S4 && ++ ev_code <= CCI400_PMU_EVENT_SLAVE_MAX) ++ return hw_event; ++ else if (CCI400_PMU_EVENT_SOURCE_M0 <= ev_source && ++ ev_source <= CCI400_PMU_EVENT_SOURCE_M2 && ++ CCI400_PMU_EVENT_MASTER_MIN <= ev_code && ++ ev_code <= CCI400_PMU_EVENT_MASTER_MAX) ++ return hw_event; ++ ++ return -EINVAL; ++} ++ ++static inline int cci_pmu_counter_is_valid(struct arm_pmu *cci_pmu, int idx) ++{ ++ return CCI400_PMU_CYCLE_COUNTER_IDX <= idx && ++ idx <= CCI400_PMU_COUNTER_LAST(cci_pmu); ++} ++ ++static inline u32 cci_pmu_read_register(int idx, unsigned int offset) ++{ ++ return readl_relaxed(cci_pmu_base + CCI400_PMU_CNTR_BASE(idx) + offset); ++} ++ ++static inline void cci_pmu_write_register(u32 value, int idx, unsigned int offset) ++{ ++ return writel_relaxed(value, cci_pmu_base + CCI400_PMU_CNTR_BASE(idx) + offset); ++} ++ ++static inline void cci_pmu_disable_counter(int idx) ++{ ++ cci_pmu_write_register(0, idx, CCI400_PMU_CNTR_CTRL); ++} ++ ++static inline void cci_pmu_enable_counter(int idx) ++{ ++ cci_pmu_write_register(1, idx, CCI400_PMU_CNTR_CTRL); ++} ++ ++static inline void cci_pmu_select_event(int idx, unsigned long event) ++{ ++ event &= CCI400_PMU_EVENT_MASK; ++ cci_pmu_write_register(event, idx, CCI400_PMU_EVT_SEL); ++} ++ ++static u32 cci_pmu_get_max_counters(void) ++{ ++ u32 n_cnts = (readl_relaxed(cci_ctrl_base + CCI400_PMCR) & ++ CCI400_PMCR_NCNT_MASK) >> CCI400_PMCR_NCNT_SHIFT; ++ ++ /* add 1 for cycle counter */ ++ return n_cnts + 1; ++} ++ ++static struct pmu_hw_events *cci_pmu_get_hw_events(void) ++{ ++ return &cci_hw_events; ++} ++ ++static int cci_pmu_get_event_idx(struct pmu_hw_events *hw, struct perf_event *event) ++{ ++ struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu); ++ struct hw_perf_event *hw_event = &event->hw; ++ unsigned long cci_event = hw_event->config_base & CCI400_PMU_EVENT_MASK; ++ int idx; ++ ++ if (cci_event == CCI400_PMU_CYCLES) { ++ if (test_and_set_bit(CCI400_PMU_CYCLE_COUNTER_IDX, hw->used_mask)) ++ return -EAGAIN; ++ ++ return CCI400_PMU_CYCLE_COUNTER_IDX; ++ } ++ ++ for (idx = CCI400_PMU_COUNTER0_IDX; idx <= CCI400_PMU_COUNTER_LAST(cci_pmu); ++idx) { ++ if (!test_and_set_bit(idx, hw->used_mask)) ++ return idx; ++ } ++ ++ /* No counters available */ ++ return -EAGAIN; ++} ++ ++static int cci_pmu_map_event(struct perf_event *event) ++{ ++ int mapping; ++ u8 config = event->attr.config & CCI400_PMU_EVENT_MASK; ++ ++ if (event->attr.type < PERF_TYPE_MAX) ++ return -ENOENT; ++ ++ /* 0xff is used to represent CCI Cycles */ ++ if (config == 0xff) ++ mapping = config; ++ else ++ mapping = cci_pmu_validate_hw_event(config); ++ ++ return mapping; ++} ++ ++static int cci_pmu_request_irq(struct arm_pmu *cci_pmu, irq_handler_t handler) ++{ ++ int irq, err, i = 0; ++ struct platform_device *pmu_device = cci_pmu->plat_device; ++ ++ if (unlikely(!pmu_device)) ++ return -ENODEV; ++ ++ /* CCI exports 6 interrupts - 1 nERRORIRQ + 5 nEVNTCNTOVERFLOW (PMU) ++ nERRORIRQ will be handled by secure firmware on TC2. So we ++ assume that all CCI interrupts listed in the linux device ++ tree are PMU interrupts. ++ ++ The following code should then be able to handle different routing ++ of the CCI PMU interrupts. ++ */ ++ while ((irq = platform_get_irq(pmu_device, i)) > 0) { ++ err = request_irq(irq, handler, 0, "arm-cci-pmu", cci_pmu); ++ if (err) { ++ dev_err(&pmu_device->dev, "unable to request IRQ%d for ARM CCI PMU counters\n", ++ irq); ++ return err; ++ } ++ i++; ++ } ++ ++ return 0; ++} ++ ++static irqreturn_t cci_pmu_handle_irq(int irq_num, void *dev) ++{ ++ struct arm_pmu *cci_pmu = (struct arm_pmu *)dev; ++ struct pmu_hw_events *events = cci_pmu->get_hw_events(); ++ struct perf_sample_data data; ++ struct pt_regs *regs; ++ int idx; ++ ++ regs = get_irq_regs(); ++ ++ /* Iterate over counters and update the corresponding perf events. ++ This should work regardless of whether we have per-counter overflow ++ interrupt or a combined overflow interrupt. */ ++ for (idx = CCI400_PMU_CYCLE_COUNTER_IDX; idx <= CCI400_PMU_COUNTER_LAST(cci_pmu); idx++) { ++ struct perf_event *event = events->events[idx]; ++ struct hw_perf_event *hw_counter; ++ ++ if (!event) ++ continue; ++ ++ hw_counter = &event->hw; ++ ++ /* Did this counter overflow? */ ++ if (!(cci_pmu_read_register(idx, CCI400_PMU_OVERFLOW) & CCI400_PMU_OVERFLOW_FLAG)) ++ continue; ++ cci_pmu_write_register(CCI400_PMU_OVERFLOW_FLAG, idx, CCI400_PMU_OVERFLOW); ++ ++ armpmu_event_update(event); ++ perf_sample_data_init(&data, 0, hw_counter->last_period); ++ if (!armpmu_event_set_period(event)) ++ continue; ++ ++ if (perf_event_overflow(event, &data, regs)) ++ cci_pmu->disable(event); ++ } ++ ++ irq_work_run(); ++ return IRQ_HANDLED; ++} ++ ++static void cci_pmu_free_irq(struct arm_pmu *cci_pmu) ++{ ++ int irq, i = 0; ++ struct platform_device *pmu_device = cci_pmu->plat_device; ++ ++ while ((irq = platform_get_irq(pmu_device, i)) > 0) { ++ free_irq(irq, cci_pmu); ++ i++; ++ } ++} ++ ++static void cci_pmu_enable_event(struct perf_event *event) ++{ ++ unsigned long flags; ++ struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu); ++ struct pmu_hw_events *events = cci_pmu->get_hw_events(); ++ struct hw_perf_event *hw_counter = &event->hw; ++ int idx = hw_counter->idx; ++ ++ if (unlikely(!cci_pmu_counter_is_valid(cci_pmu, idx))) { ++ dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx); ++ return; ++ } ++ ++ raw_spin_lock_irqsave(&events->pmu_lock, flags); ++ ++ /* Configure the event to count, unless you are counting cycles */ ++ if (idx != CCI400_PMU_CYCLE_COUNTER_IDX) ++ cci_pmu_select_event(idx, hw_counter->config_base); ++ ++ cci_pmu_enable_counter(idx); ++ ++ raw_spin_unlock_irqrestore(&events->pmu_lock, flags); ++} ++ ++static void cci_pmu_disable_event(struct perf_event *event) ++{ ++ unsigned long flags; ++ struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu); ++ struct pmu_hw_events *events = cci_pmu->get_hw_events(); ++ struct hw_perf_event *hw_counter = &event->hw; ++ int idx = hw_counter->idx; ++ ++ if (unlikely(!cci_pmu_counter_is_valid(cci_pmu, idx))) { ++ dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx); ++ return; ++ } ++ ++ raw_spin_lock_irqsave(&events->pmu_lock, flags); ++ ++ cci_pmu_disable_counter(idx); ++ ++ raw_spin_unlock_irqrestore(&events->pmu_lock, flags); ++} ++ ++static void cci_pmu_start(struct arm_pmu *cci_pmu) ++{ ++ u32 val; ++ unsigned long flags; ++ struct pmu_hw_events *events = cci_pmu->get_hw_events(); ++ ++ raw_spin_lock_irqsave(&events->pmu_lock, flags); ++ ++ /* Enable all the PMU counters. */ ++ val = readl(cci_ctrl_base + CCI400_PMCR) | CCI400_PMCR_CEN; ++ writel(val, cci_ctrl_base + CCI400_PMCR); ++ ++ raw_spin_unlock_irqrestore(&events->pmu_lock, flags); ++} ++ ++static void cci_pmu_stop(struct arm_pmu *cci_pmu) ++{ ++ u32 val; ++ unsigned long flags; ++ struct pmu_hw_events *events = cci_pmu->get_hw_events(); ++ ++ raw_spin_lock_irqsave(&events->pmu_lock, flags); ++ ++ /* Disable all the PMU counters. */ ++ val = readl(cci_ctrl_base + CCI400_PMCR) & ~CCI400_PMCR_CEN; ++ writel(val, cci_ctrl_base + CCI400_PMCR); ++ ++ raw_spin_unlock_irqrestore(&events->pmu_lock, flags); ++} ++ ++static u32 cci_pmu_read_counter(struct perf_event *event) ++{ ++ struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu); ++ struct hw_perf_event *hw_counter = &event->hw; ++ int idx = hw_counter->idx; ++ u32 value; ++ ++ if (unlikely(!cci_pmu_counter_is_valid(cci_pmu, idx))) { ++ dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx); ++ return 0; ++ } ++ value = cci_pmu_read_register(idx, CCI400_PMU_CNTR); ++ ++ return value; ++} ++ ++static void cci_pmu_write_counter(struct perf_event *event, u32 value) ++{ ++ struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu); ++ struct hw_perf_event *hw_counter = &event->hw; ++ int idx = hw_counter->idx; ++ ++ if (unlikely(!cci_pmu_counter_is_valid(cci_pmu, idx))) ++ dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx); ++ else ++ cci_pmu_write_register(value, idx, CCI400_PMU_CNTR); ++} ++ ++static struct arm_pmu cci_pmu = { ++ .name = DRIVER_NAME, ++ .max_period = (1LLU << 32) - 1, ++ .get_hw_events = cci_pmu_get_hw_events, ++ .get_event_idx = cci_pmu_get_event_idx, ++ .map_event = cci_pmu_map_event, ++ .request_irq = cci_pmu_request_irq, ++ .handle_irq = cci_pmu_handle_irq, ++ .free_irq = cci_pmu_free_irq, ++ .enable = cci_pmu_enable_event, ++ .disable = cci_pmu_disable_event, ++ .start = cci_pmu_start, ++ .stop = cci_pmu_stop, ++ .read_counter = cci_pmu_read_counter, ++ .write_counter = cci_pmu_write_counter, ++}; ++ ++static int cci_pmu_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ cci_pmu_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(cci_pmu_base)) ++ return PTR_ERR(cci_pmu_base); ++ ++ cci_pmu.plat_device = pdev; ++ cci_pmu.num_events = cci_pmu_get_max_counters(); ++ raw_spin_lock_init(&cci_hw_events.pmu_lock); ++ cpumask_setall(&cci_pmu.valid_cpus); ++ ++ return armpmu_register(&cci_pmu, -1); ++} ++ ++static const struct of_device_id arm_cci_pmu_matches[] = { ++ {.compatible = "arm,cci-400-pmu"}, ++ {}, ++}; ++ ++static struct platform_driver cci_pmu_platform_driver = { ++ .driver = { ++ .name = DRIVER_NAME, ++ .of_match_table = arm_cci_pmu_matches, ++ }, ++ .probe = cci_pmu_probe, ++}; ++ ++static int __init cci_pmu_init(void) ++{ ++ if (platform_driver_register(&cci_pmu_platform_driver)) ++ WARN(1, "unable to register CCI platform driver\n"); ++ return 0; ++} ++ ++#else ++ ++static int __init cci_pmu_init(void) ++{ ++ return 0; ++} ++ ++#endif /* CONFIG_HW_PERF_EVENTS */ ++ ++struct cpu_port { ++ u64 mpidr; ++ u32 port; ++}; ++ ++/* ++ * Use the port MSB as valid flag, shift can be made dynamic ++ * by computing number of bits required for port indexes. ++ * Code disabling CCI cpu ports runs with D-cache invalidated ++ * and SCTLR bit clear so data accesses must be kept to a minimum ++ * to improve performance; for now shift is left static to ++ * avoid one more data access while disabling the CCI port. ++ */ ++#define PORT_VALID_SHIFT 31 ++#define PORT_VALID (0x1 << PORT_VALID_SHIFT) ++ ++static inline void init_cpu_port(struct cpu_port *port, u32 index, u64 mpidr) ++{ ++ port->port = PORT_VALID | index; ++ port->mpidr = mpidr; ++} ++ ++static inline bool cpu_port_is_valid(struct cpu_port *port) ++{ ++ return !!(port->port & PORT_VALID); ++} ++ ++static inline bool cpu_port_match(struct cpu_port *port, u64 mpidr) ++{ ++ return port->mpidr == (mpidr & MPIDR_HWID_BITMASK); ++} ++ ++static struct cpu_port cpu_port[NR_CPUS]; ++ ++/** ++ * __cci_ace_get_port - Function to retrieve the port index connected to ++ * a cpu or device. ++ * ++ * @dn: device node of the device to look-up ++ * @type: port type ++ * ++ * Return value: ++ * - CCI port index if success ++ * - -ENODEV if failure ++ */ ++static int __cci_ace_get_port(struct device_node *dn, int type) ++{ ++ int i; ++ bool ace_match; ++ struct device_node *cci_portn; ++ ++ cci_portn = of_parse_phandle(dn, "cci-control-port", 0); ++ for (i = 0; i < nb_cci_ports; i++) { ++ ace_match = ports[i].type == type; ++ if (ace_match && cci_portn == ports[i].dn) ++ return i; ++ } ++ return -ENODEV; ++} ++ ++int cci_ace_get_port(struct device_node *dn) ++{ ++ return __cci_ace_get_port(dn, ACE_LITE_PORT); ++} ++EXPORT_SYMBOL_GPL(cci_ace_get_port); ++ ++static void __init cci_ace_init_ports(void) ++{ ++ int port, ac, cpu; ++ u64 hwid; ++ const u32 *cell; ++ struct device_node *cpun, *cpus; ++ ++ cpus = of_find_node_by_path("/cpus"); ++ if (WARN(!cpus, "Missing cpus node, bailing out\n")) ++ return; ++ ++ if (WARN_ON(of_property_read_u32(cpus, "#address-cells", &ac))) ++ ac = of_n_addr_cells(cpus); ++ ++ /* ++ * Port index look-up speeds up the function disabling ports by CPU, ++ * since the logical to port index mapping is done once and does ++ * not change after system boot. ++ * The stashed index array is initialized for all possible CPUs ++ * at probe time. ++ */ ++ for_each_child_of_node(cpus, cpun) { ++ if (of_node_cmp(cpun->type, "cpu")) ++ continue; ++ cell = of_get_property(cpun, "reg", NULL); ++ if (WARN(!cell, "%s: missing reg property\n", cpun->full_name)) ++ continue; ++ ++ hwid = of_read_number(cell, ac); ++ cpu = get_logical_index(hwid & MPIDR_HWID_BITMASK); ++ ++ if (cpu < 0 || !cpu_possible(cpu)) ++ continue; ++ port = __cci_ace_get_port(cpun, ACE_PORT); ++ if (port < 0) ++ continue; ++ ++ init_cpu_port(&cpu_port[cpu], port, cpu_logical_map(cpu)); ++ } ++ ++ for_each_possible_cpu(cpu) { ++ WARN(!cpu_port_is_valid(&cpu_port[cpu]), ++ "CPU %u does not have an associated CCI port\n", ++ cpu); ++ } ++} ++/* ++ * Functions to enable/disable a CCI interconnect slave port ++ * ++ * They are called by low-level power management code to disable slave ++ * interfaces snoops and DVM broadcast. ++ * Since they may execute with cache data allocation disabled and ++ * after the caches have been cleaned and invalidated the functions provide ++ * no explicit locking since they may run with D-cache disabled, so normal ++ * cacheable kernel locks based on ldrex/strex may not work. ++ * Locking has to be provided by BSP implementations to ensure proper ++ * operations. ++ */ ++ ++/** ++ * cci_port_control() - function to control a CCI port ++ * ++ * @port: index of the port to setup ++ * @enable: if true enables the port, if false disables it ++ */ ++static void notrace cci_port_control(unsigned int port, bool enable) ++{ ++ void __iomem *base = ports[port].base; ++ ++ writel_relaxed(enable ? CCI_ENABLE_REQ : 0, base + CCI_PORT_CTRL); ++ /* ++ * This function is called from power down procedures ++ * and must not execute any instruction that might ++ * cause the processor to be put in a quiescent state ++ * (eg wfi). Hence, cpu_relax() can not be added to this ++ * read loop to optimize power, since it might hide possibly ++ * disruptive operations. ++ */ ++ while (readl_relaxed(cci_ctrl_base + CCI_CTRL_STATUS) & 0x1) ++ ; ++} ++ ++/** ++ * cci_disable_port_by_cpu() - function to disable a CCI port by CPU ++ * reference ++ * ++ * @mpidr: mpidr of the CPU whose CCI port should be disabled ++ * ++ * Disabling a CCI port for a CPU implies disabling the CCI port ++ * controlling that CPU cluster. Code disabling CPU CCI ports ++ * must make sure that the CPU running the code is the last active CPU ++ * in the cluster ie all other CPUs are quiescent in a low power state. ++ * ++ * Return: ++ * 0 on success ++ * -ENODEV on port look-up failure ++ */ ++int notrace cci_disable_port_by_cpu(u64 mpidr) ++{ ++ int cpu; ++ bool is_valid; ++ for (cpu = 0; cpu < nr_cpu_ids; cpu++) { ++ is_valid = cpu_port_is_valid(&cpu_port[cpu]); ++ if (is_valid && cpu_port_match(&cpu_port[cpu], mpidr)) { ++ cci_port_control(cpu_port[cpu].port, false); ++ return 0; ++ } ++ } ++ return -ENODEV; ++} ++EXPORT_SYMBOL_GPL(cci_disable_port_by_cpu); ++ ++/** ++ * cci_enable_port_for_self() - enable a CCI port for calling CPU ++ * ++ * Enabling a CCI port for the calling CPU implies enabling the CCI ++ * port controlling that CPU's cluster. Caller must make sure that the ++ * CPU running the code is the first active CPU in the cluster and all ++ * other CPUs are quiescent in a low power state or waiting for this CPU ++ * to complete the CCI initialization. ++ * ++ * Because this is called when the MMU is still off and with no stack, ++ * the code must be position independent and ideally rely on callee ++ * clobbered registers only. To achieve this we must code this function ++ * entirely in assembler. ++ * ++ * On success this returns with the proper CCI port enabled. In case of ++ * any failure this never returns as the inability to enable the CCI is ++ * fatal and there is no possible recovery at this stage. ++ */ ++asmlinkage void __naked cci_enable_port_for_self(void) ++{ ++ asm volatile ("\n" ++ ++" mrc p15, 0, r0, c0, c0, 5 @ get MPIDR value \n" ++" and r0, r0, #"__stringify(MPIDR_HWID_BITMASK)" \n" ++" adr r1, 5f \n" ++" ldr r2, [r1] \n" ++" add r1, r1, r2 @ &cpu_port \n" ++" add ip, r1, %[sizeof_cpu_port] \n" ++ ++ /* Loop over the cpu_port array looking for a matching MPIDR */ ++"1: ldr r2, [r1, %[offsetof_cpu_port_mpidr_lsb]] \n" ++" cmp r2, r0 @ compare MPIDR \n" ++" bne 2f \n" ++ ++ /* Found a match, now test port validity */ ++" ldr r3, [r1, %[offsetof_cpu_port_port]] \n" ++" tst r3, #"__stringify(PORT_VALID)" \n" ++" bne 3f \n" ++ ++ /* no match, loop with the next cpu_port entry */ ++"2: add r1, r1, %[sizeof_struct_cpu_port] \n" ++" cmp r1, ip @ done? \n" ++" blo 1b \n" ++ ++ /* CCI port not found -- cheaply try to stall this CPU */ ++"cci_port_not_found: \n" ++" wfi \n" ++" wfe \n" ++" b cci_port_not_found \n" ++ ++ /* Use matched port index to look up the corresponding ports entry */ ++"3: bic r3, r3, #"__stringify(PORT_VALID)" \n" ++" adr r0, 6f \n" ++" ldmia r0, {r1, r2} \n" ++" sub r1, r1, r0 @ virt - phys \n" ++" ldr r0, [r0, r2] @ *(&ports) \n" ++" mov r2, %[sizeof_struct_ace_port] \n" ++" mla r0, r2, r3, r0 @ &ports[index] \n" ++" sub r0, r0, r1 @ virt_to_phys() \n" ++ ++ /* Enable the CCI port */ ++" ldr r0, [r0, %[offsetof_port_phys]] \n" ++" mov r3, #"__stringify(CCI_ENABLE_REQ)" \n" ++" str r3, [r0, #"__stringify(CCI_PORT_CTRL)"] \n" ++ ++ /* poll the status reg for completion */ ++" adr r1, 7f \n" ++" ldr r0, [r1] \n" ++" ldr r0, [r0, r1] @ cci_ctrl_base \n" ++"4: ldr r1, [r0, #"__stringify(CCI_CTRL_STATUS)"] \n" ++" tst r1, #1 \n" ++" bne 4b \n" ++ ++" mov r0, #0 \n" ++" bx lr \n" ++ ++" .align 2 \n" ++"5: .word cpu_port - . \n" ++"6: .word . \n" ++" .word ports - 6b \n" ++"7: .word cci_ctrl_phys - . \n" ++ : : ++ [sizeof_cpu_port] "i" (sizeof(cpu_port)), ++#ifndef __ARMEB__ ++ [offsetof_cpu_port_mpidr_lsb] "i" (offsetof(struct cpu_port, mpidr)), ++#else ++ [offsetof_cpu_port_mpidr_lsb] "i" (offsetof(struct cpu_port, mpidr)+4), ++#endif ++ [offsetof_cpu_port_port] "i" (offsetof(struct cpu_port, port)), ++ [sizeof_struct_cpu_port] "i" (sizeof(struct cpu_port)), ++ [sizeof_struct_ace_port] "i" (sizeof(struct cci_ace_port)), ++ [offsetof_port_phys] "i" (offsetof(struct cci_ace_port, phys)) ); ++ ++ unreachable(); ++} ++ ++/** ++ * __cci_control_port_by_device() - function to control a CCI port by device ++ * reference ++ * ++ * @dn: device node pointer of the device whose CCI port should be ++ * controlled ++ * @enable: if true enables the port, if false disables it ++ * ++ * Return: ++ * 0 on success ++ * -ENODEV on port look-up failure ++ */ ++int notrace __cci_control_port_by_device(struct device_node *dn, bool enable) ++{ ++ int port; ++ ++ if (!dn) ++ return -ENODEV; ++ ++ port = __cci_ace_get_port(dn, ACE_LITE_PORT); ++ if (WARN_ONCE(port < 0, "node %s ACE lite port look-up failure\n", ++ dn->full_name)) ++ return -ENODEV; ++ cci_port_control(port, enable); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(__cci_control_port_by_device); ++ ++/** ++ * __cci_control_port_by_index() - function to control a CCI port by port index ++ * ++ * @port: port index previously retrieved with cci_ace_get_port() ++ * @enable: if true enables the port, if false disables it ++ * ++ * Return: ++ * 0 on success ++ * -ENODEV on port index out of range ++ * -EPERM if operation carried out on an ACE PORT ++ */ ++int notrace __cci_control_port_by_index(u32 port, bool enable) ++{ ++ if (port >= nb_cci_ports || ports[port].type == ACE_INVALID_PORT) ++ return -ENODEV; ++ /* ++ * CCI control for ports connected to CPUS is extremely fragile ++ * and must be made to go through a specific and controlled ++ * interface (ie cci_disable_port_by_cpu(); control by general purpose ++ * indexing is therefore disabled for ACE ports. ++ */ ++ if (ports[port].type == ACE_PORT) ++ return -EPERM; ++ ++ cci_port_control(port, enable); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(__cci_control_port_by_index); ++ ++static const struct cci_nb_ports cci400_ports = { ++ .nb_ace = 2, ++ .nb_ace_lite = 3 ++}; ++ ++static const struct of_device_id arm_cci_matches[] = { ++ {.compatible = "arm,cci-400", .data = &cci400_ports }, ++ {}, ++}; ++ ++static const struct of_device_id arm_cci_ctrl_if_matches[] = { ++ {.compatible = "arm,cci-400-ctrl-if", }, ++ {}, ++}; ++ ++static int __init cci_probe(void) ++{ ++ struct cci_nb_ports const *cci_config; ++ int ret, i, nb_ace = 0, nb_ace_lite = 0; ++ struct device_node *np, *cp; ++ struct resource res; ++ const char *match_str; ++ bool is_ace; ++ ++ np = of_find_matching_node(NULL, arm_cci_matches); ++ if (!np) ++ return -ENODEV; ++ ++ cci_config = of_match_node(arm_cci_matches, np)->data; ++ if (!cci_config) ++ return -ENODEV; ++ ++ nb_cci_ports = cci_config->nb_ace + cci_config->nb_ace_lite; ++ ++ ports = kcalloc(sizeof(*ports), nb_cci_ports, GFP_KERNEL); ++ if (!ports) ++ return -ENOMEM; ++ ++ ret = of_address_to_resource(np, 0, &res); ++ if (!ret) { ++ cci_ctrl_base = ioremap(res.start, resource_size(&res)); ++ cci_ctrl_phys = res.start; ++ } ++ if (ret || !cci_ctrl_base) { ++ WARN(1, "unable to ioremap CCI ctrl\n"); ++ ret = -ENXIO; ++ goto memalloc_err; ++ } ++ ++ for_each_child_of_node(np, cp) { ++ if (!of_match_node(arm_cci_ctrl_if_matches, cp)) ++ continue; ++ ++ i = nb_ace + nb_ace_lite; ++ ++ if (i >= nb_cci_ports) ++ break; ++ ++ if (of_property_read_string(cp, "interface-type", ++ &match_str)) { ++ WARN(1, "node %s missing interface-type property\n", ++ cp->full_name); ++ continue; ++ } ++ is_ace = strcmp(match_str, "ace") == 0; ++ if (!is_ace && strcmp(match_str, "ace-lite")) { ++ WARN(1, "node %s containing invalid interface-type property, skipping it\n", ++ cp->full_name); ++ continue; ++ } ++ ++ ret = of_address_to_resource(cp, 0, &res); ++ if (!ret) { ++ ports[i].base = ioremap(res.start, resource_size(&res)); ++ ports[i].phys = res.start; ++ } ++ if (ret || !ports[i].base) { ++ WARN(1, "unable to ioremap CCI port %d\n", i); ++ continue; ++ } ++ ++ if (is_ace) { ++ if (WARN_ON(nb_ace >= cci_config->nb_ace)) ++ continue; ++ ports[i].type = ACE_PORT; ++ ++nb_ace; ++ } else { ++ if (WARN_ON(nb_ace_lite >= cci_config->nb_ace_lite)) ++ continue; ++ ports[i].type = ACE_LITE_PORT; ++ ++nb_ace_lite; ++ } ++ ports[i].dn = cp; ++ } ++ ++ /* initialize a stashed array of ACE ports to speed-up look-up */ ++ cci_ace_init_ports(); ++ ++ /* ++ * Multi-cluster systems may need this data when non-coherent, during ++ * cluster power-up/power-down. Make sure it reaches main memory. ++ */ ++ sync_cache_w(&cci_ctrl_base); ++ sync_cache_w(&cci_ctrl_phys); ++ sync_cache_w(&ports); ++ sync_cache_w(&cpu_port); ++ __sync_cache_range_w(ports, sizeof(*ports) * nb_cci_ports); ++ pr_info("ARM CCI driver probed\n"); ++ return 0; ++ ++memalloc_err: ++ ++ kfree(ports); ++ return ret; ++} ++ ++static int cci_init_status = -EAGAIN; ++static DEFINE_MUTEX(cci_probing); ++ ++static int __init cci_init(void) ++{ ++ if (cci_init_status != -EAGAIN) ++ return cci_init_status; ++ ++ mutex_lock(&cci_probing); ++ if (cci_init_status == -EAGAIN) ++ cci_init_status = cci_probe(); ++ mutex_unlock(&cci_probing); ++ return cci_init_status; ++} ++ ++/* ++ * To sort out early init calls ordering a helper function is provided to ++ * check if the CCI driver has beed initialized. Function check if the driver ++ * has been initialized, if not it calls the init function that probes ++ * the driver and updates the return value. ++ */ ++bool __init cci_probed(void) ++{ ++ return cci_init() == 0; ++} ++EXPORT_SYMBOL_GPL(cci_probed); ++ ++early_initcall(cci_init); ++core_initcall(cci_pmu_init); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("ARM CCI support"); +diff -Nur linux-3.10.30/drivers/bus/imx-weim.c linux-3.10.30-cubox-i/drivers/bus/imx-weim.c +--- linux-3.10.30/drivers/bus/imx-weim.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/bus/imx-weim.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,138 @@ ++/* ++ * EIM driver for Freescale's i.MX chips ++ * ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * 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 ++#include ++#include ++ ++struct imx_weim { ++ void __iomem *base; ++ struct clk *clk; ++}; ++ ++static const struct of_device_id weim_id_table[] = { ++ { .compatible = "fsl,imx6q-weim", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, weim_id_table); ++ ++#define CS_TIMING_LEN 6 ++#define CS_REG_RANGE 0x18 ++ ++/* Parse and set the timing for this device. */ ++static int ++weim_timing_setup(struct platform_device *pdev, struct device_node *np) ++{ ++ struct imx_weim *weim = platform_get_drvdata(pdev); ++ u32 value[CS_TIMING_LEN]; ++ u32 cs_idx; ++ int ret; ++ int i; ++ ++ /* get the CS index from this child node's "reg" property. */ ++ ret = of_property_read_u32(np, "reg", &cs_idx); ++ if (ret) ++ return ret; ++ ++ /* The weim has four chip selects. */ ++ if (cs_idx > 3) ++ return -EINVAL; ++ ++ ret = of_property_read_u32_array(np, "fsl,weim-cs-timing", ++ value, CS_TIMING_LEN); ++ if (ret) ++ return ret; ++ ++ /* set the timing for WEIM */ ++ for (i = 0; i < CS_TIMING_LEN; i++) ++ writel(value[i], weim->base + cs_idx * CS_REG_RANGE + i * 4); ++ return 0; ++} ++ ++static int weim_parse_dt(struct platform_device *pdev) ++{ ++ struct device_node *child; ++ int ret; ++ ++ for_each_child_of_node(pdev->dev.of_node, child) { ++ if (!child->name) ++ continue; ++ ++ ret = weim_timing_setup(pdev, child); ++ if (ret) { ++ dev_err(&pdev->dev, "%s set timing failed.\n", ++ child->full_name); ++ return ret; ++ } ++ } ++ ++ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); ++ if (ret) ++ dev_err(&pdev->dev, "%s fail to create devices.\n", ++ pdev->dev.of_node->full_name); ++ return ret; ++} ++ ++static int weim_probe(struct platform_device *pdev) ++{ ++ struct imx_weim *weim; ++ struct resource *res; ++ int ret = -EINVAL; ++ ++ weim = devm_kzalloc(&pdev->dev, sizeof(*weim), GFP_KERNEL); ++ if (!weim) { ++ ret = -ENOMEM; ++ goto weim_err; ++ } ++ platform_set_drvdata(pdev, weim); ++ ++ /* get the resource */ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ weim->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(weim->base)) { ++ ret = PTR_ERR(weim->base); ++ goto weim_err; ++ } ++ ++ /* get the clock */ ++ weim->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(weim->clk)) ++ goto weim_err; ++ ++ ret = clk_prepare_enable(weim->clk); ++ if (ret) ++ goto weim_err; ++ ++ /* parse the device node */ ++ ret = weim_parse_dt(pdev); ++ if (ret) { ++ clk_disable_unprepare(weim->clk); ++ goto weim_err; ++ } ++ ++ dev_info(&pdev->dev, "WEIM driver registered.\n"); ++ return 0; ++ ++weim_err: ++ return ret; ++} ++ ++static struct platform_driver weim_driver = { ++ .driver = { ++ .name = "imx-weim", ++ .of_match_table = weim_id_table, ++ }, ++ .probe = weim_probe, ++}; ++ ++module_platform_driver(weim_driver); ++MODULE_AUTHOR("Freescale Semiconductor Inc."); ++MODULE_DESCRIPTION("i.MX EIM Controller Driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/char/Kconfig linux-3.10.30-cubox-i/drivers/char/Kconfig +--- linux-3.10.30/drivers/char/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/char/Kconfig 2014-03-08 20:33:28.000000000 +0100 +@@ -94,6 +94,21 @@ + + If unsure, say N. + ++config FSL_OTP ++ tristate "Freescale On-Chip OTP Memory Support" ++ depends on HAS_IOMEM && OF ++ help ++ If you say Y here, you will get support for a character device ++ interface into the One Time Programmable memory pages that are ++ stored on the some Freescale i.MX processors. This will not get ++ you access to the secure memory pages however. You will need to ++ write your own secure code and reader for that. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called fsl_otp. ++ ++ If unsure, it is safe to say Y. ++ + config PRINTER + tristate "Parallel printer support" + depends on PARPORT +diff -Nur linux-3.10.30/drivers/char/Makefile linux-3.10.30-cubox-i/drivers/char/Makefile +--- linux-3.10.30/drivers/char/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/char/Makefile 2014-03-08 20:33:28.000000000 +0100 +@@ -17,6 +17,7 @@ + obj-$(CONFIG_IBM_BSR) += bsr.o + obj-$(CONFIG_SGI_MBCS) += mbcs.o + obj-$(CONFIG_BFIN_OTP) += bfin-otp.o ++obj-$(CONFIG_FSL_OTP) += fsl_otp.o + + obj-$(CONFIG_PRINTER) += lp.o + +diff -Nur linux-3.10.30/drivers/char/fsl_otp.c linux-3.10.30-cubox-i/drivers/char/fsl_otp.c +--- linux-3.10.30/drivers/char/fsl_otp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/char/fsl_otp.c 2014-03-08 20:33:28.000000000 +0100 +@@ -0,0 +1,299 @@ ++/* ++ * Freescale On-Chip OTP driver ++ * ++ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define HW_OCOTP_CTRL 0x00000000 ++#define HW_OCOTP_CTRL_SET 0x00000004 ++#define BP_OCOTP_CTRL_WR_UNLOCK 16 ++#define BM_OCOTP_CTRL_WR_UNLOCK 0xFFFF0000 ++#define BM_OCOTP_CTRL_RELOAD_SHADOWS 0x00000400 ++#define BM_OCOTP_CTRL_ERROR 0x00000200 ++#define BM_OCOTP_CTRL_BUSY 0x00000100 ++#define BP_OCOTP_CTRL_ADDR 0 ++#define BM_OCOTP_CTRL_ADDR 0x0000007F ++ ++#define HW_OCOTP_TIMING 0x00000010 ++#define BP_OCOTP_TIMING_STROBE_READ 16 ++#define BM_OCOTP_TIMING_STROBE_READ 0x003F0000 ++#define BP_OCOTP_TIMING_RELAX 12 ++#define BM_OCOTP_TIMING_RELAX 0x0000F000 ++#define BP_OCOTP_TIMING_STROBE_PROG 0 ++#define BM_OCOTP_TIMING_STROBE_PROG 0x00000FFF ++ ++#define HW_OCOTP_DATA 0x00000020 ++ ++#define HW_OCOTP_CUST_N(n) (0x00000400 + (n) * 0x10) ++#define BF(value, field) (((value) << BP_##field) & BM_##field) ++ ++#define DEF_RELAX 20 /* > 16.5ns */ ++ ++#define BANK(a, b, c, d, e, f, g, h) { \ ++ "HW_OCOTP_"#a, "HW_OCOTP_"#b, "HW_OCOTP_"#c, "HW_OCOTP_"#d, \ ++ "HW_OCOTP_"#e, "HW_OCOTP_"#f, "HW_OCOTP_"#g, "HW_OCOTP_"#h, \ ++} ++ ++static const char *imx6q_otp_desc[16][8] = { ++ BANK(LOCK, CFG0, CFG1, CFG2, CFG3, CFG4, CFG5, CFG6), ++ BANK(MEM0, MEM1, MEM2, MEM3, MEM4, ANA0, ANA1, ANA2), ++ BANK(OTPMK0, OTPMK1, OTPMK2, OTPMK3, OTPMK4, OTPMK5, OTPMK6, OTPMK7), ++ BANK(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7), ++ BANK(RESP0, HSJC_RESP1, MAC0, MAC1, HDCP_KSV0, HDCP_KSV1, GP1, GP2), ++ BANK(DTCP_KEY0, DTCP_KEY1, DTCP_KEY2, DTCP_KEY3, DTCP_KEY4, MISC_CONF, FIELD_RETURN, SRK_REVOKE), ++ BANK(HDCP_KEY0, HDCP_KEY1, HDCP_KEY2, HDCP_KEY3, HDCP_KEY4, HDCP_KEY5, HDCP_KEY6, HDCP_KEY7), ++ BANK(HDCP_KEY8, HDCP_KEY9, HDCP_KEY10, HDCP_KEY11, HDCP_KEY12, HDCP_KEY13, HDCP_KEY14, HDCP_KEY15), ++ BANK(HDCP_KEY16, HDCP_KEY17, HDCP_KEY18, HDCP_KEY19, HDCP_KEY20, HDCP_KEY21, HDCP_KEY22, HDCP_KEY23), ++ BANK(HDCP_KEY24, HDCP_KEY25, HDCP_KEY26, HDCP_KEY27, HDCP_KEY28, HDCP_KEY29, HDCP_KEY30, HDCP_KEY31), ++ BANK(HDCP_KEY32, HDCP_KEY33, HDCP_KEY34, HDCP_KEY35, HDCP_KEY36, HDCP_KEY37, HDCP_KEY38, HDCP_KEY39), ++ BANK(HDCP_KEY40, HDCP_KEY41, HDCP_KEY42, HDCP_KEY43, HDCP_KEY44, HDCP_KEY45, HDCP_KEY46, HDCP_KEY47), ++ BANK(HDCP_KEY48, HDCP_KEY49, HDCP_KEY50, HDCP_KEY51, HDCP_KEY52, HDCP_KEY53, HDCP_KEY54, HDCP_KEY55), ++ BANK(HDCP_KEY56, HDCP_KEY57, HDCP_KEY58, HDCP_KEY59, HDCP_KEY60, HDCP_KEY61, HDCP_KEY62, HDCP_KEY63), ++ BANK(HDCP_KEY64, HDCP_KEY65, HDCP_KEY66, HDCP_KEY67, HDCP_KEY68, HDCP_KEY69, HDCP_KEY70, HDCP_KEY71), ++ BANK(CRC0, CRC1, CRC2, CRC3, CRC4, CRC5, CRC6, CRC7), ++}; ++ ++static DEFINE_MUTEX(otp_mutex); ++static void __iomem *otp_base; ++static struct clk *otp_clk; ++struct kobject *otp_kobj; ++struct kobj_attribute *otp_kattr; ++struct attribute_group *otp_attr_group; ++ ++static void set_otp_timing(void) ++{ ++ unsigned long clk_rate = 0; ++ unsigned long strobe_read, relex, strobe_prog; ++ u32 timing = 0; ++ ++ clk_rate = clk_get_rate(otp_clk); ++ ++ /* do optimization for too many zeros */ ++ relex = clk_rate / (1000000000 / DEF_RELAX) - 1; ++ strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1; ++ strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1; ++ ++ timing = BF(relex, OCOTP_TIMING_RELAX); ++ timing |= BF(strobe_read, OCOTP_TIMING_STROBE_READ); ++ timing |= BF(strobe_prog, OCOTP_TIMING_STROBE_PROG); ++ ++ __raw_writel(timing, otp_base + HW_OCOTP_TIMING); ++} ++ ++static int otp_wait_busy(u32 flags) ++{ ++ int count; ++ u32 c; ++ ++ for (count = 10000; count >= 0; count--) { ++ c = __raw_readl(otp_base + HW_OCOTP_CTRL); ++ if (!(c & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR | flags))) ++ break; ++ cpu_relax(); ++ } ++ ++ if (count < 0) ++ return -ETIMEDOUT; ++ ++ return 0; ++} ++ ++static ssize_t fsl_otp_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ unsigned int index = attr - otp_kattr; ++ u32 value = 0; ++ int ret; ++ ++ ret = clk_prepare_enable(otp_clk); ++ if (ret) ++ return 0; ++ ++ mutex_lock(&otp_mutex); ++ ++ set_otp_timing(); ++ ret = otp_wait_busy(0); ++ if (ret) ++ goto out; ++ ++ value = __raw_readl(otp_base + HW_OCOTP_CUST_N(index)); ++ ++out: ++ mutex_unlock(&otp_mutex); ++ clk_disable_unprepare(otp_clk); ++ return ret ? 0 : sprintf(buf, "0x%x\n", value); ++} ++ ++static int otp_write_bits(int addr, u32 data, u32 magic) ++{ ++ u32 c; /* for control register */ ++ ++ /* init the control register */ ++ c = __raw_readl(otp_base + HW_OCOTP_CTRL); ++ c &= ~BM_OCOTP_CTRL_ADDR; ++ c |= BF(addr, OCOTP_CTRL_ADDR); ++ c |= BF(magic, OCOTP_CTRL_WR_UNLOCK); ++ __raw_writel(c, otp_base + HW_OCOTP_CTRL); ++ ++ /* init the data register */ ++ __raw_writel(data, otp_base + HW_OCOTP_DATA); ++ otp_wait_busy(0); ++ ++ mdelay(2); /* Write Postamble */ ++ ++ return 0; ++} ++ ++static ssize_t fsl_otp_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned int index = attr - otp_kattr; ++ u32 value; ++ int ret; ++ ++ sscanf(buf, "0x%x", &value); ++ ++ ret = clk_prepare_enable(otp_clk); ++ if (ret) ++ return 0; ++ ++ mutex_lock(&otp_mutex); ++ ++ set_otp_timing(); ++ ret = otp_wait_busy(0); ++ if (ret) ++ goto out; ++ ++ otp_write_bits(index, value, 0x3e77); ++ ++ /* Reload all the shadow registers */ ++ __raw_writel(BM_OCOTP_CTRL_RELOAD_SHADOWS, ++ otp_base + HW_OCOTP_CTRL_SET); ++ udelay(1); ++ otp_wait_busy(BM_OCOTP_CTRL_RELOAD_SHADOWS); ++ ++out: ++ mutex_unlock(&otp_mutex); ++ clk_disable_unprepare(otp_clk); ++ return ret ? 0 : count; ++} ++ ++static int fsl_otp_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ struct attribute **attrs; ++ const char **desc; ++ int i, num; ++ int ret; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ otp_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(otp_base)) { ++ ret = PTR_ERR(otp_base); ++ dev_err(&pdev->dev, "failed to ioremap resource: %d\n", ret); ++ return ret; ++ } ++ ++ otp_clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(otp_clk)) { ++ ret = PTR_ERR(otp_clk); ++ dev_err(&pdev->dev, "failed to get clock: %d\n", ret); ++ return ret; ++ } ++ ++ desc = (const char **) imx6q_otp_desc; ++ num = sizeof(imx6q_otp_desc) / sizeof(void *); ++ ++ /* The last one is NULL, which is used to detect the end */ ++ attrs = devm_kzalloc(&pdev->dev, (num + 1) * sizeof(*attrs), ++ GFP_KERNEL); ++ otp_kattr = devm_kzalloc(&pdev->dev, num * sizeof(*otp_kattr), ++ GFP_KERNEL); ++ otp_attr_group = devm_kzalloc(&pdev->dev, sizeof(*otp_attr_group), ++ GFP_KERNEL); ++ if (!attrs || !otp_kattr || !otp_attr_group) ++ return -ENOMEM; ++ ++ for (i = 0; i < num; i++) { ++ sysfs_attr_init(&otp_kattr[i].attr); ++ otp_kattr[i].attr.name = desc[i]; ++ otp_kattr[i].attr.mode = 0600; ++ otp_kattr[i].show = fsl_otp_show; ++ otp_kattr[i].store = fsl_otp_store; ++ attrs[i] = &otp_kattr[i].attr; ++ } ++ otp_attr_group->attrs = attrs; ++ ++ otp_kobj = kobject_create_and_add("fsl_otp", NULL); ++ if (!otp_kobj) { ++ dev_err(&pdev->dev, "failed to add kobject\n"); ++ return -ENOMEM; ++ } ++ ++ ret = sysfs_create_group(otp_kobj, otp_attr_group); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to create sysfs group: %d\n", ret); ++ kobject_put(otp_kobj); ++ return ret; ++ } ++ ++ mutex_init(&otp_mutex); ++ ++ return 0; ++} ++ ++static int fsl_otp_remove(struct platform_device *pdev) ++{ ++ sysfs_remove_group(otp_kobj, otp_attr_group); ++ kobject_put(otp_kobj); ++ ++ return 0; ++} ++ ++static const struct of_device_id fsl_otp_dt_ids[] = { ++ { .compatible = "fsl,imx6q-ocotp", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, fsl_otp_dt_ids); ++ ++static struct platform_driver fsl_otp_driver = { ++ .driver = { ++ .name = "imx-ocotp", ++ .owner = THIS_MODULE, ++ .of_match_table = fsl_otp_dt_ids, ++ }, ++ .probe = fsl_otp_probe, ++ .remove = fsl_otp_remove, ++}; ++module_platform_driver(fsl_otp_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Huang Shijie "); ++MODULE_DESCRIPTION("Freescale i.MX OCOTP driver"); +diff -Nur linux-3.10.30/drivers/clk/Kconfig linux-3.10.30-cubox-i/drivers/clk/Kconfig +--- linux-3.10.30/drivers/clk/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/clk/Kconfig 2014-03-08 20:33:29.000000000 +0100 +@@ -42,7 +42,7 @@ + + config COMMON_CLK_VERSATILE + bool "Clock driver for ARM Reference designs" +- depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS ++ depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS || ARM64 + ---help--- + Supports clocking on ARM Reference designs: + - Integrator/AP and Integrator/CP +diff -Nur linux-3.10.30/drivers/clk/clk-divider.c linux-3.10.30-cubox-i/drivers/clk/clk-divider.c +--- linux-3.10.30/drivers/clk/clk-divider.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/clk/clk-divider.c 2014-03-08 20:33:29.000000000 +0100 +@@ -150,6 +150,7 @@ + struct clk_divider *divider = to_clk_divider(hw); + int i, bestdiv = 0; + unsigned long parent_rate, best = 0, now, maxdiv; ++ unsigned long parent_rate_saved = *best_parent_rate; + + if (!rate) + rate = 1; +@@ -173,6 +174,15 @@ + for (i = 1; i <= maxdiv; i++) { + if (!_is_valid_div(divider, i)) + continue; ++ if (rate * i == parent_rate_saved) { ++ /* ++ * It's the most ideal case if the requested rate can be ++ * divided from parent clock without needing to change ++ * parent rate, so return the divider immediately. ++ */ ++ *best_parent_rate = parent_rate_saved; ++ return i; ++ } + parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), + MULT_ROUND_UP(rate, i)); + now = parent_rate / i; +diff -Nur linux-3.10.30/drivers/clk/versatile/Makefile linux-3.10.30-cubox-i/drivers/clk/versatile/Makefile +--- linux-3.10.30/drivers/clk/versatile/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/clk/versatile/Makefile 2014-03-08 20:33:29.000000000 +0100 +@@ -4,4 +4,4 @@ + obj-$(CONFIG_INTEGRATOR_IMPD1) += clk-impd1.o + obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o + obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o clk-sp810.o +-obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o ++obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o clk-vexpress-spc.o +diff -Nur linux-3.10.30/drivers/clk/versatile/clk-vexpress-osc.c linux-3.10.30-cubox-i/drivers/clk/versatile/clk-vexpress-osc.c +--- linux-3.10.30/drivers/clk/versatile/clk-vexpress-osc.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/clk/versatile/clk-vexpress-osc.c 2014-03-08 20:33:29.000000000 +0100 +@@ -107,7 +107,7 @@ + osc->func = vexpress_config_func_get_by_node(node); + if (!osc->func) { + pr_err("Failed to obtain config func for node '%s'!\n", +- node->name); ++ node->full_name); + goto error; + } + +@@ -119,7 +119,7 @@ + + of_property_read_string(node, "clock-output-names", &init.name); + if (!init.name) +- init.name = node->name; ++ init.name = node->full_name; + + init.ops = &vexpress_osc_ops; + init.flags = CLK_IS_ROOT; +diff -Nur linux-3.10.30/drivers/clk/versatile/clk-vexpress-spc.c linux-3.10.30-cubox-i/drivers/clk/versatile/clk-vexpress-spc.c +--- linux-3.10.30/drivers/clk/versatile/clk-vexpress-spc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/clk/versatile/clk-vexpress-spc.c 2014-03-08 20:33:29.000000000 +0100 +@@ -0,0 +1,131 @@ ++/* ++ * Copyright (C) 2012 ARM Limited ++ * Copyright (C) 2012 Linaro ++ * ++ * Author: Viresh Kumar ++ * ++ * 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. ++ */ ++ ++/* SPC clock programming interface for Vexpress cpus */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct clk_spc { ++ struct clk_hw hw; ++ spinlock_t *lock; ++ int cluster; ++}; ++ ++#define to_clk_spc(spc) container_of(spc, struct clk_spc, hw) ++ ++static unsigned long spc_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct clk_spc *spc = to_clk_spc(hw); ++ u32 freq; ++ ++ if (vexpress_spc_get_performance(spc->cluster, &freq)) { ++ return -EIO; ++ pr_err("%s: Failed", __func__); ++ } ++ ++ return freq * 1000; ++} ++ ++static long spc_round_rate(struct clk_hw *hw, unsigned long drate, ++ unsigned long *parent_rate) ++{ ++ return drate; ++} ++ ++static int spc_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_spc *spc = to_clk_spc(hw); ++ ++ return vexpress_spc_set_performance(spc->cluster, rate / 1000); ++} ++ ++static struct clk_ops clk_spc_ops = { ++ .recalc_rate = spc_recalc_rate, ++ .round_rate = spc_round_rate, ++ .set_rate = spc_set_rate, ++}; ++ ++struct clk *vexpress_clk_register_spc(const char *name, int cluster_id) ++{ ++ struct clk_init_data init; ++ struct clk_spc *spc; ++ struct clk *clk; ++ ++ if (!name) { ++ pr_err("Invalid name passed"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ spc = kzalloc(sizeof(*spc), GFP_KERNEL); ++ if (!spc) { ++ pr_err("could not allocate spc clk\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ spc->hw.init = &init; ++ spc->cluster = cluster_id; ++ ++ init.name = name; ++ init.ops = &clk_spc_ops; ++ init.flags = CLK_IS_ROOT | CLK_GET_RATE_NOCACHE; ++ init.num_parents = 0; ++ ++ clk = clk_register(NULL, &spc->hw); ++ if (!IS_ERR_OR_NULL(clk)) ++ return clk; ++ ++ pr_err("clk register failed\n"); ++ kfree(spc); ++ ++ return NULL; ++} ++ ++#if defined(CONFIG_OF) ++void __init vexpress_clk_of_register_spc(void) ++{ ++ char name[14] = "cpu-cluster.X"; ++ struct device_node *node = NULL; ++ struct clk *clk; ++ const u32 *val; ++ int cluster_id = 0, len; ++ ++ if (!of_find_compatible_node(NULL, NULL, "arm,vexpress-spc")) { ++ pr_debug("%s: No SPC found, Exiting!!\n", __func__); ++ return; ++ } ++ ++ while ((node = of_find_node_by_name(node, "cluster"))) { ++ val = of_get_property(node, "reg", &len); ++ if (val && len == 4) ++ cluster_id = be32_to_cpup(val); ++ ++ name[12] = cluster_id + '0'; ++ clk = vexpress_clk_register_spc(name, cluster_id); ++ if (IS_ERR(clk)) ++ return; ++ ++ pr_debug("Registered clock '%s'\n", name); ++ clk_register_clkdev(clk, NULL, name); ++ } ++} ++CLK_OF_DECLARE(spc, "arm,vexpress-spc", vexpress_clk_of_register_spc); ++#endif +diff -Nur linux-3.10.30/drivers/clocksource/Kconfig linux-3.10.30-cubox-i/drivers/clocksource/Kconfig +--- linux-3.10.30/drivers/clocksource/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/clocksource/Kconfig 2014-03-08 20:33:29.000000000 +0100 +@@ -85,3 +85,8 @@ + Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver + for all devicetree enabled platforms. This driver will be + needed only on systems that do not have the Exynos MCT available. ++ ++config VF_PIT_TIMER ++ bool ++ help ++ Support for Period Interrupt Timer on Freescale Vybrid Family SoCs. +diff -Nur linux-3.10.30/drivers/clocksource/Makefile linux-3.10.30-cubox-i/drivers/clocksource/Makefile +--- linux-3.10.30/drivers/clocksource/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/clocksource/Makefile 2014-03-08 20:33:29.000000000 +0100 +@@ -26,6 +26,7 @@ + obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o + obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o + obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o ++obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o + + obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o + obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o +diff -Nur linux-3.10.30/drivers/clocksource/vf_pit_timer.c linux-3.10.30-cubox-i/drivers/clocksource/vf_pit_timer.c +--- linux-3.10.30/drivers/clocksource/vf_pit_timer.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/clocksource/vf_pit_timer.c 2014-03-08 20:33:29.000000000 +0100 +@@ -0,0 +1,194 @@ ++/* ++ * Copyright 2012-2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version 2 ++ * of the License, or (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Each pit takes 0x10 Bytes register space ++ */ ++#define PITMCR 0x00 ++#define PIT0_OFFSET 0x100 ++#define PITn_OFFSET(n) (PIT0_OFFSET + 0x10 * (n)) ++#define PITLDVAL 0x00 ++#define PITCVAL 0x04 ++#define PITTCTRL 0x08 ++#define PITTFLG 0x0c ++ ++#define PITMCR_MDIS (0x1 << 1) ++ ++#define PITTCTRL_TEN (0x1 << 0) ++#define PITTCTRL_TIE (0x1 << 1) ++#define PITCTRL_CHN (0x1 << 2) ++ ++#define PITTFLG_TIF 0x1 ++ ++static void __iomem *clksrc_base; ++static void __iomem *clkevt_base; ++static unsigned long cycle_per_jiffy; ++ ++static inline void pit_timer_enable(void) ++{ ++ __raw_writel(PITTCTRL_TEN | PITTCTRL_TIE, clkevt_base + PITTCTRL); ++} ++ ++static inline void pit_timer_disable(void) ++{ ++ __raw_writel(0, clkevt_base + PITTCTRL); ++} ++ ++static inline void pit_irq_acknowledge(void) ++{ ++ __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG); ++} ++ ++static unsigned int pit_read_sched_clock(void) ++{ ++ return __raw_readl(clksrc_base + PITCVAL); ++} ++ ++static int __init pit_clocksource_init(unsigned long rate) ++{ ++ /* set the max load value and start the clock source counter */ ++ __raw_writel(0, clksrc_base + PITTCTRL); ++ __raw_writel(~0UL, clksrc_base + PITLDVAL); ++ __raw_writel(PITTCTRL_TEN, clksrc_base + PITTCTRL); ++ ++ setup_sched_clock(pit_read_sched_clock, 32, rate); ++ return clocksource_mmio_init(clksrc_base + PITCVAL, "vf-pit", rate, ++ 300, 32, clocksource_mmio_readl_down); ++} ++ ++static int pit_set_next_event(unsigned long delta, ++ struct clock_event_device *unused) ++{ ++ /* ++ * set a new value to PITLDVAL register will not restart the timer, ++ * to abort the current cycle and start a timer period with the new ++ * value, the timer must be disabled and enabled again. ++ * and the PITLAVAL should be set to delta minus one according to pit ++ * hardware requirement. ++ */ ++ pit_timer_disable(); ++ __raw_writel(delta - 1, clkevt_base + PITLDVAL); ++ pit_timer_enable(); ++ ++ return 0; ++} ++ ++static void pit_set_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ switch (mode) { ++ case CLOCK_EVT_MODE_PERIODIC: ++ pit_set_next_event(cycle_per_jiffy, evt); ++ break; ++ default: ++ break; ++ } ++} ++ ++static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *evt = dev_id; ++ ++ pit_irq_acknowledge(); ++ ++ /* ++ * pit hardware doesn't support oneshot, it will generate an interrupt ++ * and reload the counter value from PITLDVAL when PITCVAL reach zero, ++ * and start the counter again. So software need to disable the timer ++ * to stop the counter loop in ONESHOT mode. ++ */ ++ if (likely(evt->mode == CLOCK_EVT_MODE_ONESHOT)) ++ pit_timer_disable(); ++ ++ evt->event_handler(evt); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct clock_event_device clockevent_pit = { ++ .name = "VF pit timer", ++ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, ++ .set_mode = pit_set_mode, ++ .set_next_event = pit_set_next_event, ++ .rating = 300, ++}; ++ ++static struct irqaction pit_timer_irq = { ++ .name = "VF pit timer", ++ .flags = IRQF_TIMER | IRQF_IRQPOLL, ++ .handler = pit_timer_interrupt, ++ .dev_id = &clockevent_pit, ++}; ++ ++static int __init pit_clockevent_init(unsigned long rate, int irq) ++{ ++ __raw_writel(0, clkevt_base + PITTCTRL); ++ __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG); ++ ++ BUG_ON(setup_irq(irq, &pit_timer_irq)); ++ ++ clockevent_pit.cpumask = cpumask_of(0); ++ clockevent_pit.irq = irq; ++ /* ++ * The value for the LDVAL register trigger is calculated as: ++ * LDVAL trigger = (period / clock period) - 1 ++ * The pit is a 32-bit down count timer, when the conter value ++ * reaches 0, it will generate an interrupt, thus the minimal ++ * LDVAL trigger value is 1. And then the min_delta is ++ * minimal LDVAL trigger value + 1, and the max_delta is full 32-bit. ++ */ ++ clockevents_config_and_register(&clockevent_pit, rate, 2, 0xffffffff); ++ ++ return 0; ++} ++ ++static void __init pit_timer_init(struct device_node *np) ++{ ++ struct clk *pit_clk; ++ void __iomem *timer_base; ++ unsigned long clk_rate; ++ int irq; ++ ++ timer_base = of_iomap(np, 0); ++ BUG_ON(!timer_base); ++ ++ /* ++ * PIT0 and PIT1 can be chained to build a 64-bit timer, ++ * so choose PIT2 as clocksource, PIT3 as clockevent device, ++ * and leave PIT0 and PIT1 unused for anyone else who needs them. ++ */ ++ clksrc_base = timer_base + PITn_OFFSET(2); ++ clkevt_base = timer_base + PITn_OFFSET(3); ++ ++ irq = irq_of_parse_and_map(np, 0); ++ BUG_ON(irq <= 0); ++ ++ pit_clk = of_clk_get(np, 0); ++ BUG_ON(IS_ERR(pit_clk)); ++ ++ BUG_ON(clk_prepare_enable(pit_clk)); ++ ++ clk_rate = clk_get_rate(pit_clk); ++ cycle_per_jiffy = clk_rate / (HZ); ++ ++ /* enable the pit module */ ++ __raw_writel(~PITMCR_MDIS, timer_base + PITMCR); ++ ++ BUG_ON(pit_clocksource_init(clk_rate)); ++ ++ pit_clockevent_init(clk_rate, irq); ++} ++CLOCKSOURCE_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init); +diff -Nur linux-3.10.30/drivers/cpufreq/Kconfig linux-3.10.30-cubox-i/drivers/cpufreq/Kconfig +--- linux-3.10.30/drivers/cpufreq/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpufreq/Kconfig 2014-03-08 20:33:29.000000000 +0100 +@@ -102,6 +102,18 @@ + Be aware that not all cpufreq drivers support the conservative + governor. If unsure have a look at the help section of the + driver. Fallback governor will be the performance governor. ++ ++config CPU_FREQ_DEFAULT_GOV_INTERACTIVE ++ bool "interactive" ++ select CPU_FREQ_GOV_INTERACTIVE ++ select CPU_FREQ_GOV_PERFORMANCE ++ help ++ Use the CPUFreq governor 'interactive' as default. This allows ++ you to get a full dynamic cpu frequency capable system by simply ++ loading your cpufreq low-level hardware driver, using the ++ 'interactive' governor for latency-sensitive workloads. Fallback ++ governor will be the performance governor. ++ + endchoice + + config CPU_FREQ_GOV_PERFORMANCE +@@ -184,6 +196,23 @@ + + If in doubt, say N. + ++config CPU_FREQ_GOV_INTERACTIVE ++ tristate "'interactive' cpufreq policy governor" ++ help ++ 'interactive' - This driver adds a dynamic cpufreq policy governor ++ designed for latency-sensitive workloads. ++ ++ This governor attempts to reduce the latency of clock ++ increases so that the system is more responsive to ++ interactive workloads. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called cpufreq_interactive. ++ ++ For details, take a look at linux/Documentation/cpu-freq. ++ ++ If in doubt, say N. ++ + config GENERIC_CPUFREQ_CPU0 + tristate "Generic CPU0 cpufreq driver" + depends on HAVE_CLK && REGULATOR && PM_OPP && OF +@@ -201,7 +230,7 @@ + endmenu + + menu "ARM CPU frequency scaling drivers" +-depends on ARM ++depends on ARM || ARM64 + source "drivers/cpufreq/Kconfig.arm" + endmenu + +diff -Nur linux-3.10.30/drivers/cpufreq/Kconfig.arm linux-3.10.30-cubox-i/drivers/cpufreq/Kconfig.arm +--- linux-3.10.30/drivers/cpufreq/Kconfig.arm 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpufreq/Kconfig.arm 2014-03-08 20:33:29.000000000 +0100 +@@ -4,7 +4,7 @@ + + config ARM_BIG_LITTLE_CPUFREQ + tristate "Generic ARM big LITTLE CPUfreq driver" +- depends on ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK ++ depends on ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK && BIG_LITTLE + help + This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. + +@@ -15,6 +15,14 @@ + This enables probing via DT for Generic CPUfreq driver for ARM + big.LITTLE platform. This gets frequency tables from DT. + ++config ARM_VEXPRESS_BL_CPUFREQ ++ tristate "ARM Vexpress big LITTLE CPUfreq driver" ++ select ARM_BIG_LITTLE_CPUFREQ ++ depends on VEXPRESS_SPC ++ help ++ This enables the CPUfreq driver for ARM Vexpress big.LITTLE platform. ++ If in doubt, say N. ++ + config ARM_EXYNOS_CPUFREQ + bool "SAMSUNG EXYNOS SoCs" + depends on ARCH_EXYNOS +@@ -67,12 +75,12 @@ + + If in doubt, say N. + +-config ARM_IMX6Q_CPUFREQ +- tristate "Freescale i.MX6Q cpufreq support" +- depends on SOC_IMX6Q ++config ARM_IMX6_CPUFREQ ++ tristate "Freescale i.MX6 cpufreq support" ++ depends on SOC_IMX6Q || SOC_IMX6SL + depends on REGULATOR_ANATOP + help +- This adds cpufreq driver support for Freescale i.MX6Q SOC. ++ This adds cpufreq driver support for Freescale i.MX6 series SOC. + + If in doubt, say N. + +diff -Nur linux-3.10.30/drivers/cpufreq/Makefile linux-3.10.30-cubox-i/drivers/cpufreq/Makefile +--- linux-3.10.30/drivers/cpufreq/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpufreq/Makefile 2014-03-08 20:33:29.000000000 +0100 +@@ -9,6 +9,7 @@ + obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o + obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o + obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o ++obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o + obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o + + # CPUfreq cross-arch helpers +@@ -48,6 +49,7 @@ + obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o + # big LITTLE per platform glues. Keep DT_BL_CPUFREQ as the last entry in all big + # LITTLE drivers, so that it is probed last. ++obj-$(CONFIG_ARM_VEXPRESS_BL_CPUFREQ) += vexpress_big_little.o + obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o + + obj-$(CONFIG_ARCH_DAVINCI_DA850) += davinci-cpufreq.o +@@ -58,7 +60,7 @@ + obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o + obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o + obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o +-obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o ++obj-$(CONFIG_ARM_IMX6_CPUFREQ) += cpufreq-imx6.o + obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o + obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o + obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o +diff -Nur linux-3.10.30/drivers/cpufreq/arm_big_little.c linux-3.10.30-cubox-i/drivers/cpufreq/arm_big_little.c +--- linux-3.10.30/drivers/cpufreq/arm_big_little.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpufreq/arm_big_little.c 2014-03-08 20:33:29.000000000 +0100 +@@ -24,27 +24,148 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include + + #include "arm_big_little.h" + +-/* Currently we support only two clusters */ +-#define MAX_CLUSTERS 2 ++#ifdef CONFIG_BL_SWITCHER ++bool bL_switching_enabled; ++#endif ++ ++#define ACTUAL_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq << 1 : freq) ++#define VIRT_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq >> 1 : freq) + + static struct cpufreq_arm_bL_ops *arm_bL_ops; + static struct clk *clk[MAX_CLUSTERS]; +-static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS]; +-static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)}; ++static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1]; ++static atomic_t cluster_usage[MAX_CLUSTERS + 1] = {ATOMIC_INIT(0), ++ ATOMIC_INIT(0)}; ++ ++static unsigned int clk_big_min; /* (Big) clock frequencies */ ++static unsigned int clk_little_max; /* Maximum clock frequency (Little) */ ++ ++static DEFINE_PER_CPU(unsigned int, physical_cluster); ++static DEFINE_PER_CPU(unsigned int, cpu_last_req_freq); ++ ++static struct mutex cluster_lock[MAX_CLUSTERS]; ++ ++static unsigned int find_cluster_maxfreq(int cluster) ++{ ++ int j; ++ u32 max_freq = 0, cpu_freq; ++ ++ for_each_online_cpu(j) { ++ cpu_freq = per_cpu(cpu_last_req_freq, j); ++ ++ if ((cluster == per_cpu(physical_cluster, j)) && ++ (max_freq < cpu_freq)) ++ max_freq = cpu_freq; ++ } ++ ++ pr_debug("%s: cluster: %d, max freq: %d\n", __func__, cluster, ++ max_freq); ++ ++ return max_freq; ++} ++ ++static unsigned int clk_get_cpu_rate(unsigned int cpu) ++{ ++ u32 cur_cluster = per_cpu(physical_cluster, cpu); ++ u32 rate = clk_get_rate(clk[cur_cluster]) / 1000; ++ ++ /* For switcher we use virtual A15 clock rates */ ++ if (is_bL_switching_enabled()) ++ rate = VIRT_FREQ(cur_cluster, rate); ++ ++ pr_debug("%s: cpu: %d, cluster: %d, freq: %u\n", __func__, cpu, ++ cur_cluster, rate); ++ ++ return rate; ++} + +-static unsigned int bL_cpufreq_get(unsigned int cpu) ++static unsigned int bL_cpufreq_get_rate(unsigned int cpu) + { +- u32 cur_cluster = cpu_to_cluster(cpu); ++ if (is_bL_switching_enabled()) { ++ pr_debug("%s: freq: %d\n", __func__, per_cpu(cpu_last_req_freq, ++ cpu)); ++ ++ return per_cpu(cpu_last_req_freq, cpu); ++ } else { ++ return clk_get_cpu_rate(cpu); ++ } ++} ++ ++static unsigned int ++bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate) ++{ ++ u32 new_rate, prev_rate; ++ int ret; ++ bool bLs = is_bL_switching_enabled(); ++ ++ mutex_lock(&cluster_lock[new_cluster]); ++ ++ if (bLs) { ++ prev_rate = per_cpu(cpu_last_req_freq, cpu); ++ per_cpu(cpu_last_req_freq, cpu) = rate; ++ per_cpu(physical_cluster, cpu) = new_cluster; ++ ++ new_rate = find_cluster_maxfreq(new_cluster); ++ new_rate = ACTUAL_FREQ(new_cluster, new_rate); ++ } else { ++ new_rate = rate; ++ } ++ ++ pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d, freq: %d\n", ++ __func__, cpu, old_cluster, new_cluster, new_rate); ++ ++ ret = clk_set_rate(clk[new_cluster], new_rate * 1000); ++ if (WARN_ON(ret)) { ++ pr_err("clk_set_rate failed: %d, new cluster: %d\n", ret, ++ new_cluster); ++ if (bLs) { ++ per_cpu(cpu_last_req_freq, cpu) = prev_rate; ++ per_cpu(physical_cluster, cpu) = old_cluster; ++ } ++ ++ mutex_unlock(&cluster_lock[new_cluster]); ++ ++ return ret; ++ } ++ ++ mutex_unlock(&cluster_lock[new_cluster]); + +- return clk_get_rate(clk[cur_cluster]) / 1000; ++ /* Recalc freq for old cluster when switching clusters */ ++ if (old_cluster != new_cluster) { ++ pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d\n", ++ __func__, cpu, old_cluster, new_cluster); ++ ++ /* Switch cluster */ ++ bL_switch_request(cpu, new_cluster); ++ ++ mutex_lock(&cluster_lock[old_cluster]); ++ ++ /* Set freq of old cluster if there are cpus left on it */ ++ new_rate = find_cluster_maxfreq(old_cluster); ++ new_rate = ACTUAL_FREQ(old_cluster, new_rate); ++ ++ if (new_rate) { ++ pr_debug("%s: Updating rate of old cluster: %d, to freq: %d\n", ++ __func__, old_cluster, new_rate); ++ ++ if (clk_set_rate(clk[old_cluster], new_rate * 1000)) ++ pr_err("%s: clk_set_rate failed: %d, old cluster: %d\n", ++ __func__, ret, old_cluster); ++ } ++ mutex_unlock(&cluster_lock[old_cluster]); ++ } ++ ++ return 0; + } + + /* Validate policy frequency range */ +@@ -60,12 +181,14 @@ + unsigned int target_freq, unsigned int relation) + { + struct cpufreq_freqs freqs; +- u32 cpu = policy->cpu, freq_tab_idx, cur_cluster; ++ u32 cpu = policy->cpu, freq_tab_idx, cur_cluster, new_cluster, ++ actual_cluster; + int ret = 0; + +- cur_cluster = cpu_to_cluster(policy->cpu); ++ cur_cluster = cpu_to_cluster(cpu); ++ new_cluster = actual_cluster = per_cpu(physical_cluster, cpu); + +- freqs.old = bL_cpufreq_get(policy->cpu); ++ freqs.old = bL_cpufreq_get_rate(cpu); + + /* Determine valid target frequency using freq_table */ + cpufreq_frequency_table_target(policy, freq_table[cur_cluster], +@@ -79,13 +202,21 @@ + if (freqs.old == freqs.new) + return 0; + ++ if (is_bL_switching_enabled()) { ++ if ((actual_cluster == A15_CLUSTER) && ++ (freqs.new < clk_big_min)) { ++ new_cluster = A7_CLUSTER; ++ } else if ((actual_cluster == A7_CLUSTER) && ++ (freqs.new > clk_little_max)) { ++ new_cluster = A15_CLUSTER; ++ } ++ } ++ + cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); + +- ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000); +- if (ret) { +- pr_err("clk_set_rate failed: %d\n", ret); ++ ret = bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs.new); ++ if (ret) + return ret; +- } + + policy->cur = freqs.new; + +@@ -94,7 +225,73 @@ + return ret; + } + +-static void put_cluster_clk_and_freq_table(struct device *cpu_dev) ++static inline u32 get_table_count(struct cpufreq_frequency_table *table) ++{ ++ int count; ++ ++ for (count = 0; table[count].frequency != CPUFREQ_TABLE_END; count++) ++ ; ++ ++ return count; ++} ++ ++/* get the minimum frequency in the cpufreq_frequency_table */ ++static inline u32 get_table_min(struct cpufreq_frequency_table *table) ++{ ++ int i; ++ uint32_t min_freq = ~0; ++ for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) ++ if (table[i].frequency < min_freq) ++ min_freq = table[i].frequency; ++ return min_freq; ++} ++ ++/* get the maximum frequency in the cpufreq_frequency_table */ ++static inline u32 get_table_max(struct cpufreq_frequency_table *table) ++{ ++ int i; ++ uint32_t max_freq = 0; ++ for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) ++ if (table[i].frequency > max_freq) ++ max_freq = table[i].frequency; ++ return max_freq; ++} ++ ++static int merge_cluster_tables(void) ++{ ++ int i, j, k = 0, count = 1; ++ struct cpufreq_frequency_table *table; ++ ++ for (i = 0; i < MAX_CLUSTERS; i++) ++ count += get_table_count(freq_table[i]); ++ ++ table = kzalloc(sizeof(*table) * count, GFP_KERNEL); ++ if (!table) ++ return -ENOMEM; ++ ++ freq_table[MAX_CLUSTERS] = table; ++ ++ /* Add in reverse order to get freqs in increasing order */ ++ for (i = MAX_CLUSTERS - 1; i >= 0; i--) { ++ for (j = 0; freq_table[i][j].frequency != CPUFREQ_TABLE_END; ++ j++) { ++ table[k].frequency = VIRT_FREQ(i, ++ freq_table[i][j].frequency); ++ pr_debug("%s: index: %d, freq: %d\n", __func__, k, ++ table[k].frequency); ++ k++; ++ } ++ } ++ ++ table[k].index = k; ++ table[k].frequency = CPUFREQ_TABLE_END; ++ ++ pr_debug("%s: End, table: %p, count: %d\n", __func__, table, k); ++ ++ return 0; ++} ++ ++static void _put_cluster_clk_and_freq_table(struct device *cpu_dev) + { + u32 cluster = cpu_to_cluster(cpu_dev->id); + +@@ -105,10 +302,35 @@ + } + } + +-static int get_cluster_clk_and_freq_table(struct device *cpu_dev) ++static void put_cluster_clk_and_freq_table(struct device *cpu_dev) ++{ ++ u32 cluster = cpu_to_cluster(cpu_dev->id); ++ int i; ++ ++ if (cluster < MAX_CLUSTERS) ++ return _put_cluster_clk_and_freq_table(cpu_dev); ++ ++ if (atomic_dec_return(&cluster_usage[MAX_CLUSTERS])) ++ return; ++ ++ for (i = 0; i < MAX_CLUSTERS; i++) { ++ struct device *cdev = get_cpu_device(i); ++ if (!cdev) { ++ pr_err("%s: failed to get cpu%d device\n", __func__, i); ++ return; ++ } ++ ++ _put_cluster_clk_and_freq_table(cdev); ++ } ++ ++ /* free virtual table */ ++ kfree(freq_table[MAX_CLUSTERS]); ++} ++ ++static int _get_cluster_clk_and_freq_table(struct device *cpu_dev) + { + u32 cluster = cpu_to_cluster(cpu_dev->id); +- char name[14] = "cpu-cluster."; ++ char name[14] = "cpu-cluster.X"; + int ret; + + if (atomic_inc_return(&cluster_usage[cluster]) != 1) +@@ -149,6 +371,62 @@ + return ret; + } + ++static int get_cluster_clk_and_freq_table(struct device *cpu_dev) ++{ ++ u32 cluster = cpu_to_cluster(cpu_dev->id); ++ int i, ret; ++ ++ if (cluster < MAX_CLUSTERS) ++ return _get_cluster_clk_and_freq_table(cpu_dev); ++ ++ if (atomic_inc_return(&cluster_usage[MAX_CLUSTERS]) != 1) ++ return 0; ++ ++ /* ++ * Get data for all clusters and fill virtual cluster with a merge of ++ * both ++ */ ++ for (i = 0; i < MAX_CLUSTERS; i++) { ++ struct device *cdev = get_cpu_device(i); ++ if (!cdev) { ++ pr_err("%s: failed to get cpu%d device\n", __func__, i); ++ return -ENODEV; ++ } ++ ++ ret = _get_cluster_clk_and_freq_table(cdev); ++ if (ret) ++ goto put_clusters; ++ } ++ ++ ret = merge_cluster_tables(); ++ if (ret) ++ goto put_clusters; ++ ++ /* Assuming 2 cluster, set clk_big_min and clk_little_max */ ++ clk_big_min = get_table_min(freq_table[0]); ++ clk_little_max = VIRT_FREQ(1, get_table_max(freq_table[1])); ++ ++ pr_debug("%s: cluster: %d, clk_big_min: %d, clk_little_max: %d\n", ++ __func__, cluster, clk_big_min, clk_little_max); ++ ++ return 0; ++ ++put_clusters: ++ while (i--) { ++ struct device *cdev = get_cpu_device(i); ++ if (!cdev) { ++ pr_err("%s: failed to get cpu%d device\n", __func__, i); ++ return -ENODEV; ++ } ++ ++ _put_cluster_clk_and_freq_table(cdev); ++ } ++ ++ atomic_dec(&cluster_usage[MAX_CLUSTERS]); ++ ++ return ret; ++} ++ + /* Per-CPU initialization */ + static int bL_cpufreq_init(struct cpufreq_policy *policy) + { +@@ -177,37 +455,30 @@ + + cpufreq_frequency_table_get_attr(freq_table[cur_cluster], policy->cpu); + ++ if (cur_cluster < MAX_CLUSTERS) { ++ cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); ++ ++ per_cpu(physical_cluster, policy->cpu) = cur_cluster; ++ } else { ++ /* Assumption: during init, we are always running on A15 */ ++ per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER; ++ } ++ + if (arm_bL_ops->get_transition_latency) + policy->cpuinfo.transition_latency = + arm_bL_ops->get_transition_latency(cpu_dev); + else + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + +- policy->cur = bL_cpufreq_get(policy->cpu); ++ policy->cur = clk_get_cpu_rate(policy->cpu); + +- cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); ++ if (is_bL_switching_enabled()) ++ per_cpu(cpu_last_req_freq, policy->cpu) = policy->cur; + + dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu); + return 0; + } + +-static int bL_cpufreq_exit(struct cpufreq_policy *policy) +-{ +- struct device *cpu_dev; +- +- cpu_dev = get_cpu_device(policy->cpu); +- if (!cpu_dev) { +- pr_err("%s: failed to get cpu%d device\n", __func__, +- policy->cpu); +- return -ENODEV; +- } +- +- put_cluster_clk_and_freq_table(cpu_dev); +- dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu); +- +- return 0; +-} +- + /* Export freq_table to sysfs */ + static struct freq_attr *bL_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, +@@ -219,16 +490,47 @@ + .flags = CPUFREQ_STICKY, + .verify = bL_cpufreq_verify_policy, + .target = bL_cpufreq_set_target, +- .get = bL_cpufreq_get, ++ .get = bL_cpufreq_get_rate, + .init = bL_cpufreq_init, +- .exit = bL_cpufreq_exit, + .have_governor_per_policy = true, + .attr = bL_cpufreq_attr, + }; + ++static int bL_cpufreq_switcher_notifier(struct notifier_block *nfb, ++ unsigned long action, void *_arg) ++{ ++ pr_debug("%s: action: %ld\n", __func__, action); ++ ++ switch (action) { ++ case BL_NOTIFY_PRE_ENABLE: ++ case BL_NOTIFY_PRE_DISABLE: ++ cpufreq_unregister_driver(&bL_cpufreq_driver); ++ break; ++ ++ case BL_NOTIFY_POST_ENABLE: ++ set_switching_enabled(true); ++ cpufreq_register_driver(&bL_cpufreq_driver); ++ break; ++ ++ case BL_NOTIFY_POST_DISABLE: ++ set_switching_enabled(false); ++ cpufreq_register_driver(&bL_cpufreq_driver); ++ break; ++ ++ default: ++ return NOTIFY_DONE; ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block bL_switcher_notifier = { ++ .notifier_call = bL_cpufreq_switcher_notifier, ++}; ++ + int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) + { +- int ret; ++ int ret, i; + + if (arm_bL_ops) { + pr_debug("%s: Already registered: %s, exiting\n", __func__, +@@ -243,16 +545,29 @@ + + arm_bL_ops = ops; + ++ ret = bL_switcher_get_enabled(); ++ set_switching_enabled(ret); ++ ++ for (i = 0; i < MAX_CLUSTERS; i++) ++ mutex_init(&cluster_lock[i]); ++ + ret = cpufreq_register_driver(&bL_cpufreq_driver); + if (ret) { + pr_info("%s: Failed registering platform driver: %s, err: %d\n", + __func__, ops->name, ret); + arm_bL_ops = NULL; + } else { +- pr_info("%s: Registered platform driver: %s\n", __func__, +- ops->name); ++ ret = bL_switcher_register_notifier(&bL_switcher_notifier); ++ if (ret) { ++ cpufreq_unregister_driver(&bL_cpufreq_driver); ++ arm_bL_ops = NULL; ++ } else { ++ pr_info("%s: Registered platform driver: %s\n", ++ __func__, ops->name); ++ } + } + ++ bL_switcher_put_enabled(); + return ret; + } + EXPORT_SYMBOL_GPL(bL_cpufreq_register); +@@ -265,9 +580,31 @@ + return; + } + ++ bL_switcher_get_enabled(); ++ bL_switcher_unregister_notifier(&bL_switcher_notifier); + cpufreq_unregister_driver(&bL_cpufreq_driver); ++ bL_switcher_put_enabled(); + pr_info("%s: Un-registered platform driver: %s\n", __func__, + arm_bL_ops->name); ++ ++ /* For saving table get/put on every cpu in/out */ ++ if (is_bL_switching_enabled()) { ++ put_cluster_clk_and_freq_table(get_cpu_device(0)); ++ } else { ++ int i; ++ ++ for (i = 0; i < MAX_CLUSTERS; i++) { ++ struct device *cdev = get_cpu_device(i); ++ if (!cdev) { ++ pr_err("%s: failed to get cpu%d device\n", ++ __func__, i); ++ return; ++ } ++ ++ put_cluster_clk_and_freq_table(cdev); ++ } ++ } ++ + arm_bL_ops = NULL; + } + EXPORT_SYMBOL_GPL(bL_cpufreq_unregister); +diff -Nur linux-3.10.30/drivers/cpufreq/arm_big_little.h linux-3.10.30-cubox-i/drivers/cpufreq/arm_big_little.h +--- linux-3.10.30/drivers/cpufreq/arm_big_little.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpufreq/arm_big_little.h 2014-03-08 20:33:29.000000000 +0100 +@@ -23,6 +23,20 @@ + #include + #include + ++/* Currently we support only two clusters */ ++#define A15_CLUSTER 0 ++#define A7_CLUSTER 1 ++#define MAX_CLUSTERS 2 ++ ++#ifdef CONFIG_BL_SWITCHER ++extern bool bL_switching_enabled; ++#define is_bL_switching_enabled() bL_switching_enabled ++#define set_switching_enabled(x) (bL_switching_enabled = (x)) ++#else ++#define is_bL_switching_enabled() false ++#define set_switching_enabled(x) do { } while (0) ++#endif ++ + struct cpufreq_arm_bL_ops { + char name[CPUFREQ_NAME_LEN]; + int (*get_transition_latency)(struct device *cpu_dev); +@@ -36,7 +50,8 @@ + + static inline int cpu_to_cluster(int cpu) + { +- return topology_physical_package_id(cpu); ++ return is_bL_switching_enabled() ? MAX_CLUSTERS: ++ topology_physical_package_id(cpu); + } + + int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops); +diff -Nur linux-3.10.30/drivers/cpufreq/cpufreq-imx6.c linux-3.10.30-cubox-i/drivers/cpufreq/cpufreq-imx6.c +--- linux-3.10.30/drivers/cpufreq/cpufreq-imx6.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpufreq/cpufreq-imx6.c 2014-03-08 20:33:29.000000000 +0100 +@@ -0,0 +1,483 @@ ++/* ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This program 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 ++ ++static struct regulator *arm_reg; ++static struct regulator *pu_reg; ++static struct regulator *soc_reg; ++ ++static struct clk *arm_clk; ++static struct clk *pll1_sys_clk; ++static struct clk *pll1_sw_clk; ++static struct clk *step_clk; ++static struct clk *pll2_pfd2_396m_clk; ++ ++static struct device *cpu_dev; ++static struct cpufreq_frequency_table *freq_table; ++static unsigned int transition_latency; ++static DEFINE_MUTEX(set_cpufreq_lock); ++ ++struct soc_opp { ++ u32 arm_freq; ++ u32 soc_volt; ++}; ++ ++static struct soc_opp *imx6_soc_opp; ++static u32 soc_opp_count; ++ ++static int imx6_verify_speed(struct cpufreq_policy *policy) ++{ ++ return cpufreq_frequency_table_verify(policy, freq_table); ++} ++ ++static unsigned int imx6_get_speed(unsigned int cpu) ++{ ++ return clk_get_rate(arm_clk) / 1000; ++} ++ ++static int imx6_set_target(struct cpufreq_policy *policy, ++ unsigned int target_freq, unsigned int relation) ++{ ++ struct cpufreq_freqs freqs; ++ struct opp *opp; ++ unsigned long freq_hz, volt, volt_old; ++ unsigned int index, soc_opp_index = 0; ++ int ret; ++ ++ mutex_lock(&set_cpufreq_lock); ++ ++ ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, ++ relation, &index); ++ if (ret) { ++ dev_err(cpu_dev, "failed to match target frequency %d: %d\n", ++ target_freq, ret); ++ mutex_unlock(&set_cpufreq_lock); ++ return ret; ++ } ++ ++ freqs.new = freq_table[index].frequency; ++ freq_hz = freqs.new * 1000; ++ freqs.old = clk_get_rate(arm_clk) / 1000; ++ ++ if (freqs.old == freqs.new) { ++ mutex_unlock(&set_cpufreq_lock); ++ return 0; ++ } ++ ++ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); ++ ++ rcu_read_lock(); ++ opp = opp_find_freq_ceil(cpu_dev, &freq_hz); ++ if (IS_ERR(opp)) { ++ rcu_read_unlock(); ++ dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); ++ mutex_unlock(&set_cpufreq_lock); ++ return PTR_ERR(opp); ++ } ++ ++ volt = opp_get_voltage(opp); ++ rcu_read_unlock(); ++ volt_old = regulator_get_voltage(arm_reg); ++ ++ /* Find the matching VDDSOC/VDDPU operating voltage */ ++ while (soc_opp_index < soc_opp_count) { ++ if (freqs.new == imx6_soc_opp[soc_opp_index].arm_freq) ++ break; ++ soc_opp_index++; ++ } ++ if (soc_opp_index >= soc_opp_count) { ++ dev_err(cpu_dev, ++ "Cannot find matching imx6_soc_opp voltage\n"); ++ mutex_unlock(&set_cpufreq_lock); ++ return -EINVAL; ++ } ++ ++ dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", ++ freqs.old / 1000, volt_old / 1000, ++ freqs.new / 1000, volt / 1000); ++ ++ /* ++ * CPU freq is increasing, so need to ensure ++ * that bus frequency is increased too. ++ */ ++ if (freqs.old == freq_table[0].frequency) ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ /* scaling up? scale voltage before frequency */ ++ if (freqs.new > freqs.old) { ++ if (regulator_is_enabled(pu_reg)) { ++ ret = regulator_set_voltage_tol(pu_reg, ++ imx6_soc_opp[soc_opp_index].soc_volt, ++ 0); ++ if (ret) { ++ dev_err(cpu_dev, ++ "failed to scale vddpu up: %d\n", ret); ++ goto err1; ++ } ++ } ++ ret = regulator_set_voltage_tol(soc_reg, ++ imx6_soc_opp[soc_opp_index].soc_volt, 0); ++ if (ret) { ++ dev_err(cpu_dev, ++ "failed to scale vddsoc up: %d\n", ret); ++ goto err1; ++ } ++ ret = regulator_set_voltage_tol(arm_reg, volt, 0); ++ if (ret) { ++ dev_err(cpu_dev, ++ "failed to scale vddarm up: %d\n", ret); ++ goto err1; ++ } ++ } ++ ++ /* ++ * The setpoints are selected per PLL/PDF frequencies, so we need to ++ * reprogram PLL for frequency scaling. The procedure of reprogramming ++ * PLL1 is as below. ++ * ++ * - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it ++ * - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it ++ * - Disable pll2_pfd2_396m_clk ++ */ ++ clk_set_parent(step_clk, pll2_pfd2_396m_clk); ++ clk_set_parent(pll1_sw_clk, step_clk); ++ if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) { ++ clk_set_rate(pll1_sys_clk, freqs.new * 1000); ++ clk_set_parent(pll1_sw_clk, pll1_sys_clk); ++ } ++ ++ /* Ensure the arm clock divider is what we expect */ ++ ret = clk_set_rate(arm_clk, freqs.new * 1000); ++ if (ret) { ++ dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); ++ goto err1; ++ } ++ ++ /* scaling down? scale voltage after frequency */ ++ if (freqs.new < freqs.old) { ++ ret = regulator_set_voltage_tol(arm_reg, volt, 0); ++ if (ret) { ++ dev_warn(cpu_dev, ++ "failed to scale vddarm down: %d\n", ret); ++ goto err1; ++ } ++ ++ ret = regulator_set_voltage_tol(soc_reg, ++ imx6_soc_opp[soc_opp_index].soc_volt, 0); ++ if (ret) { ++ dev_err(cpu_dev, ++ "failed to scale vddsoc down: %d\n", ret); ++ goto err1; ++ } ++ ++ if (regulator_is_enabled(pu_reg)) { ++ ret = regulator_set_voltage_tol(pu_reg, ++ imx6_soc_opp[soc_opp_index].soc_volt, ++ 0); ++ if (ret) { ++ dev_err(cpu_dev, ++ "failed to scale vddpu down: %d\n", ret); ++ goto err1; ++ } ++ } ++ } ++ /* ++ * If CPU is dropped to the lowest level, release the need ++ * for a high bus frequency. ++ */ ++ if (freqs.new == freq_table[0].frequency) ++ release_bus_freq(BUS_FREQ_HIGH); ++ ++ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); ++ ++ mutex_unlock(&set_cpufreq_lock); ++ return 0; ++err1: ++ mutex_unlock(&set_cpufreq_lock); ++ return -1; ++} ++ ++static int imx6_cpufreq_init(struct cpufreq_policy *policy) ++{ ++ int ret; ++ ++ ret = cpufreq_frequency_table_cpuinfo(policy, freq_table); ++ if (ret) { ++ dev_err(cpu_dev, "invalid frequency table: %d\n", ret); ++ return ret; ++ } ++ ++ policy->cpuinfo.transition_latency = transition_latency; ++ policy->cur = clk_get_rate(arm_clk) / 1000; ++ cpumask_setall(policy->cpus); ++ cpufreq_frequency_table_get_attr(freq_table, policy->cpu); ++ ++ if (policy->cur > freq_table[0].frequency) ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ return 0; ++} ++ ++static int imx6_cpufreq_exit(struct cpufreq_policy *policy) ++{ ++ cpufreq_frequency_table_put_attr(policy->cpu); ++ return 0; ++} ++ ++static struct freq_attr *imx6_cpufreq_attr[] = { ++ &cpufreq_freq_attr_scaling_available_freqs, ++ NULL, ++}; ++ ++static struct cpufreq_driver imx6_cpufreq_driver = { ++ .verify = imx6_verify_speed, ++ .target = imx6_set_target, ++ .get = imx6_get_speed, ++ .init = imx6_cpufreq_init, ++ .exit = imx6_cpufreq_exit, ++ .name = "imx6-cpufreq", ++ .attr = imx6_cpufreq_attr, ++}; ++ ++static int imx6_cpufreq_pm_notify(struct notifier_block *nb, ++ unsigned long event, void *dummy) ++{ ++ struct cpufreq_policy *data = cpufreq_cpu_get(0); ++ static u32 cpufreq_policy_min_pre_suspend; ++ ++ /* ++ * During suspend/resume, When cpufreq driver try to increase ++ * voltage/freq, it needs to control I2C/SPI to communicate ++ * with external PMIC to adjust voltage, but these I2C/SPI ++ * devices may be already suspended, to avoid such scenario, ++ * we just increase cpufreq to highest setpoint before suspend. ++ */ ++ switch (event) { ++ case PM_SUSPEND_PREPARE: ++ cpufreq_policy_min_pre_suspend = data->user_policy.min; ++ data->user_policy.min = data->user_policy.max; ++ break; ++ case PM_POST_SUSPEND: ++ data->user_policy.min = cpufreq_policy_min_pre_suspend; ++ break; ++ default: ++ break; ++ } ++ ++ cpufreq_update_policy(0); ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block imx6_cpufreq_pm_notifier = { ++ .notifier_call = imx6_cpufreq_pm_notify, ++}; ++ ++static int imx6_cpufreq_probe(struct platform_device *pdev) ++{ ++ struct device_node *np; ++ struct opp *opp; ++ unsigned long min_volt = 0, max_volt = 0; ++ int num, ret; ++ const struct property *prop; ++ const __be32 *val; ++ u32 nr, i; ++ ++ cpu_dev = &pdev->dev; ++ ++ np = of_find_node_by_path("/cpus/cpu@0"); ++ if (!np) { ++ dev_err(cpu_dev, "failed to find cpu0 node\n"); ++ return -ENOENT; ++ } ++ ++ cpu_dev->of_node = np; ++ ++ arm_clk = devm_clk_get(cpu_dev, "arm"); ++ pll1_sys_clk = devm_clk_get(cpu_dev, "pll1_sys"); ++ pll1_sw_clk = devm_clk_get(cpu_dev, "pll1_sw"); ++ step_clk = devm_clk_get(cpu_dev, "step"); ++ pll2_pfd2_396m_clk = devm_clk_get(cpu_dev, "pll2_pfd2_396m"); ++ if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) || ++ IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk)) { ++ dev_err(cpu_dev, "failed to get clocks\n"); ++ ret = -ENOENT; ++ goto put_node; ++ } ++ ++ arm_reg = devm_regulator_get(cpu_dev, "arm"); ++ pu_reg = devm_regulator_get(cpu_dev, "pu"); ++ soc_reg = devm_regulator_get(cpu_dev, "soc"); ++ if (IS_ERR(arm_reg) || IS_ERR(pu_reg) || IS_ERR(soc_reg)) { ++ dev_err(cpu_dev, "failed to get regulators\n"); ++ ret = -ENOENT; ++ goto put_node; ++ } ++ ++ /* We expect an OPP table supplied by platform */ ++ num = opp_get_opp_count(cpu_dev); ++ if (num < 0) { ++ ret = num; ++ dev_err(cpu_dev, "no OPP table is found: %d\n", ret); ++ goto put_node; ++ } ++ ++ ret = opp_init_cpufreq_table(cpu_dev, &freq_table); ++ if (ret) { ++ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); ++ goto put_node; ++ } ++ ++ prop = of_find_property(np, "fsl,soc-operating-points", NULL); ++ if (!prop) { ++ dev_err(cpu_dev, ++ "fsl,soc-operating-points node not found\n"); ++ goto free_freq_table; ++ } ++ if (!prop->value) { ++ dev_err(cpu_dev, ++ "No entries in fsl-soc-operating-points node.\n"); ++ goto free_freq_table; ++ } ++ ++ /* ++ * Each OPP is a set of tuples consisting of frequency and ++ * voltage like . ++ */ ++ nr = prop->length / sizeof(u32); ++ if (nr % 2) { ++ dev_err(cpu_dev, "Invalid fsl-soc-operating-points list\n"); ++ goto free_freq_table; ++ } ++ ++ /* Get the VDDSOC/VDDPU voltages that need to track the CPU voltages. */ ++ imx6_soc_opp = devm_kzalloc(cpu_dev, ++ sizeof(struct soc_opp) * (nr / 2), ++ GFP_KERNEL); ++ ++ if (imx6_soc_opp == NULL) { ++ dev_err(cpu_dev, "No Memory for VDDSOC/PU table\n"); ++ goto free_freq_table; ++ } ++ ++ rcu_read_lock(); ++ val = prop->value; ++ ++ for (i = 0; i < nr / 2; i++) { ++ unsigned long freq = be32_to_cpup(val++); ++ unsigned long volt = be32_to_cpup(val++); ++ ++ if (i == 0) ++ min_volt = max_volt = volt; ++ if (volt < min_volt) ++ min_volt = volt; ++ if (volt > max_volt) ++ max_volt = volt; ++ opp = opp_find_freq_exact(cpu_dev, ++ freq * 1000, true); ++ if (IS_ERR(opp)) { ++ opp = opp_find_freq_exact(cpu_dev, ++ freq * 1000, false); ++ if (IS_ERR(opp)) { ++ dev_err(cpu_dev, ++ "freq in soc-operating-points does not \ ++ match cpufreq table\n"); ++ rcu_read_unlock(); ++ goto free_freq_table; ++ } ++ } ++ imx6_soc_opp[i].arm_freq = freq; ++ imx6_soc_opp[i].soc_volt = volt; ++ soc_opp_count++; ++ } ++ rcu_read_unlock(); ++ ++ if (of_property_read_u32(np, "clock-latency", &transition_latency)) ++ transition_latency = CPUFREQ_ETERNAL; ++ ++ /* ++ * Calculate the ramp time for max voltage change in the ++ * VDDSOC and VDDPU regulators. ++ */ ++ ret = regulator_set_voltage_time(soc_reg, min_volt, max_volt); ++ if (ret > 0) ++ transition_latency += ret * 1000; ++ ++ ret = regulator_set_voltage_time(pu_reg, min_volt, max_volt); ++ if (ret > 0) ++ transition_latency += ret * 1000; ++ ++ /* ++ * OPP is maintained in order of increasing frequency, and ++ * freq_table initialised from OPP is therefore sorted in the ++ * same order. ++ */ ++ rcu_read_lock(); ++ opp = opp_find_freq_exact(cpu_dev, ++ freq_table[0].frequency * 1000, true); ++ min_volt = opp_get_voltage(opp); ++ opp = opp_find_freq_exact(cpu_dev, ++ freq_table[num - 1].frequency * 1000, true); ++ max_volt = opp_get_voltage(opp); ++ rcu_read_unlock(); ++ ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt); ++ if (ret > 0) ++ transition_latency += ret * 1000; ++ ++ mutex_init(&set_cpufreq_lock); ++ register_pm_notifier(&imx6_cpufreq_pm_notifier); ++ ++ ret = cpufreq_register_driver(&imx6_cpufreq_driver); ++ if (ret) { ++ dev_err(cpu_dev, "failed register driver: %d\n", ret); ++ goto free_freq_table; ++ } ++ ++ of_node_put(np); ++ return 0; ++ ++free_freq_table: ++ opp_free_cpufreq_table(cpu_dev, &freq_table); ++put_node: ++ of_node_put(np); ++ return ret; ++} ++ ++static int imx6_cpufreq_remove(struct platform_device *pdev) ++{ ++ cpufreq_unregister_driver(&imx6_cpufreq_driver); ++ opp_free_cpufreq_table(cpu_dev, &freq_table); ++ ++ return 0; ++} ++ ++static struct platform_driver imx6_cpufreq_platdrv = { ++ .driver = { ++ .name = "imx6-cpufreq", ++ .owner = THIS_MODULE, ++ }, ++ .probe = imx6_cpufreq_probe, ++ .remove = imx6_cpufreq_remove, ++}; ++module_platform_driver(imx6_cpufreq_platdrv); ++ ++MODULE_AUTHOR("Shawn Guo "); ++MODULE_DESCRIPTION("Freescale i.MX6 cpufreq driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/cpufreq/cpufreq_interactive.c linux-3.10.30-cubox-i/drivers/cpufreq/cpufreq_interactive.c +--- linux-3.10.30/drivers/cpufreq/cpufreq_interactive.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpufreq/cpufreq_interactive.c 2014-03-08 20:33:29.000000000 +0100 +@@ -0,0 +1,705 @@ ++/* ++ * drivers/cpufreq/cpufreq_interactive.c ++ * ++ * Copyright (C) 2010 Google, Inc. ++ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ * Author: Mike Chan (mike@android.com) ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static atomic_t active_count = ATOMIC_INIT(0); ++ ++struct cpufreq_interactive_cpuinfo { ++ struct timer_list cpu_timer; ++ int timer_idlecancel; ++ u64 time_in_idle; ++ u64 idle_exit_time; ++ u64 timer_run_time; ++ int idling; ++ u64 freq_change_time; ++ u64 freq_change_time_in_idle; ++ struct cpufreq_policy *policy; ++ struct cpufreq_frequency_table *freq_table; ++ unsigned int target_freq; ++ int governor_enabled; ++}; ++ ++static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo); ++ ++/* Workqueues handle frequency scaling */ ++static struct task_struct *up_task; ++static struct workqueue_struct *down_wq; ++static struct work_struct freq_scale_down_work; ++static cpumask_t up_cpumask; ++static spinlock_t up_cpumask_lock; ++static cpumask_t down_cpumask; ++static spinlock_t down_cpumask_lock; ++static struct mutex set_speed_lock; ++ ++/* Hi speed to bump to from lo speed when load burst (default max) */ ++static u64 hispeed_freq; ++ ++/* Go to hi speed when CPU load at or above this value. */ ++#define DEFAULT_GO_HISPEED_LOAD 95 ++static unsigned long go_hispeed_load; ++ ++/* ++ * The minimum amount of time to spend at a frequency before we can ramp down. ++ */ ++#define DEFAULT_MIN_SAMPLE_TIME (20 * USEC_PER_MSEC) ++static unsigned long min_sample_time; ++ ++/* ++ * The sample rate of the timer used to increase frequency ++ */ ++#define DEFAULT_TIMER_RATE (50 * USEC_PER_MSEC) ++#define CPUFREQ_IRQ_LEN 60 ++#define CPUFREQ_NOTE_LEN 120 ++static unsigned long timer_rate; ++ ++static int cpufreq_governor_interactive(struct cpufreq_policy *policy, ++ unsigned int event); ++ ++#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE ++static ++#endif ++struct cpufreq_governor cpufreq_gov_interactive = { ++ .name = "interactive", ++ .governor = cpufreq_governor_interactive, ++ .max_transition_latency = 10000000, ++ .owner = THIS_MODULE, ++}; ++ ++static void cpufreq_interactive_timer(unsigned long data) ++{ ++ unsigned int delta_idle; ++ unsigned int delta_time; ++ int cpu_load; ++ int load_since_change; ++ u64 time_in_idle; ++ u64 idle_exit_time; ++ struct cpufreq_interactive_cpuinfo *pcpu = ++ &per_cpu(cpuinfo, data); ++ u64 now_idle; ++ unsigned int new_freq; ++ unsigned int index; ++ unsigned long flags; ++ ++ smp_rmb(); ++ ++ if (!pcpu->governor_enabled) ++ goto exit; ++ ++ /* ++ * Once pcpu->timer_run_time is updated to >= pcpu->idle_exit_time, ++ * this lets idle exit know the current idle time sample has ++ * been processed, and idle exit can generate a new sample and ++ * re-arm the timer. This prevents a concurrent idle ++ * exit on that CPU from writing a new set of info at the same time ++ * the timer function runs (the timer function can't use that info ++ * until more time passes). ++ */ ++ time_in_idle = pcpu->time_in_idle; ++ idle_exit_time = pcpu->idle_exit_time; ++ now_idle = get_cpu_idle_time_us(data, &pcpu->timer_run_time); ++ smp_wmb(); ++ ++ /* If we raced with cancelling a timer, skip. */ ++ if (!idle_exit_time) ++ goto exit; ++ ++ delta_idle = (unsigned int)(now_idle - time_in_idle); ++ delta_time = (unsigned int)(pcpu->timer_run_time - idle_exit_time); ++ ++ /* ++ * If timer ran less than 1ms after short-term sample started, retry. ++ */ ++ if (delta_time < 1000) ++ goto rearm; ++ ++ if (delta_idle > delta_time) ++ cpu_load = 0; ++ else ++ cpu_load = 100 * (delta_time - delta_idle) / delta_time; ++ ++ delta_idle = (unsigned int)(now_idle - pcpu->freq_change_time_in_idle); ++ delta_time = (unsigned int)(pcpu->timer_run_time - ++ pcpu->freq_change_time); ++ ++ if ((delta_time == 0) || (delta_idle > delta_time)) ++ load_since_change = 0; ++ else ++ load_since_change = ++ 100 * (delta_time - delta_idle) / delta_time; ++ ++ /* ++ * Choose greater of short-term load (since last idle timer ++ * started or timer function re-armed itself) or long-term load ++ * (since last frequency change). ++ */ ++ if (load_since_change > cpu_load) ++ cpu_load = load_since_change; ++ ++ if (cpu_load >= go_hispeed_load) { ++ if (pcpu->policy->cur == pcpu->policy->min) ++ new_freq = hispeed_freq; ++ else ++ new_freq = pcpu->policy->max * cpu_load / 100; ++ } else { ++ new_freq = pcpu->policy->cur * cpu_load / 100; ++ } ++ ++ if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table, ++ new_freq, CPUFREQ_RELATION_H, ++ &index)) { ++ pr_warn_once("timer %d: cpufreq_frequency_table_target error\n", ++ (int) data); ++ goto rearm; ++ } ++ ++ new_freq = pcpu->freq_table[index].frequency; ++ if (pcpu->target_freq == new_freq) ++ goto rearm_if_notmax; ++ ++ /* ++ * Do not scale down unless we have been at this frequency for the ++ * minimum sample time. ++ */ ++ if (new_freq < pcpu->target_freq) { ++ if ((pcpu->timer_run_time - pcpu->freq_change_time) ++ < min_sample_time) ++ goto rearm; ++ } ++ ++ if (new_freq < pcpu->target_freq) { ++ pcpu->target_freq = new_freq; ++ spin_lock_irqsave(&down_cpumask_lock, flags); ++ cpumask_set_cpu(data, &down_cpumask); ++ spin_unlock_irqrestore(&down_cpumask_lock, flags); ++ queue_work(down_wq, &freq_scale_down_work); ++ } else { ++ pcpu->target_freq = new_freq; ++ spin_lock_irqsave(&up_cpumask_lock, flags); ++ cpumask_set_cpu(data, &up_cpumask); ++ spin_unlock_irqrestore(&up_cpumask_lock, flags); ++ wake_up_process(up_task); ++ } ++ ++rearm_if_notmax: ++ /* ++ * Already set max speed and don't see a need to change that, ++ * wait until next idle to re-evaluate, don't need timer. ++ */ ++ if (pcpu->target_freq == pcpu->policy->max) ++ goto exit; ++ ++rearm: ++ if (!timer_pending(&pcpu->cpu_timer)) { ++ /* ++ * If already at min: if that CPU is idle, don't set timer. ++ * Else cancel the timer if that CPU goes idle. We don't ++ * need to re-evaluate speed until the next idle exit. ++ */ ++ if (pcpu->target_freq == pcpu->policy->min) { ++ smp_rmb(); ++ ++ if (pcpu->idling) ++ goto exit; ++ ++ pcpu->timer_idlecancel = 1; ++ } ++ ++ pcpu->time_in_idle = get_cpu_idle_time_us( ++ data, &pcpu->idle_exit_time); ++ mod_timer(&pcpu->cpu_timer, ++ jiffies + usecs_to_jiffies(timer_rate)); ++ } ++ ++exit: ++ return; ++} ++ ++static void cpufreq_interactive_idle_start(void) ++{ ++ struct cpufreq_interactive_cpuinfo *pcpu = ++ &per_cpu(cpuinfo, smp_processor_id()); ++ int pending; ++ ++ pcpu->idling = 1; ++ smp_wmb(); ++ if (!pcpu->governor_enabled) ++ return; ++ pending = timer_pending(&pcpu->cpu_timer); ++ ++ if (pcpu->target_freq != pcpu->policy->min) { ++#ifdef CONFIG_SMP ++ /* ++ * Entering idle while not at lowest speed. On some ++ * platforms this can hold the other CPU(s) at that speed ++ * even though the CPU is idle. Set a timer to re-evaluate ++ * speed so this idle CPU doesn't hold the other CPUs above ++ * min indefinitely. This should probably be a quirk of ++ * the CPUFreq driver. ++ */ ++ if (!pending) { ++ pcpu->time_in_idle = get_cpu_idle_time_us( ++ smp_processor_id(), &pcpu->idle_exit_time); ++ pcpu->timer_idlecancel = 0; ++ mod_timer(&pcpu->cpu_timer, ++ jiffies + usecs_to_jiffies(timer_rate)); ++ } ++#endif ++ } else { ++ /* ++ * If at min speed and entering idle after load has ++ * already been evaluated, and a timer has been set just in ++ * case the CPU suddenly goes busy, cancel that timer. The ++ * CPU didn't go busy; we'll recheck things upon idle exit. ++ */ ++ if (pending && pcpu->timer_idlecancel) { ++ del_timer(&pcpu->cpu_timer); ++ /* ++ * Ensure last timer run time is after current idle ++ * sample start time, so next idle exit will always ++ * start a new idle sampling period. ++ */ ++ pcpu->idle_exit_time = 0; ++ pcpu->timer_idlecancel = 0; ++ } ++ } ++ ++} ++ ++static void cpufreq_interactive_idle_end(void) ++{ ++ struct cpufreq_interactive_cpuinfo *pcpu = ++ &per_cpu(cpuinfo, smp_processor_id()); ++ ++ pcpu->idling = 0; ++ smp_wmb(); ++ ++ /* ++ * Arm the timer for 1-2 ticks later if not already, and if the timer ++ * function has already processed the previous load sampling ++ * interval. (If the timer is not pending but has not processed ++ * the previous interval, it is probably racing with us on another ++ * CPU. Let it compute load based on the previous sample and then ++ * re-arm the timer for another interval when it's done, rather ++ * than updating the interval start time to be "now", which doesn't ++ * give the timer function enough time to make a decision on this ++ * run.) ++ */ ++ if (timer_pending(&pcpu->cpu_timer) == 0 && ++ pcpu->timer_run_time >= pcpu->idle_exit_time && ++ pcpu->governor_enabled) { ++ pcpu->time_in_idle = ++ get_cpu_idle_time_us(smp_processor_id(), ++ &pcpu->idle_exit_time); ++ pcpu->timer_idlecancel = 0; ++ mod_timer(&pcpu->cpu_timer, ++ jiffies + usecs_to_jiffies(timer_rate)); ++ } ++ ++} ++ ++static int cpufreq_interactive_up_task(void *data) ++{ ++ unsigned int cpu; ++ unsigned long flags; ++ struct cpufreq_interactive_cpuinfo *pcpu; ++ ++ while (1) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&up_cpumask_lock, flags); ++ ++ if (cpumask_empty(&up_cpumask)) { ++ spin_unlock_irqrestore(&up_cpumask_lock, flags); ++ schedule(); ++ ++ if (kthread_should_stop()) ++ break; ++ ++ spin_lock_irqsave(&up_cpumask_lock, flags); ++ } ++ ++ set_current_state(TASK_RUNNING); ++ cpumask_clear(&up_cpumask); ++ spin_unlock_irqrestore(&up_cpumask_lock, flags); ++ ++ for_each_online_cpu(cpu) { ++ unsigned int j; ++ unsigned int max_freq = 0; ++ ++ pcpu = &per_cpu(cpuinfo, cpu); ++ smp_rmb(); ++ ++ if (!pcpu->governor_enabled) ++ continue; ++ ++ mutex_lock(&set_speed_lock); ++ ++ for_each_online_cpu(j) { ++ struct cpufreq_interactive_cpuinfo *pjcpu = ++ &per_cpu(cpuinfo, j); ++ if (pjcpu->target_freq > max_freq) ++ max_freq = pjcpu->target_freq; ++ } ++ if (max_freq != pcpu->policy->cur) ++ __cpufreq_driver_target(pcpu->policy, ++ max_freq, ++ CPUFREQ_RELATION_H); ++ mutex_unlock(&set_speed_lock); ++ ++ pcpu->freq_change_time_in_idle = ++ get_cpu_idle_time_us(cpu, ++ &pcpu->freq_change_time); ++ } ++ } ++ ++ return 0; ++} ++ ++static void cpufreq_interactive_freq_down(struct work_struct *work) ++{ ++ unsigned int cpu; ++ unsigned long flags; ++ struct cpufreq_interactive_cpuinfo *pcpu; ++ ++ spin_lock_irqsave(&down_cpumask_lock, flags); ++ cpumask_clear(&down_cpumask); ++ spin_unlock_irqrestore(&down_cpumask_lock, flags); ++ ++ for_each_online_cpu(cpu) { ++ unsigned int j; ++ unsigned int max_freq = 0; ++ ++ pcpu = &per_cpu(cpuinfo, cpu); ++ smp_rmb(); ++ ++ if (!pcpu->governor_enabled) ++ continue; ++ ++ mutex_lock(&set_speed_lock); ++ ++ for_each_online_cpu(j) { ++ struct cpufreq_interactive_cpuinfo *pjcpu = ++ &per_cpu(cpuinfo, j); ++ ++ if (pjcpu->target_freq > max_freq) ++ max_freq = pjcpu->target_freq; ++ } ++ ++ if (max_freq != pcpu->policy->cur) ++ __cpufreq_driver_target(pcpu->policy, max_freq, ++ CPUFREQ_RELATION_H); ++ ++ mutex_unlock(&set_speed_lock); ++ pcpu->freq_change_time_in_idle = ++ get_cpu_idle_time_us(cpu, ++ &pcpu->freq_change_time); ++ } ++} ++ ++static ssize_t show_hispeed_freq(struct kobject *kobj, ++ struct attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%llu\n", hispeed_freq); ++} ++ ++static ssize_t store_hispeed_freq(struct kobject *kobj, ++ struct attribute *attr, const char *buf, ++ size_t count) ++{ ++ int ret; ++ u64 val; ++ ++ ret = strict_strtoull(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ hispeed_freq = val; ++ return count; ++} ++ ++static struct global_attr hispeed_freq_attr = __ATTR(hispeed_freq, 0644, ++ show_hispeed_freq, store_hispeed_freq); ++ ++ ++static ssize_t show_go_hispeed_load(struct kobject *kobj, ++ struct attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%lu\n", go_hispeed_load); ++} ++ ++static ssize_t store_go_hispeed_load(struct kobject *kobj, ++ struct attribute *attr, const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = strict_strtoul(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ go_hispeed_load = val; ++ return count; ++} ++ ++static struct global_attr go_hispeed_load_attr = __ATTR(go_hispeed_load, 0644, ++ show_go_hispeed_load, store_go_hispeed_load); ++ ++static ssize_t show_min_sample_time(struct kobject *kobj, ++ struct attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%lu\n", min_sample_time); ++} ++ ++static ssize_t store_min_sample_time(struct kobject *kobj, ++ struct attribute *attr, const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = strict_strtoul(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ min_sample_time = val; ++ return count; ++} ++ ++static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644, ++ show_min_sample_time, store_min_sample_time); ++ ++static ssize_t show_timer_rate(struct kobject *kobj, ++ struct attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%lu\n", timer_rate); ++} ++ ++static ssize_t store_timer_rate(struct kobject *kobj, ++ struct attribute *attr, const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = strict_strtoul(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ timer_rate = val; ++ return count; ++} ++ ++static struct global_attr timer_rate_attr = __ATTR(timer_rate, 0644, ++ show_timer_rate, store_timer_rate); ++ ++static struct attribute *interactive_attributes[] = { ++ &hispeed_freq_attr.attr, ++ &go_hispeed_load_attr.attr, ++ &min_sample_time_attr.attr, ++ &timer_rate_attr.attr, ++ NULL, ++}; ++ ++static struct attribute_group interactive_attr_group = { ++ .attrs = interactive_attributes, ++ .name = "interactive", ++}; ++ ++static int cpufreq_governor_interactive(struct cpufreq_policy *policy, ++ unsigned int event) ++{ ++ int rc; ++ unsigned int j; ++ struct cpufreq_interactive_cpuinfo *pcpu; ++ struct cpufreq_frequency_table *freq_table; ++ ++ switch (event) { ++ case CPUFREQ_GOV_START: ++ if (!cpu_online(policy->cpu)) ++ return -EINVAL; ++ ++ freq_table = ++ cpufreq_frequency_get_table(policy->cpu); ++ ++ for_each_cpu(j, policy->cpus) { ++ pcpu = &per_cpu(cpuinfo, j); ++ pcpu->policy = policy; ++ if (pcpu->idling) ++ pcpu->target_freq = policy->min; ++ else ++ pcpu->target_freq = policy->cur; ++ ++ pcpu->freq_table = freq_table; ++ pcpu->freq_change_time_in_idle = ++ get_cpu_idle_time_us(j, ++ &pcpu->freq_change_time); ++ pcpu->governor_enabled = 1; ++ smp_wmb(); ++ } ++ ++ if (!hispeed_freq) ++ hispeed_freq = policy->max; ++ ++ /* ++ * Do not register the idle hook and create sysfs ++ * entries if we have already done so. ++ */ ++ if (atomic_inc_return(&active_count) > 1) ++ return 0; ++ ++ rc = sysfs_create_group(cpufreq_global_kobject, ++ &interactive_attr_group); ++ if (rc) ++ return rc; ++ ++ break; ++ ++ case CPUFREQ_GOV_STOP: ++ for_each_cpu(j, policy->cpus) { ++ pcpu = &per_cpu(cpuinfo, j); ++ pcpu->governor_enabled = 0; ++ smp_wmb(); ++ del_timer_sync(&pcpu->cpu_timer); ++ ++ /* ++ * Reset idle exit time since we may cancel the timer ++ * before it can run after the last idle exit time, ++ * to avoid tripping the check in idle exit for a timer ++ * that is trying to run. ++ */ ++ pcpu->idle_exit_time = 0; ++ } ++ ++ flush_work(&freq_scale_down_work); ++ if (atomic_dec_return(&active_count) > 0) ++ return 0; ++ ++ sysfs_remove_group(cpufreq_global_kobject, ++ &interactive_attr_group); ++ ++ break; ++ ++ case CPUFREQ_GOV_LIMITS: ++ if (policy->max < policy->cur) ++ __cpufreq_driver_target(policy, ++ policy->max, CPUFREQ_RELATION_H); ++ else if (policy->min > policy->cur) ++ __cpufreq_driver_target(policy, ++ policy->min, CPUFREQ_RELATION_L); ++ break; ++ } ++ return 0; ++} ++ ++static int cpufreq_interactive_idle_notifier(struct notifier_block *nb, ++ unsigned long val, ++ void *data) ++{ ++ switch (val) { ++ case IDLE_START: ++ cpufreq_interactive_idle_start(); ++ break; ++ case IDLE_END: ++ cpufreq_interactive_idle_end(); ++ break; ++ } ++ ++ return 0; ++} ++ ++static struct notifier_block cpufreq_interactive_idle_nb = { ++ .notifier_call = cpufreq_interactive_idle_notifier, ++}; ++ ++static int __init cpufreq_interactive_init(void) ++{ ++ unsigned int i; ++ struct cpufreq_interactive_cpuinfo *pcpu; ++ struct sched_param param = { .sched_priority = 99 }; ++ ++ go_hispeed_load = DEFAULT_GO_HISPEED_LOAD; ++ min_sample_time = DEFAULT_MIN_SAMPLE_TIME; ++ timer_rate = DEFAULT_TIMER_RATE; ++ ++ /* Initalize per-cpu timers */ ++ for_each_possible_cpu(i) { ++ pcpu = &per_cpu(cpuinfo, i); ++ init_timer(&pcpu->cpu_timer); ++ pcpu->cpu_timer.function = cpufreq_interactive_timer; ++ pcpu->cpu_timer.data = i; ++ } ++ ++ up_task = kthread_create(cpufreq_interactive_up_task, NULL, ++ "kinteractiveup"); ++ if (IS_ERR(up_task)) ++ return PTR_ERR(up_task); ++ ++ sched_setscheduler_nocheck(up_task, SCHED_FIFO, ¶m); ++ get_task_struct(up_task); ++ ++ /* No rescuer thread, bind to CPU queuing the work for possibly ++ warm cache (probably doesn't matter much). */ ++ down_wq = alloc_workqueue("kinteractive_down", 0, 1); ++ ++ if (!down_wq) ++ goto err_freeuptask; ++ ++ INIT_WORK(&freq_scale_down_work, ++ cpufreq_interactive_freq_down); ++ ++ spin_lock_init(&up_cpumask_lock); ++ spin_lock_init(&down_cpumask_lock); ++ mutex_init(&set_speed_lock); ++ ++ idle_notifier_register(&cpufreq_interactive_idle_nb); ++ ++ return cpufreq_register_governor(&cpufreq_gov_interactive); ++ ++err_freeuptask: ++ put_task_struct(up_task); ++ return -ENOMEM; ++} ++ ++#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE ++late_initcall(cpufreq_interactive_init); ++#else ++module_init(cpufreq_interactive_init); ++#endif ++ ++static void __exit cpufreq_interactive_exit(void) ++{ ++ cpufreq_unregister_governor(&cpufreq_gov_interactive); ++ kthread_stop(up_task); ++ put_task_struct(up_task); ++ destroy_workqueue(down_wq); ++} ++ ++module_exit(cpufreq_interactive_exit); ++ ++MODULE_AUTHOR("Mike Chan "); ++MODULE_DESCRIPTION("'cpufreq_interactive' - A cpufreq governor for " ++ "Latency sensitive workloads"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/cpufreq/cpufreq_ondemand.c linux-3.10.30-cubox-i/drivers/cpufreq/cpufreq_ondemand.c +--- linux-3.10.30/drivers/cpufreq/cpufreq_ondemand.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpufreq/cpufreq_ondemand.c 2014-03-08 20:33:29.000000000 +0100 +@@ -76,6 +76,8 @@ + boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model >= 15) + return 1; ++#else if defined(CONFIG_ARM_IMX6_CPUFREQ) ++ return 1; + #endif + return 0; + } +diff -Nur linux-3.10.30/drivers/cpufreq/cpufreq_stats.c linux-3.10.30-cubox-i/drivers/cpufreq/cpufreq_stats.c +--- linux-3.10.30/drivers/cpufreq/cpufreq_stats.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpufreq/cpufreq_stats.c 2014-03-08 20:33:29.000000000 +0100 +@@ -21,6 +21,9 @@ + #include + #include + #include ++#ifdef CONFIG_BL_SWITCHER ++#include ++#endif + + static spinlock_t cpufreq_stats_lock; + +@@ -378,7 +381,7 @@ + .notifier_call = cpufreq_stat_notifier_trans + }; + +-static int __init cpufreq_stats_init(void) ++static int cpufreq_stats_setup(void) + { + int ret; + unsigned int cpu; +@@ -406,7 +409,8 @@ + + return 0; + } +-static void __exit cpufreq_stats_exit(void) ++ ++static void cpufreq_stats_cleanup(void) + { + unsigned int cpu; + +@@ -421,6 +425,54 @@ + } + } + ++#ifdef CONFIG_BL_SWITCHER ++static int cpufreq_stats_switcher_notifier(struct notifier_block *nfb, ++ unsigned long action, void *_arg) ++{ ++ switch (action) { ++ case BL_NOTIFY_PRE_ENABLE: ++ case BL_NOTIFY_PRE_DISABLE: ++ cpufreq_stats_cleanup(); ++ break; ++ ++ case BL_NOTIFY_POST_ENABLE: ++ case BL_NOTIFY_POST_DISABLE: ++ cpufreq_stats_setup(); ++ break; ++ ++ default: ++ return NOTIFY_DONE; ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block switcher_notifier = { ++ .notifier_call = cpufreq_stats_switcher_notifier, ++}; ++#endif ++ ++static int __init cpufreq_stats_init(void) ++{ ++ int ret; ++ spin_lock_init(&cpufreq_stats_lock); ++ ++ ret = cpufreq_stats_setup(); ++#ifdef CONFIG_BL_SWITCHER ++ if (!ret) ++ bL_switcher_register_notifier(&switcher_notifier); ++#endif ++ return ret; ++} ++ ++static void __exit cpufreq_stats_exit(void) ++{ ++#ifdef CONFIG_BL_SWITCHER ++ bL_switcher_unregister_notifier(&switcher_notifier); ++#endif ++ cpufreq_stats_cleanup(); ++} ++ + MODULE_AUTHOR("Zou Nan hai "); + MODULE_DESCRIPTION("'cpufreq_stats' - A driver to export cpufreq stats " + "through sysfs filesystem"); +diff -Nur linux-3.10.30/drivers/cpufreq/imx6q-cpufreq.c linux-3.10.30-cubox-i/drivers/cpufreq/imx6q-cpufreq.c +--- linux-3.10.30/drivers/cpufreq/imx6q-cpufreq.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpufreq/imx6q-cpufreq.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,330 +0,0 @@ +-/* +- * Copyright (C) 2013 Freescale Semiconductor, Inc. +- * +- * This program 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 PU_SOC_VOLTAGE_NORMAL 1250000 +-#define PU_SOC_VOLTAGE_HIGH 1275000 +-#define FREQ_1P2_GHZ 1200000000 +- +-static struct regulator *arm_reg; +-static struct regulator *pu_reg; +-static struct regulator *soc_reg; +- +-static struct clk *arm_clk; +-static struct clk *pll1_sys_clk; +-static struct clk *pll1_sw_clk; +-static struct clk *step_clk; +-static struct clk *pll2_pfd2_396m_clk; +- +-static struct device *cpu_dev; +-static struct cpufreq_frequency_table *freq_table; +-static unsigned int transition_latency; +- +-static int imx6q_verify_speed(struct cpufreq_policy *policy) +-{ +- return cpufreq_frequency_table_verify(policy, freq_table); +-} +- +-static unsigned int imx6q_get_speed(unsigned int cpu) +-{ +- return clk_get_rate(arm_clk) / 1000; +-} +- +-static int imx6q_set_target(struct cpufreq_policy *policy, +- unsigned int target_freq, unsigned int relation) +-{ +- struct cpufreq_freqs freqs; +- struct opp *opp; +- unsigned long freq_hz, volt, volt_old; +- unsigned int index; +- int ret; +- +- ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, +- relation, &index); +- if (ret) { +- dev_err(cpu_dev, "failed to match target frequency %d: %d\n", +- target_freq, ret); +- return ret; +- } +- +- freqs.new = freq_table[index].frequency; +- freq_hz = freqs.new * 1000; +- freqs.old = clk_get_rate(arm_clk) / 1000; +- +- if (freqs.old == freqs.new) +- return 0; +- +- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); +- +- rcu_read_lock(); +- opp = opp_find_freq_ceil(cpu_dev, &freq_hz); +- if (IS_ERR(opp)) { +- rcu_read_unlock(); +- dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); +- return PTR_ERR(opp); +- } +- +- volt = opp_get_voltage(opp); +- rcu_read_unlock(); +- volt_old = regulator_get_voltage(arm_reg); +- +- dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", +- freqs.old / 1000, volt_old / 1000, +- freqs.new / 1000, volt / 1000); +- +- /* scaling up? scale voltage before frequency */ +- if (freqs.new > freqs.old) { +- ret = regulator_set_voltage_tol(arm_reg, volt, 0); +- if (ret) { +- dev_err(cpu_dev, +- "failed to scale vddarm up: %d\n", ret); +- return ret; +- } +- +- /* +- * Need to increase vddpu and vddsoc for safety +- * if we are about to run at 1.2 GHz. +- */ +- if (freqs.new == FREQ_1P2_GHZ / 1000) { +- regulator_set_voltage_tol(pu_reg, +- PU_SOC_VOLTAGE_HIGH, 0); +- regulator_set_voltage_tol(soc_reg, +- PU_SOC_VOLTAGE_HIGH, 0); +- } +- } +- +- /* +- * The setpoints are selected per PLL/PDF frequencies, so we need to +- * reprogram PLL for frequency scaling. The procedure of reprogramming +- * PLL1 is as below. +- * +- * - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it +- * - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it +- * - Disable pll2_pfd2_396m_clk +- */ +- clk_prepare_enable(pll2_pfd2_396m_clk); +- clk_set_parent(step_clk, pll2_pfd2_396m_clk); +- clk_set_parent(pll1_sw_clk, step_clk); +- if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) { +- clk_set_rate(pll1_sys_clk, freqs.new * 1000); +- /* +- * If we are leaving 396 MHz set-point, we need to enable +- * pll1_sys_clk and disable pll2_pfd2_396m_clk to keep +- * their use count correct. +- */ +- if (freqs.old * 1000 <= clk_get_rate(pll2_pfd2_396m_clk)) { +- clk_prepare_enable(pll1_sys_clk); +- clk_disable_unprepare(pll2_pfd2_396m_clk); +- } +- clk_set_parent(pll1_sw_clk, pll1_sys_clk); +- clk_disable_unprepare(pll2_pfd2_396m_clk); +- } else { +- /* +- * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient +- * to provide the frequency. +- */ +- clk_disable_unprepare(pll1_sys_clk); +- } +- +- /* Ensure the arm clock divider is what we expect */ +- ret = clk_set_rate(arm_clk, freqs.new * 1000); +- if (ret) { +- dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); +- regulator_set_voltage_tol(arm_reg, volt_old, 0); +- return ret; +- } +- +- /* scaling down? scale voltage after frequency */ +- if (freqs.new < freqs.old) { +- ret = regulator_set_voltage_tol(arm_reg, volt, 0); +- if (ret) +- dev_warn(cpu_dev, +- "failed to scale vddarm down: %d\n", ret); +- +- if (freqs.old == FREQ_1P2_GHZ / 1000) { +- regulator_set_voltage_tol(pu_reg, +- PU_SOC_VOLTAGE_NORMAL, 0); +- regulator_set_voltage_tol(soc_reg, +- PU_SOC_VOLTAGE_NORMAL, 0); +- } +- } +- +- cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); +- +- return 0; +-} +- +-static int imx6q_cpufreq_init(struct cpufreq_policy *policy) +-{ +- int ret; +- +- ret = cpufreq_frequency_table_cpuinfo(policy, freq_table); +- if (ret) { +- dev_err(cpu_dev, "invalid frequency table: %d\n", ret); +- return ret; +- } +- +- policy->cpuinfo.transition_latency = transition_latency; +- policy->cur = clk_get_rate(arm_clk) / 1000; +- cpumask_setall(policy->cpus); +- cpufreq_frequency_table_get_attr(freq_table, policy->cpu); +- +- return 0; +-} +- +-static int imx6q_cpufreq_exit(struct cpufreq_policy *policy) +-{ +- cpufreq_frequency_table_put_attr(policy->cpu); +- return 0; +-} +- +-static struct freq_attr *imx6q_cpufreq_attr[] = { +- &cpufreq_freq_attr_scaling_available_freqs, +- NULL, +-}; +- +-static struct cpufreq_driver imx6q_cpufreq_driver = { +- .verify = imx6q_verify_speed, +- .target = imx6q_set_target, +- .get = imx6q_get_speed, +- .init = imx6q_cpufreq_init, +- .exit = imx6q_cpufreq_exit, +- .name = "imx6q-cpufreq", +- .attr = imx6q_cpufreq_attr, +-}; +- +-static int imx6q_cpufreq_probe(struct platform_device *pdev) +-{ +- struct device_node *np; +- struct opp *opp; +- unsigned long min_volt, max_volt; +- int num, ret; +- +- cpu_dev = &pdev->dev; +- +- np = of_find_node_by_path("/cpus/cpu@0"); +- if (!np) { +- dev_err(cpu_dev, "failed to find cpu0 node\n"); +- return -ENOENT; +- } +- +- cpu_dev->of_node = np; +- +- arm_clk = devm_clk_get(cpu_dev, "arm"); +- pll1_sys_clk = devm_clk_get(cpu_dev, "pll1_sys"); +- pll1_sw_clk = devm_clk_get(cpu_dev, "pll1_sw"); +- step_clk = devm_clk_get(cpu_dev, "step"); +- pll2_pfd2_396m_clk = devm_clk_get(cpu_dev, "pll2_pfd2_396m"); +- if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) || +- IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk)) { +- dev_err(cpu_dev, "failed to get clocks\n"); +- ret = -ENOENT; +- goto put_node; +- } +- +- arm_reg = devm_regulator_get(cpu_dev, "arm"); +- pu_reg = devm_regulator_get(cpu_dev, "pu"); +- soc_reg = devm_regulator_get(cpu_dev, "soc"); +- if (IS_ERR(arm_reg) || IS_ERR(pu_reg) || IS_ERR(soc_reg)) { +- dev_err(cpu_dev, "failed to get regulators\n"); +- ret = -ENOENT; +- goto put_node; +- } +- +- /* We expect an OPP table supplied by platform */ +- num = opp_get_opp_count(cpu_dev); +- if (num < 0) { +- ret = num; +- dev_err(cpu_dev, "no OPP table is found: %d\n", ret); +- goto put_node; +- } +- +- ret = opp_init_cpufreq_table(cpu_dev, &freq_table); +- if (ret) { +- dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); +- goto put_node; +- } +- +- if (of_property_read_u32(np, "clock-latency", &transition_latency)) +- transition_latency = CPUFREQ_ETERNAL; +- +- /* +- * OPP is maintained in order of increasing frequency, and +- * freq_table initialised from OPP is therefore sorted in the +- * same order. +- */ +- rcu_read_lock(); +- opp = opp_find_freq_exact(cpu_dev, +- freq_table[0].frequency * 1000, true); +- min_volt = opp_get_voltage(opp); +- opp = opp_find_freq_exact(cpu_dev, +- freq_table[--num].frequency * 1000, true); +- max_volt = opp_get_voltage(opp); +- rcu_read_unlock(); +- ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt); +- if (ret > 0) +- transition_latency += ret * 1000; +- +- /* Count vddpu and vddsoc latency in for 1.2 GHz support */ +- if (freq_table[num].frequency == FREQ_1P2_GHZ / 1000) { +- ret = regulator_set_voltage_time(pu_reg, PU_SOC_VOLTAGE_NORMAL, +- PU_SOC_VOLTAGE_HIGH); +- if (ret > 0) +- transition_latency += ret * 1000; +- ret = regulator_set_voltage_time(soc_reg, PU_SOC_VOLTAGE_NORMAL, +- PU_SOC_VOLTAGE_HIGH); +- if (ret > 0) +- transition_latency += ret * 1000; +- } +- +- ret = cpufreq_register_driver(&imx6q_cpufreq_driver); +- if (ret) { +- dev_err(cpu_dev, "failed register driver: %d\n", ret); +- goto free_freq_table; +- } +- +- of_node_put(np); +- return 0; +- +-free_freq_table: +- opp_free_cpufreq_table(cpu_dev, &freq_table); +-put_node: +- of_node_put(np); +- return ret; +-} +- +-static int imx6q_cpufreq_remove(struct platform_device *pdev) +-{ +- cpufreq_unregister_driver(&imx6q_cpufreq_driver); +- opp_free_cpufreq_table(cpu_dev, &freq_table); +- +- return 0; +-} +- +-static struct platform_driver imx6q_cpufreq_platdrv = { +- .driver = { +- .name = "imx6q-cpufreq", +- .owner = THIS_MODULE, +- }, +- .probe = imx6q_cpufreq_probe, +- .remove = imx6q_cpufreq_remove, +-}; +-module_platform_driver(imx6q_cpufreq_platdrv); +- +-MODULE_AUTHOR("Shawn Guo "); +-MODULE_DESCRIPTION("Freescale i.MX6Q cpufreq driver"); +-MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/cpufreq/vexpress_big_little.c linux-3.10.30-cubox-i/drivers/cpufreq/vexpress_big_little.c +--- linux-3.10.30/drivers/cpufreq/vexpress_big_little.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpufreq/vexpress_big_little.c 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,86 @@ ++/* ++ * Vexpress big.LITTLE CPUFreq Interface driver ++ * ++ * It provides necessary ops to arm_big_little cpufreq driver and gets ++ * Frequency information from Device Tree. Freq table in DT must be in KHz. ++ * ++ * Copyright (C) 2013 Linaro. ++ * Viresh Kumar ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "arm_big_little.h" ++ ++static int vexpress_init_opp_table(struct device *cpu_dev) ++{ ++ int i = -1, count, cluster = cpu_to_cluster(cpu_dev->id); ++ u32 *table; ++ int ret; ++ ++ count = vexpress_spc_get_freq_table(cluster, &table); ++ if (!table || !count) { ++ pr_err("SPC controller returned invalid freq table"); ++ return -EINVAL; ++ } ++ ++ while (++i < count) { ++ /* FIXME: Voltage value */ ++ ret = opp_add(cpu_dev, table[i] * 1000, 900000); ++ if (ret) { ++ dev_warn(cpu_dev, "%s: Failed to add OPP %d, err: %d\n", ++ __func__, table[i] * 1000, ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int vexpress_get_transition_latency(struct device *cpu_dev) ++{ ++ /* 1 ms */ ++ return 1000000; ++} ++ ++static struct cpufreq_arm_bL_ops vexpress_bL_ops = { ++ .name = "vexpress-bL", ++ .get_transition_latency = vexpress_get_transition_latency, ++ .init_opp_table = vexpress_init_opp_table, ++}; ++ ++static int vexpress_bL_init(void) ++{ ++ if (!vexpress_spc_check_loaded()) { ++ pr_info("%s: No SPC found\n", __func__); ++ return -ENOENT; ++ } ++ ++ return bL_cpufreq_register(&vexpress_bL_ops); ++} ++module_init(vexpress_bL_init); ++ ++static void vexpress_bL_exit(void) ++{ ++ return bL_cpufreq_unregister(&vexpress_bL_ops); ++} ++module_exit(vexpress_bL_exit); ++ ++MODULE_AUTHOR("Viresh Kumar "); ++MODULE_DESCRIPTION("ARM Vexpress big LITTLE cpufreq driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/cpuidle/Kconfig linux-3.10.30-cubox-i/drivers/cpuidle/Kconfig +--- linux-3.10.30/drivers/cpuidle/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpuidle/Kconfig 2014-03-08 20:33:30.000000000 +0100 +@@ -20,7 +20,7 @@ + + config CPU_IDLE_GOV_LADDER + bool +- depends on CPU_IDLE ++ depends on CPU_IDLE && !NO_HZ + default y + + config CPU_IDLE_GOV_MENU +diff -Nur linux-3.10.30/drivers/cpuidle/Makefile linux-3.10.30-cubox-i/drivers/cpuidle/Makefile +--- linux-3.10.30/drivers/cpuidle/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpuidle/Makefile 2014-03-08 20:33:30.000000000 +0100 +@@ -4,6 +4,6 @@ + + obj-y += cpuidle.o driver.o governor.o sysfs.o governors/ + obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o +- ++obj-$(CONFIG_BIG_LITTLE) += arm_big_little.o + obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o + obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o +diff -Nur linux-3.10.30/drivers/cpuidle/arm_big_little.c linux-3.10.30-cubox-i/drivers/cpuidle/arm_big_little.c +--- linux-3.10.30/drivers/cpuidle/arm_big_little.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpuidle/arm_big_little.c 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,183 @@ ++/* ++ * big.LITTLE CPU idle driver. ++ * ++ * Copyright (C) 2012 ARM Ltd. ++ * Author: Lorenzo Pieralisi ++ * ++ * This program 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 ++ ++static int bl_cpuidle_simple_enter(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) ++{ ++ ktime_t time_start, time_end; ++ s64 diff; ++ ++ time_start = ktime_get(); ++ ++ cpu_do_idle(); ++ ++ time_end = ktime_get(); ++ ++ local_irq_enable(); ++ ++ diff = ktime_to_us(ktime_sub(time_end, time_start)); ++ if (diff > INT_MAX) ++ diff = INT_MAX; ++ ++ dev->last_residency = (int) diff; ++ ++ return index; ++} ++ ++static int bl_enter_powerdown(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int idx); ++ ++static struct cpuidle_state bl_cpuidle_set[] __initdata = { ++ [0] = { ++ .enter = bl_cpuidle_simple_enter, ++ .exit_latency = 1, ++ .target_residency = 1, ++ .power_usage = UINT_MAX, ++ .flags = CPUIDLE_FLAG_TIME_VALID, ++ .name = "WFI", ++ .desc = "ARM WFI", ++ }, ++ [1] = { ++ .enter = bl_enter_powerdown, ++ .exit_latency = 300, ++ .target_residency = 1000, ++ .flags = CPUIDLE_FLAG_TIME_VALID, ++ .name = "C1", ++ .desc = "ARM power down", ++ }, ++}; ++ ++struct cpuidle_driver bl_idle_driver = { ++ .name = "bl_idle", ++ .owner = THIS_MODULE, ++ .safe_state_index = 0 ++}; ++ ++static DEFINE_PER_CPU(struct cpuidle_device, bl_idle_dev); ++ ++static int notrace bl_powerdown_finisher(unsigned long arg) ++{ ++ unsigned int mpidr = read_cpuid_mpidr(); ++ unsigned int cluster = (mpidr >> 8) & 0xf; ++ unsigned int cpu = mpidr & 0xf; ++ ++ mcpm_set_entry_vector(cpu, cluster, cpu_resume); ++ mcpm_cpu_suspend(0); /* 0 should be replaced with better value here */ ++ return 1; ++} ++ ++/* ++ * bl_enter_powerdown - Programs CPU to enter the specified state ++ * @dev: cpuidle device ++ * @drv: The target state to be programmed ++ * @idx: state index ++ * ++ * Called from the CPUidle framework to program the device to the ++ * specified target state selected by the governor. ++ */ ++static int bl_enter_powerdown(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int idx) ++{ ++ struct timespec ts_preidle, ts_postidle, ts_idle; ++ int ret; ++ ++ /* Used to keep track of the total time in idle */ ++ getnstimeofday(&ts_preidle); ++ ++ BUG_ON(!irqs_disabled()); ++ ++ cpu_pm_enter(); ++ ++ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu); ++ ++ ret = cpu_suspend((unsigned long) dev, bl_powerdown_finisher); ++ if (ret) ++ BUG(); ++ ++ mcpm_cpu_powered_up(); ++ ++ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); ++ ++ cpu_pm_exit(); ++ ++ getnstimeofday(&ts_postidle); ++ local_irq_enable(); ++ ts_idle = timespec_sub(ts_postidle, ts_preidle); ++ ++ dev->last_residency = ts_idle.tv_nsec / NSEC_PER_USEC + ++ ts_idle.tv_sec * USEC_PER_SEC; ++ return idx; ++} ++ ++/* ++ * bl_idle_init ++ * ++ * Registers the bl specific cpuidle driver with the cpuidle ++ * framework with the valid set of states. ++ */ ++int __init bl_idle_init(void) ++{ ++ struct cpuidle_device *dev; ++ int i, cpu_id; ++ struct cpuidle_driver *drv = &bl_idle_driver; ++ ++ if (!of_find_compatible_node(NULL, NULL, "arm,generic")) { ++ pr_info("%s: No compatible node found\n", __func__); ++ return -ENODEV; ++ } ++ ++ drv->state_count = (sizeof(bl_cpuidle_set) / ++ sizeof(struct cpuidle_state)); ++ ++ for (i = 0; i < drv->state_count; i++) { ++ memcpy(&drv->states[i], &bl_cpuidle_set[i], ++ sizeof(struct cpuidle_state)); ++ } ++ ++ cpuidle_register_driver(drv); ++ ++ for_each_cpu(cpu_id, cpu_online_mask) { ++ pr_err("CPUidle for CPU%d registered\n", cpu_id); ++ dev = &per_cpu(bl_idle_dev, cpu_id); ++ dev->cpu = cpu_id; ++ ++ dev->state_count = drv->state_count; ++ ++ if (cpuidle_register_device(dev)) { ++ printk(KERN_ERR "%s: Cpuidle register device failed\n", ++ __func__); ++ return -EIO; ++ } ++ } ++ ++ return 0; ++} ++ ++device_initcall(bl_idle_init); +diff -Nur linux-3.10.30/drivers/cpuidle/cpuidle-calxeda.c linux-3.10.30-cubox-i/drivers/cpuidle/cpuidle-calxeda.c +--- linux-3.10.30/drivers/cpuidle/cpuidle-calxeda.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/cpuidle/cpuidle-calxeda.c 2014-03-08 20:33:30.000000000 +0100 +@@ -37,20 +37,6 @@ + extern void highbank_set_cpu_jump(int cpu, void *jump_addr); + extern void *scu_base_addr; + +-static inline unsigned int get_auxcr(void) +-{ +- unsigned int val; +- asm("mrc p15, 0, %0, c1, c0, 1 @ get AUXCR" : "=r" (val) : : "cc"); +- return val; +-} +- +-static inline void set_auxcr(unsigned int val) +-{ +- asm volatile("mcr p15, 0, %0, c1, c0, 1 @ set AUXCR" +- : : "r" (val) : "cc"); +- isb(); +-} +- + static noinline void calxeda_idle_restore(void) + { + set_cr(get_cr() | CR_C); +diff -Nur linux-3.10.30/drivers/crypto/caam/Kconfig linux-3.10.30-cubox-i/drivers/crypto/caam/Kconfig +--- linux-3.10.30/drivers/crypto/caam/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/Kconfig 2014-03-08 20:33:30.000000000 +0100 +@@ -1,6 +1,6 @@ + config CRYPTO_DEV_FSL_CAAM + tristate "Freescale CAAM-Multicore driver backend" +- depends on FSL_SOC ++ depends on FSL_SOC || ARCH_MXC + help + Enables the driver module for Freescale's Cryptographic Accelerator + and Assurance Module (CAAM), also known as the SEC version 4 (SEC4). +@@ -98,3 +98,51 @@ + + To compile this as a module, choose M here: the module + will be called caamrng. ++ ++config CRYPTO_DEV_FSL_CAAM_RNG_TEST ++ boolean "Test caam rng" ++ depends on CRYPTO_DEV_FSL_CAAM_RNG_API ++ default n ++ help ++ Selecting this will enable self-test for caam rng. ++ ++config CRYPTO_DEV_FSL_CAAM_SM ++ tristate "CAAM Secure Memory / Keystore API (EXPERIMENTAL)" ++ default n ++ help ++ Enables use of a prototype kernel-level Keystore API with CAAM ++ Secure Memory for insertion/extraction of bus-protected secrets. ++ ++config CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE ++ int "Size of each keystore slot in Secure Memory" ++ depends on CRYPTO_DEV_FSL_CAAM_SM ++ range 5 9 ++ default 7 ++ help ++ Select size of allocation units to divide Secure Memory pages into ++ (the size of a "slot" as referenced inside the API code). ++ Established as powers of two. ++ Examples: ++ 5 => 32 bytes ++ 6 => 64 bytes ++ 7 => 128 bytes ++ 8 => 256 bytes ++ 9 => 512 bytes ++ ++config CRYPTO_DEV_FSL_CAAM_SM_TEST ++ tristate "CAAM Secure Memory - Keystore Test/Example (EXPERIMENTAL)" ++ depends on CRYPTO_DEV_FSL_CAAM_SM ++ default n ++ help ++ Example thread to exercise the Keystore API and to verify that ++ stored and recovered secrets can be used for general purpose ++ encryption/decryption. ++ ++config CRYPTO_DEV_FSL_CAAM_SECVIO ++ tristate "CAAM/SNVS Security Violation Handler (EXPERIMENTAL)" ++ depends on CRYPTO_DEV_FSL_CAAM ++ default n ++ help ++ Enables installation of an interrupt handler with registrable ++ handler functions which can be specified to act on the consequences ++ of a security violation. +diff -Nur linux-3.10.30/drivers/crypto/caam/Makefile linux-3.10.30-cubox-i/drivers/crypto/caam/Makefile +--- linux-3.10.30/drivers/crypto/caam/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/Makefile 2014-03-08 20:33:30.000000000 +0100 +@@ -6,5 +6,8 @@ + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o ++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM) += sm_store.o ++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST) += sm_test.o ++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO) += secvio.o + + caam-objs := ctrl.o jr.o error.o key_gen.o +diff -Nur linux-3.10.30/drivers/crypto/caam/caamalg.c linux-3.10.30-cubox-i/drivers/crypto/caam/caamalg.c +--- linux-3.10.30/drivers/crypto/caam/caamalg.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/caamalg.c 2014-03-08 20:33:30.000000000 +0100 +@@ -1,7 +1,7 @@ + /* + * caam - Freescale FSL CAAM support for crypto API + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. + * + * Based on talitos crypto API driver. + * +@@ -53,6 +53,7 @@ + #include "error.h" + #include "sg_sw_sec4.h" + #include "key_gen.h" ++#include + + /* + * crypto alg +@@ -290,6 +291,8 @@ + desc_bytes(desc), 1); + #endif + ++ dma_sync_single_for_cpu(jrdev, ctx->sh_desc_enc_dma, desc_bytes(desc), ++ DMA_TO_DEVICE); + /* + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer +@@ -357,6 +360,8 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_cpu(jrdev, ctx->sh_desc_dec_dma, desc_bytes(desc), ++ DMA_TO_DEVICE); + + /* + * Job Descriptor and Shared Descriptors +@@ -440,6 +445,8 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_cpu(jrdev, ctx->sh_desc_givenc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + return 0; + } +@@ -523,6 +530,9 @@ + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, + ctx->split_key_pad_len + enckeylen, 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->key_dma, ++ ctx->split_key_pad_len + enckeylen, ++ DMA_TO_DEVICE); + + ctx->enckeylen = enckeylen; + +@@ -561,6 +571,7 @@ + return -ENOMEM; + } + ctx->enckeylen = keylen; ++ dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); + + /* ablkcipher_encrypt shared descriptor */ + desc = ctx->sh_desc_enc; +@@ -579,10 +590,15 @@ + /* Propagate errors from shared to job descriptor */ + append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); + +- /* Load iv */ +- append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_1_CCB | tfm->ivsize); +- ++ /* load IV */ ++ if (strncmp(ablkcipher->base.__crt_alg->cra_name, "ctr(aes)", 8) == 0) { ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | tfm->ivsize | ++ (16 << LDST_OFFSET_SHIFT)); ++ } else { ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | tfm->ivsize); ++ } + /* Load operation */ + append_operation(desc, ctx->class1_alg_type | + OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); +@@ -602,6 +618,9 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); ++ + /* ablkcipher_decrypt shared descriptor */ + desc = ctx->sh_desc_dec; + +@@ -622,11 +641,20 @@ + set_jump_tgt_here(desc, jump_cmd); + + /* load IV */ +- append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_1_CCB | tfm->ivsize); ++ if (strncmp(ablkcipher->base.__crt_alg->cra_name, "ctr(aes)", 8) == 0) { ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | tfm->ivsize | ++ (16 << LDST_OFFSET_SHIFT)); + +- /* Choose operation */ +- append_dec_op1(desc, ctx->class1_alg_type); ++ append_operation(desc, ctx->class1_alg_type | ++ OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); ++ } else { ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | tfm->ivsize); ++ ++ /* Choose operation */ ++ append_dec_op1(desc, ctx->class1_alg_type); ++ } + + /* Perform operation */ + ablkcipher_append_src_dst(desc); +@@ -647,6 +675,8 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + return ret; + } +@@ -1154,7 +1184,7 @@ + dst_nents = sg_count(req->dst, req->cryptlen, &dst_chained); + + sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1, +- DMA_TO_DEVICE, assoc_chained); ++ DMA_BIDIRECTIONAL, assoc_chained); + if (likely(req->src == req->dst)) { + sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, + DMA_BIDIRECTIONAL, src_chained); +@@ -1178,9 +1208,10 @@ + sec4_sg_len += dst_nents; + + sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); ++ dma_sync_single_for_device(jrdev, iv_dma, ivsize, DMA_TO_DEVICE); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct aead_edesc) + desc_bytes + ++ edesc = kzalloc(sizeof(struct aead_edesc) + desc_bytes + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1221,6 +1252,8 @@ + sg_to_sec4_sg_last(req->dst, dst_nents, + edesc->sec4_sg + sec4_sg_index, 0); + } ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); + + return edesc; + } +@@ -1336,7 +1369,7 @@ + dst_nents = sg_count(req->dst, req->cryptlen, &dst_chained); + + sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1, +- DMA_TO_DEVICE, assoc_chained); ++ DMA_BIDIRECTIONAL, assoc_chained); + if (likely(req->src == req->dst)) { + sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1, + DMA_BIDIRECTIONAL, src_chained); +@@ -1369,8 +1402,10 @@ + + sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); + ++ dma_sync_single_for_device(jrdev, iv_dma, ivsize, DMA_TO_DEVICE); ++ + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct aead_edesc) + desc_bytes + ++ edesc = kzalloc(sizeof(struct aead_edesc) + desc_bytes + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1412,6 +1447,8 @@ + sg_to_sec4_sg_last(req->dst, dst_nents, + edesc->sec4_sg + sec4_sg_index, 0); + } ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); + + return edesc; + } +@@ -1505,6 +1542,7 @@ + * If so, include it. If not, create scatterlist. + */ + iv_dma = dma_map_single(jrdev, req->info, ivsize, DMA_TO_DEVICE); ++ dma_sync_single_for_device(jrdev, iv_dma, ivsize, DMA_TO_DEVICE); + if (!src_nents && iv_dma + ivsize == sg_dma_address(req->src)) + iv_contig = true; + else +@@ -1513,7 +1551,7 @@ + sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ablkcipher_edesc) + desc_bytes + ++ edesc = kzalloc(sizeof(struct ablkcipher_edesc) + desc_bytes + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1545,6 +1583,9 @@ + sec4_sg_bytes, DMA_TO_DEVICE); + edesc->iv_dma = iv_dma; + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "ablkcipher sec4_sg@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, edesc->sec4_sg, +@@ -2008,6 +2049,70 @@ + }, + /* ablkcipher descriptor */ + { ++ .name = "ecb(des)", ++ .driver_name = "ecb-des-caam", ++ .blocksize = DES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = DES_KEY_SIZE, ++ .max_keysize = DES_KEY_SIZE, ++ .ivsize = DES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_ECB, ++ }, ++ { ++ .name = "ecb(arc4)", ++ .driver_name = "ecb-arc4-caam", ++ .blocksize = ARC4_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = ARC4_MIN_KEY_SIZE, ++ .max_keysize = ARC4_MAX_KEY_SIZE, ++ .ivsize = ARC4_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_ARC4 | OP_ALG_AAI_ECB ++ }, ++ { ++ .name = "ecb(aes)", ++ .driver_name = "ecb-aes-caam", ++ .blocksize = AES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_ECB, ++ }, ++ { ++ .name = "ctr(aes)", ++ .driver_name = "ctr-aes-caam", ++ .blocksize = AES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, ++ }, ++ { + .name = "cbc(aes)", + .driver_name = "cbc-aes-caam", + .blocksize = AES_BLOCK_SIZE, +@@ -2024,6 +2129,22 @@ + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + }, + { ++ .name = "ecb(des3_ede)", ++ .driver_name = "ecb-des3-caam", ++ .blocksize = DES3_EDE_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = DES3_EDE_KEY_SIZE, ++ .max_keysize = DES3_EDE_KEY_SIZE, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_ECB, ++ }, ++ { + .name = "cbc(des3_ede)", + .driver_name = "cbc-3des-caam", + .blocksize = DES3_EDE_BLOCK_SIZE, +@@ -2079,7 +2200,7 @@ + * distribute tfms across job rings to ensure in-order + * crypto request processing per tfm + */ +- ctx->jrdev = priv->jrdev[(tgt_jr / 2) % priv->total_jobrs]; ++ ctx->jrdev = priv->algapi_jr[(tgt_jr / 2) % priv->num_jrs_for_algapi]; + + /* copy descriptor header template value */ + ctx->class1_alg_type = OP_TYPE_CLASS1_ALG | caam_alg->class1_alg_type; +@@ -2116,6 +2237,7 @@ + struct device *ctrldev; + struct caam_drv_private *priv; + struct caam_crypto_alg *t_alg, *n; ++ int i, err; + + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); + if (!dev_node) { +@@ -2125,21 +2247,33 @@ + } + + pdev = of_find_device_by_node(dev_node); +- if (!pdev) ++ if (!pdev) { ++ of_node_put(dev_node); + return; ++ } + + ctrldev = &pdev->dev; +- of_node_put(dev_node); + priv = dev_get_drvdata(ctrldev); + +- if (!priv->alg_list.next) ++ if (!priv->alg_list.next) { ++ of_node_put(dev_node); + return; ++ } + + list_for_each_entry_safe(t_alg, n, &priv->alg_list, entry) { + crypto_unregister_alg(&t_alg->crypto_alg); + list_del(&t_alg->entry); + kfree(t_alg); + } ++ ++ for (i = 0; i < priv->total_jobrs; i++) { ++ err = caam_jr_deregister(priv->algapi_jr[i]); ++ if (err < 0) ++ break; ++ } ++ kfree(priv->algapi_jr); ++ ++ of_node_put(dev_node); + } + + static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev, +@@ -2167,8 +2301,12 @@ + alg->cra_blocksize = template->blocksize; + alg->cra_alignmask = 0; + alg->cra_ctxsize = sizeof(struct caam_ctx); +- alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | +- template->type; ++ alg->cra_flags = CRYPTO_ALG_ASYNC | template->type; ++ ++#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY ++ alg->cra_flags |= CRYPTO_ALG_KERN_DRIVER_ONLY; ++#endif ++ + switch (template->type) { + case CRYPTO_ALG_TYPE_ABLKCIPHER: + alg->cra_type = &crypto_ablkcipher_type; +@@ -2192,9 +2330,11 @@ + { + struct device_node *dev_node; + struct platform_device *pdev; +- struct device *ctrldev; ++ struct device *ctrldev, **jrdev; + struct caam_drv_private *priv; +- int i = 0, err = 0; ++ int i = 0, err = 0, md_limit = 0; ++ int des_inst, aes_inst, md_inst; ++ u64 cha_inst; + + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); + if (!dev_node) { +@@ -2204,21 +2344,81 @@ + } + + pdev = of_find_device_by_node(dev_node); +- if (!pdev) ++ if (!pdev) { ++ of_node_put(dev_node); + return -ENODEV; ++ } + + ctrldev = &pdev->dev; + priv = dev_get_drvdata(ctrldev); +- of_node_put(dev_node); + + INIT_LIST_HEAD(&priv->alg_list); + ++ jrdev = kmalloc(sizeof(*jrdev) * priv->total_jobrs, GFP_KERNEL); ++ if (!jrdev) { ++ of_node_put(dev_node); ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < priv->total_jobrs; i++) { ++ err = caam_jr_register(ctrldev, &jrdev[i]); ++ if (err < 0) ++ break; ++ } ++ if (err < 0 && i == 0) { ++ dev_err(ctrldev, "algapi error in job ring registration: %d\n", ++ err); ++ of_node_put(dev_node); ++ kfree(jrdev); ++ return err; ++ } ++ ++ priv->num_jrs_for_algapi = i; ++ priv->algapi_jr = jrdev; + atomic_set(&priv->tfm_count, -1); + +- /* register crypto algorithms the device supports */ ++ /* ++ * register crypto algorithms the device supports ++ * first, detect presence of DES, AES, and MD blocks. If MD present, ++ * determine limit of supported digest size ++ */ ++ cha_inst = rd_reg64(&priv->ctrl->perfmon.cha_num); ++ des_inst = (cha_inst & CHA_ID_DES_MASK) >> CHA_ID_DES_SHIFT; ++ aes_inst = (cha_inst & CHA_ID_AES_MASK) >> CHA_ID_AES_SHIFT; ++ md_inst = (cha_inst & CHA_ID_MD_MASK) >> CHA_ID_MD_SHIFT; ++ if (md_inst) { ++ md_limit = SHA512_DIGEST_SIZE; ++ if ((rd_reg64(&priv->ctrl->perfmon.cha_id) & CHA_ID_MD_MASK) ++ == CHA_ID_MD_LP256) /* LP256 limits digest size */ ++ md_limit = SHA256_DIGEST_SIZE; ++ } ++ + for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { +- /* TODO: check if h/w supports alg */ + struct caam_crypto_alg *t_alg; ++ bool done = false; ++ ++authencesn: ++ /* ++ * All registrable algs in this module require a blockcipher ++ * All aead algs require message digests, so check them for ++ * instantiation and size. ++ */ ++ if (driver_algs[i].type == CRYPTO_ALG_TYPE_AEAD) { ++ /* If no MD instantiated, or MD too small, skip */ ++ if ((!md_inst) || ++ (driver_algs[i].template_aead.maxauthsize > ++ md_limit)) ++ continue; ++ } ++ /* If DES alg, and CHA not instantiated, skip */ ++ if ((driver_algs[i].class1_alg_type & OP_ALG_ALGSEL_3DES) || ++ (driver_algs[i].class1_alg_type & OP_ALG_ALGSEL_DES)) ++ if (!des_inst) ++ continue; ++ /* If AES alg, and CHA not instantiated, skip */ ++ if (driver_algs[i].class1_alg_type & OP_ALG_ALGSEL_AES) ++ if (!aes_inst) ++ continue; + + t_alg = caam_alg_alloc(ctrldev, &driver_algs[i]); + if (IS_ERR(t_alg)) { +@@ -2233,13 +2433,35 @@ + dev_warn(ctrldev, "%s alg registration failed\n", + t_alg->crypto_alg.cra_driver_name); + kfree(t_alg); +- } else ++ } else { + list_add_tail(&t_alg->entry, &priv->alg_list); ++ dev_info(ctrldev, "%s\n", ++ t_alg->crypto_alg.cra_driver_name); ++ ++ if (driver_algs[i].type == CRYPTO_ALG_TYPE_AEAD && ++ !memcmp(driver_algs[i].name, "authenc", 7) && ++ !done) { ++ char *name; ++ ++ name = driver_algs[i].name; ++ memmove(name + 10, name + 7, strlen(name) - 7); ++ memcpy(name + 7, "esn", 3); ++ ++ name = driver_algs[i].driver_name; ++ memmove(name + 10, name + 7, strlen(name) - 7); ++ memcpy(name + 7, "esn", 3); ++ ++ done = true; ++ goto authencesn; ++ } ++ } + } ++ + if (!list_empty(&priv->alg_list)) + dev_info(ctrldev, "%s algorithms registered in /proc/crypto\n", + (char *)of_get_property(dev_node, "compatible", NULL)); + ++ of_node_put(dev_node); + return err; + } + +diff -Nur linux-3.10.30/drivers/crypto/caam/caamhash.c linux-3.10.30-cubox-i/drivers/crypto/caam/caamhash.c +--- linux-3.10.30/drivers/crypto/caam/caamhash.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/caamhash.c 2014-03-08 20:33:30.000000000 +0100 +@@ -1,7 +1,7 @@ + /* + * caam - Freescale FSL CAAM support for ahash functions of crypto API + * +- * Copyright 2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. + * + * Based on caamalg.c crypto API driver. + * +@@ -62,6 +62,7 @@ + #include "error.h" + #include "sg_sw_sec4.h" + #include "key_gen.h" ++#include + + #define CAAM_CRA_PRIORITY 3000 + +@@ -116,6 +117,7 @@ + u8 key[CAAM_MAX_HASH_KEY_SIZE]; + dma_addr_t key_dma; + int ctx_len; ++ unsigned int key_len; + unsigned int split_key_len; + unsigned int split_key_pad_len; + }; +@@ -167,6 +169,7 @@ + dma_addr_t buf_dma; + + buf_dma = dma_map_single(jrdev, buf, buflen, DMA_TO_DEVICE); ++ dma_sync_single_for_device(jrdev, buf_dma, buflen, DMA_TO_DEVICE); + dma_to_sec4_sg_one(sec4_sg, buf_dma, buflen, 0); + + return buf_dma; +@@ -209,6 +212,9 @@ + u32 flag) + { + state->ctx_dma = dma_map_single(jrdev, state->caam_ctx, ctx_len, flag); ++ if ((flag == DMA_TO_DEVICE) || (flag == DMA_BIDIRECTIONAL)) ++ dma_sync_single_for_device(jrdev, state->ctx_dma, ctx_len, ++ flag); + dma_to_sec4_sg_one(sec4_sg, state->ctx_dma, ctx_len, 0); + } + +@@ -220,6 +226,13 @@ + KEY_DEST_MDHA_SPLIT | KEY_ENC); + } + ++static inline void append_key_axcbc(u32 *desc, struct caam_hash_ctx *ctx) ++{ ++ append_key_as_imm(desc, ctx->key, ctx->key_len, ++ ctx->key_len, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++} ++ + /* Append key if it has been set */ + static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) + { +@@ -241,6 +254,25 @@ + append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); + } + ++static inline void init_sh_desc_key_axcbc(u32 *desc, struct caam_hash_ctx *ctx) ++{ ++ u32 *key_jump_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ if (ctx->key_len) { ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ ++ append_key_axcbc(desc, ctx); ++ ++ set_jump_tgt_here(desc, key_jump_cmd); ++ } ++ ++ /* Propagate errors from shared to job descriptor */ ++ append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); ++ ++} + /* + * For ahash read data from seqin following state->caam_ctx, + * and write resulting class2 context to seqout, which may be state->caam_ctx +@@ -260,6 +292,20 @@ + LDST_SRCDST_BYTE_CONTEXT); + } + ++static inline void axcbc_append_load_str(u32 *desc, int digestsize) ++{ ++ /* Calculate remaining bytes to read */ ++ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Read remaining bytes */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_LAST1 | ++ FIFOLD_TYPE_MSG | KEY_VLF); ++ ++ /* Store class1 context bytes */ ++ append_seq_store(desc, digestsize, LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT); ++} ++ + /* + * For ahash update, final and finup, import context, read and write to seqout + */ +@@ -282,6 +328,27 @@ + ahash_append_load_str(desc, digestsize); + } + ++/* ++ * For ahash update, final and finup, import context, read and write to seqout ++ */ ++static inline void axcbc_ctx_data_to_out(u32 *desc, u32 op, u32 state, ++ int digestsize, ++ struct caam_hash_ctx *ctx) ++{ ++ init_sh_desc_key_axcbc(desc, ctx); ++ ++ /* Import context from software */ ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | ctx->ctx_len); ++ ++ /* Class 1 operation */ ++ append_operation(desc, op | state | OP_ALG_ENCRYPT); ++ ++ /* ++ * Load from buf and/or src and write to req->result or state->context ++ */ ++ axcbc_append_load_str(desc, digestsize); ++} + /* For ahash firsts and digest, read and write to seqout */ + static inline void ahash_data_to_out(u32 *desc, u32 op, u32 state, + int digestsize, struct caam_hash_ctx *ctx) +@@ -297,6 +364,21 @@ + ahash_append_load_str(desc, digestsize); + } + ++/* For ahash firsts and digest, read and write to seqout */ ++static inline void axcbc_data_to_out(u32 *desc, u32 op, u32 state, ++ int digestsize, struct caam_hash_ctx *ctx) ++{ ++ init_sh_desc_key_axcbc(desc, ctx); ++ ++ /* Class 1 operation */ ++ append_operation(desc, op | state | OP_ALG_ENCRYPT); ++ ++ /* ++ * Load from buf and/or src and write to req->result or state->context ++ */ ++ axcbc_append_load_str(desc, digestsize); ++} ++ + static int ahash_set_sh_desc(struct crypto_ahash *ahash) + { + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); +@@ -352,6 +434,8 @@ + print_hex_dump(KERN_ERR, "ahash update first shdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + /* ahash_final shared descriptor */ + desc = ctx->sh_desc_fin; +@@ -370,6 +454,8 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + /* ahash_finup shared descriptor */ + desc = ctx->sh_desc_finup; +@@ -388,6 +474,8 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_finup_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + /* ahash_digest shared descriptor */ + desc = ctx->sh_desc_digest; +@@ -407,10 +495,130 @@ + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + return 0; + } + ++static int axcbc_set_sh_desc(struct crypto_ahash *ahash) ++{ ++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); ++ int digestsize = crypto_ahash_digestsize(ahash); ++ struct device *jrdev = ctx->jrdev; ++ u32 have_key = 0; ++ u32 *desc; ++ ++ /* ahash_update shared descriptor */ ++ desc = ctx->sh_desc_update; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ /* Import context from software */ ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | ctx->ctx_len); ++ ++ /* Class 1 operation */ ++ append_operation(desc, ctx->alg_type | OP_ALG_AS_UPDATE | ++ OP_ALG_ENCRYPT); ++ ++ /* Load data and write to result or context */ ++ axcbc_append_load_str(desc, ctx->ctx_len); ++ ++ ctx->sh_desc_update_dma = dma_map_single(jrdev, desc, desc_bytes(desc), ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(jrdev, ctx->sh_desc_update_dma)) { ++ dev_err(jrdev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ahash update shdesc@"xstr(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++ ++ /* ahash_update_first shared descriptor */ ++ desc = ctx->sh_desc_update_first; ++ ++ axcbc_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INIT, ++ ctx->ctx_len, ctx); ++ ++ ctx->sh_desc_update_first_dma = dma_map_single(jrdev, desc, ++ desc_bytes(desc), ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(jrdev, ctx->sh_desc_update_first_dma)) { ++ dev_err(jrdev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ahash update first shdesc@"xstr(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); ++ ++ /* ahash_final shared descriptor */ ++ desc = ctx->sh_desc_fin; ++ ++ axcbc_ctx_data_to_out(desc, have_key | ctx->alg_type, ++ OP_ALG_AS_FINALIZE, digestsize, ctx); ++ ++ ctx->sh_desc_fin_dma = dma_map_single(jrdev, desc, desc_bytes(desc), ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(jrdev, ctx->sh_desc_fin_dma)) { ++ dev_err(jrdev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ahash final shdesc@"xstr(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, ++ desc_bytes(desc), 1); ++#endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); ++ ++ /* ahash_finup shared descriptor */ ++ desc = ctx->sh_desc_finup; ++ ++ axcbc_ctx_data_to_out(desc, have_key | ctx->alg_type, ++ OP_ALG_AS_FINALIZE, digestsize, ctx); ++ ++ ctx->sh_desc_finup_dma = dma_map_single(jrdev, desc, desc_bytes(desc), ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(jrdev, ctx->sh_desc_finup_dma)) { ++ dev_err(jrdev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ahash finup shdesc@"xstr(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, ++ desc_bytes(desc), 1); ++#endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_finup_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); ++ ++ /* ahash_digest shared descriptor */ ++ desc = ctx->sh_desc_digest; ++ ++ axcbc_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INITFINAL, ++ digestsize, ctx); ++ ++ ctx->sh_desc_digest_dma = dma_map_single(jrdev, desc, ++ desc_bytes(desc), ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(jrdev, ctx->sh_desc_digest_dma)) { ++ dev_err(jrdev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ahash digest shdesc@"xstr(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, ++ desc_bytes(desc), 1); ++#endif ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); ++ ++ return 0; ++} + static int gen_split_hash_key(struct caam_hash_ctx *ctx, const u8 *key_in, + u32 keylen) + { +@@ -444,6 +652,8 @@ + kfree(desc); + return -ENOMEM; + } ++ dma_sync_single_for_device(jrdev, src_dma, *keylen, DMA_TO_DEVICE); ++ + dst_dma = dma_map_single(jrdev, (void *)key_out, digestsize, + DMA_FROM_DEVICE); + if (dma_mapping_error(jrdev, dst_dma)) { +@@ -487,6 +697,7 @@ + *keylen = digestsize; + + dma_unmap_single(jrdev, src_dma, *keylen, DMA_TO_DEVICE); ++ dma_sync_single_for_cpu(jrdev, dst_dma, digestsize, DMA_FROM_DEVICE); + dma_unmap_single(jrdev, dst_dma, digestsize, DMA_FROM_DEVICE); + + kfree(desc); +@@ -544,6 +755,10 @@ + dev_err(jrdev, "unable to map key i/o memory\n"); + return -ENOMEM; + } ++ ++ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->split_key_pad_len, ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, +@@ -564,6 +779,25 @@ + return -EINVAL; + } + ++static int axcbc_setkey(struct crypto_ahash *ahash, ++ const u8 *key, unsigned int keylen) ++{ ++ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); ++ int ret = 0; ++ ++ ctx->key_len = keylen; ++ memcpy(ctx->key, key, keylen); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ++ ctx->key_len, 1); ++#endif ++ ++ ret = axcbc_set_sh_desc(ahash); ++ ++ return ret; ++} + /* + * ahash_edesc - s/w-extended ahash descriptor + * @dst_dma: physical mapped address of req->result +@@ -591,8 +825,11 @@ + if (edesc->src_nents) + dma_unmap_sg_chained(dev, req->src, edesc->src_nents, + DMA_TO_DEVICE, edesc->chained); +- if (edesc->dst_dma) ++ if (edesc->dst_dma) { ++ dma_sync_single_for_cpu(dev, edesc->dst_dma, dst_len, ++ DMA_FROM_DEVICE); + dma_unmap_single(dev, edesc->dst_dma, dst_len, DMA_FROM_DEVICE); ++ } + + if (edesc->sec4_sg_bytes) + dma_unmap_single(dev, edesc->sec4_sg_dma, +@@ -607,8 +844,12 @@ + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + +- if (state->ctx_dma) ++ if (state->ctx_dma) { ++ if ((flag == DMA_FROM_DEVICE) || (flag == DMA_BIDIRECTIONAL)) ++ dma_sync_single_for_cpu(dev, state->ctx_dma, ++ ctx->ctx_len, flag); + dma_unmap_single(dev, state->ctx_dma, ctx->ctx_len, flag); ++ } + ahash_unmap(dev, edesc, req, dst_len); + } + +@@ -802,7 +1043,7 @@ + * allocate space for base edesc and hw desc commands, + * link tables + */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, +@@ -851,6 +1092,9 @@ + + append_seq_out_ptr(desc, state->ctx_dma, ctx->ctx_len, 0); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, ++ sec4_sg_bytes, DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, +@@ -904,7 +1148,7 @@ + sec4_sg_bytes = (1 + (buflen ? 1 : 0)) * sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -936,6 +1180,9 @@ + edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, + digestsize); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +@@ -980,7 +1227,7 @@ + sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1015,6 +1262,9 @@ + edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, + digestsize); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +@@ -1055,7 +1305,7 @@ + sec4_sg_bytes = src_nents * sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + sec4_sg_bytes + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + sec4_sg_bytes + + DESC_JOB_IO_LEN, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1065,6 +1315,7 @@ + DESC_JOB_IO_LEN; + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, DMA_TO_DEVICE); ++ edesc->sec4_sg_bytes = sec4_sg_bytes; + edesc->src_nents = src_nents; + edesc->chained = chained; + +@@ -1082,6 +1333,9 @@ + } + append_seq_in_ptr(desc, src_dma, req->nbytes, options); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, ++ edesc->sec4_sg_bytes, DMA_TO_DEVICE); ++ + edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, + digestsize); + +@@ -1120,7 +1374,7 @@ + int sh_len; + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN, ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN, + GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1139,6 +1393,8 @@ + digestsize); + edesc->src_nents = 0; + ++ dma_sync_single_for_device(jrdev, state->buf_dma, buflen, ++ DMA_TO_DEVICE); + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +@@ -1191,7 +1447,7 @@ + * allocate space for base edesc and hw desc commands, + * link tables + */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, +@@ -1227,6 +1483,8 @@ + + map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, ++ sec4_sg_bytes, DMA_TO_DEVICE); + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, +@@ -1288,7 +1546,7 @@ + sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); +@@ -1320,6 +1578,9 @@ + edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result, + digestsize); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, sec4_sg_bytes, ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +@@ -1374,7 +1635,7 @@ + * allocate space for base edesc and hw desc commands, + * link tables + */ +- edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + ++ edesc = kzalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + + sec4_sg_bytes, GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, +@@ -1413,6 +1674,8 @@ + + map_seq_out_ptr_ctx(desc, jrdev, state, ctx->ctx_len); + ++ dma_sync_single_for_device(jrdev, edesc->sec4_sg_dma, ++ sec4_sg_bytes, DMA_TO_DEVICE); + #ifdef DEBUG + print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, +@@ -1460,6 +1723,8 @@ + state->final = ahash_final_no_ctx; + + state->current_buf = 0; ++ state->buflen_0 = 0; ++ state->buflen_1 = 0; + + return 0; + } +@@ -1649,6 +1914,28 @@ + .alg_type = OP_ALG_ALGSEL_MD5, + .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + }, ++ { ++ .name = "xcbc(aes)", ++ .driver_name = "xcbc-aes-caam", ++ .hmac_name = "xcbc(aes)", ++ .hmac_driver_name = "xcbc-aes-caam", ++ .blocksize = XCBC_MAC_BLOCK_WORDS * 4, ++ .template_ahash = { ++ .init = ahash_init, ++ .update = ahash_update, ++ .final = ahash_final, ++ .finup = ahash_finup, ++ .digest = ahash_digest, ++ .export = ahash_export, ++ .import = ahash_import, ++ .setkey = axcbc_setkey, ++ .halg = { ++ .digestsize = XCBC_MAC_DIGEST_SIZE, ++ }, ++ }, ++ .alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XCBC_MAC, ++ .alg_op = OP_ALG_ALGSEL_AES, ++ }, + }; + + struct caam_hash_alg { +@@ -1702,6 +1989,39 @@ + return ret; + } + ++static int caam_axcbc_cra_init(struct crypto_tfm *tfm) ++{ ++ struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); ++ struct crypto_alg *base = tfm->__crt_alg; ++ struct hash_alg_common *halg = ++ container_of(base, struct hash_alg_common, base); ++ struct ahash_alg *alg = ++ container_of(halg, struct ahash_alg, halg); ++ struct caam_hash_alg *caam_hash = ++ container_of(alg, struct caam_hash_alg, ahash_alg); ++ struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct caam_drv_private *priv = dev_get_drvdata(caam_hash->ctrldev); ++ int tgt_jr = atomic_inc_return(&priv->tfm_count); ++ int ret = 0; ++ ++ /* ++ * distribute tfms across job rings to ensure in-order ++ * crypto request processing per tfm ++ */ ++ ctx->jrdev = priv->jrdev[tgt_jr % priv->total_jobrs]; ++ ++ /* copy descriptor header template value */ ++ ctx->alg_type = OP_TYPE_CLASS1_ALG | caam_hash->alg_type; ++ ctx->alg_op = OP_TYPE_CLASS1_ALG | caam_hash->alg_op; ++ ++ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), ++ sizeof(struct caam_hash_state)); ++ ++ ret = axcbc_set_sh_desc(ahash); ++ ++ return ret; ++} ++ + static void caam_hash_cra_exit(struct crypto_tfm *tfm) + { + struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); +@@ -1747,21 +2067,26 @@ + } + + pdev = of_find_device_by_node(dev_node); +- if (!pdev) ++ if (!pdev) { ++ of_node_put(dev_node); + return; ++ } + + ctrldev = &pdev->dev; +- of_node_put(dev_node); + priv = dev_get_drvdata(ctrldev); + +- if (!priv->hash_list.next) ++ if (!priv->hash_list.next) { ++ of_node_put(dev_node); + return; ++ } + + list_for_each_entry_safe(t_alg, n, &priv->hash_list, entry) { + crypto_unregister_ahash(&t_alg->ahash_alg); + list_del(&t_alg->entry); + kfree(t_alg); + } ++ ++ of_node_put(dev_node); + } + + static struct caam_hash_alg * +@@ -1794,7 +2119,11 @@ + template->driver_name); + } + alg->cra_module = THIS_MODULE; +- alg->cra_init = caam_hash_cra_init; ++ ++ if (strstr(alg->cra_name, "xcbc") > 0) ++ alg->cra_init = caam_axcbc_cra_init; ++ else ++ alg->cra_init = caam_hash_cra_init; + alg->cra_exit = caam_hash_cra_exit; + alg->cra_ctxsize = sizeof(struct caam_hash_ctx); + alg->cra_priority = CAAM_CRA_PRIORITY; +@@ -1816,7 +2145,8 @@ + struct platform_device *pdev; + struct device *ctrldev; + struct caam_drv_private *priv; +- int i = 0, err = 0; ++ int i = 0, err = 0, md_limit = 0, md_inst; ++ u64 cha_inst; + + dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); + if (!dev_node) { +@@ -1826,22 +2156,36 @@ + } + + pdev = of_find_device_by_node(dev_node); +- if (!pdev) ++ if (!pdev) { ++ of_node_put(dev_node); + return -ENODEV; +- ++ } + ctrldev = &pdev->dev; + priv = dev_get_drvdata(ctrldev); +- of_node_put(dev_node); + + INIT_LIST_HEAD(&priv->hash_list); + + atomic_set(&priv->tfm_count, -1); + +- /* register crypto algorithms the device supports */ ++ /* register algorithms the device supports */ ++ cha_inst = rd_reg64(&priv->ctrl->perfmon.cha_num); ++ md_inst = (cha_inst & CHA_ID_MD_MASK) >> CHA_ID_MD_SHIFT; ++ if (md_inst) { ++ md_limit = SHA512_DIGEST_SIZE; ++ if ((rd_reg64(&priv->ctrl->perfmon.cha_id) & CHA_ID_MD_MASK) ++ == CHA_ID_MD_LP256) /* LP256 limits digest size */ ++ md_limit = SHA256_DIGEST_SIZE; ++ } ++ + for (i = 0; i < ARRAY_SIZE(driver_hash); i++) { +- /* TODO: check if h/w supports alg */ + struct caam_hash_alg *t_alg; + ++ /* If no MD instantiated, or MD too small, skip */ ++ if ((!md_inst) || ++ (driver_hash[i].template_ahash.halg.digestsize > ++ md_limit)) ++ continue; ++ + /* register hmac version */ + t_alg = caam_hash_alloc(ctrldev, &driver_hash[i], true); + if (IS_ERR(t_alg)) { +@@ -1877,6 +2221,7 @@ + list_add_tail(&t_alg->entry, &priv->hash_list); + } + ++ of_node_put(dev_node); + return err; + } + +diff -Nur linux-3.10.30/drivers/crypto/caam/caamrng.c linux-3.10.30-cubox-i/drivers/crypto/caam/caamrng.c +--- linux-3.10.30/drivers/crypto/caam/caamrng.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/caamrng.c 2014-03-08 20:33:30.000000000 +0100 +@@ -1,7 +1,7 @@ + /* + * caam - Freescale FSL CAAM support for hw_random + * +- * Copyright 2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. + * + * Based on caamalg.c crypto API driver. + * +@@ -76,13 +76,16 @@ + struct buf_data bufs[2]; + }; + +-static struct caam_rng_ctx rng_ctx; ++static struct caam_rng_ctx *rng_ctx; + + static inline void rng_unmap_buf(struct device *jrdev, struct buf_data *bd) + { +- if (bd->addr) ++ if (bd->addr) { ++ dma_sync_single_for_cpu(jrdev, bd->addr, RN_BUF_SIZE, ++ DMA_FROM_DEVICE); + dma_unmap_single(jrdev, bd->addr, RN_BUF_SIZE, + DMA_FROM_DEVICE); ++ } + } + + static inline void rng_unmap_ctx(struct caam_rng_ctx *ctx) +@@ -137,7 +140,7 @@ + + static int caam_read(struct hwrng *rng, void *data, size_t max, bool wait) + { +- struct caam_rng_ctx *ctx = &rng_ctx; ++ struct caam_rng_ctx *ctx = rng_ctx; + struct buf_data *bd = &ctx->bufs[ctx->current_buf]; + int next_buf_idx, copied_idx; + int err; +@@ -206,6 +209,9 @@ + + ctx->sh_desc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), + DMA_TO_DEVICE); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_dma, desc_bytes(desc), ++ DMA_TO_DEVICE); ++ + #ifdef DEBUG + print_hex_dump(KERN_ERR, "rng shdesc@: ", DUMP_PREFIX_ADDRESS, 16, 4, + desc, desc_bytes(desc), 1); +@@ -237,13 +243,56 @@ + struct buf_data *bd; + + for (i = 0; i < 2; i++) { +- bd = &rng_ctx.bufs[i]; ++ bd = &rng_ctx->bufs[i]; + if (atomic_read(&bd->empty) == BUF_PENDING) + wait_for_completion(&bd->filled); + } + +- rng_unmap_ctx(&rng_ctx); ++ rng_unmap_ctx(rng_ctx); ++} ++ ++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST ++static inline void test_len(struct hwrng *rng, size_t len, bool wait) ++{ ++ u8 *buf; ++ int real_len; ++ ++ buf = kzalloc(sizeof(u8) * len, GFP_KERNEL); ++ real_len = rng->read(rng, buf, len, wait); ++ if (real_len == 0 && wait) ++ pr_err("WAITING FAILED\n"); ++ pr_info("wanted %d bytes, got %d\n", len, real_len); ++ print_hex_dump(KERN_INFO, "random bytes@: ", DUMP_PREFIX_ADDRESS, ++ 16, 4, buf, real_len, 1); ++ kfree(buf); ++} ++ ++static inline void test_mode_once(struct hwrng *rng, bool wait) ++{ ++#define TEST_CHUNK (RN_BUF_SIZE / 4) ++ ++ test_len(rng, TEST_CHUNK, wait); ++ test_len(rng, RN_BUF_SIZE * 2, wait); ++ test_len(rng, RN_BUF_SIZE * 2 - TEST_CHUNK, wait); ++} ++ ++static inline void test_mode(struct hwrng *rng, bool wait) ++{ ++#define TEST_PASS 1 ++ int i; ++ ++ for (i = 0; i < TEST_PASS; i++) ++ test_mode_once(rng, wait); ++} ++ ++static void self_test(struct hwrng *rng) ++{ ++ pr_info("testing without waiting\n"); ++ test_mode(rng, false); ++ pr_info("testing with waiting\n"); ++ test_mode(rng, true); + } ++#endif + + static void caam_init_buf(struct caam_rng_ctx *ctx, int buf_id) + { +@@ -298,7 +347,17 @@ + priv = dev_get_drvdata(ctrldev); + of_node_put(dev_node); + +- caam_init_rng(&rng_ctx, priv->jrdev[0]); ++ /* Check RNG present in hardware before registration */ ++ if (!(rd_reg64(&priv->ctrl->perfmon.cha_num) & CHA_ID_RNG_MASK)) ++ return -ENODEV; ++ ++ rng_ctx = kmalloc(sizeof(struct caam_rng_ctx), GFP_KERNEL | GFP_DMA); ++ ++ caam_init_rng(rng_ctx, priv->jrdev[0]); ++ ++#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST ++ self_test(&caam_rng); ++#endif + + dev_info(priv->jrdev[0], "registering rng-caam\n"); + return hwrng_register(&caam_rng); +diff -Nur linux-3.10.30/drivers/crypto/caam/compat.h linux-3.10.30-cubox-i/drivers/crypto/caam/compat.h +--- linux-3.10.30/drivers/crypto/caam/compat.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/compat.h 2014-03-08 20:33:30.000000000 +0100 +@@ -14,6 +14,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -23,6 +25,10 @@ + #include + #include + #include ++ ++#ifdef CONFIG_ARM /* needs the clock control subsystem */ ++#include ++#endif + #include + + #include +diff -Nur linux-3.10.30/drivers/crypto/caam/ctrl.c linux-3.10.30-cubox-i/drivers/crypto/caam/ctrl.c +--- linux-3.10.30/drivers/crypto/caam/ctrl.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/ctrl.c 2014-03-08 20:33:30.000000000 +0100 +@@ -2,7 +2,7 @@ + * CAAM control-plane driver backend + * Controller-level driver, kernel property detection, initialization + * +- * Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. + */ + + #include "compat.h" +@@ -12,6 +12,10 @@ + #include "desc_constr.h" + #include "error.h" + #include "ctrl.h" ++#include "sm.h" ++ ++/* Used to capture the array of job rings */ ++struct device **caam_jr_dev; + + static int caam_remove(struct platform_device *pdev) + { +@@ -40,6 +44,13 @@ + /* Unmap controller region */ + iounmap(&topregs->ctrl); + ++#ifdef CONFIG_ARM ++ /* shut clocks off before finalizing shutdown */ ++ clk_disable(ctrlpriv->caam_ipg); ++ clk_disable(ctrlpriv->caam_mem); ++ clk_disable(ctrlpriv->caam_aclk); ++#endif ++ + kfree(ctrlpriv->jrdev); + kfree(ctrlpriv); + +@@ -70,9 +81,13 @@ + */ + append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW); + ++} ++ ++static void generate_secure_keys_desc(u32 *desc) ++{ + /* generate secure keys (non-test) */ + append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | +- OP_ALG_RNG4_SK); ++ OP_ALG_RNG4_SK); + } + + struct instantiate_result { +@@ -95,7 +110,7 @@ + complete(&instantiation->completion); + } + +-static int instantiate_rng(struct device *jrdev) ++static int instantiate_rng(struct device *jrdev, u32 keys_generated) + { + struct instantiate_result instantiation; + +@@ -110,7 +125,14 @@ + } + + build_instantiation_desc(desc); ++ ++ /* If keys have not been generated, add op code to generate key. */ ++ if (!keys_generated) ++ generate_secure_keys_desc(desc); ++ + desc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); ++ dma_sync_single_for_device(jrdev, desc_dma, desc_bytes(desc), ++ DMA_TO_DEVICE); + init_completion(&instantiation.completion); + ret = caam_jr_enqueue(jrdev, desc, rng4_init_done, &instantiation); + if (!ret) { +@@ -142,16 +164,18 @@ + topregs = (struct caam_full __iomem *)ctrlpriv->ctrl; + r4tst = &topregs->ctrl.r4tst[0]; + ++ val = rd_reg32(&r4tst->rtmctl); + /* put RNG4 into program mode */ + setbits32(&r4tst->rtmctl, RTMCTL_PRGM); +- /* 1600 clocks per sample */ ++ /* Set clocks per sample to the default, and divider to zero */ + val = rd_reg32(&r4tst->rtsdctl); +- val = (val & ~RTSDCTL_ENT_DLY_MASK) | (1600 << RTSDCTL_ENT_DLY_SHIFT); ++ val = (val & ~RTSDCTL_ENT_DLY_MASK) | ++ (RNG4_ENT_CLOCKS_SAMPLE << RTSDCTL_ENT_DLY_SHIFT); + wr_reg32(&r4tst->rtsdctl, val); + /* min. freq. count */ +- wr_reg32(&r4tst->rtfrqmin, 400); ++ wr_reg32(&r4tst->rtfrqmin, RNG4_ENT_CLOCKS_SAMPLE / 4); + /* max. freq. count */ +- wr_reg32(&r4tst->rtfrqmax, 6400); ++ wr_reg32(&r4tst->rtfrqmax, RNG4_ENT_CLOCKS_SAMPLE * 8); + /* put RNG4 into run mode */ + clrbits32(&r4tst->rtmctl, RTMCTL_PRGM); + } +@@ -176,7 +200,20 @@ + {0x0A14, 1, 3}, + {0x0A14, 2, 4}, + {0x0A16, 1, 4}, +- {0x0A11, 1, 4} ++ {0x0A11, 1, 4}, ++ {0x0A10, 3, 4}, ++ {0x0A18, 1, 4}, ++ {0x0A11, 2, 5}, ++ {0x0A12, 2, 5}, ++ {0x0A13, 1, 5}, ++ {0x0A1C, 1, 5}, ++ {0x0A12, 4, 6}, ++ {0x0A13, 2, 6}, ++ {0x0A16, 2, 6}, ++ {0x0A18, 2, 6}, ++ {0x0A1A, 1, 6}, ++ {0x0A1C, 2, 6}, ++ {0x0A17, 1, 6} + }; + int i; + +@@ -189,6 +226,18 @@ + } + EXPORT_SYMBOL(caam_get_era); + ++/* ++ * Return a job ring device. This is available so outside ++ * entities can gain direct access to the job ring. For now, ++ * this function returns the first job ring (at index 0). ++ */ ++struct device *caam_get_jrdev(void) ++{ ++ return caam_jr_dev[0]; ++} ++EXPORT_SYMBOL(caam_get_jrdev); ++ ++ + /* Probe routine for CAAM top (controller) level */ + static int caam_probe(struct platform_device *pdev) + { +@@ -198,6 +247,7 @@ + struct device_node *nprop, *np; + struct caam_ctrl __iomem *ctrl; + struct caam_full __iomem *topregs; ++ struct snvs_full __iomem *snvsregs; + struct caam_drv_private *ctrlpriv; + #ifdef CONFIG_DEBUG_FS + struct caam_perfmon *perfmon; +@@ -227,6 +277,90 @@ + /* Get the IRQ of the controller (for security violations only) */ + ctrlpriv->secvio_irq = of_irq_to_resource(nprop, 0, NULL); + ++ /* Get SNVS register Page */ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-snvs"); ++ ++ if (!np) ++ return -ENODEV; ++ ++ snvsregs = of_iomap(np, 0); ++ ctrlpriv->snvs = snvsregs; ++ /* Get CAAM-SM node and of_iomap() and save */ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm"); ++ ++ if (!np) ++ return -ENODEV; ++ ++ ctrlpriv->sm_base = of_iomap(np, 0); ++ ctrlpriv->sm_size = 0x3fff; ++ ++/* ++ * ARM targets tend to have clock control subsystems that can ++ * enable/disable clocking to our device. Turn clocking on to proceed ++ */ ++#ifdef CONFIG_ARM ++ ctrlpriv->caam_ipg = devm_clk_get(&ctrlpriv->pdev->dev, "caam_ipg"); ++ if (IS_ERR(ctrlpriv->caam_ipg)) { ++ ret = PTR_ERR(ctrlpriv->caam_ipg); ++ dev_err(&ctrlpriv->pdev->dev, ++ "can't identify CAAM ipg clk: %d\n", ret); ++ return -ENODEV; ++ } ++ ctrlpriv->caam_mem = devm_clk_get(&ctrlpriv->pdev->dev, "caam_mem"); ++ if (IS_ERR(ctrlpriv->caam_mem)) { ++ ret = PTR_ERR(ctrlpriv->caam_mem); ++ dev_err(&ctrlpriv->pdev->dev, ++ "can't identify CAAM secure mem clk: %d\n", ret); ++ return -ENODEV; ++ } ++ ctrlpriv->caam_aclk = devm_clk_get(&ctrlpriv->pdev->dev, "caam_aclk"); ++ if (IS_ERR(ctrlpriv->caam_aclk)) { ++ ret = PTR_ERR(ctrlpriv->caam_aclk); ++ dev_err(&ctrlpriv->pdev->dev, ++ "can't identify CAAM aclk clk: %d\n", ret); ++ return -ENODEV; ++ } ++ ++ ret = clk_prepare(ctrlpriv->caam_ipg); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't prepare CAAM ipg clock: %d\n", ret); ++ return -ENODEV; ++ } ++ ret = clk_prepare(ctrlpriv->caam_mem); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't prepare CAAM secure mem clock: %d\n", ret); ++ return -ENODEV; ++ } ++ ret = clk_prepare(ctrlpriv->caam_aclk); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't prepare CAAM aclk clock: %d\n", ret); ++ return -ENODEV; ++ } ++ ++ ret = clk_enable(ctrlpriv->caam_ipg); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't enable CAAM ipg clock: %d\n", ret); ++ return -ENODEV; ++ } ++ ret = clk_enable(ctrlpriv->caam_mem); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't enable CAAM secure mem clock: %d\n", ret); ++ return -ENODEV; ++ } ++ ret = clk_enable(ctrlpriv->caam_aclk); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't enable CAAM aclk clock: %d\n", ret); ++ return -ENODEV; ++ } ++ ++ pr_debug("%s caam_ipg clock:%d\n", __func__, ++ (int)clk_get_rate(ctrlpriv->caam_ipg)); ++ pr_debug("%s caam_mem clock:%d\n", __func__, ++ (int)clk_get_rate(ctrlpriv->caam_mem)); ++ pr_debug("%s caam_aclk clock:%d\n", __func__, ++ (int)clk_get_rate(ctrlpriv->caam_aclk)); ++#endif ++ + /* + * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, + * long pointers in master configuration register +@@ -234,6 +368,22 @@ + setbits32(&topregs->ctrl.mcr, MCFGR_WDENABLE | + (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0)); + ++#ifdef CONFIG_ARCH_MX6 ++ /* ++ * ERRATA: mx6 devices have an issue wherein AXI bus transactions ++ * may not occur in the correct order. This isn't a problem running ++ * single descriptors, but can be if running multiple concurrent ++ * descriptors. Reworking the driver to throttle to single requests ++ * is impractical, thus the workaround is to limit the AXI pipeline ++ * to a depth of 1 (from it's default of 4) to preclude this situation ++ * from occurring. ++ */ ++ wr_reg32(&topregs->ctrl.mcr, ++ (rd_reg32(&topregs->ctrl.mcr) & ~(MCFGR_AXIPIPE_MASK)) | ++ ((1 << MCFGR_AXIPIPE_SHIFT) & MCFGR_AXIPIPE_MASK)); ++#endif ++ ++ /* Set DMA masks according to platform ranging */ + if (sizeof(dma_addr_t) == sizeof(u64)) + if (of_device_is_compatible(nprop, "fsl,sec-v5.0")) + dma_set_mask(dev, DMA_BIT_MASK(40)); +@@ -265,13 +415,36 @@ + ring = 0; + ctrlpriv->total_jobrs = 0; + for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") { +- caam_jr_probe(pdev, np, ring); ++ ret = caam_jr_probe(pdev, np, ring); ++ if (ret < 0) { ++ /* ++ * Job ring not found, error out. At some ++ * point, we should enhance job ring handling ++ * to allow for non-consecutive job rings to ++ * be found. ++ */ ++ pr_err("fsl,sec-v4.0-job-ring not found "); ++ pr_err("(ring %d)\n", ring); ++ return ret; ++ } + ctrlpriv->total_jobrs++; + ring++; + } ++ + if (!ring) { + for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") { +- caam_jr_probe(pdev, np, ring); ++ ret = caam_jr_probe(pdev, np, ring); ++ if (ret < 0) { ++ /* ++ * Job ring not found, error out. At some ++ * point, we should enhance job ring handling ++ * to allow for non-consecutive job rings to ++ * be found. ++ */ ++ pr_err("fsl,sec4.0-job-ring not found "); ++ pr_err("(ring %d)\n", ring); ++ return ret; ++ } + ctrlpriv->total_jobrs++; + ring++; + } +@@ -294,19 +467,40 @@ + } + + /* +- * RNG4 based SECs (v5+) need special initialization prior +- * to executing any descriptors ++ * RNG4 based SECs (v5+ | >= i.MX6) need special initialization prior ++ * to executing any descriptors. If there's a problem with init, ++ * remove other subsystems and return; internal padding functions ++ * cannot run without an RNG. This procedure assumes a single RNG4 ++ * instance. + */ +- if (of_device_is_compatible(nprop, "fsl,sec-v5.0")) { +- kick_trng(pdev); +- ret = instantiate_rng(ctrlpriv->jrdev[0]); +- if (ret) { +- caam_remove(pdev); +- return ret; ++ if ((rd_reg64(&topregs->ctrl.perfmon.cha_id) & CHA_ID_RNG_MASK) ++ == CHA_ID_RNG_4) { ++ struct rng4tst __iomem *r4tst; ++ u32 rdsta, rng_if, rng_skvn; ++ ++ /* ++ * Check to see if the RNG has already been instantiated. ++ * If either the state 0 or 1 instantiated flags are set, ++ * then don't continue on and try to instantiate the RNG ++ * again. ++ */ ++ r4tst = &topregs->ctrl.r4tst[0]; ++ rdsta = rd_reg32(&r4tst->rdsta); /* Read RDSTA register */ ++ ++ /* Check IF bit for non-deterministic instantiation */ ++ rng_if = rdsta & RDSTA_IF; ++ ++ /* Check SKVN bit for non-deterministic key generation */ ++ rng_skvn = rdsta & RDSTA_SKVN; ++ if (!rng_if) { ++ kick_trng(pdev); ++ ret = instantiate_rng(ctrlpriv->jrdev[0], rng_skvn); ++ if (ret) { ++ caam_remove(pdev); ++ return -ENODEV; ++ } ++ ctrlpriv->rng_inst++; + } +- +- /* Enable RDB bit so that RNG works faster */ +- setbits32(&topregs->ctrl.scfgr, SCFGR_RDBENABLE); + } + + /* NOTE: RTIC detection ought to go here, around Si time */ +diff -Nur linux-3.10.30/drivers/crypto/caam/desc.h linux-3.10.30-cubox-i/drivers/crypto/caam/desc.h +--- linux-3.10.30/drivers/crypto/caam/desc.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/desc.h 2014-03-08 20:33:30.000000000 +0100 +@@ -2,19 +2,35 @@ + * CAAM descriptor composition header + * Definitions to support CAAM descriptor instruction generation + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. + */ + + #ifndef DESC_H + #define DESC_H + ++/* ++ * 16-byte hardware scatter/gather table ++ * An 8-byte table exists in the hardware spec, but has never been ++ * implemented to date. The 8/16 option is selected at RTL-compile-time. ++ * and this selection is visible in the Compile Time Parameters Register ++ */ ++ ++#define SEC4_SG_LEN_EXT 0x80000000 /* Entry points to table */ ++#define SEC4_SG_LEN_FIN 0x40000000 /* Last ent in table */ ++#define SEC4_SG_BPID_MASK 0x000000ff ++#define SEC4_SG_BPID_SHIFT 16 ++#define SEC4_SG_LEN_MASK 0x3fffffff /* Excludes EXT and FINAL */ ++#define SEC4_SG_OFFS_MASK 0x00001fff ++ + struct sec4_sg_entry { ++#ifdef CONFIG_64BIT + u64 ptr; +-#define SEC4_SG_LEN_FIN 0x40000000 +-#define SEC4_SG_LEN_EXT 0x80000000 ++#else ++ u32 reserved; ++ u32 ptr; ++#endif + u32 len; +- u8 reserved; +- u8 buf_pool_id; ++ u16 buf_pool_id; + u16 offset; + }; + +@@ -1087,6 +1103,23 @@ + #define OP_PCL_PKPROT_ECC 0x0002 + #define OP_PCL_PKPROT_F2M 0x0001 + ++/* Blob protocol protinfo bits */ ++#define OP_PCL_BLOB_TK 0x0200 ++#define OP_PCL_BLOB_EKT 0x0100 ++ ++#define OP_PCL_BLOB_K2KR_MEM 0x0000 ++#define OP_PCL_BLOB_K2KR_C1KR 0x0010 ++#define OP_PCL_BLOB_K2KR_C2KR 0x0030 ++#define OP_PCL_BLOB_K2KR_AFHAS 0x0050 ++#define OP_PCL_BLOB_K2KR_C2KR_SPLIT 0x0070 ++ ++#define OP_PCL_BLOB_PTXT_SECMEM 0x0008 ++#define OP_PCL_BLOB_BLACK 0x0004 ++ ++#define OP_PCL_BLOB_FMT_NORMAL 0x0000 ++#define OP_PCL_BLOB_FMT_MSTR 0x0002 ++#define OP_PCL_BLOB_FMT_TEST 0x0003 ++ + /* For non-protocol/alg-only op commands */ + #define OP_ALG_TYPE_SHIFT 24 + #define OP_ALG_TYPE_MASK (0x7 << OP_ALG_TYPE_SHIFT) +@@ -1600,4 +1633,28 @@ + #define NFIFOENTRY_PLEN_SHIFT 0 + #define NFIFOENTRY_PLEN_MASK (0xFF << NFIFOENTRY_PLEN_SHIFT) + ++/* ++ * PDB internal definitions ++ */ ++ ++/* IPSec ESP CBC Encap/Decap Options */ ++#define PDBOPTS_ESPCBC_ARSNONE 0x00 /* no antireplay window */ ++#define PDBOPTS_ESPCBC_ARS32 0x40 /* 32-entry antireplay window */ ++#define PDBOPTS_ESPCBC_ARS64 0xc0 /* 64-entry antireplay window */ ++#define PDBOPTS_ESPCBC_IVSRC 0x20 /* IV comes from internal random gen */ ++#define PDBOPTS_ESPCBC_ESN 0x10 /* extended sequence included */ ++#define PDBOPTS_ESPCBC_OUTFMT 0x08 /* output only decapsulation (decap) */ ++#define PDBOPTS_ESPCBC_IPHDRSRC 0x08 /* IP header comes from PDB (encap) */ ++#define PDBOPTS_ESPCBC_INCIPHDR 0x04 /* Prepend IP header to output frame */ ++#define PDBOPTS_ESPCBC_IPVSN 0x02 /* process IPv6 header */ ++#define PDBOPTS_ESPCBC_TUNNEL 0x01 /* tunnel mode next-header byte */ ++ ++#define ARC4_BLOCK_SIZE 1 ++#define ARC4_MAX_KEY_SIZE 256 ++#define ARC4_MIN_KEY_SIZE 1 ++ ++#define XCBC_MAC_DIGEST_SIZE 16 ++#define XCBC_MAC_BLOCK_WORDS 16 ++ ++ + #endif /* DESC_H */ +diff -Nur linux-3.10.30/drivers/crypto/caam/intern.h linux-3.10.30-cubox-i/drivers/crypto/caam/intern.h +--- linux-3.10.30/drivers/crypto/caam/intern.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/intern.h 2014-03-08 20:33:30.000000000 +0100 +@@ -2,7 +2,7 @@ + * CAAM/SEC 4.x driver backend + * Private/internal definitions between modules + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. + * + */ + +@@ -12,6 +12,9 @@ + #define JOBR_UNASSIGNED 0 + #define JOBR_ASSIGNED 1 + ++/* Default clock/sample settings for an RNG4 entropy source */ ++#define RNG4_ENT_CLOCKS_SAMPLE 1600 ++ + /* Currently comes from Kconfig param as a ^2 (driver-required) */ + #define JOBR_DEPTH (1 << CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE) + +@@ -67,6 +70,8 @@ + struct caam_drv_private { + + struct device *dev; ++ struct device *smdev; ++ struct device *secviodev; + struct device **jrdev; /* Alloc'ed array per sub-device */ + spinlock_t jr_alloc_lock; + struct platform_device *pdev; +@@ -76,6 +81,9 @@ + struct caam_deco **deco; /* DECO/CCB views */ + struct caam_assurance *ac; + struct caam_queue_if *qi; /* QI control region */ ++ struct snvs_full __iomem *snvs; /* SNVS HP+LP register space */ ++ dma_addr_t __iomem *sm_base; /* Secure memory storage base */ ++ u32 sm_size; + + /* + * Detected geometry block. Filled in from device tree if powerpc, +@@ -84,14 +92,22 @@ + u8 total_jobrs; /* Total Job Rings in device */ + u8 qi_present; /* Nonzero if QI present in device */ + int secvio_irq; /* Security violation interrupt number */ ++ int rng_inst; /* Total instantiated RNGs */ + + /* which jr allocated to scatterlist crypto */ + atomic_t tfm_count ____cacheline_aligned; ++ int num_jrs_for_algapi; ++ struct device **algapi_jr; + /* list of registered crypto algorithms (mk generic context handle?) */ + struct list_head alg_list; + /* list of registered hash algorithms (mk generic context handle?) */ + struct list_head hash_list; + ++#ifdef CONFIG_ARM ++ struct clk *caam_ipg; ++ struct clk *caam_mem; ++ struct clk *caam_aclk; ++#endif + /* + * debugfs entries for developer view into driver/device + * variables at runtime. +diff -Nur linux-3.10.30/drivers/crypto/caam/jr.c linux-3.10.30-cubox-i/drivers/crypto/caam/jr.c +--- linux-3.10.30/drivers/crypto/caam/jr.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/jr.c 2014-03-08 20:33:30.000000000 +0100 +@@ -2,7 +2,7 @@ + * CAAM/SEC 4.x transport/backend driver + * JobR backend functionality + * +- * Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. + */ + + #include "compat.h" +@@ -58,6 +58,9 @@ + void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg); + u32 *userdesc, userstatus; + void *userarg; ++ dma_addr_t outbusaddr; ++ ++ outbusaddr = rd_reg64(&jrp->rregs->outring_base); + + while (rd_reg32(&jrp->rregs->outring_used)) { + +@@ -67,6 +70,9 @@ + + sw_idx = tail = jrp->tail; + hw_idx = jrp->out_ring_read_index; ++ dma_sync_single_for_cpu(dev, outbusaddr, ++ sizeof(struct jr_outentry) * JOBR_DEPTH, ++ DMA_FROM_DEVICE); + + for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) { + sw_idx = (tail + i) & (JOBR_DEPTH - 1); +@@ -94,6 +100,8 @@ + userdesc = jrp->entinfo[sw_idx].desc_addr_virt; + userstatus = jrp->outring[hw_idx].jrstatus; + ++ smp_mb(); ++ + /* set done */ + wr_reg32(&jrp->rregs->outring_rmvd, 1); + +@@ -227,7 +235,7 @@ + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + struct caam_jrentry_info *head_entry; + int head, tail, desc_size; +- dma_addr_t desc_dma; ++ dma_addr_t desc_dma, inpbusaddr; + + desc_size = (*desc & HDR_JD_LENGTH_MASK) * sizeof(u32); + desc_dma = dma_map_single(dev, desc, desc_size, DMA_TO_DEVICE); +@@ -236,6 +244,13 @@ + return -EIO; + } + ++ dma_sync_single_for_device(dev, desc_dma, desc_size, DMA_TO_DEVICE); ++ ++ inpbusaddr = rd_reg64(&jrp->rregs->inpring_base); ++ dma_sync_single_for_device(dev, inpbusaddr, ++ sizeof(dma_addr_t) * JOBR_DEPTH, ++ DMA_TO_DEVICE); ++ + spin_lock_bh(&jrp->inplock); + + head = jrp->head; +@@ -257,12 +272,18 @@ + + jrp->inpring[jrp->inp_ring_write_index] = desc_dma; + ++ dma_sync_single_for_device(dev, inpbusaddr, ++ sizeof(dma_addr_t) * JOBR_DEPTH, ++ DMA_TO_DEVICE); ++ + smp_wmb(); + + jrp->inp_ring_write_index = (jrp->inp_ring_write_index + 1) & + (JOBR_DEPTH - 1); + jrp->head = (head + 1) & (JOBR_DEPTH - 1); + ++ wmb(); ++ + wr_reg32(&jrp->rregs->inpring_jobadd, 1); + + spin_unlock_bh(&jrp->inplock); +@@ -423,7 +444,8 @@ + struct platform_device *jr_pdev; + struct caam_drv_private *ctrlpriv; + struct caam_drv_private_jr *jrpriv; +- u32 *jroffset; ++ const __be32 *jroffset_addr; ++ u32 jroffset; + int error; + + ctrldev = &pdev->dev; +@@ -445,9 +467,21 @@ + * need to add in the offset to this JobR. Don't know if I + * like this long-term, but it'll run + */ +- jroffset = (u32 *)of_get_property(np, "reg", NULL); ++ jroffset_addr = of_get_property(np, "reg", NULL); ++ ++ if (jroffset_addr == NULL) { ++ kfree(jrpriv); ++ return -EINVAL; ++ } ++ ++ /* ++ * Fix the endianness of this value read from the device ++ * tree if running on ARM. ++ */ ++ jroffset = be32_to_cpup(jroffset_addr); ++ + jrpriv->rregs = (struct caam_job_ring __iomem *)((void *)ctrlpriv->ctrl +- + *jroffset); ++ + jroffset); + + /* Build a local dev for each detected queue */ + jr_pdev = of_platform_device_create(np, NULL, ctrldev); +@@ -471,6 +505,10 @@ + + /* Identify the interrupt */ + jrpriv->irq = of_irq_to_resource(np, 0, NULL); ++ if (jrpriv->irq <= 0) { ++ kfree(jrpriv); ++ return -EINVAL; ++ } + + /* Now do the platform independent part */ + error = caam_jr_init(jrdev); /* now turn on hardware */ +diff -Nur linux-3.10.30/drivers/crypto/caam/jr.h linux-3.10.30-cubox-i/drivers/crypto/caam/jr.h +--- linux-3.10.30/drivers/crypto/caam/jr.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/jr.h 2014-03-08 20:33:30.000000000 +0100 +@@ -1,7 +1,7 @@ + /* + * CAAM public-level include definitions for the JobR backend + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. + */ + + #ifndef JR_H +@@ -18,4 +18,5 @@ + extern int caam_jr_probe(struct platform_device *pdev, struct device_node *np, + int ring); + extern int caam_jr_shutdown(struct device *dev); ++extern struct device *caam_get_jrdev(void); + #endif /* JR_H */ +diff -Nur linux-3.10.30/drivers/crypto/caam/key_gen.c linux-3.10.30-cubox-i/drivers/crypto/caam/key_gen.c +--- linux-3.10.30/drivers/crypto/caam/key_gen.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/key_gen.c 2014-03-08 20:33:30.000000000 +0100 +@@ -1,7 +1,7 @@ + /* + * CAAM/SEC 4.x functions for handling key-generation jobs + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. + * + */ + #include "compat.h" +@@ -68,6 +68,7 @@ + kfree(desc); + return -ENOMEM; + } ++ dma_sync_single_for_device(jrdev, dma_addr_in, keylen, DMA_TO_DEVICE); + append_key(desc, dma_addr_in, keylen, CLASS_2 | KEY_DEST_CLASS_REG); + + /* Sets MDHA up into an HMAC-INIT */ +@@ -115,7 +116,8 @@ + split_key_pad_len, 1); + #endif + } +- ++ dma_sync_single_for_cpu(jrdev, dma_addr_out, split_key_pad_len, ++ DMA_FROM_DEVICE); + dma_unmap_single(jrdev, dma_addr_out, split_key_pad_len, + DMA_FROM_DEVICE); + dma_unmap_single(jrdev, dma_addr_in, keylen, DMA_TO_DEVICE); +diff -Nur linux-3.10.30/drivers/crypto/caam/regs.h linux-3.10.30-cubox-i/drivers/crypto/caam/regs.h +--- linux-3.10.30/drivers/crypto/caam/regs.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/regs.h 2014-03-08 20:33:30.000000000 +0100 +@@ -1,7 +1,7 @@ + /* + * CAAM hardware register-level view + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. + */ + + #ifndef REGS_H +@@ -74,15 +74,21 @@ + #endif + #else + #ifdef __LITTLE_ENDIAN +-#define wr_reg32(reg, data) __raw_writel(reg, data) +-#define rd_reg32(reg) __raw_readl(reg) ++#define wr_reg32(reg, data) writel(data, reg) ++#define rd_reg32(reg) readl(reg) + #ifdef CONFIG_64BIT +-#define wr_reg64(reg, data) __raw_writeq(reg, data) +-#define rd_reg64(reg) __raw_readq(reg) ++#define wr_reg64(reg, data) writeq(data, reg) ++#define rd_reg64(reg) readq(reg) + #endif + #endif + #endif + ++#ifdef CONFIG_ARM ++/* These are common macros for Power, put here for ARMs */ ++#define setbits32(_addr, _v) writel((readl(_addr) | (_v)), (_addr)) ++#define clrbits32(_addr, _v) writel((readl(_addr) & ~(_v)), (_addr)) ++#endif ++ + #ifndef CONFIG_64BIT + static inline void wr_reg64(u64 __iomem *reg, u64 data) + { +@@ -107,6 +113,98 @@ + } __packed; + + /* ++ * CHA version ID / instantiation bitfields ++ * Defined for use within cha_id in perfmon ++ * Note that the same shift/mask selectors can be used to pull out number ++ * of instantiated blocks within cha_num in perfmon, the locations are ++ * the same. ++ */ ++ ++/* Job Ring */ ++#define CHA_ID_JR_SHIFT 60 ++#define CHA_ID_JR_MASK (0xfull << CHA_ID_JR_SHIFT) ++ ++/* DEscriptor COntroller */ ++#define CHA_ID_DECO_SHIFT 56 ++#define CHA_ID_DECO_MASK (0xfull << CHA_ID_DECO_SHIFT) ++#define CHA_NUM_DECONUM_SHIFT 56 /* legacy definition */ ++#define CHA_NUM_DECONUM_MASK (0xfull << CHA_NUM_DECONUM_SHIFT) ++ ++/* ZUC-Authentication */ ++#define CHA_ID_ZA_SHIFT 44 ++#define CHA_ID_ZA_MASK (0xfull << CHA_ID_ZA_SHIFT) ++ ++/* ZUC-Encryption */ ++#define CHA_ID_ZE_SHIFT 40 ++#define CHA_ID_ZE_MASK (0xfull << CHA_ID_ZE_SHIFT) ++ ++/* SNOW f9 */ ++#define CHA_ID_SNW9_SHIFT 36 ++#define CHA_ID_SNW9_MASK (0xfull << CHA_ID_SNW9_SHIFT) ++ ++/* CRC */ ++#define CHA_ID_CRC_SHIFT 32 ++#define CHA_ID_CRC_MASK (0xfull << CHA_ID_CRC_SHIFT) ++ ++/* Public Key */ ++#define CHA_ID_PK_SHIFT 28 ++#define CHA_ID_PK_MASK (0xfull << CHA_ID_PK_SHIFT) ++ ++/* Kasumi */ ++#define CHA_ID_KAS_SHIFT 24 ++#define CHA_ID_KAS_MASK (0xfull << CHA_ID_KAS_SHIFT) ++ ++/* SNOW f8 */ ++#define CHA_ID_SNW8_SHIFT 20 ++#define CHA_ID_SNW8_MASK (0xfull << CHA_ID_SNW8_SHIFT) ++ ++/* ++ * Random Generator ++ * RNG4 = FIPS-verification-compliant, requires init kickstart for use ++ */ ++#define CHA_ID_RNG_SHIFT 16 ++#define CHA_ID_RNG_MASK (0xfull << CHA_ID_RNG_SHIFT) ++#define CHA_ID_RNG_A (0x1ull << CHA_ID_RNG_SHIFT) ++#define CHA_ID_RNG_B (0x2ull << CHA_ID_RNG_SHIFT) ++#define CHA_ID_RNG_C (0x3ull << CHA_ID_RNG_SHIFT) ++#define CHA_ID_RNG_4 (0x4ull << CHA_ID_RNG_SHIFT) ++ ++/* ++ * Message Digest ++ * LP256 = Low Power (MD5/SHA1/SHA224/SHA256 + HMAC) ++ * LP512 = Low Power (LP256 + SHA384/SHA512) ++ * HP = High Power (LP512 + SMAC) ++ */ ++#define CHA_ID_MD_SHIFT 12 ++#define CHA_ID_MD_MASK (0xfull << CHA_ID_MD_SHIFT) ++#define CHA_ID_MD_LP256 (0x0ull << CHA_ID_MD_SHIFT) ++#define CHA_ID_MD_LP512 (0x1ull << CHA_ID_MD_SHIFT) ++#define CHA_ID_MD_HP (0x2ull << CHA_ID_MD_SHIFT) ++ ++/* ARC4 Streamcipher */ ++#define CHA_ID_ARC4_SHIFT 8 ++#define CHA_ID_ARC4_MASK (0xfull << CHA_ID_ARC4_SHIFT) ++#define CHA_ID_ARC4_LP (0x0ull << CHA_ID_ARC4_SHIFT) ++#define CHA_ID_ARC4_HP (0x1ull << CHA_ID_ARC4_SHIFT) ++ ++/* DES Blockcipher Accelerator */ ++#define CHA_ID_DES_SHIFT 4 ++#define CHA_ID_DES_MASK (0xfull << CHA_ID_DES_SHIFT) ++ ++/* ++ * AES Blockcipher + Combo Mode Accelerator ++ * LP = Low Power (includes ECB/CBC/CFB128/OFB/CTR/CCM/CMAC/XCBC-MAC) ++ * HP = High Power (LP + CBCXCBC/CTRXCBC/XTS/GCM) ++ * DIFFPWR = ORed in if differential-power-analysis resistance implemented ++ */ ++#define CHA_ID_AES_SHIFT 0 ++#define CHA_ID_AES_MASK (0xfull << CHA_ID_AES_SHIFT) ++#define CHA_ID_AES_LP (0x3ull << CHA_ID_AES_SHIFT) ++#define CHA_ID_AES_HP (0x4ull << CHA_ID_AES_SHIFT) ++#define CHA_ID_AES_DIFFPWR (0x1ull << CHA_ID_AES_SHIFT) ++ ++ ++/* + * caam_perfmon - Performance Monitor/Secure Memory Status/ + * CAAM Global Status/Component Version IDs + * +@@ -123,6 +221,10 @@ + u8 min_rev; + }; + ++#define SEC_VID_IPID_SHIFT 16 ++#define SEC_VID_MAJ_SHIFT 8 ++#define SEC_VID_MAJ_MASK 0xFF00 ++ + struct caam_perfmon { + /* Performance Monitor Registers f00-f9f */ + u64 req_dequeued; /* PC_REQ_DEQ - Dequeued Requests */ +@@ -139,15 +241,21 @@ + #define CTPR_QI_SHIFT 57 + #define CTPR_QI_MASK (0x1ull << CTPR_QI_SHIFT) + u64 comp_parms; /* CTPR - Compile Parameters Register */ +- u64 rsvd1[2]; ++ ++ /* Secure Memory State Visibility */ ++ u32 rsvd1; ++ u32 smstatus; /* Secure memory status */ ++ u32 rsvd2; ++ u32 smpartown; /* Secure memory partition owner */ + + /* CAAM Global Status fc0-fdf */ + u64 faultaddr; /* FAR - Fault Address */ + u32 faultliodn; /* FALR - Fault Address LIODN */ + u32 faultdetail; /* FADR - Fault Addr Detail */ +- u32 rsvd2; ++ u32 rsvd3; + u32 status; /* CSTA - CAAM Status */ +- u64 rsvd3; ++ u32 smpart; /* Secure Memory Partition Parameters */ ++ u32 smvid; /* Secure Memory Version ID */ + + /* Component Instantiation Parameters fe0-fff */ + u32 rtic_id; /* RVID - RTIC Version ID */ +@@ -157,6 +265,62 @@ + u64 caam_id; /* CAAMVID - CAAM Version ID */ + }; + ++#define SMSTATUS_PART_SHIFT 28 ++#define SMSTATUS_PART_MASK (0xf << SMSTATUS_PART_SHIFT) ++#define SMSTATUS_PAGE_SHIFT 16 ++#define SMSTATUS_PAGE_MASK (0x7ff << SMSTATUS_PAGE_SHIFT) ++#define SMSTATUS_MID_SHIFT 8 ++#define SMSTATUS_MID_MASK (0x3f << SMSTATUS_MID_SHIFT) ++#define SMSTATUS_ACCERR_SHIFT 4 ++#define SMSTATUS_ACCERR_MASK (0xf << SMSTATUS_ACCERR_SHIFT) ++#define SMSTATUS_ACCERR_NONE 0 ++#define SMSTATUS_ACCERR_ALLOC 1 /* Page not allocated */ ++#define SMSTATUS_ACCESS_ID 2 /* Not granted by ID */ ++#define SMSTATUS_ACCESS_WRITE 3 /* Writes not allowed */ ++#define SMSTATUS_ACCESS_READ 4 /* Reads not allowed */ ++#define SMSTATUS_ACCESS_NONKEY 6 /* Non-key reads not allowed */ ++#define SMSTATUS_ACCESS_BLOB 9 /* Blob access not allowed */ ++#define SMSTATUS_ACCESS_DESCB 10 /* Descriptor Blob access spans pages */ ++#define SMSTATUS_ACCESS_NON_SM 11 /* Outside Secure Memory range */ ++#define SMSTATUS_ACCESS_XPAGE 12 /* Access crosses pages */ ++#define SMSTATUS_ACCESS_INITPG 13 /* Page still initializing */ ++#define SMSTATUS_STATE_SHIFT 0 ++#define SMSTATUS_STATE_MASK (0xf << SMSTATUS_STATE_SHIFT) ++#define SMSTATUS_STATE_RESET 0 ++#define SMSTATUS_STATE_INIT 1 ++#define SMSTATUS_STATE_NORMAL 2 ++#define SMSTATUS_STATE_FAIL 3 ++ ++/* up to 15 rings, 2 bits shifted by ring number */ ++#define SMPARTOWN_RING_SHIFT 2 ++#define SMPARTOWN_RING_MASK 3 ++#define SMPARTOWN_AVAILABLE 0 ++#define SMPARTOWN_NOEXIST 1 ++#define SMPARTOWN_UNAVAILABLE 2 ++#define SMPARTOWN_OURS 3 ++ ++/* Maximum number of pages possible */ ++#define SMPART_MAX_NUMPG_SHIFT 16 ++#define SMPART_MAX_NUMPG_MASK (0x3f << SMPART_MAX_NUMPG_SHIFT) ++ ++/* Maximum partition number */ ++#define SMPART_MAX_PNUM_SHIFT 12 ++#define SMPART_MAX_PNUM_MASK (0xf << SMPART_MAX_PNUM_SHIFT) ++ ++/* Highest possible page number */ ++#define SMPART_MAX_PG_SHIFT 0 ++#define SMPART_MAX_PG_MASK (0x3f << SMPART_MAX_PG_SHIFT) ++ ++/* Max size of a page */ ++#define SMVID_PG_SIZE_SHIFT 16 ++#define SMVID_PG_SIZE_MASK (0x7 << SMVID_PG_SIZE_SHIFT) ++ ++/* Major/Minor Version ID */ ++#define SMVID_MAJ_VERS_SHIFT 8 ++#define SMVID_MAJ_VERS (0xf << SMVID_MAJ_VERS_SHIFT) ++#define SMVID_MIN_VERS_SHIFT 0 ++#define SMVID_MIN_VERS (0xf << SMVID_MIN_VERS_SHIFT) ++ + /* LIODN programming for DMA configuration */ + #define MSTRID_LOCK_LIODN 0x80000000 + #define MSTRID_LOCK_MAKETRUSTED 0x00010000 /* only for JR masterid */ +@@ -228,7 +392,13 @@ + u32 rtfrqmax; /* PRGM=1: freq. count max. limit register */ + u32 rtfrqcnt; /* PRGM=0: freq. count register */ + }; +- u32 rsvd1[56]; ++ u32 rsvd1[40]; ++#define RDSTA_IF 0x00000003 /* state handle instantiated flags 0 and 1 */ ++#define RDSTA_SKVN 0x40000000 /* Secure Key Valid Non-Test mode */ ++#define RDSTA_SKVT 0x80000000 /* Secure Key Valid Test. non-test mode */ ++#define RDSTA_TF 0x00000300 /* State handle instantiated Test-mode */ ++ u32 rdsta; /* DRNG status register */ ++ u32 rsvd2[15]; + }; + + /* +@@ -359,7 +529,18 @@ + u32 rsvd11; + u32 jrcommand; /* JRCRx - JobR command */ + +- u32 rsvd12[932]; ++ u32 rsvd12[33]; ++ ++ /* Secure Memory Configuration - if you have it */ ++ u32 sm_cmd; /* SMCJRx - Secure memory command */ ++ u32 rsvd13; ++ u32 sm_status; /* SMCSJRx - Secure memory status */ ++ u32 rsvd14; ++ u32 sm_perm; /* SMAPJRx - Secure memory access perms */ ++ u32 sm_group2; /* SMAP2JRx - Secure memory access group 2 */ ++ u32 sm_group1; /* SMAP1JRx - Secure memory access group 1 */ ++ ++ u32 rsvd15[891]; + + /* Performance Monitor f00-fff */ + struct caam_perfmon perfmon; +@@ -482,6 +663,62 @@ + + #define JRCR_RESET 0x01 + ++/* secure memory command */ ++#define SMC_PAGE_SHIFT 16 ++#define SMC_PAGE_MASK (0xffff << SMC_PAGE_SHIFT) ++#define SMC_PART_SHIFT 8 ++#define SMC_PART_MASK (0x0f << SMC_PART_SHIFT) ++#define SMC_CMD_SHIFT 0 ++#define SMC_CMD_MASK (0x0f << SMC_CMD_SHIFT) ++ ++#define SMC_CMD_ALLOC_PAGE 0x01 /* allocate page to this partition */ ++#define SMC_CMD_DEALLOC_PAGE 0x02 /* deallocate page from partition */ ++#define SMC_CMD_DEALLOC_PART 0x03 /* deallocate partition */ ++#define SMC_CMD_PAGE_INQUIRY 0x05 /* find partition associate with page */ ++ ++/* secure memory (command) status */ ++#define SMCS_PAGE_SHIFT 16 ++#define SMCS_PAGE_MASK (0x0fff << SMCS_PAGE_SHIFT) ++#define SMCS_CMDERR_SHIFT 14 ++#define SMCS_CMDERR_MASK (3 << SMCS_CMDERR_SHIFT) ++#define SMCS_ALCERR_SHIFT 12 ++#define SMCS_ALCERR_MASK (3 << SMCS_ALCERR_SHIFT) ++#define SMCS_PGOWN_SHIFT 6 ++#define SMCS_PGWON_MASK (3 << SMCS_PGOWN_SHIFT) ++#define SMCS_PART_SHIFT 0 ++#define SMCS_PART_MASK (0xf << SMCS_PART_SHIFT) ++ ++#define SMCS_CMDERR_NONE 0 ++#define SMCS_CMDERR_INCOMP 1 /* Command not yet complete */ ++#define SMCS_CMDERR_SECFAIL 2 /* Security failure occurred */ ++#define SMCS_CMDERR_OVERFLOW 3 /* Command overflow */ ++ ++#define SMCS_ALCERR_NONE 0 ++#define SMCS_ALCERR_PSPERR 1 /* Partion marked PSP (dealloc only) */ ++#define SMCS_ALCERR_PAGEAVAIL 2 /* Page not available */ ++#define SMCS_ALCERR_PARTOWN 3 /* Partition ownership error */ ++ ++#define SMCS_PGOWN_AVAIL 0 /* Page is available */ ++#define SMCS_PGOWN_NOEXIST 1 /* Page initializing or nonexistent */ ++#define SMCS_PGOWN_NOOWN 2 /* Page owned by another processor */ ++#define SMCS_PGOWN_OWNED 3 /* Page belongs to this processor */ ++ ++/* secure memory access permissions */ ++#define SMCS_PERM_KEYMOD_SHIFT 16 ++#define SMCA_PERM_KEYMOD_MASK (0xff << SMCS_PERM_KEYMOD_SHIFT) ++#define SMCA_PERM_CSP_ZERO 0x8000 /* Zero when deallocated or released */ ++#define SMCA_PERM_PSP_LOCK 0x4000 /* Part./pages can't be deallocated */ ++#define SMCA_PERM_PERM_LOCK 0x2000 /* Lock permissions */ ++#define SMCA_PERM_GRP_LOCK 0x1000 /* Lock access groups */ ++#define SMCA_PERM_RINGID_SHIFT 10 ++#define SMCA_PERM_RINGID_MASK (3 << SMCA_PERM_RINGID_SHIFT) ++#define SMCA_PERM_G2_BLOB 0x0080 /* Group 2 blob import/export */ ++#define SMCA_PERM_G2_WRITE 0x0020 /* Group 2 write */ ++#define SMCA_PERM_G2_READ 0x0010 /* Group 2 read */ ++#define SMCA_PERM_G1_BLOB 0x0008 /* Group 1... */ ++#define SMCA_PERM_G1_WRITE 0x0002 ++#define SMCA_PERM_G1_READ 0x0001 ++ + /* + * caam_assurance - Assurance Controller View + * base + 0x6000 padded out to 0x1000 +diff -Nur linux-3.10.30/drivers/crypto/caam/secvio.c linux-3.10.30-cubox-i/drivers/crypto/caam/secvio.c +--- linux-3.10.30/drivers/crypto/caam/secvio.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/secvio.c 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,333 @@ ++ ++/* ++ * CAAM/SEC 4.x Security Violation Handler ++ * Copyright (C) 2013 Freescale Semiconductor, Inc., All Rights Reserved ++ */ ++ ++#include "compat.h" ++#include "intern.h" ++#include "secvio.h" ++#include "regs.h" ++ ++/* ++ * These names are associated with each violation handler. ++ * The source names were taken from MX6, and are based on recommendations ++ * for most common SoCs. ++ */ ++static const u8 *violation_src_name[] = { ++ "CAAM Security Violation", ++ "JTAG Alarm", ++ "Watchdog", ++ "(reserved)", ++ "External Boot", ++ "Tamper Detect", ++}; ++ ++/* Top-level security violation interrupt */ ++static irqreturn_t caam_secvio_interrupt(int irq, void *snvsdev) ++{ ++ struct device *dev = snvsdev; ++ struct caam_drv_private_secvio *svpriv = dev_get_drvdata(dev); ++ u32 irqstate; ++ ++ /* Check the HP secvio status register */ ++ irqstate = rd_reg32(&svpriv->svregs->hp.secvio_status) | ++ HP_SECVIOST_SECVIOMASK; ++ ++ if (!irqstate) ++ return IRQ_NONE; ++ ++ /* Mask out one or more causes for deferred service */ ++ clrbits32(&svpriv->svregs->hp.secvio_int_ctl, irqstate); ++ ++ /* Now ACK causes */ ++ setbits32(&svpriv->svregs->hp.secvio_status, irqstate); ++ ++ /* And run deferred service */ ++ preempt_disable(); ++ tasklet_schedule(&svpriv->irqtask[smp_processor_id()]); ++ preempt_enable(); ++ ++ return IRQ_HANDLED; ++} ++ ++/* Deferred service handler. Tasklet arg is simply the SNVS dev */ ++static void caam_secvio_dispatch(unsigned long indev) ++{ ++ struct device *dev = (struct device *)indev; ++ struct caam_drv_private_secvio *svpriv = dev_get_drvdata(dev); ++ unsigned long flags, cause; ++ int i; ++ ++ ++ /* ++ * Capture the interrupt cause, using masked interrupts as ++ * identification. This only works if all are enabled; if ++ * this changes in the future, a "cause queue" will have to ++ * be built ++ */ ++ cause = rd_reg32(&svpriv->svregs->hp.secvio_int_ctl) & ++ (HP_SECVIO_INTEN_SRC5 | HP_SECVIO_INTEN_SRC4 | ++ HP_SECVIO_INTEN_SRC3 | HP_SECVIO_INTEN_SRC2 | ++ HP_SECVIO_INTEN_SRC1 | HP_SECVIO_INTEN_SRC0); ++ ++ /* Look through causes, call each handler if exists */ ++ for (i = 0; i < MAX_SECVIO_SOURCES; i++) ++ if (cause & (1 << i)) { ++ spin_lock_irqsave(&svpriv->svlock, flags); ++ svpriv->intsrc[i].handler(dev, i, ++ svpriv->intsrc[i].ext); ++ spin_unlock_irqrestore(&svpriv->svlock, flags); ++ }; ++ ++ /* Re-enable now-serviced interrupts */ ++ setbits32(&svpriv->svregs->hp.secvio_int_ctl, cause); ++} ++ ++/* ++ * Default cause handler, used in lieu of an application-defined handler. ++ * All it does at this time is print a console message. It could force a halt. ++ */ ++static void caam_secvio_default(struct device *dev, u32 cause, void *ext) ++{ ++ struct caam_drv_private_secvio *svpriv = dev_get_drvdata(dev); ++ ++ dev_err(dev, "Unhandled Security Violation Interrupt %d = %s\n", ++ cause, svpriv->intsrc[cause].intname); ++} ++ ++/* ++ * Install an application-defined handler for a specified cause ++ * Arguments: ++ * - dev points to SNVS-owning device ++ * - cause interrupt source cause ++ * - handler application-defined handler, gets called with dev ++ * source cause, and locally-defined handler argument ++ * - cause_description points to a string to override the default cause ++ * name, this can be used as an alternate for error ++ * messages and such. If left NULL, the default ++ * description string is used. ++ * - ext pointer to any extra data needed by the handler. ++ */ ++int caam_secvio_install_handler(struct device *dev, enum secvio_cause cause, ++ void (*handler)(struct device *dev, u32 cause, ++ void *ext), ++ u8 *cause_description, void *ext) ++{ ++ unsigned long flags; ++ struct caam_drv_private_secvio *svpriv; ++ ++ svpriv = dev_get_drvdata(dev); ++ ++ if ((handler == NULL) || (cause > SECVIO_CAUSE_SOURCE_5)) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&svpriv->svlock, flags); ++ svpriv->intsrc[cause].handler = handler; ++ if (cause_description != NULL) ++ svpriv->intsrc[cause].intname = cause_description; ++ if (ext != NULL) ++ svpriv->intsrc[cause].ext = ext; ++ spin_unlock_irqrestore(&svpriv->svlock, flags); ++ ++ return 0; ++} ++EXPORT_SYMBOL(caam_secvio_install_handler); ++ ++/* ++ * Remove an application-defined handler for a specified cause (and, by ++ * implication, restore the "default". ++ * Arguments: ++ * - dev points to SNVS-owning device ++ * - cause interrupt source cause ++ */ ++int caam_secvio_remove_handler(struct device *dev, enum secvio_cause cause) ++{ ++ unsigned long flags; ++ struct caam_drv_private_secvio *svpriv; ++ ++ svpriv = dev_get_drvdata(dev); ++ ++ if (cause > SECVIO_CAUSE_SOURCE_5) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&svpriv->svlock, flags); ++ svpriv->intsrc[cause].intname = violation_src_name[cause]; ++ svpriv->intsrc[cause].handler = caam_secvio_default; ++ svpriv->intsrc[cause].ext = NULL; ++ spin_unlock_irqrestore(&svpriv->svlock, flags); ++ return 0; ++} ++EXPORT_SYMBOL(caam_secvio_remove_handler); ++ ++int caam_secvio_startup(struct platform_device *pdev) ++{ ++ struct device *ctrldev, *svdev; ++ struct caam_drv_private *ctrlpriv; ++ struct caam_drv_private_secvio *svpriv; ++ struct platform_device *svpdev; ++ struct device_node *np; ++ const void *prop; ++ int i, error, secvio_inten_src; ++ ++ ctrldev = &pdev->dev; ++ ctrlpriv = dev_get_drvdata(ctrldev); ++ /* ++ * Set up the private block for secure memory ++ * Only one instance is possible ++ */ ++ svpriv = kzalloc(sizeof(struct caam_drv_private_secvio), GFP_KERNEL); ++ if (svpriv == NULL) { ++ dev_err(ctrldev, "can't alloc private mem for secvio\n"); ++ return -ENOMEM; ++ } ++ svpriv->parentdev = ctrldev; ++ ++ /* Create the security violation dev */ ++#ifdef CONFIG_OF ++ ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-secvio"); ++ if (!np) ++ return -ENODEV; ++ ++ ctrlpriv->secvio_irq = of_irq_to_resource(np, 0, NULL); ++ ++ prop = of_get_property(np, "secvio_src", NULL); ++ if (prop) ++ secvio_inten_src = of_read_ulong(prop, 1); ++ else ++ secvio_inten_src = HP_SECVIO_INTEN_ALL; ++ ++ svpdev = of_platform_device_create(np, NULL, ctrldev); ++ if (!svpdev) ++ return -ENODEV; ++ ++#else ++ svpdev = platform_device_register_data(ctrldev, "caam_secvio", 0, ++ svpriv, ++ sizeof(struct caam_drv_private_secvio)); ++ ++ secvio_inten_src = HP_SECVIO_INTEN_ALL; ++#endif ++ if (svpdev == NULL) { ++ kfree(svpriv); ++ return -EINVAL; ++ } ++ svdev = &svpdev->dev; ++ dev_set_drvdata(svdev, svpriv); ++ ctrlpriv->secviodev = svdev; ++ svpriv->svregs = ctrlpriv->snvs; ++ ++ /* ++ * Now we have all the dev data set up. Init interrupt ++ * source descriptions ++ */ ++ for (i = 0; i < MAX_SECVIO_SOURCES; i++) { ++ svpriv->intsrc[i].intname = violation_src_name[i]; ++ svpriv->intsrc[i].handler = caam_secvio_default; ++ } ++ ++ /* Connect main handler */ ++ for_each_possible_cpu(i) ++ tasklet_init(&svpriv->irqtask[i], caam_secvio_dispatch, ++ (unsigned long)svdev); ++ ++ error = request_irq(ctrlpriv->secvio_irq, caam_secvio_interrupt, ++ IRQF_SHARED, "caam_secvio", svdev); ++ if (error) { ++ dev_err(svdev, "can't connect secvio interrupt\n"); ++ irq_dispose_mapping(ctrlpriv->secvio_irq); ++ ctrlpriv->secvio_irq = 0; ++ return -EINVAL; ++ } ++ ++ /* Enable all sources */ ++ wr_reg32(&svpriv->svregs->hp.secvio_int_ctl, secvio_inten_src); ++ ++ dev_info(svdev, "security violation service handlers armed\n"); ++ ++ return 0; ++} ++ ++void caam_secvio_shutdown(struct platform_device *pdev) ++{ ++ struct device *ctrldev, *svdev; ++ struct caam_drv_private *priv; ++ struct caam_drv_private_secvio *svpriv; ++ int i; ++ ++ ctrldev = &pdev->dev; ++ priv = dev_get_drvdata(ctrldev); ++ svdev = priv->secviodev; ++ svpriv = dev_get_drvdata(svdev); ++ ++ /* Shut off all sources */ ++ ++ wr_reg32(&svpriv->svregs->hp.secvio_int_ctl, 0); ++ ++ /* Remove tasklets and release interrupt */ ++ for_each_possible_cpu(i) ++ tasklet_kill(&svpriv->irqtask[i]); ++ ++ free_irq(priv->secvio_irq, svdev); ++ ++ kfree(svpriv); ++} ++ ++ ++#ifdef CONFIG_OF ++static void __exit caam_secvio_exit(void) ++{ ++ struct device_node *dev_node; ++ struct platform_device *pdev; ++ ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); ++ if (!dev_node) { ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); ++ if (!dev_node) ++ return; ++ } ++ ++ pdev = of_find_device_by_node(dev_node); ++ if (!pdev) ++ return; ++ ++ of_node_get(dev_node); ++ ++ caam_secvio_shutdown(pdev); ++ ++} ++ ++static int __init caam_secvio_init(void) ++{ ++ struct device_node *dev_node; ++ struct platform_device *pdev; ++ ++ /* ++ * Do of_find_compatible_node() then of_find_device_by_node() ++ * once a functional device tree is available ++ */ ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); ++ if (!dev_node) { ++ dev_node = of_find_compatible_node(NULL, NULL, ++ "arm,imx6-caam-secvio"); ++ if (!dev_node) ++ return -ENODEV; ++ } ++ ++ pdev = of_find_device_by_node(dev_node); ++ if (!pdev) ++ return -ENODEV; ++ ++ of_node_put(dev_node); ++ ++ return caam_secvio_startup(pdev); ++} ++ ++module_init(caam_secvio_init); ++module_exit(caam_secvio_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("FSL CAAM/SNVS Security Violation Handler"); ++MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD"); ++#endif +diff -Nur linux-3.10.30/drivers/crypto/caam/secvio.h linux-3.10.30-cubox-i/drivers/crypto/caam/secvio.h +--- linux-3.10.30/drivers/crypto/caam/secvio.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/secvio.h 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,64 @@ ++ ++/* ++ * CAAM Security Violation Handler ++ * Copyright (C) 2013 Freescale Semiconductor, Inc., All Rights Reserved ++ */ ++ ++#ifndef SECVIO_H ++#define SECVIO_H ++ ++#include "snvsregs.h" ++ ++ ++/* ++ * Defines the published interfaces to install/remove application-specified ++ * handlers for catching violations ++ */ ++ ++#define MAX_SECVIO_SOURCES 6 ++ ++/* these are the untranslated causes */ ++enum secvio_cause { ++ SECVIO_CAUSE_SOURCE_0, ++ SECVIO_CAUSE_SOURCE_1, ++ SECVIO_CAUSE_SOURCE_2, ++ SECVIO_CAUSE_SOURCE_3, ++ SECVIO_CAUSE_SOURCE_4, ++ SECVIO_CAUSE_SOURCE_5 ++}; ++ ++/* These are common "recommended" cause definitions for most devices */ ++#define SECVIO_CAUSE_CAAM_VIOLATION SECVIO_CAUSE_SOURCE_0 ++#define SECVIO_CAUSE JTAG_ALARM SECVIO_CAUSE_SOURCE_1 ++#define SECVIO_CAUSE_WATCHDOG SECVIO_CAUSE_SOURCE_2 ++#define SECVIO_CAUSE_EXTERNAL_BOOT SECVIO_CAUSE_SOURCE_4 ++#define SECVIO_CAUSE_TAMPER_DETECT SECVIO_CAUSE_SOURCE_5 ++ ++int caam_secvio_install_handler(struct device *dev, enum secvio_cause cause, ++ void (*handler)(struct device *dev, u32 cause, ++ void *ext), ++ u8 *cause_description, void *ext); ++int caam_secvio_remove_handler(struct device *dev, enum secvio_cause cause); ++ ++/* ++ * Private data definitions for the secvio "driver" ++ */ ++ ++struct secvio_int_src { ++ const u8 *intname; /* Points to a descriptive name for source */ ++ void *ext; /* Extended data to pass to the handler */ ++ void (*handler)(struct device *dev, u32 cause, void *ext); ++}; ++ ++struct caam_drv_private_secvio { ++ struct device *parentdev; /* points back to the controller */ ++ spinlock_t svlock ____cacheline_aligned; ++ struct tasklet_struct irqtask[NR_CPUS]; ++ struct snvs_full __iomem *svregs; /* both HP and LP domains */ ++ ++ /* Registered handlers for each violation */ ++ struct secvio_int_src intsrc[MAX_SECVIO_SOURCES]; ++ ++}; ++ ++#endif /* SECVIO_H */ +diff -Nur linux-3.10.30/drivers/crypto/caam/sg_sw_sec4.h linux-3.10.30-cubox-i/drivers/crypto/caam/sg_sw_sec4.h +--- linux-3.10.30/drivers/crypto/caam/sg_sw_sec4.h 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/sg_sw_sec4.h 2014-03-08 20:33:30.000000000 +0100 +@@ -1,7 +1,7 @@ + /* + * CAAM/SEC 4.x functions for using scatterlists in caam driver + * +- * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. + * + */ + +@@ -91,13 +91,22 @@ + { + if (unlikely(chained)) { + int i; ++ struct scatterlist *tsg = sg; ++ ++ /* We use a local copy of the sg pointer to avoid moving the ++ * head of the list pointed to by sg as we wall the list. ++ */ + for (i = 0; i < nents; i++) { +- dma_map_sg(dev, sg, 1, dir); +- sg = scatterwalk_sg_next(sg); ++ dma_map_sg(dev, tsg, 1, dir); ++ tsg = scatterwalk_sg_next(tsg); + } + } else { + dma_map_sg(dev, sg, nents, dir); + } ++ ++ if ((dir == DMA_TO_DEVICE) || (dir == DMA_BIDIRECTIONAL)) ++ dma_sync_sg_for_device(dev, sg, nents, dir); ++ + return nents; + } + +@@ -105,6 +114,9 @@ + unsigned int nents, enum dma_data_direction dir, + bool chained) + { ++ if ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)) ++ dma_sync_sg_for_cpu(dev, sg, nents, dir); ++ + if (unlikely(chained)) { + int i; + for (i = 0; i < nents; i++) { +diff -Nur linux-3.10.30/drivers/crypto/caam/sm.h linux-3.10.30-cubox-i/drivers/crypto/caam/sm.h +--- linux-3.10.30/drivers/crypto/caam/sm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/sm.h 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,88 @@ ++ ++/* ++ * CAAM Secure Memory/Keywrap API Definitions ++ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. ++ */ ++ ++#ifndef SM_H ++#define SM_H ++ ++ ++/* Storage access permissions */ ++#define SM_PERM_READ 0x01 ++#define SM_PERM_WRITE 0x02 ++#define SM_PERM_BLOB 0x03 ++ ++ ++/* Keystore maintenance functions */ ++void sm_init_keystore(struct device *dev); ++u32 sm_detect_keystore_units(struct device *dev); ++int sm_establish_keystore(struct device *dev, u32 unit); ++void sm_release_keystore(struct device *dev, u32 unit); ++void caam_sm_shutdown(struct platform_device *pdev); ++int caam_sm_example_init(struct platform_device *pdev); ++ ++/* Keystore accessor functions */ ++extern int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size, ++ u32 *slot); ++extern int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot); ++extern int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot, ++ const u8 *key_data, u32 key_length); ++extern int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot, ++ u32 key_length, u8 *key_data); ++extern int sm_keystore_slot_encapsulate(struct device *dev, u32 unit, ++ u32 inslot, u32 outslot, u16 secretlen, ++ u8 *keymod, u16 keymodlen); ++extern int sm_keystore_slot_decapsulate(struct device *dev, u32 unit, ++ u32 inslot, u32 outslot, u16 secretlen, ++ u8 *keymod, u16 keymodlen); ++ ++/* Data structure to hold per-slot information */ ++struct keystore_data_slot_info { ++ u8 allocated; /* Track slot assignments */ ++ u32 key_length; /* Size of the key */ ++}; ++ ++/* Data structure to hold keystore information */ ++struct keystore_data { ++ void *base_address; /* Base of the Secure Partition */ ++ u32 slot_count; /* Number of slots in the keystore */ ++ struct keystore_data_slot_info *slot; /* Per-slot information */ ++}; ++ ++/* store the detected attributes of a secure memory page */ ++struct sm_page_descriptor { ++ u16 phys_pagenum; /* may be discontiguous */ ++ u16 own_part; /* Owning partition */ ++ void *pg_base; /* Calculated virtual address */ ++ struct keystore_data *ksdata; ++}; ++ ++struct caam_drv_private_sm { ++ struct device *parentdev; /* this ends up as the controller */ ++ struct device *smringdev; /* ring that owns this instance */ ++ spinlock_t kslock ____cacheline_aligned; ++ ++ /* Default parameters for geometry */ ++ u32 max_pages; /* maximum pages this instance can support */ ++ u32 top_partition; /* highest partition number in this instance */ ++ u32 top_page; /* highest page number in this instance */ ++ u32 page_size; /* page size */ ++ u32 slot_size; /* selected size of each storage block */ ++ ++ /* Partition/Page Allocation Map */ ++ u32 localpages; /* Number of pages we can access */ ++ struct sm_page_descriptor *pagedesc; /* Allocated per-page */ ++ ++ /* Installed handlers for keystore access */ ++ int (*data_init)(struct device *dev, u32 unit); ++ void (*data_cleanup)(struct device *dev, u32 unit); ++ int (*slot_alloc)(struct device *dev, u32 unit, u32 size, u32 *slot); ++ int (*slot_dealloc)(struct device *dev, u32 unit, u32 slot); ++ void *(*slot_get_address)(struct device *dev, u32 unit, u32 handle); ++ u32 (*slot_get_base)(struct device *dev, u32 unit, u32 handle); ++ u32 (*slot_get_offset)(struct device *dev, u32 unit, u32 handle); ++ u32 (*slot_get_slot_size)(struct device *dev, u32 unit, u32 handle); ++}; ++ ++#endif /* SM_H */ +diff -Nur linux-3.10.30/drivers/crypto/caam/sm_store.c linux-3.10.30-cubox-i/drivers/crypto/caam/sm_store.c +--- linux-3.10.30/drivers/crypto/caam/sm_store.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/sm_store.c 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,896 @@ ++ ++/* ++ * CAAM Secure Memory Storage Interface ++ * Copyright (C) 2008-2013 Freescale Semiconductor, Inc. ++ * ++ * Loosely based on the SHW Keystore API for SCC/SCC2 ++ * Experimental implementation and NOT intended for upstream use. Expect ++ * this interface to be amended significantly in the future once it becomes ++ * integrated into live applications. ++ * ++ * Known issues: ++ * ++ * - Executes one instance of an secure memory "driver". This is tied to the ++ * fact that job rings can't run as standalone instances in the present ++ * configuration. ++ * ++ * - It does not expose a userspace interface. The value of a userspace ++ * interface for access to secrets is a point for further architectural ++ * discussion. ++ * ++ * - Partition/permission management is not part of this interface. It ++ * depends on some level of "knowledge" agreed upon between bootloader, ++ * provisioning applications, and OS-hosted software (which uses this ++ * driver). ++ * ++ * - No means of identifying the location or purpose of secrets managed by ++ * this interface exists; "slot location" and format of a given secret ++ * needs to be agreed upon between bootloader, provisioner, and OS-hosted ++ * application. ++ */ ++ ++#include "compat.h" ++#include "regs.h" ++#include "jr.h" ++#include "desc.h" ++#include "intern.h" ++#include "error.h" ++#include "sm.h" ++ ++#ifdef SM_DEBUG_CONT ++void sm_show_page(struct device *dev, struct sm_page_descriptor *pgdesc) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ u32 i, *smdata; ++ ++ dev_info(dev, "physical page %d content at 0x%08x\n", ++ pgdesc->phys_pagenum, pgdesc->pg_base); ++ smdata = pgdesc->pg_base; ++ for (i = 0; i < (smpriv->page_size / sizeof(u32)); i += 4) ++ dev_info(dev, "[0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ (u32)&smdata[i], smdata[i], smdata[i+1], smdata[i+2], ++ smdata[i+3]); ++} ++#endif ++ ++/* ++ * Construct a secure memory blob encapsulation job descriptor ++ * ++ * - desc pointer to hold new (to be allocated) pointer to the generated ++ * descriptor for later use. Calling thread can kfree the ++ * descriptor after execution. ++ * - keymod Physical pointer to key modifier (contiguous piece). ++ * - keymodsz Size of key modifier in bytes (should normally be 8). ++ * - secretbuf Physical pointer (within an accessible secure memory page) ++ * of the secret to be encapsulated. ++ * - outbuf Physical pointer (within an accessible secure memory page) ++ * of the encapsulated output. This will be larger than the ++ * input secret because of the added encapsulation data. ++ * - secretsz Size of input secret, in bytes. ++ * - auth If nonzero, use AES-CCM for encapsulation, else use ECB ++ * ++ * Note: this uses 32-bit pointers at present ++ */ ++#define INITIAL_DESCSZ 16 /* size of tmp buffer for descriptor const. */ ++static int blob_encap_desc(u32 **desc, dma_addr_t keymod, u16 keymodsz, ++ dma_addr_t secretbuf, dma_addr_t outbuf, ++ u16 secretsz, bool auth) ++{ ++ u32 *tdesc, tmpdesc[INITIAL_DESCSZ]; ++ u16 dsize, idx; ++ ++ memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32)); ++ idx = 1; ++ ++ /* Load key modifier */ ++ tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY | ++ ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK) | ++ (keymodsz & LDST_LEN_MASK); ++ ++ tmpdesc[idx++] = (u32)keymod; ++ ++ /* Encapsulate to secure memory */ ++ tmpdesc[idx++] = CMD_SEQ_IN_PTR | secretsz; ++ tmpdesc[idx++] = (u32)secretbuf; ++ ++ /* Add space for BKEK and MAC tag */ ++ tmpdesc[idx++] = CMD_SEQ_IN_PTR | (secretsz + (32 + 16)); ++ ++ tmpdesc[idx++] = (u32)outbuf; ++ tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB | ++ OP_PCL_BLOB_PTXT_SECMEM; ++ if (auth) ++ tmpdesc[idx] |= OP_PCL_BLOB_EKT; ++ ++ idx++; ++ tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK); ++ dsize = idx * sizeof(u32); ++ ++ tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA); ++ if (tdesc == NULL) ++ return 0; ++ ++ memcpy(tdesc, tmpdesc, dsize); ++ *desc = tdesc; ++ return dsize; ++} ++ ++/* ++ * Construct a secure memory blob decapsulation job descriptor ++ * ++ * - desc pointer to hold new (to be allocated) pointer to the generated ++ * descriptor for later use. Calling thread can kfree the ++ * descriptor after execution. ++ * - keymod Physical pointer to key modifier (contiguous piece). ++ * - keymodsz Size of key modifier in bytes (should normally be 16). ++ * - blobbuf Physical pointer (within an accessible secure memory page) ++ * of the blob to be decapsulated. ++ * - outbuf Physical pointer (within an accessible secure memory page) ++ * of the decapsulated output. ++ * - secretsz Size of input blob, in bytes. ++ * - auth If nonzero, assume AES-CCM for decapsulation, else use ECB ++ * ++ * Note: this uses 32-bit pointers at present ++ */ ++static int blob_decap_desc(u32 **desc, dma_addr_t keymod, u16 keymodsz, ++ dma_addr_t blobbuf, dma_addr_t outbuf, ++ u16 blobsz, bool auth) ++{ ++ u32 *tdesc, tmpdesc[INITIAL_DESCSZ]; ++ u16 dsize, idx; ++ ++ memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32)); ++ idx = 1; ++ ++ /* Load key modifier */ ++ tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY | ++ ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK) | ++ (keymodsz & LDST_LEN_MASK); ++ ++ tmpdesc[idx++] = (u32)keymod; ++ ++ /* Compensate BKEK + MAC tag */ ++ tmpdesc[idx++] = CMD_SEQ_IN_PTR | (blobsz + 32 + 16); ++ ++ tmpdesc[idx++] = (u32)blobbuf; ++ tmpdesc[idx++] = CMD_SEQ_OUT_PTR | blobsz; ++ tmpdesc[idx++] = (u32)outbuf; ++ ++ /* Decapsulate from secure memory partition to black blob */ ++ tmpdesc[idx] = CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB | ++ OP_PCL_BLOB_PTXT_SECMEM | OP_PCL_BLOB_BLACK; ++ if (auth) ++ tmpdesc[idx] |= OP_PCL_BLOB_EKT; ++ ++ idx++; ++ tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK); ++ dsize = idx * sizeof(u32); ++ ++ tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA); ++ if (tdesc == NULL) ++ return 0; ++ ++ memcpy(tdesc, tmpdesc, dsize); ++ *desc = tdesc; ++ return dsize; ++} ++ ++/* ++ * Pseudo-synchronous ring access functions for carrying out key ++ * encapsulation and decapsulation ++ */ ++ ++struct sm_key_job_result { ++ int error; ++ struct completion completion; ++}; ++ ++void sm_key_job_done(struct device *dev, u32 *desc, u32 err, void *context) ++{ ++ struct sm_key_job_result *res = context; ++ ++ res->error = err; /* save off the error for postprocessing */ ++ complete(&res->completion); /* mark us complete */ ++} ++ ++static int sm_key_job(struct device *ksdev, u32 *jobdesc) ++{ ++ struct sm_key_job_result testres; ++ struct caam_drv_private_sm *kspriv; ++ int rtn = 0; ++ ++ kspriv = dev_get_drvdata(ksdev); ++ ++ init_completion(&testres.completion); ++ ++ rtn = caam_jr_enqueue(kspriv->smringdev, jobdesc, sm_key_job_done, ++ &testres); ++ if (!rtn) { ++ wait_for_completion_interruptible(&testres.completion); ++ rtn = testres.error; ++ } ++ return rtn; ++} ++ ++/* ++ * Following section establishes the default methods for keystore access ++ * They are NOT intended for use external to this module ++ * ++ * In the present version, these are the only means for the higher-level ++ * interface to deal with the mechanics of accessing the phyiscal keystore ++ */ ++ ++ ++int slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata; ++ u32 i; ++#ifdef SM_DEBUG ++ dev_info(dev, "slot_alloc(): requesting slot for %d bytes\n", size); ++#endif ++ ++ if (size > smpriv->slot_size) ++ return -EKEYREJECTED; ++ ++ for (i = 0; i < ksdata->slot_count; i++) { ++ if (ksdata->slot[i].allocated == 0) { ++ ksdata->slot[i].allocated = 1; ++ (*slot) = i; ++#ifdef SM_DEBUG ++ dev_info(dev, "slot_alloc(): new slot %d allocated\n", ++ *slot); ++#endif ++ return 0; ++ } ++ } ++ ++ return -ENOSPC; ++} ++EXPORT_SYMBOL(slot_alloc); ++ ++int slot_dealloc(struct device *dev, u32 unit, u32 slot) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata; ++ u8 __iomem *slotdata; ++ ++#ifdef SM_DEBUG ++ dev_info(dev, "slot_dealloc(): releasing slot %d\n", slot); ++#endif ++ if (slot >= ksdata->slot_count) ++ return -EINVAL; ++ slotdata = ksdata->base_address + slot * smpriv->slot_size; ++ ++ if (ksdata->slot[slot].allocated == 1) { ++ /* Forcibly overwrite the data from the keystore */ ++ memset(ksdata->base_address + slot * smpriv->slot_size, 0, ++ smpriv->slot_size); ++ ++ ksdata->slot[slot].allocated = 0; ++#ifdef SM_DEBUG ++ dev_info(dev, "slot_dealloc(): slot %d released\n", slot); ++#endif ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++EXPORT_SYMBOL(slot_dealloc); ++ ++void *slot_get_address(struct device *dev, u32 unit, u32 slot) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata; ++ ++ if (slot >= ksdata->slot_count) ++ return NULL; ++ ++#ifdef SM_DEBUG ++ dev_info(dev, "slot_get_address(): slot %d is 0x%08x\n", slot, ++ (u32)ksdata->base_address + slot * smpriv->slot_size); ++#endif ++ ++ return ksdata->base_address + slot * smpriv->slot_size; ++} ++ ++u32 slot_get_base(struct device *dev, u32 unit, u32 slot) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata; ++ ++ /* ++ * There could potentially be more than one secure partition object ++ * associated with this keystore. For now, there is just one. ++ */ ++ ++ (void)slot; ++ ++#ifdef SM_DEBUG ++ dev_info(dev, "slot_get_base(): slot %d = 0x%08x\n", ++ slot, (u32)ksdata->base_address); ++#endif ++ ++ return (u32)(ksdata->base_address); ++} ++ ++u32 slot_get_offset(struct device *dev, u32 unit, u32 slot) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata; ++ ++ if (slot >= ksdata->slot_count) ++ return -EINVAL; ++ ++#ifdef SM_DEBUG ++ dev_info(dev, "slot_get_offset(): slot %d = %d\n", slot, ++ slot * smpriv->slot_size); ++#endif ++ ++ return slot * smpriv->slot_size; ++} ++ ++u32 slot_get_slot_size(struct device *dev, u32 unit, u32 slot) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ ++ ++#ifdef SM_DEBUG ++ dev_info(dev, "slot_get_slot_size(): slot %d = %d\n", slot, ++ smpriv->slot_size); ++#endif ++ /* All slots are the same size in the default implementation */ ++ return smpriv->slot_size; ++} ++ ++ ++ ++int kso_init_data(struct device *dev, u32 unit) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ int retval = -EINVAL; ++ struct keystore_data *keystore_data = NULL; ++ u32 slot_count; ++ u32 keystore_data_size; ++ ++ /* ++ * Calculate the required size of the keystore data structure, based ++ * on the number of keys that can fit in the partition. ++ */ ++ slot_count = smpriv->page_size / smpriv->slot_size; ++#ifdef SM_DEBUG ++ dev_info(dev, "kso_init_data: %d slots initializing\n", slot_count); ++#endif ++ ++ keystore_data_size = sizeof(struct keystore_data) + ++ slot_count * ++ sizeof(struct keystore_data_slot_info); ++ ++ keystore_data = kzalloc(keystore_data_size, GFP_KERNEL); ++ ++ if (keystore_data == NULL) { ++ retval = -ENOSPC; ++ goto out; ++ } ++ ++#ifdef SM_DEBUG ++ dev_info(dev, "kso_init_data: keystore data size = %d\n", ++ keystore_data_size); ++#endif ++ ++ /* ++ * Place the slot information structure directly after the keystore data ++ * structure. ++ */ ++ keystore_data->slot = (struct keystore_data_slot_info *) ++ (keystore_data + 1); ++ keystore_data->slot_count = slot_count; ++ ++ smpriv->pagedesc[unit].ksdata = keystore_data; ++ smpriv->pagedesc[unit].ksdata->base_address = ++ smpriv->pagedesc[unit].pg_base; ++ ++ retval = 0; ++ ++out: ++ if (retval != 0) ++ if (keystore_data != NULL) ++ kfree(keystore_data); ++ ++ ++ return retval; ++} ++ ++void kso_cleanup_data(struct device *dev, u32 unit) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ struct keystore_data *keystore_data = NULL; ++ ++ if (smpriv->pagedesc[unit].ksdata != NULL) ++ keystore_data = smpriv->pagedesc[unit].ksdata; ++ ++ /* Release the allocated keystore management data */ ++ kfree(smpriv->pagedesc[unit].ksdata); ++ ++ return; ++} ++ ++ ++ ++/* ++ * Keystore management section ++ */ ++ ++void sm_init_keystore(struct device *dev) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ ++ smpriv->data_init = kso_init_data; ++ smpriv->data_cleanup = kso_cleanup_data; ++ smpriv->slot_alloc = slot_alloc; ++ smpriv->slot_dealloc = slot_dealloc; ++ smpriv->slot_get_address = slot_get_address; ++ smpriv->slot_get_base = slot_get_base; ++ smpriv->slot_get_offset = slot_get_offset; ++ smpriv->slot_get_slot_size = slot_get_slot_size; ++#ifdef SM_DEBUG ++ dev_info(dev, "sm_init_keystore(): handlers installed\n"); ++#endif ++} ++EXPORT_SYMBOL(sm_init_keystore); ++ ++/* Return available pages/units */ ++u32 sm_detect_keystore_units(struct device *dev) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ ++ return smpriv->localpages; ++} ++EXPORT_SYMBOL(sm_detect_keystore_units); ++ ++/* ++ * Do any keystore specific initializations ++ */ ++int sm_establish_keystore(struct device *dev, u32 unit) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ ++#ifdef SM_DEBUG ++ dev_info(dev, "sm_establish_keystore(): unit %d initializing\n", unit); ++#endif ++ ++ if (smpriv->data_init == NULL) ++ return -EINVAL; ++ ++ /* Call the data_init function for any user setup */ ++ return smpriv->data_init(dev, unit); ++} ++EXPORT_SYMBOL(sm_establish_keystore); ++ ++void sm_release_keystore(struct device *dev, u32 unit) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ ++#ifdef SM_DEBUG ++ dev_info(dev, "sm_establish_keystore(): unit %d releasing\n", unit); ++#endif ++ if ((smpriv != NULL) && (smpriv->data_cleanup != NULL)) ++ smpriv->data_cleanup(dev, unit); ++ ++ return; ++} ++EXPORT_SYMBOL(sm_release_keystore); ++ ++/* ++ * Subsequent interfacce (sm_keystore_*) forms the accessor interfacce to ++ * the keystore ++ */ ++int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ int retval = -EINVAL; ++ ++ spin_lock(&smpriv->kslock); ++ ++ if ((smpriv->slot_alloc == NULL) || ++ (smpriv->pagedesc[unit].ksdata == NULL)) ++ goto out; ++ ++ retval = smpriv->slot_alloc(dev, unit, size, slot); ++ ++out: ++ spin_unlock(&smpriv->kslock); ++ return retval; ++} ++EXPORT_SYMBOL(sm_keystore_slot_alloc); ++ ++int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ int retval = -EINVAL; ++ ++ spin_lock(&smpriv->kslock); ++ ++ if ((smpriv->slot_alloc == NULL) || ++ (smpriv->pagedesc[unit].ksdata == NULL)) ++ goto out; ++ ++ retval = smpriv->slot_dealloc(dev, unit, slot); ++out: ++ spin_unlock(&smpriv->kslock); ++ return retval; ++} ++EXPORT_SYMBOL(sm_keystore_slot_dealloc); ++ ++int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot, ++ const u8 *key_data, u32 key_length) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ int retval = -EINVAL; ++ u32 slot_size; ++ u32 i; ++ u8 __iomem *slot_location; ++ ++ spin_lock(&smpriv->kslock); ++ ++ slot_size = smpriv->slot_get_slot_size(dev, unit, slot); ++ ++ if (key_length > slot_size) { ++ retval = -EFBIG; ++ goto out; ++ } ++ ++ slot_location = smpriv->slot_get_address(dev, unit, slot); ++ ++ for (i = 0; i < key_length; i++) ++ slot_location[i] = key_data[i]; ++ ++ retval = 0; ++ ++out: ++ spin_unlock(&smpriv->kslock); ++ return retval; ++} ++EXPORT_SYMBOL(sm_keystore_slot_load); ++ ++int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot, ++ u32 key_length, u8 *key_data) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ int retval = -EINVAL; ++ u8 __iomem *slot_addr; ++ u32 slot_size; ++ ++ spin_lock(&smpriv->kslock); ++ ++ slot_addr = smpriv->slot_get_address(dev, unit, slot); ++ slot_size = smpriv->slot_get_slot_size(dev, unit, slot); ++ ++ if (key_length > slot_size) { ++ retval = -EKEYREJECTED; ++ goto out; ++ } ++ ++ memcpy(key_data, slot_addr, key_length); ++ retval = 0; ++ ++out: ++ spin_unlock(&smpriv->kslock); ++ return retval; ++} ++EXPORT_SYMBOL(sm_keystore_slot_read); ++ ++int sm_keystore_slot_encapsulate(struct device *dev, u32 unit, u32 inslot, ++ u32 outslot, u16 secretlen, u8 *keymod, ++ u16 keymodlen) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ int retval = 0; ++ u32 slot_length, dsize, jstat; ++ u32 __iomem *encapdesc = NULL; ++ u8 __iomem *lkeymod, *inpslotaddr, *outslotaddr; ++ dma_addr_t keymod_dma; ++ ++ /* Ensure that the full blob will fit in the key slot */ ++ slot_length = smpriv->slot_get_slot_size(dev, unit, outslot); ++ if ((secretlen + 48) > slot_length) ++ goto out; ++ ++ /* Get the base addresses of both keystore slots */ ++ inpslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, inslot); ++ outslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, outslot); ++ ++ /* Build the key modifier */ ++ lkeymod = kmalloc(keymodlen, GFP_KERNEL | GFP_DMA); ++ memcpy(lkeymod, keymod, keymodlen); ++ keymod_dma = dma_map_single(dev, lkeymod, keymodlen, DMA_TO_DEVICE); ++ dma_sync_single_for_device(dev, keymod_dma, keymodlen, DMA_TO_DEVICE); ++ ++ /* Build the encapsulation job descriptor */ ++ dsize = blob_encap_desc(&encapdesc, keymod_dma, keymodlen, ++ __pa(inpslotaddr), __pa(outslotaddr), ++ secretlen, 0); ++ if (!dsize) { ++ dev_err(dev, "can't alloc an encap descriptor\n"); ++ retval = -ENOMEM; ++ goto out; ++ } ++ jstat = sm_key_job(dev, encapdesc); ++ ++ dma_unmap_single(dev, keymod_dma, keymodlen, DMA_TO_DEVICE); ++ kfree(encapdesc); ++ ++out: ++ return retval; ++ ++} ++EXPORT_SYMBOL(sm_keystore_slot_encapsulate); ++ ++int sm_keystore_slot_decapsulate(struct device *dev, u32 unit, u32 inslot, ++ u32 outslot, u16 secretlen, u8 *keymod, ++ u16 keymodlen) ++{ ++ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev); ++ int retval = 0; ++ u32 slot_length, dsize, jstat; ++ u32 __iomem *decapdesc = NULL; ++ u8 __iomem *lkeymod, *inpslotaddr, *outslotaddr; ++ dma_addr_t keymod_dma; ++ ++ /* Ensure that the decap data will fit in the key slot */ ++ slot_length = smpriv->slot_get_slot_size(dev, unit, outslot); ++ if (secretlen > slot_length) ++ goto out; ++ ++ /* Get the base addresses of both keystore slots */ ++ inpslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, inslot); ++ outslotaddr = (u8 *)smpriv->slot_get_address(dev, unit, outslot); ++ ++ /* Build the key modifier */ ++ lkeymod = kmalloc(keymodlen, GFP_KERNEL | GFP_DMA); ++ memcpy(lkeymod, keymod, keymodlen); ++ keymod_dma = dma_map_single(dev, lkeymod, keymodlen, DMA_TO_DEVICE); ++ dma_sync_single_for_device(dev, keymod_dma, keymodlen, DMA_TO_DEVICE); ++ ++ /* Build the decapsulation job descriptor */ ++ dsize = blob_decap_desc(&decapdesc, keymod_dma, keymodlen, ++ __pa(inpslotaddr), __pa(outslotaddr), ++ secretlen, 0); ++ if (!dsize) { ++ dev_err(dev, "can't alloc a decap descriptor\n"); ++ retval = -ENOMEM; ++ goto out; ++ } ++ jstat = sm_key_job(dev, decapdesc); ++ ++ dma_unmap_single(dev, keymod_dma, keymodlen, DMA_TO_DEVICE); ++ kfree(decapdesc); ++ ++out: ++ return retval; ++ ++} ++EXPORT_SYMBOL(sm_keystore_slot_decapsulate); ++ ++ ++/* ++ * Initialization/shutdown subsystem ++ * Assumes statically-invoked startup/shutdown from the controller driver ++ * for the present time, to be reworked when a device tree becomes ++ * available. This code will not modularize in present form. ++ * ++ * Also, simply uses ring 0 for execution at the present ++ */ ++ ++int caam_sm_startup(struct platform_device *pdev) ++{ ++ struct device *ctrldev, *smdev; ++ struct caam_drv_private *ctrlpriv; ++ struct caam_drv_private_sm *smpriv; ++ struct caam_drv_private_jr *jrpriv; /* need this for reg page */ ++ struct platform_device *sm_pdev; ++ struct sm_page_descriptor *lpagedesc; ++ u32 page, pgstat, lpagect, detectedpage; ++ ++ struct device_node *np; ++ ctrldev = &pdev->dev; ++ ctrlpriv = dev_get_drvdata(ctrldev); ++ ++ /* ++ * Set up the private block for secure memory ++ * Only one instance is possible ++ */ ++ smpriv = kzalloc(sizeof(struct caam_drv_private_sm), GFP_KERNEL); ++ if (smpriv == NULL) { ++ dev_err(ctrldev, "can't alloc private mem for secure memory\n"); ++ return -ENOMEM; ++ } ++ smpriv->parentdev = ctrldev; /* copy of parent dev is handy */ ++ ++ /* Create the dev */ ++#ifdef CONFIG_OF ++ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm"); ++ sm_pdev = of_platform_device_create(np, "caam_sm", ctrldev); ++#else ++ sm_pdev = platform_device_register_data(ctrldev, "caam_sm", 0, ++ smpriv, ++ sizeof(struct caam_drv_private_sm)); ++#endif ++ if (sm_pdev == NULL) { ++ kfree(smpriv); ++ return -EINVAL; ++ } ++ smdev = &sm_pdev->dev; ++ dev_set_drvdata(smdev, smpriv); ++ ctrlpriv->smdev = smdev; ++ ++ /* ++ * Collect configuration limit data for reference ++ * This batch comes from the partition data/vid registers in perfmon ++ */ ++ smpriv->max_pages = ((rd_reg32(&ctrlpriv->ctrl->perfmon.smpart) ++ & SMPART_MAX_NUMPG_MASK) >> ++ SMPART_MAX_NUMPG_SHIFT) + 1; ++ smpriv->top_partition = ((rd_reg32(&ctrlpriv->ctrl->perfmon.smpart) ++ & SMPART_MAX_PNUM_MASK) >> ++ SMPART_MAX_PNUM_SHIFT) + 1; ++ smpriv->top_page = ((rd_reg32(&ctrlpriv->ctrl->perfmon.smpart) ++ & SMPART_MAX_PG_MASK) >> SMPART_MAX_PG_SHIFT) + 1; ++ smpriv->page_size = 1024 << ((rd_reg32(&ctrlpriv->ctrl->perfmon.smvid) ++ & SMVID_PG_SIZE_MASK) >> SMVID_PG_SIZE_SHIFT); ++ smpriv->slot_size = 1 << CONFIG_CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE; ++ ++#ifdef SM_DEBUG ++ dev_info(smdev, "max pages = %d, top partition = %d\n", ++ smpriv->max_pages, smpriv->top_partition); ++ dev_info(smdev, "top page = %d, page size = %d (total = %d)\n", ++ smpriv->top_page, smpriv->page_size, ++ smpriv->top_page * smpriv->page_size); ++ dev_info(smdev, "selected slot size = %d\n", smpriv->slot_size); ++#endif ++ ++ /* ++ * Now probe for partitions/pages to which we have access. Note that ++ * these have likely been set up by a bootloader or platform ++ * provisioning application, so we have to assume that we "inherit" ++ * a configuration and work within the constraints of what it might be. ++ * ++ * Assume use of the zeroth ring in the present iteration (until ++ * we can divorce the controller and ring drivers, and then assign ++ * an SM instance to any ring instance). ++ */ ++ smpriv->smringdev = ctrlpriv->jrdev[0]; ++ jrpriv = dev_get_drvdata(smpriv->smringdev); ++ lpagect = 0; ++ lpagedesc = kzalloc(sizeof(struct sm_page_descriptor) ++ * smpriv->max_pages, GFP_KERNEL); ++ if (lpagedesc == NULL) { ++ kfree(smpriv); ++ return -ENOMEM; ++ } ++ ++ for (page = 0; page < smpriv->max_pages; page++) { ++ wr_reg32(&jrpriv->rregs->sm_cmd, ++ ((page << SMC_PAGE_SHIFT) & SMC_PAGE_MASK) | ++ (SMC_CMD_PAGE_INQUIRY & SMC_CMD_MASK)); ++ pgstat = rd_reg32(&jrpriv->rregs->sm_status); ++ if (((pgstat & SMCS_PGWON_MASK) >> SMCS_PGOWN_SHIFT) ++ == SMCS_PGOWN_OWNED) { /* our page? */ ++ lpagedesc[page].phys_pagenum = ++ (pgstat & SMCS_PAGE_MASK) >> SMCS_PAGE_SHIFT; ++ lpagedesc[page].own_part = ++ (pgstat & SMCS_PART_SHIFT) >> SMCS_PART_MASK; ++ lpagedesc[page].pg_base = ctrlpriv->sm_base + ++ ((smpriv->page_size * page) / sizeof(u32)); ++ lpagect++; ++#ifdef SM_DEBUG ++ dev_info(smdev, ++ "physical page %d, owning partition = %d\n", ++ lpagedesc[page].phys_pagenum, ++ lpagedesc[page].own_part); ++#endif ++ } ++ } ++ ++ smpriv->pagedesc = kzalloc(sizeof(struct sm_page_descriptor) * lpagect, ++ GFP_KERNEL); ++ if (smpriv->pagedesc == NULL) { ++ kfree(lpagedesc); ++ kfree(smpriv); ++ return -ENOMEM; ++ } ++ smpriv->localpages = lpagect; ++ ++ detectedpage = 0; ++ for (page = 0; page < smpriv->max_pages; page++) { ++ if (lpagedesc[page].pg_base != NULL) { /* e.g. live entry */ ++ memcpy(&smpriv->pagedesc[detectedpage], ++ &lpagedesc[page], ++ sizeof(struct sm_page_descriptor)); ++#ifdef SM_DEBUG_CONT ++ sm_show_page(smdev, &smpriv->pagedesc[detectedpage]); ++#endif ++ detectedpage++; ++ } ++ } ++ ++ kfree(lpagedesc); ++ ++ sm_init_keystore(smdev); ++ ++ return 0; ++} ++ ++void caam_sm_shutdown(struct platform_device *pdev) ++{ ++ struct device *ctrldev, *smdev; ++ struct caam_drv_private *priv; ++ struct caam_drv_private_sm *smpriv; ++ ++ ctrldev = &pdev->dev; ++ priv = dev_get_drvdata(ctrldev); ++ smdev = priv->smdev; ++ smpriv = dev_get_drvdata(smdev); ++ ++ kfree(smpriv->pagedesc); ++ kfree(smpriv); ++} ++EXPORT_SYMBOL(caam_sm_shutdown); ++#ifdef CONFIG_OF ++static void __exit caam_sm_exit(void) ++{ ++ struct device_node *dev_node; ++ struct platform_device *pdev; ++ ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); ++ if (!dev_node) { ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); ++ if (!dev_node) ++ return; ++ } ++ ++ pdev = of_find_device_by_node(dev_node); ++ if (!pdev) ++ return; ++ ++ of_node_put(dev_node); ++ ++ caam_sm_shutdown(pdev); ++ ++ return; ++} ++ ++static int __init caam_sm_init(void) ++{ ++ struct device_node *dev_node; ++ struct platform_device *pdev; ++ ++ /* ++ * Do of_find_compatible_node() then of_find_device_by_node() ++ * once a functional device tree is available ++ */ ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); ++ if (!dev_node) { ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); ++ if (!dev_node) ++ return -ENODEV; ++ } ++ ++ pdev = of_find_device_by_node(dev_node); ++ if (!pdev) ++ return -ENODEV; ++ ++ of_node_get(dev_node); ++ ++ caam_sm_startup(pdev); ++ ++ return 0; ++} ++ ++module_init(caam_sm_init); ++module_exit(caam_sm_exit); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("FSL CAAM Secure Memory / Keystore"); ++MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD"); ++#endif +diff -Nur linux-3.10.30/drivers/crypto/caam/sm_test.c linux-3.10.30-cubox-i/drivers/crypto/caam/sm_test.c +--- linux-3.10.30/drivers/crypto/caam/sm_test.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/sm_test.c 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,844 @@ ++/* ++ * Secure Memory / Keystore Exemplification Module ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. All Rights Reserved ++ * ++ * Serves as a functional example, and as a self-contained unit test for ++ * the functionality contained in sm_store.c. ++ * ++ * The example function, caam_sm_example_init(), runs a thread that: ++ * ++ * - initializes a set of fixed keys ++ * - stores one copy in clear buffers ++ * - stores them again in secure memory ++ * - extracts stored keys back out for use ++ * - intializes 3 data buffers for a test: ++ * (1) containing cleartext ++ * (2) to hold ciphertext encrypted with an extracted black key ++ * (3) to hold extracted cleartext decrypted with an equivalent clear key ++ * ++ * The function then builds simple job descriptors that reference the key ++ * material and buffers as initialized, and executes an encryption job ++ * with a black key, and a decryption job using a the same key held in the ++ * clear. The output of the decryption job is compared to the original ++ * cleartext; if they don't compare correctly, one can assume a key problem ++ * exists, where the function will exit with an error. ++ * ++ * This module can use a substantial amount of refactoring, which may occur ++ * after the API gets some mileage. Furthermore, expect this module to ++ * eventually disappear once the API is integrated into "real" software. ++ */ ++ ++#include "compat.h" ++#include "intern.h" ++#include "desc.h" ++#include "error.h" ++#include "jr.h" ++#include "sm.h" ++ ++static u8 skeymod[] = { ++ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, ++ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 ++}; ++static u8 symkey[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f ++}; ++ ++static u8 symdata[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x0f, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, ++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ++ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, ++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, ++ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, ++ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, ++ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, ++ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, ++ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, ++ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, ++ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, ++ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, ++ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, ++ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, ++ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, ++ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, ++ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, ++ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, ++ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, ++ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, ++ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, ++ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, ++ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, ++ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff ++}; ++ ++static int mk_job_desc(u32 *desc, dma_addr_t key, u16 keysz, dma_addr_t indata, ++ dma_addr_t outdata, u16 sz, u32 cipherdir, u32 keymode) ++{ ++ desc[1] = CMD_KEY | CLASS_1 | (keysz & KEY_LENGTH_MASK) | keymode; ++ desc[2] = (u32)key; ++ desc[3] = CMD_OPERATION | OP_TYPE_CLASS1_ALG | OP_ALG_AAI_ECB | ++ cipherdir; ++ desc[4] = CMD_FIFO_LOAD | FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1 | sz; ++ desc[5] = (u32)indata; ++ desc[6] = CMD_FIFO_STORE | FIFOST_TYPE_MESSAGE_DATA | sz; ++ desc[7] = (u32)outdata; ++ ++ desc[0] = CMD_DESC_HDR | HDR_ONE | (8 & HDR_DESCLEN_MASK); ++ return 8 * sizeof(u32); ++} ++ ++struct exec_test_result { ++ int error; ++ struct completion completion; ++}; ++ ++void exec_test_done(struct device *dev, u32 *desc, u32 err, void *context) ++{ ++ struct exec_test_result *res = context; ++ ++ if (err) { ++ char tmp[CAAM_ERROR_STR_MAX]; ++ dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err)); ++ } ++ ++ res->error = err; ++ complete(&res->completion); ++} ++ ++static int exec_test_job(struct device *ksdev, u32 *jobdesc) ++{ ++ struct exec_test_result testres; ++ struct caam_drv_private_sm *kspriv; ++ int rtn = 0; ++ ++ kspriv = dev_get_drvdata(ksdev); ++ ++ init_completion(&testres.completion); ++ ++ rtn = caam_jr_enqueue(kspriv->smringdev, jobdesc, exec_test_done, ++ &testres); ++ if (!rtn) { ++ wait_for_completion_interruptible(&testres.completion); ++ rtn = testres.error; ++ } ++ return rtn; ++} ++ ++ ++int caam_sm_example_init(struct platform_device *pdev) ++{ ++ struct device *ctrldev, *ksdev; ++ struct caam_drv_private *ctrlpriv; ++ struct caam_drv_private_sm *kspriv; ++ u32 unit, units, jdescsz; ++ int stat, jstat, rtnval = 0; ++ u8 __iomem *syminp, *symint, *symout = NULL; ++ dma_addr_t syminp_dma, symint_dma, symout_dma; ++ u8 __iomem *black_key_des, *black_key_aes128; ++ u8 __iomem *black_key_aes256; ++ dma_addr_t black_key_des_dma, black_key_aes128_dma; ++ dma_addr_t black_key_aes256_dma; ++ u8 __iomem *clear_key_des, *clear_key_aes128, *clear_key_aes256; ++ dma_addr_t clear_key_des_dma, clear_key_aes128_dma; ++ dma_addr_t clear_key_aes256_dma; ++ u32 __iomem *jdesc; ++ u32 keyslot_des, keyslot_aes128, keyslot_aes256 = 0; ++ ++ jdesc = NULL; ++ black_key_des = black_key_aes128 = black_key_aes256 = NULL; ++ clear_key_des = clear_key_aes128 = clear_key_aes256 = NULL; ++ ++ /* We can lose this cruft once we can get a pdev by name */ ++ ctrldev = &pdev->dev; ++ ctrlpriv = dev_get_drvdata(ctrldev); ++ ksdev = ctrlpriv->smdev; ++ kspriv = dev_get_drvdata(ksdev); ++ if (kspriv == NULL) ++ return -ENODEV; ++ ++ /* Now that we have the dev for the single SM instance, connect */ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test_init() running\n"); ++#endif ++ /* Probe to see what keystores are available to us */ ++ units = sm_detect_keystore_units(ksdev); ++ if (!units) ++ dev_err(ksdev, "caam_sm_test: no keystore units available\n"); ++ ++ /* ++ * MX6 bootloader stores some stuff in unit 0, so let's ++ * use 1 or above ++ */ ++ if (units < 2) { ++ dev_err(ksdev, "caam_sm_test: insufficient keystore units\n"); ++ return -ENODEV; ++ } ++ unit = 1; ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test: %d keystore units available\n", units); ++#endif ++ ++ /* Initialize/Establish Keystore */ ++ sm_establish_keystore(ksdev, unit); /* Initalize store in #1 */ ++ ++ /* ++ * Top of main test thread ++ */ ++ ++ /* Allocate test data blocks (input, intermediate, output) */ ++ syminp = kmalloc(256, GFP_KERNEL | GFP_DMA); ++ symint = kmalloc(256, GFP_KERNEL | GFP_DMA); ++ symout = kmalloc(256, GFP_KERNEL | GFP_DMA); ++ if ((syminp == NULL) || (symint == NULL) || (symout == NULL)) { ++ rtnval = -ENOMEM; ++ dev_err(ksdev, "caam_sm_test: can't get test data buffers\n"); ++ goto freemem; ++ } ++ ++ /* Allocate storage for 3 black keys: encapsulated 8, 16, 32 */ ++ black_key_des = kmalloc(16, GFP_KERNEL | GFP_DMA); /* padded to 16... */ ++ black_key_aes128 = kmalloc(16, GFP_KERNEL | GFP_DMA); ++ black_key_aes256 = kmalloc(16, GFP_KERNEL | GFP_DMA); ++ if ((black_key_des == NULL) || (black_key_aes128 == NULL) || ++ (black_key_aes256 == NULL)) { ++ rtnval = -ENOMEM; ++ dev_err(ksdev, "caam_sm_test: can't black key buffers\n"); ++ goto freemem; ++ } ++ ++ clear_key_des = kmalloc(8, GFP_KERNEL | GFP_DMA); ++ clear_key_aes128 = kmalloc(16, GFP_KERNEL | GFP_DMA); ++ clear_key_aes256 = kmalloc(32, GFP_KERNEL | GFP_DMA); ++ if ((clear_key_des == NULL) || (clear_key_aes128 == NULL) || ++ (clear_key_aes256 == NULL)) { ++ rtnval = -ENOMEM; ++ dev_err(ksdev, "caam_sm_test: can't get clear key buffers\n"); ++ goto freemem; ++ } ++ ++ /* Allocate storage for job descriptor */ ++ jdesc = kmalloc(8 * sizeof(u32), GFP_KERNEL | GFP_DMA); ++ if (jdesc == NULL) { ++ rtnval = -ENOMEM; ++ dev_err(ksdev, "caam_sm_test: can't get descriptor buffers\n"); ++ goto freemem; ++ } ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test: all buffers allocated\n"); ++#endif ++ ++ /* Load up input data block, clear outputs */ ++ memcpy(syminp, symdata, 256); ++ memset(symint, 0, 256); ++ memset(symout, 0, 256); ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ syminp[0], syminp[1], syminp[2], syminp[3], ++ syminp[4], syminp[5], syminp[6], syminp[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[0], symint[1], symint[2], symint[3], ++ symint[4], symint[5], symint[6], symint[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symout[0], symout[1], symout[2], symout[3], ++ symout[4], symout[5], symout[6], symout[7]); ++ ++ dev_info(ksdev, "caam_sm_test: data buffers initialized\n"); ++#endif ++ ++ /* Load up clear keys */ ++ memcpy(clear_key_des, symkey, 8); ++ memcpy(clear_key_aes128, symkey, 16); ++ memcpy(clear_key_aes256, symkey, 32); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test: all clear keys loaded\n"); ++#endif ++ ++ /* ++ * Place clear keys in keystore. ++ * All the interesting stuff happens here. ++ */ ++ /* 8 bit DES key */ ++ stat = sm_keystore_slot_alloc(ksdev, unit, 8, &keyslot_des); ++ if (stat) ++ goto freemem; ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test: 8 byte key slot in %d\n", keyslot_des); ++#endif ++ stat = sm_keystore_slot_load(ksdev, unit, keyslot_des, clear_key_des, ++ 8); ++ if (stat) { ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test: can't load 8 byte key in %d\n", ++ keyslot_des); ++#endif ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); ++ goto freemem; ++ } ++ ++ /* 16 bit AES key */ ++ stat = sm_keystore_slot_alloc(ksdev, unit, 16, &keyslot_aes128); ++ if (stat) { ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); ++ goto freemem; ++ } ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test: 16 byte key slot in %d\n", ++ keyslot_aes128); ++#endif ++ stat = sm_keystore_slot_load(ksdev, unit, keyslot_aes128, ++ clear_key_aes128, 16); ++ if (stat) { ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test: can't load 16 byte key in %d\n", ++ keyslot_aes128); ++#endif ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128); ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); ++ goto freemem; ++ } ++ ++ /* 32 bit AES key */ ++ stat = sm_keystore_slot_alloc(ksdev, unit, 32, &keyslot_aes256); ++ if (stat) { ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128); ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); ++ goto freemem; ++ } ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test: 32 byte key slot in %d\n", ++ keyslot_aes256); ++#endif ++ stat = sm_keystore_slot_load(ksdev, unit, keyslot_aes256, ++ clear_key_aes256, 32); ++ if (stat) { ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test: can't load 32 byte key in %d\n", ++ keyslot_aes128); ++#endif ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes256); ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128); ++ sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); ++ goto freemem; ++ } ++ ++ /* Encapsulate all keys as SM blobs */ ++ stat = sm_keystore_slot_encapsulate(ksdev, unit, keyslot_des, ++ keyslot_des, 8, skeymod, 8); ++ if (stat) { ++ dev_info(ksdev, "caam_sm_test: can't encapsulate DES key\n"); ++ goto freekeys; ++ } ++ ++ stat = sm_keystore_slot_encapsulate(ksdev, unit, keyslot_aes128, ++ keyslot_aes128, 16, skeymod, 8); ++ if (stat) { ++ dev_info(ksdev, "caam_sm_test: can't encapsulate AES128 key\n"); ++ goto freekeys; ++ } ++ ++ stat = sm_keystore_slot_encapsulate(ksdev, unit, keyslot_aes256, ++ keyslot_aes256, 32, skeymod, 8); ++ if (stat) { ++ dev_info(ksdev, "caam_sm_test: can't encapsulate AES256 key\n"); ++ goto freekeys; ++ } ++ ++ /* Now decapsulate as black key blobs */ ++ stat = sm_keystore_slot_decapsulate(ksdev, unit, keyslot_des, ++ keyslot_des, 8, skeymod, 8); ++ if (stat) { ++ dev_info(ksdev, "caam_sm_test: can't decapsulate DES key\n"); ++ goto freekeys; ++ } ++ ++ stat = sm_keystore_slot_decapsulate(ksdev, unit, keyslot_aes128, ++ keyslot_aes128, 16, skeymod, 8); ++ if (stat) { ++ dev_info(ksdev, "caam_sm_test: can't decapsulate AES128 key\n"); ++ goto freekeys; ++ } ++ ++ stat = sm_keystore_slot_decapsulate(ksdev, unit, keyslot_aes256, ++ keyslot_aes256, 32, skeymod, 8); ++ if (stat) { ++ dev_info(ksdev, "caam_sm_test: can't decapsulate AES128 key\n"); ++ goto freekeys; ++ } ++ ++ /* Extract 8/16/32 byte black keys */ ++ sm_keystore_slot_read(ksdev, unit, keyslot_des, 8, black_key_des); ++ sm_keystore_slot_read(ksdev, unit, keyslot_aes128, 16, ++ black_key_aes128); ++ sm_keystore_slot_read(ksdev, unit, keyslot_aes256, 32, ++ black_key_aes256); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test: all black keys extracted\n"); ++#endif ++ ++ /* DES encrypt using 8 byte black key */ ++ black_key_des_dma = dma_map_single(ksdev, black_key_des, 8, ++ DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, black_key_des_dma, 8, DMA_TO_DEVICE); ++ syminp_dma = dma_map_single(ksdev, syminp, 256, DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, syminp_dma, 256, DMA_TO_DEVICE); ++ symint_dma = dma_map_single(ksdev, symint, 256, DMA_FROM_DEVICE); ++ ++ jdescsz = mk_job_desc(jdesc, black_key_des_dma, 8, syminp_dma, ++ symint_dma, 256, ++ OP_ALG_ENCRYPT | OP_ALG_ALGSEL_DES, 0); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "jobdesc:\n"); ++ dev_info(ksdev, "0x%08x\n", jdesc[0]); ++ dev_info(ksdev, "0x%08x\n", jdesc[1]); ++ dev_info(ksdev, "0x%08x\n", jdesc[2]); ++ dev_info(ksdev, "0x%08x\n", jdesc[3]); ++ dev_info(ksdev, "0x%08x\n", jdesc[4]); ++ dev_info(ksdev, "0x%08x\n", jdesc[5]); ++ dev_info(ksdev, "0x%08x\n", jdesc[6]); ++ dev_info(ksdev, "0x%08x\n", jdesc[7]); ++#endif ++ ++ jstat = exec_test_job(ksdev, jdesc); ++ ++ dma_sync_single_for_cpu(ksdev, symint_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, symint_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, syminp_dma, 256, DMA_TO_DEVICE); ++ dma_unmap_single(ksdev, black_key_des_dma, 8, DMA_TO_DEVICE); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "input block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ syminp[0], syminp[1], syminp[2], syminp[3], ++ syminp[4], syminp[5], syminp[6], syminp[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ syminp[8], syminp[9], syminp[10], syminp[11], ++ syminp[12], syminp[13], syminp[14], syminp[15]); ++ dev_info(ksdev, "intermediate block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[0], symint[1], symint[2], symint[3], ++ symint[4], symint[5], symint[6], symint[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[8], symint[9], symint[10], symint[11], ++ symint[12], symint[13], symint[14], symint[15]); ++ dev_info(ksdev, "caam_sm_test: encrypt cycle with 8 byte key\n"); ++#endif ++ ++ /* DES decrypt using 8 byte clear key */ ++ clear_key_des_dma = dma_map_single(ksdev, clear_key_des, 8, ++ DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, clear_key_des_dma, 8, DMA_TO_DEVICE); ++ symint_dma = dma_map_single(ksdev, symint, 256, DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, symint_dma, 256, DMA_TO_DEVICE); ++ symout_dma = dma_map_single(ksdev, symout, 256, DMA_FROM_DEVICE); ++ ++ jdescsz = mk_job_desc(jdesc, clear_key_des_dma, 8, symint_dma, ++ symout_dma, 256, ++ OP_ALG_DECRYPT | OP_ALG_ALGSEL_DES, 0); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "jobdesc:\n"); ++ dev_info(ksdev, "0x%08x\n", jdesc[0]); ++ dev_info(ksdev, "0x%08x\n", jdesc[1]); ++ dev_info(ksdev, "0x%08x\n", jdesc[2]); ++ dev_info(ksdev, "0x%08x\n", jdesc[3]); ++ dev_info(ksdev, "0x%08x\n", jdesc[4]); ++ dev_info(ksdev, "0x%08x\n", jdesc[5]); ++ dev_info(ksdev, "0x%08x\n", jdesc[6]); ++ dev_info(ksdev, "0x%08x\n", jdesc[7]); ++#endif ++ ++ jstat = exec_test_job(ksdev, jdesc); ++ ++ dma_sync_single_for_cpu(ksdev, symout_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, symout_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, symint_dma, 256, DMA_TO_DEVICE); ++ dma_unmap_single(ksdev, clear_key_des_dma, 8, DMA_TO_DEVICE); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "intermediate block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[0], symint[1], symint[2], symint[3], ++ symint[4], symint[5], symint[6], symint[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[8], symint[9], symint[10], symint[11], ++ symint[12], symint[13], symint[14], symint[15]); ++ dev_info(ksdev, "decrypted block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symout[0], symout[1], symout[2], symout[3], ++ symout[4], symout[5], symout[6], symout[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symout[8], symout[9], symout[10], symout[11], ++ symout[12], symout[13], symout[14], symout[15]); ++ dev_info(ksdev, "caam_sm_test: decrypt cycle with 8 byte key\n"); ++#endif ++ ++ /* Check result */ ++ if (memcmp(symout, syminp, 256)) { ++ dev_info(ksdev, "caam_sm_test: 8-byte key test mismatch\n"); ++ rtnval = -1; ++ goto freekeys; ++ } else ++ dev_info(ksdev, "caam_sm_test: 8-byte key test match OK\n"); ++ ++ /* AES-128 encrypt using 16 byte black key */ ++ black_key_aes128_dma = dma_map_single(ksdev, black_key_aes128, 16, ++ DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, black_key_aes128_dma, 16, ++ DMA_TO_DEVICE); ++ syminp_dma = dma_map_single(ksdev, syminp, 256, DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, syminp_dma, 256, DMA_TO_DEVICE); ++ symint_dma = dma_map_single(ksdev, symint, 256, DMA_FROM_DEVICE); ++ ++ jdescsz = mk_job_desc(jdesc, black_key_aes128_dma, 16, syminp_dma, ++ symint_dma, 256, ++ OP_ALG_ENCRYPT | OP_ALG_ALGSEL_AES, 0); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "jobdesc:\n"); ++ dev_info(ksdev, "0x%08x\n", jdesc[0]); ++ dev_info(ksdev, "0x%08x\n", jdesc[1]); ++ dev_info(ksdev, "0x%08x\n", jdesc[2]); ++ dev_info(ksdev, "0x%08x\n", jdesc[3]); ++ dev_info(ksdev, "0x%08x\n", jdesc[4]); ++ dev_info(ksdev, "0x%08x\n", jdesc[5]); ++ dev_info(ksdev, "0x%08x\n", jdesc[6]); ++ dev_info(ksdev, "0x%08x\n", jdesc[7]); ++#endif ++ ++ jstat = exec_test_job(ksdev, jdesc); ++ ++ dma_sync_single_for_cpu(ksdev, symint_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, symint_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, syminp_dma, 256, DMA_TO_DEVICE); ++ dma_unmap_single(ksdev, black_key_aes128_dma, 16, DMA_TO_DEVICE); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "input block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ syminp[0], syminp[1], syminp[2], syminp[3], ++ syminp[4], syminp[5], syminp[6], syminp[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ syminp[8], syminp[9], syminp[10], syminp[11], ++ syminp[12], syminp[13], syminp[14], syminp[15]); ++ dev_info(ksdev, "intermediate block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[0], symint[1], symint[2], symint[3], ++ symint[4], symint[5], symint[6], symint[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[8], symint[9], symint[10], symint[11], ++ symint[12], symint[13], symint[14], symint[15]); ++ dev_info(ksdev, "caam_sm_test: encrypt cycle with 16 byte key\n"); ++#endif ++ ++ /* AES-128 decrypt using 16 byte clear key */ ++ clear_key_aes128_dma = dma_map_single(ksdev, clear_key_aes128, 16, ++ DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, clear_key_aes128_dma, 16, ++ DMA_TO_DEVICE); ++ symint_dma = dma_map_single(ksdev, symint, 256, DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, symint_dma, 256, DMA_TO_DEVICE); ++ symout_dma = dma_map_single(ksdev, symout, 256, DMA_FROM_DEVICE); ++ ++ jdescsz = mk_job_desc(jdesc, clear_key_aes128_dma, 16, symint_dma, ++ symout_dma, 256, ++ OP_ALG_DECRYPT | OP_ALG_ALGSEL_AES, 0); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "jobdesc:\n"); ++ dev_info(ksdev, "0x%08x\n", jdesc[0]); ++ dev_info(ksdev, "0x%08x\n", jdesc[1]); ++ dev_info(ksdev, "0x%08x\n", jdesc[2]); ++ dev_info(ksdev, "0x%08x\n", jdesc[3]); ++ dev_info(ksdev, "0x%08x\n", jdesc[4]); ++ dev_info(ksdev, "0x%08x\n", jdesc[5]); ++ dev_info(ksdev, "0x%08x\n", jdesc[6]); ++ dev_info(ksdev, "0x%08x\n", jdesc[7]); ++#endif ++ jstat = exec_test_job(ksdev, jdesc); ++ ++ dma_sync_single_for_cpu(ksdev, symout_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, symout_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, symint_dma, 256, DMA_TO_DEVICE); ++ dma_unmap_single(ksdev, clear_key_aes128_dma, 16, DMA_TO_DEVICE); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "intermediate block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[0], symint[1], symint[2], symint[3], ++ symint[4], symint[5], symint[6], symint[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[8], symint[9], symint[10], symint[11], ++ symint[12], symint[13], symint[14], symint[15]); ++ dev_info(ksdev, "decrypted block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symout[0], symout[1], symout[2], symout[3], ++ symout[4], symout[5], symout[6], symout[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symout[8], symout[9], symout[10], symout[11], ++ symout[12], symout[13], symout[14], symout[15]); ++ dev_info(ksdev, "caam_sm_test: decrypt cycle with 16 byte key\n"); ++#endif ++ ++ /* Check result */ ++ if (memcmp(symout, syminp, 256)) { ++ dev_info(ksdev, "caam_sm_test: 16-byte key test mismatch\n"); ++ rtnval = -1; ++ goto freekeys; ++ } else ++ dev_info(ksdev, "caam_sm_test: 16-byte key test match OK\n"); ++ ++ /* AES-256 encrypt using 32 byte black key */ ++ black_key_aes256_dma = dma_map_single(ksdev, black_key_aes256, 32, ++ DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, black_key_aes256_dma, 32, ++ DMA_TO_DEVICE); ++ syminp_dma = dma_map_single(ksdev, syminp, 256, DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, syminp_dma, 256, DMA_TO_DEVICE); ++ symint_dma = dma_map_single(ksdev, symint, 256, DMA_FROM_DEVICE); ++ ++ jdescsz = mk_job_desc(jdesc, black_key_aes256_dma, 32, syminp_dma, ++ symint_dma, 256, ++ OP_ALG_ENCRYPT | OP_ALG_ALGSEL_AES, 0); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "jobdesc:\n"); ++ dev_info(ksdev, "0x%08x\n", jdesc[0]); ++ dev_info(ksdev, "0x%08x\n", jdesc[1]); ++ dev_info(ksdev, "0x%08x\n", jdesc[2]); ++ dev_info(ksdev, "0x%08x\n", jdesc[3]); ++ dev_info(ksdev, "0x%08x\n", jdesc[4]); ++ dev_info(ksdev, "0x%08x\n", jdesc[5]); ++ dev_info(ksdev, "0x%08x\n", jdesc[6]); ++ dev_info(ksdev, "0x%08x\n", jdesc[7]); ++#endif ++ ++ jstat = exec_test_job(ksdev, jdesc); ++ ++ dma_sync_single_for_cpu(ksdev, symint_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, symint_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, syminp_dma, 256, DMA_TO_DEVICE); ++ dma_unmap_single(ksdev, black_key_aes256_dma, 32, DMA_TO_DEVICE); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "input block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ syminp[0], syminp[1], syminp[2], syminp[3], ++ syminp[4], syminp[5], syminp[6], syminp[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ syminp[8], syminp[9], syminp[10], syminp[11], ++ syminp[12], syminp[13], syminp[14], syminp[15]); ++ dev_info(ksdev, "intermediate block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[0], symint[1], symint[2], symint[3], ++ symint[4], symint[5], symint[6], symint[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[8], symint[9], symint[10], symint[11], ++ symint[12], symint[13], symint[14], symint[15]); ++ dev_info(ksdev, "caam_sm_test: encrypt cycle with 32 byte key\n"); ++#endif ++ ++ /* AES-256 decrypt using 32-byte black key */ ++ clear_key_aes256_dma = dma_map_single(ksdev, clear_key_aes256, 32, ++ DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, clear_key_aes256_dma, 32, ++ DMA_TO_DEVICE); ++ symint_dma = dma_map_single(ksdev, symint, 256, DMA_TO_DEVICE); ++ dma_sync_single_for_device(ksdev, symint_dma, 256, DMA_TO_DEVICE); ++ symout_dma = dma_map_single(ksdev, symout, 256, DMA_FROM_DEVICE); ++ ++ jdescsz = mk_job_desc(jdesc, clear_key_aes256_dma, 32, symint_dma, ++ symout_dma, 256, ++ OP_ALG_DECRYPT | OP_ALG_ALGSEL_AES, 0); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "jobdesc:\n"); ++ dev_info(ksdev, "0x%08x\n", jdesc[0]); ++ dev_info(ksdev, "0x%08x\n", jdesc[1]); ++ dev_info(ksdev, "0x%08x\n", jdesc[2]); ++ dev_info(ksdev, "0x%08x\n", jdesc[3]); ++ dev_info(ksdev, "0x%08x\n", jdesc[4]); ++ dev_info(ksdev, "0x%08x\n", jdesc[5]); ++ dev_info(ksdev, "0x%08x\n", jdesc[6]); ++ dev_info(ksdev, "0x%08x\n", jdesc[7]); ++#endif ++ ++ jstat = exec_test_job(ksdev, jdesc); ++ ++ dma_sync_single_for_cpu(ksdev, symout_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, symout_dma, 256, DMA_FROM_DEVICE); ++ dma_unmap_single(ksdev, symint_dma, 256, DMA_TO_DEVICE); ++ dma_unmap_single(ksdev, clear_key_aes256_dma, 32, DMA_TO_DEVICE); ++ ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "intermediate block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[0], symint[1], symint[2], symint[3], ++ symint[4], symint[5], symint[6], symint[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symint[8], symint[9], symint[10], symint[11], ++ symint[12], symint[13], symint[14], symint[15]); ++ dev_info(ksdev, "decrypted block:\n"); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symout[0], symout[1], symout[2], symout[3], ++ symout[4], symout[5], symout[6], symout[7]); ++ dev_info(ksdev, "0x%02x 0x%02x 0x%02x 0x%02x " \ ++ "0x%02x 0x%02x 0x%02x 0x%02x\n", ++ symout[8], symout[9], symout[10], symout[11], ++ symout[12], symout[13], symout[14], symout[15]); ++ dev_info(ksdev, "caam_sm_test: decrypt cycle with 32 byte key\n"); ++#endif ++ ++ /* Check result */ ++ if (memcmp(symout, syminp, 256)) { ++ dev_info(ksdev, "caam_sm_test: 32-byte key test mismatch\n"); ++ rtnval = -1; ++ goto freekeys; ++ } else ++ dev_info(ksdev, "caam_sm_test: 32-byte key test match OK\n"); ++ ++ ++ /* Remove 8/16/32 byte keys from keystore */ ++freekeys: ++ stat = sm_keystore_slot_dealloc(ksdev, unit, keyslot_des); ++ if (stat) ++ dev_info(ksdev, "caam_sm_test: can't release slot %d\n", ++ keyslot_des); ++ ++ stat = sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes128); ++ if (stat) ++ dev_info(ksdev, "caam_sm_test: can't release slot %d\n", ++ keyslot_aes128); ++ ++ stat = sm_keystore_slot_dealloc(ksdev, unit, keyslot_aes256); ++ if (stat) ++ dev_info(ksdev, "caam_sm_test: can't release slot %d\n", ++ keyslot_aes256); ++ ++ ++ /* Free resources */ ++freemem: ++#ifdef SM_TEST_DETAIL ++ dev_info(ksdev, "caam_sm_test: cleaning up\n"); ++#endif ++ kfree(syminp); ++ kfree(symint); ++ kfree(symout); ++ kfree(clear_key_des); ++ kfree(clear_key_aes128); ++ kfree(clear_key_aes256); ++ kfree(black_key_des); ++ kfree(black_key_aes128); ++ kfree(black_key_aes256); ++ kfree(jdesc); ++ ++ /* Disconnect from keystore and leave */ ++ sm_release_keystore(ksdev, unit); ++ ++ return rtnval; ++} ++EXPORT_SYMBOL(caam_sm_example_init); ++ ++void caam_sm_example_shutdown(void) ++{ ++ /* unused in present version */ ++ struct device_node *dev_node; ++ struct platform_device *pdev; ++ ++ /* ++ * Do of_find_compatible_node() then of_find_device_by_node() ++ * once a functional device tree is available ++ */ ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); ++ if (!dev_node) { ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); ++ if (!dev_node) ++ return; ++ } ++ ++ pdev = of_find_device_by_node(dev_node); ++ if (!pdev) ++ return; ++ ++ of_node_get(dev_node); ++ ++} ++ ++static int __init caam_sm_test_init(void) ++{ ++ struct device_node *dev_node; ++ struct platform_device *pdev; ++ ++ /* ++ * Do of_find_compatible_node() then of_find_device_by_node() ++ * once a functional device tree is available ++ */ ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); ++ if (!dev_node) { ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); ++ if (!dev_node) ++ return -ENODEV; ++ } ++ ++ pdev = of_find_device_by_node(dev_node); ++ if (!pdev) ++ return -ENODEV; ++ ++ of_node_put(dev_node); ++ ++ caam_sm_example_init(pdev); ++ ++ return 0; ++} ++ ++ ++/* Module-based initialization needs to wait for dev tree */ ++#ifdef CONFIG_OF ++module_init(caam_sm_test_init); ++module_exit(caam_sm_example_shutdown); ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("FSL CAAM Keystore Usage Example"); ++MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD"); ++#endif +diff -Nur linux-3.10.30/drivers/crypto/caam/snvsregs.h linux-3.10.30-cubox-i/drivers/crypto/caam/snvsregs.h +--- linux-3.10.30/drivers/crypto/caam/snvsregs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/crypto/caam/snvsregs.h 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,237 @@ ++/* ++ * SNVS hardware register-level view ++ * ++ * Copyright (C) 2013 Freescale Semiconductor, Inc., All Rights Reserved ++ */ ++ ++#ifndef SNVSREGS_H ++#define SNVSREGS_H ++ ++#include ++#include ++ ++/* ++ * SNVS High Power Domain ++ * Includes security violations, HA counter, RTC, alarm ++ */ ++struct snvs_hp { ++ u32 lock; ++ u32 cmd; ++ u32 ctl; ++ u32 secvio_int_en; /* Security Violation Interrupt Enable */ ++ u32 secvio_int_ctl; /* Security Violation Interrupt Control */ ++ u32 status; ++ u32 secvio_status; /* Security Violation Status */ ++ u32 ha_counteriv; /* High Assurance Counter IV */ ++ u32 ha_counter; /* High Assurance Counter */ ++ u32 rtc_msb; /* Real Time Clock/Counter MSB */ ++ u32 rtc_lsb; /* Real Time Counter LSB */ ++ u32 time_alarm_msb; /* Time Alarm MSB */ ++ u32 time_alarm_lsb; /* Time Alarm LSB */ ++}; ++ ++#define HP_LOCK_HAC_LCK 0x00040000 ++#define HP_LOCK_HPSICR_LCK 0x00020000 ++#define HP_LOCK_HPSVCR_LCK 0x00010000 ++#define HP_LOCK_MKEYSEL_LCK 0x00000200 ++#define HP_LOCK_TAMPCFG_LCK 0x00000100 ++#define HP_LOCK_TAMPFLT_LCK 0x00000080 ++#define HP_LOCK_SECVIO_LCK 0x00000040 ++#define HP_LOCK_GENP_LCK 0x00000020 ++#define HP_LOCK_MONOCTR_LCK 0x00000010 ++#define HP_LOCK_CALIB_LCK 0x00000008 ++#define HP_LOCK_SRTC_LCK 0x00000004 ++#define HP_LOCK_ZMK_RD_LCK 0x00000002 ++#define HP_LOCK_ZMK_WT_LCK 0x00000001 ++ ++#define HP_CMD_NONPRIV_AXS 0x80000000 ++#define HP_CMD_HAC_STOP 0x00080000 ++#define HP_CMD_HAC_CLEAR 0x00040000 ++#define HP_CMD_HAC_LOAD 0x00020000 ++#define HP_CMD_HAC_CFG_EN 0x00010000 ++#define HP_CMD_SNVS_MSTR_KEY 0x00002000 ++#define HP_CMD_PROG_ZMK 0x00001000 ++#define HP_CMD_SW_LPSV 0x00000400 ++#define HP_CMD_SW_FSV 0x00000200 ++#define HP_CMD_SW_SV 0x00000100 ++#define HP_CMD_LP_SWR_DIS 0x00000020 ++#define HP_CMD_LP_SWR 0x00000010 ++#define HP_CMD_SSM_SFNS_DIS 0x00000004 ++#define HP_CMD_SSM_ST_DIS 0x00000002 ++#define HP_CMD_SMM_ST 0x00000001 ++ ++#define HP_CTL_TIME_SYNC 0x00010000 ++#define HP_CTL_CAL_VAL_SHIFT 10 ++#define HP_CTL_CAL_VAL_MASK (0x1f << HP_CTL_CALIB_SHIFT) ++#define HP_CTL_CALIB_EN 0x00000100 ++#define HP_CTL_PI_FREQ_SHIFT 4 ++#define HP_CTL_PI_FREQ_MASK (0xf << HP_CTL_PI_FREQ_SHIFT) ++#define HP_CTL_PI_EN 0x00000008 ++#define HP_CTL_TIMEALARM_EN 0x00000002 ++#define HP_CTL_RTC_EN 0x00000001 ++ ++#define HP_SECVIO_INTEN_EN 0x10000000 ++#define HP_SECVIO_INTEN_SRC5 0x00000020 ++#define HP_SECVIO_INTEN_SRC4 0x00000010 ++#define HP_SECVIO_INTEN_SRC3 0x00000008 ++#define HP_SECVIO_INTEN_SRC2 0x00000004 ++#define HP_SECVIO_INTEN_SRC1 0x00000002 ++#define HP_SECVIO_INTEN_SRC0 0x00000001 ++#define HP_SECVIO_INTEN_ALL 0x8000003f ++ ++#define HP_SECVIO_ICTL_CFG_SHIFT 30 ++#define HP_SECVIO_ICTL_CFG_MASK (0x3 << HP_SECVIO_ICTL_CFG_SHIFT) ++#define HP_SECVIO_ICTL_CFG5_SHIFT 5 ++#define HP_SECVIO_ICTL_CFG5_MASK (0x3 << HP_SECVIO_ICTL_CFG5_SHIFT) ++#define HP_SECVIO_ICTL_CFG_DISABLE 0 ++#define HP_SECVIO_ICTL_CFG_NONFATAL 1 ++#define HP_SECVIO_ICTL_CFG_FATAL 2 ++#define HP_SECVIO_ICTL_CFG4_FATAL 0x00000010 ++#define HP_SECVIO_ICTL_CFG3_FATAL 0x00000008 ++#define HP_SECVIO_ICTL_CFG2_FATAL 0x00000004 ++#define HP_SECVIO_ICTL_CFG1_FATAL 0x00000002 ++#define HP_SECVIO_ICTL_CFG0_FATAL 0x00000001 ++ ++#define HP_STATUS_ZMK_ZERO 0x80000000 ++#define HP_STATUS_OTPMK_ZERO 0x08000000 ++#define HP_STATUS_OTPMK_SYN_SHIFT 16 ++#define HP_STATUS_OTPMK_SYN_MASK (0x1ff << HP_STATUS_OTPMK_SYN_SHIFT) ++#define HP_STATUS_SSM_ST_SHIFT 8 ++#define HP_STATUS_SSM_ST_MASK (0xf << HP_STATUS_SSM_ST_SHIFT) ++#define HP_STATUS_SSM_ST_INIT 0 ++#define HP_STATUS_SSM_ST_HARDFAIL 1 ++#define HP_STATUS_SSM_ST_SOFTFAIL 3 ++#define HP_STATUS_SSM_ST_INITINT 8 ++#define HP_STATUS_SSM_ST_CHECK 9 ++#define HP_STATUS_SSM_ST_NONSECURE 11 ++#define HP_STATUS_SSM_ST_TRUSTED 13 ++#define HP_STATUS_SSM_ST_SECURE 15 ++ ++#define HP_SECVIOST_ZMK_ECC_FAIL 0x08000000 /* write to clear */ ++#define HP_SECVIOST_ZMK_SYN_SHIFT 16 ++#define HP_SECVIOST_ZMK_SYN_MASK (0x1ff << HP_SECVIOST_ZMK_SYN_SHIFT) ++#define HP_SECVIOST_SECVIO5 0x00000020 ++#define HP_SECVIOST_SECVIO4 0x00000010 ++#define HP_SECVIOST_SECVIO3 0x00000008 ++#define HP_SECVIOST_SECVIO2 0x00000004 ++#define HP_SECVIOST_SECVIO1 0x00000002 ++#define HP_SECVIOST_SECVIO0 0x00000001 ++#define HP_SECVIOST_SECVIOMASK 0x0000003f ++ ++/* ++ * SNVS Low Power Domain ++ * Includes glitch detector, SRTC, alarm, monotonic counter, ZMK ++ */ ++struct snvs_lp { ++ u32 lock; ++ u32 ctl; ++ u32 mstr_key_ctl; /* Master Key Control */ ++ u32 secvio_ctl; /* Security Violation Control */ ++ u32 tamper_filt_cfg; /* Tamper Glitch Filters Configuration */ ++ u32 tamper_det_cfg; /* Tamper Detectors Configuration */ ++ u32 status; ++ u32 srtc_msb; /* Secure Real Time Clock/Counter MSB */ ++ u32 srtc_lsb; /* Secure Real Time Clock/Counter LSB */ ++ u32 time_alarm; /* Time Alarm */ ++ u32 smc_msb; /* Secure Monotonic Counter MSB */ ++ u32 smc_lsb; /* Secure Monotonic Counter LSB */ ++ u32 pwr_glitch_det; /* Power Glitch Detector */ ++ u32 gen_purpose; ++ u32 zmk[8]; /* Zeroizable Master Key */ ++}; ++ ++#define LP_LOCK_MKEYSEL_LCK 0x00000200 ++#define LP_LOCK_TAMPDET_LCK 0x00000100 ++#define LP_LOCK_TAMPFLT_LCK 0x00000080 ++#define LP_LOCK_SECVIO_LCK 0x00000040 ++#define LP_LOCK_GENP_LCK 0x00000020 ++#define LP_LOCK_MONOCTR_LCK 0x00000010 ++#define LP_LOCK_CALIB_LCK 0x00000008 ++#define LP_LOCK_SRTC_LCK 0x00000004 ++#define LP_LOCK_ZMK_RD_LCK 0x00000002 ++#define LP_LOCK_ZMK_WT_LCK 0x00000001 ++ ++#define LP_CTL_CAL_VAL_SHIFT 10 ++#define LP_CTL_CAL_VAL_MASK (0x1f << LP_CTL_CAL_VAL_SHIFT) ++#define LP_CTL_CALIB_EN 0x00000100 ++#define LP_CTL_SRTC_INVAL_EN 0x00000010 ++#define LP_CTL_WAKE_INT_EN 0x00000008 ++#define LP_CTL_MONOCTR_EN 0x00000004 ++#define LP_CTL_TIMEALARM_EN 0x00000002 ++#define LP_CTL_SRTC_EN 0x00000001 ++ ++#define LP_MKEYCTL_ZMKECC_SHIFT 8 ++#define LP_MKEYCTL_ZMKECC_MASK (0xff << LP_MKEYCTL_ZMKECC_SHIFT) ++#define LP_MKEYCTL_ZMKECC_EN 0x00000010 ++#define LP_MKEYCTL_ZMKECC_VAL 0x00000008 ++#define LP_MKEYCTL_ZMKECC_PROG 0x00000004 ++#define LP_MKEYCTL_MKSEL_SHIFT 0 ++#define LP_MKEYCTL_MKSEL_MASK (3 << LP_MKEYCTL_MKSEL_SHIFT) ++#define LP_MKEYCTL_MK_OTP 0 ++#define LP_MKEYCTL_MK_ZMK 2 ++#define LP_MKEYCTL_MK_COMB 3 ++ ++#define LP_SECVIO_CTL_SRC5 0x20 ++#define LP_SECVIO_CTL_SRC4 0x10 ++#define LP_SECVIO_CTL_SRC3 0x08 ++#define LP_SECVIO_CTL_SRC2 0x04 ++#define LP_SECVIO_CTL_SRC1 0x02 ++#define LP_SECVIO_CTL_SRC0 0x01 ++ ++#define LP_TAMPFILT_EXT2_EN 0x80000000 ++#define LP_TAMPFILT_EXT2_SHIFT 24 ++#define LP_TAMPFILT_EXT2_MASK (0x1f << LP_TAMPFILT_EXT2_SHIFT) ++#define LP_TAMPFILT_EXT1_EN 0x00800000 ++#define LP_TAMPFILT_EXT1_SHIFT 16 ++#define LP_TAMPFILT_EXT1_MASK (0x1f << LP_TAMPFILT_EXT1_SHIFT) ++#define LP_TAMPFILT_WM_EN 0x00000080 ++#define LP_TAMPFILT_WM_SHIFT 0 ++#define LP_TAMPFILT_WM_MASK (0x1f << LP_TAMPFILT_WM_SHIFT) ++ ++#define LP_TAMPDET_OSC_BPS 0x10000000 ++#define LP_TAMPDET_VRC_SHIFT 24 ++#define LP_TAMPDET_VRC_MASK (3 << LP_TAMPFILT_VRC_SHIFT) ++#define LP_TAMPDET_HTDC_SHIFT 20 ++#define LP_TAMPDET_HTDC_MASK (3 << LP_TAMPFILT_HTDC_SHIFT) ++#define LP_TAMPDET_LTDC_SHIFT 16 ++#define LP_TAMPDET_LTDC_MASK (3 << LP_TAMPFILT_LTDC_SHIFT) ++#define LP_TAMPDET_POR_OBS 0x00008000 ++#define LP_TAMPDET_PFD_OBS 0x00004000 ++#define LP_TAMPDET_ET2_EN 0x00000400 ++#define LP_TAMPDET_ET1_EN 0x00000200 ++#define LP_TAMPDET_WMT2_EN 0x00000100 ++#define LP_TAMPDET_WMT1_EN 0x00000080 ++#define LP_TAMPDET_VT_EN 0x00000040 ++#define LP_TAMPDET_TT_EN 0x00000020 ++#define LP_TAMPDET_CT_EN 0x00000010 ++#define LP_TAMPDET_MCR_EN 0x00000004 ++#define LP_TAMPDET_SRTCR_EN 0x00000002 ++ ++#define LP_STATUS_SECURE ++#define LP_STATUS_NONSECURE ++#define LP_STATUS_SCANEXIT 0x00100000 /* all write 1 clear here on */ ++#define LP_STATUS_EXT_SECVIO 0x00010000 ++#define LP_STATUS_ET2 0x00000400 ++#define LP_STATUS_ET1 0x00000200 ++#define LP_STATUS_WMT2 0x00000100 ++#define LP_STATUS_WMT1 0x00000080 ++#define LP_STATUS_VTD 0x00000040 ++#define LP_STATUS_TTD 0x00000020 ++#define LP_STATUS_CTD 0x00000010 ++#define LP_STATUS_PGD 0x00000008 ++#define LP_STATUS_MCR 0x00000004 ++#define LP_STATUS_SRTCR 0x00000002 ++#define LP_STATUS_LPTA 0x00000001 ++ ++/* Full SNVS register page, including version/options */ ++struct snvs_full { ++ struct snvs_hp hp; ++ struct snvs_lp lp; ++ u32 rsvd[731]; /* deadspace 0x08c-0xbf7 */ ++ ++ /* Version / Revision / Option ID space - end of register page */ ++ u32 vid; /* 0xbf8 HP Version ID (VID 1) */ ++ u32 opt_rev; /* 0xbfc HP Options / Revision (VID 2) */ ++}; ++ ++#endif /* SNVSREGS_H */ +diff -Nur linux-3.10.30/drivers/dma/Kconfig linux-3.10.30-cubox-i/drivers/dma/Kconfig +--- linux-3.10.30/drivers/dma/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/dma/Kconfig 2014-03-08 20:33:30.000000000 +0100 +@@ -152,6 +152,19 @@ + To avoid bloating the irq_desc[] array we allocate a sufficient + number of IRQ slots and map them dynamically to specific sources. + ++config MXC_PXP_V2 ++ bool "MXC PxP V2 support" ++ depends on ARM ++ select DMA_ENGINE ++ help ++ Support the PxP (Pixel Pipeline) on i.MX6 DualLite and i.MX6 SoloLite. ++ If unsure, select N. ++ ++config MXC_PXP_CLIENT_DEVICE ++ bool "MXC PxP Client Device" ++ default y ++ depends on MXC_PXP_V2 ++ + config TXX9_DMAC + tristate "Toshiba TXx9 SoC DMA support" + depends on MACH_TX49XX || MACH_TX39XX +diff -Nur linux-3.10.30/drivers/dma/Makefile linux-3.10.30-cubox-i/drivers/dma/Makefile +--- linux-3.10.30/drivers/dma/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/dma/Makefile 2014-03-08 20:33:30.000000000 +0100 +@@ -18,6 +18,7 @@ + obj-$(CONFIG_DW_DMAC) += dw_dmac.o + obj-$(CONFIG_AT_HDMAC) += at_hdmac.o + obj-$(CONFIG_MX3_IPU) += ipu/ ++obj-$(CONFIG_MXC_PXP_V2) += pxp/ + obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o + obj-$(CONFIG_SH_DMAE_BASE) += sh/ + obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o +diff -Nur linux-3.10.30/drivers/dma/imx-sdma.c linux-3.10.30-cubox-i/drivers/dma/imx-sdma.c +--- linux-3.10.30/drivers/dma/imx-sdma.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/dma/imx-sdma.c 2014-03-08 20:33:30.000000000 +0100 +@@ -7,7 +7,7 @@ + * + * Based on code from Freescale: + * +- * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -36,6 +37,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -231,6 +233,14 @@ + + struct sdma_engine; + ++enum sdma_mode { ++ SDMA_MODE_INVALID = 0, ++ SDMA_MODE_LOOP, ++ SDMA_MODE_NORMAL, ++ SDMA_MODE_P2P, ++ SDMA_MODE_NO_BD, ++}; ++ + /** + * struct sdma_channel - housekeeping for a SDMA channel + * +@@ -244,6 +254,7 @@ + * @buf_tail ID of the buffer that was processed + * @done channel completion + * @num_bd max NUM_BD. number of descriptors currently handling ++ * @bd_iram flag indicating the memory location of buffer descriptor + */ + struct sdma_channel { + struct sdma_engine *sdma; +@@ -258,12 +269,16 @@ + unsigned int num_bd; + struct sdma_buffer_descriptor *bd; + dma_addr_t bd_phys; ++ bool bd_iram; + unsigned int pc_from_device, pc_to_device; +- unsigned long flags; +- dma_addr_t per_address; ++ unsigned int device_to_device; ++ unsigned int other_script; ++ enum sdma_mode mode; ++ dma_addr_t per_address, per_address2; + unsigned long event_mask[2]; + unsigned long watermark_level; + u32 shp_addr, per_addr; ++ u32 data_addr1, data_addr2; + struct dma_chan chan; + spinlock_t lock; + struct dma_async_tx_descriptor desc; +@@ -273,8 +288,6 @@ + struct tasklet_struct tasklet; + }; + +-#define IMX_DMA_SG_LOOP BIT(0) +- + #define MAX_DMA_CHANNELS 32 + #define MXC_SDMA_DEFAULT_PRIORITY 1 + #define MXC_SDMA_MIN_PRIORITY 1 +@@ -326,6 +339,7 @@ + struct clk *clk_ahb; + spinlock_t channel_0_lock; + struct sdma_script_start_addrs *script_addrs; ++ struct gen_pool *iram_pool; + }; + + static struct platform_device_id sdma_devtypes[] = { +@@ -435,12 +449,14 @@ + dma_addr_t buf_phys; + int ret; + unsigned long flags; ++ bool use_iram = true; + +- buf_virt = dma_alloc_coherent(NULL, +- size, +- &buf_phys, GFP_KERNEL); ++ buf_virt = gen_pool_dma_alloc(sdma->iram_pool, size, &buf_phys); + if (!buf_virt) { +- return -ENOMEM; ++ use_iram = false; ++ buf_virt = dma_alloc_coherent(NULL, size, &buf_phys, GFP_KERNEL); ++ if (!buf_virt) ++ return -ENOMEM; + } + + spin_lock_irqsave(&sdma->channel_0_lock, flags); +@@ -457,7 +473,10 @@ + + spin_unlock_irqrestore(&sdma->channel_0_lock, flags); + +- dma_free_coherent(NULL, size, buf_virt, buf_phys); ++ if (use_iram) ++ gen_pool_free(sdma->iram_pool, (unsigned long)buf_virt, size); ++ else ++ dma_free_coherent(NULL, size, buf_virt, buf_phys); + + return ret; + } +@@ -542,16 +561,33 @@ + sdmac->desc.callback(sdmac->desc.callback_param); + } + ++static void sdma_handle_other_intr(struct sdma_channel *sdmac) ++{ ++ if (sdmac->desc.callback) ++ sdmac->desc.callback(sdmac->desc.callback_param); ++} ++ + static void sdma_tasklet(unsigned long data) + { + struct sdma_channel *sdmac = (struct sdma_channel *) data; ++ struct sdma_engine *sdma = sdmac->sdma; + + complete(&sdmac->done); + +- if (sdmac->flags & IMX_DMA_SG_LOOP) ++ switch (sdmac->mode) { ++ case SDMA_MODE_LOOP: + sdma_handle_channel_loop(sdmac); +- else ++ break; ++ case SDMA_MODE_NORMAL: + mxc_sdma_handle_channel_normal(sdmac); ++ break; ++ case SDMA_MODE_NO_BD: ++ sdma_handle_other_intr(sdmac); ++ break; ++ default: ++ dev_err(sdma->dev, "invalid SDMA MODE!\n"); ++ break; ++ } + } + + static irqreturn_t sdma_int_handler(int irq, void *dev_id) +@@ -589,9 +625,12 @@ + * two peripherals or memory-to-memory transfers + */ + int per_2_per = 0, emi_2_emi = 0; ++ int other = 0; + + sdmac->pc_from_device = 0; + sdmac->pc_to_device = 0; ++ sdmac->device_to_device = 0; ++ sdmac->other_script = 0; + + switch (peripheral_type) { + case IMX_DMATYPE_MEMORY: +@@ -624,6 +663,9 @@ + emi_2_per = sdma->script_addrs->mcu_2_app_addr; + break; + case IMX_DMATYPE_SSI_SP: ++ per_2_emi = sdma->script_addrs->ssish_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_ssish_addr; ++ break; + case IMX_DMATYPE_MMC: + case IMX_DMATYPE_SDHC: + case IMX_DMATYPE_CSPI_SP: +@@ -633,8 +675,8 @@ + emi_2_per = sdma->script_addrs->mcu_2_shp_addr; + break; + case IMX_DMATYPE_ASRC: +- per_2_emi = sdma->script_addrs->asrc_2_mcu_addr; +- emi_2_per = sdma->script_addrs->asrc_2_mcu_addr; ++ per_2_emi = sdma->script_addrs->shp_2_mcu_addr; ++ emi_2_per = sdma->script_addrs->mcu_2_shp_addr; + per_2_per = sdma->script_addrs->per_2_per_addr; + break; + case IMX_DMATYPE_MSHC: +@@ -651,12 +693,17 @@ + case IMX_DMATYPE_IPU_MEMORY: + emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr; + break; ++ case IMX_DMATYPE_HDMI: ++ other = sdma->script_addrs->hdmi_dma_addr; ++ break; + default: + break; + } + + sdmac->pc_from_device = per_2_emi; + sdmac->pc_to_device = emi_2_per; ++ sdmac->device_to_device = per_2_per; ++ sdmac->other_script = other; + } + + static int sdma_load_context(struct sdma_channel *sdmac) +@@ -669,11 +716,14 @@ + int ret; + unsigned long flags; + +- if (sdmac->direction == DMA_DEV_TO_MEM) { ++ if (sdmac->direction == DMA_DEV_TO_MEM) + load_address = sdmac->pc_from_device; +- } else { ++ else if (sdmac->direction == DMA_DEV_TO_DEV) ++ load_address = sdmac->device_to_device; ++ else if (sdmac->direction == DMA_MEM_TO_DEV) + load_address = sdmac->pc_to_device; +- } ++ else ++ load_address = sdmac->other_script; + + if (load_address < 0) + return load_address; +@@ -693,11 +743,16 @@ + /* Send by context the event mask,base address for peripheral + * and watermark level + */ +- context->gReg[0] = sdmac->event_mask[1]; +- context->gReg[1] = sdmac->event_mask[0]; +- context->gReg[2] = sdmac->per_addr; +- context->gReg[6] = sdmac->shp_addr; +- context->gReg[7] = sdmac->watermark_level; ++ if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) { ++ context->gReg[4] = sdmac->data_addr1; ++ context->gReg[6] = sdmac->data_addr2; ++ } else { ++ context->gReg[0] = sdmac->event_mask[1]; ++ context->gReg[1] = sdmac->event_mask[0]; ++ context->gReg[2] = sdmac->per_addr; ++ context->gReg[6] = sdmac->shp_addr; ++ context->gReg[7] = sdmac->watermark_level; ++ } + + bd0->mode.command = C0_SETDM; + bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD; +@@ -722,6 +777,7 @@ + + static int sdma_config_channel(struct sdma_channel *sdmac) + { ++ struct imx_dma_data *data = sdmac->chan.private; + int ret; + + sdma_disable_channel(sdmac); +@@ -730,12 +786,19 @@ + sdmac->event_mask[1] = 0; + sdmac->shp_addr = 0; + sdmac->per_addr = 0; ++ sdmac->data_addr1 = 0; ++ sdmac->data_addr2 = 0; + + if (sdmac->event_id0) { + if (sdmac->event_id0 >= sdmac->sdma->num_events) + return -EINVAL; + sdma_event_enable(sdmac, sdmac->event_id0); + } ++ if (sdmac->event_id1) { ++ if (sdmac->event_id1 >= sdmac->sdma->num_events) ++ return -EINVAL; ++ sdma_event_enable(sdmac, sdmac->event_id1); ++ } + + switch (sdmac->peripheral_type) { + case IMX_DMATYPE_DSP: +@@ -755,19 +818,75 @@ + (sdmac->peripheral_type != IMX_DMATYPE_DSP)) { + /* Handle multiple event channels differently */ + if (sdmac->event_id1) { +- sdmac->event_mask[1] = BIT(sdmac->event_id1 % 32); +- if (sdmac->event_id1 > 31) +- __set_bit(31, &sdmac->watermark_level); +- sdmac->event_mask[0] = BIT(sdmac->event_id0 % 32); +- if (sdmac->event_id0 > 31) +- __set_bit(30, &sdmac->watermark_level); ++ if (sdmac->event_id0 > 31) { ++ sdmac->event_mask[0] |= 0; ++ __set_bit(28, &sdmac->watermark_level); ++ sdmac->event_mask[1] |= ++ BIT(sdmac->event_id0 % 32); ++ } else { ++ sdmac->event_mask[1] |= 0; ++ sdmac->event_mask[0] |= ++ BIT(sdmac->event_id0 % 32); ++ } ++ if (sdmac->event_id1 > 31) { ++ sdmac->event_mask[0] |= 0; ++ __set_bit(29, &sdmac->watermark_level); ++ sdmac->event_mask[1] |= ++ BIT(sdmac->event_id1 % 32); ++ } else { ++ sdmac->event_mask[1] |= 0; ++ sdmac->event_mask[0] |= ++ BIT(sdmac->event_id1 % 32); ++ } ++ /* BIT 11: ++ * 1 : Source on SPBA ++ * 0 : Source on AIPS ++ */ ++ __set_bit(11, &sdmac->watermark_level); ++ /* BIT 12: ++ * 1 : Destination on SPBA ++ * 0 : Destination on AIPS ++ */ ++ __set_bit(12, &sdmac->watermark_level); ++ __set_bit(31, &sdmac->watermark_level); ++ /* BIT 31: ++ * 1 : Amount of samples to be transferred is ++ * unknown and script will keep on transferring ++ * samples as long as both events are detected ++ * and script must be manually stopped by the ++ * application. ++ * 0 : The amount of samples to be is equal to ++ * the count field of mode word ++ * */ ++ __set_bit(25, &sdmac->watermark_level); ++ __clear_bit(24, &sdmac->watermark_level); + } else { +- __set_bit(sdmac->event_id0, sdmac->event_mask); ++ if (sdmac->event_id0 > 31) { ++ sdmac->event_mask[0] = 0; ++ sdmac->event_mask[1] |= ++ BIT(sdmac->event_id0 % 32); ++ } else { ++ sdmac->event_mask[0] |= ++ BIT(sdmac->event_id0 % 32); ++ sdmac->event_mask[1] = 0; ++ } + } + /* Watermark Level */ + sdmac->watermark_level |= sdmac->watermark_level; + /* Address */ +- sdmac->shp_addr = sdmac->per_address; ++ if (sdmac->direction == DMA_DEV_TO_DEV) { ++ sdmac->shp_addr = sdmac->per_address2; ++ sdmac->per_addr = sdmac->per_address; ++ } else if (sdmac->direction == DMA_TRANS_NONE) { ++ if (sdmac->peripheral_type != IMX_DMATYPE_HDMI || ++ !data->data_addr1 || !data->data_addr2) ++ return -EINVAL; ++ sdmac->data_addr1 = *(u32 *)data->data_addr1; ++ sdmac->data_addr2 = *(u32 *)data->data_addr2; ++ sdmac->watermark_level = 0; ++ } else { ++ sdmac->shp_addr = sdmac->per_address; ++ } + } else { + sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */ + } +@@ -799,10 +918,15 @@ + int channel = sdmac->channel; + int ret = -EBUSY; + +- sdmac->bd = dma_alloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL); ++ sdmac->bd_iram = true; ++ sdmac->bd = gen_pool_dma_alloc(sdma->iram_pool, PAGE_SIZE, &sdmac->bd_phys); + if (!sdmac->bd) { +- ret = -ENOMEM; +- goto out; ++ sdmac->bd_iram = false; ++ sdmac->bd = dma_alloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys, GFP_KERNEL); ++ if (!sdmac->bd) { ++ ret = -ENOMEM; ++ goto out; ++ } + } + + memset(sdmac->bd, 0, PAGE_SIZE); +@@ -863,7 +987,8 @@ + } + + sdmac->peripheral_type = data->peripheral_type; +- sdmac->event_id0 = data->dma_request; ++ sdmac->event_id0 = data->dma_request0; ++ sdmac->event_id1 = data->dma_request1; + + clk_enable(sdmac->sdma->clk_ipg); + clk_enable(sdmac->sdma->clk_ahb); +@@ -881,6 +1006,9 @@ + /* txd.flags will be overwritten in prep funcs */ + sdmac->desc.flags = DMA_CTRL_ACK; + ++ /* Set SDMA channel mode to unvalid to avoid misconfig */ ++ sdmac->mode = SDMA_MODE_INVALID; ++ + return 0; + } + +@@ -901,7 +1029,10 @@ + + sdma_set_channel_priority(sdmac, 0); + +- dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys); ++ if (sdmac->bd_iram) ++ gen_pool_free(sdma->iram_pool, (unsigned long)sdmac->bd, PAGE_SIZE); ++ else ++ dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys); + + clk_disable(sdma->clk_ipg); + clk_disable(sdma->clk_ahb); +@@ -922,7 +1053,7 @@ + return NULL; + sdmac->status = DMA_IN_PROGRESS; + +- sdmac->flags = 0; ++ sdmac->mode = SDMA_MODE_NORMAL; + + sdmac->buf_tail = 0; + +@@ -1015,9 +1146,9 @@ + { + struct sdma_channel *sdmac = to_sdma_chan(chan); + struct sdma_engine *sdma = sdmac->sdma; +- int num_periods = buf_len / period_len; + int channel = sdmac->channel; + int ret, i = 0, buf = 0; ++ int num_periods; + + dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel); + +@@ -1028,12 +1159,33 @@ + + sdmac->buf_tail = 0; + +- sdmac->flags |= IMX_DMA_SG_LOOP; + sdmac->direction = direction; ++ ++ switch (sdmac->direction) { ++ case DMA_DEV_TO_DEV: ++ sdmac->mode = SDMA_MODE_P2P; ++ break; ++ case DMA_TRANS_NONE: ++ sdmac->mode = SDMA_MODE_NO_BD; ++ break; ++ case DMA_MEM_TO_DEV: ++ case DMA_DEV_TO_MEM: ++ sdmac->mode = SDMA_MODE_LOOP; ++ break; ++ default: ++ dev_err(sdma->dev, "invalid SDMA direction %d\n", direction); ++ return NULL; ++ } ++ + ret = sdma_load_context(sdmac); + if (ret) + goto err_out; + ++ if (period_len) ++ num_periods = buf_len / period_len; ++ else ++ return &sdmac->desc; ++ + if (num_periods > NUM_BD) { + dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n", + channel, num_periods, NUM_BD); +@@ -1098,18 +1250,31 @@ + sdma_disable_channel(sdmac); + return 0; + case DMA_SLAVE_CONFIG: +- if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) { ++ if (dmaengine_cfg->direction == DMA_DEV_TO_DEV) { ++ sdmac->per_address = dmaengine_cfg->src_addr; ++ sdmac->per_address2 = dmaengine_cfg->dst_addr; ++ sdmac->watermark_level = 0; ++ sdmac->watermark_level |= ++ dmaengine_cfg->src_maxburst; ++ sdmac->watermark_level |= ++ dmaengine_cfg->dst_maxburst << 16; ++ sdmac->word_size = dmaengine_cfg->dst_addr_width; ++ } else if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) { + sdmac->per_address = dmaengine_cfg->src_addr; + sdmac->watermark_level = dmaengine_cfg->src_maxburst * + dmaengine_cfg->src_addr_width; + sdmac->word_size = dmaengine_cfg->src_addr_width; +- } else { ++ } else if (dmaengine_cfg->direction == DMA_MEM_TO_DEV) { + sdmac->per_address = dmaengine_cfg->dst_addr; + sdmac->watermark_level = dmaengine_cfg->dst_maxburst * + dmaengine_cfg->dst_addr_width; + sdmac->word_size = dmaengine_cfg->dst_addr_width; + } + sdmac->direction = dmaengine_cfg->direction; ++ if (dmaengine_cfg->dma_request0) ++ sdmac->event_id0 = dmaengine_cfg->dma_request0; ++ if (dmaengine_cfg->dma_request1) ++ sdmac->event_id1 = dmaengine_cfg->dma_request1; + return sdma_config_channel(sdmac); + default: + return -ENOSYS; +@@ -1142,7 +1307,7 @@ + sdma_enable_channel(sdma, sdmac->channel); + } + +-#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 ++#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 38 + + static void sdma_add_scripts(struct sdma_engine *sdma, + const struct sdma_script_start_addrs *addr) +@@ -1214,7 +1379,7 @@ + + static int __init sdma_init(struct sdma_engine *sdma) + { +- int i, ret; ++ int i, ret, ccbsize; + dma_addr_t ccb_phys; + + switch (sdma->devtype) { +@@ -1236,14 +1401,17 @@ + /* Be sure SDMA has not started yet */ + writel_relaxed(0, sdma->regs + SDMA_H_C0PTR); + +- sdma->channel_control = dma_alloc_coherent(NULL, +- MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) + +- sizeof(struct sdma_context_data), +- &ccb_phys, GFP_KERNEL); ++ ccbsize = MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) ++ + sizeof(struct sdma_context_data); + ++ sdma->channel_control = gen_pool_dma_alloc(sdma->iram_pool, ccbsize, &ccb_phys); + if (!sdma->channel_control) { +- ret = -ENOMEM; +- goto err_dma_alloc; ++ sdma->channel_control = dma_alloc_coherent(NULL, ccbsize, ++ &ccb_phys, GFP_KERNEL); ++ if (!sdma->channel_control) { ++ ret = -ENOMEM; ++ goto err_dma_alloc; ++ } + } + + sdma->context = (void *)sdma->channel_control + +@@ -1296,6 +1464,36 @@ + return ret; + } + ++static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param) ++{ ++ struct imx_dma_data *data = fn_param; ++ ++ if (!imx_dma_is_general_purpose(chan)) ++ return false; ++ ++ chan->private = data; ++ ++ return true; ++} ++ ++static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec, ++ struct of_dma *ofdma) ++{ ++ struct sdma_engine *sdma = ofdma->of_dma_data; ++ dma_cap_mask_t mask = sdma->dma_device.cap_mask; ++ struct imx_dma_data data; ++ ++ if (dma_spec->args_count != 3) ++ return NULL; ++ ++ data.dma_request0 = dma_spec->args[0]; ++ data.peripheral_type = dma_spec->args[1]; ++ data.priority = dma_spec->args[2]; ++ data.dma_request1 = 0; ++ ++ return dma_request_channel(mask, sdma_filter_fn, &data); ++} ++ + static int __init sdma_probe(struct platform_device *pdev) + { + const struct of_device_id *of_id = +@@ -1397,6 +1595,11 @@ + &sdma->dma_device.channels); + } + ++ if (np) ++ sdma->iram_pool = of_get_named_gen_pool(np, "iram", 0); ++ if (!sdma->iram_pool) ++ dev_warn(&pdev->dev, "no iram assigned, using external mem\n"); ++ + ret = sdma_init(sdma); + if (ret) + goto err_init; +@@ -1443,10 +1646,20 @@ + goto err_init; + } + ++ if (np) { ++ ret = of_dma_controller_register(np, sdma_xlate, sdma); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to register controller\n"); ++ goto err_register; ++ } ++ } ++ + dev_info(sdma->dev, "initialized\n"); + + return 0; + ++err_register: ++ dma_async_device_unregister(&sdma->dma_device); + err_init: + kfree(sdma->script_addrs); + err_alloc: +diff -Nur linux-3.10.30/drivers/dma/pxp/Makefile linux-3.10.30-cubox-i/drivers/dma/pxp/Makefile +--- linux-3.10.30/drivers/dma/pxp/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/dma/pxp/Makefile 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_MXC_PXP_V2) += pxp_dma_v2.o ++obj-$(CONFIG_MXC_PXP_CLIENT_DEVICE) += pxp_device.o +diff -Nur linux-3.10.30/drivers/dma/pxp/pxp_device.c linux-3.10.30-cubox-i/drivers/dma/pxp/pxp_device.c +--- linux-3.10.30/drivers/dma/pxp/pxp_device.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/dma/pxp/pxp_device.c 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,489 @@ ++/* ++ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static atomic_t open_count = ATOMIC_INIT(0); ++ ++static DEFINE_SPINLOCK(pxp_mem_lock); ++static DEFINE_SPINLOCK(pxp_chan_lock); ++static LIST_HEAD(head); ++static LIST_HEAD(list); ++static struct pxp_irq_info irq_info[NR_PXP_VIRT_CHANNEL]; ++ ++struct pxp_chan_handle { ++ int chan_id; ++ int hist_status; ++}; ++ ++/* To track the allocated memory buffer */ ++struct memalloc_record { ++ struct list_head list; ++ struct pxp_mem_desc mem; ++}; ++ ++struct pxp_chan_info { ++ int chan_id; ++ struct dma_chan *dma_chan; ++ struct list_head list; ++}; ++ ++static int pxp_alloc_dma_buffer(struct pxp_mem_desc *mem) ++{ ++ mem->cpu_addr = (unsigned long) ++ dma_alloc_coherent(NULL, PAGE_ALIGN(mem->size), ++ (dma_addr_t *) (&mem->phys_addr), ++ GFP_DMA | GFP_KERNEL); ++ pr_debug("[ALLOC] mem alloc phys_addr = 0x%x\n", mem->phys_addr); ++ if ((void *)(mem->cpu_addr) == NULL) { ++ printk(KERN_ERR "Physical memory allocation error!\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++static void pxp_free_dma_buffer(struct pxp_mem_desc *mem) ++{ ++ if (mem->cpu_addr != 0) { ++ dma_free_coherent(0, PAGE_ALIGN(mem->size), ++ (void *)mem->cpu_addr, mem->phys_addr); ++ } ++} ++ ++static int pxp_free_buffers(void) ++{ ++ struct memalloc_record *rec, *n; ++ struct pxp_mem_desc mem; ++ ++ list_for_each_entry_safe(rec, n, &head, list) { ++ mem = rec->mem; ++ if (mem.cpu_addr != 0) { ++ pxp_free_dma_buffer(&mem); ++ pr_debug("[FREE] freed paddr=0x%08X\n", mem.phys_addr); ++ /* delete from list */ ++ list_del(&rec->list); ++ kfree(rec); ++ } ++ } ++ ++ return 0; ++} ++ ++/* Callback function triggered after PxP receives an EOF interrupt */ ++static void pxp_dma_done(void *arg) ++{ ++ struct pxp_tx_desc *tx_desc = to_tx_desc(arg); ++ struct dma_chan *chan = tx_desc->txd.chan; ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ int chan_id = pxp_chan->dma_chan.chan_id; ++ ++ pr_debug("DMA Done ISR, chan_id %d\n", chan_id); ++ ++ irq_info[chan_id].irq_pending++; ++ irq_info[chan_id].hist_status = tx_desc->hist_status; ++ ++ wake_up_interruptible(&(irq_info[chan_id].waitq)); ++} ++ ++static int pxp_ioc_config_chan(unsigned long arg) ++{ ++ struct scatterlist sg[3]; ++ struct pxp_tx_desc *desc; ++ struct dma_async_tx_descriptor *txd; ++ struct pxp_chan_info *info; ++ struct pxp_config_data pxp_conf; ++ dma_cookie_t cookie; ++ int chan_id; ++ int i, length, ret; ++ ++ ret = copy_from_user(&pxp_conf, ++ (struct pxp_config_data *)arg, ++ sizeof(struct pxp_config_data)); ++ if (ret) ++ return -EFAULT; ++ ++ chan_id = pxp_conf.chan_id; ++ if (chan_id < 0 || chan_id >= NR_PXP_VIRT_CHANNEL) ++ return -ENODEV; ++ ++ init_waitqueue_head(&(irq_info[chan_id].waitq)); ++ ++ /* find the channel */ ++ spin_lock(&pxp_chan_lock); ++ list_for_each_entry(info, &list, list) { ++ if (info->dma_chan->chan_id == chan_id) ++ break; ++ } ++ spin_unlock(&pxp_chan_lock); ++ ++ sg_init_table(sg, 3); ++ ++ txd = ++ info->dma_chan->device->device_prep_slave_sg(info->dma_chan, ++ sg, 3, ++ DMA_TO_DEVICE, ++ DMA_PREP_INTERRUPT, ++ NULL); ++ if (!txd) { ++ pr_err("Error preparing a DMA transaction descriptor.\n"); ++ return -EIO; ++ } ++ ++ txd->callback_param = txd; ++ txd->callback = pxp_dma_done; ++ ++ desc = to_tx_desc(txd); ++ ++ length = desc->len; ++ for (i = 0; i < length; i++) { ++ if (i == 0) { /* S0 */ ++ memcpy(&desc->proc_data, ++ &pxp_conf.proc_data, ++ sizeof(struct pxp_proc_data)); ++ memcpy(&desc->layer_param.s0_param, ++ &pxp_conf.s0_param, ++ sizeof(struct pxp_layer_param)); ++ } else if (i == 1) { /* Output */ ++ memcpy(&desc->layer_param.out_param, ++ &pxp_conf.out_param, ++ sizeof(struct pxp_layer_param)); ++ } else { ++ /* OverLay */ ++ memcpy(&desc->layer_param.ol_param, ++ &pxp_conf.ol_param, ++ sizeof(struct pxp_layer_param)); ++ } ++ ++ desc = desc->next; ++ } ++ ++ cookie = txd->tx_submit(txd); ++ if (cookie < 0) { ++ pr_err("Error tx_submit\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int pxp_device_open(struct inode *inode, struct file *filp) ++{ ++ atomic_inc(&open_count); ++ ++ return 0; ++} ++ ++static int pxp_device_release(struct inode *inode, struct file *filp) ++{ ++ if (atomic_dec_and_test(&open_count)) ++ pxp_free_buffers(); ++ ++ return 0; ++} ++ ++static int pxp_device_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct memalloc_record *rec, *n; ++ int request_size, found; ++ ++ request_size = vma->vm_end - vma->vm_start; ++ found = 0; ++ ++ pr_debug("start=0x%x, pgoff=0x%x, size=0x%x\n", ++ (unsigned int)(vma->vm_start), (unsigned int)(vma->vm_pgoff), ++ request_size); ++ ++ spin_lock(&pxp_mem_lock); ++ list_for_each_entry_safe(rec, n, &head, list) { ++ if (rec->mem.phys_addr == (vma->vm_pgoff << PAGE_SHIFT) && ++ (rec->mem.size <= request_size)) { ++ found = 1; ++ break; ++ } ++ } ++ spin_unlock(&pxp_mem_lock); ++ ++ if (found == 0) ++ return -ENOMEM; ++ ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ ++ return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, ++ request_size, vma->vm_page_prot) ? -EAGAIN : 0; ++} ++ ++static bool chan_filter(struct dma_chan *chan, void *arg) ++{ ++ if (imx_dma_is_pxp(chan)) ++ return true; ++ else ++ return false; ++} ++ ++static long pxp_device_ioctl(struct file *filp, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++ ++ switch (cmd) { ++ case PXP_IOC_GET_CHAN: ++ { ++ struct pxp_chan_info *info; ++ dma_cap_mask_t mask; ++ ++ pr_debug("drv: PXP_IOC_GET_CHAN Line %d\n", __LINE__); ++ info = kzalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) { ++ pr_err("%d: alloc err\n", __LINE__); ++ return -ENOMEM; ++ } ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); ++ dma_cap_set(DMA_PRIVATE, mask); ++ info->dma_chan = ++ dma_request_channel(mask, chan_filter, NULL); ++ if (!info->dma_chan) { ++ pr_err("Unsccessfully received channel!\n"); ++ kfree(info); ++ return -EBUSY; ++ } ++ pr_debug("Successfully received channel." ++ "chan_id %d\n", info->dma_chan->chan_id); ++ ++ spin_lock(&pxp_chan_lock); ++ list_add_tail(&info->list, &list); ++ spin_unlock(&pxp_chan_lock); ++ ++ if (put_user ++ (info->dma_chan->chan_id, (u32 __user *) arg)) ++ return -EFAULT; ++ ++ break; ++ } ++ case PXP_IOC_PUT_CHAN: ++ { ++ int chan_id; ++ struct pxp_chan_info *info; ++ ++ if (get_user(chan_id, (u32 __user *) arg)) ++ return -EFAULT; ++ ++ if (chan_id < 0 || chan_id >= NR_PXP_VIRT_CHANNEL) ++ return -ENODEV; ++ ++ spin_lock(&pxp_chan_lock); ++ list_for_each_entry(info, &list, list) { ++ if (info->dma_chan->chan_id == chan_id) ++ break; ++ } ++ spin_unlock(&pxp_chan_lock); ++ ++ pr_debug("%d release chan_id %d\n", __LINE__, ++ info->dma_chan->chan_id); ++ /* REVISIT */ ++ dma_release_channel(info->dma_chan); ++ spin_lock(&pxp_chan_lock); ++ list_del_init(&info->list); ++ spin_unlock(&pxp_chan_lock); ++ kfree(info); ++ ++ break; ++ } ++ case PXP_IOC_CONFIG_CHAN: ++ { ++ ++ int ret; ++ ++ ret = pxp_ioc_config_chan(arg); ++ if (ret) ++ return ret; ++ ++ break; ++ } ++ case PXP_IOC_START_CHAN: ++ { ++ struct pxp_chan_info *info; ++ int chan_id; ++ ++ if (get_user(chan_id, (u32 __user *) arg)) ++ return -EFAULT; ++ ++ /* find the channel */ ++ spin_lock(&pxp_chan_lock); ++ list_for_each_entry(info, &list, list) { ++ if (info->dma_chan->chan_id == chan_id) ++ break; ++ } ++ spin_unlock(&pxp_chan_lock); ++ ++ dma_async_issue_pending(info->dma_chan); ++ ++ break; ++ } ++ case PXP_IOC_GET_PHYMEM: ++ { ++ struct memalloc_record *rec; ++ ++ rec = kzalloc(sizeof(*rec), GFP_KERNEL); ++ if (!rec) ++ return -ENOMEM; ++ ++ ret = copy_from_user(&(rec->mem), ++ (struct pxp_mem_desc *)arg, ++ sizeof(struct pxp_mem_desc)); ++ if (ret) { ++ kfree(rec); ++ return -EFAULT; ++ } ++ ++ pr_debug("[ALLOC] mem alloc size = 0x%x\n", ++ rec->mem.size); ++ ++ ret = pxp_alloc_dma_buffer(&(rec->mem)); ++ if (ret == -1) { ++ kfree(rec); ++ printk(KERN_ERR ++ "Physical memory allocation error!\n"); ++ break; ++ } ++ ret = copy_to_user((void __user *)arg, &(rec->mem), ++ sizeof(struct pxp_mem_desc)); ++ if (ret) { ++ kfree(rec); ++ ret = -EFAULT; ++ break; ++ } ++ ++ spin_lock(&pxp_mem_lock); ++ list_add(&rec->list, &head); ++ spin_unlock(&pxp_mem_lock); ++ ++ break; ++ } ++ case PXP_IOC_PUT_PHYMEM: ++ { ++ struct memalloc_record *rec, *n; ++ struct pxp_mem_desc pxp_mem; ++ ++ ret = copy_from_user(&pxp_mem, ++ (struct pxp_mem_desc *)arg, ++ sizeof(struct pxp_mem_desc)); ++ if (ret) ++ return -EACCES; ++ ++ pr_debug("[FREE] mem freed cpu_addr = 0x%x\n", ++ pxp_mem.cpu_addr); ++ if ((void *)pxp_mem.cpu_addr != NULL) ++ pxp_free_dma_buffer(&pxp_mem); ++ ++ spin_lock(&pxp_mem_lock); ++ list_for_each_entry_safe(rec, n, &head, list) { ++ if (rec->mem.cpu_addr == pxp_mem.cpu_addr) { ++ /* delete from list */ ++ list_del(&rec->list); ++ kfree(rec); ++ break; ++ } ++ } ++ spin_unlock(&pxp_mem_lock); ++ ++ break; ++ } ++ case PXP_IOC_WAIT4CMPLT: ++ { ++ struct pxp_chan_handle chan_handle; ++ int ret, chan_id; ++ ++ ret = copy_from_user(&chan_handle, ++ (struct pxp_chan_handle *)arg, ++ sizeof(struct pxp_chan_handle)); ++ if (ret) ++ return -EFAULT; ++ ++ chan_id = chan_handle.chan_id; ++ if (chan_id < 0 || chan_id >= NR_PXP_VIRT_CHANNEL) ++ return -ENODEV; ++ ++ ret = wait_event_interruptible ++ (irq_info[chan_id].waitq, ++ (irq_info[chan_id].irq_pending != 0)); ++ if (ret < 0) { ++ printk(KERN_WARNING ++ "pxp interrupt received.\n"); ++ return -ERESTARTSYS; ++ } else ++ irq_info[chan_id].irq_pending--; ++ ++ chan_handle.hist_status = irq_info[chan_id].hist_status; ++ ret = copy_to_user((struct pxp_chan_handle *)arg, ++ &chan_handle, ++ sizeof(struct pxp_chan_handle)); ++ if (ret) ++ return -EFAULT; ++ break; ++ } ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static const struct file_operations pxp_device_fops = { ++ .open = pxp_device_open, ++ .release = pxp_device_release, ++ .unlocked_ioctl = pxp_device_ioctl, ++ .mmap = pxp_device_mmap, ++}; ++ ++static struct miscdevice pxp_device_miscdev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "pxp_device", ++ .fops = &pxp_device_fops, ++}; ++ ++int register_pxp_device(void) ++{ ++ int ret; ++ ++ ret = misc_register(&pxp_device_miscdev); ++ if (ret) ++ return ret; ++ ++ pr_debug("PxP_Device registered Successfully\n"); ++ return 0; ++} ++ ++void unregister_pxp_device(void) ++{ ++ misc_deregister(&pxp_device_miscdev); ++} +diff -Nur linux-3.10.30/drivers/dma/pxp/pxp_dma_v2.c linux-3.10.30-cubox-i/drivers/dma/pxp/pxp_dma_v2.c +--- linux-3.10.30/drivers/dma/pxp/pxp_dma_v2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/dma/pxp/pxp_dma_v2.c 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,1936 @@ ++/* ++ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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 ++ * ++ */ ++/* ++ * Based on STMP378X PxP driver ++ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "regs-pxp_v2.h" ++ ++#define PXP_DOWNSCALE_THRESHOLD 0x4000 ++ ++static LIST_HEAD(head); ++static int timeout_in_ms = 600; ++static unsigned int block_size; ++struct mutex hard_lock; ++ ++struct pxp_dma { ++ struct dma_device dma; ++}; ++ ++struct pxps { ++ struct platform_device *pdev; ++ struct clk *clk; ++ void __iomem *base; ++ int irq; /* PXP IRQ to the CPU */ ++ ++ spinlock_t lock; ++ struct mutex clk_mutex; ++ int clk_stat; ++#define CLK_STAT_OFF 0 ++#define CLK_STAT_ON 1 ++ int pxp_ongoing; ++ int lut_state; ++ ++ struct device *dev; ++ struct pxp_dma pxp_dma; ++ struct pxp_channel channel[NR_PXP_VIRT_CHANNEL]; ++ struct work_struct work; ++ ++ /* describes most recent processing configuration */ ++ struct pxp_config_data pxp_conf_state; ++ ++ /* to turn clock off when pxp is inactive */ ++ struct timer_list clk_timer; ++}; ++ ++#define to_pxp_dma(d) container_of(d, struct pxp_dma, dma) ++#define to_tx_desc(tx) container_of(tx, struct pxp_tx_desc, txd) ++#define to_pxp_channel(d) container_of(d, struct pxp_channel, dma_chan) ++#define to_pxp(id) container_of(id, struct pxps, pxp_dma) ++ ++#define PXP_DEF_BUFS 2 ++#define PXP_MIN_PIX 8 ++ ++static uint32_t pxp_s0_formats[] = { ++ PXP_PIX_FMT_RGB32, ++ PXP_PIX_FMT_RGB565, ++ PXP_PIX_FMT_RGB555, ++ PXP_PIX_FMT_YUV420P, ++ PXP_PIX_FMT_YUV422P, ++}; ++ ++/* ++ * PXP common functions ++ */ ++static void dump_pxp_reg(struct pxps *pxp) ++{ ++ dev_dbg(pxp->dev, "PXP_CTRL 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CTRL)); ++ dev_dbg(pxp->dev, "PXP_STAT 0x%x", ++ __raw_readl(pxp->base + HW_PXP_STAT)); ++ dev_dbg(pxp->dev, "PXP_OUT_CTRL 0x%x", ++ __raw_readl(pxp->base + HW_PXP_OUT_CTRL)); ++ dev_dbg(pxp->dev, "PXP_OUT_BUF 0x%x", ++ __raw_readl(pxp->base + HW_PXP_OUT_BUF)); ++ dev_dbg(pxp->dev, "PXP_OUT_BUF2 0x%x", ++ __raw_readl(pxp->base + HW_PXP_OUT_BUF2)); ++ dev_dbg(pxp->dev, "PXP_OUT_PITCH 0x%x", ++ __raw_readl(pxp->base + HW_PXP_OUT_PITCH)); ++ dev_dbg(pxp->dev, "PXP_OUT_LRC 0x%x", ++ __raw_readl(pxp->base + HW_PXP_OUT_LRC)); ++ dev_dbg(pxp->dev, "PXP_OUT_PS_ULC 0x%x", ++ __raw_readl(pxp->base + HW_PXP_OUT_PS_ULC)); ++ dev_dbg(pxp->dev, "PXP_OUT_PS_LRC 0x%x", ++ __raw_readl(pxp->base + HW_PXP_OUT_PS_LRC)); ++ dev_dbg(pxp->dev, "PXP_OUT_AS_ULC 0x%x", ++ __raw_readl(pxp->base + HW_PXP_OUT_AS_ULC)); ++ dev_dbg(pxp->dev, "PXP_OUT_AS_LRC 0x%x", ++ __raw_readl(pxp->base + HW_PXP_OUT_AS_LRC)); ++ dev_dbg(pxp->dev, "PXP_PS_CTRL 0x%x", ++ __raw_readl(pxp->base + HW_PXP_PS_CTRL)); ++ dev_dbg(pxp->dev, "PXP_PS_BUF 0x%x", ++ __raw_readl(pxp->base + HW_PXP_PS_BUF)); ++ dev_dbg(pxp->dev, "PXP_PS_UBUF 0x%x", ++ __raw_readl(pxp->base + HW_PXP_PS_UBUF)); ++ dev_dbg(pxp->dev, "PXP_PS_VBUF 0x%x", ++ __raw_readl(pxp->base + HW_PXP_PS_VBUF)); ++ dev_dbg(pxp->dev, "PXP_PS_PITCH 0x%x", ++ __raw_readl(pxp->base + HW_PXP_PS_PITCH)); ++ dev_dbg(pxp->dev, "PXP_PS_BACKGROUND 0x%x", ++ __raw_readl(pxp->base + HW_PXP_PS_BACKGROUND)); ++ dev_dbg(pxp->dev, "PXP_PS_SCALE 0x%x", ++ __raw_readl(pxp->base + HW_PXP_PS_SCALE)); ++ dev_dbg(pxp->dev, "PXP_PS_OFFSET 0x%x", ++ __raw_readl(pxp->base + HW_PXP_PS_OFFSET)); ++ dev_dbg(pxp->dev, "PXP_PS_CLRKEYLOW 0x%x", ++ __raw_readl(pxp->base + HW_PXP_PS_CLRKEYLOW)); ++ dev_dbg(pxp->dev, "PXP_PS_CLRKEYHIGH 0x%x", ++ __raw_readl(pxp->base + HW_PXP_PS_CLRKEYHIGH)); ++ dev_dbg(pxp->dev, "PXP_AS_CTRL 0x%x", ++ __raw_readl(pxp->base + HW_PXP_AS_CTRL)); ++ dev_dbg(pxp->dev, "PXP_AS_BUF 0x%x", ++ __raw_readl(pxp->base + HW_PXP_AS_BUF)); ++ dev_dbg(pxp->dev, "PXP_AS_PITCH 0x%x", ++ __raw_readl(pxp->base + HW_PXP_AS_PITCH)); ++ dev_dbg(pxp->dev, "PXP_AS_CLRKEYLOW 0x%x", ++ __raw_readl(pxp->base + HW_PXP_AS_CLRKEYLOW)); ++ dev_dbg(pxp->dev, "PXP_AS_CLRKEYHIGH 0x%x", ++ __raw_readl(pxp->base + HW_PXP_AS_CLRKEYHIGH)); ++ dev_dbg(pxp->dev, "PXP_CSC1_COEF0 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CSC1_COEF0)); ++ dev_dbg(pxp->dev, "PXP_CSC1_COEF1 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CSC1_COEF1)); ++ dev_dbg(pxp->dev, "PXP_CSC1_COEF2 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CSC1_COEF2)); ++ dev_dbg(pxp->dev, "PXP_CSC2_CTRL 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CSC2_CTRL)); ++ dev_dbg(pxp->dev, "PXP_CSC2_COEF0 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CSC2_COEF0)); ++ dev_dbg(pxp->dev, "PXP_CSC2_COEF1 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CSC2_COEF1)); ++ dev_dbg(pxp->dev, "PXP_CSC2_COEF2 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CSC2_COEF2)); ++ dev_dbg(pxp->dev, "PXP_CSC2_COEF3 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CSC2_COEF3)); ++ dev_dbg(pxp->dev, "PXP_CSC2_COEF4 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CSC2_COEF4)); ++ dev_dbg(pxp->dev, "PXP_CSC2_COEF5 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CSC2_COEF5)); ++ dev_dbg(pxp->dev, "PXP_LUT_CTRL 0x%x", ++ __raw_readl(pxp->base + HW_PXP_LUT_CTRL)); ++ dev_dbg(pxp->dev, "PXP_LUT_ADDR 0x%x", ++ __raw_readl(pxp->base + HW_PXP_LUT_ADDR)); ++ dev_dbg(pxp->dev, "PXP_LUT_DATA 0x%x", ++ __raw_readl(pxp->base + HW_PXP_LUT_DATA)); ++ dev_dbg(pxp->dev, "PXP_LUT_EXTMEM 0x%x", ++ __raw_readl(pxp->base + HW_PXP_LUT_EXTMEM)); ++ dev_dbg(pxp->dev, "PXP_CFA 0x%x", ++ __raw_readl(pxp->base + HW_PXP_CFA)); ++ dev_dbg(pxp->dev, "PXP_HIST_CTRL 0x%x", ++ __raw_readl(pxp->base + HW_PXP_HIST_CTRL)); ++ dev_dbg(pxp->dev, "PXP_HIST2_PARAM 0x%x", ++ __raw_readl(pxp->base + HW_PXP_HIST2_PARAM)); ++ dev_dbg(pxp->dev, "PXP_HIST4_PARAM 0x%x", ++ __raw_readl(pxp->base + HW_PXP_HIST4_PARAM)); ++ dev_dbg(pxp->dev, "PXP_HIST8_PARAM0 0x%x", ++ __raw_readl(pxp->base + HW_PXP_HIST8_PARAM0)); ++ dev_dbg(pxp->dev, "PXP_HIST8_PARAM1 0x%x", ++ __raw_readl(pxp->base + HW_PXP_HIST8_PARAM1)); ++ dev_dbg(pxp->dev, "PXP_HIST16_PARAM0 0x%x", ++ __raw_readl(pxp->base + HW_PXP_HIST16_PARAM0)); ++ dev_dbg(pxp->dev, "PXP_HIST16_PARAM1 0x%x", ++ __raw_readl(pxp->base + HW_PXP_HIST16_PARAM1)); ++ dev_dbg(pxp->dev, "PXP_HIST16_PARAM2 0x%x", ++ __raw_readl(pxp->base + HW_PXP_HIST16_PARAM2)); ++ dev_dbg(pxp->dev, "PXP_HIST16_PARAM3 0x%x", ++ __raw_readl(pxp->base + HW_PXP_HIST16_PARAM3)); ++ dev_dbg(pxp->dev, "PXP_POWER 0x%x", ++ __raw_readl(pxp->base + HW_PXP_POWER)); ++ dev_dbg(pxp->dev, "PXP_NEXT 0x%x", ++ __raw_readl(pxp->base + HW_PXP_NEXT)); ++ dev_dbg(pxp->dev, "PXP_DEBUGCTRL 0x%x", ++ __raw_readl(pxp->base + HW_PXP_DEBUGCTRL)); ++ dev_dbg(pxp->dev, "PXP_DEBUG 0x%x", ++ __raw_readl(pxp->base + HW_PXP_DEBUG)); ++ dev_dbg(pxp->dev, "PXP_VERSION 0x%x", ++ __raw_readl(pxp->base + HW_PXP_VERSION)); ++} ++ ++static bool is_yuv(u32 pix_fmt) ++{ ++ if ((pix_fmt == PXP_PIX_FMT_YUYV) | ++ (pix_fmt == PXP_PIX_FMT_UYVY) | ++ (pix_fmt == PXP_PIX_FMT_YVYU) | ++ (pix_fmt == PXP_PIX_FMT_VYUY) | ++ (pix_fmt == PXP_PIX_FMT_Y41P) | ++ (pix_fmt == PXP_PIX_FMT_YUV444) | ++ (pix_fmt == PXP_PIX_FMT_NV12) | ++ (pix_fmt == PXP_PIX_FMT_NV16) | ++ (pix_fmt == PXP_PIX_FMT_NV61) | ++ (pix_fmt == PXP_PIX_FMT_GREY) | ++ (pix_fmt == PXP_PIX_FMT_GY04) | ++ (pix_fmt == PXP_PIX_FMT_YVU410P) | ++ (pix_fmt == PXP_PIX_FMT_YUV410P) | ++ (pix_fmt == PXP_PIX_FMT_YVU420P) | ++ (pix_fmt == PXP_PIX_FMT_YUV420P) | ++ (pix_fmt == PXP_PIX_FMT_YUV420P2) | ++ (pix_fmt == PXP_PIX_FMT_YVU422P) | ++ (pix_fmt == PXP_PIX_FMT_YUV422P)) { ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++static void pxp_set_ctrl(struct pxps *pxp) ++{ ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ struct pxp_proc_data *proc_data = &pxp_conf->proc_data; ++ u32 ctrl; ++ u32 fmt_ctrl; ++ int need_swap = 0; /* to support YUYV and YVYU formats */ ++ ++ /* Configure S0 input format */ ++ switch (pxp_conf->s0_param.pixel_fmt) { ++ case PXP_PIX_FMT_RGB32: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB888; ++ break; ++ case PXP_PIX_FMT_RGB565: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB565; ++ break; ++ case PXP_PIX_FMT_RGB555: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB555; ++ break; ++ case PXP_PIX_FMT_YUV420P: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV420; ++ break; ++ case PXP_PIX_FMT_YVU420P: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV420; ++ break; ++ case PXP_PIX_FMT_GREY: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__Y8; ++ break; ++ case PXP_PIX_FMT_GY04: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__Y4; ++ break; ++ case PXP_PIX_FMT_YUV422P: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV422; ++ break; ++ case PXP_PIX_FMT_UYVY: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422; ++ break; ++ case PXP_PIX_FMT_YUYV: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422; ++ need_swap = 1; ++ break; ++ case PXP_PIX_FMT_VYUY: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__VYUY1P422; ++ break; ++ case PXP_PIX_FMT_YVYU: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__VYUY1P422; ++ need_swap = 1; ++ break; ++ case PXP_PIX_FMT_NV12: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV2P420; ++ break; ++ case PXP_PIX_FMT_NV21: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YVU2P420; ++ break; ++ case PXP_PIX_FMT_NV16: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV2P422; ++ break; ++ case PXP_PIX_FMT_NV61: ++ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YVU2P422; ++ break; ++ default: ++ fmt_ctrl = 0; ++ } ++ ++ ctrl = BF_PXP_PS_CTRL_FORMAT(fmt_ctrl) | BF_PXP_PS_CTRL_SWAP(need_swap); ++ __raw_writel(ctrl, pxp->base + HW_PXP_PS_CTRL_SET); ++ ++ /* Configure output format based on out_channel format */ ++ switch (pxp_conf->out_param.pixel_fmt) { ++ case PXP_PIX_FMT_RGB32: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB888; ++ break; ++ case PXP_PIX_FMT_BGRA32: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__ARGB8888; ++ break; ++ case PXP_PIX_FMT_RGB24: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB888P; ++ break; ++ case PXP_PIX_FMT_RGB565: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB565; ++ break; ++ case PXP_PIX_FMT_RGB555: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB555; ++ break; ++ case PXP_PIX_FMT_GREY: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__Y8; ++ break; ++ case PXP_PIX_FMT_GY04: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__Y4; ++ break; ++ case PXP_PIX_FMT_UYVY: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__UYVY1P422; ++ break; ++ case PXP_PIX_FMT_VYUY: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__VYUY1P422; ++ break; ++ case PXP_PIX_FMT_NV12: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YUV2P420; ++ break; ++ case PXP_PIX_FMT_NV21: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YVU2P420; ++ break; ++ case PXP_PIX_FMT_NV16: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YUV2P422; ++ break; ++ case PXP_PIX_FMT_NV61: ++ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YVU2P422; ++ break; ++ default: ++ fmt_ctrl = 0; ++ } ++ ++ ctrl = BF_PXP_OUT_CTRL_FORMAT(fmt_ctrl); ++ __raw_writel(ctrl, pxp->base + HW_PXP_OUT_CTRL); ++ ++ ctrl = 0; ++ if (proc_data->scaling) ++ ; ++ if (proc_data->vflip) ++ ctrl |= BM_PXP_CTRL_VFLIP; ++ if (proc_data->hflip) ++ ctrl |= BM_PXP_CTRL_HFLIP; ++ if (proc_data->rotate) { ++ ctrl |= BF_PXP_CTRL_ROTATE(proc_data->rotate / 90); ++ if (proc_data->rot_pos) ++ ctrl |= BM_PXP_CTRL_ROT_POS; ++ } ++ ++ /* In default, the block size is set to 8x8 ++ * But block size can be set to 16x16 due to ++ * blocksize variable modification ++ */ ++ ctrl |= block_size << 23; ++ ++ __raw_writel(ctrl, pxp->base + HW_PXP_CTRL); ++} ++ ++static int pxp_start(struct pxps *pxp) ++{ ++ __raw_writel(BM_PXP_CTRL_IRQ_ENABLE, pxp->base + HW_PXP_CTRL_SET); ++ __raw_writel(BM_PXP_CTRL_ENABLE, pxp->base + HW_PXP_CTRL_SET); ++ dump_pxp_reg(pxp); ++ ++ return 0; ++} ++ ++static void pxp_set_outbuf(struct pxps *pxp) ++{ ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ struct pxp_layer_param *out_params = &pxp_conf->out_param; ++ ++ __raw_writel(out_params->paddr, pxp->base + HW_PXP_OUT_BUF); ++ ++ __raw_writel(BF_PXP_OUT_LRC_X(out_params->width - 1) | ++ BF_PXP_OUT_LRC_Y(out_params->height - 1), ++ pxp->base + HW_PXP_OUT_LRC); ++ ++ if (out_params->pixel_fmt == PXP_PIX_FMT_RGB24) { ++ __raw_writel(out_params->stride * 3, ++ pxp->base + HW_PXP_OUT_PITCH); ++ } else if (out_params->pixel_fmt == PXP_PIX_FMT_BGRA32 || ++ out_params->pixel_fmt == PXP_PIX_FMT_RGB32) { ++ __raw_writel(out_params->stride << 2, ++ pxp->base + HW_PXP_OUT_PITCH); ++ } else if (out_params->pixel_fmt == PXP_PIX_FMT_RGB565) { ++ __raw_writel(out_params->stride << 1, ++ pxp->base + HW_PXP_OUT_PITCH); ++ } else if (out_params->pixel_fmt == PXP_PIX_FMT_UYVY || ++ (out_params->pixel_fmt == PXP_PIX_FMT_VYUY)) { ++ __raw_writel(out_params->stride << 1, ++ pxp->base + HW_PXP_OUT_PITCH); ++ } else if (out_params->pixel_fmt == PXP_PIX_FMT_GREY || ++ out_params->pixel_fmt == PXP_PIX_FMT_NV12 || ++ out_params->pixel_fmt == PXP_PIX_FMT_NV21 || ++ out_params->pixel_fmt == PXP_PIX_FMT_NV16 || ++ out_params->pixel_fmt == PXP_PIX_FMT_NV61) { ++ __raw_writel(out_params->stride, ++ pxp->base + HW_PXP_OUT_PITCH); ++ } else if (out_params->pixel_fmt == PXP_PIX_FMT_GY04) { ++ __raw_writel(out_params->stride >> 1, ++ pxp->base + HW_PXP_OUT_PITCH); ++ } else { ++ __raw_writel(0, pxp->base + HW_PXP_OUT_PITCH); ++ } ++ ++ /* set global alpha if necessary */ ++ if (out_params->global_alpha_enable) { ++ __raw_writel(out_params->global_alpha << 24, ++ pxp->base + HW_PXP_OUT_CTRL_SET); ++ __raw_writel(BM_PXP_OUT_CTRL_ALPHA_OUTPUT, ++ pxp->base + HW_PXP_OUT_CTRL_SET); ++ } ++} ++ ++static void pxp_set_s0colorkey(struct pxps *pxp) ++{ ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ struct pxp_layer_param *s0_params = &pxp_conf->s0_param; ++ ++ /* Low and high are set equal. V4L does not allow a chromakey range */ ++ if (s0_params->color_key_enable == 0 || s0_params->color_key == -1) { ++ /* disable color key */ ++ __raw_writel(0xFFFFFF, pxp->base + HW_PXP_PS_CLRKEYLOW); ++ __raw_writel(0, pxp->base + HW_PXP_PS_CLRKEYHIGH); ++ } else { ++ __raw_writel(s0_params->color_key, ++ pxp->base + HW_PXP_PS_CLRKEYLOW); ++ __raw_writel(s0_params->color_key, ++ pxp->base + HW_PXP_PS_CLRKEYHIGH); ++ } ++} ++ ++static void pxp_set_olcolorkey(int layer_no, struct pxps *pxp) ++{ ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ struct pxp_layer_param *ol_params = &pxp_conf->ol_param[layer_no]; ++ ++ /* Low and high are set equal. V4L does not allow a chromakey range */ ++ if (ol_params->color_key_enable != 0 && ol_params->color_key != -1) { ++ __raw_writel(ol_params->color_key, ++ pxp->base + HW_PXP_AS_CLRKEYLOW); ++ __raw_writel(ol_params->color_key, ++ pxp->base + HW_PXP_AS_CLRKEYHIGH); ++ } else { ++ /* disable color key */ ++ __raw_writel(0xFFFFFF, pxp->base + HW_PXP_AS_CLRKEYLOW); ++ __raw_writel(0, pxp->base + HW_PXP_AS_CLRKEYHIGH); ++ } ++} ++ ++static void pxp_set_oln(int layer_no, struct pxps *pxp) ++{ ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ struct pxp_layer_param *olparams_data = &pxp_conf->ol_param[layer_no]; ++ dma_addr_t phys_addr = olparams_data->paddr; ++ u32 pitch = olparams_data->stride ? olparams_data->stride : ++ olparams_data->width; ++ ++ __raw_writel(phys_addr, pxp->base + HW_PXP_AS_BUF); ++ ++ /* Fixme */ ++ if (olparams_data->width == 0 && olparams_data->height == 0) { ++ __raw_writel(0xffffffff, pxp->base + HW_PXP_OUT_AS_ULC); ++ __raw_writel(0x0, pxp->base + HW_PXP_OUT_AS_LRC); ++ } else { ++ __raw_writel(0x0, pxp->base + HW_PXP_OUT_AS_ULC); ++ if (pxp_conf->proc_data.rotate == 90 || ++ pxp_conf->proc_data.rotate == 270) { ++ if (pxp_conf->proc_data.rot_pos == 1) { ++ __raw_writel(BF_PXP_OUT_AS_LRC_X(olparams_data->height - 1) | ++ BF_PXP_OUT_AS_LRC_Y(olparams_data->width - 1), ++ pxp->base + HW_PXP_OUT_AS_LRC); ++ } else { ++ __raw_writel(BF_PXP_OUT_AS_LRC_X(olparams_data->width - 1) | ++ BF_PXP_OUT_AS_LRC_Y(olparams_data->height - 1), ++ pxp->base + HW_PXP_OUT_AS_LRC); ++ } ++ } else { ++ __raw_writel(BF_PXP_OUT_AS_LRC_X(olparams_data->width - 1) | ++ BF_PXP_OUT_AS_LRC_Y(olparams_data->height - 1), ++ pxp->base + HW_PXP_OUT_AS_LRC); ++ } ++ } ++ ++ if ((olparams_data->pixel_fmt == PXP_PIX_FMT_BGRA32) | ++ (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB32)) { ++ __raw_writel(pitch << 2, ++ pxp->base + HW_PXP_AS_PITCH); ++ } else if (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB565) { ++ __raw_writel(pitch << 1, ++ pxp->base + HW_PXP_AS_PITCH); ++ } else { ++ __raw_writel(0, pxp->base + HW_PXP_AS_PITCH); ++ } ++} ++ ++static void pxp_set_olparam(int layer_no, struct pxps *pxp) ++{ ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ struct pxp_layer_param *olparams_data = &pxp_conf->ol_param[layer_no]; ++ u32 olparam; ++ ++ olparam = BF_PXP_AS_CTRL_ALPHA(olparams_data->global_alpha); ++ if (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB32) { ++ olparam |= ++ BF_PXP_AS_CTRL_FORMAT(BV_PXP_AS_CTRL_FORMAT__RGB888); ++ } else if (olparams_data->pixel_fmt == PXP_PIX_FMT_BGRA32) { ++ olparam |= ++ BF_PXP_AS_CTRL_FORMAT(BV_PXP_AS_CTRL_FORMAT__ARGB8888); ++ if (!olparams_data->combine_enable) { ++ olparam |= ++ BF_PXP_AS_CTRL_ALPHA_CTRL ++ (BV_PXP_AS_CTRL_ALPHA_CTRL__ROPs); ++ olparam |= 0x3 << 16; ++ } ++ } else if (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB565) { ++ olparam |= ++ BF_PXP_AS_CTRL_FORMAT(BV_PXP_AS_CTRL_FORMAT__RGB565); ++ } ++ if (olparams_data->global_alpha_enable) { ++ if (olparams_data->global_override) { ++ olparam |= ++ BF_PXP_AS_CTRL_ALPHA_CTRL ++ (BV_PXP_AS_CTRL_ALPHA_CTRL__Override); ++ } else { ++ olparam |= ++ BF_PXP_AS_CTRL_ALPHA_CTRL ++ (BV_PXP_AS_CTRL_ALPHA_CTRL__Multiply); ++ } ++ if (olparams_data->alpha_invert) ++ olparam |= BM_PXP_AS_CTRL_ALPHA_INVERT; ++ } ++ if (olparams_data->color_key_enable) ++ olparam |= BM_PXP_AS_CTRL_ENABLE_COLORKEY; ++ ++ __raw_writel(olparam, pxp->base + HW_PXP_AS_CTRL); ++} ++ ++static void pxp_set_s0param(struct pxps *pxp) ++{ ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ struct pxp_proc_data *proc_data = &pxp_conf->proc_data; ++ u32 s0param; ++ ++ /* contains the coordinate for the PS in the OUTPUT buffer. */ ++ if ((pxp_conf->s0_param).width == 0 && ++ (pxp_conf->s0_param).height == 0) { ++ __raw_writel(0xffffffff, pxp->base + HW_PXP_OUT_PS_ULC); ++ __raw_writel(0x0, pxp->base + HW_PXP_OUT_PS_LRC); ++ } else { ++ s0param = BF_PXP_OUT_PS_ULC_X(proc_data->drect.left); ++ s0param |= BF_PXP_OUT_PS_ULC_Y(proc_data->drect.top); ++ __raw_writel(s0param, pxp->base + HW_PXP_OUT_PS_ULC); ++ s0param = BF_PXP_OUT_PS_LRC_X(proc_data->drect.left + ++ proc_data->drect.width - 1); ++ s0param |= BF_PXP_OUT_PS_LRC_Y(proc_data->drect.top + ++ proc_data->drect.height - 1); ++ __raw_writel(s0param, pxp->base + HW_PXP_OUT_PS_LRC); ++ } ++} ++ ++/* crop behavior is re-designed in h/w. */ ++static void pxp_set_s0crop(struct pxps *pxp) ++{ ++ /* ++ * place-holder, it's implemented in other functions in this driver. ++ * Refer to "Clipping source images" section in RM for detail. ++ */ ++} ++ ++static int pxp_set_scaling(struct pxps *pxp) ++{ ++ int ret = 0; ++ u32 xscale, yscale, s0scale; ++ u32 decx, decy, xdec = 0, ydec = 0; ++ struct pxp_proc_data *proc_data = &pxp->pxp_conf_state.proc_data; ++ ++ if (((proc_data->srect.width == proc_data->drect.width) && ++ (proc_data->srect.height == proc_data->drect.height)) || ++ ((proc_data->srect.width == 0) && (proc_data->srect.height == 0))) { ++ proc_data->scaling = 0; ++ __raw_writel(0x10001000, pxp->base + HW_PXP_PS_SCALE); ++ __raw_writel(0, pxp->base + HW_PXP_PS_CTRL); ++ goto out; ++ } ++ ++ proc_data->scaling = 1; ++ decx = proc_data->srect.width / proc_data->drect.width; ++ decy = proc_data->srect.height / proc_data->drect.height; ++ if (decx > 0) { ++ if (decx >= 2 && decx < 4) { ++ decx = 2; ++ xdec = 1; ++ } else if (decx >= 4 && decx < 8) { ++ decx = 4; ++ xdec = 2; ++ } else if (decx >= 8) { ++ decx = 8; ++ xdec = 3; ++ } ++ xscale = proc_data->srect.width * 0x1000 / ++ (proc_data->drect.width * decx); ++ } else ++ xscale = proc_data->srect.width * 0x1000 / ++ proc_data->drect.width; ++ if (decy > 0) { ++ if (decy >= 2 && decy < 4) { ++ decy = 2; ++ ydec = 1; ++ } else if (decy >= 4 && decy < 8) { ++ decy = 4; ++ ydec = 2; ++ } else if (decy >= 8) { ++ decy = 8; ++ ydec = 3; ++ } ++ yscale = proc_data->srect.height * 0x1000 / ++ (proc_data->drect.height * decy); ++ } else ++ yscale = proc_data->srect.height * 0x1000 / ++ proc_data->drect.height; ++ ++ __raw_writel((xdec << 10) | (ydec << 8), pxp->base + HW_PXP_PS_CTRL); ++ ++ if (xscale > PXP_DOWNSCALE_THRESHOLD) ++ xscale = PXP_DOWNSCALE_THRESHOLD; ++ if (yscale > PXP_DOWNSCALE_THRESHOLD) ++ yscale = PXP_DOWNSCALE_THRESHOLD; ++ s0scale = BF_PXP_PS_SCALE_YSCALE(yscale) | ++ BF_PXP_PS_SCALE_XSCALE(xscale); ++ __raw_writel(s0scale, pxp->base + HW_PXP_PS_SCALE); ++ ++out: ++ pxp_set_ctrl(pxp); ++ ++ return ret; ++} ++ ++static void pxp_set_bg(struct pxps *pxp) ++{ ++ __raw_writel(pxp->pxp_conf_state.proc_data.bgcolor, ++ pxp->base + HW_PXP_PS_BACKGROUND); ++} ++ ++static void pxp_set_lut(struct pxps *pxp) ++{ ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ int lut_op = pxp_conf->proc_data.lut_transform; ++ u32 reg_val; ++ int i; ++ bool use_cmap = (lut_op & PXP_LUT_USE_CMAP) ? true : false; ++ u8 *cmap = pxp_conf->proc_data.lut_map; ++ u32 entry_src; ++ u32 pix_val; ++ u8 entry[4]; ++ ++ /* ++ * If LUT already configured as needed, return... ++ * Unless CMAP is needed and it has been updated. ++ */ ++ if ((pxp->lut_state == lut_op) && ++ !(use_cmap && pxp_conf->proc_data.lut_map_updated)) ++ return; ++ ++ if (lut_op == PXP_LUT_NONE) { ++ __raw_writel(BM_PXP_LUT_CTRL_BYPASS, ++ pxp->base + HW_PXP_LUT_CTRL); ++ } else if (((lut_op & PXP_LUT_INVERT) != 0) ++ && ((lut_op & PXP_LUT_BLACK_WHITE) != 0)) { ++ /* Fill out LUT table with inverted monochromized values */ ++ ++ /* clear bypass bit, set lookup mode & out mode */ ++ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE ++ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) | ++ BF_PXP_LUT_CTRL_OUT_MODE ++ (BV_PXP_LUT_CTRL_OUT_MODE__Y8), ++ pxp->base + HW_PXP_LUT_CTRL); ++ ++ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */ ++ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR); ++ ++ /* LUT address pointer auto-increments after each data write */ ++ for (pix_val = 0; pix_val < 256; pix_val += 4) { ++ for (i = 0; i < 4; i++) { ++ entry_src = use_cmap ? ++ cmap[pix_val + i] : pix_val + i; ++ entry[i] = (entry_src < 0x80) ? 0xFF : 0x00; ++ } ++ reg_val = (entry[3] << 24) | (entry[2] << 16) | ++ (entry[1] << 8) | entry[0]; ++ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA); ++ } ++ } else if ((lut_op & PXP_LUT_INVERT) != 0) { ++ /* Fill out LUT table with 8-bit inverted values */ ++ ++ /* clear bypass bit, set lookup mode & out mode */ ++ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE ++ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) | ++ BF_PXP_LUT_CTRL_OUT_MODE ++ (BV_PXP_LUT_CTRL_OUT_MODE__Y8), ++ pxp->base + HW_PXP_LUT_CTRL); ++ ++ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */ ++ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR); ++ ++ /* LUT address pointer auto-increments after each data write */ ++ for (pix_val = 0; pix_val < 256; pix_val += 4) { ++ for (i = 0; i < 4; i++) { ++ entry_src = use_cmap ? ++ cmap[pix_val + i] : pix_val + i; ++ entry[i] = ~entry_src & 0xFF; ++ } ++ reg_val = (entry[3] << 24) | (entry[2] << 16) | ++ (entry[1] << 8) | entry[0]; ++ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA); ++ } ++ } else if ((lut_op & PXP_LUT_BLACK_WHITE) != 0) { ++ /* Fill out LUT table with 8-bit monochromized values */ ++ ++ /* clear bypass bit, set lookup mode & out mode */ ++ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE ++ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) | ++ BF_PXP_LUT_CTRL_OUT_MODE ++ (BV_PXP_LUT_CTRL_OUT_MODE__Y8), ++ pxp->base + HW_PXP_LUT_CTRL); ++ ++ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */ ++ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR); ++ ++ /* LUT address pointer auto-increments after each data write */ ++ for (pix_val = 0; pix_val < 256; pix_val += 4) { ++ for (i = 0; i < 4; i++) { ++ entry_src = use_cmap ? ++ cmap[pix_val + i] : pix_val + i; ++ entry[i] = (entry_src < 0x80) ? 0x00 : 0xFF; ++ } ++ reg_val = (entry[3] << 24) | (entry[2] << 16) | ++ (entry[1] << 8) | entry[0]; ++ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA); ++ } ++ } else if (use_cmap) { ++ /* Fill out LUT table using colormap values */ ++ ++ /* clear bypass bit, set lookup mode & out mode */ ++ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE ++ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) | ++ BF_PXP_LUT_CTRL_OUT_MODE ++ (BV_PXP_LUT_CTRL_OUT_MODE__Y8), ++ pxp->base + HW_PXP_LUT_CTRL); ++ ++ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */ ++ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR); ++ ++ /* LUT address pointer auto-increments after each data write */ ++ for (pix_val = 0; pix_val < 256; pix_val += 4) { ++ for (i = 0; i < 4; i++) ++ entry[i] = cmap[pix_val + i]; ++ reg_val = (entry[3] << 24) | (entry[2] << 16) | ++ (entry[1] << 8) | entry[0]; ++ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA); ++ } ++ } ++ ++ pxp->lut_state = lut_op; ++} ++ ++static void pxp_set_csc(struct pxps *pxp) ++{ ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ struct pxp_layer_param *s0_params = &pxp_conf->s0_param; ++ struct pxp_layer_param *ol_params = &pxp_conf->ol_param[0]; ++ struct pxp_layer_param *out_params = &pxp_conf->out_param; ++ ++ bool input_is_YUV = is_yuv(s0_params->pixel_fmt); ++ bool output_is_YUV = is_yuv(out_params->pixel_fmt); ++ ++ if (input_is_YUV && output_is_YUV) { ++ /* ++ * Input = YUV, Output = YUV ++ * No CSC unless we need to do combining ++ */ ++ if (ol_params->combine_enable) { ++ /* Must convert to RGB for combining with RGB overlay */ ++ ++ /* CSC1 - YUV->RGB */ ++ __raw_writel(0x04030000, pxp->base + HW_PXP_CSC1_COEF0); ++ __raw_writel(0x01230208, pxp->base + HW_PXP_CSC1_COEF1); ++ __raw_writel(0x076b079c, pxp->base + HW_PXP_CSC1_COEF2); ++ ++ /* CSC2 - RGB->YUV */ ++ __raw_writel(0x4, pxp->base + HW_PXP_CSC2_CTRL); ++ __raw_writel(0x0096004D, pxp->base + HW_PXP_CSC2_COEF0); ++ __raw_writel(0x05DA001D, pxp->base + HW_PXP_CSC2_COEF1); ++ __raw_writel(0x007005B6, pxp->base + HW_PXP_CSC2_COEF2); ++ __raw_writel(0x057C009E, pxp->base + HW_PXP_CSC2_COEF3); ++ __raw_writel(0x000005E6, pxp->base + HW_PXP_CSC2_COEF4); ++ __raw_writel(0x00000000, pxp->base + HW_PXP_CSC2_COEF5); ++ } else { ++ /* Input & Output both YUV, so bypass both CSCs */ ++ ++ /* CSC1 - Bypass */ ++ __raw_writel(0x40000000, pxp->base + HW_PXP_CSC1_COEF0); ++ ++ /* CSC2 - Bypass */ ++ __raw_writel(0x1, pxp->base + HW_PXP_CSC2_CTRL); ++ } ++ } else if (input_is_YUV && !output_is_YUV) { ++ /* ++ * Input = YUV, Output = RGB ++ * Use CSC1 to convert to RGB ++ */ ++ ++ /* CSC1 - YUV->RGB */ ++ __raw_writel(0x84ab01f0, pxp->base + HW_PXP_CSC1_COEF0); ++ __raw_writel(0x01980204, pxp->base + HW_PXP_CSC1_COEF1); ++ __raw_writel(0x0730079c, pxp->base + HW_PXP_CSC1_COEF2); ++ ++ /* CSC2 - Bypass */ ++ __raw_writel(0x1, pxp->base + HW_PXP_CSC2_CTRL); ++ } else if (!input_is_YUV && output_is_YUV) { ++ /* ++ * Input = RGB, Output = YUV ++ * Use CSC2 to convert to YUV ++ */ ++ ++ /* CSC1 - Bypass */ ++ __raw_writel(0x40000000, pxp->base + HW_PXP_CSC1_COEF0); ++ ++ /* CSC2 - RGB->YUV */ ++ __raw_writel(0x4, pxp->base + HW_PXP_CSC2_CTRL); ++ __raw_writel(0x0096004D, pxp->base + HW_PXP_CSC2_COEF0); ++ __raw_writel(0x05DA001D, pxp->base + HW_PXP_CSC2_COEF1); ++ __raw_writel(0x007005B6, pxp->base + HW_PXP_CSC2_COEF2); ++ __raw_writel(0x057C009E, pxp->base + HW_PXP_CSC2_COEF3); ++ __raw_writel(0x000005E6, pxp->base + HW_PXP_CSC2_COEF4); ++ __raw_writel(0x00000000, pxp->base + HW_PXP_CSC2_COEF5); ++ } else { ++ /* ++ * Input = RGB, Output = RGB ++ * Input & Output both RGB, so bypass both CSCs ++ */ ++ ++ /* CSC1 - Bypass */ ++ __raw_writel(0x40000000, pxp->base + HW_PXP_CSC1_COEF0); ++ ++ /* CSC2 - Bypass */ ++ __raw_writel(0x1, pxp->base + HW_PXP_CSC2_CTRL); ++ } ++ ++ /* YCrCb colorspace */ ++ /* Not sure when we use this...no YCrCb formats are defined for PxP */ ++ /* ++ __raw_writel(0x84ab01f0, HW_PXP_CSCCOEFF0_ADDR); ++ __raw_writel(0x01230204, HW_PXP_CSCCOEFF1_ADDR); ++ __raw_writel(0x0730079c, HW_PXP_CSCCOEFF2_ADDR); ++ */ ++ ++} ++ ++static void pxp_set_s0buf(struct pxps *pxp) ++{ ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ struct pxp_layer_param *s0_params = &pxp_conf->s0_param; ++ struct pxp_proc_data *proc_data = &pxp_conf->proc_data; ++ dma_addr_t Y, U, V; ++ dma_addr_t Y1, U1, V1; ++ u32 offset, bpp = 1; ++ u32 pitch = s0_params->stride ? s0_params->stride : ++ s0_params->width; ++ ++ Y = s0_params->paddr; ++ ++ if (s0_params->pixel_fmt == PXP_PIX_FMT_RGB565) ++ bpp = 2; ++ else if (s0_params->pixel_fmt == PXP_PIX_FMT_RGB32) ++ bpp = 4; ++ offset = (proc_data->srect.top * s0_params->width + ++ proc_data->srect.left) * bpp; ++ /* clipping or cropping */ ++ Y1 = Y + offset; ++ __raw_writel(Y1, pxp->base + HW_PXP_PS_BUF); ++ if ((s0_params->pixel_fmt == PXP_PIX_FMT_YUV420P) || ++ (s0_params->pixel_fmt == PXP_PIX_FMT_YVU420P) || ++ (s0_params->pixel_fmt == PXP_PIX_FMT_GREY) || ++ (s0_params->pixel_fmt == PXP_PIX_FMT_YUV422P)) { ++ /* Set to 1 if YUV format is 4:2:2 rather than 4:2:0 */ ++ int s = 2; ++ if (s0_params->pixel_fmt == PXP_PIX_FMT_YUV422P) ++ s = 1; ++ ++ offset = proc_data->srect.top * s0_params->width / 4 + ++ proc_data->srect.left / 2; ++ U = Y + (s0_params->width * s0_params->height); ++ U1 = U + offset; ++ V = U + ((s0_params->width * s0_params->height) >> s); ++ V1 = V + offset; ++ __raw_writel(U1, pxp->base + HW_PXP_PS_UBUF); ++ __raw_writel(V1, pxp->base + HW_PXP_PS_VBUF); ++ } else if ((s0_params->pixel_fmt == PXP_PIX_FMT_NV12) || ++ (s0_params->pixel_fmt == PXP_PIX_FMT_NV21) || ++ (s0_params->pixel_fmt == PXP_PIX_FMT_NV16) || ++ (s0_params->pixel_fmt == PXP_PIX_FMT_NV61)) { ++ int s = 2; ++ if ((s0_params->pixel_fmt == PXP_PIX_FMT_NV16) || ++ (s0_params->pixel_fmt == PXP_PIX_FMT_NV61)) ++ s = 1; ++ ++ offset = (proc_data->srect.top * s0_params->width + ++ proc_data->srect.left) / s; ++ U = Y + (s0_params->width * s0_params->height); ++ U1 = U + offset; ++ ++ __raw_writel(U1, pxp->base + HW_PXP_PS_UBUF); ++ } ++ ++ /* TODO: only support RGB565, Y8, Y4, YUV420 */ ++ if (s0_params->pixel_fmt == PXP_PIX_FMT_GREY || ++ s0_params->pixel_fmt == PXP_PIX_FMT_YUV420P || ++ s0_params->pixel_fmt == PXP_PIX_FMT_YVU420P || ++ s0_params->pixel_fmt == PXP_PIX_FMT_NV12 || ++ s0_params->pixel_fmt == PXP_PIX_FMT_NV21 || ++ s0_params->pixel_fmt == PXP_PIX_FMT_NV16 || ++ s0_params->pixel_fmt == PXP_PIX_FMT_NV61 || ++ s0_params->pixel_fmt == PXP_PIX_FMT_YUV422P) { ++ __raw_writel(pitch, pxp->base + HW_PXP_PS_PITCH); ++ } ++ else if (s0_params->pixel_fmt == PXP_PIX_FMT_GY04) ++ __raw_writel(pitch >> 1, ++ pxp->base + HW_PXP_PS_PITCH); ++ else if (s0_params->pixel_fmt == PXP_PIX_FMT_RGB32) ++ __raw_writel(pitch << 2, ++ pxp->base + HW_PXP_PS_PITCH); ++ else if (s0_params->pixel_fmt == PXP_PIX_FMT_UYVY || ++ s0_params->pixel_fmt == PXP_PIX_FMT_YUYV || ++ s0_params->pixel_fmt == PXP_PIX_FMT_VYUY || ++ s0_params->pixel_fmt == PXP_PIX_FMT_YVYU) ++ __raw_writel(pitch << 1, ++ pxp->base + HW_PXP_PS_PITCH); ++ else if (s0_params->pixel_fmt == PXP_PIX_FMT_RGB565) ++ __raw_writel(pitch << 1, ++ pxp->base + HW_PXP_PS_PITCH); ++ else ++ __raw_writel(0, pxp->base + HW_PXP_PS_PITCH); ++} ++ ++/** ++ * pxp_config() - configure PxP for a processing task ++ * @pxps: PXP context. ++ * @pxp_chan: PXP channel. ++ * @return: 0 on success or negative error code on failure. ++ */ ++static int pxp_config(struct pxps *pxp, struct pxp_channel *pxp_chan) ++{ ++ struct pxp_config_data *pxp_conf_data = &pxp->pxp_conf_state; ++ int ol_nr; ++ int i; ++ ++ /* Configure PxP regs */ ++ pxp_set_ctrl(pxp); ++ pxp_set_s0param(pxp); ++ pxp_set_s0crop(pxp); ++ pxp_set_scaling(pxp); ++ ol_nr = pxp_conf_data->layer_nr - 2; ++ while (ol_nr > 0) { ++ i = pxp_conf_data->layer_nr - 2 - ol_nr; ++ pxp_set_oln(i, pxp); ++ pxp_set_olparam(i, pxp); ++ /* only the color key in higher overlay will take effect. */ ++ pxp_set_olcolorkey(i, pxp); ++ ol_nr--; ++ } ++ pxp_set_s0colorkey(pxp); ++ pxp_set_csc(pxp); ++ pxp_set_bg(pxp); ++ pxp_set_lut(pxp); ++ ++ pxp_set_s0buf(pxp); ++ pxp_set_outbuf(pxp); ++ ++ return 0; ++} ++ ++static void pxp_clk_enable(struct pxps *pxp) ++{ ++ mutex_lock(&pxp->clk_mutex); ++ ++ if (pxp->clk_stat == CLK_STAT_ON) { ++ mutex_unlock(&pxp->clk_mutex); ++ return; ++ } ++ ++ pm_runtime_get_sync(pxp->dev); ++ ++ clk_prepare_enable(pxp->clk); ++ pxp->clk_stat = CLK_STAT_ON; ++ ++ mutex_unlock(&pxp->clk_mutex); ++} ++ ++static void pxp_clk_disable(struct pxps *pxp) ++{ ++ unsigned long flags; ++ ++ mutex_lock(&pxp->clk_mutex); ++ ++ if (pxp->clk_stat == CLK_STAT_OFF) { ++ mutex_unlock(&pxp->clk_mutex); ++ return; ++ } ++ ++ spin_lock_irqsave(&pxp->lock, flags); ++ if ((pxp->pxp_ongoing == 0) && list_empty(&head)) { ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ clk_disable_unprepare(pxp->clk); ++ pxp->clk_stat = CLK_STAT_OFF; ++ } else ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ ++ pm_runtime_put_sync_suspend(pxp->dev); ++ ++ mutex_unlock(&pxp->clk_mutex); ++} ++ ++static inline void clkoff_callback(struct work_struct *w) ++{ ++ struct pxps *pxp = container_of(w, struct pxps, work); ++ ++ pxp_clk_disable(pxp); ++} ++ ++static void pxp_clkoff_timer(unsigned long arg) ++{ ++ struct pxps *pxp = (struct pxps *)arg; ++ ++ if ((pxp->pxp_ongoing == 0) && list_empty(&head)) ++ schedule_work(&pxp->work); ++ else ++ mod_timer(&pxp->clk_timer, ++ jiffies + msecs_to_jiffies(timeout_in_ms)); ++} ++ ++static struct pxp_tx_desc *pxpdma_first_active(struct pxp_channel *pxp_chan) ++{ ++ return list_entry(pxp_chan->active_list.next, struct pxp_tx_desc, list); ++} ++ ++static struct pxp_tx_desc *pxpdma_first_queued(struct pxp_channel *pxp_chan) ++{ ++ return list_entry(pxp_chan->queue.next, struct pxp_tx_desc, list); ++} ++ ++/* called with pxp_chan->lock held */ ++static void __pxpdma_dostart(struct pxp_channel *pxp_chan) ++{ ++ struct pxp_dma *pxp_dma = to_pxp_dma(pxp_chan->dma_chan.device); ++ struct pxps *pxp = to_pxp(pxp_dma); ++ struct pxp_tx_desc *desc; ++ struct pxp_tx_desc *child; ++ int i = 0; ++ ++ /* so far we presume only one transaction on active_list */ ++ /* S0 */ ++ desc = pxpdma_first_active(pxp_chan); ++ memcpy(&pxp->pxp_conf_state.s0_param, ++ &desc->layer_param.s0_param, sizeof(struct pxp_layer_param)); ++ memcpy(&pxp->pxp_conf_state.proc_data, ++ &desc->proc_data, sizeof(struct pxp_proc_data)); ++ ++ /* Save PxP configuration */ ++ list_for_each_entry(child, &desc->tx_list, list) { ++ if (i == 0) { /* Output */ ++ memcpy(&pxp->pxp_conf_state.out_param, ++ &child->layer_param.out_param, ++ sizeof(struct pxp_layer_param)); ++ } else { /* Overlay */ ++ memcpy(&pxp->pxp_conf_state.ol_param[i - 1], ++ &child->layer_param.ol_param, ++ sizeof(struct pxp_layer_param)); ++ } ++ ++ i++; ++ } ++ pr_debug("%s:%d S0 w/h %d/%d paddr %08x\n", __func__, __LINE__, ++ pxp->pxp_conf_state.s0_param.width, ++ pxp->pxp_conf_state.s0_param.height, ++ pxp->pxp_conf_state.s0_param.paddr); ++ pr_debug("%s:%d OUT w/h %d/%d paddr %08x\n", __func__, __LINE__, ++ pxp->pxp_conf_state.out_param.width, ++ pxp->pxp_conf_state.out_param.height, ++ pxp->pxp_conf_state.out_param.paddr); ++} ++ ++static void pxpdma_dostart_work(struct pxps *pxp) ++{ ++ struct pxp_channel *pxp_chan = NULL; ++ unsigned long flags, flags1; ++ ++ spin_lock_irqsave(&pxp->lock, flags); ++ if (list_empty(&head)) { ++ pxp->pxp_ongoing = 0; ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ return; ++ } ++ ++ pxp_chan = list_entry(head.next, struct pxp_channel, list); ++ ++ spin_lock_irqsave(&pxp_chan->lock, flags1); ++ if (!list_empty(&pxp_chan->active_list)) { ++ struct pxp_tx_desc *desc; ++ /* REVISIT */ ++ desc = pxpdma_first_active(pxp_chan); ++ __pxpdma_dostart(pxp_chan); ++ } ++ spin_unlock_irqrestore(&pxp_chan->lock, flags1); ++ ++ /* Configure PxP */ ++ pxp_config(pxp, pxp_chan); ++ ++ pxp_start(pxp); ++ ++ spin_unlock_irqrestore(&pxp->lock, flags); ++} ++ ++static void pxpdma_dequeue(struct pxp_channel *pxp_chan, struct list_head *list) ++{ ++ struct pxp_tx_desc *desc = NULL; ++ do { ++ desc = pxpdma_first_queued(pxp_chan); ++ list_move_tail(&desc->list, list); ++ } while (!list_empty(&pxp_chan->queue)); ++} ++ ++static dma_cookie_t pxp_tx_submit(struct dma_async_tx_descriptor *tx) ++{ ++ struct pxp_tx_desc *desc = to_tx_desc(tx); ++ struct pxp_channel *pxp_chan = to_pxp_channel(tx->chan); ++ dma_cookie_t cookie; ++ unsigned long flags; ++ ++ dev_dbg(&pxp_chan->dma_chan.dev->device, "received TX\n"); ++ ++ mutex_lock(&pxp_chan->chan_mutex); ++ ++ cookie = pxp_chan->dma_chan.cookie; ++ ++ if (++cookie < 0) ++ cookie = 1; ++ ++ /* from dmaengine.h: "last cookie value returned to client" */ ++ pxp_chan->dma_chan.cookie = cookie; ++ tx->cookie = cookie; ++ ++ /* pxp_chan->lock can be taken under ichan->lock, but not v.v. */ ++ spin_lock_irqsave(&pxp_chan->lock, flags); ++ ++ /* Here we add the tx descriptor to our PxP task queue. */ ++ list_add_tail(&desc->list, &pxp_chan->queue); ++ ++ spin_unlock_irqrestore(&pxp_chan->lock, flags); ++ ++ dev_dbg(&pxp_chan->dma_chan.dev->device, "done TX\n"); ++ ++ mutex_unlock(&pxp_chan->chan_mutex); ++ return cookie; ++} ++ ++/* Called with pxp_chan->chan_mutex held */ ++static int pxp_desc_alloc(struct pxp_channel *pxp_chan, int n) ++{ ++ struct pxp_tx_desc *desc = vmalloc(n * sizeof(struct pxp_tx_desc)); ++ ++ if (!desc) ++ return -ENOMEM; ++ ++ pxp_chan->n_tx_desc = n; ++ pxp_chan->desc = desc; ++ INIT_LIST_HEAD(&pxp_chan->active_list); ++ INIT_LIST_HEAD(&pxp_chan->queue); ++ INIT_LIST_HEAD(&pxp_chan->free_list); ++ ++ while (n--) { ++ struct dma_async_tx_descriptor *txd = &desc->txd; ++ ++ memset(txd, 0, sizeof(*txd)); ++ INIT_LIST_HEAD(&desc->tx_list); ++ dma_async_tx_descriptor_init(txd, &pxp_chan->dma_chan); ++ txd->tx_submit = pxp_tx_submit; ++ ++ list_add(&desc->list, &pxp_chan->free_list); ++ ++ desc++; ++ } ++ ++ return 0; ++} ++ ++/** ++ * pxp_init_channel() - initialize a PXP channel. ++ * @pxp_dma: PXP DMA context. ++ * @pchan: pointer to the channel object. ++ * @return 0 on success or negative error code on failure. ++ */ ++static int pxp_init_channel(struct pxp_dma *pxp_dma, ++ struct pxp_channel *pxp_chan) ++{ ++ unsigned long flags; ++ struct pxps *pxp = to_pxp(pxp_dma); ++ int ret = 0, n_desc = 0; ++ ++ /* ++ * We are using _virtual_ channel here. ++ * Each channel contains all parameters of corresponding layers ++ * for one transaction; each layer is represented as one descriptor ++ * (i.e., pxp_tx_desc) here. ++ */ ++ ++ spin_lock_irqsave(&pxp->lock, flags); ++ ++ /* max desc nr: S0+OL+OUT = 1+8+1 */ ++ n_desc = 16; ++ ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ ++ if (n_desc && !pxp_chan->desc) ++ ret = pxp_desc_alloc(pxp_chan, n_desc); ++ ++ return ret; ++} ++ ++/** ++ * pxp_uninit_channel() - uninitialize a PXP channel. ++ * @pxp_dma: PXP DMA context. ++ * @pchan: pointer to the channel object. ++ * @return 0 on success or negative error code on failure. ++ */ ++static int pxp_uninit_channel(struct pxp_dma *pxp_dma, ++ struct pxp_channel *pxp_chan) ++{ ++ int ret = 0; ++ ++ if (pxp_chan->desc) ++ vfree(pxp_chan->desc); ++ ++ pxp_chan->desc = NULL; ++ ++ return ret; ++} ++ ++static irqreturn_t pxp_irq(int irq, void *dev_id) ++{ ++ struct pxps *pxp = dev_id; ++ struct pxp_channel *pxp_chan; ++ struct pxp_tx_desc *desc; ++ dma_async_tx_callback callback; ++ void *callback_param; ++ unsigned long flags; ++ u32 hist_status; ++ ++ dump_pxp_reg(pxp); ++ ++ hist_status = ++ __raw_readl(pxp->base + HW_PXP_HIST_CTRL) & BM_PXP_HIST_CTRL_STATUS; ++ ++ __raw_writel(BM_PXP_STAT_IRQ, pxp->base + HW_PXP_STAT_CLR); ++ ++ spin_lock_irqsave(&pxp->lock, flags); ++ ++ if (list_empty(&head)) { ++ pxp->pxp_ongoing = 0; ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ return IRQ_NONE; ++ } ++ ++ pxp_chan = list_entry(head.next, struct pxp_channel, list); ++ list_del_init(&pxp_chan->list); ++ ++ if (list_empty(&pxp_chan->active_list)) { ++ pr_debug("PXP_IRQ pxp_chan->active_list empty. chan_id %d\n", ++ pxp_chan->dma_chan.chan_id); ++ pxp->pxp_ongoing = 0; ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ return IRQ_NONE; ++ } ++ ++ /* Get descriptor and call callback */ ++ desc = pxpdma_first_active(pxp_chan); ++ ++ pxp_chan->completed = desc->txd.cookie; ++ ++ callback = desc->txd.callback; ++ callback_param = desc->txd.callback_param; ++ ++ /* Send histogram status back to caller */ ++ desc->hist_status = hist_status; ++ ++ if ((desc->txd.flags & DMA_PREP_INTERRUPT) && callback) ++ callback(callback_param); ++ ++ pxp_chan->status = PXP_CHANNEL_INITIALIZED; ++ ++ list_splice_init(&desc->tx_list, &pxp_chan->free_list); ++ list_move(&desc->list, &pxp_chan->free_list); ++ ++ mutex_unlock(&hard_lock); ++ pxp->pxp_ongoing = 0; ++ mod_timer(&pxp->clk_timer, jiffies + msecs_to_jiffies(timeout_in_ms)); ++ ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ ++ return IRQ_HANDLED; ++} ++ ++/* called with pxp_chan->lock held */ ++static struct pxp_tx_desc *pxpdma_desc_get(struct pxp_channel *pxp_chan) ++{ ++ struct pxp_tx_desc *desc, *_desc; ++ struct pxp_tx_desc *ret = NULL; ++ ++ list_for_each_entry_safe(desc, _desc, &pxp_chan->free_list, list) { ++ list_del_init(&desc->list); ++ ret = desc; ++ break; ++ } ++ ++ return ret; ++} ++ ++/* called with pxp_chan->lock held */ ++static void pxpdma_desc_put(struct pxp_channel *pxp_chan, ++ struct pxp_tx_desc *desc) ++{ ++ if (desc) { ++ struct device *dev = &pxp_chan->dma_chan.dev->device; ++ struct pxp_tx_desc *child; ++ ++ list_for_each_entry(child, &desc->tx_list, list) ++ dev_info(dev, "moving child desc %p to freelist\n", child); ++ list_splice_init(&desc->tx_list, &pxp_chan->free_list); ++ dev_info(dev, "moving desc %p to freelist\n", desc); ++ list_add(&desc->list, &pxp_chan->free_list); ++ } ++} ++ ++/* Allocate and initialise a transfer descriptor. */ ++static struct dma_async_tx_descriptor *pxp_prep_slave_sg(struct dma_chan *chan, ++ struct scatterlist ++ *sgl, ++ unsigned int sg_len, ++ enum ++ dma_transfer_direction ++ direction, ++ unsigned long tx_flags, ++ void *context) ++{ ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ struct pxp_dma *pxp_dma = to_pxp_dma(chan->device); ++ struct pxps *pxp = to_pxp(pxp_dma); ++ struct pxp_tx_desc *desc = NULL; ++ struct pxp_tx_desc *first = NULL, *prev = NULL; ++ struct scatterlist *sg; ++ unsigned long flags; ++ dma_addr_t phys_addr; ++ int i; ++ ++ if (direction != DMA_DEV_TO_MEM && direction != DMA_MEM_TO_DEV) { ++ dev_err(chan->device->dev, "Invalid DMA direction %d!\n", ++ direction); ++ return NULL; ++ } ++ ++ if (unlikely(sg_len < 2)) ++ return NULL; ++ ++ spin_lock_irqsave(&pxp_chan->lock, flags); ++ for_each_sg(sgl, sg, sg_len, i) { ++ desc = pxpdma_desc_get(pxp_chan); ++ if (!desc) { ++ pxpdma_desc_put(pxp_chan, first); ++ dev_err(chan->device->dev, "Can't get DMA desc.\n"); ++ spin_unlock_irqrestore(&pxp_chan->lock, flags); ++ return NULL; ++ } ++ ++ phys_addr = sg_dma_address(sg); ++ ++ if (!first) { ++ first = desc; ++ ++ desc->layer_param.s0_param.paddr = phys_addr; ++ } else { ++ list_add_tail(&desc->list, &first->tx_list); ++ prev->next = desc; ++ desc->next = NULL; ++ ++ if (i == 1) ++ desc->layer_param.out_param.paddr = phys_addr; ++ else ++ desc->layer_param.ol_param.paddr = phys_addr; ++ } ++ ++ prev = desc; ++ } ++ spin_unlock_irqrestore(&pxp_chan->lock, flags); ++ ++ pxp->pxp_conf_state.layer_nr = sg_len; ++ first->txd.flags = tx_flags; ++ first->len = sg_len; ++ pr_debug("%s:%d first %p, first->len %d, flags %08x\n", ++ __func__, __LINE__, first, first->len, first->txd.flags); ++ ++ return &first->txd; ++} ++ ++static void pxp_issue_pending(struct dma_chan *chan) ++{ ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ struct pxp_dma *pxp_dma = to_pxp_dma(chan->device); ++ struct pxps *pxp = to_pxp(pxp_dma); ++ unsigned long flags0, flags; ++ ++ spin_lock_irqsave(&pxp->lock, flags0); ++ spin_lock_irqsave(&pxp_chan->lock, flags); ++ ++ if (!list_empty(&pxp_chan->queue)) { ++ pxpdma_dequeue(pxp_chan, &pxp_chan->active_list); ++ pxp_chan->status = PXP_CHANNEL_READY; ++ list_add_tail(&pxp_chan->list, &head); ++ } else { ++ spin_unlock_irqrestore(&pxp_chan->lock, flags); ++ spin_unlock_irqrestore(&pxp->lock, flags0); ++ return; ++ } ++ spin_unlock_irqrestore(&pxp_chan->lock, flags); ++ spin_unlock_irqrestore(&pxp->lock, flags0); ++ ++ pxp_clk_enable(pxp); ++ mutex_lock(&hard_lock); ++ ++ spin_lock_irqsave(&pxp->lock, flags); ++ pxp->pxp_ongoing = 1; ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ pxpdma_dostart_work(pxp); ++} ++ ++static void __pxp_terminate_all(struct dma_chan *chan) ++{ ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ unsigned long flags; ++ ++ /* pchan->queue is modified in ISR, have to spinlock */ ++ spin_lock_irqsave(&pxp_chan->lock, flags); ++ list_splice_init(&pxp_chan->queue, &pxp_chan->free_list); ++ list_splice_init(&pxp_chan->active_list, &pxp_chan->free_list); ++ ++ spin_unlock_irqrestore(&pxp_chan->lock, flags); ++ ++ pxp_chan->status = PXP_CHANNEL_INITIALIZED; ++} ++ ++static int pxp_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, ++ unsigned long arg) ++{ ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ ++ /* Only supports DMA_TERMINATE_ALL */ ++ if (cmd != DMA_TERMINATE_ALL) ++ return -ENXIO; ++ ++ mutex_lock(&pxp_chan->chan_mutex); ++ __pxp_terminate_all(chan); ++ mutex_unlock(&pxp_chan->chan_mutex); ++ ++ return 0; ++} ++ ++static int pxp_alloc_chan_resources(struct dma_chan *chan) ++{ ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ struct pxp_dma *pxp_dma = to_pxp_dma(chan->device); ++ int ret; ++ ++ /* dmaengine.c now guarantees to only offer free channels */ ++ BUG_ON(chan->client_count > 1); ++ WARN_ON(pxp_chan->status != PXP_CHANNEL_FREE); ++ ++ chan->cookie = 1; ++ pxp_chan->completed = -ENXIO; ++ ++ pr_debug("%s dma_chan.chan_id %d\n", __func__, chan->chan_id); ++ ret = pxp_init_channel(pxp_dma, pxp_chan); ++ if (ret < 0) ++ goto err_chan; ++ ++ pxp_chan->status = PXP_CHANNEL_INITIALIZED; ++ ++ dev_dbg(&chan->dev->device, "Found channel 0x%x, irq %d\n", ++ chan->chan_id, pxp_chan->eof_irq); ++ ++ return ret; ++ ++err_chan: ++ return ret; ++} ++ ++static void pxp_free_chan_resources(struct dma_chan *chan) ++{ ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ struct pxp_dma *pxp_dma = to_pxp_dma(chan->device); ++ ++ mutex_lock(&pxp_chan->chan_mutex); ++ ++ __pxp_terminate_all(chan); ++ ++ pxp_chan->status = PXP_CHANNEL_FREE; ++ ++ pxp_uninit_channel(pxp_dma, pxp_chan); ++ ++ mutex_unlock(&pxp_chan->chan_mutex); ++} ++ ++static enum dma_status pxp_tx_status(struct dma_chan *chan, ++ dma_cookie_t cookie, ++ struct dma_tx_state *txstate) ++{ ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ ++ if (cookie != chan->cookie) ++ return DMA_ERROR; ++ ++ if (txstate) { ++ txstate->last = pxp_chan->completed; ++ txstate->used = chan->cookie; ++ txstate->residue = 0; ++ } ++ return DMA_SUCCESS; ++} ++ ++static int pxp_hw_init(struct pxps *pxp) ++{ ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state; ++ struct pxp_proc_data *proc_data = &pxp_conf->proc_data; ++ u32 reg_val; ++ ++ /* Pull PxP out of reset */ ++ __raw_writel(0, pxp->base + HW_PXP_CTRL); ++ ++ /* Config defaults */ ++ ++ /* Initialize non-channel-specific PxP parameters */ ++ proc_data->drect.left = proc_data->srect.left = 0; ++ proc_data->drect.top = proc_data->srect.top = 0; ++ proc_data->drect.width = proc_data->srect.width = 0; ++ proc_data->drect.height = proc_data->srect.height = 0; ++ proc_data->scaling = 0; ++ proc_data->hflip = 0; ++ proc_data->vflip = 0; ++ proc_data->rotate = 0; ++ proc_data->bgcolor = 0; ++ ++ /* Initialize S0 channel parameters */ ++ pxp_conf->s0_param.pixel_fmt = pxp_s0_formats[0]; ++ pxp_conf->s0_param.width = 0; ++ pxp_conf->s0_param.height = 0; ++ pxp_conf->s0_param.color_key = -1; ++ pxp_conf->s0_param.color_key_enable = false; ++ ++ /* Initialize OL channel parameters */ ++ pxp_conf->ol_param[0].combine_enable = false; ++ pxp_conf->ol_param[0].width = 0; ++ pxp_conf->ol_param[0].height = 0; ++ pxp_conf->ol_param[0].pixel_fmt = PXP_PIX_FMT_RGB565; ++ pxp_conf->ol_param[0].color_key_enable = false; ++ pxp_conf->ol_param[0].color_key = -1; ++ pxp_conf->ol_param[0].global_alpha_enable = false; ++ pxp_conf->ol_param[0].global_alpha = 0; ++ pxp_conf->ol_param[0].local_alpha_enable = false; ++ ++ /* Initialize Output channel parameters */ ++ pxp_conf->out_param.width = 0; ++ pxp_conf->out_param.height = 0; ++ pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_RGB565; ++ ++ proc_data->overlay_state = 0; ++ ++ /* Write default h/w config */ ++ pxp_set_ctrl(pxp); ++ pxp_set_s0param(pxp); ++ pxp_set_s0crop(pxp); ++ /* ++ * simply program the ULC to a higher value than the LRC ++ * to avoid any AS pixels to show up in the output buffer. ++ */ ++ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_OUT_AS_ULC); ++ pxp_set_olparam(0, pxp); ++ pxp_set_olcolorkey(0, pxp); ++ ++ pxp_set_s0colorkey(pxp); ++ pxp_set_csc(pxp); ++ pxp_set_bg(pxp); ++ pxp_set_lut(pxp); ++ ++ /* One-time histogram configuration */ ++ reg_val = ++ BF_PXP_HIST_CTRL_PANEL_MODE(BV_PXP_HIST_CTRL_PANEL_MODE__GRAY16); ++ __raw_writel(reg_val, pxp->base + HW_PXP_HIST_CTRL); ++ ++ reg_val = BF_PXP_HIST2_PARAM_VALUE0(0x00) | ++ BF_PXP_HIST2_PARAM_VALUE1(0x00F); ++ __raw_writel(reg_val, pxp->base + HW_PXP_HIST2_PARAM); ++ ++ reg_val = BF_PXP_HIST4_PARAM_VALUE0(0x00) | ++ BF_PXP_HIST4_PARAM_VALUE1(0x05) | ++ BF_PXP_HIST4_PARAM_VALUE2(0x0A) | BF_PXP_HIST4_PARAM_VALUE3(0x0F); ++ __raw_writel(reg_val, pxp->base + HW_PXP_HIST4_PARAM); ++ ++ reg_val = BF_PXP_HIST8_PARAM0_VALUE0(0x00) | ++ BF_PXP_HIST8_PARAM0_VALUE1(0x02) | ++ BF_PXP_HIST8_PARAM0_VALUE2(0x04) | BF_PXP_HIST8_PARAM0_VALUE3(0x06); ++ __raw_writel(reg_val, pxp->base + HW_PXP_HIST8_PARAM0); ++ reg_val = BF_PXP_HIST8_PARAM1_VALUE4(0x09) | ++ BF_PXP_HIST8_PARAM1_VALUE5(0x0B) | ++ BF_PXP_HIST8_PARAM1_VALUE6(0x0D) | BF_PXP_HIST8_PARAM1_VALUE7(0x0F); ++ __raw_writel(reg_val, pxp->base + HW_PXP_HIST8_PARAM1); ++ ++ reg_val = BF_PXP_HIST16_PARAM0_VALUE0(0x00) | ++ BF_PXP_HIST16_PARAM0_VALUE1(0x01) | ++ BF_PXP_HIST16_PARAM0_VALUE2(0x02) | ++ BF_PXP_HIST16_PARAM0_VALUE3(0x03); ++ __raw_writel(reg_val, pxp->base + HW_PXP_HIST16_PARAM0); ++ reg_val = BF_PXP_HIST16_PARAM1_VALUE4(0x04) | ++ BF_PXP_HIST16_PARAM1_VALUE5(0x05) | ++ BF_PXP_HIST16_PARAM1_VALUE6(0x06) | ++ BF_PXP_HIST16_PARAM1_VALUE7(0x07); ++ __raw_writel(reg_val, pxp->base + HW_PXP_HIST16_PARAM1); ++ reg_val = BF_PXP_HIST16_PARAM2_VALUE8(0x08) | ++ BF_PXP_HIST16_PARAM2_VALUE9(0x09) | ++ BF_PXP_HIST16_PARAM2_VALUE10(0x0A) | ++ BF_PXP_HIST16_PARAM2_VALUE11(0x0B); ++ __raw_writel(reg_val, pxp->base + HW_PXP_HIST16_PARAM2); ++ reg_val = BF_PXP_HIST16_PARAM3_VALUE12(0x0C) | ++ BF_PXP_HIST16_PARAM3_VALUE13(0x0D) | ++ BF_PXP_HIST16_PARAM3_VALUE14(0x0E) | ++ BF_PXP_HIST16_PARAM3_VALUE15(0x0F); ++ __raw_writel(reg_val, pxp->base + HW_PXP_HIST16_PARAM3); ++ ++ return 0; ++} ++ ++static int pxp_dma_init(struct pxps *pxp) ++{ ++ struct pxp_dma *pxp_dma = &pxp->pxp_dma; ++ struct dma_device *dma = &pxp_dma->dma; ++ int i; ++ ++ dma_cap_set(DMA_SLAVE, dma->cap_mask); ++ dma_cap_set(DMA_PRIVATE, dma->cap_mask); ++ ++ /* Compulsory common fields */ ++ dma->dev = pxp->dev; ++ dma->device_alloc_chan_resources = pxp_alloc_chan_resources; ++ dma->device_free_chan_resources = pxp_free_chan_resources; ++ dma->device_tx_status = pxp_tx_status; ++ dma->device_issue_pending = pxp_issue_pending; ++ ++ /* Compulsory for DMA_SLAVE fields */ ++ dma->device_prep_slave_sg = pxp_prep_slave_sg; ++ dma->device_control = pxp_control; ++ ++ /* Initialize PxP Channels */ ++ INIT_LIST_HEAD(&dma->channels); ++ for (i = 0; i < NR_PXP_VIRT_CHANNEL; i++) { ++ struct pxp_channel *pxp_chan = pxp->channel + i; ++ struct dma_chan *dma_chan = &pxp_chan->dma_chan; ++ ++ spin_lock_init(&pxp_chan->lock); ++ mutex_init(&pxp_chan->chan_mutex); ++ ++ /* Only one EOF IRQ for PxP, shared by all channels */ ++ pxp_chan->eof_irq = pxp->irq; ++ pxp_chan->status = PXP_CHANNEL_FREE; ++ pxp_chan->completed = -ENXIO; ++ snprintf(pxp_chan->eof_name, sizeof(pxp_chan->eof_name), ++ "PXP EOF %d", i); ++ ++ dma_chan->device = &pxp_dma->dma; ++ dma_chan->cookie = 1; ++ dma_chan->chan_id = i; ++ list_add_tail(&dma_chan->device_node, &dma->channels); ++ } ++ ++ return dma_async_device_register(&pxp_dma->dma); ++} ++ ++static ssize_t clk_off_timeout_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%d\n", timeout_in_ms); ++} ++ ++static ssize_t clk_off_timeout_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int val; ++ if (sscanf(buf, "%d", &val) > 0) { ++ timeout_in_ms = val; ++ return count; ++ } ++ return -EINVAL; ++} ++ ++static DEVICE_ATTR(clk_off_timeout, 0644, clk_off_timeout_show, ++ clk_off_timeout_store); ++ ++static ssize_t block_size_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return sprintf(buf, "%d\n", block_size); ++} ++ ++static ssize_t block_size_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ char **last = NULL; ++ ++ block_size = simple_strtoul(buf, last, 0); ++ if (block_size > 1) ++ block_size = 1; ++ ++ return count; ++} ++static DEVICE_ATTR(block_size, S_IWUSR | S_IRUGO, ++ block_size_show, block_size_store); ++ ++static const struct of_device_id imx_pxpdma_dt_ids[] = { ++ { .compatible = "fsl,imx6dl-pxp-dma", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, imx_pxpdma_dt_ids); ++ ++static int pxp_probe(struct platform_device *pdev) ++{ ++ struct pxps *pxp; ++ struct resource *res; ++ int irq; ++ int err = 0; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_irq(pdev, 0); ++ if (!res || irq < 0) { ++ err = -ENODEV; ++ goto exit; ++ } ++ ++ pxp = devm_kzalloc(&pdev->dev, sizeof(*pxp), GFP_KERNEL); ++ if (!pxp) { ++ dev_err(&pdev->dev, "failed to allocate control object\n"); ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ pxp->dev = &pdev->dev; ++ ++ platform_set_drvdata(pdev, pxp); ++ pxp->irq = irq; ++ ++ pxp->pxp_ongoing = 0; ++ pxp->lut_state = 0; ++ ++ spin_lock_init(&pxp->lock); ++ mutex_init(&pxp->clk_mutex); ++ mutex_init(&hard_lock); ++ ++ pxp->base = devm_request_and_ioremap(&pdev->dev, res); ++ if (pxp->base == NULL) { ++ dev_err(&pdev->dev, "Couldn't ioremap regs\n"); ++ err = -ENODEV; ++ goto exit; ++ } ++ ++ pxp->pdev = pdev; ++ ++ pxp->clk = devm_clk_get(&pdev->dev, "pxp-axi"); ++ clk_prepare_enable(pxp->clk); ++ ++ err = pxp_hw_init(pxp); ++ clk_disable_unprepare(pxp->clk); ++ if (err) { ++ dev_err(&pdev->dev, "failed to initialize hardware\n"); ++ goto exit; ++ } ++ ++ err = devm_request_irq(&pdev->dev, pxp->irq, pxp_irq, 0, ++ "pxp-dmaengine", pxp); ++ if (err) ++ goto exit; ++ /* Initialize DMA engine */ ++ err = pxp_dma_init(pxp); ++ if (err < 0) ++ goto exit; ++ ++ if (device_create_file(&pdev->dev, &dev_attr_clk_off_timeout)) { ++ dev_err(&pdev->dev, ++ "Unable to create file from clk_off_timeout\n"); ++ goto exit; ++ } ++ ++ device_create_file(&pdev->dev, &dev_attr_block_size); ++ dump_pxp_reg(pxp); ++ ++ INIT_WORK(&pxp->work, clkoff_callback); ++ init_timer(&pxp->clk_timer); ++ pxp->clk_timer.function = pxp_clkoff_timer; ++ pxp->clk_timer.data = (unsigned long)pxp; ++ ++ register_pxp_device(); ++ ++ pm_runtime_enable(pxp->dev); ++ ++exit: ++ if (err) ++ dev_err(&pdev->dev, "Exiting (unsuccessfully) pxp_probe()\n"); ++ return err; ++} ++ ++static int pxp_remove(struct platform_device *pdev) ++{ ++ struct pxps *pxp = platform_get_drvdata(pdev); ++ ++ unregister_pxp_device(); ++ cancel_work_sync(&pxp->work); ++ del_timer_sync(&pxp->clk_timer); ++ clk_disable_unprepare(pxp->clk); ++ device_remove_file(&pdev->dev, &dev_attr_clk_off_timeout); ++ device_remove_file(&pdev->dev, &dev_attr_block_size); ++ dma_async_device_unregister(&(pxp->pxp_dma.dma)); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int pxp_suspend(struct device *dev) ++{ ++ struct pxps *pxp = dev_get_drvdata(dev); ++ ++ pxp_clk_enable(pxp); ++ while (__raw_readl(pxp->base + HW_PXP_CTRL) & BM_PXP_CTRL_ENABLE) ++ ; ++ ++ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL); ++ pxp_clk_disable(pxp); ++ ++ return 0; ++} ++ ++static int pxp_resume(struct device *dev) ++{ ++ struct pxps *pxp = dev_get_drvdata(dev); ++ ++ pxp_clk_enable(pxp); ++ /* Pull PxP out of reset */ ++ __raw_writel(0, pxp->base + HW_PXP_CTRL); ++ pxp_clk_disable(pxp); ++ ++ return 0; ++} ++#else ++#define pxp_suspend NULL ++#define pxp_resume NULL ++#endif ++ ++#ifdef CONFIG_PM_RUNTIME ++static int pxp_runtime_suspend(struct device *dev) ++{ ++ release_bus_freq(BUS_FREQ_HIGH); ++ dev_dbg(dev, "pxp busfreq high release.\n"); ++ ++ return 0; ++} ++ ++static int pxp_runtime_resume(struct device *dev) ++{ ++ request_bus_freq(BUS_FREQ_HIGH); ++ dev_dbg(dev, "pxp busfreq high request.\n"); ++ ++ return 0; ++} ++#else ++#define pxp_runtime_suspend NULL ++#define pxp_runtime_resume NULL ++#endif ++ ++static const struct dev_pm_ops pxp_pm_ops = { ++ SET_RUNTIME_PM_OPS(pxp_runtime_suspend, pxp_runtime_resume, NULL) ++ SET_SYSTEM_SLEEP_PM_OPS(pxp_suspend, pxp_resume) ++}; ++ ++static struct platform_driver pxp_driver = { ++ .driver = { ++ .name = "imx-pxp", ++ .of_match_table = of_match_ptr(imx_pxpdma_dt_ids), ++ .pm = &pxp_pm_ops, ++ }, ++ .probe = pxp_probe, ++ .remove = pxp_remove, ++}; ++ ++module_platform_driver(pxp_driver); ++ ++ ++MODULE_DESCRIPTION("i.MX PxP driver"); ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/dma/pxp/regs-pxp_v2.h linux-3.10.30-cubox-i/drivers/dma/pxp/regs-pxp_v2.h +--- linux-3.10.30/drivers/dma/pxp/regs-pxp_v2.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/dma/pxp/regs-pxp_v2.h 2014-03-08 20:33:30.000000000 +0100 +@@ -0,0 +1,1152 @@ ++/* ++ * Freescale PXP Register Definitions ++ * ++ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * 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 ++ * ++ * This file is created by xml file. Don't Edit it. ++ * ++ * Xml Revision: 1.29 ++ * Template revision: 1.3 ++ */ ++ ++#ifndef __ARCH_ARM___PXP_H ++#define __ARCH_ARM___PXP_H ++ ++#define HW_PXP_CTRL (0x00000000) ++#define HW_PXP_CTRL_SET (0x00000004) ++#define HW_PXP_CTRL_CLR (0x00000008) ++#define HW_PXP_CTRL_TOG (0x0000000c) ++ ++#define BM_PXP_CTRL_SFTRST 0x80000000 ++#define BM_PXP_CTRL_CLKGATE 0x40000000 ++#define BM_PXP_CTRL_RSVD4 0x20000000 ++#define BM_PXP_CTRL_EN_REPEAT 0x10000000 ++#define BP_PXP_CTRL_RSVD3 26 ++#define BM_PXP_CTRL_RSVD3 0x0C000000 ++#define BF_PXP_CTRL_RSVD3(v) \ ++ (((v) << 26) & BM_PXP_CTRL_RSVD3) ++#define BP_PXP_CTRL_INTERLACED_INPUT 24 ++#define BM_PXP_CTRL_INTERLACED_INPUT 0x03000000 ++#define BF_PXP_CTRL_INTERLACED_INPUT(v) \ ++ (((v) << 24) & BM_PXP_CTRL_INTERLACED_INPUT) ++#define BV_PXP_CTRL_INTERLACED_INPUT__PROGRESSIVE 0x0 ++#define BV_PXP_CTRL_INTERLACED_INPUT__FIELD0 0x2 ++#define BV_PXP_CTRL_INTERLACED_INPUT__FIELD1 0x3 ++#define BM_PXP_CTRL_BLOCK_SIZE 0x00800000 ++#define BV_PXP_CTRL_BLOCK_SIZE__8X8 0x0 ++#define BV_PXP_CTRL_BLOCK_SIZE__16X16 0x1 ++#define BM_PXP_CTRL_ROT_POS 0x00400000 ++#define BM_PXP_CTRL_IN_PLACE 0x00200000 ++#define BP_PXP_CTRL_RSVD1 12 ++#define BM_PXP_CTRL_RSVD1 0x001FF000 ++#define BF_PXP_CTRL_RSVD1(v) \ ++ (((v) << 12) & BM_PXP_CTRL_RSVD1) ++#define BM_PXP_CTRL_VFLIP 0x00000800 ++#define BM_PXP_CTRL_HFLIP 0x00000400 ++#define BP_PXP_CTRL_ROTATE 8 ++#define BM_PXP_CTRL_ROTATE 0x00000300 ++#define BF_PXP_CTRL_ROTATE(v) \ ++ (((v) << 8) & BM_PXP_CTRL_ROTATE) ++#define BV_PXP_CTRL_ROTATE__ROT_0 0x0 ++#define BV_PXP_CTRL_ROTATE__ROT_90 0x1 ++#define BV_PXP_CTRL_ROTATE__ROT_180 0x2 ++#define BV_PXP_CTRL_ROTATE__ROT_270 0x3 ++#define BP_PXP_CTRL_RSVD0 5 ++#define BM_PXP_CTRL_RSVD0 0x000000E0 ++#define BF_PXP_CTRL_RSVD0(v) \ ++ (((v) << 5) & BM_PXP_CTRL_RSVD0) ++#define BM_PXP_CTRL_ENABLE_LCD_HANDSHAKE 0x00000010 ++#define BM_PXP_CTRL_LUT_DMA_IRQ_ENABLE 0x00000008 ++#define BM_PXP_CTRL_NEXT_IRQ_ENABLE 0x00000004 ++#define BM_PXP_CTRL_IRQ_ENABLE 0x00000002 ++#define BM_PXP_CTRL_ENABLE 0x00000001 ++ ++#define HW_PXP_STAT (0x00000010) ++#define HW_PXP_STAT_SET (0x00000014) ++#define HW_PXP_STAT_CLR (0x00000018) ++#define HW_PXP_STAT_TOG (0x0000001c) ++ ++#define BP_PXP_STAT_BLOCKX 24 ++#define BM_PXP_STAT_BLOCKX 0xFF000000 ++#define BF_PXP_STAT_BLOCKX(v) \ ++ (((v) << 24) & BM_PXP_STAT_BLOCKX) ++#define BP_PXP_STAT_BLOCKY 16 ++#define BM_PXP_STAT_BLOCKY 0x00FF0000 ++#define BF_PXP_STAT_BLOCKY(v) \ ++ (((v) << 16) & BM_PXP_STAT_BLOCKY) ++#define BP_PXP_STAT_RSVD2 9 ++#define BM_PXP_STAT_RSVD2 0x0000FE00 ++#define BF_PXP_STAT_RSVD2(v) \ ++ (((v) << 9) & BM_PXP_STAT_RSVD2) ++#define BM_PXP_STAT_LUT_DMA_LOAD_DONE_IRQ 0x00000100 ++#define BP_PXP_STAT_AXI_ERROR_ID 4 ++#define BM_PXP_STAT_AXI_ERROR_ID 0x000000F0 ++#define BF_PXP_STAT_AXI_ERROR_ID(v) \ ++ (((v) << 4) & BM_PXP_STAT_AXI_ERROR_ID) ++#define BM_PXP_STAT_NEXT_IRQ 0x00000008 ++#define BM_PXP_STAT_AXI_READ_ERROR 0x00000004 ++#define BM_PXP_STAT_AXI_WRITE_ERROR 0x00000002 ++#define BM_PXP_STAT_IRQ 0x00000001 ++ ++#define HW_PXP_OUT_CTRL (0x00000020) ++#define HW_PXP_OUT_CTRL_SET (0x00000024) ++#define HW_PXP_OUT_CTRL_CLR (0x00000028) ++#define HW_PXP_OUT_CTRL_TOG (0x0000002c) ++ ++#define BP_PXP_OUT_CTRL_ALPHA 24 ++#define BM_PXP_OUT_CTRL_ALPHA 0xFF000000 ++#define BF_PXP_OUT_CTRL_ALPHA(v) \ ++ (((v) << 24) & BM_PXP_OUT_CTRL_ALPHA) ++#define BM_PXP_OUT_CTRL_ALPHA_OUTPUT 0x00800000 ++#define BP_PXP_OUT_CTRL_RSVD1 10 ++#define BM_PXP_OUT_CTRL_RSVD1 0x007FFC00 ++#define BF_PXP_OUT_CTRL_RSVD1(v) \ ++ (((v) << 10) & BM_PXP_OUT_CTRL_RSVD1) ++#define BP_PXP_OUT_CTRL_INTERLACED_OUTPUT 8 ++#define BM_PXP_OUT_CTRL_INTERLACED_OUTPUT 0x00000300 ++#define BF_PXP_OUT_CTRL_INTERLACED_OUTPUT(v) \ ++ (((v) << 8) & BM_PXP_OUT_CTRL_INTERLACED_OUTPUT) ++#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__PROGRESSIVE 0x0 ++#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__FIELD0 0x1 ++#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__FIELD1 0x2 ++#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__INTERLACED 0x3 ++#define BP_PXP_OUT_CTRL_RSVD0 5 ++#define BM_PXP_OUT_CTRL_RSVD0 0x000000E0 ++#define BF_PXP_OUT_CTRL_RSVD0(v) \ ++ (((v) << 5) & BM_PXP_OUT_CTRL_RSVD0) ++#define BP_PXP_OUT_CTRL_FORMAT 0 ++#define BM_PXP_OUT_CTRL_FORMAT 0x0000001F ++#define BF_PXP_OUT_CTRL_FORMAT(v) \ ++ (((v) << 0) & BM_PXP_OUT_CTRL_FORMAT) ++#define BV_PXP_OUT_CTRL_FORMAT__ARGB8888 0x0 ++#define BV_PXP_OUT_CTRL_FORMAT__RGB888 0x4 ++#define BV_PXP_OUT_CTRL_FORMAT__RGB888P 0x5 ++#define BV_PXP_OUT_CTRL_FORMAT__ARGB1555 0x8 ++#define BV_PXP_OUT_CTRL_FORMAT__ARGB4444 0x9 ++#define BV_PXP_OUT_CTRL_FORMAT__RGB555 0xC ++#define BV_PXP_OUT_CTRL_FORMAT__RGB444 0xD ++#define BV_PXP_OUT_CTRL_FORMAT__RGB565 0xE ++#define BV_PXP_OUT_CTRL_FORMAT__YUV1P444 0x10 ++#define BV_PXP_OUT_CTRL_FORMAT__UYVY1P422 0x12 ++#define BV_PXP_OUT_CTRL_FORMAT__VYUY1P422 0x13 ++#define BV_PXP_OUT_CTRL_FORMAT__Y8 0x14 ++#define BV_PXP_OUT_CTRL_FORMAT__Y4 0x15 ++#define BV_PXP_OUT_CTRL_FORMAT__YUV2P422 0x18 ++#define BV_PXP_OUT_CTRL_FORMAT__YUV2P420 0x19 ++#define BV_PXP_OUT_CTRL_FORMAT__YVU2P422 0x1A ++#define BV_PXP_OUT_CTRL_FORMAT__YVU2P420 0x1B ++ ++#define HW_PXP_OUT_BUF (0x00000030) ++ ++#define BP_PXP_OUT_BUF_ADDR 0 ++#define BM_PXP_OUT_BUF_ADDR 0xFFFFFFFF ++#define BF_PXP_OUT_BUF_ADDR(v) (v) ++ ++#define HW_PXP_OUT_BUF2 (0x00000040) ++ ++#define BP_PXP_OUT_BUF2_ADDR 0 ++#define BM_PXP_OUT_BUF2_ADDR 0xFFFFFFFF ++#define BF_PXP_OUT_BUF2_ADDR(v) (v) ++ ++#define HW_PXP_OUT_PITCH (0x00000050) ++ ++#define BP_PXP_OUT_PITCH_RSVD 16 ++#define BM_PXP_OUT_PITCH_RSVD 0xFFFF0000 ++#define BF_PXP_OUT_PITCH_RSVD(v) \ ++ (((v) << 16) & BM_PXP_OUT_PITCH_RSVD) ++#define BP_PXP_OUT_PITCH_PITCH 0 ++#define BM_PXP_OUT_PITCH_PITCH 0x0000FFFF ++#define BF_PXP_OUT_PITCH_PITCH(v) \ ++ (((v) << 0) & BM_PXP_OUT_PITCH_PITCH) ++ ++#define HW_PXP_OUT_LRC (0x00000060) ++ ++#define BP_PXP_OUT_LRC_RSVD1 30 ++#define BM_PXP_OUT_LRC_RSVD1 0xC0000000 ++#define BF_PXP_OUT_LRC_RSVD1(v) \ ++ (((v) << 30) & BM_PXP_OUT_LRC_RSVD1) ++#define BP_PXP_OUT_LRC_X 16 ++#define BM_PXP_OUT_LRC_X 0x3FFF0000 ++#define BF_PXP_OUT_LRC_X(v) \ ++ (((v) << 16) & BM_PXP_OUT_LRC_X) ++#define BP_PXP_OUT_LRC_RSVD0 14 ++#define BM_PXP_OUT_LRC_RSVD0 0x0000C000 ++#define BF_PXP_OUT_LRC_RSVD0(v) \ ++ (((v) << 14) & BM_PXP_OUT_LRC_RSVD0) ++#define BP_PXP_OUT_LRC_Y 0 ++#define BM_PXP_OUT_LRC_Y 0x00003FFF ++#define BF_PXP_OUT_LRC_Y(v) \ ++ (((v) << 0) & BM_PXP_OUT_LRC_Y) ++ ++#define HW_PXP_OUT_PS_ULC (0x00000070) ++ ++#define BP_PXP_OUT_PS_ULC_RSVD1 30 ++#define BM_PXP_OUT_PS_ULC_RSVD1 0xC0000000 ++#define BF_PXP_OUT_PS_ULC_RSVD1(v) \ ++ (((v) << 30) & BM_PXP_OUT_PS_ULC_RSVD1) ++#define BP_PXP_OUT_PS_ULC_X 16 ++#define BM_PXP_OUT_PS_ULC_X 0x3FFF0000 ++#define BF_PXP_OUT_PS_ULC_X(v) \ ++ (((v) << 16) & BM_PXP_OUT_PS_ULC_X) ++#define BP_PXP_OUT_PS_ULC_RSVD0 14 ++#define BM_PXP_OUT_PS_ULC_RSVD0 0x0000C000 ++#define BF_PXP_OUT_PS_ULC_RSVD0(v) \ ++ (((v) << 14) & BM_PXP_OUT_PS_ULC_RSVD0) ++#define BP_PXP_OUT_PS_ULC_Y 0 ++#define BM_PXP_OUT_PS_ULC_Y 0x00003FFF ++#define BF_PXP_OUT_PS_ULC_Y(v) \ ++ (((v) << 0) & BM_PXP_OUT_PS_ULC_Y) ++ ++#define HW_PXP_OUT_PS_LRC (0x00000080) ++ ++#define BP_PXP_OUT_PS_LRC_RSVD1 30 ++#define BM_PXP_OUT_PS_LRC_RSVD1 0xC0000000 ++#define BF_PXP_OUT_PS_LRC_RSVD1(v) \ ++ (((v) << 30) & BM_PXP_OUT_PS_LRC_RSVD1) ++#define BP_PXP_OUT_PS_LRC_X 16 ++#define BM_PXP_OUT_PS_LRC_X 0x3FFF0000 ++#define BF_PXP_OUT_PS_LRC_X(v) \ ++ (((v) << 16) & BM_PXP_OUT_PS_LRC_X) ++#define BP_PXP_OUT_PS_LRC_RSVD0 14 ++#define BM_PXP_OUT_PS_LRC_RSVD0 0x0000C000 ++#define BF_PXP_OUT_PS_LRC_RSVD0(v) \ ++ (((v) << 14) & BM_PXP_OUT_PS_LRC_RSVD0) ++#define BP_PXP_OUT_PS_LRC_Y 0 ++#define BM_PXP_OUT_PS_LRC_Y 0x00003FFF ++#define BF_PXP_OUT_PS_LRC_Y(v) \ ++ (((v) << 0) & BM_PXP_OUT_PS_LRC_Y) ++ ++#define HW_PXP_OUT_AS_ULC (0x00000090) ++ ++#define BP_PXP_OUT_AS_ULC_RSVD1 30 ++#define BM_PXP_OUT_AS_ULC_RSVD1 0xC0000000 ++#define BF_PXP_OUT_AS_ULC_RSVD1(v) \ ++ (((v) << 30) & BM_PXP_OUT_AS_ULC_RSVD1) ++#define BP_PXP_OUT_AS_ULC_X 16 ++#define BM_PXP_OUT_AS_ULC_X 0x3FFF0000 ++#define BF_PXP_OUT_AS_ULC_X(v) \ ++ (((v) << 16) & BM_PXP_OUT_AS_ULC_X) ++#define BP_PXP_OUT_AS_ULC_RSVD0 14 ++#define BM_PXP_OUT_AS_ULC_RSVD0 0x0000C000 ++#define BF_PXP_OUT_AS_ULC_RSVD0(v) \ ++ (((v) << 14) & BM_PXP_OUT_AS_ULC_RSVD0) ++#define BP_PXP_OUT_AS_ULC_Y 0 ++#define BM_PXP_OUT_AS_ULC_Y 0x00003FFF ++#define BF_PXP_OUT_AS_ULC_Y(v) \ ++ (((v) << 0) & BM_PXP_OUT_AS_ULC_Y) ++ ++#define HW_PXP_OUT_AS_LRC (0x000000a0) ++ ++#define BP_PXP_OUT_AS_LRC_RSVD1 30 ++#define BM_PXP_OUT_AS_LRC_RSVD1 0xC0000000 ++#define BF_PXP_OUT_AS_LRC_RSVD1(v) \ ++ (((v) << 30) & BM_PXP_OUT_AS_LRC_RSVD1) ++#define BP_PXP_OUT_AS_LRC_X 16 ++#define BM_PXP_OUT_AS_LRC_X 0x3FFF0000 ++#define BF_PXP_OUT_AS_LRC_X(v) \ ++ (((v) << 16) & BM_PXP_OUT_AS_LRC_X) ++#define BP_PXP_OUT_AS_LRC_RSVD0 14 ++#define BM_PXP_OUT_AS_LRC_RSVD0 0x0000C000 ++#define BF_PXP_OUT_AS_LRC_RSVD0(v) \ ++ (((v) << 14) & BM_PXP_OUT_AS_LRC_RSVD0) ++#define BP_PXP_OUT_AS_LRC_Y 0 ++#define BM_PXP_OUT_AS_LRC_Y 0x00003FFF ++#define BF_PXP_OUT_AS_LRC_Y(v) \ ++ (((v) << 0) & BM_PXP_OUT_AS_LRC_Y) ++ ++#define HW_PXP_PS_CTRL (0x000000b0) ++#define HW_PXP_PS_CTRL_SET (0x000000b4) ++#define HW_PXP_PS_CTRL_CLR (0x000000b8) ++#define HW_PXP_PS_CTRL_TOG (0x000000bc) ++ ++#define BP_PXP_PS_CTRL_RSVD1 12 ++#define BM_PXP_PS_CTRL_RSVD1 0xFFFFF000 ++#define BF_PXP_PS_CTRL_RSVD1(v) \ ++ (((v) << 12) & BM_PXP_PS_CTRL_RSVD1) ++#define BP_PXP_PS_CTRL_DECX 10 ++#define BM_PXP_PS_CTRL_DECX 0x00000C00 ++#define BF_PXP_PS_CTRL_DECX(v) \ ++ (((v) << 10) & BM_PXP_PS_CTRL_DECX) ++#define BV_PXP_PS_CTRL_DECX__DISABLE 0x0 ++#define BV_PXP_PS_CTRL_DECX__DECX2 0x1 ++#define BV_PXP_PS_CTRL_DECX__DECX4 0x2 ++#define BV_PXP_PS_CTRL_DECX__DECX8 0x3 ++#define BP_PXP_PS_CTRL_DECY 8 ++#define BM_PXP_PS_CTRL_DECY 0x00000300 ++#define BF_PXP_PS_CTRL_DECY(v) \ ++ (((v) << 8) & BM_PXP_PS_CTRL_DECY) ++#define BV_PXP_PS_CTRL_DECY__DISABLE 0x0 ++#define BV_PXP_PS_CTRL_DECY__DECY2 0x1 ++#define BV_PXP_PS_CTRL_DECY__DECY4 0x2 ++#define BV_PXP_PS_CTRL_DECY__DECY8 0x3 ++#define BP_PXP_PS_CTRL_SWAP 5 ++#define BM_PXP_PS_CTRL_SWAP 0x000000E0 ++#define BF_PXP_PS_CTRL_SWAP(v) \ ++ (((v) << 5) & BM_PXP_PS_CTRL_SWAP) ++#define BP_PXP_PS_CTRL_FORMAT 0 ++#define BM_PXP_PS_CTRL_FORMAT 0x0000001F ++#define BF_PXP_PS_CTRL_FORMAT(v) \ ++ (((v) << 0) & BM_PXP_PS_CTRL_FORMAT) ++#define BV_PXP_PS_CTRL_FORMAT__RGB888 0x4 ++#define BV_PXP_PS_CTRL_FORMAT__RGB555 0xC ++#define BV_PXP_PS_CTRL_FORMAT__RGB444 0xD ++#define BV_PXP_PS_CTRL_FORMAT__RGB565 0xE ++#define BV_PXP_PS_CTRL_FORMAT__YUV1P444 0x10 ++#define BV_PXP_PS_CTRL_FORMAT__UYVY1P422 0x12 ++#define BV_PXP_PS_CTRL_FORMAT__VYUY1P422 0x13 ++#define BV_PXP_PS_CTRL_FORMAT__Y8 0x14 ++#define BV_PXP_PS_CTRL_FORMAT__Y4 0x15 ++#define BV_PXP_PS_CTRL_FORMAT__YUV2P422 0x18 ++#define BV_PXP_PS_CTRL_FORMAT__YUV2P420 0x19 ++#define BV_PXP_PS_CTRL_FORMAT__YVU2P422 0x1A ++#define BV_PXP_PS_CTRL_FORMAT__YVU2P420 0x1B ++#define BV_PXP_PS_CTRL_FORMAT__YUV422 0x1E ++#define BV_PXP_PS_CTRL_FORMAT__YUV420 0x1F ++ ++#define HW_PXP_PS_BUF (0x000000c0) ++ ++#define BP_PXP_PS_BUF_ADDR 0 ++#define BM_PXP_PS_BUF_ADDR 0xFFFFFFFF ++#define BF_PXP_PS_BUF_ADDR(v) (v) ++ ++#define HW_PXP_PS_UBUF (0x000000d0) ++ ++#define BP_PXP_PS_UBUF_ADDR 0 ++#define BM_PXP_PS_UBUF_ADDR 0xFFFFFFFF ++#define BF_PXP_PS_UBUF_ADDR(v) (v) ++ ++#define HW_PXP_PS_VBUF (0x000000e0) ++ ++#define BP_PXP_PS_VBUF_ADDR 0 ++#define BM_PXP_PS_VBUF_ADDR 0xFFFFFFFF ++#define BF_PXP_PS_VBUF_ADDR(v) (v) ++ ++#define HW_PXP_PS_PITCH (0x000000f0) ++ ++#define BP_PXP_PS_PITCH_RSVD 16 ++#define BM_PXP_PS_PITCH_RSVD 0xFFFF0000 ++#define BF_PXP_PS_PITCH_RSVD(v) \ ++ (((v) << 16) & BM_PXP_PS_PITCH_RSVD) ++#define BP_PXP_PS_PITCH_PITCH 0 ++#define BM_PXP_PS_PITCH_PITCH 0x0000FFFF ++#define BF_PXP_PS_PITCH_PITCH(v) \ ++ (((v) << 0) & BM_PXP_PS_PITCH_PITCH) ++ ++#define HW_PXP_PS_BACKGROUND (0x00000100) ++ ++#define BP_PXP_PS_BACKGROUND_RSVD 24 ++#define BM_PXP_PS_BACKGROUND_RSVD 0xFF000000 ++#define BF_PXP_PS_BACKGROUND_RSVD(v) \ ++ (((v) << 24) & BM_PXP_PS_BACKGROUND_RSVD) ++#define BP_PXP_PS_BACKGROUND_COLOR 0 ++#define BM_PXP_PS_BACKGROUND_COLOR 0x00FFFFFF ++#define BF_PXP_PS_BACKGROUND_COLOR(v) \ ++ (((v) << 0) & BM_PXP_PS_BACKGROUND_COLOR) ++ ++#define HW_PXP_PS_SCALE (0x00000110) ++ ++#define BM_PXP_PS_SCALE_RSVD2 0x80000000 ++#define BP_PXP_PS_SCALE_YSCALE 16 ++#define BM_PXP_PS_SCALE_YSCALE 0x7FFF0000 ++#define BF_PXP_PS_SCALE_YSCALE(v) \ ++ (((v) << 16) & BM_PXP_PS_SCALE_YSCALE) ++#define BM_PXP_PS_SCALE_RSVD1 0x00008000 ++#define BP_PXP_PS_SCALE_XSCALE 0 ++#define BM_PXP_PS_SCALE_XSCALE 0x00007FFF ++#define BF_PXP_PS_SCALE_XSCALE(v) \ ++ (((v) << 0) & BM_PXP_PS_SCALE_XSCALE) ++ ++#define HW_PXP_PS_OFFSET (0x00000120) ++ ++#define BP_PXP_PS_OFFSET_RSVD2 28 ++#define BM_PXP_PS_OFFSET_RSVD2 0xF0000000 ++#define BF_PXP_PS_OFFSET_RSVD2(v) \ ++ (((v) << 28) & BM_PXP_PS_OFFSET_RSVD2) ++#define BP_PXP_PS_OFFSET_YOFFSET 16 ++#define BM_PXP_PS_OFFSET_YOFFSET 0x0FFF0000 ++#define BF_PXP_PS_OFFSET_YOFFSET(v) \ ++ (((v) << 16) & BM_PXP_PS_OFFSET_YOFFSET) ++#define BP_PXP_PS_OFFSET_RSVD1 12 ++#define BM_PXP_PS_OFFSET_RSVD1 0x0000F000 ++#define BF_PXP_PS_OFFSET_RSVD1(v) \ ++ (((v) << 12) & BM_PXP_PS_OFFSET_RSVD1) ++#define BP_PXP_PS_OFFSET_XOFFSET 0 ++#define BM_PXP_PS_OFFSET_XOFFSET 0x00000FFF ++#define BF_PXP_PS_OFFSET_XOFFSET(v) \ ++ (((v) << 0) & BM_PXP_PS_OFFSET_XOFFSET) ++ ++#define HW_PXP_PS_CLRKEYLOW (0x00000130) ++ ++#define BP_PXP_PS_CLRKEYLOW_RSVD1 24 ++#define BM_PXP_PS_CLRKEYLOW_RSVD1 0xFF000000 ++#define BF_PXP_PS_CLRKEYLOW_RSVD1(v) \ ++ (((v) << 24) & BM_PXP_PS_CLRKEYLOW_RSVD1) ++#define BP_PXP_PS_CLRKEYLOW_PIXEL 0 ++#define BM_PXP_PS_CLRKEYLOW_PIXEL 0x00FFFFFF ++#define BF_PXP_PS_CLRKEYLOW_PIXEL(v) \ ++ (((v) << 0) & BM_PXP_PS_CLRKEYLOW_PIXEL) ++ ++#define HW_PXP_PS_CLRKEYHIGH (0x00000140) ++ ++#define BP_PXP_PS_CLRKEYHIGH_RSVD1 24 ++#define BM_PXP_PS_CLRKEYHIGH_RSVD1 0xFF000000 ++#define BF_PXP_PS_CLRKEYHIGH_RSVD1(v) \ ++ (((v) << 24) & BM_PXP_PS_CLRKEYHIGH_RSVD1) ++#define BP_PXP_PS_CLRKEYHIGH_PIXEL 0 ++#define BM_PXP_PS_CLRKEYHIGH_PIXEL 0x00FFFFFF ++#define BF_PXP_PS_CLRKEYHIGH_PIXEL(v) \ ++ (((v) << 0) & BM_PXP_PS_CLRKEYHIGH_PIXEL) ++ ++#define HW_PXP_AS_CTRL (0x00000150) ++ ++#define BP_PXP_AS_CTRL_RSVD1 21 ++#define BM_PXP_AS_CTRL_RSVD1 0xFFE00000 ++#define BF_PXP_AS_CTRL_RSVD1(v) \ ++ (((v) << 21) & BM_PXP_AS_CTRL_RSVD1) ++#define BM_PXP_AS_CTRL_ALPHA_INVERT 0x00100000 ++#define BP_PXP_AS_CTRL_ROP 16 ++#define BM_PXP_AS_CTRL_ROP 0x000F0000 ++#define BF_PXP_AS_CTRL_ROP(v) \ ++ (((v) << 16) & BM_PXP_AS_CTRL_ROP) ++#define BV_PXP_AS_CTRL_ROP__MASKAS 0x0 ++#define BV_PXP_AS_CTRL_ROP__MASKNOTAS 0x1 ++#define BV_PXP_AS_CTRL_ROP__MASKASNOT 0x2 ++#define BV_PXP_AS_CTRL_ROP__MERGEAS 0x3 ++#define BV_PXP_AS_CTRL_ROP__MERGENOTAS 0x4 ++#define BV_PXP_AS_CTRL_ROP__MERGEASNOT 0x5 ++#define BV_PXP_AS_CTRL_ROP__NOTCOPYAS 0x6 ++#define BV_PXP_AS_CTRL_ROP__NOT 0x7 ++#define BV_PXP_AS_CTRL_ROP__NOTMASKAS 0x8 ++#define BV_PXP_AS_CTRL_ROP__NOTMERGEAS 0x9 ++#define BV_PXP_AS_CTRL_ROP__XORAS 0xA ++#define BV_PXP_AS_CTRL_ROP__NOTXORAS 0xB ++#define BP_PXP_AS_CTRL_ALPHA 8 ++#define BM_PXP_AS_CTRL_ALPHA 0x0000FF00 ++#define BF_PXP_AS_CTRL_ALPHA(v) \ ++ (((v) << 8) & BM_PXP_AS_CTRL_ALPHA) ++#define BP_PXP_AS_CTRL_FORMAT 4 ++#define BM_PXP_AS_CTRL_FORMAT 0x000000F0 ++#define BF_PXP_AS_CTRL_FORMAT(v) \ ++ (((v) << 4) & BM_PXP_AS_CTRL_FORMAT) ++#define BV_PXP_AS_CTRL_FORMAT__ARGB8888 0x0 ++#define BV_PXP_AS_CTRL_FORMAT__RGB888 0x4 ++#define BV_PXP_AS_CTRL_FORMAT__ARGB1555 0x8 ++#define BV_PXP_AS_CTRL_FORMAT__ARGB4444 0x9 ++#define BV_PXP_AS_CTRL_FORMAT__RGB555 0xC ++#define BV_PXP_AS_CTRL_FORMAT__RGB444 0xD ++#define BV_PXP_AS_CTRL_FORMAT__RGB565 0xE ++#define BM_PXP_AS_CTRL_ENABLE_COLORKEY 0x00000008 ++#define BP_PXP_AS_CTRL_ALPHA_CTRL 1 ++#define BM_PXP_AS_CTRL_ALPHA_CTRL 0x00000006 ++#define BF_PXP_AS_CTRL_ALPHA_CTRL(v) \ ++ (((v) << 1) & BM_PXP_AS_CTRL_ALPHA_CTRL) ++#define BV_PXP_AS_CTRL_ALPHA_CTRL__Embedded 0x0 ++#define BV_PXP_AS_CTRL_ALPHA_CTRL__Override 0x1 ++#define BV_PXP_AS_CTRL_ALPHA_CTRL__Multiply 0x2 ++#define BV_PXP_AS_CTRL_ALPHA_CTRL__ROPs 0x3 ++#define BM_PXP_AS_CTRL_RSVD0 0x00000001 ++ ++#define HW_PXP_AS_BUF (0x00000160) ++ ++#define BP_PXP_AS_BUF_ADDR 0 ++#define BM_PXP_AS_BUF_ADDR 0xFFFFFFFF ++#define BF_PXP_AS_BUF_ADDR(v) (v) ++ ++#define HW_PXP_AS_PITCH (0x00000170) ++ ++#define BP_PXP_AS_PITCH_RSVD 16 ++#define BM_PXP_AS_PITCH_RSVD 0xFFFF0000 ++#define BF_PXP_AS_PITCH_RSVD(v) \ ++ (((v) << 16) & BM_PXP_AS_PITCH_RSVD) ++#define BP_PXP_AS_PITCH_PITCH 0 ++#define BM_PXP_AS_PITCH_PITCH 0x0000FFFF ++#define BF_PXP_AS_PITCH_PITCH(v) \ ++ (((v) << 0) & BM_PXP_AS_PITCH_PITCH) ++ ++#define HW_PXP_AS_CLRKEYLOW (0x00000180) ++ ++#define BP_PXP_AS_CLRKEYLOW_RSVD1 24 ++#define BM_PXP_AS_CLRKEYLOW_RSVD1 0xFF000000 ++#define BF_PXP_AS_CLRKEYLOW_RSVD1(v) \ ++ (((v) << 24) & BM_PXP_AS_CLRKEYLOW_RSVD1) ++#define BP_PXP_AS_CLRKEYLOW_PIXEL 0 ++#define BM_PXP_AS_CLRKEYLOW_PIXEL 0x00FFFFFF ++#define BF_PXP_AS_CLRKEYLOW_PIXEL(v) \ ++ (((v) << 0) & BM_PXP_AS_CLRKEYLOW_PIXEL) ++ ++#define HW_PXP_AS_CLRKEYHIGH (0x00000190) ++ ++#define BP_PXP_AS_CLRKEYHIGH_RSVD1 24 ++#define BM_PXP_AS_CLRKEYHIGH_RSVD1 0xFF000000 ++#define BF_PXP_AS_CLRKEYHIGH_RSVD1(v) \ ++ (((v) << 24) & BM_PXP_AS_CLRKEYHIGH_RSVD1) ++#define BP_PXP_AS_CLRKEYHIGH_PIXEL 0 ++#define BM_PXP_AS_CLRKEYHIGH_PIXEL 0x00FFFFFF ++#define BF_PXP_AS_CLRKEYHIGH_PIXEL(v) \ ++ (((v) << 0) & BM_PXP_AS_CLRKEYHIGH_PIXEL) ++ ++#define HW_PXP_CSC1_COEF0 (0x000001a0) ++ ++#define BM_PXP_CSC1_COEF0_YCBCR_MODE 0x80000000 ++#define BM_PXP_CSC1_COEF0_BYPASS 0x40000000 ++#define BM_PXP_CSC1_COEF0_RSVD1 0x20000000 ++#define BP_PXP_CSC1_COEF0_C0 18 ++#define BM_PXP_CSC1_COEF0_C0 0x1FFC0000 ++#define BF_PXP_CSC1_COEF0_C0(v) \ ++ (((v) << 18) & BM_PXP_CSC1_COEF0_C0) ++#define BP_PXP_CSC1_COEF0_UV_OFFSET 9 ++#define BM_PXP_CSC1_COEF0_UV_OFFSET 0x0003FE00 ++#define BF_PXP_CSC1_COEF0_UV_OFFSET(v) \ ++ (((v) << 9) & BM_PXP_CSC1_COEF0_UV_OFFSET) ++#define BP_PXP_CSC1_COEF0_Y_OFFSET 0 ++#define BM_PXP_CSC1_COEF0_Y_OFFSET 0x000001FF ++#define BF_PXP_CSC1_COEF0_Y_OFFSET(v) \ ++ (((v) << 0) & BM_PXP_CSC1_COEF0_Y_OFFSET) ++ ++#define HW_PXP_CSC1_COEF1 (0x000001b0) ++ ++#define BP_PXP_CSC1_COEF1_RSVD1 27 ++#define BM_PXP_CSC1_COEF1_RSVD1 0xF8000000 ++#define BF_PXP_CSC1_COEF1_RSVD1(v) \ ++ (((v) << 27) & BM_PXP_CSC1_COEF1_RSVD1) ++#define BP_PXP_CSC1_COEF1_C1 16 ++#define BM_PXP_CSC1_COEF1_C1 0x07FF0000 ++#define BF_PXP_CSC1_COEF1_C1(v) \ ++ (((v) << 16) & BM_PXP_CSC1_COEF1_C1) ++#define BP_PXP_CSC1_COEF1_RSVD0 11 ++#define BM_PXP_CSC1_COEF1_RSVD0 0x0000F800 ++#define BF_PXP_CSC1_COEF1_RSVD0(v) \ ++ (((v) << 11) & BM_PXP_CSC1_COEF1_RSVD0) ++#define BP_PXP_CSC1_COEF1_C4 0 ++#define BM_PXP_CSC1_COEF1_C4 0x000007FF ++#define BF_PXP_CSC1_COEF1_C4(v) \ ++ (((v) << 0) & BM_PXP_CSC1_COEF1_C4) ++ ++#define HW_PXP_CSC1_COEF2 (0x000001c0) ++ ++#define BP_PXP_CSC1_COEF2_RSVD1 27 ++#define BM_PXP_CSC1_COEF2_RSVD1 0xF8000000 ++#define BF_PXP_CSC1_COEF2_RSVD1(v) \ ++ (((v) << 27) & BM_PXP_CSC1_COEF2_RSVD1) ++#define BP_PXP_CSC1_COEF2_C2 16 ++#define BM_PXP_CSC1_COEF2_C2 0x07FF0000 ++#define BF_PXP_CSC1_COEF2_C2(v) \ ++ (((v) << 16) & BM_PXP_CSC1_COEF2_C2) ++#define BP_PXP_CSC1_COEF2_RSVD0 11 ++#define BM_PXP_CSC1_COEF2_RSVD0 0x0000F800 ++#define BF_PXP_CSC1_COEF2_RSVD0(v) \ ++ (((v) << 11) & BM_PXP_CSC1_COEF2_RSVD0) ++#define BP_PXP_CSC1_COEF2_C3 0 ++#define BM_PXP_CSC1_COEF2_C3 0x000007FF ++#define BF_PXP_CSC1_COEF2_C3(v) \ ++ (((v) << 0) & BM_PXP_CSC1_COEF2_C3) ++ ++#define HW_PXP_CSC2_CTRL (0x000001d0) ++ ++#define BP_PXP_CSC2_CTRL_RSVD 3 ++#define BM_PXP_CSC2_CTRL_RSVD 0xFFFFFFF8 ++#define BF_PXP_CSC2_CTRL_RSVD(v) \ ++ (((v) << 3) & BM_PXP_CSC2_CTRL_RSVD) ++#define BP_PXP_CSC2_CTRL_CSC_MODE 1 ++#define BM_PXP_CSC2_CTRL_CSC_MODE 0x00000006 ++#define BF_PXP_CSC2_CTRL_CSC_MODE(v) \ ++ (((v) << 1) & BM_PXP_CSC2_CTRL_CSC_MODE) ++#define BV_PXP_CSC2_CTRL_CSC_MODE__YUV2RGB 0x0 ++#define BV_PXP_CSC2_CTRL_CSC_MODE__YCbCr2RGB 0x1 ++#define BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YUV 0x2 ++#define BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YCbCr 0x3 ++#define BM_PXP_CSC2_CTRL_BYPASS 0x00000001 ++ ++#define HW_PXP_CSC2_COEF0 (0x000001e0) ++ ++#define BP_PXP_CSC2_COEF0_RSVD1 27 ++#define BM_PXP_CSC2_COEF0_RSVD1 0xF8000000 ++#define BF_PXP_CSC2_COEF0_RSVD1(v) \ ++ (((v) << 27) & BM_PXP_CSC2_COEF0_RSVD1) ++#define BP_PXP_CSC2_COEF0_A2 16 ++#define BM_PXP_CSC2_COEF0_A2 0x07FF0000 ++#define BF_PXP_CSC2_COEF0_A2(v) \ ++ (((v) << 16) & BM_PXP_CSC2_COEF0_A2) ++#define BP_PXP_CSC2_COEF0_RSVD0 11 ++#define BM_PXP_CSC2_COEF0_RSVD0 0x0000F800 ++#define BF_PXP_CSC2_COEF0_RSVD0(v) \ ++ (((v) << 11) & BM_PXP_CSC2_COEF0_RSVD0) ++#define BP_PXP_CSC2_COEF0_A1 0 ++#define BM_PXP_CSC2_COEF0_A1 0x000007FF ++#define BF_PXP_CSC2_COEF0_A1(v) \ ++ (((v) << 0) & BM_PXP_CSC2_COEF0_A1) ++ ++#define HW_PXP_CSC2_COEF1 (0x000001f0) ++ ++#define BP_PXP_CSC2_COEF1_RSVD1 27 ++#define BM_PXP_CSC2_COEF1_RSVD1 0xF8000000 ++#define BF_PXP_CSC2_COEF1_RSVD1(v) \ ++ (((v) << 27) & BM_PXP_CSC2_COEF1_RSVD1) ++#define BP_PXP_CSC2_COEF1_B1 16 ++#define BM_PXP_CSC2_COEF1_B1 0x07FF0000 ++#define BF_PXP_CSC2_COEF1_B1(v) \ ++ (((v) << 16) & BM_PXP_CSC2_COEF1_B1) ++#define BP_PXP_CSC2_COEF1_RSVD0 11 ++#define BM_PXP_CSC2_COEF1_RSVD0 0x0000F800 ++#define BF_PXP_CSC2_COEF1_RSVD0(v) \ ++ (((v) << 11) & BM_PXP_CSC2_COEF1_RSVD0) ++#define BP_PXP_CSC2_COEF1_A3 0 ++#define BM_PXP_CSC2_COEF1_A3 0x000007FF ++#define BF_PXP_CSC2_COEF1_A3(v) \ ++ (((v) << 0) & BM_PXP_CSC2_COEF1_A3) ++ ++#define HW_PXP_CSC2_COEF2 (0x00000200) ++ ++#define BP_PXP_CSC2_COEF2_RSVD1 27 ++#define BM_PXP_CSC2_COEF2_RSVD1 0xF8000000 ++#define BF_PXP_CSC2_COEF2_RSVD1(v) \ ++ (((v) << 27) & BM_PXP_CSC2_COEF2_RSVD1) ++#define BP_PXP_CSC2_COEF2_B3 16 ++#define BM_PXP_CSC2_COEF2_B3 0x07FF0000 ++#define BF_PXP_CSC2_COEF2_B3(v) \ ++ (((v) << 16) & BM_PXP_CSC2_COEF2_B3) ++#define BP_PXP_CSC2_COEF2_RSVD0 11 ++#define BM_PXP_CSC2_COEF2_RSVD0 0x0000F800 ++#define BF_PXP_CSC2_COEF2_RSVD0(v) \ ++ (((v) << 11) & BM_PXP_CSC2_COEF2_RSVD0) ++#define BP_PXP_CSC2_COEF2_B2 0 ++#define BM_PXP_CSC2_COEF2_B2 0x000007FF ++#define BF_PXP_CSC2_COEF2_B2(v) \ ++ (((v) << 0) & BM_PXP_CSC2_COEF2_B2) ++ ++#define HW_PXP_CSC2_COEF3 (0x00000210) ++ ++#define BP_PXP_CSC2_COEF3_RSVD1 27 ++#define BM_PXP_CSC2_COEF3_RSVD1 0xF8000000 ++#define BF_PXP_CSC2_COEF3_RSVD1(v) \ ++ (((v) << 27) & BM_PXP_CSC2_COEF3_RSVD1) ++#define BP_PXP_CSC2_COEF3_C2 16 ++#define BM_PXP_CSC2_COEF3_C2 0x07FF0000 ++#define BF_PXP_CSC2_COEF3_C2(v) \ ++ (((v) << 16) & BM_PXP_CSC2_COEF3_C2) ++#define BP_PXP_CSC2_COEF3_RSVD0 11 ++#define BM_PXP_CSC2_COEF3_RSVD0 0x0000F800 ++#define BF_PXP_CSC2_COEF3_RSVD0(v) \ ++ (((v) << 11) & BM_PXP_CSC2_COEF3_RSVD0) ++#define BP_PXP_CSC2_COEF3_C1 0 ++#define BM_PXP_CSC2_COEF3_C1 0x000007FF ++#define BF_PXP_CSC2_COEF3_C1(v) \ ++ (((v) << 0) & BM_PXP_CSC2_COEF3_C1) ++ ++#define HW_PXP_CSC2_COEF4 (0x00000220) ++ ++#define BP_PXP_CSC2_COEF4_RSVD1 25 ++#define BM_PXP_CSC2_COEF4_RSVD1 0xFE000000 ++#define BF_PXP_CSC2_COEF4_RSVD1(v) \ ++ (((v) << 25) & BM_PXP_CSC2_COEF4_RSVD1) ++#define BP_PXP_CSC2_COEF4_D1 16 ++#define BM_PXP_CSC2_COEF4_D1 0x01FF0000 ++#define BF_PXP_CSC2_COEF4_D1(v) \ ++ (((v) << 16) & BM_PXP_CSC2_COEF4_D1) ++#define BP_PXP_CSC2_COEF4_RSVD0 11 ++#define BM_PXP_CSC2_COEF4_RSVD0 0x0000F800 ++#define BF_PXP_CSC2_COEF4_RSVD0(v) \ ++ (((v) << 11) & BM_PXP_CSC2_COEF4_RSVD0) ++#define BP_PXP_CSC2_COEF4_C3 0 ++#define BM_PXP_CSC2_COEF4_C3 0x000007FF ++#define BF_PXP_CSC2_COEF4_C3(v) \ ++ (((v) << 0) & BM_PXP_CSC2_COEF4_C3) ++ ++#define HW_PXP_CSC2_COEF5 (0x00000230) ++ ++#define BP_PXP_CSC2_COEF5_RSVD1 25 ++#define BM_PXP_CSC2_COEF5_RSVD1 0xFE000000 ++#define BF_PXP_CSC2_COEF5_RSVD1(v) \ ++ (((v) << 25) & BM_PXP_CSC2_COEF5_RSVD1) ++#define BP_PXP_CSC2_COEF5_D3 16 ++#define BM_PXP_CSC2_COEF5_D3 0x01FF0000 ++#define BF_PXP_CSC2_COEF5_D3(v) \ ++ (((v) << 16) & BM_PXP_CSC2_COEF5_D3) ++#define BP_PXP_CSC2_COEF5_RSVD0 9 ++#define BM_PXP_CSC2_COEF5_RSVD0 0x0000FE00 ++#define BF_PXP_CSC2_COEF5_RSVD0(v) \ ++ (((v) << 9) & BM_PXP_CSC2_COEF5_RSVD0) ++#define BP_PXP_CSC2_COEF5_D2 0 ++#define BM_PXP_CSC2_COEF5_D2 0x000001FF ++#define BF_PXP_CSC2_COEF5_D2(v) \ ++ (((v) << 0) & BM_PXP_CSC2_COEF5_D2) ++ ++#define HW_PXP_LUT_CTRL (0x00000240) ++ ++#define BM_PXP_LUT_CTRL_BYPASS 0x80000000 ++#define BP_PXP_LUT_CTRL_RSVD3 26 ++#define BM_PXP_LUT_CTRL_RSVD3 0x7C000000 ++#define BF_PXP_LUT_CTRL_RSVD3(v) \ ++ (((v) << 26) & BM_PXP_LUT_CTRL_RSVD3) ++#define BP_PXP_LUT_CTRL_LOOKUP_MODE 24 ++#define BM_PXP_LUT_CTRL_LOOKUP_MODE 0x03000000 ++#define BF_PXP_LUT_CTRL_LOOKUP_MODE(v) \ ++ (((v) << 24) & BM_PXP_LUT_CTRL_LOOKUP_MODE) ++#define BV_PXP_LUT_CTRL_LOOKUP_MODE__CACHE_RGB565 0x0 ++#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8 0x1 ++#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_RGB444 0x2 ++#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_RGB454 0x3 ++#define BP_PXP_LUT_CTRL_RSVD2 18 ++#define BM_PXP_LUT_CTRL_RSVD2 0x00FC0000 ++#define BF_PXP_LUT_CTRL_RSVD2(v) \ ++ (((v) << 18) & BM_PXP_LUT_CTRL_RSVD2) ++#define BP_PXP_LUT_CTRL_OUT_MODE 16 ++#define BM_PXP_LUT_CTRL_OUT_MODE 0x00030000 ++#define BF_PXP_LUT_CTRL_OUT_MODE(v) \ ++ (((v) << 16) & BM_PXP_LUT_CTRL_OUT_MODE) ++#define BV_PXP_LUT_CTRL_OUT_MODE__RESERVED 0x0 ++#define BV_PXP_LUT_CTRL_OUT_MODE__Y8 0x1 ++#define BV_PXP_LUT_CTRL_OUT_MODE__RGBW4444CFA 0x2 ++#define BV_PXP_LUT_CTRL_OUT_MODE__RGB888 0x3 ++#define BP_PXP_LUT_CTRL_RSVD1 11 ++#define BM_PXP_LUT_CTRL_RSVD1 0x0000F800 ++#define BF_PXP_LUT_CTRL_RSVD1(v) \ ++ (((v) << 11) & BM_PXP_LUT_CTRL_RSVD1) ++#define BM_PXP_LUT_CTRL_SEL_8KB 0x00000400 ++#define BM_PXP_LUT_CTRL_LRU_UPD 0x00000200 ++#define BM_PXP_LUT_CTRL_INVALID 0x00000100 ++#define BP_PXP_LUT_CTRL_RSVD0 1 ++#define BM_PXP_LUT_CTRL_RSVD0 0x000000FE ++#define BF_PXP_LUT_CTRL_RSVD0(v) \ ++ (((v) << 1) & BM_PXP_LUT_CTRL_RSVD0) ++#define BM_PXP_LUT_CTRL_DMA_START 0x00000001 ++ ++#define HW_PXP_LUT_ADDR (0x00000250) ++ ++#define BM_PXP_LUT_ADDR_RSVD2 0x80000000 ++#define BP_PXP_LUT_ADDR_NUM_BYTES 16 ++#define BM_PXP_LUT_ADDR_NUM_BYTES 0x7FFF0000 ++#define BF_PXP_LUT_ADDR_NUM_BYTES(v) \ ++ (((v) << 16) & BM_PXP_LUT_ADDR_NUM_BYTES) ++#define BP_PXP_LUT_ADDR_RSVD1 14 ++#define BM_PXP_LUT_ADDR_RSVD1 0x0000C000 ++#define BF_PXP_LUT_ADDR_RSVD1(v) \ ++ (((v) << 14) & BM_PXP_LUT_ADDR_RSVD1) ++#define BP_PXP_LUT_ADDR_ADDR 0 ++#define BM_PXP_LUT_ADDR_ADDR 0x00003FFF ++#define BF_PXP_LUT_ADDR_ADDR(v) \ ++ (((v) << 0) & BM_PXP_LUT_ADDR_ADDR) ++ ++#define HW_PXP_LUT_DATA (0x00000260) ++ ++#define BP_PXP_LUT_DATA_DATA 0 ++#define BM_PXP_LUT_DATA_DATA 0xFFFFFFFF ++#define BF_PXP_LUT_DATA_DATA(v) (v) ++ ++#define HW_PXP_LUT_EXTMEM (0x00000270) ++ ++#define BP_PXP_LUT_EXTMEM_ADDR 0 ++#define BM_PXP_LUT_EXTMEM_ADDR 0xFFFFFFFF ++#define BF_PXP_LUT_EXTMEM_ADDR(v) (v) ++ ++#define HW_PXP_CFA (0x00000280) ++ ++#define BP_PXP_CFA_DATA 0 ++#define BM_PXP_CFA_DATA 0xFFFFFFFF ++#define BF_PXP_CFA_DATA(v) (v) ++ ++#define HW_PXP_HIST_CTRL (0x00000290) ++ ++#define BP_PXP_HIST_CTRL_RSVD 6 ++#define BM_PXP_HIST_CTRL_RSVD 0xFFFFFFC0 ++#define BF_PXP_HIST_CTRL_RSVD(v) \ ++ (((v) << 6) & BM_PXP_HIST_CTRL_RSVD) ++#define BP_PXP_HIST_CTRL_PANEL_MODE 4 ++#define BM_PXP_HIST_CTRL_PANEL_MODE 0x00000030 ++#define BF_PXP_HIST_CTRL_PANEL_MODE(v) \ ++ (((v) << 4) & BM_PXP_HIST_CTRL_PANEL_MODE) ++#define BV_PXP_HIST_CTRL_PANEL_MODE__GRAY4 0x0 ++#define BV_PXP_HIST_CTRL_PANEL_MODE__GRAY8 0x1 ++#define BV_PXP_HIST_CTRL_PANEL_MODE__GRAY16 0x2 ++#define BV_PXP_HIST_CTRL_PANEL_MODE__GRAY32 0x3 ++#define BP_PXP_HIST_CTRL_STATUS 0 ++#define BM_PXP_HIST_CTRL_STATUS 0x0000000F ++#define BF_PXP_HIST_CTRL_STATUS(v) \ ++ (((v) << 0) & BM_PXP_HIST_CTRL_STATUS) ++ ++#define HW_PXP_HIST2_PARAM (0x000002a0) ++ ++#define BP_PXP_HIST2_PARAM_RSVD 16 ++#define BM_PXP_HIST2_PARAM_RSVD 0xFFFF0000 ++#define BF_PXP_HIST2_PARAM_RSVD(v) \ ++ (((v) << 16) & BM_PXP_HIST2_PARAM_RSVD) ++#define BP_PXP_HIST2_PARAM_RSVD1 13 ++#define BM_PXP_HIST2_PARAM_RSVD1 0x0000E000 ++#define BF_PXP_HIST2_PARAM_RSVD1(v) \ ++ (((v) << 13) & BM_PXP_HIST2_PARAM_RSVD1) ++#define BP_PXP_HIST2_PARAM_VALUE1 8 ++#define BM_PXP_HIST2_PARAM_VALUE1 0x00001F00 ++#define BF_PXP_HIST2_PARAM_VALUE1(v) \ ++ (((v) << 8) & BM_PXP_HIST2_PARAM_VALUE1) ++#define BP_PXP_HIST2_PARAM_RSVD0 5 ++#define BM_PXP_HIST2_PARAM_RSVD0 0x000000E0 ++#define BF_PXP_HIST2_PARAM_RSVD0(v) \ ++ (((v) << 5) & BM_PXP_HIST2_PARAM_RSVD0) ++#define BP_PXP_HIST2_PARAM_VALUE0 0 ++#define BM_PXP_HIST2_PARAM_VALUE0 0x0000001F ++#define BF_PXP_HIST2_PARAM_VALUE0(v) \ ++ (((v) << 0) & BM_PXP_HIST2_PARAM_VALUE0) ++ ++#define HW_PXP_HIST4_PARAM (0x000002b0) ++ ++#define BP_PXP_HIST4_PARAM_RSVD3 29 ++#define BM_PXP_HIST4_PARAM_RSVD3 0xE0000000 ++#define BF_PXP_HIST4_PARAM_RSVD3(v) \ ++ (((v) << 29) & BM_PXP_HIST4_PARAM_RSVD3) ++#define BP_PXP_HIST4_PARAM_VALUE3 24 ++#define BM_PXP_HIST4_PARAM_VALUE3 0x1F000000 ++#define BF_PXP_HIST4_PARAM_VALUE3(v) \ ++ (((v) << 24) & BM_PXP_HIST4_PARAM_VALUE3) ++#define BP_PXP_HIST4_PARAM_RSVD2 21 ++#define BM_PXP_HIST4_PARAM_RSVD2 0x00E00000 ++#define BF_PXP_HIST4_PARAM_RSVD2(v) \ ++ (((v) << 21) & BM_PXP_HIST4_PARAM_RSVD2) ++#define BP_PXP_HIST4_PARAM_VALUE2 16 ++#define BM_PXP_HIST4_PARAM_VALUE2 0x001F0000 ++#define BF_PXP_HIST4_PARAM_VALUE2(v) \ ++ (((v) << 16) & BM_PXP_HIST4_PARAM_VALUE2) ++#define BP_PXP_HIST4_PARAM_RSVD1 13 ++#define BM_PXP_HIST4_PARAM_RSVD1 0x0000E000 ++#define BF_PXP_HIST4_PARAM_RSVD1(v) \ ++ (((v) << 13) & BM_PXP_HIST4_PARAM_RSVD1) ++#define BP_PXP_HIST4_PARAM_VALUE1 8 ++#define BM_PXP_HIST4_PARAM_VALUE1 0x00001F00 ++#define BF_PXP_HIST4_PARAM_VALUE1(v) \ ++ (((v) << 8) & BM_PXP_HIST4_PARAM_VALUE1) ++#define BP_PXP_HIST4_PARAM_RSVD0 5 ++#define BM_PXP_HIST4_PARAM_RSVD0 0x000000E0 ++#define BF_PXP_HIST4_PARAM_RSVD0(v) \ ++ (((v) << 5) & BM_PXP_HIST4_PARAM_RSVD0) ++#define BP_PXP_HIST4_PARAM_VALUE0 0 ++#define BM_PXP_HIST4_PARAM_VALUE0 0x0000001F ++#define BF_PXP_HIST4_PARAM_VALUE0(v) \ ++ (((v) << 0) & BM_PXP_HIST4_PARAM_VALUE0) ++ ++#define HW_PXP_HIST8_PARAM0 (0x000002c0) ++ ++#define BP_PXP_HIST8_PARAM0_RSVD3 29 ++#define BM_PXP_HIST8_PARAM0_RSVD3 0xE0000000 ++#define BF_PXP_HIST8_PARAM0_RSVD3(v) \ ++ (((v) << 29) & BM_PXP_HIST8_PARAM0_RSVD3) ++#define BP_PXP_HIST8_PARAM0_VALUE3 24 ++#define BM_PXP_HIST8_PARAM0_VALUE3 0x1F000000 ++#define BF_PXP_HIST8_PARAM0_VALUE3(v) \ ++ (((v) << 24) & BM_PXP_HIST8_PARAM0_VALUE3) ++#define BP_PXP_HIST8_PARAM0_RSVD2 21 ++#define BM_PXP_HIST8_PARAM0_RSVD2 0x00E00000 ++#define BF_PXP_HIST8_PARAM0_RSVD2(v) \ ++ (((v) << 21) & BM_PXP_HIST8_PARAM0_RSVD2) ++#define BP_PXP_HIST8_PARAM0_VALUE2 16 ++#define BM_PXP_HIST8_PARAM0_VALUE2 0x001F0000 ++#define BF_PXP_HIST8_PARAM0_VALUE2(v) \ ++ (((v) << 16) & BM_PXP_HIST8_PARAM0_VALUE2) ++#define BP_PXP_HIST8_PARAM0_RSVD1 13 ++#define BM_PXP_HIST8_PARAM0_RSVD1 0x0000E000 ++#define BF_PXP_HIST8_PARAM0_RSVD1(v) \ ++ (((v) << 13) & BM_PXP_HIST8_PARAM0_RSVD1) ++#define BP_PXP_HIST8_PARAM0_VALUE1 8 ++#define BM_PXP_HIST8_PARAM0_VALUE1 0x00001F00 ++#define BF_PXP_HIST8_PARAM0_VALUE1(v) \ ++ (((v) << 8) & BM_PXP_HIST8_PARAM0_VALUE1) ++#define BP_PXP_HIST8_PARAM0_RSVD0 5 ++#define BM_PXP_HIST8_PARAM0_RSVD0 0x000000E0 ++#define BF_PXP_HIST8_PARAM0_RSVD0(v) \ ++ (((v) << 5) & BM_PXP_HIST8_PARAM0_RSVD0) ++#define BP_PXP_HIST8_PARAM0_VALUE0 0 ++#define BM_PXP_HIST8_PARAM0_VALUE0 0x0000001F ++#define BF_PXP_HIST8_PARAM0_VALUE0(v) \ ++ (((v) << 0) & BM_PXP_HIST8_PARAM0_VALUE0) ++ ++#define HW_PXP_HIST8_PARAM1 (0x000002d0) ++ ++#define BP_PXP_HIST8_PARAM1_RSVD7 29 ++#define BM_PXP_HIST8_PARAM1_RSVD7 0xE0000000 ++#define BF_PXP_HIST8_PARAM1_RSVD7(v) \ ++ (((v) << 29) & BM_PXP_HIST8_PARAM1_RSVD7) ++#define BP_PXP_HIST8_PARAM1_VALUE7 24 ++#define BM_PXP_HIST8_PARAM1_VALUE7 0x1F000000 ++#define BF_PXP_HIST8_PARAM1_VALUE7(v) \ ++ (((v) << 24) & BM_PXP_HIST8_PARAM1_VALUE7) ++#define BP_PXP_HIST8_PARAM1_RSVD6 21 ++#define BM_PXP_HIST8_PARAM1_RSVD6 0x00E00000 ++#define BF_PXP_HIST8_PARAM1_RSVD6(v) \ ++ (((v) << 21) & BM_PXP_HIST8_PARAM1_RSVD6) ++#define BP_PXP_HIST8_PARAM1_VALUE6 16 ++#define BM_PXP_HIST8_PARAM1_VALUE6 0x001F0000 ++#define BF_PXP_HIST8_PARAM1_VALUE6(v) \ ++ (((v) << 16) & BM_PXP_HIST8_PARAM1_VALUE6) ++#define BP_PXP_HIST8_PARAM1_RSVD5 13 ++#define BM_PXP_HIST8_PARAM1_RSVD5 0x0000E000 ++#define BF_PXP_HIST8_PARAM1_RSVD5(v) \ ++ (((v) << 13) & BM_PXP_HIST8_PARAM1_RSVD5) ++#define BP_PXP_HIST8_PARAM1_VALUE5 8 ++#define BM_PXP_HIST8_PARAM1_VALUE5 0x00001F00 ++#define BF_PXP_HIST8_PARAM1_VALUE5(v) \ ++ (((v) << 8) & BM_PXP_HIST8_PARAM1_VALUE5) ++#define BP_PXP_HIST8_PARAM1_RSVD4 5 ++#define BM_PXP_HIST8_PARAM1_RSVD4 0x000000E0 ++#define BF_PXP_HIST8_PARAM1_RSVD4(v) \ ++ (((v) << 5) & BM_PXP_HIST8_PARAM1_RSVD4) ++#define BP_PXP_HIST8_PARAM1_VALUE4 0 ++#define BM_PXP_HIST8_PARAM1_VALUE4 0x0000001F ++#define BF_PXP_HIST8_PARAM1_VALUE4(v) \ ++ (((v) << 0) & BM_PXP_HIST8_PARAM1_VALUE4) ++ ++#define HW_PXP_HIST16_PARAM0 (0x000002e0) ++ ++#define BP_PXP_HIST16_PARAM0_RSVD3 29 ++#define BM_PXP_HIST16_PARAM0_RSVD3 0xE0000000 ++#define BF_PXP_HIST16_PARAM0_RSVD3(v) \ ++ (((v) << 29) & BM_PXP_HIST16_PARAM0_RSVD3) ++#define BP_PXP_HIST16_PARAM0_VALUE3 24 ++#define BM_PXP_HIST16_PARAM0_VALUE3 0x1F000000 ++#define BF_PXP_HIST16_PARAM0_VALUE3(v) \ ++ (((v) << 24) & BM_PXP_HIST16_PARAM0_VALUE3) ++#define BP_PXP_HIST16_PARAM0_RSVD2 21 ++#define BM_PXP_HIST16_PARAM0_RSVD2 0x00E00000 ++#define BF_PXP_HIST16_PARAM0_RSVD2(v) \ ++ (((v) << 21) & BM_PXP_HIST16_PARAM0_RSVD2) ++#define BP_PXP_HIST16_PARAM0_VALUE2 16 ++#define BM_PXP_HIST16_PARAM0_VALUE2 0x001F0000 ++#define BF_PXP_HIST16_PARAM0_VALUE2(v) \ ++ (((v) << 16) & BM_PXP_HIST16_PARAM0_VALUE2) ++#define BP_PXP_HIST16_PARAM0_RSVD1 13 ++#define BM_PXP_HIST16_PARAM0_RSVD1 0x0000E000 ++#define BF_PXP_HIST16_PARAM0_RSVD1(v) \ ++ (((v) << 13) & BM_PXP_HIST16_PARAM0_RSVD1) ++#define BP_PXP_HIST16_PARAM0_VALUE1 8 ++#define BM_PXP_HIST16_PARAM0_VALUE1 0x00001F00 ++#define BF_PXP_HIST16_PARAM0_VALUE1(v) \ ++ (((v) << 8) & BM_PXP_HIST16_PARAM0_VALUE1) ++#define BP_PXP_HIST16_PARAM0_RSVD0 5 ++#define BM_PXP_HIST16_PARAM0_RSVD0 0x000000E0 ++#define BF_PXP_HIST16_PARAM0_RSVD0(v) \ ++ (((v) << 5) & BM_PXP_HIST16_PARAM0_RSVD0) ++#define BP_PXP_HIST16_PARAM0_VALUE0 0 ++#define BM_PXP_HIST16_PARAM0_VALUE0 0x0000001F ++#define BF_PXP_HIST16_PARAM0_VALUE0(v) \ ++ (((v) << 0) & BM_PXP_HIST16_PARAM0_VALUE0) ++ ++#define HW_PXP_HIST16_PARAM1 (0x000002f0) ++ ++#define BP_PXP_HIST16_PARAM1_RSVD7 29 ++#define BM_PXP_HIST16_PARAM1_RSVD7 0xE0000000 ++#define BF_PXP_HIST16_PARAM1_RSVD7(v) \ ++ (((v) << 29) & BM_PXP_HIST16_PARAM1_RSVD7) ++#define BP_PXP_HIST16_PARAM1_VALUE7 24 ++#define BM_PXP_HIST16_PARAM1_VALUE7 0x1F000000 ++#define BF_PXP_HIST16_PARAM1_VALUE7(v) \ ++ (((v) << 24) & BM_PXP_HIST16_PARAM1_VALUE7) ++#define BP_PXP_HIST16_PARAM1_RSVD6 21 ++#define BM_PXP_HIST16_PARAM1_RSVD6 0x00E00000 ++#define BF_PXP_HIST16_PARAM1_RSVD6(v) \ ++ (((v) << 21) & BM_PXP_HIST16_PARAM1_RSVD6) ++#define BP_PXP_HIST16_PARAM1_VALUE6 16 ++#define BM_PXP_HIST16_PARAM1_VALUE6 0x001F0000 ++#define BF_PXP_HIST16_PARAM1_VALUE6(v) \ ++ (((v) << 16) & BM_PXP_HIST16_PARAM1_VALUE6) ++#define BP_PXP_HIST16_PARAM1_RSVD5 13 ++#define BM_PXP_HIST16_PARAM1_RSVD5 0x0000E000 ++#define BF_PXP_HIST16_PARAM1_RSVD5(v) \ ++ (((v) << 13) & BM_PXP_HIST16_PARAM1_RSVD5) ++#define BP_PXP_HIST16_PARAM1_VALUE5 8 ++#define BM_PXP_HIST16_PARAM1_VALUE5 0x00001F00 ++#define BF_PXP_HIST16_PARAM1_VALUE5(v) \ ++ (((v) << 8) & BM_PXP_HIST16_PARAM1_VALUE5) ++#define BP_PXP_HIST16_PARAM1_RSVD4 5 ++#define BM_PXP_HIST16_PARAM1_RSVD4 0x000000E0 ++#define BF_PXP_HIST16_PARAM1_RSVD4(v) \ ++ (((v) << 5) & BM_PXP_HIST16_PARAM1_RSVD4) ++#define BP_PXP_HIST16_PARAM1_VALUE4 0 ++#define BM_PXP_HIST16_PARAM1_VALUE4 0x0000001F ++#define BF_PXP_HIST16_PARAM1_VALUE4(v) \ ++ (((v) << 0) & BM_PXP_HIST16_PARAM1_VALUE4) ++ ++#define HW_PXP_HIST16_PARAM2 (0x00000300) ++ ++#define BP_PXP_HIST16_PARAM2_RSVD11 29 ++#define BM_PXP_HIST16_PARAM2_RSVD11 0xE0000000 ++#define BF_PXP_HIST16_PARAM2_RSVD11(v) \ ++ (((v) << 29) & BM_PXP_HIST16_PARAM2_RSVD11) ++#define BP_PXP_HIST16_PARAM2_VALUE11 24 ++#define BM_PXP_HIST16_PARAM2_VALUE11 0x1F000000 ++#define BF_PXP_HIST16_PARAM2_VALUE11(v) \ ++ (((v) << 24) & BM_PXP_HIST16_PARAM2_VALUE11) ++#define BP_PXP_HIST16_PARAM2_RSVD10 21 ++#define BM_PXP_HIST16_PARAM2_RSVD10 0x00E00000 ++#define BF_PXP_HIST16_PARAM2_RSVD10(v) \ ++ (((v) << 21) & BM_PXP_HIST16_PARAM2_RSVD10) ++#define BP_PXP_HIST16_PARAM2_VALUE10 16 ++#define BM_PXP_HIST16_PARAM2_VALUE10 0x001F0000 ++#define BF_PXP_HIST16_PARAM2_VALUE10(v) \ ++ (((v) << 16) & BM_PXP_HIST16_PARAM2_VALUE10) ++#define BP_PXP_HIST16_PARAM2_RSVD9 13 ++#define BM_PXP_HIST16_PARAM2_RSVD9 0x0000E000 ++#define BF_PXP_HIST16_PARAM2_RSVD9(v) \ ++ (((v) << 13) & BM_PXP_HIST16_PARAM2_RSVD9) ++#define BP_PXP_HIST16_PARAM2_VALUE9 8 ++#define BM_PXP_HIST16_PARAM2_VALUE9 0x00001F00 ++#define BF_PXP_HIST16_PARAM2_VALUE9(v) \ ++ (((v) << 8) & BM_PXP_HIST16_PARAM2_VALUE9) ++#define BP_PXP_HIST16_PARAM2_RSVD8 5 ++#define BM_PXP_HIST16_PARAM2_RSVD8 0x000000E0 ++#define BF_PXP_HIST16_PARAM2_RSVD8(v) \ ++ (((v) << 5) & BM_PXP_HIST16_PARAM2_RSVD8) ++#define BP_PXP_HIST16_PARAM2_VALUE8 0 ++#define BM_PXP_HIST16_PARAM2_VALUE8 0x0000001F ++#define BF_PXP_HIST16_PARAM2_VALUE8(v) \ ++ (((v) << 0) & BM_PXP_HIST16_PARAM2_VALUE8) ++ ++#define HW_PXP_HIST16_PARAM3 (0x00000310) ++ ++#define BP_PXP_HIST16_PARAM3_RSVD15 29 ++#define BM_PXP_HIST16_PARAM3_RSVD15 0xE0000000 ++#define BF_PXP_HIST16_PARAM3_RSVD15(v) \ ++ (((v) << 29) & BM_PXP_HIST16_PARAM3_RSVD15) ++#define BP_PXP_HIST16_PARAM3_VALUE15 24 ++#define BM_PXP_HIST16_PARAM3_VALUE15 0x1F000000 ++#define BF_PXP_HIST16_PARAM3_VALUE15(v) \ ++ (((v) << 24) & BM_PXP_HIST16_PARAM3_VALUE15) ++#define BP_PXP_HIST16_PARAM3_RSVD14 21 ++#define BM_PXP_HIST16_PARAM3_RSVD14 0x00E00000 ++#define BF_PXP_HIST16_PARAM3_RSVD14(v) \ ++ (((v) << 21) & BM_PXP_HIST16_PARAM3_RSVD14) ++#define BP_PXP_HIST16_PARAM3_VALUE14 16 ++#define BM_PXP_HIST16_PARAM3_VALUE14 0x001F0000 ++#define BF_PXP_HIST16_PARAM3_VALUE14(v) \ ++ (((v) << 16) & BM_PXP_HIST16_PARAM3_VALUE14) ++#define BP_PXP_HIST16_PARAM3_RSVD13 13 ++#define BM_PXP_HIST16_PARAM3_RSVD13 0x0000E000 ++#define BF_PXP_HIST16_PARAM3_RSVD13(v) \ ++ (((v) << 13) & BM_PXP_HIST16_PARAM3_RSVD13) ++#define BP_PXP_HIST16_PARAM3_VALUE13 8 ++#define BM_PXP_HIST16_PARAM3_VALUE13 0x00001F00 ++#define BF_PXP_HIST16_PARAM3_VALUE13(v) \ ++ (((v) << 8) & BM_PXP_HIST16_PARAM3_VALUE13) ++#define BP_PXP_HIST16_PARAM3_RSVD12 5 ++#define BM_PXP_HIST16_PARAM3_RSVD12 0x000000E0 ++#define BF_PXP_HIST16_PARAM3_RSVD12(v) \ ++ (((v) << 5) & BM_PXP_HIST16_PARAM3_RSVD12) ++#define BP_PXP_HIST16_PARAM3_VALUE12 0 ++#define BM_PXP_HIST16_PARAM3_VALUE12 0x0000001F ++#define BF_PXP_HIST16_PARAM3_VALUE12(v) \ ++ (((v) << 0) & BM_PXP_HIST16_PARAM3_VALUE12) ++ ++#define HW_PXP_POWER (0x00000320) ++ ++#define BP_PXP_POWER_CTRL 12 ++#define BM_PXP_POWER_CTRL 0xFFFFF000 ++#define BF_PXP_POWER_CTRL(v) \ ++ (((v) << 12) & BM_PXP_POWER_CTRL) ++#define BP_PXP_POWER_ROT_MEM_LP_STATE 9 ++#define BM_PXP_POWER_ROT_MEM_LP_STATE 0x00000E00 ++#define BF_PXP_POWER_ROT_MEM_LP_STATE(v) \ ++ (((v) << 9) & BM_PXP_POWER_ROT_MEM_LP_STATE) ++#define BV_PXP_POWER_ROT_MEM_LP_STATE__NONE 0x0 ++#define BV_PXP_POWER_ROT_MEM_LP_STATE__LS 0x1 ++#define BV_PXP_POWER_ROT_MEM_LP_STATE__DS 0x2 ++#define BV_PXP_POWER_ROT_MEM_LP_STATE__SD 0x4 ++#define BP_PXP_POWER_LUT_LP_STATE_WAY1_BANKN 6 ++#define BM_PXP_POWER_LUT_LP_STATE_WAY1_BANKN 0x000001C0 ++#define BF_PXP_POWER_LUT_LP_STATE_WAY1_BANKN(v) \ ++ (((v) << 6) & BM_PXP_POWER_LUT_LP_STATE_WAY1_BANKN) ++#define BV_PXP_POWER_LUT_LP_STATE_WAY1_BANKN__NONE 0x0 ++#define BV_PXP_POWER_LUT_LP_STATE_WAY1_BANKN__LS 0x1 ++#define BV_PXP_POWER_LUT_LP_STATE_WAY1_BANKN__DS 0x2 ++#define BV_PXP_POWER_LUT_LP_STATE_WAY1_BANKN__SD 0x4 ++#define BP_PXP_POWER_LUT_LP_STATE_WAY0_BANKN 3 ++#define BM_PXP_POWER_LUT_LP_STATE_WAY0_BANKN 0x00000038 ++#define BF_PXP_POWER_LUT_LP_STATE_WAY0_BANKN(v) \ ++ (((v) << 3) & BM_PXP_POWER_LUT_LP_STATE_WAY0_BANKN) ++#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANKN__NONE 0x0 ++#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANKN__LS 0x1 ++#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANKN__DS 0x2 ++#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANKN__SD 0x4 ++#define BP_PXP_POWER_LUT_LP_STATE_WAY0_BANK0 0 ++#define BM_PXP_POWER_LUT_LP_STATE_WAY0_BANK0 0x00000007 ++#define BF_PXP_POWER_LUT_LP_STATE_WAY0_BANK0(v) \ ++ (((v) << 0) & BM_PXP_POWER_LUT_LP_STATE_WAY0_BANK0) ++#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANK0__NONE 0x0 ++#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANK0__LS 0x1 ++#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANK0__DS 0x2 ++#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANK0__SD 0x4 ++ ++#define HW_PXP_NEXT (0x00000400) ++ ++#define BP_PXP_NEXT_POINTER 2 ++#define BM_PXP_NEXT_POINTER 0xFFFFFFFC ++#define BF_PXP_NEXT_POINTER(v) \ ++ (((v) << 2) & BM_PXP_NEXT_POINTER) ++#define BM_PXP_NEXT_RSVD 0x00000002 ++#define BM_PXP_NEXT_ENABLED 0x00000001 ++ ++#define HW_PXP_DEBUGCTRL (0x00000410) ++ ++#define BP_PXP_DEBUGCTRL_RSVD 12 ++#define BM_PXP_DEBUGCTRL_RSVD 0xFFFFF000 ++#define BF_PXP_DEBUGCTRL_RSVD(v) \ ++ (((v) << 12) & BM_PXP_DEBUGCTRL_RSVD) ++#define BP_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT 8 ++#define BM_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT 0x00000F00 ++#define BF_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT(v) \ ++ (((v) << 8) & BM_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT) ++#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__NONE 0x0 ++#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__MISS_CNT 0x1 ++#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__HIT_CNT 0x2 ++#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__LAT_CNT 0x4 ++#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__MAX_LAT 0x8 ++#define BP_PXP_DEBUGCTRL_SELECT 0 ++#define BM_PXP_DEBUGCTRL_SELECT 0x000000FF ++#define BF_PXP_DEBUGCTRL_SELECT(v) \ ++ (((v) << 0) & BM_PXP_DEBUGCTRL_SELECT) ++#define BV_PXP_DEBUGCTRL_SELECT__NONE 0x0 ++#define BV_PXP_DEBUGCTRL_SELECT__CTRL 0x1 ++#define BV_PXP_DEBUGCTRL_SELECT__PSBUF 0x2 ++#define BV_PXP_DEBUGCTRL_SELECT__PSBAX 0x3 ++#define BV_PXP_DEBUGCTRL_SELECT__PSBAY 0x4 ++#define BV_PXP_DEBUGCTRL_SELECT__ASBUF 0x5 ++#define BV_PXP_DEBUGCTRL_SELECT__ROTATION 0x6 ++#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF0 0x7 ++#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF1 0x8 ++#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF2 0x9 ++#define BV_PXP_DEBUGCTRL_SELECT__LUT_STAT 0x10 ++#define BV_PXP_DEBUGCTRL_SELECT__LUT_MISS 0x11 ++#define BV_PXP_DEBUGCTRL_SELECT__LUT_HIT 0x12 ++#define BV_PXP_DEBUGCTRL_SELECT__LUT_LAT 0x13 ++#define BV_PXP_DEBUGCTRL_SELECT__LUT_MAX_LAT 0x14 ++ ++#define HW_PXP_DEBUG (0x00000420) ++ ++#define BP_PXP_DEBUG_DATA 0 ++#define BM_PXP_DEBUG_DATA 0xFFFFFFFF ++#define BF_PXP_DEBUG_DATA(v) (v) ++ ++#define HW_PXP_VERSION (0x00000430) ++ ++#define BP_PXP_VERSION_MAJOR 24 ++#define BM_PXP_VERSION_MAJOR 0xFF000000 ++#define BF_PXP_VERSION_MAJOR(v) \ ++ (((v) << 24) & BM_PXP_VERSION_MAJOR) ++#define BP_PXP_VERSION_MINOR 16 ++#define BM_PXP_VERSION_MINOR 0x00FF0000 ++#define BF_PXP_VERSION_MINOR(v) \ ++ (((v) << 16) & BM_PXP_VERSION_MINOR) ++#define BP_PXP_VERSION_STEP 0 ++#define BM_PXP_VERSION_STEP 0x0000FFFF ++#define BF_PXP_VERSION_STEP(v) \ ++ (((v) << 0) & BM_PXP_VERSION_STEP) ++#endif /* __ARCH_ARM___PXP_H */ +diff -Nur linux-3.10.30/drivers/extcon/extcon-adc-jack.c linux-3.10.30-cubox-i/drivers/extcon/extcon-adc-jack.c +--- linux-3.10.30/drivers/extcon/extcon-adc-jack.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/extcon/extcon-adc-jack.c 2014-03-08 20:33:31.000000000 +0100 +@@ -87,7 +87,8 @@ + { + struct adc_jack_data *data = _data; + +- schedule_delayed_work(&data->handler, data->handling_delay); ++ queue_delayed_work(system_power_efficient_wq, ++ &data->handler, data->handling_delay); + return IRQ_HANDLED; + } + +diff -Nur linux-3.10.30/drivers/extcon/extcon-gpio.c linux-3.10.30-cubox-i/drivers/extcon/extcon-gpio.c +--- linux-3.10.30/drivers/extcon/extcon-gpio.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/extcon/extcon-gpio.c 2014-03-08 20:33:31.000000000 +0100 +@@ -56,7 +56,7 @@ + { + struct gpio_extcon_data *extcon_data = dev_id; + +- schedule_delayed_work(&extcon_data->work, ++ queue_delayed_work(system_power_efficient_wq, &extcon_data->work, + extcon_data->debounce_jiffies); + return IRQ_HANDLED; + } +diff -Nur linux-3.10.30/drivers/gator/Kconfig linux-3.10.30-cubox-i/drivers/gator/Kconfig +--- linux-3.10.30/drivers/gator/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/Kconfig 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,33 @@ ++config GATOR ++ tristate "Gator module for ARM's Streamline Performance Analyzer" ++ default m if (ARM || ARM64) ++ depends on PROFILING ++ depends on HIGH_RES_TIMERS ++ depends on LOCAL_TIMERS || !(ARM && SMP) ++ select TRACING ++ ++config GATOR_WITH_MALI_SUPPORT ++ bool ++ ++choice ++ prompt "Enable Mali GPU support in Gator" ++ depends on GATOR ++ optional ++ ++config GATOR_MALI_400MP ++ bool "Mali-400MP" ++ select GATOR_WITH_MALI_SUPPORT ++ ++config GATOR_MALI_T6XX ++ bool "Mali-T604 or Mali-T658" ++ select GATOR_WITH_MALI_SUPPORT ++ ++endchoice ++ ++config GATOR_MALI_PATH ++ string "Path to Mali driver" ++ depends on GATOR_WITH_MALI_SUPPORT ++ default "drivers/gpu/arm/mali400mp" ++ help ++ The gator code adds this to its include path so it can get the Mali ++ trace headers with: #include "linux/mali_linux_trace.h" +diff -Nur linux-3.10.30/drivers/gator/LICENSE linux-3.10.30-cubox-i/drivers/gator/LICENSE +--- linux-3.10.30/drivers/gator/LICENSE 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/LICENSE 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,339 @@ ++ GNU GENERAL PUBLIC LICENSE ++ Version 2, June 1991 ++ ++ Copyright (C) 1989, 1991 Free Software Foundation, Inc., ++ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The licenses for most software are designed to take away your ++freedom to share and change it. By contrast, the GNU General Public ++License is intended to guarantee your freedom to share and change free ++software--to make sure the software is free for all its users. This ++General Public License applies to most of the Free Software ++Foundation's software and to any other program whose authors commit to ++using it. (Some other Free Software Foundation software is covered by ++the GNU Lesser General Public License instead.) You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++this service if you wish), that you receive source code or can get it ++if you want it, that you can change the software or use pieces of it ++in new free programs; and that you know you can do these things. ++ ++ To protect your rights, we need to make restrictions that forbid ++anyone to deny you these rights or to ask you to surrender the rights. ++These restrictions translate to certain responsibilities for you if you ++distribute copies of the software, or if you modify it. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must give the recipients all the rights that ++you have. You must make sure that they, too, receive or can get the ++source code. And you must show them these terms so they know their ++rights. ++ ++ We protect your rights with two steps: (1) copyright the software, and ++(2) offer you this license which gives you legal permission to copy, ++distribute and/or modify the software. ++ ++ Also, for each author's protection and ours, we want to make certain ++that everyone understands that there is no warranty for this free ++software. If the software is modified by someone else and passed on, we ++want its recipients to know that what they have is not the original, so ++that any problems introduced by others will not reflect on the original ++authors' reputations. ++ ++ Finally, any free program is threatened constantly by software ++patents. We wish to avoid the danger that redistributors of a free ++program will individually obtain patent licenses, in effect making the ++program proprietary. To prevent this, we have made it clear that any ++patent must be licensed for everyone's free use or not licensed at all. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ GNU GENERAL PUBLIC LICENSE ++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++ 0. This License applies to any program or other work which contains ++a notice placed by the copyright holder saying it may be distributed ++under the terms of this General Public License. The "Program", below, ++refers to any such program or work, and a "work based on the Program" ++means either the Program or any derivative work under copyright law: ++that is to say, a work containing the Program or a portion of it, ++either verbatim or with modifications and/or translated into another ++language. (Hereinafter, translation is included without limitation in ++the term "modification".) Each licensee is addressed as "you". ++ ++Activities other than copying, distribution and modification are not ++covered by this License; they are outside its scope. The act of ++running the Program is not restricted, and the output from the Program ++is covered only if its contents constitute a work based on the ++Program (independent of having been made by running the Program). ++Whether that is true depends on what the Program does. ++ ++ 1. You may copy and distribute verbatim copies of the Program's ++source code as you receive it, in any medium, provided that you ++conspicuously and appropriately publish on each copy an appropriate ++copyright notice and disclaimer of warranty; keep intact all the ++notices that refer to this License and to the absence of any warranty; ++and give any other recipients of the Program a copy of this License ++along with the Program. ++ ++You may charge a fee for the physical act of transferring a copy, and ++you may at your option offer warranty protection in exchange for a fee. ++ ++ 2. You may modify your copy or copies of the Program or any portion ++of it, thus forming a work based on the Program, and copy and ++distribute such modifications or work under the terms of Section 1 ++above, provided that you also meet all of these conditions: ++ ++ a) You must cause the modified files to carry prominent notices ++ stating that you changed the files and the date of any change. ++ ++ b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any ++ part thereof, to be licensed as a whole at no charge to all third ++ parties under the terms of this License. ++ ++ c) If the modified program normally reads commands interactively ++ when run, you must cause it, when started running for such ++ interactive use in the most ordinary way, to print or display an ++ announcement including an appropriate copyright notice and a ++ notice that there is no warranty (or else, saying that you provide ++ a warranty) and that users may redistribute the program under ++ these conditions, and telling the user how to view a copy of this ++ License. (Exception: if the Program itself is interactive but ++ does not normally print such an announcement, your work based on ++ the Program is not required to print an announcement.) ++ ++These requirements apply to the modified work as a whole. If ++identifiable sections of that work are not derived from the Program, ++and can be reasonably considered independent and separate works in ++themselves, then this License, and its terms, do not apply to those ++sections when you distribute them as separate works. But when you ++distribute the same sections as part of a whole which is a work based ++on the Program, the distribution of the whole must be on the terms of ++this License, whose permissions for other licensees extend to the ++entire whole, and thus to each and every part regardless of who wrote it. ++ ++Thus, it is not the intent of this section to claim rights or contest ++your rights to work written entirely by you; rather, the intent is to ++exercise the right to control the distribution of derivative or ++collective works based on the Program. ++ ++In addition, mere aggregation of another work not based on the Program ++with the Program (or with a work based on the Program) on a volume of ++a storage or distribution medium does not bring the other work under ++the scope of this License. ++ ++ 3. You may copy and distribute the Program (or a work based on it, ++under Section 2) in object code or executable form under the terms of ++Sections 1 and 2 above provided that you also do one of the following: ++ ++ a) Accompany it with the complete corresponding machine-readable ++ source code, which must be distributed under the terms of Sections ++ 1 and 2 above on a medium customarily used for software interchange; or, ++ ++ b) Accompany it with a written offer, valid for at least three ++ years, to give any third party, for a charge no more than your ++ cost of physically performing source distribution, a complete ++ machine-readable copy of the corresponding source code, to be ++ distributed under the terms of Sections 1 and 2 above on a medium ++ customarily used for software interchange; or, ++ ++ c) Accompany it with the information you received as to the offer ++ to distribute corresponding source code. (This alternative is ++ allowed only for noncommercial distribution and only if you ++ received the program in object code or executable form with such ++ an offer, in accord with Subsection b above.) ++ ++The source code for a work means the preferred form of the work for ++making modifications to it. For an executable work, complete source ++code means all the source code for all modules it contains, plus any ++associated interface definition files, plus the scripts used to ++control compilation and installation of the executable. However, as a ++special exception, the source code distributed need not include ++anything that is normally distributed (in either source or binary ++form) with the major components (compiler, kernel, and so on) of the ++operating system on which the executable runs, unless that component ++itself accompanies the executable. ++ ++If distribution of executable or object code is made by offering ++access to copy from a designated place, then offering equivalent ++access to copy the source code from the same place counts as ++distribution of the source code, even though third parties are not ++compelled to copy the source along with the object code. ++ ++ 4. You may not copy, modify, sublicense, or distribute the Program ++except as expressly provided under this License. Any attempt ++otherwise to copy, modify, sublicense or distribute the Program is ++void, and will automatically terminate your rights under this License. ++However, parties who have received copies, or rights, from you under ++this License will not have their licenses terminated so long as such ++parties remain in full compliance. ++ ++ 5. You are not required to accept this License, since you have not ++signed it. However, nothing else grants you permission to modify or ++distribute the Program or its derivative works. These actions are ++prohibited by law if you do not accept this License. Therefore, by ++modifying or distributing the Program (or any work based on the ++Program), you indicate your acceptance of this License to do so, and ++all its terms and conditions for copying, distributing or modifying ++the Program or works based on it. ++ ++ 6. Each time you redistribute the Program (or any work based on the ++Program), the recipient automatically receives a license from the ++original licensor to copy, distribute or modify the Program subject to ++these terms and conditions. You may not impose any further ++restrictions on the recipients' exercise of the rights granted herein. ++You are not responsible for enforcing compliance by third parties to ++this License. ++ ++ 7. If, as a consequence of a court judgment or allegation of patent ++infringement or for any other reason (not limited to patent issues), ++conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot ++distribute so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you ++may not distribute the Program at all. For example, if a patent ++license would not permit royalty-free redistribution of the Program by ++all those who receive copies directly or indirectly through you, then ++the only way you could satisfy both it and this License would be to ++refrain entirely from distribution of the Program. ++ ++If any portion of this section is held invalid or unenforceable under ++any particular circumstance, the balance of the section is intended to ++apply and the section as a whole is intended to apply in other ++circumstances. ++ ++It is not the purpose of this section to induce you to infringe any ++patents or other property right claims or to contest validity of any ++such claims; this section has the sole purpose of protecting the ++integrity of the free software distribution system, which is ++implemented by public license practices. Many people have made ++generous contributions to the wide range of software distributed ++through that system in reliance on consistent application of that ++system; it is up to the author/donor to decide if he or she is willing ++to distribute software through any other system and a licensee cannot ++impose that choice. ++ ++This section is intended to make thoroughly clear what is believed to ++be a consequence of the rest of this License. ++ ++ 8. If the distribution and/or use of the Program is restricted in ++certain countries either by patents or by copyrighted interfaces, the ++original copyright holder who places the Program under this License ++may add an explicit geographical distribution limitation excluding ++those countries, so that distribution is permitted only in or among ++countries not thus excluded. In such case, this License incorporates ++the limitation as if written in the body of this License. ++ ++ 9. The Free Software Foundation may publish revised and/or new versions ++of the General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++Each version is given a distinguishing version number. If the Program ++specifies a version number of this License which applies to it and "any ++later version", you have the option of following the terms and conditions ++either of that version or of any later version published by the Free ++Software Foundation. If the Program does not specify a version number of ++this License, you may choose any version ever published by the Free Software ++Foundation. ++ ++ 10. If you wish to incorporate parts of the Program into other free ++programs whose distribution conditions are different, write to the author ++to ask for permission. For software which is copyrighted by the Free ++Software Foundation, write to the Free Software Foundation; we sometimes ++make exceptions for this. Our decision will be guided by the two goals ++of preserving the free status of all derivatives of our free software and ++of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++REPAIR OR CORRECTION. ++ ++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++POSSIBILITY OF SUCH DAMAGES. ++ ++ END OF TERMS AND CONDITIONS ++ ++ How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++convey the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) ++ ++ 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., ++ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this ++when it starts in an interactive mode: ++ ++ Gnomovision version 69, Copyright (C) year name of author ++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may ++be called something other than `show w' and `show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++ `Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++ , 1 April 1989 ++ Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Lesser General ++Public License instead of this License. +diff -Nur linux-3.10.30/drivers/gator/Makefile linux-3.10.30-cubox-i/drivers/gator/Makefile +--- linux-3.10.30/drivers/gator/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/Makefile 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,76 @@ ++ifneq ($(KERNELRELEASE),) ++ ++# Uncomment the following line to enable kernel stack unwinding within gator, or update gator_backtrace.c ++# EXTRA_CFLAGS += -DGATOR_KERNEL_STACK_UNWINDING ++ ++CONFIG_GATOR ?= m ++obj-$(CONFIG_GATOR) := gator.o ++ ++gator-y := gator_main.o \ ++ gator_events_irq.o \ ++ gator_events_sched.o \ ++ gator_events_net.o \ ++ gator_events_block.o \ ++ gator_events_meminfo.o \ ++ gator_events_perf_pmu.o \ ++ gator_events_mmapped.o \ ++ ++# Convert the old GATOR_WITH_MALI_SUPPORT to the new kernel flags ++ifneq ($(GATOR_WITH_MALI_SUPPORT),) ++ CONFIG_GATOR_WITH_MALI_SUPPORT := y ++ ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx) ++ CONFIG_GATOR_MALI_4XXMP := n ++ CONFIG_GATOR_MALI_T6XX := y ++ else ++ CONFIG_GATOR_MALI_4XXMP := y ++ CONFIG_GATOR_MALI_T6XX := n ++ endif ++ EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT) ++ ifneq ($(GATOR_MALI_INTERFACE_STYLE),) ++ EXTRA_CFLAGS += -DGATOR_MALI_INTERFACE_STYLE=$(GATOR_MALI_INTERFACE_STYLE) ++ endif ++endif ++ ++ifeq ($(CONFIG_GATOR_WITH_MALI_SUPPORT),y) ++ ifeq ($(CONFIG_GATOR_MALI_T6XX),y) ++ gator-y += gator_events_mali_t6xx.o \ ++ gator_events_mali_t6xx_hw.o ++ include $(src)/mali_t6xx.mk ++ else ++ gator-y += gator_events_mali_4xx.o ++ endif ++ gator-y += gator_events_mali_common.o ++ ++ ifneq ($(CONFIG_GATOR_MALI_PATH),) ++ ccflags-y += -I$(CONFIG_GATOR_MALI_PATH) ++ endif ++ ccflags-$(CONFIG_GATOR_MALI_4XXMP) += -DMALI_SUPPORT=MALI_4xx ++ ccflags-$(CONFIG_GATOR_MALI_T6XX) += -DMALI_SUPPORT=MALI_T6xx ++endif ++ ++# GATOR_TEST controls whether to include (=1) or exclude (=0) test code. ++GATOR_TEST ?= 0 ++EXTRA_CFLAGS += -DGATOR_TEST=$(GATOR_TEST) ++ ++gator-$(CONFIG_ARM) += gator_events_armv6.o \ ++ gator_events_armv7.o \ ++ gator_events_ccn-504.o \ ++ gator_events_l2c-310.o \ ++ gator_events_scorpion.o ++ ++gator-$(CONFIG_ARM64) += gator_events_ccn-504.o ++ ++else ++ ++all: ++ @echo ++ @echo "usage:" ++ @echo " make -C M=\`pwd\` ARCH=arm CROSS_COMPILE=<...> modules" ++ @echo ++ $(error) ++ ++clean: ++ rm -f *.o .*.cmd modules.order Module.symvers gator.ko gator.mod.c ++ rm -rf .tmp_versions ++ ++endif +diff -Nur linux-3.10.30/drivers/gator/gator.h linux-3.10.30-cubox-i/drivers/gator/gator.h +--- linux-3.10.30/drivers/gator/gator.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator.h 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,142 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 GATOR_H_ ++#define GATOR_H_ ++ ++#include ++#include ++#include ++#include ++ ++#define GATOR_PERF_SUPPORT LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) ++#define GATOR_PERF_PMU_SUPPORT GATOR_PERF_SUPPORT && defined(CONFIG_PERF_EVENTS) && (!(defined(__arm__) || defined(__aarch64__)) || defined(CONFIG_HW_PERF_EVENTS)) ++#define GATOR_NO_PERF_SUPPORT (!(GATOR_PERF_SUPPORT)) ++#define GATOR_CPU_FREQ_SUPPORT (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) && defined(CONFIG_CPU_FREQ) ++#define GATOR_IKS_SUPPORT defined(CONFIG_BL_SWITCHER) ++ ++// cpu ids ++#define ARM1136 0xb36 ++#define ARM1156 0xb56 ++#define ARM1176 0xb76 ++#define ARM11MPCORE 0xb02 ++#define CORTEX_A5 0xc05 ++#define CORTEX_A7 0xc07 ++#define CORTEX_A8 0xc08 ++#define CORTEX_A9 0xc09 ++#define CORTEX_A12 0xc0d ++#define CORTEX_A15 0xc0f ++#define SCORPION 0x00f ++#define SCORPIONMP 0x02d ++#define KRAITSIM 0x049 ++#define KRAIT 0x04d ++#define KRAIT_S4_PRO 0x06f ++#define CORTEX_A53 0xd03 ++#define CORTEX_A57 0xd07 ++#define AARCH64 0xd0f ++#define OTHER 0xfff ++ ++#define MAXSIZE_CORE_NAME 32 ++ ++struct gator_cpu { ++ const int cpuid; ++ // Human readable name ++ const char core_name[MAXSIZE_CORE_NAME]; ++ // Perf PMU name ++ const char * const pmu_name; ++ // gatorfs event name ++ const char * const pmnc_name; ++ // compatible from Documentation/devicetree/bindings/arm/cpus.txt ++ const char * const dt_name; ++ const int pmnc_counters; ++}; ++ ++const struct gator_cpu *gator_find_cpu_by_cpuid(const u32 cpuid); ++const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name); ++ ++/****************************************************************************** ++ * Filesystem ++ ******************************************************************************/ ++int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root, ++ char const *name, ++ const struct file_operations *fops, int perm); ++ ++struct dentry *gatorfs_mkdir(struct super_block *sb, struct dentry *root, ++ char const *name); ++ ++int gatorfs_create_ulong(struct super_block *sb, struct dentry *root, ++ char const *name, unsigned long *val); ++ ++int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root, ++ char const *name, unsigned long *val); ++ ++void gator_op_create_files(struct super_block *sb, struct dentry *root); ++ ++/****************************************************************************** ++ * Tracepoints ++ ******************************************************************************/ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) ++# error Kernels prior to 2.6.32 not supported ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) ++# define GATOR_DEFINE_PROBE(probe_name, proto) \ ++ static void probe_##probe_name(PARAMS(proto)) ++# define GATOR_REGISTER_TRACE(probe_name) \ ++ register_trace_##probe_name(probe_##probe_name) ++# define GATOR_UNREGISTER_TRACE(probe_name) \ ++ unregister_trace_##probe_name(probe_##probe_name) ++#else ++# define GATOR_DEFINE_PROBE(probe_name, proto) \ ++ static void probe_##probe_name(void *data, PARAMS(proto)) ++# define GATOR_REGISTER_TRACE(probe_name) \ ++ register_trace_##probe_name(probe_##probe_name, NULL) ++# define GATOR_UNREGISTER_TRACE(probe_name) \ ++ unregister_trace_##probe_name(probe_##probe_name, NULL) ++#endif ++ ++/****************************************************************************** ++ * Events ++ ******************************************************************************/ ++struct gator_interface { ++ void (*shutdown)(void); // Complementary function to init ++ int (*create_files)(struct super_block *sb, struct dentry *root); ++ int (*start)(void); ++ void (*stop)(void); // Complementary function to start ++ int (*online)(int **buffer, bool migrate); ++ int (*offline)(int **buffer, bool migrate); ++ void (*online_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu' ++ void (*offline_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu' ++ int (*read)(int **buffer); ++ int (*read64)(long long **buffer); ++ int (*read_proc)(long long **buffer, struct task_struct *); ++ struct list_head list; ++}; ++ ++int gator_events_install(struct gator_interface *interface); ++int gator_events_get_key(void); ++u32 gator_cpuid(void); ++ ++void gator_backtrace_handler(struct pt_regs *const regs); ++ ++#if !GATOR_IKS_SUPPORT ++ ++#define get_physical_cpu() smp_processor_id() ++#define lcpu_to_pcpu(lcpu) lcpu ++#define pcpu_to_lcpu(pcpu) pcpu ++ ++#else ++ ++#define get_physical_cpu() lcpu_to_pcpu(get_logical_cpu()) ++int lcpu_to_pcpu(const int lcpu); ++int pcpu_to_lcpu(const int pcpu); ++ ++#endif ++ ++#define get_logical_cpu() smp_processor_id() ++#define on_primary_core() (get_logical_cpu() == 0) ++ ++#endif // GATOR_H_ +diff -Nur linux-3.10.30/drivers/gator/gator_annotate.c linux-3.10.30-cubox-i/drivers/gator/gator_annotate.c +--- linux-3.10.30/drivers/gator/gator_annotate.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_annotate.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,186 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 ++ ++static DEFINE_SPINLOCK(annotate_lock); ++static bool collect_annotations = false; ++ ++static int annotate_copy(struct file *file, char const __user *buf, size_t count) ++{ ++ int cpu = 0; ++ int write = per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF]; ++ ++ if (file == NULL) { ++ // copy from kernel ++ memcpy(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count); ++ } else { ++ // copy from user space ++ if (copy_from_user(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count) != 0) ++ return -1; ++ } ++ per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF] = (write + count) & gator_buffer_mask[ANNOTATE_BUF]; ++ ++ return 0; ++} ++ ++static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count_orig, loff_t *offset) ++{ ++ int pid, cpu, header_size, available, contiguous, length1, length2, size, count = count_orig & 0x7fffffff; ++ bool interrupt_context; ++ ++ if (*offset) { ++ return -EINVAL; ++ } ++ ++ interrupt_context = in_interrupt(); ++ // Annotations are not supported in interrupt context, but may work if you comment out the the next four lines of code. ++ // By doing so, annotations in interrupt context can result in deadlocks and lost data. ++ if (interrupt_context) { ++ printk(KERN_WARNING "gator: Annotations are not supported in interrupt context. Edit gator_annotate.c in the gator driver to enable annotations in interrupt context.\n"); ++ return -EINVAL; ++ } ++ ++ retry: ++ // synchronize between cores and with collect_annotations ++ spin_lock(&annotate_lock); ++ ++ if (!collect_annotations) { ++ // Not collecting annotations, tell the caller everything was written ++ size = count_orig; ++ goto annotate_write_out; ++ } ++ ++ // Annotation only uses a single per-cpu buffer as the data must be in order to the engine ++ cpu = 0; ++ ++ if (current == NULL) { ++ pid = 0; ++ } else { ++ pid = current->pid; ++ } ++ ++ // determine total size of the payload ++ header_size = MAXSIZE_PACK32 * 3 + MAXSIZE_PACK64; ++ available = buffer_bytes_available(cpu, ANNOTATE_BUF) - header_size; ++ size = count < available ? count : available; ++ ++ if (size <= 0) { ++ // Buffer is full, wait until space is available ++ spin_unlock(&annotate_lock); ++ ++ // Drop the annotation as blocking is not allowed in interrupt context ++ if (interrupt_context) { ++ return -EINVAL; ++ } ++ ++ wait_event_interruptible(gator_annotate_wait, buffer_bytes_available(cpu, ANNOTATE_BUF) > header_size || !collect_annotations); ++ ++ // Check to see if a signal is pending ++ if (signal_pending(current)) { ++ return -EINTR; ++ } ++ ++ goto retry; ++ } ++ ++ // synchronize shared variables annotateBuf and annotatePos ++ if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF]) { ++ u64 time = gator_get_time(); ++ gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu()); ++ gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid); ++ gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, time); ++ gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, size); ++ ++ // determine the sizes to capture, length1 + length2 will equal size ++ contiguous = contiguous_space_available(cpu, ANNOTATE_BUF); ++ if (size < contiguous) { ++ length1 = size; ++ length2 = 0; ++ } else { ++ length1 = contiguous; ++ length2 = size - contiguous; ++ } ++ ++ if (annotate_copy(file, buf, length1) != 0) { ++ size = -EINVAL; ++ goto annotate_write_out; ++ } ++ ++ if (length2 > 0 && annotate_copy(file, &buf[length1], length2) != 0) { ++ size = -EINVAL; ++ goto annotate_write_out; ++ } ++ ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, ANNOTATE_BUF, time); ++ } ++ ++annotate_write_out: ++ spin_unlock(&annotate_lock); ++ ++ // return the number of bytes written ++ return size; ++} ++ ++#include "gator_annotate_kernel.c" ++ ++static int annotate_release(struct inode *inode, struct file *file) ++{ ++ int cpu = 0; ++ ++ // synchronize between cores ++ spin_lock(&annotate_lock); ++ ++ if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) { ++ uint32_t pid = current->pid; ++ gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu()); ++ gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid); ++ gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); // time ++ gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); // size ++ } ++ ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, ANNOTATE_BUF, gator_get_time()); ++ ++ spin_unlock(&annotate_lock); ++ ++ return 0; ++} ++ ++static const struct file_operations annotate_fops = { ++ .write = annotate_write, ++ .release = annotate_release ++}; ++ ++static int gator_annotate_create_files(struct super_block *sb, struct dentry *root) ++{ ++ return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666); ++} ++ ++static int gator_annotate_start(void) ++{ ++ collect_annotations = true; ++ return 0; ++} ++ ++static void gator_annotate_stop(void) ++{ ++ // the spinlock here will ensure that when this function exits, we are not in the middle of an annotation ++ spin_lock(&annotate_lock); ++ collect_annotations = false; ++ wake_up(&gator_annotate_wait); ++ spin_unlock(&annotate_lock); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_annotate_kernel.c linux-3.10.30-cubox-i/drivers/gator/gator_annotate_kernel.c +--- linux-3.10.30/drivers/gator/gator_annotate_kernel.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_annotate_kernel.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,200 @@ ++/** ++ * Copyright (C) ARM Limited 2012-2013. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#define ESCAPE_CODE 0x1c ++#define STRING_ANNOTATION 0x06 ++#define NAME_CHANNEL_ANNOTATION 0x07 ++#define NAME_GROUP_ANNOTATION 0x08 ++#define VISUAL_ANNOTATION 0x04 ++#define MARKER_ANNOTATION 0x05 ++ ++static void kannotate_write(const char *ptr, unsigned int size) ++{ ++ int retval; ++ int pos = 0; ++ loff_t offset = 0; ++ while (pos < size) { ++ retval = annotate_write(NULL, &ptr[pos], size - pos, &offset); ++ if (retval < 0) { ++ printk(KERN_WARNING "gator: kannotate_write failed with return value %d\n", retval); ++ return; ++ } ++ pos += retval; ++ } ++} ++ ++static void marshal_u16(char *buf, u16 val) { ++ buf[0] = val & 0xff; ++ buf[1] = (val >> 8) & 0xff; ++} ++ ++static void marshal_u32(char *buf, u32 val) { ++ buf[0] = val & 0xff; ++ buf[1] = (val >> 8) & 0xff; ++ buf[2] = (val >> 16) & 0xff; ++ buf[3] = (val >> 24) & 0xff; ++} ++ ++void gator_annotate_channel(int channel, const char *str) ++{ ++ const u16 str_size = strlen(str) & 0xffff; ++ char header[8]; ++ header[0] = ESCAPE_CODE; ++ header[1] = STRING_ANNOTATION; ++ marshal_u32(header + 2, channel); ++ marshal_u16(header + 6, str_size); ++ kannotate_write(header, sizeof(header)); ++ kannotate_write(str, str_size); ++} ++ ++EXPORT_SYMBOL(gator_annotate_channel); ++ ++void gator_annotate(const char *str) ++{ ++ gator_annotate_channel(0, str); ++} ++ ++EXPORT_SYMBOL(gator_annotate); ++ ++void gator_annotate_channel_color(int channel, int color, const char *str) ++{ ++ const u16 str_size = (strlen(str) + 4) & 0xffff; ++ char header[12]; ++ header[0] = ESCAPE_CODE; ++ header[1] = STRING_ANNOTATION; ++ marshal_u32(header + 2, channel); ++ marshal_u16(header + 6, str_size); ++ marshal_u32(header + 8, color); ++ kannotate_write(header, sizeof(header)); ++ kannotate_write(str, str_size - 4); ++} ++ ++EXPORT_SYMBOL(gator_annotate_channel_color); ++ ++void gator_annotate_color(int color, const char *str) ++{ ++ gator_annotate_channel_color(0, color, str); ++} ++ ++EXPORT_SYMBOL(gator_annotate_color); ++ ++void gator_annotate_channel_end(int channel) ++{ ++ char header[8]; ++ header[0] = ESCAPE_CODE; ++ header[1] = STRING_ANNOTATION; ++ marshal_u32(header + 2, channel); ++ marshal_u16(header + 6, 0); ++ kannotate_write(header, sizeof(header)); ++} ++ ++EXPORT_SYMBOL(gator_annotate_channel_end); ++ ++void gator_annotate_end(void) ++{ ++ gator_annotate_channel_end(0); ++} ++ ++EXPORT_SYMBOL(gator_annotate_end); ++ ++void gator_annotate_name_channel(int channel, int group, const char* str) ++{ ++ const u16 str_size = strlen(str) & 0xffff; ++ char header[12]; ++ header[0] = ESCAPE_CODE; ++ header[1] = NAME_CHANNEL_ANNOTATION; ++ marshal_u32(header + 2, channel); ++ marshal_u32(header + 6, group); ++ marshal_u16(header + 10, str_size); ++ kannotate_write(header, sizeof(header)); ++ kannotate_write(str, str_size); ++} ++ ++EXPORT_SYMBOL(gator_annotate_name_channel); ++ ++void gator_annotate_name_group(int group, const char* str) ++{ ++ const u16 str_size = strlen(str) & 0xffff; ++ char header[8]; ++ header[0] = ESCAPE_CODE; ++ header[1] = NAME_GROUP_ANNOTATION; ++ marshal_u32(header + 2, group); ++ marshal_u16(header + 6, str_size); ++ kannotate_write(header, sizeof(header)); ++ kannotate_write(str, str_size); ++} ++ ++EXPORT_SYMBOL(gator_annotate_name_group); ++ ++void gator_annotate_visual(const char *data, unsigned int length, const char *str) ++{ ++ const u16 str_size = strlen(str) & 0xffff; ++ char header[4]; ++ char header_length[4]; ++ header[0] = ESCAPE_CODE; ++ header[1] = VISUAL_ANNOTATION; ++ marshal_u16(header + 2, str_size); ++ marshal_u32(header_length, length); ++ kannotate_write(header, sizeof(header)); ++ kannotate_write(str, str_size); ++ kannotate_write(header_length, sizeof(header_length)); ++ kannotate_write(data, length); ++} ++ ++EXPORT_SYMBOL(gator_annotate_visual); ++ ++void gator_annotate_marker(void) ++{ ++ char header[4]; ++ header[0] = ESCAPE_CODE; ++ header[1] = MARKER_ANNOTATION; ++ marshal_u16(header + 2, 0); ++ kannotate_write(header, sizeof(header)); ++} ++ ++EXPORT_SYMBOL(gator_annotate_marker); ++ ++void gator_annotate_marker_str(const char *str) ++{ ++ const u16 str_size = strlen(str) & 0xffff; ++ char header[4]; ++ header[0] = ESCAPE_CODE; ++ header[1] = MARKER_ANNOTATION; ++ marshal_u16(header + 2, str_size); ++ kannotate_write(header, sizeof(header)); ++ kannotate_write(str, str_size); ++} ++ ++EXPORT_SYMBOL(gator_annotate_marker_str); ++ ++void gator_annotate_marker_color(int color) ++{ ++ char header[8]; ++ header[0] = ESCAPE_CODE; ++ header[1] = MARKER_ANNOTATION; ++ marshal_u16(header + 2, 4); ++ marshal_u32(header + 4, color); ++ kannotate_write(header, sizeof(header)); ++} ++ ++EXPORT_SYMBOL(gator_annotate_marker_color); ++ ++void gator_annotate_marker_color_str(int color, const char *str) ++{ ++ const u16 str_size = (strlen(str) + 4) & 0xffff; ++ char header[8]; ++ header[0] = ESCAPE_CODE; ++ header[1] = MARKER_ANNOTATION; ++ marshal_u16(header + 2, str_size); ++ marshal_u32(header + 4, color); ++ kannotate_write(header, sizeof(header)); ++ kannotate_write(str, str_size - 4); ++} ++ ++EXPORT_SYMBOL(gator_annotate_marker_color_str); +diff -Nur linux-3.10.30/drivers/gator/gator_backtrace.c linux-3.10.30-cubox-i/drivers/gator/gator_backtrace.c +--- linux-3.10.30/drivers/gator/gator_backtrace.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_backtrace.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,168 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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. ++ * ++ */ ++ ++/* ++ * EABI backtrace stores {fp,lr} on the stack. ++ */ ++struct stack_frame_eabi { ++ union { ++ struct { ++ unsigned long fp; ++ // May be the fp in the case of a leaf function or clang ++ unsigned long lr; ++ // If lr is really the fp, lr2 is the corresponding lr ++ unsigned long lr2; ++ }; ++ // Used to read 32 bit fp/lr from a 64 bit kernel ++ struct { ++ u32 fp_32; ++ // same as lr above ++ u32 lr_32; ++ // same as lr2 above ++ u32 lr2_32; ++ }; ++ }; ++}; ++ ++static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int depth) ++{ ++#if defined(__arm__) || defined(__aarch64__) ++ struct stack_frame_eabi *curr; ++ struct stack_frame_eabi bufcurr; ++#if defined(__arm__) ++ const bool is_compat = false; ++ unsigned long fp = regs->ARM_fp; ++ unsigned long sp = regs->ARM_sp; ++ unsigned long lr = regs->ARM_lr; ++ const int gcc_frame_offset = sizeof(unsigned long); ++#else ++ // Is userspace aarch32 (32 bit) ++ const bool is_compat = compat_user_mode(regs); ++ unsigned long fp = (is_compat ? regs->regs[11] : regs->regs[29]); ++ unsigned long sp = (is_compat ? regs->compat_sp : regs->sp); ++ unsigned long lr = (is_compat ? regs->compat_lr : regs->regs[30]); ++ const int gcc_frame_offset = (is_compat ? sizeof(u32) : 0); ++#endif ++ // clang frame offset is always zero ++ int is_user_mode = user_mode(regs); ++ ++ // pc (current function) has already been added ++ ++ if (!is_user_mode) { ++ return; ++ } ++ ++ // Add the lr (parent function) ++ // entry preamble may not have executed ++ gator_add_trace(cpu, lr); ++ ++ // check fp is valid ++ if (fp == 0 || fp < sp) { ++ return; ++ } ++ ++ // Get the current stack frame ++ curr = (struct stack_frame_eabi *)(fp - gcc_frame_offset); ++ if ((unsigned long)curr & 3) { ++ return; ++ } ++ ++ while (depth-- && curr) { ++ if (!access_ok(VERIFY_READ, curr, sizeof(struct stack_frame_eabi)) || ++ __copy_from_user_inatomic(&bufcurr, curr, sizeof(struct stack_frame_eabi))) { ++ return; ++ } ++ ++ fp = (is_compat ? bufcurr.fp_32 : bufcurr.fp); ++ lr = (is_compat ? bufcurr.lr_32 : bufcurr.lr); ++ ++#define calc_next(reg) ((reg) - gcc_frame_offset) ++ // Returns true if reg is a valid fp ++#define validate_next(reg, curr) \ ++ ((reg) != 0 && (calc_next(reg) & 3) == 0 && (unsigned long)(curr) < calc_next(reg)) ++ ++ // Try lr from the stack as the fp because gcc leaf functions do not push lr ++ // If gcc_frame_offset is non-zero, the lr will also be the clang fp ++ // This assumes code is at a lower address than the stack ++ if (validate_next(lr, curr)) { ++ fp = lr; ++ lr = (is_compat ? bufcurr.lr2_32 : bufcurr.lr2); ++ } ++ ++ gator_add_trace(cpu, lr); ++ ++ if (!validate_next(fp, curr)) { ++ return; ++ } ++ ++ // Move to the next stack frame ++ curr = (struct stack_frame_eabi *)calc_next(fp); ++ } ++#endif ++} ++ ++#if defined(__arm__) || defined(__aarch64__) ++static int report_trace(struct stackframe *frame, void *d) ++{ ++ unsigned int *depth = d, cookie = NO_COOKIE; ++ unsigned long addr = frame->pc; ++ ++ if (*depth) { ++#if defined(MODULE) ++ unsigned int cpu = get_physical_cpu(); ++ struct module *mod = __module_address(addr); ++ if (mod) { ++ cookie = get_cookie(cpu, current, mod->name, false); ++ addr = addr - (unsigned long)mod->module_core; ++ } ++#endif ++ marshal_backtrace(addr & ~1, cookie); ++ (*depth)--; ++ } ++ ++ return *depth == 0; ++} ++#endif ++ ++// Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile ++// #define GATOR_KERNEL_STACK_UNWINDING ++ ++#if (defined(__arm__) || defined(__aarch64__)) && !defined(GATOR_KERNEL_STACK_UNWINDING) ++// Disabled by default ++MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding."); ++bool kernel_stack_unwinding = 0; ++module_param(kernel_stack_unwinding, bool, 0644); ++#endif ++ ++static void kernel_backtrace(int cpu, struct pt_regs *const regs) ++{ ++#if defined(__arm__) || defined(__aarch64__) ++#ifdef GATOR_KERNEL_STACK_UNWINDING ++ int depth = gator_backtrace_depth; ++#else ++ int depth = (kernel_stack_unwinding ? gator_backtrace_depth : 1); ++#endif ++ struct stackframe frame; ++ if (depth == 0) ++ depth = 1; ++#if defined(__arm__) ++ frame.fp = regs->ARM_fp; ++ frame.sp = regs->ARM_sp; ++ frame.lr = regs->ARM_lr; ++ frame.pc = regs->ARM_pc; ++#else ++ frame.fp = regs->regs[29]; ++ frame.sp = regs->sp; ++ frame.pc = regs->pc; ++#endif ++ walk_stackframe(&frame, report_trace, &depth); ++#else ++ marshal_backtrace(PC_REG & ~1, NO_COOKIE); ++#endif ++} +diff -Nur linux-3.10.30/drivers/gator/gator_cookies.c linux-3.10.30-cubox-i/drivers/gator/gator_cookies.c +--- linux-3.10.30/drivers/gator/gator_cookies.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_cookies.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,433 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */ ++#define TRANSLATE_BUFFER_SIZE 512 // must be a power of 2 - 512/4 = 128 entries ++#define TRANSLATE_TEXT_SIZE 256 ++#define MAX_COLLISIONS 2 ++ ++static uint32_t *gator_crc32_table; ++static unsigned int translate_buffer_mask; ++ ++struct cookie_args { ++ struct task_struct *task; ++ const char *text; ++}; ++ ++static DEFINE_PER_CPU(char *, translate_text); ++static DEFINE_PER_CPU(uint32_t, cookie_next_key); ++static DEFINE_PER_CPU(uint64_t *, cookie_keys); ++static DEFINE_PER_CPU(uint32_t *, cookie_values); ++static DEFINE_PER_CPU(int, translate_buffer_read); ++static DEFINE_PER_CPU(int, translate_buffer_write); ++static DEFINE_PER_CPU(struct cookie_args *, translate_buffer); ++ ++static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq); ++static void wq_cookie_handler(struct work_struct *unused); ++DECLARE_WORK(cookie_work, wq_cookie_handler); ++static struct timer_list app_process_wake_up_timer; ++static void app_process_wake_up_handler(unsigned long unused_data); ++ ++static uint32_t cookiemap_code(uint64_t value64) ++{ ++ uint32_t value = (uint32_t)((value64 >> 32) + value64); ++ uint32_t cookiecode = (value >> 24) & 0xff; ++ cookiecode = cookiecode * 31 + ((value >> 16) & 0xff); ++ cookiecode = cookiecode * 31 + ((value >> 8) & 0xff); ++ cookiecode = cookiecode * 31 + ((value >> 0) & 0xff); ++ cookiecode &= (COOKIEMAP_ENTRIES - 1); ++ return cookiecode * MAX_COLLISIONS; ++} ++ ++static uint32_t gator_chksum_crc32(const char *data) ++{ ++ register unsigned long crc; ++ const unsigned char *block = data; ++ int i, length = strlen(data); ++ ++ crc = 0xFFFFFFFF; ++ for (i = 0; i < length; i++) { ++ crc = ((crc >> 8) & 0x00FFFFFF) ^ gator_crc32_table[(crc ^ *block++) & 0xFF]; ++ } ++ ++ return (crc ^ 0xFFFFFFFF); ++} ++ ++/* ++ * Exists ++ * Pre: [0][1][v][3]..[n-1] ++ * Post: [v][0][1][3]..[n-1] ++ */ ++static uint32_t cookiemap_exists(uint64_t key) ++{ ++ unsigned long x, flags, retval = 0; ++ int cpu = get_physical_cpu(); ++ uint32_t cookiecode = cookiemap_code(key); ++ uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]); ++ uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]); ++ ++ // Can be called from interrupt handler or from work queue ++ local_irq_save(flags); ++ for (x = 0; x < MAX_COLLISIONS; x++) { ++ if (keys[x] == key) { ++ uint32_t value = values[x]; ++ for (; x > 0; x--) { ++ keys[x] = keys[x - 1]; ++ values[x] = values[x - 1]; ++ } ++ keys[0] = key; ++ values[0] = value; ++ retval = value; ++ break; ++ } ++ } ++ local_irq_restore(flags); ++ ++ return retval; ++} ++ ++/* ++ * Add ++ * Pre: [0][1][2][3]..[n-1] ++ * Post: [v][0][1][2]..[n-2] ++ */ ++static void cookiemap_add(uint64_t key, uint32_t value) ++{ ++ int cpu = get_physical_cpu(); ++ int cookiecode = cookiemap_code(key); ++ uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]); ++ uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]); ++ int x; ++ ++ for (x = MAX_COLLISIONS - 1; x > 0; x--) { ++ keys[x] = keys[x - 1]; ++ values[x] = values[x - 1]; ++ } ++ keys[0] = key; ++ values[0] = value; ++} ++ ++#ifndef CONFIG_PREEMPT_RT_FULL ++static void translate_buffer_write_args(int cpu, struct task_struct *task, const char *text) ++{ ++ unsigned long flags; ++ int write; ++ int next_write; ++ struct cookie_args *args; ++ ++ local_irq_save(flags); ++ ++ write = per_cpu(translate_buffer_write, cpu); ++ next_write = (write + 1) & translate_buffer_mask; ++ ++ // At least one entry must always remain available as when read == write, the queue is empty not full ++ if (next_write != per_cpu(translate_buffer_read, cpu)) { ++ args = &per_cpu(translate_buffer, cpu)[write]; ++ args->task = task; ++ args->text = text; ++ get_task_struct(task); ++ per_cpu(translate_buffer_write, cpu) = next_write; ++ } ++ ++ local_irq_restore(flags); ++} ++#endif ++ ++static void translate_buffer_read_args(int cpu, struct cookie_args *args) ++{ ++ unsigned long flags; ++ int read; ++ ++ local_irq_save(flags); ++ ++ read = per_cpu(translate_buffer_read, cpu); ++ *args = per_cpu(translate_buffer, cpu)[read]; ++ per_cpu(translate_buffer_read, cpu) = (read + 1) & translate_buffer_mask; ++ ++ local_irq_restore(flags); ++} ++ ++static void wq_cookie_handler(struct work_struct *unused) ++{ ++ struct cookie_args args; ++ int cpu = get_physical_cpu(), cookie; ++ ++ mutex_lock(&start_mutex); ++ ++ if (gator_started != 0) { ++ while (per_cpu(translate_buffer_read, cpu) != per_cpu(translate_buffer_write, cpu)) { ++ translate_buffer_read_args(cpu, &args); ++ cookie = get_cookie(cpu, args.task, args.text, true); ++ marshal_link(cookie, args.task->tgid, args.task->pid); ++ put_task_struct(args.task); ++ } ++ } ++ ++ mutex_unlock(&start_mutex); ++} ++ ++static void app_process_wake_up_handler(unsigned long unused_data) ++{ ++ // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater ++ schedule_work(&cookie_work); ++} ++ ++// Retrieve full name from proc/pid/cmdline for java processes on Android ++static int translate_app_process(const char **text, int cpu, struct task_struct *task, bool from_wq) ++{ ++ void *maddr; ++ unsigned int len; ++ unsigned long addr; ++ struct mm_struct *mm; ++ struct page *page = NULL; ++ struct vm_area_struct *page_vma; ++ int bytes, offset, retval = 0; ++ char *buf = per_cpu(translate_text, cpu); ++ ++#ifndef CONFIG_PREEMPT_RT_FULL ++ // Push work into a work queue if in atomic context as the kernel functions below might sleep ++ // Rely on the in_interrupt variable rather than in_irq() or in_interrupt() kernel functions, as the value of these functions seems ++ // inconsistent during a context switch between android/linux versions ++ if (!from_wq) { ++ // Check if already in buffer ++ int pos = per_cpu(translate_buffer_read, cpu); ++ while (pos != per_cpu(translate_buffer_write, cpu)) { ++ if (per_cpu(translate_buffer, cpu)[pos].task == task) ++ goto out; ++ pos = (pos + 1) & translate_buffer_mask; ++ } ++ ++ translate_buffer_write_args(cpu, task, *text); ++ ++ // Not safe to call in RT-Preempt full in schedule switch context ++ mod_timer(&app_process_wake_up_timer, jiffies + 1); ++ goto out; ++ } ++#endif ++ ++ mm = get_task_mm(task); ++ if (!mm) ++ goto out; ++ if (!mm->arg_end) ++ goto outmm; ++ addr = mm->arg_start; ++ len = mm->arg_end - mm->arg_start; ++ ++ if (len > TRANSLATE_TEXT_SIZE) ++ len = TRANSLATE_TEXT_SIZE; ++ ++ down_read(&mm->mmap_sem); ++ while (len) { ++ if (get_user_pages(task, mm, addr, 1, 0, 1, &page, &page_vma) <= 0) ++ goto outsem; ++ ++ maddr = kmap(page); ++ offset = addr & (PAGE_SIZE - 1); ++ bytes = len; ++ if (bytes > PAGE_SIZE - offset) ++ bytes = PAGE_SIZE - offset; ++ ++ copy_from_user_page(page_vma, page, addr, buf, maddr + offset, bytes); ++ ++ kunmap(page); // release page allocated by get_user_pages() ++ page_cache_release(page); ++ ++ len -= bytes; ++ buf += bytes; ++ addr += bytes; ++ ++ *text = per_cpu(translate_text, cpu); ++ retval = 1; ++ } ++ ++ // On app_process startup, /proc/pid/cmdline is initially "zygote" then "" but changes after an initial startup period ++ if (strcmp(*text, "zygote") == 0 || strcmp(*text, "") == 0) ++ retval = 0; ++ ++outsem: ++ up_read(&mm->mmap_sem); ++outmm: ++ mmput(mm); ++out: ++ return retval; ++} ++ ++static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq) ++{ ++ unsigned long flags, cookie; ++ uint64_t key; ++ ++ key = gator_chksum_crc32(text); ++ key = (key << 32) | (uint32_t)task->tgid; ++ ++ cookie = cookiemap_exists(key); ++ if (cookie) { ++ return cookie; ++ } ++ ++ if (strcmp(text, "app_process") == 0) { ++ if (!translate_app_process(&text, cpu, task, from_wq)) ++ return UNRESOLVED_COOKIE; ++ } ++ ++ // Can be called from interrupt handler or from work queue or from scheduler trace ++ local_irq_save(flags); ++ ++ cookie = UNRESOLVED_COOKIE; ++ if (marshal_cookie_header(text)) { ++ cookie = per_cpu(cookie_next_key, cpu) += nr_cpu_ids; ++ cookiemap_add(key, cookie); ++ marshal_cookie(cookie, text); ++ } ++ ++ local_irq_restore(flags); ++ ++ return cookie; ++} ++ ++static int get_exec_cookie(int cpu, struct task_struct *task) ++{ ++ struct mm_struct *mm = task->mm; ++ const char *text; ++ ++ // kernel threads have no address space ++ if (!mm) ++ return NO_COOKIE; ++ ++ if (task && task->mm && task->mm->exe_file) { ++ text = task->mm->exe_file->f_path.dentry->d_name.name; ++ return get_cookie(cpu, task, text, false); ++ } ++ ++ return UNRESOLVED_COOKIE; ++} ++ ++static unsigned long get_address_cookie(int cpu, struct task_struct *task, unsigned long addr, off_t *offset) ++{ ++ unsigned long cookie = NO_COOKIE; ++ struct mm_struct *mm = task->mm; ++ struct vm_area_struct *vma; ++ const char *text; ++ ++ if (!mm) ++ return cookie; ++ ++ for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { ++ if (addr < vma->vm_start || addr >= vma->vm_end) ++ continue; ++ ++ if (vma->vm_file) { ++ text = vma->vm_file->f_path.dentry->d_name.name; ++ cookie = get_cookie(cpu, task, text, false); ++ *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start; ++ } else { ++ /* must be an anonymous map */ ++ *offset = addr; ++ } ++ ++ break; ++ } ++ ++ if (!vma) ++ cookie = UNRESOLVED_COOKIE; ++ ++ return cookie; ++} ++ ++static int cookies_initialize(void) ++{ ++ uint32_t crc, poly; ++ int i, j, cpu, size, err = 0; ++ ++ translate_buffer_mask = TRANSLATE_BUFFER_SIZE / sizeof(per_cpu(translate_buffer, 0)[0]) - 1; ++ ++ for_each_present_cpu(cpu) { ++ per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu; ++ ++ size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t); ++ per_cpu(cookie_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL); ++ if (!per_cpu(cookie_keys, cpu)) { ++ err = -ENOMEM; ++ goto cookie_setup_error; ++ } ++ memset(per_cpu(cookie_keys, cpu), 0, size); ++ ++ size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint32_t); ++ per_cpu(cookie_values, cpu) = (uint32_t *)kmalloc(size, GFP_KERNEL); ++ if (!per_cpu(cookie_values, cpu)) { ++ err = -ENOMEM; ++ goto cookie_setup_error; ++ } ++ memset(per_cpu(cookie_values, cpu), 0, size); ++ ++ per_cpu(translate_buffer, cpu) = (struct cookie_args *)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL); ++ if (!per_cpu(translate_buffer, cpu)) { ++ err = -ENOMEM; ++ goto cookie_setup_error; ++ } ++ ++ per_cpu(translate_buffer_write, cpu) = 0; ++ per_cpu(translate_buffer_read, cpu) = 0; ++ ++ per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_TEXT_SIZE, GFP_KERNEL); ++ if (!per_cpu(translate_text, cpu)) { ++ err = -ENOMEM; ++ goto cookie_setup_error; ++ } ++ } ++ ++ // build CRC32 table ++ poly = 0x04c11db7; ++ gator_crc32_table = (uint32_t *)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL); ++ if (!gator_crc32_table) { ++ err = -ENOMEM; ++ goto cookie_setup_error; ++ } ++ for (i = 0; i < 256; i++) { ++ crc = i; ++ for (j = 8; j > 0; j--) { ++ if (crc & 1) { ++ crc = (crc >> 1) ^ poly; ++ } else { ++ crc >>= 1; ++ } ++ } ++ gator_crc32_table[i] = crc; ++ } ++ ++ setup_timer(&app_process_wake_up_timer, app_process_wake_up_handler, 0); ++ ++cookie_setup_error: ++ return err; ++} ++ ++static void cookies_release(void) ++{ ++ int cpu; ++ ++ for_each_present_cpu(cpu) { ++ kfree(per_cpu(cookie_keys, cpu)); ++ per_cpu(cookie_keys, cpu) = NULL; ++ ++ kfree(per_cpu(cookie_values, cpu)); ++ per_cpu(cookie_values, cpu) = NULL; ++ ++ kfree(per_cpu(translate_buffer, cpu)); ++ per_cpu(translate_buffer, cpu) = NULL; ++ per_cpu(translate_buffer_read, cpu) = 0; ++ per_cpu(translate_buffer_write, cpu) = 0; ++ ++ kfree(per_cpu(translate_text, cpu)); ++ per_cpu(translate_text, cpu) = NULL; ++ } ++ ++ del_timer_sync(&app_process_wake_up_timer); ++ kfree(gator_crc32_table); ++ gator_crc32_table = NULL; ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_armv6.c linux-3.10.30-cubox-i/drivers/gator/gator_events_armv6.c +--- linux-3.10.30/drivers/gator/gator_events_armv6.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_armv6.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,237 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++ ++// gator_events_perf_pmu.c is used if perf is supported ++#if GATOR_NO_PERF_SUPPORT ++ ++static const char *pmnc_name; ++ ++/* ++ * Per-CPU PMCR ++ */ ++#define PMCR_E (1 << 0) /* Enable */ ++#define PMCR_P (1 << 1) /* Count reset */ ++#define PMCR_C (1 << 2) /* Cycle counter reset */ ++#define PMCR_OFL_PMN0 (1 << 8) /* Count reg 0 overflow */ ++#define PMCR_OFL_PMN1 (1 << 9) /* Count reg 1 overflow */ ++#define PMCR_OFL_CCNT (1 << 10) /* Cycle counter overflow */ ++ ++#define PMN0 0 ++#define PMN1 1 ++#define CCNT 2 ++#define CNTMAX (CCNT+1) ++ ++static int pmnc_counters = 0; ++static unsigned long pmnc_enabled[CNTMAX]; ++static unsigned long pmnc_event[CNTMAX]; ++static unsigned long pmnc_key[CNTMAX]; ++ ++static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt); ++ ++static inline void armv6_pmnc_write(u32 val) ++{ ++ /* upper 4bits and 7, 11 are write-as-0 */ ++ val &= 0x0ffff77f; ++ asm volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val)); ++} ++ ++static inline u32 armv6_pmnc_read(void) ++{ ++ u32 val; ++ asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val)); ++ return val; ++} ++ ++static void armv6_pmnc_reset_counter(unsigned int cnt) ++{ ++ u32 val = 0; ++ switch (cnt) { ++ case CCNT: ++ asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val)); ++ break; ++ case PMN0: ++ asm volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val)); ++ break; ++ case PMN1: ++ asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val)); ++ break; ++ } ++} ++ ++int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root) ++{ ++ struct dentry *dir; ++ int i; ++ ++ pmnc_counters = 3; ++ ++ for (i = PMN0; i <= CCNT; i++) { ++ char buf[40]; ++ if (i == CCNT) { ++ snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name); ++ } else { ++ snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i); ++ } ++ dir = gatorfs_mkdir(sb, root, buf); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]); ++ gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]); ++ if (i != CCNT) { ++ gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]); ++ } ++ } ++ ++ return 0; ++} ++ ++static int gator_events_armv6_online(int **buffer, bool migrate) ++{ ++ unsigned int cnt, len = 0, cpu = smp_processor_id(); ++ u32 pmnc; ++ ++ if (armv6_pmnc_read() & PMCR_E) { ++ armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E); ++ } ++ ++ /* initialize PMNC, reset overflow, D bit, C bit and P bit. */ ++ armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT | ++ PMCR_C | PMCR_P); ++ ++ /* configure control register */ ++ for (pmnc = 0, cnt = PMN0; cnt <= CCNT; cnt++) { ++ unsigned long event; ++ ++ if (!pmnc_enabled[cnt]) ++ continue; ++ ++ event = pmnc_event[cnt] & 255; ++ ++ // Set event (if destined for PMNx counters) ++ if (cnt == PMN0) { ++ pmnc |= event << 20; ++ } else if (cnt == PMN1) { ++ pmnc |= event << 12; ++ } ++ ++ // Reset counter ++ armv6_pmnc_reset_counter(cnt); ++ } ++ armv6_pmnc_write(pmnc | PMCR_E); ++ ++ // return zero values, no need to read as the counters were just reset ++ for (cnt = PMN0; cnt <= CCNT; cnt++) { ++ if (pmnc_enabled[cnt]) { ++ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; ++ per_cpu(perfCnt, cpu)[len++] = 0; ++ } ++ } ++ ++ if (buffer) ++ *buffer = per_cpu(perfCnt, cpu); ++ ++ return len; ++} ++ ++static int gator_events_armv6_offline(int **buffer, bool migrate) ++{ ++ unsigned int cnt; ++ ++ armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E); ++ for (cnt = PMN0; cnt <= CCNT; cnt++) { ++ armv6_pmnc_reset_counter(cnt); ++ } ++ ++ return 0; ++} ++ ++static void gator_events_armv6_stop(void) ++{ ++ unsigned int cnt; ++ ++ for (cnt = PMN0; cnt <= CCNT; cnt++) { ++ pmnc_enabled[cnt] = 0; ++ pmnc_event[cnt] = 0; ++ } ++} ++ ++static int gator_events_armv6_read(int **buffer) ++{ ++ int cnt, len = 0; ++ int cpu = smp_processor_id(); ++ ++ // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled ++ if (!(armv6_pmnc_read() & PMCR_E)) { ++ return 0; ++ } ++ ++ for (cnt = PMN0; cnt <= CCNT; cnt++) { ++ if (pmnc_enabled[cnt]) { ++ u32 value = 0; ++ switch (cnt) { ++ case CCNT: ++ asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value)); ++ break; ++ case PMN0: ++ asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (value)); ++ break; ++ case PMN1: ++ asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (value)); ++ break; ++ } ++ armv6_pmnc_reset_counter(cnt); ++ ++ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; ++ per_cpu(perfCnt, cpu)[len++] = value; ++ } ++ } ++ ++ if (buffer) ++ *buffer = per_cpu(perfCnt, cpu); ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_armv6_interface = { ++ .create_files = gator_events_armv6_create_files, ++ .stop = gator_events_armv6_stop, ++ .online = gator_events_armv6_online, ++ .offline = gator_events_armv6_offline, ++ .read = gator_events_armv6_read, ++}; ++ ++int gator_events_armv6_init(void) ++{ ++ unsigned int cnt; ++ ++ switch (gator_cpuid()) { ++ case ARM1136: ++ case ARM1156: ++ case ARM1176: ++ pmnc_name = "ARM11"; ++ break; ++ case ARM11MPCORE: ++ pmnc_name = "ARM11MPCore"; ++ break; ++ default: ++ return -1; ++ } ++ ++ for (cnt = PMN0; cnt <= CCNT; cnt++) { ++ pmnc_enabled[cnt] = 0; ++ pmnc_event[cnt] = 0; ++ pmnc_key[cnt] = gator_events_get_key(); ++ } ++ ++ return gator_events_install(&gator_events_armv6_interface); ++} ++ ++#endif +diff -Nur linux-3.10.30/drivers/gator/gator_events_armv7.c linux-3.10.30-cubox-i/drivers/gator/gator_events_armv7.c +--- linux-3.10.30/drivers/gator/gator_events_armv7.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_armv7.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,312 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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. ++ */ ++ ++/* Disabling interrupts ++ * Many of the functions below disable interrupts via local_irq_save(). This disabling of interrupts is done to prevent any race conditions ++ * between multiple entities (e.g. hrtimer interrupts and event based interrupts) calling the same functions. As accessing the pmu involves ++ * several steps (disable, select, read, enable), these steps must be performed atomically. Normal synchronization routines cannot be used ++ * as these functions are being called from interrupt context. ++ */ ++ ++#include "gator.h" ++ ++// gator_events_perf_pmu.c is used if perf is supported ++#if GATOR_NO_PERF_SUPPORT ++ ++// Per-CPU PMNC: config reg ++#define PMNC_E (1 << 0) /* Enable all counters */ ++#define PMNC_P (1 << 1) /* Reset all counters */ ++#define PMNC_C (1 << 2) /* Cycle counter reset */ ++#define PMNC_MASK 0x3f /* Mask for writable bits */ ++ ++// ccnt reg ++#define CCNT_REG (1 << 31) ++ ++#define CCNT 0 ++#define CNT0 1 ++#define CNTMAX (6+1) ++ ++static const char *pmnc_name; ++static int pmnc_counters; ++ ++static unsigned long pmnc_enabled[CNTMAX]; ++static unsigned long pmnc_event[CNTMAX]; ++static unsigned long pmnc_key[CNTMAX]; ++ ++static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt); ++ ++inline void armv7_pmnc_write(u32 val) ++{ ++ val &= PMNC_MASK; ++ asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val)); ++} ++ ++inline u32 armv7_pmnc_read(void) ++{ ++ u32 val; ++ asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); ++ return val; ++} ++ ++inline u32 armv7_ccnt_read(u32 reset_value) ++{ ++ unsigned long flags; ++ u32 newval = -reset_value; ++ u32 den = CCNT_REG; ++ u32 val; ++ ++ local_irq_save(flags); ++ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable ++ asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); // read ++ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (newval)); // new value ++ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable ++ local_irq_restore(flags); ++ ++ return val; ++} ++ ++inline u32 armv7_cntn_read(unsigned int cnt, u32 reset_value) ++{ ++ unsigned long flags; ++ u32 newval = -reset_value; ++ u32 sel = (cnt - CNT0); ++ u32 den = 1 << sel; ++ u32 oldval; ++ ++ local_irq_save(flags); ++ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable ++ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); // select ++ asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (oldval)); // read ++ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (newval)); // new value ++ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable ++ local_irq_restore(flags); ++ ++ return oldval; ++} ++ ++static inline void armv7_pmnc_disable_interrupt(unsigned int cnt) ++{ ++ u32 val = cnt ? (1 << (cnt - CNT0)) : (1 << 31); ++ asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val)); ++} ++ ++inline u32 armv7_pmnc_reset_interrupt(void) ++{ ++ // Get and reset overflow status flags ++ u32 flags; ++ asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (flags)); ++ flags &= 0x8000003f; ++ asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (flags)); ++ return flags; ++} ++ ++static inline u32 armv7_pmnc_enable_counter(unsigned int cnt) ++{ ++ u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG; ++ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val)); ++ return cnt; ++} ++ ++static inline u32 armv7_pmnc_disable_counter(unsigned int cnt) ++{ ++ u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG; ++ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val)); ++ return cnt; ++} ++ ++static inline int armv7_pmnc_select_counter(unsigned int cnt) ++{ ++ u32 val = (cnt - CNT0); ++ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val)); ++ return cnt; ++} ++ ++static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val) ++{ ++ if (armv7_pmnc_select_counter(cnt) == cnt) { ++ asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); ++ } ++} ++ ++static int gator_events_armv7_create_files(struct super_block *sb, struct dentry *root) ++{ ++ struct dentry *dir; ++ int i; ++ ++ for (i = 0; i < pmnc_counters; i++) { ++ char buf[40]; ++ if (i == 0) { ++ snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name); ++ } else { ++ snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i - 1); ++ } ++ dir = gatorfs_mkdir(sb, root, buf); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]); ++ gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]); ++ if (i > 0) { ++ gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]); ++ } ++ } ++ ++ return 0; ++} ++ ++static int gator_events_armv7_online(int **buffer, bool migrate) ++{ ++ unsigned int cnt, len = 0, cpu = smp_processor_id(); ++ ++ if (armv7_pmnc_read() & PMNC_E) { ++ armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); ++ } ++ ++ // Initialize & Reset PMNC: C bit and P bit ++ armv7_pmnc_write(PMNC_P | PMNC_C); ++ ++ // Reset overflow flags ++ armv7_pmnc_reset_interrupt(); ++ ++ for (cnt = CCNT; cnt < CNTMAX; cnt++) { ++ unsigned long event; ++ ++ if (!pmnc_enabled[cnt]) ++ continue; ++ ++ // Disable counter ++ armv7_pmnc_disable_counter(cnt); ++ ++ event = pmnc_event[cnt] & 255; ++ ++ // Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count ++ if (cnt != CCNT) ++ armv7_pmnc_write_evtsel(cnt, event); ++ ++ armv7_pmnc_disable_interrupt(cnt); ++ ++ // Reset counter ++ cnt ? armv7_cntn_read(cnt, 0) : armv7_ccnt_read(0); ++ ++ // Enable counter ++ armv7_pmnc_enable_counter(cnt); ++ } ++ ++ // enable ++ armv7_pmnc_write(armv7_pmnc_read() | PMNC_E); ++ ++ // return zero values, no need to read as the counters were just reset ++ for (cnt = 0; cnt < pmnc_counters; cnt++) { ++ if (pmnc_enabled[cnt]) { ++ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; ++ per_cpu(perfCnt, cpu)[len++] = 0; ++ } ++ } ++ ++ if (buffer) ++ *buffer = per_cpu(perfCnt, cpu); ++ ++ return len; ++} ++ ++static int gator_events_armv7_offline(int **buffer, bool migrate) ++{ ++ // disable all counters, including PMCCNTR; overflow IRQs will not be signaled ++ armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); ++ ++ return 0; ++} ++ ++static void gator_events_armv7_stop(void) ++{ ++ unsigned int cnt; ++ ++ for (cnt = CCNT; cnt < CNTMAX; cnt++) { ++ pmnc_enabled[cnt] = 0; ++ pmnc_event[cnt] = 0; ++ } ++} ++ ++static int gator_events_armv7_read(int **buffer) ++{ ++ int cnt, len = 0; ++ int cpu = smp_processor_id(); ++ ++ // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled ++ if (!(armv7_pmnc_read() & PMNC_E)) { ++ return 0; ++ } ++ ++ for (cnt = 0; cnt < pmnc_counters; cnt++) { ++ if (pmnc_enabled[cnt]) { ++ int value; ++ if (cnt == CCNT) { ++ value = armv7_ccnt_read(0); ++ } else { ++ value = armv7_cntn_read(cnt, 0); ++ } ++ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; ++ per_cpu(perfCnt, cpu)[len++] = value; ++ } ++ } ++ ++ if (buffer) ++ *buffer = per_cpu(perfCnt, cpu); ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_armv7_interface = { ++ .create_files = gator_events_armv7_create_files, ++ .stop = gator_events_armv7_stop, ++ .online = gator_events_armv7_online, ++ .offline = gator_events_armv7_offline, ++ .read = gator_events_armv7_read, ++}; ++ ++int gator_events_armv7_init(void) ++{ ++ unsigned int cnt; ++ ++ switch (gator_cpuid()) { ++ case CORTEX_A5: ++ pmnc_name = "Cortex-A5"; ++ pmnc_counters = 2; ++ break; ++ case CORTEX_A7: ++ pmnc_name = "Cortex-A7"; ++ pmnc_counters = 4; ++ break; ++ case CORTEX_A8: ++ pmnc_name = "Cortex-A8"; ++ pmnc_counters = 4; ++ break; ++ case CORTEX_A9: ++ pmnc_name = "Cortex-A9"; ++ pmnc_counters = 6; ++ break; ++ case CORTEX_A15: ++ pmnc_name = "Cortex-A15"; ++ pmnc_counters = 6; ++ break; ++ default: ++ return -1; ++ } ++ ++ pmnc_counters++; // CNT[n] + CCNT ++ ++ for (cnt = CCNT; cnt < CNTMAX; cnt++) { ++ pmnc_enabled[cnt] = 0; ++ pmnc_event[cnt] = 0; ++ pmnc_key[cnt] = gator_events_get_key(); ++ } ++ ++ return gator_events_install(&gator_events_armv7_interface); ++} ++ ++#endif +diff -Nur linux-3.10.30/drivers/gator/gator_events_block.c linux-3.10.30-cubox-i/drivers/gator/gator_events_block.c +--- linux-3.10.30/drivers/gator/gator_events_block.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_block.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,153 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++#include ++ ++#define BLOCK_RQ_WR 0 ++#define BLOCK_RQ_RD 1 ++ ++#define BLOCK_TOTAL (BLOCK_RQ_RD+1) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) ++#define EVENTWRITE REQ_RW ++#else ++#define EVENTWRITE REQ_WRITE ++#endif ++ ++static ulong block_rq_wr_enabled; ++static ulong block_rq_rd_enabled; ++static ulong block_rq_wr_key; ++static ulong block_rq_rd_key; ++static atomic_t blockCnt[BLOCK_TOTAL]; ++static int blockGet[BLOCK_TOTAL * 4]; ++ ++GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq)) ++{ ++ int write, size; ++ ++ if (!rq) ++ return; ++ ++ write = rq->cmd_flags & EVENTWRITE; ++ size = rq->resid_len; ++ ++ if (!size) ++ return; ++ ++ if (write) { ++ if (block_rq_wr_enabled) { ++ atomic_add(size, &blockCnt[BLOCK_RQ_WR]); ++ } ++ } else { ++ if (block_rq_rd_enabled) { ++ atomic_add(size, &blockCnt[BLOCK_RQ_RD]); ++ } ++ } ++} ++ ++static int gator_events_block_create_files(struct super_block *sb, struct dentry *root) ++{ ++ struct dentry *dir; ++ ++ /* block_complete_wr */ ++ dir = gatorfs_mkdir(sb, root, "Linux_block_rq_wr"); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &block_rq_wr_enabled); ++ gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_wr_key); ++ ++ /* block_complete_rd */ ++ dir = gatorfs_mkdir(sb, root, "Linux_block_rq_rd"); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &block_rq_rd_enabled); ++ gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_rd_key); ++ ++ return 0; ++} ++ ++static int gator_events_block_start(void) ++{ ++ // register tracepoints ++ if (block_rq_wr_enabled || block_rq_rd_enabled) ++ if (GATOR_REGISTER_TRACE(block_rq_complete)) ++ goto fail_block_rq_exit; ++ pr_debug("gator: registered block event tracepoints\n"); ++ ++ return 0; ++ ++ // unregister tracepoints on error ++fail_block_rq_exit: ++ pr_err("gator: block event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); ++ ++ return -1; ++} ++ ++static void gator_events_block_stop(void) ++{ ++ if (block_rq_wr_enabled || block_rq_rd_enabled) ++ GATOR_UNREGISTER_TRACE(block_rq_complete); ++ pr_debug("gator: unregistered block event tracepoints\n"); ++ ++ block_rq_wr_enabled = 0; ++ block_rq_rd_enabled = 0; ++} ++ ++static int gator_events_block_read(int **buffer) ++{ ++ int len, value, data = 0; ++ ++ if (!on_primary_core()) { ++ return 0; ++ } ++ ++ len = 0; ++ if (block_rq_wr_enabled && (value = atomic_read(&blockCnt[BLOCK_RQ_WR])) > 0) { ++ atomic_sub(value, &blockCnt[BLOCK_RQ_WR]); ++ blockGet[len++] = block_rq_wr_key; ++ blockGet[len++] = 0; // indicates to Streamline that value bytes were written now, not since the last message ++ blockGet[len++] = block_rq_wr_key; ++ blockGet[len++] = value; ++ data += value; ++ } ++ if (block_rq_rd_enabled && (value = atomic_read(&blockCnt[BLOCK_RQ_RD])) > 0) { ++ atomic_sub(value, &blockCnt[BLOCK_RQ_RD]); ++ blockGet[len++] = block_rq_rd_key; ++ blockGet[len++] = 0; // indicates to Streamline that value bytes were read now, not since the last message ++ blockGet[len++] = block_rq_rd_key; ++ blockGet[len++] = value; ++ data += value; ++ } ++ ++ if (buffer) ++ *buffer = blockGet; ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_block_interface = { ++ .create_files = gator_events_block_create_files, ++ .start = gator_events_block_start, ++ .stop = gator_events_block_stop, ++ .read = gator_events_block_read, ++}; ++ ++int gator_events_block_init(void) ++{ ++ block_rq_wr_enabled = 0; ++ block_rq_rd_enabled = 0; ++ ++ block_rq_wr_key = gator_events_get_key(); ++ block_rq_rd_key = gator_events_get_key(); ++ ++ return gator_events_install(&gator_events_block_interface); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_ccn-504.c linux-3.10.30-cubox-i/drivers/gator/gator_events_ccn-504.c +--- linux-3.10.30/drivers/gator/gator_events_ccn-504.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_ccn-504.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,346 @@ ++/** ++ * Copyright (C) ARM Limited 2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++ ++#define NUM_REGIONS 256 ++#define REGION_SIZE (64*1024) ++#define REGION_DEBUG 1 ++#define REGION_XP 64 ++#define NUM_XPS 11 ++ ++// DT (Debug) region ++#define PMEVCNTSR0 0x0150 ++#define PMCCNTRSR 0x0190 ++#define PMCR 0x01A8 ++#define PMSR 0x01B0 ++#define PMSR_REQ 0x01B8 ++#define PMSR_CLR 0x01C0 ++ ++// XP region ++#define DT_CONFIG 0x0300 ++#define DT_CONTROL 0x0370 ++ ++// Multiple ++#define PMU_EVENT_SEL 0x0600 ++#define OLY_ID 0xFF00 ++ ++#define CCNT 4 ++#define CNTMAX (CCNT + 1) ++ ++#define get_pmu_event_id(event) (((event) >> 0) & 0xFF) ++#define get_node_type(event) (((event) >> 8) & 0xFF) ++#define get_region(event) (((event) >> 16) & 0xFF) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) ++ ++// From kernel/params.c ++#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \ ++ int param_set_##name(const char *val, struct kernel_param *kp) \ ++ { \ ++ tmptype l; \ ++ int ret; \ ++ \ ++ if (!val) return -EINVAL; \ ++ ret = strtolfn(val, 0, &l); \ ++ if (ret == -EINVAL || ((type)l != l)) \ ++ return -EINVAL; \ ++ *((type *)kp->arg) = l; \ ++ return 0; \ ++ } \ ++ int param_get_##name(char *buffer, struct kernel_param *kp) \ ++ { \ ++ return sprintf(buffer, format, *((type *)kp->arg)); \ ++ } ++ ++#else ++ ++// From kernel/params.c ++#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \ ++ int param_set_##name(const char *val, const struct kernel_param *kp) \ ++ { \ ++ tmptype l; \ ++ int ret; \ ++ \ ++ ret = strtolfn(val, 0, &l); \ ++ if (ret < 0 || ((type)l != l)) \ ++ return ret < 0 ? ret : -EINVAL; \ ++ *((type *)kp->arg) = l; \ ++ return 0; \ ++ } \ ++ int param_get_##name(char *buffer, const struct kernel_param *kp) \ ++ { \ ++ return scnprintf(buffer, PAGE_SIZE, format, \ ++ *((type *)kp->arg)); \ ++ } \ ++ struct kernel_param_ops param_ops_##name = { \ ++ .set = param_set_##name, \ ++ .get = param_get_##name, \ ++ }; \ ++ EXPORT_SYMBOL(param_set_##name); \ ++ EXPORT_SYMBOL(param_get_##name); \ ++ EXPORT_SYMBOL(param_ops_##name) ++ ++#endif ++ ++STANDARD_PARAM_DEF(u64, u64, "%llu", u64, strict_strtoull); ++ ++// From include/linux/moduleparam.h ++#define param_check_u64(name, p) __param_check(name, p, u64) ++ ++MODULE_PARM_DESC(ccn504_addr, "CCN-504 physical base address"); ++static u64 ccn504_addr = 0; ++module_param(ccn504_addr, u64, 0444); ++ ++static void __iomem *gator_events_ccn504_base; ++static bool gator_events_ccn504_global_enabled; ++static unsigned long gator_events_ccn504_enabled[CNTMAX]; ++static unsigned long gator_events_ccn504_event[CNTMAX]; ++static unsigned long gator_events_ccn504_key[CNTMAX]; ++static int gator_events_ccn504_buffer[2*CNTMAX]; ++static int gator_events_ccn504_prev[CNTMAX]; ++ ++static void gator_events_ccn504_create_shutdown(void) ++{ ++ if (gator_events_ccn504_base != NULL) { ++ iounmap(gator_events_ccn504_base); ++ } ++} ++ ++static int gator_events_ccn504_create_files(struct super_block *sb, struct dentry *root) ++{ ++ struct dentry *dir; ++ int i; ++ char buf[32]; ++ ++ for (i = 0; i < CNTMAX; ++i) { ++ if (i == CCNT) { ++ snprintf(buf, sizeof(buf), "CCN-504_ccnt"); ++ } else { ++ snprintf(buf, sizeof(buf), "CCN-504_cnt%i", i); ++ } ++ dir = gatorfs_mkdir(sb, root, buf); ++ if (!dir) { ++ return -1; ++ } ++ ++ gatorfs_create_ulong(sb, dir, "enabled", &gator_events_ccn504_enabled[i]); ++ if (i != CCNT) { ++ gatorfs_create_ulong(sb, dir, "event", &gator_events_ccn504_event[i]); ++ } ++ gatorfs_create_ro_ulong(sb, dir, "key", &gator_events_ccn504_key[i]); ++ } ++ ++ return 0; ++} ++ ++static void gator_events_ccn504_set_dt_config(int xp_node_id, int event_num, int value) ++{ ++ u32 dt_config; ++ ++ dt_config = readl(gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG); ++ dt_config |= (value + event_num) << (4*event_num); ++ writel(dt_config, gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG); ++} ++ ++static int gator_events_ccn504_start(void) ++{ ++ int i; ++ ++ gator_events_ccn504_global_enabled = 0; ++ for (i = 0; i < CNTMAX; ++i) { ++ if (gator_events_ccn504_enabled[i]) { ++ gator_events_ccn504_global_enabled = 1; ++ break; ++ } ++ } ++ ++ if (!gator_events_ccn504_global_enabled) { ++ return 0; ++ } ++ ++ memset(&gator_events_ccn504_prev, 0x80, sizeof(gator_events_ccn504_prev)); ++ ++ // Disable INTREQ on overflow ++ // [6] ovfl_intr_en = 0 ++ // perhaps set to 1? ++ // [5] cntr_rst = 0 ++ // No register paring ++ // [4:1] cntcfg = 0 ++ // Enable PMU features ++ // [0] pmu_en = 1 ++ writel(0x1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMCR); ++ ++ // Configure the XPs ++ for (i = 0; i < NUM_XPS; ++i) { ++ int dt_control; ++ ++ // Pass on all events ++ writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG); ++ ++ // Enable PMU capability ++ // [0] dt_enable = 1 ++ dt_control = readl(gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL); ++ dt_control |= 0x1; ++ writel(dt_control, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL); ++ } ++ ++ // Assume no other pmu_event_sel registers are set ++ ++ // cycle counter does not need to be enabled ++ for (i = 0; i < CCNT; ++i) { ++ int pmu_event_id; ++ int node_type; ++ int region; ++ u32 pmu_event_sel; ++ u32 oly_id_whole; ++ u32 oly_id; ++ u32 node_id; ++ ++ if (!gator_events_ccn504_enabled[i]) { ++ continue; ++ } ++ ++ pmu_event_id = get_pmu_event_id(gator_events_ccn504_event[i]); ++ node_type = get_node_type(gator_events_ccn504_event[i]); ++ region = get_region(gator_events_ccn504_event[i]); ++ ++ // Verify the node_type ++ oly_id_whole = readl(gator_events_ccn504_base + region*REGION_SIZE + OLY_ID); ++ oly_id = oly_id_whole & 0x1F; ++ node_id = (oly_id_whole >> 8) & 0x7F; ++ if ((oly_id != node_type) || ++ ((node_type == 0x16) && ((oly_id != 0x14) && (oly_id != 0x15) && (oly_id != 0x16) && (oly_id != 0x18) && (oly_id != 0x19) && (oly_id != 0x1A)))) { ++ printk(KERN_ERR "gator: oly_id is 0x%x expected 0x%x\n", oly_id, node_type); ++ return -1; ++ } ++ ++ // Set the control register ++ pmu_event_sel = readl(gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL); ++ switch (node_type) { ++ case 0x08: // XP ++ pmu_event_sel |= pmu_event_id << (7*i); ++ gator_events_ccn504_set_dt_config(node_id, i, 0x4); ++ break; ++ case 0x04: // HN-F ++ case 0x16: // RN-I ++ case 0x10: // SBAS ++ pmu_event_sel |= pmu_event_id << (4*i); ++ gator_events_ccn504_set_dt_config(node_id/2, i, (node_id & 1) == 0 ? 0x8 : 0xC); ++ break; ++ } ++ writel(pmu_event_sel, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL); ++ } ++ ++ return 0; ++} ++ ++static void gator_events_ccn504_stop(void) ++{ ++ int i; ++ ++ if (!gator_events_ccn504_global_enabled) { ++ return; ++ } ++ ++ // cycle counter does not need to be disabled ++ for (i = 0; i < CCNT; ++i) { ++ int region; ++ ++ if (!gator_events_ccn504_enabled[i]) { ++ continue; ++ } ++ ++ region = get_region(gator_events_ccn504_event[i]); ++ ++ writel(0, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL); ++ } ++ ++ // Clear dt_config ++ for (i = 0; i < NUM_XPS; ++i) { ++ writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG); ++ } ++} ++ ++static int gator_events_ccn504_read(int **buffer) ++{ ++ int i; ++ int len = 0; ++ int value; ++ ++ if (!on_primary_core() || !gator_events_ccn504_global_enabled) { ++ return 0; ++ } ++ ++ // Verify the pmsr register is zero ++ while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0); ++ ++ // Request a PMU snapshot ++ writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_REQ); ++ ++ // Wait for the snapshot ++ while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0); ++ ++ // Read the shadow registers ++ for (i = 0; i < CNTMAX; ++i) { ++ if (!gator_events_ccn504_enabled[i]) { ++ continue; ++ } ++ ++ value = readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + (i == CCNT ? PMCCNTRSR : PMEVCNTSR0 + 8*i)); ++ if (gator_events_ccn504_prev[i] != 0x80808080) { ++ gator_events_ccn504_buffer[len++] = gator_events_ccn504_key[i]; ++ gator_events_ccn504_buffer[len++] = value - gator_events_ccn504_prev[i]; ++ } ++ gator_events_ccn504_prev[i] = value; ++ ++ // Are the counters registers cleared when read? Is that what the cntr_rst bit on the pmcr register does? ++ } ++ ++ // Clear the PMU snapshot status ++ writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_CLR); ++ ++ if (buffer) ++ *buffer = gator_events_ccn504_buffer; ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_ccn504_interface = { ++ .shutdown = gator_events_ccn504_create_shutdown, ++ .create_files = gator_events_ccn504_create_files, ++ .start = gator_events_ccn504_start, ++ .stop = gator_events_ccn504_stop, ++ .read = gator_events_ccn504_read, ++}; ++ ++int gator_events_ccn504_init(void) ++{ ++ int i; ++ ++ if (ccn504_addr == 0) { ++ return -1; ++ } ++ ++ gator_events_ccn504_base = ioremap(ccn504_addr, NUM_REGIONS*REGION_SIZE); ++ if (gator_events_ccn504_base == NULL) { ++ printk(KERN_ERR "gator: ioremap returned NULL\n"); ++ return -1; ++ } ++ ++ for (i = 0; i < CNTMAX; ++i) { ++ gator_events_ccn504_enabled[i] = 0; ++ gator_events_ccn504_event[i] = 0; ++ gator_events_ccn504_key[i] = gator_events_get_key(); ++ } ++ ++ return gator_events_install(&gator_events_ccn504_interface); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_irq.c linux-3.10.30-cubox-i/drivers/gator/gator_events_irq.c +--- linux-3.10.30/drivers/gator/gator_events_irq.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_irq.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,165 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++#include ++ ++#define HARDIRQ 0 ++#define SOFTIRQ 1 ++#define TOTALIRQ (SOFTIRQ+1) ++ ++static ulong hardirq_enabled; ++static ulong softirq_enabled; ++static ulong hardirq_key; ++static ulong softirq_key; ++static DEFINE_PER_CPU(atomic_t[TOTALIRQ], irqCnt); ++static DEFINE_PER_CPU(int[TOTALIRQ * 2], irqGet); ++ ++GATOR_DEFINE_PROBE(irq_handler_exit, ++ TP_PROTO(int irq, struct irqaction *action, int ret)) ++{ ++ atomic_inc(&per_cpu(irqCnt, get_physical_cpu())[HARDIRQ]); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) ++GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(struct softirq_action *h, struct softirq_action *vec)) ++#else ++GATOR_DEFINE_PROBE(softirq_exit, TP_PROTO(unsigned int vec_nr)) ++#endif ++{ ++ atomic_inc(&per_cpu(irqCnt, get_physical_cpu())[SOFTIRQ]); ++} ++ ++static int gator_events_irq_create_files(struct super_block *sb, struct dentry *root) ++{ ++ struct dentry *dir; ++ ++ /* irq */ ++ dir = gatorfs_mkdir(sb, root, "Linux_irq_irq"); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &hardirq_enabled); ++ gatorfs_create_ro_ulong(sb, dir, "key", &hardirq_key); ++ ++ /* soft irq */ ++ dir = gatorfs_mkdir(sb, root, "Linux_irq_softirq"); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &softirq_enabled); ++ gatorfs_create_ro_ulong(sb, dir, "key", &softirq_key); ++ ++ return 0; ++} ++ ++static int gator_events_irq_online(int **buffer, bool migrate) ++{ ++ int len = 0, cpu = get_physical_cpu(); ++ ++ // synchronization with the irq_exit functions is not necessary as the values are being reset ++ if (hardirq_enabled) { ++ atomic_set(&per_cpu(irqCnt, cpu)[HARDIRQ], 0); ++ per_cpu(irqGet, cpu)[len++] = hardirq_key; ++ per_cpu(irqGet, cpu)[len++] = 0; ++ } ++ ++ if (softirq_enabled) { ++ atomic_set(&per_cpu(irqCnt, cpu)[SOFTIRQ], 0); ++ per_cpu(irqGet, cpu)[len++] = softirq_key; ++ per_cpu(irqGet, cpu)[len++] = 0; ++ } ++ ++ if (buffer) ++ *buffer = per_cpu(irqGet, cpu); ++ ++ return len; ++} ++ ++static int gator_events_irq_start(void) ++{ ++ // register tracepoints ++ if (hardirq_enabled) ++ if (GATOR_REGISTER_TRACE(irq_handler_exit)) ++ goto fail_hardirq_exit; ++ if (softirq_enabled) ++ if (GATOR_REGISTER_TRACE(softirq_exit)) ++ goto fail_softirq_exit; ++ pr_debug("gator: registered irq tracepoints\n"); ++ ++ return 0; ++ ++ // unregister tracepoints on error ++fail_softirq_exit: ++ if (hardirq_enabled) ++ GATOR_UNREGISTER_TRACE(irq_handler_exit); ++fail_hardirq_exit: ++ pr_err("gator: irq tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); ++ ++ return -1; ++} ++ ++static void gator_events_irq_stop(void) ++{ ++ if (hardirq_enabled) ++ GATOR_UNREGISTER_TRACE(irq_handler_exit); ++ if (softirq_enabled) ++ GATOR_UNREGISTER_TRACE(softirq_exit); ++ pr_debug("gator: unregistered irq tracepoints\n"); ++ ++ hardirq_enabled = 0; ++ softirq_enabled = 0; ++} ++ ++static int gator_events_irq_read(int **buffer) ++{ ++ int len, value; ++ int cpu = get_physical_cpu(); ++ ++ len = 0; ++ if (hardirq_enabled) { ++ value = atomic_read(&per_cpu(irqCnt, cpu)[HARDIRQ]); ++ atomic_sub(value, &per_cpu(irqCnt, cpu)[HARDIRQ]); ++ ++ per_cpu(irqGet, cpu)[len++] = hardirq_key; ++ per_cpu(irqGet, cpu)[len++] = value; ++ } ++ ++ if (softirq_enabled) { ++ value = atomic_read(&per_cpu(irqCnt, cpu)[SOFTIRQ]); ++ atomic_sub(value, &per_cpu(irqCnt, cpu)[SOFTIRQ]); ++ ++ per_cpu(irqGet, cpu)[len++] = softirq_key; ++ per_cpu(irqGet, cpu)[len++] = value; ++ } ++ ++ if (buffer) ++ *buffer = per_cpu(irqGet, cpu); ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_irq_interface = { ++ .create_files = gator_events_irq_create_files, ++ .online = gator_events_irq_online, ++ .start = gator_events_irq_start, ++ .stop = gator_events_irq_stop, ++ .read = gator_events_irq_read, ++}; ++ ++int gator_events_irq_init(void) ++{ ++ hardirq_key = gator_events_get_key(); ++ softirq_key = gator_events_get_key(); ++ ++ hardirq_enabled = 0; ++ softirq_enabled = 0; ++ ++ return gator_events_install(&gator_events_irq_interface); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_l2c-310.c linux-3.10.30-cubox-i/drivers/gator/gator_events_l2c-310.c +--- linux-3.10.30/drivers/gator/gator_events_l2c-310.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_l2c-310.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,208 @@ ++/** ++ * l2c310 (L2 Cache Controller) event counters for gator ++ * ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 ++#if defined(CONFIG_OF) ++#include ++#include ++#endif ++#include ++ ++#include "gator.h" ++ ++#define L2C310_COUNTERS_NUM 2 ++ ++static struct { ++ unsigned long enabled; ++ unsigned long event; ++ unsigned long key; ++} l2c310_counters[L2C310_COUNTERS_NUM]; ++ ++static int l2c310_buffer[L2C310_COUNTERS_NUM * 2]; ++ ++static void __iomem *l2c310_base; ++ ++static void gator_events_l2c310_reset_counters(void) ++{ ++ u32 val = readl(l2c310_base + L2X0_EVENT_CNT_CTRL); ++ ++ val |= ((1 << L2C310_COUNTERS_NUM) - 1) << 1; ++ ++ writel(val, l2c310_base + L2X0_EVENT_CNT_CTRL); ++} ++ ++static int gator_events_l2c310_create_files(struct super_block *sb, ++ struct dentry *root) ++{ ++ int i; ++ ++ for (i = 0; i < L2C310_COUNTERS_NUM; i++) { ++ char buf[16]; ++ struct dentry *dir; ++ ++ snprintf(buf, sizeof(buf), "L2C-310_cnt%d", i); ++ dir = gatorfs_mkdir(sb, root, buf); ++ if (WARN_ON(!dir)) ++ return -1; ++ gatorfs_create_ulong(sb, dir, "enabled", ++ &l2c310_counters[i].enabled); ++ gatorfs_create_ulong(sb, dir, "event", ++ &l2c310_counters[i].event); ++ gatorfs_create_ro_ulong(sb, dir, "key", ++ &l2c310_counters[i].key); ++ } ++ ++ return 0; ++} ++ ++static int gator_events_l2c310_start(void) ++{ ++ static const unsigned long l2x0_event_cntx_cfg[L2C310_COUNTERS_NUM] = { ++ L2X0_EVENT_CNT0_CFG, ++ L2X0_EVENT_CNT1_CFG, ++ }; ++ int i; ++ ++ /* Counter event sources */ ++ for (i = 0; i < L2C310_COUNTERS_NUM; i++) ++ writel((l2c310_counters[i].event & 0xf) << 2, ++ l2c310_base + l2x0_event_cntx_cfg[i]); ++ ++ gator_events_l2c310_reset_counters(); ++ ++ /* Event counter enable */ ++ writel(1, l2c310_base + L2X0_EVENT_CNT_CTRL); ++ ++ return 0; ++} ++ ++static void gator_events_l2c310_stop(void) ++{ ++ /* Event counter disable */ ++ writel(0, l2c310_base + L2X0_EVENT_CNT_CTRL); ++} ++ ++static int gator_events_l2c310_read(int **buffer) ++{ ++ static const unsigned long l2x0_event_cntx_val[L2C310_COUNTERS_NUM] = { ++ L2X0_EVENT_CNT0_VAL, ++ L2X0_EVENT_CNT1_VAL, ++ }; ++ int i; ++ int len = 0; ++ ++ if (!on_primary_core()) ++ return 0; ++ ++ for (i = 0; i < L2C310_COUNTERS_NUM; i++) { ++ if (l2c310_counters[i].enabled) { ++ l2c310_buffer[len++] = l2c310_counters[i].key; ++ l2c310_buffer[len++] = readl(l2c310_base + ++ l2x0_event_cntx_val[i]); ++ } ++ } ++ ++ /* l2c310 counters are saturating, not wrapping in case of overflow */ ++ gator_events_l2c310_reset_counters(); ++ ++ if (buffer) ++ *buffer = l2c310_buffer; ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_l2c310_interface = { ++ .create_files = gator_events_l2c310_create_files, ++ .start = gator_events_l2c310_start, ++ .stop = gator_events_l2c310_stop, ++ .read = gator_events_l2c310_read, ++}; ++ ++#define L2C310_ADDR_PROBE (~0) ++ ++MODULE_PARM_DESC(l2c310_addr, "L2C310 physical base address (0 to disable)"); ++static unsigned long l2c310_addr = L2C310_ADDR_PROBE; ++module_param(l2c310_addr, ulong, 0444); ++ ++static void __iomem *gator_events_l2c310_probe(void) ++{ ++ phys_addr_t variants[] = { ++#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_S5PV310) ++ 0x10502000, ++#endif ++#if defined(CONFIG_ARCH_OMAP4) ++ 0x48242000, ++#endif ++#if defined(CONFIG_ARCH_TEGRA) ++ 0x50043000, ++#endif ++#if defined(CONFIG_ARCH_U8500) ++ 0xa0412000, ++#endif ++#if defined(CONFIG_ARCH_VEXPRESS) ++ 0x1e00a000, // A9x4 core tile (HBI-0191) ++ 0x2c0f0000, // New memory map tiles ++#endif ++ }; ++ int i; ++ void __iomem *base; ++#if defined(CONFIG_OF) ++ struct device_node *node = of_find_all_nodes(NULL); ++ ++ if (node) { ++ of_node_put(node); ++ ++ node = of_find_compatible_node(NULL, NULL, "arm,pl310-cache"); ++ base = of_iomap(node, 0); ++ of_node_put(node); ++ ++ return base; ++ } ++#endif ++ ++ for (i = 0; i < ARRAY_SIZE(variants); i++) { ++ base = ioremap(variants[i], SZ_4K); ++ if (base) { ++ u32 cache_id = readl(base + L2X0_CACHE_ID); ++ ++ if ((cache_id & 0xff0003c0) == 0x410000c0) ++ return base; ++ ++ iounmap(base); ++ } ++ } ++ ++ return NULL; ++} ++ ++int gator_events_l2c310_init(void) ++{ ++ int i; ++ ++ if (gator_cpuid() != CORTEX_A5 && gator_cpuid() != CORTEX_A9) ++ return -1; ++ ++ if (l2c310_addr == L2C310_ADDR_PROBE) ++ l2c310_base = gator_events_l2c310_probe(); ++ else if (l2c310_addr) ++ l2c310_base = ioremap(l2c310_addr, SZ_4K); ++ ++ if (!l2c310_base) ++ return -1; ++ ++ for (i = 0; i < L2C310_COUNTERS_NUM; i++) { ++ l2c310_counters[i].enabled = 0; ++ l2c310_counters[i].key = gator_events_get_key(); ++ } ++ ++ return gator_events_install(&gator_events_l2c310_interface); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_mali_4xx.c linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_4xx.c +--- linux-3.10.30/drivers/gator/gator_events_mali_4xx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_4xx.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,723 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++ ++#include ++#include ++#include ++ ++#include "linux/mali_linux_trace.h" ++ ++#include "gator_events_mali_common.h" ++#include "gator_events_mali_4xx.h" ++ ++/* ++ * There are (currently) four different variants of the comms between gator and Mali: ++ * 1 (deprecated): No software counter support ++ * 2 (deprecated): Tracepoint called for each separate s/w counter value as it appears ++ * 3 (default): Single tracepoint for all s/w counters in a bundle. ++ * Interface style 3 is the default if no other is specified. 1 and 2 will be eliminated when ++ * existing Mali DDKs are upgraded. ++ * 4. As above, but for the Utgard (Mali-450) driver. ++ */ ++ ++#if !defined(GATOR_MALI_INTERFACE_STYLE) ++#define GATOR_MALI_INTERFACE_STYLE (3) ++#endif ++ ++#if GATOR_MALI_INTERFACE_STYLE < 4 ++#include "mali/mali_mjollnir_profiling_gator_api.h" ++#else ++#include "mali/mali_utgard_profiling_gator_api.h" ++#endif ++ ++/* ++ * Check that the MALI_SUPPORT define is set to one of the allowable device codes. ++ */ ++#if (MALI_SUPPORT != MALI_4xx) ++#error MALI_SUPPORT set to an invalid device code: expecting MALI_4xx ++#endif ++ ++/* gatorfs variables for counter enable state, ++ * the event the counter should count and the ++ * 'key' (a unique id set by gatord and returned ++ * by gator.ko) ++ */ ++static unsigned long counter_enabled[NUMBER_OF_EVENTS]; ++static unsigned long counter_event[NUMBER_OF_EVENTS]; ++static unsigned long counter_key[NUMBER_OF_EVENTS]; ++ ++/* The data we have recorded */ ++static u32 counter_data[NUMBER_OF_EVENTS]; ++/* The address to sample (or 0 if samples are sent to us) */ ++static u32 *counter_address[NUMBER_OF_EVENTS]; ++ ++/* An array used to return the data we recorded ++ * as key,value pairs hence the *2 ++ */ ++static unsigned long counter_dump[NUMBER_OF_EVENTS * 2]; ++static unsigned long counter_prev[NUMBER_OF_EVENTS]; ++ ++/* Note whether tracepoints have been registered */ ++static int trace_registered; ++ ++/* ++ * These numbers define the actual numbers of each block type that exist in the system. Initially ++ * these are set to the maxima defined above; if the driver is capable of being queried (newer ++ * drivers only) then the values may be revised. ++ */ ++static unsigned int n_vp_cores = MAX_NUM_VP_CORES; ++static unsigned int n_l2_cores = MAX_NUM_L2_CACHE_CORES; ++static unsigned int n_fp_cores = MAX_NUM_FP_CORES; ++ ++/** ++ * Calculate the difference and handle the overflow. ++ */ ++static u32 get_difference(u32 start, u32 end) ++{ ++ if (start - end >= 0) { ++ return start - end; ++ } ++ ++ // Mali counters are unsigned 32 bit values that wrap. ++ return (4294967295u - end) + start; ++} ++ ++/** ++ * Returns non-zero if the given counter ID is an activity counter. ++ */ ++static inline int is_activity_counter(unsigned int event_id) ++{ ++ return (event_id >= FIRST_ACTIVITY_EVENT && ++ event_id <= LAST_ACTIVITY_EVENT); ++} ++ ++/** ++ * Returns non-zero if the given counter ID is a hardware counter. ++ */ ++static inline int is_hw_counter(unsigned int event_id) ++{ ++ return (event_id >= FIRST_HW_COUNTER && event_id <= LAST_HW_COUNTER); ++} ++ ++/* ++ * These are provided for utgard compatibility. ++ */ ++typedef void _mali_profiling_get_mali_version_type(struct _mali_profiling_mali_version *values); ++typedef u32 _mali_profiling_get_l2_counters_type(_mali_profiling_l2_counter_values *values); ++ ++#if GATOR_MALI_INTERFACE_STYLE == 2 ++/** ++ * Returns non-zero if the given counter ID is a software counter. ++ */ ++static inline int is_sw_counter(unsigned int event_id) ++{ ++ return (event_id >= FIRST_SW_COUNTER && event_id <= LAST_SW_COUNTER); ++} ++#endif ++ ++#if GATOR_MALI_INTERFACE_STYLE == 2 ++/* ++ * The Mali DDK uses s64 types to contain software counter values, but gator ++ * can only use a maximum of 32 bits. This function scales a software counter ++ * to an appropriate range. ++ */ ++static u32 scale_sw_counter_value(unsigned int event_id, signed long long value) ++{ ++ u32 scaled_value; ++ ++ switch (event_id) { ++ case COUNTER_GLES_UPLOAD_TEXTURE_TIME: ++ case COUNTER_GLES_UPLOAD_VBO_TIME: ++ scaled_value = (u32)div_s64(value, 1000000); ++ break; ++ default: ++ scaled_value = (u32)value; ++ break; ++ } ++ ++ return scaled_value; ++} ++#endif ++ ++/* Probe for continuously sampled counter */ ++#if 0 //WE_DONT_CURRENTLY_USE_THIS_SO_SUPPRESS_WARNING ++GATOR_DEFINE_PROBE(mali_sample_address, TP_PROTO(unsigned int event_id, u32 *addr)) ++{ ++ /* Turning on too many pr_debug statements in frequently called functions ++ * can cause stability and/or performance problems ++ */ ++ //pr_debug("gator: mali_sample_address %d %d\n", event_id, addr); ++ if (event_id >= ACTIVITY_VP && event_id <= COUNTER_FP3_C1) { ++ counter_address[event_id] = addr; ++ } ++} ++#endif ++ ++/* Probe for hardware counter events */ ++GATOR_DEFINE_PROBE(mali_hw_counter, TP_PROTO(unsigned int event_id, unsigned int value)) ++{ ++ /* Turning on too many pr_debug statements in frequently called functions ++ * can cause stability and/or performance problems ++ */ ++ //pr_debug("gator: mali_hw_counter %d %d\n", event_id, value); ++ if (is_hw_counter(event_id)) { ++ counter_data[event_id] = value; ++ } ++} ++ ++#if GATOR_MALI_INTERFACE_STYLE == 2 ++GATOR_DEFINE_PROBE(mali_sw_counter, TP_PROTO(unsigned int event_id, signed long long value)) ++{ ++ if (is_sw_counter(event_id)) { ++ counter_data[event_id] = scale_sw_counter_value(event_id, value); ++ } ++} ++#endif /* GATOR_MALI_INTERFACE_STYLE == 2 */ ++ ++#if GATOR_MALI_INTERFACE_STYLE >= 3 ++GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surface_id, unsigned int *counters)) ++{ ++ u32 i; ++ ++ /* Copy over the values for those counters which are enabled. */ ++ for (i = FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++) { ++ if (counter_enabled[i]) { ++ counter_data[i] = (u32)(counters[i - FIRST_SW_COUNTER]); ++ } ++ } ++} ++#endif /* GATOR_MALI_INTERFACE_STYLE >= 3 */ ++ ++/** ++ * Create a single filesystem entry for a specified event. ++ * @param sb the superblock ++ * @param root Filesystem root ++ * @param name The name of the entry to create ++ * @param event The ID of the event ++ * @param create_event_item boolean indicating whether to create an 'event' filesystem entry. True to create. ++ * ++ * @return 0 if ok, non-zero if the create failed. ++ */ ++static int create_fs_entry(struct super_block *sb, struct dentry *root, const char *name, int event, int create_event_item) ++{ ++ struct dentry *dir; ++ ++ dir = gatorfs_mkdir(sb, root, name); ++ ++ if (!dir) { ++ return -1; ++ } ++ ++ if (create_event_item) { ++ gatorfs_create_ulong(sb, dir, "event", &counter_event[event]); ++ } ++ ++ gatorfs_create_ulong(sb, dir, "enabled", &counter_enabled[event]); ++ gatorfs_create_ro_ulong(sb, dir, "key", &counter_key[event]); ++ ++ return 0; ++} ++ ++#if GATOR_MALI_INTERFACE_STYLE > 3 ++/* ++ * Read the version info structure if available ++ */ ++static void initialise_version_info(void) ++{ ++ _mali_profiling_get_mali_version_type *mali_profiling_get_mali_version_symbol; ++ ++ mali_profiling_get_mali_version_symbol = symbol_get(_mali_profiling_get_mali_version); ++ ++ if (mali_profiling_get_mali_version_symbol) { ++ struct _mali_profiling_mali_version version_info; ++ ++ pr_debug("gator: mali online _mali_profiling_get_mali_version symbol @ %p\n", ++ mali_profiling_get_mali_version_symbol); ++ ++ /* ++ * Revise the number of each different core type using information derived from the DDK. ++ */ ++ mali_profiling_get_mali_version_symbol(&version_info); ++ ++ n_fp_cores = version_info.num_of_fp_cores; ++ n_vp_cores = version_info.num_of_vp_cores; ++ n_l2_cores = version_info.num_of_l2_cores; ++ ++ /* Release the function - we're done with it. */ ++ symbol_put(_mali_profiling_get_mali_version); ++ } else { ++ printk("gator: mali online _mali_profiling_get_mali_version symbol not found\n"); ++ } ++} ++#endif ++ ++static int create_files(struct super_block *sb, struct dentry *root) ++{ ++ int event; ++ const char *mali_name = gator_mali_get_mali_name(); ++ ++ char buf[40]; ++ int core_id; ++ int counter_number; ++ ++ pr_debug("gator: Initialising counters with style = %d\n", GATOR_MALI_INTERFACE_STYLE); ++ ++#if GATOR_MALI_INTERFACE_STYLE > 3 ++ /* ++ * Initialise first: this sets up the number of cores available (on compatible DDK versions). ++ * Ideally this would not need guarding but other parts of the code depend on the interface style being set ++ * correctly; if it is not then the system can enter an inconsistent state. ++ */ ++ initialise_version_info(); ++#endif ++ ++ /* Vertex processor counters */ ++ for (core_id = 0; core_id < n_vp_cores; core_id++) { ++ int activity_counter_id = ACTIVITY_VP_0; ++ snprintf(buf, sizeof buf, "ARM_%s_VP_%d_active", mali_name, core_id); ++ if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) { ++ return -1; ++ } ++ ++ for (counter_number = 0; counter_number < 2; counter_number++) { ++ int counter_id = COUNTER_VP_0_C0 + (2 * core_id) + counter_number; ++ ++ snprintf(buf, sizeof buf, "ARM_%s_VP_%d_cnt%d", mali_name, core_id, counter_number); ++ if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) { ++ return -1; ++ } ++ } ++ } ++ ++ /* Fragment processors' counters */ ++ for (core_id = 0; core_id < n_fp_cores; core_id++) { ++ int activity_counter_id = ACTIVITY_FP_0 + core_id; ++ ++ snprintf(buf, sizeof buf, "ARM_%s_FP_%d_active", mali_name, core_id); ++ if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) { ++ return -1; ++ } ++ ++ for (counter_number = 0; counter_number < 2; counter_number++) { ++ int counter_id = COUNTER_FP_0_C0 + (2 * core_id) + counter_number; ++ ++ snprintf(buf, sizeof buf, "ARM_%s_FP_%d_cnt%d", mali_name, core_id, counter_number); ++ if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) { ++ return -1; ++ } ++ } ++ } ++ ++ /* L2 Cache counters */ ++ for (core_id = 0; core_id < n_l2_cores; core_id++) { ++ for (counter_number = 0; counter_number < 2; counter_number++) { ++ int counter_id = COUNTER_L2_0_C0 + (2 * core_id) + counter_number; ++ ++ snprintf(buf, sizeof buf, "ARM_%s_L2_%d_cnt%d", mali_name, core_id, counter_number); ++ if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) { ++ return -1; ++ } ++ } ++ } ++ ++ /* Now set up the software counter entries */ ++ for (event = FIRST_SW_COUNTER; event <= LAST_SW_COUNTER; event++) { ++ snprintf(buf, sizeof(buf), "ARM_%s_SW_%d", mali_name, event - FIRST_SW_COUNTER); ++ ++ if (create_fs_entry(sb, root, buf, event, 0) != 0) { ++ return -1; ++ } ++ } ++ ++ /* Now set up the special counter entries */ ++ snprintf(buf, sizeof(buf), "ARM_%s_Filmstrip_cnt0", mali_name); ++ if (create_fs_entry(sb, root, buf, COUNTER_FILMSTRIP, 1) != 0) { ++ return -1; ++ } ++ ++#ifdef DVFS_REPORTED_BY_DDK ++ snprintf(buf, sizeof(buf), "ARM_%s_Frequency", mali_name); ++ if (create_fs_entry(sb, root, buf, COUNTER_FREQUENCY, 1) != 0) { ++ return -1; ++ } ++ ++ snprintf(buf, sizeof(buf), "ARM_%s_Voltage", mali_name); ++ if (create_fs_entry(sb, root, buf, COUNTER_VOLTAGE, 1) != 0) { ++ return -1; ++ } ++#endif ++ ++ return 0; ++} ++ ++/* ++ * Local store for the get_counters entry point into the DDK. ++ * This is stored here since it is used very regularly. ++ */ ++static mali_profiling_get_counters_type *mali_get_counters = NULL; ++static _mali_profiling_get_l2_counters_type *mali_get_l2_counters = NULL; ++ ++/* ++ * Examine list of counters between two index limits and determine if any one is enabled. ++ * Returns 1 if any counter is enabled, 0 if none is. ++ */ ++static int is_any_counter_enabled(unsigned int first_counter, unsigned int last_counter) ++{ ++ unsigned int i; ++ ++ for (i = first_counter; i <= last_counter; i++) { ++ if (counter_enabled[i]) { ++ return 1; /* At least one counter is enabled */ ++ } ++ } ++ ++ return 0; /* No s/w counters enabled */ ++} ++ ++static void init_counters(unsigned int from_counter, unsigned int to_counter) ++{ ++ unsigned int counter_id; ++ ++ /* If a Mali driver is present and exporting the appropriate symbol ++ * then we can request the HW counters (of which there are only 2) ++ * be configured to count the desired events ++ */ ++ mali_profiling_set_event_type *mali_set_hw_event; ++ ++ mali_set_hw_event = symbol_get(_mali_profiling_set_event); ++ ++ if (mali_set_hw_event) { ++ pr_debug("gator: mali online _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event); ++ ++ for (counter_id = from_counter; counter_id <= to_counter; counter_id++) { ++ if (counter_enabled[counter_id]) { ++ mali_set_hw_event(counter_id, counter_event[counter_id]); ++ } else { ++ mali_set_hw_event(counter_id, 0xFFFFFFFF); ++ } ++ } ++ ++ symbol_put(_mali_profiling_set_event); ++ } else { ++ printk("gator: mali online _mali_profiling_set_event symbol not found\n"); ++ } ++} ++ ++static void mali_counter_initialize(void) ++{ ++ int i; ++ int core_id; ++ ++ mali_profiling_control_type *mali_control; ++ ++ init_counters(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores) - 1); ++ init_counters(COUNTER_VP_0_C0, COUNTER_VP_0_C0 + (2 * n_vp_cores) - 1); ++ init_counters(COUNTER_FP_0_C0, COUNTER_FP_0_C0 + (2 * n_fp_cores) - 1); ++ ++ /* Generic control interface for Mali DDK. */ ++ mali_control = symbol_get(_mali_profiling_control); ++ if (mali_control) { ++ /* The event attribute in the XML file keeps the actual frame rate. */ ++ unsigned int rate = counter_event[COUNTER_FILMSTRIP] & 0xff; ++ unsigned int resize_factor = (counter_event[COUNTER_FILMSTRIP] >> 8) & 0xff; ++ ++ pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control); ++ ++ mali_control(SW_COUNTER_ENABLE, (is_any_counter_enabled(FIRST_SW_COUNTER, LAST_SW_COUNTER) ? 1 : 0)); ++ mali_control(FBDUMP_CONTROL_ENABLE, (counter_enabled[COUNTER_FILMSTRIP] ? 1 : 0)); ++ mali_control(FBDUMP_CONTROL_RATE, rate); ++ mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor); ++ ++ pr_debug("gator: sent mali_control enabled=%d, rate=%d\n", (counter_enabled[COUNTER_FILMSTRIP] ? 1 : 0), rate); ++ ++ symbol_put(_mali_profiling_control); ++ } else { ++ printk("gator: mali online _mali_profiling_control symbol not found\n"); ++ } ++ ++ mali_get_counters = symbol_get(_mali_profiling_get_counters); ++ if (mali_get_counters) { ++ pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", mali_get_counters); ++ ++ } else { ++ pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined"); ++ } ++ ++ mali_get_l2_counters = symbol_get(_mali_profiling_get_l2_counters); ++ if (mali_get_l2_counters) { ++ pr_debug("gator: mali online _mali_profiling_get_l2_counters symbol @ %p\n", mali_get_l2_counters); ++ ++ } else { ++ pr_debug("gator WARNING: mali _mali_profiling_get_l2_counters symbol not defined"); ++ } ++ ++ if (!mali_get_counters && !mali_get_l2_counters) { ++ pr_debug("gator: WARNING: no L2 counters available"); ++ n_l2_cores = 0; ++ } ++ ++ for (core_id = 0; core_id < n_l2_cores; core_id++) { ++ int counter_id = COUNTER_L2_0_C0 + (2 * core_id); ++ counter_prev[counter_id] = 0; ++ counter_prev[counter_id + 1] = 0; ++ } ++ ++ /* Clear counters in the start */ ++ for (i = 0; i < NUMBER_OF_EVENTS; i++) { ++ counter_data[i] = 0; ++ } ++} ++ ++static void mali_counter_deinitialize(void) ++{ ++ mali_profiling_set_event_type *mali_set_hw_event; ++ mali_profiling_control_type *mali_control; ++ ++ mali_set_hw_event = symbol_get(_mali_profiling_set_event); ++ ++ if (mali_set_hw_event) { ++ int i; ++ ++ pr_debug("gator: mali offline _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event); ++ for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++) { ++ mali_set_hw_event(i, 0xFFFFFFFF); ++ } ++ ++ symbol_put(_mali_profiling_set_event); ++ } else { ++ printk("gator: mali offline _mali_profiling_set_event symbol not found\n"); ++ } ++ ++ /* Generic control interface for Mali DDK. */ ++ mali_control = symbol_get(_mali_profiling_control); ++ ++ if (mali_control) { ++ pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_control); ++ ++ /* Reset the DDK state - disable counter collection */ ++ mali_control(SW_COUNTER_ENABLE, 0); ++ ++ mali_control(FBDUMP_CONTROL_ENABLE, 0); ++ ++ symbol_put(_mali_profiling_control); ++ } else { ++ printk("gator: mali offline _mali_profiling_control symbol not found\n"); ++ } ++ ++ if (mali_get_counters) { ++ symbol_put(_mali_profiling_get_counters); ++ } ++ ++ if (mali_get_l2_counters) { ++ symbol_put(_mali_profiling_get_l2_counters); ++ } ++} ++ ++static int start(void) ++{ ++ // register tracepoints ++ if (GATOR_REGISTER_TRACE(mali_hw_counter)) { ++ printk("gator: mali_hw_counter tracepoint failed to activate\n"); ++ return -1; ++ } ++ ++#if GATOR_MALI_INTERFACE_STYLE == 1 ++ /* None. */ ++#elif GATOR_MALI_INTERFACE_STYLE == 2 ++ /* For patched Mali driver. */ ++ if (GATOR_REGISTER_TRACE(mali_sw_counter)) { ++ printk("gator: mali_sw_counter tracepoint failed to activate\n"); ++ return -1; ++ } ++#elif GATOR_MALI_INTERFACE_STYLE >= 3 ++ /* For Mali drivers with built-in support. */ ++ if (GATOR_REGISTER_TRACE(mali_sw_counters)) { ++ printk("gator: mali_sw_counters tracepoint failed to activate\n"); ++ return -1; ++ } ++#else ++#error Unknown GATOR_MALI_INTERFACE_STYLE option. ++#endif ++ ++ trace_registered = 1; ++ ++ mali_counter_initialize(); ++ return 0; ++} ++ ++static void stop(void) ++{ ++ unsigned int cnt; ++ ++ pr_debug("gator: mali stop\n"); ++ ++ if (trace_registered) { ++ GATOR_UNREGISTER_TRACE(mali_hw_counter); ++ ++#if GATOR_MALI_INTERFACE_STYLE == 1 ++ /* None. */ ++#elif GATOR_MALI_INTERFACE_STYLE == 2 ++ /* For patched Mali driver. */ ++ GATOR_UNREGISTER_TRACE(mali_sw_counter); ++#elif GATOR_MALI_INTERFACE_STYLE >= 3 ++ /* For Mali drivers with built-in support. */ ++ GATOR_UNREGISTER_TRACE(mali_sw_counters); ++#else ++#error Unknown GATOR_MALI_INTERFACE_STYLE option. ++#endif ++ ++ pr_debug("gator: mali timeline tracepoint deactivated\n"); ++ ++ trace_registered = 0; ++ } ++ ++ for (cnt = 0; cnt < NUMBER_OF_EVENTS; cnt++) { ++ counter_enabled[cnt] = 0; ++ counter_event[cnt] = 0; ++ counter_address[cnt] = NULL; ++ } ++ ++ mali_counter_deinitialize(); ++} ++ ++static void dump_counters(unsigned int from_counter, unsigned int to_counter, unsigned int *len) ++{ ++ unsigned int counter_id; ++ ++ for (counter_id = from_counter; counter_id <= to_counter; counter_id++) { ++ if (counter_enabled[counter_id]) { ++ counter_dump[(*len)++] = counter_key[counter_id]; ++ counter_dump[(*len)++] = counter_data[counter_id]; ++ ++ counter_data[counter_id] = 0; ++ } ++ } ++} ++ ++static int read(int **buffer) ++{ ++ int len = 0; ++ ++ if (!on_primary_core()) ++ return 0; ++ ++ // Read the L2 C0 and C1 here. ++ if (n_l2_cores > 0 && is_any_counter_enabled(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores))) { ++ unsigned int unavailable_l2_caches = 0; ++ _mali_profiling_l2_counter_values cache_values; ++ unsigned int cache_id; ++ struct _mali_profiling_core_counters *per_core; ++ ++ /* Poke the driver to get the counter values - older style; only one L2 cache */ ++ if (mali_get_l2_counters) { ++ unavailable_l2_caches = mali_get_l2_counters(&cache_values); ++ } else if (mali_get_counters) { ++ per_core = &cache_values.cores[0]; ++ mali_get_counters(&per_core->source0, &per_core->value0, &per_core->source1, &per_core->value1); ++ } else { ++ /* This should never happen, as n_l2_caches is only set > 0 if one of the above functions is found. */ ++ } ++ ++ /* Fill in the two cache counter values for each cache block. */ ++ for (cache_id = 0; cache_id < n_l2_cores; cache_id++) { ++ unsigned int counter_id_0 = COUNTER_L2_0_C0 + (2 * cache_id); ++ unsigned int counter_id_1 = counter_id_0 + 1; ++ ++ if ((1 << cache_id) & unavailable_l2_caches) { ++ continue; /* This cache is unavailable (powered-off, possibly). */ ++ } ++ ++ per_core = &cache_values.cores[cache_id]; ++ ++ if (counter_enabled[counter_id_0]) { ++ // Calculate and save src0's counter val0 ++ counter_dump[len++] = counter_key[counter_id_0]; ++ counter_dump[len++] = get_difference(per_core->value0, counter_prev[counter_id_0]); ++ } ++ ++ if (counter_enabled[counter_id_1]) { ++ // Calculate and save src1's counter val1 ++ counter_dump[len++] = counter_key[counter_id_1]; ++ counter_dump[len++] = get_difference(per_core->value1, counter_prev[counter_id_1]); ++ } ++ ++ // Save the previous values for the counters. ++ counter_prev[counter_id_0] = per_core->value0; ++ counter_prev[counter_id_1] = per_core->value1; ++ } ++ } ++ ++ /* Process other (non-timeline) counters. */ ++ dump_counters(COUNTER_VP_0_C0, COUNTER_VP_0_C0 + (2 * n_vp_cores) - 1, &len); ++ dump_counters(COUNTER_FP_0_C0, COUNTER_FP_0_C0 + (2 * n_fp_cores) - 1, &len); ++ ++ dump_counters(FIRST_SW_COUNTER, LAST_SW_COUNTER, &len); ++ ++#ifdef DVFS_REPORTED_BY_DDK ++ { ++ int cnt; ++ /* ++ * Add in the voltage and frequency counters if enabled. Note that, since these are ++ * actually passed as events, the counter value should not be cleared. ++ */ ++ cnt = COUNTER_FREQUENCY; ++ if (counter_enabled[cnt]) { ++ counter_dump[len++] = counter_key[cnt]; ++ counter_dump[len++] = counter_data[cnt]; ++ } ++ ++ cnt = COUNTER_VOLTAGE; ++ if (counter_enabled[cnt]) { ++ counter_dump[len++] = counter_key[cnt]; ++ counter_dump[len++] = counter_data[cnt]; ++ } ++ } ++#endif ++ ++ if (buffer) { ++ *buffer = (int *)counter_dump; ++ } ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_mali_interface = { ++ .create_files = create_files, ++ .start = start, ++ .stop = stop, ++ .read = read, ++}; ++ ++extern void gator_events_mali_log_dvfs_event(unsigned int frequency_mhz, unsigned int voltage_mv) ++{ ++#ifdef DVFS_REPORTED_BY_DDK ++ counter_data[COUNTER_FREQUENCY] = frequency_mhz; ++ counter_data[COUNTER_VOLTAGE] = voltage_mv; ++#endif ++} ++ ++int gator_events_mali_init(void) ++{ ++ unsigned int cnt; ++ ++ pr_debug("gator: mali init\n"); ++ ++ for (cnt = 0; cnt < NUMBER_OF_EVENTS; cnt++) { ++ counter_enabled[cnt] = 0; ++ counter_event[cnt] = 0; ++ counter_key[cnt] = gator_events_get_key(); ++ counter_address[cnt] = NULL; ++ counter_data[cnt] = 0; ++ } ++ ++ trace_registered = 0; ++ ++ return gator_events_install(&gator_events_mali_interface); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_mali_4xx.h linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_4xx.h +--- linux-3.10.30/drivers/gator/gator_events_mali_4xx.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_4xx.h 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,18 @@ ++/** ++ * Copyright (C) ARM Limited 2011-2013. All rights reserved. ++ * ++ * This program 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. ++ * ++ */ ++ ++/* ++ * Header contains common definitions for the Mali-4xx processors. ++ */ ++#if !defined(GATOR_EVENTS_MALI_4xx_H) ++#define GATOR_EVENTS_MALI_4xx_H ++ ++extern void gator_events_mali_log_dvfs_event(unsigned int d0, unsigned int d1); ++ ++#endif /* GATOR_EVENTS_MALI_4xx_H */ +diff -Nur linux-3.10.30/drivers/gator/gator_events_mali_common.c linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_common.c +--- linux-3.10.30/drivers/gator/gator_events_mali_common.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_common.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,81 @@ ++/** ++ * Copyright (C) ARM Limited 2012-2013. All rights reserved. ++ * ++ * This program 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 "gator_events_mali_common.h" ++ ++static u32 gator_mali_get_id(void) ++{ ++ return MALI_SUPPORT; ++} ++ ++extern const char *gator_mali_get_mali_name(void) ++{ ++ u32 id = gator_mali_get_id(); ++ ++ switch (id) { ++ case MALI_T6xx: ++ return "Mali-T6xx"; ++ case MALI_4xx: ++ return "Mali-4xx"; ++ default: ++ pr_debug("gator: Mali-T6xx: unknown Mali ID (%d)\n", id); ++ return "Mali-Unknown"; ++ } ++} ++ ++extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event) ++{ ++ int err; ++ char buf[255]; ++ struct dentry *dir; ++ ++ /* If the counter name is empty ignore it */ ++ if (strlen(event_name) != 0) { ++ /* Set up the filesystem entry for this event. */ ++ snprintf(buf, sizeof(buf), "ARM_%s_%s", mali_name, event_name); ++ ++ dir = gatorfs_mkdir(sb, root, buf); ++ ++ if (dir == NULL) { ++ pr_debug("gator: Mali-T6xx: error creating file system for: %s (%s)", event_name, buf); ++ return -1; ++ } ++ ++ err = gatorfs_create_ulong(sb, dir, "enabled", &counter->enabled); ++ if (err != 0) { ++ pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ulong for: %s (%s)", event_name, buf); ++ return -1; ++ } ++ err = gatorfs_create_ro_ulong(sb, dir, "key", &counter->key); ++ if (err != 0) { ++ pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ro_ulong for: %s (%s)", event_name, buf); ++ return -1; ++ } ++ if (event != NULL) { ++ err = gatorfs_create_ulong(sb, dir, "event", event); ++ if (err != 0) { ++ pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ro_ulong for: %s (%s)", event_name, buf); ++ return -1; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++extern void gator_mali_initialise_counters(mali_counter counters[], unsigned int n_counters) ++{ ++ unsigned int cnt; ++ ++ for (cnt = 0; cnt < n_counters; cnt++) { ++ mali_counter *counter = &counters[cnt]; ++ ++ counter->key = gator_events_get_key(); ++ counter->enabled = 0; ++ } ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_mali_common.h linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_common.h +--- linux-3.10.30/drivers/gator/gator_events_mali_common.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_common.h 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,86 @@ ++/** ++ * Copyright (C) ARM Limited 2012-2013. All rights reserved. ++ * ++ * This program 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. ++ * ++ */ ++ ++#if !defined(GATOR_EVENTS_MALI_COMMON_H) ++#define GATOR_EVENTS_MALI_COMMON_H ++ ++#include "gator.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Device codes for each known GPU */ ++#define MALI_4xx (0x0b07) ++#define MALI_T6xx (0x0056) ++ ++/* Ensure that MALI_SUPPORT has been defined to something. */ ++#ifndef MALI_SUPPORT ++#error MALI_SUPPORT not defined! ++#endif ++ ++/* Values for the supported activity event types */ ++#define ACTIVITY_START (1) ++#define ACTIVITY_STOP (2) ++ ++/* ++ * Runtime state information for a counter. ++ */ ++typedef struct { ++ unsigned long key; /* 'key' (a unique id set by gatord and returned by gator.ko) */ ++ unsigned long enabled; /* counter enable state */ ++} mali_counter; ++ ++/* ++ * Mali-4xx ++ */ ++typedef int mali_profiling_set_event_type(unsigned int, int); ++typedef void mali_profiling_control_type(unsigned int, unsigned int); ++typedef void mali_profiling_get_counters_type(unsigned int *, unsigned int *, unsigned int *, unsigned int *); ++ ++/* ++ * Driver entry points for functions called directly by gator. ++ */ ++extern int _mali_profiling_set_event(unsigned int, int); ++extern void _mali_profiling_control(unsigned int, unsigned int); ++extern void _mali_profiling_get_counters(unsigned int *, unsigned int *, unsigned int *, unsigned int *); ++ ++/** ++ * Returns a name which identifies the GPU type (eg Mali-4xx, Mali-T6xx). ++ * ++ * @return The name as a constant string. ++ */ ++extern const char *gator_mali_get_mali_name(void); ++ ++/** ++ * Creates a filesystem entry under /dev/gator relating to the specified event name and key, and ++ * associate the key/enable values with this entry point. ++ * ++ * @param mali_name A name related to the type of GPU, obtained from a call to gator_mali_get_mali_name() ++ * @param event_name The name of the event. ++ * @param sb Linux super block ++ * @param root Directory under which the entry will be created. ++ * @param counter_key Ptr to location which will be associated with the counter key. ++ * @param counter_enabled Ptr to location which will be associated with the counter enable state. ++ * ++ * @return 0 if entry point was created, non-zero if not. ++ */ ++extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event); ++ ++/** ++ * Initializes the counter array. ++ * ++ * @param keys The array of counters ++ * @param n_counters The number of entries in each of the arrays. ++ */ ++extern void gator_mali_initialise_counters(mali_counter counters[], unsigned int n_counters); ++ ++#endif /* GATOR_EVENTS_MALI_COMMON_H */ +diff -Nur linux-3.10.30/drivers/gator/gator_events_mali_t6xx.c linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_t6xx.c +--- linux-3.10.30/drivers/gator/gator_events_mali_t6xx.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_t6xx.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,560 @@ ++/** ++ * Copyright (C) ARM Limited 2011-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "linux/mali_linux_trace.h" ++ ++#include "gator_events_mali_common.h" ++ ++/* ++ * Check that the MALI_SUPPORT define is set to one of the allowable device codes. ++ */ ++#if (MALI_SUPPORT != MALI_T6xx) ++#error MALI_SUPPORT set to an invalid device code: expecting MALI_T6xx ++#endif ++ ++/* Counters for Mali-T6xx: ++ * ++ * - Timeline events ++ * They are tracepoints, but instead of reporting a number they report a START/STOP event. ++ * They are reported in Streamline as number of microseconds while that particular counter was active. ++ * ++ * - SW counters ++ * They are tracepoints reporting a particular number. ++ * They are accumulated in sw_counter_data array until they are passed to Streamline, then they are zeroed. ++ * ++ * - Accumulators ++ * They are the same as software counters but their value is not zeroed. ++ */ ++ ++/* Timeline (start/stop) activity */ ++static const char *timeline_event_names[] = { ++ "PM_SHADER_0", ++ "PM_SHADER_1", ++ "PM_SHADER_2", ++ "PM_SHADER_3", ++ "PM_SHADER_4", ++ "PM_SHADER_5", ++ "PM_SHADER_6", ++ "PM_SHADER_7", ++ "PM_TILER_0", ++ "PM_L2_0", ++ "PM_L2_1", ++ "MMU_AS_0", ++ "MMU_AS_1", ++ "MMU_AS_2", ++ "MMU_AS_3" ++}; ++ ++enum { ++ PM_SHADER_0 = 0, ++ PM_SHADER_1, ++ PM_SHADER_2, ++ PM_SHADER_3, ++ PM_SHADER_4, ++ PM_SHADER_5, ++ PM_SHADER_6, ++ PM_SHADER_7, ++ PM_TILER_0, ++ PM_L2_0, ++ PM_L2_1, ++ MMU_AS_0, ++ MMU_AS_1, ++ MMU_AS_2, ++ MMU_AS_3 ++}; ++/* The number of shader blocks in the enum above */ ++#define NUM_PM_SHADER (8) ++ ++/* Software Counters */ ++static const char *software_counter_names[] = { ++ "MMU_PAGE_FAULT_0", ++ "MMU_PAGE_FAULT_1", ++ "MMU_PAGE_FAULT_2", ++ "MMU_PAGE_FAULT_3" ++}; ++ ++enum { ++ MMU_PAGE_FAULT_0 = 0, ++ MMU_PAGE_FAULT_1, ++ MMU_PAGE_FAULT_2, ++ MMU_PAGE_FAULT_3 ++}; ++ ++/* Software Counters */ ++static const char *accumulators_names[] = { ++ "TOTAL_ALLOC_PAGES" ++}; ++ ++enum { ++ TOTAL_ALLOC_PAGES = 0 ++}; ++ ++#define FIRST_TIMELINE_EVENT (0) ++#define NUMBER_OF_TIMELINE_EVENTS (sizeof(timeline_event_names) / sizeof(timeline_event_names[0])) ++#define FIRST_SOFTWARE_COUNTER (FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS) ++#define NUMBER_OF_SOFTWARE_COUNTERS (sizeof(software_counter_names) / sizeof(software_counter_names[0])) ++#define FIRST_ACCUMULATOR (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS) ++#define NUMBER_OF_ACCUMULATORS (sizeof(accumulators_names) / sizeof(accumulators_names[0])) ++#define FILMSTRIP (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS) ++#define NUMBER_OF_EVENTS (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS + 1) ++ ++/* ++ * gatorfs variables for counter enable state ++ */ ++static mali_counter counters[NUMBER_OF_EVENTS]; ++static unsigned long filmstrip_event; ++ ++/* An array used to return the data we recorded ++ * as key,value pairs hence the *2 ++ */ ++static unsigned long counter_dump[NUMBER_OF_EVENTS * 2]; ++ ++/* ++ * Array holding counter start times (in ns) for each counter. A zero here ++ * indicates that the activity monitored by this counter is not running. ++ */ ++static struct timespec timeline_event_starttime[NUMBER_OF_TIMELINE_EVENTS]; ++ ++/* The data we have recorded */ ++static unsigned int timeline_data[NUMBER_OF_TIMELINE_EVENTS]; ++static unsigned int sw_counter_data[NUMBER_OF_SOFTWARE_COUNTERS]; ++static unsigned int accumulators_data[NUMBER_OF_ACCUMULATORS]; ++ ++/* Hold the previous timestamp, used to calculate the sample interval. */ ++static struct timespec prev_timestamp; ++ ++/** ++ * Returns the timespan (in microseconds) between the two specified timestamps. ++ * ++ * @param start Ptr to the start timestamp ++ * @param end Ptr to the end timestamp ++ * ++ * @return Number of microseconds between the two timestamps (can be negative if start follows end). ++ */ ++static inline long get_duration_us(const struct timespec *start, const struct timespec *end) ++{ ++ long event_duration_us = (end->tv_nsec - start->tv_nsec) / 1000; ++ event_duration_us += (end->tv_sec - start->tv_sec) * 1000000; ++ ++ return event_duration_us; ++} ++ ++static void record_timeline_event(unsigned int timeline_index, unsigned int type) ++{ ++ struct timespec event_timestamp; ++ struct timespec *event_start = &timeline_event_starttime[timeline_index]; ++ ++ switch (type) { ++ case ACTIVITY_START: ++ /* Get the event time... */ ++ getnstimeofday(&event_timestamp); ++ ++ /* Remember the start time if the activity is not already started */ ++ if (event_start->tv_sec == 0) { ++ *event_start = event_timestamp; /* Structure copy */ ++ } ++ break; ++ ++ case ACTIVITY_STOP: ++ /* if the counter was started... */ ++ if (event_start->tv_sec != 0) { ++ /* Get the event time... */ ++ getnstimeofday(&event_timestamp); ++ ++ /* Accumulate the duration in us */ ++ timeline_data[timeline_index] += get_duration_us(event_start, &event_timestamp); ++ ++ /* Reset the start time to indicate the activity is stopped. */ ++ event_start->tv_sec = 0; ++ } ++ break; ++ ++ default: ++ /* Other activity events are ignored. */ ++ break; ++ } ++} ++ ++/* ++ * Documentation about the following tracepoints is in mali_linux_trace.h ++ */ ++ ++GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long long value)) ++{ ++#define SHADER_PRESENT_LO 0x100 /* (RO) Shader core present bitmap, low word */ ++#define TILER_PRESENT_LO 0x110 /* (RO) Tiler core present bitmap, low word */ ++#define L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */ ++#define BIT_AT(value, pos) ((value >> pos) & 1) ++ ++ static unsigned long long previous_shader_bitmask = 0; ++ static unsigned long long previous_tiler_bitmask = 0; ++ static unsigned long long previous_l2_bitmask = 0; ++ ++ switch (event_id) { ++ case SHADER_PRESENT_LO: ++ { ++ unsigned long long changed_bitmask = previous_shader_bitmask ^ value; ++ int pos; ++ ++ for (pos = 0; pos < NUM_PM_SHADER; ++pos) { ++ if (BIT_AT(changed_bitmask, pos)) { ++ record_timeline_event(PM_SHADER_0 + pos, BIT_AT(value, pos) ? ACTIVITY_START : ACTIVITY_STOP); ++ } ++ } ++ ++ previous_shader_bitmask = value; ++ break; ++ } ++ ++ case TILER_PRESENT_LO: ++ { ++ unsigned long long changed = previous_tiler_bitmask ^ value; ++ ++ if (BIT_AT(changed, 0)) { ++ record_timeline_event(PM_TILER_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP); ++ } ++ ++ previous_tiler_bitmask = value; ++ break; ++ } ++ ++ case L2_PRESENT_LO: ++ { ++ unsigned long long changed = previous_l2_bitmask ^ value; ++ ++ if (BIT_AT(changed, 0)) { ++ record_timeline_event(PM_L2_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP); ++ } ++ if (BIT_AT(changed, 4)) { ++ record_timeline_event(PM_L2_1, BIT_AT(value, 4) ? ACTIVITY_START : ACTIVITY_STOP); ++ } ++ ++ previous_l2_bitmask = value; ++ break; ++ } ++ ++ default: ++ /* No other blocks are supported at present */ ++ break; ++ } ++ ++#undef SHADER_PRESENT_LO ++#undef TILER_PRESENT_LO ++#undef L2_PRESENT_LO ++#undef BIT_AT ++} ++ ++GATOR_DEFINE_PROBE(mali_page_fault_insert_pages, TP_PROTO(int event_id, unsigned long value)) ++{ ++ /* We add to the previous since we may receive many tracepoints in one sample period */ ++ sw_counter_data[MMU_PAGE_FAULT_0 + event_id] += value; ++} ++ ++GATOR_DEFINE_PROBE(mali_mmu_as_in_use, TP_PROTO(int event_id)) ++{ ++ record_timeline_event(MMU_AS_0 + event_id, ACTIVITY_START); ++} ++ ++GATOR_DEFINE_PROBE(mali_mmu_as_released, TP_PROTO(int event_id)) ++{ ++ record_timeline_event(MMU_AS_0 + event_id, ACTIVITY_STOP); ++} ++ ++GATOR_DEFINE_PROBE(mali_total_alloc_pages_change, TP_PROTO(long long int event_id)) ++{ ++ accumulators_data[TOTAL_ALLOC_PAGES] = event_id; ++} ++ ++static int create_files(struct super_block *sb, struct dentry *root) ++{ ++ int event; ++ /* ++ * Create the filesystem for all events ++ */ ++ int counter_index = 0; ++ const char *mali_name = gator_mali_get_mali_name(); ++ mali_profiling_control_type *mali_control; ++ ++ for (event = FIRST_TIMELINE_EVENT; event < FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS; event++) { ++ if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event], NULL) != 0) { ++ return -1; ++ } ++ counter_index++; ++ } ++ counter_index = 0; ++ for (event = FIRST_SOFTWARE_COUNTER; event < FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS; event++) { ++ if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event], NULL) != 0) { ++ return -1; ++ } ++ counter_index++; ++ } ++ counter_index = 0; ++ for (event = FIRST_ACCUMULATOR; event < FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS; event++) { ++ if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event], NULL) != 0) { ++ return -1; ++ } ++ counter_index++; ++ } ++ ++ mali_control = symbol_get(_mali_profiling_control); ++ if (mali_control) { ++ if (gator_mali_create_file_system(mali_name, "Filmstrip_cnt0", sb, root, &counters[FILMSTRIP], &filmstrip_event) != 0) { ++ return -1; ++ } ++ symbol_put(_mali_profiling_control); ++ } ++ ++ return 0; ++} ++ ++static int register_tracepoints(void) ++{ ++ if (GATOR_REGISTER_TRACE(mali_pm_status)) { ++ pr_debug("gator: Mali-T6xx: mali_pm_status tracepoint failed to activate\n"); ++ return 0; ++ } ++ ++ if (GATOR_REGISTER_TRACE(mali_page_fault_insert_pages)) { ++ pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages tracepoint failed to activate\n"); ++ return 0; ++ } ++ ++ if (GATOR_REGISTER_TRACE(mali_mmu_as_in_use)) { ++ pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use tracepoint failed to activate\n"); ++ return 0; ++ } ++ ++ if (GATOR_REGISTER_TRACE(mali_mmu_as_released)) { ++ pr_debug("gator: Mali-T6xx: mali_mmu_as_released tracepoint failed to activate\n"); ++ return 0; ++ } ++ ++ if (GATOR_REGISTER_TRACE(mali_total_alloc_pages_change)) { ++ pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change tracepoint failed to activate\n"); ++ return 0; ++ } ++ ++ pr_debug("gator: Mali-T6xx: start\n"); ++ pr_debug("gator: Mali-T6xx: mali_pm_status probe is at %p\n", &probe_mali_pm_status); ++ pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages probe is at %p\n", &probe_mali_page_fault_insert_pages); ++ pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use probe is at %p\n", &probe_mali_mmu_as_in_use); ++ pr_debug("gator: Mali-T6xx: mali_mmu_as_released probe is at %p\n", &probe_mali_mmu_as_released); ++ pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change probe is at %p\n", &probe_mali_total_alloc_pages_change); ++ ++ return 1; ++} ++ ++static int start(void) ++{ ++ unsigned int cnt; ++ mali_profiling_control_type *mali_control; ++ ++ /* Clean all data for the next capture */ ++ for (cnt = 0; cnt < NUMBER_OF_TIMELINE_EVENTS; cnt++) { ++ timeline_event_starttime[cnt].tv_sec = timeline_event_starttime[cnt].tv_nsec = 0; ++ timeline_data[cnt] = 0; ++ } ++ ++ for (cnt = 0; cnt < NUMBER_OF_SOFTWARE_COUNTERS; cnt++) { ++ sw_counter_data[cnt] = 0; ++ } ++ ++ for (cnt = 0; cnt < NUMBER_OF_ACCUMULATORS; cnt++) { ++ accumulators_data[cnt] = 0; ++ } ++ ++ /* Register tracepoints */ ++ if (register_tracepoints() == 0) { ++ return -1; ++ } ++ ++ /* Generic control interface for Mali DDK. */ ++ mali_control = symbol_get(_mali_profiling_control); ++ if (mali_control) { ++ /* The event attribute in the XML file keeps the actual frame rate. */ ++ unsigned int enabled = counters[FILMSTRIP].enabled ? 1 : 0; ++ unsigned int rate = filmstrip_event & 0xff; ++ unsigned int resize_factor = (filmstrip_event >> 8) & 0xff; ++ ++ pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control); ++ ++#define FBDUMP_CONTROL_ENABLE (1) ++#define FBDUMP_CONTROL_RATE (2) ++#define FBDUMP_CONTROL_RESIZE_FACTOR (4) ++ mali_control(FBDUMP_CONTROL_ENABLE, enabled); ++ mali_control(FBDUMP_CONTROL_RATE, rate); ++ mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor); ++ ++ pr_debug("gator: sent mali_control enabled=%d, rate=%d, resize_factor=%d\n", enabled, rate, resize_factor); ++ ++ symbol_put(_mali_profiling_control); ++ } else { ++ printk("gator: mali online _mali_profiling_control symbol not found\n"); ++ } ++ ++ /* ++ * Set the first timestamp for calculating the sample interval. The first interval could be quite long, ++ * since it will be the time between 'start' and the first 'read'. ++ * This means that timeline values will be divided by a big number for the first sample. ++ */ ++ getnstimeofday(&prev_timestamp); ++ ++ return 0; ++} ++ ++static void stop(void) ++{ ++ mali_profiling_control_type *mali_control; ++ ++ pr_debug("gator: Mali-T6xx: stop\n"); ++ ++ /* ++ * It is safe to unregister traces even if they were not successfully ++ * registered, so no need to check. ++ */ ++ GATOR_UNREGISTER_TRACE(mali_pm_status); ++ pr_debug("gator: Mali-T6xx: mali_pm_status tracepoint deactivated\n"); ++ ++ GATOR_UNREGISTER_TRACE(mali_page_fault_insert_pages); ++ pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages tracepoint deactivated\n"); ++ ++ GATOR_UNREGISTER_TRACE(mali_mmu_as_in_use); ++ pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use tracepoint deactivated\n"); ++ ++ GATOR_UNREGISTER_TRACE(mali_mmu_as_released); ++ pr_debug("gator: Mali-T6xx: mali_mmu_as_released tracepoint deactivated\n"); ++ ++ GATOR_UNREGISTER_TRACE(mali_total_alloc_pages_change); ++ pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change tracepoint deactivated\n"); ++ ++ /* Generic control interface for Mali DDK. */ ++ mali_control = symbol_get(_mali_profiling_control); ++ if (mali_control) { ++ pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_control); ++ ++ mali_control(FBDUMP_CONTROL_ENABLE, 0); ++ ++ symbol_put(_mali_profiling_control); ++ } else { ++ printk("gator: mali offline _mali_profiling_control symbol not found\n"); ++ } ++} ++ ++static int read(int **buffer) ++{ ++ int cnt; ++ int len = 0; ++ long sample_interval_us = 0; ++ struct timespec read_timestamp; ++ ++ if (!on_primary_core()) { ++ return 0; ++ } ++ ++ /* Get the start of this sample period. */ ++ getnstimeofday(&read_timestamp); ++ ++ /* ++ * Calculate the sample interval if the previous sample time is valid. ++ * We use tv_sec since it will not be 0. ++ */ ++ if (prev_timestamp.tv_sec != 0) { ++ sample_interval_us = get_duration_us(&prev_timestamp, &read_timestamp); ++ } ++ ++ /* Structure copy. Update the previous timestamp. */ ++ prev_timestamp = read_timestamp; ++ ++ /* ++ * Report the timeline counters (ACTIVITY_START/STOP) ++ */ ++ for (cnt = FIRST_TIMELINE_EVENT; cnt < (FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS); cnt++) { ++ mali_counter *counter = &counters[cnt]; ++ if (counter->enabled) { ++ const int index = cnt - FIRST_TIMELINE_EVENT; ++ unsigned int value; ++ ++ /* If the activity is still running, reset its start time to the start of this sample period ++ * to correct the count. Add the time up to the end of the sample onto the count. */ ++ if (timeline_event_starttime[index].tv_sec != 0) { ++ const long event_duration = get_duration_us(&timeline_event_starttime[index], &read_timestamp); ++ timeline_data[index] += event_duration; ++ timeline_event_starttime[index] = read_timestamp; /* Activity is still running. */ ++ } ++ ++ if (sample_interval_us != 0) { ++ /* Convert the counter to a percent-of-sample value */ ++ value = (timeline_data[index] * 100) / sample_interval_us; ++ } else { ++ pr_debug("gator: Mali-T6xx: setting value to zero\n"); ++ value = 0; ++ } ++ ++ /* Clear the counter value ready for the next sample. */ ++ timeline_data[index] = 0; ++ ++ counter_dump[len++] = counter->key; ++ counter_dump[len++] = value; ++ } ++ } ++ ++ /* Report the software counters */ ++ for (cnt = FIRST_SOFTWARE_COUNTER; cnt < (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS); cnt++) { ++ const mali_counter *counter = &counters[cnt]; ++ if (counter->enabled) { ++ const int index = cnt - FIRST_SOFTWARE_COUNTER; ++ counter_dump[len++] = counter->key; ++ counter_dump[len++] = sw_counter_data[index]; ++ /* Set the value to zero for the next time */ ++ sw_counter_data[index] = 0; ++ } ++ } ++ ++ /* Report the accumulators */ ++ for (cnt = FIRST_ACCUMULATOR; cnt < (FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS); cnt++) { ++ const mali_counter *counter = &counters[cnt]; ++ if (counter->enabled) { ++ const int index = cnt - FIRST_ACCUMULATOR; ++ counter_dump[len++] = counter->key; ++ counter_dump[len++] = accumulators_data[index]; ++ /* Do not zero the accumulator */ ++ } ++ } ++ ++ /* Update the buffer */ ++ if (buffer) { ++ *buffer = (int *)counter_dump; ++ } ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_mali_t6xx_interface = { ++ .create_files = create_files, ++ .start = start, ++ .stop = stop, ++ .read = read ++}; ++ ++extern int gator_events_mali_t6xx_init(void) ++{ ++ pr_debug("gator: Mali-T6xx: sw_counters init\n"); ++ ++ gator_mali_initialise_counters(counters, NUMBER_OF_EVENTS); ++ ++ return gator_events_install(&gator_events_mali_t6xx_interface); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_mali_t6xx_hw.c linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_t6xx_hw.c +--- linux-3.10.30/drivers/gator/gator_events_mali_t6xx_hw.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_t6xx_hw.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,784 @@ ++/** ++ * Copyright (C) ARM Limited 2012-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Mali T6xx DDK includes */ ++#include "linux/mali_linux_trace.h" ++#include "kbase/src/common/mali_kbase.h" ++#include "kbase/src/linux/mali_kbase_mem_linux.h" ++ ++#include "gator_events_mali_common.h" ++ ++/* If API version is not specified then assume API version 1. */ ++#ifndef MALI_DDK_GATOR_API_VERSION ++#define MALI_DDK_GATOR_API_VERSION 1 ++#endif ++ ++#if (MALI_DDK_GATOR_API_VERSION != 1) && (MALI_DDK_GATOR_API_VERSION != 2) ++#error MALI_DDK_GATOR_API_VERSION is invalid (must be 1 for r1/r2 DDK, or 2 for r3 DDK). ++#endif ++ ++/* ++ * Mali-T6xx ++ */ ++typedef struct kbase_device *kbase_find_device_type(int); ++typedef kbase_context *kbase_create_context_type(kbase_device *); ++typedef void kbase_destroy_context_type(kbase_context *); ++ ++#if MALI_DDK_GATOR_API_VERSION == 1 ++typedef void *kbase_va_alloc_type(kbase_context *, u32); ++typedef void kbase_va_free_type(kbase_context *, void *); ++#elif MALI_DDK_GATOR_API_VERSION == 2 ++typedef void *kbase_va_alloc_type(kbase_context *, u32, kbase_hwc_dma_mapping * handle); ++typedef void kbase_va_free_type(kbase_context *, kbase_hwc_dma_mapping * handle); ++#endif ++ ++typedef mali_error kbase_instr_hwcnt_enable_type(kbase_context *, kbase_uk_hwcnt_setup *); ++typedef mali_error kbase_instr_hwcnt_disable_type(kbase_context *); ++typedef mali_error kbase_instr_hwcnt_clear_type(kbase_context *); ++typedef mali_error kbase_instr_hwcnt_dump_irq_type(kbase_context *); ++typedef mali_bool kbase_instr_hwcnt_dump_complete_type(kbase_context *, mali_bool *); ++ ++static kbase_find_device_type *kbase_find_device_symbol; ++static kbase_create_context_type *kbase_create_context_symbol; ++static kbase_va_alloc_type *kbase_va_alloc_symbol; ++static kbase_instr_hwcnt_enable_type *kbase_instr_hwcnt_enable_symbol; ++static kbase_instr_hwcnt_clear_type *kbase_instr_hwcnt_clear_symbol; ++static kbase_instr_hwcnt_dump_irq_type *kbase_instr_hwcnt_dump_irq_symbol; ++static kbase_instr_hwcnt_dump_complete_type *kbase_instr_hwcnt_dump_complete_symbol; ++static kbase_instr_hwcnt_disable_type *kbase_instr_hwcnt_disable_symbol; ++static kbase_va_free_type *kbase_va_free_symbol; ++static kbase_destroy_context_type *kbase_destroy_context_symbol; ++ ++static long shader_present_low = 0; ++ ++/** The interval between reads, in ns. ++ * ++ * Earlier we introduced ++ * a 'hold off for 1ms after last read' to resolve MIDBASE-2178 and MALINE-724. ++ * However, the 1ms hold off is too long if no context switches occur as there is a race ++ * between this value and the tick of the read clock in gator which is also 1ms. If we 'miss' the ++ * current read, the counter values are effectively 'spread' over 2ms and the values seen are half ++ * what they should be (since Streamline averages over sample time). In the presence of context switches ++ * this spread can vary and markedly affect the counters. Currently there is no 'proper' solution to ++ * this, but empirically we have found that reducing the minimum read interval to 950us causes the ++ * counts to be much more stable. ++ */ ++static const int READ_INTERVAL_NSEC = 950000; ++ ++#if GATOR_TEST ++#include "gator_events_mali_t6xx_hw_test.c" ++#endif ++ ++/* Blocks for HW counters */ ++enum { ++ JM_BLOCK = 0, ++ TILER_BLOCK, ++ SHADER_BLOCK, ++ MMU_BLOCK ++}; ++ ++/* Counters for Mali-T6xx: ++ * ++ * - HW counters, 4 blocks ++ * For HW counters we need strings to create /dev/gator/events files. ++ * Enums are not needed because the position of the HW name in the array is the same ++ * of the corresponding value in the received block of memory. ++ * HW counters are requested by calculating a bitmask, passed then to the driver. ++ * Every millisecond a HW counters dump is requested, and if the previous has been completed they are read. ++ */ ++ ++/* Hardware Counters */ ++static const char *const hardware_counter_names[] = { ++ /* Job Manager */ ++ "", ++ "", ++ "", ++ "", ++ "MESSAGES_SENT", ++ "MESSAGES_RECEIVED", ++ "GPU_ACTIVE", /* 6 */ ++ "IRQ_ACTIVE", ++ "JS0_JOBS", ++ "JS0_TASKS", ++ "JS0_ACTIVE", ++ "", ++ "JS0_WAIT_READ", ++ "JS0_WAIT_ISSUE", ++ "JS0_WAIT_DEPEND", ++ "JS0_WAIT_FINISH", ++ "JS1_JOBS", ++ "JS1_TASKS", ++ "JS1_ACTIVE", ++ "", ++ "JS1_WAIT_READ", ++ "JS1_WAIT_ISSUE", ++ "JS1_WAIT_DEPEND", ++ "JS1_WAIT_FINISH", ++ "JS2_JOBS", ++ "JS2_TASKS", ++ "JS2_ACTIVE", ++ "", ++ "JS2_WAIT_READ", ++ "JS2_WAIT_ISSUE", ++ "JS2_WAIT_DEPEND", ++ "JS2_WAIT_FINISH", ++ "JS3_JOBS", ++ "JS3_TASKS", ++ "JS3_ACTIVE", ++ "", ++ "JS3_WAIT_READ", ++ "JS3_WAIT_ISSUE", ++ "JS3_WAIT_DEPEND", ++ "JS3_WAIT_FINISH", ++ "JS4_JOBS", ++ "JS4_TASKS", ++ "JS4_ACTIVE", ++ "", ++ "JS4_WAIT_READ", ++ "JS4_WAIT_ISSUE", ++ "JS4_WAIT_DEPEND", ++ "JS4_WAIT_FINISH", ++ "JS5_JOBS", ++ "JS5_TASKS", ++ "JS5_ACTIVE", ++ "", ++ "JS5_WAIT_READ", ++ "JS5_WAIT_ISSUE", ++ "JS5_WAIT_DEPEND", ++ "JS5_WAIT_FINISH", ++ "JS6_JOBS", ++ "JS6_TASKS", ++ "JS6_ACTIVE", ++ "", ++ "JS6_WAIT_READ", ++ "JS6_WAIT_ISSUE", ++ "JS6_WAIT_DEPEND", ++ "JS6_WAIT_FINISH", ++ ++ /*Tiler */ ++ "", ++ "", ++ "", ++ "JOBS_PROCESSED", ++ "TRIANGLES", ++ "QUADS", ++ "POLYGONS", ++ "POINTS", ++ "LINES", ++ "VCACHE_HIT", ++ "VCACHE_MISS", ++ "FRONT_FACING", ++ "BACK_FACING", ++ "PRIM_VISIBLE", ++ "PRIM_CULLED", ++ "PRIM_CLIPPED", ++ "LEVEL0", ++ "LEVEL1", ++ "LEVEL2", ++ "LEVEL3", ++ "LEVEL4", ++ "LEVEL5", ++ "LEVEL6", ++ "LEVEL7", ++ "COMMAND_1", ++ "COMMAND_2", ++ "COMMAND_3", ++ "COMMAND_4", ++ "COMMAND_4_7", ++ "COMMAND_8_15", ++ "COMMAND_16_63", ++ "COMMAND_64", ++ "COMPRESS_IN", ++ "COMPRESS_OUT", ++ "COMPRESS_FLUSH", ++ "TIMESTAMPS", ++ "PCACHE_HIT", ++ "PCACHE_MISS", ++ "PCACHE_LINE", ++ "PCACHE_STALL", ++ "WRBUF_HIT", ++ "WRBUF_MISS", ++ "WRBUF_LINE", ++ "WRBUF_PARTIAL", ++ "WRBUF_STALL", ++ "ACTIVE", ++ "LOADING_DESC", ++ "INDEX_WAIT", ++ "INDEX_RANGE_WAIT", ++ "VERTEX_WAIT", ++ "PCACHE_WAIT", ++ "WRBUF_WAIT", ++ "BUS_READ", ++ "BUS_WRITE", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "UTLB_STALL", ++ "UTLB_REPLAY_MISS", ++ "UTLB_REPLAY_FULL", ++ "UTLB_NEW_MISS", ++ "UTLB_HIT", ++ ++ /* Shader Core */ ++ "", ++ "", ++ "", ++ "SHADER_CORE_ACTIVE", ++ "FRAG_ACTIVE", ++ "FRAG_PRIMATIVES", ++ "FRAG_PRIMATIVES_DROPPED", ++ "FRAG_CYCLE_DESC", ++ "FRAG_CYCLES_PLR", ++ "FRAG_CYCLES_VERT", ++ "FRAG_CYCLES_TRISETUP", ++ "FRAG_CYCLES_RAST", ++ "FRAG_THREADS", ++ "FRAG_DUMMY_THREADS", ++ "FRAG_QUADS_RAST", ++ "FRAG_QUADS_EZS_TEST", ++ "FRAG_QUADS_EZS_KILLED", ++ "FRAG_QUADS_LZS_TEST", ++ "FRAG_QUADS_LZS_KILLED", ++ "FRAG_CYCLE_NO_TILE", ++ "FRAG_NUM_TILES", ++ "FRAG_TRANS_ELIM", ++ "COMPUTE_ACTIVE", ++ "COMPUTE_TASKS", ++ "COMPUTE_THREADS", ++ "COMPUTE_CYCLES_DESC", ++ "TRIPIPE_ACTIVE", ++ "ARITH_WORDS", ++ "ARITH_CYCLES_REG", ++ "ARITH_CYCLES_L0", ++ "ARITH_FRAG_DEPEND", ++ "LS_WORDS", ++ "LS_ISSUES", ++ "LS_RESTARTS", ++ "LS_REISSUES_MISS", ++ "LS_REISSUES_VD", ++ "LS_REISSUE_ATTRIB_MISS", ++ "LS_NO_WB", ++ "TEX_WORDS", ++ "TEX_BUBBLES", ++ "TEX_WORDS_L0", ++ "TEX_WORDS_DESC", ++ "TEX_THREADS", ++ "TEX_RECIRC_FMISS", ++ "TEX_RECIRC_DESC", ++ "TEX_RECIRC_MULTI", ++ "TEX_RECIRC_PMISS", ++ "TEX_RECIRC_CONF", ++ "LSC_READ_HITS", ++ "LSC_READ_MISSES", ++ "LSC_WRITE_HITS", ++ "LSC_WRITE_MISSES", ++ "LSC_ATOMIC_HITS", ++ "LSC_ATOMIC_MISSES", ++ "LSC_LINE_FETCHES", ++ "LSC_DIRTY_LINE", ++ "LSC_SNOOPS", ++ "AXI_TLB_STALL", ++ "AXI_TLB_MIESS", ++ "AXI_TLB_TRANSACTION", ++ "LS_TLB_MISS", ++ "LS_TLB_HIT", ++ "AXI_BEATS_READ", ++ "AXI_BEATS_WRITTEN", ++ ++ /*L2 and MMU */ ++ "", ++ "", ++ "", ++ "", ++ "MMU_HIT", ++ "MMU_NEW_MISS", ++ "MMU_REPLAY_FULL", ++ "MMU_REPLAY_MISS", ++ "MMU_TABLE_WALK", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "UTLB_HIT", ++ "UTLB_NEW_MISS", ++ "UTLB_REPLAY_FULL", ++ "UTLB_REPLAY_MISS", ++ "UTLB_STALL", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "", ++ "L2_WRITE_BEATS", ++ "L2_READ_BEATS", ++ "L2_ANY_LOOKUP", ++ "L2_READ_LOOKUP", ++ "L2_SREAD_LOOKUP", ++ "L2_READ_REPLAY", ++ "L2_READ_SNOOP", ++ "L2_READ_HIT", ++ "L2_CLEAN_MISS", ++ "L2_WRITE_LOOKUP", ++ "L2_SWRITE_LOOKUP", ++ "L2_WRITE_REPLAY", ++ "L2_WRITE_SNOOP", ++ "L2_WRITE_HIT", ++ "L2_EXT_READ_FULL", ++ "L2_EXT_READ_HALF", ++ "L2_EXT_WRITE_FULL", ++ "L2_EXT_WRITE_HALF", ++ "L2_EXT_READ", ++ "L2_EXT_READ_LINE", ++ "L2_EXT_WRITE", ++ "L2_EXT_WRITE_LINE", ++ "L2_EXT_WRITE_SMALL", ++ "L2_EXT_BARRIER", ++ "L2_EXT_AR_STALL", ++ "L2_EXT_R_BUF_FULL", ++ "L2_EXT_RD_BUF_FULL", ++ "L2_EXT_R_RAW", ++ "L2_EXT_W_STALL", ++ "L2_EXT_W_BUF_FULL", ++ "L2_EXT_R_W_HAZARD", ++ "L2_TAG_HAZARD", ++ "L2_SNOOP_FULL", ++ "L2_REPLAY_FULL" ++}; ++ ++#define NUMBER_OF_HARDWARE_COUNTERS (sizeof(hardware_counter_names) / sizeof(hardware_counter_names[0])) ++ ++#define GET_HW_BLOCK(c) (((c) >> 6) & 0x3) ++#define GET_COUNTER_OFFSET(c) ((c) & 0x3f) ++ ++/* Memory to dump hardware counters into */ ++static void *kernel_dump_buffer; ++ ++#if MALI_DDK_GATOR_API_VERSION == 2 ++/* DMA state used to manage lifetime of the buffer */ ++kbase_hwc_dma_mapping kernel_dump_buffer_handle; ++#endif ++ ++/* kbase context and device */ ++static kbase_context *kbcontext = NULL; ++static struct kbase_device *kbdevice = NULL; ++ ++/* ++ * The following function has no external prototype in older DDK revisions. When the DDK ++ * is updated then this should be removed. ++ */ ++struct kbase_device *kbase_find_device(int minor); ++ ++static volatile bool kbase_device_busy = false; ++static unsigned int num_hardware_counters_enabled; ++ ++/* ++ * gatorfs variables for counter enable state ++ */ ++static mali_counter counters[NUMBER_OF_HARDWARE_COUNTERS]; ++ ++/* An array used to return the data we recorded ++ * as key,value pairs hence the *2 ++ */ ++static unsigned long counter_dump[NUMBER_OF_HARDWARE_COUNTERS * 2]; ++ ++#define SYMBOL_GET(FUNCTION, ERROR_COUNT) \ ++ if(FUNCTION ## _symbol) \ ++ { \ ++ printk("gator: mali " #FUNCTION " symbol was already registered\n"); \ ++ (ERROR_COUNT)++; \ ++ } \ ++ else \ ++ { \ ++ FUNCTION ## _symbol = symbol_get(FUNCTION); \ ++ if(! FUNCTION ## _symbol) \ ++ { \ ++ printk("gator: mali online " #FUNCTION " symbol not found\n"); \ ++ (ERROR_COUNT)++; \ ++ } \ ++ } ++ ++#define SYMBOL_CLEANUP(FUNCTION) \ ++ if(FUNCTION ## _symbol) \ ++ { \ ++ symbol_put(FUNCTION); \ ++ FUNCTION ## _symbol = NULL; \ ++ } ++ ++/** ++ * Execute symbol_get for all the Mali symbols and check for success. ++ * @return the number of symbols not loaded. ++ */ ++static int init_symbols(void) ++{ ++ int error_count = 0; ++ SYMBOL_GET(kbase_find_device, error_count); ++ SYMBOL_GET(kbase_create_context, error_count); ++ SYMBOL_GET(kbase_va_alloc, error_count); ++ SYMBOL_GET(kbase_instr_hwcnt_enable, error_count); ++ SYMBOL_GET(kbase_instr_hwcnt_clear, error_count); ++ SYMBOL_GET(kbase_instr_hwcnt_dump_irq, error_count); ++ SYMBOL_GET(kbase_instr_hwcnt_dump_complete, error_count); ++ SYMBOL_GET(kbase_instr_hwcnt_disable, error_count); ++ SYMBOL_GET(kbase_va_free, error_count); ++ SYMBOL_GET(kbase_destroy_context, error_count); ++ ++ return error_count; ++} ++ ++/** ++ * Execute symbol_put for all the registered Mali symbols. ++ */ ++static void clean_symbols(void) ++{ ++ SYMBOL_CLEANUP(kbase_find_device); ++ SYMBOL_CLEANUP(kbase_create_context); ++ SYMBOL_CLEANUP(kbase_va_alloc); ++ SYMBOL_CLEANUP(kbase_instr_hwcnt_enable); ++ SYMBOL_CLEANUP(kbase_instr_hwcnt_clear); ++ SYMBOL_CLEANUP(kbase_instr_hwcnt_dump_irq); ++ SYMBOL_CLEANUP(kbase_instr_hwcnt_dump_complete); ++ SYMBOL_CLEANUP(kbase_instr_hwcnt_disable); ++ SYMBOL_CLEANUP(kbase_va_free); ++ SYMBOL_CLEANUP(kbase_destroy_context); ++} ++ ++/** ++ * Determines whether a read should take place ++ * @param current_time The current time, obtained from getnstimeofday() ++ * @param prev_time_s The number of seconds at the previous read attempt. ++ * @param next_read_time_ns The time (in ns) when the next read should be allowed. ++ * ++ * Note that this function has been separated out here to allow it to be tested. ++ */ ++static int is_read_scheduled(const struct timespec *current_time, u32 *prev_time_s, s32 *next_read_time_ns) ++{ ++ /* If the current ns count rolls over a second, roll the next read time too. */ ++ if (current_time->tv_sec != *prev_time_s) { ++ *next_read_time_ns = *next_read_time_ns - NSEC_PER_SEC; ++ } ++ ++ /* Abort the read if the next read time has not arrived. */ ++ if (current_time->tv_nsec < *next_read_time_ns) { ++ return 0; ++ } ++ ++ /* Set the next read some fixed time after this one, and update the read timestamp. */ ++ *next_read_time_ns = current_time->tv_nsec + READ_INTERVAL_NSEC; ++ ++ *prev_time_s = current_time->tv_sec; ++ return 1; ++} ++ ++static int start(void) ++{ ++ kbase_uk_hwcnt_setup setup; ++ mali_error err; ++ int cnt; ++ u16 bitmask[] = { 0, 0, 0, 0 }; ++ unsigned long long shadersPresent = 0; ++ ++ /* Setup HW counters */ ++ num_hardware_counters_enabled = 0; ++ ++ if (NUMBER_OF_HARDWARE_COUNTERS != 256) { ++ pr_debug("Unexpected number of hardware counters defined: expecting 256, got %d\n", NUMBER_OF_HARDWARE_COUNTERS); ++ } ++ ++ /* Calculate enable bitmasks based on counters_enabled array */ ++ for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++) { ++ const mali_counter *counter = &counters[cnt]; ++ if (counter->enabled) { ++ int block = GET_HW_BLOCK(cnt); ++ int enable_bit = GET_COUNTER_OFFSET(cnt) / 4; ++ bitmask[block] |= (1 << enable_bit); ++ pr_debug("gator: Mali-T6xx: hardware counter %s selected [%d]\n", hardware_counter_names[cnt], cnt); ++ num_hardware_counters_enabled++; ++ } ++ } ++ ++ /* Create a kbase context for HW counters */ ++ if (num_hardware_counters_enabled > 0) { ++ if (init_symbols() > 0) { ++ clean_symbols(); ++ /* No Mali driver code entrypoints found - not a fault. */ ++ return 0; ++ } ++ ++ kbdevice = kbase_find_device_symbol(-1); ++ ++ /* If we already got a context, fail */ ++ if (kbcontext) { ++ pr_debug("gator: Mali-T6xx: error context already present\n"); ++ goto out; ++ } ++ ++ /* kbcontext will only be valid after all the Mali symbols are loaded successfully */ ++ kbcontext = kbase_create_context_symbol(kbdevice); ++ if (!kbcontext) { ++ pr_debug("gator: Mali-T6xx: error creating kbase context\n"); ++ goto out; ++ } ++ ++ ++ /* See if we can get the number of shader cores */ ++ shadersPresent = kbdevice->shader_present_bitmap; ++ shader_present_low = (unsigned long)shadersPresent; ++ ++ /* ++ * The amount of memory needed to store the dump (bytes) ++ * DUMP_SIZE = number of core groups ++ * * number of blocks (always 8 for midgard) ++ * * number of counters per block (always 64 for midgard) ++ * * number of bytes per counter (always 4 in midgard) ++ * For a Mali-T6xx with a single core group = 1 * 8 * 64 * 4 = 2048 ++ * For a Mali-T6xx with a dual core group = 2 * 8 * 64 * 4 = 4096 ++ */ ++#if MALI_DDK_GATOR_API_VERSION == 1 ++ kernel_dump_buffer = kbase_va_alloc_symbol(kbcontext, 4096); ++#elif MALI_DDK_GATOR_API_VERSION == 2 ++ kernel_dump_buffer = kbase_va_alloc_symbol(kbcontext, 4096, &kernel_dump_buffer_handle); ++#endif ++ if (!kernel_dump_buffer) { ++ pr_debug("gator: Mali-T6xx: error trying to allocate va\n"); ++ goto destroy_context; ++ } ++ ++ setup.dump_buffer = (uintptr_t)kernel_dump_buffer; ++ setup.jm_bm = bitmask[JM_BLOCK]; ++ setup.tiler_bm = bitmask[TILER_BLOCK]; ++ setup.shader_bm = bitmask[SHADER_BLOCK]; ++ setup.mmu_l2_bm = bitmask[MMU_BLOCK]; ++ /* These counters do not exist on Mali-T60x */ ++ setup.l3_cache_bm = 0; ++ ++ /* Use kbase API to enable hardware counters and provide dump buffer */ ++ err = kbase_instr_hwcnt_enable_symbol(kbcontext, &setup); ++ if (err != MALI_ERROR_NONE) { ++ pr_debug("gator: Mali-T6xx: can't setup hardware counters\n"); ++ goto free_buffer; ++ } ++ pr_debug("gator: Mali-T6xx: hardware counters enabled\n"); ++ kbase_instr_hwcnt_clear_symbol(kbcontext); ++ pr_debug("gator: Mali-T6xx: hardware counters cleared \n"); ++ ++ kbase_device_busy = false; ++ } ++ ++ return 0; ++ ++free_buffer: ++#if MALI_DDK_GATOR_API_VERSION == 1 ++ kbase_va_free_symbol(kbcontext, kernel_dump_buffer); ++#elif MALI_DDK_GATOR_API_VERSION == 2 ++ kbase_va_free_symbol(kbcontext, &kernel_dump_buffer_handle); ++#endif ++ ++destroy_context: ++ kbase_destroy_context_symbol(kbcontext); ++ ++out: ++ clean_symbols(); ++ return -1; ++} ++ ++static void stop(void) ++{ ++ unsigned int cnt; ++ kbase_context *temp_kbcontext; ++ ++ pr_debug("gator: Mali-T6xx: stop\n"); ++ ++ /* Set all counters as disabled */ ++ for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++) { ++ counters[cnt].enabled = 0; ++ } ++ ++ /* Destroy the context for HW counters */ ++ if (num_hardware_counters_enabled > 0 && kbcontext != NULL) { ++ /* ++ * Set the global variable to NULL before destroying it, because ++ * other function will check this before using it. ++ */ ++ temp_kbcontext = kbcontext; ++ kbcontext = NULL; ++ ++ kbase_instr_hwcnt_disable_symbol(temp_kbcontext); ++ ++#if MALI_DDK_GATOR_API_VERSION == 1 ++ kbase_va_free_symbol(temp_kbcontext, kernel_dump_buffer); ++#elif MALI_DDK_GATOR_API_VERSION == 2 ++ kbase_va_free_symbol(temp_kbcontext, &kernel_dump_buffer_handle); ++#endif ++ ++ kbase_destroy_context_symbol(temp_kbcontext); ++ ++ pr_debug("gator: Mali-T6xx: hardware counters stopped\n"); ++ ++ clean_symbols(); ++ } ++} ++ ++static int read(int **buffer) ++{ ++ int cnt; ++ int len = 0; ++ u32 value = 0; ++ mali_bool success; ++ ++ struct timespec current_time; ++ static u32 prev_time_s = 0; ++ static s32 next_read_time_ns = 0; ++ ++ if (!on_primary_core()) { ++ return 0; ++ } ++ ++ getnstimeofday(¤t_time); ++ ++ /* ++ * Discard reads unless a respectable time has passed. This reduces the load on the GPU without sacrificing ++ * accuracy on the Streamline display. ++ */ ++ if (!is_read_scheduled(¤t_time, &prev_time_s, &next_read_time_ns)) { ++ return 0; ++ } ++ ++ /* ++ * Report the HW counters ++ * Only process hardware counters if at least one of the hardware counters is enabled. ++ */ ++ if (num_hardware_counters_enabled > 0) { ++ const unsigned int vithar_blocks[] = { ++ 0x700, /* VITHAR_JOB_MANAGER, Block 0 */ ++ 0x400, /* VITHAR_TILER, Block 1 */ ++ 0x000, /* VITHAR_SHADER_CORE, Block 2 */ ++ 0x500 /* VITHAR_MEMORY_SYSTEM, Block 3 */ ++ }; ++ ++ if (!kbcontext) { ++ return -1; ++ } ++ ++ /* Mali symbols can be called safely since a kbcontext is valid */ ++ if (kbase_instr_hwcnt_dump_complete_symbol(kbcontext, &success) == MALI_TRUE) { ++ kbase_device_busy = false; ++ ++ if (success == MALI_TRUE) { ++ /* Cycle through hardware counters and accumulate totals */ ++ for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++) { ++ const mali_counter *counter = &counters[cnt]; ++ if (counter->enabled) { ++ const int block = GET_HW_BLOCK(cnt); ++ const int counter_offset = GET_COUNTER_OFFSET(cnt); ++ ++ const char* block_base_address = (char*)kernel_dump_buffer + vithar_blocks[block]; ++ ++ /* If counter belongs to shader block need to take into account all cores */ ++ if (block == SHADER_BLOCK) { ++ int i = 0; ++ int shader_core_count = 0; ++ value = 0; ++ ++ for (i = 0; i < 4; i++) { ++ if ((shader_present_low >> i) & 1) { ++ value += *((u32*) (block_base_address + (0x100 * i)) + counter_offset); ++ shader_core_count++; ++ } ++ } ++ ++ for (i = 0; i < 4; i++) { ++ if((shader_present_low >> (i+4)) & 1) { ++ value += *((u32*)(block_base_address + (0x100 * i) + 0x800) + counter_offset); ++ shader_core_count++; ++ } ++ } ++ ++ /* Need to total by number of cores to produce an average */ ++ if (shader_core_count != 0) { ++ value /= shader_core_count; ++ } ++ } else { ++ value = *((u32*)block_base_address + counter_offset); ++ } ++ ++ counter_dump[len++] = counter->key; ++ counter_dump[len++] = value; ++ } ++ } ++ } ++ } ++ ++ if (!kbase_device_busy) { ++ kbase_device_busy = true; ++ kbase_instr_hwcnt_dump_irq_symbol(kbcontext); ++ } ++ } ++ ++ /* Update the buffer */ ++ if (buffer) { ++ *buffer = (int *)counter_dump; ++ } ++ ++ return len; ++} ++ ++static int create_files(struct super_block *sb, struct dentry *root) ++{ ++ unsigned int event; ++ /* ++ * Create the filesystem for all events ++ */ ++ int counter_index = 0; ++ const char *mali_name = gator_mali_get_mali_name(); ++ ++ for (event = 0; event < NUMBER_OF_HARDWARE_COUNTERS; event++) { ++ if (gator_mali_create_file_system(mali_name, hardware_counter_names[counter_index], sb, root, &counters[event], NULL) != 0) ++ return -1; ++ counter_index++; ++ } ++ ++ return 0; ++} ++ ++static struct gator_interface gator_events_mali_t6xx_interface = { ++ .create_files = create_files, ++ .start = start, ++ .stop = stop, ++ .read = read ++}; ++ ++int gator_events_mali_t6xx_hw_init(void) ++{ ++ pr_debug("gator: Mali-T6xx: sw_counters init\n"); ++ ++#if GATOR_TEST ++ test_all_is_read_scheduled(); ++#endif ++ ++ gator_mali_initialise_counters(counters, NUMBER_OF_HARDWARE_COUNTERS); ++ ++ return gator_events_install(&gator_events_mali_t6xx_interface); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_mali_t6xx_hw_test.c linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_t6xx_hw_test.c +--- linux-3.10.30/drivers/gator/gator_events_mali_t6xx_hw_test.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_mali_t6xx_hw_test.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,55 @@ ++/** ++ * Copyright (C) ARM Limited 2012-2013. All rights reserved. ++ * ++ * This program 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. ++ * ++ */ ++ ++/** ++ * Test functions for mali_t600_hw code. ++ */ ++ ++static int is_read_scheduled(const struct timespec *current_time, u32 *prev_time_s, s32 *next_read_time_ns); ++ ++static int test_is_read_scheduled(u32 s, u32 ns, u32 prev_s, s32 next_ns, int expected_result, s32 expected_next_ns) ++{ ++ struct timespec current_time; ++ u32 prev_time_s = prev_s; ++ s32 next_read_time_ns = next_ns; ++ ++ current_time.tv_sec = s; ++ current_time.tv_nsec = ns; ++ ++ if (is_read_scheduled(¤t_time, &prev_time_s, &next_read_time_ns) != expected_result) { ++ printk("Failed do_read(%u, %u, %u, %d): expected %d\n", s, ns, prev_s, next_ns, expected_result); ++ return 0; ++ } ++ ++ if (next_read_time_ns != expected_next_ns) { ++ printk("Failed: next_read_ns expected=%d, actual=%d\n", expected_next_ns, next_read_time_ns); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static void test_all_is_read_scheduled(void) ++{ ++ const int HIGHEST_NS = 999999999; ++ int n_tests_passed = 0; ++ ++ printk("gator: running tests on %s\n", __FILE__); ++ ++ n_tests_passed += test_is_read_scheduled(0, 0, 0, 0, 1, READ_INTERVAL_NSEC); /* Null time */ ++ n_tests_passed += test_is_read_scheduled(100, 1000, 0, 0, 1, READ_INTERVAL_NSEC + 1000); /* Initial values */ ++ ++ n_tests_passed += test_is_read_scheduled(100, HIGHEST_NS, 100, HIGHEST_NS + 500, 0, HIGHEST_NS + 500); ++ n_tests_passed += test_is_read_scheduled(101, 0001, 100, HIGHEST_NS + 500, 0, HIGHEST_NS + 500 - NSEC_PER_SEC); ++ n_tests_passed += test_is_read_scheduled(101, 600, 100, HIGHEST_NS + 500 - NSEC_PER_SEC, 1, 600 + READ_INTERVAL_NSEC); ++ ++ n_tests_passed += test_is_read_scheduled(101, 600, 100, HIGHEST_NS + 500, 1, 600 + READ_INTERVAL_NSEC); ++ ++ printk("gator: %d tests passed\n", n_tests_passed); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_meminfo.c linux-3.10.30-cubox-i/drivers/gator/gator_events_meminfo.c +--- linux-3.10.30/drivers/gator/gator_events_meminfo.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_meminfo.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,387 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum { ++ MEMINFO_MEMFREE, ++ MEMINFO_MEMUSED, ++ MEMINFO_BUFFERRAM, ++ MEMINFO_TOTAL, ++}; ++ ++enum { ++ PROC_SIZE, ++ PROC_SHARE, ++ PROC_TEXT, ++ PROC_DATA, ++ PROC_COUNT, ++}; ++ ++static const char * const meminfo_names[] = { ++ "Linux_meminfo_memfree", ++ "Linux_meminfo_memused", ++ "Linux_meminfo_bufferram", ++}; ++ ++static const char * const proc_names[] = { ++ "Linux_proc_statm_size", ++ "Linux_proc_statm_share", ++ "Linux_proc_statm_text", ++ "Linux_proc_statm_data", ++}; ++ ++static bool meminfo_global_enabled; ++static ulong meminfo_enabled[MEMINFO_TOTAL]; ++static ulong meminfo_keys[MEMINFO_TOTAL]; ++static long long meminfo_buffer[2 * (MEMINFO_TOTAL + 2)]; ++static int meminfo_length = 0; ++static bool new_data_avail; ++ ++static bool proc_global_enabled; ++static ulong proc_enabled[PROC_COUNT]; ++static ulong proc_keys[PROC_COUNT]; ++static DEFINE_PER_CPU(long long, proc_buffer[2 * (PROC_COUNT + 3)]); ++ ++static int gator_meminfo_func(void *data); ++static bool gator_meminfo_run; ++// Initialize semaphore unlocked to initialize memory values ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) ++static DECLARE_MUTEX(gator_meminfo_sem); ++#else ++static DEFINE_SEMAPHORE(gator_meminfo_sem); ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) ++GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order)) ++#else ++GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order)) ++#endif ++{ ++ up(&gator_meminfo_sem); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) ++GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold)) ++#else ++GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold)) ++#endif ++{ ++ up(&gator_meminfo_sem); ++} ++ ++GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype)) ++{ ++ up(&gator_meminfo_sem); ++} ++ ++static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root) ++{ ++ struct dentry *dir; ++ int i; ++ ++ for (i = 0; i < MEMINFO_TOTAL; i++) { ++ dir = gatorfs_mkdir(sb, root, meminfo_names[i]); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]); ++ gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_keys[i]); ++ } ++ ++ for (i = 0; i < PROC_COUNT; ++i) { ++ dir = gatorfs_mkdir(sb, root, proc_names[i]); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &proc_enabled[i]); ++ gatorfs_create_ro_ulong(sb, dir, "key", &proc_keys[i]); ++ } ++ ++ return 0; ++} ++ ++static int gator_events_meminfo_start(void) ++{ ++ int i; ++ ++ new_data_avail = false; ++ meminfo_global_enabled = 0; ++ for (i = 0; i < MEMINFO_TOTAL; i++) { ++ if (meminfo_enabled[i]) { ++ meminfo_global_enabled = 1; ++ break; ++ } ++ } ++ ++ proc_global_enabled = 0; ++ for (i = 0; i < PROC_COUNT; ++i) { ++ if (proc_enabled[i]) { ++ proc_global_enabled = 1; ++ break; ++ } ++ } ++ if (meminfo_enabled[MEMINFO_MEMUSED]) { ++ proc_global_enabled = 1; ++ } ++ ++ if (meminfo_global_enabled == 0) ++ return 0; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) ++ if (GATOR_REGISTER_TRACE(mm_page_free_direct)) ++#else ++ if (GATOR_REGISTER_TRACE(mm_page_free)) ++#endif ++ goto mm_page_free_exit; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) ++ if (GATOR_REGISTER_TRACE(mm_pagevec_free)) ++#else ++ if (GATOR_REGISTER_TRACE(mm_page_free_batched)) ++#endif ++ goto mm_page_free_batched_exit; ++ if (GATOR_REGISTER_TRACE(mm_page_alloc)) ++ goto mm_page_alloc_exit; ++ ++ // Start worker thread ++ gator_meminfo_run = true; ++ // Since the mutex starts unlocked, memory values will be initialized ++ if (IS_ERR(kthread_run(gator_meminfo_func, NULL, "gator_meminfo"))) ++ goto kthread_run_exit; ++ ++ return 0; ++ ++kthread_run_exit: ++ GATOR_UNREGISTER_TRACE(mm_page_alloc); ++mm_page_alloc_exit: ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) ++ GATOR_UNREGISTER_TRACE(mm_pagevec_free); ++#else ++ GATOR_UNREGISTER_TRACE(mm_page_free_batched); ++#endif ++mm_page_free_batched_exit: ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) ++ GATOR_UNREGISTER_TRACE(mm_page_free_direct); ++#else ++ GATOR_UNREGISTER_TRACE(mm_page_free); ++#endif ++mm_page_free_exit: ++ return -1; ++} ++ ++static void gator_events_meminfo_stop(void) ++{ ++ if (meminfo_global_enabled) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) ++ GATOR_UNREGISTER_TRACE(mm_page_free_direct); ++ GATOR_UNREGISTER_TRACE(mm_pagevec_free); ++#else ++ GATOR_UNREGISTER_TRACE(mm_page_free); ++ GATOR_UNREGISTER_TRACE(mm_page_free_batched); ++#endif ++ GATOR_UNREGISTER_TRACE(mm_page_alloc); ++ ++ // Stop worker thread ++ gator_meminfo_run = false; ++ up(&gator_meminfo_sem); ++ } ++} ++ ++// Must be run in process context as the kernel function si_meminfo() can sleep ++static int gator_meminfo_func(void *data) ++{ ++ struct sysinfo info; ++ int i, len; ++ unsigned long long value; ++ ++ for (;;) { ++ if (down_killable(&gator_meminfo_sem)) { ++ break; ++ } ++ ++ // Eat up any pending events ++ while (!down_trylock(&gator_meminfo_sem)); ++ ++ if (!gator_meminfo_run) { ++ break; ++ } ++ ++ meminfo_length = len = 0; ++ ++ si_meminfo(&info); ++ for (i = 0; i < MEMINFO_TOTAL; i++) { ++ if (meminfo_enabled[i]) { ++ switch (i) { ++ case MEMINFO_MEMFREE: ++ value = info.freeram * PAGE_SIZE; ++ break; ++ case MEMINFO_MEMUSED: ++ // pid -1 means system wide ++ meminfo_buffer[len++] = 1; ++ meminfo_buffer[len++] = -1; ++ // Emit value ++ meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED]; ++ meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE; ++ // Clear pid ++ meminfo_buffer[len++] = 1; ++ meminfo_buffer[len++] = 0; ++ continue; ++ case MEMINFO_BUFFERRAM: ++ value = info.bufferram * PAGE_SIZE; ++ break; ++ default: ++ value = 0; ++ break; ++ } ++ meminfo_buffer[len++] = meminfo_keys[i]; ++ meminfo_buffer[len++] = value; ++ } ++ } ++ ++ meminfo_length = len; ++ new_data_avail = true; ++ } ++ ++ return 0; ++} ++ ++static int gator_events_meminfo_read(long long **buffer) ++{ ++ if (!on_primary_core() || !meminfo_global_enabled) ++ return 0; ++ ++ if (!new_data_avail) ++ return 0; ++ ++ new_data_avail = false; ++ ++ if (buffer) ++ *buffer = meminfo_buffer; ++ ++ return meminfo_length; ++} ++ ++static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct *task) ++{ ++ struct mm_struct *mm; ++ u64 share = 0; ++ int i; ++ long long value; ++ int len = 0; ++ int cpu = get_physical_cpu(); ++ long long *buf = per_cpu(proc_buffer, cpu); ++ ++ if (!proc_global_enabled) { ++ return 0; ++ } ++ ++ // Collect the memory stats of the process instead of the thread ++ if (task->group_leader != NULL) { ++ task = task->group_leader; ++ } ++ ++ // get_task_mm/mmput is not needed in this context because the task and it's mm are required as part of the sched_switch ++ mm = task->mm; ++ if (mm == NULL) { ++ return 0; ++ } ++ ++ // Derived from task_statm in fs/proc/task_mmu.c ++ if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) { ++ share = get_mm_counter(mm, ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) ++ file_rss ++#else ++ MM_FILEPAGES ++#endif ++ ); ++ } ++ ++ // key of 1 indicates a pid ++ buf[len++] = 1; ++ buf[len++] = task->pid; ++ ++ for (i = 0; i < PROC_COUNT; ++i) { ++ if (proc_enabled[i]) { ++ switch (i) { ++ case PROC_SIZE: ++ value = mm->total_vm; ++ break; ++ case PROC_SHARE: ++ value = share; ++ break; ++ case PROC_TEXT: ++ value = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> PAGE_SHIFT; ++ break; ++ case PROC_DATA: ++ value = mm->total_vm - mm->shared_vm; ++ break; ++ } ++ ++ buf[len++] = proc_keys[i]; ++ buf[len++] = value * PAGE_SIZE; ++ } ++ } ++ ++ if (meminfo_enabled[MEMINFO_MEMUSED]) { ++ value = share + get_mm_counter(mm, ++#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) ++ anon_rss ++#else ++ MM_ANONPAGES ++#endif ++ ); ++ // Send resident for this pid ++ buf[len++] = meminfo_keys[MEMINFO_MEMUSED]; ++ buf[len++] = value * PAGE_SIZE; ++ } ++ ++ // Clear pid ++ buf[len++] = 1; ++ buf[len++] = 0; ++ ++ if (buffer) ++ *buffer = buf; ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_meminfo_interface = { ++ .create_files = gator_events_meminfo_create_files, ++ .start = gator_events_meminfo_start, ++ .stop = gator_events_meminfo_stop, ++ .read64 = gator_events_meminfo_read, ++ .read_proc = gator_events_meminfo_read_proc, ++}; ++ ++int gator_events_meminfo_init(void) ++{ ++ int i; ++ ++ meminfo_global_enabled = 0; ++ for (i = 0; i < MEMINFO_TOTAL; i++) { ++ meminfo_enabled[i] = 0; ++ meminfo_keys[i] = gator_events_get_key(); ++ } ++ ++ proc_global_enabled = 0; ++ for (i = 0; i < PROC_COUNT; ++i) { ++ proc_enabled[i] = 0; ++ proc_keys[i] = gator_events_get_key(); ++ } ++ ++ return gator_events_install(&gator_events_meminfo_interface); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_mmapped.c linux-3.10.30-cubox-i/drivers/gator/gator_events_mmapped.c +--- linux-3.10.30/drivers/gator/gator_events_mmapped.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_mmapped.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,209 @@ ++/* ++ * Example events provider ++ * ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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. ++ * ++ * Similar entries to those below must be present in the events.xml file. ++ * To add them to the events.xml, create an events-mmap.xml with the ++ * following contents and rebuild gatord: ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * When adding custom events, be sure do the following ++ * - add any needed .c files to the gator driver Makefile ++ * - call gator_events_install in the events init function ++ * - add the init function to GATOR_EVENTS_LIST in gator_main.c ++ * - add a new events-*.xml file to the gator daemon and rebuild ++ */ ++ ++#include ++#include ++#include ++ ++#include "gator.h" ++ ++#define MMAPPED_COUNTERS_NUM 3 ++ ++static int mmapped_global_enabled; ++ ++static struct { ++ unsigned long enabled; ++ unsigned long event; ++ unsigned long key; ++} mmapped_counters[MMAPPED_COUNTERS_NUM]; ++ ++static int mmapped_buffer[MMAPPED_COUNTERS_NUM * 2]; ++ ++static s64 prev_time; ++ ++/* Adds mmapped_cntX directories and enabled, event, and key files to /dev/gator/events */ ++static int gator_events_mmapped_create_files(struct super_block *sb, ++ struct dentry *root) ++{ ++ int i; ++ ++ for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { ++ char buf[16]; ++ struct dentry *dir; ++ ++ snprintf(buf, sizeof(buf), "mmapped_cnt%d", i); ++ dir = gatorfs_mkdir(sb, root, buf); ++ if (WARN_ON(!dir)) ++ return -1; ++ gatorfs_create_ulong(sb, dir, "enabled", ++ &mmapped_counters[i].enabled); ++ gatorfs_create_ulong(sb, dir, "event", ++ &mmapped_counters[i].event); ++ gatorfs_create_ro_ulong(sb, dir, "key", ++ &mmapped_counters[i].key); ++ } ++ ++ return 0; ++} ++ ++static int gator_events_mmapped_start(void) ++{ ++ int i; ++ struct timespec ts; ++ ++ getnstimeofday(&ts); ++ prev_time = timespec_to_ns(&ts); ++ ++ mmapped_global_enabled = 0; ++ for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { ++ if (mmapped_counters[i].enabled) { ++ mmapped_global_enabled = 1; ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++static void gator_events_mmapped_stop(void) ++{ ++} ++ ++/* This function "simulates" counters, generating values of fancy ++ * functions like sine or triangle... */ ++static int mmapped_simulate(int counter, int delta_in_us) ++{ ++ int result = 0; ++ ++ switch (counter) { ++ case 0: /* sort-of-sine */ ++ { ++ static int t = 0; ++ int x; ++ ++ t += delta_in_us; ++ if (t > 2048000) ++ t = 0; ++ ++ if (t % 1024000 < 512000) ++ x = 512000 - (t % 512000); ++ else ++ x = t % 512000; ++ ++ result = 32 * x / 512000; ++ result = result * result; ++ ++ if (t < 1024000) ++ result = 1922 - result; ++ } ++ break; ++ case 1: /* triangle */ ++ { ++ static int v, d = 1; ++ ++ v = v + d * delta_in_us; ++ if (v < 0) { ++ v = 0; ++ d = 1; ++ } else if (v > 1000000) { ++ v = 1000000; ++ d = -1; ++ } ++ ++ result = v; ++ } ++ break; ++ case 2: /* PWM signal */ ++ { ++ static int dc, x, t = 0; ++ ++ t += delta_in_us; ++ if (t > 1000000) ++ t = 0; ++ if (x / 1000000 != (x + delta_in_us) / 1000000) ++ dc = (dc + 100000) % 1000000; ++ x += delta_in_us; ++ ++ result = t < dc ? 0 : 10; ++ } ++ break; ++ } ++ ++ return result; ++} ++ ++static int gator_events_mmapped_read(int **buffer) ++{ ++ int i; ++ int len = 0; ++ int delta_in_us; ++ struct timespec ts; ++ s64 time; ++ ++ /* System wide counters - read from one core only */ ++ if (!on_primary_core() || !mmapped_global_enabled) ++ return 0; ++ ++ getnstimeofday(&ts); ++ time = timespec_to_ns(&ts); ++ delta_in_us = (int)(time - prev_time) / 1000; ++ prev_time = time; ++ ++ for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { ++ if (mmapped_counters[i].enabled) { ++ mmapped_buffer[len++] = mmapped_counters[i].key; ++ mmapped_buffer[len++] = ++ mmapped_simulate(mmapped_counters[i].event, ++ delta_in_us); ++ } ++ } ++ ++ if (buffer) ++ *buffer = mmapped_buffer; ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_mmapped_interface = { ++ .create_files = gator_events_mmapped_create_files, ++ .start = gator_events_mmapped_start, ++ .stop = gator_events_mmapped_stop, ++ .read = gator_events_mmapped_read, ++}; ++ ++/* Must not be static! */ ++int __init gator_events_mmapped_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { ++ mmapped_counters[i].enabled = 0; ++ mmapped_counters[i].key = gator_events_get_key(); ++ } ++ ++ return gator_events_install(&gator_events_mmapped_interface); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_net.c linux-3.10.30-cubox-i/drivers/gator/gator_events_net.c +--- linux-3.10.30/drivers/gator/gator_events_net.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_net.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,172 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++#include ++#include ++ ++#define NETRX 0 ++#define NETTX 1 ++#define TOTALNET 2 ++ ++static ulong netrx_enabled; ++static ulong nettx_enabled; ++static ulong netrx_key; ++static ulong nettx_key; ++static int rx_total, tx_total; ++static ulong netPrev[TOTALNET]; ++static int netGet[TOTALNET * 4]; ++ ++static struct timer_list net_wake_up_timer; ++ ++// Must be run in process context as the kernel function dev_get_stats() can sleep ++static void get_network_stats(struct work_struct *wsptr) ++{ ++ int rx = 0, tx = 0; ++ struct net_device *dev; ++ ++ for_each_netdev(&init_net, dev) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) ++ const struct net_device_stats *stats = dev_get_stats(dev); ++#else ++ struct rtnl_link_stats64 temp; ++ const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); ++#endif ++ rx += stats->rx_bytes; ++ tx += stats->tx_bytes; ++ } ++ rx_total = rx; ++ tx_total = tx; ++} ++ ++DECLARE_WORK(wq_get_stats, get_network_stats); ++ ++static void net_wake_up_handler(unsigned long unused_data) ++{ ++ // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater ++ schedule_work(&wq_get_stats); ++} ++ ++static void calculate_delta(int *rx, int *tx) ++{ ++ int rx_calc, tx_calc; ++ ++ rx_calc = (int)(rx_total - netPrev[NETRX]); ++ if (rx_calc < 0) ++ rx_calc = 0; ++ netPrev[NETRX] += rx_calc; ++ ++ tx_calc = (int)(tx_total - netPrev[NETTX]); ++ if (tx_calc < 0) ++ tx_calc = 0; ++ netPrev[NETTX] += tx_calc; ++ ++ *rx = rx_calc; ++ *tx = tx_calc; ++} ++ ++static int gator_events_net_create_files(struct super_block *sb, struct dentry *root) ++{ ++ // Network counters are not currently supported in RT-Preempt full because mod_timer is used ++#ifndef CONFIG_PREEMPT_RT_FULL ++ struct dentry *dir; ++ ++ dir = gatorfs_mkdir(sb, root, "Linux_net_rx"); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &netrx_enabled); ++ gatorfs_create_ro_ulong(sb, dir, "key", &netrx_key); ++ ++ dir = gatorfs_mkdir(sb, root, "Linux_net_tx"); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &nettx_enabled); ++ gatorfs_create_ro_ulong(sb, dir, "key", &nettx_key); ++#endif ++ ++ return 0; ++} ++ ++static int gator_events_net_start(void) ++{ ++ get_network_stats(0); ++ netPrev[NETRX] = rx_total; ++ netPrev[NETTX] = tx_total; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) ++ setup_timer(&net_wake_up_timer, net_wake_up_handler, 0); ++#else ++ setup_deferrable_timer_on_stack(&net_wake_up_timer, net_wake_up_handler, 0); ++#endif ++ return 0; ++} ++ ++static void gator_events_net_stop(void) ++{ ++ del_timer_sync(&net_wake_up_timer); ++ netrx_enabled = 0; ++ nettx_enabled = 0; ++} ++ ++static int gator_events_net_read(int **buffer) ++{ ++ int len, rx_delta, tx_delta; ++ static int last_rx_delta = 0, last_tx_delta = 0; ++ ++ if (!on_primary_core()) ++ return 0; ++ ++ if (!netrx_enabled && !nettx_enabled) ++ return 0; ++ ++ mod_timer(&net_wake_up_timer, jiffies + 1); ++ ++ calculate_delta(&rx_delta, &tx_delta); ++ ++ len = 0; ++ if (netrx_enabled && last_rx_delta != rx_delta) { ++ last_rx_delta = rx_delta; ++ netGet[len++] = netrx_key; ++ netGet[len++] = 0; // indicates to Streamline that rx_delta bytes were transmitted now, not since the last message ++ netGet[len++] = netrx_key; ++ netGet[len++] = rx_delta; ++ } ++ ++ if (nettx_enabled && last_tx_delta != tx_delta) { ++ last_tx_delta = tx_delta; ++ netGet[len++] = nettx_key; ++ netGet[len++] = 0; // indicates to Streamline that tx_delta bytes were transmitted now, not since the last message ++ netGet[len++] = nettx_key; ++ netGet[len++] = tx_delta; ++ } ++ ++ if (buffer) ++ *buffer = netGet; ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_net_interface = { ++ .create_files = gator_events_net_create_files, ++ .start = gator_events_net_start, ++ .stop = gator_events_net_stop, ++ .read = gator_events_net_read, ++}; ++ ++int gator_events_net_init(void) ++{ ++ netrx_key = gator_events_get_key(); ++ nettx_key = gator_events_get_key(); ++ ++ netrx_enabled = 0; ++ nettx_enabled = 0; ++ ++ return gator_events_install(&gator_events_net_interface); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_perf_pmu.c linux-3.10.30-cubox-i/drivers/gator/gator_events_perf_pmu.c +--- linux-3.10.30/drivers/gator/gator_events_perf_pmu.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_perf_pmu.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,587 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++ ++// gator_events_armvX.c is used for Linux 2.6.x ++#if GATOR_PERF_PMU_SUPPORT ++ ++#include ++#ifdef CONFIG_OF ++#include ++#endif ++#include ++#include ++ ++extern bool event_based_sampling; ++ ++// Maximum number of per-core counters - currently reserves enough space for two full hardware PMUs for big.LITTLE ++#define CNTMAX 16 ++#define CCI_400 4 ++// Maximum number of uncore counters ++// + 1 for the cci-400 cycles counter ++#define UCCNT (CCI_400 + 1) ++ ++// Default to 0 if unable to probe the revision which was the previous behavior ++#define DEFAULT_CCI_REVISION 0 ++ ++// A gator_attr is needed for every counter ++struct gator_attr { ++ // Set once in gator_events_perf_pmu_*_init - the name of the event in the gatorfs ++ char name[40]; ++ // Exposed in gatorfs - set by gatord to enable this counter ++ unsigned long enabled; ++ // Set once in gator_events_perf_pmu_*_init - the perf type to use, see perf_type_id in the perf_event.h header file. ++ unsigned long type; ++ // Exposed in gatorfs - set by gatord to select the event to collect ++ unsigned long event; ++ // Exposed in gatorfs - set by gatord with the sample period to use and enable EBS for this counter ++ unsigned long count; ++ // Exposed as read only in gatorfs - set once in __attr_init as the key to use in the APC data ++ unsigned long key; ++}; ++ ++// Per-core counter attributes ++static struct gator_attr attrs[CNTMAX]; ++// Number of initialized per-core counters ++static int attr_count; ++// Uncore counter attributes ++static struct gator_attr uc_attrs[UCCNT]; ++// Number of initialized uncore counters ++static int uc_attr_count; ++ ++struct gator_event { ++ int curr; ++ int prev; ++ int prev_delta; ++ bool zero; ++ struct perf_event *pevent; ++ struct perf_event_attr *pevent_attr; ++}; ++ ++static DEFINE_PER_CPU(struct gator_event[CNTMAX], events); ++static struct gator_event uc_events[UCCNT]; ++static DEFINE_PER_CPU(int[(CNTMAX + UCCNT)*2], perf_cnt); ++ ++static void gator_events_perf_pmu_stop(void); ++ ++static int __create_files(struct super_block *sb, struct dentry *root, struct gator_attr *const attr) ++{ ++ struct dentry *dir; ++ ++ if (attr->name[0] == '\0') { ++ return 0; ++ } ++ dir = gatorfs_mkdir(sb, root, attr->name); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &attr->enabled); ++ gatorfs_create_ulong(sb, dir, "count", &attr->count); ++ gatorfs_create_ro_ulong(sb, dir, "key", &attr->key); ++ gatorfs_create_ulong(sb, dir, "event", &attr->event); ++ ++ return 0; ++} ++ ++static int gator_events_perf_pmu_create_files(struct super_block *sb, struct dentry *root) ++{ ++ int cnt; ++ ++ for (cnt = 0; cnt < attr_count; cnt++) { ++ if (__create_files(sb, root, &attrs[cnt]) != 0) { ++ return -1; ++ } ++ } ++ ++ for (cnt = 0; cnt < uc_attr_count; cnt++) { ++ if (__create_files(sb, root, &uc_attrs[cnt]) != 0) { ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) ++static void ebs_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs) ++#else ++static void ebs_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs) ++#endif ++{ ++ gator_backtrace_handler(regs); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) ++static void dummy_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs) ++#else ++static void dummy_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs) ++#endif ++{ ++// Required as perf_event_create_kernel_counter() requires an overflow handler, even though all we do is poll ++} ++ ++static int gator_events_perf_pmu_read(int **buffer); ++ ++static int gator_events_perf_pmu_online(int **buffer, bool migrate) ++{ ++ return gator_events_perf_pmu_read(buffer); ++} ++ ++static void __online_dispatch(int cpu, bool migrate, struct gator_attr *const attr, struct gator_event *const event) ++{ ++ perf_overflow_handler_t handler; ++ ++ event->zero = true; ++ ++ if (event->pevent != NULL || event->pevent_attr == 0 || migrate) { ++ return; ++ } ++ ++ if (attr->count > 0) { ++ handler = ebs_overflow_handler; ++ } else { ++ handler = dummy_handler; ++ } ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) ++ event->pevent = perf_event_create_kernel_counter(event->pevent_attr, cpu, 0, handler); ++#else ++ event->pevent = perf_event_create_kernel_counter(event->pevent_attr, cpu, 0, handler, 0); ++#endif ++ if (IS_ERR(event->pevent)) { ++ pr_debug("gator: unable to online a counter on cpu %d\n", cpu); ++ event->pevent = NULL; ++ return; ++ } ++ ++ if (event->pevent->state != PERF_EVENT_STATE_ACTIVE) { ++ pr_debug("gator: inactive counter on cpu %d\n", cpu); ++ perf_event_release_kernel(event->pevent); ++ event->pevent = NULL; ++ return; ++ } ++} ++ ++static void gator_events_perf_pmu_online_dispatch(int cpu, bool migrate) ++{ ++ int cnt; ++ ++ cpu = pcpu_to_lcpu(cpu); ++ ++ for (cnt = 0; cnt < attr_count; cnt++) { ++ __online_dispatch(cpu, migrate, &attrs[cnt], &per_cpu(events, cpu)[cnt]); ++ } ++ ++ if (cpu == 0) { ++ for (cnt = 0; cnt < uc_attr_count; cnt++) { ++ __online_dispatch(cpu, migrate, &uc_attrs[cnt], &uc_events[cnt]); ++ } ++ } ++} ++ ++static void __offline_dispatch(int cpu, struct gator_event *const event) ++{ ++ struct perf_event *pe = NULL; ++ ++ if (event->pevent) { ++ pe = event->pevent; ++ event->pevent = NULL; ++ } ++ ++ if (pe) { ++ perf_event_release_kernel(pe); ++ } ++} ++ ++static void gator_events_perf_pmu_offline_dispatch(int cpu, bool migrate) ++{ ++ int cnt; ++ ++ if (migrate) { ++ return; ++ } ++ cpu = pcpu_to_lcpu(cpu); ++ ++ for (cnt = 0; cnt < attr_count; cnt++) { ++ __offline_dispatch(cpu, &per_cpu(events, cpu)[cnt]); ++ } ++ ++ if (cpu == 0) { ++ for (cnt = 0; cnt < uc_attr_count; cnt++) { ++ __offline_dispatch(cpu, &uc_events[cnt]); ++ } ++ } ++} ++ ++static int __check_ebs(struct gator_attr *const attr) ++{ ++ if (attr->count > 0) { ++ if (!event_based_sampling) { ++ event_based_sampling = true; ++ } else { ++ printk(KERN_WARNING "gator: Only one ebs counter is allowed\n"); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static int __start(struct gator_attr *const attr, struct gator_event *const event) ++{ ++ u32 size = sizeof(struct perf_event_attr); ++ ++ event->pevent = NULL; ++ if (!attr->enabled) { // Skip disabled counters ++ return 0; ++ } ++ ++ event->prev = 0; ++ event->curr = 0; ++ event->prev_delta = 0; ++ event->pevent_attr = kmalloc(size, GFP_KERNEL); ++ if (!event->pevent_attr) { ++ gator_events_perf_pmu_stop(); ++ return -1; ++ } ++ ++ memset(event->pevent_attr, 0, size); ++ event->pevent_attr->type = attr->type; ++ event->pevent_attr->size = size; ++ event->pevent_attr->config = attr->event; ++ event->pevent_attr->sample_period = attr->count; ++ event->pevent_attr->pinned = 1; ++ ++ return 0; ++} ++ ++static int gator_events_perf_pmu_start(void) ++{ ++ int cnt, cpu; ++ ++ event_based_sampling = false; ++ for (cnt = 0; cnt < attr_count; cnt++) { ++ if (__check_ebs(&attrs[cnt]) != 0) { ++ return -1; ++ } ++ } ++ ++ for (cnt = 0; cnt < uc_attr_count; cnt++) { ++ if (__check_ebs(&uc_attrs[cnt]) != 0) { ++ return -1; ++ } ++ } ++ ++ for_each_present_cpu(cpu) { ++ for (cnt = 0; cnt < attr_count; cnt++) { ++ if (__start(&attrs[cnt], &per_cpu(events, cpu)[cnt]) != 0) { ++ return -1; ++ } ++ } ++ } ++ ++ for (cnt = 0; cnt < uc_attr_count; cnt++) { ++ if (__start(&uc_attrs[cnt], &uc_events[cnt]) != 0) { ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++static void __event_stop(struct gator_event *const event) ++{ ++ if (event->pevent_attr) { ++ kfree(event->pevent_attr); ++ event->pevent_attr = NULL; ++ } ++} ++ ++static void __attr_stop(struct gator_attr *const attr) ++{ ++ attr->enabled = 0; ++ attr->event = 0; ++ attr->count = 0; ++} ++ ++static void gator_events_perf_pmu_stop(void) ++{ ++ unsigned int cnt, cpu; ++ ++ for_each_present_cpu(cpu) { ++ for (cnt = 0; cnt < attr_count; cnt++) { ++ __event_stop(&per_cpu(events, cpu)[cnt]); ++ } ++ } ++ ++ for (cnt = 0; cnt < uc_attr_count; cnt++) { ++ __event_stop(&uc_events[cnt]); ++ } ++ ++ for (cnt = 0; cnt < attr_count; cnt++) { ++ __attr_stop(&attrs[cnt]); ++ } ++ ++ for (cnt = 0; cnt < uc_attr_count; cnt++) { ++ __attr_stop(&uc_attrs[cnt]); ++ } ++} ++ ++static void __read(int *const len, int cpu, struct gator_attr *const attr, struct gator_event *const event) ++{ ++ int delta; ++ ++ struct perf_event *const ev = event->pevent; ++ if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) { ++ /* After creating the perf counter in __online_dispatch, there ++ * is a race condition between gator_events_perf_pmu_online and ++ * gator_events_perf_pmu_read. So have ++ * gator_events_perf_pmu_online call gator_events_perf_pmu_read ++ * and in __read check to see if it's the first call after ++ * __online_dispatch and if so, run the online code. ++ */ ++ if (event->zero) { ++ ev->pmu->read(ev); ++ event->prev = event->curr = local64_read(&ev->count); ++ event->prev_delta = 0; ++ per_cpu(perf_cnt, cpu)[(*len)++] = attr->key; ++ per_cpu(perf_cnt, cpu)[(*len)++] = 0; ++ event->zero = false; ++ } else { ++ ev->pmu->read(ev); ++ event->curr = local64_read(&ev->count); ++ delta = event->curr - event->prev; ++ if (delta != 0 || delta != event->prev_delta) { ++ event->prev_delta = delta; ++ event->prev = event->curr; ++ per_cpu(perf_cnt, cpu)[(*len)++] = attr->key; ++ if (delta < 0) { ++ delta *= -1; ++ } ++ per_cpu(perf_cnt, cpu)[(*len)++] = delta; ++ } ++ } ++ } ++} ++ ++static int gator_events_perf_pmu_read(int **buffer) ++{ ++ int cnt, len = 0; ++ const int cpu = get_logical_cpu(); ++ ++ for (cnt = 0; cnt < attr_count; cnt++) { ++ __read(&len, cpu, &attrs[cnt], &per_cpu(events, cpu)[cnt]); ++ } ++ ++ if (cpu == 0) { ++ for (cnt = 0; cnt < uc_attr_count; cnt++) { ++ __read(&len, cpu, &uc_attrs[cnt], &uc_events[cnt]); ++ } ++ } ++ ++ if (buffer) { ++ *buffer = per_cpu(perf_cnt, cpu); ++ } ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_perf_pmu_interface = { ++ .create_files = gator_events_perf_pmu_create_files, ++ .start = gator_events_perf_pmu_start, ++ .stop = gator_events_perf_pmu_stop, ++ .online = gator_events_perf_pmu_online, ++ .online_dispatch = gator_events_perf_pmu_online_dispatch, ++ .offline_dispatch = gator_events_perf_pmu_offline_dispatch, ++ .read = gator_events_perf_pmu_read, ++}; ++ ++static void __attr_init(struct gator_attr *const attr) ++{ ++ attr->name[0] = '\0'; ++ attr->enabled = 0; ++ attr->type = 0; ++ attr->event = 0; ++ attr->count = 0; ++ attr->key = gator_events_get_key(); ++} ++ ++#ifdef CONFIG_OF ++ ++static const struct of_device_id arm_cci_matches[] = { ++ {.compatible = "arm,cci-400" }, ++ {}, ++}; ++ ++static int probe_cci_revision(void) ++{ ++ struct device_node *np; ++ struct resource res; ++ void __iomem *cci_ctrl_base; ++ int rev; ++ int ret = DEFAULT_CCI_REVISION; ++ ++ np = of_find_matching_node(NULL, arm_cci_matches); ++ if (!np) { ++ return ret; ++ } ++ ++ if (of_address_to_resource(np, 0, &res)) { ++ goto node_put; ++ } ++ ++ cci_ctrl_base = ioremap(res.start, resource_size(&res)); ++ ++ rev = (readl_relaxed(cci_ctrl_base + 0xfe8) >> 4) & 0xf; ++ ++ if (rev <= 4) { ++ ret = 0; ++ } else if (rev <= 6) { ++ ret = 1; ++ } ++ ++ iounmap(cci_ctrl_base); ++ ++ node_put: ++ of_node_put(np); ++ ++ return ret; ++} ++ ++#else ++ ++static int probe_cci_revision(void) ++{ ++ return DEFAULT_CCI_REVISION; ++} ++ ++#endif ++ ++static void gator_events_perf_pmu_cci_init(const int type) ++{ ++ int cnt; ++ const char *cci_name; ++ ++ switch (probe_cci_revision()) { ++ case 0: ++ cci_name = "cci-400"; ++ break; ++ case 1: ++ cci_name = "cci-400-r1"; ++ break; ++ default: ++ pr_debug("gator: unrecognized cci-400 revision\n"); ++ return; ++ } ++ ++ snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", cci_name); ++ uc_attrs[uc_attr_count].type = type; ++ ++uc_attr_count; ++ ++ for (cnt = 0; cnt < CCI_400; ++cnt, ++uc_attr_count) { ++ struct gator_attr *const attr = &uc_attrs[uc_attr_count]; ++ snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", cci_name, cnt); ++ attr->type = type; ++ } ++} ++ ++static void gator_events_perf_pmu_cpu_init(const struct gator_cpu *const gator_cpu, const int type) ++{ ++ int cnt; ++ ++ snprintf(attrs[attr_count].name, sizeof(attrs[attr_count].name), "%s_ccnt", gator_cpu->pmnc_name); ++ attrs[attr_count].type = type; ++ ++attr_count; ++ ++ for (cnt = 0; cnt < gator_cpu->pmnc_counters; ++cnt, ++attr_count) { ++ struct gator_attr *const attr = &attrs[attr_count]; ++ snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", gator_cpu->pmnc_name, cnt); ++ attr->type = type; ++ } ++} ++ ++int gator_events_perf_pmu_init(void) ++{ ++ struct perf_event_attr pea; ++ struct perf_event *pe; ++ const struct gator_cpu *gator_cpu; ++ int type; ++ int cpu; ++ int cnt; ++ bool found_cpu = false; ++ ++ for (cnt = 0; cnt < CNTMAX; cnt++) { ++ __attr_init(&attrs[cnt]); ++ } ++ for (cnt = 0; cnt < UCCNT; cnt++) { ++ __attr_init(&uc_attrs[cnt]); ++ } ++ ++ memset(&pea, 0, sizeof(pea)); ++ pea.size = sizeof(pea); ++ pea.config = 0xFF; ++ attr_count = 0; ++ uc_attr_count = 0; ++ for (type = PERF_TYPE_MAX; type < 0x20; ++type) { ++ pea.type = type; ++ ++ // A particular PMU may work on some but not all cores, so try on each core ++ pe = NULL; ++ for_each_present_cpu(cpu) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) ++ pe = perf_event_create_kernel_counter(&pea, cpu, 0, dummy_handler); ++#else ++ pe = perf_event_create_kernel_counter(&pea, cpu, 0, dummy_handler, 0); ++#endif ++ if (!IS_ERR(pe)) { ++ break; ++ } ++ } ++ // Assume that valid PMUs are contiguous ++ if (IS_ERR(pe)) { ++ break; ++ } ++ ++ if (pe->pmu != NULL && type == pe->pmu->type) { ++ if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0) { ++ gator_events_perf_pmu_cci_init(type); ++ } else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) { ++ found_cpu = true; ++ gator_events_perf_pmu_cpu_init(gator_cpu, type); ++ } ++ // Initialize gator_attrs for dynamic PMUs here ++ } ++ ++ perf_event_release_kernel(pe); ++ } ++ ++ if (!found_cpu) { ++ const struct gator_cpu *const gator_cpu = gator_find_cpu_by_cpuid(gator_cpuid()); ++ if (gator_cpu == NULL) { ++ return -1; ++ } ++ gator_events_perf_pmu_cpu_init(gator_cpu, PERF_TYPE_RAW); ++ } ++ ++ // Initialize gator_attrs for non-dynamic PMUs here ++ ++ if (attr_count > CNTMAX) { ++ printk(KERN_ERR "gator: Too many perf counters\n"); ++ return -1; ++ } ++ ++ if (uc_attr_count > UCCNT) { ++ printk(KERN_ERR "gator: Too many perf uncore counters\n"); ++ return -1; ++ } ++ ++ return gator_events_install(&gator_events_perf_pmu_interface); ++} ++ ++#endif +diff -Nur linux-3.10.30/drivers/gator/gator_events_sched.c linux-3.10.30-cubox-i/drivers/gator/gator_events_sched.c +--- linux-3.10.30/drivers/gator/gator_events_sched.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_sched.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,113 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++#include ++ ++#define SCHED_SWITCH 0 ++#define SCHED_TOTAL (SCHED_SWITCH+1) ++ ++static ulong sched_switch_enabled; ++static ulong sched_switch_key; ++static DEFINE_PER_CPU(int[SCHED_TOTAL], schedCnt); ++static DEFINE_PER_CPU(int[SCHED_TOTAL * 2], schedGet); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) ++GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next)) ++#else ++GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next)) ++#endif ++{ ++ unsigned long flags; ++ ++ // disable interrupts to synchronize with gator_events_sched_read() ++ // spinlocks not needed since percpu buffers are used ++ local_irq_save(flags); ++ per_cpu(schedCnt, get_physical_cpu())[SCHED_SWITCH]++; ++ local_irq_restore(flags); ++} ++ ++static int gator_events_sched_create_files(struct super_block *sb, struct dentry *root) ++{ ++ struct dentry *dir; ++ ++ /* switch */ ++ dir = gatorfs_mkdir(sb, root, "Linux_sched_switch"); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &sched_switch_enabled); ++ gatorfs_create_ro_ulong(sb, dir, "key", &sched_switch_key); ++ ++ return 0; ++} ++ ++static int gator_events_sched_start(void) ++{ ++ // register tracepoints ++ if (sched_switch_enabled) ++ if (GATOR_REGISTER_TRACE(sched_switch)) ++ goto sched_switch_exit; ++ pr_debug("gator: registered scheduler event tracepoints\n"); ++ ++ return 0; ++ ++ // unregister tracepoints on error ++sched_switch_exit: ++ pr_err("gator: scheduler event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); ++ ++ return -1; ++} ++ ++static void gator_events_sched_stop(void) ++{ ++ if (sched_switch_enabled) ++ GATOR_UNREGISTER_TRACE(sched_switch); ++ pr_debug("gator: unregistered scheduler event tracepoints\n"); ++ ++ sched_switch_enabled = 0; ++} ++ ++static int gator_events_sched_read(int **buffer) ++{ ++ unsigned long flags; ++ int len, value; ++ int cpu = get_physical_cpu(); ++ ++ len = 0; ++ if (sched_switch_enabled) { ++ local_irq_save(flags); ++ value = per_cpu(schedCnt, cpu)[SCHED_SWITCH]; ++ per_cpu(schedCnt, cpu)[SCHED_SWITCH] = 0; ++ local_irq_restore(flags); ++ per_cpu(schedGet, cpu)[len++] = sched_switch_key; ++ per_cpu(schedGet, cpu)[len++] = value; ++ } ++ ++ if (buffer) ++ *buffer = per_cpu(schedGet, cpu); ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_sched_interface = { ++ .create_files = gator_events_sched_create_files, ++ .start = gator_events_sched_start, ++ .stop = gator_events_sched_stop, ++ .read = gator_events_sched_read, ++}; ++ ++int gator_events_sched_init(void) ++{ ++ sched_switch_enabled = 0; ++ ++ sched_switch_key = gator_events_get_key(); ++ ++ return gator_events_install(&gator_events_sched_interface); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_events_scorpion.c linux-3.10.30-cubox-i/drivers/gator/gator_events_scorpion.c +--- linux-3.10.30/drivers/gator/gator_events_scorpion.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_events_scorpion.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,669 @@ ++/** ++ * Copyright (C) ARM Limited 2011-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++ ++// gator_events_perf_pmu.c is used if perf is supported ++#if GATOR_NO_PERF_SUPPORT ++ ++static const char *pmnc_name; ++static int pmnc_counters; ++ ++// Per-CPU PMNC: config reg ++#define PMNC_E (1 << 0) /* Enable all counters */ ++#define PMNC_P (1 << 1) /* Reset all counters */ ++#define PMNC_C (1 << 2) /* Cycle counter reset */ ++#define PMNC_D (1 << 3) /* CCNT counts every 64th cpu cycle */ ++#define PMNC_X (1 << 4) /* Export to ETM */ ++#define PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug */ ++#define PMNC_MASK 0x3f /* Mask for writable bits */ ++ ++// ccnt reg ++#define CCNT_REG (1 << 31) ++ ++#define CCNT 0 ++#define CNT0 1 ++#define CNTMAX (4+1) ++ ++static unsigned long pmnc_enabled[CNTMAX]; ++static unsigned long pmnc_event[CNTMAX]; ++static unsigned long pmnc_key[CNTMAX]; ++ ++static DEFINE_PER_CPU(int[CNTMAX * 2], perfCnt); ++ ++enum scorpion_perf_types { ++ SCORPION_ICACHE_EXPL_INV = 0x4c, ++ SCORPION_ICACHE_MISS = 0x4d, ++ SCORPION_ICACHE_ACCESS = 0x4e, ++ SCORPION_ICACHE_CACHEREQ_L2 = 0x4f, ++ SCORPION_ICACHE_NOCACHE_L2 = 0x50, ++ SCORPION_HIQUP_NOPED = 0x51, ++ SCORPION_DATA_ABORT = 0x52, ++ SCORPION_IRQ = 0x53, ++ SCORPION_FIQ = 0x54, ++ SCORPION_ALL_EXCPT = 0x55, ++ SCORPION_UNDEF = 0x56, ++ SCORPION_SVC = 0x57, ++ SCORPION_SMC = 0x58, ++ SCORPION_PREFETCH_ABORT = 0x59, ++ SCORPION_INDEX_CHECK = 0x5a, ++ SCORPION_NULL_CHECK = 0x5b, ++ SCORPION_EXPL_ICIALLU = 0x5c, ++ SCORPION_IMPL_ICIALLU = 0x5d, ++ SCORPION_NONICIALLU_BTAC_INV = 0x5e, ++ SCORPION_ICIMVAU_IMPL_ICIALLU = 0x5f, ++ SCORPION_SPIPE_ONLY_CYCLES = 0x60, ++ SCORPION_XPIPE_ONLY_CYCLES = 0x61, ++ SCORPION_DUAL_CYCLES = 0x62, ++ SCORPION_DISPATCH_ANY_CYCLES = 0x63, ++ SCORPION_FIFO_FULLBLK_CMT = 0x64, ++ SCORPION_FAIL_COND_INST = 0x65, ++ SCORPION_PASS_COND_INST = 0x66, ++ SCORPION_ALLOW_VU_CLK = 0x67, ++ SCORPION_VU_IDLE = 0x68, ++ SCORPION_ALLOW_L2_CLK = 0x69, ++ SCORPION_L2_IDLE = 0x6a, ++ SCORPION_DTLB_IMPL_INV_SCTLR_DACR = 0x6b, ++ SCORPION_DTLB_EXPL_INV = 0x6c, ++ SCORPION_DTLB_MISS = 0x6d, ++ SCORPION_DTLB_ACCESS = 0x6e, ++ SCORPION_ITLB_MISS = 0x6f, ++ SCORPION_ITLB_IMPL_INV = 0x70, ++ SCORPION_ITLB_EXPL_INV = 0x71, ++ SCORPION_UTLB_D_MISS = 0x72, ++ SCORPION_UTLB_D_ACCESS = 0x73, ++ SCORPION_UTLB_I_MISS = 0x74, ++ SCORPION_UTLB_I_ACCESS = 0x75, ++ SCORPION_UTLB_INV_ASID = 0x76, ++ SCORPION_UTLB_INV_MVA = 0x77, ++ SCORPION_UTLB_INV_ALL = 0x78, ++ SCORPION_S2_HOLD_RDQ_UNAVAIL = 0x79, ++ SCORPION_S2_HOLD = 0x7a, ++ SCORPION_S2_HOLD_DEV_OP = 0x7b, ++ SCORPION_S2_HOLD_ORDER = 0x7c, ++ SCORPION_S2_HOLD_BARRIER = 0x7d, ++ SCORPION_VIU_DUAL_CYCLE = 0x7e, ++ SCORPION_VIU_SINGLE_CYCLE = 0x7f, ++ SCORPION_VX_PIPE_WAR_STALL_CYCLES = 0x80, ++ SCORPION_VX_PIPE_WAW_STALL_CYCLES = 0x81, ++ SCORPION_VX_PIPE_RAW_STALL_CYCLES = 0x82, ++ SCORPION_VX_PIPE_LOAD_USE_STALL = 0x83, ++ SCORPION_VS_PIPE_WAR_STALL_CYCLES = 0x84, ++ SCORPION_VS_PIPE_WAW_STALL_CYCLES = 0x85, ++ SCORPION_VS_PIPE_RAW_STALL_CYCLES = 0x86, ++ SCORPION_EXCEPTIONS_INV_OPERATION = 0x87, ++ SCORPION_EXCEPTIONS_DIV_BY_ZERO = 0x88, ++ SCORPION_COND_INST_FAIL_VX_PIPE = 0x89, ++ SCORPION_COND_INST_FAIL_VS_PIPE = 0x8a, ++ SCORPION_EXCEPTIONS_OVERFLOW = 0x8b, ++ SCORPION_EXCEPTIONS_UNDERFLOW = 0x8c, ++ SCORPION_EXCEPTIONS_DENORM = 0x8d, ++#ifdef CONFIG_ARCH_MSM_SCORPIONMP ++ SCORPIONMP_NUM_BARRIERS = 0x8e, ++ SCORPIONMP_BARRIER_CYCLES = 0x8f, ++#else ++ SCORPION_BANK_AB_HIT = 0x8e, ++ SCORPION_BANK_AB_ACCESS = 0x8f, ++ SCORPION_BANK_CD_HIT = 0x90, ++ SCORPION_BANK_CD_ACCESS = 0x91, ++ SCORPION_BANK_AB_DSIDE_HIT = 0x92, ++ SCORPION_BANK_AB_DSIDE_ACCESS = 0x93, ++ SCORPION_BANK_CD_DSIDE_HIT = 0x94, ++ SCORPION_BANK_CD_DSIDE_ACCESS = 0x95, ++ SCORPION_BANK_AB_ISIDE_HIT = 0x96, ++ SCORPION_BANK_AB_ISIDE_ACCESS = 0x97, ++ SCORPION_BANK_CD_ISIDE_HIT = 0x98, ++ SCORPION_BANK_CD_ISIDE_ACCESS = 0x99, ++ SCORPION_ISIDE_RD_WAIT = 0x9a, ++ SCORPION_DSIDE_RD_WAIT = 0x9b, ++ SCORPION_BANK_BYPASS_WRITE = 0x9c, ++ SCORPION_BANK_AB_NON_CASTOUT = 0x9d, ++ SCORPION_BANK_AB_L2_CASTOUT = 0x9e, ++ SCORPION_BANK_CD_NON_CASTOUT = 0x9f, ++ SCORPION_BANK_CD_L2_CASTOUT = 0xa0, ++#endif ++ MSM_MAX_EVT ++}; ++ ++struct scorp_evt { ++ u32 evt_type; ++ u32 val; ++ u8 grp; ++ u32 evt_type_act; ++}; ++ ++static const struct scorp_evt sc_evt[] = { ++ {SCORPION_ICACHE_EXPL_INV, 0x80000500, 0, 0x4d}, ++ {SCORPION_ICACHE_MISS, 0x80050000, 0, 0x4e}, ++ {SCORPION_ICACHE_ACCESS, 0x85000000, 0, 0x4f}, ++ {SCORPION_ICACHE_CACHEREQ_L2, 0x86000000, 0, 0x4f}, ++ {SCORPION_ICACHE_NOCACHE_L2, 0x87000000, 0, 0x4f}, ++ {SCORPION_HIQUP_NOPED, 0x80080000, 0, 0x4e}, ++ {SCORPION_DATA_ABORT, 0x8000000a, 0, 0x4c}, ++ {SCORPION_IRQ, 0x80000a00, 0, 0x4d}, ++ {SCORPION_FIQ, 0x800a0000, 0, 0x4e}, ++ {SCORPION_ALL_EXCPT, 0x8a000000, 0, 0x4f}, ++ {SCORPION_UNDEF, 0x8000000b, 0, 0x4c}, ++ {SCORPION_SVC, 0x80000b00, 0, 0x4d}, ++ {SCORPION_SMC, 0x800b0000, 0, 0x4e}, ++ {SCORPION_PREFETCH_ABORT, 0x8b000000, 0, 0x4f}, ++ {SCORPION_INDEX_CHECK, 0x8000000c, 0, 0x4c}, ++ {SCORPION_NULL_CHECK, 0x80000c00, 0, 0x4d}, ++ {SCORPION_EXPL_ICIALLU, 0x8000000d, 0, 0x4c}, ++ {SCORPION_IMPL_ICIALLU, 0x80000d00, 0, 0x4d}, ++ {SCORPION_NONICIALLU_BTAC_INV, 0x800d0000, 0, 0x4e}, ++ {SCORPION_ICIMVAU_IMPL_ICIALLU, 0x8d000000, 0, 0x4f}, ++ ++ {SCORPION_SPIPE_ONLY_CYCLES, 0x80000600, 1, 0x51}, ++ {SCORPION_XPIPE_ONLY_CYCLES, 0x80060000, 1, 0x52}, ++ {SCORPION_DUAL_CYCLES, 0x86000000, 1, 0x53}, ++ {SCORPION_DISPATCH_ANY_CYCLES, 0x89000000, 1, 0x53}, ++ {SCORPION_FIFO_FULLBLK_CMT, 0x8000000d, 1, 0x50}, ++ {SCORPION_FAIL_COND_INST, 0x800d0000, 1, 0x52}, ++ {SCORPION_PASS_COND_INST, 0x8d000000, 1, 0x53}, ++ {SCORPION_ALLOW_VU_CLK, 0x8000000e, 1, 0x50}, ++ {SCORPION_VU_IDLE, 0x80000e00, 1, 0x51}, ++ {SCORPION_ALLOW_L2_CLK, 0x800e0000, 1, 0x52}, ++ {SCORPION_L2_IDLE, 0x8e000000, 1, 0x53}, ++ ++ {SCORPION_DTLB_IMPL_INV_SCTLR_DACR, 0x80000001, 2, 0x54}, ++ {SCORPION_DTLB_EXPL_INV, 0x80000100, 2, 0x55}, ++ {SCORPION_DTLB_MISS, 0x80010000, 2, 0x56}, ++ {SCORPION_DTLB_ACCESS, 0x81000000, 2, 0x57}, ++ {SCORPION_ITLB_MISS, 0x80000200, 2, 0x55}, ++ {SCORPION_ITLB_IMPL_INV, 0x80020000, 2, 0x56}, ++ {SCORPION_ITLB_EXPL_INV, 0x82000000, 2, 0x57}, ++ {SCORPION_UTLB_D_MISS, 0x80000003, 2, 0x54}, ++ {SCORPION_UTLB_D_ACCESS, 0x80000300, 2, 0x55}, ++ {SCORPION_UTLB_I_MISS, 0x80030000, 2, 0x56}, ++ {SCORPION_UTLB_I_ACCESS, 0x83000000, 2, 0x57}, ++ {SCORPION_UTLB_INV_ASID, 0x80000400, 2, 0x55}, ++ {SCORPION_UTLB_INV_MVA, 0x80040000, 2, 0x56}, ++ {SCORPION_UTLB_INV_ALL, 0x84000000, 2, 0x57}, ++ {SCORPION_S2_HOLD_RDQ_UNAVAIL, 0x80000800, 2, 0x55}, ++ {SCORPION_S2_HOLD, 0x88000000, 2, 0x57}, ++ {SCORPION_S2_HOLD_DEV_OP, 0x80000900, 2, 0x55}, ++ {SCORPION_S2_HOLD_ORDER, 0x80090000, 2, 0x56}, ++ {SCORPION_S2_HOLD_BARRIER, 0x89000000, 2, 0x57}, ++ ++ {SCORPION_VIU_DUAL_CYCLE, 0x80000001, 4, 0x5c}, ++ {SCORPION_VIU_SINGLE_CYCLE, 0x80000100, 4, 0x5d}, ++ {SCORPION_VX_PIPE_WAR_STALL_CYCLES, 0x80000005, 4, 0x5c}, ++ {SCORPION_VX_PIPE_WAW_STALL_CYCLES, 0x80000500, 4, 0x5d}, ++ {SCORPION_VX_PIPE_RAW_STALL_CYCLES, 0x80050000, 4, 0x5e}, ++ {SCORPION_VX_PIPE_LOAD_USE_STALL, 0x80000007, 4, 0x5c}, ++ {SCORPION_VS_PIPE_WAR_STALL_CYCLES, 0x80000008, 4, 0x5c}, ++ {SCORPION_VS_PIPE_WAW_STALL_CYCLES, 0x80000800, 4, 0x5d}, ++ {SCORPION_VS_PIPE_RAW_STALL_CYCLES, 0x80080000, 4, 0x5e}, ++ {SCORPION_EXCEPTIONS_INV_OPERATION, 0x8000000b, 4, 0x5c}, ++ {SCORPION_EXCEPTIONS_DIV_BY_ZERO, 0x80000b00, 4, 0x5d}, ++ {SCORPION_COND_INST_FAIL_VX_PIPE, 0x800b0000, 4, 0x5e}, ++ {SCORPION_COND_INST_FAIL_VS_PIPE, 0x8b000000, 4, 0x5f}, ++ {SCORPION_EXCEPTIONS_OVERFLOW, 0x8000000c, 4, 0x5c}, ++ {SCORPION_EXCEPTIONS_UNDERFLOW, 0x80000c00, 4, 0x5d}, ++ {SCORPION_EXCEPTIONS_DENORM, 0x8c000000, 4, 0x5f}, ++ ++#ifdef CONFIG_ARCH_MSM_SCORPIONMP ++ {SCORPIONMP_NUM_BARRIERS, 0x80000e00, 3, 0x59}, ++ {SCORPIONMP_BARRIER_CYCLES, 0x800e0000, 3, 0x5a}, ++#else ++ {SCORPION_BANK_AB_HIT, 0x80000001, 3, 0x58}, ++ {SCORPION_BANK_AB_ACCESS, 0x80000100, 3, 0x59}, ++ {SCORPION_BANK_CD_HIT, 0x80010000, 3, 0x5a}, ++ {SCORPION_BANK_CD_ACCESS, 0x81000000, 3, 0x5b}, ++ {SCORPION_BANK_AB_DSIDE_HIT, 0x80000002, 3, 0x58}, ++ {SCORPION_BANK_AB_DSIDE_ACCESS, 0x80000200, 3, 0x59}, ++ {SCORPION_BANK_CD_DSIDE_HIT, 0x80020000, 3, 0x5a}, ++ {SCORPION_BANK_CD_DSIDE_ACCESS, 0x82000000, 3, 0x5b}, ++ {SCORPION_BANK_AB_ISIDE_HIT, 0x80000003, 3, 0x58}, ++ {SCORPION_BANK_AB_ISIDE_ACCESS, 0x80000300, 3, 0x59}, ++ {SCORPION_BANK_CD_ISIDE_HIT, 0x80030000, 3, 0x5a}, ++ {SCORPION_BANK_CD_ISIDE_ACCESS, 0x83000000, 3, 0x5b}, ++ {SCORPION_ISIDE_RD_WAIT, 0x80000009, 3, 0x58}, ++ {SCORPION_DSIDE_RD_WAIT, 0x80090000, 3, 0x5a}, ++ {SCORPION_BANK_BYPASS_WRITE, 0x8000000a, 3, 0x58}, ++ {SCORPION_BANK_AB_NON_CASTOUT, 0x8000000c, 3, 0x58}, ++ {SCORPION_BANK_AB_L2_CASTOUT, 0x80000c00, 3, 0x59}, ++ {SCORPION_BANK_CD_NON_CASTOUT, 0x800c0000, 3, 0x5a}, ++ {SCORPION_BANK_CD_L2_CASTOUT, 0x8c000000, 3, 0x5b}, ++#endif ++}; ++ ++static inline void scorpion_pmnc_write(u32 val) ++{ ++ val &= PMNC_MASK; ++ asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val)); ++} ++ ++static inline u32 scorpion_pmnc_read(void) ++{ ++ u32 val; ++ asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); ++ return val; ++} ++ ++static inline u32 scorpion_ccnt_read(void) ++{ ++ u32 val; ++ asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); ++ return val; ++} ++ ++static inline u32 scorpion_cntn_read(void) ++{ ++ u32 val; ++ asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); ++ return val; ++} ++ ++static inline u32 scorpion_pmnc_enable_counter(unsigned int cnt) ++{ ++ u32 val; ++ ++ if (cnt >= CNTMAX) { ++ pr_err("gator: CPU%u enabling wrong PMNC counter %d\n", smp_processor_id(), cnt); ++ return -1; ++ } ++ ++ if (cnt == CCNT) ++ val = CCNT_REG; ++ else ++ val = (1 << (cnt - CNT0)); ++ ++ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val)); ++ ++ return cnt; ++} ++ ++static inline u32 scorpion_pmnc_disable_counter(unsigned int cnt) ++{ ++ u32 val; ++ ++ if (cnt >= CNTMAX) { ++ pr_err("gator: CPU%u disabling wrong PMNC counter %d\n", smp_processor_id(), cnt); ++ return -1; ++ } ++ ++ if (cnt == CCNT) ++ val = CCNT_REG; ++ else ++ val = (1 << (cnt - CNT0)); ++ ++ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val)); ++ ++ return cnt; ++} ++ ++static inline int scorpion_pmnc_select_counter(unsigned int cnt) ++{ ++ u32 val; ++ ++ if ((cnt == CCNT) || (cnt >= CNTMAX)) { ++ pr_err("gator: CPU%u selecting wrong PMNC counter %d\n", smp_processor_id(), cnt); ++ return -1; ++ } ++ ++ val = (cnt - CNT0); ++ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val)); ++ ++ return cnt; ++} ++ ++static u32 scorpion_read_lpm0(void) ++{ ++ u32 val; ++ asm volatile("mrc p15, 0, %0, c15, c0, 0" : "=r" (val)); ++ return val; ++} ++ ++static void scorpion_write_lpm0(u32 val) ++{ ++ asm volatile("mcr p15, 0, %0, c15, c0, 0" : : "r" (val)); ++} ++ ++static u32 scorpion_read_lpm1(void) ++{ ++ u32 val; ++ asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (val)); ++ return val; ++} ++ ++static void scorpion_write_lpm1(u32 val) ++{ ++ asm volatile("mcr p15, 1, %0, c15, c0, 0" : : "r" (val)); ++} ++ ++static u32 scorpion_read_lpm2(void) ++{ ++ u32 val; ++ asm volatile("mrc p15, 2, %0, c15, c0, 0" : "=r" (val)); ++ return val; ++} ++ ++static void scorpion_write_lpm2(u32 val) ++{ ++ asm volatile("mcr p15, 2, %0, c15, c0, 0" : : "r" (val)); ++} ++ ++static u32 scorpion_read_l2lpm(void) ++{ ++ u32 val; ++ asm volatile("mrc p15, 3, %0, c15, c2, 0" : "=r" (val)); ++ return val; ++} ++ ++static void scorpion_write_l2lpm(u32 val) ++{ ++ asm volatile("mcr p15, 3, %0, c15, c2, 0" : : "r" (val)); ++} ++ ++static u32 scorpion_read_vlpm(void) ++{ ++ u32 val; ++ asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val)); ++ return val; ++} ++ ++static void scorpion_write_vlpm(u32 val) ++{ ++ asm volatile("mcr p10, 7, %0, c11, c0, 0" : : "r" (val)); ++} ++ ++struct scorpion_access_funcs { ++ u32(*read)(void); ++ void (*write)(u32); ++}; ++ ++struct scorpion_access_funcs scor_func[] = { ++ {scorpion_read_lpm0, scorpion_write_lpm0}, ++ {scorpion_read_lpm1, scorpion_write_lpm1}, ++ {scorpion_read_lpm2, scorpion_write_lpm2}, ++ {scorpion_read_l2lpm, scorpion_write_l2lpm}, ++ {scorpion_read_vlpm, scorpion_write_vlpm}, ++}; ++ ++u32 venum_orig_val; ++u32 fp_orig_val; ++ ++static void scorpion_pre_vlpm(void) ++{ ++ u32 venum_new_val; ++ u32 fp_new_val; ++ ++ /* CPACR Enable CP10 access */ ++ asm volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (venum_orig_val)); ++ venum_new_val = venum_orig_val | 0x00300000; ++ asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_new_val)); ++ /* Enable FPEXC */ ++ asm volatile("mrc p10, 7, %0, c8, c0, 0" : "=r" (fp_orig_val)); ++ fp_new_val = fp_orig_val | 0x40000000; ++ asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_new_val)); ++} ++ ++static void scorpion_post_vlpm(void) ++{ ++ /* Restore FPEXC */ ++ asm volatile("mcr p10, 7, %0, c8, c0, 0" : : "r" (fp_orig_val)); ++ /* Restore CPACR */ ++ asm volatile("mcr p15, 0, %0, c1, c0, 2" : : "r" (venum_orig_val)); ++} ++ ++#define COLMN0MASK 0x000000ff ++#define COLMN1MASK 0x0000ff00 ++#define COLMN2MASK 0x00ff0000 ++static u32 scorpion_get_columnmask(u32 setval) ++{ ++ if (setval & COLMN0MASK) ++ return 0xffffff00; ++ else if (setval & COLMN1MASK) ++ return 0xffff00ff; ++ else if (setval & COLMN2MASK) ++ return 0xff00ffff; ++ else ++ return 0x80ffffff; ++} ++ ++static void scorpion_evt_setup(u32 gr, u32 setval) ++{ ++ u32 val; ++ if (gr == 4) ++ scorpion_pre_vlpm(); ++ val = scorpion_get_columnmask(setval) & scor_func[gr].read(); ++ val = val | setval; ++ scor_func[gr].write(val); ++ if (gr == 4) ++ scorpion_post_vlpm(); ++} ++ ++static int get_scorpion_evtinfo(unsigned int evt_type, struct scorp_evt *evtinfo) ++{ ++ u32 idx; ++ if ((evt_type < 0x4c) || (evt_type >= MSM_MAX_EVT)) ++ return 0; ++ idx = evt_type - 0x4c; ++ if (sc_evt[idx].evt_type == evt_type) { ++ evtinfo->val = sc_evt[idx].val; ++ evtinfo->grp = sc_evt[idx].grp; ++ evtinfo->evt_type_act = sc_evt[idx].evt_type_act; ++ return 1; ++ } ++ return 0; ++} ++ ++static inline void scorpion_pmnc_write_evtsel(unsigned int cnt, u32 val) ++{ ++ if (scorpion_pmnc_select_counter(cnt) == cnt) { ++ if (val < 0x40) { ++ asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); ++ } else { ++ u32 zero = 0; ++ struct scorp_evt evtinfo; ++ // extract evtinfo.grp and evtinfo.tevt_type_act from val ++ if (get_scorpion_evtinfo(val, &evtinfo) == 0) ++ return; ++ asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (evtinfo.evt_type_act)); ++ asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (zero)); ++ scorpion_evt_setup(evtinfo.grp, val); ++ } ++ } ++} ++ ++static void scorpion_pmnc_reset_counter(unsigned int cnt) ++{ ++ u32 val = 0; ++ ++ if (cnt == CCNT) { ++ scorpion_pmnc_disable_counter(cnt); ++ ++ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val)); ++ ++ if (pmnc_enabled[cnt] != 0) ++ scorpion_pmnc_enable_counter(cnt); ++ ++ } else if (cnt >= CNTMAX) { ++ pr_err("gator: CPU%u resetting wrong PMNC counter %d\n", smp_processor_id(), cnt); ++ } else { ++ scorpion_pmnc_disable_counter(cnt); ++ ++ if (scorpion_pmnc_select_counter(cnt) == cnt) ++ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val)); ++ ++ if (pmnc_enabled[cnt] != 0) ++ scorpion_pmnc_enable_counter(cnt); ++ } ++} ++ ++static int gator_events_scorpion_create_files(struct super_block *sb, struct dentry *root) ++{ ++ struct dentry *dir; ++ int i; ++ ++ for (i = 0; i < pmnc_counters; i++) { ++ char buf[40]; ++ if (i == 0) { ++ snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name); ++ } else { ++ snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1); ++ } ++ dir = gatorfs_mkdir(sb, root, buf); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]); ++ gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]); ++ if (i > 0) { ++ gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]); ++ } ++ } ++ ++ return 0; ++} ++ ++static int gator_events_scorpion_online(int **buffer, bool migrate) ++{ ++ unsigned int cnt, len = 0, cpu = smp_processor_id(); ++ ++ if (scorpion_pmnc_read() & PMNC_E) { ++ scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E); ++ } ++ ++ /* Initialize & Reset PMNC: C bit and P bit */ ++ scorpion_pmnc_write(PMNC_P | PMNC_C); ++ ++ for (cnt = CCNT; cnt < CNTMAX; cnt++) { ++ unsigned long event; ++ ++ if (!pmnc_enabled[cnt]) ++ continue; ++ ++ // disable counter ++ scorpion_pmnc_disable_counter(cnt); ++ ++ event = pmnc_event[cnt] & 255; ++ ++ // Set event (if destined for PMNx counters), We don't need to set the event if it's a cycle count ++ if (cnt != CCNT) ++ scorpion_pmnc_write_evtsel(cnt, event); ++ ++ // reset counter ++ scorpion_pmnc_reset_counter(cnt); ++ ++ // Enable counter, do not enable interrupt for this counter ++ scorpion_pmnc_enable_counter(cnt); ++ } ++ ++ // enable ++ scorpion_pmnc_write(scorpion_pmnc_read() | PMNC_E); ++ ++ // read the counters and toss the invalid data, return zero instead ++ for (cnt = 0; cnt < pmnc_counters; cnt++) { ++ if (pmnc_enabled[cnt]) { ++ if (cnt == CCNT) { ++ scorpion_ccnt_read(); ++ } else if (scorpion_pmnc_select_counter(cnt) == cnt) { ++ scorpion_cntn_read(); ++ } ++ scorpion_pmnc_reset_counter(cnt); ++ ++ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; ++ per_cpu(perfCnt, cpu)[len++] = 0; ++ } ++ } ++ ++ if (buffer) ++ *buffer = per_cpu(perfCnt, cpu); ++ ++ return len; ++} ++ ++static int gator_events_scorpion_offline(int **buffer, bool migrate) ++{ ++ scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E); ++ return 0; ++} ++ ++static void gator_events_scorpion_stop(void) ++{ ++ unsigned int cnt; ++ ++ for (cnt = CCNT; cnt < CNTMAX; cnt++) { ++ pmnc_enabled[cnt] = 0; ++ pmnc_event[cnt] = 0; ++ } ++} ++ ++static int gator_events_scorpion_read(int **buffer) ++{ ++ int cnt, len = 0; ++ int cpu = smp_processor_id(); ++ ++ // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled ++ if (!(scorpion_pmnc_read() & PMNC_E)) { ++ return 0; ++ } ++ ++ for (cnt = 0; cnt < pmnc_counters; cnt++) { ++ if (pmnc_enabled[cnt]) { ++ int value; ++ if (cnt == CCNT) { ++ value = scorpion_ccnt_read(); ++ } else if (scorpion_pmnc_select_counter(cnt) == cnt) { ++ value = scorpion_cntn_read(); ++ } else { ++ value = 0; ++ } ++ scorpion_pmnc_reset_counter(cnt); ++ ++ per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; ++ per_cpu(perfCnt, cpu)[len++] = value; ++ } ++ } ++ ++ if (buffer) ++ *buffer = per_cpu(perfCnt, cpu); ++ ++ return len; ++} ++ ++static struct gator_interface gator_events_scorpion_interface = { ++ .create_files = gator_events_scorpion_create_files, ++ .stop = gator_events_scorpion_stop, ++ .online = gator_events_scorpion_online, ++ .offline = gator_events_scorpion_offline, ++ .read = gator_events_scorpion_read, ++}; ++ ++int gator_events_scorpion_init(void) ++{ ++ unsigned int cnt; ++ ++ switch (gator_cpuid()) { ++ case SCORPION: ++ pmnc_name = "Scorpion"; ++ pmnc_counters = 4; ++ break; ++ case SCORPIONMP: ++ pmnc_name = "ScorpionMP"; ++ pmnc_counters = 4; ++ break; ++ default: ++ return -1; ++ } ++ ++ pmnc_counters++; // CNT[n] + CCNT ++ ++ for (cnt = CCNT; cnt < CNTMAX; cnt++) { ++ pmnc_enabled[cnt] = 0; ++ pmnc_event[cnt] = 0; ++ pmnc_key[cnt] = gator_events_get_key(); ++ } ++ ++ return gator_events_install(&gator_events_scorpion_interface); ++} ++ ++#endif +diff -Nur linux-3.10.30/drivers/gator/gator_fs.c linux-3.10.30-cubox-i/drivers/gator/gator_fs.c +--- linux-3.10.30/drivers/gator/gator_fs.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_fs.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,382 @@ ++/** ++ * @file gatorfs.c ++ * ++ * @remark Copyright 2002 OProfile authors ++ * @remark Read the file COPYING ++ * ++ * @author John Levon ++ * ++ * A simple filesystem for configuration and ++ * access of oprofile. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define gatorfs_MAGIC 0x24051020 ++#define TMPBUFSIZE 50 ++DEFINE_SPINLOCK(gatorfs_lock); ++ ++static struct inode *gatorfs_get_inode(struct super_block *sb, int mode) ++{ ++ struct inode *inode = new_inode(sb); ++ ++ if (inode) { ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) ++ inode->i_ino = get_next_ino(); ++#endif ++ inode->i_mode = mode; ++ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; ++ } ++ return inode; ++} ++ ++static const struct super_operations s_ops = { ++ .statfs = simple_statfs, ++ .drop_inode = generic_delete_inode, ++}; ++ ++ssize_t gatorfs_str_to_user(char const *str, char __user *buf, size_t count, loff_t *offset) ++{ ++ return simple_read_from_buffer(buf, count, offset, str, strlen(str)); ++} ++ ++ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset) ++{ ++ char tmpbuf[TMPBUFSIZE]; ++ size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val); ++ if (maxlen > TMPBUFSIZE) ++ maxlen = TMPBUFSIZE; ++ return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen); ++} ++ ++ssize_t gatorfs_u64_to_user(u64 val, char __user *buf, size_t count, loff_t *offset) ++{ ++ char tmpbuf[TMPBUFSIZE]; ++ size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%llu\n", val); ++ if (maxlen > TMPBUFSIZE) ++ maxlen = TMPBUFSIZE; ++ return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen); ++} ++ ++int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count) ++{ ++ char tmpbuf[TMPBUFSIZE]; ++ unsigned long flags; ++ ++ if (!count) ++ return 0; ++ ++ if (count > TMPBUFSIZE - 1) ++ return -EINVAL; ++ ++ memset(tmpbuf, 0x0, TMPBUFSIZE); ++ ++ if (copy_from_user(tmpbuf, buf, count)) ++ return -EFAULT; ++ ++ spin_lock_irqsave(&gatorfs_lock, flags); ++ *val = simple_strtoul(tmpbuf, NULL, 0); ++ spin_unlock_irqrestore(&gatorfs_lock, flags); ++ return 0; ++} ++ ++int gatorfs_u64_from_user(u64 *val, char const __user *buf, size_t count) ++{ ++ char tmpbuf[TMPBUFSIZE]; ++ unsigned long flags; ++ ++ if (!count) ++ return 0; ++ ++ if (count > TMPBUFSIZE - 1) ++ return -EINVAL; ++ ++ memset(tmpbuf, 0x0, TMPBUFSIZE); ++ ++ if (copy_from_user(tmpbuf, buf, count)) ++ return -EFAULT; ++ ++ spin_lock_irqsave(&gatorfs_lock, flags); ++ *val = simple_strtoull(tmpbuf, NULL, 0); ++ spin_unlock_irqrestore(&gatorfs_lock, flags); ++ return 0; ++} ++ ++static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset) ++{ ++ unsigned long *val = file->private_data; ++ return gatorfs_ulong_to_user(*val, buf, count, offset); ++} ++ ++static ssize_t u64_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset) ++{ ++ u64 *val = file->private_data; ++ return gatorfs_u64_to_user(*val, buf, count, offset); ++} ++ ++static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset) ++{ ++ unsigned long *value = file->private_data; ++ int retval; ++ ++ if (*offset) ++ return -EINVAL; ++ ++ retval = gatorfs_ulong_from_user(value, buf, count); ++ ++ if (retval) ++ return retval; ++ return count; ++} ++ ++static ssize_t u64_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset) ++{ ++ u64 *value = file->private_data; ++ int retval; ++ ++ if (*offset) ++ return -EINVAL; ++ ++ retval = gatorfs_u64_from_user(value, buf, count); ++ ++ if (retval) ++ return retval; ++ return count; ++} ++ ++static int default_open(struct inode *inode, struct file *filp) ++{ ++ if (inode->i_private) ++ filp->private_data = inode->i_private; ++ return 0; ++} ++ ++static const struct file_operations ulong_fops = { ++ .read = ulong_read_file, ++ .write = ulong_write_file, ++ .open = default_open, ++}; ++ ++static const struct file_operations u64_fops = { ++ .read = u64_read_file, ++ .write = u64_write_file, ++ .open = default_open, ++}; ++ ++static const struct file_operations ulong_ro_fops = { ++ .read = ulong_read_file, ++ .open = default_open, ++}; ++ ++static const struct file_operations u64_ro_fops = { ++ .read = u64_read_file, ++ .open = default_open, ++}; ++ ++static struct dentry *__gatorfs_create_file(struct super_block *sb, ++ struct dentry *root, ++ char const *name, ++ const struct file_operations *fops, ++ int perm) ++{ ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ dentry = d_alloc_name(root, name); ++ if (!dentry) ++ return NULL; ++ inode = gatorfs_get_inode(sb, S_IFREG | perm); ++ if (!inode) { ++ dput(dentry); ++ return NULL; ++ } ++ inode->i_fop = fops; ++ d_add(dentry, inode); ++ return dentry; ++} ++ ++int gatorfs_create_ulong(struct super_block *sb, struct dentry *root, ++ char const *name, unsigned long *val) ++{ ++ struct dentry *d = __gatorfs_create_file(sb, root, name, ++ &ulong_fops, 0644); ++ if (!d) ++ return -EFAULT; ++ ++ d->d_inode->i_private = val; ++ return 0; ++} ++ ++int gatorfs_create_u64(struct super_block *sb, struct dentry *root, ++ char const *name, u64 *val) ++{ ++ struct dentry *d = __gatorfs_create_file(sb, root, name, ++ &u64_fops, 0644); ++ if (!d) ++ return -EFAULT; ++ ++ d->d_inode->i_private = val; ++ return 0; ++} ++ ++int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root, ++ char const *name, unsigned long *val) ++{ ++ struct dentry *d = __gatorfs_create_file(sb, root, name, ++ &ulong_ro_fops, 0444); ++ if (!d) ++ return -EFAULT; ++ ++ d->d_inode->i_private = val; ++ return 0; ++} ++ ++int gatorfs_create_ro_u64(struct super_block *sb, struct dentry *root, ++ char const *name, u64 * val) ++{ ++ struct dentry *d = ++ __gatorfs_create_file(sb, root, name, &u64_ro_fops, 0444); ++ if (!d) ++ return -EFAULT; ++ ++ d->d_inode->i_private = val; ++ return 0; ++} ++ ++static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset) ++{ ++ atomic_t *val = file->private_data; ++ return gatorfs_ulong_to_user(atomic_read(val), buf, count, offset); ++} ++ ++static const struct file_operations atomic_ro_fops = { ++ .read = atomic_read_file, ++ .open = default_open, ++}; ++ ++int gatorfs_create_ro_atomic(struct super_block *sb, struct dentry *root, ++ char const *name, atomic_t *val) ++{ ++ struct dentry *d = __gatorfs_create_file(sb, root, name, ++ &atomic_ro_fops, 0444); ++ if (!d) ++ return -EFAULT; ++ ++ d->d_inode->i_private = val; ++ return 0; ++} ++ ++int gatorfs_create_file(struct super_block *sb, struct dentry *root, ++ char const *name, const struct file_operations *fops) ++{ ++ if (!__gatorfs_create_file(sb, root, name, fops, 0644)) ++ return -EFAULT; ++ return 0; ++} ++ ++int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root, ++ char const *name, ++ const struct file_operations *fops, int perm) ++{ ++ if (!__gatorfs_create_file(sb, root, name, fops, perm)) ++ return -EFAULT; ++ return 0; ++} ++ ++struct dentry *gatorfs_mkdir(struct super_block *sb, ++ struct dentry *root, char const *name) ++{ ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ dentry = d_alloc_name(root, name); ++ if (!dentry) ++ return NULL; ++ inode = gatorfs_get_inode(sb, S_IFDIR | 0755); ++ if (!inode) { ++ dput(dentry); ++ return NULL; ++ } ++ inode->i_op = &simple_dir_inode_operations; ++ inode->i_fop = &simple_dir_operations; ++ d_add(dentry, inode); ++ return dentry; ++} ++ ++static int gatorfs_fill_super(struct super_block *sb, void *data, int silent) ++{ ++ struct inode *root_inode; ++ struct dentry *root_dentry; ++ ++ sb->s_blocksize = PAGE_CACHE_SIZE; ++ sb->s_blocksize_bits = PAGE_CACHE_SHIFT; ++ sb->s_magic = gatorfs_MAGIC; ++ sb->s_op = &s_ops; ++ sb->s_time_gran = 1; ++ ++ root_inode = gatorfs_get_inode(sb, S_IFDIR | 0755); ++ if (!root_inode) ++ return -ENOMEM; ++ root_inode->i_op = &simple_dir_inode_operations; ++ root_inode->i_fop = &simple_dir_operations; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) ++ root_dentry = d_alloc_root(root_inode); ++#else ++ root_dentry = d_make_root(root_inode); ++#endif ++ ++ if (!root_dentry) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) ++ iput(root_inode); ++#endif ++ return -ENOMEM; ++ } ++ ++ sb->s_root = root_dentry; ++ ++ gator_op_create_files(sb, root_dentry); ++ ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) ++static int gatorfs_get_sb(struct file_system_type *fs_type, ++ int flags, const char *dev_name, void *data, ++ struct vfsmount *mnt) ++{ ++ return get_sb_single(fs_type, flags, data, gatorfs_fill_super, mnt); ++} ++#else ++static struct dentry *gatorfs_mount(struct file_system_type *fs_type, ++ int flags, const char *dev_name, void *data) ++{ ++ return mount_nodev(fs_type, flags, data, gatorfs_fill_super); ++} ++#endif ++ ++static struct file_system_type gatorfs_type = { ++ .owner = THIS_MODULE, ++ .name = "gatorfs", ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) ++ .get_sb = gatorfs_get_sb, ++#else ++ .mount = gatorfs_mount, ++#endif ++ ++ .kill_sb = kill_litter_super, ++}; ++ ++int __init gatorfs_register(void) ++{ ++ return register_filesystem(&gatorfs_type); ++} ++ ++void gatorfs_unregister(void) ++{ ++ unregister_filesystem(&gatorfs_type); ++} +diff -Nur linux-3.10.30/drivers/gator/gator_hrtimer_gator.c linux-3.10.30-cubox-i/drivers/gator/gator_hrtimer_gator.c +--- linux-3.10.30/drivers/gator/gator_hrtimer_gator.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_hrtimer_gator.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,86 @@ ++/** ++ * Copyright (C) ARM Limited 2011-2013. All rights reserved. ++ * ++ * This program 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. ++ * ++ */ ++ ++// gator_hrtimer_perf.c is used if perf is supported ++// update, gator_hrtimer_gator.c always used until issues resolved with perf hrtimers ++#if 1 ++ ++void (*callback)(void); ++DEFINE_PER_CPU(struct hrtimer, percpu_hrtimer); ++DEFINE_PER_CPU(ktime_t, hrtimer_expire); ++DEFINE_PER_CPU(int, hrtimer_is_active); ++static ktime_t profiling_interval; ++static void gator_hrtimer_online(void); ++static void gator_hrtimer_offline(void); ++ ++static enum hrtimer_restart gator_hrtimer_notify(struct hrtimer *hrtimer) ++{ ++ int cpu = get_logical_cpu(); ++ hrtimer_forward(hrtimer, per_cpu(hrtimer_expire, cpu), profiling_interval); ++ per_cpu(hrtimer_expire, cpu) = ktime_add(per_cpu(hrtimer_expire, cpu), profiling_interval); ++ (*callback)(); ++ return HRTIMER_RESTART; ++} ++ ++static void gator_hrtimer_online(void) ++{ ++ int cpu = get_logical_cpu(); ++ struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu); ++ ++ if (per_cpu(hrtimer_is_active, cpu) || profiling_interval.tv64 == 0) ++ return; ++ ++ per_cpu(hrtimer_is_active, cpu) = 1; ++ hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); ++ hrtimer->function = gator_hrtimer_notify; ++#ifdef CONFIG_PREEMPT_RT_BASE ++ hrtimer->irqsafe = 1; ++#endif ++ per_cpu(hrtimer_expire, cpu) = ktime_add(hrtimer->base->get_time(), profiling_interval); ++ hrtimer_start(hrtimer, per_cpu(hrtimer_expire, cpu), HRTIMER_MODE_ABS_PINNED); ++} ++ ++static void gator_hrtimer_offline(void) ++{ ++ int cpu = get_logical_cpu(); ++ struct hrtimer *hrtimer = &per_cpu(percpu_hrtimer, cpu); ++ ++ if (!per_cpu(hrtimer_is_active, cpu)) ++ return; ++ ++ per_cpu(hrtimer_is_active, cpu) = 0; ++ hrtimer_cancel(hrtimer); ++} ++ ++static int gator_hrtimer_init(int interval, void (*func)(void)) ++{ ++ int cpu; ++ ++ (callback) = (func); ++ ++ for_each_present_cpu(cpu) { ++ per_cpu(hrtimer_is_active, cpu) = 0; ++ } ++ ++ // calculate profiling interval ++ if (interval > 0) { ++ profiling_interval = ns_to_ktime(1000000000UL / interval); ++ } else { ++ profiling_interval.tv64 = 0; ++ } ++ ++ return 0; ++} ++ ++static void gator_hrtimer_shutdown(void) ++{ ++ /* empty */ ++} ++ ++#endif +diff -Nur linux-3.10.30/drivers/gator/gator_hrtimer_perf.c linux-3.10.30-cubox-i/drivers/gator/gator_hrtimer_perf.c +--- linux-3.10.30/drivers/gator/gator_hrtimer_perf.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_hrtimer_perf.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,113 @@ ++/** ++ * Copyright (C) ARM Limited 2011-2013. All rights reserved. ++ * ++ * This program 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. ++ * ++ */ ++ ++// gator_hrtimer_gator.c is used if perf is not supported ++// update, gator_hrtimer_gator.c always used until issues resolved with perf hrtimers ++#if 0 ++ ++// Note: perf Cortex support added in 2.6.35 and PERF_COUNT_SW_CPU_CLOCK/hrtimer broken on 2.6.35 and 2.6.36 ++// not relevant as this code is not active until 3.0.0, but wanted to document the issue ++ ++void (*callback)(void); ++static int profiling_interval; ++static DEFINE_PER_CPU(struct perf_event *, perf_hrtimer); ++static DEFINE_PER_CPU(struct perf_event_attr *, perf_hrtimer_attr); ++ ++static void gator_hrtimer_shutdown(void); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) ++static void hrtimer_overflow_handler(struct perf_event *event, int unused, struct perf_sample_data *data, struct pt_regs *regs) ++#else ++static void hrtimer_overflow_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs) ++#endif ++{ ++ (*callback)(); ++} ++ ++static int gator_online_single_hrtimer(int cpu) ++{ ++ if (per_cpu(perf_hrtimer, cpu) != 0 || per_cpu(perf_hrtimer_attr, cpu) == 0) ++ return 0; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) ++ per_cpu(perf_hrtimer, cpu) = perf_event_create_kernel_counter(per_cpu(perf_hrtimer_attr, cpu), cpu, 0, hrtimer_overflow_handler); ++#else ++ per_cpu(perf_hrtimer, cpu) = perf_event_create_kernel_counter(per_cpu(perf_hrtimer_attr, cpu), cpu, 0, hrtimer_overflow_handler, 0); ++#endif ++ if (IS_ERR(per_cpu(perf_hrtimer, cpu))) { ++ per_cpu(perf_hrtimer, cpu) = NULL; ++ return -1; ++ } ++ ++ if (per_cpu(perf_hrtimer, cpu)->state != PERF_EVENT_STATE_ACTIVE) { ++ perf_event_release_kernel(per_cpu(perf_hrtimer, cpu)); ++ per_cpu(perf_hrtimer, cpu) = NULL; ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void gator_hrtimer_online(int cpu) ++{ ++ if (gator_online_single_hrtimer(cpu) < 0) { ++ pr_debug("gator: unable to online the hrtimer on cpu%d\n", cpu); ++ } ++} ++ ++static void gator_hrtimer_offline(int cpu) ++{ ++ if (per_cpu(perf_hrtimer, cpu)) { ++ perf_event_release_kernel(per_cpu(perf_hrtimer, cpu)); ++ per_cpu(perf_hrtimer, cpu) = NULL; ++ } ++} ++ ++static int gator_hrtimer_init(int interval, void (*func)(void)) ++{ ++ u32 size = sizeof(struct perf_event_attr); ++ int cpu; ++ ++ callback = func; ++ ++ // calculate profiling interval ++ profiling_interval = 1000000000 / interval; ++ ++ for_each_present_cpu(cpu) { ++ per_cpu(perf_hrtimer, cpu) = 0; ++ per_cpu(perf_hrtimer_attr, cpu) = kmalloc(size, GFP_KERNEL); ++ if (per_cpu(perf_hrtimer_attr, cpu) == 0) { ++ gator_hrtimer_shutdown(); ++ return -1; ++ } ++ ++ memset(per_cpu(perf_hrtimer_attr, cpu), 0, size); ++ per_cpu(perf_hrtimer_attr, cpu)->type = PERF_TYPE_SOFTWARE; ++ per_cpu(perf_hrtimer_attr, cpu)->size = size; ++ per_cpu(perf_hrtimer_attr, cpu)->config = PERF_COUNT_SW_CPU_CLOCK; ++ per_cpu(perf_hrtimer_attr, cpu)->sample_period = profiling_interval; ++ per_cpu(perf_hrtimer_attr, cpu)->pinned = 1; ++ } ++ ++ return 0; ++} ++ ++static void gator_hrtimer_shutdown(void) ++{ ++ int cpu; ++ ++ for_each_present_cpu(cpu) { ++ if (per_cpu(perf_hrtimer_attr, cpu)) { ++ kfree(per_cpu(perf_hrtimer_attr, cpu)); ++ per_cpu(perf_hrtimer_attr, cpu) = NULL; ++ } ++ } ++} ++ ++#endif +diff -Nur linux-3.10.30/drivers/gator/gator_iks.c linux-3.10.30-cubox-i/drivers/gator/gator_iks.c +--- linux-3.10.30/drivers/gator/gator_iks.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_iks.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,197 @@ ++/** ++ * Copyright (C) ARM Limited 2013. All rights reserved. ++ * ++ * This program 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. ++ * ++ */ ++ ++#if GATOR_IKS_SUPPORT ++ ++#include ++#include ++#include ++#include ++ ++static bool map_cpuids; ++static int mpidr_cpuids[NR_CPUS]; ++static const struct gator_cpu * mpidr_cpus[NR_CPUS]; ++static int __lcpu_to_pcpu[NR_CPUS]; ++ ++static const struct gator_cpu *gator_find_cpu_by_dt_name(const char *const name) ++{ ++ int i; ++ ++ for (i = 0; gator_cpus[i].cpuid != 0; ++i) { ++ const struct gator_cpu *const gator_cpu = &gator_cpus[i]; ++ if (gator_cpu->dt_name != NULL && strcmp(gator_cpu->dt_name, name) == 0) { ++ return gator_cpu; ++ } ++ } ++ ++ return NULL; ++} ++ ++static void calc_first_cluster_size(void) ++{ ++ int len; ++ const u32 *val; ++ const char *compatible; ++ struct device_node *cn = NULL; ++ int mpidr_cpuids_count = 0; ++ ++ // Zero is a valid cpuid, so initialize the array to 0xff's ++ memset(&mpidr_cpuids, 0xff, sizeof(mpidr_cpuids)); ++ memset(&mpidr_cpus, 0, sizeof(mpidr_cpus)); ++ ++ while ((cn = of_find_node_by_type(cn, "cpu"))) { ++ BUG_ON(mpidr_cpuids_count >= NR_CPUS); ++ ++ val = of_get_property(cn, "reg", &len); ++ if (!val || len != 4) { ++ pr_err("%s missing reg property\n", cn->full_name); ++ continue; ++ } ++ compatible = of_get_property(cn, "compatible", NULL); ++ if (compatible == NULL) { ++ pr_err("%s missing compatible property\n", cn->full_name); ++ continue; ++ } ++ ++ mpidr_cpuids[mpidr_cpuids_count] = be32_to_cpup(val); ++ mpidr_cpus[mpidr_cpuids_count] = gator_find_cpu_by_dt_name(compatible); ++ ++mpidr_cpuids_count; ++ } ++ ++ map_cpuids = (mpidr_cpuids_count == nr_cpu_ids); ++} ++ ++static int linearize_mpidr(int mpidr) ++{ ++ int i; ++ for (i = 0; i < nr_cpu_ids; ++i) { ++ if (mpidr_cpuids[i] == mpidr) { ++ return i; ++ } ++ } ++ ++ BUG(); ++} ++ ++int lcpu_to_pcpu(const int lcpu) ++{ ++ int pcpu; ++ ++ if (!map_cpuids) ++ return lcpu; ++ ++ BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0); ++ pcpu = __lcpu_to_pcpu[lcpu]; ++ BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0); ++ return pcpu; ++} ++ ++int pcpu_to_lcpu(const int pcpu) ++{ ++ int lcpu; ++ ++ if (!map_cpuids) ++ return pcpu; ++ ++ BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0); ++ for (lcpu = 0; lcpu < nr_cpu_ids; ++lcpu) { ++ if (__lcpu_to_pcpu[lcpu] == pcpu) { ++ BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0); ++ return lcpu; ++ } ++ } ++ BUG(); ++} ++ ++static void gator_update_cpu_mapping(u32 cpu_hwid) ++{ ++ int lcpu = smp_processor_id(); ++ int pcpu = linearize_mpidr(cpu_hwid & MPIDR_HWID_BITMASK); ++ BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0); ++ BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0); ++ __lcpu_to_pcpu[lcpu] = pcpu; ++} ++ ++GATOR_DEFINE_PROBE(cpu_migrate_begin, TP_PROTO(u64 timestamp, u32 cpu_hwid)) ++{ ++ const int cpu = get_physical_cpu(); ++ ++ gator_timer_offline((void *)1); ++ gator_timer_offline_dispatch(cpu, true); ++} ++ ++GATOR_DEFINE_PROBE(cpu_migrate_finish, TP_PROTO(u64 timestamp, u32 cpu_hwid)) ++{ ++ int cpu; ++ ++ gator_update_cpu_mapping(cpu_hwid); ++ ++ // get_physical_cpu must be called after gator_update_cpu_mapping ++ cpu = get_physical_cpu(); ++ gator_timer_online_dispatch(cpu, true); ++ gator_timer_online((void *)1); ++} ++ ++GATOR_DEFINE_PROBE(cpu_migrate_current, TP_PROTO(u64 timestamp, u32 cpu_hwid)) ++{ ++ gator_update_cpu_mapping(cpu_hwid); ++} ++ ++static void gator_send_iks_core_names(void) ++{ ++ int cpu; ++ // Send the cpu names ++ preempt_disable(); ++ for (cpu = 0; cpu < nr_cpu_ids; ++cpu) { ++ if (mpidr_cpus[cpu] != NULL) { ++ gator_send_core_name(cpu, mpidr_cpus[cpu]->cpuid, mpidr_cpus[cpu]); ++ } ++ } ++ preempt_enable(); ++} ++ ++static int gator_migrate_start(void) ++{ ++ int retval = 0; ++ ++ if (!map_cpuids) ++ return retval; ++ ++ if (retval == 0) ++ retval = GATOR_REGISTER_TRACE(cpu_migrate_begin); ++ if (retval == 0) ++ retval = GATOR_REGISTER_TRACE(cpu_migrate_finish); ++ if (retval == 0) ++ retval = GATOR_REGISTER_TRACE(cpu_migrate_current); ++ if (retval == 0) { ++ // Initialize the logical to physical cpu mapping ++ memset(&__lcpu_to_pcpu, 0xff, sizeof(__lcpu_to_pcpu)); ++ bL_switcher_trace_trigger(); ++ } ++ return retval; ++} ++ ++static void gator_migrate_stop(void) ++{ ++ if (!map_cpuids) ++ return; ++ ++ GATOR_UNREGISTER_TRACE(cpu_migrate_current); ++ GATOR_UNREGISTER_TRACE(cpu_migrate_finish); ++ GATOR_UNREGISTER_TRACE(cpu_migrate_begin); ++} ++ ++#else ++ ++#define calc_first_cluster_size() ++#define gator_send_iks_core_names() ++#define gator_migrate_start() 0 ++#define gator_migrate_stop() ++ ++#endif +diff -Nur linux-3.10.30/drivers/gator/gator_main.c linux-3.10.30-cubox-i/drivers/gator/gator_main.c +--- linux-3.10.30/drivers/gator/gator_main.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_main.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,1532 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 version must match the gator daemon version ++#define PROTOCOL_VERSION 17 ++static unsigned long gator_protocol_version = PROTOCOL_VERSION; ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "gator.h" ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) ++#error kernels prior to 2.6.32 are not supported ++#endif ++ ++#if defined(MODULE) && !defined(CONFIG_MODULES) ++#error Cannot build a module against a kernel that does not support modules. To resolve, either rebuild the kernel to support modules or build gator as part of the kernel. ++#endif ++ ++#if !defined(CONFIG_GENERIC_TRACER) && !defined(CONFIG_TRACING) ++#error gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined ++#endif ++ ++#ifndef CONFIG_PROFILING ++#error gator requires the kernel to have CONFIG_PROFILING defined ++#endif ++ ++#ifndef CONFIG_HIGH_RES_TIMERS ++#error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined to support PC sampling ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) ++#error gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems ++#endif ++ ++#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT)) ++#ifndef CONFIG_PERF_EVENTS ++#warning gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters ++#elif !defined CONFIG_HW_PERF_EVENTS ++#warning gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters ++#endif ++#endif ++ ++/****************************************************************************** ++ * DEFINES ++ ******************************************************************************/ ++#define SUMMARY_BUFFER_SIZE (1*1024) ++#define BACKTRACE_BUFFER_SIZE (128*1024) ++#define NAME_BUFFER_SIZE (64*1024) ++#define COUNTER_BUFFER_SIZE (64*1024) // counters have the core as part of the data and the core value in the frame header may be discarded ++#define BLOCK_COUNTER_BUFFER_SIZE (128*1024) ++#define ANNOTATE_BUFFER_SIZE (128*1024) // annotate counters have the core as part of the data and the core value in the frame header may be discarded ++#define SCHED_TRACE_BUFFER_SIZE (128*1024) ++#define GPU_TRACE_BUFFER_SIZE (64*1024) // gpu trace counters have the core as part of the data and the core value in the frame header may be discarded ++#define IDLE_BUFFER_SIZE (32*1024) // idle counters have the core as part of the data and the core value in the frame header may be discarded ++ ++#define NO_COOKIE 0U ++#define UNRESOLVED_COOKIE ~0U ++ ++#define FRAME_SUMMARY 1 ++#define FRAME_BACKTRACE 2 ++#define FRAME_NAME 3 ++#define FRAME_COUNTER 4 ++#define FRAME_BLOCK_COUNTER 5 ++#define FRAME_ANNOTATE 6 ++#define FRAME_SCHED_TRACE 7 ++#define FRAME_GPU_TRACE 8 ++#define FRAME_IDLE 9 ++ ++#define MESSAGE_END_BACKTRACE 1 ++ ++#define MESSAGE_COOKIE 1 ++#define MESSAGE_THREAD_NAME 2 ++#define HRTIMER_CORE_NAME 3 ++#define MESSAGE_LINK 4 ++ ++#define MESSAGE_GPU_START 1 ++#define MESSAGE_GPU_STOP 2 ++ ++#define MESSAGE_SCHED_SWITCH 1 ++#define MESSAGE_SCHED_EXIT 2 ++#define MESSAGE_SCHED_START 3 ++ ++#define MESSAGE_IDLE_ENTER 1 ++#define MESSAGE_IDLE_EXIT 2 ++ ++#define MAXSIZE_PACK32 5 ++#define MAXSIZE_PACK64 10 ++ ++#define FRAME_HEADER_SIZE 3 ++ ++#if defined(__arm__) ++#define PC_REG regs->ARM_pc ++#elif defined(__aarch64__) ++#define PC_REG regs->pc ++#else ++#define PC_REG regs->ip ++#endif ++ ++enum { ++ SUMMARY_BUF, ++ BACKTRACE_BUF, ++ NAME_BUF, ++ COUNTER_BUF, ++ BLOCK_COUNTER_BUF, ++ ANNOTATE_BUF, ++ SCHED_TRACE_BUF, ++ GPU_TRACE_BUF, ++ IDLE_BUF, ++ NUM_GATOR_BUFS ++}; ++ ++/****************************************************************************** ++ * Globals ++ ******************************************************************************/ ++static unsigned long gator_cpu_cores; ++// Size of the largest buffer. Effectively constant, set in gator_op_create_files ++static unsigned long userspace_buffer_size; ++static unsigned long gator_backtrace_depth; ++// How often to commit the buffers for live in nanoseconds ++static u64 gator_live_rate; ++ ++static unsigned long gator_started; ++static u64 gator_monotonic_started; ++static u64 gator_hibernate_time; ++static unsigned long gator_buffer_opened; ++static unsigned long gator_timer_count; ++static unsigned long gator_response_type; ++static DEFINE_MUTEX(start_mutex); ++static DEFINE_MUTEX(gator_buffer_mutex); ++ ++bool event_based_sampling; ++ ++static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait); ++static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait); ++static struct timer_list gator_buffer_wake_up_timer; ++static bool gator_buffer_wake_stop; ++static struct task_struct *gator_buffer_wake_thread; ++static LIST_HEAD(gator_events); ++ ++static DEFINE_PER_CPU(u64, last_timestamp); ++ ++static bool printed_monotonic_warning; ++ ++static bool sent_core_name[NR_CPUS]; ++ ++/****************************************************************************** ++ * Prototypes ++ ******************************************************************************/ ++static void buffer_check(int cpu, int buftype, u64 time); ++static void gator_commit_buffer(int cpu, int buftype, u64 time); ++static int buffer_bytes_available(int cpu, int buftype); ++static bool buffer_check_space(int cpu, int buftype, int bytes); ++static int contiguous_space_available(int cpu, int bufytpe); ++static void gator_buffer_write_packed_int(int cpu, int buftype, int x); ++static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x); ++static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len); ++static void gator_buffer_write_string(int cpu, int buftype, const char *x); ++static void gator_add_trace(int cpu, unsigned long address); ++static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time); ++static u64 gator_get_time(void); ++ ++// Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup. ++static uint32_t gator_buffer_size[NUM_GATOR_BUFS]; ++// gator_buffer_size - 1, bitwise and with pos to get offset into the array. Effectively constant, set in gator_op_setup. ++static uint32_t gator_buffer_mask[NUM_GATOR_BUFS]; ++// Read position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are read by userspace in userspace_buffer_read ++static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_read); ++// Write position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are written to the buffer ++static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_write); ++// Commit position in the buffer. Initialized to zero in gator_op_setup and incremented after a frame is ready to be read by userspace ++static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_commit); ++// If set to false, decreases the number of bytes returned by buffer_bytes_available. Set in buffer_check_space if no space is remaining. Initialized to true in gator_op_setup ++// This means that if we run out of space, continue to report that no space is available until bytes are read by userspace ++static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], buffer_space_available); ++// The buffer. Allocated in gator_op_setup ++static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer); ++// The time after which the buffer should be committed for live display ++static DEFINE_PER_CPU(u64, gator_buffer_commit_time); ++ ++// List of all gator events - new events must be added to this list ++#define GATOR_EVENTS_LIST \ ++ GATOR_EVENT(gator_events_armv6_init) \ ++ GATOR_EVENT(gator_events_armv7_init) \ ++ GATOR_EVENT(gator_events_block_init) \ ++ GATOR_EVENT(gator_events_ccn504_init) \ ++ GATOR_EVENT(gator_events_irq_init) \ ++ GATOR_EVENT(gator_events_l2c310_init) \ ++ GATOR_EVENT(gator_events_mali_init) \ ++ GATOR_EVENT(gator_events_mali_t6xx_hw_init) \ ++ GATOR_EVENT(gator_events_mali_t6xx_init) \ ++ GATOR_EVENT(gator_events_meminfo_init) \ ++ GATOR_EVENT(gator_events_mmapped_init) \ ++ GATOR_EVENT(gator_events_net_init) \ ++ GATOR_EVENT(gator_events_perf_pmu_init) \ ++ GATOR_EVENT(gator_events_sched_init) \ ++ GATOR_EVENT(gator_events_scorpion_init) \ ++ ++#define GATOR_EVENT(EVENT_INIT) __weak int EVENT_INIT(void); ++GATOR_EVENTS_LIST ++#undef GATOR_EVENT ++ ++static int (*gator_events_list[])(void) = { ++#define GATOR_EVENT(EVENT_INIT) EVENT_INIT, ++GATOR_EVENTS_LIST ++#undef GATOR_EVENT ++}; ++ ++/****************************************************************************** ++ * Application Includes ++ ******************************************************************************/ ++#include "gator_marshaling.c" ++#include "gator_hrtimer_perf.c" ++#include "gator_hrtimer_gator.c" ++#include "gator_cookies.c" ++#include "gator_annotate.c" ++#include "gator_trace_sched.c" ++#include "gator_trace_power.c" ++#include "gator_trace_gpu.c" ++#include "gator_backtrace.c" ++#include "gator_fs.c" ++#include "gator_pack.c" ++ ++/****************************************************************************** ++ * Misc ++ ******************************************************************************/ ++ ++const struct gator_cpu gator_cpus[] = { ++ { ++ .cpuid = ARM1136, ++ .core_name = "ARM1136", ++ .pmnc_name = "ARM_ARM11", ++ .dt_name = "arm,arm1136", ++ .pmnc_counters = 3, ++ }, ++ { ++ .cpuid = ARM1156, ++ .core_name = "ARM1156", ++ .pmnc_name = "ARM_ARM11", ++ .dt_name = "arm,arm1156", ++ .pmnc_counters = 3, ++ }, ++ { ++ .cpuid = ARM1176, ++ .core_name = "ARM1176", ++ .pmnc_name = "ARM_ARM11", ++ .dt_name = "arm,arm1176", ++ .pmnc_counters = 3, ++ }, ++ { ++ .cpuid = ARM11MPCORE, ++ .core_name = "ARM11MPCore", ++ .pmnc_name = "ARM_ARM11MPCore", ++ .dt_name = "arm,arm11mpcore", ++ .pmnc_counters = 3, ++ }, ++ { ++ .cpuid = CORTEX_A5, ++ .core_name = "Cortex-A5", ++ .pmu_name = "ARMv7_Cortex_A5", ++ .pmnc_name = "ARM_Cortex-A5", ++ .dt_name = "arm,cortex-a5", ++ .pmnc_counters = 2, ++ }, ++ { ++ .cpuid = CORTEX_A7, ++ .core_name = "Cortex-A7", ++ .pmu_name = "ARMv7_Cortex_A7", ++ .pmnc_name = "ARM_Cortex-A7", ++ .dt_name = "arm,cortex-a7", ++ .pmnc_counters = 4, ++ }, ++ { ++ .cpuid = CORTEX_A8, ++ .core_name = "Cortex-A8", ++ .pmu_name = "ARMv7_Cortex_A8", ++ .pmnc_name = "ARM_Cortex-A8", ++ .dt_name = "arm,cortex-a8", ++ .pmnc_counters = 4, ++ }, ++ { ++ .cpuid = CORTEX_A9, ++ .core_name = "Cortex-A9", ++ .pmu_name = "ARMv7_Cortex_A9", ++ .pmnc_name = "ARM_Cortex-A9", ++ .dt_name = "arm,cortex-a9", ++ .pmnc_counters = 6, ++ }, ++ { ++ .cpuid = CORTEX_A12, ++ .core_name = "Cortex-A12", ++ .pmu_name = "ARMv7_Cortex_A12", ++ .pmnc_name = "ARM_Cortex-A12", ++ .dt_name = "arm,cortex-a12", ++ .pmnc_counters = 6, ++ }, ++ { ++ .cpuid = CORTEX_A15, ++ .core_name = "Cortex-A15", ++ .pmu_name = "ARMv7_Cortex_A15", ++ .pmnc_name = "ARM_Cortex-A15", ++ .dt_name = "arm,cortex-a15", ++ .pmnc_counters = 6, ++ }, ++ { ++ .cpuid = SCORPION, ++ .core_name = "Scorpion", ++ .pmnc_name = "Scorpion", ++ .pmnc_counters = 4, ++ }, ++ { ++ .cpuid = SCORPIONMP, ++ .core_name = "ScorpionMP", ++ .pmnc_name = "ScorpionMP", ++ .pmnc_counters = 4, ++ }, ++ { ++ .cpuid = KRAITSIM, ++ .core_name = "KraitSIM", ++ .pmnc_name = "Krait", ++ .pmnc_counters = 4, ++ }, ++ { ++ .cpuid = KRAIT, ++ .core_name = "Krait", ++ .pmnc_name = "Krait", ++ .pmnc_counters = 4, ++ }, ++ { ++ .cpuid = KRAIT_S4_PRO, ++ .core_name = "Krait S4 Pro", ++ .pmnc_name = "Krait", ++ .pmnc_counters = 4, ++ }, ++ { ++ .cpuid = CORTEX_A53, ++ .core_name = "Cortex-A53", ++ .pmnc_name = "ARM_Cortex-A53", ++ .dt_name = "arm,cortex-a53", ++ .pmnc_counters = 6, ++ }, ++ { ++ .cpuid = CORTEX_A57, ++ .core_name = "Cortex-A57", ++ .pmnc_name = "ARM_Cortex-A57", ++ .dt_name = "arm,cortex-a57", ++ .pmnc_counters = 6, ++ }, ++ { ++ .cpuid = AARCH64, ++ .core_name = "AArch64", ++ .pmnc_name = "ARM_AArch64", ++ .pmnc_counters = 6, ++ }, ++ { ++ .cpuid = OTHER, ++ .core_name = "Other", ++ .pmnc_name = "Other", ++ .pmnc_counters = 6, ++ }, ++ {} ++}; ++ ++const struct gator_cpu *gator_find_cpu_by_cpuid(const u32 cpuid) ++{ ++ int i; ++ ++ for (i = 0; gator_cpus[i].cpuid != 0; ++i) { ++ const struct gator_cpu *const gator_cpu = &gator_cpus[i]; ++ if (gator_cpu->cpuid == cpuid) { ++ return gator_cpu; ++ } ++ } ++ ++ return NULL; ++} ++ ++const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name) ++{ ++ int i; ++ ++ for (i = 0; gator_cpus[i].cpuid != 0; ++i) { ++ const struct gator_cpu *const gator_cpu = &gator_cpus[i]; ++ if (gator_cpu->pmu_name != NULL && strcmp(gator_cpu->pmu_name, name) == 0) { ++ return gator_cpu; ++ } ++ } ++ ++ return NULL; ++} ++ ++u32 gator_cpuid(void) ++{ ++#if defined(__arm__) || defined(__aarch64__) ++ u32 val; ++#if !defined(__aarch64__) ++ asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (val)); ++#else ++ asm volatile("mrs %0, midr_el1" : "=r" (val)); ++#endif ++ return (val >> 4) & 0xfff; ++#else ++ return OTHER; ++#endif ++} ++ ++static void gator_buffer_wake_up(unsigned long data) ++{ ++ wake_up(&gator_buffer_wait); ++} ++ ++static int gator_buffer_wake_func(void *data) ++{ ++ while (!gator_buffer_wake_stop) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule(); ++ if (gator_buffer_wake_stop) { ++ break; ++ } ++ ++ gator_buffer_wake_up(0); ++ } ++ ++ return 0; ++} ++ ++/****************************************************************************** ++ * Commit interface ++ ******************************************************************************/ ++static bool buffer_commit_ready(int *cpu, int *buftype) ++{ ++ int cpu_x, x; ++ for_each_present_cpu(cpu_x) { ++ for (x = 0; x < NUM_GATOR_BUFS; x++) ++ if (per_cpu(gator_buffer_commit, cpu_x)[x] != per_cpu(gator_buffer_read, cpu_x)[x]) { ++ *cpu = cpu_x; ++ *buftype = x; ++ return true; ++ } ++ } ++ *cpu = -1; ++ *buftype = -1; ++ return false; ++} ++ ++/****************************************************************************** ++ * Buffer management ++ ******************************************************************************/ ++static int buffer_bytes_available(int cpu, int buftype) ++{ ++ int remaining, filled; ++ ++ filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype]; ++ if (filled < 0) { ++ filled += gator_buffer_size[buftype]; ++ } ++ ++ remaining = gator_buffer_size[buftype] - filled; ++ ++ if (per_cpu(buffer_space_available, cpu)[buftype]) { ++ // Give some extra room; also allows space to insert the overflow error packet ++ remaining -= 200; ++ } else { ++ // Hysteresis, prevents multiple overflow messages ++ remaining -= 2000; ++ } ++ ++ return remaining; ++} ++ ++static int contiguous_space_available(int cpu, int buftype) ++{ ++ int remaining = buffer_bytes_available(cpu, buftype); ++ int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype]; ++ if (remaining < contiguous) ++ return remaining; ++ else ++ return contiguous; ++} ++ ++static bool buffer_check_space(int cpu, int buftype, int bytes) ++{ ++ int remaining = buffer_bytes_available(cpu, buftype); ++ ++ if (remaining < bytes) { ++ per_cpu(buffer_space_available, cpu)[buftype] = false; ++ } else { ++ per_cpu(buffer_space_available, cpu)[buftype] = true; ++ } ++ ++ return per_cpu(buffer_space_available, cpu)[buftype]; ++} ++ ++static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int len) ++{ ++ int i; ++ u32 write = per_cpu(gator_buffer_write, cpu)[buftype]; ++ u32 mask = gator_buffer_mask[buftype]; ++ char *buffer = per_cpu(gator_buffer, cpu)[buftype]; ++ ++ for (i = 0; i < len; i++) { ++ buffer[write] = x[i]; ++ write = (write + 1) & mask; ++ } ++ ++ per_cpu(gator_buffer_write, cpu)[buftype] = write; ++} ++ ++static void gator_buffer_write_string(int cpu, int buftype, const char *x) ++{ ++ int len = strlen(x); ++ gator_buffer_write_packed_int(cpu, buftype, len); ++ gator_buffer_write_bytes(cpu, buftype, x, len); ++} ++ ++static void gator_commit_buffer(int cpu, int buftype, u64 time) ++{ ++ int type_length, commit, length, byte; ++ ++ if (!per_cpu(gator_buffer, cpu)[buftype]) ++ return; ++ ++ // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload ++ type_length = gator_response_type ? 1 : 0; ++ commit = per_cpu(gator_buffer_commit, cpu)[buftype]; ++ length = per_cpu(gator_buffer_write, cpu)[buftype] - commit; ++ if (length < 0) { ++ length += gator_buffer_size[buftype]; ++ } ++ length = length - type_length - sizeof(s32); ++ ++ if (length <= FRAME_HEADER_SIZE) { ++ // Nothing to write, only the frame header is present ++ return; ++ } ++ ++ for (byte = 0; byte < sizeof(s32); byte++) { ++ per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF; ++ } ++ ++ per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype]; ++ ++ if (gator_live_rate > 0) { ++ while (time > per_cpu(gator_buffer_commit_time, cpu)) { ++ per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate; ++ } ++ } ++ ++ marshal_frame(cpu, buftype); ++ ++ // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater ++ if (per_cpu(in_scheduler_context, cpu)) { ++#ifndef CONFIG_PREEMPT_RT_FULL ++ // mod_timer can not be used in interrupt context in RT-Preempt full ++ mod_timer(&gator_buffer_wake_up_timer, jiffies + 1); ++#endif ++ } else { ++ wake_up_process(gator_buffer_wake_thread); ++ } ++} ++ ++static void buffer_check(int cpu, int buftype, u64 time) ++{ ++ int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype]; ++ if (filled < 0) { ++ filled += gator_buffer_size[buftype]; ++ } ++ if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) { ++ gator_commit_buffer(cpu, buftype, time); ++ } ++} ++ ++static void gator_add_trace(int cpu, unsigned long address) ++{ ++ off_t offset = 0; ++ unsigned long cookie = get_address_cookie(cpu, current, address & ~1, &offset); ++ ++ if (cookie == NO_COOKIE || cookie == UNRESOLVED_COOKIE) { ++ offset = address; ++ } ++ ++ marshal_backtrace(offset & ~1, cookie); ++} ++ ++static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time) ++{ ++ bool inKernel; ++ unsigned long exec_cookie; ++ ++ if (!regs) ++ return; ++ ++ inKernel = !user_mode(regs); ++ exec_cookie = get_exec_cookie(cpu, current); ++ ++ if (!marshal_backtrace_header(exec_cookie, current->tgid, current->pid, inKernel, time)) ++ return; ++ ++ if (inKernel) { ++ kernel_backtrace(cpu, regs); ++ } else { ++ // Cookie+PC ++ gator_add_trace(cpu, PC_REG); ++ ++ // Backtrace ++ if (gator_backtrace_depth) ++ arm_backtrace_eabi(cpu, regs, gator_backtrace_depth); ++ } ++ ++ marshal_backtrace_footer(time); ++} ++ ++/****************************************************************************** ++ * hrtimer interrupt processing ++ ******************************************************************************/ ++static void gator_timer_interrupt(void) ++{ ++ struct pt_regs *const regs = get_irq_regs(); ++ gator_backtrace_handler(regs); ++} ++ ++void gator_backtrace_handler(struct pt_regs *const regs) ++{ ++ u64 time = gator_get_time(); ++ int cpu = get_physical_cpu(); ++ ++ // Output backtrace ++ gator_add_sample(cpu, regs, time); ++ ++ // Collect counters ++ if (!per_cpu(collecting, cpu)) { ++ collect_counters(time, NULL); ++ } ++ ++ // No buffer flushing occurs during sched switch for RT-Preempt full. The block counter frame will be flushed by collect_counters, but the sched buffer needs to be explicitly flushed ++#ifdef CONFIG_PREEMPT_RT_FULL ++ buffer_check(cpu, SCHED_TRACE_BUF, time); ++#endif ++} ++ ++static int gator_running; ++ ++// This function runs in interrupt context and on the appropriate core ++static void gator_timer_offline(void *migrate) ++{ ++ struct gator_interface *gi; ++ int i, len, cpu = get_physical_cpu(); ++ int *buffer; ++ u64 time; ++ ++ gator_trace_sched_offline(); ++ gator_trace_power_offline(); ++ ++ if (!migrate) { ++ gator_hrtimer_offline(); ++ } ++ ++ // Offline any events and output counters ++ time = gator_get_time(); ++ if (marshal_event_header(time)) { ++ list_for_each_entry(gi, &gator_events, list) { ++ if (gi->offline) { ++ len = gi->offline(&buffer, migrate); ++ marshal_event(len, buffer); ++ } ++ } ++ // Only check after writing all counters so that time and corresponding counters appear in the same frame ++ buffer_check(cpu, BLOCK_COUNTER_BUF, time); ++ } ++ ++ // Flush all buffers on this core ++ for (i = 0; i < NUM_GATOR_BUFS; i++) ++ gator_commit_buffer(cpu, i, time); ++} ++ ++// This function runs in interrupt context and may be running on a core other than core 'cpu' ++static void gator_timer_offline_dispatch(int cpu, bool migrate) ++{ ++ struct gator_interface *gi; ++ ++ list_for_each_entry(gi, &gator_events, list) { ++ if (gi->offline_dispatch) { ++ gi->offline_dispatch(cpu, migrate); ++ } ++ } ++} ++ ++static void gator_timer_stop(void) ++{ ++ int cpu; ++ ++ if (gator_running) { ++ on_each_cpu(gator_timer_offline, NULL, 1); ++ for_each_online_cpu(cpu) { ++ gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false); ++ } ++ ++ gator_running = 0; ++ gator_hrtimer_shutdown(); ++ } ++} ++ ++#if defined(__arm__) || defined(__aarch64__) ++static void gator_send_core_name(int cpu, const u32 cpuid, const struct gator_cpu *const gator_cpu) { ++ const char *core_name = NULL; ++ char core_name_buf[32]; ++ ++ if (!sent_core_name[cpu]) { ++ if (gator_cpu != NULL) { ++ core_name = gator_cpu->core_name; ++ } else { ++ snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.3x)", cpuid); ++ core_name = core_name_buf; ++ } ++ ++ marshal_core_name(cpu, cpuid, core_name); ++ sent_core_name[cpu] = true; ++ } ++} ++#endif ++ ++// This function runs in interrupt context and on the appropriate core ++static void gator_timer_online(void *migrate) ++{ ++ struct gator_interface *gi; ++ int len, cpu = get_physical_cpu(); ++ int *buffer; ++ u64 time; ++ ++ gator_trace_power_online(); ++ ++ // online any events and output counters ++ time = gator_get_time(); ++ if (marshal_event_header(time)) { ++ list_for_each_entry(gi, &gator_events, list) { ++ if (gi->online) { ++ len = gi->online(&buffer, migrate); ++ marshal_event(len, buffer); ++ } ++ } ++ // Only check after writing all counters so that time and corresponding counters appear in the same frame ++ buffer_check(cpu, BLOCK_COUNTER_BUF, time); ++ } ++ ++ if (!migrate) { ++ gator_hrtimer_online(); ++ } ++ ++#if defined(__arm__) || defined(__aarch64__) ++ if (!sent_core_name[cpu]) { ++ const u32 cpuid = gator_cpuid(); ++ gator_send_core_name(cpu, cpuid, gator_find_cpu_by_cpuid(cpuid)); ++ } ++#endif ++} ++ ++// This function runs in interrupt context and may be running on a core other than core 'cpu' ++static void gator_timer_online_dispatch(int cpu, bool migrate) ++{ ++ struct gator_interface *gi; ++ ++ list_for_each_entry(gi, &gator_events, list) { ++ if (gi->online_dispatch) { ++ gi->online_dispatch(cpu, migrate); ++ } ++ } ++} ++ ++#include "gator_iks.c" ++ ++int gator_timer_start(unsigned long sample_rate) ++{ ++ int cpu; ++ ++ if (gator_running) { ++ pr_notice("gator: already running\n"); ++ return 0; ++ } ++ ++ gator_running = 1; ++ ++ // event based sampling trumps hr timer based sampling ++ if (event_based_sampling) { ++ sample_rate = 0; ++ } ++ ++ if (gator_hrtimer_init(sample_rate, gator_timer_interrupt) == -1) ++ return -1; ++ ++ gator_send_iks_core_names(); ++ for_each_online_cpu(cpu) { ++ gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false); ++ } ++ on_each_cpu(gator_timer_online, NULL, 1); ++ ++ return 0; ++} ++ ++static u64 gator_get_time(void) ++{ ++ struct timespec ts; ++ u64 timestamp; ++ u64 prev_timestamp; ++ u64 delta; ++ int cpu = smp_processor_id(); ++ ++ // Match clock_gettime(CLOCK_MONOTONIC_RAW, &ts) from userspace ++ getrawmonotonic(&ts); ++ timestamp = timespec_to_ns(&ts); ++ ++ // getrawmonotonic is not monotonic on all systems. Detect and attempt to correct these cases. ++ // up to 0.5ms delta has been seen on some systems, which can skew Streamline data when viewing at high resolution. ++ // This doesn't work well with interrupts, but that it's OK - the real concern is to catch big jumps in time ++ prev_timestamp = per_cpu(last_timestamp, cpu); ++ if (prev_timestamp <= timestamp) { ++ per_cpu(last_timestamp, cpu) = timestamp; ++ } else { ++ delta = prev_timestamp - timestamp; ++ // Log the error once ++ if (!printed_monotonic_warning && delta > 500000) { ++ printk(KERN_ERR "%s: getrawmonotonic is not monotonic cpu: %i delta: %lli\nSkew in Streamline data may be present at the fine zoom levels\n", __FUNCTION__, cpu, delta); ++ printed_monotonic_warning = true; ++ } ++ timestamp = prev_timestamp; ++ } ++ ++ return timestamp - gator_monotonic_started; ++} ++ ++/****************************************************************************** ++ * cpu hotplug and pm notifiers ++ ******************************************************************************/ ++static int __cpuinit gator_hotcpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) ++{ ++ int cpu = lcpu_to_pcpu((long)hcpu); ++ ++ switch (action) { ++ case CPU_DOWN_PREPARE: ++ case CPU_DOWN_PREPARE_FROZEN: ++ smp_call_function_single(cpu, gator_timer_offline, NULL, 1); ++ gator_timer_offline_dispatch(cpu, false); ++ break; ++ case CPU_ONLINE: ++ case CPU_ONLINE_FROZEN: ++ gator_timer_online_dispatch(cpu, false); ++ smp_call_function_single(cpu, gator_timer_online, NULL, 1); ++ break; ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block __refdata gator_hotcpu_notifier = { ++ .notifier_call = gator_hotcpu_notify, ++}; ++ ++// n.b. calling "on_each_cpu" only runs on those that are online ++// Registered linux events are not disabled, so their counters will continue to collect ++static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy) ++{ ++ int cpu; ++ struct timespec ts; ++ ++ switch (event) { ++ case PM_HIBERNATION_PREPARE: ++ case PM_SUSPEND_PREPARE: ++ unregister_hotcpu_notifier(&gator_hotcpu_notifier); ++ unregister_scheduler_tracepoints(); ++ on_each_cpu(gator_timer_offline, NULL, 1); ++ for_each_online_cpu(cpu) { ++ gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false); ++ } ++ ++ // Record the wallclock hibernate time ++ getnstimeofday(&ts); ++ gator_hibernate_time = timespec_to_ns(&ts) - gator_get_time(); ++ break; ++ case PM_POST_HIBERNATION: ++ case PM_POST_SUSPEND: ++ // Adjust gator_monotonic_started for the time spent sleeping, as gator_get_time does not account for it ++ if (gator_hibernate_time > 0) { ++ getnstimeofday(&ts); ++ gator_monotonic_started += gator_hibernate_time + gator_get_time() - timespec_to_ns(&ts); ++ gator_hibernate_time = 0; ++ } ++ ++ for_each_online_cpu(cpu) { ++ gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false); ++ } ++ on_each_cpu(gator_timer_online, NULL, 1); ++ register_scheduler_tracepoints(); ++ register_hotcpu_notifier(&gator_hotcpu_notifier); ++ break; ++ } ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block gator_pm_notifier = { ++ .notifier_call = gator_pm_notify, ++}; ++ ++static int gator_notifier_start(void) ++{ ++ int retval; ++ retval = register_hotcpu_notifier(&gator_hotcpu_notifier); ++ if (retval == 0) ++ retval = register_pm_notifier(&gator_pm_notifier); ++ return retval; ++} ++ ++static void gator_notifier_stop(void) ++{ ++ unregister_pm_notifier(&gator_pm_notifier); ++ unregister_hotcpu_notifier(&gator_hotcpu_notifier); ++} ++ ++/****************************************************************************** ++ * Main ++ ******************************************************************************/ ++static void gator_summary(void) ++{ ++ u64 timestamp, uptime; ++ struct timespec ts; ++ char uname_buf[512]; ++ void (*m2b)(struct timespec *ts); ++ unsigned long flags; ++ ++ snprintf(uname_buf, sizeof(uname_buf), "%s %s %s %s %s GNU/Linux", utsname()->sysname, utsname()->nodename, utsname()->release, utsname()->version, utsname()->machine); ++ ++ getnstimeofday(&ts); ++ timestamp = timespec_to_ns(&ts); ++ ++ do_posix_clock_monotonic_gettime(&ts); ++ // monotonic_to_bootbased is not defined for some versions of Android ++ m2b = symbol_get(monotonic_to_bootbased); ++ if (m2b) { ++ m2b(&ts); ++ } ++ uptime = timespec_to_ns(&ts); ++ ++ // Disable interrupts as gator_get_time calls smp_processor_id to verify time is monotonic ++ local_irq_save(flags); ++ // Set monotonic_started to zero as gator_get_time is uptime minus monotonic_started ++ gator_monotonic_started = 0; ++ gator_monotonic_started = gator_get_time(); ++ local_irq_restore(flags); ++ ++ marshal_summary(timestamp, uptime, gator_monotonic_started, uname_buf); ++} ++ ++int gator_events_install(struct gator_interface *interface) ++{ ++ list_add_tail(&interface->list, &gator_events); ++ ++ return 0; ++} ++ ++int gator_events_get_key(void) ++{ ++ // key 0 is reserved as a timestamp ++ // key 1 is reserved as the marker for thread specific counters ++ // Odd keys are assigned by the driver, even keys by the daemon ++ static int key = 3; ++ ++ const int ret = key; ++ key += 2; ++ return ret; ++} ++ ++static int gator_init(void) ++{ ++ int i; ++ ++ calc_first_cluster_size(); ++ ++ // events sources ++ for (i = 0; i < ARRAY_SIZE(gator_events_list); i++) ++ if (gator_events_list[i]) ++ gator_events_list[i](); ++ ++ gator_trace_sched_init(); ++ gator_trace_power_init(); ++ ++ return 0; ++} ++ ++static void gator_exit(void) ++{ ++ struct gator_interface *gi; ++ ++ list_for_each_entry(gi, &gator_events, list) ++ if (gi->shutdown) ++ gi->shutdown(); ++} ++ ++static int gator_start(void) ++{ ++ unsigned long cpu, i; ++ struct gator_interface *gi; ++ ++ gator_buffer_wake_stop = false; ++ if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) { ++ goto bwake_failure; ++ } ++ ++ if (gator_migrate_start()) ++ goto migrate_failure; ++ ++ // Initialize the buffer with the frame type and core ++ for_each_present_cpu(cpu) { ++ for (i = 0; i < NUM_GATOR_BUFS; i++) { ++ marshal_frame(cpu, i); ++ } ++ per_cpu(last_timestamp, cpu) = 0; ++ } ++ printed_monotonic_warning = false; ++ ++ // Capture the start time ++ gator_summary(); ++ ++ // start all events ++ list_for_each_entry(gi, &gator_events, list) { ++ if (gi->start && gi->start() != 0) { ++ struct list_head *ptr = gi->list.prev; ++ ++ while (ptr != &gator_events) { ++ gi = list_entry(ptr, struct gator_interface, list); ++ ++ if (gi->stop) ++ gi->stop(); ++ ++ ptr = ptr->prev; ++ } ++ goto events_failure; ++ } ++ } ++ ++ // cookies shall be initialized before trace_sched_start() and gator_timer_start() ++ if (cookies_initialize()) ++ goto cookies_failure; ++ if (gator_annotate_start()) ++ goto annotate_failure; ++ if (gator_trace_sched_start()) ++ goto sched_failure; ++ if (gator_trace_power_start()) ++ goto power_failure; ++ if (gator_trace_gpu_start()) ++ goto gpu_failure; ++ if (gator_timer_start(gator_timer_count)) ++ goto timer_failure; ++ if (gator_notifier_start()) ++ goto notifier_failure; ++ ++ return 0; ++ ++notifier_failure: ++ gator_timer_stop(); ++timer_failure: ++ gator_trace_gpu_stop(); ++gpu_failure: ++ gator_trace_power_stop(); ++power_failure: ++ gator_trace_sched_stop(); ++sched_failure: ++ gator_annotate_stop(); ++annotate_failure: ++ cookies_release(); ++cookies_failure: ++ // stop all events ++ list_for_each_entry(gi, &gator_events, list) ++ if (gi->stop) ++ gi->stop(); ++events_failure: ++ gator_migrate_stop(); ++migrate_failure: ++ gator_buffer_wake_stop = true; ++ wake_up_process(gator_buffer_wake_thread); ++bwake_failure: ++ ++ return -1; ++} ++ ++static void gator_stop(void) ++{ ++ struct gator_interface *gi; ++ ++ gator_annotate_stop(); ++ gator_trace_sched_stop(); ++ gator_trace_power_stop(); ++ gator_trace_gpu_stop(); ++ ++ // stop all interrupt callback reads before tearing down other interfaces ++ gator_notifier_stop(); // should be called before gator_timer_stop to avoid re-enabling the hrtimer after it has been offlined ++ gator_timer_stop(); ++ ++ // stop all events ++ list_for_each_entry(gi, &gator_events, list) ++ if (gi->stop) ++ gi->stop(); ++ ++ gator_migrate_stop(); ++ ++ gator_buffer_wake_stop = true; ++ wake_up_process(gator_buffer_wake_thread); ++} ++ ++/****************************************************************************** ++ * Filesystem ++ ******************************************************************************/ ++/* fopen("buffer") */ ++static int gator_op_setup(void) ++{ ++ int err = 0; ++ int cpu, i; ++ ++ mutex_lock(&start_mutex); ++ ++ gator_buffer_size[SUMMARY_BUF] = SUMMARY_BUFFER_SIZE; ++ gator_buffer_mask[SUMMARY_BUF] = SUMMARY_BUFFER_SIZE - 1; ++ ++ gator_buffer_size[BACKTRACE_BUF] = BACKTRACE_BUFFER_SIZE; ++ gator_buffer_mask[BACKTRACE_BUF] = BACKTRACE_BUFFER_SIZE - 1; ++ ++ gator_buffer_size[NAME_BUF] = NAME_BUFFER_SIZE; ++ gator_buffer_mask[NAME_BUF] = NAME_BUFFER_SIZE - 1; ++ ++ gator_buffer_size[COUNTER_BUF] = COUNTER_BUFFER_SIZE; ++ gator_buffer_mask[COUNTER_BUF] = COUNTER_BUFFER_SIZE - 1; ++ ++ gator_buffer_size[BLOCK_COUNTER_BUF] = BLOCK_COUNTER_BUFFER_SIZE; ++ gator_buffer_mask[BLOCK_COUNTER_BUF] = BLOCK_COUNTER_BUFFER_SIZE - 1; ++ ++ gator_buffer_size[ANNOTATE_BUF] = ANNOTATE_BUFFER_SIZE; ++ gator_buffer_mask[ANNOTATE_BUF] = ANNOTATE_BUFFER_SIZE - 1; ++ ++ gator_buffer_size[SCHED_TRACE_BUF] = SCHED_TRACE_BUFFER_SIZE; ++ gator_buffer_mask[SCHED_TRACE_BUF] = SCHED_TRACE_BUFFER_SIZE - 1; ++ ++ gator_buffer_size[GPU_TRACE_BUF] = GPU_TRACE_BUFFER_SIZE; ++ gator_buffer_mask[GPU_TRACE_BUF] = GPU_TRACE_BUFFER_SIZE - 1; ++ ++ gator_buffer_size[IDLE_BUF] = IDLE_BUFFER_SIZE; ++ gator_buffer_mask[IDLE_BUF] = IDLE_BUFFER_SIZE - 1; ++ ++ // Initialize percpu per buffer variables ++ for (i = 0; i < NUM_GATOR_BUFS; i++) { ++ // Verify buffers are a power of 2 ++ if (gator_buffer_size[i] & (gator_buffer_size[i] - 1)) { ++ err = -ENOEXEC; ++ goto setup_error; ++ } ++ ++ for_each_present_cpu(cpu) { ++ per_cpu(gator_buffer_read, cpu)[i] = 0; ++ per_cpu(gator_buffer_write, cpu)[i] = 0; ++ per_cpu(gator_buffer_commit, cpu)[i] = 0; ++ per_cpu(buffer_space_available, cpu)[i] = true; ++ per_cpu(gator_buffer_commit_time, cpu) = gator_live_rate; ++ ++ // Annotation is a special case that only uses a single buffer ++ if (cpu > 0 && i == ANNOTATE_BUF) { ++ per_cpu(gator_buffer, cpu)[i] = NULL; ++ continue; ++ } ++ ++ per_cpu(gator_buffer, cpu)[i] = vmalloc(gator_buffer_size[i]); ++ if (!per_cpu(gator_buffer, cpu)[i]) { ++ err = -ENOMEM; ++ goto setup_error; ++ } ++ } ++ } ++ ++setup_error: ++ mutex_unlock(&start_mutex); ++ return err; ++} ++ ++/* Actually start profiling (echo 1>/dev/gator/enable) */ ++static int gator_op_start(void) ++{ ++ int err = 0; ++ ++ mutex_lock(&start_mutex); ++ ++ if (gator_started || gator_start()) ++ err = -EINVAL; ++ else ++ gator_started = 1; ++ ++ mutex_unlock(&start_mutex); ++ ++ return err; ++} ++ ++/* echo 0>/dev/gator/enable */ ++static void gator_op_stop(void) ++{ ++ mutex_lock(&start_mutex); ++ ++ if (gator_started) { ++ gator_stop(); ++ ++ mutex_lock(&gator_buffer_mutex); ++ ++ gator_started = 0; ++ gator_monotonic_started = 0; ++ cookies_release(); ++ wake_up(&gator_buffer_wait); ++ ++ mutex_unlock(&gator_buffer_mutex); ++ } ++ ++ mutex_unlock(&start_mutex); ++} ++ ++static void gator_shutdown(void) ++{ ++ int cpu, i; ++ ++ mutex_lock(&start_mutex); ++ ++ for_each_present_cpu(cpu) { ++ mutex_lock(&gator_buffer_mutex); ++ for (i = 0; i < NUM_GATOR_BUFS; i++) { ++ vfree(per_cpu(gator_buffer, cpu)[i]); ++ per_cpu(gator_buffer, cpu)[i] = NULL; ++ per_cpu(gator_buffer_read, cpu)[i] = 0; ++ per_cpu(gator_buffer_write, cpu)[i] = 0; ++ per_cpu(gator_buffer_commit, cpu)[i] = 0; ++ per_cpu(buffer_space_available, cpu)[i] = true; ++ per_cpu(gator_buffer_commit_time, cpu) = 0; ++ } ++ mutex_unlock(&gator_buffer_mutex); ++ } ++ ++ memset(&sent_core_name, 0, sizeof(sent_core_name)); ++ ++ mutex_unlock(&start_mutex); ++} ++ ++static int gator_set_backtrace(unsigned long val) ++{ ++ int err = 0; ++ ++ mutex_lock(&start_mutex); ++ ++ if (gator_started) ++ err = -EBUSY; ++ else ++ gator_backtrace_depth = val; ++ ++ mutex_unlock(&start_mutex); ++ ++ return err; ++} ++ ++static ssize_t enable_read(struct file *file, char __user *buf, size_t count, loff_t *offset) ++{ ++ return gatorfs_ulong_to_user(gator_started, buf, count, offset); ++} ++ ++static ssize_t enable_write(struct file *file, char const __user *buf, size_t count, loff_t *offset) ++{ ++ unsigned long val; ++ int retval; ++ ++ if (*offset) ++ return -EINVAL; ++ ++ retval = gatorfs_ulong_from_user(&val, buf, count); ++ if (retval) ++ return retval; ++ ++ if (val) ++ retval = gator_op_start(); ++ else ++ gator_op_stop(); ++ ++ if (retval) ++ return retval; ++ return count; ++} ++ ++static const struct file_operations enable_fops = { ++ .read = enable_read, ++ .write = enable_write, ++}; ++ ++static int userspace_buffer_open(struct inode *inode, struct file *file) ++{ ++ int err = -EPERM; ++ ++ if (!capable(CAP_SYS_ADMIN)) ++ return -EPERM; ++ ++ if (test_and_set_bit_lock(0, &gator_buffer_opened)) ++ return -EBUSY; ++ ++ if ((err = gator_op_setup())) ++ goto fail; ++ ++ /* NB: the actual start happens from userspace ++ * echo 1 >/dev/gator/enable ++ */ ++ ++ return 0; ++ ++fail: ++ __clear_bit_unlock(0, &gator_buffer_opened); ++ return err; ++} ++ ++static int userspace_buffer_release(struct inode *inode, struct file *file) ++{ ++ gator_op_stop(); ++ gator_shutdown(); ++ __clear_bit_unlock(0, &gator_buffer_opened); ++ return 0; ++} ++ ++static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t count, loff_t *offset) ++{ ++ int commit, length1, length2, read; ++ char *buffer1; ++ char *buffer2; ++ int cpu, buftype; ++ int written = 0; ++ ++ // ensure there is enough space for a whole frame ++ if (count < userspace_buffer_size || *offset) { ++ return -EINVAL; ++ } ++ ++ // sleep until the condition is true or a signal is received ++ // the condition is checked each time gator_buffer_wait is woken up ++ wait_event_interruptible(gator_buffer_wait, buffer_commit_ready(&cpu, &buftype) || !gator_started); ++ ++ if (signal_pending(current)) { ++ return -EINTR; ++ } ++ ++ if (buftype == -1 || cpu == -1) { ++ return 0; ++ } ++ ++ mutex_lock(&gator_buffer_mutex); ++ ++ do { ++ read = per_cpu(gator_buffer_read, cpu)[buftype]; ++ commit = per_cpu(gator_buffer_commit, cpu)[buftype]; ++ ++ // May happen if the buffer is freed during pending reads. ++ if (!per_cpu(gator_buffer, cpu)[buftype]) { ++ break; ++ } ++ ++ // determine the size of two halves ++ length1 = commit - read; ++ length2 = 0; ++ buffer1 = &(per_cpu(gator_buffer, cpu)[buftype][read]); ++ buffer2 = &(per_cpu(gator_buffer, cpu)[buftype][0]); ++ if (length1 < 0) { ++ length1 = gator_buffer_size[buftype] - read; ++ length2 = commit; ++ } ++ ++ if (length1 + length2 > count - written) { ++ break; ++ } ++ ++ // start, middle or end ++ if (length1 > 0 && copy_to_user(&buf[written], buffer1, length1)) { ++ break; ++ } ++ ++ // possible wrap around ++ if (length2 > 0 && copy_to_user(&buf[written + length1], buffer2, length2)) { ++ break; ++ } ++ ++ per_cpu(gator_buffer_read, cpu)[buftype] = commit; ++ written += length1 + length2; ++ ++ // Wake up annotate_write if more space is available ++ if (buftype == ANNOTATE_BUF) { ++ wake_up(&gator_annotate_wait); ++ } ++ } while (buffer_commit_ready(&cpu, &buftype)); ++ ++ mutex_unlock(&gator_buffer_mutex); ++ ++ // kick just in case we've lost an SMP event ++ wake_up(&gator_buffer_wait); ++ ++ return written > 0 ? written : -EFAULT; ++} ++ ++const struct file_operations gator_event_buffer_fops = { ++ .open = userspace_buffer_open, ++ .release = userspace_buffer_release, ++ .read = userspace_buffer_read, ++}; ++ ++static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset) ++{ ++ return gatorfs_ulong_to_user(gator_backtrace_depth, buf, count, offset); ++} ++ ++static ssize_t depth_write(struct file *file, char const __user *buf, size_t count, loff_t *offset) ++{ ++ unsigned long val; ++ int retval; ++ ++ if (*offset) ++ return -EINVAL; ++ ++ retval = gatorfs_ulong_from_user(&val, buf, count); ++ if (retval) ++ return retval; ++ ++ retval = gator_set_backtrace(val); ++ ++ if (retval) ++ return retval; ++ return count; ++} ++ ++static const struct file_operations depth_fops = { ++ .read = depth_read, ++ .write = depth_write ++}; ++ ++void gator_op_create_files(struct super_block *sb, struct dentry *root) ++{ ++ struct dentry *dir; ++ struct gator_interface *gi; ++ int cpu; ++ ++ /* reinitialize default values */ ++ gator_cpu_cores = 0; ++ for_each_present_cpu(cpu) { ++ gator_cpu_cores++; ++ } ++ userspace_buffer_size = BACKTRACE_BUFFER_SIZE; ++ gator_response_type = 1; ++ gator_live_rate = 0; ++ ++ gatorfs_create_file(sb, root, "enable", &enable_fops); ++ gatorfs_create_file(sb, root, "buffer", &gator_event_buffer_fops); ++ gatorfs_create_file(sb, root, "backtrace_depth", &depth_fops); ++ gatorfs_create_ro_ulong(sb, root, "cpu_cores", &gator_cpu_cores); ++ gatorfs_create_ro_ulong(sb, root, "buffer_size", &userspace_buffer_size); ++ gatorfs_create_ulong(sb, root, "tick", &gator_timer_count); ++ gatorfs_create_ulong(sb, root, "response_type", &gator_response_type); ++ gatorfs_create_ro_ulong(sb, root, "version", &gator_protocol_version); ++ gatorfs_create_ro_u64(sb, root, "started", &gator_monotonic_started); ++ gatorfs_create_u64(sb, root, "live_rate", &gator_live_rate); ++ ++ // Annotate interface ++ gator_annotate_create_files(sb, root); ++ ++ // Linux Events ++ dir = gatorfs_mkdir(sb, root, "events"); ++ list_for_each_entry(gi, &gator_events, list) ++ if (gi->create_files) ++ gi->create_files(sb, dir); ++ ++ // Sched Events ++ sched_trace_create_files(sb, dir); ++ ++ // Power interface ++ gator_trace_power_create_files(sb, dir); ++} ++ ++/****************************************************************************** ++ * Module ++ ******************************************************************************/ ++static int __init gator_module_init(void) ++{ ++ if (gatorfs_register()) { ++ return -1; ++ } ++ ++ if (gator_init()) { ++ gatorfs_unregister(); ++ return -1; ++ } ++ ++ setup_timer(&gator_buffer_wake_up_timer, gator_buffer_wake_up, 0); ++ ++ return 0; ++} ++ ++static void __exit gator_module_exit(void) ++{ ++ del_timer_sync(&gator_buffer_wake_up_timer); ++ tracepoint_synchronize_unregister(); ++ gator_exit(); ++ gatorfs_unregister(); ++} ++ ++module_init(gator_module_init); ++module_exit(gator_module_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("ARM Ltd"); ++MODULE_DESCRIPTION("Gator system profiler"); ++#define STRIFY2(ARG) #ARG ++#define STRIFY(ARG) STRIFY2(ARG) ++MODULE_VERSION(STRIFY(PROTOCOL_VERSION)); +diff -Nur linux-3.10.30/drivers/gator/gator_marshaling.c linux-3.10.30-cubox-i/drivers/gator/gator_marshaling.c +--- linux-3.10.30/drivers/gator/gator_marshaling.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_marshaling.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,432 @@ ++/** ++ * Copyright (C) ARM Limited 2012-2013. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#define NEWLINE_CANARY \ ++ /* Unix */ \ ++ "1\n" \ ++ /* Windows */ \ ++ "2\r\n" \ ++ /* Mac OS */ \ ++ "3\r" \ ++ /* RISC OS */ \ ++ "4\n\r" \ ++ /* Add another character so the length isn't 0x0a bytes */ \ ++ "5" ++ ++#ifdef MALI_SUPPORT ++#include "gator_events_mali_common.h" ++#endif ++ ++static void marshal_summary(long long timestamp, long long uptime, long long monotonic_delta, const char * uname) ++{ ++ unsigned long flags; ++ int cpu = 0; ++ ++ local_irq_save(flags); ++ gator_buffer_write_string(cpu, SUMMARY_BUF, NEWLINE_CANARY); ++ gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, timestamp); ++ gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, uptime); ++ gator_buffer_write_packed_int64(cpu, SUMMARY_BUF, monotonic_delta); ++ gator_buffer_write_string(cpu, SUMMARY_BUF, "uname"); ++ gator_buffer_write_string(cpu, SUMMARY_BUF, uname); ++#if GATOR_IKS_SUPPORT ++ gator_buffer_write_string(cpu, SUMMARY_BUF, "iks"); ++ gator_buffer_write_string(cpu, SUMMARY_BUF, ""); ++#endif ++ // Let Streamline know which GPU is used so that it can label the GPU Activity appropriately. This is a temporary fix, to be improved in a future release. ++#ifdef MALI_SUPPORT ++ gator_buffer_write_string(cpu, SUMMARY_BUF, "mali_type"); ++#if (MALI_SUPPORT == MALI_4xx) ++ gator_buffer_write_string(cpu, SUMMARY_BUF, "4xx"); ++#elif (MALI_SUPPORT == MALI_T6xx) ++ gator_buffer_write_string(cpu, SUMMARY_BUF, "6xx"); ++#else ++ gator_buffer_write_string(cpu, SUMMARY_BUF, "unknown"); ++#endif ++#endif ++ gator_buffer_write_string(cpu, SUMMARY_BUF, ""); ++ // Commit the buffer now so it can be one of the first frames read by Streamline ++ gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time()); ++ local_irq_restore(flags); ++} ++ ++static bool marshal_cookie_header(const char *text) ++{ ++ int cpu = get_physical_cpu(); ++ return buffer_check_space(cpu, NAME_BUF, strlen(text) + 3 * MAXSIZE_PACK32); ++} ++ ++static void marshal_cookie(int cookie, const char *text) ++{ ++ int cpu = get_physical_cpu(); ++ // buffer_check_space already called by marshal_cookie_header ++ gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_COOKIE); ++ gator_buffer_write_packed_int(cpu, NAME_BUF, cookie); ++ gator_buffer_write_string(cpu, NAME_BUF, text); ++ buffer_check(cpu, NAME_BUF, gator_get_time()); ++} ++ ++static void marshal_thread_name(int pid, char *name) ++{ ++ unsigned long flags, cpu; ++ u64 time; ++ local_irq_save(flags); ++ cpu = get_physical_cpu(); ++ time = gator_get_time(); ++ if (buffer_check_space(cpu, NAME_BUF, TASK_COMM_LEN + 3 * MAXSIZE_PACK32 + MAXSIZE_PACK64)) { ++ gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_THREAD_NAME); ++ gator_buffer_write_packed_int64(cpu, NAME_BUF, time); ++ gator_buffer_write_packed_int(cpu, NAME_BUF, pid); ++ gator_buffer_write_string(cpu, NAME_BUF, name); ++ } ++ buffer_check(cpu, NAME_BUF, time); ++ local_irq_restore(flags); ++} ++ ++static void marshal_link(int cookie, int tgid, int pid) ++{ ++ unsigned long cpu = get_physical_cpu(), flags; ++ u64 time; ++ ++ local_irq_save(flags); ++ time = gator_get_time(); ++ if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { ++ gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_LINK); ++ gator_buffer_write_packed_int64(cpu, NAME_BUF, time); ++ gator_buffer_write_packed_int(cpu, NAME_BUF, cookie); ++ gator_buffer_write_packed_int(cpu, NAME_BUF, tgid); ++ gator_buffer_write_packed_int(cpu, NAME_BUF, pid); ++ } ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, NAME_BUF, time); ++ local_irq_restore(flags); ++} ++ ++static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inKernel, u64 time) ++{ ++ int cpu = get_physical_cpu(); ++ if (!buffer_check_space(cpu, BACKTRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32 + gator_backtrace_depth * 2 * MAXSIZE_PACK32)) { ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, BACKTRACE_BUF, time); ++ ++ return false; ++ } ++ ++ gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, time); ++ gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, exec_cookie); ++ gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, tgid); ++ gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, pid); ++ gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, inKernel); ++ ++ return true; ++} ++ ++static void marshal_backtrace(unsigned long address, int cookie) ++{ ++ int cpu = get_physical_cpu(); ++ gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, cookie); ++ gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, address); ++} ++ ++static void marshal_backtrace_footer(u64 time) ++{ ++ int cpu = get_physical_cpu(); ++ gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, MESSAGE_END_BACKTRACE); ++ ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, BACKTRACE_BUF, time); ++} ++ ++static bool marshal_event_header(u64 time) ++{ ++ unsigned long flags, cpu = get_physical_cpu(); ++ bool retval = false; ++ ++ local_irq_save(flags); ++ if (buffer_check_space(cpu, BLOCK_COUNTER_BUF, MAXSIZE_PACK32 + MAXSIZE_PACK64)) { ++ gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, 0); // key of zero indicates a timestamp ++ gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, time); ++ retval = true; ++ } ++ local_irq_restore(flags); ++ ++ return retval; ++} ++ ++static void marshal_event(int len, int *buffer) ++{ ++ unsigned long i, flags, cpu = get_physical_cpu(); ++ ++ if (len <= 0) ++ return; ++ ++ // length must be even since all data is a (key, value) pair ++ if (len & 0x1) { ++ pr_err("gator: invalid counter data detected and discarded"); ++ return; ++ } ++ ++ // events must be written in key,value pairs ++ local_irq_save(flags); ++ for (i = 0; i < len; i += 2) { ++ if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK32)) { ++ break; ++ } ++ gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i]); ++ gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i + 1]); ++ } ++ local_irq_restore(flags); ++} ++ ++static void marshal_event64(int len, long long *buffer64) ++{ ++ unsigned long i, flags, cpu = get_physical_cpu(); ++ ++ if (len <= 0) ++ return; ++ ++ // length must be even since all data is a (key, value) pair ++ if (len & 0x1) { ++ pr_err("gator: invalid counter data detected and discarded"); ++ return; ++ } ++ ++ // events must be written in key,value pairs ++ local_irq_save(flags); ++ for (i = 0; i < len; i += 2) { ++ if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK64)) { ++ break; ++ } ++ gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i]); ++ gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i + 1]); ++ } ++ local_irq_restore(flags); ++} ++ ++#if GATOR_CPU_FREQ_SUPPORT ++static void marshal_event_single(int core, int key, int value) ++{ ++ unsigned long flags, cpu; ++ u64 time; ++ ++ local_irq_save(flags); ++ cpu = get_physical_cpu(); ++ time = gator_get_time(); ++ if (buffer_check_space(cpu, COUNTER_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) { ++ gator_buffer_write_packed_int64(cpu, COUNTER_BUF, time); ++ gator_buffer_write_packed_int(cpu, COUNTER_BUF, core); ++ gator_buffer_write_packed_int(cpu, COUNTER_BUF, key); ++ gator_buffer_write_packed_int(cpu, COUNTER_BUF, value); ++ } ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, COUNTER_BUF, time); ++ local_irq_restore(flags); ++} ++#endif ++ ++static void marshal_sched_gpu_start(int unit, int core, int tgid, int pid) ++{ ++ unsigned long cpu = get_physical_cpu(), flags; ++ u64 time; ++ ++ if (!per_cpu(gator_buffer, cpu)[GPU_TRACE_BUF]) ++ return; ++ ++ local_irq_save(flags); ++ time = gator_get_time(); ++ if (buffer_check_space(cpu, GPU_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { ++ gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, MESSAGE_GPU_START); ++ gator_buffer_write_packed_int64(cpu, GPU_TRACE_BUF, time); ++ gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit); ++ gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core); ++ gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, tgid); ++ gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, pid); ++ } ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, GPU_TRACE_BUF, time); ++ local_irq_restore(flags); ++} ++ ++static void marshal_sched_gpu_stop(int unit, int core) ++{ ++ unsigned long cpu = get_physical_cpu(), flags; ++ u64 time; ++ ++ if (!per_cpu(gator_buffer, cpu)[GPU_TRACE_BUF]) ++ return; ++ ++ local_irq_save(flags); ++ time = gator_get_time(); ++ if (buffer_check_space(cpu, GPU_TRACE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) { ++ gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, MESSAGE_GPU_STOP); ++ gator_buffer_write_packed_int64(cpu, GPU_TRACE_BUF, time); ++ gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit); ++ gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core); ++ } ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, GPU_TRACE_BUF, time); ++ local_irq_restore(flags); ++} ++ ++static void marshal_sched_trace_start(int tgid, int pid, int cookie) ++{ ++ unsigned long cpu = get_physical_cpu(), flags; ++ u64 time; ++ ++ if (!per_cpu(gator_buffer, cpu)[SCHED_TRACE_BUF]) ++ return; ++ ++ local_irq_save(flags); ++ time = gator_get_time(); ++ if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { ++ gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, MESSAGE_SCHED_START); ++ gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time); ++ gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, tgid); ++ gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid); ++ gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie); ++ } ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, SCHED_TRACE_BUF, time); ++ local_irq_restore(flags); ++} ++ ++static void marshal_sched_trace_switch(int tgid, int pid, int cookie, int state) ++{ ++ unsigned long cpu = get_physical_cpu(), flags; ++ u64 time; ++ ++ if (!per_cpu(gator_buffer, cpu)[SCHED_TRACE_BUF]) ++ return; ++ ++ local_irq_save(flags); ++ time = gator_get_time(); ++ if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { ++ gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, MESSAGE_SCHED_SWITCH); ++ gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time); ++ gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, tgid); ++ gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid); ++ gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie); ++ gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, state); ++ } ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, SCHED_TRACE_BUF, time); ++ local_irq_restore(flags); ++} ++ ++static void marshal_sched_trace_exit(int tgid, int pid) ++{ ++ unsigned long cpu = get_physical_cpu(), flags; ++ u64 time; ++ ++ if (!per_cpu(gator_buffer, cpu)[SCHED_TRACE_BUF]) ++ return; ++ ++ local_irq_save(flags); ++ time = gator_get_time(); ++ if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) { ++ gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, MESSAGE_SCHED_EXIT); ++ gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time); ++ gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid); ++ } ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, SCHED_TRACE_BUF, time); ++ local_irq_restore(flags); ++} ++ ++#if GATOR_CPU_FREQ_SUPPORT ++static void marshal_idle(int core, int state) ++{ ++ unsigned long flags, cpu; ++ u64 time; ++ ++ local_irq_save(flags); ++ cpu = get_physical_cpu(); ++ time = gator_get_time(); ++ if (buffer_check_space(cpu, IDLE_BUF, MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) { ++ gator_buffer_write_packed_int(cpu, IDLE_BUF, state); ++ gator_buffer_write_packed_int64(cpu, IDLE_BUF, time); ++ gator_buffer_write_packed_int(cpu, IDLE_BUF, core); ++ } ++ // Check and commit; commit is set to occur once buffer is 3/4 full ++ buffer_check(cpu, IDLE_BUF, time); ++ local_irq_restore(flags); ++} ++#endif ++ ++static void marshal_frame(int cpu, int buftype) ++{ ++ int frame; ++ ++ if (!per_cpu(gator_buffer, cpu)[buftype]) { ++ return; ++ } ++ ++ switch (buftype) { ++ case SUMMARY_BUF: ++ frame = FRAME_SUMMARY; ++ break; ++ case BACKTRACE_BUF: ++ frame = FRAME_BACKTRACE; ++ break; ++ case NAME_BUF: ++ frame = FRAME_NAME; ++ break; ++ case COUNTER_BUF: ++ frame = FRAME_COUNTER; ++ break; ++ case BLOCK_COUNTER_BUF: ++ frame = FRAME_BLOCK_COUNTER; ++ break; ++ case ANNOTATE_BUF: ++ frame = FRAME_ANNOTATE; ++ break; ++ case SCHED_TRACE_BUF: ++ frame = FRAME_SCHED_TRACE; ++ break; ++ case GPU_TRACE_BUF: ++ frame = FRAME_GPU_TRACE; ++ break; ++ case IDLE_BUF: ++ frame = FRAME_IDLE; ++ break; ++ default: ++ frame = -1; ++ break; ++ } ++ ++ // add response type ++ if (gator_response_type > 0) { ++ gator_buffer_write_packed_int(cpu, buftype, gator_response_type); ++ } ++ ++ // leave space for 4-byte unpacked length ++ per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + sizeof(s32)) & gator_buffer_mask[buftype]; ++ ++ // add frame type and core number ++ gator_buffer_write_packed_int(cpu, buftype, frame); ++ gator_buffer_write_packed_int(cpu, buftype, cpu); ++} ++ ++#if defined(__arm__) || defined(__aarch64__) ++static void marshal_core_name(const int core, const int cpuid, const char *name) ++{ ++ int cpu = get_physical_cpu(); ++ unsigned long flags; ++ local_irq_save(flags); ++ if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK32 + MAXSIZE_CORE_NAME)) { ++ gator_buffer_write_packed_int(cpu, NAME_BUF, HRTIMER_CORE_NAME); ++ gator_buffer_write_packed_int(cpu, NAME_BUF, core); ++ gator_buffer_write_packed_int(cpu, NAME_BUF, cpuid); ++ gator_buffer_write_string(cpu, NAME_BUF, name); ++ } ++ // Commit core names now so that they can show up in live ++ gator_commit_buffer(cpu, NAME_BUF, gator_get_time()); ++ local_irq_restore(flags); ++} ++#endif +diff -Nur linux-3.10.30/drivers/gator/gator_pack.c linux-3.10.30-cubox-i/drivers/gator/gator_pack.c +--- linux-3.10.30/drivers/gator/gator_pack.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_pack.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,58 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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. ++ * ++ */ ++ ++static void gator_buffer_write_packed_int(int cpu, int buftype, int x) ++{ ++ uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype]; ++ uint32_t mask = gator_buffer_mask[buftype]; ++ char *buffer = per_cpu(gator_buffer, cpu)[buftype]; ++ int packedBytes = 0; ++ int more = true; ++ while (more) { ++ // low order 7 bits of x ++ char b = x & 0x7f; ++ x >>= 7; ++ ++ if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) { ++ more = false; ++ } else { ++ b |= 0x80; ++ } ++ ++ buffer[(write + packedBytes) & mask] = b; ++ packedBytes++; ++ } ++ ++ per_cpu(gator_buffer_write, cpu)[buftype] = (write + packedBytes) & mask; ++} ++ ++static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x) ++{ ++ uint32_t write = per_cpu(gator_buffer_write, cpu)[buftype]; ++ uint32_t mask = gator_buffer_mask[buftype]; ++ char *buffer = per_cpu(gator_buffer, cpu)[buftype]; ++ int packedBytes = 0; ++ int more = true; ++ while (more) { ++ // low order 7 bits of x ++ char b = x & 0x7f; ++ x >>= 7; ++ ++ if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) { ++ more = false; ++ } else { ++ b |= 0x80; ++ } ++ ++ buffer[(write + packedBytes) & mask] = b; ++ packedBytes++; ++ } ++ ++ per_cpu(gator_buffer_write, cpu)[buftype] = (write + packedBytes) & mask; ++} +diff -Nur linux-3.10.30/drivers/gator/gator_trace_gpu.c linux-3.10.30-cubox-i/drivers/gator/gator_trace_gpu.c +--- linux-3.10.30/drivers/gator/gator_trace_gpu.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_trace_gpu.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,294 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++ ++#include ++#include ++#include ++#include ++ ++#ifdef MALI_SUPPORT ++#include "linux/mali_linux_trace.h" ++#endif ++#include "gator_trace_gpu.h" ++ ++/* ++ * Taken from MALI_PROFILING_EVENT_TYPE_* items in Mali DDK. ++ */ ++#define EVENT_TYPE_SINGLE 0 ++#define EVENT_TYPE_START 1 ++#define EVENT_TYPE_STOP 2 ++#define EVENT_TYPE_SUSPEND 3 ++#define EVENT_TYPE_RESUME 4 ++ ++/* Note whether tracepoints have been registered */ ++static int mali_timeline_trace_registered; ++static int mali_job_slots_trace_registered; ++static int gpu_trace_registered; ++ ++enum { ++ GPU_UNIT_NONE = 0, ++ GPU_UNIT_VP, ++ GPU_UNIT_FP, ++ GPU_UNIT_CL, ++ NUMBER_OF_GPU_UNITS ++}; ++ ++#define MALI_4xx (0x0b07) ++#define MALI_T6xx (0x0056) ++ ++struct mali_gpu_job { ++ int count; ++ int last_tgid; ++ int last_pid; ++ int last_job_id; ++}; ++ ++#define NUMBER_OF_GPU_CORES 16 ++static struct mali_gpu_job mali_gpu_jobs[NUMBER_OF_GPU_UNITS][NUMBER_OF_GPU_CORES]; ++static DEFINE_SPINLOCK(mali_gpu_jobs_lock); ++ ++/* Only one event should be running on a unit and core at a time (ie, a start ++ * event can only be followed by a stop and vice versa), but because the kernel ++ * only knows when a job is enqueued and not started, it is possible for a ++ * start1, start2, stop1, stop2. Change it back into start1, stop1, start2, ++ * stop2 by queueing up start2 and releasing it when stop1 is received. ++ */ ++static void mali_gpu_enqueue(int unit, int core, int tgid, int pid, int job_id) ++{ ++ int count; ++ ++ spin_lock(&mali_gpu_jobs_lock); ++ count = mali_gpu_jobs[unit][core].count; ++ BUG_ON(count < 0); ++ ++mali_gpu_jobs[unit][core].count; ++ if (count) { ++ mali_gpu_jobs[unit][core].last_tgid = tgid; ++ mali_gpu_jobs[unit][core].last_pid = pid; ++ mali_gpu_jobs[unit][core].last_job_id = job_id; ++ } ++ spin_unlock(&mali_gpu_jobs_lock); ++ ++ if (!count) { ++ marshal_sched_gpu_start(unit, core, tgid, pid/*, job_id*/); ++ } ++} ++ ++static void mali_gpu_stop(int unit, int core) ++{ ++ int count; ++ int last_tgid = 0; ++ int last_pid = 0; ++ //int last_job_id = 0; ++ ++ spin_lock(&mali_gpu_jobs_lock); ++ if (mali_gpu_jobs[unit][core].count == 0) { ++ spin_unlock(&mali_gpu_jobs_lock); ++ return; ++ } ++ --mali_gpu_jobs[unit][core].count; ++ count = mali_gpu_jobs[unit][core].count; ++ if (count) { ++ last_tgid = mali_gpu_jobs[unit][core].last_tgid; ++ last_pid = mali_gpu_jobs[unit][core].last_pid; ++ //last_job_id = mali_gpu_jobs[unit][core].last_job_id; ++ } ++ spin_unlock(&mali_gpu_jobs_lock); ++ ++ marshal_sched_gpu_stop(unit, core); ++ if (count) { ++ marshal_sched_gpu_start(unit, core, last_tgid, last_pid/*, last_job_id*/); ++ } ++} ++ ++#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx) ++#include "gator_events_mali_4xx.h" ++ ++/* ++ * Taken from MALI_PROFILING_EVENT_CHANNEL_* in Mali DDK. ++ */ ++enum { ++ EVENT_CHANNEL_SOFTWARE = 0, ++ EVENT_CHANNEL_VP0 = 1, ++ EVENT_CHANNEL_FP0 = 5, ++ EVENT_CHANNEL_FP1, ++ EVENT_CHANNEL_FP2, ++ EVENT_CHANNEL_FP3, ++ EVENT_CHANNEL_FP4, ++ EVENT_CHANNEL_FP5, ++ EVENT_CHANNEL_FP6, ++ EVENT_CHANNEL_FP7, ++ EVENT_CHANNEL_GPU = 21 ++}; ++ ++/** ++ * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SINGLE is used from the GPU channel ++ */ ++enum { ++ EVENT_REASON_SINGLE_GPU_NONE = 0, ++ EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE = 1, ++}; ++ ++GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4)) ++{ ++ unsigned int component, state; ++ ++ // do as much work as possible before disabling interrupts ++ component = (event_id >> 16) & 0xFF; // component is an 8-bit field ++ state = (event_id >> 24) & 0xF; // state is a 4-bit field ++ ++ switch (state) { ++ case EVENT_TYPE_START: ++ if (component == EVENT_CHANNEL_VP0) { ++ /* tgid = d0; pid = d1; */ ++ mali_gpu_enqueue(GPU_UNIT_VP, 0, d0, d1, 0); ++ } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) { ++ /* tgid = d0; pid = d1; */ ++ mali_gpu_enqueue(GPU_UNIT_FP, component - EVENT_CHANNEL_FP0, d0, d1, 0); ++ } ++ break; ++ ++ case EVENT_TYPE_STOP: ++ if (component == EVENT_CHANNEL_VP0) { ++ mali_gpu_stop(GPU_UNIT_VP, 0); ++ } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) { ++ mali_gpu_stop(GPU_UNIT_FP, component - EVENT_CHANNEL_FP0); ++ } ++ break; ++ ++ case EVENT_TYPE_SINGLE: ++ if (component == EVENT_CHANNEL_GPU) { ++ unsigned int reason = (event_id & 0xffff); ++ ++ if (reason == EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE) { ++ gator_events_mali_log_dvfs_event(d0, d1); ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++} ++#endif ++ ++#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx) ++#if defined(MALI_JOB_SLOTS_EVENT_CHANGED) ++GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid, unsigned char job_id)) ++#else ++GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid)) ++#endif ++{ ++ unsigned int component, state, unit; ++#if !defined(MALI_JOB_SLOTS_EVENT_CHANGED) ++ unsigned char job_id = 0; ++#endif ++ ++ component = (event_id >> 16) & 0xFF; // component is an 8-bit field ++ state = (event_id >> 24) & 0xF; // state is a 4-bit field ++ ++ switch (component) { ++ case 0: ++ unit = GPU_UNIT_FP; ++ break; ++ case 1: ++ unit = GPU_UNIT_VP; ++ break; ++ case 2: ++ unit = GPU_UNIT_CL; ++ break; ++ default: ++ unit = GPU_UNIT_NONE; ++ } ++ ++ if (unit != GPU_UNIT_NONE) { ++ switch (state) { ++ case EVENT_TYPE_START: ++ mali_gpu_enqueue(unit, 0, tgid, (pid != 0 ? pid : tgid), job_id); ++ break; ++ case EVENT_TYPE_STOP: ++ mali_gpu_stop(unit, 0); ++ break; ++ default: ++ /* ++ * Some jobs can be soft-stopped, so ensure that this terminates the activity trace. ++ */ ++ mali_gpu_stop(unit, 0); ++ } ++ } ++} ++#endif ++ ++GATOR_DEFINE_PROBE(gpu_activity_start, TP_PROTO(int gpu_unit, int gpu_core, struct task_struct *p)) ++{ ++ mali_gpu_enqueue(gpu_unit, gpu_core, (int)p->tgid, (int)p->pid, 0); ++} ++ ++GATOR_DEFINE_PROBE(gpu_activity_stop, TP_PROTO(int gpu_unit, int gpu_core)) ++{ ++ mali_gpu_stop(gpu_unit, gpu_core); ++} ++ ++int gator_trace_gpu_start(void) ++{ ++ /* ++ * Returns nonzero for installation failed ++ * Absence of gpu trace points is not an error ++ */ ++ ++ memset(&mali_gpu_jobs, 0, sizeof(mali_gpu_jobs)); ++ gpu_trace_registered = mali_timeline_trace_registered = mali_job_slots_trace_registered = 0; ++ ++#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx) ++ if (!GATOR_REGISTER_TRACE(mali_timeline_event)) { ++ mali_timeline_trace_registered = 1; ++ } ++#endif ++ ++#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx) ++ if (!GATOR_REGISTER_TRACE(mali_job_slots_event)) { ++ mali_job_slots_trace_registered = 1; ++ } ++#endif ++ ++ if (!mali_timeline_trace_registered) { ++ if (GATOR_REGISTER_TRACE(gpu_activity_start)) { ++ return 0; ++ } ++ if (GATOR_REGISTER_TRACE(gpu_activity_stop)) { ++ GATOR_UNREGISTER_TRACE(gpu_activity_start); ++ return 0; ++ } ++ gpu_trace_registered = 1; ++ } ++ ++ return 0; ++} ++ ++void gator_trace_gpu_stop(void) ++{ ++#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx) ++ if (mali_timeline_trace_registered) { ++ GATOR_UNREGISTER_TRACE(mali_timeline_event); ++ } ++#endif ++ ++#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx) ++ if (mali_job_slots_trace_registered) { ++ GATOR_UNREGISTER_TRACE(mali_job_slots_event); ++ } ++#endif ++ ++ if (gpu_trace_registered) { ++ GATOR_UNREGISTER_TRACE(gpu_activity_stop); ++ GATOR_UNREGISTER_TRACE(gpu_activity_start); ++ } ++ ++ gpu_trace_registered = mali_timeline_trace_registered = mali_job_slots_trace_registered = 0; ++} +diff -Nur linux-3.10.30/drivers/gator/gator_trace_gpu.h linux-3.10.30-cubox-i/drivers/gator/gator_trace_gpu.h +--- linux-3.10.30/drivers/gator/gator_trace_gpu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_trace_gpu.h 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,79 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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. ++ */ ++ ++#undef TRACE_GPU ++#define TRACE_GPU gpu ++ ++#if !defined(_TRACE_GPU_H) ++#define _TRACE_GPU_H ++ ++#include ++ ++/* ++ * UNIT - the GPU processor type ++ * 1 = Vertex Processor ++ * 2 = Fragment Processor ++ * ++ * CORE - the GPU processor core number ++ * this is not the CPU core number ++ */ ++ ++/* ++ * Tracepoint for calling GPU unit start activity on core ++ */ ++TRACE_EVENT(gpu_activity_start, ++ ++ TP_PROTO(int gpu_unit, int gpu_core, struct task_struct *p), ++ ++ TP_ARGS(gpu_unit, gpu_core, p), ++ ++ TP_STRUCT__entry( ++ __field(int, gpu_unit) ++ __field(int, gpu_core) ++ __array(char, comm, TASK_COMM_LEN) ++ __field(pid_t, pid) ++ ), ++ ++ TP_fast_assign( ++ __entry->gpu_unit = gpu_unit; ++ __entry->gpu_core = gpu_core; ++ memcpy(__entry->comm, p->comm, TASK_COMM_LEN); ++ __entry->pid = p->pid; ++ ), ++ ++ TP_printk("unit=%d core=%d comm=%s pid=%d", ++ __entry->gpu_unit, __entry->gpu_core, __entry->comm, ++ __entry->pid) ++ ); ++ ++/* ++ * Tracepoint for calling GPU unit stop activity on core ++ */ ++TRACE_EVENT(gpu_activity_stop, ++ ++ TP_PROTO(int gpu_unit, int gpu_core), ++ ++ TP_ARGS(gpu_unit, gpu_core), ++ ++ TP_STRUCT__entry( ++ __field(int, gpu_unit) ++ __field(int, gpu_core) ++ ), ++ ++ TP_fast_assign( ++ __entry->gpu_unit = gpu_unit; ++ __entry->gpu_core = gpu_core; ++ ), ++ ++ TP_printk("unit=%d core=%d", __entry->gpu_unit, __entry->gpu_core) ++ ); ++ ++#endif /* _TRACE_GPU_H */ ++ ++/* This part must be outside protection */ ++#include +diff -Nur linux-3.10.30/drivers/gator/gator_trace_power.c linux-3.10.30-cubox-i/drivers/gator/gator_trace_power.c +--- linux-3.10.30/drivers/gator/gator_trace_power.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_trace_power.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,203 @@ ++/** ++ * Copyright (C) ARM Limited 2011-2013. All rights reserved. ++ * ++ * This program 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 ++ ++#if defined(__arm__) ++ ++#include ++ ++#define implements_wfi() (!machine_is_omap3_beagle()) ++ ++#else ++ ++#define implements_wfi() false ++ ++#endif ++ ++// cpu_frequency and cpu_idle trace points were introduced in Linux kernel v2.6.38 ++// the now deprecated power_frequency trace point was available prior to 2.6.38, but only for x86 ++#if GATOR_CPU_FREQ_SUPPORT ++enum { ++ POWER_CPU_FREQ, ++ POWER_CPU_IDLE, ++ POWER_TOTAL ++}; ++ ++static DEFINE_PER_CPU(ulong, idle_prev_state); ++static ulong power_cpu_enabled[POWER_TOTAL]; ++static ulong power_cpu_key[POWER_TOTAL]; ++ ++static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root) ++{ ++ struct dentry *dir; ++ int cpu; ++ bool found_nonzero_freq = false; ++ ++ // Even if CONFIG_CPU_FREQ is defined, it still may not be used. Check ++ // for non-zero values from cpufreq_quick_get ++ for_each_online_cpu(cpu) { ++ if (cpufreq_quick_get(cpu) > 0) { ++ found_nonzero_freq = true; ++ break; ++ } ++ } ++ ++ if (found_nonzero_freq) { ++ // cpu_frequency ++ dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_freq"); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_FREQ]); ++ gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_FREQ]); ++ } ++ ++ // cpu_idle ++ dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_idle"); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_IDLE]); ++ gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_IDLE]); ++ ++ return 0; ++} ++ ++// 'cpu' may not equal smp_processor_id(), i.e. may not be running on the core that is having the freq/idle state change ++GATOR_DEFINE_PROBE(cpu_frequency, TP_PROTO(unsigned int frequency, unsigned int cpu)) ++{ ++ cpu = lcpu_to_pcpu(cpu); ++ marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], frequency * 1000); ++} ++ ++GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu)) ++{ ++ cpu = lcpu_to_pcpu(cpu); ++ ++ if (state == per_cpu(idle_prev_state, cpu)) { ++ return; ++ } ++ ++ if (implements_wfi()) { ++ if (state == PWR_EVENT_EXIT) { ++ // transition from wfi to non-wfi ++ marshal_idle(cpu, MESSAGE_IDLE_EXIT); ++ } else { ++ // transition from non-wfi to wfi ++ marshal_idle(cpu, MESSAGE_IDLE_ENTER); ++ } ++ } ++ ++ per_cpu(idle_prev_state, cpu) = state; ++ ++ if (power_cpu_enabled[POWER_CPU_IDLE]) { ++ // Increment state so that no negative numbers are sent ++ marshal_event_single(cpu, power_cpu_key[POWER_CPU_IDLE], state + 1); ++ } ++} ++ ++static void gator_trace_power_online(void) ++{ ++ int pcpu = get_physical_cpu(); ++ int lcpu = get_logical_cpu(); ++ if (power_cpu_enabled[POWER_CPU_FREQ]) { ++ marshal_event_single(pcpu, power_cpu_key[POWER_CPU_FREQ], cpufreq_quick_get(lcpu) * 1000); ++ } ++} ++ ++static void gator_trace_power_offline(void) ++{ ++ // Set frequency to zero on an offline ++ int cpu = get_physical_cpu(); ++ if (power_cpu_enabled[POWER_CPU_FREQ]) { ++ marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], 0); ++ } ++} ++ ++static int gator_trace_power_start(void) ++{ ++ int cpu; ++ ++ // register tracepoints ++ if (power_cpu_enabled[POWER_CPU_FREQ]) ++ if (GATOR_REGISTER_TRACE(cpu_frequency)) ++ goto fail_cpu_frequency_exit; ++ ++ // Always register for cpu:idle for detecting WFI, independent of power_cpu_enabled[POWER_CPU_IDLE] ++ if (GATOR_REGISTER_TRACE(cpu_idle)) ++ goto fail_cpu_idle_exit; ++ pr_debug("gator: registered power event tracepoints\n"); ++ ++ for_each_present_cpu(cpu) { ++ per_cpu(idle_prev_state, cpu) = 0; ++ } ++ ++ return 0; ++ ++ // unregister tracepoints on error ++fail_cpu_idle_exit: ++ if (power_cpu_enabled[POWER_CPU_FREQ]) ++ GATOR_UNREGISTER_TRACE(cpu_frequency); ++fail_cpu_frequency_exit: ++ pr_err("gator: power event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); ++ ++ return -1; ++} ++ ++static void gator_trace_power_stop(void) ++{ ++ int i; ++ ++ if (power_cpu_enabled[POWER_CPU_FREQ]) ++ GATOR_UNREGISTER_TRACE(cpu_frequency); ++ GATOR_UNREGISTER_TRACE(cpu_idle); ++ pr_debug("gator: unregistered power event tracepoints\n"); ++ ++ for (i = 0; i < POWER_TOTAL; i++) { ++ power_cpu_enabled[i] = 0; ++ } ++} ++ ++void gator_trace_power_init(void) ++{ ++ int i; ++ for (i = 0; i < POWER_TOTAL; i++) { ++ power_cpu_enabled[i] = 0; ++ power_cpu_key[i] = gator_events_get_key(); ++ } ++} ++#else ++static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root) ++{ ++ return 0; ++} ++ ++static void gator_trace_power_online(void) ++{ ++} ++ ++static void gator_trace_power_offline(void) ++{ ++} ++ ++static int gator_trace_power_start(void) ++{ ++ return 0; ++} ++ ++static void gator_trace_power_stop(void) ++{ ++} ++ ++void gator_trace_power_init(void) ++{ ++} ++#endif +diff -Nur linux-3.10.30/drivers/gator/gator_trace_sched.c linux-3.10.30-cubox-i/drivers/gator/gator_trace_sched.c +--- linux-3.10.30/drivers/gator/gator_trace_sched.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/gator_trace_sched.c 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,270 @@ ++/** ++ * Copyright (C) ARM Limited 2010-2013. All rights reserved. ++ * ++ * This program 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 "gator.h" ++ ++#define TASK_MAP_ENTRIES 1024 /* must be power of 2 */ ++#define TASK_MAX_COLLISIONS 2 ++ ++enum { ++ STATE_WAIT_ON_OTHER = 0, ++ STATE_CONTENTION, ++ STATE_WAIT_ON_IO, ++ CPU_WAIT_TOTAL ++}; ++ ++static DEFINE_PER_CPU(uint64_t *, taskname_keys); ++static DEFINE_PER_CPU(int, collecting); ++static DEFINE_PER_CPU(bool, in_scheduler_context); ++ ++// this array is never read as the cpu wait charts are derived counters ++// the files are needed, nonetheless, to show that these counters are available ++static ulong cpu_wait_enabled[CPU_WAIT_TOTAL]; ++static ulong sched_cpu_key[CPU_WAIT_TOTAL]; ++ ++static int sched_trace_create_files(struct super_block *sb, struct dentry *root) ++{ ++ struct dentry *dir; ++ ++ // CPU Wait - Contention ++ dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_contention"); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_CONTENTION]); ++ gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_CONTENTION]); ++ ++ // CPU Wait - I/O ++ dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_io"); ++ if (!dir) { ++ return -1; ++ } ++ gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_WAIT_ON_IO]); ++ gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_WAIT_ON_IO]); ++ ++ return 0; ++} ++ ++void emit_pid_name(struct task_struct *task) ++{ ++ bool found = false; ++ char taskcomm[TASK_COMM_LEN + 3]; ++ unsigned long x, cpu = get_physical_cpu(); ++ uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]); ++ uint64_t value; ++ ++ value = gator_chksum_crc32(task->comm); ++ value = (value << 32) | (uint32_t)task->pid; ++ ++ // determine if the thread name was emitted already ++ for (x = 0; x < TASK_MAX_COLLISIONS; x++) { ++ if (keys[x] == value) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) { ++ // shift values, new value always in front ++ uint64_t oldv, newv = value; ++ for (x = 0; x < TASK_MAX_COLLISIONS; x++) { ++ oldv = keys[x]; ++ keys[x] = newv; ++ newv = oldv; ++ } ++ ++ // emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions ++ if (strlcpy(taskcomm, task->comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1) { ++ // append ellipses if task->comm has length of TASK_COMM_LEN - 1 ++ strcat(taskcomm, "..."); ++ } ++ ++ marshal_thread_name(task->pid, taskcomm); ++ } ++} ++ ++static void collect_counters(u64 time, struct task_struct *task) ++{ ++ int *buffer, len, cpu = get_physical_cpu(); ++ long long *buffer64; ++ struct gator_interface *gi; ++ ++ if (marshal_event_header(time)) { ++ list_for_each_entry(gi, &gator_events, list) { ++ if (gi->read) { ++ len = gi->read(&buffer); ++ marshal_event(len, buffer); ++ } else if (gi->read64) { ++ len = gi->read64(&buffer64); ++ marshal_event64(len, buffer64); ++ } ++ if (gi->read_proc && task != NULL) { ++ len = gi->read_proc(&buffer64, task); ++ marshal_event64(len, buffer64); ++ } ++ } ++ // Only check after writing all counters so that time and corresponding counters appear in the same frame ++ buffer_check(cpu, BLOCK_COUNTER_BUF, time); ++ ++ // Commit buffers on timeout ++ if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) { ++ static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF }; ++ unsigned long flags; ++ int i; ++ ++ local_irq_save(flags); ++ for (i = 0; i < ARRAY_SIZE(buftypes); ++i) { ++ gator_commit_buffer(cpu, buftypes[i], time); ++ } ++ local_irq_restore(flags); ++ ++ // Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full ++ if (on_primary_core() && spin_trylock(&annotate_lock)) { ++ gator_commit_buffer(0, ANNOTATE_BUF, time); ++ spin_unlock(&annotate_lock); ++ } ++ } ++ } ++} ++ ++// special case used during a suspend of the system ++static void trace_sched_insert_idle(void) ++{ ++ marshal_sched_trace_switch(0, 0, 0, 0); ++} ++ ++GATOR_DEFINE_PROBE(sched_process_fork, TP_PROTO(struct task_struct *parent, struct task_struct *child)) ++{ ++ int cookie; ++ int cpu = get_physical_cpu(); ++ ++ cookie = get_exec_cookie(cpu, child); ++ emit_pid_name(child); ++ ++ marshal_sched_trace_start(child->tgid, child->pid, cookie); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) ++GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next)) ++#else ++GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next)) ++#endif ++{ ++ int cookie; ++ int state; ++ int cpu = get_physical_cpu(); ++ ++ per_cpu(in_scheduler_context, cpu) = true; ++ ++ // do as much work as possible before disabling interrupts ++ cookie = get_exec_cookie(cpu, next); ++ emit_pid_name(next); ++ if (prev->state == TASK_RUNNING) { ++ state = STATE_CONTENTION; ++ } else if (prev->in_iowait) { ++ state = STATE_WAIT_ON_IO; ++ } else { ++ state = STATE_WAIT_ON_OTHER; ++ } ++ ++ per_cpu(collecting, cpu) = 1; ++ collect_counters(gator_get_time(), prev); ++ per_cpu(collecting, cpu) = 0; ++ ++ marshal_sched_trace_switch(next->tgid, next->pid, cookie, state); ++ ++ per_cpu(in_scheduler_context, cpu) = false; ++} ++ ++GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p)) ++{ ++ marshal_sched_trace_exit(p->tgid, p->pid); ++} ++ ++static void do_nothing(void *info) ++{ ++ // Intentionally do nothing ++ (void)info; ++} ++ ++static int register_scheduler_tracepoints(void) ++{ ++ // register tracepoints ++ if (GATOR_REGISTER_TRACE(sched_process_fork)) ++ goto fail_sched_process_fork; ++ if (GATOR_REGISTER_TRACE(sched_switch)) ++ goto fail_sched_switch; ++ if (GATOR_REGISTER_TRACE(sched_process_free)) ++ goto fail_sched_process_free; ++ pr_debug("gator: registered tracepoints\n"); ++ ++ // Now that the scheduler tracepoint is registered, force a context switch ++ // on all cpus to capture what is currently running. ++ on_each_cpu(do_nothing, NULL, 0); ++ ++ return 0; ++ ++ // unregister tracepoints on error ++fail_sched_process_free: ++ GATOR_UNREGISTER_TRACE(sched_switch); ++fail_sched_switch: ++ GATOR_UNREGISTER_TRACE(sched_process_fork); ++fail_sched_process_fork: ++ pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); ++ ++ return -1; ++} ++ ++int gator_trace_sched_start(void) ++{ ++ int cpu, size; ++ ++ for_each_present_cpu(cpu) { ++ size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t); ++ per_cpu(taskname_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL); ++ if (!per_cpu(taskname_keys, cpu)) ++ return -1; ++ memset(per_cpu(taskname_keys, cpu), 0, size); ++ } ++ ++ return register_scheduler_tracepoints(); ++} ++ ++void gator_trace_sched_offline(void) ++{ ++ trace_sched_insert_idle(); ++} ++ ++static void unregister_scheduler_tracepoints(void) ++{ ++ GATOR_UNREGISTER_TRACE(sched_process_fork); ++ GATOR_UNREGISTER_TRACE(sched_switch); ++ GATOR_UNREGISTER_TRACE(sched_process_free); ++ pr_debug("gator: unregistered tracepoints\n"); ++} ++ ++void gator_trace_sched_stop(void) ++{ ++ int cpu; ++ unregister_scheduler_tracepoints(); ++ ++ for_each_present_cpu(cpu) { ++ kfree(per_cpu(taskname_keys, cpu)); ++ } ++} ++ ++void gator_trace_sched_init(void) ++{ ++ int i; ++ for (i = 0; i < CPU_WAIT_TOTAL; i++) { ++ cpu_wait_enabled[i] = 0; ++ sched_cpu_key[i] = gator_events_get_key(); ++ } ++} +diff -Nur linux-3.10.30/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h linux-3.10.30-cubox-i/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h +--- linux-3.10.30/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,163 @@ ++/** ++ * Copyright (C) ARM Limited 2013. All rights reserved. ++ * ++ * This program 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 __MALI_MJOLLNIR_PROFILING_GATOR_API_H__ ++#define __MALI_MJOLLNIR_PROFILING_GATOR_API_H__ ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++ ++/* ++ * The number of processor cores. Update to suit your hardware implementation. ++ */ ++#define MAX_NUM_FP_CORES (4) ++#define MAX_NUM_VP_CORES (1) ++#define MAX_NUM_L2_CACHE_CORES (1) ++ ++enum counters ++{ ++ /* Timeline activity */ ++ ACTIVITY_VP_0 = 0, ++ ACTIVITY_FP_0, ++ ACTIVITY_FP_1, ++ ACTIVITY_FP_2, ++ ACTIVITY_FP_3, ++ ++ /* L2 cache counters */ ++ COUNTER_L2_0_C0, ++ COUNTER_L2_0_C1, ++ ++ /* Vertex processor counters */ ++ COUNTER_VP_0_C0, ++ COUNTER_VP_0_C1, ++ ++ /* Fragment processor counters */ ++ COUNTER_FP_0_C0, ++ COUNTER_FP_0_C1, ++ COUNTER_FP_1_C0, ++ COUNTER_FP_1_C1, ++ COUNTER_FP_2_C0, ++ COUNTER_FP_2_C1, ++ COUNTER_FP_3_C0, ++ COUNTER_FP_3_C1, ++ ++ /* EGL Software Counters */ ++ COUNTER_EGL_BLIT_TIME, ++ ++ /* GLES Software Counters */ ++ COUNTER_GLES_DRAW_ELEMENTS_CALLS, ++ COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES, ++ COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED, ++ COUNTER_GLES_DRAW_ARRAYS_CALLS, ++ COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED, ++ COUNTER_GLES_DRAW_POINTS, ++ COUNTER_GLES_DRAW_LINES, ++ COUNTER_GLES_DRAW_LINE_LOOP, ++ COUNTER_GLES_DRAW_LINE_STRIP, ++ COUNTER_GLES_DRAW_TRIANGLES, ++ COUNTER_GLES_DRAW_TRIANGLE_STRIP, ++ COUNTER_GLES_DRAW_TRIANGLE_FAN, ++ COUNTER_GLES_NON_VBO_DATA_COPY_TIME, ++ COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI, ++ COUNTER_GLES_UPLOAD_TEXTURE_TIME, ++ COUNTER_GLES_UPLOAD_VBO_TIME, ++ COUNTER_GLES_NUM_FLUSHES, ++ COUNTER_GLES_NUM_VSHADERS_GENERATED, ++ COUNTER_GLES_NUM_FSHADERS_GENERATED, ++ COUNTER_GLES_VSHADER_GEN_TIME, ++ COUNTER_GLES_FSHADER_GEN_TIME, ++ COUNTER_GLES_INPUT_TRIANGLES, ++ COUNTER_GLES_VXCACHE_HIT, ++ COUNTER_GLES_VXCACHE_MISS, ++ COUNTER_GLES_VXCACHE_COLLISION, ++ COUNTER_GLES_CULLED_TRIANGLES, ++ COUNTER_GLES_CULLED_LINES, ++ COUNTER_GLES_BACKFACE_TRIANGLES, ++ COUNTER_GLES_GBCLIP_TRIANGLES, ++ COUNTER_GLES_GBCLIP_LINES, ++ COUNTER_GLES_TRIANGLES_DRAWN, ++ COUNTER_GLES_DRAWCALL_TIME, ++ COUNTER_GLES_TRIANGLES_COUNT, ++ COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT, ++ COUNTER_GLES_STRIP_TRIANGLES_COUNT, ++ COUNTER_GLES_FAN_TRIANGLES_COUNT, ++ COUNTER_GLES_LINES_COUNT, ++ COUNTER_GLES_INDEPENDENT_LINES_COUNT, ++ COUNTER_GLES_STRIP_LINES_COUNT, ++ COUNTER_GLES_LOOP_LINES_COUNT, ++ ++ COUNTER_FILMSTRIP, ++ COUNTER_FREQUENCY, ++ COUNTER_VOLTAGE, ++ ++ NUMBER_OF_EVENTS ++}; ++ ++#define FIRST_ACTIVITY_EVENT ACTIVITY_VP_0 ++#define LAST_ACTIVITY_EVENT ACTIVITY_FP_3 ++ ++#define FIRST_HW_COUNTER COUNTER_L2_0_C0 ++#define LAST_HW_COUNTER COUNTER_FP_3_C1 ++ ++#define FIRST_SW_COUNTER COUNTER_EGL_BLIT_TIME ++#define LAST_SW_COUNTER COUNTER_GLES_LOOP_LINES_COUNT ++ ++/* Signifies that the system is able to report voltage and frequency numbers. */ ++#define DVFS_REPORTED_BY_DDK 1 ++ ++/** ++ * Structure to pass performance counter data of a Mali core ++ */ ++typedef struct _mali_profiling_core_counters ++{ ++ u32 source0; ++ u32 value0; ++ u32 source1; ++ u32 value1; ++} _mali_profiling_core_counters; ++ ++/* ++ * For compatibility with utgard. ++ */ ++typedef struct _mali_profiling_l2_counter_values ++{ ++ struct _mali_profiling_core_counters cores[MAX_NUM_L2_CACHE_CORES]; ++} _mali_profiling_l2_counter_values; ++ ++typedef struct _mali_profiling_mali_version ++{ ++ u32 mali_product_id; ++ u32 mali_version_major; ++ u32 mali_version_minor; ++ u32 num_of_l2_cores; ++ u32 num_of_fp_cores; ++ u32 num_of_vp_cores; ++} _mali_profiling_mali_version; ++ ++extern void _mali_profiling_get_mali_version(struct _mali_profiling_mali_version *values); ++extern u32 _mali_profiling_get_l2_counters(_mali_profiling_l2_counter_values *values); ++ ++/* ++ * List of possible actions allowing DDK to be controlled by Streamline. ++ * The following numbers are used by DDK to control the frame buffer dumping. ++ */ ++#define FBDUMP_CONTROL_ENABLE (1) ++#define FBDUMP_CONTROL_RATE (2) ++#define SW_COUNTER_ENABLE (3) ++#define FBDUMP_CONTROL_RESIZE_FACTOR (4) ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_MJOLLNIR_PROFILING_GATOR_API_H__ */ +diff -Nur linux-3.10.30/drivers/gator/mali/mali_utgard_profiling_gator_api.h linux-3.10.30-cubox-i/drivers/gator/mali/mali_utgard_profiling_gator_api.h +--- linux-3.10.30/drivers/gator/mali/mali_utgard_profiling_gator_api.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/mali/mali_utgard_profiling_gator_api.h 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,201 @@ ++/** ++ * Copyright (C) ARM Limited 2013. All rights reserved. ++ * ++ * This program 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 __MALI_UTGARD_PROFILING_GATOR_API_H__ ++#define __MALI_UTGARD_PROFILING_GATOR_API_H__ ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++#define MALI_PROFILING_API_VERSION 4 ++ ++#define MAX_NUM_L2_CACHE_CORES 3 ++#define MAX_NUM_FP_CORES 8 ++#define MAX_NUM_VP_CORES 1 ++ ++/** The list of events supported by the Mali DDK. */ ++typedef enum ++{ ++ /* Vertex processor activity */ ++ ACTIVITY_VP_0 = 0, ++ ++ /* Fragment processor activity */ ++ ACTIVITY_FP_0, /* 1 */ ++ ACTIVITY_FP_1, ++ ACTIVITY_FP_2, ++ ACTIVITY_FP_3, ++ ACTIVITY_FP_4, ++ ACTIVITY_FP_5, ++ ACTIVITY_FP_6, ++ ACTIVITY_FP_7, ++ ++ /* L2 cache counters */ ++ COUNTER_L2_0_C0, ++ COUNTER_L2_0_C1, ++ COUNTER_L2_1_C0, ++ COUNTER_L2_1_C1, ++ COUNTER_L2_2_C0, ++ COUNTER_L2_2_C1, ++ ++ /* Vertex processor counters */ ++ COUNTER_VP_0_C0, /*15*/ ++ COUNTER_VP_0_C1, ++ ++ /* Fragment processor counters */ ++ COUNTER_FP_0_C0, ++ COUNTER_FP_0_C1, ++ COUNTER_FP_1_C0, ++ COUNTER_FP_1_C1, ++ COUNTER_FP_2_C0, ++ COUNTER_FP_2_C1, ++ COUNTER_FP_3_C0, ++ COUNTER_FP_3_C1, ++ COUNTER_FP_4_C0, ++ COUNTER_FP_4_C1, ++ COUNTER_FP_5_C0, ++ COUNTER_FP_5_C1, ++ COUNTER_FP_6_C0, ++ COUNTER_FP_6_C1, ++ COUNTER_FP_7_C0, ++ COUNTER_FP_7_C1, /* 32 */ ++ ++ /* ++ * If more hardware counters are added, the _mali_osk_hw_counter_table ++ * below should also be updated. ++ */ ++ ++ /* EGL software counters */ ++ COUNTER_EGL_BLIT_TIME, ++ ++ /* GLES software counters */ ++ COUNTER_GLES_DRAW_ELEMENTS_CALLS, ++ COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES, ++ COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED, ++ COUNTER_GLES_DRAW_ARRAYS_CALLS, ++ COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED, ++ COUNTER_GLES_DRAW_POINTS, ++ COUNTER_GLES_DRAW_LINES, ++ COUNTER_GLES_DRAW_LINE_LOOP, ++ COUNTER_GLES_DRAW_LINE_STRIP, ++ COUNTER_GLES_DRAW_TRIANGLES, ++ COUNTER_GLES_DRAW_TRIANGLE_STRIP, ++ COUNTER_GLES_DRAW_TRIANGLE_FAN, ++ COUNTER_GLES_NON_VBO_DATA_COPY_TIME, ++ COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI, ++ COUNTER_GLES_UPLOAD_TEXTURE_TIME, ++ COUNTER_GLES_UPLOAD_VBO_TIME, ++ COUNTER_GLES_NUM_FLUSHES, ++ COUNTER_GLES_NUM_VSHADERS_GENERATED, ++ COUNTER_GLES_NUM_FSHADERS_GENERATED, ++ COUNTER_GLES_VSHADER_GEN_TIME, ++ COUNTER_GLES_FSHADER_GEN_TIME, ++ COUNTER_GLES_INPUT_TRIANGLES, ++ COUNTER_GLES_VXCACHE_HIT, ++ COUNTER_GLES_VXCACHE_MISS, ++ COUNTER_GLES_VXCACHE_COLLISION, ++ COUNTER_GLES_CULLED_TRIANGLES, ++ COUNTER_GLES_CULLED_LINES, ++ COUNTER_GLES_BACKFACE_TRIANGLES, ++ COUNTER_GLES_GBCLIP_TRIANGLES, ++ COUNTER_GLES_GBCLIP_LINES, ++ COUNTER_GLES_TRIANGLES_DRAWN, ++ COUNTER_GLES_DRAWCALL_TIME, ++ COUNTER_GLES_TRIANGLES_COUNT, ++ COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT, ++ COUNTER_GLES_STRIP_TRIANGLES_COUNT, ++ COUNTER_GLES_FAN_TRIANGLES_COUNT, ++ COUNTER_GLES_LINES_COUNT, ++ COUNTER_GLES_INDEPENDENT_LINES_COUNT, ++ COUNTER_GLES_STRIP_LINES_COUNT, ++ COUNTER_GLES_LOOP_LINES_COUNT, ++ ++ /* Framebuffer capture pseudo-counter */ ++ COUNTER_FILMSTRIP, ++ ++ NUMBER_OF_EVENTS ++} _mali_osk_counter_id; ++ ++#define FIRST_ACTIVITY_EVENT ACTIVITY_VP_0 ++#define LAST_ACTIVITY_EVENT ACTIVITY_FP_7 ++ ++#define FIRST_HW_COUNTER COUNTER_L2_0_C0 ++#define LAST_HW_COUNTER COUNTER_FP_7_C1 ++ ++#define FIRST_SW_COUNTER COUNTER_EGL_BLIT_TIME ++#define LAST_SW_COUNTER COUNTER_GLES_LOOP_LINES_COUNT ++ ++#define FIRST_SPECIAL_COUNTER COUNTER_FILMSTRIP ++#define LAST_SPECIAL_COUNTER COUNTER_FILMSTRIP ++ ++/** ++ * Structure to pass performance counter data of a Mali core ++ */ ++typedef struct _mali_profiling_core_counters ++{ ++ u32 source0; ++ u32 value0; ++ u32 source1; ++ u32 value1; ++} _mali_profiling_core_counters; ++ ++/** ++ * Structure to pass performance counter data of Mali L2 cache cores ++ */ ++typedef struct _mali_profiling_l2_counter_values ++{ ++ struct _mali_profiling_core_counters cores[MAX_NUM_L2_CACHE_CORES]; ++} _mali_profiling_l2_counter_values; ++ ++/** ++ * Structure to pass data defining Mali instance in use: ++ * ++ * mali_product_id - Mali product id ++ * mali_version_major - Mali version major number ++ * mali_version_minor - Mali version minor number ++ * num_of_l2_cores - number of L2 cache cores ++ * num_of_fp_cores - number of fragment processor cores ++ * num_of_vp_cores - number of vertex processor cores ++ */ ++typedef struct _mali_profiling_mali_version ++{ ++ u32 mali_product_id; ++ u32 mali_version_major; ++ u32 mali_version_minor; ++ u32 num_of_l2_cores; ++ u32 num_of_fp_cores; ++ u32 num_of_vp_cores; ++} _mali_profiling_mali_version; ++ ++/* ++ * List of possible actions to be controlled by Streamline. ++ * The following numbers are used by gator to control the frame buffer dumping and s/w counter reporting. ++ * We cannot use the enums in mali_uk_types.h because they are unknown inside gator. ++ */ ++#define FBDUMP_CONTROL_ENABLE (1) ++#define FBDUMP_CONTROL_RATE (2) ++#define SW_COUNTER_ENABLE (3) ++#define FBDUMP_CONTROL_RESIZE_FACTOR (4) ++ ++void _mali_profiling_control(u32 action, u32 value); ++ ++u32 _mali_profiling_get_l2_counters(_mali_profiling_l2_counter_values *values); ++ ++int _mali_profiling_set_event(u32 counter_id, s32 event_id); ++ ++u32 _mali_profiling_get_api_version(void); ++ ++void _mali_profiling_get_mali_version(struct _mali_profiling_mali_version *values); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_UTGARD_PROFILING_GATOR_API_H__ */ +diff -Nur linux-3.10.30/drivers/gator/mali_t6xx.mk linux-3.10.30-cubox-i/drivers/gator/mali_t6xx.mk +--- linux-3.10.30/drivers/gator/mali_t6xx.mk 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gator/mali_t6xx.mk 2014-03-08 20:33:31.000000000 +0100 +@@ -0,0 +1,26 @@ ++# Defines for Mali-T6xx driver ++EXTRA_CFLAGS += -DMALI_USE_UMP=1 \ ++ -DMALI_LICENSE_IS_GPL=1 \ ++ -DMALI_BASE_TRACK_MEMLEAK=0 \ ++ -DMALI_DEBUG=0 \ ++ -DMALI_ERROR_INJECT_ON=0 \ ++ -DMALI_CUSTOMER_RELEASE=1 \ ++ -DMALI_UNIT_TEST=0 \ ++ -DMALI_BACKEND_KERNEL=1 \ ++ -DMALI_NO_MALI=0 ++ ++DDK_DIR ?= . ++KBASE_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase ++OSK_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase/osk ++UMP_DIR = $(DDK_DIR)/include/linux ++ ++# Include directories in the DDK ++EXTRA_CFLAGS += -I$(KBASE_DIR)/ \ ++ -I$(KBASE_DIR)/.. \ ++ -I$(OSK_DIR)/.. \ ++ -I$(UMP_DIR)/.. \ ++ -I$(DDK_DIR)/include \ ++ -I$(KBASE_DIR)/osk/src/linux/include \ ++ -I$(KBASE_DIR)/platform_dummy \ ++ -I$(KBASE_DIR)/src ++ +diff -Nur linux-3.10.30/drivers/gpio/devres.c linux-3.10.30-cubox-i/drivers/gpio/devres.c +--- linux-3.10.30/drivers/gpio/devres.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gpio/devres.c 2014-03-08 20:33:31.000000000 +0100 +@@ -19,6 +19,89 @@ + #include + #include + ++static void devm_gpiod_release(struct device *dev, void *res) ++{ ++ struct gpio_desc **desc = res; ++ ++ gpiod_put(*desc); ++} ++ ++static int devm_gpiod_match(struct device *dev, void *res, void *data) ++{ ++ struct gpio_desc **this = res, **gpio = data; ++ ++ return *this == *gpio; ++} ++ ++/** ++ * devm_gpiod_get - Resource-managed gpiod_get() ++ * @dev: GPIO consumer ++ * @con_id: function within the GPIO consumer ++ * ++ * Managed gpiod_get(). GPIO descriptors returned from this function are ++ * automatically disposed on driver detach. See gpiod_get() for detailed ++ * information about behavior and return values. ++ */ ++struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, ++ const char *con_id) ++{ ++ return devm_gpiod_get_index(dev, con_id, 0); ++} ++EXPORT_SYMBOL(devm_gpiod_get); ++ ++/** ++ * devm_gpiod_get_index - Resource-managed gpiod_get_index() ++ * @dev: GPIO consumer ++ * @con_id: function within the GPIO consumer ++ * @idx: index of the GPIO to obtain in the consumer ++ * ++ * Managed gpiod_get_index(). GPIO descriptors returned from this function are ++ * automatically disposed on driver detach. See gpiod_get_index() for detailed ++ * information about behavior and return values. ++ */ ++struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, ++ const char *con_id, ++ unsigned int idx) ++{ ++ struct gpio_desc **dr; ++ struct gpio_desc *desc; ++ ++ dr = devres_alloc(devm_gpiod_release, sizeof(struct gpiod_desc *), ++ GFP_KERNEL); ++ if (!dr) ++ return ERR_PTR(-ENOMEM); ++ ++ desc = gpiod_get_index(dev, con_id, idx); ++ if (IS_ERR(desc)) { ++ devres_free(dr); ++ return desc; ++ } ++ ++ *dr = desc; ++ devres_add(dev, dr); ++ ++ return desc; ++} ++EXPORT_SYMBOL(devm_gpiod_get_index); ++ ++/** ++ * devm_gpiod_put - Resource-managed gpiod_put() ++ * @desc: GPIO descriptor to dispose of ++ * ++ * Dispose of a GPIO descriptor obtained with devm_gpiod_get() or ++ * devm_gpiod_get_index(). Normally this function will not be called as the GPIO ++ * will be disposed of by the resource management code. ++ */ ++void devm_gpiod_put(struct device *dev, struct gpio_desc *desc) ++{ ++ WARN_ON(devres_release(dev, devm_gpiod_release, devm_gpiod_match, ++ &desc)); ++} ++EXPORT_SYMBOL(devm_gpiod_put); ++ ++ ++ ++ + static void devm_gpio_release(struct device *dev, void *res) + { + unsigned *gpio = res; +diff -Nur linux-3.10.30/drivers/gpio/gpio-mxc.c linux-3.10.30-cubox-i/drivers/gpio/gpio-mxc.c +--- linux-3.10.30/drivers/gpio/gpio-mxc.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gpio/gpio-mxc.c 2014-03-08 20:33:31.000000000 +0100 +@@ -405,34 +405,19 @@ + + mxc_gpio_get_hw(pdev); + +- port = kzalloc(sizeof(struct mxc_gpio_port), GFP_KERNEL); ++ port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!iores) { +- err = -ENODEV; +- goto out_kfree; +- } +- +- if (!request_mem_region(iores->start, resource_size(iores), +- pdev->name)) { +- err = -EBUSY; +- goto out_kfree; +- } +- +- port->base = ioremap(iores->start, resource_size(iores)); +- if (!port->base) { +- err = -ENOMEM; +- goto out_release_mem; +- } ++ port->base = devm_ioremap_resource(&pdev->dev, iores); ++ if (IS_ERR(port->base)) ++ return PTR_ERR(port->base); + + port->irq_high = platform_get_irq(pdev, 1); + port->irq = platform_get_irq(pdev, 0); +- if (port->irq < 0) { +- err = -EINVAL; +- goto out_iounmap; +- } ++ if (port->irq < 0) ++ return -EINVAL; + + /* disable the interrupt and clear the status */ + writel(0, port->base + GPIO_IMR); +@@ -462,7 +447,7 @@ + port->base + GPIO_DR, NULL, + port->base + GPIO_GDIR, NULL, 0); + if (err) +- goto out_iounmap; ++ goto out_bgio; + + port->bgc.gc.to_irq = mxc_gpio_to_irq; + port->bgc.gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 : +@@ -498,12 +483,7 @@ + WARN_ON(gpiochip_remove(&port->bgc.gc) < 0); + out_bgpio_remove: + bgpio_remove(&port->bgc); +-out_iounmap: +- iounmap(port->base); +-out_release_mem: +- release_mem_region(iores->start, resource_size(iores)); +-out_kfree: +- kfree(port); ++out_bgio: + dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err); + return err; + } +diff -Nur linux-3.10.30/drivers/gpio/gpio-pca953x.c linux-3.10.30-cubox-i/drivers/gpio/gpio-pca953x.c +--- linux-3.10.30/drivers/gpio/gpio-pca953x.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gpio/gpio-pca953x.c 2014-03-08 20:33:31.000000000 +0100 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #ifdef CONFIG_OF_GPIO + #include +@@ -752,6 +753,10 @@ + + mutex_init(&chip->i2c_lock); + ++ ret = device_reset(&client->dev); ++ if (ret == -ENODEV) ++ return -EPROBE_DEFER; ++ + /* initialize cached registers from their original values. + * we can't share this chip with another i2c master. + */ +diff -Nur linux-3.10.30/drivers/gpio/gpiolib-of.c linux-3.10.30-cubox-i/drivers/gpio/gpiolib-of.c +--- linux-3.10.30/drivers/gpio/gpiolib-of.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gpio/gpiolib-of.c 2014-03-08 20:33:32.000000000 +0100 +@@ -15,19 +15,21 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include + #include + #include + ++struct gpio_desc; ++ + /* Private data structure for of_gpiochip_find_and_xlate */ + struct gg_data { + enum of_gpio_flags *flags; + struct of_phandle_args gpiospec; + +- int out_gpio; ++ struct gpio_desc *out_gpio; + }; + + /* Private function for resolving node pointer to gpio_chip */ +@@ -45,28 +47,31 @@ + if (ret < 0) + return false; + +- gg_data->out_gpio = ret + gc->base; ++ gg_data->out_gpio = gpio_to_desc(ret + gc->base); + return true; + } + + /** +- * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API ++ * of_get_named_gpiod_flags() - Get a GPIO descriptor and flags for GPIO API + * @np: device node to get GPIO from + * @propname: property name containing gpio specifier(s) + * @index: index of the GPIO + * @flags: a flags pointer to fill in + * +- * Returns GPIO number to use with Linux generic GPIO API, or one of the errno ++ * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno + * value on the error condition. If @flags is not NULL the function also fills + * in flags for the GPIO. + */ +-int of_get_named_gpio_flags(struct device_node *np, const char *propname, +- int index, enum of_gpio_flags *flags) ++struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np, ++ const char *propname, int index, enum of_gpio_flags *flags) + { + /* Return -EPROBE_DEFER to support probe() functions to be called + * later when the GPIO actually becomes available + */ +- struct gg_data gg_data = { .flags = flags, .out_gpio = -EPROBE_DEFER }; ++ struct gg_data gg_data = { ++ .flags = flags, ++ .out_gpio = ERR_PTR(-EPROBE_DEFER) ++ }; + int ret; + + /* .of_xlate might decide to not fill in the flags, so clear it. */ +@@ -76,17 +81,19 @@ + ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index, + &gg_data.gpiospec); + if (ret) { +- pr_debug("%s: can't parse gpios property\n", __func__); +- return ret; ++ pr_debug("%s: can't parse gpios property of node '%s[%d]'\n", ++ __func__, np->full_name, index); ++ return ERR_PTR(ret); + } + + gpiochip_find(&gg_data, of_gpiochip_find_and_xlate); + + of_node_put(gg_data.gpiospec.np); +- pr_debug("%s exited with status %d\n", __func__, gg_data.out_gpio); ++ pr_debug("%s exited with status %d\n", __func__, ++ PTR_RET(gg_data.out_gpio)); + return gg_data.out_gpio; + } +-EXPORT_SYMBOL(of_get_named_gpio_flags); ++EXPORT_SYMBOL(of_get_named_gpiod_flags); + + /** + * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags +@@ -194,8 +201,8 @@ + return; + + for (;; index++) { +- ret = of_parse_phandle_with_args(np, "gpio-ranges", +- "#gpio-range-cells", index, &pinspec); ++ ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, ++ index, &pinspec); + if (ret) + break; + +diff -Nur linux-3.10.30/drivers/gpio/gpiolib.c linux-3.10.30-cubox-i/drivers/gpio/gpiolib.c +--- linux-3.10.30/drivers/gpio/gpiolib.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gpio/gpiolib.c 2014-03-08 20:33:32.000000000 +0100 +@@ -12,20 +12,16 @@ + #include + #include + #include ++#include + + #define CREATE_TRACE_POINTS + #include + +-/* Optional implementation infrastructure for GPIO interfaces. ++/* Implementation infrastructure for GPIO interfaces. + * +- * Platforms may want to use this if they tend to use very many GPIOs +- * that aren't part of a System-On-Chip core; or across I2C/SPI/etc. +- * +- * When kernel footprint or instruction count is an issue, simpler +- * implementations may be preferred. The GPIO programming interface +- * allows for inlining speed-critical get/set operations for common +- * cases, so that access to SOC-integrated GPIOs can sometimes cost +- * only an instruction or two per bit. ++ * The GPIO programming interface allows for inlining speed-critical ++ * get/set operations for common cases, so that access to SOC-integrated ++ * GPIOs can sometimes cost only an instruction or two per bit. + */ + + +@@ -57,9 +53,10 @@ + #define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */ + #define FLAG_TRIG_FALL 4 /* trigger on falling edge */ + #define FLAG_TRIG_RISE 5 /* trigger on rising edge */ +-#define FLAG_ACTIVE_LOW 6 /* sysfs value has active low */ ++#define FLAG_ACTIVE_LOW 6 /* value has active low */ + #define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */ + #define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */ ++#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */ + + #define ID_SHIFT 16 /* add new flags before this one */ + +@@ -74,34 +71,50 @@ + + #define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio) + ++static DEFINE_MUTEX(gpio_lookup_lock); ++static LIST_HEAD(gpio_lookup_list); + static LIST_HEAD(gpio_chips); + + #ifdef CONFIG_GPIO_SYSFS + static DEFINE_IDR(dirent_idr); + #endif + +-/* +- * Internal gpiod_* API using descriptors instead of the integer namespace. +- * Most of this should eventually go public. +- */ + static int gpiod_request(struct gpio_desc *desc, const char *label); + static void gpiod_free(struct gpio_desc *desc); +-static int gpiod_direction_input(struct gpio_desc *desc); +-static int gpiod_direction_output(struct gpio_desc *desc, int value); +-static int gpiod_get_direction(const struct gpio_desc *desc); +-static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); +-static int gpiod_get_value_cansleep(const struct gpio_desc *desc); +-static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); +-static int gpiod_get_value(const struct gpio_desc *desc); +-static void gpiod_set_value(struct gpio_desc *desc, int value); +-static int gpiod_cansleep(const struct gpio_desc *desc); +-static int gpiod_to_irq(const struct gpio_desc *desc); +-static int gpiod_export(struct gpio_desc *desc, bool direction_may_change); +-static int gpiod_export_link(struct device *dev, const char *name, +- struct gpio_desc *desc); +-static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value); +-static void gpiod_unexport(struct gpio_desc *desc); + ++#ifdef CONFIG_DEBUG_FS ++#define gpiod_emerg(desc, fmt, ...) \ ++ pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ ++ ##__VA_ARGS__) ++#define gpiod_crit(desc, fmt, ...) \ ++ pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ ++ ##__VA_ARGS__) ++#define gpiod_err(desc, fmt, ...) \ ++ pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ ++ ##__VA_ARGS__) ++#define gpiod_warn(desc, fmt, ...) \ ++ pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ ++ ##__VA_ARGS__) ++#define gpiod_info(desc, fmt, ...) \ ++ pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ ++ ##__VA_ARGS__) ++#define gpiod_dbg(desc, fmt, ...) \ ++ pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label, \ ++ ##__VA_ARGS__) ++#else ++#define gpiod_emerg(desc, fmt, ...) \ ++ pr_emerg("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) ++#define gpiod_crit(desc, fmt, ...) \ ++ pr_crit("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) ++#define gpiod_err(desc, fmt, ...) \ ++ pr_err("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) ++#define gpiod_warn(desc, fmt, ...) \ ++ pr_warn("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) ++#define gpiod_info(desc, fmt, ...) \ ++ pr_info("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) ++#define gpiod_dbg(desc, fmt, ...) \ ++ pr_debug("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__) ++#endif + + static inline void desc_set_label(struct gpio_desc *d, const char *label) + { +@@ -121,23 +134,36 @@ + /** + * Convert a GPIO number to its descriptor + */ +-static struct gpio_desc *gpio_to_desc(unsigned gpio) ++struct gpio_desc *gpio_to_desc(unsigned gpio) + { + if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio)) + return NULL; + else + return &gpio_desc[gpio]; + } ++EXPORT_SYMBOL_GPL(gpio_to_desc); ++ ++/** ++ * Convert an offset on a certain chip to a corresponding descriptor ++ */ ++static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip, ++ unsigned int offset) ++{ ++ unsigned int gpio = chip->base + offset; ++ ++ return gpio_to_desc(gpio); ++} + + /** + * Convert a GPIO descriptor to the integer namespace. + * This should disappear in the future but is needed since we still + * use GPIO numbers for error messages and sysfs nodes + */ +-static int desc_to_gpio(const struct gpio_desc *desc) ++int desc_to_gpio(const struct gpio_desc *desc) + { +- return desc->chip->base + gpio_chip_hwgpio(desc); ++ return desc - &gpio_desc[0]; + } ++EXPORT_SYMBOL_GPL(desc_to_gpio); + + + /* Warn when drivers omit gpio_request() calls -- legal but ill-advised +@@ -172,16 +198,15 @@ + return 0; + } + +-static struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) ++/** ++ * gpiod_to_chip - Return the GPIO chip to which a GPIO descriptor belongs ++ * @desc: descriptor to return the chip of ++ */ ++struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) + { + return desc ? desc->chip : NULL; + } +- +-/* caller holds gpio_lock *OR* gpio is marked as requested */ +-struct gpio_chip *gpio_to_chip(unsigned gpio) +-{ +- return gpiod_to_chip(gpio_to_desc(gpio)); +-} ++EXPORT_SYMBOL_GPL(gpiod_to_chip); + + /* dynamic allocation of GPIOs, e.g. on a hotplugged device */ + static int gpiochip_find_base(int ngpio) +@@ -207,8 +232,15 @@ + } + } + +-/* caller ensures gpio is valid and requested, chip->get_direction may sleep */ +-static int gpiod_get_direction(const struct gpio_desc *desc) ++/** ++ * gpiod_get_direction - return the current direction of a GPIO ++ * @desc: GPIO to get the direction of ++ * ++ * Return GPIOF_DIR_IN or GPIOF_DIR_OUT, or an error code in case of error. ++ * ++ * This function may sleep if gpiod_cansleep() is true. ++ */ ++int gpiod_get_direction(const struct gpio_desc *desc) + { + struct gpio_chip *chip; + unsigned offset; +@@ -234,6 +266,7 @@ + } + return status; + } ++EXPORT_SYMBOL_GPL(gpiod_get_direction); + + #ifdef CONFIG_GPIO_SYSFS + +@@ -318,17 +351,10 @@ + + mutex_lock(&sysfs_lock); + +- if (!test_bit(FLAG_EXPORT, &desc->flags)) { ++ if (!test_bit(FLAG_EXPORT, &desc->flags)) + status = -EIO; +- } else { +- int value; +- +- value = !!gpiod_get_value_cansleep(desc); +- if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) +- value = !value; +- +- status = sprintf(buf, "%d\n", value); +- } ++ else ++ status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc)); + + mutex_unlock(&sysfs_lock); + return status; +@@ -349,11 +375,9 @@ + else { + long value; + +- status = strict_strtol(buf, 0, &value); ++ status = kstrtol(buf, 0, &value); + if (status == 0) { +- if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) +- value = !value; +- gpiod_set_value_cansleep(desc, value != 0); ++ gpiod_set_value_cansleep(desc, value); + status = size; + } + } +@@ -395,6 +419,7 @@ + desc->flags &= ~GPIO_TRIGGER_MASK; + + if (!gpio_flags) { ++ gpiod_unlock_as_irq(desc); + ret = 0; + goto free_id; + } +@@ -433,6 +458,12 @@ + if (ret < 0) + goto free_id; + ++ ret = gpiod_lock_as_irq(desc); ++ if (ret < 0) { ++ gpiod_warn(desc, "failed to flag the GPIO for IRQ\n"); ++ goto free_id; ++ } ++ + desc->flags |= gpio_flags; + return 0; + +@@ -570,7 +601,7 @@ + } else { + long value; + +- status = strict_strtol(buf, 0, &value); ++ status = kstrtol(buf, 0, &value); + if (status == 0) + status = sysfs_set_active_low(desc, dev, value != 0); + } +@@ -652,7 +683,7 @@ + struct gpio_desc *desc; + int status; + +- status = strict_strtol(buf, 0, &gpio); ++ status = kstrtol(buf, 0, &gpio); + if (status < 0) + goto done; + +@@ -694,7 +725,7 @@ + struct gpio_desc *desc; + int status; + +- status = strict_strtol(buf, 0, &gpio); ++ status = kstrtol(buf, 0, &gpio); + if (status < 0) + goto done; + +@@ -736,7 +767,7 @@ + + + /** +- * gpio_export - export a GPIO through sysfs ++ * gpiod_export - export a GPIO through sysfs + * @gpio: gpio to make available, already requested + * @direction_may_change: true if userspace may change gpio direction + * Context: arch_initcall or later +@@ -750,7 +781,7 @@ + * + * Returns zero on success, else an error. + */ +-static int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ++int gpiod_export(struct gpio_desc *desc, bool direction_may_change) + { + unsigned long flags; + int status; +@@ -828,12 +859,7 @@ + status); + return status; + } +- +-int gpio_export(unsigned gpio, bool direction_may_change) +-{ +- return gpiod_export(gpio_to_desc(gpio), direction_may_change); +-} +-EXPORT_SYMBOL_GPL(gpio_export); ++EXPORT_SYMBOL_GPL(gpiod_export); + + static int match_export(struct device *dev, const void *data) + { +@@ -841,7 +867,7 @@ + } + + /** +- * gpio_export_link - create a sysfs link to an exported GPIO node ++ * gpiod_export_link - create a sysfs link to an exported GPIO node + * @dev: device under which to create symlink + * @name: name of the symlink + * @gpio: gpio to create symlink to, already exported +@@ -851,8 +877,8 @@ + * + * Returns zero on success, else an error. + */ +-static int gpiod_export_link(struct device *dev, const char *name, +- struct gpio_desc *desc) ++int gpiod_export_link(struct device *dev, const char *name, ++ struct gpio_desc *desc) + { + int status = -EINVAL; + +@@ -883,15 +909,10 @@ + + return status; + } +- +-int gpio_export_link(struct device *dev, const char *name, unsigned gpio) +-{ +- return gpiod_export_link(dev, name, gpio_to_desc(gpio)); +-} +-EXPORT_SYMBOL_GPL(gpio_export_link); ++EXPORT_SYMBOL_GPL(gpiod_export_link); + + /** +- * gpio_sysfs_set_active_low - set the polarity of gpio sysfs value ++ * gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value + * @gpio: gpio to change + * @value: non-zero to use active low, i.e. inverted values + * +@@ -902,7 +923,7 @@ + * + * Returns zero on success, else an error. + */ +-static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) ++int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) + { + struct device *dev = NULL; + int status = -EINVAL; +@@ -933,20 +954,15 @@ + + return status; + } +- +-int gpio_sysfs_set_active_low(unsigned gpio, int value) +-{ +- return gpiod_sysfs_set_active_low(gpio_to_desc(gpio), value); +-} +-EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); ++EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low); + + /** +- * gpio_unexport - reverse effect of gpio_export() ++ * gpiod_unexport - reverse effect of gpio_export() + * @gpio: gpio to make unavailable + * + * This is implicit on gpio_free(). + */ +-static void gpiod_unexport(struct gpio_desc *desc) ++void gpiod_unexport(struct gpio_desc *desc) + { + int status = 0; + struct device *dev = NULL; +@@ -979,12 +995,7 @@ + pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc), + status); + } +- +-void gpio_unexport(unsigned gpio) +-{ +- gpiod_unexport(gpio_to_desc(gpio)); +-} +-EXPORT_SYMBOL_GPL(gpio_unexport); ++EXPORT_SYMBOL_GPL(gpiod_unexport); + + static int gpiochip_export(struct gpio_chip *chip) + { +@@ -1091,27 +1102,6 @@ + { + } + +-static inline int gpiod_export(struct gpio_desc *desc, +- bool direction_may_change) +-{ +- return -ENOSYS; +-} +- +-static inline int gpiod_export_link(struct device *dev, const char *name, +- struct gpio_desc *desc) +-{ +- return -ENOSYS; +-} +- +-static inline int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value) +-{ +- return -ENOSYS; +-} +- +-static inline void gpiod_unexport(struct gpio_desc *desc) +-{ +-} +- + #endif /* CONFIG_GPIO_SYSFS */ + + /* +@@ -1214,15 +1204,14 @@ + } + } + ++ spin_unlock_irqrestore(&gpio_lock, flags); ++ + #ifdef CONFIG_PINCTRL + INIT_LIST_HEAD(&chip->pin_ranges); + #endif + + of_gpiochip_add(chip); + +-unlock: +- spin_unlock_irqrestore(&gpio_lock, flags); +- + if (status) + goto fail; + +@@ -1235,6 +1224,9 @@ + chip->label ? : "generic"); + + return 0; ++ ++unlock: ++ spin_unlock_irqrestore(&gpio_lock, flags); + fail: + /* failures here can mean systems won't boot... */ + pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", +@@ -1315,6 +1307,18 @@ + } + EXPORT_SYMBOL_GPL(gpiochip_find); + ++static int gpiochip_match_name(struct gpio_chip *chip, void *data) ++{ ++ const char *name = data; ++ ++ return !strcmp(chip->label, name); ++} ++ ++static struct gpio_chip *find_chip_by_name(const char *name) ++{ ++ return gpiochip_find((void *)name, gpiochip_match_name); ++} ++ + #ifdef CONFIG_PINCTRL + + /** +@@ -1621,23 +1625,37 @@ + * rely on gpio_request() having been called beforehand. + */ + +-static int gpiod_direction_input(struct gpio_desc *desc) ++/** ++ * gpiod_direction_input - set the GPIO direction to input ++ * @desc: GPIO to set to input ++ * ++ * Set the direction of the passed GPIO to input, such as gpiod_get_value() can ++ * be called safely on it. ++ * ++ * Return 0 in case of success, else an error code. ++ */ ++int gpiod_direction_input(struct gpio_desc *desc) + { + unsigned long flags; + struct gpio_chip *chip; + int status = -EINVAL; + int offset; + +- if (!desc) { ++ if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + ++ chip = desc->chip; ++ if (!chip->get || !chip->direction_input) { ++ gpiod_warn(desc, ++ "%s: missing get() or direction_input() operations\n", ++ __func__); ++ return -EIO; ++ } ++ + spin_lock_irqsave(&gpio_lock, flags); + +- chip = desc->chip; +- if (!chip || !chip->get || !chip->direction_input) +- goto fail; + status = gpio_ensure_requested(desc); + if (status < 0) + goto fail; +@@ -1652,8 +1670,7 @@ + if (status) { + status = chip->request(chip, offset); + if (status < 0) { +- pr_debug("GPIO-%d: chip request fail, %d\n", +- desc_to_gpio(desc), status); ++ gpiod_dbg(desc, "chip request fail, %d\n", status); + /* and it's not available to anyone else ... + * gpio_request() is the fully clean solution. + */ +@@ -1671,29 +1688,41 @@ + fail: + spin_unlock_irqrestore(&gpio_lock, flags); + if (status) +- pr_debug("%s: gpio-%d status %d\n", __func__, +- desc_to_gpio(desc), status); ++ gpiod_dbg(desc, "%s status %d\n", __func__, status); + return status; + } ++EXPORT_SYMBOL_GPL(gpiod_direction_input); + +-int gpio_direction_input(unsigned gpio) +-{ +- return gpiod_direction_input(gpio_to_desc(gpio)); +-} +-EXPORT_SYMBOL_GPL(gpio_direction_input); +- +-static int gpiod_direction_output(struct gpio_desc *desc, int value) ++/** ++ * gpiod_direction_output - set the GPIO direction to input ++ * @desc: GPIO to set to output ++ * @value: initial output value of the GPIO ++ * ++ * Set the direction of the passed GPIO to output, such as gpiod_set_value() can ++ * be called safely on it. The initial value of the output must be specified. ++ * ++ * Return 0 in case of success, else an error code. ++ */ ++int gpiod_direction_output(struct gpio_desc *desc, int value) + { + unsigned long flags; + struct gpio_chip *chip; + int status = -EINVAL; + int offset; + +- if (!desc) { ++ if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + ++ /* GPIOs used for IRQs shall not be set as output */ ++ if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) { ++ gpiod_err(desc, ++ "%s: tried to set a GPIO tied to an IRQ as output\n", ++ __func__); ++ return -EIO; ++ } ++ + /* Open drain pin should not be driven to 1 */ + if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) + return gpiod_direction_input(desc); +@@ -1702,11 +1731,16 @@ + if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) + return gpiod_direction_input(desc); + ++ chip = desc->chip; ++ if (!chip->set || !chip->direction_output) { ++ gpiod_warn(desc, ++ "%s: missing set() or direction_output() operations\n", ++ __func__); ++ return -EIO; ++ } ++ + spin_lock_irqsave(&gpio_lock, flags); + +- chip = desc->chip; +- if (!chip || !chip->set || !chip->direction_output) +- goto fail; + status = gpio_ensure_requested(desc); + if (status < 0) + goto fail; +@@ -1721,8 +1755,7 @@ + if (status) { + status = chip->request(chip, offset); + if (status < 0) { +- pr_debug("GPIO-%d: chip request fail, %d\n", +- desc_to_gpio(desc), status); ++ gpiod_dbg(desc, "chip request fail, %d\n", status); + /* and it's not available to anyone else ... + * gpio_request() is the fully clean solution. + */ +@@ -1740,39 +1773,40 @@ + fail: + spin_unlock_irqrestore(&gpio_lock, flags); + if (status) +- pr_debug("%s: gpio-%d status %d\n", __func__, +- desc_to_gpio(desc), status); ++ gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status); + return status; + } +- +-int gpio_direction_output(unsigned gpio, int value) +-{ +- return gpiod_direction_output(gpio_to_desc(gpio), value); +-} +-EXPORT_SYMBOL_GPL(gpio_direction_output); ++EXPORT_SYMBOL_GPL(gpiod_direction_output); + + /** +- * gpio_set_debounce - sets @debounce time for a @gpio ++ * gpiod_set_debounce - sets @debounce time for a @gpio + * @gpio: the gpio to set debounce time + * @debounce: debounce time is microseconds ++ * ++ * returns -ENOTSUPP if the controller does not support setting ++ * debounce. + */ +-static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) ++int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) + { + unsigned long flags; + struct gpio_chip *chip; + int status = -EINVAL; + int offset; + +- if (!desc) { ++ if (!desc || !desc->chip) { + pr_warn("%s: invalid GPIO\n", __func__); + return -EINVAL; + } + +- spin_lock_irqsave(&gpio_lock, flags); +- + chip = desc->chip; +- if (!chip || !chip->set || !chip->set_debounce) +- goto fail; ++ if (!chip->set || !chip->set_debounce) { ++ gpiod_dbg(desc, ++ "%s: missing set() or set_debounce() operations\n", ++ __func__); ++ return -ENOTSUPP; ++ } ++ ++ spin_lock_irqsave(&gpio_lock, flags); + + status = gpio_ensure_requested(desc); + if (status < 0) +@@ -1790,17 +1824,23 @@ + fail: + spin_unlock_irqrestore(&gpio_lock, flags); + if (status) +- pr_debug("%s: gpio-%d status %d\n", __func__, +- desc_to_gpio(desc), status); ++ gpiod_dbg(desc, "%s: status %d\n", __func__, status); + + return status; + } ++EXPORT_SYMBOL_GPL(gpiod_set_debounce); + +-int gpio_set_debounce(unsigned gpio, unsigned debounce) ++/** ++ * gpiod_is_active_low - test whether a GPIO is active-low or not ++ * @desc: the gpio descriptor to test ++ * ++ * Returns 1 if the GPIO is active-low, 0 otherwise. ++ */ ++int gpiod_is_active_low(const struct gpio_desc *desc) + { +- return gpiod_set_debounce(gpio_to_desc(gpio), debounce); ++ return test_bit(FLAG_ACTIVE_LOW, &desc->flags); + } +-EXPORT_SYMBOL_GPL(gpio_set_debounce); ++EXPORT_SYMBOL_GPL(gpiod_is_active_low); + + /* I/O calls are only valid after configuration completed; the relevant + * "is this a valid GPIO" error checks should already have been done. +@@ -1824,42 +1864,68 @@ + * that the GPIO was actually requested. + */ + +-/** +- * __gpio_get_value() - return a gpio's value +- * @gpio: gpio whose value will be returned +- * Context: any +- * +- * This is used directly or indirectly to implement gpio_get_value(). +- * It returns the zero or nonzero value provided by the associated +- * gpio_chip.get() method; or zero if no such method is provided. +- */ +-static int gpiod_get_value(const struct gpio_desc *desc) ++static int _gpiod_get_raw_value(const struct gpio_desc *desc) + { + struct gpio_chip *chip; + int value; + int offset; + +- if (!desc) +- return 0; + chip = desc->chip; + offset = gpio_chip_hwgpio(desc); +- /* Should be using gpio_get_value_cansleep() */ +- WARN_ON(chip->can_sleep); + value = chip->get ? chip->get(chip, offset) : 0; + trace_gpio_value(desc_to_gpio(desc), 1, value); + return value; + } + +-int __gpio_get_value(unsigned gpio) ++/** ++ * gpiod_get_raw_value() - return a gpio's raw value ++ * @desc: gpio whose value will be returned ++ * ++ * Return the GPIO's raw value, i.e. the value of the physical line disregarding ++ * its ACTIVE_LOW status. ++ * ++ * This function should be called from contexts where we cannot sleep, and will ++ * complain if the GPIO chip functions potentially sleep. ++ */ ++int gpiod_get_raw_value(const struct gpio_desc *desc) + { +- return gpiod_get_value(gpio_to_desc(gpio)); ++ if (!desc) ++ return 0; ++ /* Should be using gpio_get_value_cansleep() */ ++ WARN_ON(desc->chip->can_sleep); ++ return _gpiod_get_raw_value(desc); ++} ++EXPORT_SYMBOL_GPL(gpiod_get_raw_value); ++ ++/** ++ * gpiod_get_value() - return a gpio's value ++ * @desc: gpio whose value will be returned ++ * ++ * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into ++ * account. ++ * ++ * This function should be called from contexts where we cannot sleep, and will ++ * complain if the GPIO chip functions potentially sleep. ++ */ ++int gpiod_get_value(const struct gpio_desc *desc) ++{ ++ int value; ++ if (!desc) ++ return 0; ++ /* Should be using gpio_get_value_cansleep() */ ++ WARN_ON(desc->chip->can_sleep); ++ ++ value = _gpiod_get_raw_value(desc); ++ if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) ++ value = !value; ++ ++ return value; + } +-EXPORT_SYMBOL_GPL(__gpio_get_value); ++EXPORT_SYMBOL_GPL(gpiod_get_value); + + /* + * _gpio_set_open_drain_value() - Set the open drain gpio's value. +- * @gpio: Gpio whose state need to be set. +- * @chip: Gpio chip. ++ * @desc: gpio descriptor whose state need to be set. + * @value: Non-zero for setting it HIGH otherise it will set to LOW. + */ + static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value) +@@ -1879,14 +1945,14 @@ + } + trace_gpio_direction(desc_to_gpio(desc), value, err); + if (err < 0) +- pr_err("%s: Error in set_value for open drain gpio%d err %d\n", +- __func__, desc_to_gpio(desc), err); ++ gpiod_err(desc, ++ "%s: Error in set_value for open drain err %d\n", ++ __func__, err); + } + + /* +- * _gpio_set_open_source() - Set the open source gpio's value. +- * @gpio: Gpio whose state need to be set. +- * @chip: Gpio chip. ++ * _gpio_set_open_source_value() - Set the open source gpio's value. ++ * @desc: gpio descriptor whose state need to be set. + * @value: Non-zero for setting it HIGH otherise it will set to LOW. + */ + static void _gpio_set_open_source_value(struct gpio_desc *desc, int value) +@@ -1906,28 +1972,16 @@ + } + trace_gpio_direction(desc_to_gpio(desc), !value, err); + if (err < 0) +- pr_err("%s: Error in set_value for open source gpio%d err %d\n", +- __func__, desc_to_gpio(desc), err); ++ gpiod_err(desc, ++ "%s: Error in set_value for open source err %d\n", ++ __func__, err); + } + +-/** +- * __gpio_set_value() - assign a gpio's value +- * @gpio: gpio whose value will be assigned +- * @value: value to assign +- * Context: any +- * +- * This is used directly or indirectly to implement gpio_set_value(). +- * It invokes the associated gpio_chip.set() method. +- */ +-static void gpiod_set_value(struct gpio_desc *desc, int value) ++static void _gpiod_set_raw_value(struct gpio_desc *desc, int value) + { + struct gpio_chip *chip; + +- if (!desc) +- return; + chip = desc->chip; +- /* Should be using gpio_set_value_cansleep() */ +- WARN_ON(chip->can_sleep); + trace_gpio_value(desc_to_gpio(desc), 0, value); + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) + _gpio_set_open_drain_value(desc, value); +@@ -1937,44 +1991,71 @@ + chip->set(chip, gpio_chip_hwgpio(desc), value); + } + +-void __gpio_set_value(unsigned gpio, int value) ++/** ++ * gpiod_set_raw_value() - assign a gpio's raw value ++ * @desc: gpio whose value will be assigned ++ * @value: value to assign ++ * ++ * Set the raw value of the GPIO, i.e. the value of its physical line without ++ * regard for its ACTIVE_LOW status. ++ * ++ * This function should be called from contexts where we cannot sleep, and will ++ * complain if the GPIO chip functions potentially sleep. ++ */ ++void gpiod_set_raw_value(struct gpio_desc *desc, int value) + { +- return gpiod_set_value(gpio_to_desc(gpio), value); ++ if (!desc) ++ return; ++ /* Should be using gpio_set_value_cansleep() */ ++ WARN_ON(desc->chip->can_sleep); ++ _gpiod_set_raw_value(desc, value); + } +-EXPORT_SYMBOL_GPL(__gpio_set_value); ++EXPORT_SYMBOL_GPL(gpiod_set_raw_value); + + /** +- * __gpio_cansleep() - report whether gpio value access will sleep +- * @gpio: gpio in question +- * Context: any ++ * gpiod_set_value() - assign a gpio's value ++ * @desc: gpio whose value will be assigned ++ * @value: value to assign ++ * ++ * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into ++ * account + * +- * This is used directly or indirectly to implement gpio_cansleep(). It +- * returns nonzero if access reading or writing the GPIO value can sleep. ++ * This function should be called from contexts where we cannot sleep, and will ++ * complain if the GPIO chip functions potentially sleep. + */ +-static int gpiod_cansleep(const struct gpio_desc *desc) ++void gpiod_set_value(struct gpio_desc *desc, int value) + { + if (!desc) +- return 0; +- /* only call this on GPIOs that are valid! */ +- return desc->chip->can_sleep; ++ return; ++ /* Should be using gpio_set_value_cansleep() */ ++ WARN_ON(desc->chip->can_sleep); ++ if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) ++ value = !value; ++ _gpiod_set_raw_value(desc, value); + } ++EXPORT_SYMBOL_GPL(gpiod_set_value); + +-int __gpio_cansleep(unsigned gpio) ++/** ++ * gpiod_cansleep() - report whether gpio value access may sleep ++ * @desc: gpio to check ++ * ++ */ ++int gpiod_cansleep(const struct gpio_desc *desc) + { +- return gpiod_cansleep(gpio_to_desc(gpio)); ++ if (!desc) ++ return 0; ++ return desc->chip->can_sleep; + } +-EXPORT_SYMBOL_GPL(__gpio_cansleep); ++EXPORT_SYMBOL_GPL(gpiod_cansleep); + + /** +- * __gpio_to_irq() - return the IRQ corresponding to a GPIO +- * @gpio: gpio whose IRQ will be returned (already requested) +- * Context: any ++ * gpiod_to_irq() - return the IRQ corresponding to a GPIO ++ * @desc: gpio whose IRQ will be returned (already requested) + * +- * This is used directly or indirectly to implement gpio_to_irq(). +- * It returns the number of the IRQ signaled by this (input) GPIO, +- * or a negative errno. ++ * Return the IRQ corresponding to the passed GPIO, or an error code in case of ++ * error. + */ +-static int gpiod_to_irq(const struct gpio_desc *desc) ++int gpiod_to_irq(const struct gpio_desc *desc) + { + struct gpio_chip *chip; + int offset; +@@ -1985,62 +2066,336 @@ + offset = gpio_chip_hwgpio(desc); + return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO; + } ++EXPORT_SYMBOL_GPL(gpiod_to_irq); + +-int __gpio_to_irq(unsigned gpio) ++/** ++ * gpiod_lock_as_irq() - lock a GPIO to be used as IRQ ++ * @gpio: the GPIO line to lock as used for IRQ ++ * ++ * This is used directly by GPIO drivers that want to lock down ++ * a certain GPIO line to be used as IRQs, for example in the ++ * .to_irq() callback of their gpio_chip, or in the .irq_enable() ++ * of its irq_chip implementation if the GPIO is known from that ++ * code. ++ */ ++int gpiod_lock_as_irq(struct gpio_desc *desc) + { +- return gpiod_to_irq(gpio_to_desc(gpio)); ++ if (!desc) ++ return -EINVAL; ++ ++ if (test_bit(FLAG_IS_OUT, &desc->flags)) { ++ gpiod_err(desc, ++ "%s: tried to flag a GPIO set as output for IRQ\n", ++ __func__); ++ return -EIO; ++ } ++ ++ set_bit(FLAG_USED_AS_IRQ, &desc->flags); ++ return 0; + } +-EXPORT_SYMBOL_GPL(__gpio_to_irq); ++EXPORT_SYMBOL_GPL(gpiod_lock_as_irq); + ++int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset) ++{ ++ return gpiod_lock_as_irq(gpiochip_offset_to_desc(chip, offset)); ++} ++EXPORT_SYMBOL_GPL(gpio_lock_as_irq); + +-/* There's no value in making it easy to inline GPIO calls that may sleep. +- * Common examples include ones connected to I2C or SPI chips. ++/** ++ * gpiod_unlock_as_irq() - unlock a GPIO used as IRQ ++ * @gpio: the GPIO line to unlock from IRQ usage ++ * ++ * This is used directly by GPIO drivers that want to indicate ++ * that a certain GPIO is no longer used exclusively for IRQ. + */ ++void gpiod_unlock_as_irq(struct gpio_desc *desc) ++{ ++ if (!desc) ++ return; + +-static int gpiod_get_value_cansleep(const struct gpio_desc *desc) ++ clear_bit(FLAG_USED_AS_IRQ, &desc->flags); ++} ++EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq); ++ ++void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset) ++{ ++ return gpiod_unlock_as_irq(gpiochip_offset_to_desc(chip, offset)); ++} ++EXPORT_SYMBOL_GPL(gpio_unlock_as_irq); ++ ++/** ++ * gpiod_get_raw_value_cansleep() - return a gpio's raw value ++ * @desc: gpio whose value will be returned ++ * ++ * Return the GPIO's raw value, i.e. the value of the physical line disregarding ++ * its ACTIVE_LOW status. ++ * ++ * This function is to be called from contexts that can sleep. ++ */ ++int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) ++{ ++ might_sleep_if(extra_checks); ++ if (!desc) ++ return 0; ++ return _gpiod_get_raw_value(desc); ++} ++EXPORT_SYMBOL_GPL(gpiod_get_raw_value_cansleep); ++ ++/** ++ * gpiod_get_value_cansleep() - return a gpio's value ++ * @desc: gpio whose value will be returned ++ * ++ * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into ++ * account. ++ * ++ * This function is to be called from contexts that can sleep. ++ */ ++int gpiod_get_value_cansleep(const struct gpio_desc *desc) + { +- struct gpio_chip *chip; + int value; +- int offset; + + might_sleep_if(extra_checks); + if (!desc) + return 0; +- chip = desc->chip; +- offset = gpio_chip_hwgpio(desc); +- value = chip->get ? chip->get(chip, offset) : 0; +- trace_gpio_value(desc_to_gpio(desc), 1, value); ++ ++ value = _gpiod_get_raw_value(desc); ++ if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) ++ value = !value; ++ + return value; + } ++EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep); + +-int gpio_get_value_cansleep(unsigned gpio) ++/** ++ * gpiod_set_raw_value_cansleep() - assign a gpio's raw value ++ * @desc: gpio whose value will be assigned ++ * @value: value to assign ++ * ++ * Set the raw value of the GPIO, i.e. the value of its physical line without ++ * regard for its ACTIVE_LOW status. ++ * ++ * This function is to be called from contexts that can sleep. ++ */ ++void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) + { +- return gpiod_get_value_cansleep(gpio_to_desc(gpio)); ++ might_sleep_if(extra_checks); ++ if (!desc) ++ return; ++ _gpiod_set_raw_value(desc, value); + } +-EXPORT_SYMBOL_GPL(gpio_get_value_cansleep); ++EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep); + +-static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) ++/** ++ * gpiod_set_value_cansleep() - assign a gpio's value ++ * @desc: gpio whose value will be assigned ++ * @value: value to assign ++ * ++ * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into ++ * account ++ * ++ * This function is to be called from contexts that can sleep. ++ */ ++void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) + { +- struct gpio_chip *chip; +- + might_sleep_if(extra_checks); + if (!desc) + return; +- chip = desc->chip; +- trace_gpio_value(desc_to_gpio(desc), 0, value); +- if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) +- _gpio_set_open_drain_value(desc, value); +- else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) +- _gpio_set_open_source_value(desc, value); ++ ++ if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) ++ value = !value; ++ _gpiod_set_raw_value(desc, value); ++} ++EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); ++ ++/** ++ * gpiod_add_table() - register GPIO device consumers ++ * @table: array of consumers to register ++ * @num: number of consumers in table ++ */ ++void gpiod_add_table(struct gpiod_lookup *table, size_t size) ++{ ++ mutex_lock(&gpio_lookup_lock); ++ ++ while (size--) { ++ list_add_tail(&table->list, &gpio_lookup_list); ++ table++; ++ } ++ ++ mutex_unlock(&gpio_lookup_lock); ++} ++ ++#ifdef CONFIG_OF ++static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, ++ unsigned int idx, ++ enum gpio_lookup_flags *flags) ++{ ++ char prop_name[32]; /* 32 is max size of property name */ ++ enum of_gpio_flags of_flags; ++ struct gpio_desc *desc; ++ ++ if (con_id) ++ snprintf(prop_name, 32, "%s-gpios", con_id); + else +- chip->set(chip, gpio_chip_hwgpio(desc), value); ++ snprintf(prop_name, 32, "gpios"); ++ ++ desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx, ++ &of_flags); ++ ++ if (IS_ERR(desc)) ++ return desc; ++ ++ if (of_flags & OF_GPIO_ACTIVE_LOW) ++ *flags |= GPIO_ACTIVE_LOW; ++ ++ return desc; ++} ++#else ++static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, ++ unsigned int idx, unsigned long *flags) ++{ ++ return ERR_PTR(-ENODEV); ++} ++#endif ++ ++static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, ++ unsigned int idx, ++ enum gpio_lookup_flags *flags) ++{ ++ const char *dev_id = dev ? dev_name(dev) : NULL; ++ struct gpio_desc *desc = ERR_PTR(-ENODEV); ++ unsigned int match, best = 0; ++ struct gpiod_lookup *p; ++ ++ mutex_lock(&gpio_lookup_lock); ++ ++ list_for_each_entry(p, &gpio_lookup_list, list) { ++ match = 0; ++ ++ if (p->dev_id) { ++ if (!dev_id || strcmp(p->dev_id, dev_id)) ++ continue; ++ ++ match += 2; ++ } ++ ++ if (p->con_id) { ++ if (!con_id || strcmp(p->con_id, con_id)) ++ continue; ++ ++ match += 1; ++ } ++ ++ if (p->idx != idx) ++ continue; ++ ++ if (match > best) { ++ struct gpio_chip *chip; ++ ++ chip = find_chip_by_name(p->chip_label); ++ ++ if (!chip) { ++ dev_warn(dev, "cannot find GPIO chip %s\n", ++ p->chip_label); ++ continue; ++ } ++ ++ if (chip->ngpio >= p->chip_hwnum) { ++ dev_warn(dev, "GPIO chip %s has %d GPIOs\n", ++ chip->label, chip->ngpio); ++ continue; ++ } ++ ++ desc = gpio_to_desc(chip->base + p->chip_hwnum); ++ *flags = p->flags; ++ ++ if (match != 3) ++ best = match; ++ else ++ break; ++ } ++ } ++ ++ mutex_unlock(&gpio_lookup_lock); ++ ++ return desc; ++} ++ ++/** ++ * gpio_get - obtain a GPIO for a given GPIO function ++ * @dev: GPIO consumer ++ * @con_id: function within the GPIO consumer ++ * ++ * Return the GPIO descriptor corresponding to the function con_id of device ++ * dev, or an IS_ERR() condition if an error occured. ++ */ ++struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id) ++{ ++ return gpiod_get_index(dev, con_id, 0); ++} ++EXPORT_SYMBOL_GPL(gpiod_get); ++ ++/** ++ * gpiod_get_index - obtain a GPIO from a multi-index GPIO function ++ * @dev: GPIO consumer ++ * @con_id: function within the GPIO consumer ++ * @idx: index of the GPIO to obtain in the consumer ++ * ++ * This variant of gpiod_get() allows to access GPIOs other than the first ++ * defined one for functions that define several GPIOs. ++ * ++ * Return a valid GPIO descriptor, or an IS_ERR() condition in case of error. ++ */ ++struct gpio_desc *__must_check gpiod_get_index(struct device *dev, ++ const char *con_id, ++ unsigned int idx) ++{ ++ struct gpio_desc *desc; ++ int status; ++ enum gpio_lookup_flags flags = 0; ++ ++ dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); ++ ++ /* Using device tree? */ ++ if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) { ++ dev_dbg(dev, "using device tree for GPIO lookup\n"); ++ desc = of_find_gpio(dev, con_id, idx, &flags); ++ } else { ++ dev_dbg(dev, "using lookup tables for GPIO lookup"); ++ desc = gpiod_find(dev, con_id, idx, &flags); ++ } ++ ++ if (IS_ERR(desc)) { ++ dev_warn(dev, "lookup for GPIO %s failed\n", con_id); ++ return desc; ++ } ++ ++ status = gpiod_request(desc, con_id); ++ ++ if (status < 0) ++ return ERR_PTR(status); ++ ++ if (flags & GPIO_ACTIVE_LOW) ++ set_bit(FLAG_ACTIVE_LOW, &desc->flags); ++ if (flags & GPIO_OPEN_DRAIN) ++ set_bit(FLAG_OPEN_DRAIN, &desc->flags); ++ if (flags & GPIO_OPEN_SOURCE) ++ set_bit(FLAG_OPEN_SOURCE, &desc->flags); ++ ++ return desc; + } ++EXPORT_SYMBOL_GPL(gpiod_get_index); + +-void gpio_set_value_cansleep(unsigned gpio, int value) ++/** ++ * gpiod_put - dispose of a GPIO descriptor ++ * @desc: GPIO descriptor to dispose of ++ * ++ * No descriptor can be used after gpiod_put() has been called on it. ++ */ ++void gpiod_put(struct gpio_desc *desc) + { +- return gpiod_set_value_cansleep(gpio_to_desc(gpio), value); ++ gpiod_free(desc); + } +-EXPORT_SYMBOL_GPL(gpio_set_value_cansleep); ++EXPORT_SYMBOL_GPL(gpiod_put); + + #ifdef CONFIG_DEBUG_FS + +@@ -2050,6 +2405,7 @@ + unsigned gpio = chip->base; + struct gpio_desc *gdesc = &chip->desc[0]; + int is_out; ++ int is_irq; + + for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) { + if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) +@@ -2057,12 +2413,14 @@ + + gpiod_get_direction(gdesc); + is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); +- seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", ++ is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags); ++ seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s", + gpio, gdesc->label, + is_out ? "out" : "in ", + chip->get + ? (chip->get(chip, i) ? "hi" : "lo") +- : "? "); ++ : "? ", ++ is_irq ? "IRQ" : " "); + seq_printf(s, "\n"); + } + } +diff -Nur linux-3.10.30/drivers/gpu/drm/Kconfig linux-3.10.30-cubox-i/drivers/gpu/drm/Kconfig +--- linux-3.10.30/drivers/gpu/drm/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gpu/drm/Kconfig 2014-03-08 20:33:32.000000000 +0100 +@@ -199,6 +199,13 @@ + Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister + chipset. If M is selected the module will be called savage. + ++config DRM_VIVANTE ++ tristate "Vivante GCCore" ++ depends on DRM ++ help ++ Choose this option if you have a Vivante graphics card. ++ If M is selected, the module will be called vivante. ++ + source "drivers/gpu/drm/exynos/Kconfig" + + source "drivers/gpu/drm/vmwgfx/Kconfig" +diff -Nur linux-3.10.30/drivers/gpu/drm/Makefile linux-3.10.30-cubox-i/drivers/gpu/drm/Makefile +--- linux-3.10.30/drivers/gpu/drm/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gpu/drm/Makefile 2014-03-08 20:33:32.000000000 +0100 +@@ -1,3 +1,24 @@ ++############################################################################## ++# ++# Copyright (C) 2005 - 2013 by Vivante Corp. ++# ++# 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++# ++############################################################################## ++ ++ + # + # Makefile for the drm device driver. This driver provides support for the + # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. +@@ -29,8 +50,8 @@ + CFLAGS_drm_trace_points.o := -I$(src) + + obj-$(CONFIG_DRM) += drm.o +-obj-$(CONFIG_DRM_USB) += drm_usb.o + obj-$(CONFIG_DRM_TTM) += ttm/ ++obj-$(CONFIG_DRM_VIVANTE) += vivante/ + obj-$(CONFIG_DRM_TDFX) += tdfx/ + obj-$(CONFIG_DRM_R128) += r128/ + obj-$(CONFIG_DRM_RADEON)+= radeon/ +diff -Nur linux-3.10.30/drivers/gpu/drm/drm_crtc_helper.c linux-3.10.30-cubox-i/drivers/gpu/drm/drm_crtc_helper.c +--- linux-3.10.30/drivers/gpu/drm/drm_crtc_helper.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gpu/drm/drm_crtc_helper.c 2014-03-08 20:33:32.000000000 +0100 +@@ -308,6 +308,29 @@ + EXPORT_SYMBOL(drm_helper_disable_unused_functions); + + /** ++ * drm_helper_crtc_possible_mask - find the mask of a registered CRTC ++ * @crtc: crtc to find mask for ++ * ++ * Given a registered CRTC, return the mask bit of that CRTC for an ++ * encoder's possible_crtcs field. ++ */ ++uint32_t drm_helper_crtc_possible_mask(struct drm_crtc *crtc) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct drm_crtc *tmp; ++ uint32_t crtc_mask = 1; ++ ++ list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { ++ if (tmp == crtc) ++ return crtc_mask; ++ crtc_mask <<= 1; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(drm_helper_crtc_possible_mask); ++ ++/** + * drm_encoder_crtc_ok - can a given crtc drive a given encoder? + * @encoder: encoder to test + * @crtc: crtc to test +@@ -317,23 +340,13 @@ + static bool drm_encoder_crtc_ok(struct drm_encoder *encoder, + struct drm_crtc *crtc) + { +- struct drm_device *dev; +- struct drm_crtc *tmp; +- int crtc_mask = 1; ++ uint32_t crtc_mask; + + WARN(!crtc, "checking null crtc?\n"); + +- dev = crtc->dev; ++ crtc_mask = drm_helper_crtc_possible_mask(crtc); + +- list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { +- if (tmp == crtc) +- break; +- crtc_mask <<= 1; +- } +- +- if (encoder->possible_crtcs & crtc_mask) +- return true; +- return false; ++ return !!(encoder->possible_crtcs & crtc_mask); + } + + /* +diff -Nur linux-3.10.30/drivers/gpu/drm/vivante/Makefile linux-3.10.30-cubox-i/drivers/gpu/drm/vivante/Makefile +--- linux-3.10.30/drivers/gpu/drm/vivante/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gpu/drm/vivante/Makefile 2014-03-08 20:33:35.000000000 +0100 +@@ -0,0 +1,29 @@ ++############################################################################## ++# ++# Copyright (C) 2005 - 2013 by Vivante Corp. ++# ++# 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++# ++############################################################################## ++ ++ ++# ++# Makefile for the drm device driver. This driver provides support for the ++# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. ++ ++ccflags-y := -Iinclude/drm ++vivante-y := vivante_drv.o ++ ++obj-$(CONFIG_DRM_VIVANTE) += vivante.o +diff -Nur linux-3.10.30/drivers/gpu/drm/vivante/vivante_drv.c linux-3.10.30-cubox-i/drivers/gpu/drm/vivante/vivante_drv.c +--- linux-3.10.30/drivers/gpu/drm/vivante/vivante_drv.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gpu/drm/vivante/vivante_drv.c 2014-03-08 20:33:35.000000000 +0100 +@@ -0,0 +1,111 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2013 by Vivante Corp. ++* ++* 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++* ++*****************************************************************************/ ++ ++ ++/* vivante_drv.c -- vivante driver -*- linux-c -*- ++ * ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: ++ * Rickard E. (Rik) Faith ++ * Daryll Strauss ++ * Gareth Hughes ++ */ ++ ++#include ++#include ++ ++#include "drmP.h" ++#include "vivante_drv.h" ++ ++#include "drm_pciids.h" ++ ++static char platformdevicename[] = "Vivante GCCore"; ++static struct platform_device *pplatformdev; ++ ++static const struct file_operations viv_driver_fops = { ++ .owner = THIS_MODULE, ++ .open = drm_open, ++ .release = drm_release, ++ .unlocked_ioctl = drm_ioctl, ++ .mmap = drm_mmap, ++ .poll = drm_poll, ++ .fasync = drm_fasync, ++ .llseek = noop_llseek, ++}; ++ ++static struct drm_driver driver = { ++ .driver_features = DRIVER_USE_MTRR, ++ .fops = &viv_driver_fops, ++ .name = DRIVER_NAME, ++ .desc = DRIVER_DESC, ++ .date = DRIVER_DATE, ++ .major = DRIVER_MAJOR, ++ .minor = DRIVER_MINOR, ++ .patchlevel = DRIVER_PATCHLEVEL, ++}; ++ ++static int __init vivante_init(void) ++{ ++ int retcode; ++ ++ pplatformdev = platform_device_register_simple(platformdevicename, ++ -1, NULL, 0); ++ if (pplatformdev == NULL) ++ printk(KERN_ERR"Platform device is null\n"); ++ ++ retcode = drm_platform_init(&driver, pplatformdev); ++ ++ return retcode; ++} ++ ++static void __exit vivante_exit(void) ++{ ++ if (pplatformdev) { ++ drm_platform_exit(&driver, pplatformdev); ++ platform_device_unregister(pplatformdev); ++ pplatformdev = NULL; ++ } ++} ++ ++module_init(vivante_init); ++module_exit(vivante_exit); ++ ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL and additional rights"); +diff -Nur linux-3.10.30/drivers/gpu/drm/vivante/vivante_drv.h linux-3.10.30-cubox-i/drivers/gpu/drm/vivante/vivante_drv.h +--- linux-3.10.30/drivers/gpu/drm/vivante/vivante_drv.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/gpu/drm/vivante/vivante_drv.h 2014-03-08 20:33:35.000000000 +0100 +@@ -0,0 +1,66 @@ ++/**************************************************************************** ++* ++* Copyright (C) 2005 - 2013 by Vivante Corp. ++* ++* 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++* ++*****************************************************************************/ ++ ++ ++/* vivante_drv.h -- Vivante DRM template customization -*- linux-c -*- ++ * Created: Wed Feb 14 12:32:32 2012 by John Zhao ++ */ ++/* ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: ++ * Gareth Hughes ++ */ ++ ++#ifndef __VIVANTE_DRV_H__ ++#define __VIVANTE_DRV_H__ ++ ++/* General customization: ++ */ ++ ++#define DRIVER_AUTHOR "Vivante Inc." ++ ++#define DRIVER_NAME "vivante" ++#define DRIVER_DESC "Vivante GCCore" ++#define DRIVER_DATE "20120216" ++ ++#define DRIVER_MAJOR 1 ++#define DRIVER_MINOR 0 ++#define DRIVER_PATCHLEVEL 0 ++ ++#endif +diff -Nur linux-3.10.30/drivers/hwmon/Kconfig linux-3.10.30-cubox-i/drivers/hwmon/Kconfig +--- linux-3.10.30/drivers/hwmon/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/hwmon/Kconfig 2014-03-08 20:33:35.000000000 +0100 +@@ -867,6 +867,15 @@ + This driver can also be built as a module. If so, the module + will be called max1668. + ++config SENSORS_MAX17135 ++ tristate "Maxim MAX17135 EPD temperature sensor" ++ depends on I2C ++ help ++ If you say yes here you get support for MAX17135 PMIC sensor. ++ ++ This driver can also be built as a module. If so, the module ++ will be called max17135_sensor. ++ + config SENSORS_MAX197 + tristate "Maxim MAX197 and compatibles" + help +@@ -1556,4 +1565,18 @@ + + endif # ACPI + ++config SENSORS_MAG3110 ++ tristate "Freescale MAG3110 e-compass sensor" ++ depends on I2C && SYSFS ++ help ++ If you say yes here you get support for the Freescale MAG3110 ++ e-compass sensor. ++ This driver can also be built as a module. If so, the module ++ will be called mag3110. ++ ++config MXC_MMA8451 ++ tristate "MMA8451 device driver" ++ depends on I2C ++ default y ++ + endif # HWMON +diff -Nur linux-3.10.30/drivers/hwmon/Makefile linux-3.10.30-cubox-i/drivers/hwmon/Makefile +--- linux-3.10.30/drivers/hwmon/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/hwmon/Makefile 2014-03-08 20:33:35.000000000 +0100 +@@ -101,6 +101,7 @@ + obj-$(CONFIG_SENSORS_MAX16065) += max16065.o + obj-$(CONFIG_SENSORS_MAX1619) += max1619.o + obj-$(CONFIG_SENSORS_MAX1668) += max1668.o ++obj-$(CONFIG_SENSORS_MAX17135) += max17135-hwmon.o + obj-$(CONFIG_SENSORS_MAX197) += max197.o + obj-$(CONFIG_SENSORS_MAX6639) += max6639.o + obj-$(CONFIG_SENSORS_MAX6642) += max6642.o +@@ -140,6 +141,8 @@ + obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o + obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o + obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o ++obj-$(CONFIG_SENSORS_MAG3110) += mag3110.o ++obj-$(CONFIG_MXC_MMA8451) += mxc_mma8451.o + + obj-$(CONFIG_PMBUS) += pmbus/ + +diff -Nur linux-3.10.30/drivers/hwmon/mag3110.c linux-3.10.30-cubox-i/drivers/hwmon/mag3110.c +--- linux-3.10.30/drivers/hwmon/mag3110.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/hwmon/mag3110.c 2014-03-08 20:33:36.000000000 +0100 +@@ -0,0 +1,611 @@ ++/* ++ * ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ ++ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAG3110_DRV_NAME "mag3110" ++#define MAG3110_ID 0xC4 ++#define MAG3110_XYZ_DATA_LEN 6 ++#define MAG3110_STATUS_ZYXDR 0x08 ++ ++#define MAG3110_AC_MASK (0x01) ++#define MAG3110_AC_OFFSET 0 ++#define MAG3110_DR_MODE_MASK (0x7 << 5) ++#define MAG3110_DR_MODE_OFFSET 5 ++#define MAG3110_IRQ_USED 0 ++ ++#define POLL_INTERVAL_MAX 500 ++#define POLL_INTERVAL 100 ++#define INT_TIMEOUT 1000 ++#define DEFAULT_POSITION 2 ++/* register enum for mag3110 registers */ ++enum { ++ MAG3110_DR_STATUS = 0x00, ++ MAG3110_OUT_X_MSB, ++ MAG3110_OUT_X_LSB, ++ MAG3110_OUT_Y_MSB, ++ MAG3110_OUT_Y_LSB, ++ MAG3110_OUT_Z_MSB, ++ MAG3110_OUT_Z_LSB, ++ MAG3110_WHO_AM_I, ++ ++ MAG3110_OFF_X_MSB, ++ MAG3110_OFF_X_LSB, ++ MAG3110_OFF_Y_MSB, ++ MAG3110_OFF_Y_LSB, ++ MAG3110_OFF_Z_MSB, ++ MAG3110_OFF_Z_LSB, ++ ++ MAG3110_DIE_TEMP, ++ ++ MAG3110_CTRL_REG1 = 0x10, ++ MAG3110_CTRL_REG2, ++}; ++enum { ++ MAG_STANDBY, ++ MAG_ACTIVED ++}; ++struct mag3110_data { ++ struct i2c_client *client; ++ struct input_polled_dev *poll_dev; ++ struct device *hwmon_dev; ++ wait_queue_head_t waitq; ++ bool data_ready; ++ u8 ctl_reg1; ++ int active; ++ int position; ++}; ++static short MAGHAL[8][3][3] = { ++ { {0, 1, 0}, {-1, 0, 0}, {0, 0, 1} }, ++ { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} }, ++ { {0, -1, 0}, {1, 0, 0}, {0, 0, 1} }, ++ { {-1, 0, 0}, {0, -1, 0}, {0, 0, 1} }, ++ ++ { {0, 1, 0}, {1, 0, 0}, {0, 0, -1} }, ++ { {1, 0, 0}, {0, -1, 0}, {0, 0, -1} }, ++ { {0, -1, 0}, {-1, 0, 0}, {0, 0, -1} }, ++ { {-1, 0, 0}, {0, 1, 0}, {0, 0, -1} }, ++}; ++ ++static struct mag3110_data *mag3110_pdata; ++/*! ++ * This function do one mag3110 register read. ++ */ ++static DEFINE_MUTEX(mag3110_lock); ++static int mag3110_adjust_position(short *x, short *y, short *z) ++{ ++ short rawdata[3], data[3]; ++ int i, j; ++ int position = mag3110_pdata->position; ++ if (position < 0 || position > 7) ++ position = 0; ++ rawdata[0] = *x; ++ rawdata[1] = *y; ++ rawdata[2] = *z; ++ for (i = 0; i < 3; i++) { ++ data[i] = 0; ++ for (j = 0; j < 3; j++) ++ data[i] += rawdata[j] * MAGHAL[position][i][j]; ++ } ++ *x = data[0]; ++ *y = data[1]; ++ *z = data[2]; ++ return 0; ++} ++ ++static int mag3110_read_reg(struct i2c_client *client, u8 reg) ++{ ++ return i2c_smbus_read_byte_data(client, reg); ++} ++ ++/*! ++ * This function do one mag3110 register write. ++ */ ++static int mag3110_write_reg(struct i2c_client *client, u8 reg, char value) ++{ ++ int ret; ++ ++ ret = i2c_smbus_write_byte_data(client, reg, value); ++ if (ret < 0) ++ dev_err(&client->dev, "i2c write failed\n"); ++ return ret; ++} ++ ++/*! ++ * This function do multiple mag3110 registers read. ++ */ ++static int mag3110_read_block_data(struct i2c_client *client, u8 reg, ++ int count, u8 *addr) ++{ ++ if (i2c_smbus_read_i2c_block_data(client, reg, count, addr) < count) { ++ dev_err(&client->dev, "i2c block read failed\n"); ++ return -1; ++ } ++ ++ return count; ++} ++ ++/* ++ * Initialization function ++ */ ++static int mag3110_init_client(struct i2c_client *client) ++{ ++ int val, ret; ++ ++ /* enable automatic resets */ ++ val = 0x80; ++ ret = mag3110_write_reg(client, MAG3110_CTRL_REG2, val); ++ ++ /* set default data rate to 10HZ */ ++ val = mag3110_read_reg(client, MAG3110_CTRL_REG1); ++ val |= (0x0 << MAG3110_DR_MODE_OFFSET); ++ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, val); ++ ++ return ret; ++} ++ ++/*************************************************************** ++* ++* read sensor data from mag3110 ++* ++***************************************************************/ ++static int mag3110_read_data(short *x, short *y, short *z) ++{ ++ struct mag3110_data *data; ++ int retry = 3; ++ u8 tmp_data[MAG3110_XYZ_DATA_LEN]; ++ int result; ++ if (!mag3110_pdata || mag3110_pdata->active == MAG_STANDBY) ++ return -EINVAL; ++ ++ data = mag3110_pdata; ++#if MAG3110_IRQ_USED ++ if (!wait_event_interruptible_timeout ++ (data->waitq, data->data_ready != 0, ++ msecs_to_jiffies(INT_TIMEOUT))) { ++ dev_dbg(&data->client->dev, "interrupt not received\n"); ++ return -ETIME; ++ } ++#else ++ do { ++ msleep(1); ++ result = i2c_smbus_read_byte_data(data->client, ++ MAG3110_DR_STATUS); ++ retry--; ++ } while (!(result & MAG3110_STATUS_ZYXDR) && retry > 0); ++ /* Clear data_ready flag after data is read out */ ++ if (retry == 0) ++ return -EINVAL; ++#endif ++ ++ data->data_ready = 0; ++ ++ if (mag3110_read_block_data(data->client, ++ MAG3110_OUT_X_MSB, MAG3110_XYZ_DATA_LEN, ++ tmp_data) < 0) ++ return -1; ++ ++ *x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; ++ *y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; ++ *z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5]; ++ ++ return 0; ++} ++ ++static void report_abs(void) ++{ ++ struct input_dev *idev; ++ short x, y, z; ++ ++ mutex_lock(&mag3110_lock); ++ if (mag3110_read_data(&x, &y, &z) != 0) ++ goto out; ++ mag3110_adjust_position(&x, &y, &z); ++ idev = mag3110_pdata->poll_dev->input; ++ input_report_abs(idev, ABS_X, x); ++ input_report_abs(idev, ABS_Y, y); ++ input_report_abs(idev, ABS_Z, z); ++ input_sync(idev); ++out: ++ mutex_unlock(&mag3110_lock); ++} ++ ++static void mag3110_dev_poll(struct input_polled_dev *dev) ++{ ++ report_abs(); ++} ++ ++#if MAG3110_IRQ_USED ++static irqreturn_t mag3110_irq_handler(int irq, void *dev_id) ++{ ++ mag3110_pdata->data_ready = 1; ++ wake_up_interruptible(&mag3110_pdata->waitq); ++ ++ return IRQ_HANDLED; ++} ++#endif ++static ssize_t mag3110_enable_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client; ++ int val; ++ mutex_lock(&mag3110_lock); ++ client = mag3110_pdata->client; ++ val = mag3110_read_reg(client, MAG3110_CTRL_REG1) & MAG3110_AC_MASK; ++ ++ mutex_unlock(&mag3110_lock); ++ return sprintf(buf, "%d\n", val); ++} ++ ++static ssize_t mag3110_enable_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client; ++ int reg, ret; ++ long enable; ++ u8 tmp_data[MAG3110_XYZ_DATA_LEN]; ++ ++ ret = strict_strtol(buf, 10, &enable); ++ if (ret) { ++ dev_err(dev, "string to long error\n"); ++ return ret; ++ } ++ ++ mutex_lock(&mag3110_lock); ++ client = mag3110_pdata->client; ++ reg = mag3110_read_reg(client, MAG3110_CTRL_REG1); ++ if (enable && mag3110_pdata->active == MAG_STANDBY) { ++ reg |= MAG3110_AC_MASK; ++ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); ++ if (!ret) ++ mag3110_pdata->active = MAG_ACTIVED; ++ } else if (!enable && mag3110_pdata->active == MAG_ACTIVED) { ++ reg &= ~MAG3110_AC_MASK; ++ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); ++ if (!ret) ++ mag3110_pdata->active = MAG_STANDBY; ++ } ++ ++ if (mag3110_pdata->active == MAG_ACTIVED) { ++ msleep(100); ++ /* Read out MSB data to clear interrupt flag automatically */ ++ mag3110_read_block_data(client, MAG3110_OUT_X_MSB, ++ MAG3110_XYZ_DATA_LEN, tmp_data); ++ } ++ mutex_unlock(&mag3110_lock); ++ return count; ++} ++ ++static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, ++ mag3110_enable_show, mag3110_enable_store); ++ ++static ssize_t mag3110_dr_mode_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client; ++ int val; ++ ++ client = mag3110_pdata->client; ++ val = (mag3110_read_reg(client, MAG3110_CTRL_REG1) ++ & MAG3110_DR_MODE_MASK) >> MAG3110_DR_MODE_OFFSET; ++ ++ return sprintf(buf, "%d\n", val); ++} ++ ++static ssize_t mag3110_dr_mode_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client; ++ int reg, ret; ++ unsigned long val; ++ ++ /* This must be done when mag3110 is disabled */ ++ if ((strict_strtoul(buf, 10, &val) < 0) || (val > 7)) ++ return -EINVAL; ++ ++ client = mag3110_pdata->client; ++ reg = mag3110_read_reg(client, MAG3110_CTRL_REG1) & ++ ~MAG3110_DR_MODE_MASK; ++ reg |= (val << MAG3110_DR_MODE_OFFSET); ++ /* MAG3110_CTRL_REG1 bit 5-7: data rate mode */ ++ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(dr_mode, S_IWUSR | S_IRUGO, ++ mag3110_dr_mode_show, mag3110_dr_mode_store); ++ ++static ssize_t mag3110_position_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int val; ++ mutex_lock(&mag3110_lock); ++ val = mag3110_pdata->position; ++ mutex_unlock(&mag3110_lock); ++ return sprintf(buf, "%d\n", val); ++} ++ ++static ssize_t mag3110_position_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ long position; ++ int ret; ++ ret = strict_strtol(buf, 10, &position); ++ if (ret) { ++ dev_err(dev, "string to long error\n"); ++ return ret; ++ } ++ ++ mutex_lock(&mag3110_lock); ++ mag3110_pdata->position = (int)position; ++ mutex_unlock(&mag3110_lock); ++ return count; ++} ++ ++static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, ++ mag3110_position_show, mag3110_position_store); ++ ++static struct attribute *mag3110_attributes[] = { ++ &dev_attr_enable.attr, ++ &dev_attr_dr_mode.attr, ++ &dev_attr_position.attr, ++ NULL ++}; ++ ++static const struct attribute_group mag3110_attr_group = { ++ .attrs = mag3110_attributes, ++}; ++ ++static int mag3110_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adapter; ++ struct input_dev *idev; ++ struct mag3110_data *data; ++ int ret = 0; ++ struct regulator *vdd, *vdd_io; ++ u32 pos = 0; ++ struct device_node *of_node = client->dev.of_node; ++ vdd = NULL; ++ vdd_io = NULL; ++ ++ vdd = devm_regulator_get(&client->dev, "vdd"); ++ if (!IS_ERR(vdd)) { ++ ret = regulator_enable(vdd); ++ if (ret) { ++ dev_err(&client->dev, "vdd set voltage error\n"); ++ return ret; ++ } ++ } ++ ++ vdd_io = devm_regulator_get(&client->dev, "vddio"); ++ if (!IS_ERR(vdd_io)) { ++ ret = regulator_enable(vdd_io); ++ if (ret) { ++ dev_err(&client->dev, "vddio set voltage error\n"); ++ return ret; ++ } ++ } ++ ++ adapter = to_i2c_adapter(client->dev.parent); ++ if (!i2c_check_functionality(adapter, ++ I2C_FUNC_SMBUS_BYTE | ++ I2C_FUNC_SMBUS_BYTE_DATA | ++ I2C_FUNC_SMBUS_I2C_BLOCK)) ++ return -EIO; ++ ++ dev_info(&client->dev, "check mag3110 chip ID\n"); ++ ret = mag3110_read_reg(client, MAG3110_WHO_AM_I); ++ ++ if (MAG3110_ID != ret) { ++ dev_err(&client->dev, ++ "read chip ID 0x%x is not equal to 0x%x!\n", ret, ++ MAG3110_ID); ++ return -EINVAL; ++ } ++ data = kzalloc(sizeof(struct mag3110_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ data->client = client; ++ i2c_set_clientdata(client, data); ++ /* Init queue */ ++ init_waitqueue_head(&data->waitq); ++ ++ data->hwmon_dev = hwmon_device_register(&client->dev); ++ if (IS_ERR(data->hwmon_dev)) { ++ dev_err(&client->dev, "hwmon register failed!\n"); ++ ret = PTR_ERR(data->hwmon_dev); ++ goto error_rm_dev_sysfs; ++ } ++ ++ /*input poll device register */ ++ data->poll_dev = input_allocate_polled_device(); ++ if (!data->poll_dev) { ++ dev_err(&client->dev, "alloc poll device failed!\n"); ++ ret = -ENOMEM; ++ goto error_rm_hwmon_dev; ++ } ++ data->poll_dev->poll = mag3110_dev_poll; ++ data->poll_dev->poll_interval = POLL_INTERVAL; ++ data->poll_dev->poll_interval_max = POLL_INTERVAL_MAX; ++ idev = data->poll_dev->input; ++ idev->name = MAG3110_DRV_NAME; ++ idev->id.bustype = BUS_I2C; ++ idev->evbit[0] = BIT_MASK(EV_ABS); ++ input_set_abs_params(idev, ABS_X, -15000, 15000, 0, 0); ++ input_set_abs_params(idev, ABS_Y, -15000, 15000, 0, 0); ++ input_set_abs_params(idev, ABS_Z, -15000, 15000, 0, 0); ++ ret = input_register_polled_device(data->poll_dev); ++ if (ret) { ++ dev_err(&client->dev, "register poll device failed!\n"); ++ goto error_free_poll_dev; ++ } ++ ++ /*create device group in sysfs as user interface */ ++ ret = sysfs_create_group(&idev->dev.kobj, &mag3110_attr_group); ++ if (ret) { ++ dev_err(&client->dev, "create device file failed!\n"); ++ ret = -EINVAL; ++ goto error_rm_poll_dev; ++ } ++ /* set irq type to edge rising */ ++#if MAG3110_IRQ_USED ++ ret = request_irq(client->irq, mag3110_irq_handler, ++ IRQF_TRIGGER_RISING, client->dev.driver->name, idev); ++ if (ret < 0) { ++ dev_err(&client->dev, "failed to register irq %d!\n", ++ client->irq); ++ goto error_rm_dev_sysfs; ++ } ++#endif ++ /* Initialize mag3110 chip */ ++ mag3110_init_client(client); ++ mag3110_pdata = data; ++ mag3110_pdata->active = MAG_STANDBY; ++ ret = of_property_read_u32(of_node, "position", &pos); ++ if (ret) ++ pos = DEFAULT_POSITION; ++ mag3110_pdata->position = (int)pos; ++ dev_info(&client->dev, "mag3110 is probed\n"); ++ return 0; ++error_rm_dev_sysfs: ++ sysfs_remove_group(&client->dev.kobj, &mag3110_attr_group); ++error_rm_poll_dev: ++ input_unregister_polled_device(data->poll_dev); ++error_free_poll_dev: ++ input_free_polled_device(data->poll_dev); ++error_rm_hwmon_dev: ++ hwmon_device_unregister(data->hwmon_dev); ++ ++ kfree(data); ++ mag3110_pdata = NULL; ++ ++ return ret; ++} ++ ++static int mag3110_remove(struct i2c_client *client) ++{ ++ struct mag3110_data *data; ++ int ret; ++ ++ data = i2c_get_clientdata(client); ++ ++ data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); ++ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, ++ data->ctl_reg1 & ~MAG3110_AC_MASK); ++ ++ free_irq(client->irq, data); ++ input_unregister_polled_device(data->poll_dev); ++ input_free_polled_device(data->poll_dev); ++ hwmon_device_unregister(data->hwmon_dev); ++ sysfs_remove_group(&client->dev.kobj, &mag3110_attr_group); ++ kfree(data); ++ mag3110_pdata = NULL; ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PM ++static int mag3110_suspend(struct i2c_client *client, pm_message_t mesg) ++{ ++ int ret = 0; ++ struct mag3110_data *data = i2c_get_clientdata(client); ++ if (data->active == MAG_ACTIVED) { ++ data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1); ++ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, ++ data->ctl_reg1 & ~MAG3110_AC_MASK); ++ } ++ return ret; ++} ++ ++static int mag3110_resume(struct i2c_client *client) ++{ ++ int ret = 0; ++ u8 tmp_data[MAG3110_XYZ_DATA_LEN]; ++ struct mag3110_data *data = i2c_get_clientdata(client); ++ if (data->active == MAG_ACTIVED) { ++ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, ++ data->ctl_reg1); ++ ++ if (data->ctl_reg1 & MAG3110_AC_MASK) { ++ /* Read out MSB data to clear interrupt ++ flag automatically */ ++ mag3110_read_block_data(client, MAG3110_OUT_X_MSB, ++ MAG3110_XYZ_DATA_LEN, tmp_data); ++ } ++ } ++ return ret; ++} ++ ++#else ++#define mag3110_suspend NULL ++#define mag3110_resume NULL ++#endif /* CONFIG_PM */ ++ ++static const struct i2c_device_id mag3110_id[] = { ++ {MAG3110_DRV_NAME, 0}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, mag3110_id); ++static struct i2c_driver mag3110_driver = { ++ .driver = {.name = MAG3110_DRV_NAME, ++ .owner = THIS_MODULE,}, ++ .suspend = mag3110_suspend, ++ .resume = mag3110_resume, ++ .probe = mag3110_probe, ++ .remove = mag3110_remove, ++ .id_table = mag3110_id, ++}; ++ ++static int __init mag3110_init(void) ++{ ++ return i2c_add_driver(&mag3110_driver); ++} ++ ++static void __exit mag3110_exit(void) ++{ ++ i2c_del_driver(&mag3110_driver); ++} ++ ++module_init(mag3110_init); ++module_exit(mag3110_exit); ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("Freescale mag3110 3-axis magnetometer driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/hwmon/max17135-hwmon.c linux-3.10.30-cubox-i/drivers/hwmon/max17135-hwmon.c +--- linux-3.10.30/drivers/hwmon/max17135-hwmon.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/hwmon/max17135-hwmon.c 2014-03-08 20:33:36.000000000 +0100 +@@ -0,0 +1,176 @@ ++/* ++ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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 ++ * ++ */ ++/* ++ * max17135.c ++ * ++ * Based on the MAX1619 driver. ++ * Copyright (C) 2003-2004 Alexey Fisher ++ * Jean Delvare ++ * ++ * The MAX17135 is a sensor chip made by Maxim. ++ * It reports up to two temperatures (its own plus up to ++ * one external one). ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Conversions ++ */ ++static int temp_from_reg(int val) ++{ ++ return val >> 8; ++} ++ ++/* ++ * Functions declaration ++ */ ++static int max17135_sensor_probe(struct platform_device *pdev); ++static int max17135_sensor_remove(struct platform_device *pdev); ++ ++static const struct platform_device_id max17135_sns_id[] = { ++ { "max17135-sns", 0}, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(platform, max17135_sns_id); ++ ++/* ++ * Driver data (common to all clients) ++ */ ++static struct platform_driver max17135_sensor_driver = { ++ .probe = max17135_sensor_probe, ++ .remove = max17135_sensor_remove, ++ .id_table = max17135_sns_id, ++ .driver = { ++ .name = "max17135_sensor", ++ }, ++}; ++ ++/* ++ * Client data (each client gets its own) ++ */ ++struct max17135_data { ++ struct device *hwmon_dev; ++}; ++ ++/* ++ * Sysfs stuff ++ */ ++static ssize_t show_temp_input1(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned int reg_val; ++ max17135_reg_read(REG_MAX17135_INT_TEMP, ®_val); ++ return snprintf(buf, PAGE_SIZE, "%d\n", temp_from_reg(reg_val)); ++} ++ ++static ssize_t show_temp_input2(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned int reg_val; ++ max17135_reg_read(REG_MAX17135_EXT_TEMP, ®_val); ++ return snprintf(buf, PAGE_SIZE, "%d\n", temp_from_reg(reg_val)); ++} ++ ++static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); ++static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL); ++ ++static struct attribute *max17135_attributes[] = { ++ &dev_attr_temp1_input.attr, ++ &dev_attr_temp2_input.attr, ++ NULL ++}; ++ ++static const struct attribute_group max17135_group = { ++ .attrs = max17135_attributes, ++}; ++ ++/* ++ * Real code ++ */ ++static int max17135_sensor_probe(struct platform_device *pdev) ++{ ++ struct max17135_data *data; ++ int err; ++ ++ data = kzalloc(sizeof(struct max17135_data), GFP_KERNEL); ++ if (!data) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ /* Register sysfs hooks */ ++ err = sysfs_create_group(&pdev->dev.kobj, &max17135_group); ++ if (err) ++ goto exit_free; ++ ++ data->hwmon_dev = hwmon_device_register(&pdev->dev); ++ if (IS_ERR(data->hwmon_dev)) { ++ err = PTR_ERR(data->hwmon_dev); ++ goto exit_remove_files; ++ } ++ ++ platform_set_drvdata(pdev, data); ++ ++ return 0; ++ ++exit_remove_files: ++ sysfs_remove_group(&pdev->dev.kobj, &max17135_group); ++exit_free: ++ kfree(data); ++exit: ++ return err; ++} ++ ++static int max17135_sensor_remove(struct platform_device *pdev) ++{ ++ struct max17135_data *data = platform_get_drvdata(pdev); ++ ++ hwmon_device_unregister(data->hwmon_dev); ++ sysfs_remove_group(&pdev->dev.kobj, &max17135_group); ++ ++ kfree(data); ++ return 0; ++} ++ ++static int __init sensors_max17135_init(void) ++{ ++ return platform_driver_register(&max17135_sensor_driver); ++} ++module_init(sensors_max17135_init); ++ ++static void __exit sensors_max17135_exit(void) ++{ ++ platform_driver_unregister(&max17135_sensor_driver); ++} ++module_exit(sensors_max17135_exit); ++ ++MODULE_DESCRIPTION("MAX17135 sensor driver"); ++MODULE_LICENSE("GPL"); ++ +diff -Nur linux-3.10.30/drivers/hwmon/mxc_mma8451.c linux-3.10.30-cubox-i/drivers/hwmon/mxc_mma8451.c +--- linux-3.10.30/drivers/hwmon/mxc_mma8451.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/hwmon/mxc_mma8451.c 2014-03-08 20:33:36.000000000 +0100 +@@ -0,0 +1,538 @@ ++/* ++ * mma8451.c - Linux kernel modules for 3-Axis Orientation/Motion ++ * Detection Sensor ++ * ++ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MMA8451_I2C_ADDR 0x1C ++#define MMA8451_ID 0x1A ++#define MMA8452_ID 0x2A ++#define MMA8453_ID 0x3A ++ ++#define POLL_INTERVAL_MIN 1 ++#define POLL_INTERVAL_MAX 500 ++#define POLL_INTERVAL 100 /* msecs */ ++#define INPUT_FUZZ 32 ++#define INPUT_FLAT 32 ++#define MODE_CHANGE_DELAY_MS 100 ++ ++#define MMA8451_STATUS_ZYXDR 0x08 ++#define MMA8451_BUF_SIZE 7 ++#define DEFAULT_POSITION 0 ++ ++/* register enum for mma8451 registers */ ++enum { ++ MMA8451_STATUS = 0x00, ++ MMA8451_OUT_X_MSB, ++ MMA8451_OUT_X_LSB, ++ MMA8451_OUT_Y_MSB, ++ MMA8451_OUT_Y_LSB, ++ MMA8451_OUT_Z_MSB, ++ MMA8451_OUT_Z_LSB, ++ ++ MMA8451_F_SETUP = 0x09, ++ MMA8451_TRIG_CFG, ++ MMA8451_SYSMOD, ++ MMA8451_INT_SOURCE, ++ MMA8451_WHO_AM_I, ++ MMA8451_XYZ_DATA_CFG, ++ MMA8451_HP_FILTER_CUTOFF, ++ ++ MMA8451_PL_STATUS, ++ MMA8451_PL_CFG, ++ MMA8451_PL_COUNT, ++ MMA8451_PL_BF_ZCOMP, ++ MMA8451_P_L_THS_REG, ++ ++ MMA8451_FF_MT_CFG, ++ MMA8451_FF_MT_SRC, ++ MMA8451_FF_MT_THS, ++ MMA8451_FF_MT_COUNT, ++ ++ MMA8451_TRANSIENT_CFG = 0x1D, ++ MMA8451_TRANSIENT_SRC, ++ MMA8451_TRANSIENT_THS, ++ MMA8451_TRANSIENT_COUNT, ++ ++ MMA8451_PULSE_CFG, ++ MMA8451_PULSE_SRC, ++ MMA8451_PULSE_THSX, ++ MMA8451_PULSE_THSY, ++ MMA8451_PULSE_THSZ, ++ MMA8451_PULSE_TMLT, ++ MMA8451_PULSE_LTCY, ++ MMA8451_PULSE_WIND, ++ ++ MMA8451_ASLP_COUNT, ++ MMA8451_CTRL_REG1, ++ MMA8451_CTRL_REG2, ++ MMA8451_CTRL_REG3, ++ MMA8451_CTRL_REG4, ++ MMA8451_CTRL_REG5, ++ ++ MMA8451_OFF_X, ++ MMA8451_OFF_Y, ++ MMA8451_OFF_Z, ++ ++ MMA8451_REG_END, ++}; ++ ++/* The sensitivity is represented in counts/g. In 2g mode the ++sensitivity is 1024 counts/g. In 4g mode the sensitivity is 512 ++counts/g and in 8g mode the sensitivity is 256 counts/g. ++ */ ++enum { ++ MODE_2G = 0, ++ MODE_4G, ++ MODE_8G, ++}; ++ ++enum { ++ MMA_STANDBY = 0, ++ MMA_ACTIVED, ++}; ++ ++/* mma8451 status */ ++struct mma8451_status { ++ u8 mode; ++ u8 ctl_reg1; ++ int active; ++ int position; ++}; ++ ++static struct mma8451_status mma_status; ++static struct input_polled_dev *mma8451_idev; ++static struct device *hwmon_dev; ++static struct i2c_client *mma8451_i2c_client; ++ ++static int senstive_mode = MODE_2G; ++static int ACCHAL[8][3][3] = { ++ { {0, -1, 0}, {1, 0, 0}, {0, 0, 1} }, ++ { {-1, 0, 0}, {0, -1, 0}, {0, 0, 1} }, ++ { {0, 1, 0}, {-1, 0, 0}, {0, 0, 1} }, ++ { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} }, ++ ++ { {0, -1, 0}, {-1, 0, 0}, {0, 0, -1} }, ++ { {-1, 0, 0}, {0, 1, 0}, {0, 0, -1} }, ++ { {0, 1, 0}, {1, 0, 0}, {0, 0, -1} }, ++ { {1, 0, 0}, {0, -1, 0}, {0, 0, -1} }, ++}; ++ ++static DEFINE_MUTEX(mma8451_lock); ++static int mma8451_adjust_position(short *x, short *y, short *z) ++{ ++ short rawdata[3], data[3]; ++ int i, j; ++ int position = mma_status.position; ++ if (position < 0 || position > 7) ++ position = 0; ++ rawdata[0] = *x; ++ rawdata[1] = *y; ++ rawdata[2] = *z; ++ for (i = 0; i < 3; i++) { ++ data[i] = 0; ++ for (j = 0; j < 3; j++) ++ data[i] += rawdata[j] * ACCHAL[position][i][j]; ++ } ++ *x = data[0]; ++ *y = data[1]; ++ *z = data[2]; ++ return 0; ++} ++ ++static int mma8451_change_mode(struct i2c_client *client, int mode) ++{ ++ int result; ++ ++ mma_status.ctl_reg1 = 0; ++ result = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, 0); ++ if (result < 0) ++ goto out; ++ ++ mma_status.mode = mode; ++ result = i2c_smbus_write_byte_data(client, MMA8451_XYZ_DATA_CFG, ++ mma_status.mode); ++ if (result < 0) ++ goto out; ++ mma_status.active = MMA_STANDBY; ++ mdelay(MODE_CHANGE_DELAY_MS); ++ ++ return 0; ++out: ++ dev_err(&client->dev, "error when init mma8451:(%d)", result); ++ return result; ++} ++ ++static int mma8451_read_data(short *x, short *y, short *z) ++{ ++ u8 tmp_data[MMA8451_BUF_SIZE]; ++ int ret; ++ ++ ret = i2c_smbus_read_i2c_block_data(mma8451_i2c_client, ++ MMA8451_OUT_X_MSB, 7, tmp_data); ++ if (ret < MMA8451_BUF_SIZE) { ++ dev_err(&mma8451_i2c_client->dev, "i2c block read failed\n"); ++ return -EIO; ++ } ++ ++ *x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1]; ++ *y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3]; ++ *z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5]; ++ return 0; ++} ++ ++static void report_abs(void) ++{ ++ short x, y, z; ++ int result; ++ int retry = 3; ++ ++ mutex_lock(&mma8451_lock); ++ if (mma_status.active == MMA_STANDBY) ++ goto out; ++ /* wait for the data ready */ ++ do { ++ result = i2c_smbus_read_byte_data(mma8451_i2c_client, ++ MMA8451_STATUS); ++ retry--; ++ msleep(1); ++ } while (!(result & MMA8451_STATUS_ZYXDR) && retry > 0); ++ if (retry == 0) ++ goto out; ++ if (mma8451_read_data(&x, &y, &z) != 0) ++ goto out; ++ mma8451_adjust_position(&x, &y, &z); ++ input_report_abs(mma8451_idev->input, ABS_X, x); ++ input_report_abs(mma8451_idev->input, ABS_Y, y); ++ input_report_abs(mma8451_idev->input, ABS_Z, z); ++ input_sync(mma8451_idev->input); ++out: ++ mutex_unlock(&mma8451_lock); ++} ++ ++static void mma8451_dev_poll(struct input_polled_dev *dev) ++{ ++ report_abs(); ++} ++ ++static ssize_t mma8451_enable_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client; ++ u8 val; ++ int enable; ++ ++ mutex_lock(&mma8451_lock); ++ client = mma8451_i2c_client; ++ val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1); ++ if ((val & 0x01) && mma_status.active == MMA_ACTIVED) ++ enable = 1; ++ else ++ enable = 0; ++ mutex_unlock(&mma8451_lock); ++ return sprintf(buf, "%d\n", enable); ++} ++ ++static ssize_t mma8451_enable_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client; ++ int ret; ++ unsigned long enable; ++ u8 val = 0; ++ ++ ret = strict_strtoul(buf, 10, &enable); ++ if (ret) { ++ dev_err(dev, "string transform error\n"); ++ return ret; ++ } ++ ++ mutex_lock(&mma8451_lock); ++ client = mma8451_i2c_client; ++ enable = (enable > 0) ? 1 : 0; ++ if (enable && mma_status.active == MMA_STANDBY) { ++ val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1); ++ ret = ++ i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, ++ val | 0x01); ++ if (!ret) ++ mma_status.active = MMA_ACTIVED; ++ ++ } else if (enable == 0 && mma_status.active == MMA_ACTIVED) { ++ val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1); ++ ret = ++ i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, ++ val & 0xFE); ++ if (!ret) ++ mma_status.active = MMA_STANDBY; ++ ++ } ++ mutex_unlock(&mma8451_lock); ++ return count; ++} ++ ++static ssize_t mma8451_position_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ int position = 0; ++ mutex_lock(&mma8451_lock); ++ position = mma_status.position; ++ mutex_unlock(&mma8451_lock); ++ return sprintf(buf, "%d\n", position); ++} ++ ++static ssize_t mma8451_position_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned long position; ++ int ret; ++ ret = strict_strtoul(buf, 10, &position); ++ if (ret) { ++ dev_err(dev, "string transform error\n"); ++ return ret; ++ } ++ ++ mutex_lock(&mma8451_lock); ++ mma_status.position = (int)position; ++ mutex_unlock(&mma8451_lock); ++ return count; ++} ++ ++static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, ++ mma8451_enable_show, mma8451_enable_store); ++static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, ++ mma8451_position_show, mma8451_position_store); ++ ++static struct attribute *mma8451_attributes[] = { ++ &dev_attr_enable.attr, ++ &dev_attr_position.attr, ++ NULL ++}; ++ ++static const struct attribute_group mma8451_attr_group = { ++ .attrs = mma8451_attributes, ++}; ++ ++static int mma8451_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ int result, client_id; ++ struct input_dev *idev; ++ struct i2c_adapter *adapter; ++ u32 pos; ++ struct device_node *of_node = client->dev.of_node; ++ struct regulator *vdd, *vdd_io; ++ ++ mma8451_i2c_client = client; ++ ++ vdd = devm_regulator_get(&client->dev, "vdd"); ++ if (!IS_ERR(vdd)) { ++ result = regulator_enable(vdd); ++ if (result) { ++ dev_err(&client->dev, "vdd set voltage error\n"); ++ return result; ++ } ++ } ++ ++ vdd_io = devm_regulator_get(&client->dev, "vddio"); ++ if (!IS_ERR(vdd_io)) { ++ result = regulator_enable(vdd_io); ++ if (result) { ++ dev_err(&client->dev, "vddio set voltage error\n"); ++ return result; ++ } ++ } ++ ++ adapter = to_i2c_adapter(client->dev.parent); ++ result = i2c_check_functionality(adapter, ++ I2C_FUNC_SMBUS_BYTE | ++ I2C_FUNC_SMBUS_BYTE_DATA); ++ if (!result) ++ goto err_out; ++ ++ client_id = i2c_smbus_read_byte_data(client, MMA8451_WHO_AM_I); ++ if (client_id != MMA8451_ID && client_id != MMA8452_ID ++ && client_id != MMA8453_ID) { ++ dev_err(&client->dev, ++ "read chip ID 0x%x is not equal to 0x%x or 0x%x!\n", ++ result, MMA8451_ID, MMA8452_ID); ++ result = -EINVAL; ++ goto err_out; ++ } ++ ++ /* Initialize the MMA8451 chip */ ++ result = mma8451_change_mode(client, senstive_mode); ++ if (result) { ++ dev_err(&client->dev, ++ "error when init mma8451 chip:(%d)\n", result); ++ goto err_out; ++ } ++ ++ hwmon_dev = hwmon_device_register(&client->dev); ++ if (!hwmon_dev) { ++ result = -ENOMEM; ++ dev_err(&client->dev, "error when register hwmon device\n"); ++ goto err_out; ++ } ++ ++ mma8451_idev = input_allocate_polled_device(); ++ if (!mma8451_idev) { ++ result = -ENOMEM; ++ dev_err(&client->dev, "alloc poll device failed!\n"); ++ goto err_alloc_poll_device; ++ } ++ mma8451_idev->poll = mma8451_dev_poll; ++ mma8451_idev->poll_interval = POLL_INTERVAL; ++ mma8451_idev->poll_interval_min = POLL_INTERVAL_MIN; ++ mma8451_idev->poll_interval_max = POLL_INTERVAL_MAX; ++ idev = mma8451_idev->input; ++ idev->name = "mma845x"; ++ idev->id.bustype = BUS_I2C; ++ idev->evbit[0] = BIT_MASK(EV_ABS); ++ ++ input_set_abs_params(idev, ABS_X, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); ++ input_set_abs_params(idev, ABS_Y, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); ++ input_set_abs_params(idev, ABS_Z, -8192, 8191, INPUT_FUZZ, INPUT_FLAT); ++ ++ result = input_register_polled_device(mma8451_idev); ++ if (result) { ++ dev_err(&client->dev, "register poll device failed!\n"); ++ goto err_register_polled_device; ++ } ++ result = sysfs_create_group(&idev->dev.kobj, &mma8451_attr_group); ++ if (result) { ++ dev_err(&client->dev, "create device file failed!\n"); ++ result = -EINVAL; ++ goto err_register_polled_device; ++ } ++ ++ result = of_property_read_u32(of_node, "position", &pos); ++ if (result) ++ pos = DEFAULT_POSITION; ++ mma_status.position = (int)pos; ++ ++ return 0; ++err_register_polled_device: ++ input_free_polled_device(mma8451_idev); ++err_alloc_poll_device: ++ hwmon_device_unregister(&client->dev); ++err_out: ++ return result; ++} ++ ++static int mma8451_stop_chip(struct i2c_client *client) ++{ ++ int ret = 0; ++ if (mma_status.active == MMA_ACTIVED) { ++ mma_status.ctl_reg1 = i2c_smbus_read_byte_data(client, ++ MMA8451_CTRL_REG1); ++ ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, ++ mma_status.ctl_reg1 & 0xFE); ++ } ++ return ret; ++} ++ ++static int mma8451_remove(struct i2c_client *client) ++{ ++ int ret; ++ ret = mma8451_stop_chip(client); ++ hwmon_device_unregister(hwmon_dev); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int mma8451_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ return mma8451_stop_chip(client); ++} ++ ++static int mma8451_resume(struct device *dev) ++{ ++ int ret = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ if (mma_status.active == MMA_ACTIVED) ++ ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, ++ mma_status.ctl_reg1); ++ return ret; ++ ++} ++#endif ++ ++static const struct i2c_device_id mma8451_id[] = { ++ {"mma8451", 0}, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, mma8451_id); ++ ++static SIMPLE_DEV_PM_OPS(mma8451_pm_ops, mma8451_suspend, mma8451_resume); ++static struct i2c_driver mma8451_driver = { ++ .driver = { ++ .name = "mma8451", ++ .owner = THIS_MODULE, ++ .pm = &mma8451_pm_ops, ++ }, ++ .probe = mma8451_probe, ++ .remove = mma8451_remove, ++ .id_table = mma8451_id, ++}; ++ ++static int __init mma8451_init(void) ++{ ++ /* register driver */ ++ int res; ++ ++ res = i2c_add_driver(&mma8451_driver); ++ if (res < 0) { ++ printk(KERN_INFO "add mma8451 i2c driver failed\n"); ++ return -ENODEV; ++ } ++ return res; ++} ++ ++static void __exit mma8451_exit(void) ++{ ++ i2c_del_driver(&mma8451_driver); ++} ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("MMA8451 3-Axis Orientation/Motion Detection Sensor driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(mma8451_init); ++module_exit(mma8451_exit); +diff -Nur linux-3.10.30/drivers/i2c/busses/i2c-davinci.c linux-3.10.30-cubox-i/drivers/i2c/busses/i2c-davinci.c +--- linux-3.10.30/drivers/i2c/busses/i2c-davinci.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/i2c/busses/i2c-davinci.c 2014-03-08 20:33:36.000000000 +0100 +@@ -646,13 +646,6 @@ + struct resource *mem, *irq; + int r; + +- /* NOTE: driver uses the static register mapping */ +- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!mem) { +- dev_err(&pdev->dev, "no mem resource?\n"); +- return -ENODEV; +- } +- + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) { + dev_err(&pdev->dev, "no irq resource?\n"); +@@ -697,6 +690,7 @@ + return -ENODEV; + clk_prepare_enable(dev->clk); + ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dev->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(dev->base)) { + r = PTR_ERR(dev->base); +diff -Nur linux-3.10.30/drivers/i2c/busses/i2c-designware-platdrv.c linux-3.10.30-cubox-i/drivers/i2c/busses/i2c-designware-platdrv.c +--- linux-3.10.30/drivers/i2c/busses/i2c-designware-platdrv.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/i2c/busses/i2c-designware-platdrv.c 2014-03-08 20:33:36.000000000 +0100 +@@ -87,13 +87,6 @@ + struct resource *mem; + int irq, r; + +- /* NOTE: driver uses the static register mapping */ +- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!mem) { +- dev_err(&pdev->dev, "no mem resource?\n"); +- return -EINVAL; +- } +- + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq resource?\n"); +@@ -104,6 +97,7 @@ + if (!dev) + return -ENOMEM; + ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dev->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(dev->base)) + return PTR_ERR(dev->base); +diff -Nur linux-3.10.30/drivers/i2c/busses/i2c-imx.c linux-3.10.30-cubox-i/drivers/i2c/busses/i2c-imx.c +--- linux-3.10.30/drivers/i2c/busses/i2c-imx.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/i2c/busses/i2c-imx.c 2014-03-08 20:33:36.000000000 +0100 +@@ -51,7 +51,6 @@ + #include + #include + #include +-#include + #include + + /** Defines ******************************************************************** +@@ -97,7 +96,7 @@ + * Duplicated divider values removed from list + */ + +-static u16 __initdata i2c_clk_div[50][2] = { ++static u16 i2c_clk_div[50][2] = { + { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, + { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, + { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, +@@ -128,6 +127,9 @@ + int stopped; + unsigned int ifdr; /* IMX_I2C_IFDR */ + enum imx_i2c_type devtype; ++ ++ unsigned int cur_clk; ++ unsigned int bitrate; + }; + + static struct platform_device_id imx_i2c_devtype[] = { +@@ -148,6 +150,7 @@ + { .compatible = "fsl,imx21-i2c", .data = &imx_i2c_devtype[IMX21_I2C], }, + { /* sentinel */ } + }; ++MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids); + + static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx) + { +@@ -205,6 +208,49 @@ + return 0; + } + ++static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) ++{ ++ unsigned int i2c_clk_rate; ++ unsigned int div; ++ int i; ++ ++ /* Divider value calculation */ ++ i2c_clk_rate = clk_get_rate(i2c_imx->clk); ++ if (i2c_imx->cur_clk == i2c_clk_rate) ++ return; ++ else ++ i2c_imx->cur_clk = i2c_clk_rate; ++ ++ div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate; ++ if (div < i2c_clk_div[0][0]) ++ i = 0; ++ else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0]) ++ i = ARRAY_SIZE(i2c_clk_div) - 1; ++ else ++ for (i = 0; i2c_clk_div[i][0] < div; i++) ++ ; ++ ++ /* Store divider value */ ++ i2c_imx->ifdr = i2c_clk_div[i][1]; ++ ++ /* ++ * There dummy delay is calculated. ++ * It should be about one I2C clock period long. ++ * This delay is used in I2C bus disable function ++ * to fix chip hardware bug. ++ */ ++ i2c_imx->disable_delay = (500000U * i2c_clk_div[i][0] ++ + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2); ++ ++ /* dev_dbg() can't be used, because adapter is not yet registered */ ++#ifdef CONFIG_I2C_DEBUG_BUS ++ dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n", ++ __func__, i2c_clk_rate, div); ++ dev_dbg(&i2c_imx->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n", ++ __func__, i2c_clk_div[i][1], i2c_clk_div[i][0]); ++#endif ++} ++ + static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) + { + unsigned int temp = 0; +@@ -212,6 +258,7 @@ + + dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); + ++ i2c_imx_set_clk(i2c_imx); + clk_prepare_enable(i2c_imx->clk); + writeb(i2c_imx->ifdr, i2c_imx->base + IMX_I2C_IFDR); + /* Enable I2C controller */ +@@ -264,44 +311,6 @@ + clk_disable_unprepare(i2c_imx->clk); + } + +-static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, +- unsigned int rate) +-{ +- unsigned int i2c_clk_rate; +- unsigned int div; +- int i; +- +- /* Divider value calculation */ +- i2c_clk_rate = clk_get_rate(i2c_imx->clk); +- div = (i2c_clk_rate + rate - 1) / rate; +- if (div < i2c_clk_div[0][0]) +- i = 0; +- else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0]) +- i = ARRAY_SIZE(i2c_clk_div) - 1; +- else +- for (i = 0; i2c_clk_div[i][0] < div; i++); +- +- /* Store divider value */ +- i2c_imx->ifdr = i2c_clk_div[i][1]; +- +- /* +- * There dummy delay is calculated. +- * It should be about one I2C clock period long. +- * This delay is used in I2C bus disable function +- * to fix chip hardware bug. +- */ +- i2c_imx->disable_delay = (500000U * i2c_clk_div[i][0] +- + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2); +- +- /* dev_dbg() can't be used, because adapter is not yet registered */ +-#ifdef CONFIG_I2C_DEBUG_BUS +- dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n", +- __func__, i2c_clk_rate, div); +- dev_dbg(&i2c_imx->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n", +- __func__, i2c_clk_div[i][1], i2c_clk_div[i][0]); +-#endif +-} +- + static irqreturn_t i2c_imx_isr(int irq, void *dev_id) + { + struct imx_i2c_struct *i2c_imx = dev_id; +@@ -493,24 +502,18 @@ + struct imx_i2c_struct *i2c_imx; + struct resource *res; + struct imxi2c_platform_data *pdata = pdev->dev.platform_data; +- struct pinctrl *pinctrl; + void __iomem *base; + int irq, ret; +- u32 bitrate; + + dev_dbg(&pdev->dev, "<%s>\n", __func__); + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!res) { +- dev_err(&pdev->dev, "can't get device resources\n"); +- return -ENOENT; +- } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "can't get irq number\n"); + return -ENOENT; + } + ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); +@@ -535,12 +538,6 @@ + i2c_imx->adapter.dev.of_node = pdev->dev.of_node; + i2c_imx->base = base; + +- pinctrl = devm_pinctrl_get_select_default(&pdev->dev); +- if (IS_ERR(pinctrl)) { +- dev_err(&pdev->dev, "can't get/select pinctrl\n"); +- return PTR_ERR(pinctrl); +- } +- + /* Get I2C clock */ + i2c_imx->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c_imx->clk)) { +@@ -548,6 +545,11 @@ + return PTR_ERR(i2c_imx->clk); + } + ++ ret = clk_prepare_enable(i2c_imx->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "can't enable I2C clock\n"); ++ return ret; ++ } + /* Request IRQ */ + ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0, + pdev->name, i2c_imx); +@@ -563,12 +565,12 @@ + i2c_set_adapdata(&i2c_imx->adapter, i2c_imx); + + /* Set up clock divider */ +- bitrate = IMX_I2C_BIT_RATE; ++ i2c_imx->bitrate = IMX_I2C_BIT_RATE; + ret = of_property_read_u32(pdev->dev.of_node, +- "clock-frequency", &bitrate); ++ "clock-frequency", &i2c_imx->bitrate); + if (ret < 0 && pdata && pdata->bitrate) +- bitrate = pdata->bitrate; +- i2c_imx_set_clk(i2c_imx, bitrate); ++ i2c_imx->bitrate = pdata->bitrate; ++ i2c_imx_set_clk(i2c_imx); + + /* Set up chip registers to defaults */ + writeb(0, i2c_imx->base + IMX_I2C_I2CR); +@@ -585,6 +587,7 @@ + + /* Set up platform driver data */ + platform_set_drvdata(pdev, i2c_imx); ++ clk_disable_unprepare(i2c_imx->clk); + + dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq); + dev_dbg(&i2c_imx->adapter.dev, "device resources from 0x%x to 0x%x\n", +diff -Nur linux-3.10.30/drivers/i2c/busses/i2c-omap.c linux-3.10.30-cubox-i/drivers/i2c/busses/i2c-omap.c +--- linux-3.10.30/drivers/i2c/busses/i2c-omap.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/i2c/busses/i2c-omap.c 2014-03-08 20:33:36.000000000 +0100 +@@ -1087,13 +1087,6 @@ + u32 rev; + u16 minor, major, scheme; + +- /* NOTE: driver uses the static register mapping */ +- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!mem) { +- dev_err(&pdev->dev, "no mem resource?\n"); +- return -ENODEV; +- } +- + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq resource?\n"); +@@ -1106,6 +1099,7 @@ + return -ENOMEM; + } + ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dev->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(dev->base)) + return PTR_ERR(dev->base); +diff -Nur linux-3.10.30/drivers/i2c/busses/i2c-rcar.c linux-3.10.30-cubox-i/drivers/i2c/busses/i2c-rcar.c +--- linux-3.10.30/drivers/i2c/busses/i2c-rcar.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/i2c/busses/i2c-rcar.c 2014-03-08 20:33:37.000000000 +0100 +@@ -623,12 +623,6 @@ + u32 bus_speed; + int ret; + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!res) { +- dev_err(dev, "no mmio resources\n"); +- return -ENODEV; +- } +- + priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL); + if (!priv) { + dev_err(dev, "no mem for private data\n"); +@@ -642,6 +636,7 @@ + if (ret < 0) + return ret; + ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->io = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->io)) + return PTR_ERR(priv->io); +diff -Nur linux-3.10.30/drivers/input/keyboard/gpio_keys.c linux-3.10.30-cubox-i/drivers/input/keyboard/gpio_keys.c +--- linux-3.10.30/drivers/input/keyboard/gpio_keys.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/input/keyboard/gpio_keys.c 2014-03-08 20:33:39.000000000 +0100 +@@ -3,6 +3,7 @@ + * + * Copyright 2005 Phil Blundell + * Copyright 2010, 2011 David Jander ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -472,6 +473,8 @@ + + isr = gpio_keys_gpio_isr; + irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; ++ if (bdata->button->wakeup) ++ irqflags |= IRQF_NO_SUSPEND; + + } else { + if (!button->irq) { +diff -Nur linux-3.10.30/drivers/input/keyboard/imx_keypad.c linux-3.10.30-cubox-i/drivers/input/keyboard/imx_keypad.c +--- linux-3.10.30/drivers/input/keyboard/imx_keypad.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/input/keyboard/imx_keypad.c 2014-03-08 20:33:39.000000000 +0100 +@@ -1,6 +1,7 @@ + /* + * Driver for the IMX keypad port. + * Copyright (C) 2009 Alberto Panizzo ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -553,6 +554,8 @@ + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(kbd->irq); ++ else ++ pinctrl_pm_select_sleep_state(dev); + + return 0; + } +@@ -566,6 +569,8 @@ + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(kbd->irq); ++ else ++ pinctrl_pm_select_default_state(dev); + + mutex_lock(&input_dev->mutex); + +diff -Nur linux-3.10.30/drivers/input/misc/Kconfig linux-3.10.30-cubox-i/drivers/input/misc/Kconfig +--- linux-3.10.30/drivers/input/misc/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/input/misc/Kconfig 2014-03-08 20:33:39.000000000 +0100 +@@ -637,4 +637,14 @@ + To compile this driver as a module, choose M here: the + module will be called xen-kbdfront. + ++config INPUT_ISL29023 ++ tristate "Intersil ISL29023 ambient light sensor" ++ depends on I2C && SYSFS ++ help ++ If you say yes here you get support for the Intersil ISL29023 ++ ambient light sensor. ++ ++ This driver can also be built as a module. If so, the module ++ will be called isl29023. ++ + endif +diff -Nur linux-3.10.30/drivers/input/misc/Makefile linux-3.10.30-cubox-i/drivers/input/misc/Makefile +--- linux-3.10.30/drivers/input/misc/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/input/misc/Makefile 2014-03-08 20:33:39.000000000 +0100 +@@ -60,3 +60,4 @@ + obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o + obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o + obj-$(CONFIG_INPUT_YEALINK) += yealink.o ++obj-$(CONFIG_INPUT_ISL29023) += isl29023.o +diff -Nur linux-3.10.30/drivers/input/misc/isl29023.c linux-3.10.30-cubox-i/drivers/input/misc/isl29023.c +--- linux-3.10.30/drivers/input/misc/isl29023.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/input/misc/isl29023.c 2014-03-08 20:33:39.000000000 +0100 +@@ -0,0 +1,1029 @@ ++/* ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ISL29023_DRV_NAME "isl29023" ++#define DRIVER_VERSION "1.0" ++ ++#define ISL29023_COMMAND1 0x00 ++#define ISL29023_MODE_SHIFT (5) ++#define ISL29023_MODE_MASK (0x7 << ISL29023_MODE_SHIFT) ++#define ISL29023_INT_FLAG_SHIFT (2) ++#define ISL29023_INT_FLAG_MASK (0x1 << ISL29023_INT_FLAG_SHIFT) ++#define ISL29023_INT_PERSISTS_SHIFT (0) ++#define ISL29023_INT_PERSISTS_MASK (0x3 << ISL29023_INT_PERSISTS_SHIFT) ++ ++#define ISL29023_COMMAND2 0x01 ++#define ISL29023_RES_SHIFT (2) ++#define ISL29023_RES_MASK (0x3 << ISL29023_RES_SHIFT) ++#define ISL29023_RANGE_SHIFT (0) ++#define ISL29023_RANGE_MASK (0x3 << ISL29023_RANGE_SHIFT) ++ ++#define ISL29023_REG_LSB_SENSOR 0x02 ++#define ISL29023_REG_MSB_SENSOR 0x03 ++#define ISL29023_REG_IRQ_TH_LO_LSB 0x04 ++#define ISL29023_REG_IRQ_TH_LO_MSB 0x05 ++#define ISL29023_REG_IRQ_TH_HI_LSB 0x06 ++#define ISL29023_REG_IRQ_TH_HI_MSB 0x07 ++ ++#define ISL29023_NUM_CACHABLE_REGS 8 ++#define DEF_RANGE 2 ++#define DEFAULT_REGISTOR_VAL 499 ++ ++struct isl29023_data { ++ struct i2c_client *client; ++ struct mutex lock; ++ struct input_dev *input; ++ struct work_struct work; ++ struct workqueue_struct *workqueue; ++ char phys[32]; ++ u8 reg_cache[ISL29023_NUM_CACHABLE_REGS]; ++ u8 mode_before_suspend; ++ u8 mode_before_interrupt; ++ u16 rext; ++}; ++ ++static int gain_range[] = { ++ 1000, 4000, 16000, 64000 ++}; ++ ++/* ++ * register access helpers ++ */ ++static int __isl29023_read_reg(struct i2c_client *client, ++ u32 reg, u8 mask, u8 shift) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ return (data->reg_cache[reg] & mask) >> shift; ++} ++ ++static int __isl29023_write_reg(struct i2c_client *client, ++ u32 reg, u8 mask, u8 shift, u8 val) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int ret = 0; ++ u8 tmp; ++ ++ if (reg >= ISL29023_NUM_CACHABLE_REGS) ++ return -EINVAL; ++ ++ mutex_lock(&data->lock); ++ ++ tmp = data->reg_cache[reg]; ++ tmp &= ~mask; ++ tmp |= val << shift; ++ ++ ret = i2c_smbus_write_byte_data(client, reg, tmp); ++ if (!ret) ++ data->reg_cache[reg] = tmp; ++ ++ mutex_unlock(&data->lock); ++ return ret; ++} ++ ++/* ++ * internally used functions ++ */ ++ ++/* interrupt persists */ ++static int isl29023_get_int_persists(struct i2c_client *client) ++{ ++ return __isl29023_read_reg(client, ISL29023_COMMAND1, ++ ISL29023_INT_PERSISTS_MASK, ISL29023_INT_PERSISTS_SHIFT); ++} ++ ++static int isl29023_set_int_persists(struct i2c_client *client, ++ int int_persists) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND1, ++ ISL29023_INT_PERSISTS_MASK, ISL29023_INT_PERSISTS_SHIFT, ++ int_persists); ++} ++ ++/* interrupt flag */ ++static int isl29023_get_int_flag(struct i2c_client *client) ++{ ++ return __isl29023_read_reg(client, ISL29023_COMMAND1, ++ ISL29023_INT_FLAG_MASK, ISL29023_INT_FLAG_SHIFT); ++} ++ ++static int isl29023_set_int_flag(struct i2c_client *client, int flag) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND1, ++ ISL29023_INT_FLAG_MASK, ISL29023_INT_FLAG_SHIFT, flag); ++} ++ ++/* interrupt lt */ ++static int isl29023_get_int_lt(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int lsb, msb, lt; ++ ++ mutex_lock(&data->lock); ++ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB); ++ ++ if (lsb < 0) { ++ mutex_unlock(&data->lock); ++ return lsb; ++ } ++ ++ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB); ++ mutex_unlock(&data->lock); ++ ++ if (msb < 0) ++ return msb; ++ ++ lt = ((msb << 8) | lsb); ++ ++ return lt; ++} ++ ++static int isl29023_set_int_lt(struct i2c_client *client, int lt) ++{ ++ int ret = 0; ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ ++ mutex_lock(&data->lock); ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB, ++ lt & 0xff); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB, ++ (lt >> 8) & 0xff); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ data->reg_cache[ISL29023_REG_IRQ_TH_LO_MSB] = (lt >> 8) & 0xff; ++ data->reg_cache[ISL29023_REG_IRQ_TH_LO_LSB] = lt & 0xff; ++ mutex_unlock(&data->lock); ++ ++ return ret; ++} ++ ++/* interrupt ht */ ++static int isl29023_get_int_ht(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int lsb, msb, ht; ++ ++ mutex_lock(&data->lock); ++ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB); ++ ++ if (lsb < 0) { ++ mutex_unlock(&data->lock); ++ return lsb; ++ } ++ ++ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB); ++ mutex_unlock(&data->lock); ++ ++ if (msb < 0) ++ return msb; ++ ++ ht = ((msb << 8) | lsb); ++ ++ return ht; ++} ++ ++static int isl29023_set_int_ht(struct i2c_client *client, int ht) ++{ ++ int ret = 0; ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ ++ mutex_lock(&data->lock); ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB, ++ ht & 0xff); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB, ++ (ht >> 8) & 0xff); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ data->reg_cache[ISL29023_REG_IRQ_TH_HI_MSB] = (ht >> 8) & 0xff; ++ data->reg_cache[ISL29023_REG_IRQ_TH_HI_LSB] = ht & 0xff; ++ mutex_unlock(&data->lock); ++ ++ return ret; ++} ++ ++/* range */ ++static int isl29023_get_range(struct i2c_client *client) ++{ ++ return __isl29023_read_reg(client, ISL29023_COMMAND2, ++ ISL29023_RANGE_MASK, ISL29023_RANGE_SHIFT); ++} ++ ++static int isl29023_set_range(struct i2c_client *client, int range) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND2, ++ ISL29023_RANGE_MASK, ISL29023_RANGE_SHIFT, range); ++} ++ ++/* resolution */ ++static int isl29023_get_resolution(struct i2c_client *client) ++{ ++ return __isl29023_read_reg(client, ISL29023_COMMAND2, ++ ISL29023_RES_MASK, ISL29023_RES_SHIFT); ++} ++ ++static int isl29023_set_resolution(struct i2c_client *client, int res) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND2, ++ ISL29023_RES_MASK, ISL29023_RES_SHIFT, res); ++} ++ ++/* mode */ ++static int isl29023_get_mode(struct i2c_client *client) ++{ ++ return __isl29023_read_reg(client, ISL29023_COMMAND1, ++ ISL29023_MODE_MASK, ISL29023_MODE_SHIFT); ++} ++ ++static int isl29023_set_mode(struct i2c_client *client, int mode) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND1, ++ ISL29023_MODE_MASK, ISL29023_MODE_SHIFT, mode); ++} ++ ++/* power_state */ ++static int isl29023_set_power_state(struct i2c_client *client, int state) ++{ ++ return __isl29023_write_reg(client, ISL29023_COMMAND1, ++ ISL29023_MODE_MASK, ISL29023_MODE_SHIFT, ++ state ? ++ ISL29023_ALS_ONCE_MODE : ISL29023_PD_MODE); ++} ++ ++static int isl29023_get_power_state(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ u8 cmdreg = data->reg_cache[ISL29023_COMMAND1]; ++ ++ if (cmdreg & ISL29023_MODE_MASK) ++ return 1; ++ else ++ return 0; ++} ++ ++static int isl29023_get_adc_value(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int lsb, msb, range, bitdepth; ++ ++ mutex_lock(&data->lock); ++ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_LSB_SENSOR); ++ ++ if (lsb < 0) { ++ mutex_unlock(&data->lock); ++ return lsb; ++ } ++ ++ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_MSB_SENSOR); ++ mutex_unlock(&data->lock); ++ ++ if (msb < 0) ++ return msb; ++ ++ range = isl29023_get_range(client); ++ bitdepth = (4 - isl29023_get_resolution(client)) * 4; ++ return (((msb << 8) | lsb) * ((gain_range[range] * 499) / data->rext)) ++ >> bitdepth; ++} ++ ++static int isl29023_get_int_lt_value(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int lsb, msb, range, bitdepth; ++ ++ mutex_lock(&data->lock); ++ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB); ++ ++ if (lsb < 0) { ++ mutex_unlock(&data->lock); ++ return lsb; ++ } ++ ++ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB); ++ mutex_unlock(&data->lock); ++ ++ if (msb < 0) ++ return msb; ++ ++ range = isl29023_get_range(client); ++ bitdepth = (4 - isl29023_get_resolution(client)) * 4; ++ return (((msb << 8) | lsb) * ((gain_range[range] * 499) / data->rext)) ++ >> bitdepth; ++} ++ ++static int isl29023_get_int_ht_value(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int lsb, msb, range, bitdepth; ++ ++ mutex_lock(&data->lock); ++ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB); ++ ++ if (lsb < 0) { ++ mutex_unlock(&data->lock); ++ return lsb; ++ } ++ ++ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB); ++ mutex_unlock(&data->lock); ++ ++ if (msb < 0) ++ return msb; ++ ++ range = isl29023_get_range(client); ++ bitdepth = (4 - isl29023_get_resolution(client)) * 4; ++ return (((msb << 8) | lsb) * ((gain_range[range] * 499) / data->rext)) ++ >> bitdepth; ++} ++ ++/* ++ * sysfs layer ++ */ ++ ++/* interrupt persists */ ++static ssize_t isl29023_show_int_persists(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%i\n", isl29023_get_int_persists(client)); ++} ++ ++static ssize_t isl29023_store_int_persists(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || ++ (val > ISL29023_INT_PERSISTS_16)) ++ return -EINVAL; ++ ++ ret = isl29023_set_int_persists(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_persists, S_IWUSR | S_IRUGO, ++ isl29023_show_int_persists, isl29023_store_int_persists); ++ ++/* interrupt flag */ ++static ssize_t isl29023_show_int_flag(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%i\n", isl29023_get_int_flag(client)); ++} ++ ++static ssize_t isl29023_store_int_flag(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || (val > 1)) ++ return -EINVAL; ++ ++ ret = isl29023_set_int_flag(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_flag, S_IWUSR | S_IRUGO, ++ isl29023_show_int_flag, isl29023_store_int_flag); ++ ++/* interrupt lt */ ++static ssize_t isl29023_show_int_lt(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%i\n", isl29023_get_int_lt(client)); ++} ++ ++static ssize_t isl29023_store_int_lt(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 16, &val) < 0) || (val > 0xffff)) ++ return -EINVAL; ++ ++ ret = isl29023_set_int_lt(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_lt, S_IWUSR | S_IRUGO, ++ isl29023_show_int_lt, isl29023_store_int_lt); ++ ++/* interrupt ht */ ++static ssize_t isl29023_show_int_ht(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%i\n", isl29023_get_int_ht(client)); ++} ++ ++static ssize_t isl29023_store_int_ht(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 16, &val) < 0) || (val > 0xffff)) ++ return -EINVAL; ++ ++ ret = isl29023_set_int_ht(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_ht, S_IWUSR | S_IRUGO, ++ isl29023_show_int_ht, isl29023_store_int_ht); ++ ++/* range */ ++static ssize_t isl29023_show_range(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%i\n", isl29023_get_range(client)); ++} ++ ++static ssize_t isl29023_store_range(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || (val > ISL29023_RANGE_64K)) ++ return -EINVAL; ++ ++ ret = isl29023_set_range(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(range, S_IWUSR | S_IRUGO, ++ isl29023_show_range, isl29023_store_range); ++ ++ ++/* resolution */ ++static ssize_t isl29023_show_resolution(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%d\n", isl29023_get_resolution(client)); ++} ++ ++static ssize_t isl29023_store_resolution(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || (val > ISL29023_RES_4)) ++ return -EINVAL; ++ ++ ret = isl29023_set_resolution(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(resolution, S_IWUSR | S_IRUGO, ++ isl29023_show_resolution, isl29023_store_resolution); ++ ++/* mode */ ++static ssize_t isl29023_show_mode(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%d\n", isl29023_get_mode(client)); ++} ++ ++static ssize_t isl29023_store_mode(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || ++ (val > ISL29023_IR_CONT_MODE)) ++ return -EINVAL; ++ ++ ret = isl29023_set_mode(client, val); ++ if (ret < 0) ++ return ret; ++ ++ return count; ++} ++ ++static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, ++ isl29023_show_mode, isl29023_store_mode); ++ ++ ++/* power state */ ++static ssize_t isl29023_show_power_state(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ return sprintf(buf, "%d\n", isl29023_get_power_state(client)); ++} ++ ++static ssize_t isl29023_store_power_state(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned long val; ++ int ret; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0) || (val > 1)) ++ return -EINVAL; ++ ++ ret = isl29023_set_power_state(client, val); ++ return ret ? ret : count; ++} ++ ++static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO, ++ isl29023_show_power_state, isl29023_store_power_state); ++ ++/* lux */ ++static ssize_t isl29023_show_lux(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ /* No LUX data if not operational */ ++ if (!isl29023_get_power_state(client)) ++ return -EBUSY; ++ ++ return sprintf(buf, "%d\n", isl29023_get_adc_value(client)); ++} ++ ++static DEVICE_ATTR(lux, S_IRUGO, isl29023_show_lux, NULL); ++ ++/* lux interrupt low threshold */ ++static ssize_t isl29023_show_int_lt_lux(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ /* No LUX data if not operational */ ++ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE && ++ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE) ++ return -EIO; ++ ++ return sprintf(buf, "%d\n", isl29023_get_int_lt_value(client)); ++} ++ ++static ssize_t isl29023_store_int_lt_lux(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ unsigned long val, lux_data; ++ int range, bitdepth, ret; ++ u8 lsb, msb; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0)) ++ return -EINVAL; ++ ++ /* No LUX data if not operational */ ++ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE && ++ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE) ++ return -EIO; ++ ++ if (val > (gain_range[isl29023_get_range(client)]*499/data->rext)) ++ return -EINVAL; ++ ++ range = isl29023_get_range(client); ++ bitdepth = (4 - isl29023_get_resolution(client)) * 4; ++ lux_data = ((unsigned long)(val << bitdepth)) / ++ ((gain_range[range] * 499) / data->rext); ++ lux_data &= 0xffff; ++ ++ msb = lux_data >> 8; ++ lsb = lux_data & 0xff; ++ ++ mutex_lock(&data->lock); ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB, ++ lsb); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB, ++ msb); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ data->reg_cache[ISL29023_REG_IRQ_TH_LO_MSB] = msb; ++ data->reg_cache[ISL29023_REG_IRQ_TH_LO_LSB] = lsb; ++ mutex_unlock(&data->lock); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_lt_lux, S_IWUSR | S_IRUGO, ++ isl29023_show_int_lt_lux, isl29023_store_int_lt_lux); ++ ++/* lux interrupt high threshold */ ++static ssize_t isl29023_show_int_ht_lux(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ /* No LUX data if not operational */ ++ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE && ++ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE) ++ return -EIO; ++ ++ return sprintf(buf, "%d\n", isl29023_get_int_ht_value(client)); ++} ++ ++static ssize_t isl29023_store_int_ht_lux(struct device *dev, ++ struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ unsigned long val, lux_data; ++ int range, bitdepth, ret; ++ u8 lsb, msb; ++ ++ if ((strict_strtoul(buf, 10, &val) < 0)) ++ return -EINVAL; ++ ++ /* No LUX data if not operational */ ++ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE && ++ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE) ++ return -EIO; ++ ++ if (val > (gain_range[isl29023_get_range(client)]*499/data->rext)) ++ return -EINVAL; ++ ++ range = isl29023_get_range(client); ++ bitdepth = (4 - isl29023_get_resolution(client)) * 4; ++ lux_data = ((unsigned long)(val << bitdepth)) / ++ ((gain_range[range] * 499) / data->rext); ++ lux_data &= 0xffff; ++ ++ msb = lux_data >> 8; ++ lsb = lux_data & 0xff; ++ ++ mutex_lock(&data->lock); ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB, ++ lsb); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB, ++ msb); ++ if (ret < 0) { ++ mutex_unlock(&data->lock); ++ return ret; ++ } ++ ++ data->reg_cache[ISL29023_REG_IRQ_TH_HI_MSB] = msb; ++ data->reg_cache[ISL29023_REG_IRQ_TH_HI_LSB] = lsb; ++ mutex_unlock(&data->lock); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(int_ht_lux, S_IWUSR | S_IRUGO, ++ isl29023_show_int_ht_lux, isl29023_store_int_ht_lux); ++ ++static struct attribute *isl29023_attributes[] = { ++ &dev_attr_int_persists.attr, ++ &dev_attr_range.attr, ++ &dev_attr_resolution.attr, ++ &dev_attr_mode.attr, ++ &dev_attr_power_state.attr, ++ &dev_attr_lux.attr, ++ &dev_attr_int_lt_lux.attr, ++ &dev_attr_int_ht_lux.attr, ++ &dev_attr_int_lt.attr, ++ &dev_attr_int_ht.attr, ++ &dev_attr_int_flag.attr, ++ NULL ++}; ++ ++static const struct attribute_group isl29023_attr_group = { ++ .attrs = isl29023_attributes, ++}; ++ ++static int isl29023_init_client(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ int i; ++ ++ /* read all the registers once to fill the cache. ++ * if one of the reads fails, we consider the init failed */ ++ for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) { ++ int v = i2c_smbus_read_byte_data(client, i); ++ if (v < 0) ++ return -ENODEV; ++ ++ data->reg_cache[i] = v; ++ } ++ ++ /* set defaults */ ++ isl29023_set_int_persists(client, ISL29023_INT_PERSISTS_8); ++ isl29023_set_int_ht(client, 0xffff); ++ isl29023_set_int_lt(client, 0x0); ++ isl29023_set_range(client, ISL29023_RANGE_16K); ++ isl29023_set_resolution(client, ISL29023_RES_16); ++ isl29023_set_mode(client, ISL29023_ALS_ONCE_MODE); ++ isl29023_set_int_flag(client, 0); ++ isl29023_set_power_state(client, 0); ++ ++ return 0; ++} ++ ++static void isl29023_work(struct work_struct *work) ++{ ++ struct isl29023_data *data = ++ container_of(work, struct isl29023_data, work); ++ struct i2c_client *client = data->client; ++ int lux; ++ ++ /* Clear interrupt flag */ ++ isl29023_set_int_flag(client, 0); ++ ++ data->mode_before_interrupt = isl29023_get_mode(client); ++ lux = isl29023_get_adc_value(client); ++ ++ /* To clear the interrpt status */ ++ isl29023_set_power_state(client, ISL29023_PD_MODE); ++ isl29023_set_mode(client, data->mode_before_interrupt); ++ ++ msleep(100); ++ ++ input_report_abs(data->input, ABS_MISC, lux); ++ input_sync(data->input); ++} ++ ++static irqreturn_t isl29023_irq_handler(int irq, void *handle) ++{ ++ struct isl29023_data *data = handle; ++ queue_work(data->workqueue, &data->work); ++ return IRQ_HANDLED; ++} ++ ++/* ++ * I2C layer ++ */ ++ ++static int isl29023_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); ++ struct isl29023_data *data; ++ struct input_dev *input_dev; ++ int err = 0; ++ struct regulator *vdd = NULL; ++ u32 rext = 0; ++ struct device_node *of_node = client->dev.of_node; ++ ++ vdd = devm_regulator_get(&client->dev, "vdd"); ++ if (!IS_ERR(vdd)) { ++ err = regulator_enable(vdd); ++ if (err) { ++ dev_err(&client->dev, "vdd set voltage error\n"); ++ return err; ++ } ++ } ++ ++ err = of_property_read_u32(of_node, "rext", &rext); ++ if (err) ++ rext = DEFAULT_REGISTOR_VAL; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) ++ return -EIO; ++ ++ data = kzalloc(sizeof(struct isl29023_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->client = client; ++ data->rext = (u16)rext; ++ snprintf(data->phys, sizeof(data->phys), ++ "%s", dev_name(&client->dev)); ++ i2c_set_clientdata(client, data); ++ mutex_init(&data->lock); ++ ++ /* initialize the ISL29023 chip */ ++ err = isl29023_init_client(client); ++ if (err) ++ goto exit_kfree; ++ ++ /* register sysfs hooks */ ++ err = sysfs_create_group(&client->dev.kobj, &isl29023_attr_group); ++ if (err) ++ goto exit_kfree; ++ ++ input_dev = input_allocate_device(); ++ if (!input_dev) { ++ err = -ENOMEM; ++ goto exit_kfree; ++ } ++ ++ data->input = input_dev; ++ input_dev->name = "isl29023 light sensor"; ++ input_dev->id.bustype = BUS_I2C; ++ input_dev->phys = data->phys; ++ ++ __set_bit(EV_ABS, input_dev->evbit); ++ input_set_abs_params(input_dev, ABS_MISC, 0, ++ gain_range[DEF_RANGE]*499/data->rext, 0, 0); ++ ++ err = input_register_device(input_dev); ++ if (err) ++ goto exit_free_input; ++ ++ /* set irq type to edge falling */ ++ irq_set_irq_type(client->irq, IRQF_TRIGGER_FALLING); ++ err = request_irq(client->irq, isl29023_irq_handler, 0, ++ client->dev.driver->name, data); ++ if (err < 0) { ++ dev_err(&client->dev, "failed to register irq %d!\n", ++ client->irq); ++ goto exit_free_input; ++ } ++ ++ data->workqueue = create_singlethread_workqueue("isl29023"); ++ INIT_WORK(&data->work, isl29023_work); ++ if (data->workqueue == NULL) { ++ dev_err(&client->dev, "couldn't create workqueue\n"); ++ err = -ENOMEM; ++ goto exit_free_interrupt; ++ } ++ ++ dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION); ++ return 0; ++ ++exit_free_interrupt: ++ free_irq(client->irq, data); ++exit_free_input: ++ input_free_device(input_dev); ++exit_kfree: ++ kfree(data); ++ return err; ++} ++ ++static int isl29023_remove(struct i2c_client *client) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ ++ cancel_work_sync(&data->work); ++ destroy_workqueue(data->workqueue); ++ free_irq(client->irq, data); ++ input_unregister_device(data->input); ++ input_free_device(data->input); ++ sysfs_remove_group(&client->dev.kobj, &isl29023_attr_group); ++ isl29023_set_power_state(client, 0); ++ kfree(i2c_get_clientdata(client)); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int isl29023_suspend(struct i2c_client *client, pm_message_t mesg) ++{ ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ ++ data->mode_before_suspend = isl29023_get_mode(client); ++ return isl29023_set_power_state(client, ISL29023_PD_MODE); ++} ++ ++static int isl29023_resume(struct i2c_client *client) ++{ ++ int i; ++ struct isl29023_data *data = i2c_get_clientdata(client); ++ ++ /* restore registers from cache */ ++ for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) ++ if (i2c_smbus_write_byte_data(client, i, data->reg_cache[i])) ++ return -EIO; ++ ++ return isl29023_set_mode(client, data->mode_before_suspend); ++} ++ ++#else ++#define isl29023_suspend NULL ++#define isl29023_resume NULL ++#endif /* CONFIG_PM */ ++ ++static const struct i2c_device_id isl29023_id[] = { ++ { ISL29023_DRV_NAME, 0 }, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, isl29023_id); ++ ++static struct i2c_driver isl29023_driver = { ++ .driver = { ++ .name = ISL29023_DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .suspend = isl29023_suspend, ++ .resume = isl29023_resume, ++ .probe = isl29023_probe, ++ .remove = isl29023_remove, ++ .id_table = isl29023_id, ++}; ++ ++static int __init isl29023_init(void) ++{ ++ return i2c_add_driver(&isl29023_driver); ++} ++ ++static void __exit isl29023_exit(void) ++{ ++ i2c_del_driver(&isl29023_driver); ++} ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("ISL29023 ambient light sensor driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRIVER_VERSION); ++ ++module_init(isl29023_init); ++module_exit(isl29023_exit); +diff -Nur linux-3.10.30/drivers/input/misc/mma8450.c linux-3.10.30-cubox-i/drivers/input/misc/mma8450.c +--- linux-3.10.30/drivers/input/misc/mma8450.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/input/misc/mma8450.c 2014-03-08 20:33:39.000000000 +0100 +@@ -1,7 +1,7 @@ + /* + * Driver for Freescale's 3-Axis Accelerometer MMA8450 + * +- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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 +@@ -51,6 +51,8 @@ + + #define MMA8450_CTRL_REG1 0x38 + #define MMA8450_CTRL_REG2 0x39 ++#define MMA8450_ID 0xC6 ++#define MMA8450_WHO_AM_I 0x0F + + /* mma8450 status */ + struct mma8450 { +@@ -172,7 +174,25 @@ + { + struct input_polled_dev *idev; + struct mma8450 *m; +- int err; ++ int err, client_id; ++ struct i2c_adapter *adapter = NULL; ++ ++ adapter = to_i2c_adapter(c->dev.parent); ++ err = i2c_check_functionality(adapter, ++ I2C_FUNC_SMBUS_BYTE | ++ I2C_FUNC_SMBUS_BYTE_DATA); ++ if (!err) ++ goto err_out; ++ ++ client_id = i2c_smbus_read_byte_data(c, MMA8450_WHO_AM_I); ++ ++ if (MMA8450_ID != client_id) { ++ dev_err(&c->dev, ++ "read chip ID 0x%x is not equal to 0x%x!\n", client_id, ++ MMA8450_ID); ++ err = -EINVAL; ++ goto err_out; ++ } + + m = kzalloc(sizeof(struct mma8450), GFP_KERNEL); + idev = input_allocate_polled_device(); +@@ -209,6 +229,7 @@ + err_free_mem: + input_free_polled_device(idev); + kfree(m); ++err_out: + return err; + } + +diff -Nur linux-3.10.30/drivers/input/touchscreen/Kconfig linux-3.10.30-cubox-i/drivers/input/touchscreen/Kconfig +--- linux-3.10.30/drivers/input/touchscreen/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/input/touchscreen/Kconfig 2014-03-08 20:33:40.000000000 +0100 +@@ -235,6 +235,27 @@ + To compile this driver as a module, choose M here: the + module will be called egalax_ts. + ++config TOUCHSCREEN_EGALAX_SINGLE_TOUCH ++ bool "EETI eGalax touchscreen as single-touch" ++ default N ++ depends on TOUCHSCREEN_EGALAX ++ help ++ If you say yes here you get single-touch touchscreen support ++ on the eGalax I2C controller. ++ If you say "no", you'll get the normal multi-touch ++ ++config TOUCHSCREEN_ELAN ++ tristate "ELAN touchscreen input driver" ++ depends on I2C ++ help ++ Say Y here if you have an I2C ELAN touchscreen ++ attached. ++ ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called elan-touch. ++ + config TOUCHSCREEN_FUJITSU + tristate "Fujitsu serial touchscreen" + select SERIO +diff -Nur linux-3.10.30/drivers/input/touchscreen/Makefile linux-3.10.30-cubox-i/drivers/input/touchscreen/Makefile +--- linux-3.10.30/drivers/input/touchscreen/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/input/touchscreen/Makefile 2014-03-08 20:33:40.000000000 +0100 +@@ -27,6 +27,7 @@ + obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o + obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o + obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o ++obj-$(CONFIG_TOUCHSCREEN_ELAN) += elan_ts.o + obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o + obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o + obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o +diff -Nur linux-3.10.30/drivers/input/touchscreen/egalax_ts.c linux-3.10.30-cubox-i/drivers/input/touchscreen/egalax_ts.c +--- linux-3.10.30/drivers/input/touchscreen/egalax_ts.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/input/touchscreen/egalax_ts.c 2014-03-08 20:33:40.000000000 +0100 +@@ -1,7 +1,7 @@ + /* + * Driver for EETI eGalax Multiple Touch Controller + * +- * Copyright (C) 2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. + * + * based on max11801_ts.c + * +@@ -35,7 +35,7 @@ + * which can only report one point at a given time. + * This driver will ignore events in this mode. + */ +-#define REPORT_MODE_MOUSE 0x1 ++#define REPORT_MODE_SINGLE 0x1 + /* + * Vendor Mode: this mode is used to transfer some vendor specific + * messages. +@@ -47,6 +47,8 @@ + + #define MAX_SUPPORT_POINTS 5 + ++#define EVENT_MODE 0 ++#define EVENT_STATUS 1 + #define EVENT_VALID_OFFSET 7 + #define EVENT_VALID_MASK (0x1 << EVENT_VALID_OFFSET) + #define EVENT_ID_OFFSET 2 +@@ -56,13 +58,21 @@ + + #define MAX_I2C_DATA_LEN 10 + +-#define EGALAX_MAX_X 32760 +-#define EGALAX_MAX_Y 32760 ++#define EGALAX_MAX_X 32767 ++#define EGALAX_MAX_Y 32767 + #define EGALAX_MAX_TRIES 100 + ++struct egalax_pointer { ++ bool valid; ++ bool status; ++ u16 x; ++ u16 y; ++}; ++ + struct egalax_ts { + struct i2c_client *client; + struct input_dev *input_dev; ++ struct egalax_pointer events[MAX_SUPPORT_POINTS]; + }; + + static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id) +@@ -70,8 +80,9 @@ + struct egalax_ts *ts = dev_id; + struct input_dev *input_dev = ts->input_dev; + struct i2c_client *client = ts->client; ++ struct egalax_pointer *events = ts->events; + u8 buf[MAX_I2C_DATA_LEN]; +- int id, ret, x, y, z; ++ int i, id, ret, x, y; + int tries = 0; + bool down, valid; + u8 state; +@@ -83,15 +94,38 @@ + if (ret < 0) + return IRQ_HANDLED; + +- if (buf[0] != REPORT_MODE_MTTOUCH) { +- /* ignore mouse events and vendor events */ ++ dev_dbg(&client->dev, "recv ret:%d", ret); ++ for (i = 0; i < MAX_I2C_DATA_LEN; i++) ++ dev_dbg(&client->dev, " %x ", buf[i]); ++ ++ if (buf[0] != REPORT_MODE_VENDOR ++ && buf[0] != REPORT_MODE_SINGLE ++ && buf[0] != REPORT_MODE_MTTOUCH) { ++ /* invalid point */ ++ return IRQ_HANDLED; ++ } ++ ++ if (buf[0] == REPORT_MODE_VENDOR) { ++ dev_dbg(&client->dev, "vendor message, ignored\n"); + return IRQ_HANDLED; + } + + state = buf[1]; + x = (buf[3] << 8) | buf[2]; + y = (buf[5] << 8) | buf[4]; +- z = (buf[7] << 8) | buf[6]; ++ ++ /* Currently, the panel Freescale using on SMD board _NOT_ ++ * support single pointer mode. All event are going to ++ * multiple pointer mode. Add single pointer mode according ++ * to EETI eGalax I2C programming manual. ++ */ ++ if (buf[0] == REPORT_MODE_SINGLE) { ++ input_report_abs(input_dev, ABS_X, x); ++ input_report_abs(input_dev, ABS_Y, y); ++ input_report_key(input_dev, BTN_TOUCH, !!state); ++ input_sync(input_dev); ++ return IRQ_HANDLED; ++ } + + valid = state & EVENT_VALID_MASK; + id = (state & EVENT_ID_MASK) >> EVENT_ID_OFFSET; +@@ -102,19 +136,50 @@ + return IRQ_HANDLED; + } + +- input_mt_slot(input_dev, id); +- input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, down); +- +- dev_dbg(&client->dev, "%s id:%d x:%d y:%d z:%d", +- down ? "down" : "up", id, x, y, z); +- + if (down) { +- input_report_abs(input_dev, ABS_MT_POSITION_X, x); +- input_report_abs(input_dev, ABS_MT_POSITION_Y, y); +- input_report_abs(input_dev, ABS_MT_PRESSURE, z); ++ events[id].valid = valid; ++ events[id].status = down; ++ events[id].x = x; ++ events[id].y = y; ++ ++#ifdef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH ++ input_report_abs(input_dev, ABS_X, x); ++ input_report_abs(input_dev, ABS_Y, y); ++ input_event(ts->input_dev, EV_KEY, BTN_TOUCH, 1); ++ input_report_abs(input_dev, ABS_PRESSURE, 1); ++#endif ++ } else { ++ dev_dbg(&client->dev, "release id:%d\n", id); ++ events[id].valid = 0; ++ events[id].status = 0; ++#ifdef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH ++ input_report_key(input_dev, BTN_TOUCH, 0); ++ input_report_abs(input_dev, ABS_PRESSURE, 0); ++#else ++ input_report_abs(input_dev, ABS_MT_TRACKING_ID, id); ++ input_event(input_dev, EV_ABS, ABS_MT_TOUCH_MAJOR, 0); ++ input_mt_sync(input_dev); ++#endif + } + +- input_mt_report_pointer_emulation(input_dev, true); ++#ifndef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH ++ /* report all pointers */ ++ for (i = 0; i < MAX_SUPPORT_POINTS; i++) { ++ if (!events[i].valid) ++ continue; ++ dev_dbg(&client->dev, "report id:%d valid:%d x:%d y:%d", ++ i, valid, x, y); ++ input_report_abs(input_dev, ++ ABS_MT_TRACKING_ID, i); ++ input_report_abs(input_dev, ++ ABS_MT_TOUCH_MAJOR, 1); ++ input_report_abs(input_dev, ++ ABS_MT_POSITION_X, events[i].x); ++ input_report_abs(input_dev, ++ ABS_MT_POSITION_Y, events[i].y); ++ input_mt_sync(input_dev); ++ } ++#endif + input_sync(input_dev); + + return IRQ_HANDLED; +@@ -203,22 +268,34 @@ + goto err_free_dev; + } + +- input_dev->name = "EETI eGalax Touch Screen"; ++ input_dev->name = "eGalax Touch Screen"; ++ input_dev->phys = "I2C", + input_dev->id.bustype = BUS_I2C; ++ input_dev->id.vendor = 0x0EEF; ++ input_dev->id.product = 0x0020; ++ input_dev->id.version = 0x0001; + input_dev->dev.parent = &client->dev; + + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(BTN_TOUCH, input_dev->keybit); +- ++ __set_bit(ABS_X, input_dev->absbit); ++ __set_bit(ABS_Y, input_dev->absbit); ++ __set_bit(ABS_PRESSURE, input_dev->absbit); + input_set_abs_params(input_dev, ABS_X, 0, EGALAX_MAX_X, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, EGALAX_MAX_Y, 0, 0); +- input_set_abs_params(input_dev, +- ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0); +- input_set_abs_params(input_dev, +- ABS_MT_POSITION_Y, 0, EGALAX_MAX_Y, 0, 0); +- input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0, 0); + ++#ifndef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH ++ input_set_abs_params(input_dev, ABS_MT_POSITION_X, ++ 0, EGALAX_MAX_X, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, ++ 0, EGALAX_MAX_Y, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); ++ input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, ++ MAX_SUPPORT_POINTS, 0, 0); ++#endif + input_set_drvdata(input_dev, ts); + + error = request_threaded_irq(client->irq, NULL, egalax_ts_interrupt, +diff -Nur linux-3.10.30/drivers/input/touchscreen/elan_ts.c linux-3.10.30-cubox-i/drivers/input/touchscreen/elan_ts.c +--- linux-3.10.30/drivers/input/touchscreen/elan_ts.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/input/touchscreen/elan_ts.c 2014-03-08 20:33:40.000000000 +0100 +@@ -0,0 +1,472 @@ ++/* ++ * Copyright (C) 2007-2008 HTC Corporation. ++ * ++ * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * ++ * This driver is adapted from elan8232_i2c.c written by Shan-Fu Chiou ++ * and Jay Tu . ++ * This driver is also adapted from the ELAN Touch Screen driver ++ * written by Stanley Zeng ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const char ELAN_TS_NAME[] = "elan-touch"; ++ ++#define ELAN_TS_X_MAX 1088 ++#define ELAN_TS_Y_MAX 768 ++#define ELAN_USER_X_MAX 800 ++#define ELAN_USER_Y_MAX 600 ++#define IDX_PACKET_SIZE 8 ++ ++enum { ++ hello_packet = 0x55, ++ idx_coordinate_packet = 0x5a, ++}; ++ ++enum { ++ idx_finger_state = 7, ++}; ++ ++static struct workqueue_struct *elan_wq; ++ ++static struct elan_data { ++ int intr_gpio; ++ int use_irq; ++ struct hrtimer timer; ++ struct work_struct work; ++ struct i2c_client *client; ++ struct input_dev *input; ++ wait_queue_head_t wait; ++} elan_touch_data; ++ ++/*--------------------------------------------------------------*/ ++static int elan_touch_detect_int_level(void) ++{ ++ int v; ++ v = gpio_get_value(elan_touch_data.intr_gpio); ++ ++ return v; ++} ++ ++static int __elan_touch_poll(struct i2c_client *client) ++{ ++ int status = 0, retry = 20; ++ ++ do { ++ status = elan_touch_detect_int_level(); ++ retry--; ++ mdelay(20); ++ } while (status == 1 && retry > 0); ++ ++ return (status == 0 ? 0 : -ETIMEDOUT); ++} ++ ++static int elan_touch_poll(struct i2c_client *client) ++{ ++ return __elan_touch_poll(client); ++} ++ ++static int __hello_packet_handler(struct i2c_client *client) ++{ ++ int rc; ++ uint8_t buf_recv[4] = { 0 }; ++ ++ rc = elan_touch_poll(client); ++ ++ if (rc < 0) ++ return -EINVAL; ++ ++ rc = i2c_master_recv(client, buf_recv, 4); ++ ++ if (rc != 4) { ++ return rc; ++ } else { ++ int i; ++ pr_info("hello packet: [0x%02x 0x%02x 0x%02x 0x%02x]\n", ++ buf_recv[0], buf_recv[1], buf_recv[2], buf_recv[3]); ++ ++ for (i = 0; i < 4; i++) ++ if (buf_recv[i] != hello_packet) ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static inline int elan_touch_parse_xy(uint8_t *data, uint16_t *x, ++ uint16_t *y) ++{ ++ *x = (data[0] & 0xf0); ++ *x <<= 4; ++ *x |= data[1]; ++ if (*x >= ELAN_TS_X_MAX) ++ *x = ELAN_TS_X_MAX; ++ *x = ((((ELAN_TS_X_MAX - ++ *x) * 1000) / ELAN_TS_X_MAX) * ELAN_USER_X_MAX) / 1000; ++ ++ *y = (data[0] & 0x0f); ++ *y <<= 8; ++ *y |= data[2]; ++ if (*y >= ELAN_TS_Y_MAX) ++ *y = ELAN_TS_Y_MAX; ++ *y = ((((ELAN_TS_Y_MAX - ++ *y) * 1000) / ELAN_TS_Y_MAX) * ELAN_USER_Y_MAX) / 1000; ++ ++ return 0; ++} ++ ++/* __elan_touch_init -- hand shaking with touch panel ++ * ++ * 1.recv hello packet ++ */ ++static int __elan_touch_init(struct i2c_client *client) ++{ ++ int rc; ++ rc = __hello_packet_handler(client); ++ if (rc < 0) ++ goto hand_shake_failed; ++ ++hand_shake_failed: ++ return rc; ++} ++ ++static int elan_touch_recv_data(struct i2c_client *client, uint8_t * buf) ++{ ++ int rc, bytes_to_recv = IDX_PACKET_SIZE; ++ ++ if (buf == NULL) ++ return -EINVAL; ++ ++ memset(buf, 0, bytes_to_recv); ++ rc = i2c_master_recv(client, buf, bytes_to_recv); ++ if (rc != bytes_to_recv) ++ return -EINVAL; ++ ++ return rc; ++} ++ ++static void elan_touch_report_data(struct i2c_client *client, uint8_t * buf) ++{ ++ switch (buf[0]) { ++ case idx_coordinate_packet: ++ { ++ uint16_t x1, x2, y1, y2; ++ uint8_t finger_stat; ++ ++ finger_stat = (buf[idx_finger_state] & 0x06) >> 1; ++ ++ if (finger_stat == 0) { ++ input_report_key(elan_touch_data.input, BTN_TOUCH, 0); ++ input_report_key(elan_touch_data.input, BTN_2, 0); ++ } else if (finger_stat == 1) { ++ elan_touch_parse_xy(&buf[1], &x1, &y1); ++ input_report_abs(elan_touch_data.input, ABS_X, x1); ++ input_report_abs(elan_touch_data.input, ABS_Y, y1); ++ input_report_key(elan_touch_data.input, BTN_TOUCH, 1); ++ input_report_key(elan_touch_data.input, BTN_2, 0); ++ } else if (finger_stat == 2) { ++ elan_touch_parse_xy(&buf[1], &x1, &y1); ++ input_report_abs(elan_touch_data.input, ABS_X, x1); ++ input_report_abs(elan_touch_data.input, ABS_Y, y1); ++ input_report_key(elan_touch_data.input, BTN_TOUCH, 1); ++ elan_touch_parse_xy(&buf[4], &x2, &y2); ++ input_report_abs(elan_touch_data.input, ABS_HAT0X, x2); ++ input_report_abs(elan_touch_data.input, ABS_HAT0Y, y2); ++ input_report_key(elan_touch_data.input, BTN_2, 1); ++ } ++ input_sync(elan_touch_data.input); ++ break; ++ } ++ ++ default: ++ break; ++ } ++} ++ ++static void elan_touch_work_func(struct work_struct *work) ++{ ++ int rc; ++ uint8_t buf[IDX_PACKET_SIZE] = { 0 }; ++ struct i2c_client *client = elan_touch_data.client; ++ ++ if (elan_touch_detect_int_level()) ++ return; ++ ++ rc = elan_touch_recv_data(client, buf); ++ if (rc < 0) ++ return; ++ ++ elan_touch_report_data(client, buf); ++} ++ ++static irqreturn_t elan_touch_ts_interrupt(int irq, void *dev_id) ++{ ++ queue_work(elan_wq, &elan_touch_data.work); ++ ++ return IRQ_HANDLED; ++} ++ ++static enum hrtimer_restart elan_touch_timer_func(struct hrtimer *timer) ++{ ++ queue_work(elan_wq, &elan_touch_data.work); ++ hrtimer_start(&elan_touch_data.timer, ktime_set(0, 12500000), ++ HRTIMER_MODE_REL); ++ ++ return HRTIMER_NORESTART; ++} ++ ++static int elan_touch_register_interrupt(struct i2c_client *client) ++{ ++ int err = 0; ++ ++ if (client->irq) { ++ elan_touch_data.use_irq = 1; ++ err = ++ request_irq(client->irq, elan_touch_ts_interrupt, ++ IRQF_TRIGGER_FALLING, ELAN_TS_NAME, ++ &elan_touch_data); ++ ++ if (err < 0) { ++ pr_info("%s(%s): Can't allocate irq %d\n", __FILE__, ++ __func__, client->irq); ++ elan_touch_data.use_irq = 0; ++ } ++ } ++ ++ if (!elan_touch_data.use_irq) { ++ hrtimer_init(&elan_touch_data.timer, CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); ++ elan_touch_data.timer.function = elan_touch_timer_func; ++ hrtimer_start(&elan_touch_data.timer, ktime_set(1, 0), ++ HRTIMER_MODE_REL); ++ } ++ ++ pr_info("elan ts starts in %s mode.\n", ++ elan_touch_data.use_irq == 1 ? "interrupt" : "polling"); ++ ++ return 0; ++} ++ ++static int elan_touch_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device_node *np = client->dev.of_node; ++ int gpio_elan_cs, gpio_elan_rst, err = 0; ++ ++ if (!np) ++ return -ENODEV; ++ ++ elan_touch_data.intr_gpio = of_get_named_gpio(np, "gpio_intr", 0); ++ if (!gpio_is_valid(elan_touch_data.intr_gpio)) ++ return -ENODEV; ++ ++ err = devm_gpio_request_one(&client->dev, elan_touch_data.intr_gpio, ++ GPIOF_IN, "gpio_elan_intr"); ++ if (err < 0) { ++ dev_err(&client->dev, ++ "request gpio failed: %d\n", err); ++ return err; ++ } ++ ++ /* elan touch init */ ++ gpio_elan_cs = of_get_named_gpio(np, "gpio_elan_cs", 0); ++ if (!gpio_is_valid(gpio_elan_cs)) ++ return -ENODEV; ++ ++ err = devm_gpio_request_one(&client->dev, gpio_elan_cs, ++ GPIOF_OUT_INIT_HIGH, "gpio_elan_cs"); ++ if (err < 0) { ++ dev_err(&client->dev, ++ "request gpio failed: %d\n", err); ++ return err; ++ } ++ gpio_set_value(gpio_elan_cs, 0); ++ ++ gpio_elan_rst = of_get_named_gpio(np, "gpio_elan_rst", 0); ++ if (!gpio_is_valid(gpio_elan_rst)) ++ return -ENODEV; ++ ++ err = devm_gpio_request_one(&client->dev, gpio_elan_rst, ++ GPIOF_OUT_INIT_HIGH, "gpio_elan_rst"); ++ if (err < 0) { ++ dev_err(&client->dev, ++ "request gpio failed: %d\n", err); ++ return err; ++ } ++ gpio_set_value(gpio_elan_rst, 0); ++ msleep(10); ++ gpio_set_value(gpio_elan_rst, 1); ++ ++ gpio_set_value(gpio_elan_cs, 1); ++ msleep(100); ++ ++ elan_wq = create_singlethread_workqueue("elan_wq"); ++ if (!elan_wq) { ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ elan_touch_data.client = client; ++ strlcpy(client->name, ELAN_TS_NAME, I2C_NAME_SIZE); ++ ++ INIT_WORK(&elan_touch_data.work, elan_touch_work_func); ++ ++ elan_touch_data.input = input_allocate_device(); ++ if (elan_touch_data.input == NULL) { ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ err = __elan_touch_init(client); ++ if (err < 0) { ++ dev_err(&client->dev, "elan - Read Hello Packet Failed\n"); ++ goto fail; ++ } ++ ++ elan_touch_data.input->name = ELAN_TS_NAME; ++ elan_touch_data.input->id.bustype = BUS_I2C; ++ ++ set_bit(EV_SYN, elan_touch_data.input->evbit); ++ ++ set_bit(EV_KEY, elan_touch_data.input->evbit); ++ set_bit(BTN_TOUCH, elan_touch_data.input->keybit); ++ set_bit(BTN_2, elan_touch_data.input->keybit); ++ ++ set_bit(EV_ABS, elan_touch_data.input->evbit); ++ set_bit(ABS_X, elan_touch_data.input->absbit); ++ set_bit(ABS_Y, elan_touch_data.input->absbit); ++ set_bit(ABS_HAT0X, elan_touch_data.input->absbit); ++ set_bit(ABS_HAT0Y, elan_touch_data.input->absbit); ++ ++ input_set_abs_params(elan_touch_data.input, ABS_X, 0, ELAN_USER_X_MAX, ++ 0, 0); ++ input_set_abs_params(elan_touch_data.input, ABS_Y, 0, ELAN_USER_Y_MAX, ++ 0, 0); ++ input_set_abs_params(elan_touch_data.input, ABS_HAT0X, 0, ++ ELAN_USER_X_MAX, 0, 0); ++ input_set_abs_params(elan_touch_data.input, ABS_HAT0Y, 0, ++ ELAN_USER_Y_MAX, 0, 0); ++ ++ err = input_register_device(elan_touch_data.input); ++ if (err < 0) ++ goto fail; ++ ++ elan_touch_register_interrupt(elan_touch_data.client); ++ ++ return 0; ++ ++fail: ++ input_free_device(elan_touch_data.input); ++ if (elan_wq) ++ destroy_workqueue(elan_wq); ++ return err; ++} ++ ++static int elan_touch_remove(struct i2c_client *client) ++{ ++ if (elan_wq) ++ destroy_workqueue(elan_wq); ++ ++ input_unregister_device(elan_touch_data.input); ++ ++ if (elan_touch_data.use_irq) ++ free_irq(client->irq, client); ++ else ++ hrtimer_cancel(&elan_touch_data.timer); ++ return 0; ++} ++ ++/* -------------------------------------------------------------------- */ ++static const struct i2c_device_id elan_touch_id[] = { ++ {"elan-touch", 0}, ++ {} ++}; ++ ++static const struct of_device_id elan_dt_ids[] = { ++ { ++ .compatible = "elan,elan-touch", ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(of, elan_dt_ids); ++ ++static int elan_suspend(struct device *dev) ++{ ++ return 0; ++} ++ ++static int elan_resume(struct device *dev) ++{ ++ uint8_t buf[IDX_PACKET_SIZE] = { 0 }; ++ ++ if (0 == elan_touch_detect_int_level()) { ++ dev_dbg(dev, "Got touch during suspend period.\n"); ++ /* ++ * if touch screen during suspend, recv and drop the ++ * data, then touch interrupt pin will return high after ++ * receving data. ++ */ ++ elan_touch_recv_data(elan_touch_data.client, buf); ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops elan_dev_pm_ops = { ++ .suspend = elan_suspend, ++ .resume = elan_resume, ++}; ++ ++static struct i2c_driver elan_touch_driver = { ++ .probe = elan_touch_probe, ++ .remove = elan_touch_remove, ++ .id_table = elan_touch_id, ++ .driver = { ++ .name = "elan-touch", ++ .owner = THIS_MODULE, ++ .of_match_table = elan_dt_ids, ++#ifdef CONFIG_PM ++ .pm = &elan_dev_pm_ops, ++#endif ++ }, ++}; ++ ++static int __init elan_touch_init(void) ++{ ++ return i2c_add_driver(&elan_touch_driver); ++} ++ ++static void __exit elan_touch_exit(void) ++{ ++ i2c_del_driver(&elan_touch_driver); ++} ++ ++module_init(elan_touch_init); ++module_exit(elan_touch_exit); ++ ++MODULE_AUTHOR("Stanley Zeng "); ++MODULE_DESCRIPTION("ELAN Touch Screen driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/input/touchscreen/max11801_ts.c linux-3.10.30-cubox-i/drivers/input/touchscreen/max11801_ts.c +--- linux-3.10.30/drivers/input/touchscreen/max11801_ts.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/input/touchscreen/max11801_ts.c 2014-03-08 20:33:40.000000000 +0100 +@@ -2,7 +2,7 @@ + * Driver for MAXI MAX11801 - A Resistive touch screen controller with + * i2c interface + * +- * Copyright (C) 2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. + * Author: Zhang Jiejing + * + * Based on mcs5000_ts.c +@@ -39,6 +39,10 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + + /* Register Address define */ + #define GENERNAL_STATUS_REG 0x00 +@@ -54,13 +58,30 @@ + #define AUX_MESURE_CONF_REG 0x0a + #define OP_MODE_CONF_REG 0x0b + ++#define Panel_Setup_X (0x69 << 1) ++#define Panel_Setup_Y (0x6b << 1) ++ ++#define XY_combined_measurement (0x70 << 1) ++#define X_measurement (0x78 << 1) ++#define Y_measurement (0x7a << 1) ++#define AUX_measurement (0x76 << 1) ++ + /* FIFO is found only in max11800 and max11801 */ + #define FIFO_RD_CMD (0x50 << 1) + #define MAX11801_FIFO_INT (1 << 2) + #define MAX11801_FIFO_OVERFLOW (1 << 3) ++#define MAX11801_EDGE_INT (1 << 1) ++ ++#define FIFO_RD_X_MSB (0x52 << 1) ++#define FIFO_RD_X_LSB (0x53 << 1) ++#define FIFO_RD_Y_MSB (0x54 << 1) ++#define FIFO_RD_Y_LSB (0x55 << 1) ++#define FIFO_RD_AUX_MSB (0x5a << 1) ++#define FIFO_RD_AUX_LSB (0x5b << 1) + + #define XY_BUFSIZE 4 + #define XY_BUF_OFFSET 4 ++#define AUX_BUFSIZE 2 + + #define MAX11801_MAX_X 0xfff + #define MAX11801_MAX_Y 0xfff +@@ -85,6 +106,64 @@ + struct input_dev *input_dev; + }; + ++static struct i2c_client *max11801_client; ++static unsigned int max11801_workmode; ++static u8 aux_buf[AUX_BUFSIZE]; ++ ++static int max11801_dcm_write_command(struct i2c_client *client, int command) ++{ ++ return i2c_smbus_write_byte(client, command); ++} ++ ++static u32 max11801_dcm_sample_aux(struct i2c_client *client) ++{ ++ int ret; ++ int aux = 0; ++ u32 sample_data; ++ ++ /* AUX_measurement */ ++ max11801_dcm_write_command(client, AUX_measurement); ++ mdelay(5); ++ ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_MSB, ++ 1, &aux_buf[0]); ++ if (ret < 1) { ++ dev_err(&client->dev, "FIFO_RD_AUX_MSB read fails\n"); ++ return ret; ++ } ++ mdelay(5); ++ ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_LSB, ++ 1, &aux_buf[1]); ++ if (ret < 1) { ++ dev_err(&client->dev, "FIFO_RD_AUX_LSB read fails\n"); ++ return ret; ++ } ++ ++ aux = (aux_buf[0] << 4) + (aux_buf[1] >> 4); ++ /* ++ * voltage = (9170*aux)/7371; ++ * voltage is (26.2*3150*aux)/(16.2*0xFFF) ++ * V(aux)=3150*sample/0xFFF,V(battery)=212*V(aux)/81 ++ * sample_data = (14840*aux)/7371-1541; ++ */ ++ sample_data = (14840 * aux) / 7371; ++ ++ return sample_data; ++} ++ ++u32 max11801_read_adc(void) ++{ ++ u32 adc_data; ++ ++ if (!max11801_client) { ++ pr_err("FAIL max11801_client not initialize\n"); ++ return -1; ++ } ++ adc_data = max11801_dcm_sample_aux(max11801_client); ++ ++ return adc_data; ++} ++EXPORT_SYMBOL_GPL(max11801_read_adc); ++ + static u8 read_register(struct i2c_client *client, int addr) + { + /* XXX: The chip ignores LSB of register address */ +@@ -105,29 +184,62 @@ + u8 buf[XY_BUFSIZE]; + int x = -1; + int y = -1; ++ u8 command = FIFO_RD_X_MSB; + + status = read_register(data->client, GENERNAL_STATUS_REG); +- +- if (status & (MAX11801_FIFO_INT | MAX11801_FIFO_OVERFLOW)) { ++ if ((!max11801_workmode && (status & (MAX11801_FIFO_INT | ++ MAX11801_FIFO_OVERFLOW))) || (max11801_workmode && (status & ++ MAX11801_EDGE_INT))) { + status = read_register(data->client, GENERNAL_STATUS_REG); ++ if (!max11801_workmode) { ++ /* ACM mode */ ++ ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD, ++ XY_BUFSIZE, buf); ++ /* ++ * We should get 4 bytes buffer that contains X,Y ++ * and event tag ++ */ ++ if (ret < XY_BUFSIZE) ++ goto out; ++ } else { ++ /* DCM mode */ ++ /* X = panel setup */ ++ max11801_dcm_write_command(client, Panel_Setup_X); ++ /* X_measurement */ ++ max11801_dcm_write_command(client, X_measurement); ++ for (i = 0; i < 2; i++) { ++ ret = i2c_smbus_read_i2c_block_data(client, ++ command, 1, &buf[i]); ++ if (ret < 1) ++ goto out; ++ ++ command = FIFO_RD_X_LSB; ++ } ++ ++ /* Y = panel setup */ ++ max11801_dcm_write_command(client, Panel_Setup_Y); ++ /* Y_measurement */ ++ max11801_dcm_write_command(client, Y_measurement); ++ command = FIFO_RD_Y_MSB; ++ for (i = 2; i < XY_BUFSIZE; i++) { ++ ret = i2c_smbus_read_i2c_block_data(client, ++ command, 1, &buf[i]); ++ if (ret < 1) ++ goto out; + +- ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD, +- XY_BUFSIZE, buf); +- +- /* +- * We should get 4 bytes buffer that contains X,Y +- * and event tag +- */ +- if (ret < XY_BUFSIZE) +- goto out; ++ command = FIFO_RD_Y_LSB; ++ } ++ } + + for (i = 0; i < XY_BUFSIZE; i += XY_BUFSIZE / 2) { +- if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_X_TAG) ++ if ((buf[i + 1] & MEASURE_TAG_MASK) == ++ MEASURE_X_TAG) + x = (buf[i] << XY_BUF_OFFSET) + +- (buf[i + 1] >> XY_BUF_OFFSET); +- else if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_Y_TAG) ++ (buf[i + 1] >> XY_BUF_OFFSET); ++ else if ((buf[i + 1] & MEASURE_TAG_MASK) == ++ MEASURE_Y_TAG) + y = (buf[i] << XY_BUF_OFFSET) + +- (buf[i + 1] >> XY_BUF_OFFSET); ++ (buf[i + 1] >> XY_BUF_OFFSET); + } + + if ((buf[1] & EVENT_TAG_MASK) != (buf[3] & EVENT_TAG_MASK)) +@@ -138,18 +250,17 @@ + /* fall through */ + case EVENT_MIDDLE: + input_report_abs(data->input_dev, ABS_X, x); ++ y = MAX11801_MAX_Y - y; /* Calibration */ + input_report_abs(data->input_dev, ABS_Y, y); + input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1); + input_sync(data->input_dev); + break; +- + case EVENT_RELEASE: + input_event(data->input_dev, EV_KEY, BTN_TOUCH, 0); + input_sync(data->input_dev); + break; +- + case EVENT_FIFO_END: +- break; ++ break; + } + } + out: +@@ -160,18 +271,37 @@ + { + struct i2c_client *client = data->client; + +- /* Average X,Y, take 16 samples, average eight media sample */ ++ max11801_client = client; ++ /* Average X,Y, take 16 samples average eight media sample */ + max11801_write_reg(client, MESURE_AVER_CONF_REG, 0xff); + /* X,Y panel setup time set to 20us */ + max11801_write_reg(client, PANEL_SETUPTIME_CONF_REG, 0x11); +- /* Rough pullup time (2uS), Fine pullup time (10us) */ ++ /* Rough pullup time (2uS), Fine pullup time (10us) */ + max11801_write_reg(client, TOUCH_DETECT_PULLUP_CONF_REG, 0x10); +- /* Auto mode init period = 5ms , scan period = 5ms*/ ++ /* Auto mode init period = 5ms, scan period = 5ms */ + max11801_write_reg(client, AUTO_MODE_TIME_CONF_REG, 0xaa); + /* Aperture X,Y set to +- 4LSB */ + max11801_write_reg(client, APERTURE_CONF_REG, 0x33); +- /* Enable Power, enable Automode, enable Aperture, enable Average X,Y */ +- max11801_write_reg(client, OP_MODE_CONF_REG, 0x36); ++ /* ++ * Enable Power, enable Automode, enable Aperture, ++ * enable Average X,Y ++ */ ++ if (!max11801_workmode) ++ max11801_write_reg(client, OP_MODE_CONF_REG, 0x36); ++ else { ++ max11801_write_reg(client, OP_MODE_CONF_REG, 0x16); ++ /* ++ * Delay initial=1ms, Sampling time 2us ++ * Averaging sample depth 2 ++ * samples, Resolution 12bit ++ */ ++ max11801_write_reg(client, AUX_MESURE_CONF_REG, 0x76); ++ /* ++ * Use edge interrupt with ++ * direct conversion mode ++ */ ++ max11801_write_reg(client, GENERNAL_CONF_REG, 0xf3); ++ } + } + + static int max11801_ts_probe(struct i2c_client *client, +@@ -180,6 +310,7 @@ + struct max11801_data *data; + struct input_dev *input_dev; + int error; ++ struct device_node *of_node = client->dev.of_node; + + data = kzalloc(sizeof(struct max11801_data), GFP_KERNEL); + input_dev = input_allocate_device(); +@@ -203,11 +334,14 @@ + input_set_abs_params(input_dev, ABS_Y, 0, MAX11801_MAX_Y, 0, 0); + input_set_drvdata(input_dev, data); + ++ if (of_property_read_u32(of_node, "work-mode", &max11801_workmode)) ++ max11801_workmode = *(int *)(client->dev).platform_data; ++ + max11801_ts_phy_init(data); + + error = request_threaded_irq(client->irq, NULL, max11801_ts_interrupt, +- IRQF_TRIGGER_LOW | IRQF_ONESHOT, +- "max11801_ts", data); ++ IRQF_TRIGGER_LOW | IRQF_ONESHOT, ++ "max11801_ts", data); + if (error) { + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_free_mem; +@@ -245,10 +379,17 @@ + }; + MODULE_DEVICE_TABLE(i2c, max11801_ts_id); + ++static const struct of_device_id max11801_ts_dt_ids[] = { ++ { .compatible = "maxim,max11801", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, max11801_ts_dt_ids); ++ + static struct i2c_driver max11801_ts_driver = { + .driver = { + .name = "max11801_ts", + .owner = THIS_MODULE, ++ .of_match_table = max11801_ts_dt_ids, + }, + .id_table = max11801_ts_id, + .probe = max11801_ts_probe, +diff -Nur linux-3.10.30/drivers/irqchip/irq-gic.c linux-3.10.30-cubox-i/drivers/irqchip/irq-gic.c +--- linux-3.10.30/drivers/irqchip/irq-gic.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/irqchip/irq-gic.c 2014-03-08 20:33:41.000000000 +0100 +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -253,10 +254,9 @@ + if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids) + return -EINVAL; + ++ raw_spin_lock(&irq_controller_lock); + mask = 0xff << shift; + bit = gic_cpu_map[cpu] << shift; +- +- raw_spin_lock(&irq_controller_lock); + val = readl_relaxed(reg) & ~mask; + writel_relaxed(val | bit, reg); + raw_spin_unlock(&irq_controller_lock); +@@ -453,6 +453,12 @@ + writel_relaxed(1, base + GIC_CPU_CTRL); + } + ++void gic_cpu_if_down(void) ++{ ++ void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]); ++ writel_relaxed(0, cpu_base + GIC_CPU_CTRL); ++} ++ + #ifdef CONFIG_CPU_PM + /* + * Saves the GIC distributor registers during suspend or idle. Must be called +@@ -646,11 +652,15 @@ + void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) + { + int cpu; +- unsigned long map = 0; ++ unsigned long flags, map = 0; ++ ++ raw_spin_lock_irqsave(&irq_controller_lock, flags); + + /* Convert our logical CPU mask into a physical one. */ +- for_each_cpu(cpu, mask) ++ for_each_cpu(cpu, mask) { ++ trace_arm_ipi_send(irq, cpu); + map |= gic_cpu_map[cpu]; ++ } + + /* + * Ensure that stores to Normal memory are visible to the +@@ -660,7 +670,143 @@ + + /* this always happens on GIC0 */ + writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); ++ ++ raw_spin_unlock_irqrestore(&irq_controller_lock, flags); ++} ++#endif ++ ++#ifdef CONFIG_BL_SWITCHER ++/* ++ * gic_send_sgi - send a SGI directly to given CPU interface number ++ * ++ * cpu_id: the ID for the destination CPU interface ++ * irq: the IPI number to send a SGI for ++ */ ++void gic_send_sgi(unsigned int cpu_id, unsigned int irq) ++{ ++ BUG_ON(cpu_id >= NR_GIC_CPU_IF); ++ cpu_id = 1 << cpu_id; ++ /* this always happens on GIC0 */ ++ writel_relaxed((cpu_id << 16) | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); ++} ++ ++/* ++ * gic_get_cpu_id - get the CPU interface ID for the specified CPU ++ * ++ * @cpu: the logical CPU number to get the GIC ID for. ++ * ++ * Return the CPU interface ID for the given logical CPU number, ++ * or -1 if the CPU number is too large or the interface ID is ++ * unknown (more than one bit set). ++ */ ++int gic_get_cpu_id(unsigned int cpu) ++{ ++ unsigned int cpu_bit; ++ ++ if (cpu >= NR_GIC_CPU_IF) ++ return -1; ++ cpu_bit = gic_cpu_map[cpu]; ++ if (cpu_bit & (cpu_bit - 1)) ++ return -1; ++ return __ffs(cpu_bit); ++} ++ ++/* ++ * gic_migrate_target - migrate IRQs to another PU interface ++ * ++ * @new_cpu_id: the CPU target ID to migrate IRQs to ++ * ++ * Migrate all peripheral interrupts with a target matching the current CPU ++ * to the interface corresponding to @new_cpu_id. The CPU interface mapping ++ * is also updated. Targets to other CPU interfaces are unchanged. ++ * This must be called with IRQs locally disabled. ++ */ ++void gic_migrate_target(unsigned int new_cpu_id) ++{ ++ unsigned int old_cpu_id, gic_irqs, gic_nr = 0; ++ void __iomem *dist_base; ++ int i, ror_val, cpu = smp_processor_id(); ++ u32 val, old_mask, active_mask; ++ ++ if (gic_nr >= MAX_GIC_NR) ++ BUG(); ++ ++ dist_base = gic_data_dist_base(&gic_data[gic_nr]); ++ if (!dist_base) ++ return; ++ gic_irqs = gic_data[gic_nr].gic_irqs; ++ ++ old_cpu_id = __ffs(gic_cpu_map[cpu]); ++ old_mask = 0x01010101 << old_cpu_id; ++ ror_val = (old_cpu_id - new_cpu_id) & 31; ++ ++ raw_spin_lock(&irq_controller_lock); ++ ++ gic_cpu_map[cpu] = 1 << new_cpu_id; ++ ++ for (i = 8; i < DIV_ROUND_UP(gic_irqs, 4); i++) { ++ val = readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4); ++ active_mask = val & old_mask; ++ if (active_mask) { ++ val &= ~active_mask; ++ val |= ror32(active_mask, ror_val); ++ writel_relaxed(val, dist_base + GIC_DIST_TARGET + i * 4); ++ } ++ } ++ ++ raw_spin_unlock(&irq_controller_lock); ++ ++ /* ++ * Now let's migrate and clear any potential SGIs that might be ++ * pending for us (old_cpu_id). Since GIC_DIST_SGI_PENDING_SET ++ * is a banked register, we can only forward the SGI using ++ * GIC_DIST_SOFTINT. The original SGI source is lost but Linux ++ * doesn't use that information anyway. ++ * ++ * For the same reason we do not adjust SGI source information ++ * for previously sent SGIs by us to other CPUs either. ++ */ ++ for (i = 0; i < 16; i += 4) { ++ int j; ++ val = readl_relaxed(dist_base + GIC_DIST_SGI_PENDING_SET + i); ++ if (!val) ++ continue; ++ writel_relaxed(val, dist_base + GIC_DIST_SGI_PENDING_CLEAR + i); ++ for (j = i; j < i + 4; j++) { ++ if (val & 0xff) ++ writel_relaxed((1 << (new_cpu_id + 16)) | j, ++ dist_base + GIC_DIST_SOFTINT); ++ val >>= 8; ++ } ++ } + } ++ ++/* ++ * gic_get_sgir_physaddr - get the physical address for the SGI register ++ * ++ * REturn the physical address of the SGI register to be used ++ * by some early assembly code when the kernel is not yet available. ++ */ ++static unsigned long gic_dist_physaddr; ++ ++unsigned long gic_get_sgir_physaddr(void) ++{ ++ if (!gic_dist_physaddr) ++ return 0; ++ return gic_dist_physaddr + GIC_DIST_SOFTINT; ++} ++ ++void __init gic_init_physaddr(struct device_node *node) ++{ ++ struct resource res; ++ if (of_address_to_resource(node, 0, &res) == 0) { ++ gic_dist_physaddr = res.start; ++ pr_info("GIC physical location is %#lx\n", gic_dist_physaddr); ++ } ++} ++ ++#else ++#define gic_init_physaddr(node) do { } while(0) + #endif + + static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, +@@ -844,6 +990,8 @@ + percpu_offset = 0; + + gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node); ++ if (!gic_cnt) ++ gic_init_physaddr(node); + + if (parent) { + irq = irq_of_parse_and_map(node, 0); +diff -Nur linux-3.10.30/drivers/leds/leds-pwm.c linux-3.10.30-cubox-i/drivers/leds/leds-pwm.c +--- linux-3.10.30/drivers/leds/leds-pwm.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/leds/leds-pwm.c 2014-03-08 20:33:42.000000000 +0100 +@@ -67,8 +67,13 @@ + container_of(led_cdev, struct led_pwm_data, cdev); + unsigned int max = led_dat->cdev.max_brightness; + unsigned int period = led_dat->period; ++ int duty; + +- led_dat->duty = brightness * period / max; ++ duty = brightness * period / max; ++ if (led_dat->active_low) ++ duty = period - duty; ++ ++ led_dat->duty = duty; + + if (led_dat->can_sleep) + schedule_work(&led_dat->work); +@@ -102,6 +107,10 @@ + for_each_child_of_node(node, child) { + struct led_pwm_data *led_dat = &priv->leds[priv->num_leds]; + ++ led_dat->cdev.brightness_set = led_pwm_set; ++ led_dat->cdev.brightness = LED_OFF; ++ led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; ++ + led_dat->cdev.name = of_get_property(child, "label", + NULL) ? : child->name; + +@@ -118,10 +127,9 @@ + "linux,default-trigger", NULL); + of_property_read_u32(child, "max-brightness", + &led_dat->cdev.max_brightness); +- +- led_dat->cdev.brightness_set = led_pwm_set; +- led_dat->cdev.brightness = LED_OFF; +- led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; ++ of_property_read_u32(child, "default-brightness", ++ &led_dat->cdev.brightness); ++ led_dat->active_low = of_property_read_bool(child, "active-low"); + + led_dat->can_sleep = pwm_can_sleep(led_dat->pwm); + if (led_dat->can_sleep) +diff -Nur linux-3.10.30/drivers/media/platform/Kconfig linux-3.10.30-cubox-i/drivers/media/platform/Kconfig +--- linux-3.10.30/drivers/media/platform/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/Kconfig 2014-03-08 20:33:46.000000000 +0100 +@@ -121,6 +121,21 @@ + To compile this driver as a module, choose M here: the module + will be called s3c-camif. + ++config VIDEO_MXC_OUTPUT ++ tristate "MXC Video For Linux Video Output" ++ depends on VIDEO_DEV && ARCH_MXC && FB_MXC ++ select VIDEOBUF_DMA_CONTIG ++ ---help--- ++ This is the video4linux2 output driver based on MXC module. ++ ++config VIDEO_MXC_CAPTURE ++ tristate "MXC Video For Linux Video Capture" ++ depends on VIDEO_V4L2 && VIDEO_V4L2_INT_DEVICE ++ ---help--- ++ This is the video4linux2 capture driver based on i.MX video-in module. ++ ++source "drivers/media/platform/mxc/capture/Kconfig" ++source "drivers/media/platform/mxc/output/Kconfig" + source "drivers/media/platform/soc_camera/Kconfig" + source "drivers/media/platform/exynos4-is/Kconfig" + source "drivers/media/platform/s5p-tv/Kconfig" +diff -Nur linux-3.10.30/drivers/media/platform/Makefile linux-3.10.30-cubox-i/drivers/media/platform/Makefile +--- linux-3.10.30/drivers/media/platform/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/Makefile 2014-03-08 20:33:46.000000000 +0100 +@@ -50,4 +50,7 @@ + + obj-$(CONFIG_ARCH_OMAP) += omap/ + ++obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc/capture/ ++obj-$(CONFIG_VIDEO_MXC_OUTPUT) += mxc/output/ ++ + ccflags-y += -I$(srctree)/drivers/media/i2c +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/Kconfig linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/Kconfig +--- linux-3.10.30/drivers/media/platform/mxc/capture/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/Kconfig 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,86 @@ ++if VIDEO_MXC_CAPTURE ++ ++menu "MXC Camera/V4L2 PRP Features support" ++config VIDEO_MXC_IPU_CAMERA ++ bool ++ depends on VIDEO_MXC_CAPTURE && MXC_IPU ++ default y ++ ++config VIDEO_MXC_CSI_CAMERA ++ tristate "CSI camera support" ++ depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2 ++ ---help--- ++ This is the video4linux2 capture driver based on CSI module. ++ ++config MXC_CAMERA_OV5640 ++ tristate "OmniVision ov5640 camera support" ++ depends on !VIDEO_MXC_EMMA_CAMERA && I2C ++ ---help--- ++ If you plan to use the ov5640 Camera with your MXC system, say Y here. ++ ++config MXC_CAMERA_OV5642 ++ tristate "OmniVision ov5642 camera support" ++ depends on !VIDEO_MXC_EMMA_CAMERA && I2C ++ ---help--- ++ If you plan to use the ov5642 Camera with your MXC system, say Y here. ++ ++config MXC_CAMERA_OV5640_MIPI ++ tristate "OmniVision ov5640 camera support using mipi" ++ depends on !VIDEO_MXC_EMMA_CAMERA && I2C ++ ---help--- ++ If you plan to use the ov5640 Camera with mipi interface in your MXC system, say Y here. ++ ++config MXC_TVIN_ADV7180 ++ tristate "Analog Device adv7180 TV Decoder Input support" ++ depends on !VIDEO_MXC_EMMA_CAMERA && I2C ++ ---help--- ++ If you plan to use the adv7180 video decoder with your MXC system, say Y here. ++ ++choice ++ prompt "Select Overlay Rounting" ++ default MXC_IPU_DEVICE_QUEUE_SDC ++ depends on VIDEO_MXC_IPU_CAMERA && FB_MXC_SYNC_PANEL ++ ++config MXC_IPU_DEVICE_QUEUE_SDC ++ tristate "Queue ipu device for overlay library" ++ depends on VIDEO_MXC_IPU_CAMERA ++ ---help--- ++ Use case CSI->MEM->IPU DEVICE->SDC: ++ Images from sensor will be frist recieved in memory,then ++ queue to ipu device for processing if needed, and displaying ++ it on synchronous display with SDC use case. ++ ++config MXC_IPU_PRP_VF_SDC ++ bool "Pre-Processor VF SDC library" ++ depends on VIDEO_MXC_IPU_CAMERA ++ ---help--- ++ Use case PRP_VF_SDC: ++ Preprocessing image from smart sensor for viewfinder and ++ displaying it on synchronous display with SDC use case. ++ If SDC BG is selected, Rotation will not be supported. ++ CSI -> IC (PRP VF) -> MEM ++ MEM -> IC (ROT) -> MEM ++ MEM -> SDC (FG/BG) ++ ++endchoice ++ ++config MXC_IPU_PRP_ENC ++ tristate "Pre-processor Encoder library" ++ depends on VIDEO_MXC_IPU_CAMERA ++ default y ++ ---help--- ++ Use case PRP_ENC: ++ Preprocessing image from smart sensor for encoder. ++ CSI -> IC (PRP ENC) -> MEM ++ ++config MXC_IPU_CSI_ENC ++ tristate "IPU CSI Encoder library" ++ depends on VIDEO_MXC_IPU_CAMERA ++ default y ++ ---help--- ++ Use case IPU_CSI_ENC: ++ Get raw image with CSI from smart sensor for encoder. ++ CSI -> MEM ++endmenu ++ ++endif +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/Makefile linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/Makefile +--- linux-3.10.30/drivers/media/platform/mxc/capture/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/Makefile 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,21 @@ ++obj-$(CONFIG_VIDEO_MXC_CSI_CAMERA) += fsl_csi.o csi_v4l2_capture.o ++ ++ifeq ($(CONFIG_VIDEO_MXC_IPU_CAMERA),y) ++ obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc_v4l2_capture.o ++ obj-$(CONFIG_MXC_IPU_PRP_VF_SDC) += ipu_prp_vf_sdc.o ipu_prp_vf_sdc_bg.o ++ obj-$(CONFIG_MXC_IPU_DEVICE_QUEUE_SDC) += ipu_fg_overlay_sdc.o ipu_bg_overlay_sdc.o ++ obj-$(CONFIG_MXC_IPU_PRP_ENC) += ipu_prp_enc.o ipu_still.o ++ obj-$(CONFIG_MXC_IPU_CSI_ENC) += ipu_csi_enc.o ipu_still.o ++endif ++ ++ov5640_camera-objs := ov5640.o ++obj-$(CONFIG_MXC_CAMERA_OV5640) += ov5640_camera.o ++ ++ov5642_camera-objs := ov5642.o ++obj-$(CONFIG_MXC_CAMERA_OV5642) += ov5642_camera.o ++ ++ov5640_camera_mipi-objs := ov5640_mipi.o ++obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI) += ov5640_camera_mipi.o ++ ++adv7180_tvin-objs := adv7180.o ++obj-$(CONFIG_MXC_TVIN_ADV7180) += adv7180_tvin.o +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/adv7180.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/adv7180.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/adv7180.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/adv7180.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,1344 @@ ++/* ++ * Copyright 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file adv7180.c ++ * ++ * @brief Analog Device ADV7180 video decoder functions ++ * ++ * @ingroup Camera ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++ ++#define ADV7180_VOLTAGE_ANALOG 1800000 ++#define ADV7180_VOLTAGE_DIGITAL_CORE 1800000 ++#define ADV7180_VOLTAGE_DIGITAL_IO 3300000 ++#define ADV7180_VOLTAGE_PLL 1800000 ++ ++static struct regulator *dvddio_regulator; ++static struct regulator *dvdd_regulator; ++static struct regulator *avdd_regulator; ++static struct regulator *pvdd_regulator; ++static int pwn_gpio; ++ ++static int adv7180_probe(struct i2c_client *adapter, ++ const struct i2c_device_id *id); ++static int adv7180_detach(struct i2c_client *client); ++ ++static const struct i2c_device_id adv7180_id[] = { ++ {"adv7180", 0}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, adv7180_id); ++ ++static struct i2c_driver adv7180_i2c_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "adv7180", ++ }, ++ .probe = adv7180_probe, ++ .remove = adv7180_detach, ++ .id_table = adv7180_id, ++}; ++ ++/*! ++ * Maintains the information on the current state of the sensor. ++ */ ++struct sensor { ++ struct sensor_data sen; ++ v4l2_std_id std_id; ++} adv7180_data; ++ ++ ++/*! List of input video formats supported. The video formats is corresponding ++ * with v4l2 id in video_fmt_t ++ */ ++typedef enum { ++ ADV7180_NTSC = 0, /*!< Locked on (M) NTSC video signal. */ ++ ADV7180_PAL, /*!< (B, G, H, I, N)PAL video signal. */ ++ ADV7180_NOT_LOCKED, /*!< Not locked on a signal. */ ++} video_fmt_idx; ++ ++/*! Number of video standards supported (including 'not locked' signal). */ ++#define ADV7180_STD_MAX (ADV7180_PAL + 1) ++ ++/*! Video format structure. */ ++typedef struct { ++ int v4l2_id; /*!< Video for linux ID. */ ++ char name[16]; /*!< Name (e.g., "NTSC", "PAL", etc.) */ ++ u16 raw_width; /*!< Raw width. */ ++ u16 raw_height; /*!< Raw height. */ ++ u16 active_width; /*!< Active width. */ ++ u16 active_height; /*!< Active height. */ ++} video_fmt_t; ++ ++/*! Description of video formats supported. ++ * ++ * PAL: raw=720x625, active=720x576. ++ * NTSC: raw=720x525, active=720x480. ++ */ ++static video_fmt_t video_fmts[] = { ++ { /*! NTSC */ ++ .v4l2_id = V4L2_STD_NTSC, ++ .name = "NTSC", ++ .raw_width = 720, /* SENS_FRM_WIDTH */ ++ .raw_height = 525, /* SENS_FRM_HEIGHT */ ++ .active_width = 720, /* ACT_FRM_WIDTH plus 1 */ ++ .active_height = 480, /* ACT_FRM_WIDTH plus 1 */ ++ }, ++ { /*! (B, G, H, I, N) PAL */ ++ .v4l2_id = V4L2_STD_PAL, ++ .name = "PAL", ++ .raw_width = 720, ++ .raw_height = 625, ++ .active_width = 720, ++ .active_height = 576, ++ }, ++ { /*! Unlocked standard */ ++ .v4l2_id = V4L2_STD_ALL, ++ .name = "Autodetect", ++ .raw_width = 720, ++ .raw_height = 625, ++ .active_width = 720, ++ .active_height = 576, ++ }, ++}; ++ ++/*!* Standard index of ADV7180. */ ++static video_fmt_idx video_idx = ADV7180_PAL; ++ ++/*! @brief This mutex is used to provide mutual exclusion. ++ * ++ * Create a mutex that can be used to provide mutually exclusive ++ * read/write access to the globally accessible data structures ++ * and variables that were defined above. ++ */ ++static DEFINE_MUTEX(mutex); ++ ++#define IF_NAME "adv7180" ++#define ADV7180_INPUT_CTL 0x00 /* Input Control */ ++#define ADV7180_STATUS_1 0x10 /* Status #1 */ ++#define ADV7180_BRIGHTNESS 0x0a /* Brightness */ ++#define ADV7180_IDENT 0x11 /* IDENT */ ++#define ADV7180_VSYNC_FIELD_CTL_1 0x31 /* VSYNC Field Control #1 */ ++#define ADV7180_MANUAL_WIN_CTL 0x3d /* Manual Window Control */ ++#define ADV7180_SD_SATURATION_CB 0xe3 /* SD Saturation Cb */ ++#define ADV7180_SD_SATURATION_CR 0xe4 /* SD Saturation Cr */ ++#define ADV7180_PWR_MNG 0x0f /* Power Management */ ++ ++/* supported controls */ ++/* This hasn't been fully implemented yet. ++ * This is how it should work, though. */ ++static struct v4l2_queryctrl adv7180_qctrl[] = { ++ { ++ .id = V4L2_CID_BRIGHTNESS, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Brightness", ++ .minimum = 0, /* check this value */ ++ .maximum = 255, /* check this value */ ++ .step = 1, /* check this value */ ++ .default_value = 127, /* check this value */ ++ .flags = 0, ++ }, { ++ .id = V4L2_CID_SATURATION, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Saturation", ++ .minimum = 0, /* check this value */ ++ .maximum = 255, /* check this value */ ++ .step = 0x1, /* check this value */ ++ .default_value = 127, /* check this value */ ++ .flags = 0, ++ } ++}; ++ ++static inline void adv7180_power_down(int enable) ++{ ++ gpio_set_value_cansleep(pwn_gpio, !enable); ++ msleep(2); ++} ++ ++static int adv7180_regulator_enable(struct device *dev) ++{ ++ int ret = 0; ++ ++ dvddio_regulator = devm_regulator_get(dev, "DOVDD"); ++ ++ if (!IS_ERR(dvddio_regulator)) { ++ regulator_set_voltage(dvddio_regulator, ++ ADV7180_VOLTAGE_DIGITAL_IO, ++ ADV7180_VOLTAGE_DIGITAL_IO); ++ ret = regulator_enable(dvddio_regulator); ++ if (ret) { ++ dev_err(dev, "set io voltage failed\n"); ++ return ret; ++ } else { ++ dev_dbg(dev, "set io voltage ok\n"); ++ } ++ } else { ++ dev_warn(dev, "cannot get io voltage\n"); ++ } ++ ++ dvdd_regulator = devm_regulator_get(dev, "DVDD"); ++ if (!IS_ERR(dvdd_regulator)) { ++ regulator_set_voltage(dvdd_regulator, ++ ADV7180_VOLTAGE_DIGITAL_CORE, ++ ADV7180_VOLTAGE_DIGITAL_CORE); ++ ret = regulator_enable(dvdd_regulator); ++ if (ret) { ++ dev_err(dev, "set core voltage failed\n"); ++ return ret; ++ } else { ++ dev_dbg(dev, "set core voltage ok\n"); ++ } ++ } else { ++ dev_warn(dev, "cannot get core voltage\n"); ++ } ++ ++ avdd_regulator = devm_regulator_get(dev, "AVDD"); ++ if (!IS_ERR(avdd_regulator)) { ++ regulator_set_voltage(avdd_regulator, ++ ADV7180_VOLTAGE_ANALOG, ++ ADV7180_VOLTAGE_ANALOG); ++ ret = regulator_enable(avdd_regulator); ++ if (ret) { ++ dev_err(dev, "set analog voltage failed\n"); ++ return ret; ++ } else { ++ dev_dbg(dev, "set analog voltage ok\n"); ++ } ++ } else { ++ dev_warn(dev, "cannot get analog voltage\n"); ++ } ++ ++ pvdd_regulator = devm_regulator_get(dev, "PVDD"); ++ if (!IS_ERR(pvdd_regulator)) { ++ regulator_set_voltage(pvdd_regulator, ++ ADV7180_VOLTAGE_PLL, ++ ADV7180_VOLTAGE_PLL); ++ ret = regulator_enable(pvdd_regulator); ++ if (ret) { ++ dev_err(dev, "set pll voltage failed\n"); ++ return ret; ++ } else { ++ dev_dbg(dev, "set pll voltage ok\n"); ++ } ++ } else { ++ dev_warn(dev, "cannot get pll voltage\n"); ++ } ++ ++ return ret; ++} ++ ++ ++/*********************************************************************** ++ * I2C transfert. ++ ***********************************************************************/ ++ ++/*! Read one register from a ADV7180 i2c slave device. ++ * ++ * @param *reg register in the device we wish to access. ++ * ++ * @return 0 if success, an error code otherwise. ++ */ ++static inline int adv7180_read(u8 reg) ++{ ++ int val; ++ ++ val = i2c_smbus_read_byte_data(adv7180_data.sen.i2c_client, reg); ++ if (val < 0) { ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ "%s:read reg error: reg=%2x\n", __func__, reg); ++ return -1; ++ } ++ return val; ++} ++ ++/*! Write one register of a ADV7180 i2c slave device. ++ * ++ * @param *reg register in the device we wish to access. ++ * ++ * @return 0 if success, an error code otherwise. ++ */ ++static int adv7180_write_reg(u8 reg, u8 val) ++{ ++ s32 ret; ++ ++ ret = i2c_smbus_write_byte_data(adv7180_data.sen.i2c_client, reg, val); ++ if (ret < 0) { ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ "%s:write reg error:reg=%2x,val=%2x\n", __func__, ++ reg, val); ++ return -1; ++ } ++ return 0; ++} ++ ++/*********************************************************************** ++ * mxc_v4l2_capture interface. ++ ***********************************************************************/ ++ ++/*! ++ * Return attributes of current video standard. ++ * Since this device autodetects the current standard, this function also ++ * sets the values that need to be changed if the standard changes. ++ * There is no set std equivalent function. ++ * ++ * @return None. ++ */ ++static void adv7180_get_std(v4l2_std_id *std) ++{ ++ int tmp; ++ int idx; ++ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_get_std\n"); ++ ++ /* Read the AD_RESULT to get the detect output video standard */ ++ tmp = adv7180_read(ADV7180_STATUS_1) & 0x70; ++ ++ mutex_lock(&mutex); ++ if (tmp == 0x40) { ++ /* PAL */ ++ *std = V4L2_STD_PAL; ++ idx = ADV7180_PAL; ++ } else if (tmp == 0) { ++ /*NTSC*/ ++ *std = V4L2_STD_NTSC; ++ idx = ADV7180_NTSC; ++ } else { ++ *std = V4L2_STD_ALL; ++ idx = ADV7180_NOT_LOCKED; ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ "Got invalid video standard!\n"); ++ } ++ mutex_unlock(&mutex); ++ ++ /* This assumes autodetect which this device uses. */ ++ if (*std != adv7180_data.std_id) { ++ video_idx = idx; ++ adv7180_data.std_id = *std; ++ adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width; ++ adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height; ++ } ++} ++ ++/*********************************************************************** ++ * IOCTL Functions from v4l2_int_ioctl_desc. ++ ***********************************************************************/ ++ ++/*! ++ * ioctl_g_ifparm - V4L2 sensor interface handler for vidioc_int_g_ifparm_num ++ * s: pointer to standard V4L2 device structure ++ * p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure ++ * ++ * Gets slave interface parameters. ++ * Calculates the required xclk value to support the requested ++ * clock parameters in p. This value is returned in the p ++ * parameter. ++ * ++ * vidioc_int_g_ifparm returns platform-specific information about the ++ * interface settings used by the sensor. ++ * ++ * Called on open. ++ */ ++static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) ++{ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_ifparm\n"); ++ ++ if (s == NULL) { ++ pr_err(" ERROR!! no slave device set!\n"); ++ return -1; ++ } ++ ++ /* Initialize structure to 0s then set any non-0 values. */ ++ memset(p, 0, sizeof(*p)); ++ p->if_type = V4L2_IF_TYPE_BT656; /* This is the only possibility. */ ++ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; ++ p->u.bt656.nobt_hs_inv = 1; ++ p->u.bt656.bt_sync_correct = 1; ++ ++ /* ADV7180 has a dedicated clock so no clock settings needed. */ ++ ++ return 0; ++} ++ ++/*! ++ * Sets the camera power. ++ * ++ * s pointer to the camera device ++ * on if 1, power is to be turned on. 0 means power is to be turned off ++ * ++ * ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num ++ * @s: pointer to standard V4L2 device structure ++ * @on: power state to which device is to be set ++ * ++ * Sets devices power state to requrested state, if possible. ++ * This is called on open, close, suspend and resume. ++ */ ++static int ioctl_s_power(struct v4l2_int_device *s, int on) ++{ ++ struct sensor *sensor = s->priv; ++ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_s_power\n"); ++ ++ if (on && !sensor->sen.on) { ++ if (adv7180_write_reg(ADV7180_PWR_MNG, 0x04) != 0) ++ return -EIO; ++ ++ /* ++ * FIXME:Additional 400ms to wait the chip to be stable? ++ * This is a workaround for preview scrolling issue. ++ */ ++ msleep(400); ++ } else if (!on && sensor->sen.on) { ++ if (adv7180_write_reg(ADV7180_PWR_MNG, 0x24) != 0) ++ return -EIO; ++ } ++ ++ sensor->sen.on = on; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure ++ * ++ * Returns the sensor's video CAPTURE parameters. ++ */ ++static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) ++{ ++ struct sensor *sensor = s->priv; ++ struct v4l2_captureparm *cparm = &a->parm.capture; ++ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_parm\n"); ++ ++ switch (a->type) { ++ /* These are all the possible cases. */ ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); ++ memset(a, 0, sizeof(*a)); ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ cparm->capability = sensor->sen.streamcap.capability; ++ cparm->timeperframe = sensor->sen.streamcap.timeperframe; ++ cparm->capturemode = sensor->sen.streamcap.capturemode; ++ break; ++ ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ case V4L2_BUF_TYPE_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_VBI_OUTPUT: ++ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: ++ break; ++ ++ default: ++ pr_debug("ioctl_g_parm:type is unknown %d\n", a->type); ++ break; ++ } ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure ++ * ++ * Configures the sensor to use the input parameters, if possible. If ++ * not possible, reverts to the old parameters and returns the ++ * appropriate error code. ++ * ++ * This driver cannot change these settings. ++ */ ++static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) ++{ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_parm\n"); ++ ++ switch (a->type) { ++ /* These are all the possible cases. */ ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ case V4L2_BUF_TYPE_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_VBI_OUTPUT: ++ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: ++ break; ++ ++ default: ++ pr_debug(" type is unknown - %d\n", a->type); ++ break; ++ } ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap ++ * @s: pointer to standard V4L2 device structure ++ * @f: pointer to standard V4L2 v4l2_format structure ++ * ++ * Returns the sensor's current pixel format in the v4l2_format ++ * parameter. ++ */ ++static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) ++{ ++ struct sensor *sensor = s->priv; ++ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_fmt_cap\n"); ++ ++ switch (f->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ pr_debug(" Returning size of %dx%d\n", ++ sensor->sen.pix.width, sensor->sen.pix.height); ++ f->fmt.pix = sensor->sen.pix; ++ break; ++ ++ case V4L2_BUF_TYPE_PRIVATE: { ++ v4l2_std_id std; ++ adv7180_get_std(&std); ++ f->fmt.pix.pixelformat = (u32)std; ++ } ++ break; ++ ++ default: ++ f->fmt.pix = sensor->sen.pix; ++ break; ++ } ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure ++ * ++ * If the requested control is supported, returns the control information ++ * from the video_control[] array. Otherwise, returns -EINVAL if the ++ * control is not supported. ++ */ ++static int ioctl_queryctrl(struct v4l2_int_device *s, ++ struct v4l2_queryctrl *qc) ++{ ++ int i; ++ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_queryctrl\n"); ++ ++ for (i = 0; i < ARRAY_SIZE(adv7180_qctrl); i++) ++ if (qc->id && qc->id == adv7180_qctrl[i].id) { ++ memcpy(qc, &(adv7180_qctrl[i]), ++ sizeof(*qc)); ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++/*! ++ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure ++ * ++ * If the requested control is supported, returns the control's current ++ * value from the video_control[] array. Otherwise, returns -EINVAL ++ * if the control is not supported. ++ */ ++static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) ++{ ++ int ret = 0; ++ int sat = 0; ++ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_ctrl\n"); ++ ++ switch (vc->id) { ++ case V4L2_CID_BRIGHTNESS: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_BRIGHTNESS\n"); ++ adv7180_data.sen.brightness = adv7180_read(ADV7180_BRIGHTNESS); ++ vc->value = adv7180_data.sen.brightness; ++ break; ++ case V4L2_CID_CONTRAST: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_CONTRAST\n"); ++ vc->value = adv7180_data.sen.contrast; ++ break; ++ case V4L2_CID_SATURATION: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_SATURATION\n"); ++ sat = adv7180_read(ADV7180_SD_SATURATION_CB); ++ adv7180_data.sen.saturation = sat; ++ vc->value = adv7180_data.sen.saturation; ++ break; ++ case V4L2_CID_HUE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_HUE\n"); ++ vc->value = adv7180_data.sen.hue; ++ break; ++ case V4L2_CID_AUTO_WHITE_BALANCE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_AUTO_WHITE_BALANCE\n"); ++ break; ++ case V4L2_CID_DO_WHITE_BALANCE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_DO_WHITE_BALANCE\n"); ++ break; ++ case V4L2_CID_RED_BALANCE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_RED_BALANCE\n"); ++ vc->value = adv7180_data.sen.red; ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_BLUE_BALANCE\n"); ++ vc->value = adv7180_data.sen.blue; ++ break; ++ case V4L2_CID_GAMMA: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_GAMMA\n"); ++ break; ++ case V4L2_CID_EXPOSURE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_EXPOSURE\n"); ++ vc->value = adv7180_data.sen.ae_mode; ++ break; ++ case V4L2_CID_AUTOGAIN: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_AUTOGAIN\n"); ++ break; ++ case V4L2_CID_GAIN: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_GAIN\n"); ++ break; ++ case V4L2_CID_HFLIP: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_HFLIP\n"); ++ break; ++ case V4L2_CID_VFLIP: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_VFLIP\n"); ++ break; ++ default: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " Default case\n"); ++ vc->value = 0; ++ ret = -EPERM; ++ break; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure ++ * ++ * If the requested control is supported, sets the control's current ++ * value in HW (and updates the video_control[] array). Otherwise, ++ * returns -EINVAL if the control is not supported. ++ */ ++static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) ++{ ++ int retval = 0; ++ u8 tmp; ++ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_ctrl\n"); ++ ++ switch (vc->id) { ++ case V4L2_CID_BRIGHTNESS: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_BRIGHTNESS\n"); ++ tmp = vc->value; ++ adv7180_write_reg(ADV7180_BRIGHTNESS, tmp); ++ adv7180_data.sen.brightness = vc->value; ++ break; ++ case V4L2_CID_CONTRAST: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_CONTRAST\n"); ++ break; ++ case V4L2_CID_SATURATION: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_SATURATION\n"); ++ tmp = vc->value; ++ adv7180_write_reg(ADV7180_SD_SATURATION_CB, tmp); ++ adv7180_write_reg(ADV7180_SD_SATURATION_CR, tmp); ++ adv7180_data.sen.saturation = vc->value; ++ break; ++ case V4L2_CID_HUE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_HUE\n"); ++ break; ++ case V4L2_CID_AUTO_WHITE_BALANCE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_AUTO_WHITE_BALANCE\n"); ++ break; ++ case V4L2_CID_DO_WHITE_BALANCE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_DO_WHITE_BALANCE\n"); ++ break; ++ case V4L2_CID_RED_BALANCE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_RED_BALANCE\n"); ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_BLUE_BALANCE\n"); ++ break; ++ case V4L2_CID_GAMMA: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_GAMMA\n"); ++ break; ++ case V4L2_CID_EXPOSURE: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_EXPOSURE\n"); ++ break; ++ case V4L2_CID_AUTOGAIN: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_AUTOGAIN\n"); ++ break; ++ case V4L2_CID_GAIN: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_GAIN\n"); ++ break; ++ case V4L2_CID_HFLIP: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_HFLIP\n"); ++ break; ++ case V4L2_CID_VFLIP: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " V4L2_CID_VFLIP\n"); ++ break; ++ default: ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ " Default case\n"); ++ retval = -EPERM; ++ break; ++ } ++ ++ return retval; ++} ++ ++/*! ++ * ioctl_enum_framesizes - V4L2 sensor interface handler for ++ * VIDIOC_ENUM_FRAMESIZES ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure ++ * ++ * Return 0 if successful, otherwise -EINVAL. ++ */ ++static int ioctl_enum_framesizes(struct v4l2_int_device *s, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ if (fsize->index >= 1) ++ return -EINVAL; ++ ++ fsize->discrete.width = video_fmts[video_idx].active_width; ++ fsize->discrete.height = video_fmts[video_idx].active_height; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_g_chip_ident - V4L2 sensor interface handler for ++ * VIDIOC_DBG_G_CHIP_IDENT ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @id: pointer to int ++ * ++ * Return 0. ++ */ ++static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id) ++{ ++ ((struct v4l2_dbg_chip_ident *)id)->match.type = ++ V4L2_CHIP_MATCH_I2C_DRIVER; ++ strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, ++ "adv7180_decoder"); ++ ((struct v4l2_dbg_chip_ident *)id)->ident = V4L2_IDENT_ADV7180; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT ++ * @s: pointer to standard V4L2 device structure ++ */ ++static int ioctl_init(struct v4l2_int_device *s) ++{ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_init\n"); ++ return 0; ++} ++ ++/*! ++ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num ++ * @s: pointer to standard V4L2 device structure ++ * ++ * Initialise the device when slave attaches to the master. ++ */ ++static int ioctl_dev_init(struct v4l2_int_device *s) ++{ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_dev_init\n"); ++ return 0; ++} ++ ++/*! ++ * This structure defines all the ioctls for this module. ++ */ ++static struct v4l2_int_ioctl_desc adv7180_ioctl_desc[] = { ++ ++ {vidioc_int_dev_init_num, (v4l2_int_ioctl_func*)ioctl_dev_init}, ++ ++ /*! ++ * Delinitialise the dev. at slave detach. ++ * The complement of ioctl_dev_init. ++ */ ++/* {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func *)ioctl_dev_exit}, */ ++ ++ {vidioc_int_s_power_num, (v4l2_int_ioctl_func*)ioctl_s_power}, ++ {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*)ioctl_g_ifparm}, ++/* {vidioc_int_g_needs_reset_num, ++ (v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */ ++/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */ ++ {vidioc_int_init_num, (v4l2_int_ioctl_func*)ioctl_init}, ++ ++ /*! ++ * VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type. ++ */ ++/* {vidioc_int_enum_fmt_cap_num, ++ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap}, */ ++ ++ /*! ++ * VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. ++ * This ioctl is used to negotiate the image capture size and ++ * pixel format without actually making it take effect. ++ */ ++/* {vidioc_int_try_fmt_cap_num, ++ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */ ++ ++ {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func*)ioctl_g_fmt_cap}, ++ ++ /*! ++ * If the requested format is supported, configures the HW to use that ++ * format, returns error code if format not supported or HW can't be ++ * correctly configured. ++ */ ++/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */ ++ ++ {vidioc_int_g_parm_num, (v4l2_int_ioctl_func*)ioctl_g_parm}, ++ {vidioc_int_s_parm_num, (v4l2_int_ioctl_func*)ioctl_s_parm}, ++ {vidioc_int_queryctrl_num, (v4l2_int_ioctl_func*)ioctl_queryctrl}, ++ {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func*)ioctl_g_ctrl}, ++ {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func*)ioctl_s_ctrl}, ++ {vidioc_int_enum_framesizes_num, ++ (v4l2_int_ioctl_func *) ioctl_enum_framesizes}, ++ {vidioc_int_g_chip_ident_num, ++ (v4l2_int_ioctl_func *)ioctl_g_chip_ident}, ++}; ++ ++static struct v4l2_int_slave adv7180_slave = { ++ .ioctls = adv7180_ioctl_desc, ++ .num_ioctls = ARRAY_SIZE(adv7180_ioctl_desc), ++}; ++ ++static struct v4l2_int_device adv7180_int_device = { ++ .module = THIS_MODULE, ++ .name = "adv7180", ++ .type = v4l2_int_type_slave, ++ .u = { ++ .slave = &adv7180_slave, ++ }, ++}; ++ ++ ++/*********************************************************************** ++ * I2C client and driver. ++ ***********************************************************************/ ++ ++/*! ADV7180 Reset function. ++ * ++ * @return None. ++ */ ++static void adv7180_hard_reset(bool cvbs) ++{ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ "In adv7180:adv7180_hard_reset\n"); ++ ++ if (cvbs) { ++ /* Set CVBS input on AIN1 */ ++ adv7180_write_reg(ADV7180_INPUT_CTL, 0x00); ++ } else { ++ /* ++ * Set YPbPr input on AIN1,4,5 and normal ++ * operations(autodection of all stds). ++ */ ++ adv7180_write_reg(ADV7180_INPUT_CTL, 0x09); ++ } ++ ++ /* Datasheet recommends */ ++ adv7180_write_reg(0x01, 0xc8); ++ adv7180_write_reg(0x02, 0x04); ++ adv7180_write_reg(0x03, 0x00); ++ adv7180_write_reg(0x04, 0x45); ++ adv7180_write_reg(0x05, 0x00); ++ adv7180_write_reg(0x06, 0x02); ++ adv7180_write_reg(0x07, 0x7F); ++ adv7180_write_reg(0x08, 0x80); ++ adv7180_write_reg(0x0A, 0x00); ++ adv7180_write_reg(0x0B, 0x00); ++ adv7180_write_reg(0x0C, 0x36); ++ adv7180_write_reg(0x0D, 0x7C); ++ adv7180_write_reg(0x0E, 0x00); ++ adv7180_write_reg(0x0F, 0x00); ++ adv7180_write_reg(0x13, 0x00); ++ adv7180_write_reg(0x14, 0x12); ++ adv7180_write_reg(0x15, 0x00); ++ adv7180_write_reg(0x16, 0x00); ++ adv7180_write_reg(0x17, 0x01); ++ adv7180_write_reg(0x18, 0x93); ++ adv7180_write_reg(0xF1, 0x19); ++ adv7180_write_reg(0x1A, 0x00); ++ adv7180_write_reg(0x1B, 0x00); ++ adv7180_write_reg(0x1C, 0x00); ++ adv7180_write_reg(0x1D, 0x40); ++ adv7180_write_reg(0x1E, 0x00); ++ adv7180_write_reg(0x1F, 0x00); ++ adv7180_write_reg(0x20, 0x00); ++ adv7180_write_reg(0x21, 0x00); ++ adv7180_write_reg(0x22, 0x00); ++ adv7180_write_reg(0x23, 0xC0); ++ adv7180_write_reg(0x24, 0x00); ++ adv7180_write_reg(0x25, 0x00); ++ adv7180_write_reg(0x26, 0x00); ++ adv7180_write_reg(0x27, 0x58); ++ adv7180_write_reg(0x28, 0x00); ++ adv7180_write_reg(0x29, 0x00); ++ adv7180_write_reg(0x2A, 0x00); ++ adv7180_write_reg(0x2B, 0xE1); ++ adv7180_write_reg(0x2C, 0xAE); ++ adv7180_write_reg(0x2D, 0xF4); ++ adv7180_write_reg(0x2E, 0x00); ++ adv7180_write_reg(0x2F, 0xF0); ++ adv7180_write_reg(0x30, 0x00); ++ adv7180_write_reg(0x31, 0x12); ++ adv7180_write_reg(0x32, 0x41); ++ adv7180_write_reg(0x33, 0x84); ++ adv7180_write_reg(0x34, 0x00); ++ adv7180_write_reg(0x35, 0x02); ++ adv7180_write_reg(0x36, 0x00); ++ adv7180_write_reg(0x37, 0x01); ++ adv7180_write_reg(0x38, 0x80); ++ adv7180_write_reg(0x39, 0xC0); ++ adv7180_write_reg(0x3A, 0x10); ++ adv7180_write_reg(0x3B, 0x05); ++ adv7180_write_reg(0x3C, 0x58); ++ adv7180_write_reg(0x3D, 0xB2); ++ adv7180_write_reg(0x3E, 0x64); ++ adv7180_write_reg(0x3F, 0xE4); ++ adv7180_write_reg(0x40, 0x90); ++ adv7180_write_reg(0x41, 0x01); ++ adv7180_write_reg(0x42, 0x7E); ++ adv7180_write_reg(0x43, 0xA4); ++ adv7180_write_reg(0x44, 0xFF); ++ adv7180_write_reg(0x45, 0xB6); ++ adv7180_write_reg(0x46, 0x12); ++ adv7180_write_reg(0x48, 0x00); ++ adv7180_write_reg(0x49, 0x00); ++ adv7180_write_reg(0x4A, 0x00); ++ adv7180_write_reg(0x4B, 0x00); ++ adv7180_write_reg(0x4C, 0x00); ++ adv7180_write_reg(0x4D, 0xEF); ++ adv7180_write_reg(0x4E, 0x08); ++ adv7180_write_reg(0x4F, 0x08); ++ adv7180_write_reg(0x50, 0x08); ++ adv7180_write_reg(0x51, 0x24); ++ adv7180_write_reg(0x52, 0x0B); ++ adv7180_write_reg(0x53, 0x4E); ++ adv7180_write_reg(0x54, 0x80); ++ adv7180_write_reg(0x55, 0x00); ++ adv7180_write_reg(0x56, 0x10); ++ adv7180_write_reg(0x57, 0x00); ++ adv7180_write_reg(0x58, 0x00); ++ adv7180_write_reg(0x59, 0x00); ++ adv7180_write_reg(0x5A, 0x00); ++ adv7180_write_reg(0x5B, 0x00); ++ adv7180_write_reg(0x5C, 0x00); ++ adv7180_write_reg(0x5D, 0x00); ++ adv7180_write_reg(0x5E, 0x00); ++ adv7180_write_reg(0x5F, 0x00); ++ adv7180_write_reg(0x60, 0x00); ++ adv7180_write_reg(0x61, 0x00); ++ adv7180_write_reg(0x62, 0x20); ++ adv7180_write_reg(0x63, 0x00); ++ adv7180_write_reg(0x64, 0x00); ++ adv7180_write_reg(0x65, 0x00); ++ adv7180_write_reg(0x66, 0x00); ++ adv7180_write_reg(0x67, 0x03); ++ adv7180_write_reg(0x68, 0x01); ++ adv7180_write_reg(0x69, 0x00); ++ adv7180_write_reg(0x6A, 0x00); ++ adv7180_write_reg(0x6B, 0xC0); ++ adv7180_write_reg(0x6C, 0x00); ++ adv7180_write_reg(0x6D, 0x00); ++ adv7180_write_reg(0x6E, 0x00); ++ adv7180_write_reg(0x6F, 0x00); ++ adv7180_write_reg(0x70, 0x00); ++ adv7180_write_reg(0x71, 0x00); ++ adv7180_write_reg(0x72, 0x00); ++ adv7180_write_reg(0x73, 0x10); ++ adv7180_write_reg(0x74, 0x04); ++ adv7180_write_reg(0x75, 0x01); ++ adv7180_write_reg(0x76, 0x00); ++ adv7180_write_reg(0x77, 0x3F); ++ adv7180_write_reg(0x78, 0xFF); ++ adv7180_write_reg(0x79, 0xFF); ++ adv7180_write_reg(0x7A, 0xFF); ++ adv7180_write_reg(0x7B, 0x1E); ++ adv7180_write_reg(0x7C, 0xC0); ++ adv7180_write_reg(0x7D, 0x00); ++ adv7180_write_reg(0x7E, 0x00); ++ adv7180_write_reg(0x7F, 0x00); ++ adv7180_write_reg(0x80, 0x00); ++ adv7180_write_reg(0x81, 0xC0); ++ adv7180_write_reg(0x82, 0x04); ++ adv7180_write_reg(0x83, 0x00); ++ adv7180_write_reg(0x84, 0x0C); ++ adv7180_write_reg(0x85, 0x02); ++ adv7180_write_reg(0x86, 0x03); ++ adv7180_write_reg(0x87, 0x63); ++ adv7180_write_reg(0x88, 0x5A); ++ adv7180_write_reg(0x89, 0x08); ++ adv7180_write_reg(0x8A, 0x10); ++ adv7180_write_reg(0x8B, 0x00); ++ adv7180_write_reg(0x8C, 0x40); ++ adv7180_write_reg(0x8D, 0x00); ++ adv7180_write_reg(0x8E, 0x40); ++ adv7180_write_reg(0x8F, 0x00); ++ adv7180_write_reg(0x90, 0x00); ++ adv7180_write_reg(0x91, 0x50); ++ adv7180_write_reg(0x92, 0x00); ++ adv7180_write_reg(0x93, 0x00); ++ adv7180_write_reg(0x94, 0x00); ++ adv7180_write_reg(0x95, 0x00); ++ adv7180_write_reg(0x96, 0x00); ++ adv7180_write_reg(0x97, 0xF0); ++ adv7180_write_reg(0x98, 0x00); ++ adv7180_write_reg(0x99, 0x00); ++ adv7180_write_reg(0x9A, 0x00); ++ adv7180_write_reg(0x9B, 0x00); ++ adv7180_write_reg(0x9C, 0x00); ++ adv7180_write_reg(0x9D, 0x00); ++ adv7180_write_reg(0x9E, 0x00); ++ adv7180_write_reg(0x9F, 0x00); ++ adv7180_write_reg(0xA0, 0x00); ++ adv7180_write_reg(0xA1, 0x00); ++ adv7180_write_reg(0xA2, 0x00); ++ adv7180_write_reg(0xA3, 0x00); ++ adv7180_write_reg(0xA4, 0x00); ++ adv7180_write_reg(0xA5, 0x00); ++ adv7180_write_reg(0xA6, 0x00); ++ adv7180_write_reg(0xA7, 0x00); ++ adv7180_write_reg(0xA8, 0x00); ++ adv7180_write_reg(0xA9, 0x00); ++ adv7180_write_reg(0xAA, 0x00); ++ adv7180_write_reg(0xAB, 0x00); ++ adv7180_write_reg(0xAC, 0x00); ++ adv7180_write_reg(0xAD, 0x00); ++ adv7180_write_reg(0xAE, 0x60); ++ adv7180_write_reg(0xAF, 0x00); ++ adv7180_write_reg(0xB0, 0x00); ++ adv7180_write_reg(0xB1, 0x60); ++ adv7180_write_reg(0xB2, 0x1C); ++ adv7180_write_reg(0xB3, 0x54); ++ adv7180_write_reg(0xB4, 0x00); ++ adv7180_write_reg(0xB5, 0x00); ++ adv7180_write_reg(0xB6, 0x00); ++ adv7180_write_reg(0xB7, 0x13); ++ adv7180_write_reg(0xB8, 0x03); ++ adv7180_write_reg(0xB9, 0x33); ++ adv7180_write_reg(0xBF, 0x02); ++ adv7180_write_reg(0xC0, 0x00); ++ adv7180_write_reg(0xC1, 0x00); ++ adv7180_write_reg(0xC2, 0x00); ++ adv7180_write_reg(0xC3, 0x00); ++ adv7180_write_reg(0xC4, 0x00); ++ adv7180_write_reg(0xC5, 0x81); ++ adv7180_write_reg(0xC6, 0x00); ++ adv7180_write_reg(0xC7, 0x00); ++ adv7180_write_reg(0xC8, 0x00); ++ adv7180_write_reg(0xC9, 0x04); ++ adv7180_write_reg(0xCC, 0x69); ++ adv7180_write_reg(0xCD, 0x00); ++ adv7180_write_reg(0xCE, 0x01); ++ adv7180_write_reg(0xCF, 0xB4); ++ adv7180_write_reg(0xD0, 0x00); ++ adv7180_write_reg(0xD1, 0x10); ++ adv7180_write_reg(0xD2, 0xFF); ++ adv7180_write_reg(0xD3, 0xFF); ++ adv7180_write_reg(0xD4, 0x7F); ++ adv7180_write_reg(0xD5, 0x7F); ++ adv7180_write_reg(0xD6, 0x3E); ++ adv7180_write_reg(0xD7, 0x08); ++ adv7180_write_reg(0xD8, 0x3C); ++ adv7180_write_reg(0xD9, 0x08); ++ adv7180_write_reg(0xDA, 0x3C); ++ adv7180_write_reg(0xDB, 0x9B); ++ adv7180_write_reg(0xDC, 0xAC); ++ adv7180_write_reg(0xDD, 0x4C); ++ adv7180_write_reg(0xDE, 0x00); ++ adv7180_write_reg(0xDF, 0x00); ++ adv7180_write_reg(0xE0, 0x14); ++ adv7180_write_reg(0xE1, 0x80); ++ adv7180_write_reg(0xE2, 0x80); ++ adv7180_write_reg(0xE3, 0x80); ++ adv7180_write_reg(0xE4, 0x80); ++ adv7180_write_reg(0xE5, 0x25); ++ adv7180_write_reg(0xE6, 0x44); ++ adv7180_write_reg(0xE7, 0x63); ++ adv7180_write_reg(0xE8, 0x65); ++ adv7180_write_reg(0xE9, 0x14); ++ adv7180_write_reg(0xEA, 0x63); ++ adv7180_write_reg(0xEB, 0x55); ++ adv7180_write_reg(0xEC, 0x55); ++ adv7180_write_reg(0xEE, 0x00); ++ adv7180_write_reg(0xEF, 0x4A); ++ adv7180_write_reg(0xF0, 0x44); ++ adv7180_write_reg(0xF1, 0x0C); ++ adv7180_write_reg(0xF2, 0x32); ++ adv7180_write_reg(0xF3, 0x00); ++ adv7180_write_reg(0xF4, 0x3F); ++ adv7180_write_reg(0xF5, 0xE0); ++ adv7180_write_reg(0xF6, 0x69); ++ adv7180_write_reg(0xF7, 0x10); ++ adv7180_write_reg(0xF8, 0x00); ++ adv7180_write_reg(0xF9, 0x03); ++ adv7180_write_reg(0xFA, 0xFA); ++ adv7180_write_reg(0xFB, 0x40); ++} ++ ++/*! ADV7180 I2C attach function. ++ * ++ * @param *adapter struct i2c_adapter *. ++ * ++ * @return Error code indicating success or failure. ++ */ ++ ++/*! ++ * ADV7180 I2C probe function. ++ * Function set in i2c_driver struct. ++ * Called by insmod. ++ * ++ * @param *adapter I2C adapter descriptor. ++ * ++ * @return Error code indicating success or failure. ++ */ ++static int adv7180_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ int rev_id; ++ int ret = 0; ++ u32 cvbs = true; ++ struct pinctrl *pinctrl; ++ struct device *dev = &client->dev; ++ ++ printk(KERN_ERR"DBG sensor data is at %p\n", &adv7180_data); ++ ++ /* ov5640 pinctrl */ ++ pinctrl = devm_pinctrl_get_select_default(dev); ++ if (IS_ERR(pinctrl)) { ++ dev_err(dev, "setup pinctrl failed\n"); ++ return PTR_ERR(pinctrl); ++ } ++ ++ /* request power down pin */ ++ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); ++ if (!gpio_is_valid(pwn_gpio)) { ++ dev_err(dev, "no sensor pwdn pin available\n"); ++ return -ENODEV; ++ } ++ ret = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, ++ "adv7180_pwdn"); ++ if (ret < 0) { ++ dev_err(dev, "no power pin available!\n"); ++ return ret; ++ } ++ ++ adv7180_regulator_enable(dev); ++ ++ adv7180_power_down(0); ++ ++ msleep(1); ++ ++ /* Set initial values for the sensor struct. */ ++ memset(&adv7180_data, 0, sizeof(adv7180_data)); ++ adv7180_data.sen.i2c_client = client; ++ adv7180_data.sen.streamcap.timeperframe.denominator = 30; ++ adv7180_data.sen.streamcap.timeperframe.numerator = 1; ++ adv7180_data.std_id = V4L2_STD_ALL; ++ video_idx = ADV7180_NOT_LOCKED; ++ adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width; ++ adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height; ++ adv7180_data.sen.pix.pixelformat = V4L2_PIX_FMT_UYVY; /* YUV422 */ ++ adv7180_data.sen.pix.priv = 1; /* 1 is used to indicate TV in */ ++ adv7180_data.sen.on = true; ++ ++ adv7180_data.sen.sensor_clk = devm_clk_get(dev, "csi_mclk"); ++ if (IS_ERR(adv7180_data.sen.sensor_clk)) { ++ dev_err(dev, "get mclk failed\n"); ++ return PTR_ERR(adv7180_data.sen.sensor_clk); ++ } ++ ++ ret = of_property_read_u32(dev->of_node, "mclk", ++ &adv7180_data.sen.mclk); ++ if (ret) { ++ dev_err(dev, "mclk frequency is invalid\n"); ++ return ret; ++ } ++ ++ ret = of_property_read_u32( ++ dev->of_node, "mclk_source", ++ (u32 *) &(adv7180_data.sen.mclk_source)); ++ if (ret) { ++ dev_err(dev, "mclk_source invalid\n"); ++ return ret; ++ } ++ ++ ret = of_property_read_u32(dev->of_node, "csi_id", ++ &(adv7180_data.sen.csi)); ++ if (ret) { ++ dev_err(dev, "csi_id invalid\n"); ++ return ret; ++ } ++ ++ clk_prepare_enable(adv7180_data.sen.sensor_clk); ++ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ "%s:adv7180 probe i2c address is 0x%02X\n", ++ __func__, adv7180_data.sen.i2c_client->addr); ++ ++ /*! Read the revision ID of the tvin chip */ ++ rev_id = adv7180_read(ADV7180_IDENT); ++ dev_dbg(dev, ++ "%s:Analog Device adv7%2X0 detected!\n", __func__, ++ rev_id); ++ ++ ret = of_property_read_u32(dev->of_node, "cvbs", &(cvbs)); ++ if (ret) { ++ dev_err(dev, "cvbs setting is not found\n"); ++ cvbs = true; ++ } ++ ++ /*! ADV7180 initialization. */ ++ adv7180_hard_reset(cvbs); ++ ++ pr_debug(" type is %d (expect %d)\n", ++ adv7180_int_device.type, v4l2_int_type_slave); ++ pr_debug(" num ioctls is %d\n", ++ adv7180_int_device.u.slave->num_ioctls); ++ ++ /* This function attaches this structure to the /dev/video0 device. ++ * The pointer in priv points to the adv7180_data structure here.*/ ++ adv7180_int_device.priv = &adv7180_data; ++ ret = v4l2_int_device_register(&adv7180_int_device); ++ ++ clk_disable_unprepare(adv7180_data.sen.sensor_clk); ++ ++ return ret; ++} ++ ++/*! ++ * ADV7180 I2C detach function. ++ * Called on rmmod. ++ * ++ * @param *client struct i2c_client*. ++ * ++ * @return Error code indicating success or failure. ++ */ ++static int adv7180_detach(struct i2c_client *client) ++{ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, ++ "%s:Removing %s video decoder @ 0x%02X from adapter %s\n", ++ __func__, IF_NAME, client->addr << 1, client->adapter->name); ++ ++ /* Power down via i2c */ ++ adv7180_write_reg(ADV7180_PWR_MNG, 0x24); ++ ++ if (dvddio_regulator) ++ regulator_disable(dvddio_regulator); ++ ++ if (dvdd_regulator) ++ regulator_disable(dvdd_regulator); ++ ++ if (avdd_regulator) ++ regulator_disable(avdd_regulator); ++ ++ if (pvdd_regulator) ++ regulator_disable(pvdd_regulator); ++ ++ v4l2_int_device_unregister(&adv7180_int_device); ++ ++ return 0; ++} ++ ++/*! ++ * ADV7180 init function. ++ * Called on insmod. ++ * ++ * @return Error code indicating success or failure. ++ */ ++static __init int adv7180_init(void) ++{ ++ u8 err = 0; ++ ++ pr_debug("In adv7180_init\n"); ++ ++ /* Tells the i2c driver what functions to call for this driver. */ ++ err = i2c_add_driver(&adv7180_i2c_driver); ++ if (err != 0) ++ pr_err("%s:driver registration failed, error=%d\n", ++ __func__, err); ++ ++ return err; ++} ++ ++/*! ++ * ADV7180 cleanup function. ++ * Called on rmmod. ++ * ++ * @return Error code indicating success or failure. ++ */ ++static void __exit adv7180_clean(void) ++{ ++ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_clean\n"); ++ i2c_del_driver(&adv7180_i2c_driver); ++} ++ ++module_init(adv7180_init); ++module_exit(adv7180_clean); ++ ++MODULE_AUTHOR("Freescale Semiconductor"); ++MODULE_DESCRIPTION("Anolog Device ADV7180 video decoder driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/csi_v4l2_capture.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/csi_v4l2_capture.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/csi_v4l2_capture.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/csi_v4l2_capture.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,2047 @@ ++/* ++ * Copyright 2009-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file drivers/media/video/mxc/capture/csi_v4l2_capture.c ++ * This file is derived from mxc_v4l2_capture.c ++ * ++ * @brief Video For Linux 2 capture driver ++ * ++ * @ingroup MXC_V4L2_CAPTURE ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++#include "fsl_csi.h" ++ ++static int video_nr = -1; ++static cam_data *g_cam; ++static int req_buf_number; ++ ++static int csi_v4l2_master_attach(struct v4l2_int_device *slave); ++static void csi_v4l2_master_detach(struct v4l2_int_device *slave); ++static u8 camera_power(cam_data *cam, bool cameraOn); ++struct v4l2_crop crop_current; ++struct v4l2_window win_current; ++ ++/*! Information about this driver. */ ++static struct v4l2_int_master csi_v4l2_master = { ++ .attach = csi_v4l2_master_attach, ++ .detach = csi_v4l2_master_detach, ++}; ++ ++static struct v4l2_int_device csi_v4l2_int_device = { ++ .module = THIS_MODULE, ++ .name = "csi_v4l2_cap", ++ .type = v4l2_int_type_master, ++ .u = { ++ .master = &csi_v4l2_master, ++ }, ++}; ++ ++static struct v4l2_queryctrl pxp_controls[] = { ++ { ++ .id = V4L2_CID_HFLIP, ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .name = "Horizontal Flip", ++ .minimum = 0, ++ .maximum = 1, ++ .step = 1, ++ .default_value = 0, ++ .flags = 0, ++ }, { ++ .id = V4L2_CID_VFLIP, ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .name = "Vertical Flip", ++ .minimum = 0, ++ .maximum = 1, ++ .step = 1, ++ .default_value = 0, ++ .flags = 0, ++ }, { ++ .id = V4L2_CID_PRIVATE_BASE, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Rotation", ++ .minimum = 0, ++ .maximum = 270, ++ .step = 90, ++ .default_value = 0, ++ .flags = 0, ++ }, ++}; ++ ++/* Callback function triggered after PxP receives an EOF interrupt */ ++static void pxp_dma_done(void *arg) ++{ ++ struct pxp_tx_desc *tx_desc = to_tx_desc(arg); ++ struct dma_chan *chan = tx_desc->txd.chan; ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ cam_data *cam = pxp_chan->client; ++ ++ /* This call will signal wait_for_completion_timeout() */ ++ complete(&cam->pxp_tx_cmpl); ++} ++ ++static bool chan_filter(struct dma_chan *chan, void *arg) ++{ ++ if (imx_dma_is_pxp(chan)) ++ return true; ++ else ++ return false; ++} ++ ++/* Function to request PXP DMA channel */ ++static int pxp_chan_init(cam_data *cam) ++{ ++ dma_cap_mask_t mask; ++ struct dma_chan *chan; ++ ++ /* Request a free channel */ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); ++ dma_cap_set(DMA_PRIVATE, mask); ++ chan = dma_request_channel(mask, chan_filter, NULL); ++ if (!chan) { ++ pr_err("Unsuccessfully request channel!\n"); ++ return -EBUSY; ++ } ++ ++ cam->pxp_chan = to_pxp_channel(chan); ++ cam->pxp_chan->client = cam; ++ ++ init_completion(&cam->pxp_tx_cmpl); ++ ++ return 0; ++} ++ ++/* ++ * Function to call PxP DMA driver and send our new V4L2 buffer ++ * through the PxP. ++ * Note: This is a blocking call, so upon return the PxP tx should be complete. ++ */ ++static int pxp_process_update(cam_data *cam) ++{ ++ dma_cookie_t cookie; ++ struct scatterlist *sg = cam->sg; ++ struct dma_chan *dma_chan; ++ struct pxp_tx_desc *desc; ++ struct dma_async_tx_descriptor *txd; ++ struct pxp_config_data *pxp_conf = &cam->pxp_conf; ++ struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; ++ int i, ret; ++ int length; ++ ++ pr_debug("Starting PxP Send Buffer\n"); ++ ++ /* First, check to see that we have acquired a PxP Channel object */ ++ if (cam->pxp_chan == NULL) { ++ /* ++ * PxP Channel has not yet been created and initialized, ++ * so let's go ahead and try ++ */ ++ ret = pxp_chan_init(cam); ++ if (ret) { ++ /* ++ * PxP channel init failed, and we can't use the ++ * PxP until the PxP DMA driver has loaded, so we abort ++ */ ++ pr_err("PxP chan init failed\n"); ++ return -ENODEV; ++ } ++ } ++ ++ /* ++ * Init completion, so that we can be properly informed of ++ * the completion of the PxP task when it is done. ++ */ ++ init_completion(&cam->pxp_tx_cmpl); ++ ++ dma_chan = &cam->pxp_chan->dma_chan; ++ ++ txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg, 2, ++ DMA_TO_DEVICE, ++ DMA_PREP_INTERRUPT, ++ NULL); ++ if (!txd) { ++ pr_err("Error preparing a DMA transaction descriptor.\n"); ++ return -EIO; ++ } ++ ++ txd->callback_param = txd; ++ txd->callback = pxp_dma_done; ++ ++ /* ++ * Configure PxP for processing of new v4l2 buf ++ */ ++ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_UYVY; ++ pxp_conf->s0_param.color_key = -1; ++ pxp_conf->s0_param.color_key_enable = false; ++ pxp_conf->s0_param.width = cam->v2f.fmt.pix.width; ++ pxp_conf->s0_param.height = cam->v2f.fmt.pix.height; ++ ++ pxp_conf->ol_param[0].combine_enable = false; ++ ++ proc_data->srect.top = 0; ++ proc_data->srect.left = 0; ++ proc_data->srect.width = pxp_conf->s0_param.width; ++ proc_data->srect.height = pxp_conf->s0_param.height; ++ ++ if (crop_current.c.top != 0) ++ proc_data->srect.top = crop_current.c.top; ++ if (crop_current.c.left != 0) ++ proc_data->srect.left = crop_current.c.left; ++ if (crop_current.c.width != 0) ++ proc_data->srect.width = crop_current.c.width; ++ if (crop_current.c.height != 0) ++ proc_data->srect.height = crop_current.c.height; ++ ++ proc_data->drect.left = 0; ++ proc_data->drect.top = 0; ++ proc_data->drect.width = proc_data->srect.width; ++ proc_data->drect.height = proc_data->srect.height; ++ ++ if (win_current.w.left != 0) ++ proc_data->drect.left = win_current.w.left; ++ if (win_current.w.top != 0) ++ proc_data->drect.top = win_current.w.top; ++ if (win_current.w.width != 0) ++ proc_data->drect.width = win_current.w.width; ++ if (win_current.w.height != 0) ++ proc_data->drect.height = win_current.w.height; ++ ++ pr_debug("srect l: %d, t: %d, w: %d, h: %d; " ++ "drect l: %d, t: %d, w: %d, h: %d\n", ++ proc_data->srect.left, proc_data->srect.top, ++ proc_data->srect.width, proc_data->srect.height, ++ proc_data->drect.left, proc_data->drect.top, ++ proc_data->drect.width, proc_data->drect.height); ++ ++ pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_RGB565; ++ pxp_conf->out_param.width = proc_data->drect.width; ++ pxp_conf->out_param.height = proc_data->drect.height; ++ ++ if (cam->rotation % 180) ++ pxp_conf->out_param.stride = pxp_conf->out_param.height; ++ else ++ pxp_conf->out_param.stride = pxp_conf->out_param.width; ++ ++ desc = to_tx_desc(txd); ++ length = desc->len; ++ for (i = 0; i < length; i++) { ++ if (i == 0) {/* S0 */ ++ memcpy(&desc->proc_data, proc_data, ++ sizeof(struct pxp_proc_data)); ++ pxp_conf->s0_param.paddr = sg_dma_address(&sg[0]); ++ memcpy(&desc->layer_param.s0_param, &pxp_conf->s0_param, ++ sizeof(struct pxp_layer_param)); ++ } else if (i == 1) { ++ pxp_conf->out_param.paddr = sg_dma_address(&sg[1]); ++ memcpy(&desc->layer_param.out_param, ++ &pxp_conf->out_param, ++ sizeof(struct pxp_layer_param)); ++ } ++ ++ desc = desc->next; ++ } ++ ++ /* Submitting our TX starts the PxP processing task */ ++ cookie = txd->tx_submit(txd); ++ if (cookie < 0) { ++ pr_err("Error sending FB through PxP\n"); ++ return -EIO; ++ } ++ ++ cam->txd = txd; ++ ++ /* trigger PxP */ ++ dma_async_issue_pending(dma_chan); ++ ++ return 0; ++} ++ ++static int pxp_complete_update(cam_data *cam) ++{ ++ int ret; ++ /* ++ * Wait for completion event, which will be set ++ * through our TX callback function. ++ */ ++ ret = wait_for_completion_timeout(&cam->pxp_tx_cmpl, HZ / 10); ++ if (ret <= 0) { ++ pr_warning("PxP operation failed due to %s\n", ++ ret < 0 ? "user interrupt" : "timeout"); ++ dma_release_channel(&cam->pxp_chan->dma_chan); ++ cam->pxp_chan = NULL; ++ return ret ? : -ETIMEDOUT; ++ } ++ ++ dma_release_channel(&cam->pxp_chan->dma_chan); ++ cam->pxp_chan = NULL; ++ ++ pr_debug("TX completed\n"); ++ ++ return 0; ++} ++ ++/*! ++ * Camera V4l2 callback function. ++ * ++ * @param mask u32 ++ * @param dev void device structure ++ * ++ * @return none ++ */ ++static void camera_callback(u32 mask, void *dev) ++{ ++ struct mxc_v4l_frame *done_frame; ++ struct mxc_v4l_frame *ready_frame; ++ cam_data *cam; ++ ++ cam = (cam_data *) dev; ++ if (cam == NULL) ++ return; ++ ++ spin_lock(&cam->queue_int_lock); ++ spin_lock(&cam->dqueue_int_lock); ++ if (!list_empty(&cam->working_q)) { ++ done_frame = list_entry(cam->working_q.next, ++ struct mxc_v4l_frame, queue); ++ ++ if (done_frame->csi_buf_num != cam->ping_pong_csi) ++ goto next; ++ ++ if (done_frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) { ++ done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE; ++ done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; ++ ++ /* Added to the done queue */ ++ list_del(cam->working_q.next); ++ list_add_tail(&done_frame->queue, &cam->done_q); ++ cam->enc_counter++; ++ wake_up_interruptible(&cam->enc_queue); ++ } else { ++ pr_err("ERROR: v4l2 capture: %s: " ++ "buffer not queued\n", __func__); ++ } ++ } ++ ++next: ++ if (!list_empty(&cam->ready_q)) { ++ ready_frame = list_entry(cam->ready_q.next, ++ struct mxc_v4l_frame, queue); ++ list_del(cam->ready_q.next); ++ list_add_tail(&ready_frame->queue, &cam->working_q); ++ ++ __raw_writel(ready_frame->paddress, ++ cam->ping_pong_csi == 1 ? CSI_CSIDMASA_FB1 : ++ CSI_CSIDMASA_FB2); ++ ready_frame->csi_buf_num = cam->ping_pong_csi; ++ } else { ++ __raw_writel(cam->dummy_frame.paddress, ++ cam->ping_pong_csi == 1 ? CSI_CSIDMASA_FB1 : ++ CSI_CSIDMASA_FB2); ++ } ++ spin_unlock(&cam->dqueue_int_lock); ++ spin_unlock(&cam->queue_int_lock); ++ ++ return; ++} ++ ++/*! ++ * Make csi ready for capture image. ++ * ++ * @param cam structure cam_data * ++ * ++ * @return status 0 success ++ */ ++static int csi_cap_image(cam_data *cam) ++{ ++ unsigned int value; ++ ++ value = __raw_readl(CSI_CSICR3); ++ __raw_writel(value | BIT_FRMCNT_RST, CSI_CSICR3); ++ value = __raw_readl(CSI_CSISR); ++ __raw_writel(value, CSI_CSISR); ++ ++ return 0; ++} ++ ++/*************************************************************************** ++ * Functions for handling Frame buffers. ++ **************************************************************************/ ++ ++/*! ++ * Free frame buffers ++ * ++ * @param cam Structure cam_data * ++ * ++ * @return status 0 success. ++ */ ++static int csi_free_frame_buf(cam_data *cam) ++{ ++ int i; ++ ++ pr_debug("MVC: In %s\n", __func__); ++ ++ for (i = 0; i < FRAME_NUM; i++) { ++ if (cam->frame[i].vaddress != 0) { ++ dma_free_coherent(0, cam->frame[i].buffer.length, ++ cam->frame[i].vaddress, ++ cam->frame[i].paddress); ++ cam->frame[i].vaddress = 0; ++ } ++ } ++ ++ if (cam->dummy_frame.vaddress != 0) { ++ dma_free_coherent(0, cam->dummy_frame.buffer.length, ++ cam->dummy_frame.vaddress, ++ cam->dummy_frame.paddress); ++ cam->dummy_frame.vaddress = 0; ++ } ++ ++ return 0; ++} ++ ++/*! ++ * Allocate frame buffers ++ * ++ * @param cam Structure cam_data * ++ * @param count int number of buffer need to allocated ++ * ++ * @return status -0 Successfully allocated a buffer, -ENOBUFS failed. ++ */ ++static int csi_allocate_frame_buf(cam_data *cam, int count) ++{ ++ int i; ++ ++ pr_debug("In MVC:%s- size=%d\n", ++ __func__, cam->v2f.fmt.pix.sizeimage); ++ for (i = 0; i < count; i++) { ++ cam->frame[i].vaddress = dma_alloc_coherent(0, PAGE_ALIGN ++ (cam->v2f.fmt. ++ pix.sizeimage), ++ &cam->frame[i]. ++ paddress, ++ GFP_DMA | ++ GFP_KERNEL); ++ if (cam->frame[i].vaddress == 0) { ++ pr_err("ERROR: v4l2 capture: " ++ "%s failed.\n", __func__); ++ csi_free_frame_buf(cam); ++ return -ENOBUFS; ++ } ++ cam->frame[i].buffer.index = i; ++ cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED; ++ cam->frame[i].buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ cam->frame[i].buffer.length = cam->v2f.fmt.pix.sizeimage; ++ cam->frame[i].buffer.memory = V4L2_MEMORY_MMAP; ++ cam->frame[i].buffer.m.offset = cam->frame[i].paddress; ++ cam->frame[i].index = i; ++ cam->frame[i].csi_buf_num = 0; ++ } ++ ++ return 0; ++} ++ ++/*! ++ * Free frame buffers status ++ * ++ * @param cam Structure cam_data * ++ * ++ * @return none ++ */ ++static void csi_free_frames(cam_data *cam) ++{ ++ int i; ++ ++ pr_debug("In MVC: %s\n", __func__); ++ ++ for (i = 0; i < FRAME_NUM; i++) ++ cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED; ++ ++ cam->enc_counter = 0; ++ INIT_LIST_HEAD(&cam->ready_q); ++ INIT_LIST_HEAD(&cam->working_q); ++ INIT_LIST_HEAD(&cam->done_q); ++ ++ return; ++} ++ ++/*! ++ * Return the buffer status ++ * ++ * @param cam Structure cam_data * ++ * @param buf Structure v4l2_buffer * ++ * ++ * @return status 0 success, EINVAL failed. ++ */ ++static int csi_v4l2_buffer_status(cam_data *cam, struct v4l2_buffer *buf) ++{ ++ pr_debug("In MVC: %s\n", __func__); ++ ++ if (buf->index < 0 || buf->index >= FRAME_NUM) { ++ pr_err("ERROR: v4l2 capture: %s buffers " ++ "not allocated\n", __func__); ++ return -EINVAL; ++ } ++ ++ memcpy(buf, &(cam->frame[buf->index].buffer), sizeof(*buf)); ++ ++ return 0; ++} ++ ++static int csi_v4l2_release_bufs(cam_data *cam) ++{ ++ pr_debug("In MVC:csi_v4l2_release_bufs\n"); ++ return 0; ++} ++ ++static int csi_v4l2_prepare_bufs(cam_data *cam, struct v4l2_buffer *buf) ++{ ++ pr_debug("In MVC:csi_v4l2_prepare_bufs\n"); ++ ++ if (buf->index < 0 || buf->index >= FRAME_NUM || buf->length < ++ cam->v2f.fmt.pix.sizeimage) { ++ pr_err("ERROR: v4l2 capture: csi_v4l2_prepare_bufs buffers " ++ "not allocated,index=%d, length=%d\n", buf->index, ++ buf->length); ++ return -EINVAL; ++ } ++ ++ cam->frame[buf->index].buffer.index = buf->index; ++ cam->frame[buf->index].buffer.flags = V4L2_BUF_FLAG_MAPPED; ++ cam->frame[buf->index].buffer.length = buf->length; ++ cam->frame[buf->index].buffer.m.offset = cam->frame[buf->index].paddress ++ = buf->m.offset; ++ cam->frame[buf->index].buffer.type = buf->type; ++ cam->frame[buf->index].buffer.memory = V4L2_MEMORY_USERPTR; ++ cam->frame[buf->index].index = buf->index; ++ ++ return 0; ++} ++ ++/*! ++ * Indicates whether the palette is supported. ++ * ++ * @param palette V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_UYVY or V4L2_PIX_FMT_YUV420 ++ * ++ * @return 0 if failed ++ */ ++static inline int valid_mode(u32 palette) ++{ ++ return (palette == V4L2_PIX_FMT_RGB565) || ++ (palette == V4L2_PIX_FMT_YUYV) || ++ (palette == V4L2_PIX_FMT_UYVY) || (palette == V4L2_PIX_FMT_YUV420); ++} ++ ++/*! ++ * Start stream I/O ++ * ++ * @param cam structure cam_data * ++ * ++ * @return status 0 Success ++ */ ++static int csi_streamon(cam_data *cam) ++{ ++ struct mxc_v4l_frame *frame; ++ unsigned long flags; ++ unsigned long val; ++ int timeout, timeout2; ++ ++ pr_debug("In MVC: %s\n", __func__); ++ ++ if (NULL == cam) { ++ pr_err("ERROR: v4l2 capture: %s cam parameter is NULL\n", ++ __func__); ++ return -1; ++ } ++ cam->dummy_frame.vaddress = dma_alloc_coherent(0, ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), ++ &cam->dummy_frame.paddress, ++ GFP_DMA | GFP_KERNEL); ++ if (cam->dummy_frame.vaddress == 0) { ++ pr_err("ERROR: v4l2 capture: Allocate dummy frame " ++ "failed.\n"); ++ return -ENOBUFS; ++ } ++ cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE; ++ cam->dummy_frame.buffer.length = cam->v2f.fmt.pix.sizeimage; ++ cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress; ++ ++ spin_lock_irqsave(&cam->queue_int_lock, flags); ++ /* move the frame from readyq to workingq */ ++ if (list_empty(&cam->ready_q)) { ++ pr_err("ERROR: v4l2 capture: %s: " ++ "ready_q queue empty\n", __func__); ++ spin_unlock_irqrestore(&cam->queue_int_lock, flags); ++ return -1; ++ } ++ frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); ++ list_del(cam->ready_q.next); ++ list_add_tail(&frame->queue, &cam->working_q); ++ __raw_writel(frame->paddress, CSI_CSIDMASA_FB1); ++ frame->csi_buf_num = 1; ++ ++ if (list_empty(&cam->ready_q)) { ++ pr_err("ERROR: v4l2 capture: %s: " ++ "ready_q queue empty\n", __func__); ++ spin_unlock_irqrestore(&cam->queue_int_lock, flags); ++ return -1; ++ } ++ frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); ++ list_del(cam->ready_q.next); ++ list_add_tail(&frame->queue, &cam->working_q); ++ __raw_writel(frame->paddress, CSI_CSIDMASA_FB2); ++ frame->csi_buf_num = 2; ++ spin_unlock_irqrestore(&cam->queue_int_lock, flags); ++ ++ cam->capture_pid = current->pid; ++ cam->capture_on = true; ++ csi_cap_image(cam); ++ ++ local_irq_save(flags); ++ for (timeout = 1000000; timeout > 0; timeout--) { ++ if (__raw_readl(CSI_CSISR) & BIT_SOF_INT) { ++ val = __raw_readl(CSI_CSICR3); ++ __raw_writel(val | BIT_DMA_REFLASH_RFF, CSI_CSICR3); ++ for (timeout2 = 1000000; timeout2 > 0; timeout2--) { ++ if (__raw_readl(CSI_CSICR3) & ++ BIT_DMA_REFLASH_RFF) ++ cpu_relax(); ++ else ++ break; ++ } ++ if (timeout2 <= 0) { ++ pr_err("timeout when wait for reflash done.\n"); ++ local_irq_restore(flags); ++ return -ETIME; ++ } ++ ++ csi_dmareq_rff_enable(); ++ csi_enable_int(1); ++ break; ++ } else ++ cpu_relax(); ++ } ++ if (timeout <= 0) { ++ pr_err("timeout when wait for SOF\n"); ++ local_irq_restore(flags); ++ return -ETIME; ++ } ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++/*! ++ * Stop stream I/O ++ * ++ * @param cam structure cam_data * ++ * ++ * @return status 0 Success ++ */ ++static int csi_streamoff(cam_data *cam) ++{ ++ pr_debug("In MVC: %s\n", __func__); ++ ++ if (cam->capture_on == false) ++ return 0; ++ ++ csi_dmareq_rff_disable(); ++ csi_disable_int(); ++ cam->capture_on = false; ++ ++ /* set CSI_CSIDMASA_FB1 and CSI_CSIDMASA_FB2 to default value */ ++ __raw_writel(0, CSI_CSIDMASA_FB1); ++ __raw_writel(0, CSI_CSIDMASA_FB2); ++ ++ csi_free_frames(cam); ++ csi_free_frame_buf(cam); ++ ++ return 0; ++} ++ ++/*! ++ * start the viewfinder job ++ * ++ * @param cam structure cam_data * ++ * ++ * @return status 0 Success ++ */ ++static int start_preview(cam_data *cam) ++{ ++ unsigned long fb_addr = (unsigned long)cam->v4l2_fb.base; ++ ++ __raw_writel(fb_addr, CSI_CSIDMASA_FB1); ++ __raw_writel(fb_addr, CSI_CSIDMASA_FB2); ++ __raw_writel(__raw_readl(CSI_CSICR3) | BIT_DMA_REFLASH_RFF, CSI_CSICR3); ++ ++ csi_enable_int(0); ++ ++ return 0; ++} ++ ++/*! ++ * shut down the viewfinder job ++ * ++ * @param cam structure cam_data * ++ * ++ * @return status 0 Success ++ */ ++static int stop_preview(cam_data *cam) ++{ ++ csi_disable_int(); ++ ++ /* set CSI_CSIDMASA_FB1 and CSI_CSIDMASA_FB2 to default value */ ++ __raw_writel(0, CSI_CSIDMASA_FB1); ++ __raw_writel(0, CSI_CSIDMASA_FB2); ++ __raw_writel(__raw_readl(CSI_CSICR3) | BIT_DMA_REFLASH_RFF, CSI_CSICR3); ++ ++ return 0; ++} ++ ++/*************************************************************************** ++ * VIDIOC Functions. ++ **************************************************************************/ ++ ++/*! ++ * ++ * @param cam structure cam_data * ++ * ++ * @param f structure v4l2_format * ++ * ++ * @return status 0 success, EINVAL failed ++ */ ++static int csi_v4l2_g_fmt(cam_data *cam, struct v4l2_format *f) ++{ ++ int retval = 0; ++ ++ switch (f->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); ++ f->fmt.pix = cam->v2f.fmt.pix; ++ break; ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ pr_debug(" type is V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); ++ f->fmt.win = cam->win; ++ break; ++ default: ++ pr_debug(" type is invalid\n"); ++ retval = -EINVAL; ++ } ++ ++ pr_debug("End of %s: v2f pix widthxheight %d x %d\n", ++ __func__, cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); ++ ++ return retval; ++} ++ ++/*! ++ * V4L2 - csi_v4l2_s_fmt function ++ * ++ * @param cam structure cam_data * ++ * ++ * @param f structure v4l2_format * ++ * ++ * @return status 0 success, EINVAL failed ++ */ ++static int csi_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f) ++{ ++ int retval = 0; ++ int size = 0; ++ int bytesperline = 0; ++ int *width, *height; ++ ++ pr_debug("In MVC: %s\n", __func__); ++ ++ switch (f->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ pr_debug(" type=V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); ++ if (!valid_mode(f->fmt.pix.pixelformat)) { ++ pr_err("ERROR: v4l2 capture: %s: format " ++ "not supported\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* Handle case where size requested is larger than cuurent ++ * camera setting. */ ++ if ((f->fmt.pix.width > cam->crop_bounds.width) ++ || (f->fmt.pix.height > cam->crop_bounds.height)) { ++ /* Need the logic here, calling vidioc_s_param if ++ * camera can change. */ ++ pr_debug("csi_v4l2_s_fmt size changed\n"); ++ } ++ if (cam->rotation % 180) { ++ height = &f->fmt.pix.width; ++ width = &f->fmt.pix.height; ++ } else { ++ width = &f->fmt.pix.width; ++ height = &f->fmt.pix.height; ++ } ++ ++ if ((cam->crop_bounds.width / *width > 8) || ++ ((cam->crop_bounds.width / *width == 8) && ++ (cam->crop_bounds.width % *width))) { ++ *width = cam->crop_bounds.width / 8; ++ if (*width % 8) ++ *width += 8 - *width % 8; ++ pr_err("ERROR: v4l2 capture: width exceeds limit " ++ "resize to %d.\n", *width); ++ } ++ ++ if ((cam->crop_bounds.height / *height > 8) || ++ ((cam->crop_bounds.height / *height == 8) && ++ (cam->crop_bounds.height % *height))) { ++ *height = cam->crop_bounds.height / 8; ++ if (*height % 8) ++ *height += 8 - *height % 8; ++ pr_err("ERROR: v4l2 capture: height exceeds limit " ++ "resize to %d.\n", *height); ++ } ++ ++ switch (f->fmt.pix.pixelformat) { ++ case V4L2_PIX_FMT_RGB565: ++ size = f->fmt.pix.width * f->fmt.pix.height * 2; ++ csi_init_format(V4L2_PIX_FMT_UYVY); ++ csi_set_16bit_imagpara(f->fmt.pix.width, ++ f->fmt.pix.height); ++ bytesperline = f->fmt.pix.width * 2; ++ break; ++ case V4L2_PIX_FMT_UYVY: ++ size = f->fmt.pix.width * f->fmt.pix.height * 2; ++ csi_init_format(f->fmt.pix.pixelformat); ++ csi_set_16bit_imagpara(f->fmt.pix.width, ++ f->fmt.pix.height); ++ bytesperline = f->fmt.pix.width * 2; ++ break; ++ case V4L2_PIX_FMT_YUYV: ++ size = f->fmt.pix.width * f->fmt.pix.height * 2; ++ csi_init_format(f->fmt.pix.pixelformat); ++ csi_set_16bit_imagpara(f->fmt.pix.width, ++ f->fmt.pix.height); ++ bytesperline = f->fmt.pix.width * 2; ++ break; ++ case V4L2_PIX_FMT_YUV420: ++ size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2; ++ csi_set_12bit_imagpara(f->fmt.pix.width, ++ f->fmt.pix.height); ++ bytesperline = f->fmt.pix.width; ++ break; ++ case V4L2_PIX_FMT_YUV422P: ++ case V4L2_PIX_FMT_RGB24: ++ case V4L2_PIX_FMT_BGR24: ++ case V4L2_PIX_FMT_BGR32: ++ case V4L2_PIX_FMT_RGB32: ++ case V4L2_PIX_FMT_NV12: ++ default: ++ pr_debug(" case not supported\n"); ++ break; ++ } ++ ++ if (f->fmt.pix.bytesperline < bytesperline) ++ f->fmt.pix.bytesperline = bytesperline; ++ else ++ bytesperline = f->fmt.pix.bytesperline; ++ ++ if (f->fmt.pix.sizeimage < size) ++ f->fmt.pix.sizeimage = size; ++ else ++ size = f->fmt.pix.sizeimage; ++ ++ cam->v2f.fmt.pix = f->fmt.pix; ++ ++ if (cam->v2f.fmt.pix.priv != 0) { ++ if (copy_from_user(&cam->offset, ++ (void *)cam->v2f.fmt.pix.priv, ++ sizeof(cam->offset))) { ++ retval = -EFAULT; ++ break; ++ } ++ } ++ break; ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ pr_debug(" type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); ++ cam->win = f->fmt.win; ++ win_current = f->fmt.win; ++ size = win_current.w.width * win_current.w.height * 2; ++ if (cam->v2f.fmt.pix.sizeimage < size) ++ cam->v2f.fmt.pix.sizeimage = size; ++ ++ break; ++ default: ++ retval = -EINVAL; ++ } ++ ++ pr_debug("End of %s: v2f pix widthxheight %d x %d\n", ++ __func__, cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); ++ ++ return retval; ++} ++ ++/*! ++ * V4L2 - csi_v4l2_s_param function ++ * Allows setting of capturemode and frame rate. ++ * ++ * @param cam structure cam_data * ++ * @param parm structure v4l2_streamparm * ++ * ++ * @return status 0 success, EINVAL failed ++ */ ++static int csi_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) ++{ ++ struct v4l2_ifparm ifparm; ++ struct v4l2_format cam_fmt; ++ struct v4l2_streamparm currentparm; ++ int err = 0; ++ ++ pr_debug("In %s\n", __func__); ++ ++ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { ++ pr_err(KERN_ERR "%s invalid type\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* Stop the viewfinder */ ++ if (cam->overlay_on == true) ++ stop_preview(cam); ++ ++ currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ++ /* First check that this device can support the changes requested. */ ++ err = vidioc_int_g_parm(cam->sensor, ¤tparm); ++ if (err) { ++ pr_err("%s: vidioc_int_g_parm returned an error %d\n", ++ __func__, err); ++ goto exit; ++ } ++ ++ pr_debug(" Current capabilities are %x\n", ++ currentparm.parm.capture.capability); ++ pr_debug(" Current capturemode is %d change to %d\n", ++ currentparm.parm.capture.capturemode, ++ parm->parm.capture.capturemode); ++ pr_debug(" Current framerate is %d change to %d\n", ++ currentparm.parm.capture.timeperframe.denominator, ++ parm->parm.capture.timeperframe.denominator); ++ ++ err = vidioc_int_s_parm(cam->sensor, parm); ++ if (err) { ++ pr_err("%s: vidioc_int_s_parm returned an error %d\n", ++ __func__, err); ++ goto exit; ++ } ++ ++ vidioc_int_g_ifparm(cam->sensor, &ifparm); ++ cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); ++ pr_debug(" g_fmt_cap returns widthxheight of input as %d x %d\n", ++ cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height); ++ ++ cam->crop_bounds.top = cam->crop_bounds.left = 0; ++ cam->crop_bounds.width = cam_fmt.fmt.pix.width; ++ cam->crop_bounds.height = cam_fmt.fmt.pix.height; ++ cam->crop_current.width = cam->crop_bounds.width; ++ cam->crop_current.height = cam->crop_bounds.height; ++ ++exit: ++ return err; ++} ++ ++static int pxp_set_cstate(cam_data *cam, struct v4l2_control *vc) ++{ ++ struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; ++ ++ if (vc->id == V4L2_CID_HFLIP) { ++ proc_data->hflip = vc->value; ++ } else if (vc->id == V4L2_CID_VFLIP) { ++ proc_data->vflip = vc->value; ++ } else if (vc->id == V4L2_CID_PRIVATE_BASE) { ++ if (vc->value % 90) ++ return -ERANGE; ++ proc_data->rotate = vc->value; ++ cam->rotation = vc->value; ++ } ++ ++ return 0; ++} ++ ++static int pxp_get_cstate(cam_data *cam, struct v4l2_control *vc) ++{ ++ struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; ++ ++ if (vc->id == V4L2_CID_HFLIP) ++ vc->value = proc_data->hflip; ++ else if (vc->id == V4L2_CID_VFLIP) ++ vc->value = proc_data->vflip; ++ else if (vc->id == V4L2_CID_PRIVATE_BASE) ++ vc->value = proc_data->rotate; ++ ++ return 0; ++} ++ ++ ++/*! ++ * Dequeue one V4L capture buffer ++ * ++ * @param cam structure cam_data * ++ * @param buf structure v4l2_buffer * ++ * ++ * @return status 0 success, EINVAL invalid frame number ++ * ETIME timeout, ERESTARTSYS interrupted by user ++ */ ++static int csi_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf) ++{ ++ int retval = 0; ++ struct mxc_v4l_frame *frame; ++ unsigned long lock_flags; ++ ++ if (!wait_event_interruptible_timeout(cam->enc_queue, ++ cam->enc_counter != 0, 10 * HZ)) { ++ pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue timeout " ++ "enc_counter %x\n", cam->enc_counter); ++ return -ETIME; ++ } else if (signal_pending(current)) { ++ pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue() " ++ "interrupt received\n"); ++ return -ERESTARTSYS; ++ } ++ ++ if (down_interruptible(&cam->busy_lock)) ++ return -EBUSY; ++ ++ spin_lock_irqsave(&cam->dqueue_int_lock, lock_flags); ++ ++ if (list_empty(&cam->done_q)) { ++ spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags); ++ up(&cam->busy_lock); ++ return -EINVAL; ++ } ++ ++ cam->enc_counter--; ++ ++ frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue); ++ list_del(cam->done_q.next); ++ ++ if (frame->buffer.flags & V4L2_BUF_FLAG_DONE) { ++ frame->buffer.flags &= ~V4L2_BUF_FLAG_DONE; ++ } else if (frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: " ++ "Buffer not filled.\n"); ++ frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; ++ retval = -EINVAL; ++ } else if ((frame->buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: " ++ "Buffer not queued.\n"); ++ retval = -EINVAL; ++ } ++ ++ spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags); ++ ++ buf->bytesused = cam->v2f.fmt.pix.sizeimage; ++ buf->index = frame->index; ++ buf->flags = frame->buffer.flags; ++ buf->m = cam->frame[frame->index].buffer.m; ++ ++ /* ++ * Note: ++ * If want to do preview on LCD, use PxP CSC to convert from UYVY ++ * to RGB565; but for encoding, usually we don't use RGB format. ++ */ ++ if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { ++ sg_dma_address(&cam->sg[0]) = buf->m.offset; ++ sg_dma_address(&cam->sg[1]) = ++ cam->frame[req_buf_number].paddress; ++ retval = pxp_process_update(cam); ++ if (retval) { ++ pr_err("Unable to submit PxP update task.\n"); ++ return retval; ++ } ++ pxp_complete_update(cam); ++ if (cam->frame[buf->index].vaddress) ++ memcpy(cam->frame[buf->index].vaddress, ++ cam->frame[req_buf_number].vaddress, ++ cam->v2f.fmt.pix.sizeimage); ++ } ++ up(&cam->busy_lock); ++ ++ return retval; ++} ++ ++/*! ++ * V4L interface - open function ++ * ++ * @param file structure file * ++ * ++ * @return status 0 success, ENODEV invalid device instance, ++ * ENODEV timeout, ERESTARTSYS interrupted by user ++ */ ++static int csi_v4l_open(struct file *file) ++{ ++ struct v4l2_ifparm ifparm; ++ struct v4l2_format cam_fmt; ++ struct video_device *dev = video_devdata(file); ++ cam_data *cam = video_get_drvdata(dev); ++ struct sensor_data *sensor; ++ int err = 0; ++ ++ pr_debug(" device name is %s\n", dev->name); ++ ++ if (!cam) { ++ pr_err("%s: Internal error, cam_data not found!\n", __func__); ++ return -EBADF; ++ } ++ ++ if (!cam->sensor) { ++ pr_err("%s: Internal error, camera is not found!\n", __func__); ++ return -EBADF; ++ } ++ ++ sensor = cam->sensor->priv; ++ if (!sensor) { ++ pr_err("%s: Internal error, sensor_data is not found!\n", __func__); ++ return -EBADF; ++ } ++ ++ down(&cam->busy_lock); ++ err = 0; ++ if (signal_pending(current)) ++ goto oops; ++ ++ if (cam->open_count++ == 0) { ++ wait_event_interruptible(cam->power_queue, ++ cam->low_power == false); ++ ++ cam->enc_counter = 0; ++ INIT_LIST_HEAD(&cam->ready_q); ++ INIT_LIST_HEAD(&cam->working_q); ++ INIT_LIST_HEAD(&cam->done_q); ++ ++ vidioc_int_g_ifparm(cam->sensor, &ifparm); ++ ++ cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ clk_prepare_enable(sensor->sensor_clk); ++ vidioc_int_s_power(cam->sensor, 1); ++ vidioc_int_init(cam->sensor); ++ vidioc_int_dev_init(cam->sensor); ++ } ++ ++ file->private_data = dev; ++ ++oops: ++ up(&cam->busy_lock); ++ return err; ++} ++ ++/*! ++ * V4L interface - close function ++ * ++ * @param file struct file * ++ * ++ * @return 0 success ++ */ ++static int csi_v4l_close(struct file *file) ++{ ++ struct video_device *dev = video_devdata(file); ++ int err = 0; ++ cam_data *cam = video_get_drvdata(dev); ++ struct sensor_data *sensor; ++ ++ pr_debug("In MVC:%s\n", __func__); ++ ++ if (!cam) { ++ pr_err("%s: Internal error, cam_data not found!\n", __func__); ++ return -EBADF; ++ } ++ ++ if (!cam->sensor) { ++ pr_err("%s: Internal error, camera is not found!\n", __func__); ++ return -EBADF; ++ } ++ ++ sensor = cam->sensor->priv; ++ if (!sensor) { ++ pr_err("%s: Internal error, sensor_data is not found!\n", __func__); ++ return -EBADF; ++ } ++ ++ /* for the case somebody hit the ctrl C */ ++ if (cam->overlay_pid == current->pid) { ++ err = stop_preview(cam); ++ cam->overlay_on = false; ++ } ++ ++ if (--cam->open_count == 0) { ++ wait_event_interruptible(cam->power_queue, ++ cam->low_power == false); ++ file->private_data = NULL; ++ vidioc_int_s_power(cam->sensor, 0); ++ clk_disable_unprepare(sensor->sensor_clk); ++ } ++ ++ return err; ++} ++ ++/* ++ * V4L interface - read function ++ * ++ * @param file struct file * ++ * @param read buf char * ++ * @param count size_t ++ * @param ppos structure loff_t * ++ * ++ * @return bytes read ++ */ ++static ssize_t csi_v4l_read(struct file *file, char *buf, size_t count, ++ loff_t *ppos) ++{ ++ int err = 0; ++ struct video_device *dev = video_devdata(file); ++ cam_data *cam = video_get_drvdata(dev); ++ ++ if (down_interruptible(&cam->busy_lock)) ++ return -EINTR; ++ ++ /* Stop the viewfinder */ ++ if (cam->overlay_on == true) ++ stop_preview(cam); ++ ++ if (cam->still_buf_vaddr == NULL) { ++ cam->still_buf_vaddr = dma_alloc_coherent(0, ++ PAGE_ALIGN ++ (cam->v2f.fmt. ++ pix.sizeimage), ++ &cam-> ++ still_buf[0], ++ GFP_DMA | GFP_KERNEL); ++ if (cam->still_buf_vaddr == NULL) { ++ pr_err("alloc dma memory failed\n"); ++ return -ENOMEM; ++ } ++ cam->still_counter = 0; ++ __raw_writel(cam->still_buf[0], CSI_CSIDMASA_FB2); ++ __raw_writel(cam->still_buf[0], CSI_CSIDMASA_FB1); ++ __raw_writel(__raw_readl(CSI_CSICR3) | BIT_DMA_REFLASH_RFF, ++ CSI_CSICR3); ++ __raw_writel(__raw_readl(CSI_CSISR), CSI_CSISR); ++ __raw_writel(__raw_readl(CSI_CSICR3) | BIT_FRMCNT_RST, ++ CSI_CSICR3); ++ csi_enable_int(1); ++ } ++ ++ wait_event_interruptible(cam->still_queue, cam->still_counter); ++ csi_disable_int(); ++ err = copy_to_user(buf, cam->still_buf_vaddr, ++ cam->v2f.fmt.pix.sizeimage); ++ ++ if (cam->still_buf_vaddr != NULL) { ++ dma_free_coherent(0, PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), ++ cam->still_buf_vaddr, cam->still_buf[0]); ++ cam->still_buf[0] = 0; ++ cam->still_buf_vaddr = NULL; ++ } ++ ++ if (cam->overlay_on == true) ++ start_preview(cam); ++ ++ up(&cam->busy_lock); ++ if (err < 0) ++ return err; ++ ++ return cam->v2f.fmt.pix.sizeimage - err; ++} ++ ++/*! ++ * V4L interface - ioctl function ++ * ++ * @param file struct file* ++ * ++ * @param ioctlnr unsigned int ++ * ++ * @param arg void* ++ * ++ * @return 0 success, ENODEV for invalid device instance, ++ * -1 for other errors. ++ */ ++static long csi_v4l_do_ioctl(struct file *file, ++ unsigned int ioctlnr, void *arg) ++{ ++ struct video_device *dev = video_devdata(file); ++ cam_data *cam = video_get_drvdata(dev); ++ int retval = 0; ++ unsigned long lock_flags; ++ ++ pr_debug("In MVC: %s, %x\n", __func__, ioctlnr); ++ wait_event_interruptible(cam->power_queue, cam->low_power == false); ++ /* make this _really_ smp-safe */ ++ if (ioctlnr != VIDIOC_DQBUF) ++ if (down_interruptible(&cam->busy_lock)) ++ return -EBUSY; ++ ++ switch (ioctlnr) { ++ /*! ++ * V4l2 VIDIOC_G_FMT ioctl ++ */ ++ case VIDIOC_G_FMT:{ ++ struct v4l2_format *gf = arg; ++ pr_debug(" case VIDIOC_G_FMT\n"); ++ retval = csi_v4l2_g_fmt(cam, gf); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_S_FMT ioctl ++ */ ++ case VIDIOC_S_FMT:{ ++ struct v4l2_format *sf = arg; ++ pr_debug(" case VIDIOC_S_FMT\n"); ++ retval = csi_v4l2_s_fmt(cam, sf); ++ vidioc_int_s_fmt_cap(cam->sensor, sf); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_OVERLAY ioctl ++ */ ++ case VIDIOC_OVERLAY:{ ++ int *on = arg; ++ pr_debug(" case VIDIOC_OVERLAY\n"); ++ if (*on) { ++ cam->overlay_on = true; ++ cam->overlay_pid = current->pid; ++ start_preview(cam); ++ } ++ if (!*on) { ++ stop_preview(cam); ++ cam->overlay_on = false; ++ } ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_G_FBUF ioctl ++ */ ++ case VIDIOC_G_FBUF:{ ++ struct v4l2_framebuffer *fb = arg; ++ *fb = cam->v4l2_fb; ++ fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY; ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_S_FBUF ioctl ++ */ ++ case VIDIOC_S_FBUF:{ ++ struct v4l2_framebuffer *fb = arg; ++ cam->v4l2_fb = *fb; ++ break; ++ } ++ ++ case VIDIOC_G_PARM:{ ++ struct v4l2_streamparm *parm = arg; ++ pr_debug(" case VIDIOC_G_PARM\n"); ++ vidioc_int_g_parm(cam->sensor, parm); ++ break; ++ } ++ ++ case VIDIOC_S_PARM:{ ++ struct v4l2_streamparm *parm = arg; ++ pr_debug(" case VIDIOC_S_PARM\n"); ++ retval = csi_v4l2_s_param(cam, parm); ++ break; ++ } ++ ++ case VIDIOC_QUERYCAP:{ ++ struct v4l2_capability *cap = arg; ++ pr_debug(" case VIDIOC_QUERYCAP\n"); ++ strcpy(cap->driver, "csi_v4l2"); ++ cap->version = KERNEL_VERSION(0, 1, 11); ++ cap->capabilities = V4L2_CAP_VIDEO_OVERLAY | ++ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | ++ V4L2_CAP_VIDEO_OUTPUT_OVERLAY | V4L2_CAP_READWRITE; ++ cap->card[0] = '\0'; ++ cap->bus_info[0] = '\0'; ++ break; ++ } ++ ++ case VIDIOC_CROPCAP: ++ { ++ struct v4l2_cropcap *cap = arg; ++ ++ if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && ++ cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) { ++ retval = -EINVAL; ++ break; ++ } ++ cap->bounds = cam->crop_bounds; ++ cap->defrect = cam->crop_defrect; ++ break; ++ } ++ case VIDIOC_S_CROP: ++ { ++ struct v4l2_crop *crop = arg; ++ struct v4l2_rect *b = &cam->crop_bounds; ++ ++ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { ++ retval = -EINVAL; ++ break; ++ } ++ ++ crop->c.top = (crop->c.top < b->top) ? b->top ++ : crop->c.top; ++ if (crop->c.top > b->top + b->height) ++ crop->c.top = b->top + b->height - 1; ++ if (crop->c.height > b->top + b->height - crop->c.top) ++ crop->c.height = ++ b->top + b->height - crop->c.top; ++ ++ crop->c.left = (crop->c.left < b->left) ? b->left ++ : crop->c.left; ++ if (crop->c.left > b->left + b->width) ++ crop->c.left = b->left + b->width - 1; ++ if (crop->c.width > b->left - crop->c.left + b->width) ++ crop->c.width = ++ b->left - crop->c.left + b->width; ++ ++ crop->c.width -= crop->c.width % 8; ++ crop->c.height -= crop->c.height % 8; ++ ++ crop_current.c = crop->c; ++ ++ break; ++ } ++ case VIDIOC_G_CROP: ++ { ++ struct v4l2_crop *crop = arg; ++ ++ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { ++ retval = -EINVAL; ++ break; ++ } ++ crop->c = crop_current.c; ++ ++ break; ++ ++ } ++ case VIDIOC_REQBUFS: { ++ struct v4l2_requestbuffers *req = arg; ++ pr_debug(" case VIDIOC_REQBUFS\n"); ++ ++ if (req->count > FRAME_NUM) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: " ++ "not enough buffers\n"); ++ req->count = FRAME_NUM; ++ } ++ ++ if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: " ++ "wrong buffer type\n"); ++ retval = -EINVAL; ++ break; ++ } ++ ++ csi_streamoff(cam); ++ if (req->memory & V4L2_MEMORY_MMAP) { ++ csi_free_frame_buf(cam); ++ retval = csi_allocate_frame_buf(cam, req->count + 1); ++ req_buf_number = req->count; ++ } ++ break; ++ } ++ ++ case VIDIOC_QUERYBUF: { ++ struct v4l2_buffer *buf = arg; ++ int index = buf->index; ++ pr_debug(" case VIDIOC_QUERYBUF\n"); ++ ++ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { ++ retval = -EINVAL; ++ break; ++ } ++ ++ if (buf->memory & V4L2_MEMORY_MMAP) { ++ memset(buf, 0, sizeof(buf)); ++ buf->index = index; ++ } ++ ++ down(&cam->param_lock); ++ if (buf->memory & V4L2_MEMORY_USERPTR) { ++ csi_v4l2_release_bufs(cam); ++ retval = csi_v4l2_prepare_bufs(cam, buf); ++ } ++ if (buf->memory & V4L2_MEMORY_MMAP) ++ retval = csi_v4l2_buffer_status(cam, buf); ++ up(&cam->param_lock); ++ break; ++ } ++ ++ case VIDIOC_QBUF: { ++ struct v4l2_buffer *buf = arg; ++ int index = buf->index; ++ pr_debug(" case VIDIOC_QBUF\n"); ++ ++ spin_lock_irqsave(&cam->queue_int_lock, lock_flags); ++ cam->frame[index].buffer.m.offset = buf->m.offset; ++ if ((cam->frame[index].buffer.flags & 0x7) == ++ V4L2_BUF_FLAG_MAPPED) { ++ cam->frame[index].buffer.flags |= V4L2_BUF_FLAG_QUEUED; ++ list_add_tail(&cam->frame[index].queue, &cam->ready_q); ++ } else if (cam->frame[index].buffer.flags & ++ V4L2_BUF_FLAG_QUEUED) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: " ++ "buffer already queued\n"); ++ retval = -EINVAL; ++ } else if (cam->frame[index].buffer. ++ flags & V4L2_BUF_FLAG_DONE) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: " ++ "overwrite done buffer.\n"); ++ cam->frame[index].buffer.flags &= ++ ~V4L2_BUF_FLAG_DONE; ++ cam->frame[index].buffer.flags |= ++ V4L2_BUF_FLAG_QUEUED; ++ retval = -EINVAL; ++ } ++ buf->flags = cam->frame[index].buffer.flags; ++ spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); ++ ++ break; ++ } ++ ++ case VIDIOC_DQBUF: { ++ struct v4l2_buffer *buf = arg; ++ pr_debug(" case VIDIOC_DQBUF\n"); ++ ++ retval = csi_v4l_dqueue(cam, buf); ++ ++ break; ++ } ++ ++ case VIDIOC_STREAMON: { ++ pr_debug(" case VIDIOC_STREAMON\n"); ++ retval = csi_streamon(cam); ++ break; ++ } ++ ++ case VIDIOC_STREAMOFF: { ++ pr_debug(" case VIDIOC_STREAMOFF\n"); ++ retval = csi_streamoff(cam); ++ break; ++ } ++ case VIDIOC_ENUM_FMT: { ++ struct v4l2_fmtdesc *fmt = arg; ++ if (cam->sensor) ++ retval = vidioc_int_enum_fmt_cap(cam->sensor, fmt); ++ else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ retval = -ENODEV; ++ } ++ break; ++ } ++ case VIDIOC_ENUM_FRAMESIZES: { ++ struct v4l2_frmsizeenum *fsize = arg; ++ if (cam->sensor) ++ retval = vidioc_int_enum_framesizes(cam->sensor, fsize); ++ else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ retval = -ENODEV; ++ } ++ break; ++ } ++ case VIDIOC_ENUM_FRAMEINTERVALS: { ++ struct v4l2_frmivalenum *fival = arg; ++ if (cam->sensor) ++ retval = vidioc_int_enum_frameintervals(cam->sensor, ++ fival); ++ else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ retval = -ENODEV; ++ } ++ break; ++ } ++ case VIDIOC_DBG_G_CHIP_IDENT: { ++ struct v4l2_dbg_chip_ident *p = arg; ++ p->ident = V4L2_IDENT_NONE; ++ p->revision = 0; ++ if (cam->sensor) ++ retval = vidioc_int_g_chip_ident(cam->sensor, (int *)p); ++ else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ retval = -ENODEV; ++ } ++ break; ++ } ++ ++ case VIDIOC_S_CTRL: ++ { ++ struct v4l2_control *vc = arg; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) ++ if (vc->id == pxp_controls[i].id) { ++ if (vc->value < pxp_controls[i].minimum || ++ vc->value > pxp_controls[i].maximum) { ++ retval = -ERANGE; ++ break; ++ } ++ retval = pxp_set_cstate(cam, vc); ++ break; ++ } ++ ++ if (i >= ARRAY_SIZE(pxp_controls)) ++ retval = -EINVAL; ++ break; ++ ++ } ++ case VIDIOC_G_CTRL: ++ { ++ struct v4l2_control *vc = arg; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) ++ if (vc->id == pxp_controls[i].id) { ++ retval = pxp_get_cstate(cam, vc); ++ break; ++ } ++ ++ if (i >= ARRAY_SIZE(pxp_controls)) ++ retval = -EINVAL; ++ break; ++ } ++ case VIDIOC_QUERYCTRL: ++ { ++ struct v4l2_queryctrl *qc = arg; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) ++ if (qc->id && qc->id == pxp_controls[i].id) { ++ memcpy(qc, &(pxp_controls[i]), sizeof(*qc)); ++ break; ++ } ++ ++ if (i >= ARRAY_SIZE(pxp_controls)) ++ retval = -EINVAL; ++ break; ++ } ++ case VIDIOC_G_STD: ++ case VIDIOC_G_OUTPUT: ++ case VIDIOC_S_OUTPUT: ++ case VIDIOC_ENUMSTD: ++ case VIDIOC_S_STD: ++ case VIDIOC_TRY_FMT: ++ case VIDIOC_ENUMINPUT: ++ case VIDIOC_G_INPUT: ++ case VIDIOC_S_INPUT: ++ case VIDIOC_G_TUNER: ++ case VIDIOC_S_TUNER: ++ case VIDIOC_G_FREQUENCY: ++ case VIDIOC_S_FREQUENCY: ++ case VIDIOC_ENUMOUTPUT: ++ default: ++ pr_debug(" case not supported\n"); ++ retval = -EINVAL; ++ break; ++ } ++ ++ if (ioctlnr != VIDIOC_DQBUF) ++ up(&cam->busy_lock); ++ return retval; ++} ++ ++/* ++ * V4L interface - ioctl function ++ * ++ * @return None ++ */ ++static long csi_v4l_ioctl(struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ return video_usercopy(file, cmd, arg, csi_v4l_do_ioctl); ++} ++ ++/*! ++ * V4L interface - mmap function ++ * ++ * @param file structure file * ++ * ++ * @param vma structure vm_area_struct * ++ * ++ * @return status 0 Success, EINTR busy lock error, ENOBUFS remap_page error ++ */ ++static int csi_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct video_device *dev = video_devdata(file); ++ unsigned long size; ++ int res = 0; ++ cam_data *cam = video_get_drvdata(dev); ++ ++ pr_debug("%s\n", __func__); ++ pr_debug("\npgoff=0x%lx, start=0x%lx, end=0x%lx\n", ++ vma->vm_pgoff, vma->vm_start, vma->vm_end); ++ ++ /* make this _really_ smp-safe */ ++ if (down_interruptible(&cam->busy_lock)) ++ return -EINTR; ++ ++ size = vma->vm_end - vma->vm_start; ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++ ++ if (remap_pfn_range(vma, vma->vm_start, ++ vma->vm_pgoff, size, vma->vm_page_prot)) { ++ pr_err("ERROR: v4l2 capture: %s : " ++ "remap_pfn_range failed\n", __func__); ++ res = -ENOBUFS; ++ goto csi_mmap_exit; ++ } ++ ++ vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ ++ ++csi_mmap_exit: ++ up(&cam->busy_lock); ++ return res; ++} ++ ++/*! ++ * This structure defines the functions to be called in this driver. ++ */ ++static struct v4l2_file_operations csi_v4l_fops = { ++ .owner = THIS_MODULE, ++ .open = csi_v4l_open, ++ .release = csi_v4l_close, ++ .read = csi_v4l_read, ++ .ioctl = csi_v4l_ioctl, ++ .mmap = csi_mmap, ++}; ++ ++static struct video_device csi_v4l_template = { ++ .name = "Mx25 Camera", ++ .fops = &csi_v4l_fops, ++ .release = video_device_release, ++}; ++ ++/*! ++ * initialize cam_data structure ++ * ++ * @param cam structure cam_data * ++ * ++ * @return status 0 Success ++ */ ++static void init_camera_struct(cam_data *cam) ++{ ++ struct pxp_proc_data *proc_data = &cam->pxp_conf.proc_data; ++ pr_debug("In MVC: %s\n", __func__); ++ ++ proc_data->hflip = 0; ++ proc_data->vflip = 0; ++ proc_data->rotate = 0; ++ proc_data->bgcolor = 0; ++ ++ /* Default everything to 0 */ ++ memset(cam, 0, sizeof(cam_data)); ++ ++ sema_init(&cam->param_lock, 1); ++ sema_init(&cam->busy_lock, 1); ++ ++ cam->video_dev = video_device_alloc(); ++ if (cam->video_dev == NULL) ++ return; ++ ++ *(cam->video_dev) = csi_v4l_template; ++ ++ video_set_drvdata(cam->video_dev, cam); ++ cam->video_dev->minor = -1; ++ ++ init_waitqueue_head(&cam->enc_queue); ++ init_waitqueue_head(&cam->still_queue); ++ ++ cam->streamparm.parm.capture.capturemode = 0; ++ ++ cam->standard.index = 0; ++ cam->standard.id = V4L2_STD_UNKNOWN; ++ cam->standard.frameperiod.denominator = 30; ++ cam->standard.frameperiod.numerator = 1; ++ cam->standard.framelines = 480; ++ cam->standard_autodetect = true; ++ cam->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ cam->streamparm.parm.capture.timeperframe = cam->standard.frameperiod; ++ cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; ++ cam->overlay_on = false; ++ cam->capture_on = false; ++ cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY; ++ ++ cam->v2f.fmt.pix.sizeimage = 480 * 640 * 2; ++ cam->v2f.fmt.pix.bytesperline = 640 * 2; ++ cam->v2f.fmt.pix.width = 640; ++ cam->v2f.fmt.pix.height = 480; ++ cam->v2f.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; ++ cam->win.w.width = 160; ++ cam->win.w.height = 160; ++ cam->win.w.left = 0; ++ cam->win.w.top = 0; ++ cam->still_counter = 0; ++ /* setup cropping */ ++ cam->crop_bounds.left = 0; ++ cam->crop_bounds.width = 640; ++ cam->crop_bounds.top = 0; ++ cam->crop_bounds.height = 480; ++ cam->crop_current = cam->crop_defrect = cam->crop_bounds; ++ ++ cam->enc_callback = camera_callback; ++ csi_start_callback(cam); ++ init_waitqueue_head(&cam->power_queue); ++ spin_lock_init(&cam->queue_int_lock); ++ spin_lock_init(&cam->dqueue_int_lock); ++} ++ ++/*! ++ * camera_power function ++ * Turns Sensor power On/Off ++ * ++ * @param cam cam data struct ++ * @param cameraOn true to turn camera on, false to turn off power. ++ * ++ * @return status ++ */ ++static u8 camera_power(cam_data *cam, bool cameraOn) ++{ ++ pr_debug("In MVC: %s on=%d\n", __func__, cameraOn); ++ ++ if (cameraOn == true) { ++ vidioc_int_s_power(cam->sensor, 1); ++ } else { ++ vidioc_int_s_power(cam->sensor, 0); ++ } ++ return 0; ++} ++ ++static const struct of_device_id imx_csi_v4l2_dt_ids[] = { ++ { .compatible = "fsl,imx6sl-csi-v4l2", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, imx_csi_v4l2_dt_ids); ++ ++static int csi_v4l2_probe(struct platform_device *pdev) ++{ ++ struct scatterlist *sg; ++ u8 err = 0; ++ ++ /* Create g_cam and initialize it. */ ++ g_cam = kmalloc(sizeof(cam_data), GFP_KERNEL); ++ if (g_cam == NULL) { ++ pr_err("ERROR: v4l2 capture: failed to register camera\n"); ++ err = -ENOMEM; ++ goto out; ++ } ++ memset(&crop_current, 0, sizeof(crop_current)); ++ memset(&win_current, 0, sizeof(win_current)); ++ init_camera_struct(g_cam); ++ platform_set_drvdata(pdev, (void *)g_cam); ++ ++ /* Set up the v4l2 device and register it */ ++ csi_v4l2_int_device.priv = g_cam; ++ /* This function contains a bug that won't let this be rmmod'd. */ ++ v4l2_int_device_register(&csi_v4l2_int_device); ++ ++ /* register v4l video device */ ++ if (video_register_device(g_cam->video_dev, VFL_TYPE_GRABBER, video_nr) ++ == -1) { ++ kfree(g_cam); ++ g_cam = NULL; ++ pr_err("ERROR: v4l2 capture: video_register_device failed\n"); ++ err = -ENODEV; ++ goto out; ++ } ++ pr_debug(" Video device registered: %s #%d\n", ++ g_cam->video_dev->name, g_cam->video_dev->minor); ++ ++ g_cam->pxp_chan = NULL; ++ /* Initialize Scatter-gather list containing 2 buffer addresses. */ ++ sg = g_cam->sg; ++ sg_init_table(sg, 2); ++ ++out: ++ return err; ++} ++ ++static int csi_v4l2_remove(struct platform_device *pdev) ++{ ++ if (g_cam->open_count) { ++ pr_err("ERROR: v4l2 capture:camera open " ++ "-- setting ops to NULL\n"); ++ } else { ++ pr_info("V4L2 freeing image input device\n"); ++ v4l2_int_device_unregister(&csi_v4l2_int_device); ++ csi_stop_callback(g_cam); ++ video_unregister_device(g_cam->video_dev); ++ platform_set_drvdata(pdev, NULL); ++ ++ kfree(g_cam); ++ g_cam = NULL; ++ } ++ ++ return 0; ++} ++ ++/*! ++ * This function is called to put the sensor in a low power state. ++ * Refer to the document driver-model/driver.txt in the kernel source tree ++ * for more information. ++ * ++ * @param pdev the device structure used to give information on which I2C ++ * to suspend ++ * @param state the power state the device is entering ++ * ++ * @return The function returns 0 on success and -1 on failure. ++ */ ++static int csi_v4l2_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ cam_data *cam = platform_get_drvdata(pdev); ++ ++ pr_debug("In MVC: %s\n", __func__); ++ ++ if (cam == NULL) ++ return -1; ++ ++ cam->low_power = true; ++ ++ if (cam->overlay_on == true) ++ stop_preview(cam); ++ ++ if (cam->capture_on == true || cam->overlay_on == true) ++ camera_power(cam, false); ++ ++ return 0; ++} ++ ++/*! ++ * This function is called to bring the sensor back from a low power state. ++ * Refer to the document driver-model/driver.txt in the kernel source tree ++ * for more information. ++ * ++ * @param pdev the device structure ++ * ++ * @return The function returns 0 on success and -1 on failure ++ */ ++static int csi_v4l2_resume(struct platform_device *pdev) ++{ ++ cam_data *cam = platform_get_drvdata(pdev); ++ ++ pr_debug("In MVC: %s\n", __func__); ++ ++ if (cam == NULL) ++ return -1; ++ ++ cam->low_power = false; ++ wake_up_interruptible(&cam->power_queue); ++ if (cam->capture_on == true || cam->overlay_on == true) ++ camera_power(cam, true); ++ ++ if (cam->overlay_on == true) ++ start_preview(cam); ++ ++ return 0; ++} ++ ++/*! ++ * This structure contains pointers to the power management callback functions. ++ */ ++static struct platform_driver csi_v4l2_driver = { ++ .driver = { ++ .name = "csi_v4l2", ++ .of_match_table = of_match_ptr(imx_csi_v4l2_dt_ids), ++ }, ++ .probe = csi_v4l2_probe, ++ .remove = csi_v4l2_remove, ++#ifdef CONFIG_PM ++ .suspend = csi_v4l2_suspend, ++ .resume = csi_v4l2_resume, ++#endif ++ .shutdown = NULL, ++}; ++ ++/*! ++ * Initializes the camera driver. ++ */ ++static int csi_v4l2_master_attach(struct v4l2_int_device *slave) ++{ ++ cam_data *cam = slave->u.slave->master->priv; ++ struct v4l2_format cam_fmt; ++ ++ pr_debug("In MVC: %s\n", __func__); ++ pr_debug(" slave.name = %s\n", slave->name); ++ pr_debug(" master.name = %s\n", slave->u.slave->master->name); ++ ++ cam->sensor = slave; ++ if (slave == NULL) { ++ pr_err("ERROR: v4l2 capture: slave parameter not valid.\n"); ++ return -1; ++ } ++ ++ cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); ++ ++ /* Used to detect TV in (type 1) vs. camera (type 0) */ ++ cam->device_type = cam_fmt.fmt.pix.priv; ++ ++ cam->crop_bounds.top = cam->crop_bounds.left = 0; ++ cam->crop_bounds.width = cam_fmt.fmt.pix.width; ++ cam->crop_bounds.height = cam_fmt.fmt.pix.height; ++ ++ /* This also is the max crop size for this device. */ ++ cam->crop_defrect.top = cam->crop_defrect.left = 0; ++ cam->crop_defrect.width = cam_fmt.fmt.pix.width; ++ cam->crop_defrect.height = cam_fmt.fmt.pix.height; ++ ++ /* At this point, this is also the current image size. */ ++ cam->crop_current.top = cam->crop_current.left = 0; ++ cam->crop_current.width = cam_fmt.fmt.pix.width; ++ cam->crop_current.height = cam_fmt.fmt.pix.height; ++ ++ pr_debug("End of %s: v2f pix widthxheight %d x %d\n", ++ __func__, cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); ++ ++ return 0; ++} ++ ++/*! ++ * Disconnects the camera driver. ++ */ ++static void csi_v4l2_master_detach(struct v4l2_int_device *slave) ++{ ++ pr_debug("In MVC: %s\n", __func__); ++ ++ vidioc_int_dev_exit(slave); ++} ++ ++module_platform_driver(csi_v4l2_driver); ++ ++module_param(video_nr, int, 0444); ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("V4L2 capture driver for Mx25 based cameras"); ++MODULE_LICENSE("GPL"); ++MODULE_SUPPORTED_DEVICE("video"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/fsl_csi.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/fsl_csi.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/fsl_csi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/fsl_csi.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,302 @@ ++/* ++ * Copyright 2009-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file fsl_csi.c, this file is derived from mx27_csi.c ++ * ++ * @brief mx25 CMOS Sensor interface functions ++ * ++ * @ingroup CSI ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mxc_v4l2_capture.h" ++#include "fsl_csi.h" ++ ++void __iomem *csi_regbase; ++EXPORT_SYMBOL(csi_regbase); ++static int irq_nr; ++static csi_irq_callback_t g_callback; ++static void *g_callback_data; ++ ++static irqreturn_t csi_irq_handler(int irq, void *data) ++{ ++ cam_data *cam = (cam_data *) data; ++ unsigned long status = __raw_readl(CSI_CSISR); ++ ++ __raw_writel(status, CSI_CSISR); ++ ++ if (status & BIT_HRESP_ERR_INT) ++ pr_warning("Hresponse error is detected.\n"); ++ ++ if (status & BIT_DMA_TSF_DONE_FB1) { ++ if (cam->capture_on) { ++ spin_lock(&cam->queue_int_lock); ++ cam->ping_pong_csi = 1; ++ spin_unlock(&cam->queue_int_lock); ++ cam->enc_callback(0, cam); ++ } else { ++ cam->still_counter++; ++ wake_up_interruptible(&cam->still_queue); ++ } ++ } ++ ++ if (status & BIT_DMA_TSF_DONE_FB2) { ++ if (cam->capture_on) { ++ spin_lock(&cam->queue_int_lock); ++ cam->ping_pong_csi = 2; ++ spin_unlock(&cam->queue_int_lock); ++ cam->enc_callback(0, cam); ++ } else { ++ cam->still_counter++; ++ wake_up_interruptible(&cam->still_queue); ++ } ++ } ++ ++ if (g_callback) ++ g_callback(g_callback_data, status); ++ ++ pr_debug("CSI status = 0x%08lX\n", status); ++ ++ return IRQ_HANDLED; ++} ++ ++static void csihw_reset_frame_count(void) ++{ ++ __raw_writel(__raw_readl(CSI_CSICR3) | BIT_FRMCNT_RST, CSI_CSICR3); ++} ++ ++static void csihw_reset(void) ++{ ++ csihw_reset_frame_count(); ++ __raw_writel(CSICR1_RESET_VAL, CSI_CSICR1); ++ __raw_writel(CSICR2_RESET_VAL, CSI_CSICR2); ++ __raw_writel(CSICR3_RESET_VAL, CSI_CSICR3); ++} ++ ++/*! ++ * csi_init_interface ++ * Init csi interface ++ */ ++void csi_init_interface(void) ++{ ++ unsigned int val = 0; ++ unsigned int imag_para; ++ ++ val |= BIT_SOF_POL; ++ val |= BIT_REDGE; ++ val |= BIT_GCLK_MODE; ++ val |= BIT_HSYNC_POL; ++ val |= BIT_PACK_DIR; ++ val |= BIT_FCC; ++ val |= BIT_SWAP16_EN; ++ val |= 1 << SHIFT_MCLKDIV; ++ val |= BIT_MCLKEN; ++ __raw_writel(val, CSI_CSICR1); ++ ++ imag_para = (640 << 16) | 960; ++ __raw_writel(imag_para, CSI_CSIIMAG_PARA); ++ ++ val = 0x1010; ++ val |= BIT_DMA_REFLASH_RFF; ++ __raw_writel(val, CSI_CSICR3); ++} ++EXPORT_SYMBOL(csi_init_interface); ++ ++void csi_init_format(int fmt) ++{ ++ unsigned int val; ++ ++ val = __raw_readl(CSI_CSICR1); ++ if (fmt == V4L2_PIX_FMT_YUYV) { ++ val &= ~BIT_PACK_DIR; ++ val &= ~BIT_SWAP16_EN; ++ } else if (fmt == V4L2_PIX_FMT_UYVY) { ++ val |= BIT_PACK_DIR; ++ val |= BIT_SWAP16_EN; ++ } else ++ pr_warning("unsupported format, old format remains.\n"); ++ ++ __raw_writel(val, CSI_CSICR1); ++} ++EXPORT_SYMBOL(csi_init_format); ++ ++/*! ++ * csi_read_mclk_flag ++ * ++ * @return gcsi_mclk_source ++ */ ++int csi_read_mclk_flag(void) ++{ ++ return 0; ++} ++EXPORT_SYMBOL(csi_read_mclk_flag); ++ ++void csi_start_callback(void *data) ++{ ++ cam_data *cam = (cam_data *) data; ++ ++ if (request_irq(irq_nr, csi_irq_handler, 0, "csi", cam) < 0) ++ pr_debug("CSI error: irq request fail\n"); ++ ++} ++EXPORT_SYMBOL(csi_start_callback); ++ ++void csi_stop_callback(void *data) ++{ ++ cam_data *cam = (cam_data *) data; ++ ++ free_irq(irq_nr, cam); ++} ++EXPORT_SYMBOL(csi_stop_callback); ++ ++void csi_enable_int(int arg) ++{ ++ unsigned long cr1 = __raw_readl(CSI_CSICR1); ++ ++ cr1 |= BIT_SOF_INTEN; ++ if (arg == 1) { ++ /* still capture needs DMA intterrupt */ ++ cr1 |= BIT_FB1_DMA_DONE_INTEN; ++ cr1 |= BIT_FB2_DMA_DONE_INTEN; ++ } ++ __raw_writel(cr1, CSI_CSICR1); ++} ++EXPORT_SYMBOL(csi_enable_int); ++ ++void csi_disable_int(void) ++{ ++ unsigned long cr1 = __raw_readl(CSI_CSICR1); ++ ++ cr1 &= ~BIT_SOF_INTEN; ++ cr1 &= ~BIT_FB1_DMA_DONE_INTEN; ++ cr1 &= ~BIT_FB2_DMA_DONE_INTEN; ++ __raw_writel(cr1, CSI_CSICR1); ++} ++EXPORT_SYMBOL(csi_disable_int); ++ ++void csi_set_16bit_imagpara(int width, int height) ++{ ++ int imag_para = 0; ++ unsigned long cr3 = __raw_readl(CSI_CSICR3); ++ ++ imag_para = (width << 16) | (height * 2); ++ __raw_writel(imag_para, CSI_CSIIMAG_PARA); ++ ++ /* reflash the embeded DMA controller */ ++ __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, CSI_CSICR3); ++} ++EXPORT_SYMBOL(csi_set_16bit_imagpara); ++ ++void csi_set_12bit_imagpara(int width, int height) ++{ ++ int imag_para = 0; ++ unsigned long cr3 = __raw_readl(CSI_CSICR3); ++ ++ imag_para = (width << 16) | (height * 3 / 2); ++ __raw_writel(imag_para, CSI_CSIIMAG_PARA); ++ ++ /* reflash the embeded DMA controller */ ++ __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, CSI_CSICR3); ++} ++EXPORT_SYMBOL(csi_set_12bit_imagpara); ++ ++void csi_dmareq_rff_enable(void) ++{ ++ unsigned long cr3 = __raw_readl(CSI_CSICR3); ++ ++ cr3 |= BIT_DMA_REQ_EN_RFF; ++ cr3 |= BIT_HRESP_ERR_EN; ++ __raw_writel(cr3, CSI_CSICR3); ++} ++EXPORT_SYMBOL(csi_dmareq_rff_enable); ++ ++void csi_dmareq_rff_disable(void) ++{ ++ unsigned long cr3 = __raw_readl(CSI_CSICR3); ++ ++ cr3 &= ~BIT_DMA_REQ_EN_RFF; ++ cr3 &= ~BIT_HRESP_ERR_EN; ++ __raw_writel(cr3, CSI_CSICR3); ++} ++EXPORT_SYMBOL(csi_dmareq_rff_disable); ++ ++static const struct of_device_id fsl_csi_dt_ids[] = { ++ { .compatible = "fsl,imx6sl-csi", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, fsl_csi_dt_ids); ++ ++static int csi_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct resource *res; ++ ++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "No csi irq found.\n"); ++ ret = -ENODEV; ++ goto err; ++ } ++ irq_nr = res->start; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ dev_err(&pdev->dev, "No csi base address found.\n"); ++ ret = -ENODEV; ++ goto err; ++ } ++ csi_regbase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); ++ if (!csi_regbase) { ++ dev_err(&pdev->dev, "ioremap failed with csi base\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ csihw_reset(); ++ csi_init_interface(); ++ csi_dmareq_rff_disable(); ++ ++err: ++ return ret; ++} ++ ++static int csi_remove(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++static struct platform_driver csi_driver = { ++ .driver = { ++ .name = "fsl_csi", ++ .of_match_table = of_match_ptr(fsl_csi_dt_ids), ++ }, ++ .probe = csi_probe, ++ .remove = csi_remove, ++}; ++ ++module_platform_driver(csi_driver); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("fsl CSI driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/fsl_csi.h linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/fsl_csi.h +--- linux-3.10.30/drivers/media/platform/mxc/capture/fsl_csi.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/fsl_csi.h 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,198 @@ ++/* ++ * Copyright 2009-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file fsl_csi.h ++ * ++ * @brief mx25 CMOS Sensor interface functions ++ * ++ * @ingroup CSI ++ */ ++ ++#ifndef MX25_CSI_H ++#define MX25_CSI_H ++ ++#include ++ ++/* reset values */ ++#define CSICR1_RESET_VAL 0x40000800 ++#define CSICR2_RESET_VAL 0x0 ++#define CSICR3_RESET_VAL 0x0 ++ ++/* csi control reg 1 */ ++#define BIT_SWAP16_EN (0x1 << 31) ++#define BIT_EXT_VSYNC (0x1 << 30) ++#define BIT_EOF_INT_EN (0x1 << 29) ++#define BIT_PRP_IF_EN (0x1 << 28) ++#define BIT_CCIR_MODE (0x1 << 27) ++#define BIT_COF_INT_EN (0x1 << 26) ++#define BIT_SF_OR_INTEN (0x1 << 25) ++#define BIT_RF_OR_INTEN (0x1 << 24) ++#define BIT_SFF_DMA_DONE_INTEN (0x1 << 22) ++#define BIT_STATFF_INTEN (0x1 << 21) ++#define BIT_FB2_DMA_DONE_INTEN (0x1 << 20) ++#define BIT_FB1_DMA_DONE_INTEN (0x1 << 19) ++#define BIT_RXFF_INTEN (0x1 << 18) ++#define BIT_SOF_POL (0x1 << 17) ++#define BIT_SOF_INTEN (0x1 << 16) ++#define BIT_MCLKDIV (0xF << 12) ++#define BIT_HSYNC_POL (0x1 << 11) ++#define BIT_CCIR_EN (0x1 << 10) ++#define BIT_MCLKEN (0x1 << 9) ++#define BIT_FCC (0x1 << 8) ++#define BIT_PACK_DIR (0x1 << 7) ++#define BIT_CLR_STATFIFO (0x1 << 6) ++#define BIT_CLR_RXFIFO (0x1 << 5) ++#define BIT_GCLK_MODE (0x1 << 4) ++#define BIT_INV_DATA (0x1 << 3) ++#define BIT_INV_PCLK (0x1 << 2) ++#define BIT_REDGE (0x1 << 1) ++#define BIT_PIXEL_BIT (0x1 << 0) ++ ++#define SHIFT_MCLKDIV 12 ++ ++/* control reg 3 */ ++#define BIT_FRMCNT (0xFFFF << 16) ++#define BIT_FRMCNT_RST (0x1 << 15) ++#define BIT_DMA_REFLASH_RFF (0x1 << 14) ++#define BIT_DMA_REFLASH_SFF (0x1 << 13) ++#define BIT_DMA_REQ_EN_RFF (0x1 << 12) ++#define BIT_DMA_REQ_EN_SFF (0x1 << 11) ++#define BIT_STATFF_LEVEL (0x7 << 8) ++#define BIT_HRESP_ERR_EN (0x1 << 7) ++#define BIT_RXFF_LEVEL (0x7 << 4) ++#define BIT_TWO_8BIT_SENSOR (0x1 << 3) ++#define BIT_ZERO_PACK_EN (0x1 << 2) ++#define BIT_ECC_INT_EN (0x1 << 1) ++#define BIT_ECC_AUTO_EN (0x1 << 0) ++ ++#define SHIFT_FRMCNT 16 ++ ++/* csi status reg */ ++#define BIT_SFF_OR_INT (0x1 << 25) ++#define BIT_RFF_OR_INT (0x1 << 24) ++#define BIT_DMA_TSF_DONE_SFF (0x1 << 22) ++#define BIT_STATFF_INT (0x1 << 21) ++#define BIT_DMA_TSF_DONE_FB2 (0x1 << 20) ++#define BIT_DMA_TSF_DONE_FB1 (0x1 << 19) ++#define BIT_RXFF_INT (0x1 << 18) ++#define BIT_EOF_INT (0x1 << 17) ++#define BIT_SOF_INT (0x1 << 16) ++#define BIT_F2_INT (0x1 << 15) ++#define BIT_F1_INT (0x1 << 14) ++#define BIT_COF_INT (0x1 << 13) ++#define BIT_HRESP_ERR_INT (0x1 << 7) ++#define BIT_ECC_INT (0x1 << 1) ++#define BIT_DRDY (0x1 << 0) ++ ++#define CSI_MCLK_VF 1 ++#define CSI_MCLK_ENC 2 ++#define CSI_MCLK_RAW 4 ++#define CSI_MCLK_I2C 8 ++#endif ++ ++extern void __iomem *csi_regbase; ++#define CSI_CSICR1 (csi_regbase) ++#define CSI_CSICR2 (csi_regbase + 0x4) ++#define CSI_CSICR3 (csi_regbase + 0x8) ++#define CSI_STATFIFO (csi_regbase + 0xC) ++#define CSI_CSIRXFIFO (csi_regbase + 0x10) ++#define CSI_CSIRXCNT (csi_regbase + 0x14) ++#define CSI_CSISR (csi_regbase + 0x18) ++ ++#define CSI_CSIDBG (csi_regbase + 0x1C) ++#define CSI_CSIDMASA_STATFIFO (csi_regbase + 0x20) ++#define CSI_CSIDMATS_STATFIFO (csi_regbase + 0x24) ++#define CSI_CSIDMASA_FB1 (csi_regbase + 0x28) ++#define CSI_CSIDMASA_FB2 (csi_regbase + 0x2C) ++#define CSI_CSIFBUF_PARA (csi_regbase + 0x30) ++#define CSI_CSIIMAG_PARA (csi_regbase + 0x34) ++ ++static inline void csi_clear_status(unsigned long status) ++{ ++ __raw_writel(status, CSI_CSISR); ++} ++ ++struct csi_signal_cfg_t { ++ unsigned data_width:3; ++ unsigned clk_mode:2; ++ unsigned ext_vsync:1; ++ unsigned Vsync_pol:1; ++ unsigned Hsync_pol:1; ++ unsigned pixclk_pol:1; ++ unsigned data_pol:1; ++ unsigned sens_clksrc:1; ++}; ++ ++struct csi_config_t { ++ /* control reg 1 */ ++ unsigned int swap16_en:1; ++ unsigned int ext_vsync:1; ++ unsigned int eof_int_en:1; ++ unsigned int prp_if_en:1; ++ unsigned int ccir_mode:1; ++ unsigned int cof_int_en:1; ++ unsigned int sf_or_inten:1; ++ unsigned int rf_or_inten:1; ++ unsigned int sff_dma_done_inten:1; ++ unsigned int statff_inten:1; ++ unsigned int fb2_dma_done_inten:1; ++ unsigned int fb1_dma_done_inten:1; ++ unsigned int rxff_inten:1; ++ unsigned int sof_pol:1; ++ unsigned int sof_inten:1; ++ unsigned int mclkdiv:4; ++ unsigned int hsync_pol:1; ++ unsigned int ccir_en:1; ++ unsigned int mclken:1; ++ unsigned int fcc:1; ++ unsigned int pack_dir:1; ++ unsigned int gclk_mode:1; ++ unsigned int inv_data:1; ++ unsigned int inv_pclk:1; ++ unsigned int redge:1; ++ unsigned int pixel_bit:1; ++ ++ /* control reg 3 */ ++ unsigned int frmcnt:16; ++ unsigned int frame_reset:1; ++ unsigned int dma_reflash_rff:1; ++ unsigned int dma_reflash_sff:1; ++ unsigned int dma_req_en_rff:1; ++ unsigned int dma_req_en_sff:1; ++ unsigned int statff_level:3; ++ unsigned int hresp_err_en:1; ++ unsigned int rxff_level:3; ++ unsigned int two_8bit_sensor:1; ++ unsigned int zero_pack_en:1; ++ unsigned int ecc_int_en:1; ++ unsigned int ecc_auto_en:1; ++ /* fifo counter */ ++ unsigned int rxcnt; ++}; ++ ++typedef void (*csi_irq_callback_t) (void *data, unsigned long status); ++ ++void csi_init_interface(void); ++void csi_init_format(int fmt); ++void csi_set_16bit_imagpara(int width, int height); ++void csi_set_12bit_imagpara(int width, int height); ++int csi_read_mclk_flag(void); ++void csi_start_callback(void *data); ++void csi_stop_callback(void *data); ++void csi_enable_int(int arg); ++void csi_disable_int(void); ++void csi_mclk_enable(void); ++void csi_mclk_disable(void); ++void csi_dmareq_rff_enable(void); ++void csi_dmareq_rff_disable(void); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,554 @@ ++ ++/* ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file ipu_bg_overlay_sdc_bg.c ++ * ++ * @brief IPU Use case for PRP-VF back-ground ++ * ++ * @ingroup IPU ++ */ ++#include ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++#include "ipu_prp_sw.h" ++ ++static int csi_buffer_num; ++static u32 bpp, csi_mem_bufsize = 3; ++static u32 out_format; ++static struct ipu_soc *disp_ipu; ++static u32 offset; ++ ++static void csi_buf_work_func(struct work_struct *work) ++{ ++ int err = 0; ++ cam_data *cam = ++ container_of(work, struct _cam_data, csi_work_struct); ++ ++ struct ipu_task task; ++ memset(&task, 0, sizeof(task)); ++ ++ if (csi_buffer_num) ++ task.input.paddr = cam->vf_bufs[0]; ++ else ++ task.input.paddr = cam->vf_bufs[1]; ++ task.input.width = cam->crop_current.width; ++ task.input.height = cam->crop_current.height; ++ task.input.format = IPU_PIX_FMT_UYVY; ++ ++ task.output.paddr = offset; ++ task.output.width = cam->overlay_fb->var.xres; ++ task.output.height = cam->overlay_fb->var.yres; ++ task.output.format = out_format; ++ task.output.rotate = cam->rotation; ++ task.output.crop.pos.x = cam->win.w.left; ++ task.output.crop.pos.y = cam->win.w.top; ++ if (cam->win.w.width > 1024 || cam->win.w.height > 1024) { ++ task.output.crop.w = cam->overlay_fb->var.xres; ++ task.output.crop.h = cam->overlay_fb->var.yres; ++ } else { ++ task.output.crop.w = cam->win.w.width; ++ task.output.crop.h = cam->win.w.height; ++ } ++again: ++ err = ipu_check_task(&task); ++ if (err != IPU_CHECK_OK) { ++ if (err > IPU_CHECK_ERR_MIN) { ++ if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) { ++ task.input.crop.w -= 8; ++ goto again; ++ } ++ if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) { ++ task.input.crop.h -= 8; ++ goto again; ++ } ++ if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) { ++ task.output.width -= 8; ++ task.output.crop.w = task.output.width; ++ goto again; ++ } ++ if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) { ++ task.output.height -= 8; ++ task.output.crop.h = task.output.height; ++ goto again; ++ } ++ printk(KERN_ERR "check ipu taks fail\n"); ++ return; ++ } ++ printk(KERN_ERR "check ipu taks fail\n"); ++ return; ++ } ++ err = ipu_queue_task(&task); ++ if (err < 0) ++ printk(KERN_ERR "queue ipu task error\n"); ++} ++ ++static void get_disp_ipu(cam_data *cam) ++{ ++ if (cam->output > 2) ++ disp_ipu = ipu_get_soc(1); /* using DISP4 */ ++ else ++ disp_ipu = ipu_get_soc(0); ++} ++ ++ ++/*! ++ * csi ENC callback function. ++ * ++ * @param irq int irq line ++ * @param dev_id void * device id ++ * ++ * @return status IRQ_HANDLED for handled ++ */ ++static irqreturn_t csi_enc_callback(int irq, void *dev_id) ++{ ++ cam_data *cam = (cam_data *) dev_id; ++ ++ ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, csi_buffer_num); ++ schedule_work(&cam->csi_work_struct); ++ csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0; ++ return IRQ_HANDLED; ++} ++ ++static int csi_enc_setup(cam_data *cam) ++{ ++ ipu_channel_params_t params; ++ u32 pixel_fmt; ++ int err = 0, sensor_protocol = 0; ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ if (!cam) { ++ printk(KERN_ERR "cam private is NULL\n"); ++ return -ENXIO; ++ } ++ ++ memset(¶ms, 0, sizeof(ipu_channel_params_t)); ++ params.csi_mem.csi = cam->csi; ++ ++ sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi); ++ switch (sensor_protocol) { ++ case IPU_CSI_CLK_MODE_GATED_CLK: ++ case IPU_CSI_CLK_MODE_NONGATED_CLK: ++ case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: ++ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: ++ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: ++ params.csi_mem.interlaced = false; ++ break; ++ case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: ++ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: ++ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: ++ params.csi_mem.interlaced = true; ++ break; ++ default: ++ printk(KERN_ERR "sensor protocol unsupported\n"); ++ return -EINVAL; ++ } ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) { ++ params.csi_mem.mipi_en = true; ++ params.csi_mem.mipi_vc = ++ mipi_csi2_get_virtual_channel(mipi_csi2_info); ++ params.csi_mem.mipi_id = ++ mipi_csi2_get_datatype(mipi_csi2_info); ++ ++ mipi_csi2_pixelclk_enable(mipi_csi2_info); ++ } else { ++ params.csi_mem.mipi_en = false; ++ params.csi_mem.mipi_vc = 0; ++ params.csi_mem.mipi_id = 0; ++ } ++ } else { ++ params.csi_mem.mipi_en = false; ++ params.csi_mem.mipi_vc = 0; ++ params.csi_mem.mipi_id = 0; ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], ++ (dma_addr_t) cam->vf_bufs[0]); ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], ++ (dma_addr_t) cam->vf_bufs[1]); ++ } ++ csi_mem_bufsize = ++ cam->crop_current.width * cam->crop_current.height * 2; ++ cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize); ++ cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0, ++ cam->vf_bufs_size[0], ++ (dma_addr_t *) & ++ cam->vf_bufs[0], ++ GFP_DMA | ++ GFP_KERNEL); ++ if (cam->vf_bufs_vaddr[0] == NULL) { ++ printk(KERN_ERR "Error to allocate vf buffer\n"); ++ err = -ENOMEM; ++ goto out_2; ++ } ++ cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize); ++ cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0, ++ cam->vf_bufs_size[1], ++ (dma_addr_t *) & ++ cam->vf_bufs[1], ++ GFP_DMA | ++ GFP_KERNEL); ++ if (cam->vf_bufs_vaddr[1] == NULL) { ++ printk(KERN_ERR "Error to allocate vf buffer\n"); ++ err = -ENOMEM; ++ goto out_1; ++ } ++ pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]); ++ ++ err = ipu_init_channel(cam->ipu, CSI_MEM, ¶ms); ++ if (err != 0) { ++ printk(KERN_ERR "ipu_init_channel %d\n", err); ++ goto out_1; ++ } ++ ++ pixel_fmt = IPU_PIX_FMT_UYVY; ++ err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, ++ pixel_fmt, cam->crop_current.width, ++ cam->crop_current.height, ++ cam->crop_current.width, IPU_ROTATE_NONE, ++ cam->vf_bufs[0], cam->vf_bufs[1], 0, ++ cam->offset.u_offset, cam->offset.u_offset); ++ if (err != 0) { ++ printk(KERN_ERR "CSI_MEM output buffer\n"); ++ goto out_1; ++ } ++ err = ipu_enable_channel(cam->ipu, CSI_MEM); ++ if (err < 0) { ++ printk(KERN_ERR "ipu_enable_channel CSI_MEM\n"); ++ goto out_1; ++ } ++ ++ csi_buffer_num = 0; ++ ++ ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0); ++ ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 1); ++ return err; ++out_1: ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], ++ (dma_addr_t) cam->vf_bufs[0]); ++ cam->vf_bufs_vaddr[0] = NULL; ++ cam->vf_bufs[0] = 0; ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], ++ (dma_addr_t) cam->vf_bufs[1]); ++ cam->vf_bufs_vaddr[1] = NULL; ++ cam->vf_bufs[1] = 0; ++ } ++out_2: ++ return err; ++} ++ ++/*! ++ * Enable encoder task ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int csi_enc_enabling_tasks(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++ ++ ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF); ++ err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, ++ csi_enc_callback, 0, "Mxc Camera", cam); ++ if (err != 0) { ++ printk(KERN_ERR "Error registering CSI0_OUT_EOF irq\n"); ++ return err; ++ } ++ ++ INIT_WORK(&cam->csi_work_struct, csi_buf_work_func); ++ ++ err = csi_enc_setup(cam); ++ if (err != 0) { ++ printk(KERN_ERR "csi_enc_setup %d\n", err); ++ goto out1; ++ } ++ ++ return err; ++out1: ++ ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam); ++ return err; ++} ++ ++/*! ++ * bg_overlay_start - start the overlay task ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ */ ++static int bg_overlay_start(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++ ++ if (!cam) { ++ printk(KERN_ERR "private is NULL\n"); ++ return -EIO; ++ } ++ ++ if (cam->overlay_active == true) { ++ pr_debug("already start.\n"); ++ return 0; ++ } ++ ++ get_disp_ipu(cam); ++ ++ out_format = cam->v4l2_fb.fmt.pixelformat; ++ if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) { ++ bpp = 3, csi_mem_bufsize = 3; ++ pr_info("BGR24\n"); ++ } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) { ++ bpp = 2, csi_mem_bufsize = 2; ++ pr_info("RGB565\n"); ++ } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) { ++ bpp = 4, csi_mem_bufsize = 4; ++ pr_info("BGR32\n"); ++ } else { ++ printk(KERN_ERR ++ "unsupported fix format from the framebuffer.\n"); ++ return -EINVAL; ++ } ++ ++ offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top + ++ csi_mem_bufsize * cam->win.w.left; ++ ++ if (cam->v4l2_fb.base == 0) ++ printk(KERN_ERR "invalid frame buffer address.\n"); ++ else ++ offset += (u32) cam->v4l2_fb.base; ++ ++ csi_mem_bufsize = cam->win.w.width * cam->win.w.height ++ * csi_mem_bufsize; ++ ++ err = csi_enc_enabling_tasks(cam); ++ if (err != 0) { ++ printk(KERN_ERR "Error csi enc enable fail\n"); ++ return err; ++ } ++ ++ cam->overlay_active = true; ++ return err; ++} ++ ++/*! ++ * bg_overlay_stop - stop the overlay task ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ */ ++static int bg_overlay_stop(void *private) ++{ ++ int err = 0; ++ cam_data *cam = (cam_data *) private; ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ if (cam->overlay_active == false) ++ return 0; ++ ++ err = ipu_disable_channel(cam->ipu, CSI_MEM, true); ++ ++ ipu_uninit_channel(cam->ipu, CSI_MEM); ++ ++ csi_buffer_num = 0; ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) ++ mipi_csi2_pixelclk_disable(mipi_csi2_info); ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ flush_work(&cam->csi_work_struct); ++ cancel_work_sync(&cam->csi_work_struct); ++ ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], cam->vf_bufs[0]); ++ cam->vf_bufs_vaddr[0] = NULL; ++ cam->vf_bufs[0] = 0; ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], cam->vf_bufs[1]); ++ cam->vf_bufs_vaddr[1] = NULL; ++ cam->vf_bufs[1] = 0; ++ } ++ if (cam->rot_vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->rot_vf_buf_size[0], ++ cam->rot_vf_bufs_vaddr[0], ++ cam->rot_vf_bufs[0]); ++ cam->rot_vf_bufs_vaddr[0] = NULL; ++ cam->rot_vf_bufs[0] = 0; ++ } ++ if (cam->rot_vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->rot_vf_buf_size[1], ++ cam->rot_vf_bufs_vaddr[1], ++ cam->rot_vf_bufs[1]); ++ cam->rot_vf_bufs_vaddr[1] = NULL; ++ cam->rot_vf_bufs[1] = 0; ++ } ++ ++ cam->overlay_active = false; ++ return err; ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int bg_overlay_enable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ return ipu_enable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * Disable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int bg_overlay_disable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ /* free csi eof irq firstly. ++ * when disable csi, wait for idmac eof. ++ * it requests eof irq again */ ++ ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam); ++ ++ return ipu_disable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * function to select bg as the working path ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ * @return status ++ */ ++int bg_overlay_sdc_select(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ if (cam) { ++ cam->vf_start_sdc = bg_overlay_start; ++ cam->vf_stop_sdc = bg_overlay_stop; ++ cam->vf_enable_csi = bg_overlay_enable_csi; ++ cam->vf_disable_csi = bg_overlay_disable_csi; ++ cam->overlay_active = false; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(bg_overlay_sdc_select); ++ ++/*! ++ * function to de-select bg as the working path ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ * @return status ++ */ ++int bg_overlay_sdc_deselect(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ if (cam) { ++ cam->vf_start_sdc = NULL; ++ cam->vf_stop_sdc = NULL; ++ cam->vf_enable_csi = NULL; ++ cam->vf_disable_csi = NULL; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(bg_overlay_sdc_deselect); ++ ++/*! ++ * Init background overlay task. ++ * ++ * @return Error code indicating success or failure ++ */ ++__init int bg_overlay_sdc_init(void) ++{ ++ return 0; ++} ++ ++/*! ++ * Deinit background overlay task. ++ * ++ * @return Error code indicating success or failure ++ */ ++void __exit bg_overlay_sdc_exit(void) ++{ ++} ++ ++module_init(bg_overlay_sdc_init); ++module_exit(bg_overlay_sdc_exit); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/ipu_csi_enc.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_csi_enc.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/ipu_csi_enc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_csi_enc.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,426 @@ ++/* ++ * Copyright 2009-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file ipu_csi_enc.c ++ * ++ * @brief CSI Use case for video capture ++ * ++ * @ingroup IPU ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++#include "ipu_prp_sw.h" ++ ++#ifdef CAMERA_DBG ++ #define CAMERA_TRACE(x) (printk)x ++#else ++ #define CAMERA_TRACE(x) ++#endif ++ ++/* ++ * Function definitions ++ */ ++ ++/*! ++ * csi ENC callback function. ++ * ++ * @param irq int irq line ++ * @param dev_id void * device id ++ * ++ * @return status IRQ_HANDLED for handled ++ */ ++static irqreturn_t csi_enc_callback(int irq, void *dev_id) ++{ ++ cam_data *cam = (cam_data *) dev_id; ++ ++ if (cam->enc_callback == NULL) ++ return IRQ_HANDLED; ++ ++ cam->enc_callback(irq, dev_id); ++ return IRQ_HANDLED; ++} ++ ++/*! ++ * CSI ENC enable channel setup function ++ * ++ * @param cam struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int csi_enc_setup(cam_data *cam) ++{ ++ ipu_channel_params_t params; ++ u32 pixel_fmt; ++ int err = 0, sensor_protocol = 0; ++ dma_addr_t dummy = cam->dummy_frame.buffer.m.offset; ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ CAMERA_TRACE("In csi_enc_setup\n"); ++ if (!cam) { ++ printk(KERN_ERR "cam private is NULL\n"); ++ return -ENXIO; ++ } ++ ++ memset(¶ms, 0, sizeof(ipu_channel_params_t)); ++ params.csi_mem.csi = cam->csi; ++ ++ sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi); ++ switch (sensor_protocol) { ++ case IPU_CSI_CLK_MODE_GATED_CLK: ++ case IPU_CSI_CLK_MODE_NONGATED_CLK: ++ case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: ++ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: ++ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: ++ params.csi_mem.interlaced = false; ++ break; ++ case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: ++ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: ++ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: ++ params.csi_mem.interlaced = true; ++ break; ++ default: ++ printk(KERN_ERR "sensor protocol unsupported\n"); ++ return -EINVAL; ++ } ++ ++ if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) ++ pixel_fmt = IPU_PIX_FMT_YUV420P; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) ++ pixel_fmt = IPU_PIX_FMT_YVU420P; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) ++ pixel_fmt = IPU_PIX_FMT_YUV422P; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) ++ pixel_fmt = IPU_PIX_FMT_UYVY; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) ++ pixel_fmt = IPU_PIX_FMT_YUYV; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) ++ pixel_fmt = IPU_PIX_FMT_NV12; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) ++ pixel_fmt = IPU_PIX_FMT_BGR24; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) ++ pixel_fmt = IPU_PIX_FMT_RGB24; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) ++ pixel_fmt = IPU_PIX_FMT_RGB565; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) ++ pixel_fmt = IPU_PIX_FMT_BGR32; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) ++ pixel_fmt = IPU_PIX_FMT_RGB32; ++ else { ++ printk(KERN_ERR "format not supported\n"); ++ return -EINVAL; ++ } ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) { ++ params.csi_mem.mipi_en = true; ++ params.csi_mem.mipi_vc = ++ mipi_csi2_get_virtual_channel(mipi_csi2_info); ++ params.csi_mem.mipi_id = ++ mipi_csi2_get_datatype(mipi_csi2_info); ++ ++ mipi_csi2_pixelclk_enable(mipi_csi2_info); ++ } else { ++ params.csi_mem.mipi_en = false; ++ params.csi_mem.mipi_vc = 0; ++ params.csi_mem.mipi_id = 0; ++ } ++ } else { ++ params.csi_mem.mipi_en = false; ++ params.csi_mem.mipi_vc = 0; ++ params.csi_mem.mipi_id = 0; ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ err = ipu_init_channel(cam->ipu, CSI_MEM, ¶ms); ++ if (err != 0) { ++ printk(KERN_ERR "ipu_init_channel %d\n", err); ++ return err; ++ } ++ ++ err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, ++ pixel_fmt, cam->v2f.fmt.pix.width, ++ cam->v2f.fmt.pix.height, ++ cam->v2f.fmt.pix.bytesperline, ++ IPU_ROTATE_NONE, ++ dummy, dummy, 0, ++ cam->offset.u_offset, ++ cam->offset.v_offset); ++ if (err != 0) { ++ printk(KERN_ERR "CSI_MEM output buffer\n"); ++ return err; ++ } ++ err = ipu_enable_channel(cam->ipu, CSI_MEM); ++ if (err < 0) { ++ printk(KERN_ERR "ipu_enable_channel CSI_MEM\n"); ++ return err; ++ } ++ ++ return err; ++} ++ ++/*! ++ * function to update physical buffer address for encorder IDMA channel ++ * ++ * @param eba physical buffer address for encorder IDMA channel ++ * @param buffer_num int buffer 0 or buffer 1 ++ * ++ * @return status ++ */ ++static int csi_enc_eba_update(struct ipu_soc *ipu, dma_addr_t eba, ++ int *buffer_num) ++{ ++ int err = 0; ++ ++ pr_debug("eba %x\n", eba); ++ err = ipu_update_channel_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER, ++ *buffer_num, eba); ++ if (err != 0) { ++ ipu_clear_buffer_ready(ipu, CSI_MEM, IPU_OUTPUT_BUFFER, ++ *buffer_num); ++ ++ err = ipu_update_channel_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER, ++ *buffer_num, eba); ++ if (err != 0) { ++ pr_err("ERROR: v4l2 capture: fail to update " ++ "buf%d\n", *buffer_num); ++ return err; ++ } ++ } ++ ++ ipu_select_buffer(ipu, CSI_MEM, IPU_OUTPUT_BUFFER, *buffer_num); ++ ++ *buffer_num = (*buffer_num == 0) ? 1 : 0; ++ ++ return 0; ++} ++ ++/*! ++ * Enable encoder task ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int csi_enc_enabling_tasks(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++ CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n"); ++ ++ cam->dummy_frame.vaddress = dma_alloc_coherent(0, ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), ++ &cam->dummy_frame.paddress, ++ GFP_DMA | GFP_KERNEL); ++ if (cam->dummy_frame.vaddress == 0) { ++ pr_err("ERROR: v4l2 capture: Allocate dummy frame " ++ "failed.\n"); ++ return -ENOBUFS; ++ } ++ cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE; ++ cam->dummy_frame.buffer.length = ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); ++ cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress; ++ ++ ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF); ++ err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, ++ csi_enc_callback, 0, "Mxc Camera", cam); ++ if (err != 0) { ++ printk(KERN_ERR "Error registering rot irq\n"); ++ return err; ++ } ++ ++ err = csi_enc_setup(cam); ++ if (err != 0) { ++ printk(KERN_ERR "csi_enc_setup %d\n", err); ++ return err; ++ } ++ ++ return err; ++} ++ ++/*! ++ * Disable encoder task ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return int ++ */ ++static int csi_enc_disabling_tasks(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ err = ipu_disable_channel(cam->ipu, CSI_MEM, true); ++ ++ ipu_uninit_channel(cam->ipu, CSI_MEM); ++ ++ if (cam->dummy_frame.vaddress != 0) { ++ dma_free_coherent(0, cam->dummy_frame.buffer.length, ++ cam->dummy_frame.vaddress, ++ cam->dummy_frame.paddress); ++ cam->dummy_frame.vaddress = 0; ++ } ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) ++ mipi_csi2_pixelclk_disable(mipi_csi2_info); ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ return err; ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int csi_enc_enable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ return ipu_enable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * Disable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int csi_enc_disable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ /* free csi eof irq firstly. ++ * when disable csi, wait for idmac eof. ++ * it requests eof irq again */ ++ ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam); ++ ++ return ipu_disable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * function to select CSI ENC as the working path ++ * ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return int ++ */ ++int csi_enc_select(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++ ++ if (cam) { ++ cam->enc_update_eba = csi_enc_eba_update; ++ cam->enc_enable = csi_enc_enabling_tasks; ++ cam->enc_disable = csi_enc_disabling_tasks; ++ cam->enc_enable_csi = csi_enc_enable_csi; ++ cam->enc_disable_csi = csi_enc_disable_csi; ++ } else { ++ err = -EIO; ++ } ++ ++ return err; ++} ++EXPORT_SYMBOL(csi_enc_select); ++ ++/*! ++ * function to de-select CSI ENC as the working path ++ * ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return int ++ */ ++int csi_enc_deselect(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++ ++ if (cam) { ++ cam->enc_update_eba = NULL; ++ cam->enc_enable = NULL; ++ cam->enc_disable = NULL; ++ cam->enc_enable_csi = NULL; ++ cam->enc_disable_csi = NULL; ++ } ++ ++ return err; ++} ++EXPORT_SYMBOL(csi_enc_deselect); ++ ++/*! ++ * Init the Encorder channels ++ * ++ * @return Error code indicating success or failure ++ */ ++__init int csi_enc_init(void) ++{ ++ return 0; ++} ++ ++/*! ++ * Deinit the Encorder channels ++ * ++ */ ++void __exit csi_enc_exit(void) ++{ ++} ++ ++module_init(csi_enc_init); ++module_exit(csi_enc_exit); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("CSI ENC Driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,642 @@ ++/* ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++/* * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file ipu_foreground_sdc.c ++ * ++ * @brief IPU Use case for PRP-VF ++ * ++ * @ingroup IPU ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mxc_v4l2_capture.h" ++#include "ipu_prp_sw.h" ++ ++#ifdef CAMERA_DBG ++ #define CAMERA_TRACE(x) (printk)x ++#else ++ #define CAMERA_TRACE(x) ++#endif ++ ++static int csi_buffer_num, buffer_num; ++static u32 csi_mem_bufsize; ++static struct ipu_soc *disp_ipu; ++static struct fb_info *fbi; ++static struct fb_var_screeninfo fbvar; ++static u32 vf_out_format; ++static void csi_buf_work_func(struct work_struct *work) ++{ ++ int err = 0; ++ cam_data *cam = ++ container_of(work, struct _cam_data, csi_work_struct); ++ ++ struct ipu_task task; ++ memset(&task, 0, sizeof(task)); ++ ++ if (csi_buffer_num) ++ task.input.paddr = cam->vf_bufs[0]; ++ else ++ task.input.paddr = cam->vf_bufs[1]; ++ task.input.width = cam->crop_current.width; ++ task.input.height = cam->crop_current.height; ++ task.input.format = IPU_PIX_FMT_NV12; ++ ++ if (buffer_num == 0) ++ task.output.paddr = fbi->fix.smem_start + ++ (fbi->fix.line_length * fbvar.yres); ++ else ++ task.output.paddr = fbi->fix.smem_start; ++ task.output.width = cam->win.w.width; ++ task.output.height = cam->win.w.height; ++ task.output.format = vf_out_format; ++ task.output.rotate = cam->rotation; ++again: ++ err = ipu_check_task(&task); ++ if (err != IPU_CHECK_OK) { ++ if (err > IPU_CHECK_ERR_MIN) { ++ if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) { ++ task.input.crop.w -= 8; ++ goto again; ++ } ++ if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) { ++ task.input.crop.h -= 8; ++ goto again; ++ } ++ if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) { ++ task.output.width -= 8; ++ task.output.crop.w = task.output.width; ++ goto again; ++ } ++ if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) { ++ task.output.height -= 8; ++ task.output.crop.h = task.output.height; ++ goto again; ++ } ++ printk(KERN_ERR "check ipu taks fail\n"); ++ return; ++ } ++ printk(KERN_ERR "check ipu taks fail\n"); ++ return; ++ } ++ err = ipu_queue_task(&task); ++ if (err < 0) ++ printk(KERN_ERR "queue ipu task error\n"); ++ ipu_select_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, buffer_num); ++ buffer_num = (buffer_num == 0) ? 1 : 0; ++} ++ ++static void get_disp_ipu(cam_data *cam) ++{ ++ if (cam->output > 2) ++ disp_ipu = ipu_get_soc(1); /* using DISP4 */ ++ else ++ disp_ipu = ipu_get_soc(0); ++} ++ ++/*! ++ * csi ENC callback function. ++ * ++ * @param irq int irq line ++ * @param dev_id void * device id ++ * ++ * @return status IRQ_HANDLED for handled ++ */ ++static irqreturn_t csi_enc_callback(int irq, void *dev_id) ++{ ++ cam_data *cam = (cam_data *) dev_id; ++ ++ ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, csi_buffer_num); ++ if ((cam->crop_current.width != cam->win.w.width) || ++ (cam->crop_current.height != cam->win.w.height) || ++ (vf_out_format != IPU_PIX_FMT_NV12) || ++ (cam->rotation >= IPU_ROTATE_VERT_FLIP)) ++ schedule_work(&cam->csi_work_struct); ++ csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0; ++ return IRQ_HANDLED; ++} ++ ++static int csi_enc_setup(cam_data *cam) ++{ ++ ipu_channel_params_t params; ++ int err = 0, sensor_protocol = 0; ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ CAMERA_TRACE("In csi_enc_setup\n"); ++ if (!cam) { ++ printk(KERN_ERR "cam private is NULL\n"); ++ return -ENXIO; ++ } ++ ++ memset(¶ms, 0, sizeof(ipu_channel_params_t)); ++ params.csi_mem.csi = cam->csi; ++ ++ sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi); ++ switch (sensor_protocol) { ++ case IPU_CSI_CLK_MODE_GATED_CLK: ++ case IPU_CSI_CLK_MODE_NONGATED_CLK: ++ case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: ++ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: ++ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: ++ params.csi_mem.interlaced = false; ++ break; ++ case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: ++ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: ++ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: ++ params.csi_mem.interlaced = true; ++ break; ++ default: ++ printk(KERN_ERR "sensor protocol unsupported\n"); ++ return -EINVAL; ++ } ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) { ++ params.csi_mem.mipi_en = true; ++ params.csi_mem.mipi_vc = ++ mipi_csi2_get_virtual_channel(mipi_csi2_info); ++ params.csi_mem.mipi_id = ++ mipi_csi2_get_datatype(mipi_csi2_info); ++ ++ mipi_csi2_pixelclk_enable(mipi_csi2_info); ++ } else { ++ params.csi_mem.mipi_en = false; ++ params.csi_mem.mipi_vc = 0; ++ params.csi_mem.mipi_id = 0; ++ } ++ } else { ++ params.csi_mem.mipi_en = false; ++ params.csi_mem.mipi_vc = 0; ++ params.csi_mem.mipi_id = 0; ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], ++ (dma_addr_t) cam->vf_bufs[0]); ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], ++ (dma_addr_t) cam->vf_bufs[1]); ++ } ++ csi_mem_bufsize = cam->crop_current.width * ++ cam->crop_current.height * 3/2; ++ cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize); ++ cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0, ++ cam->vf_bufs_size[0], ++ (dma_addr_t *) & ++ cam->vf_bufs[0], ++ GFP_DMA | ++ GFP_KERNEL); ++ if (cam->vf_bufs_vaddr[0] == NULL) { ++ printk(KERN_ERR "Error to allocate vf buffer\n"); ++ err = -ENOMEM; ++ goto out_2; ++ } ++ cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize); ++ cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0, ++ cam->vf_bufs_size[1], ++ (dma_addr_t *) & ++ cam->vf_bufs[1], ++ GFP_DMA | ++ GFP_KERNEL); ++ if (cam->vf_bufs_vaddr[1] == NULL) { ++ printk(KERN_ERR "Error to allocate vf buffer\n"); ++ err = -ENOMEM; ++ goto out_1; ++ } ++ pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]); ++ ++ err = ipu_init_channel(cam->ipu, CSI_MEM, ¶ms); ++ if (err != 0) { ++ printk(KERN_ERR "ipu_init_channel %d\n", err); ++ goto out_1; ++ } ++ ++ if ((cam->crop_current.width == cam->win.w.width) && ++ (cam->crop_current.height == cam->win.w.height) && ++ (vf_out_format == IPU_PIX_FMT_NV12) && ++ (cam->rotation < IPU_ROTATE_VERT_FLIP)) { ++ err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, ++ IPU_OUTPUT_BUFFER, ++ IPU_PIX_FMT_NV12, ++ cam->crop_current.width, ++ cam->crop_current.height, ++ cam->crop_current.width, IPU_ROTATE_NONE, ++ fbi->fix.smem_start + ++ (fbi->fix.line_length * fbvar.yres), ++ fbi->fix.smem_start, 0, ++ cam->offset.u_offset, cam->offset.u_offset); ++ } else { ++ err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, ++ IPU_OUTPUT_BUFFER, ++ IPU_PIX_FMT_NV12, ++ cam->crop_current.width, ++ cam->crop_current.height, ++ cam->crop_current.width, IPU_ROTATE_NONE, ++ cam->vf_bufs[0], cam->vf_bufs[1], 0, ++ cam->offset.u_offset, cam->offset.u_offset); ++ } ++ if (err != 0) { ++ printk(KERN_ERR "CSI_MEM output buffer\n"); ++ goto out_1; ++ } ++ err = ipu_enable_channel(cam->ipu, CSI_MEM); ++ if (err < 0) { ++ printk(KERN_ERR "ipu_enable_channel CSI_MEM\n"); ++ goto out_1; ++ } ++ ++ csi_buffer_num = 0; ++ ++ ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0); ++ ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 1); ++ return err; ++out_1: ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], ++ (dma_addr_t) cam->vf_bufs[0]); ++ cam->vf_bufs_vaddr[0] = NULL; ++ cam->vf_bufs[0] = 0; ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], ++ (dma_addr_t) cam->vf_bufs[1]); ++ cam->vf_bufs_vaddr[1] = NULL; ++ cam->vf_bufs[1] = 0; ++ } ++out_2: ++ return err; ++} ++ ++/*! ++ * Enable encoder task ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int csi_enc_enabling_tasks(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++ CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n"); ++ ++ ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF); ++ err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, ++ csi_enc_callback, 0, "Mxc Camera", cam); ++ if (err != 0) { ++ printk(KERN_ERR "Error registering CSI0_OUT_EOF irq\n"); ++ return err; ++ } ++ ++ INIT_WORK(&cam->csi_work_struct, csi_buf_work_func); ++ ++ err = csi_enc_setup(cam); ++ if (err != 0) { ++ printk(KERN_ERR "csi_enc_setup %d\n", err); ++ goto out1; ++ } ++ ++ return err; ++out1: ++ ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam); ++ return err; ++} ++ ++/* ++ * Function definitions ++ */ ++ ++/*! ++ * foreground_start - start the vf task ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ */ ++static int foreground_start(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0, i = 0, screen_size; ++ char *base; ++ ++ if (!cam) { ++ printk(KERN_ERR "private is NULL\n"); ++ return -EIO; ++ } ++ ++ if (cam->overlay_active == true) { ++ pr_debug("already started.\n"); ++ return 0; ++ } ++ ++ get_disp_ipu(cam); ++ ++ for (i = 0; i < num_registered_fb; i++) { ++ char *idstr = registered_fb[i]->fix.id; ++ if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) || ++ ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) { ++ fbi = registered_fb[i]; ++ break; ++ } ++ } ++ ++ if (fbi == NULL) { ++ printk(KERN_ERR "DISP FG fb not found\n"); ++ return -EPERM; ++ } ++ ++ fbvar = fbi->var; ++ ++ /* Store the overlay frame buffer's original std */ ++ cam->fb_origin_std = fbvar.nonstd; ++ ++ if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) { ++ /* Use DP to do CSC so that we can get better performance */ ++ vf_out_format = IPU_PIX_FMT_NV12; ++ fbvar.nonstd = vf_out_format; ++ } else { ++ vf_out_format = IPU_PIX_FMT_RGB565; ++ fbvar.nonstd = 0; ++ } ++ ++ fbvar.bits_per_pixel = 16; ++ fbvar.xres = fbvar.xres_virtual = cam->win.w.width; ++ fbvar.yres = cam->win.w.height; ++ fbvar.yres_virtual = cam->win.w.height * 2; ++ fbvar.yoffset = 0; ++ fbvar.vmode &= ~FB_VMODE_YWRAP; ++ fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG; ++ fbvar.activate |= FB_ACTIVATE_FORCE; ++ fb_set_var(fbi, &fbvar); ++ ++ ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left, ++ cam->win.w.top); ++ ++ /* Fill black color for framebuffer */ ++ base = (char *) fbi->screen_base; ++ screen_size = fbi->var.xres * fbi->var.yres; ++ if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) { ++ memset(base, 0, screen_size); ++ base += screen_size; ++ for (i = 0; i < screen_size / 2; i++, base++) ++ *base = 0x80; ++ } else { ++ for (i = 0; i < screen_size * 2; i++, base++) ++ *base = 0x00; ++ } ++ ++ console_lock(); ++ fb_blank(fbi, FB_BLANK_UNBLANK); ++ console_unlock(); ++ ++ /* correct display ch buffer address */ ++ ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, ++ 0, fbi->fix.smem_start + ++ (fbi->fix.line_length * fbvar.yres)); ++ ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, ++ 1, fbi->fix.smem_start); ++ ++ err = csi_enc_enabling_tasks(cam); ++ if (err != 0) { ++ printk(KERN_ERR "Error csi enc enable fail\n"); ++ return err; ++ } ++ ++ cam->overlay_active = true; ++ return err; ++ ++} ++ ++/*! ++ * foreground_stop - stop the vf task ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ */ ++static int foreground_stop(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0, i = 0; ++ struct fb_info *fbi = NULL; ++ struct fb_var_screeninfo fbvar; ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ if (cam->overlay_active == false) ++ return 0; ++ ++ err = ipu_disable_channel(cam->ipu, CSI_MEM, true); ++ ++ ipu_uninit_channel(cam->ipu, CSI_MEM); ++ ++ csi_buffer_num = 0; ++ buffer_num = 0; ++ ++ for (i = 0; i < num_registered_fb; i++) { ++ char *idstr = registered_fb[i]->fix.id; ++ if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) || ++ ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) { ++ fbi = registered_fb[i]; ++ break; ++ } ++ } ++ ++ if (fbi == NULL) { ++ printk(KERN_ERR "DISP FG fb not found\n"); ++ return -EPERM; ++ } ++ ++ console_lock(); ++ fb_blank(fbi, FB_BLANK_POWERDOWN); ++ console_unlock(); ++ ++ /* Set the overlay frame buffer std to what it is used to be */ ++ fbvar = fbi->var; ++ fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG; ++ fbvar.nonstd = cam->fb_origin_std; ++ fbvar.activate |= FB_ACTIVATE_FORCE; ++ fb_set_var(fbi, &fbvar); ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) ++ mipi_csi2_pixelclk_disable(mipi_csi2_info); ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ flush_work(&cam->csi_work_struct); ++ cancel_work_sync(&cam->csi_work_struct); ++ ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], ++ (dma_addr_t) cam->vf_bufs[0]); ++ cam->vf_bufs_vaddr[0] = NULL; ++ cam->vf_bufs[0] = 0; ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], ++ (dma_addr_t) cam->vf_bufs[1]); ++ cam->vf_bufs_vaddr[1] = NULL; ++ cam->vf_bufs[1] = 0; ++ } ++ ++ cam->overlay_active = false; ++ return err; ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int foreground_enable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ return ipu_enable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * Disable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int foreground_disable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ /* free csi eof irq firstly. ++ * when disable csi, wait for idmac eof. ++ * it requests eof irq again */ ++ ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam); ++ ++ return ipu_disable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * function to select foreground as the working path ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ * @return status ++ */ ++int foreground_sdc_select(void *private) ++{ ++ cam_data *cam; ++ int err = 0; ++ if (private) { ++ cam = (cam_data *) private; ++ cam->vf_start_sdc = foreground_start; ++ cam->vf_stop_sdc = foreground_stop; ++ cam->vf_enable_csi = foreground_enable_csi; ++ cam->vf_disable_csi = foreground_disable_csi; ++ cam->overlay_active = false; ++ } else ++ err = -EIO; ++ ++ return err; ++} ++EXPORT_SYMBOL(foreground_sdc_select); ++ ++/*! ++ * function to de-select foreground as the working path ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ * @return int ++ */ ++int foreground_sdc_deselect(void *private) ++{ ++ cam_data *cam; ++ ++ if (private) { ++ cam = (cam_data *) private; ++ cam->vf_start_sdc = NULL; ++ cam->vf_stop_sdc = NULL; ++ cam->vf_enable_csi = NULL; ++ cam->vf_disable_csi = NULL; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(foreground_sdc_deselect); ++ ++/*! ++ * Init viewfinder task. ++ * ++ * @return Error code indicating success or failure ++ */ ++__init int foreground_sdc_init(void) ++{ ++ return 0; ++} ++ ++/*! ++ * Deinit viewfinder task. ++ * ++ * @return Error code indicating success or failure ++ */ ++void __exit foreground_sdc_exit(void) ++{ ++} ++ ++module_init(foreground_sdc_init); ++module_exit(foreground_sdc_exit); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("IPU PRP VF SDC Driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/ipu_prp_enc.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_prp_enc.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/ipu_prp_enc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_prp_enc.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,603 @@ ++/* ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file ipu_prp_enc.c ++ * ++ * @brief IPU Use case for PRP-ENC ++ * ++ * @ingroup IPU ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++#include "ipu_prp_sw.h" ++ ++#ifdef CAMERA_DBG ++ #define CAMERA_TRACE(x) (printk)x ++#else ++ #define CAMERA_TRACE(x) ++#endif ++ ++static ipu_rotate_mode_t grotation = IPU_ROTATE_NONE; ++ ++/* ++ * Function definitions ++ */ ++ ++/*! ++ * IPU ENC callback function. ++ * ++ * @param irq int irq line ++ * @param dev_id void * device id ++ * ++ * @return status IRQ_HANDLED for handled ++ */ ++static irqreturn_t prp_enc_callback(int irq, void *dev_id) ++{ ++ cam_data *cam = (cam_data *) dev_id; ++ ++ if (cam->enc_callback == NULL) ++ return IRQ_HANDLED; ++ ++ cam->enc_callback(irq, dev_id); ++ ++ return IRQ_HANDLED; ++} ++ ++/*! ++ * PrpENC enable channel setup function ++ * ++ * @param cam struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_enc_setup(cam_data *cam) ++{ ++ ipu_channel_params_t enc; ++ int err = 0; ++ dma_addr_t dummy = cam->dummy_frame.buffer.m.offset; ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ CAMERA_TRACE("In prp_enc_setup\n"); ++ if (!cam) { ++ printk(KERN_ERR "cam private is NULL\n"); ++ return -ENXIO; ++ } ++ memset(&enc, 0, sizeof(ipu_channel_params_t)); ++ ++ ipu_csi_get_window_size(cam->ipu, &enc.csi_prp_enc_mem.in_width, ++ &enc.csi_prp_enc_mem.in_height, cam->csi); ++ ++ enc.csi_prp_enc_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY; ++ enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.width; ++ enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.height; ++ enc.csi_prp_enc_mem.csi = cam->csi; ++ if (cam->rotation >= IPU_ROTATE_90_RIGHT) { ++ enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.height; ++ enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.width; ++ } ++ ++ if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) { ++ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV420P; ++ pr_info("YUV420\n"); ++ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) { ++ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YVU420P; ++ pr_info("YVU420\n"); ++ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) { ++ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV422P; ++ pr_info("YUV422P\n"); ++ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) { ++ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUYV; ++ pr_info("YUYV\n"); ++ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) { ++ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_UYVY; ++ pr_info("UYVY\n"); ++ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) { ++ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_NV12; ++ pr_info("NV12\n"); ++ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) { ++ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR24; ++ pr_info("BGR24\n"); ++ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) { ++ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB24; ++ pr_info("RGB24\n"); ++ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { ++ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB565; ++ pr_info("RGB565\n"); ++ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) { ++ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR32; ++ pr_info("BGR32\n"); ++ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) { ++ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB32; ++ pr_info("RGB32\n"); ++ } else { ++ printk(KERN_ERR "format not supported\n"); ++ return -EINVAL; ++ } ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) { ++ enc.csi_prp_enc_mem.mipi_en = true; ++ enc.csi_prp_enc_mem.mipi_vc = ++ mipi_csi2_get_virtual_channel(mipi_csi2_info); ++ enc.csi_prp_enc_mem.mipi_id = ++ mipi_csi2_get_datatype(mipi_csi2_info); ++ ++ mipi_csi2_pixelclk_enable(mipi_csi2_info); ++ } else { ++ enc.csi_prp_enc_mem.mipi_en = false; ++ enc.csi_prp_enc_mem.mipi_vc = 0; ++ enc.csi_prp_enc_mem.mipi_id = 0; ++ } ++ } else { ++ enc.csi_prp_enc_mem.mipi_en = false; ++ enc.csi_prp_enc_mem.mipi_vc = 0; ++ enc.csi_prp_enc_mem.mipi_id = 0; ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ err = ipu_init_channel(cam->ipu, CSI_PRP_ENC_MEM, &enc); ++ if (err != 0) { ++ printk(KERN_ERR "ipu_init_channel %d\n", err); ++ return err; ++ } ++ ++ grotation = cam->rotation; ++ if (cam->rotation >= IPU_ROTATE_90_RIGHT) { ++ if (cam->rot_enc_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->rot_enc_buf_size[0], ++ cam->rot_enc_bufs_vaddr[0], ++ cam->rot_enc_bufs[0]); ++ } ++ if (cam->rot_enc_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->rot_enc_buf_size[1], ++ cam->rot_enc_bufs_vaddr[1], ++ cam->rot_enc_bufs[1]); ++ } ++ cam->rot_enc_buf_size[0] = ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); ++ cam->rot_enc_bufs_vaddr[0] = ++ (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[0], ++ &cam->rot_enc_bufs[0], ++ GFP_DMA | GFP_KERNEL); ++ if (!cam->rot_enc_bufs_vaddr[0]) { ++ printk(KERN_ERR "alloc enc_bufs0\n"); ++ return -ENOMEM; ++ } ++ cam->rot_enc_buf_size[1] = ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); ++ cam->rot_enc_bufs_vaddr[1] = ++ (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[1], ++ &cam->rot_enc_bufs[1], ++ GFP_DMA | GFP_KERNEL); ++ if (!cam->rot_enc_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->rot_enc_buf_size[0], ++ cam->rot_enc_bufs_vaddr[0], ++ cam->rot_enc_bufs[0]); ++ cam->rot_enc_bufs_vaddr[0] = NULL; ++ cam->rot_enc_bufs[0] = 0; ++ printk(KERN_ERR "alloc enc_bufs1\n"); ++ return -ENOMEM; ++ } ++ ++ err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM, ++ IPU_OUTPUT_BUFFER, ++ enc.csi_prp_enc_mem.out_pixel_fmt, ++ enc.csi_prp_enc_mem.out_width, ++ enc.csi_prp_enc_mem.out_height, ++ enc.csi_prp_enc_mem.out_width, ++ IPU_ROTATE_NONE, ++ cam->rot_enc_bufs[0], ++ cam->rot_enc_bufs[1], 0, 0, 0); ++ if (err != 0) { ++ printk(KERN_ERR "CSI_PRP_ENC_MEM err\n"); ++ return err; ++ } ++ ++ err = ipu_init_channel(cam->ipu, MEM_ROT_ENC_MEM, NULL); ++ if (err != 0) { ++ printk(KERN_ERR "MEM_ROT_ENC_MEM channel err\n"); ++ return err; ++ } ++ ++ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM, ++ IPU_INPUT_BUFFER, ++ enc.csi_prp_enc_mem.out_pixel_fmt, ++ enc.csi_prp_enc_mem.out_width, ++ enc.csi_prp_enc_mem.out_height, ++ enc.csi_prp_enc_mem.out_width, ++ cam->rotation, ++ cam->rot_enc_bufs[0], ++ cam->rot_enc_bufs[1], 0, 0, 0); ++ if (err != 0) { ++ printk(KERN_ERR "MEM_ROT_ENC_MEM input buffer\n"); ++ return err; ++ } ++ ++ err = ++ ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM, ++ IPU_OUTPUT_BUFFER, ++ enc.csi_prp_enc_mem.out_pixel_fmt, ++ enc.csi_prp_enc_mem.out_height, ++ enc.csi_prp_enc_mem.out_width, ++ cam->v2f.fmt.pix.bytesperline / ++ bytes_per_pixel(enc.csi_prp_enc_mem. ++ out_pixel_fmt), ++ IPU_ROTATE_NONE, ++ dummy, dummy, 0, ++ cam->offset.u_offset, ++ cam->offset.v_offset); ++ if (err != 0) { ++ printk(KERN_ERR "MEM_ROT_ENC_MEM output buffer\n"); ++ return err; ++ } ++ ++ err = ipu_link_channels(cam->ipu, ++ CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM); ++ if (err < 0) { ++ printk(KERN_ERR ++ "link CSI_PRP_ENC_MEM-MEM_ROT_ENC_MEM\n"); ++ return err; ++ } ++ ++ err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM); ++ if (err < 0) { ++ printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n"); ++ return err; ++ } ++ err = ipu_enable_channel(cam->ipu, MEM_ROT_ENC_MEM); ++ if (err < 0) { ++ printk(KERN_ERR "ipu_enable_channel MEM_ROT_ENC_MEM\n"); ++ return err; ++ } ++ ++ ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM, ++ IPU_OUTPUT_BUFFER, 0); ++ ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM, ++ IPU_OUTPUT_BUFFER, 1); ++ } else { ++ err = ++ ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM, ++ IPU_OUTPUT_BUFFER, ++ enc.csi_prp_enc_mem.out_pixel_fmt, ++ enc.csi_prp_enc_mem.out_width, ++ enc.csi_prp_enc_mem.out_height, ++ cam->v2f.fmt.pix.bytesperline / ++ bytes_per_pixel(enc.csi_prp_enc_mem. ++ out_pixel_fmt), ++ cam->rotation, ++ dummy, dummy, 0, ++ cam->offset.u_offset, ++ cam->offset.v_offset); ++ if (err != 0) { ++ printk(KERN_ERR "CSI_PRP_ENC_MEM output buffer\n"); ++ return err; ++ } ++ err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM); ++ if (err < 0) { ++ printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n"); ++ return err; ++ } ++ } ++ ++ return err; ++} ++ ++/*! ++ * function to update physical buffer address for encorder IDMA channel ++ * ++ * @param eba physical buffer address for encorder IDMA channel ++ * @param buffer_num int buffer 0 or buffer 1 ++ * ++ * @return status ++ */ ++static int prp_enc_eba_update(struct ipu_soc *ipu, dma_addr_t eba, ++ int *buffer_num) ++{ ++ int err = 0; ++ ++ pr_debug("eba %x\n", eba); ++ if (grotation >= IPU_ROTATE_90_RIGHT) { ++ err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM, ++ IPU_OUTPUT_BUFFER, *buffer_num, ++ eba); ++ } else { ++ err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM, ++ IPU_OUTPUT_BUFFER, *buffer_num, ++ eba); ++ } ++ if (err != 0) { ++ if (grotation >= IPU_ROTATE_90_RIGHT) { ++ ipu_clear_buffer_ready(ipu, MEM_ROT_ENC_MEM, ++ IPU_OUTPUT_BUFFER, ++ *buffer_num); ++ err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM, ++ IPU_OUTPUT_BUFFER, ++ *buffer_num, ++ eba); ++ } else { ++ ipu_clear_buffer_ready(ipu, CSI_PRP_ENC_MEM, ++ IPU_OUTPUT_BUFFER, ++ *buffer_num); ++ err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM, ++ IPU_OUTPUT_BUFFER, ++ *buffer_num, ++ eba); ++ } ++ ++ if (err != 0) { ++ pr_err("ERROR: v4l2 capture: fail to update " ++ "buf%d\n", *buffer_num); ++ return err; ++ } ++ } ++ ++ if (grotation >= IPU_ROTATE_90_RIGHT) { ++ ipu_select_buffer(ipu, MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER, ++ *buffer_num); ++ } else { ++ ipu_select_buffer(ipu, CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER, ++ *buffer_num); ++ } ++ ++ *buffer_num = (*buffer_num == 0) ? 1 : 0; ++ return 0; ++} ++ ++/*! ++ * Enable encoder task ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_enc_enabling_tasks(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++ CAMERA_TRACE("IPU:In prp_enc_enabling_tasks\n"); ++ ++ cam->dummy_frame.vaddress = dma_alloc_coherent(0, ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), ++ &cam->dummy_frame.paddress, ++ GFP_DMA | GFP_KERNEL); ++ if (cam->dummy_frame.vaddress == 0) { ++ pr_err("ERROR: v4l2 capture: Allocate dummy frame " ++ "failed.\n"); ++ return -ENOBUFS; ++ } ++ cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE; ++ cam->dummy_frame.buffer.length = ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); ++ cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress; ++ ++ if (cam->rotation >= IPU_ROTATE_90_RIGHT) { ++ err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF, ++ prp_enc_callback, 0, "Mxc Camera", cam); ++ } else { ++ err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF, ++ prp_enc_callback, 0, "Mxc Camera", cam); ++ } ++ if (err != 0) { ++ printk(KERN_ERR "Error registering rot irq\n"); ++ return err; ++ } ++ ++ err = prp_enc_setup(cam); ++ if (err != 0) { ++ printk(KERN_ERR "prp_enc_setup %d\n", err); ++ return err; ++ } ++ ++ return err; ++} ++ ++/*! ++ * Disable encoder task ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return int ++ */ ++static int prp_enc_disabling_tasks(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ if (cam->rotation >= IPU_ROTATE_90_RIGHT) { ++ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF, cam); ++ ipu_unlink_channels(cam->ipu, CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM); ++ } ++ ++ err = ipu_disable_channel(cam->ipu, CSI_PRP_ENC_MEM, true); ++ if (cam->rotation >= IPU_ROTATE_90_RIGHT) ++ err |= ipu_disable_channel(cam->ipu, MEM_ROT_ENC_MEM, true); ++ ++ ipu_uninit_channel(cam->ipu, CSI_PRP_ENC_MEM); ++ if (cam->rotation >= IPU_ROTATE_90_RIGHT) ++ ipu_uninit_channel(cam->ipu, MEM_ROT_ENC_MEM); ++ ++ if (cam->dummy_frame.vaddress != 0) { ++ dma_free_coherent(0, cam->dummy_frame.buffer.length, ++ cam->dummy_frame.vaddress, ++ cam->dummy_frame.paddress); ++ cam->dummy_frame.vaddress = 0; ++ } ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) ++ mipi_csi2_pixelclk_disable(mipi_csi2_info); ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ return err; ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_enc_enable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ return ipu_enable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * Disable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_enc_disable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ /* free csi eof irq firstly. ++ * when disable csi, wait for idmac eof. ++ * it requests eof irq again */ ++ if (cam->rotation < IPU_ROTATE_90_RIGHT) ++ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF, cam); ++ ++ return ipu_disable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * function to select PRP-ENC as the working path ++ * ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return int ++ */ ++int prp_enc_select(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++ ++ if (cam) { ++ cam->enc_update_eba = prp_enc_eba_update; ++ cam->enc_enable = prp_enc_enabling_tasks; ++ cam->enc_disable = prp_enc_disabling_tasks; ++ cam->enc_enable_csi = prp_enc_enable_csi; ++ cam->enc_disable_csi = prp_enc_disable_csi; ++ } else { ++ err = -EIO; ++ } ++ ++ return err; ++} ++EXPORT_SYMBOL(prp_enc_select); ++ ++/*! ++ * function to de-select PRP-ENC as the working path ++ * ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return int ++ */ ++int prp_enc_deselect(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++ ++ if (cam) { ++ cam->enc_update_eba = NULL; ++ cam->enc_enable = NULL; ++ cam->enc_disable = NULL; ++ cam->enc_enable_csi = NULL; ++ cam->enc_disable_csi = NULL; ++ if (cam->rot_enc_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->rot_enc_buf_size[0], ++ cam->rot_enc_bufs_vaddr[0], ++ cam->rot_enc_bufs[0]); ++ cam->rot_enc_bufs_vaddr[0] = NULL; ++ cam->rot_enc_bufs[0] = 0; ++ } ++ if (cam->rot_enc_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->rot_enc_buf_size[1], ++ cam->rot_enc_bufs_vaddr[1], ++ cam->rot_enc_bufs[1]); ++ cam->rot_enc_bufs_vaddr[1] = NULL; ++ cam->rot_enc_bufs[1] = 0; ++ } ++ } ++ ++ return err; ++} ++EXPORT_SYMBOL(prp_enc_deselect); ++ ++/*! ++ * Init the Encorder channels ++ * ++ * @return Error code indicating success or failure ++ */ ++__init int prp_enc_init(void) ++{ ++ return 0; ++} ++ ++/*! ++ * Deinit the Encorder channels ++ * ++ */ ++void __exit prp_enc_exit(void) ++{ ++} ++ ++module_init(prp_enc_init); ++module_exit(prp_enc_exit); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("IPU PRP ENC Driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/ipu_prp_sw.h linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_prp_sw.h +--- linux-3.10.30/drivers/media/platform/mxc/capture/ipu_prp_sw.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_prp_sw.h 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,43 @@ ++/* ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file ipu_prp_sw.h ++ * ++ * @brief This file contains the IPU PRP use case driver header. ++ * ++ * @ingroup IPU ++ */ ++ ++#ifndef _INCLUDE_IPU__PRP_SW_H_ ++#define _INCLUDE_IPU__PRP_SW_H_ ++ ++int csi_enc_select(void *private); ++int csi_enc_deselect(void *private); ++int prp_enc_select(void *private); ++int prp_enc_deselect(void *private); ++#ifdef CONFIG_MXC_IPU_PRP_VF_SDC ++int prp_vf_sdc_select(void *private); ++int prp_vf_sdc_deselect(void *private); ++int prp_vf_sdc_select_bg(void *private); ++int prp_vf_sdc_deselect_bg(void *private); ++#else ++int foreground_sdc_select(void *private); ++int foreground_sdc_deselect(void *private); ++int bg_overlay_sdc_select(void *private); ++int bg_overlay_sdc_deselect(void *private); ++#endif ++int prp_still_select(void *private); ++int prp_still_deselect(void *private); ++ ++#endif +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,590 @@ ++/* ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++/* * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file ipu_prp_vf_sdc.c ++ * ++ * @brief IPU Use case for PRP-VF ++ * ++ * @ingroup IPU ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++#include "ipu_prp_sw.h" ++ ++static int buffer_num; ++static struct ipu_soc *disp_ipu; ++ ++static void get_disp_ipu(cam_data *cam) ++{ ++ if (cam->output > 2) ++ disp_ipu = ipu_get_soc(1); /* using DISP4 */ ++ else ++ disp_ipu = ipu_get_soc(0); ++} ++ ++static irqreturn_t prpvf_rot_eof_callback(int irq, void *dev_id) ++{ ++ cam_data *cam = dev_id; ++ pr_debug("buffer_num %d\n", buffer_num); ++ ++ if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { ++ ipu_select_buffer(disp_ipu, MEM_FG_SYNC, ++ IPU_INPUT_BUFFER, buffer_num); ++ buffer_num = (buffer_num == 0) ? 1 : 0; ++ ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM, ++ IPU_OUTPUT_BUFFER, buffer_num); ++ } else { ++ ipu_select_buffer(disp_ipu, MEM_FG_SYNC, ++ IPU_INPUT_BUFFER, buffer_num); ++ buffer_num = (buffer_num == 0) ? 1 : 0; ++ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, ++ IPU_OUTPUT_BUFFER, buffer_num); ++ } ++ return IRQ_HANDLED; ++} ++/* ++ * Function definitions ++ */ ++ ++/*! ++ * prpvf_start - start the vf task ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ */ ++static int prpvf_start(void *private) ++{ ++ struct fb_var_screeninfo fbvar; ++ struct fb_info *fbi = NULL; ++ cam_data *cam = (cam_data *) private; ++ ipu_channel_params_t vf; ++ u32 vf_out_format = 0; ++ u32 size = 2, temp = 0; ++ int err = 0, i = 0; ++ short *tmp, color; ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ if (!cam) { ++ printk(KERN_ERR "private is NULL\n"); ++ return -EIO; ++ } ++ ++ if (cam->overlay_active == true) { ++ pr_debug("already started.\n"); ++ return 0; ++ } ++ ++ get_disp_ipu(cam); ++ ++ for (i = 0; i < num_registered_fb; i++) { ++ char *idstr = registered_fb[i]->fix.id; ++ if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) || ++ ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) { ++ fbi = registered_fb[i]; ++ break; ++ } ++ } ++ ++ if (fbi == NULL) { ++ printk(KERN_ERR "DISP FG fb not found\n"); ++ return -EPERM; ++ } ++ ++ fbvar = fbi->var; ++ ++ /* Store the overlay frame buffer's original std */ ++ cam->fb_origin_std = fbvar.nonstd; ++ ++ if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) { ++ /* Use DP to do CSC so that we can get better performance */ ++ vf_out_format = IPU_PIX_FMT_UYVY; ++ fbvar.nonstd = vf_out_format; ++ color = 0x80; ++ } else { ++ vf_out_format = IPU_PIX_FMT_RGB565; ++ fbvar.nonstd = 0; ++ color = 0x0; ++ } ++ ++ fbvar.bits_per_pixel = 16; ++ fbvar.xres = fbvar.xres_virtual = cam->win.w.width; ++ fbvar.yres = cam->win.w.height; ++ fbvar.yres_virtual = cam->win.w.height * 2; ++ fbvar.yoffset = 0; ++ fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG; ++ fbvar.activate |= FB_ACTIVATE_FORCE; ++ fb_set_var(fbi, &fbvar); ++ ++ ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left, ++ cam->win.w.top); ++ ++ /* Fill black color for framebuffer */ ++ tmp = (short *) fbi->screen_base; ++ for (i = 0; i < (fbi->fix.line_length * fbi->var.yres)/2; ++ i++, tmp++) ++ *tmp = color; ++ ++ console_lock(); ++ fb_blank(fbi, FB_BLANK_UNBLANK); ++ console_unlock(); ++ ++ /* correct display ch buffer address */ ++ ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, ++ 0, fbi->fix.smem_start + ++ (fbi->fix.line_length * fbvar.yres)); ++ ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, ++ 1, fbi->fix.smem_start); ++ ++ memset(&vf, 0, sizeof(ipu_channel_params_t)); ++ ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width, ++ &vf.csi_prp_vf_mem.in_height, cam->csi); ++ vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY; ++ vf.csi_prp_vf_mem.out_width = cam->win.w.width; ++ vf.csi_prp_vf_mem.out_height = cam->win.w.height; ++ vf.csi_prp_vf_mem.csi = cam->csi; ++ if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) { ++ vf.csi_prp_vf_mem.out_width = cam->win.w.height; ++ vf.csi_prp_vf_mem.out_height = cam->win.w.width; ++ } ++ vf.csi_prp_vf_mem.out_pixel_fmt = vf_out_format; ++ size = cam->win.w.width * cam->win.w.height * size; ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) { ++ vf.csi_prp_vf_mem.mipi_en = true; ++ vf.csi_prp_vf_mem.mipi_vc = ++ mipi_csi2_get_virtual_channel(mipi_csi2_info); ++ vf.csi_prp_vf_mem.mipi_id = ++ mipi_csi2_get_datatype(mipi_csi2_info); ++ ++ mipi_csi2_pixelclk_enable(mipi_csi2_info); ++ } else { ++ vf.csi_prp_vf_mem.mipi_en = false; ++ vf.csi_prp_vf_mem.mipi_vc = 0; ++ vf.csi_prp_vf_mem.mipi_id = 0; ++ } ++ } else { ++ vf.csi_prp_vf_mem.mipi_en = false; ++ vf.csi_prp_vf_mem.mipi_vc = 0; ++ vf.csi_prp_vf_mem.mipi_id = 0; ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf); ++ if (err != 0) ++ goto out_5; ++ ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], ++ (dma_addr_t) cam->vf_bufs[0]); ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], ++ (dma_addr_t) cam->vf_bufs[1]); ++ } ++ cam->vf_bufs_size[0] = PAGE_ALIGN(size); ++ cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0, ++ cam->vf_bufs_size[0], ++ (dma_addr_t *) & ++ cam->vf_bufs[0], ++ GFP_DMA | ++ GFP_KERNEL); ++ if (cam->vf_bufs_vaddr[0] == NULL) { ++ printk(KERN_ERR "Error to allocate vf buffer\n"); ++ err = -ENOMEM; ++ goto out_4; ++ } ++ cam->vf_bufs_size[1] = PAGE_ALIGN(size); ++ cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0, ++ cam->vf_bufs_size[1], ++ (dma_addr_t *) & ++ cam->vf_bufs[1], ++ GFP_DMA | ++ GFP_KERNEL); ++ if (cam->vf_bufs_vaddr[1] == NULL) { ++ printk(KERN_ERR "Error to allocate vf buffer\n"); ++ err = -ENOMEM; ++ goto out_3; ++ } ++ pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]); ++ ++ if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { ++ err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM, ++ IPU_OUTPUT_BUFFER, ++ vf_out_format, ++ vf.csi_prp_vf_mem.out_width, ++ vf.csi_prp_vf_mem.out_height, ++ vf.csi_prp_vf_mem.out_width, ++ IPU_ROTATE_NONE, ++ cam->vf_bufs[0], cam->vf_bufs[1], ++ 0, 0, 0); ++ if (err != 0) ++ goto out_3; ++ ++ err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL); ++ if (err != 0) { ++ printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n"); ++ goto out_3; ++ } ++ ++ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM, ++ IPU_INPUT_BUFFER, ++ vf_out_format, ++ vf.csi_prp_vf_mem.out_width, ++ vf.csi_prp_vf_mem.out_height, ++ vf.csi_prp_vf_mem.out_width, ++ cam->vf_rotation, ++ cam->vf_bufs[0], ++ cam->vf_bufs[1], ++ 0, 0, 0); ++ if (err != 0) { ++ printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n"); ++ goto out_2; ++ } ++ ++ if (cam->vf_rotation < IPU_ROTATE_90_RIGHT) { ++ temp = vf.csi_prp_vf_mem.out_width; ++ vf.csi_prp_vf_mem.out_width = ++ vf.csi_prp_vf_mem.out_height; ++ vf.csi_prp_vf_mem.out_height = temp; ++ } ++ ++ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM, ++ IPU_OUTPUT_BUFFER, ++ vf_out_format, ++ vf.csi_prp_vf_mem.out_height, ++ vf.csi_prp_vf_mem.out_width, ++ vf.csi_prp_vf_mem.out_height, ++ IPU_ROTATE_NONE, ++ fbi->fix.smem_start + ++ (fbi->fix.line_length * ++ fbi->var.yres), ++ fbi->fix.smem_start, 0, 0, 0); ++ ++ if (err != 0) { ++ printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n"); ++ goto out_2; ++ } ++ ++ ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF); ++ err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF, ++ prpvf_rot_eof_callback, ++ 0, "Mxc Camera", cam); ++ if (err < 0) { ++ printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_ROT_OUT_EOF\n"); ++ goto out_2; ++ } ++ ++ err = ipu_link_channels(cam->ipu, ++ CSI_PRP_VF_MEM, MEM_ROT_VF_MEM); ++ if (err < 0) { ++ printk(KERN_ERR ++ "Error link CSI_PRP_VF_MEM-MEM_ROT_VF_MEM\n"); ++ goto out_1; ++ } ++ ++ ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM); ++ ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM); ++ ++ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, ++ IPU_OUTPUT_BUFFER, 0); ++ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, ++ IPU_OUTPUT_BUFFER, 1); ++ ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM, ++ IPU_OUTPUT_BUFFER, 0); ++ } else { ++ err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM, ++ IPU_OUTPUT_BUFFER, ++ vf_out_format, cam->win.w.width, ++ cam->win.w.height, ++ cam->win.w.width, ++ cam->vf_rotation, ++ fbi->fix.smem_start + ++ (fbi->fix.line_length * ++ fbi->var.yres), ++ fbi->fix.smem_start, 0, 0, 0); ++ if (err != 0) { ++ printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n"); ++ goto out_4; ++ } ++ ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF); ++ err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, ++ prpvf_rot_eof_callback, ++ 0, "Mxc Camera", cam); ++ if (err < 0) { ++ printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_OUT_EOF\n"); ++ goto out_4; ++ } ++ ++ ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM); ++ ++ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, ++ IPU_OUTPUT_BUFFER, 0); ++ } ++ ++ cam->overlay_active = true; ++ return err; ++ ++out_1: ++ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL); ++out_2: ++ if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) ++ ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM); ++out_3: ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], ++ (dma_addr_t) cam->vf_bufs[0]); ++ cam->vf_bufs_vaddr[0] = NULL; ++ cam->vf_bufs[0] = 0; ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], ++ (dma_addr_t) cam->vf_bufs[1]); ++ cam->vf_bufs_vaddr[1] = NULL; ++ cam->vf_bufs[1] = 0; ++ } ++out_4: ++ ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM); ++out_5: ++ return err; ++} ++ ++/*! ++ * prpvf_stop - stop the vf task ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ */ ++static int prpvf_stop(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0, i = 0; ++ struct fb_info *fbi = NULL; ++ struct fb_var_screeninfo fbvar; ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ if (cam->overlay_active == false) ++ return 0; ++ ++ for (i = 0; i < num_registered_fb; i++) { ++ char *idstr = registered_fb[i]->fix.id; ++ if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) || ++ ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) { ++ fbi = registered_fb[i]; ++ break; ++ } ++ } ++ ++ if (fbi == NULL) { ++ printk(KERN_ERR "DISP FG fb not found\n"); ++ return -EPERM; ++ } ++ ++ if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { ++ ipu_unlink_channels(cam->ipu, CSI_PRP_VF_MEM, MEM_ROT_VF_MEM); ++ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF, cam); ++ } ++ buffer_num = 0; ++ ++ ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true); ++ ++ if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { ++ ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true); ++ ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM); ++ } ++ ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM); ++ ++ console_lock(); ++ fb_blank(fbi, FB_BLANK_POWERDOWN); ++ console_unlock(); ++ ++ /* Set the overlay frame buffer std to what it is used to be */ ++ fbvar = fbi->var; ++ fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG; ++ fbvar.nonstd = cam->fb_origin_std; ++ fbvar.activate |= FB_ACTIVATE_FORCE; ++ fb_set_var(fbi, &fbvar); ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) ++ mipi_csi2_pixelclk_disable(mipi_csi2_info); ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], ++ (dma_addr_t) cam->vf_bufs[0]); ++ cam->vf_bufs_vaddr[0] = NULL; ++ cam->vf_bufs[0] = 0; ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], ++ (dma_addr_t) cam->vf_bufs[1]); ++ cam->vf_bufs_vaddr[1] = NULL; ++ cam->vf_bufs[1] = 0; ++ } ++ ++ cam->overlay_active = false; ++ return err; ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_vf_enable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ return ipu_enable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * Disable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_vf_disable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ /* free csi eof irq firstly. ++ * when disable csi, wait for idmac eof. ++ * it requests eof irq again */ ++ if (cam->vf_rotation < IPU_ROTATE_VERT_FLIP) ++ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam); ++ ++ return ipu_disable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * function to select PRP-VF as the working path ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ * @return status ++ */ ++int prp_vf_sdc_select(void *private) ++{ ++ cam_data *cam; ++ int err = 0; ++ if (private) { ++ cam = (cam_data *) private; ++ cam->vf_start_sdc = prpvf_start; ++ cam->vf_stop_sdc = prpvf_stop; ++ cam->vf_enable_csi = prp_vf_enable_csi; ++ cam->vf_disable_csi = prp_vf_disable_csi; ++ cam->overlay_active = false; ++ } else ++ err = -EIO; ++ ++ return err; ++} ++EXPORT_SYMBOL(prp_vf_sdc_select); ++ ++/*! ++ * function to de-select PRP-VF as the working path ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ * @return int ++ */ ++int prp_vf_sdc_deselect(void *private) ++{ ++ cam_data *cam; ++ ++ if (private) { ++ cam = (cam_data *) private; ++ cam->vf_start_sdc = NULL; ++ cam->vf_stop_sdc = NULL; ++ cam->vf_enable_csi = NULL; ++ cam->vf_disable_csi = NULL; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(prp_vf_sdc_deselect); ++ ++/*! ++ * Init viewfinder task. ++ * ++ * @return Error code indicating success or failure ++ */ ++__init int prp_vf_sdc_init(void) ++{ ++ return 0; ++} ++ ++/*! ++ * Deinit viewfinder task. ++ * ++ * @return Error code indicating success or failure ++ */ ++void __exit prp_vf_sdc_exit(void) ++{ ++} ++ ++module_init(prp_vf_sdc_init); ++module_exit(prp_vf_sdc_exit); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("IPU PRP VF SDC Driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,529 @@ ++/* ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file ipu_prp_vf_sdc_bg.c ++ * ++ * @brief IPU Use case for PRP-VF back-ground ++ * ++ * @ingroup IPU ++ */ ++#include ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++#include "ipu_prp_sw.h" ++ ++static int buffer_num; ++static int buffer_ready; ++static struct ipu_soc *disp_ipu; ++ ++static void get_disp_ipu(cam_data *cam) ++{ ++ if (cam->output > 2) ++ disp_ipu = ipu_get_soc(1); /* using DISP4 */ ++ else ++ disp_ipu = ipu_get_soc(0); ++} ++ ++/* ++ * Function definitions ++ */ ++ ++/*! ++ * SDC V-Sync callback function. ++ * ++ * @param irq int irq line ++ * @param dev_id void * device id ++ * ++ * @return status IRQ_HANDLED for handled ++ */ ++static irqreturn_t prpvf_sdc_vsync_callback(int irq, void *dev_id) ++{ ++ cam_data *cam = dev_id; ++ if (buffer_ready > 0) { ++ ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM, ++ IPU_OUTPUT_BUFFER, 0); ++ buffer_ready--; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/*! ++ * VF EOF callback function. ++ * ++ * @param irq int irq line ++ * @param dev_id void * device id ++ * ++ * @return status IRQ_HANDLED for handled ++ */ ++static irqreturn_t prpvf_vf_eof_callback(int irq, void *dev_id) ++{ ++ cam_data *cam = dev_id; ++ pr_debug("buffer_ready %d buffer_num %d\n", buffer_ready, buffer_num); ++ ++ ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM, ++ IPU_INPUT_BUFFER, buffer_num); ++ buffer_num = (buffer_num == 0) ? 1 : 0; ++ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, ++ IPU_OUTPUT_BUFFER, buffer_num); ++ buffer_ready++; ++ return IRQ_HANDLED; ++} ++ ++/*! ++ * prpvf_start - start the vf task ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ */ ++static int prpvf_start(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ipu_channel_params_t vf; ++ u32 format; ++ u32 offset; ++ u32 bpp, size = 3; ++ int err = 0; ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ if (!cam) { ++ printk(KERN_ERR "private is NULL\n"); ++ return -EIO; ++ } ++ ++ if (cam->overlay_active == true) { ++ pr_debug("already start.\n"); ++ return 0; ++ } ++ ++ get_disp_ipu(cam); ++ ++ format = cam->v4l2_fb.fmt.pixelformat; ++ if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) { ++ bpp = 3, size = 3; ++ pr_info("BGR24\n"); ++ } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) { ++ bpp = 2, size = 2; ++ pr_info("RGB565\n"); ++ } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) { ++ bpp = 4, size = 4; ++ pr_info("BGR32\n"); ++ } else { ++ printk(KERN_ERR ++ "unsupported fix format from the framebuffer.\n"); ++ return -EINVAL; ++ } ++ ++ offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top + ++ size * cam->win.w.left; ++ ++ if (cam->v4l2_fb.base == 0) ++ printk(KERN_ERR "invalid frame buffer address.\n"); ++ else ++ offset += (u32) cam->v4l2_fb.base; ++ ++ memset(&vf, 0, sizeof(ipu_channel_params_t)); ++ ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width, ++ &vf.csi_prp_vf_mem.in_height, cam->csi); ++ vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY; ++ vf.csi_prp_vf_mem.out_width = cam->win.w.width; ++ vf.csi_prp_vf_mem.out_height = cam->win.w.height; ++ vf.csi_prp_vf_mem.csi = cam->csi; ++ if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) { ++ vf.csi_prp_vf_mem.out_width = cam->win.w.height; ++ vf.csi_prp_vf_mem.out_height = cam->win.w.width; ++ } ++ vf.csi_prp_vf_mem.out_pixel_fmt = format; ++ size = cam->win.w.width * cam->win.w.height * size; ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) { ++ vf.csi_prp_vf_mem.mipi_en = true; ++ vf.csi_prp_vf_mem.mipi_vc = ++ mipi_csi2_get_virtual_channel(mipi_csi2_info); ++ vf.csi_prp_vf_mem.mipi_id = ++ mipi_csi2_get_datatype(mipi_csi2_info); ++ ++ mipi_csi2_pixelclk_enable(mipi_csi2_info); ++ } else { ++ vf.csi_prp_vf_mem.mipi_en = false; ++ vf.csi_prp_vf_mem.mipi_vc = 0; ++ vf.csi_prp_vf_mem.mipi_id = 0; ++ } ++ } else { ++ vf.csi_prp_vf_mem.mipi_en = false; ++ vf.csi_prp_vf_mem.mipi_vc = 0; ++ vf.csi_prp_vf_mem.mipi_id = 0; ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf); ++ if (err != 0) ++ goto out_4; ++ ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], cam->vf_bufs[0]); ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], cam->vf_bufs[1]); ++ } ++ cam->vf_bufs_size[0] = PAGE_ALIGN(size); ++ cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0, ++ cam->vf_bufs_size[0], ++ &cam->vf_bufs[0], ++ GFP_DMA | ++ GFP_KERNEL); ++ if (cam->vf_bufs_vaddr[0] == NULL) { ++ printk(KERN_ERR "Error to allocate vf buffer\n"); ++ err = -ENOMEM; ++ goto out_3; ++ } ++ cam->vf_bufs_size[1] = PAGE_ALIGN(size); ++ cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0, ++ cam->vf_bufs_size[1], ++ &cam->vf_bufs[1], ++ GFP_DMA | ++ GFP_KERNEL); ++ if (cam->vf_bufs_vaddr[1] == NULL) { ++ printk(KERN_ERR "Error to allocate vf buffer\n"); ++ err = -ENOMEM; ++ goto out_3; ++ } ++ ++ err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM, ++ IPU_OUTPUT_BUFFER, ++ format, vf.csi_prp_vf_mem.out_width, ++ vf.csi_prp_vf_mem.out_height, ++ vf.csi_prp_vf_mem.out_width, ++ IPU_ROTATE_NONE, ++ cam->vf_bufs[0], ++ cam->vf_bufs[1], ++ 0, 0, 0); ++ if (err != 0) { ++ printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n"); ++ goto out_3; ++ } ++ err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL); ++ if (err != 0) { ++ printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n"); ++ goto out_3; ++ } ++ ++ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM, ++ IPU_INPUT_BUFFER, ++ format, vf.csi_prp_vf_mem.out_width, ++ vf.csi_prp_vf_mem.out_height, ++ vf.csi_prp_vf_mem.out_width, ++ cam->vf_rotation, ++ cam->vf_bufs[0], ++ cam->vf_bufs[1], ++ 0, 0, 0); ++ if (err != 0) { ++ printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n"); ++ goto out_2; ++ } ++ ++ if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) { ++ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM, ++ IPU_OUTPUT_BUFFER, ++ format, ++ vf.csi_prp_vf_mem.out_height, ++ vf.csi_prp_vf_mem.out_width, ++ cam->overlay_fb->var.xres * bpp, ++ IPU_ROTATE_NONE, ++ offset, 0, 0, 0, 0); ++ ++ if (err != 0) { ++ printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n"); ++ goto out_2; ++ } ++ } else { ++ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM, ++ IPU_OUTPUT_BUFFER, ++ format, ++ vf.csi_prp_vf_mem.out_width, ++ vf.csi_prp_vf_mem.out_height, ++ cam->overlay_fb->var.xres * bpp, ++ IPU_ROTATE_NONE, ++ offset, 0, 0, 0, 0); ++ if (err != 0) { ++ printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n"); ++ goto out_2; ++ } ++ } ++ ++ ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF); ++ err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, ++ prpvf_vf_eof_callback, ++ 0, "Mxc Camera", cam); ++ if (err != 0) { ++ printk(KERN_ERR ++ "Error registering IPU_IRQ_PRP_VF_OUT_EOF irq.\n"); ++ goto out_2; ++ } ++ ++ ipu_clear_irq(disp_ipu, IPU_IRQ_BG_SF_END); ++ err = ipu_request_irq(disp_ipu, IPU_IRQ_BG_SF_END, ++ prpvf_sdc_vsync_callback, ++ 0, "Mxc Camera", cam); ++ if (err != 0) { ++ printk(KERN_ERR "Error registering IPU_IRQ_BG_SF_END irq.\n"); ++ goto out_1; ++ } ++ ++ ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM); ++ ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM); ++ ++ buffer_num = 0; ++ buffer_ready = 0; ++ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0); ++ ++ cam->overlay_active = true; ++ return err; ++ ++out_1: ++ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL); ++out_2: ++ ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM); ++out_3: ++ ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM); ++out_4: ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], cam->vf_bufs[0]); ++ cam->vf_bufs_vaddr[0] = NULL; ++ cam->vf_bufs[0] = 0; ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], cam->vf_bufs[1]); ++ cam->vf_bufs_vaddr[1] = NULL; ++ cam->vf_bufs[1] = 0; ++ } ++ if (cam->rot_vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->rot_vf_buf_size[0], ++ cam->rot_vf_bufs_vaddr[0], ++ cam->rot_vf_bufs[0]); ++ cam->rot_vf_bufs_vaddr[0] = NULL; ++ cam->rot_vf_bufs[0] = 0; ++ } ++ if (cam->rot_vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->rot_vf_buf_size[1], ++ cam->rot_vf_bufs_vaddr[1], ++ cam->rot_vf_bufs[1]); ++ cam->rot_vf_bufs_vaddr[1] = NULL; ++ cam->rot_vf_bufs[1] = 0; ++ } ++ return err; ++} ++ ++/*! ++ * prpvf_stop - stop the vf task ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ */ ++static int prpvf_stop(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ void *mipi_csi2_info; ++ int ipu_id; ++ int csi_id; ++#endif ++ ++ if (cam->overlay_active == false) ++ return 0; ++ ++ ipu_free_irq(disp_ipu, IPU_IRQ_BG_SF_END, cam); ++ ++ ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true); ++ ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true); ++ ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM); ++ ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM); ++ ++#ifdef CONFIG_MXC_MIPI_CSI2 ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ if (mipi_csi2_info) { ++ if (mipi_csi2_get_status(mipi_csi2_info)) { ++ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); ++ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); ++ ++ if (cam->ipu == ipu_get_soc(ipu_id) ++ && cam->csi == csi_id) ++ mipi_csi2_pixelclk_disable(mipi_csi2_info); ++ } ++ } else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++#endif ++ ++ if (cam->vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->vf_bufs_size[0], ++ cam->vf_bufs_vaddr[0], cam->vf_bufs[0]); ++ cam->vf_bufs_vaddr[0] = NULL; ++ cam->vf_bufs[0] = 0; ++ } ++ if (cam->vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->vf_bufs_size[1], ++ cam->vf_bufs_vaddr[1], cam->vf_bufs[1]); ++ cam->vf_bufs_vaddr[1] = NULL; ++ cam->vf_bufs[1] = 0; ++ } ++ if (cam->rot_vf_bufs_vaddr[0]) { ++ dma_free_coherent(0, cam->rot_vf_buf_size[0], ++ cam->rot_vf_bufs_vaddr[0], ++ cam->rot_vf_bufs[0]); ++ cam->rot_vf_bufs_vaddr[0] = NULL; ++ cam->rot_vf_bufs[0] = 0; ++ } ++ if (cam->rot_vf_bufs_vaddr[1]) { ++ dma_free_coherent(0, cam->rot_vf_buf_size[1], ++ cam->rot_vf_bufs_vaddr[1], ++ cam->rot_vf_bufs[1]); ++ cam->rot_vf_bufs_vaddr[1] = NULL; ++ cam->rot_vf_bufs[1] = 0; ++ } ++ ++ buffer_num = 0; ++ buffer_ready = 0; ++ cam->overlay_active = false; ++ return 0; ++} ++ ++/*! ++ * Enable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_vf_enable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ return ipu_enable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * Disable csi ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_vf_disable_csi(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ /* free csi eof irq firstly. ++ * when disable csi, wait for idmac eof. ++ * it requests eof irq again */ ++ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam); ++ ++ return ipu_disable_csi(cam->ipu, cam->csi); ++} ++ ++/*! ++ * function to select PRP-VF as the working path ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ * @return status ++ */ ++int prp_vf_sdc_select_bg(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ if (cam) { ++ cam->vf_start_sdc = prpvf_start; ++ cam->vf_stop_sdc = prpvf_stop; ++ cam->vf_enable_csi = prp_vf_enable_csi; ++ cam->vf_disable_csi = prp_vf_disable_csi; ++ cam->overlay_active = false; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(prp_vf_sdc_select_bg); ++ ++/*! ++ * function to de-select PRP-VF as the working path ++ * ++ * @param private cam_data * mxc v4l2 main structure ++ * ++ * @return status ++ */ ++int prp_vf_sdc_deselect_bg(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ if (cam) { ++ cam->vf_start_sdc = NULL; ++ cam->vf_stop_sdc = NULL; ++ cam->vf_enable_csi = NULL; ++ cam->vf_disable_csi = NULL; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(prp_vf_sdc_deselect_bg); ++ ++/*! ++ * Init viewfinder task. ++ * ++ * @return Error code indicating success or failure ++ */ ++__init int prp_vf_sdc_init_bg(void) ++{ ++ return 0; ++} ++ ++/*! ++ * Deinit viewfinder task. ++ * ++ * @return Error code indicating success or failure ++ */ ++void __exit prp_vf_sdc_exit_bg(void) ++{ ++} ++ ++module_init(prp_vf_sdc_init_bg); ++module_exit(prp_vf_sdc_exit_bg); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/ipu_still.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_still.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/ipu_still.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ipu_still.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,268 @@ ++/* ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file ipu_still.c ++ * ++ * @brief IPU Use case for still image capture ++ * ++ * @ingroup IPU ++ */ ++ ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++#include "ipu_prp_sw.h" ++ ++static int callback_eof_flag; ++#ifndef CONFIG_MXC_IPU_V1 ++static int buffer_num; ++#endif ++ ++#ifdef CONFIG_MXC_IPU_V1 ++static int callback_flag; ++/* ++ * Function definitions ++ */ ++/*! ++ * CSI EOF callback function. ++ * ++ * @param irq int irq line ++ * @param dev_id void * device id ++ * ++ * @return status IRQ_HANDLED for handled ++ */ ++static irqreturn_t prp_csi_eof_callback(int irq, void *dev_id) ++{ ++ cam_data *cam = devid; ++ ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, ++ callback_flag%2 ? 1 : 0); ++ if (callback_flag == 0) ++ ipu_enable_channel(cam->ipu, CSI_MEM); ++ ++ callback_flag++; ++ return IRQ_HANDLED; ++} ++#endif ++ ++/*! ++ * CSI callback function. ++ * ++ * @param irq int irq line ++ * @param dev_id void * device id ++ * ++ * @return status IRQ_HANDLED for handled ++ */ ++static irqreturn_t prp_still_callback(int irq, void *dev_id) ++{ ++ cam_data *cam = (cam_data *) dev_id; ++ ++ callback_eof_flag++; ++ if (callback_eof_flag < 5) { ++#ifndef CONFIG_MXC_IPU_V1 ++ buffer_num = (buffer_num == 0) ? 1 : 0; ++ ipu_select_buffer(cam->ipu, CSI_MEM, ++ IPU_OUTPUT_BUFFER, buffer_num); ++#endif ++ } else { ++ cam->still_counter++; ++ wake_up_interruptible(&cam->still_queue); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/*! ++ * start csi->mem task ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_still_start(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ u32 pixel_fmt; ++ int err; ++ ipu_channel_params_t params; ++ ++ if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) ++ pixel_fmt = IPU_PIX_FMT_YUV420P; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) ++ pixel_fmt = IPU_PIX_FMT_NV12; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) ++ pixel_fmt = IPU_PIX_FMT_YUV422P; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) ++ pixel_fmt = IPU_PIX_FMT_UYVY; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) ++ pixel_fmt = IPU_PIX_FMT_YUYV; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) ++ pixel_fmt = IPU_PIX_FMT_BGR24; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) ++ pixel_fmt = IPU_PIX_FMT_RGB24; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) ++ pixel_fmt = IPU_PIX_FMT_RGB565; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) ++ pixel_fmt = IPU_PIX_FMT_BGR32; ++ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) ++ pixel_fmt = IPU_PIX_FMT_RGB32; ++ else { ++ printk(KERN_ERR "format not supported\n"); ++ return -EINVAL; ++ } ++ ++ memset(¶ms, 0, sizeof(params)); ++ err = ipu_init_channel(cam->ipu, CSI_MEM, ¶ms); ++ if (err != 0) ++ return err; ++ ++ err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, ++ pixel_fmt, cam->v2f.fmt.pix.width, ++ cam->v2f.fmt.pix.height, ++ cam->v2f.fmt.pix.width, IPU_ROTATE_NONE, ++ cam->still_buf[0], cam->still_buf[1], 0, ++ 0, 0); ++ if (err != 0) ++ return err; ++ ++#ifdef CONFIG_MXC_IPU_V1 ++ ipu_clear_irq(IPU_IRQ_SENSOR_OUT_EOF); ++ err = ipu_request_irq(IPU_IRQ_SENSOR_OUT_EOF, prp_still_callback, ++ 0, "Mxc Camera", cam); ++ if (err != 0) { ++ printk(KERN_ERR "Error registering irq.\n"); ++ return err; ++ } ++ callback_flag = 0; ++ callback_eof_flag = 0; ++ ipu_clear_irq(IPU_IRQ_SENSOR_EOF); ++ err = ipu_request_irq(IPU_IRQ_SENSOR_EOF, prp_csi_eof_callback, ++ 0, "Mxc Camera", cam); ++ if (err != 0) { ++ printk(KERN_ERR "Error IPU_IRQ_SENSOR_EOF\n"); ++ return err; ++ } ++#else ++ callback_eof_flag = 0; ++ buffer_num = 0; ++ ++ ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF); ++ err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, ++ prp_still_callback, ++ 0, "Mxc Camera", cam); ++ if (err != 0) { ++ printk(KERN_ERR "Error registering irq.\n"); ++ return err; ++ } ++ ++ ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0); ++ ipu_enable_channel(cam->ipu, CSI_MEM); ++ ipu_enable_csi(cam->ipu, cam->csi); ++#endif ++ ++ return err; ++} ++ ++/*! ++ * stop csi->mem encoder task ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++static int prp_still_stop(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++ ++#ifdef CONFIG_MXC_IPU_V1 ++ ipu_free_irq(IPU_IRQ_SENSOR_EOF, NULL); ++ ipu_free_irq(IPU_IRQ_SENSOR_OUT_EOF, cam); ++#else ++ ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam); ++#endif ++ ++ ipu_disable_csi(cam->ipu, cam->csi); ++ ipu_disable_channel(cam->ipu, CSI_MEM, true); ++ ipu_uninit_channel(cam->ipu, CSI_MEM); ++ ++ return err; ++} ++ ++/*! ++ * function to select CSI_MEM as the working path ++ * ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++int prp_still_select(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ ++ if (cam) { ++ cam->csi_start = prp_still_start; ++ cam->csi_stop = prp_still_stop; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(prp_still_select); ++ ++/*! ++ * function to de-select CSI_MEM as the working path ++ * ++ * @param private struct cam_data * mxc capture instance ++ * ++ * @return status ++ */ ++int prp_still_deselect(void *private) ++{ ++ cam_data *cam = (cam_data *) private; ++ int err = 0; ++ ++ err = prp_still_stop(cam); ++ ++ if (cam) { ++ cam->csi_start = NULL; ++ cam->csi_stop = NULL; ++ } ++ ++ return err; ++} ++EXPORT_SYMBOL(prp_still_deselect); ++ ++/*! ++ * Init the Encorder channels ++ * ++ * @return Error code indicating success or failure ++ */ ++__init int prp_still_init(void) ++{ ++ return 0; ++} ++ ++/*! ++ * Deinit the Encorder channels ++ * ++ */ ++void __exit prp_still_exit(void) ++{ ++} ++ ++module_init(prp_still_init); ++module_exit(prp_still_exit); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("IPU PRP STILL IMAGE Driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,3109 @@ ++/* ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file drivers/media/video/mxc/capture/mxc_v4l2_capture.c ++ * ++ * @brief Mxc Video For Linux 2 driver ++ * ++ * @ingroup MXC_V4L2_CAPTURE ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++#include "ipu_prp_sw.h" ++ ++#define init_MUTEX(sem) sema_init(sem, 1) ++ ++static struct platform_device_id imx_v4l2_devtype[] = { ++ { ++ .name = "v4l2-capture-imx5", ++ .driver_data = IMX5_V4L2, ++ }, { ++ .name = "v4l2-capture-imx6", ++ .driver_data = IMX6_V4L2, ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(platform, imx_v4l2_devtype); ++ ++static const struct of_device_id mxc_v4l2_dt_ids[] = { ++ { ++ .compatible = "fsl,imx6q-v4l2-capture", ++ .data = &imx_v4l2_devtype[IMX6_V4L2], ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(of, mxc_v4l2_dt_ids); ++ ++static int video_nr = -1; ++ ++/*! This data is used for the output to the display. */ ++#define MXC_V4L2_CAPTURE_NUM_OUTPUTS 6 ++#define MXC_V4L2_CAPTURE_NUM_INPUTS 2 ++static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = { ++ { ++ .index = 0, ++ .name = "DISP3 BG", ++ .type = V4L2_OUTPUT_TYPE_ANALOG, ++ .audioset = 0, ++ .modulator = 0, ++ .std = V4L2_STD_UNKNOWN, ++ }, ++ { ++ .index = 1, ++ .name = "DISP3 BG - DI1", ++ .type = V4L2_OUTPUT_TYPE_ANALOG, ++ .audioset = 0, ++ .modulator = 0, ++ .std = V4L2_STD_UNKNOWN, ++ }, ++ { ++ .index = 2, ++ .name = "DISP3 FG", ++ .type = V4L2_OUTPUT_TYPE_ANALOG, ++ .audioset = 0, ++ .modulator = 0, ++ .std = V4L2_STD_UNKNOWN, ++ }, ++ { ++ .index = 3, ++ .name = "DISP4 BG", ++ .type = V4L2_OUTPUT_TYPE_ANALOG, ++ .audioset = 0, ++ .modulator = 0, ++ .std = V4L2_STD_UNKNOWN, ++ }, ++ { ++ .index = 4, ++ .name = "DISP4 BG - DI1", ++ .type = V4L2_OUTPUT_TYPE_ANALOG, ++ .audioset = 0, ++ .modulator = 0, ++ .std = V4L2_STD_UNKNOWN, ++ }, ++ { ++ .index = 5, ++ .name = "DISP4 FG", ++ .type = V4L2_OUTPUT_TYPE_ANALOG, ++ .audioset = 0, ++ .modulator = 0, ++ .std = V4L2_STD_UNKNOWN, ++ }, ++}; ++ ++static struct v4l2_input mxc_capture_inputs[MXC_V4L2_CAPTURE_NUM_INPUTS] = { ++ { ++ .index = 0, ++ .name = "CSI IC MEM", ++ .type = V4L2_INPUT_TYPE_CAMERA, ++ .audioset = 0, ++ .tuner = 0, ++ .std = V4L2_STD_UNKNOWN, ++ .status = 0, ++ }, ++ { ++ .index = 1, ++ .name = "CSI MEM", ++ .type = V4L2_INPUT_TYPE_CAMERA, ++ .audioset = 0, ++ .tuner = 0, ++ .std = V4L2_STD_UNKNOWN, ++ .status = V4L2_IN_ST_NO_POWER, ++ }, ++}; ++ ++/*! List of TV input video formats supported. The video formats is corresponding ++ * to the v4l2_id in video_fmt_t. ++ * Currently, only PAL and NTSC is supported. Needs to be expanded in the ++ * future. ++ */ ++typedef enum { ++ TV_NTSC = 0, /*!< Locked on (M) NTSC video signal. */ ++ TV_PAL, /*!< (B, G, H, I, N)PAL video signal. */ ++ TV_NOT_LOCKED, /*!< Not locked on a signal. */ ++} video_fmt_idx; ++ ++/*! Number of video standards supported (including 'not locked' signal). */ ++#define TV_STD_MAX (TV_NOT_LOCKED + 1) ++ ++/*! Video format structure. */ ++typedef struct { ++ int v4l2_id; /*!< Video for linux ID. */ ++ char name[16]; /*!< Name (e.g., "NTSC", "PAL", etc.) */ ++ u16 raw_width; /*!< Raw width. */ ++ u16 raw_height; /*!< Raw height. */ ++ u16 active_width; /*!< Active width. */ ++ u16 active_height; /*!< Active height. */ ++ u16 active_top; /*!< Active top. */ ++ u16 active_left; /*!< Active left. */ ++} video_fmt_t; ++ ++/*! ++ * Description of video formats supported. ++ * ++ * PAL: raw=720x625, active=720x576. ++ * NTSC: raw=720x525, active=720x480. ++ */ ++static video_fmt_t video_fmts[] = { ++ { /*! NTSC */ ++ .v4l2_id = V4L2_STD_NTSC, ++ .name = "NTSC", ++ .raw_width = 720, /* SENS_FRM_WIDTH */ ++ .raw_height = 525, /* SENS_FRM_HEIGHT */ ++ .active_width = 720, /* ACT_FRM_WIDTH */ ++ .active_height = 480, /* ACT_FRM_HEIGHT */ ++ .active_top = 13, ++ .active_left = 0, ++ }, ++ { /*! (B, G, H, I, N) PAL */ ++ .v4l2_id = V4L2_STD_PAL, ++ .name = "PAL", ++ .raw_width = 720, ++ .raw_height = 625, ++ .active_width = 720, ++ .active_height = 576, ++ .active_top = 0, ++ .active_left = 0, ++ }, ++ { /*! Unlocked standard */ ++ .v4l2_id = V4L2_STD_ALL, ++ .name = "Autodetect", ++ .raw_width = 720, ++ .raw_height = 625, ++ .active_width = 720, ++ .active_height = 576, ++ .active_top = 0, ++ .active_left = 0, ++ }, ++}; ++ ++/*!* Standard index of TV. */ ++static video_fmt_idx video_index = TV_NOT_LOCKED; ++ ++static int mxc_v4l2_master_attach(struct v4l2_int_device *slave); ++static void mxc_v4l2_master_detach(struct v4l2_int_device *slave); ++static int start_preview(cam_data *cam); ++static int stop_preview(cam_data *cam); ++ ++/*! Information about this driver. */ ++static struct v4l2_int_master mxc_v4l2_master = { ++ .attach = mxc_v4l2_master_attach, ++ .detach = mxc_v4l2_master_detach, ++}; ++ ++/*************************************************************************** ++ * Functions for handling Frame buffers. ++ **************************************************************************/ ++ ++/*! ++ * Free frame buffers ++ * ++ * @param cam Structure cam_data * ++ * ++ * @return status 0 success. ++ */ ++static int mxc_free_frame_buf(cam_data *cam) ++{ ++ int i; ++ ++ pr_debug("MVC: In mxc_free_frame_buf\n"); ++ ++ for (i = 0; i < FRAME_NUM; i++) { ++ if (cam->frame[i].vaddress != 0) { ++ dma_free_coherent(0, cam->frame[i].buffer.length, ++ cam->frame[i].vaddress, ++ cam->frame[i].paddress); ++ cam->frame[i].vaddress = 0; ++ } ++ } ++ ++ return 0; ++} ++ ++/*! ++ * Allocate frame buffers ++ * ++ * @param cam Structure cam_data* ++ * @param count int number of buffer need to allocated ++ * ++ * @return status -0 Successfully allocated a buffer, -ENOBUFS failed. ++ */ ++static int mxc_allocate_frame_buf(cam_data *cam, int count) ++{ ++ int i; ++ ++ pr_debug("In MVC:mxc_allocate_frame_buf - size=%d\n", ++ cam->v2f.fmt.pix.sizeimage); ++ ++ for (i = 0; i < count; i++) { ++ cam->frame[i].vaddress = ++ dma_alloc_coherent(0, ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), ++ &cam->frame[i].paddress, ++ GFP_DMA | GFP_KERNEL); ++ if (cam->frame[i].vaddress == 0) { ++ pr_err("ERROR: v4l2 capture: " ++ "mxc_allocate_frame_buf failed.\n"); ++ mxc_free_frame_buf(cam); ++ return -ENOBUFS; ++ } ++ cam->frame[i].buffer.index = i; ++ cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED; ++ cam->frame[i].buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ cam->frame[i].buffer.length = ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); ++ cam->frame[i].buffer.memory = V4L2_MEMORY_MMAP; ++ cam->frame[i].buffer.m.offset = cam->frame[i].paddress; ++ cam->frame[i].index = i; ++ } ++ ++ return 0; ++} ++ ++/*! ++ * Free frame buffers status ++ * ++ * @param cam Structure cam_data * ++ * ++ * @return none ++ */ ++static void mxc_free_frames(cam_data *cam) ++{ ++ int i; ++ ++ pr_debug("In MVC:mxc_free_frames\n"); ++ ++ for (i = 0; i < FRAME_NUM; i++) ++ cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED; ++ ++ cam->enc_counter = 0; ++ INIT_LIST_HEAD(&cam->ready_q); ++ INIT_LIST_HEAD(&cam->working_q); ++ INIT_LIST_HEAD(&cam->done_q); ++} ++ ++/*! ++ * Return the buffer status ++ * ++ * @param cam Structure cam_data * ++ * @param buf Structure v4l2_buffer * ++ * ++ * @return status 0 success, EINVAL failed. ++ */ ++static int mxc_v4l2_buffer_status(cam_data *cam, struct v4l2_buffer *buf) ++{ ++ pr_debug("In MVC:mxc_v4l2_buffer_status\n"); ++ ++ if (buf->index < 0 || buf->index >= FRAME_NUM) { ++ pr_err("ERROR: v4l2 capture: mxc_v4l2_buffer_status buffers " ++ "not allocated\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(buf, &(cam->frame[buf->index].buffer), sizeof(*buf)); ++ return 0; ++} ++ ++static int mxc_v4l2_release_bufs(cam_data *cam) ++{ ++ pr_debug("In MVC:mxc_v4l2_release_bufs\n"); ++ return 0; ++} ++ ++static int mxc_v4l2_prepare_bufs(cam_data *cam, struct v4l2_buffer *buf) ++{ ++ pr_debug("In MVC:mxc_v4l2_prepare_bufs\n"); ++ ++ if (buf->index < 0 || buf->index >= FRAME_NUM || buf->length < ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage)) { ++ pr_err("ERROR: v4l2 capture: mxc_v4l2_prepare_bufs buffers " ++ "not allocated,index=%d, length=%d\n", buf->index, ++ buf->length); ++ return -EINVAL; ++ } ++ ++ cam->frame[buf->index].buffer.index = buf->index; ++ cam->frame[buf->index].buffer.flags = V4L2_BUF_FLAG_MAPPED; ++ cam->frame[buf->index].buffer.length = buf->length; ++ cam->frame[buf->index].buffer.m.offset = cam->frame[buf->index].paddress ++ = buf->m.offset; ++ cam->frame[buf->index].buffer.type = buf->type; ++ cam->frame[buf->index].buffer.memory = V4L2_MEMORY_USERPTR; ++ cam->frame[buf->index].index = buf->index; ++ ++ return 0; ++} ++ ++/*************************************************************************** ++ * Functions for handling the video stream. ++ **************************************************************************/ ++ ++/*! ++ * Indicates whether the palette is supported. ++ * ++ * @param palette V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32 ++ * ++ * @return 0 if failed ++ */ ++static inline int valid_mode(u32 palette) ++{ ++ return ((palette == V4L2_PIX_FMT_RGB565) || ++ (palette == V4L2_PIX_FMT_BGR24) || ++ (palette == V4L2_PIX_FMT_RGB24) || ++ (palette == V4L2_PIX_FMT_BGR32) || ++ (palette == V4L2_PIX_FMT_RGB32) || ++ (palette == V4L2_PIX_FMT_YUV422P) || ++ (palette == V4L2_PIX_FMT_UYVY) || ++ (palette == V4L2_PIX_FMT_YUYV) || ++ (palette == V4L2_PIX_FMT_YUV420) || ++ (palette == V4L2_PIX_FMT_YVU420) || ++ (palette == V4L2_PIX_FMT_NV12)); ++} ++ ++/*! ++ * Start the encoder job ++ * ++ * @param cam structure cam_data * ++ * ++ * @return status 0 Success ++ */ ++static int mxc_streamon(cam_data *cam) ++{ ++ struct mxc_v4l_frame *frame; ++ unsigned long lock_flags; ++ int err = 0; ++ ++ pr_debug("In MVC:mxc_streamon\n"); ++ ++ if (NULL == cam) { ++ pr_err("ERROR! cam parameter is NULL\n"); ++ return -1; ++ } ++ ++ if (cam->capture_on) { ++ pr_err("ERROR: v4l2 capture: Capture stream has been turned " ++ " on\n"); ++ return -1; ++ } ++ ++ if (list_empty(&cam->ready_q)) { ++ pr_err("ERROR: v4l2 capture: mxc_streamon buffer has not been " ++ "queued yet\n"); ++ return -EINVAL; ++ } ++ if (cam->enc_update_eba && ++ cam->ready_q.prev == cam->ready_q.next) { ++ pr_err("ERROR: v4l2 capture: mxc_streamon buffer need " ++ "ping pong at least two buffers\n"); ++ return -EINVAL; ++ } ++ ++ cam->capture_pid = current->pid; ++ ++ if (cam->overlay_on == true) ++ stop_preview(cam); ++ ++ if (cam->enc_enable) { ++ err = cam->enc_enable(cam); ++ if (err != 0) ++ return err; ++ } ++ ++ spin_lock_irqsave(&cam->queue_int_lock, lock_flags); ++ cam->ping_pong_csi = 0; ++ cam->local_buf_num = 0; ++ if (cam->enc_update_eba) { ++ frame = ++ list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); ++ list_del(cam->ready_q.next); ++ list_add_tail(&frame->queue, &cam->working_q); ++ frame->ipu_buf_num = cam->ping_pong_csi; ++ err = cam->enc_update_eba(cam->ipu, frame->buffer.m.offset, ++ &cam->ping_pong_csi); ++ ++ frame = ++ list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); ++ list_del(cam->ready_q.next); ++ list_add_tail(&frame->queue, &cam->working_q); ++ frame->ipu_buf_num = cam->ping_pong_csi; ++ err |= cam->enc_update_eba(cam->ipu, frame->buffer.m.offset, ++ &cam->ping_pong_csi); ++ spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); ++ } else { ++ spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); ++ return -EINVAL; ++ } ++ ++ if (cam->overlay_on == true) ++ start_preview(cam); ++ ++ if (cam->enc_enable_csi) { ++ err = cam->enc_enable_csi(cam); ++ if (err != 0) ++ return err; ++ } ++ ++ cam->capture_on = true; ++ ++ return err; ++} ++ ++/*! ++ * Shut down the encoder job ++ * ++ * @param cam structure cam_data * ++ * ++ * @return status 0 Success ++ */ ++static int mxc_streamoff(cam_data *cam) ++{ ++ int err = 0; ++ ++ pr_debug("In MVC:mxc_streamoff\n"); ++ ++ if (cam->capture_on == false) ++ return 0; ++ ++ /* For both CSI--MEM and CSI--IC--MEM ++ * 1. wait for idmac eof ++ * 2. disable csi first ++ * 3. disable idmac ++ * 4. disable smfc (CSI--MEM channel) ++ */ ++ if (mxc_capture_inputs[cam->current_input].name != NULL) { ++ if (cam->enc_disable_csi) { ++ err = cam->enc_disable_csi(cam); ++ if (err != 0) ++ return err; ++ } ++ if (cam->enc_disable) { ++ err = cam->enc_disable(cam); ++ if (err != 0) ++ return err; ++ } ++ } ++ ++ mxc_free_frames(cam); ++ mxc_capture_inputs[cam->current_input].status |= V4L2_IN_ST_NO_POWER; ++ cam->capture_on = false; ++ return err; ++} ++ ++/*! ++ * Valid and adjust the overlay window size, position ++ * ++ * @param cam structure cam_data * ++ * @param win struct v4l2_window * ++ * ++ * @return 0 ++ */ ++static int verify_preview(cam_data *cam, struct v4l2_window *win) ++{ ++ int i = 0, width_bound = 0, height_bound = 0; ++ int *width, *height; ++ unsigned int ipu_ch = CHAN_NONE; ++ struct fb_info *bg_fbi = NULL, *fbi = NULL; ++ bool foregound_fb = false; ++ mm_segment_t old_fs; ++ ++ pr_debug("In MVC: verify_preview\n"); ++ ++ do { ++ fbi = (struct fb_info *)registered_fb[i]; ++ if (fbi == NULL) { ++ pr_err("ERROR: verify_preview frame buffer NULL.\n"); ++ return -1; ++ } ++ ++ /* Which DI supports 2 layers? */ ++ if (((strncmp(fbi->fix.id, "DISP3 BG", 8) == 0) && ++ (cam->output < 3)) || ++ ((strncmp(fbi->fix.id, "DISP4 BG", 8) == 0) && ++ (cam->output >= 3))) { ++ if (fbi->fbops->fb_ioctl) { ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN, ++ (unsigned long)&ipu_ch); ++ set_fs(old_fs); ++ } ++ if (ipu_ch == MEM_BG_SYNC) { ++ bg_fbi = fbi; ++ pr_debug("Found background frame buffer.\n"); ++ } ++ } ++ ++ /* Found the frame buffer to preview on. */ ++ if (strcmp(fbi->fix.id, ++ mxc_capture_outputs[cam->output].name) == 0) { ++ if (((strcmp(fbi->fix.id, "DISP3 FG") == 0) && ++ (cam->output < 3)) || ++ ((strcmp(fbi->fix.id, "DISP4 FG") == 0) && ++ (cam->output >= 3))) ++ foregound_fb = true; ++ ++ cam->overlay_fb = fbi; ++ break; ++ } ++ } while (++i < FB_MAX); ++ ++ if (foregound_fb) { ++ width_bound = bg_fbi->var.xres; ++ height_bound = bg_fbi->var.yres; ++ ++ if (win->w.width + win->w.left > bg_fbi->var.xres || ++ win->w.height + win->w.top > bg_fbi->var.yres) { ++ pr_err("ERROR: FG window position exceeds.\n"); ++ return -1; ++ } ++ } else { ++ /* 4 bytes alignment for BG */ ++ width_bound = cam->overlay_fb->var.xres; ++ height_bound = cam->overlay_fb->var.yres; ++ ++ if (cam->overlay_fb->var.bits_per_pixel == 24) ++ win->w.left -= win->w.left % 4; ++ else if (cam->overlay_fb->var.bits_per_pixel == 16) ++ win->w.left -= win->w.left % 2; ++ ++ if (win->w.width + win->w.left > cam->overlay_fb->var.xres) ++ win->w.width = cam->overlay_fb->var.xres - win->w.left; ++ if (win->w.height + win->w.top > cam->overlay_fb->var.yres) ++ win->w.height = cam->overlay_fb->var.yres - win->w.top; ++ } ++ ++ /* stride line limitation */ ++ win->w.height -= win->w.height % 8; ++ win->w.width -= win->w.width % 8; ++ ++ if (cam->rotation >= IPU_ROTATE_90_RIGHT) { ++ height = &win->w.width; ++ width = &win->w.height; ++ } else { ++ width = &win->w.width; ++ height = &win->w.height; ++ } ++ ++ if (*width == 0 || *height == 0) { ++ pr_err("ERROR: v4l2 capture: width or height" ++ " too small.\n"); ++ return -EINVAL; ++ } ++ ++ if ((cam->crop_bounds.width / *width > 8) || ++ ((cam->crop_bounds.width / *width == 8) && ++ (cam->crop_bounds.width % *width))) { ++ *width = cam->crop_bounds.width / 8; ++ if (*width % 8) ++ *width += 8 - *width % 8; ++ if (*width + win->w.left > width_bound) { ++ pr_err("ERROR: v4l2 capture: width exceeds " ++ "resize limit.\n"); ++ return -1; ++ } ++ pr_err("ERROR: v4l2 capture: width exceeds limit. " ++ "Resize to %d.\n", ++ *width); ++ } ++ ++ if ((cam->crop_bounds.height / *height > 8) || ++ ((cam->crop_bounds.height / *height == 8) && ++ (cam->crop_bounds.height % *height))) { ++ *height = cam->crop_bounds.height / 8; ++ if (*height % 8) ++ *height += 8 - *height % 8; ++ if (*height + win->w.top > height_bound) { ++ pr_err("ERROR: v4l2 capture: height exceeds " ++ "resize limit.\n"); ++ return -1; ++ } ++ pr_err("ERROR: v4l2 capture: height exceeds limit " ++ "resize to %d.\n", ++ *height); ++ } ++ ++ return 0; ++} ++ ++/*! ++ * start the viewfinder job ++ * ++ * @param cam structure cam_data * ++ * ++ * @return status 0 Success ++ */ ++static int start_preview(cam_data *cam) ++{ ++ int err = 0; ++ ++ pr_debug("MVC: start_preview\n"); ++ ++ if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) ++ #ifdef CONFIG_MXC_IPU_PRP_VF_SDC ++ err = prp_vf_sdc_select(cam); ++ #else ++ err = foreground_sdc_select(cam); ++ #endif ++ else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY) ++ #ifdef CONFIG_MXC_IPU_PRP_VF_SDC ++ err = prp_vf_sdc_select_bg(cam); ++ #else ++ err = bg_overlay_sdc_select(cam); ++ #endif ++ if (err != 0) ++ return err; ++ ++ if (cam->vf_start_sdc) { ++ err = cam->vf_start_sdc(cam); ++ if (err != 0) ++ return err; ++ } ++ ++ if (cam->vf_enable_csi) ++ err = cam->vf_enable_csi(cam); ++ ++ pr_debug("End of %s: v2f pix widthxheight %d x %d\n", ++ __func__, ++ cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); ++ pr_debug("End of %s: crop_bounds widthxheight %d x %d\n", ++ __func__, ++ cam->crop_bounds.width, cam->crop_bounds.height); ++ pr_debug("End of %s: crop_defrect widthxheight %d x %d\n", ++ __func__, ++ cam->crop_defrect.width, cam->crop_defrect.height); ++ pr_debug("End of %s: crop_current widthxheight %d x %d\n", ++ __func__, ++ cam->crop_current.width, cam->crop_current.height); ++ ++ return err; ++} ++ ++/*! ++ * shut down the viewfinder job ++ * ++ * @param cam structure cam_data * ++ * ++ * @return status 0 Success ++ */ ++static int stop_preview(cam_data *cam) ++{ ++ int err = 0; ++ ++ if (cam->vf_disable_csi) { ++ err = cam->vf_disable_csi(cam); ++ if (err != 0) ++ return err; ++ } ++ ++ if (cam->vf_stop_sdc) { ++ err = cam->vf_stop_sdc(cam); ++ if (err != 0) ++ return err; ++ } ++ ++ if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) ++ #ifdef CONFIG_MXC_IPU_PRP_VF_SDC ++ err = prp_vf_sdc_deselect(cam); ++ #else ++ err = foreground_sdc_deselect(cam); ++ #endif ++ else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY) ++ #ifdef CONFIG_MXC_IPU_PRP_VF_SDC ++ err = prp_vf_sdc_deselect_bg(cam); ++ #else ++ err = bg_overlay_sdc_deselect(cam); ++ #endif ++ ++ return err; ++} ++ ++/*************************************************************************** ++ * VIDIOC Functions. ++ **************************************************************************/ ++ ++/*! ++ * V4L2 - mxc_v4l2_g_fmt function ++ * ++ * @param cam structure cam_data * ++ * ++ * @param f structure v4l2_format * ++ * ++ * @return status 0 success, EINVAL failed ++ */ ++static int mxc_v4l2_g_fmt(cam_data *cam, struct v4l2_format *f) ++{ ++ int retval = 0; ++ ++ pr_debug("In MVC: mxc_v4l2_g_fmt type=%d\n", f->type); ++ ++ switch (f->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); ++ f->fmt.pix = cam->v2f.fmt.pix; ++ break; ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ pr_debug(" type is V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); ++ f->fmt.win = cam->win; ++ break; ++ default: ++ pr_debug(" type is invalid\n"); ++ retval = -EINVAL; ++ } ++ ++ pr_debug("End of %s: v2f pix widthxheight %d x %d\n", ++ __func__, ++ cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); ++ pr_debug("End of %s: crop_bounds widthxheight %d x %d\n", ++ __func__, ++ cam->crop_bounds.width, cam->crop_bounds.height); ++ pr_debug("End of %s: crop_defrect widthxheight %d x %d\n", ++ __func__, ++ cam->crop_defrect.width, cam->crop_defrect.height); ++ pr_debug("End of %s: crop_current widthxheight %d x %d\n", ++ __func__, ++ cam->crop_current.width, cam->crop_current.height); ++ ++ return retval; ++} ++ ++/*! ++ * V4L2 - mxc_v4l2_s_fmt function ++ * ++ * @param cam structure cam_data * ++ * ++ * @param f structure v4l2_format * ++ * ++ * @return status 0 success, EINVAL failed ++ */ ++static int mxc_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f) ++{ ++ int retval = 0; ++ int size = 0; ++ int bytesperline = 0; ++ int *width, *height; ++ ++ pr_debug("In MVC: mxc_v4l2_s_fmt\n"); ++ ++ switch (f->type) { ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ pr_debug(" type=V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); ++ if (!valid_mode(f->fmt.pix.pixelformat)) { ++ pr_err("ERROR: v4l2 capture: mxc_v4l2_s_fmt: format " ++ "not supported\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * Force the capture window resolution to be crop bounds ++ * for CSI MEM input mode. ++ */ ++ if (strcmp(mxc_capture_inputs[cam->current_input].name, ++ "CSI MEM") == 0) { ++ f->fmt.pix.width = cam->crop_current.width; ++ f->fmt.pix.height = cam->crop_current.height; ++ } ++ ++ if (cam->rotation >= IPU_ROTATE_90_RIGHT) { ++ height = &f->fmt.pix.width; ++ width = &f->fmt.pix.height; ++ } else { ++ width = &f->fmt.pix.width; ++ height = &f->fmt.pix.height; ++ } ++ ++ /* stride line limitation */ ++ *width -= *width % 8; ++ *height -= *height % 8; ++ ++ if (*width == 0 || *height == 0) { ++ pr_err("ERROR: v4l2 capture: width or height" ++ " too small.\n"); ++ return -EINVAL; ++ } ++ ++ if ((cam->crop_current.width / *width > 8) || ++ ((cam->crop_current.width / *width == 8) && ++ (cam->crop_current.width % *width))) { ++ *width = cam->crop_current.width / 8; ++ if (*width % 8) ++ *width += 8 - *width % 8; ++ pr_err("ERROR: v4l2 capture: width exceeds limit " ++ "resize to %d.\n", ++ *width); ++ } ++ ++ if ((cam->crop_current.height / *height > 8) || ++ ((cam->crop_current.height / *height == 8) && ++ (cam->crop_current.height % *height))) { ++ *height = cam->crop_current.height / 8; ++ if (*height % 8) ++ *height += 8 - *height % 8; ++ pr_err("ERROR: v4l2 capture: height exceeds limit " ++ "resize to %d.\n", ++ *height); ++ } ++ ++ switch (f->fmt.pix.pixelformat) { ++ case V4L2_PIX_FMT_RGB565: ++ size = f->fmt.pix.width * f->fmt.pix.height * 2; ++ bytesperline = f->fmt.pix.width * 2; ++ break; ++ case V4L2_PIX_FMT_BGR24: ++ size = f->fmt.pix.width * f->fmt.pix.height * 3; ++ bytesperline = f->fmt.pix.width * 3; ++ break; ++ case V4L2_PIX_FMT_RGB24: ++ size = f->fmt.pix.width * f->fmt.pix.height * 3; ++ bytesperline = f->fmt.pix.width * 3; ++ break; ++ case V4L2_PIX_FMT_BGR32: ++ size = f->fmt.pix.width * f->fmt.pix.height * 4; ++ bytesperline = f->fmt.pix.width * 4; ++ break; ++ case V4L2_PIX_FMT_RGB32: ++ size = f->fmt.pix.width * f->fmt.pix.height * 4; ++ bytesperline = f->fmt.pix.width * 4; ++ break; ++ case V4L2_PIX_FMT_YUV422P: ++ size = f->fmt.pix.width * f->fmt.pix.height * 2; ++ bytesperline = f->fmt.pix.width; ++ break; ++ case V4L2_PIX_FMT_UYVY: ++ case V4L2_PIX_FMT_YUYV: ++ size = f->fmt.pix.width * f->fmt.pix.height * 2; ++ bytesperline = f->fmt.pix.width * 2; ++ break; ++ case V4L2_PIX_FMT_YUV420: ++ case V4L2_PIX_FMT_YVU420: ++ size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2; ++ bytesperline = f->fmt.pix.width; ++ break; ++ case V4L2_PIX_FMT_NV12: ++ size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2; ++ bytesperline = f->fmt.pix.width; ++ break; ++ default: ++ break; ++ } ++ ++ if (f->fmt.pix.bytesperline < bytesperline) ++ f->fmt.pix.bytesperline = bytesperline; ++ else ++ bytesperline = f->fmt.pix.bytesperline; ++ ++ if (f->fmt.pix.sizeimage < size) ++ f->fmt.pix.sizeimage = size; ++ else ++ size = f->fmt.pix.sizeimage; ++ ++ cam->v2f.fmt.pix = f->fmt.pix; ++ ++ if (cam->v2f.fmt.pix.priv != 0) { ++ if (copy_from_user(&cam->offset, ++ (void *)cam->v2f.fmt.pix.priv, ++ sizeof(cam->offset))) { ++ retval = -EFAULT; ++ break; ++ } ++ } ++ break; ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ pr_debug(" type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); ++ retval = verify_preview(cam, &f->fmt.win); ++ cam->win = f->fmt.win; ++ break; ++ default: ++ retval = -EINVAL; ++ } ++ ++ pr_debug("End of %s: v2f pix widthxheight %d x %d\n", ++ __func__, ++ cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); ++ pr_debug("End of %s: crop_bounds widthxheight %d x %d\n", ++ __func__, ++ cam->crop_bounds.width, cam->crop_bounds.height); ++ pr_debug("End of %s: crop_defrect widthxheight %d x %d\n", ++ __func__, ++ cam->crop_defrect.width, cam->crop_defrect.height); ++ pr_debug("End of %s: crop_current widthxheight %d x %d\n", ++ __func__, ++ cam->crop_current.width, cam->crop_current.height); ++ ++ return retval; ++} ++ ++/*! ++ * get control param ++ * ++ * @param cam structure cam_data * ++ * ++ * @param c structure v4l2_control * ++ * ++ * @return status 0 success, EINVAL failed ++ */ ++static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c) ++{ ++ int status = 0; ++ ++ pr_debug("In MVC:mxc_v4l2_g_ctrl\n"); ++ ++ /* probably don't need to store the values that can be retrieved, ++ * locally, but they are for now. */ ++ switch (c->id) { ++ case V4L2_CID_HFLIP: ++ /* This is handled in the ipu. */ ++ if (cam->rotation == IPU_ROTATE_HORIZ_FLIP) ++ c->value = 1; ++ break; ++ case V4L2_CID_VFLIP: ++ /* This is handled in the ipu. */ ++ if (cam->rotation == IPU_ROTATE_VERT_FLIP) ++ c->value = 1; ++ break; ++ case V4L2_CID_MXC_ROT: ++ /* This is handled in the ipu. */ ++ c->value = cam->rotation; ++ break; ++ case V4L2_CID_BRIGHTNESS: ++ if (cam->sensor) { ++ c->value = cam->bright; ++ status = vidioc_int_g_ctrl(cam->sensor, c); ++ cam->bright = c->value; ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ status = -ENODEV; ++ } ++ break; ++ case V4L2_CID_HUE: ++ if (cam->sensor) { ++ c->value = cam->hue; ++ status = vidioc_int_g_ctrl(cam->sensor, c); ++ cam->hue = c->value; ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ status = -ENODEV; ++ } ++ break; ++ case V4L2_CID_CONTRAST: ++ if (cam->sensor) { ++ c->value = cam->contrast; ++ status = vidioc_int_g_ctrl(cam->sensor, c); ++ cam->contrast = c->value; ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ status = -ENODEV; ++ } ++ break; ++ case V4L2_CID_SATURATION: ++ if (cam->sensor) { ++ c->value = cam->saturation; ++ status = vidioc_int_g_ctrl(cam->sensor, c); ++ cam->saturation = c->value; ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ status = -ENODEV; ++ } ++ break; ++ case V4L2_CID_RED_BALANCE: ++ if (cam->sensor) { ++ c->value = cam->red; ++ status = vidioc_int_g_ctrl(cam->sensor, c); ++ cam->red = c->value; ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ status = -ENODEV; ++ } ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ if (cam->sensor) { ++ c->value = cam->blue; ++ status = vidioc_int_g_ctrl(cam->sensor, c); ++ cam->blue = c->value; ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ status = -ENODEV; ++ } ++ break; ++ case V4L2_CID_BLACK_LEVEL: ++ if (cam->sensor) { ++ c->value = cam->ae_mode; ++ status = vidioc_int_g_ctrl(cam->sensor, c); ++ cam->ae_mode = c->value; ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ status = -ENODEV; ++ } ++ break; ++ default: ++ pr_err("ERROR: v4l2 capture: unsupported ioctrl!\n"); ++ } ++ ++ return status; ++} ++ ++/*! ++ * V4L2 - set_control function ++ * V4L2_CID_PRIVATE_BASE is the extention for IPU preprocessing. ++ * 0 for normal operation ++ * 1 for vertical flip ++ * 2 for horizontal flip ++ * 3 for horizontal and vertical flip ++ * 4 for 90 degree rotation ++ * @param cam structure cam_data * ++ * ++ * @param c structure v4l2_control * ++ * ++ * @return status 0 success, EINVAL failed ++ */ ++static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c) ++{ ++ int i, ret = 0; ++ int tmp_rotation = IPU_ROTATE_NONE; ++ struct sensor_data *sensor_data; ++ ++ pr_debug("In MVC:mxc_v4l2_s_ctrl\n"); ++ ++ switch (c->id) { ++ case V4L2_CID_HFLIP: ++ /* This is done by the IPU */ ++ if (c->value == 1) { ++ if ((cam->rotation != IPU_ROTATE_VERT_FLIP) && ++ (cam->rotation != IPU_ROTATE_180)) ++ cam->rotation = IPU_ROTATE_HORIZ_FLIP; ++ else ++ cam->rotation = IPU_ROTATE_180; ++ } else { ++ if (cam->rotation == IPU_ROTATE_HORIZ_FLIP) ++ cam->rotation = IPU_ROTATE_NONE; ++ if (cam->rotation == IPU_ROTATE_180) ++ cam->rotation = IPU_ROTATE_VERT_FLIP; ++ } ++ break; ++ case V4L2_CID_VFLIP: ++ /* This is done by the IPU */ ++ if (c->value == 1) { ++ if ((cam->rotation != IPU_ROTATE_HORIZ_FLIP) && ++ (cam->rotation != IPU_ROTATE_180)) ++ cam->rotation = IPU_ROTATE_VERT_FLIP; ++ else ++ cam->rotation = IPU_ROTATE_180; ++ } else { ++ if (cam->rotation == IPU_ROTATE_VERT_FLIP) ++ cam->rotation = IPU_ROTATE_NONE; ++ if (cam->rotation == IPU_ROTATE_180) ++ cam->rotation = IPU_ROTATE_HORIZ_FLIP; ++ } ++ break; ++ case V4L2_CID_MXC_ROT: ++ case V4L2_CID_MXC_VF_ROT: ++ /* This is done by the IPU */ ++ switch (c->value) { ++ case V4L2_MXC_ROTATE_NONE: ++ tmp_rotation = IPU_ROTATE_NONE; ++ break; ++ case V4L2_MXC_ROTATE_VERT_FLIP: ++ tmp_rotation = IPU_ROTATE_VERT_FLIP; ++ break; ++ case V4L2_MXC_ROTATE_HORIZ_FLIP: ++ tmp_rotation = IPU_ROTATE_HORIZ_FLIP; ++ break; ++ case V4L2_MXC_ROTATE_180: ++ tmp_rotation = IPU_ROTATE_180; ++ break; ++ case V4L2_MXC_ROTATE_90_RIGHT: ++ tmp_rotation = IPU_ROTATE_90_RIGHT; ++ break; ++ case V4L2_MXC_ROTATE_90_RIGHT_VFLIP: ++ tmp_rotation = IPU_ROTATE_90_RIGHT_VFLIP; ++ break; ++ case V4L2_MXC_ROTATE_90_RIGHT_HFLIP: ++ tmp_rotation = IPU_ROTATE_90_RIGHT_HFLIP; ++ break; ++ case V4L2_MXC_ROTATE_90_LEFT: ++ tmp_rotation = IPU_ROTATE_90_LEFT; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ #ifdef CONFIG_MXC_IPU_PRP_VF_SDC ++ if (c->id == V4L2_CID_MXC_VF_ROT) ++ cam->vf_rotation = tmp_rotation; ++ else ++ cam->rotation = tmp_rotation; ++ #else ++ cam->rotation = tmp_rotation; ++ #endif ++ ++ break; ++ case V4L2_CID_HUE: ++ if (cam->sensor) { ++ cam->hue = c->value; ++ ret = vidioc_int_s_ctrl(cam->sensor, c); ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ ret = -ENODEV; ++ } ++ break; ++ case V4L2_CID_CONTRAST: ++ if (cam->sensor) { ++ cam->contrast = c->value; ++ ret = vidioc_int_s_ctrl(cam->sensor, c); ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ ret = -ENODEV; ++ } ++ break; ++ case V4L2_CID_BRIGHTNESS: ++ if (cam->sensor) { ++ cam->bright = c->value; ++ ret = vidioc_int_s_ctrl(cam->sensor, c); ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ ret = -ENODEV; ++ } ++ break; ++ case V4L2_CID_SATURATION: ++ if (cam->sensor) { ++ cam->saturation = c->value; ++ ret = vidioc_int_s_ctrl(cam->sensor, c); ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ ret = -ENODEV; ++ } ++ break; ++ case V4L2_CID_RED_BALANCE: ++ if (cam->sensor) { ++ cam->red = c->value; ++ ret = vidioc_int_s_ctrl(cam->sensor, c); ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ ret = -ENODEV; ++ } ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ if (cam->sensor) { ++ cam->blue = c->value; ++ ret = vidioc_int_s_ctrl(cam->sensor, c); ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ ret = -ENODEV; ++ } ++ break; ++ case V4L2_CID_EXPOSURE: ++ if (cam->sensor) { ++ cam->ae_mode = c->value; ++ ret = vidioc_int_s_ctrl(cam->sensor, c); ++ } else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ ret = -ENODEV; ++ } ++ break; ++ case V4L2_CID_MXC_FLASH: ++#ifdef CONFIG_MXC_IPU_V1 ++ ipu_csi_flash_strobe(true); ++#endif ++ break; ++ case V4L2_CID_MXC_SWITCH_CAM: ++ if (cam->sensor == cam->all_sensors[c->value]) ++ break; ++ ++ /* power down other cameraes before enable new one */ ++ for (i = 0; i < cam->sensor_index; i++) { ++ if (i != c->value) { ++ vidioc_int_dev_exit(cam->all_sensors[i]); ++ vidioc_int_s_power(cam->all_sensors[i], 0); ++ if (cam->mclk_on[cam->mclk_source]) { ++ ipu_csi_enable_mclk_if(cam->ipu, ++ CSI_MCLK_I2C, ++ cam->mclk_source, ++ false, false); ++ cam->mclk_on[cam->mclk_source] = ++ false; ++ } ++ } ++ } ++ sensor_data = cam->all_sensors[c->value]->priv; ++ if (sensor_data->io_init) ++ sensor_data->io_init(); ++ cam->sensor = cam->all_sensors[c->value]; ++ cam->mclk_source = sensor_data->mclk_source; ++ ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C, ++ cam->mclk_source, true, true); ++ cam->mclk_on[cam->mclk_source] = true; ++ vidioc_int_s_power(cam->sensor, 1); ++ vidioc_int_dev_init(cam->sensor); ++ break; ++ default: ++ pr_debug(" default case\n"); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * V4L2 - mxc_v4l2_s_param function ++ * Allows setting of capturemode and frame rate. ++ * ++ * @param cam structure cam_data * ++ * @param parm structure v4l2_streamparm * ++ * ++ * @return status 0 success, EINVAL failed ++ */ ++static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) ++{ ++ struct v4l2_ifparm ifparm; ++ struct v4l2_format cam_fmt; ++ struct v4l2_streamparm currentparm; ++ ipu_csi_signal_cfg_t csi_param; ++ u32 current_fps, parm_fps; ++ int err = 0; ++ ++ pr_debug("In mxc_v4l2_s_param\n"); ++ ++ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { ++ pr_err(KERN_ERR "mxc_v4l2_s_param invalid type\n"); ++ return -EINVAL; ++ } ++ ++ /* Stop the viewfinder */ ++ if (cam->overlay_on == true) ++ stop_preview(cam); ++ ++ currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ ++ /* First check that this device can support the changes requested. */ ++ err = vidioc_int_g_parm(cam->sensor, ¤tparm); ++ if (err) { ++ pr_err("%s: vidioc_int_g_parm returned an error %d\n", ++ __func__, err); ++ goto exit; ++ } ++ ++ current_fps = currentparm.parm.capture.timeperframe.denominator ++ / currentparm.parm.capture.timeperframe.numerator; ++ parm_fps = parm->parm.capture.timeperframe.denominator ++ / parm->parm.capture.timeperframe.numerator; ++ ++ pr_debug(" Current capabilities are %x\n", ++ currentparm.parm.capture.capability); ++ pr_debug(" Current capturemode is %d change to %d\n", ++ currentparm.parm.capture.capturemode, ++ parm->parm.capture.capturemode); ++ pr_debug(" Current framerate is %d change to %d\n", ++ current_fps, parm_fps); ++ ++ /* This will change any camera settings needed. */ ++ err = vidioc_int_s_parm(cam->sensor, parm); ++ if (err) { ++ pr_err("%s: vidioc_int_s_parm returned an error %d\n", ++ __func__, err); ++ goto exit; ++ } ++ ++ /* If resolution changed, need to re-program the CSI */ ++ /* Get new values. */ ++ vidioc_int_g_ifparm(cam->sensor, &ifparm); ++ ++ csi_param.data_width = 0; ++ csi_param.clk_mode = 0; ++ csi_param.ext_vsync = 0; ++ csi_param.Vsync_pol = 0; ++ csi_param.Hsync_pol = 0; ++ csi_param.pixclk_pol = 0; ++ csi_param.data_pol = 0; ++ csi_param.sens_clksrc = 0; ++ csi_param.pack_tight = 0; ++ csi_param.force_eof = 0; ++ csi_param.data_en_pol = 0; ++ csi_param.data_fmt = 0; ++ csi_param.csi = cam->csi; ++ csi_param.mclk = 0; ++ ++ /*This may not work on other platforms. Check when adding a new one.*/ ++ /*The mclk clock was never set correclty in the ipu register*/ ++ /*for now we are going to use this mclk as pixel clock*/ ++ /*to set csi0_data_dest register.*/ ++ /*This is a workaround which should be fixed*/ ++ pr_debug(" clock_curr=mclk=%d\n", ifparm.u.bt656.clock_curr); ++ if (ifparm.u.bt656.clock_curr == 0) { ++ csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; ++ /*protocol bt656 use 27Mhz pixel clock */ ++ csi_param.mclk = 27000000; ++ } else { ++ csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; ++ } ++ ++ csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv; ++ ++ if (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT) { ++ csi_param.data_width = IPU_CSI_DATA_WIDTH_8; ++ } else if (ifparm.u.bt656.mode ++ == V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT) { ++ csi_param.data_width = IPU_CSI_DATA_WIDTH_10; ++ } else { ++ csi_param.data_width = IPU_CSI_DATA_WIDTH_8; ++ } ++ ++ csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv; ++ csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv; ++ csi_param.ext_vsync = ifparm.u.bt656.bt_sync_correct; ++ ++ /* if the capturemode changed, the size bounds will have changed. */ ++ cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); ++ pr_debug(" g_fmt_cap returns widthxheight of input as %d x %d\n", ++ cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height); ++ ++ csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat; ++ ++ cam->crop_bounds.top = cam->crop_bounds.left = 0; ++ cam->crop_bounds.width = cam_fmt.fmt.pix.width; ++ cam->crop_bounds.height = cam_fmt.fmt.pix.height; ++ ++ /* ++ * Set the default current cropped resolution to be the same with ++ * the cropping boundary(except for tvin module). ++ */ ++ if (cam->device_type != 1) { ++ cam->crop_current.width = cam->crop_bounds.width; ++ cam->crop_current.height = cam->crop_bounds.height; ++ } ++ ++ /* This essentially loses the data at the left and bottom of the image ++ * giving a digital zoom image, if crop_current is less than the full ++ * size of the image. */ ++ ipu_csi_set_window_size(cam->ipu, cam->crop_current.width, ++ cam->crop_current.height, cam->csi); ++ ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left, ++ cam->crop_current.top, ++ cam->csi); ++ ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width, ++ cam->crop_bounds.height, ++ cam_fmt.fmt.pix.pixelformat, csi_param); ++ ++ ++exit: ++ if (cam->overlay_on == true) ++ start_preview(cam); ++ ++ return err; ++} ++ ++/*! ++ * V4L2 - mxc_v4l2_s_std function ++ * ++ * Sets the TV standard to be used. ++ * ++ * @param cam structure cam_data * ++ * @param parm structure v4l2_streamparm * ++ * ++ * @return status 0 success, EINVAL failed ++ */ ++static int mxc_v4l2_s_std(cam_data *cam, v4l2_std_id e) ++{ ++ printk(KERN_ERR "In mxc_v4l2_s_std %Lx\n", e); ++ if (e == V4L2_STD_PAL) { ++ pr_debug(" Setting standard to PAL %Lx\n", V4L2_STD_PAL); ++ cam->standard.id = V4L2_STD_PAL; ++ video_index = TV_PAL; ++ } else if (e == V4L2_STD_NTSC) { ++ pr_debug(" Setting standard to NTSC %Lx\n", ++ V4L2_STD_NTSC); ++ /* Get rid of the white dot line in NTSC signal input */ ++ cam->standard.id = V4L2_STD_NTSC; ++ video_index = TV_NTSC; ++ } else { ++ cam->standard.id = V4L2_STD_ALL; ++ video_index = TV_NOT_LOCKED; ++ pr_err("ERROR: unrecognized std! %Lx (PAL=%Lx, NTSC=%Lx\n", ++ e, V4L2_STD_PAL, V4L2_STD_NTSC); ++ } ++ ++ cam->standard.index = video_index; ++ strcpy(cam->standard.name, video_fmts[video_index].name); ++ cam->crop_bounds.width = video_fmts[video_index].raw_width; ++ cam->crop_bounds.height = video_fmts[video_index].raw_height; ++ cam->crop_current.width = video_fmts[video_index].active_width; ++ cam->crop_current.height = video_fmts[video_index].active_height; ++ cam->crop_current.top = video_fmts[video_index].active_top; ++ cam->crop_current.left = video_fmts[video_index].active_left; ++ ++ return 0; ++} ++ ++/*! ++ * V4L2 - mxc_v4l2_g_std function ++ * ++ * Gets the TV standard from the TV input device. ++ * ++ * @param cam structure cam_data * ++ * ++ * @param e structure v4l2_streamparm * ++ * ++ * @return status 0 success, EINVAL failed ++ */ ++static int mxc_v4l2_g_std(cam_data *cam, v4l2_std_id *e) ++{ ++ struct v4l2_format tv_fmt; ++ ++ pr_debug("In mxc_v4l2_g_std\n"); ++ ++ if (cam->device_type == 1) { ++ /* Use this function to get what the TV-In device detects the ++ * format to be. pixelformat is used to return the std value ++ * since the interface has no vidioc_g_std.*/ ++ tv_fmt.type = V4L2_BUF_TYPE_PRIVATE; ++ vidioc_int_g_fmt_cap(cam->sensor, &tv_fmt); ++ ++ /* If the TV-in automatically detects the standard, then if it ++ * changes, the settings need to change. */ ++ if (cam->standard_autodetect) { ++ if (cam->standard.id != tv_fmt.fmt.pix.pixelformat) { ++ pr_debug("MVC: mxc_v4l2_g_std: " ++ "Changing standard\n"); ++ mxc_v4l2_s_std(cam, tv_fmt.fmt.pix.pixelformat); ++ } ++ } ++ ++ *e = tv_fmt.fmt.pix.pixelformat; ++ } ++ ++ return 0; ++} ++ ++/*! ++ * Dequeue one V4L capture buffer ++ * ++ * @param cam structure cam_data * ++ * @param buf structure v4l2_buffer * ++ * ++ * @return status 0 success, EINVAL invalid frame number, ++ * ETIME timeout, ERESTARTSYS interrupted by user ++ */ ++static int mxc_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf) ++{ ++ int retval = 0; ++ struct mxc_v4l_frame *frame; ++ unsigned long lock_flags; ++ ++ pr_debug("In MVC:mxc_v4l_dqueue\n"); ++ ++ if (!wait_event_interruptible_timeout(cam->enc_queue, ++ cam->enc_counter != 0, 10 * HZ)) { ++ pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue timeout " ++ "enc_counter %x\n", ++ cam->enc_counter); ++ return -ETIME; ++ } else if (signal_pending(current)) { ++ pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue() " ++ "interrupt received\n"); ++ return -ERESTARTSYS; ++ } ++ ++ if (down_interruptible(&cam->busy_lock)) ++ return -EBUSY; ++ ++ spin_lock_irqsave(&cam->dqueue_int_lock, lock_flags); ++ cam->enc_counter--; ++ ++ frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue); ++ list_del(cam->done_q.next); ++ if (frame->buffer.flags & V4L2_BUF_FLAG_DONE) { ++ frame->buffer.flags &= ~V4L2_BUF_FLAG_DONE; ++ } else if (frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: " ++ "Buffer not filled.\n"); ++ frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; ++ retval = -EINVAL; ++ } else if ((frame->buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: " ++ "Buffer not queued.\n"); ++ retval = -EINVAL; ++ } ++ ++ cam->frame[frame->index].buffer.field = cam->device_type ? ++ V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE; ++ ++ buf->bytesused = cam->v2f.fmt.pix.sizeimage; ++ buf->index = frame->index; ++ buf->flags = frame->buffer.flags; ++ buf->m = cam->frame[frame->index].buffer.m; ++ buf->timestamp = cam->frame[frame->index].buffer.timestamp; ++ buf->field = cam->frame[frame->index].buffer.field; ++ spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags); ++ ++ up(&cam->busy_lock); ++ return retval; ++} ++ ++/*! ++ * V4L interface - open function ++ * ++ * @param file structure file * ++ * ++ * @return status 0 success, ENODEV invalid device instance, ++ * ENODEV timeout, ERESTARTSYS interrupted by user ++ */ ++static int mxc_v4l_open(struct file *file) ++{ ++ struct v4l2_ifparm ifparm; ++ struct v4l2_format cam_fmt; ++ ipu_csi_signal_cfg_t csi_param; ++ struct video_device *dev = video_devdata(file); ++ cam_data *cam = video_get_drvdata(dev); ++ int err = 0; ++ struct sensor_data *sensor; ++ ++ pr_debug("\nIn MVC: mxc_v4l_open\n"); ++ pr_debug(" device name is %s\n", dev->name); ++ ++ if (!cam) { ++ pr_err("ERROR: v4l2 capture: Internal error, " ++ "cam_data not found!\n"); ++ return -EBADF; ++ } ++ ++ if (cam->sensor == NULL || ++ cam->sensor->type != v4l2_int_type_slave) { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ return -EAGAIN; ++ } ++ ++ sensor = cam->sensor->priv; ++ if (!sensor) { ++ pr_err("%s: Internal error, sensor_data is not found!\n", __func__); ++ return -EBADF; ++ } ++ ++ down(&cam->busy_lock); ++ err = 0; ++ if (signal_pending(current)) ++ goto oops; ++ ++ if (cam->open_count++ == 0) { ++ wait_event_interruptible(cam->power_queue, ++ cam->low_power == false); ++ ++ if (strcmp(mxc_capture_inputs[cam->current_input].name, ++ "CSI MEM") == 0) { ++#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE) ++ err = csi_enc_select(cam); ++#endif ++ } else if (strcmp(mxc_capture_inputs[cam->current_input].name, ++ "CSI IC MEM") == 0) { ++#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) ++ err = prp_enc_select(cam); ++#endif ++ } ++ ++ cam->enc_counter = 0; ++ INIT_LIST_HEAD(&cam->ready_q); ++ INIT_LIST_HEAD(&cam->working_q); ++ INIT_LIST_HEAD(&cam->done_q); ++ ++ vidioc_int_g_ifparm(cam->sensor, &ifparm); ++ ++ csi_param.sens_clksrc = 0; ++ ++ csi_param.clk_mode = 0; ++ csi_param.data_pol = 0; ++ csi_param.ext_vsync = 0; ++ ++ csi_param.pack_tight = 0; ++ csi_param.force_eof = 0; ++ csi_param.data_en_pol = 0; ++ ++ csi_param.mclk = ifparm.u.bt656.clock_curr; ++ ++ csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv; ++ ++ if (ifparm.u.bt656.mode ++ == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT) ++ csi_param.data_width = IPU_CSI_DATA_WIDTH_8; ++ else if (ifparm.u.bt656.mode ++ == V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT) ++ csi_param.data_width = IPU_CSI_DATA_WIDTH_10; ++ else ++ csi_param.data_width = IPU_CSI_DATA_WIDTH_8; ++ ++ ++ csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv; ++ csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv; ++ ++ csi_param.csi = cam->csi; ++ ++ cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); ++ ++ /* Reset the sizes. Needed to prevent carryover of last ++ * operation.*/ ++ cam->crop_bounds.top = cam->crop_bounds.left = 0; ++ cam->crop_bounds.width = cam_fmt.fmt.pix.width; ++ cam->crop_bounds.height = cam_fmt.fmt.pix.height; ++ ++ /* This also is the max crop size for this device. */ ++ cam->crop_defrect.top = cam->crop_defrect.left = 0; ++ cam->crop_defrect.width = cam_fmt.fmt.pix.width; ++ cam->crop_defrect.height = cam_fmt.fmt.pix.height; ++ ++ /* At this point, this is also the current image size. */ ++ cam->crop_current.top = cam->crop_current.left = 0; ++ cam->crop_current.width = cam_fmt.fmt.pix.width; ++ cam->crop_current.height = cam_fmt.fmt.pix.height; ++ ++ pr_debug("End of %s: v2f pix widthxheight %d x %d\n", ++ __func__, ++ cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); ++ pr_debug("End of %s: crop_bounds widthxheight %d x %d\n", ++ __func__, ++ cam->crop_bounds.width, cam->crop_bounds.height); ++ pr_debug("End of %s: crop_defrect widthxheight %d x %d\n", ++ __func__, ++ cam->crop_defrect.width, cam->crop_defrect.height); ++ pr_debug("End of %s: crop_current widthxheight %d x %d\n", ++ __func__, ++ cam->crop_current.width, cam->crop_current.height); ++ ++ csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat; ++ pr_debug("On Open: Input to ipu size is %d x %d\n", ++ cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height); ++ ipu_csi_set_window_size(cam->ipu, cam->crop_current.width, ++ cam->crop_current.height, ++ cam->csi); ++ ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left, ++ cam->crop_current.top, ++ cam->csi); ++ ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width, ++ cam->crop_bounds.height, ++ cam_fmt.fmt.pix.pixelformat, ++ csi_param); ++ clk_prepare_enable(sensor->sensor_clk); ++ vidioc_int_s_power(cam->sensor, 1); ++ vidioc_int_init(cam->sensor); ++ vidioc_int_dev_init(cam->sensor); ++ } ++ ++ file->private_data = dev; ++ ++oops: ++ up(&cam->busy_lock); ++ return err; ++} ++ ++/*! ++ * V4L interface - close function ++ * ++ * @param file struct file * ++ * ++ * @return 0 success ++ */ ++static int mxc_v4l_close(struct file *file) ++{ ++ struct video_device *dev = video_devdata(file); ++ int err = 0; ++ cam_data *cam = video_get_drvdata(dev); ++ struct sensor_data *sensor; ++ pr_debug("In MVC:mxc_v4l_close\n"); ++ ++ if (!cam) { ++ pr_err("ERROR: v4l2 capture: Internal error, " ++ "cam_data not found!\n"); ++ return -EBADF; ++ } ++ ++ if (!cam->sensor) { ++ pr_err("%s: Internal error, camera is not found!\n", __func__); ++ return -EBADF; ++ } ++ ++ sensor = cam->sensor->priv; ++ if (!sensor) { ++ pr_err("%s: Internal error, sensor_data is not found!\n", __func__); ++ return -EBADF; ++ } ++ ++ down(&cam->busy_lock); ++ ++ /* for the case somebody hit the ctrl C */ ++ if (cam->overlay_pid == current->pid && cam->overlay_on) { ++ err = stop_preview(cam); ++ cam->overlay_on = false; ++ } ++ if (cam->capture_pid == current->pid) { ++ err |= mxc_streamoff(cam); ++ wake_up_interruptible(&cam->enc_queue); ++ } ++ ++ if (--cam->open_count == 0) { ++ vidioc_int_s_power(cam->sensor, 0); ++ clk_disable_unprepare(sensor->sensor_clk); ++ wait_event_interruptible(cam->power_queue, ++ cam->low_power == false); ++ pr_debug("mxc_v4l_close: release resource\n"); ++ ++ if (strcmp(mxc_capture_inputs[cam->current_input].name, ++ "CSI MEM") == 0) { ++#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE) ++ err |= csi_enc_deselect(cam); ++#endif ++ } else if (strcmp(mxc_capture_inputs[cam->current_input].name, ++ "CSI IC MEM") == 0) { ++#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) ++ err |= prp_enc_deselect(cam); ++#endif ++ } ++ ++ mxc_free_frame_buf(cam); ++ file->private_data = NULL; ++ ++ /* capture off */ ++ wake_up_interruptible(&cam->enc_queue); ++ mxc_free_frames(cam); ++ cam->enc_counter++; ++ } ++ ++ up(&cam->busy_lock); ++ ++ return err; ++} ++ ++#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC) || \ ++ defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) || \ ++ defined(CONFIG_MXC_IPU_CSI_ENC_MODULE) ++/* ++ * V4L interface - read function ++ * ++ * @param file struct file * ++ * @param read buf char * ++ * @param count size_t ++ * @param ppos structure loff_t * ++ * ++ * @return bytes read ++ */ ++static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count, ++ loff_t *ppos) ++{ ++ int err = 0; ++ u8 *v_address[2]; ++ struct video_device *dev = video_devdata(file); ++ cam_data *cam = video_get_drvdata(dev); ++ ++ if (down_interruptible(&cam->busy_lock)) ++ return -EINTR; ++ ++ /* Stop the viewfinder */ ++ if (cam->overlay_on == true) ++ stop_preview(cam); ++ ++ v_address[0] = dma_alloc_coherent(0, ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), ++ &cam->still_buf[0], ++ GFP_DMA | GFP_KERNEL); ++ ++ v_address[1] = dma_alloc_coherent(0, ++ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), ++ &cam->still_buf[1], ++ GFP_DMA | GFP_KERNEL); ++ ++ if (!v_address[0] || !v_address[1]) { ++ err = -ENOBUFS; ++ goto exit0; ++ } ++ ++ err = prp_still_select(cam); ++ if (err != 0) { ++ err = -EIO; ++ goto exit0; ++ } ++ ++ cam->still_counter = 0; ++ err = cam->csi_start(cam); ++ if (err != 0) { ++ err = -EIO; ++ goto exit1; ++ } ++ ++ if (!wait_event_interruptible_timeout(cam->still_queue, ++ cam->still_counter != 0, ++ 10 * HZ)) { ++ pr_err("ERROR: v4l2 capture: mxc_v4l_read timeout counter %x\n", ++ cam->still_counter); ++ err = -ETIME; ++ goto exit1; ++ } ++ err = copy_to_user(buf, v_address[1], cam->v2f.fmt.pix.sizeimage); ++ ++exit1: ++ prp_still_deselect(cam); ++ ++exit0: ++ if (v_address[0] != 0) ++ dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[0], ++ cam->still_buf[0]); ++ if (v_address[1] != 0) ++ dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[1], ++ cam->still_buf[1]); ++ ++ cam->still_buf[0] = cam->still_buf[1] = 0; ++ ++ if (cam->overlay_on == true) ++ start_preview(cam); ++ ++ up(&cam->busy_lock); ++ if (err < 0) ++ return err; ++ ++ return cam->v2f.fmt.pix.sizeimage - err; ++} ++#endif ++ ++/*! ++ * V4L interface - ioctl function ++ * ++ * @param file struct file* ++ * ++ * @param ioctlnr unsigned int ++ * ++ * @param arg void* ++ * ++ * @return 0 success, ENODEV for invalid device instance, ++ * -1 for other errors. ++ */ ++static long mxc_v4l_do_ioctl(struct file *file, ++ unsigned int ioctlnr, void *arg) ++{ ++ struct video_device *dev = video_devdata(file); ++ cam_data *cam = video_get_drvdata(dev); ++ int retval = 0; ++ unsigned long lock_flags; ++ ++ pr_debug("In MVC: mxc_v4l_do_ioctl %x\n", ioctlnr); ++ wait_event_interruptible(cam->power_queue, cam->low_power == false); ++ /* make this _really_ smp-safe */ ++ if (ioctlnr != VIDIOC_DQBUF) ++ if (down_interruptible(&cam->busy_lock)) ++ return -EBUSY; ++ ++ switch (ioctlnr) { ++ /*! ++ * V4l2 VIDIOC_QUERYCAP ioctl ++ */ ++ case VIDIOC_QUERYCAP: { ++ struct v4l2_capability *cap = arg; ++ pr_debug(" case VIDIOC_QUERYCAP\n"); ++ strcpy(cap->driver, "mxc_v4l2"); ++ cap->version = KERNEL_VERSION(0, 1, 11); ++ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | ++ V4L2_CAP_VIDEO_OVERLAY | ++ V4L2_CAP_STREAMING | ++ V4L2_CAP_READWRITE; ++ cap->card[0] = '\0'; ++ cap->bus_info[0] = '\0'; ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_G_FMT ioctl ++ */ ++ case VIDIOC_G_FMT: { ++ struct v4l2_format *gf = arg; ++ pr_debug(" case VIDIOC_G_FMT\n"); ++ retval = mxc_v4l2_g_fmt(cam, gf); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_S_FMT ioctl ++ */ ++ case VIDIOC_S_FMT: { ++ struct v4l2_format *sf = arg; ++ pr_debug(" case VIDIOC_S_FMT\n"); ++ retval = mxc_v4l2_s_fmt(cam, sf); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_REQBUFS ioctl ++ */ ++ case VIDIOC_REQBUFS: { ++ struct v4l2_requestbuffers *req = arg; ++ pr_debug(" case VIDIOC_REQBUFS\n"); ++ ++ if (req->count > FRAME_NUM) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: " ++ "not enough buffers\n"); ++ req->count = FRAME_NUM; ++ } ++ ++ if ((req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: " ++ "wrong buffer type\n"); ++ retval = -EINVAL; ++ break; ++ } ++ ++ mxc_streamoff(cam); ++ if (req->memory & V4L2_MEMORY_MMAP) { ++ mxc_free_frame_buf(cam); ++ retval = mxc_allocate_frame_buf(cam, req->count); ++ } ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_QUERYBUF ioctl ++ */ ++ case VIDIOC_QUERYBUF: { ++ struct v4l2_buffer *buf = arg; ++ int index = buf->index; ++ pr_debug(" case VIDIOC_QUERYBUF\n"); ++ ++ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { ++ pr_err("ERROR: v4l2 capture: " ++ "VIDIOC_QUERYBUFS: " ++ "wrong buffer type\n"); ++ retval = -EINVAL; ++ break; ++ } ++ ++ if (buf->memory & V4L2_MEMORY_MMAP) { ++ memset(buf, 0, sizeof(buf)); ++ buf->index = index; ++ } ++ ++ down(&cam->param_lock); ++ if (buf->memory & V4L2_MEMORY_USERPTR) { ++ mxc_v4l2_release_bufs(cam); ++ retval = mxc_v4l2_prepare_bufs(cam, buf); ++ } ++ ++ if (buf->memory & V4L2_MEMORY_MMAP) ++ retval = mxc_v4l2_buffer_status(cam, buf); ++ up(&cam->param_lock); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_QBUF ioctl ++ */ ++ case VIDIOC_QBUF: { ++ struct v4l2_buffer *buf = arg; ++ int index = buf->index; ++ pr_debug(" case VIDIOC_QBUF\n"); ++ ++ spin_lock_irqsave(&cam->queue_int_lock, lock_flags); ++ if ((cam->frame[index].buffer.flags & 0x7) == ++ V4L2_BUF_FLAG_MAPPED) { ++ cam->frame[index].buffer.flags |= ++ V4L2_BUF_FLAG_QUEUED; ++ list_add_tail(&cam->frame[index].queue, ++ &cam->ready_q); ++ } else if (cam->frame[index].buffer. ++ flags & V4L2_BUF_FLAG_QUEUED) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: " ++ "buffer already queued\n"); ++ retval = -EINVAL; ++ } else if (cam->frame[index].buffer. ++ flags & V4L2_BUF_FLAG_DONE) { ++ pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: " ++ "overwrite done buffer.\n"); ++ cam->frame[index].buffer.flags &= ++ ~V4L2_BUF_FLAG_DONE; ++ cam->frame[index].buffer.flags |= ++ V4L2_BUF_FLAG_QUEUED; ++ retval = -EINVAL; ++ } ++ ++ buf->flags = cam->frame[index].buffer.flags; ++ spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_DQBUF ioctl ++ */ ++ case VIDIOC_DQBUF: { ++ struct v4l2_buffer *buf = arg; ++ pr_debug(" case VIDIOC_DQBUF\n"); ++ ++ if ((cam->enc_counter == 0) && ++ (file->f_flags & O_NONBLOCK)) { ++ retval = -EAGAIN; ++ break; ++ } ++ ++ retval = mxc_v4l_dqueue(cam, buf); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_STREAMON ioctl ++ */ ++ case VIDIOC_STREAMON: { ++ pr_debug(" case VIDIOC_STREAMON\n"); ++ retval = mxc_streamon(cam); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_STREAMOFF ioctl ++ */ ++ case VIDIOC_STREAMOFF: { ++ pr_debug(" case VIDIOC_STREAMOFF\n"); ++ retval = mxc_streamoff(cam); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_G_CTRL ioctl ++ */ ++ case VIDIOC_G_CTRL: { ++ pr_debug(" case VIDIOC_G_CTRL\n"); ++ retval = mxc_v4l2_g_ctrl(cam, arg); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_S_CTRL ioctl ++ */ ++ case VIDIOC_S_CTRL: { ++ pr_debug(" case VIDIOC_S_CTRL\n"); ++ retval = mxc_v4l2_s_ctrl(cam, arg); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_CROPCAP ioctl ++ */ ++ case VIDIOC_CROPCAP: { ++ struct v4l2_cropcap *cap = arg; ++ pr_debug(" case VIDIOC_CROPCAP\n"); ++ if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && ++ cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) { ++ retval = -EINVAL; ++ break; ++ } ++ cap->bounds = cam->crop_bounds; ++ cap->defrect = cam->crop_defrect; ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_G_CROP ioctl ++ */ ++ case VIDIOC_G_CROP: { ++ struct v4l2_crop *crop = arg; ++ pr_debug(" case VIDIOC_G_CROP\n"); ++ ++ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && ++ crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) { ++ retval = -EINVAL; ++ break; ++ } ++ crop->c = cam->crop_current; ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_S_CROP ioctl ++ */ ++ case VIDIOC_S_CROP: { ++ struct v4l2_crop *crop = arg; ++ struct v4l2_rect *b = &cam->crop_bounds; ++ pr_debug(" case VIDIOC_S_CROP\n"); ++ ++ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && ++ crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) { ++ retval = -EINVAL; ++ break; ++ } ++ ++ crop->c.top = (crop->c.top < b->top) ? b->top ++ : crop->c.top; ++ if (crop->c.top > b->top + b->height) ++ crop->c.top = b->top + b->height - 1; ++ if (crop->c.height > b->top + b->height - crop->c.top) ++ crop->c.height = ++ b->top + b->height - crop->c.top; ++ ++ crop->c.left = (crop->c.left < b->left) ? b->left ++ : crop->c.left; ++ if (crop->c.left > b->left + b->width) ++ crop->c.left = b->left + b->width - 1; ++ if (crop->c.width > b->left - crop->c.left + b->width) ++ crop->c.width = ++ b->left - crop->c.left + b->width; ++ ++ crop->c.width -= crop->c.width % 8; ++ crop->c.left -= crop->c.left % 4; ++ cam->crop_current = crop->c; ++ ++ pr_debug(" Cropping Input to ipu size %d x %d\n", ++ cam->crop_current.width, ++ cam->crop_current.height); ++ ipu_csi_set_window_size(cam->ipu, cam->crop_current.width, ++ cam->crop_current.height, ++ cam->csi); ++ ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left, ++ cam->crop_current.top, ++ cam->csi); ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_OVERLAY ioctl ++ */ ++ case VIDIOC_OVERLAY: { ++ int *on = arg; ++ pr_debug(" VIDIOC_OVERLAY on=%d\n", *on); ++ if (*on) { ++ cam->overlay_on = true; ++ cam->overlay_pid = current->pid; ++ retval = start_preview(cam); ++ } ++ if (!*on) { ++ retval = stop_preview(cam); ++ cam->overlay_on = false; ++ } ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_G_FBUF ioctl ++ */ ++ case VIDIOC_G_FBUF: { ++ struct v4l2_framebuffer *fb = arg; ++ pr_debug(" case VIDIOC_G_FBUF\n"); ++ *fb = cam->v4l2_fb; ++ fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY; ++ break; ++ } ++ ++ /*! ++ * V4l2 VIDIOC_S_FBUF ioctl ++ */ ++ case VIDIOC_S_FBUF: { ++ struct v4l2_framebuffer *fb = arg; ++ pr_debug(" case VIDIOC_S_FBUF\n"); ++ cam->v4l2_fb = *fb; ++ break; ++ } ++ ++ case VIDIOC_G_PARM: { ++ struct v4l2_streamparm *parm = arg; ++ pr_debug(" case VIDIOC_G_PARM\n"); ++ if (cam->sensor) ++ retval = vidioc_int_g_parm(cam->sensor, parm); ++ else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ retval = -ENODEV; ++ } ++ break; ++ } ++ ++ case VIDIOC_S_PARM: { ++ struct v4l2_streamparm *parm = arg; ++ pr_debug(" case VIDIOC_S_PARM\n"); ++ if (cam->sensor) ++ retval = mxc_v4l2_s_param(cam, parm); ++ else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ retval = -ENODEV; ++ } ++ break; ++ } ++ ++ /* linux v4l2 bug, kernel c0485619 user c0405619 */ ++ case VIDIOC_ENUMSTD: { ++ struct v4l2_standard *e = arg; ++ pr_debug(" case VIDIOC_ENUMSTD\n"); ++ *e = cam->standard; ++ break; ++ } ++ ++ case VIDIOC_G_STD: { ++ v4l2_std_id *e = arg; ++ pr_debug(" case VIDIOC_G_STD\n"); ++ if (cam->sensor) ++ retval = mxc_v4l2_g_std(cam, e); ++ else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ retval = -ENODEV; ++ } ++ break; ++ } ++ ++ case VIDIOC_S_STD: { ++ v4l2_std_id *e = arg; ++ pr_debug(" case VIDIOC_S_STD\n"); ++ retval = mxc_v4l2_s_std(cam, *e); ++ ++ break; ++ } ++ ++ case VIDIOC_ENUMOUTPUT: { ++ struct v4l2_output *output = arg; ++ pr_debug(" case VIDIOC_ENUMOUTPUT\n"); ++ if (output->index >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) { ++ retval = -EINVAL; ++ break; ++ } ++ *output = mxc_capture_outputs[output->index]; ++ ++ break; ++ } ++ case VIDIOC_G_OUTPUT: { ++ int *p_output_num = arg; ++ pr_debug(" case VIDIOC_G_OUTPUT\n"); ++ *p_output_num = cam->output; ++ break; ++ } ++ ++ case VIDIOC_S_OUTPUT: { ++ int *p_output_num = arg; ++ pr_debug(" case VIDIOC_S_OUTPUT\n"); ++ if (*p_output_num >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) { ++ retval = -EINVAL; ++ break; ++ } ++ cam->output = *p_output_num; ++ break; ++ } ++ ++ case VIDIOC_ENUMINPUT: { ++ struct v4l2_input *input = arg; ++ pr_debug(" case VIDIOC_ENUMINPUT\n"); ++ if (input->index >= MXC_V4L2_CAPTURE_NUM_INPUTS) { ++ retval = -EINVAL; ++ break; ++ } ++ *input = mxc_capture_inputs[input->index]; ++ break; ++ } ++ ++ case VIDIOC_G_INPUT: { ++ int *index = arg; ++ pr_debug(" case VIDIOC_G_INPUT\n"); ++ *index = cam->current_input; ++ break; ++ } ++ ++ case VIDIOC_S_INPUT: { ++ int *index = arg; ++ pr_debug(" case VIDIOC_S_INPUT\n"); ++ if (*index >= MXC_V4L2_CAPTURE_NUM_INPUTS) { ++ retval = -EINVAL; ++ break; ++ } ++ ++ if (*index == cam->current_input) ++ break; ++ ++ if ((mxc_capture_inputs[cam->current_input].status & ++ V4L2_IN_ST_NO_POWER) == 0) { ++ retval = mxc_streamoff(cam); ++ if (retval) ++ break; ++ mxc_capture_inputs[cam->current_input].status |= ++ V4L2_IN_ST_NO_POWER; ++ } ++ ++ if (strcmp(mxc_capture_inputs[*index].name, "CSI MEM") == 0) { ++#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE) ++ retval = csi_enc_select(cam); ++ if (retval) ++ break; ++#endif ++ } else if (strcmp(mxc_capture_inputs[*index].name, ++ "CSI IC MEM") == 0) { ++#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) ++ retval = prp_enc_select(cam); ++ if (retval) ++ break; ++#endif ++ } ++ ++ mxc_capture_inputs[*index].status &= ~V4L2_IN_ST_NO_POWER; ++ cam->current_input = *index; ++ break; ++ } ++ case VIDIOC_ENUM_FMT: { ++ struct v4l2_fmtdesc *f = arg; ++ if (cam->sensor) ++ retval = vidioc_int_enum_fmt_cap(cam->sensor, f); ++ else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ retval = -ENODEV; ++ } ++ break; ++ } ++ case VIDIOC_ENUM_FRAMESIZES: { ++ struct v4l2_frmsizeenum *fsize = arg; ++ if (cam->sensor) ++ retval = vidioc_int_enum_framesizes(cam->sensor, fsize); ++ else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ retval = -ENODEV; ++ } ++ break; ++ } ++ case VIDIOC_DBG_G_CHIP_IDENT: { ++ struct v4l2_dbg_chip_ident *p = arg; ++ p->ident = V4L2_IDENT_NONE; ++ p->revision = 0; ++ if (cam->sensor) ++ retval = vidioc_int_g_chip_ident(cam->sensor, (int *)p); ++ else { ++ pr_err("ERROR: v4l2 capture: slave not found!\n"); ++ retval = -ENODEV; ++ } ++ break; ++ } ++ case VIDIOC_TRY_FMT: ++ case VIDIOC_QUERYCTRL: ++ case VIDIOC_G_TUNER: ++ case VIDIOC_S_TUNER: ++ case VIDIOC_G_FREQUENCY: ++ case VIDIOC_S_FREQUENCY: ++ default: ++ pr_debug(" case default or not supported\n"); ++ retval = -EINVAL; ++ break; ++ } ++ ++ if (ioctlnr != VIDIOC_DQBUF) ++ up(&cam->busy_lock); ++ return retval; ++} ++ ++/* ++ * V4L interface - ioctl function ++ * ++ * @return None ++ */ ++static long mxc_v4l_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ pr_debug("In MVC:mxc_v4l_ioctl\n"); ++ return video_usercopy(file, cmd, arg, mxc_v4l_do_ioctl); ++} ++ ++/*! ++ * V4L interface - mmap function ++ * ++ * @param file structure file * ++ * ++ * @param vma structure vm_area_struct * ++ * ++ * @return status 0 Success, EINTR busy lock error, ENOBUFS remap_page error ++ */ ++static int mxc_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct video_device *dev = video_devdata(file); ++ unsigned long size; ++ int res = 0; ++ cam_data *cam = video_get_drvdata(dev); ++ ++ pr_debug("In MVC:mxc_mmap\n"); ++ pr_debug(" pgoff=0x%lx, start=0x%lx, end=0x%lx\n", ++ vma->vm_pgoff, vma->vm_start, vma->vm_end); ++ ++ /* make this _really_ smp-safe */ ++ if (down_interruptible(&cam->busy_lock)) ++ return -EINTR; ++ ++ size = vma->vm_end - vma->vm_start; ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++ ++ if (remap_pfn_range(vma, vma->vm_start, ++ vma->vm_pgoff, size, vma->vm_page_prot)) { ++ pr_err("ERROR: v4l2 capture: mxc_mmap: " ++ "remap_pfn_range failed\n"); ++ res = -ENOBUFS; ++ goto mxc_mmap_exit; ++ } ++ ++ vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ ++ ++mxc_mmap_exit: ++ up(&cam->busy_lock); ++ return res; ++} ++ ++/*! ++ * V4L interface - poll function ++ * ++ * @param file structure file * ++ * ++ * @param wait structure poll_table_struct * ++ * ++ * @return status POLLIN | POLLRDNORM ++ */ ++static unsigned int mxc_poll(struct file *file, struct poll_table_struct *wait) ++{ ++ struct video_device *dev = video_devdata(file); ++ cam_data *cam = video_get_drvdata(dev); ++ wait_queue_head_t *queue = NULL; ++ int res = POLLIN | POLLRDNORM; ++ ++ pr_debug("In MVC:mxc_poll\n"); ++ ++ if (down_interruptible(&cam->busy_lock)) ++ return -EINTR; ++ ++ queue = &cam->enc_queue; ++ poll_wait(file, queue, wait); ++ ++ up(&cam->busy_lock); ++ ++ return res; ++} ++ ++/*! ++ * This structure defines the functions to be called in this driver. ++ */ ++static struct v4l2_file_operations mxc_v4l_fops = { ++ .owner = THIS_MODULE, ++ .open = mxc_v4l_open, ++ .release = mxc_v4l_close, ++ .read = mxc_v4l_read, ++ .ioctl = mxc_v4l_ioctl, ++ .mmap = mxc_mmap, ++ .poll = mxc_poll, ++}; ++ ++static struct video_device mxc_v4l_template = { ++ .name = "Mxc Camera", ++ .fops = &mxc_v4l_fops, ++ .release = video_device_release, ++}; ++ ++/*! ++ * This function can be used to release any platform data on closing. ++ */ ++static void camera_platform_release(struct device *device) ++{ ++} ++ ++/*! ++ * Camera V4l2 callback function. ++ * ++ * @param mask u32 ++ * ++ * @param dev void device structure ++ * ++ * @return status ++ */ ++static void camera_callback(u32 mask, void *dev) ++{ ++ struct mxc_v4l_frame *done_frame; ++ struct mxc_v4l_frame *ready_frame; ++ struct timeval cur_time; ++ ++ cam_data *cam = (cam_data *) dev; ++ if (cam == NULL) ++ return; ++ ++ pr_debug("In MVC:camera_callback\n"); ++ ++ spin_lock(&cam->queue_int_lock); ++ spin_lock(&cam->dqueue_int_lock); ++ if (!list_empty(&cam->working_q)) { ++ do_gettimeofday(&cur_time); ++ ++ done_frame = list_entry(cam->working_q.next, ++ struct mxc_v4l_frame, ++ queue); ++ ++ if (done_frame->ipu_buf_num != cam->local_buf_num) ++ goto next; ++ ++ /* ++ * Set the current time to done frame buffer's ++ * timestamp. Users can use this information to judge ++ * the frame's usage. ++ */ ++ done_frame->buffer.timestamp = cur_time; ++ ++ if (done_frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) { ++ done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE; ++ done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; ++ ++ /* Added to the done queue */ ++ list_del(cam->working_q.next); ++ list_add_tail(&done_frame->queue, &cam->done_q); ++ ++ /* Wake up the queue */ ++ cam->enc_counter++; ++ wake_up_interruptible(&cam->enc_queue); ++ } else ++ pr_err("ERROR: v4l2 capture: camera_callback: " ++ "buffer not queued\n"); ++ } ++ ++next: ++ if (!list_empty(&cam->ready_q)) { ++ ready_frame = list_entry(cam->ready_q.next, ++ struct mxc_v4l_frame, ++ queue); ++ if (cam->enc_update_eba) ++ if (cam->enc_update_eba(cam->ipu, ++ ready_frame->buffer.m.offset, ++ &cam->ping_pong_csi) == 0) { ++ list_del(cam->ready_q.next); ++ list_add_tail(&ready_frame->queue, ++ &cam->working_q); ++ ready_frame->ipu_buf_num = cam->local_buf_num; ++ } ++ } else { ++ if (cam->enc_update_eba) ++ cam->enc_update_eba( ++ cam->ipu, cam->dummy_frame.buffer.m.offset, ++ &cam->ping_pong_csi); ++ } ++ ++ cam->local_buf_num = (cam->local_buf_num == 0) ? 1 : 0; ++ spin_unlock(&cam->dqueue_int_lock); ++ spin_unlock(&cam->queue_int_lock); ++ ++ return; ++} ++ ++/*! ++ * initialize cam_data structure ++ * ++ * @param cam structure cam_data * ++ * ++ * @return status 0 Success ++ */ ++static int init_camera_struct(cam_data *cam, struct platform_device *pdev) ++{ ++ const struct of_device_id *of_id = ++ of_match_device(mxc_v4l2_dt_ids, &pdev->dev); ++ struct device_node *np = pdev->dev.of_node; ++ int ipu_id, csi_id, mclk_source; ++ int ret = 0; ++ ++ pr_debug("In MVC: init_camera_struct\n"); ++ ++ ret = of_property_read_u32(np, "ipu_id", &ipu_id); ++ if (ret) { ++ dev_err(&pdev->dev, "ipu_id missing or invalid\n"); ++ return ret; ++ } ++ ++ ret = of_property_read_u32(np, "csi_id", &csi_id); ++ if (ret) { ++ dev_err(&pdev->dev, "csi_id missing or invalid\n"); ++ return ret; ++ } ++ ++ ret = of_property_read_u32(np, "mclk_source", &mclk_source); ++ if (ret) { ++ dev_err(&pdev->dev, "sensor mclk missing or invalid\n"); ++ return ret; ++ } ++ ++ /* Default everything to 0 */ ++ memset(cam, 0, sizeof(cam_data)); ++ ++ /* get devtype to distinguish if the cpu is imx5 or imx6 ++ * IMX5_V4L2 specify the cpu is imx5 ++ * IMX6_V4L2 specify the cpu is imx6q or imx6sdl ++ */ ++ if (of_id) ++ pdev->id_entry = of_id->data; ++ cam->devtype = pdev->id_entry->driver_data; ++ ++ cam->ipu = ipu_get_soc(ipu_id); ++ if (cam->ipu == NULL) { ++ pr_err("ERROR: v4l2 capture: failed to get ipu\n"); ++ return -EINVAL; ++ } else if (cam->ipu == ERR_PTR(-ENODEV)) { ++ pr_err("ERROR: v4l2 capture: get invalid ipu\n"); ++ return -ENODEV; ++ } ++ ++ init_MUTEX(&cam->param_lock); ++ init_MUTEX(&cam->busy_lock); ++ ++ cam->video_dev = video_device_alloc(); ++ if (cam->video_dev == NULL) ++ return -ENODEV; ++ ++ *(cam->video_dev) = mxc_v4l_template; ++ ++ video_set_drvdata(cam->video_dev, cam); ++ dev_set_drvdata(&pdev->dev, (void *)cam); ++ cam->video_dev->minor = -1; ++ ++ init_waitqueue_head(&cam->enc_queue); ++ init_waitqueue_head(&cam->still_queue); ++ ++ /* setup cropping */ ++ cam->crop_bounds.left = 0; ++ cam->crop_bounds.width = 640; ++ cam->crop_bounds.top = 0; ++ cam->crop_bounds.height = 480; ++ cam->crop_current = cam->crop_defrect = cam->crop_bounds; ++ ipu_csi_set_window_size(cam->ipu, cam->crop_current.width, ++ cam->crop_current.height, cam->csi); ++ ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left, ++ cam->crop_current.top, cam->csi); ++ cam->streamparm.parm.capture.capturemode = 0; ++ ++ cam->standard.index = 0; ++ cam->standard.id = V4L2_STD_UNKNOWN; ++ cam->standard.frameperiod.denominator = 30; ++ cam->standard.frameperiod.numerator = 1; ++ cam->standard.framelines = 480; ++ cam->standard_autodetect = true; ++ cam->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ cam->streamparm.parm.capture.timeperframe = cam->standard.frameperiod; ++ cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; ++ cam->overlay_on = false; ++ cam->capture_on = false; ++ cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY; ++ ++ cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2; ++ cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2; ++ cam->v2f.fmt.pix.width = 288; ++ cam->v2f.fmt.pix.height = 352; ++ cam->v2f.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; ++ cam->win.w.width = 160; ++ cam->win.w.height = 160; ++ cam->win.w.left = 0; ++ cam->win.w.top = 0; ++ ++ cam->ipu_id = ipu_id; ++ cam->csi = csi_id; ++ cam->mclk_source = mclk_source; ++ cam->mclk_on[cam->mclk_source] = false; ++ ++ cam->enc_callback = camera_callback; ++ init_waitqueue_head(&cam->power_queue); ++ spin_lock_init(&cam->queue_int_lock); ++ spin_lock_init(&cam->dqueue_int_lock); ++ ++ cam->self = kmalloc(sizeof(struct v4l2_int_device), GFP_KERNEL); ++ cam->self->module = THIS_MODULE; ++ sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi); ++ cam->self->type = v4l2_int_type_master; ++ cam->self->u.master = &mxc_v4l2_master; ++ ++ return 0; ++} ++ ++static ssize_t show_streaming(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct video_device *video_dev = container_of(dev, ++ struct video_device, dev); ++ cam_data *cam = video_get_drvdata(video_dev); ++ ++ if (cam->capture_on) ++ return sprintf(buf, "stream on\n"); ++ else ++ return sprintf(buf, "stream off\n"); ++} ++static DEVICE_ATTR(fsl_v4l2_capture_property, S_IRUGO, show_streaming, NULL); ++ ++static ssize_t show_overlay(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct video_device *video_dev = container_of(dev, ++ struct video_device, dev); ++ cam_data *cam = video_get_drvdata(video_dev); ++ ++ if (cam->overlay_on) ++ return sprintf(buf, "overlay on\n"); ++ else ++ return sprintf(buf, "overlay off\n"); ++} ++static DEVICE_ATTR(fsl_v4l2_overlay_property, S_IRUGO, show_overlay, NULL); ++ ++static ssize_t show_csi(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct video_device *video_dev = container_of(dev, ++ struct video_device, dev); ++ cam_data *cam = video_get_drvdata(video_dev); ++ ++ return sprintf(buf, "ipu%d_csi%d\n", cam->ipu_id, cam->csi); ++} ++static DEVICE_ATTR(fsl_csi_property, S_IRUGO, show_csi, NULL); ++ ++/*! ++ * This function is called to probe the devices if registered. ++ * ++ * @param pdev the device structure used to give information on which device ++ * to probe ++ * ++ * @return The function returns 0 on success and -1 on failure. ++ */ ++static int mxc_v4l2_probe(struct platform_device *pdev) ++{ ++ /* Create cam and initialize it. */ ++ cam_data *cam = kmalloc(sizeof(cam_data), GFP_KERNEL); ++ if (cam == NULL) { ++ pr_err("ERROR: v4l2 capture: failed to register camera\n"); ++ return -1; ++ } ++ ++ init_camera_struct(cam, pdev); ++ pdev->dev.release = camera_platform_release; ++ ++ /* Set up the v4l2 device and register it*/ ++ cam->self->priv = cam; ++ v4l2_int_device_register(cam->self); ++ ++ /* register v4l video device */ ++ if (video_register_device(cam->video_dev, VFL_TYPE_GRABBER, video_nr) ++ == -1) { ++ kfree(cam); ++ cam = NULL; ++ pr_err("ERROR: v4l2 capture: video_register_device failed\n"); ++ return -1; ++ } ++ pr_debug(" Video device registered: %s #%d\n", ++ cam->video_dev->name, cam->video_dev->minor); ++ ++ if (device_create_file(&cam->video_dev->dev, ++ &dev_attr_fsl_v4l2_capture_property)) ++ dev_err(&pdev->dev, "Error on creating sysfs file" ++ " for capture\n"); ++ ++ if (device_create_file(&cam->video_dev->dev, ++ &dev_attr_fsl_v4l2_overlay_property)) ++ dev_err(&pdev->dev, "Error on creating sysfs file" ++ " for overlay\n"); ++ ++ if (device_create_file(&cam->video_dev->dev, ++ &dev_attr_fsl_csi_property)) ++ dev_err(&pdev->dev, "Error on creating sysfs file" ++ " for csi number\n"); ++ ++ return 0; ++} ++ ++/*! ++ * This function is called to remove the devices when device unregistered. ++ * ++ * @param pdev the device structure used to give information on which device ++ * to remove ++ * ++ * @return The function returns 0 on success and -1 on failure. ++ */ ++static int mxc_v4l2_remove(struct platform_device *pdev) ++{ ++ cam_data *cam = (cam_data *)platform_get_drvdata(pdev); ++ if (cam->open_count) { ++ pr_err("ERROR: v4l2 capture:camera open " ++ "-- setting ops to NULL\n"); ++ return -EBUSY; ++ } else { ++ device_remove_file(&cam->video_dev->dev, ++ &dev_attr_fsl_v4l2_capture_property); ++ device_remove_file(&cam->video_dev->dev, ++ &dev_attr_fsl_v4l2_overlay_property); ++ device_remove_file(&cam->video_dev->dev, ++ &dev_attr_fsl_csi_property); ++ ++ pr_info("V4L2 freeing image input device\n"); ++ v4l2_int_device_unregister(cam->self); ++ video_unregister_device(cam->video_dev); ++ ++ mxc_free_frame_buf(cam); ++ kfree(cam); ++ } ++ ++ pr_info("V4L2 unregistering video\n"); ++ return 0; ++} ++ ++/*! ++ * This function is called to put the sensor in a low power state. ++ * Refer to the document driver-model/driver.txt in the kernel source tree ++ * for more information. ++ * ++ * @param pdev the device structure used to give information on which I2C ++ * to suspend ++ * @param state the power state the device is entering ++ * ++ * @return The function returns 0 on success and -1 on failure. ++ */ ++static int mxc_v4l2_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ cam_data *cam = platform_get_drvdata(pdev); ++ ++ pr_debug("In MVC:mxc_v4l2_suspend\n"); ++ ++ if (cam == NULL) ++ return -1; ++ ++ down(&cam->busy_lock); ++ ++ cam->low_power = true; ++ ++ if (cam->overlay_on == true) ++ stop_preview(cam); ++ if ((cam->capture_on == true) && cam->enc_disable) ++ cam->enc_disable(cam); ++ ++ if (cam->sensor && cam->open_count) { ++ if (cam->mclk_on[cam->mclk_source]) { ++ ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C, ++ cam->mclk_source, ++ false, false); ++ cam->mclk_on[cam->mclk_source] = false; ++ } ++ vidioc_int_s_power(cam->sensor, 0); ++ } ++ ++ up(&cam->busy_lock); ++ ++ return 0; ++} ++ ++/*! ++ * This function is called to bring the sensor back from a low power state. ++ * Refer to the document driver-model/driver.txt in the kernel source tree ++ * for more information. ++ * ++ * @param pdev the device structure ++ * ++ * @return The function returns 0 on success and -1 on failure ++ */ ++static int mxc_v4l2_resume(struct platform_device *pdev) ++{ ++ cam_data *cam = platform_get_drvdata(pdev); ++ ++ pr_debug("In MVC:mxc_v4l2_resume\n"); ++ ++ if (cam == NULL) ++ return -1; ++ ++ down(&cam->busy_lock); ++ ++ cam->low_power = false; ++ wake_up_interruptible(&cam->power_queue); ++ ++ if (cam->sensor && cam->open_count) { ++ vidioc_int_s_power(cam->sensor, 1); ++ ++ if (!cam->mclk_on[cam->mclk_source]) { ++ ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C, ++ cam->mclk_source, ++ true, true); ++ cam->mclk_on[cam->mclk_source] = true; ++ } ++ } ++ ++ if (cam->overlay_on == true) ++ start_preview(cam); ++ if (cam->capture_on == true) ++ mxc_streamon(cam); ++ ++ up(&cam->busy_lock); ++ ++ return 0; ++} ++ ++/*! ++ * This structure contains pointers to the power management callback functions. ++ */ ++static struct platform_driver mxc_v4l2_driver = { ++ .driver = { ++ .name = "mxc_v4l2_capture", ++ .owner = THIS_MODULE, ++ .of_match_table = mxc_v4l2_dt_ids, ++ }, ++ .id_table = imx_v4l2_devtype, ++ .probe = mxc_v4l2_probe, ++ .remove = mxc_v4l2_remove, ++ .suspend = mxc_v4l2_suspend, ++ .resume = mxc_v4l2_resume, ++ .shutdown = NULL, ++}; ++ ++/*! ++ * Initializes the camera driver. ++ */ ++static int mxc_v4l2_master_attach(struct v4l2_int_device *slave) ++{ ++ cam_data *cam = slave->u.slave->master->priv; ++ struct v4l2_format cam_fmt; ++ int i; ++ struct sensor_data *sdata = slave->priv; ++ ++ pr_debug("In MVC: mxc_v4l2_master_attach\n"); ++ pr_debug(" slave.name = %s\n", slave->name); ++ pr_debug(" master.name = %s\n", slave->u.slave->master->name); ++ ++ if (slave == NULL) { ++ pr_err("ERROR: v4l2 capture: slave parameter not valid.\n"); ++ return -1; ++ } ++ ++ if (sdata->csi != cam->csi) { ++ pr_debug("%s: csi doesn't match\n", __func__); ++ return -1; ++ } ++ ++ cam->sensor = slave; ++ ++ if (cam->sensor_index < MXC_SENSOR_NUM) { ++ cam->all_sensors[cam->sensor_index] = slave; ++ cam->sensor_index++; ++ } else { ++ pr_err("ERROR: v4l2 capture: slave number exceeds the maximum.\n"); ++ return -1; ++ } ++ ++ for (i = 0; i < cam->sensor_index; i++) { ++ vidioc_int_dev_exit(cam->all_sensors[i]); ++ vidioc_int_s_power(cam->all_sensors[i], 0); ++ } ++ ++ cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); ++ ++ /* Used to detect TV in (type 1) vs. camera (type 0)*/ ++ cam->device_type = cam_fmt.fmt.pix.priv; ++ ++ /* Set the input size to the ipu for this device */ ++ cam->crop_bounds.top = cam->crop_bounds.left = 0; ++ cam->crop_bounds.width = cam_fmt.fmt.pix.width; ++ cam->crop_bounds.height = cam_fmt.fmt.pix.height; ++ ++ /* This also is the max crop size for this device. */ ++ cam->crop_defrect.top = cam->crop_defrect.left = 0; ++ cam->crop_defrect.width = cam_fmt.fmt.pix.width; ++ cam->crop_defrect.height = cam_fmt.fmt.pix.height; ++ ++ /* At this point, this is also the current image size. */ ++ cam->crop_current.top = cam->crop_current.left = 0; ++ cam->crop_current.width = cam_fmt.fmt.pix.width; ++ cam->crop_current.height = cam_fmt.fmt.pix.height; ++ ++ pr_debug("End of %s: v2f pix widthxheight %d x %d\n", ++ __func__, ++ cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); ++ pr_debug("End of %s: crop_bounds widthxheight %d x %d\n", ++ __func__, ++ cam->crop_bounds.width, cam->crop_bounds.height); ++ pr_debug("End of %s: crop_defrect widthxheight %d x %d\n", ++ __func__, ++ cam->crop_defrect.width, cam->crop_defrect.height); ++ pr_debug("End of %s: crop_current widthxheight %d x %d\n", ++ __func__, ++ cam->crop_current.width, cam->crop_current.height); ++ ++ return 0; ++} ++ ++/*! ++ * Disconnects the camera driver. ++ */ ++static void mxc_v4l2_master_detach(struct v4l2_int_device *slave) ++{ ++ unsigned int i; ++ cam_data *cam = slave->u.slave->master->priv; ++ ++ pr_debug("In MVC:mxc_v4l2_master_detach\n"); ++ ++ if (cam->sensor_index > 1) { ++ for (i = 0; i < cam->sensor_index; i++) { ++ if (cam->all_sensors[i] != slave) ++ continue; ++ /* Move all the sensors behind this ++ * sensor one step forward ++ */ ++ for (; i <= MXC_SENSOR_NUM - 2; i++) ++ cam->all_sensors[i] = cam->all_sensors[i+1]; ++ break; ++ } ++ /* Point current sensor to the last one */ ++ cam->sensor = cam->all_sensors[cam->sensor_index - 2]; ++ } else ++ cam->sensor = NULL; ++ ++ cam->sensor_index--; ++ vidioc_int_dev_exit(slave); ++} ++ ++/*! ++ * Entry point for the V4L2 ++ * ++ * @return Error code indicating success or failure ++ */ ++static __init int camera_init(void) ++{ ++ u8 err = 0; ++ ++ pr_debug("In MVC:camera_init\n"); ++ ++ /* Register the device driver structure. */ ++ err = platform_driver_register(&mxc_v4l2_driver); ++ if (err != 0) { ++ pr_err("ERROR: v4l2 capture:camera_init: " ++ "platform_driver_register failed.\n"); ++ return err; ++ } ++ ++ return err; ++} ++ ++/*! ++ * Exit and cleanup for the V4L2 ++ */ ++static void __exit camera_exit(void) ++{ ++ pr_debug("In MVC: camera_exit\n"); ++ ++ platform_driver_unregister(&mxc_v4l2_driver); ++} ++ ++module_init(camera_init); ++module_exit(camera_exit); ++ ++module_param(video_nr, int, 0444); ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("V4L2 capture driver for Mxc based cameras"); ++MODULE_LICENSE("GPL"); ++MODULE_SUPPORTED_DEVICE("video"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h +--- linux-3.10.30/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,260 @@ ++/* ++ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @defgroup MXC_V4L2_CAPTURE MXC V4L2 Video Capture Driver ++ */ ++/*! ++ * @file mxc_v4l2_capture.h ++ * ++ * @brief mxc V4L2 capture device API Header file ++ * ++ * It include all the defines for frame operations, also three structure defines ++ * use case ops structure, common v4l2 driver structure and frame structure. ++ * ++ * @ingroup MXC_V4L2_CAPTURE ++ */ ++#ifndef __MXC_V4L2_CAPTURE_H__ ++#define __MXC_V4L2_CAPTURE_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++ ++#define FRAME_NUM 10 ++#define MXC_SENSOR_NUM 2 ++ ++enum imx_v4l2_devtype { ++ IMX5_V4L2, ++ IMX6_V4L2, ++}; ++ ++/*! ++ * v4l2 frame structure. ++ */ ++struct mxc_v4l_frame { ++ u32 paddress; ++ void *vaddress; ++ int count; ++ int width; ++ int height; ++ ++ struct v4l2_buffer buffer; ++ struct list_head queue; ++ int index; ++ union { ++ int ipu_buf_num; ++ int csi_buf_num; ++ }; ++}; ++ ++/* Only for old version. Will go away soon. */ ++typedef struct { ++ u8 clk_mode; ++ u8 ext_vsync; ++ u8 Vsync_pol; ++ u8 Hsync_pol; ++ u8 pixclk_pol; ++ u8 data_pol; ++ u8 data_width; ++ u8 pack_tight; ++ u8 force_eof; ++ u8 data_en_pol; ++ u16 width; ++ u16 height; ++ u32 pixel_fmt; ++ u32 mclk; ++ u16 active_width; ++ u16 active_height; ++} sensor_interface; ++ ++/* Sensor control function */ ++/* Only for old version. Will go away soon. */ ++struct camera_sensor { ++ void (*set_color) (int bright, int saturation, int red, int green, ++ int blue); ++ void (*get_color) (int *bright, int *saturation, int *red, int *green, ++ int *blue); ++ void (*set_ae_mode) (int ae_mode); ++ void (*get_ae_mode) (int *ae_mode); ++ sensor_interface *(*config) (int *frame_rate, int high_quality); ++ sensor_interface *(*reset) (void); ++ void (*get_std) (v4l2_std_id *std); ++ void (*set_std) (v4l2_std_id std); ++ unsigned int csi; ++}; ++ ++/*! ++ * common v4l2 driver structure. ++ */ ++typedef struct _cam_data { ++ struct video_device *video_dev; ++ int device_type; ++ ++ /* semaphore guard against SMP multithreading */ ++ struct semaphore busy_lock; ++ ++ int open_count; ++ ++ /* params lock for this camera */ ++ struct semaphore param_lock; ++ ++ /* Encoder */ ++ struct list_head ready_q; ++ struct list_head done_q; ++ struct list_head working_q; ++ int ping_pong_csi; ++ spinlock_t queue_int_lock; ++ spinlock_t dqueue_int_lock; ++ struct mxc_v4l_frame frame[FRAME_NUM]; ++ struct mxc_v4l_frame dummy_frame; ++ wait_queue_head_t enc_queue; ++ int enc_counter; ++ dma_addr_t rot_enc_bufs[2]; ++ void *rot_enc_bufs_vaddr[2]; ++ int rot_enc_buf_size[2]; ++ enum v4l2_buf_type type; ++ ++ /* still image capture */ ++ wait_queue_head_t still_queue; ++ int still_counter; ++ dma_addr_t still_buf[2]; ++ void *still_buf_vaddr; ++ ++ /* overlay */ ++ struct v4l2_window win; ++ struct v4l2_framebuffer v4l2_fb; ++ dma_addr_t vf_bufs[2]; ++ void *vf_bufs_vaddr[2]; ++ int vf_bufs_size[2]; ++ dma_addr_t rot_vf_bufs[2]; ++ void *rot_vf_bufs_vaddr[2]; ++ int rot_vf_buf_size[2]; ++ bool overlay_active; ++ int output; ++ struct fb_info *overlay_fb; ++ int fb_origin_std; ++ struct work_struct csi_work_struct; ++ ++ /* v4l2 format */ ++ struct v4l2_format v2f; ++ int rotation; /* for IPUv1 and IPUv3, this means encoder rotation */ ++ int vf_rotation; /* viewfinder rotation only for IPUv1 and IPUv3 */ ++ struct v4l2_mxc_offset offset; ++ ++ /* V4l2 control bit */ ++ int bright; ++ int hue; ++ int contrast; ++ int saturation; ++ int red; ++ int green; ++ int blue; ++ int ae_mode; ++ ++ /* standard */ ++ struct v4l2_streamparm streamparm; ++ struct v4l2_standard standard; ++ bool standard_autodetect; ++ ++ /* crop */ ++ struct v4l2_rect crop_bounds; ++ struct v4l2_rect crop_defrect; ++ struct v4l2_rect crop_current; ++ ++ int (*enc_update_eba) (struct ipu_soc *ipu, dma_addr_t eba, ++ int *bufferNum); ++ int (*enc_enable) (void *private); ++ int (*enc_disable) (void *private); ++ int (*enc_enable_csi) (void *private); ++ int (*enc_disable_csi) (void *private); ++ void (*enc_callback) (u32 mask, void *dev); ++ int (*vf_start_adc) (void *private); ++ int (*vf_stop_adc) (void *private); ++ int (*vf_start_sdc) (void *private); ++ int (*vf_stop_sdc) (void *private); ++ int (*vf_enable_csi) (void *private); ++ int (*vf_disable_csi) (void *private); ++ int (*csi_start) (void *private); ++ int (*csi_stop) (void *private); ++ ++ /* misc status flag */ ++ bool overlay_on; ++ bool capture_on; ++ int overlay_pid; ++ int capture_pid; ++ bool low_power; ++ wait_queue_head_t power_queue; ++ unsigned int ipu_id; ++ unsigned int csi; ++ u8 mclk_source; ++ bool mclk_on[2]; /* two mclk sources at most now */ ++ int current_input; ++ ++ int local_buf_num; ++ ++ /* camera sensor interface */ ++ struct camera_sensor *cam_sensor; /* old version */ ++ struct v4l2_int_device *all_sensors[MXC_SENSOR_NUM]; ++ struct v4l2_int_device *sensor; ++ struct v4l2_int_device *self; ++ int sensor_index; ++ void *ipu; ++ enum imx_v4l2_devtype devtype; ++ ++ /* v4l2 buf elements related to PxP DMA */ ++ struct completion pxp_tx_cmpl; ++ struct pxp_channel *pxp_chan; ++ struct pxp_config_data pxp_conf; ++ struct dma_async_tx_descriptor *txd; ++ dma_cookie_t cookie; ++ struct scatterlist sg[2]; ++} cam_data; ++ ++struct sensor_data { ++ const struct ov5642_platform_data *platform_data; ++ struct v4l2_int_device *v4l2_int_device; ++ struct i2c_client *i2c_client; ++ struct v4l2_pix_format pix; ++ struct v4l2_captureparm streamcap; ++ bool on; ++ ++ /* control settings */ ++ int brightness; ++ int hue; ++ int contrast; ++ int saturation; ++ int red; ++ int green; ++ int blue; ++ int ae_mode; ++ ++ u32 mclk; ++ u8 mclk_source; ++ struct clk *sensor_clk; ++ int csi; ++ ++ void (*io_init)(void); ++}; ++ ++void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi); ++#endif /* __MXC_V4L2_CAPTURE_H__ */ +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/ov5640.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ov5640.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/ov5640.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ov5640.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,1951 @@ ++/* ++ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++ ++#define OV5640_VOLTAGE_ANALOG 2800000 ++#define OV5640_VOLTAGE_DIGITAL_CORE 1500000 ++#define OV5640_VOLTAGE_DIGITAL_IO 1800000 ++ ++#define MIN_FPS 15 ++#define MAX_FPS 30 ++#define DEFAULT_FPS 30 ++ ++#define OV5640_XCLK_MIN 6000000 ++#define OV5640_XCLK_MAX 24000000 ++ ++#define OV5640_CHIP_ID_HIGH_BYTE 0x300A ++#define OV5640_CHIP_ID_LOW_BYTE 0x300B ++ ++enum ov5640_mode { ++ ov5640_mode_MIN = 0, ++ ov5640_mode_VGA_640_480 = 0, ++ ov5640_mode_QVGA_320_240 = 1, ++ ov5640_mode_NTSC_720_480 = 2, ++ ov5640_mode_PAL_720_576 = 3, ++ ov5640_mode_720P_1280_720 = 4, ++ ov5640_mode_1080P_1920_1080 = 5, ++ ov5640_mode_QSXGA_2592_1944 = 6, ++ ov5640_mode_QCIF_176_144 = 7, ++ ov5640_mode_XGA_1024_768 = 8, ++ ov5640_mode_MAX = 8 ++}; ++ ++enum ov5640_frame_rate { ++ ov5640_15_fps, ++ ov5640_30_fps ++}; ++ ++static int ov5640_framerates[] = { ++ [ov5640_15_fps] = 15, ++ [ov5640_30_fps] = 30, ++}; ++ ++struct reg_value { ++ u16 u16RegAddr; ++ u8 u8Val; ++ u8 u8Mask; ++ u32 u32Delay_ms; ++}; ++ ++struct ov5640_mode_info { ++ enum ov5640_mode mode; ++ u32 width; ++ u32 height; ++ struct reg_value *init_data_ptr; ++ u32 init_data_size; ++}; ++ ++/*! ++ * Maintains the information on the current state of the sesor. ++ */ ++static struct sensor_data ov5640_data; ++static int pwn_gpio, rst_gpio; ++static int prev_sysclk; ++static int AE_Target = 52, night_mode; ++static int prev_HTS; ++static int AE_high, AE_low; ++ ++static struct reg_value ov5640_global_init_setting[] = { ++ {0x3008, 0x42, 0, 0}, ++ {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0}, ++ {0x3034, 0x1a, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, ++ {0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, ++ {0x3633, 0x12, 0, 0}, {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, ++ {0x3703, 0x5a, 0, 0}, {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, ++ {0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, ++ {0x3906, 0x10, 0, 0}, {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, ++ {0x3600, 0x08, 0, 0}, {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, ++ {0x3620, 0x52, 0, 0}, {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, ++ {0x3a13, 0x43, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, ++ {0x3635, 0x13, 0, 0}, {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, ++ {0x3622, 0x01, 0, 0}, {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, ++ {0x3c05, 0x98, 0, 0}, {0x3c06, 0x00, 0, 0}, {0x3c07, 0x07, 0, 0}, ++ {0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, ++ {0x3c0b, 0x40, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0}, ++ {0x3812, 0x00, 0, 0}, {0x3708, 0x64, 0, 0}, {0x4001, 0x02, 0, 0}, ++ {0x4005, 0x1a, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, ++ {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, ++ {0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x5000, 0xa7, 0, 0}, ++ {0x3008, 0x02, 0, 0}, ++}; ++ ++static struct reg_value ov5640_init_setting_30fps_VGA[] = { ++ {0x3008, 0x42, 0, 0}, ++ {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0}, ++ {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, {0x3036, 0x46, 0, 0}, ++ {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0}, ++ {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, ++ {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, ++ {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, ++ {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, ++ {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, ++ {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, ++ {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, ++ {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, ++ {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, ++ {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, ++ {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, ++ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, ++ {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, ++ {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, ++ {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5000, 0xa7, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0xf2, 0, 0}, ++ {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, {0x5187, 0x09, 0, 0}, ++ {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, {0x518a, 0x54, 0, 0}, ++ {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x50, 0, 0}, ++ {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x6c, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x09, 0, 0}, ++ {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, {0x5381, 0x1e, 0, 0}, ++ {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, {0x5384, 0x0a, 0, 0}, ++ {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, {0x5387, 0x7c, 0, 0}, ++ {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, {0x538a, 0x01, 0, 0}, ++ {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, {0x5301, 0x30, 0, 0}, ++ {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, {0x5304, 0x08, 0, 0}, ++ {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, {0x5307, 0x16, 0, 0}, ++ {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, {0x530b, 0x04, 0, 0}, ++ {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, {0x5481, 0x08, 0, 0}, ++ {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, {0x5484, 0x51, 0, 0}, ++ {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, {0x5487, 0x7d, 0, 0}, ++ {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, {0x548a, 0x9a, 0, 0}, ++ {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, {0x548d, 0xcd, 0, 0}, ++ {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, {0x5490, 0x1d, 0, 0}, ++ {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x10, 0, 0}, ++ {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, {0x558b, 0xf8, 0, 0}, ++ {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, {0x5802, 0x0f, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, {0x5805, 0x26, 0, 0}, ++ {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, {0x5808, 0x05, 0, 0}, ++ {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, {0x580b, 0x0d, 0, 0}, ++ {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, {0x580e, 0x00, 0, 0}, ++ {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, {0x5811, 0x09, 0, 0}, ++ {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x00, 0, 0}, ++ {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, {0x5817, 0x08, 0, 0}, ++ {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, {0x581a, 0x05, 0, 0}, ++ {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, {0x581d, 0x0e, 0, 0}, ++ {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, {0x5820, 0x11, 0, 0}, ++ {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, {0x5823, 0x28, 0, 0}, ++ {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, {0x5829, 0x26, 0, 0}, ++ {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, {0x582c, 0x24, 0, 0}, ++ {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, {0x582f, 0x22, 0, 0}, ++ {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, {0x5832, 0x24, 0, 0}, ++ {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, {0x5835, 0x22, 0, 0}, ++ {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, {0x5838, 0x44, 0, 0}, ++ {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, {0x583b, 0x28, 0, 0}, ++ {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, {0x5025, 0x00, 0, 0}, ++ {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, {0x3a1b, 0x30, 0, 0}, ++ {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x14, 0, 0}, ++ {0x3008, 0x02, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_VGA_640_480[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, ++ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, ++ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_VGA_640_480[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, ++ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, ++ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, ++ {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, ++ {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, ++ {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, ++ {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, ++ {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, ++ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, ++ {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, ++ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_PAL_720_576[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0}, ++ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, ++ {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_PAL_720_576[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0}, ++ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, ++ {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_720P_1280_720[] = { ++ {0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, ++ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, ++ {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, ++ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0}, ++ {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0}, ++ {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0}, ++ {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, ++ {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, ++ {0x3503, 0x00, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_720P_1280_720[] = { ++ {0x3035, 0x41, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, ++ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, ++ {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, ++ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0}, ++ {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0}, ++ {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0}, ++ {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, ++ {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, ++ {0x3503, 0x00, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, ++ {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, ++ {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, ++ {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, ++ {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, ++ {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, ++ {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, ++ {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { ++ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, ++ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, ++ {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, ++ {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0}, ++ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, ++ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, ++ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, ++ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, ++ {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0}, ++ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, ++ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++ ++static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { ++ {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, ++ {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0xee, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x05, 0, 0}, ++ {0x3807, 0xc3, 0, 0}, {0x3808, 0x07, 0, 0}, {0x3809, 0x80, 0, 0}, ++ {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, {0x380c, 0x0b, 0, 0}, ++ {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, ++ {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0}, ++ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0}, ++ {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0}, ++ {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0}, ++ {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0}, ++ {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, ++ {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { ++ {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, ++ {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, ++ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, ++ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, ++ {0x3807, 0x9f, 0, 0}, {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, ++ {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, ++ {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, ++ {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0}, ++ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0}, ++ {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0}, ++ {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0}, ++ {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0}, ++ {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, ++ {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, ++}; ++ ++static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = { ++ { ++ {ov5640_mode_VGA_640_480, 640, 480, ++ ov5640_setting_15fps_VGA_640_480, ++ ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)}, ++ {ov5640_mode_QVGA_320_240, 320, 240, ++ ov5640_setting_15fps_QVGA_320_240, ++ ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)}, ++ {ov5640_mode_NTSC_720_480, 720, 480, ++ ov5640_setting_15fps_NTSC_720_480, ++ ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)}, ++ {ov5640_mode_PAL_720_576, 720, 576, ++ ov5640_setting_15fps_PAL_720_576, ++ ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)}, ++ {ov5640_mode_720P_1280_720, 1280, 720, ++ ov5640_setting_15fps_720P_1280_720, ++ ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)}, ++ {ov5640_mode_1080P_1920_1080, 1920, 1080, ++ ov5640_setting_15fps_1080P_1920_1080, ++ ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)}, ++ {ov5640_mode_QSXGA_2592_1944, 2592, 1944, ++ ov5640_setting_15fps_QSXGA_2592_1944, ++ ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)}, ++ {ov5640_mode_QCIF_176_144, 176, 144, ++ ov5640_setting_15fps_QCIF_176_144, ++ ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)}, ++ {ov5640_mode_XGA_1024_768, 1024, 768, ++ ov5640_setting_15fps_XGA_1024_768, ++ ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)}, ++ }, ++ { ++ {ov5640_mode_VGA_640_480, 640, 480, ++ ov5640_setting_30fps_VGA_640_480, ++ ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)}, ++ {ov5640_mode_QVGA_320_240, 320, 240, ++ ov5640_setting_30fps_QVGA_320_240, ++ ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)}, ++ {ov5640_mode_NTSC_720_480, 720, 480, ++ ov5640_setting_30fps_NTSC_720_480, ++ ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)}, ++ {ov5640_mode_PAL_720_576, 720, 576, ++ ov5640_setting_30fps_PAL_720_576, ++ ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)}, ++ {ov5640_mode_720P_1280_720, 1280, 720, ++ ov5640_setting_30fps_720P_1280_720, ++ ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)}, ++ {ov5640_mode_1080P_1920_1080, 0, 0, NULL, 0}, ++ {ov5640_mode_QSXGA_2592_1944, 0, 0, NULL, 0}, ++ {ov5640_mode_QCIF_176_144, 176, 144, ++ ov5640_setting_30fps_QCIF_176_144, ++ ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)}, ++ {ov5640_mode_XGA_1024_768, 1024, 768, ++ ov5640_setting_30fps_XGA_1024_768, ++ ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)}, ++ }, ++}; ++ ++static struct regulator *io_regulator; ++static struct regulator *core_regulator; ++static struct regulator *analog_regulator; ++ ++static int ov5640_probe(struct i2c_client *adapter, ++ const struct i2c_device_id *device_id); ++static int ov5640_remove(struct i2c_client *client); ++ ++static s32 ov5640_read_reg(u16 reg, u8 *val); ++static s32 ov5640_write_reg(u16 reg, u8 val); ++ ++static const struct i2c_device_id ov5640_id[] = { ++ {"ov5640", 0}, ++ {"ov564x", 0}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, ov5640_id); ++ ++static struct i2c_driver ov5640_i2c_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "ov5640", ++ }, ++ .probe = ov5640_probe, ++ .remove = ov5640_remove, ++ .id_table = ov5640_id, ++}; ++ ++static inline void ov5640_power_down(int enable) ++{ ++ gpio_set_value(pwn_gpio, enable); ++ ++ msleep(2); ++} ++ ++static inline void ov5640_reset(void) ++{ ++ /* camera reset */ ++ gpio_set_value(rst_gpio, 1); ++ ++ /* camera power down */ ++ gpio_set_value(pwn_gpio, 1); ++ msleep(5); ++ gpio_set_value(pwn_gpio, 0); ++ msleep(5); ++ gpio_set_value(rst_gpio, 0); ++ msleep(1); ++ gpio_set_value(rst_gpio, 1); ++ msleep(5); ++ gpio_set_value(pwn_gpio, 1); ++} ++ ++static int ov5640_regulator_enable(struct device *dev) ++{ ++ int ret = 0; ++ ++ io_regulator = devm_regulator_get(dev, "DOVDD"); ++ if (!IS_ERR(io_regulator)) { ++ regulator_set_voltage(io_regulator, ++ OV5640_VOLTAGE_DIGITAL_IO, ++ OV5640_VOLTAGE_DIGITAL_IO); ++ ret = regulator_enable(io_regulator); ++ if (ret) { ++ dev_err(dev, "set io voltage failed\n"); ++ return ret; ++ } else { ++ dev_dbg(dev, "set io voltage ok\n"); ++ } ++ } else { ++ io_regulator = NULL; ++ dev_warn(dev, "cannot get io voltage\n"); ++ } ++ ++ core_regulator = devm_regulator_get(dev, "DVDD"); ++ if (!IS_ERR(core_regulator)) { ++ regulator_set_voltage(core_regulator, ++ OV5640_VOLTAGE_DIGITAL_CORE, ++ OV5640_VOLTAGE_DIGITAL_CORE); ++ ret = regulator_enable(core_regulator); ++ if (ret) { ++ dev_err(dev, "set core voltage failed\n"); ++ return ret; ++ } else { ++ dev_dbg(dev, "set core voltage ok\n"); ++ } ++ } else { ++ core_regulator = NULL; ++ dev_warn(dev, "cannot get core voltage\n"); ++ } ++ ++ analog_regulator = devm_regulator_get(dev, "AVDD"); ++ if (!IS_ERR(analog_regulator)) { ++ regulator_set_voltage(analog_regulator, ++ OV5640_VOLTAGE_ANALOG, ++ OV5640_VOLTAGE_ANALOG); ++ ret = regulator_enable(analog_regulator); ++ if (ret) { ++ dev_err(dev, "set analog voltage failed\n"); ++ return ret; ++ } else { ++ dev_dbg(dev, "set analog voltage ok\n"); ++ } ++ } else { ++ analog_regulator = NULL; ++ dev_warn(dev, "cannot get analog voltage\n"); ++ } ++ ++ return ret; ++} ++ ++static s32 ov5640_write_reg(u16 reg, u8 val) ++{ ++ u8 au8Buf[3] = {0}; ++ ++ au8Buf[0] = reg >> 8; ++ au8Buf[1] = reg & 0xff; ++ au8Buf[2] = val; ++ ++ if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) { ++ pr_err("%s:write reg error:reg=%x,val=%x\n", ++ __func__, reg, val); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static s32 ov5640_read_reg(u16 reg, u8 *val) ++{ ++ u8 au8RegBuf[2] = {0}; ++ u8 u8RdVal = 0; ++ ++ au8RegBuf[0] = reg >> 8; ++ au8RegBuf[1] = reg & 0xff; ++ ++ if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) { ++ pr_err("%s:write reg error:reg=%x\n", ++ __func__, reg); ++ return -1; ++ } ++ ++ if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) { ++ pr_err("%s:read reg error:reg=%x,val=%x\n", ++ __func__, reg, u8RdVal); ++ return -1; ++ } ++ ++ *val = u8RdVal; ++ ++ return u8RdVal; ++} ++ ++static void ov5640_soft_reset(void) ++{ ++ /* sysclk from pad */ ++ ov5640_write_reg(0x3103, 0x11); ++ ++ /* software reset */ ++ ov5640_write_reg(0x3008, 0x82); ++ ++ /* delay at least 5ms */ ++ msleep(10); ++} ++ ++/* set sensor driver capability ++ * 0x302c[7:6] - strength ++ 00 - 1x ++ 01 - 2x ++ 10 - 3x ++ 11 - 4x ++ */ ++static int ov5640_driver_capability(int strength) ++{ ++ u8 temp = 0; ++ ++ if (strength > 4 || strength < 1) { ++ pr_err("The valid driver capability of ov5640 is 1x~4x\n"); ++ return -EINVAL; ++ } ++ ++ ov5640_read_reg(0x302c, &temp); ++ ++ temp &= ~0xc0; /* clear [7:6] */ ++ temp |= ((strength - 1) << 6); /* set [7:6] */ ++ ++ ov5640_write_reg(0x302c, temp); ++ ++ return 0; ++} ++ ++/* calculate sysclk */ ++static int ov5640_get_sysclk(void) ++{ ++ int xvclk = ov5640_data.mclk / 10000; ++ int sysclk; ++ int temp1, temp2; ++ int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv, Bit_div2x, sclk_rdiv; ++ int sclk_rdiv_map[] = {1, 2, 4, 8}; ++ u8 regval = 0; ++ ++ temp1 = ov5640_read_reg(0x3034, ®val); ++ temp2 = temp1 & 0x0f; ++ if (temp2 == 8 || temp2 == 10) { ++ Bit_div2x = temp2 / 2; ++ } else { ++ pr_err("ov5640: unsupported bit mode %d\n", temp2); ++ return -1; ++ } ++ ++ temp1 = ov5640_read_reg(0x3035, ®val); ++ SysDiv = temp1 >> 4; ++ if (SysDiv == 0) ++ SysDiv = 16; ++ ++ temp1 = ov5640_read_reg(0x3036, ®val); ++ Multiplier = temp1; ++ temp1 = ov5640_read_reg(0x3037, ®val); ++ PreDiv = temp1 & 0x0f; ++ Pll_rdiv = ((temp1 >> 4) & 0x01) + 1; ++ ++ temp1 = ov5640_read_reg(0x3108, ®val); ++ temp2 = temp1 & 0x03; ++ ++ sclk_rdiv = sclk_rdiv_map[temp2]; ++ VCO = xvclk * Multiplier / PreDiv; ++ sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv; ++ ++ return sysclk; ++} ++ ++/* read HTS from register settings */ ++static int ov5640_get_HTS(void) ++{ ++ int HTS; ++ u8 temp = 0; ++ ++ HTS = ov5640_read_reg(0x380c, &temp); ++ HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp); ++ return HTS; ++} ++ ++/* read VTS from register settings */ ++static int ov5640_get_VTS(void) ++{ ++ int VTS; ++ u8 temp = 0; ++ ++ VTS = ov5640_read_reg(0x380e, &temp); ++ VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp); ++ ++ return VTS; ++} ++ ++/* write VTS to registers */ ++static int ov5640_set_VTS(int VTS) ++{ ++ int temp; ++ ++ temp = VTS & 0xff; ++ ov5640_write_reg(0x380f, temp); ++ ++ temp = VTS>>8; ++ ov5640_write_reg(0x380e, temp); ++ return 0; ++} ++ ++/* read shutter, in number of line period */ ++static int ov5640_get_shutter(void) ++{ ++ int shutter; ++ u8 regval; ++ ++ shutter = (ov5640_read_reg(0x03500, ®val) & 0x0f); ++ ++ shutter = (shutter<<8) + ov5640_read_reg(0x3501, ®val); ++ shutter = (shutter<<4) + (ov5640_read_reg(0x3502, ®val)>>4); ++ ++ return shutter; ++} ++ ++/* write shutter, in number of line period */ ++static int ov5640_set_shutter(int shutter) ++{ ++ int temp; ++ ++ shutter = shutter & 0xffff; ++ temp = shutter & 0x0f; ++ temp = temp<<4; ++ ov5640_write_reg(0x3502, temp); ++ ++ temp = shutter & 0xfff; ++ temp = temp>>4; ++ ov5640_write_reg(0x3501, temp); ++ ++ temp = shutter>>12; ++ ov5640_write_reg(0x3500, temp); ++ ++ return 0; ++} ++ ++/* read gain, 16 = 1x */ ++static int ov5640_get_gain16(void) ++{ ++ int gain16; ++ u8 regval; ++ ++ gain16 = ov5640_read_reg(0x350a, ®val) & 0x03; ++ gain16 = (gain16<<8) + ov5640_read_reg(0x350b, ®val); ++ ++ return gain16; ++} ++ ++/* write gain, 16 = 1x */ ++static int ov5640_set_gain16(int gain16) ++{ ++ int temp; ++ ++ gain16 = gain16 & 0x3ff; ++ temp = gain16 & 0xff; ++ ++ ov5640_write_reg(0x350b, temp); ++ temp = gain16>>8; ++ ++ ov5640_write_reg(0x350a, temp); ++ return 0; ++} ++ ++/* get banding filter value */ ++static int ov5640_get_light_freq(void) ++{ ++ int temp, temp1, light_frequency; ++ u8 regval; ++ ++ temp = ov5640_read_reg(0x3c01, ®val); ++ if (temp & 0x80) { ++ /* manual */ ++ temp1 = ov5640_read_reg(0x3c00, ®val); ++ if (temp1 & 0x04) { ++ /* 50Hz */ ++ light_frequency = 50; ++ } else { ++ /* 60Hz */ ++ light_frequency = 60; ++ } ++ } else { ++ /* auto */ ++ temp1 = ov5640_read_reg(0x3c0c, ®val); ++ if (temp1 & 0x01) { ++ /* 50Hz */ ++ light_frequency = 50; ++ } else { ++ /* 60Hz */ ++ light_frequency = 60; ++ } ++ } ++ ++ return light_frequency; ++} ++ ++static void ov5640_set_bandingfilter(void) ++{ ++ int prev_VTS; ++ int band_step60, max_band60, band_step50, max_band50; ++ ++ /* read preview PCLK */ ++ prev_sysclk = ov5640_get_sysclk(); ++ ++ /* read preview HTS */ ++ prev_HTS = ov5640_get_HTS(); ++ ++ /* read preview VTS */ ++ prev_VTS = ov5640_get_VTS(); ++ ++ /* calculate banding filter */ ++ /* 60Hz */ ++ band_step60 = prev_sysclk * 100/prev_HTS * 100/120; ++ ov5640_write_reg(0x3a0a, (band_step60 >> 8)); ++ ov5640_write_reg(0x3a0b, (band_step60 & 0xff)); ++ ++ max_band60 = (int)((prev_VTS-4)/band_step60); ++ ov5640_write_reg(0x3a0d, max_band60); ++ ++ /* 50Hz */ ++ band_step50 = prev_sysclk * 100/prev_HTS; ++ ov5640_write_reg(0x3a08, (band_step50 >> 8)); ++ ov5640_write_reg(0x3a09, (band_step50 & 0xff)); ++ ++ max_band50 = (int)((prev_VTS-4)/band_step50); ++ ov5640_write_reg(0x3a0e, max_band50); ++} ++ ++/* stable in high */ ++static int ov5640_set_AE_target(int target) ++{ ++ int fast_high, fast_low; ++ ++ AE_low = target * 23 / 25; /* 0.92 */ ++ AE_high = target * 27 / 25; /* 1.08 */ ++ fast_high = AE_high << 1; ++ ++ if (fast_high > 255) ++ fast_high = 255; ++ fast_low = AE_low >> 1; ++ ++ ov5640_write_reg(0x3a0f, AE_high); ++ ov5640_write_reg(0x3a10, AE_low); ++ ov5640_write_reg(0x3a1b, AE_high); ++ ov5640_write_reg(0x3a1e, AE_low); ++ ov5640_write_reg(0x3a11, fast_high); ++ ov5640_write_reg(0x3a1f, fast_low); ++ ++ return 0; ++} ++ ++/* enable = 0 to turn off night mode ++ enable = 1 to turn on night mode */ ++static int ov5640_set_night_mode(int enable) ++{ ++ u8 mode; ++ ++ ov5640_read_reg(0x3a00, &mode); ++ ++ if (enable) { ++ /* night mode on */ ++ mode |= 0x04; ++ ov5640_write_reg(0x3a00, mode); ++ } else { ++ /* night mode off */ ++ mode &= 0xfb; ++ ov5640_write_reg(0x3a00, mode); ++ } ++ ++ return 0; ++} ++ ++/* enable = 0 to turn off AEC/AGC ++ enable = 1 to turn on AEC/AGC */ ++void ov5640_turn_on_AE_AG(int enable) ++{ ++ u8 ae_ag_ctrl; ++ ++ ov5640_read_reg(0x3503, &ae_ag_ctrl); ++ if (enable) { ++ /* turn on auto AE/AG */ ++ ae_ag_ctrl = ae_ag_ctrl & ~(0x03); ++ } else { ++ /* turn off AE/AG */ ++ ae_ag_ctrl = ae_ag_ctrl | 0x03; ++ } ++ ov5640_write_reg(0x3503, ae_ag_ctrl); ++} ++ ++/* download ov5640 settings to sensor through i2c */ ++static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize) ++{ ++ register u32 Delay_ms = 0; ++ register u16 RegAddr = 0; ++ register u8 Mask = 0; ++ register u8 Val = 0; ++ u8 RegVal = 0; ++ int i, retval = 0; ++ ++ for (i = 0; i < ArySize; ++i, ++pModeSetting) { ++ Delay_ms = pModeSetting->u32Delay_ms; ++ RegAddr = pModeSetting->u16RegAddr; ++ Val = pModeSetting->u8Val; ++ Mask = pModeSetting->u8Mask; ++ ++ if (Mask) { ++ retval = ov5640_read_reg(RegAddr, &RegVal); ++ if (retval < 0) ++ goto err; ++ ++ RegVal &= ~(u8)Mask; ++ Val &= Mask; ++ Val |= RegVal; ++ } ++ ++ retval = ov5640_write_reg(RegAddr, Val); ++ if (retval < 0) ++ goto err; ++ ++ if (Delay_ms) ++ msleep(Delay_ms); ++ } ++err: ++ return retval; ++} ++ ++static int ov5640_init_mode(void) ++{ ++ struct reg_value *pModeSetting = NULL; ++ int ArySize = 0, retval = 0; ++ ++ ov5640_soft_reset(); ++ ++ pModeSetting = ov5640_global_init_setting; ++ ArySize = ARRAY_SIZE(ov5640_global_init_setting); ++ retval = ov5640_download_firmware(pModeSetting, ArySize); ++ if (retval < 0) ++ goto err; ++ ++ pModeSetting = ov5640_init_setting_30fps_VGA; ++ ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA); ++ retval = ov5640_download_firmware(pModeSetting, ArySize); ++ if (retval < 0) ++ goto err; ++ ++ /* change driver capability to 2x according to validation board. ++ * if the image is not stable, please increase the driver strength. ++ */ ++ ov5640_driver_capability(2); ++ ov5640_set_bandingfilter(); ++ ov5640_set_AE_target(AE_Target); ++ ov5640_set_night_mode(night_mode); ++ ++ /* skip 9 vysnc: start capture at 10th vsync */ ++ msleep(300); ++ ++ /* turn off night mode */ ++ night_mode = 0; ++ ov5640_data.pix.width = 640; ++ ov5640_data.pix.height = 480; ++err: ++ return retval; ++} ++ ++/* change to or back to subsampling mode set the mode directly ++ * image size below 1280 * 960 is subsampling mode */ ++static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate, ++ enum ov5640_mode mode) ++{ ++ struct reg_value *pModeSetting = NULL; ++ s32 ArySize = 0; ++ int retval = 0; ++ ++ if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) { ++ pr_err("Wrong ov5640 mode detected!\n"); ++ return -1; ++ } ++ ++ pModeSetting = ov5640_mode_info_data[frame_rate][mode].init_data_ptr; ++ ArySize = ++ ov5640_mode_info_data[frame_rate][mode].init_data_size; ++ ++ ov5640_data.pix.width = ov5640_mode_info_data[frame_rate][mode].width; ++ ov5640_data.pix.height = ov5640_mode_info_data[frame_rate][mode].height; ++ ++ if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || ++ pModeSetting == NULL || ArySize == 0) ++ return -EINVAL; ++ ++ /* set ov5640 to subsampling mode */ ++ retval = ov5640_download_firmware(pModeSetting, ArySize); ++ ++ /* turn on AE AG for subsampling mode, in case the firmware didn't */ ++ ov5640_turn_on_AE_AG(1); ++ ++ /* calculate banding filter */ ++ ov5640_set_bandingfilter(); ++ ++ /* set AE target */ ++ ov5640_set_AE_target(AE_Target); ++ ++ /* update night mode setting */ ++ ov5640_set_night_mode(night_mode); ++ ++ /* skip 9 vysnc: start capture at 10th vsync */ ++ if (mode == ov5640_mode_XGA_1024_768 && frame_rate == ov5640_30_fps) { ++ pr_warning("ov5640: actual frame rate of XGA is 22.5fps\n"); ++ /* 1/22.5 * 9*/ ++ msleep(400); ++ return retval; ++ } ++ ++ if (frame_rate == ov5640_15_fps) { ++ /* 1/15 * 9*/ ++ msleep(600); ++ } else if (frame_rate == ov5640_30_fps) { ++ /* 1/30 * 9*/ ++ msleep(300); ++ } ++ ++ return retval; ++} ++ ++/* change to scaling mode go through exposure calucation ++ * image size above 1280 * 960 is scaling mode */ ++static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate, ++ enum ov5640_mode mode) ++{ ++ int prev_shutter, prev_gain16, average; ++ int cap_shutter, cap_gain16; ++ int cap_sysclk, cap_HTS, cap_VTS; ++ int light_freq, cap_bandfilt, cap_maxband; ++ long cap_gain16_shutter; ++ u8 temp; ++ struct reg_value *pModeSetting = NULL; ++ s32 ArySize = 0; ++ int retval = 0; ++ ++ /* check if the input mode and frame rate is valid */ ++ pModeSetting = ++ ov5640_mode_info_data[frame_rate][mode].init_data_ptr; ++ ArySize = ++ ov5640_mode_info_data[frame_rate][mode].init_data_size; ++ ++ ov5640_data.pix.width = ++ ov5640_mode_info_data[frame_rate][mode].width; ++ ov5640_data.pix.height = ++ ov5640_mode_info_data[frame_rate][mode].height; ++ ++ if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || ++ pModeSetting == NULL || ArySize == 0) ++ return -EINVAL; ++ ++ /* read preview shutter */ ++ prev_shutter = ov5640_get_shutter(); ++ ++ /* read preview gain */ ++ prev_gain16 = ov5640_get_gain16(); ++ ++ /* get average */ ++ average = ov5640_read_reg(0x56a1, &temp); ++ ++ /* turn off night mode for capture */ ++ ov5640_set_night_mode(0); ++ ++ /* turn off overlay */ ++ ov5640_write_reg(0x3022, 0x06); ++ ++ /* Write capture setting */ ++ retval = ov5640_download_firmware(pModeSetting, ArySize); ++ if (retval < 0) ++ goto err; ++ ++ /* turn off AE AG when capture image. */ ++ ov5640_turn_on_AE_AG(0); ++ ++ /* read capture VTS */ ++ cap_VTS = ov5640_get_VTS(); ++ cap_HTS = ov5640_get_HTS(); ++ cap_sysclk = ov5640_get_sysclk(); ++ ++ /* calculate capture banding filter */ ++ light_freq = ov5640_get_light_freq(); ++ if (light_freq == 60) { ++ /* 60Hz */ ++ cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120; ++ } else { ++ /* 50Hz */ ++ cap_bandfilt = cap_sysclk * 100 / cap_HTS; ++ } ++ cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt); ++ /* calculate capture shutter/gain16 */ ++ if (average > AE_low && average < AE_high) { ++ /* in stable range */ ++ cap_gain16_shutter = ++ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk * ++ prev_HTS/cap_HTS * AE_Target / average; ++ } else { ++ cap_gain16_shutter = ++ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk * ++ prev_HTS/cap_HTS; ++ } ++ ++ /* gain to shutter */ ++ if (cap_gain16_shutter < (cap_bandfilt * 16)) { ++ /* shutter < 1/100 */ ++ cap_shutter = cap_gain16_shutter/16; ++ if (cap_shutter < 1) ++ cap_shutter = 1; ++ cap_gain16 = cap_gain16_shutter/cap_shutter; ++ if (cap_gain16 < 16) ++ cap_gain16 = 16; ++ } else { ++ if (cap_gain16_shutter > (cap_bandfilt*cap_maxband*16)) { ++ /* exposure reach max */ ++ cap_shutter = cap_bandfilt*cap_maxband; ++ cap_gain16 = cap_gain16_shutter / cap_shutter; ++ } else { ++ /* 1/100 < cap_shutter =< max, cap_shutter = n/100 */ ++ cap_shutter = ++ ((int)(cap_gain16_shutter/16/cap_bandfilt)) ++ * cap_bandfilt; ++ cap_gain16 = cap_gain16_shutter / cap_shutter; ++ } ++ } ++ ++ /* write capture gain */ ++ ov5640_set_gain16(cap_gain16); ++ ++ /* write capture shutter */ ++ if (cap_shutter > (cap_VTS - 4)) { ++ cap_VTS = cap_shutter + 4; ++ ov5640_set_VTS(cap_VTS); ++ } ++ ++ ov5640_set_shutter(cap_shutter); ++ ++ /* skip 2 vysnc: start capture at 3rd vsync ++ * frame rate of QSXGA and 1080P is 7.5fps: 1/7.5 * 2 ++ */ ++ pr_warning("ov5640: the actual frame rate of %s is 7.5fps\n", ++ mode == ov5640_mode_1080P_1920_1080 ? "1080P" : "QSXGA"); ++ msleep(267); ++err: ++ return retval; ++} ++ ++static int ov5640_change_mode(enum ov5640_frame_rate frame_rate, ++ enum ov5640_mode mode) ++{ ++ int retval = 0; ++ ++ if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) { ++ pr_err("Wrong ov5640 mode detected!\n"); ++ return -1; ++ } ++ ++ if (mode == ov5640_mode_1080P_1920_1080 || ++ mode == ov5640_mode_QSXGA_2592_1944) { ++ /* change to scaling mode go through exposure calucation ++ * image size above 1280 * 960 is scaling mode */ ++ retval = ov5640_change_mode_exposure_calc(frame_rate, mode); ++ } else { ++ /* change back to subsampling modem download firmware directly ++ * image size below 1280 * 960 is subsampling mode */ ++ retval = ov5640_change_mode_direct(frame_rate, mode); ++ } ++ ++ return retval; ++} ++ ++/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */ ++ ++static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) ++{ ++ if (s == NULL) { ++ pr_err(" ERROR!! no slave device set!\n"); ++ return -1; ++ } ++ ++ memset(p, 0, sizeof(*p)); ++ p->u.bt656.clock_curr = ov5640_data.mclk; ++ pr_debug(" clock_curr=mclk=%d\n", ov5640_data.mclk); ++ p->if_type = V4L2_IF_TYPE_BT656; ++ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; ++ p->u.bt656.clock_min = OV5640_XCLK_MIN; ++ p->u.bt656.clock_max = OV5640_XCLK_MAX; ++ p->u.bt656.bt_sync_correct = 1; /* Indicate external vsync */ ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @on: indicates power mode (on or off) ++ * ++ * Turns the power on or off, depending on the value of on and returns the ++ * appropriate error code. ++ */ ++static int ioctl_s_power(struct v4l2_int_device *s, int on) ++{ ++ struct sensor_data *sensor = s->priv; ++ ++ if (on && !sensor->on) { ++ if (io_regulator) ++ if (regulator_enable(io_regulator) != 0) ++ return -EIO; ++ if (core_regulator) ++ if (regulator_enable(core_regulator) != 0) ++ return -EIO; ++ if (analog_regulator) ++ if (regulator_enable(analog_regulator) != 0) ++ return -EIO; ++ /* Make sure power on */ ++ ov5640_power_down(0); ++ } else if (!on && sensor->on) { ++ if (analog_regulator) ++ regulator_disable(analog_regulator); ++ if (core_regulator) ++ regulator_disable(core_regulator); ++ if (io_regulator) ++ regulator_disable(io_regulator); ++ ++ ov5640_power_down(1); ++} ++ ++ sensor->on = on; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure ++ * ++ * Returns the sensor's video CAPTURE parameters. ++ */ ++static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) ++{ ++ struct sensor_data *sensor = s->priv; ++ struct v4l2_captureparm *cparm = &a->parm.capture; ++ int ret = 0; ++ ++ switch (a->type) { ++ /* This is the only case currently handled. */ ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ memset(a, 0, sizeof(*a)); ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ cparm->capability = sensor->streamcap.capability; ++ cparm->timeperframe = sensor->streamcap.timeperframe; ++ cparm->capturemode = sensor->streamcap.capturemode; ++ ret = 0; ++ break; ++ ++ /* These are all the possible cases. */ ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ case V4L2_BUF_TYPE_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_VBI_OUTPUT: ++ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: ++ ret = -EINVAL; ++ break; ++ ++ default: ++ pr_debug(" type is unknown - %d\n", a->type); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure ++ * ++ * Configures the sensor to use the input parameters, if possible. If ++ * not possible, reverts to the old parameters and returns the ++ * appropriate error code. ++ */ ++static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) ++{ ++ struct sensor_data *sensor = s->priv; ++ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; ++ u32 tgt_fps; /* target frames per secound */ ++ enum ov5640_frame_rate frame_rate; ++ int ret = 0; ++ ++ /* Make sure power on */ ++ ov5640_power_down(0); ++ ++ switch (a->type) { ++ /* This is the only case currently handled. */ ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ /* Check that the new frame rate is allowed. */ ++ if ((timeperframe->numerator == 0) || ++ (timeperframe->denominator == 0)) { ++ timeperframe->denominator = DEFAULT_FPS; ++ timeperframe->numerator = 1; ++ } ++ ++ tgt_fps = timeperframe->denominator / ++ timeperframe->numerator; ++ ++ if (tgt_fps > MAX_FPS) { ++ timeperframe->denominator = MAX_FPS; ++ timeperframe->numerator = 1; ++ } else if (tgt_fps < MIN_FPS) { ++ timeperframe->denominator = MIN_FPS; ++ timeperframe->numerator = 1; ++ } ++ ++ /* Actual frame rate we use */ ++ tgt_fps = timeperframe->denominator / ++ timeperframe->numerator; ++ ++ if (tgt_fps == 15) ++ frame_rate = ov5640_15_fps; ++ else if (tgt_fps == 30) ++ frame_rate = ov5640_30_fps; ++ else { ++ pr_err(" The camera frame rate is not supported!\n"); ++ return -EINVAL; ++ } ++ ++ ret = ov5640_change_mode(frame_rate, ++ a->parm.capture.capturemode); ++ if (ret < 0) ++ return ret; ++ ++ sensor->streamcap.timeperframe = *timeperframe; ++ sensor->streamcap.capturemode = a->parm.capture.capturemode; ++ ++ break; ++ ++ /* These are all the possible cases. */ ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ case V4L2_BUF_TYPE_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_VBI_OUTPUT: ++ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: ++ pr_debug(" type is not " \ ++ "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n", ++ a->type); ++ ret = -EINVAL; ++ break; ++ ++ default: ++ pr_debug(" type is unknown - %d\n", a->type); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap ++ * @s: pointer to standard V4L2 device structure ++ * @f: pointer to standard V4L2 v4l2_format structure ++ * ++ * Returns the sensor's current pixel format in the v4l2_format ++ * parameter. ++ */ ++static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) ++{ ++ struct sensor_data *sensor = s->priv; ++ ++ f->fmt.pix = sensor->pix; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure ++ * ++ * If the requested control is supported, returns the control's current ++ * value from the video_control[] array. Otherwise, returns -EINVAL ++ * if the control is not supported. ++ */ ++static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) ++{ ++ int ret = 0; ++ ++ switch (vc->id) { ++ case V4L2_CID_BRIGHTNESS: ++ vc->value = ov5640_data.brightness; ++ break; ++ case V4L2_CID_HUE: ++ vc->value = ov5640_data.hue; ++ break; ++ case V4L2_CID_CONTRAST: ++ vc->value = ov5640_data.contrast; ++ break; ++ case V4L2_CID_SATURATION: ++ vc->value = ov5640_data.saturation; ++ break; ++ case V4L2_CID_RED_BALANCE: ++ vc->value = ov5640_data.red; ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ vc->value = ov5640_data.blue; ++ break; ++ case V4L2_CID_EXPOSURE: ++ vc->value = ov5640_data.ae_mode; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure ++ * ++ * If the requested control is supported, sets the control's current ++ * value in HW (and updates the video_control[] array). Otherwise, ++ * returns -EINVAL if the control is not supported. ++ */ ++static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) ++{ ++ int retval = 0; ++ ++ pr_debug("In ov5640:ioctl_s_ctrl %d\n", ++ vc->id); ++ ++ switch (vc->id) { ++ case V4L2_CID_BRIGHTNESS: ++ break; ++ case V4L2_CID_CONTRAST: ++ break; ++ case V4L2_CID_SATURATION: ++ break; ++ case V4L2_CID_HUE: ++ break; ++ case V4L2_CID_AUTO_WHITE_BALANCE: ++ break; ++ case V4L2_CID_DO_WHITE_BALANCE: ++ break; ++ case V4L2_CID_RED_BALANCE: ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ break; ++ case V4L2_CID_GAMMA: ++ break; ++ case V4L2_CID_EXPOSURE: ++ break; ++ case V4L2_CID_AUTOGAIN: ++ break; ++ case V4L2_CID_GAIN: ++ break; ++ case V4L2_CID_HFLIP: ++ break; ++ case V4L2_CID_VFLIP: ++ break; ++ default: ++ retval = -EPERM; ++ break; ++ } ++ ++ return retval; ++} ++ ++/*! ++ * ioctl_enum_framesizes - V4L2 sensor interface handler for ++ * VIDIOC_ENUM_FRAMESIZES ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure ++ * ++ * Return 0 if successful, otherwise -EINVAL. ++ */ ++static int ioctl_enum_framesizes(struct v4l2_int_device *s, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ if (fsize->index > ov5640_mode_MAX) ++ return -EINVAL; ++ ++ fsize->pixel_format = ov5640_data.pix.pixelformat; ++ fsize->discrete.width = ++ max(ov5640_mode_info_data[0][fsize->index].width, ++ ov5640_mode_info_data[1][fsize->index].width); ++ fsize->discrete.height = ++ max(ov5640_mode_info_data[0][fsize->index].height, ++ ov5640_mode_info_data[1][fsize->index].height); ++ return 0; ++} ++ ++/*! ++ * ioctl_enum_frameintervals - V4L2 sensor interface handler for ++ * VIDIOC_ENUM_FRAMEINTERVALS ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure ++ * ++ * Return 0 if successful, otherwise -EINVAL. ++ */ ++static int ioctl_enum_frameintervals(struct v4l2_int_device *s, ++ struct v4l2_frmivalenum *fival) ++{ ++ int i, j, count; ++ ++ if (fival->index < 0 || fival->index > ov5640_mode_MAX) ++ return -EINVAL; ++ ++ if (fival->width == 0 || fival->height == 0 || ++ fival->pixel_format == 0) { ++ pr_warning("Please assign pixelformat, width and height.\n"); ++ return -EINVAL; ++ } ++ ++ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; ++ fival->discrete.numerator = 1; ++ ++ count = 0; ++ for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) { ++ for (j = 0; j < (ov5640_mode_MAX + 1); j++) { ++ if (fival->pixel_format == ov5640_data.pix.pixelformat ++ && fival->width == ov5640_mode_info_data[i][j].width ++ && fival->height == ov5640_mode_info_data[i][j].height ++ && ov5640_mode_info_data[i][j].init_data_ptr != NULL) { ++ count++; ++ } ++ if (fival->index == (count - 1)) { ++ fival->discrete.denominator = ++ ov5640_framerates[i]; ++ return 0; ++ } ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++/*! ++ * ioctl_g_chip_ident - V4L2 sensor interface handler for ++ * VIDIOC_DBG_G_CHIP_IDENT ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @id: pointer to int ++ * ++ * Return 0. ++ */ ++static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id) ++{ ++ ((struct v4l2_dbg_chip_ident *)id)->match.type = ++ V4L2_CHIP_MATCH_I2C_DRIVER; ++ strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, "ov5640_camera"); ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT ++ * @s: pointer to standard V4L2 device structure ++ */ ++static int ioctl_init(struct v4l2_int_device *s) ++{ ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT ++ * @s: pointer to standard V4L2 device structure ++ * @fmt: pointer to standard V4L2 fmt description structure ++ * ++ * Return 0. ++ */ ++static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, ++ struct v4l2_fmtdesc *fmt) ++{ ++ if (fmt->index > ov5640_mode_MAX) ++ return -EINVAL; ++ ++ fmt->pixelformat = ov5640_data.pix.pixelformat; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num ++ * @s: pointer to standard V4L2 device structure ++ * ++ * Initialise the device when slave attaches to the master. ++ */ ++static int ioctl_dev_init(struct v4l2_int_device *s) ++{ ++ struct sensor_data *sensor = s->priv; ++ u32 tgt_xclk; /* target xclk */ ++ u32 tgt_fps; /* target frames per secound */ ++ enum ov5640_frame_rate frame_rate; ++ int ret; ++ ++ ov5640_data.on = true; ++ ++ /* mclk */ ++ tgt_xclk = ov5640_data.mclk; ++ tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX); ++ tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN); ++ ov5640_data.mclk = tgt_xclk; ++ ++ pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); ++ clk_set_rate(ov5640_data.sensor_clk, ov5640_data.mclk); ++ ++ /* Default camera frame rate is set in probe */ ++ tgt_fps = sensor->streamcap.timeperframe.denominator / ++ sensor->streamcap.timeperframe.numerator; ++ ++ if (tgt_fps == 15) ++ frame_rate = ov5640_15_fps; ++ else if (tgt_fps == 30) ++ frame_rate = ov5640_30_fps; ++ else ++ return -EINVAL; /* Only support 15fps or 30fps now. */ ++ ++ ret = ov5640_init_mode(); ++ return ret; ++} ++ ++/*! ++ * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num ++ * @s: pointer to standard V4L2 device structure ++ * ++ * Delinitialise the device when slave detaches to the master. ++ */ ++static int ioctl_dev_exit(struct v4l2_int_device *s) ++{ ++ return 0; ++} ++ ++/*! ++ * This structure defines all the ioctls for this module and links them to the ++ * enumeration. ++ */ ++static struct v4l2_int_ioctl_desc ov5640_ioctl_desc[] = { ++ { vidioc_int_dev_init_num, ++ (v4l2_int_ioctl_func *)ioctl_dev_init }, ++ { vidioc_int_dev_exit_num, ++ ioctl_dev_exit}, ++ { vidioc_int_s_power_num, ++ (v4l2_int_ioctl_func *)ioctl_s_power }, ++ { vidioc_int_g_ifparm_num, ++ (v4l2_int_ioctl_func *)ioctl_g_ifparm }, ++ { vidioc_int_init_num, ++ (v4l2_int_ioctl_func *)ioctl_init }, ++ { vidioc_int_enum_fmt_cap_num, ++ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap }, ++ { vidioc_int_g_fmt_cap_num, ++ (v4l2_int_ioctl_func *)ioctl_g_fmt_cap }, ++ { vidioc_int_g_parm_num, ++ (v4l2_int_ioctl_func *)ioctl_g_parm }, ++ { vidioc_int_s_parm_num, ++ (v4l2_int_ioctl_func *)ioctl_s_parm }, ++ { vidioc_int_g_ctrl_num, ++ (v4l2_int_ioctl_func *)ioctl_g_ctrl }, ++ { vidioc_int_s_ctrl_num, ++ (v4l2_int_ioctl_func *)ioctl_s_ctrl }, ++ { vidioc_int_enum_framesizes_num, ++ (v4l2_int_ioctl_func *)ioctl_enum_framesizes }, ++ { vidioc_int_enum_frameintervals_num, ++ (v4l2_int_ioctl_func *)ioctl_enum_frameintervals }, ++ { vidioc_int_g_chip_ident_num, ++ (v4l2_int_ioctl_func *)ioctl_g_chip_ident }, ++}; ++ ++static struct v4l2_int_slave ov5640_slave = { ++ .ioctls = ov5640_ioctl_desc, ++ .num_ioctls = ARRAY_SIZE(ov5640_ioctl_desc), ++}; ++ ++static struct v4l2_int_device ov5640_int_device = { ++ .module = THIS_MODULE, ++ .name = "ov5640", ++ .type = v4l2_int_type_slave, ++ .u = { ++ .slave = &ov5640_slave, ++ }, ++}; ++ ++/*! ++ * ov5640 I2C probe function ++ * ++ * @param adapter struct i2c_adapter * ++ * @return Error code indicating success or failure ++ */ ++static int ov5640_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct pinctrl *pinctrl; ++ struct device *dev = &client->dev; ++ int retval; ++ u8 chip_id_high, chip_id_low; ++ ++ /* ov5640 pinctrl */ ++ pinctrl = devm_pinctrl_get_select_default(dev); ++ if (IS_ERR(pinctrl)) { ++ dev_err(dev, "setup pinctrl failed\n"); ++ return PTR_ERR(pinctrl); ++ } ++ ++ /* request power down pin */ ++ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); ++ if (!gpio_is_valid(pwn_gpio)) { ++ dev_err(dev, "no sensor pwdn pin available\n"); ++ return -ENODEV; ++ } ++ retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, ++ "ov5640_pwdn"); ++ if (retval < 0) ++ return retval; ++ ++ /* request reset pin */ ++ rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0); ++ if (!gpio_is_valid(rst_gpio)) { ++ dev_err(dev, "no sensor reset pin available\n"); ++ return -EINVAL; ++ } ++ retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH, ++ "ov5640_reset"); ++ if (retval < 0) ++ return retval; ++ ++ /* Set initial values for the sensor struct. */ ++ memset(&ov5640_data, 0, sizeof(ov5640_data)); ++ ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk"); ++ if (IS_ERR(ov5640_data.sensor_clk)) { ++ dev_err(dev, "get mclk failed\n"); ++ return PTR_ERR(ov5640_data.sensor_clk); ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "mclk", ++ &ov5640_data.mclk); ++ if (retval) { ++ dev_err(dev, "mclk frequency is invalid\n"); ++ return retval; ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "mclk_source", ++ (u32 *) &(ov5640_data.mclk_source)); ++ if (retval) { ++ dev_err(dev, "mclk_source invalid\n"); ++ return retval; ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "csi_id", ++ &(ov5640_data.csi)); ++ if (retval) { ++ dev_err(dev, "csi_id invalid\n"); ++ return retval; ++ } ++ ++ clk_prepare_enable(ov5640_data.sensor_clk); ++ ++ ov5640_data.io_init = ov5640_reset; ++ ov5640_data.i2c_client = client; ++ ov5640_data.pix.pixelformat = V4L2_PIX_FMT_YUYV; ++ ov5640_data.pix.width = 640; ++ ov5640_data.pix.height = 480; ++ ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY | ++ V4L2_CAP_TIMEPERFRAME; ++ ov5640_data.streamcap.capturemode = 0; ++ ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS; ++ ov5640_data.streamcap.timeperframe.numerator = 1; ++ ++ ov5640_regulator_enable(&client->dev); ++ ++ ov5640_reset(); ++ ++ ov5640_power_down(0); ++ ++ retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high); ++ if (retval < 0 || chip_id_high != 0x56) { ++ clk_disable_unprepare(ov5640_data.sensor_clk); ++ pr_warning("camera ov5640 is not found\n"); ++ return -ENODEV; ++ } ++ retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low); ++ if (retval < 0 || chip_id_low != 0x40) { ++ clk_disable_unprepare(ov5640_data.sensor_clk); ++ pr_warning("camera ov5640 is not found\n"); ++ return -ENODEV; ++ } ++ ++ ov5640_power_down(1); ++ ++ clk_disable_unprepare(ov5640_data.sensor_clk); ++ ++ ov5640_int_device.priv = &ov5640_data; ++ retval = v4l2_int_device_register(&ov5640_int_device); ++ ++ pr_info("camera ov5640 is found\n"); ++ return retval; ++} ++ ++/*! ++ * ov5640 I2C detach function ++ * ++ * @param client struct i2c_client * ++ * @return Error code indicating success or failure ++ */ ++static int ov5640_remove(struct i2c_client *client) ++{ ++ v4l2_int_device_unregister(&ov5640_int_device); ++ ++ if (analog_regulator) ++ regulator_disable(analog_regulator); ++ ++ if (core_regulator) ++ regulator_disable(core_regulator); ++ ++ if (io_regulator) ++ regulator_disable(io_regulator); ++ ++ return 0; ++} ++ ++module_i2c_driver(ov5640_i2c_driver); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("OV5640 Camera Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("1.0"); ++MODULE_ALIAS("CSI"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/ov5640_mipi.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ov5640_mipi.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/ov5640_mipi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ov5640_mipi.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,2104 @@ ++/* ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++ ++#define OV5640_VOLTAGE_ANALOG 2800000 ++#define OV5640_VOLTAGE_DIGITAL_CORE 1500000 ++#define OV5640_VOLTAGE_DIGITAL_IO 1800000 ++ ++#define MIN_FPS 15 ++#define MAX_FPS 30 ++#define DEFAULT_FPS 30 ++ ++#define OV5640_XCLK_MIN 6000000 ++#define OV5640_XCLK_MAX 24000000 ++ ++#define OV5640_CHIP_ID_HIGH_BYTE 0x300A ++#define OV5640_CHIP_ID_LOW_BYTE 0x300B ++ ++enum ov5640_mode { ++ ov5640_mode_MIN = 0, ++ ov5640_mode_VGA_640_480 = 0, ++ ov5640_mode_QVGA_320_240 = 1, ++ ov5640_mode_NTSC_720_480 = 2, ++ ov5640_mode_PAL_720_576 = 3, ++ ov5640_mode_720P_1280_720 = 4, ++ ov5640_mode_1080P_1920_1080 = 5, ++ ov5640_mode_QSXGA_2592_1944 = 6, ++ ov5640_mode_QCIF_176_144 = 7, ++ ov5640_mode_XGA_1024_768 = 8, ++ ov5640_mode_MAX = 8, ++ ov5640_mode_INIT = 0xff, /*only for sensor init*/ ++}; ++ ++enum ov5640_frame_rate { ++ ov5640_15_fps, ++ ov5640_30_fps ++}; ++ ++/* image size under 1280 * 960 are SUBSAMPLING ++ * image size upper 1280 * 960 are SCALING ++ */ ++enum ov5640_downsize_mode { ++ SUBSAMPLING, ++ SCALING, ++}; ++ ++struct reg_value { ++ u16 u16RegAddr; ++ u8 u8Val; ++ u8 u8Mask; ++ u32 u32Delay_ms; ++}; ++ ++struct ov5640_mode_info { ++ enum ov5640_mode mode; ++ enum ov5640_downsize_mode dn_mode; ++ u32 width; ++ u32 height; ++ struct reg_value *init_data_ptr; ++ u32 init_data_size; ++}; ++ ++/*! ++ * Maintains the information on the current state of the sesor. ++ */ ++static struct sensor_data ov5640_data; ++static int pwn_gpio, rst_gpio; ++ ++static struct reg_value ov5640_init_setting_30fps_VGA[] = { ++ ++ {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, ++ {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0}, ++ {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, ++ {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0}, ++ {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, ++ {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, ++ {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, ++ {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, ++ {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, ++ {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, ++ {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, ++ {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, ++ {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, ++ {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, ++ {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, ++ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, ++ {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, ++ {0x300e, 0x45, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, ++ {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, ++ {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x4837, 0x0a, 0, 0}, {0x4800, 0x04, 0, 0}, {0x3824, 0x02, 0, 0}, ++ {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, ++ {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, ++ {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, ++ {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, ++ {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, ++ {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, ++ {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, ++ {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, ++ {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, ++ {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, ++ {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, ++ {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, ++ {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, ++ {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, ++ {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, ++ {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, ++ {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, ++ {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, ++ {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, ++ {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, ++ {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, ++ {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, ++ {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, ++ {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, ++ {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, ++ {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, ++ {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, ++ {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, ++ {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, ++ {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, ++ {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, ++ {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, ++ {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, ++ {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, ++ {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, ++ {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, ++ {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, ++ {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, ++ {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, ++ {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, ++ {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, ++ {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, ++ {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, ++ {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, ++ {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, ++ {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, ++ {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, ++ {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, ++ {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_VGA_640_480[] = { ++ ++ {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, ++ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_VGA_640_480[] = { ++ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, ++ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { ++ ++ {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, ++ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0}, ++ {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, ++ {0x380b, 0x00, 0, 0}, {0x3035, 0x12, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { ++ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, ++ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3808, 0x04, 0, 0}, ++ {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { ++ {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, ++ {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { ++ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, ++ {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { ++ {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, ++ {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++}; ++static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { ++ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, ++ {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { ++ {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, ++ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { ++ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, ++ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_PAL_720_576[] = { ++ {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, ++ {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_PAL_720_576[] = { ++ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, ++ {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, ++ {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_720P_1280_720[] = { ++ {0x3008, 0x42, 0, 0}, ++ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, ++ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, ++ {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, ++ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, ++ {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, ++ {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, ++ {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, ++ {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0}, ++ {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_720P_1280_720[] = { ++ {0x3035, 0x41, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, ++ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, ++ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, ++ {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, ++ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, ++ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, ++ {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, ++ {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, ++ {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, ++ {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = { ++ {0x3008, 0x42, 0, 0}, ++ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, ++ {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, ++ {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, ++ {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, ++ {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, ++ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0}, ++ {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, ++ {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, ++ {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, ++ {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0}, ++ {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, ++ {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, ++ {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, ++ {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, ++ {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, ++ {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, ++ {0x3503, 0, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { ++ {0x3008, 0x42, 0, 0}, ++ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, ++ {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, ++ {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, ++ {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, ++ {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, ++ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x21, 0, 0}, ++ {0x3036, 0x54, 0, 1}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, ++ {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, ++ {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, ++ {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0}, ++ {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, ++ {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, ++ {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, ++ {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, ++ {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, ++ {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, ++ {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0}, ++}; ++ ++static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { ++ {0x4202, 0x0f, 0, 0}, /* stream off the sensor */ ++ {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, /*disable flip*/ ++ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, ++ {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, ++ {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, ++ {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, ++ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, ++ {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, ++ {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, ++ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, ++ {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, ++ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, ++ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, ++ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, ++ {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, ++ {0x4202, 0x00, 0, 0}, /* stream on the sensor */ ++}; ++ ++static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = { ++ { ++ {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480, ++ ov5640_setting_15fps_VGA_640_480, ++ ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)}, ++ {ov5640_mode_QVGA_320_240, SUBSAMPLING, 320, 240, ++ ov5640_setting_15fps_QVGA_320_240, ++ ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)}, ++ {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480, ++ ov5640_setting_15fps_NTSC_720_480, ++ ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)}, ++ {ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576, ++ ov5640_setting_15fps_PAL_720_576, ++ ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)}, ++ {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720, ++ ov5640_setting_15fps_720P_1280_720, ++ ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)}, ++ {ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080, ++ ov5640_setting_15fps_1080P_1920_1080, ++ ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)}, ++ {ov5640_mode_QSXGA_2592_1944, SCALING, 2592, 1944, ++ ov5640_setting_15fps_QSXGA_2592_1944, ++ ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)}, ++ {ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144, ++ ov5640_setting_15fps_QCIF_176_144, ++ ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)}, ++ {ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768, ++ ov5640_setting_15fps_XGA_1024_768, ++ ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)}, ++ }, ++ { ++ {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480, ++ ov5640_setting_30fps_VGA_640_480, ++ ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)}, ++ {ov5640_mode_QVGA_320_240, SUBSAMPLING, 320, 240, ++ ov5640_setting_30fps_QVGA_320_240, ++ ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)}, ++ {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480, ++ ov5640_setting_30fps_NTSC_720_480, ++ ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)}, ++ {ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576, ++ ov5640_setting_30fps_PAL_720_576, ++ ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)}, ++ {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720, ++ ov5640_setting_30fps_720P_1280_720, ++ ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)}, ++ {ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080, ++ ov5640_setting_30fps_1080P_1920_1080, ++ ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)}, ++ {ov5640_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0}, ++ {ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144, ++ ov5640_setting_30fps_QCIF_176_144, ++ ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)}, ++ {ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768, ++ ov5640_setting_30fps_XGA_1024_768, ++ ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)}, ++ }, ++}; ++ ++static struct regulator *io_regulator; ++static struct regulator *core_regulator; ++static struct regulator *analog_regulator; ++static struct regulator *gpo_regulator; ++ ++static int ov5640_probe(struct i2c_client *adapter, ++ const struct i2c_device_id *device_id); ++static int ov5640_remove(struct i2c_client *client); ++ ++static s32 ov5640_read_reg(u16 reg, u8 *val); ++static s32 ov5640_write_reg(u16 reg, u8 val); ++ ++static const struct i2c_device_id ov5640_id[] = { ++ {"ov5640_mipi", 0}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, ov5640_id); ++ ++static struct i2c_driver ov5640_i2c_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "ov5640_mipi", ++ }, ++ .probe = ov5640_probe, ++ .remove = ov5640_remove, ++ .id_table = ov5640_id, ++}; ++ ++static void ov5640_standby(s32 enable) ++{ ++ if (enable) ++ gpio_set_value(pwn_gpio, 1); ++ else ++ gpio_set_value(pwn_gpio, 0); ++ ++ msleep(2); ++} ++ ++static void ov5640_reset(void) ++{ ++ /* camera reset */ ++ gpio_set_value(rst_gpio, 1); ++ ++ /* camera power dowmn */ ++ gpio_set_value(pwn_gpio, 1); ++ msleep(5); ++ ++ gpio_set_value(pwn_gpio, 0); ++ msleep(5); ++ ++ gpio_set_value(rst_gpio, 0); ++ msleep(1); ++ ++ gpio_set_value(rst_gpio, 1); ++ msleep(5); ++ ++ gpio_set_value(pwn_gpio, 1); ++} ++ ++static int ov5640_power_on(struct device *dev) ++{ ++ int ret = 0; ++ ++ io_regulator = devm_regulator_get(dev, "DOVDD"); ++ if (!IS_ERR(io_regulator)) { ++ regulator_set_voltage(io_regulator, ++ OV5640_VOLTAGE_DIGITAL_IO, ++ OV5640_VOLTAGE_DIGITAL_IO); ++ ret = regulator_enable(io_regulator); ++ if (ret) { ++ pr_err("%s:io set voltage error\n", __func__); ++ return ret; ++ } else { ++ dev_dbg(dev, ++ "%s:io set voltage ok\n", __func__); ++ } ++ } else { ++ pr_err("%s: cannot get io voltage error\n", __func__); ++ io_regulator = NULL; ++ } ++ ++ core_regulator = devm_regulator_get(dev, "DVDD"); ++ if (!IS_ERR(core_regulator)) { ++ regulator_set_voltage(core_regulator, ++ OV5640_VOLTAGE_DIGITAL_CORE, ++ OV5640_VOLTAGE_DIGITAL_CORE); ++ ret = regulator_enable(core_regulator); ++ if (ret) { ++ pr_err("%s:core set voltage error\n", __func__); ++ return ret; ++ } else { ++ dev_dbg(dev, ++ "%s:core set voltage ok\n", __func__); ++ } ++ } else { ++ core_regulator = NULL; ++ pr_err("%s: cannot get core voltage error\n", __func__); ++ } ++ ++ analog_regulator = devm_regulator_get(dev, "AVDD"); ++ if (!IS_ERR(analog_regulator)) { ++ regulator_set_voltage(analog_regulator, ++ OV5640_VOLTAGE_ANALOG, ++ OV5640_VOLTAGE_ANALOG); ++ ret = regulator_enable(analog_regulator); ++ if (ret) { ++ pr_err("%s:analog set voltage error\n", ++ __func__); ++ return ret; ++ } else { ++ dev_dbg(dev, ++ "%s:analog set voltage ok\n", __func__); ++ } ++ } else { ++ analog_regulator = NULL; ++ pr_err("%s: cannot get analog voltage error\n", __func__); ++ } ++ ++ return ret; ++} ++ ++static s32 ov5640_write_reg(u16 reg, u8 val) ++{ ++ u8 au8Buf[3] = {0}; ++ ++ au8Buf[0] = reg >> 8; ++ au8Buf[1] = reg & 0xff; ++ au8Buf[2] = val; ++ ++ if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) { ++ pr_err("%s:write reg error:reg=%x,val=%x\n", ++ __func__, reg, val); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static s32 ov5640_read_reg(u16 reg, u8 *val) ++{ ++ u8 au8RegBuf[2] = {0}; ++ u8 u8RdVal = 0; ++ ++ au8RegBuf[0] = reg >> 8; ++ au8RegBuf[1] = reg & 0xff; ++ ++ if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) { ++ pr_err("%s:write reg error:reg=%x\n", ++ __func__, reg); ++ return -1; ++ } ++ ++ if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) { ++ pr_err("%s:read reg error:reg=%x,val=%x\n", ++ __func__, reg, u8RdVal); ++ return -1; ++ } ++ ++ *val = u8RdVal; ++ ++ return u8RdVal; ++} ++ ++static int prev_sysclk, prev_HTS; ++static int AE_low, AE_high, AE_Target = 52; ++ ++void OV5640_stream_on(void) ++{ ++ ov5640_write_reg(0x4202, 0x00); ++} ++ ++void OV5640_stream_off(void) ++{ ++ ov5640_write_reg(0x4202, 0x0f); ++} ++ ++ ++int OV5640_get_sysclk(void) ++{ ++ /* calculate sysclk */ ++ int xvclk = ov5640_data.mclk / 10000; ++ int temp1, temp2; ++ int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv; ++ int Bit_div2x = 1, sclk_rdiv, sysclk; ++ u8 temp; ++ ++ int sclk_rdiv_map[] = {1, 2, 4, 8}; ++ ++ temp1 = ov5640_read_reg(0x3034, &temp); ++ temp2 = temp1 & 0x0f; ++ if (temp2 == 8 || temp2 == 10) ++ Bit_div2x = temp2 / 2; ++ ++ temp1 = ov5640_read_reg(0x3035, &temp); ++ SysDiv = temp1>>4; ++ if (SysDiv == 0) ++ SysDiv = 16; ++ ++ temp1 = ov5640_read_reg(0x3036, &temp); ++ Multiplier = temp1; ++ ++ temp1 = ov5640_read_reg(0x3037, &temp); ++ PreDiv = temp1 & 0x0f; ++ Pll_rdiv = ((temp1 >> 4) & 0x01) + 1; ++ ++ temp1 = ov5640_read_reg(0x3108, &temp); ++ temp2 = temp1 & 0x03; ++ sclk_rdiv = sclk_rdiv_map[temp2]; ++ ++ VCO = xvclk * Multiplier / PreDiv; ++ ++ sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv; ++ ++ return sysclk; ++} ++ ++void OV5640_set_night_mode(void) ++{ ++ /* read HTS from register settings */ ++ u8 mode; ++ ++ ov5640_read_reg(0x3a00, &mode); ++ mode &= 0xfb; ++ ov5640_write_reg(0x3a00, mode); ++} ++ ++int OV5640_get_HTS(void) ++{ ++ /* read HTS from register settings */ ++ int HTS; ++ u8 temp; ++ ++ HTS = ov5640_read_reg(0x380c, &temp); ++ HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp); ++ ++ return HTS; ++} ++ ++int OV5640_get_VTS(void) ++{ ++ /* read VTS from register settings */ ++ int VTS; ++ u8 temp; ++ ++ /* total vertical size[15:8] high byte */ ++ VTS = ov5640_read_reg(0x380e, &temp); ++ ++ VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp); ++ ++ return VTS; ++} ++ ++int OV5640_set_VTS(int VTS) ++{ ++ /* write VTS to registers */ ++ int temp; ++ ++ temp = VTS & 0xff; ++ ov5640_write_reg(0x380f, temp); ++ ++ temp = VTS>>8; ++ ov5640_write_reg(0x380e, temp); ++ ++ return 0; ++} ++ ++int OV5640_get_shutter(void) ++{ ++ /* read shutter, in number of line period */ ++ int shutter; ++ u8 temp; ++ ++ shutter = (ov5640_read_reg(0x03500, &temp) & 0x0f); ++ shutter = (shutter<<8) + ov5640_read_reg(0x3501, &temp); ++ shutter = (shutter<<4) + (ov5640_read_reg(0x3502, &temp)>>4); ++ ++ return shutter; ++} ++ ++int OV5640_set_shutter(int shutter) ++{ ++ /* write shutter, in number of line period */ ++ int temp; ++ ++ shutter = shutter & 0xffff; ++ ++ temp = shutter & 0x0f; ++ temp = temp<<4; ++ ov5640_write_reg(0x3502, temp); ++ ++ temp = shutter & 0xfff; ++ temp = temp>>4; ++ ov5640_write_reg(0x3501, temp); ++ ++ temp = shutter>>12; ++ ov5640_write_reg(0x3500, temp); ++ ++ return 0; ++} ++ ++int OV5640_get_gain16(void) ++{ ++ /* read gain, 16 = 1x */ ++ int gain16; ++ u8 temp; ++ ++ gain16 = ov5640_read_reg(0x350a, &temp) & 0x03; ++ gain16 = (gain16<<8) + ov5640_read_reg(0x350b, &temp); ++ ++ return gain16; ++} ++ ++int OV5640_set_gain16(int gain16) ++{ ++ /* write gain, 16 = 1x */ ++ u8 temp; ++ gain16 = gain16 & 0x3ff; ++ ++ temp = gain16 & 0xff; ++ ov5640_write_reg(0x350b, temp); ++ ++ temp = gain16>>8; ++ ov5640_write_reg(0x350a, temp); ++ ++ return 0; ++} ++ ++int OV5640_get_light_freq(void) ++{ ++ /* get banding filter value */ ++ int temp, temp1, light_freq = 0; ++ u8 tmp; ++ ++ temp = ov5640_read_reg(0x3c01, &tmp); ++ ++ if (temp & 0x80) { ++ /* manual */ ++ temp1 = ov5640_read_reg(0x3c00, &tmp); ++ if (temp1 & 0x04) { ++ /* 50Hz */ ++ light_freq = 50; ++ } else { ++ /* 60Hz */ ++ light_freq = 60; ++ } ++ } else { ++ /* auto */ ++ temp1 = ov5640_read_reg(0x3c0c, &tmp); ++ if (temp1 & 0x01) { ++ /* 50Hz */ ++ light_freq = 50; ++ } else { ++ /* 60Hz */ ++ } ++ } ++ return light_freq; ++} ++ ++void OV5640_set_bandingfilter(void) ++{ ++ int prev_VTS; ++ int band_step60, max_band60, band_step50, max_band50; ++ ++ /* read preview PCLK */ ++ prev_sysclk = OV5640_get_sysclk(); ++ /* read preview HTS */ ++ prev_HTS = OV5640_get_HTS(); ++ ++ /* read preview VTS */ ++ prev_VTS = OV5640_get_VTS(); ++ ++ /* calculate banding filter */ ++ /* 60Hz */ ++ band_step60 = prev_sysclk * 100/prev_HTS * 100/120; ++ ov5640_write_reg(0x3a0a, (band_step60 >> 8)); ++ ov5640_write_reg(0x3a0b, (band_step60 & 0xff)); ++ ++ max_band60 = (int)((prev_VTS-4)/band_step60); ++ ov5640_write_reg(0x3a0d, max_band60); ++ ++ /* 50Hz */ ++ band_step50 = prev_sysclk * 100/prev_HTS; ++ ov5640_write_reg(0x3a08, (band_step50 >> 8)); ++ ov5640_write_reg(0x3a09, (band_step50 & 0xff)); ++ ++ max_band50 = (int)((prev_VTS-4)/band_step50); ++ ov5640_write_reg(0x3a0e, max_band50); ++} ++ ++int OV5640_set_AE_target(int target) ++{ ++ /* stable in high */ ++ int fast_high, fast_low; ++ AE_low = target * 23 / 25; /* 0.92 */ ++ AE_high = target * 27 / 25; /* 1.08 */ ++ ++ fast_high = AE_high<<1; ++ if (fast_high > 255) ++ fast_high = 255; ++ ++ fast_low = AE_low >> 1; ++ ++ ov5640_write_reg(0x3a0f, AE_high); ++ ov5640_write_reg(0x3a10, AE_low); ++ ov5640_write_reg(0x3a1b, AE_high); ++ ov5640_write_reg(0x3a1e, AE_low); ++ ov5640_write_reg(0x3a11, fast_high); ++ ov5640_write_reg(0x3a1f, fast_low); ++ ++ return 0; ++} ++ ++void OV5640_turn_on_AE_AG(int enable) ++{ ++ u8 ae_ag_ctrl; ++ ++ ov5640_read_reg(0x3503, &ae_ag_ctrl); ++ if (enable) { ++ /* turn on auto AE/AG */ ++ ae_ag_ctrl = ae_ag_ctrl & ~(0x03); ++ } else { ++ /* turn off AE/AG */ ++ ae_ag_ctrl = ae_ag_ctrl | 0x03; ++ } ++ ov5640_write_reg(0x3503, ae_ag_ctrl); ++} ++ ++bool binning_on(void) ++{ ++ u8 temp; ++ ov5640_read_reg(0x3821, &temp); ++ temp &= 0xfe; ++ if (temp) ++ return true; ++ else ++ return false; ++} ++ ++static void ov5640_set_virtual_channel(int channel) ++{ ++ u8 channel_id; ++ ++ ov5640_read_reg(0x4814, &channel_id); ++ channel_id &= ~(3 << 6); ++ ov5640_write_reg(0x4814, channel_id | (channel << 6)); ++} ++ ++/* download ov5640 settings to sensor through i2c */ ++static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize) ++{ ++ register u32 Delay_ms = 0; ++ register u16 RegAddr = 0; ++ register u8 Mask = 0; ++ register u8 Val = 0; ++ u8 RegVal = 0; ++ int i, retval = 0; ++ ++ for (i = 0; i < ArySize; ++i, ++pModeSetting) { ++ Delay_ms = pModeSetting->u32Delay_ms; ++ RegAddr = pModeSetting->u16RegAddr; ++ Val = pModeSetting->u8Val; ++ Mask = pModeSetting->u8Mask; ++ ++ if (Mask) { ++ retval = ov5640_read_reg(RegAddr, &RegVal); ++ if (retval < 0) ++ goto err; ++ ++ RegVal &= ~(u8)Mask; ++ Val &= Mask; ++ Val |= RegVal; ++ } ++ ++ retval = ov5640_write_reg(RegAddr, Val); ++ if (retval < 0) ++ goto err; ++ ++ if (Delay_ms) ++ msleep(Delay_ms); ++ } ++err: ++ return retval; ++} ++ ++/* sensor changes between scaling and subsampling ++ * go through exposure calcualtion ++ */ ++static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate, ++ enum ov5640_mode mode) ++{ ++ struct reg_value *pModeSetting = NULL; ++ s32 ArySize = 0; ++ u8 average; ++ int prev_shutter, prev_gain16; ++ int cap_shutter, cap_gain16; ++ int cap_sysclk, cap_HTS, cap_VTS; ++ int light_freq, cap_bandfilt, cap_maxband; ++ long cap_gain16_shutter; ++ int retval = 0; ++ ++ /* check if the input mode and frame rate is valid */ ++ pModeSetting = ++ ov5640_mode_info_data[frame_rate][mode].init_data_ptr; ++ ArySize = ++ ov5640_mode_info_data[frame_rate][mode].init_data_size; ++ ++ ov5640_data.pix.width = ++ ov5640_mode_info_data[frame_rate][mode].width; ++ ov5640_data.pix.height = ++ ov5640_mode_info_data[frame_rate][mode].height; ++ ++ if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || ++ pModeSetting == NULL || ArySize == 0) ++ return -EINVAL; ++ ++ /* auto focus */ ++ /* OV5640_auto_focus();//if no af function, just skip it */ ++ ++ /* turn off AE/AG */ ++ OV5640_turn_on_AE_AG(0); ++ ++ /* read preview shutter */ ++ prev_shutter = OV5640_get_shutter(); ++ if ((binning_on()) && (mode != ov5640_mode_720P_1280_720) ++ && (mode != ov5640_mode_1080P_1920_1080)) ++ prev_shutter *= 2; ++ ++ /* read preview gain */ ++ prev_gain16 = OV5640_get_gain16(); ++ ++ /* get average */ ++ ov5640_read_reg(0x56a1, &average); ++ ++ /* turn off night mode for capture */ ++ OV5640_set_night_mode(); ++ ++ /* turn off overlay */ ++ /* ov5640_write_reg(0x3022, 0x06);//if no af function, just skip it */ ++ ++ OV5640_stream_off(); ++ ++ /* Write capture setting */ ++ retval = ov5640_download_firmware(pModeSetting, ArySize); ++ if (retval < 0) ++ goto err; ++ ++ /* read capture VTS */ ++ cap_VTS = OV5640_get_VTS(); ++ cap_HTS = OV5640_get_HTS(); ++ cap_sysclk = OV5640_get_sysclk(); ++ ++ /* calculate capture banding filter */ ++ light_freq = OV5640_get_light_freq(); ++ if (light_freq == 60) { ++ /* 60Hz */ ++ cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120; ++ } else { ++ /* 50Hz */ ++ cap_bandfilt = cap_sysclk * 100 / cap_HTS; ++ } ++ cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt); ++ ++ /* calculate capture shutter/gain16 */ ++ if (average > AE_low && average < AE_high) { ++ /* in stable range */ ++ cap_gain16_shutter = ++ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk ++ * prev_HTS/cap_HTS * AE_Target / average; ++ } else { ++ cap_gain16_shutter = ++ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk ++ * prev_HTS/cap_HTS; ++ } ++ ++ /* gain to shutter */ ++ if (cap_gain16_shutter < (cap_bandfilt * 16)) { ++ /* shutter < 1/100 */ ++ cap_shutter = cap_gain16_shutter/16; ++ if (cap_shutter < 1) ++ cap_shutter = 1; ++ ++ cap_gain16 = cap_gain16_shutter/cap_shutter; ++ if (cap_gain16 < 16) ++ cap_gain16 = 16; ++ } else { ++ if (cap_gain16_shutter > ++ (cap_bandfilt * cap_maxband * 16)) { ++ /* exposure reach max */ ++ cap_shutter = cap_bandfilt * cap_maxband; ++ cap_gain16 = cap_gain16_shutter / cap_shutter; ++ } else { ++ /* 1/100 < (cap_shutter = n/100) =< max */ ++ cap_shutter = ++ ((int) (cap_gain16_shutter/16 / cap_bandfilt)) ++ *cap_bandfilt; ++ cap_gain16 = cap_gain16_shutter / cap_shutter; ++ } ++ } ++ ++ /* write capture gain */ ++ OV5640_set_gain16(cap_gain16); ++ ++ /* write capture shutter */ ++ if (cap_shutter > (cap_VTS - 4)) { ++ cap_VTS = cap_shutter + 4; ++ OV5640_set_VTS(cap_VTS); ++ } ++ OV5640_set_shutter(cap_shutter); ++ ++ OV5640_stream_on(); ++ ++err: ++ return retval; ++} ++ ++/* if sensor changes inside scaling or subsampling ++ * change mode directly ++ * */ ++static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate, ++ enum ov5640_mode mode) ++{ ++ struct reg_value *pModeSetting = NULL; ++ s32 ArySize = 0; ++ int retval = 0; ++ ++ /* check if the input mode and frame rate is valid */ ++ pModeSetting = ++ ov5640_mode_info_data[frame_rate][mode].init_data_ptr; ++ ArySize = ++ ov5640_mode_info_data[frame_rate][mode].init_data_size; ++ ++ ov5640_data.pix.width = ++ ov5640_mode_info_data[frame_rate][mode].width; ++ ov5640_data.pix.height = ++ ov5640_mode_info_data[frame_rate][mode].height; ++ ++ if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || ++ pModeSetting == NULL || ArySize == 0) ++ return -EINVAL; ++ ++ /* turn off AE/AG */ ++ OV5640_turn_on_AE_AG(0); ++ ++ OV5640_stream_off(); ++ ++ /* Write capture setting */ ++ retval = ov5640_download_firmware(pModeSetting, ArySize); ++ if (retval < 0) ++ goto err; ++ ++ OV5640_stream_on(); ++ ++ OV5640_turn_on_AE_AG(1); ++ ++err: ++ return retval; ++} ++ ++static int ov5640_init_mode(enum ov5640_frame_rate frame_rate, ++ enum ov5640_mode mode, enum ov5640_mode orig_mode) ++{ ++ struct reg_value *pModeSetting = NULL; ++ s32 ArySize = 0; ++ int retval = 0; ++ void *mipi_csi2_info; ++ u32 mipi_reg, msec_wait4stable = 0; ++ enum ov5640_downsize_mode dn_mode, orig_dn_mode; ++ ++ if ((mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) ++ && (mode != ov5640_mode_INIT)) { ++ pr_err("Wrong ov5640 mode detected!\n"); ++ return -1; ++ } ++ ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ /* initial mipi dphy */ ++ if (!mipi_csi2_info) { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -1; ++ } ++ ++ if (!mipi_csi2_get_status(mipi_csi2_info)) ++ mipi_csi2_enable(mipi_csi2_info); ++ ++ if (!mipi_csi2_get_status(mipi_csi2_info)) { ++ pr_err("Can not enable mipi csi2 driver!\n"); ++ return -1; ++ } ++ ++ mipi_csi2_set_lanes(mipi_csi2_info); ++ ++ /*Only reset MIPI CSI2 HW at sensor initialize*/ ++ if (mode == ov5640_mode_INIT) ++ mipi_csi2_reset(mipi_csi2_info); ++ ++ if (ov5640_data.pix.pixelformat == V4L2_PIX_FMT_UYVY) ++ mipi_csi2_set_datatype(mipi_csi2_info, MIPI_DT_YUV422); ++ else if (ov5640_data.pix.pixelformat == V4L2_PIX_FMT_RGB565) ++ mipi_csi2_set_datatype(mipi_csi2_info, MIPI_DT_RGB565); ++ else ++ pr_err("currently this sensor format can not be supported!\n"); ++ ++ dn_mode = ov5640_mode_info_data[frame_rate][mode].dn_mode; ++ orig_dn_mode = ov5640_mode_info_data[frame_rate][orig_mode].dn_mode; ++ if (mode == ov5640_mode_INIT) { ++ pModeSetting = ov5640_init_setting_30fps_VGA; ++ ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA); ++ ++ ov5640_data.pix.width = 640; ++ ov5640_data.pix.height = 480; ++ retval = ov5640_download_firmware(pModeSetting, ArySize); ++ if (retval < 0) ++ goto err; ++ ++ pModeSetting = ov5640_setting_30fps_VGA_640_480; ++ ArySize = ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480); ++ retval = ov5640_download_firmware(pModeSetting, ArySize); ++ } else if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || ++ (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { ++ /* change between subsampling and scaling ++ * go through exposure calucation */ ++ retval = ov5640_change_mode_exposure_calc(frame_rate, mode); ++ } else { ++ /* change inside subsampling or scaling ++ * download firmware directly */ ++ retval = ov5640_change_mode_direct(frame_rate, mode); ++ } ++ ++ if (retval < 0) ++ goto err; ++ ++ OV5640_set_AE_target(AE_Target); ++ OV5640_get_light_freq(); ++ OV5640_set_bandingfilter(); ++ ov5640_set_virtual_channel(ov5640_data.csi); ++ ++ /* add delay to wait for sensor stable */ ++ if (mode == ov5640_mode_QSXGA_2592_1944) { ++ /* dump the first two frames: 1/7.5*2 ++ * the frame rate of QSXGA is 7.5fps */ ++ msec_wait4stable = 267; ++ } else if (frame_rate == ov5640_15_fps) { ++ /* dump the first nine frames: 1/15*9 */ ++ msec_wait4stable = 600; ++ } else if (frame_rate == ov5640_30_fps) { ++ /* dump the first nine frames: 1/30*9 */ ++ msec_wait4stable = 300; ++ } ++ msleep(msec_wait4stable); ++ ++ if (mipi_csi2_info) { ++ unsigned int i; ++ ++ i = 0; ++ ++ /* wait for mipi sensor ready */ ++ mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info); ++ while ((mipi_reg == 0x200) && (i < 10)) { ++ mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info); ++ i++; ++ msleep(10); ++ } ++ ++ if (i >= 10) { ++ pr_err("mipi csi2 can not receive sensor clk!\n"); ++ return -1; ++ } ++ ++ i = 0; ++ ++ /* wait for mipi stable */ ++ mipi_reg = mipi_csi2_get_error1(mipi_csi2_info); ++ while ((mipi_reg != 0x0) && (i < 10)) { ++ mipi_reg = mipi_csi2_get_error1(mipi_csi2_info); ++ i++; ++ msleep(10); ++ } ++ ++ if (i >= 10) { ++ pr_err("mipi csi2 can not reveive data correctly!\n"); ++ return -1; ++ } ++ } ++err: ++ return retval; ++} ++ ++/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */ ++ ++static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) ++{ ++ if (s == NULL) { ++ pr_err(" ERROR!! no slave device set!\n"); ++ return -1; ++ } ++ ++ memset(p, 0, sizeof(*p)); ++ p->u.bt656.clock_curr = ov5640_data.mclk; ++ pr_debug(" clock_curr=mclk=%d\n", ov5640_data.mclk); ++ p->if_type = V4L2_IF_TYPE_BT656; ++ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; ++ p->u.bt656.clock_min = OV5640_XCLK_MIN; ++ p->u.bt656.clock_max = OV5640_XCLK_MAX; ++ p->u.bt656.bt_sync_correct = 1; /* Indicate external vsync */ ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @on: indicates power mode (on or off) ++ * ++ * Turns the power on or off, depending on the value of on and returns the ++ * appropriate error code. ++ */ ++static int ioctl_s_power(struct v4l2_int_device *s, int on) ++{ ++ struct sensor_data *sensor = s->priv; ++ ++ if (on && !sensor->on) { ++ if (io_regulator) ++ if (regulator_enable(io_regulator) != 0) ++ return -EIO; ++ if (core_regulator) ++ if (regulator_enable(core_regulator) != 0) ++ return -EIO; ++ if (gpo_regulator) ++ if (regulator_enable(gpo_regulator) != 0) ++ return -EIO; ++ if (analog_regulator) ++ if (regulator_enable(analog_regulator) != 0) ++ return -EIO; ++ /* Make sure power on */ ++ ov5640_standby(0); ++ } else if (!on && sensor->on) { ++ if (analog_regulator) ++ regulator_disable(analog_regulator); ++ if (core_regulator) ++ regulator_disable(core_regulator); ++ if (io_regulator) ++ regulator_disable(io_regulator); ++ if (gpo_regulator) ++ regulator_disable(gpo_regulator); ++ ++ ov5640_standby(1); ++ } ++ ++ sensor->on = on; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure ++ * ++ * Returns the sensor's video CAPTURE parameters. ++ */ ++static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) ++{ ++ struct sensor_data *sensor = s->priv; ++ struct v4l2_captureparm *cparm = &a->parm.capture; ++ int ret = 0; ++ ++ switch (a->type) { ++ /* This is the only case currently handled. */ ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ memset(a, 0, sizeof(*a)); ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ cparm->capability = sensor->streamcap.capability; ++ cparm->timeperframe = sensor->streamcap.timeperframe; ++ cparm->capturemode = sensor->streamcap.capturemode; ++ ret = 0; ++ break; ++ ++ /* These are all the possible cases. */ ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ case V4L2_BUF_TYPE_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_VBI_OUTPUT: ++ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: ++ ret = -EINVAL; ++ break; ++ ++ default: ++ pr_debug(" type is unknown - %d\n", a->type); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure ++ * ++ * Configures the sensor to use the input parameters, if possible. If ++ * not possible, reverts to the old parameters and returns the ++ * appropriate error code. ++ */ ++static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) ++{ ++ struct sensor_data *sensor = s->priv; ++ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; ++ u32 tgt_fps; /* target frames per secound */ ++ enum ov5640_frame_rate frame_rate; ++ enum ov5640_mode orig_mode; ++ int ret = 0; ++ ++ /* Make sure power on */ ++ ov5640_standby(0); ++ ++ switch (a->type) { ++ /* This is the only case currently handled. */ ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ /* Check that the new frame rate is allowed. */ ++ if ((timeperframe->numerator == 0) || ++ (timeperframe->denominator == 0)) { ++ timeperframe->denominator = DEFAULT_FPS; ++ timeperframe->numerator = 1; ++ } ++ ++ tgt_fps = timeperframe->denominator / ++ timeperframe->numerator; ++ ++ if (tgt_fps > MAX_FPS) { ++ timeperframe->denominator = MAX_FPS; ++ timeperframe->numerator = 1; ++ } else if (tgt_fps < MIN_FPS) { ++ timeperframe->denominator = MIN_FPS; ++ timeperframe->numerator = 1; ++ } ++ ++ /* Actual frame rate we use */ ++ tgt_fps = timeperframe->denominator / ++ timeperframe->numerator; ++ ++ if (tgt_fps == 15) ++ frame_rate = ov5640_15_fps; ++ else if (tgt_fps == 30) ++ frame_rate = ov5640_30_fps; ++ else { ++ pr_err(" The camera frame rate is not supported!\n"); ++ return -EINVAL; ++ } ++ ++ orig_mode = sensor->streamcap.capturemode; ++ ret = ov5640_init_mode(frame_rate, ++ (u32)a->parm.capture.capturemode, orig_mode); ++ if (ret < 0) ++ return ret; ++ ++ sensor->streamcap.timeperframe = *timeperframe; ++ sensor->streamcap.capturemode = ++ (u32)a->parm.capture.capturemode; ++ ++ break; ++ ++ /* These are all the possible cases. */ ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ case V4L2_BUF_TYPE_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_VBI_OUTPUT: ++ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: ++ pr_debug(" type is not " \ ++ "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n", ++ a->type); ++ ret = -EINVAL; ++ break; ++ ++ default: ++ pr_debug(" type is unknown - %d\n", a->type); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap ++ * @s: pointer to standard V4L2 device structure ++ * @f: pointer to standard V4L2 v4l2_format structure ++ * ++ * Returns the sensor's current pixel format in the v4l2_format ++ * parameter. ++ */ ++static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) ++{ ++ struct sensor_data *sensor = s->priv; ++ ++ f->fmt.pix = sensor->pix; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure ++ * ++ * If the requested control is supported, returns the control's current ++ * value from the video_control[] array. Otherwise, returns -EINVAL ++ * if the control is not supported. ++ */ ++static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) ++{ ++ int ret = 0; ++ ++ switch (vc->id) { ++ case V4L2_CID_BRIGHTNESS: ++ vc->value = ov5640_data.brightness; ++ break; ++ case V4L2_CID_HUE: ++ vc->value = ov5640_data.hue; ++ break; ++ case V4L2_CID_CONTRAST: ++ vc->value = ov5640_data.contrast; ++ break; ++ case V4L2_CID_SATURATION: ++ vc->value = ov5640_data.saturation; ++ break; ++ case V4L2_CID_RED_BALANCE: ++ vc->value = ov5640_data.red; ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ vc->value = ov5640_data.blue; ++ break; ++ case V4L2_CID_EXPOSURE: ++ vc->value = ov5640_data.ae_mode; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure ++ * ++ * If the requested control is supported, sets the control's current ++ * value in HW (and updates the video_control[] array). Otherwise, ++ * returns -EINVAL if the control is not supported. ++ */ ++static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) ++{ ++ int retval = 0; ++ ++ pr_debug("In ov5640:ioctl_s_ctrl %d\n", ++ vc->id); ++ ++ switch (vc->id) { ++ case V4L2_CID_BRIGHTNESS: ++ break; ++ case V4L2_CID_CONTRAST: ++ break; ++ case V4L2_CID_SATURATION: ++ break; ++ case V4L2_CID_HUE: ++ break; ++ case V4L2_CID_AUTO_WHITE_BALANCE: ++ break; ++ case V4L2_CID_DO_WHITE_BALANCE: ++ break; ++ case V4L2_CID_RED_BALANCE: ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ break; ++ case V4L2_CID_GAMMA: ++ break; ++ case V4L2_CID_EXPOSURE: ++ break; ++ case V4L2_CID_AUTOGAIN: ++ break; ++ case V4L2_CID_GAIN: ++ break; ++ case V4L2_CID_HFLIP: ++ break; ++ case V4L2_CID_VFLIP: ++ break; ++ default: ++ retval = -EPERM; ++ break; ++ } ++ ++ return retval; ++} ++ ++/*! ++ * ioctl_enum_framesizes - V4L2 sensor interface handler for ++ * VIDIOC_ENUM_FRAMESIZES ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure ++ * ++ * Return 0 if successful, otherwise -EINVAL. ++ */ ++static int ioctl_enum_framesizes(struct v4l2_int_device *s, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ if (fsize->index > ov5640_mode_MAX) ++ return -EINVAL; ++ ++ fsize->pixel_format = ov5640_data.pix.pixelformat; ++ fsize->discrete.width = ++ max(ov5640_mode_info_data[0][fsize->index].width, ++ ov5640_mode_info_data[1][fsize->index].width); ++ fsize->discrete.height = ++ max(ov5640_mode_info_data[0][fsize->index].height, ++ ov5640_mode_info_data[1][fsize->index].height); ++ return 0; ++} ++ ++/*! ++ * ioctl_g_chip_ident - V4L2 sensor interface handler for ++ * VIDIOC_DBG_G_CHIP_IDENT ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @id: pointer to int ++ * ++ * Return 0. ++ */ ++static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id) ++{ ++ ((struct v4l2_dbg_chip_ident *)id)->match.type = ++ V4L2_CHIP_MATCH_I2C_DRIVER; ++ strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, ++ "ov5640_mipi_camera"); ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT ++ * @s: pointer to standard V4L2 device structure ++ */ ++static int ioctl_init(struct v4l2_int_device *s) ++{ ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT ++ * @s: pointer to standard V4L2 device structure ++ * @fmt: pointer to standard V4L2 fmt description structure ++ * ++ * Return 0. ++ */ ++static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, ++ struct v4l2_fmtdesc *fmt) ++{ ++ if (fmt->index > ov5640_mode_MAX) ++ return -EINVAL; ++ ++ fmt->pixelformat = ov5640_data.pix.pixelformat; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num ++ * @s: pointer to standard V4L2 device structure ++ * ++ * Initialise the device when slave attaches to the master. ++ */ ++static int ioctl_dev_init(struct v4l2_int_device *s) ++{ ++ struct sensor_data *sensor = s->priv; ++ u32 tgt_xclk; /* target xclk */ ++ u32 tgt_fps; /* target frames per secound */ ++ int ret; ++ enum ov5640_frame_rate frame_rate; ++ void *mipi_csi2_info; ++ ++ ov5640_data.on = true; ++ ++ /* mclk */ ++ tgt_xclk = ov5640_data.mclk; ++ tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX); ++ tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN); ++ ov5640_data.mclk = tgt_xclk; ++ ++ pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); ++ ++ /* Default camera frame rate is set in probe */ ++ tgt_fps = sensor->streamcap.timeperframe.denominator / ++ sensor->streamcap.timeperframe.numerator; ++ ++ if (tgt_fps == 15) ++ frame_rate = ov5640_15_fps; ++ else if (tgt_fps == 30) ++ frame_rate = ov5640_30_fps; ++ else ++ return -EINVAL; /* Only support 15fps or 30fps now. */ ++ ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ /* enable mipi csi2 */ ++ if (mipi_csi2_info) ++ mipi_csi2_enable(mipi_csi2_info); ++ else { ++ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", ++ __func__, __FILE__); ++ return -EPERM; ++ } ++ ++ ret = ov5640_init_mode(frame_rate, ov5640_mode_INIT, ov5640_mode_INIT); ++ ++ return ret; ++} ++ ++/*! ++ * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num ++ * @s: pointer to standard V4L2 device structure ++ * ++ * Delinitialise the device when slave detaches to the master. ++ */ ++static int ioctl_dev_exit(struct v4l2_int_device *s) ++{ ++ void *mipi_csi2_info; ++ ++ mipi_csi2_info = mipi_csi2_get_info(); ++ ++ /* disable mipi csi2 */ ++ if (mipi_csi2_info) ++ if (mipi_csi2_get_status(mipi_csi2_info)) ++ mipi_csi2_disable(mipi_csi2_info); ++ ++ return 0; ++} ++ ++/*! ++ * This structure defines all the ioctls for this module and links them to the ++ * enumeration. ++ */ ++static struct v4l2_int_ioctl_desc ov5640_ioctl_desc[] = { ++ {vidioc_int_dev_init_num, (v4l2_int_ioctl_func *) ioctl_dev_init}, ++ {vidioc_int_dev_exit_num, ioctl_dev_exit}, ++ {vidioc_int_s_power_num, (v4l2_int_ioctl_func *) ioctl_s_power}, ++ {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func *) ioctl_g_ifparm}, ++/* {vidioc_int_g_needs_reset_num, ++ (v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */ ++/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */ ++ {vidioc_int_init_num, (v4l2_int_ioctl_func *) ioctl_init}, ++ {vidioc_int_enum_fmt_cap_num, ++ (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap}, ++/* {vidioc_int_try_fmt_cap_num, ++ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */ ++ {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_g_fmt_cap}, ++/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_s_fmt_cap}, */ ++ {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm}, ++ {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm}, ++/* {vidioc_int_queryctrl_num, (v4l2_int_ioctl_func *)ioctl_queryctrl}, */ ++ {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *) ioctl_g_ctrl}, ++ {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl}, ++ {vidioc_int_enum_framesizes_num, ++ (v4l2_int_ioctl_func *) ioctl_enum_framesizes}, ++ {vidioc_int_g_chip_ident_num, ++ (v4l2_int_ioctl_func *) ioctl_g_chip_ident}, ++}; ++ ++static struct v4l2_int_slave ov5640_slave = { ++ .ioctls = ov5640_ioctl_desc, ++ .num_ioctls = ARRAY_SIZE(ov5640_ioctl_desc), ++}; ++ ++static struct v4l2_int_device ov5640_int_device = { ++ .module = THIS_MODULE, ++ .name = "ov5640", ++ .type = v4l2_int_type_slave, ++ .u = { ++ .slave = &ov5640_slave, ++ }, ++}; ++ ++/*! ++ * ov5640 I2C probe function ++ * ++ * @param adapter struct i2c_adapter * ++ * @return Error code indicating success or failure ++ */ ++static int ov5640_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ int retval; ++ u8 chip_id_high, chip_id_low; ++ ++ /* request power down pin */ ++ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); ++ if (!gpio_is_valid(pwn_gpio)) { ++ dev_warn(dev, "no sensor pwdn pin available"); ++ return -EINVAL; ++ } ++ retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, ++ "ov5640_mipi_pwdn"); ++ if (retval < 0) ++ return retval; ++ ++ /* request reset pin */ ++ rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0); ++ if (!gpio_is_valid(rst_gpio)) { ++ dev_warn(dev, "no sensor reset pin available"); ++ return -EINVAL; ++ } ++ retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH, ++ "ov5640_mipi_reset"); ++ if (retval < 0) ++ return retval; ++ ++ /* Set initial values for the sensor struct. */ ++ memset(&ov5640_data, 0, sizeof(ov5640_data)); ++ ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk"); ++ if (IS_ERR(ov5640_data.sensor_clk)) { ++ /* assuming clock enabled by default */ ++ ov5640_data.sensor_clk = NULL; ++ dev_err(dev, "clock-frequency missing or invalid\n"); ++ return PTR_ERR(ov5640_data.sensor_clk); ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "mclk", ++ &(ov5640_data.mclk)); ++ if (retval) { ++ dev_err(dev, "mclk missing or invalid\n"); ++ return retval; ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "mclk_source", ++ (u32 *) &(ov5640_data.mclk_source)); ++ if (retval) { ++ dev_err(dev, "mclk_source missing or invalid\n"); ++ return retval; ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "csi_id", ++ &(ov5640_data.csi)); ++ if (retval) { ++ dev_err(dev, "csi id missing or invalid\n"); ++ return retval; ++ } ++ ++ clk_prepare_enable(ov5640_data.sensor_clk); ++ ++ ov5640_data.io_init = ov5640_reset; ++ ov5640_data.i2c_client = client; ++ ov5640_data.pix.pixelformat = V4L2_PIX_FMT_UYVY; ++ ov5640_data.pix.width = 640; ++ ov5640_data.pix.height = 480; ++ ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY | ++ V4L2_CAP_TIMEPERFRAME; ++ ov5640_data.streamcap.capturemode = 0; ++ ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS; ++ ov5640_data.streamcap.timeperframe.numerator = 1; ++ ++ ov5640_power_on(dev); ++ ++ ov5640_reset(); ++ ++ ov5640_standby(0); ++ ++ retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high); ++ if (retval < 0 || chip_id_high != 0x56) { ++ pr_warning("camera ov5640_mipi is not found\n"); ++ clk_disable_unprepare(ov5640_data.sensor_clk); ++ return -ENODEV; ++ } ++ retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low); ++ if (retval < 0 || chip_id_low != 0x40) { ++ pr_warning("camera ov5640_mipi is not found\n"); ++ clk_disable_unprepare(ov5640_data.sensor_clk); ++ return -ENODEV; ++ } ++ ++ ov5640_standby(1); ++ ++ ov5640_int_device.priv = &ov5640_data; ++ retval = v4l2_int_device_register(&ov5640_int_device); ++ ++ clk_disable_unprepare(ov5640_data.sensor_clk); ++ ++ pr_info("camera ov5640_mipi is found\n"); ++ return retval; ++} ++ ++/*! ++ * ov5640 I2C detach function ++ * ++ * @param client struct i2c_client * ++ * @return Error code indicating success or failure ++ */ ++static int ov5640_remove(struct i2c_client *client) ++{ ++ v4l2_int_device_unregister(&ov5640_int_device); ++ ++ if (gpo_regulator) ++ regulator_disable(gpo_regulator); ++ ++ if (analog_regulator) ++ regulator_disable(analog_regulator); ++ ++ if (core_regulator) ++ regulator_disable(core_regulator); ++ ++ if (io_regulator) ++ regulator_disable(io_regulator); ++ ++ return 0; ++} ++ ++/*! ++ * ov5640 init function ++ * Called by insmod ov5640_camera.ko. ++ * ++ * @return Error code indicating success or failure ++ */ ++static __init int ov5640_init(void) ++{ ++ u8 err; ++ ++ err = i2c_add_driver(&ov5640_i2c_driver); ++ if (err != 0) ++ pr_err("%s:driver registration failed, error=%d\n", ++ __func__, err); ++ ++ return err; ++} ++ ++/*! ++ * OV5640 cleanup function ++ * Called on rmmod ov5640_camera.ko ++ * ++ * @return Error code indicating success or failure ++ */ ++static void __exit ov5640_clean(void) ++{ ++ i2c_del_driver(&ov5640_i2c_driver); ++} ++ ++module_init(ov5640_init); ++module_exit(ov5640_clean); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("OV5640 MIPI Camera Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("1.0"); ++MODULE_ALIAS("CSI"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/capture/ov5642.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ov5642.c +--- linux-3.10.30/drivers/media/platform/mxc/capture/ov5642.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/capture/ov5642.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,4252 @@ ++/* ++ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * 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., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mxc_v4l2_capture.h" ++ ++#define OV5642_VOLTAGE_ANALOG 2800000 ++#define OV5642_VOLTAGE_DIGITAL_CORE 1500000 ++#define OV5642_VOLTAGE_DIGITAL_IO 1800000 ++ ++#define MIN_FPS 15 ++#define MAX_FPS 30 ++#define DEFAULT_FPS 30 ++ ++#define OV5642_XCLK_MIN 6000000 ++#define OV5642_XCLK_MAX 24000000 ++ ++#define OV5642_CHIP_ID_HIGH_BYTE 0x300A ++#define OV5642_CHIP_ID_LOW_BYTE 0x300B ++ ++enum ov5642_mode { ++ ov5642_mode_MIN = 0, ++ ov5642_mode_VGA_640_480 = 0, ++ ov5642_mode_QVGA_320_240 = 1, ++ ov5642_mode_NTSC_720_480 = 2, ++ ov5642_mode_PAL_720_576 = 3, ++ ov5642_mode_720P_1280_720 = 4, ++ ov5642_mode_1080P_1920_1080 = 5, ++ ov5642_mode_QSXGA_2592_1944 = 6, ++ ov5642_mode_QCIF_176_144 = 7, ++ ov5642_mode_XGA_1024_768 = 8, ++ ov5642_mode_MAX = 8 ++}; ++ ++enum ov5642_frame_rate { ++ ov5642_15_fps, ++ ov5642_30_fps ++}; ++ ++static int ov5642_framerates[] = { ++ [ov5642_15_fps] = 15, ++ [ov5642_30_fps] = 30, ++}; ++ ++struct reg_value { ++ u16 u16RegAddr; ++ u8 u8Val; ++ u8 u8Mask; ++ u32 u32Delay_ms; ++}; ++ ++struct ov5642_mode_info { ++ enum ov5642_mode mode; ++ u32 width; ++ u32 height; ++ struct reg_value *init_data_ptr; ++ u32 init_data_size; ++}; ++ ++/*! ++ * Maintains the information on the current state of the sesor. ++ */ ++static struct sensor_data ov5642_data; ++static int pwn_gpio, rst_gpio; ++ ++static struct reg_value ov5642_rot_none_VGA[] = { ++ {0x3818, 0xc1, 0x00, 0x00}, {0x3621, 0x87, 0x00, 0x00}, ++}; ++ ++static struct reg_value ov5642_rot_vert_flip_VGA[] = { ++ {0x3818, 0x20, 0xbf, 0x00}, {0x3621, 0x20, 0xff, 0x00}, ++}; ++ ++static struct reg_value ov5642_rot_horiz_flip_VGA[] = { ++ {0x3818, 0x81, 0x00, 0x01}, {0x3621, 0xa7, 0x00, 0x00}, ++}; ++ ++static struct reg_value ov5642_rot_180_VGA[] = { ++ {0x3818, 0x60, 0xff, 0x00}, {0x3621, 0x00, 0xdf, 0x00}, ++}; ++ ++ ++static struct reg_value ov5642_rot_none_FULL[] = { ++ {0x3818, 0xc0, 0x00, 0x00}, {0x3621, 0x09, 0x00, 0x00}, ++}; ++ ++static struct reg_value ov5642_rot_vert_flip_FULL[] = { ++ {0x3818, 0x20, 0xbf, 0x01}, {0x3621, 0x20, 0xff, 0x00}, ++}; ++ ++static struct reg_value ov5642_rot_horiz_flip_FULL[] = { ++ {0x3818, 0x80, 0x00, 0x01}, {0x3621, 0x29, 0x00, 0x00}, ++}; ++ ++static struct reg_value ov5642_rot_180_FULL[] = { ++ {0x3818, 0x60, 0xff, 0x00}, {0x3621, 0x00, 0xdf, 0x00}, ++}; ++ ++ ++static struct reg_value ov5642_initial_setting[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, ++ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, ++ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, ++ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0}, ++ {0x3010, 0x00, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c00, 0x04, 0, 0}, {0x3c01, 0x80, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, ++ {0x5182, 0x00, 0, 0}, {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, ++ {0x5001, 0xff, 0, 0}, {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, ++ {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, ++ {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, ++ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, ++ {0x380b, 0xe0, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, ++ {0x501f, 0x00, 0, 0}, {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, ++ {0x350b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, ++ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, ++ {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, ++ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, ++ {0x3801, 0x80, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, ++ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, ++ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, ++ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, ++ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, ++ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, ++ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, ++ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, ++ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, ++ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, ++ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, ++ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, ++ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, ++ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, ++ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, ++ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, ++ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, ++ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x0b, 0, 0}, {0x3a02, 0x00, 0, 0}, ++ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, ++ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, ++ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, ++ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, ++ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, ++ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, ++ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, ++ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, ++ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, ++ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, ++ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, ++ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, ++ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, ++ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, ++ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, ++ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, ++ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, ++ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, ++ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, ++ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, ++ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, ++ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, ++ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, ++ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, ++ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, ++ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, ++ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, ++ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, ++ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, ++ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, ++ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, ++ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, ++ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, ++ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, ++ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, ++ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, ++ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, ++ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, ++ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, ++ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, ++ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, ++ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, ++ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, ++ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, ++ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, ++ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, ++ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, ++ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, ++ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, ++ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, ++ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, ++ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, ++ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, ++ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, ++ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, ++ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, ++ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, ++ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, ++ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, ++ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, ++ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, ++ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, ++ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, ++ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, ++ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, ++ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, ++ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, ++ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, ++ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, ++ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, ++ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, ++ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, ++ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, ++ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, ++ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, ++ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, ++ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, ++ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, ++ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, ++ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, ++ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, ++ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, ++ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, ++ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, ++ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, ++ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, ++ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, ++ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, ++ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, ++ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, ++ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, ++ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, ++ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, ++ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, ++ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, ++ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, ++ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, ++ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, ++ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, ++ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, ++ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, ++ {0x302b, 0x00, 0, 300}, ++}; ++ ++static struct reg_value ov5642_setting_15fps_QCIF_176_144[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, ++ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, ++ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, ++ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0}, ++ {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0}, ++ {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0}, ++ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0}, ++ {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0}, ++ {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, ++ {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0}, ++ {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, ++ {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, ++ {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0}, ++ {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, ++ {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0}, ++ {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0}, ++ {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0}, ++ {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0}, ++ {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0}, ++ {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0}, ++ {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0}, ++ {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0}, ++ {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0}, ++ {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0}, ++ {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0}, ++ {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0}, ++ {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0}, ++ {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0}, ++ {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0}, ++ {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0}, ++ {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0}, ++ {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0}, ++ {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0}, ++ {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0}, ++ {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0}, ++ {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0}, ++ {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0}, ++ {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0}, ++ {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0}, ++ {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0}, ++ {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0}, ++ {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0}, ++ {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0}, ++ {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0}, ++ {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0}, ++ {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0}, ++ {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0}, ++ {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0}, ++ {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0}, ++ {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0}, ++ {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0}, ++ {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0}, ++ {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0}, ++ {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0}, ++ {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0}, ++ {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0}, ++ {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0}, ++ {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0}, ++ {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0}, ++ {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0}, ++ {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0}, ++ {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0}, ++ {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0}, ++ {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0}, ++ {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0}, ++ {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0}, ++ {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0}, ++ {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, ++ {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0}, ++ {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0}, ++ {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0}, ++ {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, ++ {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, ++ {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, ++ {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0}, ++ {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0}, ++ {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0}, ++ {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0}, ++ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0}, ++ {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0}, ++ {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0}, ++ {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0}, ++ {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0}, ++ {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0}, ++ {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0}, ++ {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0}, ++ {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0}, ++ {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0}, ++ {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0}, ++ {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0}, ++ {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0}, ++ {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0}, ++ {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0}, ++ {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0}, ++ {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0}, ++ {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0}, ++ {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0}, ++ {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0}, ++ {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0}, ++ {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0}, ++ {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0}, ++ {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0}, ++ {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0}, ++ {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0}, ++ {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0}, ++ {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0}, ++ {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0}, ++ {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0}, ++ {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0}, ++ {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0}, ++ {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0}, ++ {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0}, ++ {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0}, ++ {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0}, ++ {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0}, ++ {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0}, ++ {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0}, ++ {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0}, ++ {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0}, ++ {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0}, ++ {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0}, ++ {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0}, ++ {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0}, ++ {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0}, ++ {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0}, ++ {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0}, ++ {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0}, ++ {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0}, ++ {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0}, ++ {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0}, ++ {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0}, ++ {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0}, ++ {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0}, ++ {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0}, ++ {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0}, ++ {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0}, ++ {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0}, ++ {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0}, ++ {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, ++ {0x380b, 0x90, 0, 0}, {0x3a00, 0x78, 0, 0}, ++}; ++ ++static struct reg_value ov5642_setting_30fps_QCIF_176_144[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, ++ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, ++ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, ++ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x10, 0, 0}, ++ {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0}, ++ {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0}, ++ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0}, ++ {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0}, ++ {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, ++ {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0}, ++ {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, ++ {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, ++ {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0}, ++ {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, ++ {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0}, ++ {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0}, ++ {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0}, ++ {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0}, ++ {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0}, ++ {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0}, ++ {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0}, ++ {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0}, ++ {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0}, ++ {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0}, ++ {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0}, ++ {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0}, ++ {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0}, ++ {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0}, ++ {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0}, ++ {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0}, ++ {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0}, ++ {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0}, ++ {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0}, ++ {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0}, ++ {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0}, ++ {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0}, ++ {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0}, ++ {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0}, ++ {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0}, ++ {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0}, ++ {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0}, ++ {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0}, ++ {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0}, ++ {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0}, ++ {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0}, ++ {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0}, ++ {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0}, ++ {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0}, ++ {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0}, ++ {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0}, ++ {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0}, ++ {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0}, ++ {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0}, ++ {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0}, ++ {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0}, ++ {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0}, ++ {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0}, ++ {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0}, ++ {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0}, ++ {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0}, ++ {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0}, ++ {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0}, ++ {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0}, ++ {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0}, ++ {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0}, ++ {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0}, ++ {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0}, ++ {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, ++ {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0}, ++ {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0}, ++ {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0}, ++ {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, ++ {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, ++ {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, ++ {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0}, ++ {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0}, ++ {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0}, ++ {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0}, ++ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0}, ++ {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0}, ++ {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0}, ++ {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0}, ++ {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0}, ++ {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0}, ++ {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0}, ++ {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0}, ++ {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0}, ++ {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0}, ++ {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0}, ++ {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0}, ++ {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0}, ++ {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0}, ++ {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0}, ++ {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0}, ++ {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0}, ++ {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0}, ++ {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0}, ++ {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0}, ++ {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0}, ++ {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0}, ++ {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0}, ++ {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0}, ++ {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0}, ++ {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0}, ++ {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0}, ++ {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0}, ++ {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0}, ++ {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0}, ++ {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0}, ++ {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0}, ++ {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0}, ++ {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0}, ++ {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0}, ++ {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0}, ++ {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0}, ++ {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0}, ++ {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0}, ++ {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0}, ++ {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0}, ++ {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0}, ++ {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0}, ++ {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0}, ++ {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0}, ++ {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0}, ++ {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0}, ++ {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0}, ++ {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0}, ++ {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0}, ++ {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0}, ++ {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0}, ++ {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0}, ++ {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0}, ++ {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0}, ++ {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0}, ++ {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0}, ++ {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0}, ++ {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0}, ++ {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0}, ++ {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, ++ {0x380b, 0x90, 0, 0}, {0x3a00, 0x78, 0, 0}, ++}; ++ ++static struct reg_value ov5642_setting_15fps_QSXGA_2592_1944[] = { ++ {0x3503, 0x07, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, ++ {0x3002, 0x00, 0, 0}, {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, ++ {0x3005, 0xff, 0, 0}, {0x3006, 0xff, 0, 0}, {0x3007, 0x3f, 0, 0}, ++ {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3818, 0xc0, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, ++ {0x3602, 0xe4, 0, 0}, {0x3612, 0xac, 0, 0}, {0x3613, 0x44, 0, 0}, ++ {0x3622, 0x60, 0, 0}, {0x3623, 0x22, 0, 0}, {0x3604, 0x48, 0, 0}, ++ {0x3705, 0xda, 0, 0}, {0x370a, 0x80, 0, 0}, {0x3801, 0x95, 0, 0}, ++ {0x3803, 0x0e, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x20, 0, 0}, ++ {0x3806, 0x07, 0, 0}, {0x3807, 0x98, 0, 0}, {0x3808, 0x0a, 0, 0}, ++ {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, ++ {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0}, ++ {0x380f, 0xd0, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3815, 0x44, 0, 0}, ++ {0x3824, 0x11, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0}, ++ {0x3a00, 0x78, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0}, ++ {0x5682, 0x0a, 0, 0}, {0x5683, 0x20, 0, 0}, {0x5686, 0x07, 0, 0}, ++ {0x5687, 0x98, 0, 0}, {0x5001, 0xff, 0, 0}, {0x589b, 0x00, 0, 0}, ++ {0x589a, 0xc0, 0, 0}, {0x4407, 0x04, 0, 0}, {0x3008, 0x02, 0, 0}, ++ {0x460b, 0x37, 0, 0}, {0x460c, 0x22, 0, 0}, {0x471d, 0x05, 0, 0}, ++ {0x4713, 0x03, 0, 0}, {0x471c, 0xd0, 0, 0}, {0x3815, 0x01, 0, 0}, ++ {0x501f, 0x00, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3819, 0x80, 0, 0}, ++ {0x5002, 0xe0, 0, 0}, {0x530a, 0x01, 0, 0}, {0x530d, 0x10, 0, 0}, ++ {0x530c, 0x04, 0, 0}, {0x5312, 0x20, 0, 0}, {0x5282, 0x01, 0, 0}, ++ {0x3010, 0x10, 0, 0}, {0x3012, 0x00, 0, 0}, ++}; ++ ++ ++static struct reg_value ov5642_setting_VGA_2_QVGA[] = { ++ {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, ++ {0x380b, 0xf0, 0, 0}, {0x3815, 0x04, 0, 0}, ++}; ++ ++static struct reg_value ov5642_setting_QSXGA_2_VGA[] = { ++ {0x3503, 0x00, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, ++ {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, ++ {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, ++ {0x3010, 0x00, 0, 0}, {0x3818, 0xc1, 0, 0}, {0x3621, 0x87, 0, 0}, ++ {0x350c, 0x03, 0, 0}, {0x350d, 0xe8, 0, 0}, {0x3602, 0xfc, 0, 0}, ++ {0x3612, 0xff, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3622, 0x60, 0, 0}, ++ {0x3623, 0x01, 0, 0}, {0x3604, 0x48, 0, 0}, {0x3705, 0xdb, 0, 0}, ++ {0x370a, 0x81, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, ++ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, ++ {0x3807, 0xc0, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, ++ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x0c, 0, 0}, ++ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, ++ {0x3810, 0x40, 0, 0}, {0x3815, 0x04, 0, 0}, {0x3824, 0x11, 0, 0}, ++ {0x3825, 0xb4, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x5682, 0x05, 0, 0}, ++ {0x5683, 0x00, 0, 0}, {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, ++ {0x5001, 0xff, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, ++ {0x4407, 0x0c, 0, 0}, {0x3008, 0x02, 0, 0}, {0x460b, 0x37, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x471d, 0x05, 0, 0}, {0x4713, 0x02, 0, 0}, ++ {0x471c, 0xd0, 0, 0}, {0x3815, 0x04, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x3002, 0x5c, 0, 0}, {0x3819, 0x80, 0, 0}, {0x5002, 0xe0, 0, 0}, ++ {0x530a, 0x01, 0, 0}, {0x530d, 0x0c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x5312, 0x40, 0, 0}, {0x5282, 0x00, 0, 0}, ++ {0x3012, 0x02, 0, 0}, {0x3010, 0x00, 0, 0}, ++}; ++ ++static struct reg_value ov5642_setting_30fps_VGA_640_480[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, ++ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, ++ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, ++ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, ++ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, ++ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, ++ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0}, ++ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, ++ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, ++ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0}, ++ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, ++ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, ++ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, ++ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, ++ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, ++ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, ++ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, ++ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, ++ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, ++ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, ++ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, ++ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, ++ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, ++ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, ++ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, ++ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, ++ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, ++ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, ++ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, ++ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, ++ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, ++ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, ++ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, ++ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, ++ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, ++ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, ++ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, ++ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, ++ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, ++ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, ++ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, ++ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, ++ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, ++ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, ++ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, ++ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, ++ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, ++ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, ++ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, ++ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, ++ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, ++ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, ++ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, ++ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, ++ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, ++ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, ++ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, ++ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, ++ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, ++ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, ++ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, ++ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, ++ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, ++ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, ++ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, ++ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, ++ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, ++ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, ++ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, ++ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, ++ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, ++ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, ++ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, ++ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, ++ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, ++ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, ++ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, ++ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, ++ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, ++ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, ++ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, ++ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, ++ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, ++ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, ++ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, ++ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, ++ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, ++ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, ++ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, ++ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, ++ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, ++ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, ++ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, ++ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, ++ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, ++ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, ++ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, ++ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, ++ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, ++ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, ++ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, ++ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, ++ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, ++ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, ++ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, ++ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, ++ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, ++ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, ++ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, ++ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, ++ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, ++ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, ++ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, ++ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, ++ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, ++ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, ++ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, ++ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, ++ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, ++ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, ++ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, ++ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, ++ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, ++ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, ++ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, ++ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, ++ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, ++ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, ++}; ++ ++static struct reg_value ov5642_setting_15fps_VGA_640_480[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, ++ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, ++ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, ++ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, ++ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, ++ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, ++ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x07, 0, 0}, ++ {0x380f, 0xd0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, ++ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, ++ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0}, ++ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, ++ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, ++ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, ++ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, ++ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, ++ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, ++ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, ++ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, ++ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, ++ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, ++ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, ++ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, ++ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, ++ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, ++ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, ++ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, ++ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, ++ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, ++ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, ++ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, ++ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, ++ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, ++ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, ++ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, ++ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, ++ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, ++ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, ++ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, ++ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, ++ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, ++ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, ++ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, ++ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, ++ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, ++ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, ++ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, ++ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, ++ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, ++ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, ++ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, ++ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, ++ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, ++ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, ++ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, ++ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, ++ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, ++ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, ++ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, ++ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, ++ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, ++ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, ++ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, ++ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, ++ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, ++ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, ++ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, ++ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, ++ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, ++ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, ++ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, ++ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, ++ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, ++ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, ++ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, ++ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, ++ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, ++ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, ++ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, ++ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, ++ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, ++ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, ++ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, ++ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, ++ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, ++ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, ++ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, ++ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, ++ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, ++ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, ++ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, ++ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, ++ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, ++ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, ++ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, ++ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, ++ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, ++ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, ++ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, ++ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, ++ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, ++ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, ++ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, ++ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, ++ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, ++ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, ++ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, ++ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, ++ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, ++ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, ++ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, ++ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, ++ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, ++ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, ++ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, ++ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, ++ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, ++ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, ++ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, ++ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, ++ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, ++ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, ++ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, ++ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, ++ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, ++ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, ++ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, ++ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, ++ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, ++}; ++ ++ ++static struct reg_value ov5642_setting_30fps_XGA_1024_768[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, ++ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, ++ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, ++ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, ++ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, ++ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, ++ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0}, ++ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, ++ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, ++ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0}, ++ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, ++ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, ++ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, ++ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, ++ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, ++ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, ++ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, ++ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, ++ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, ++ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, ++ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, ++ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, ++ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, ++ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, ++ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, ++ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, ++ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, ++ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, ++ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, ++ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, ++ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, ++ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, ++ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, ++ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, ++ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, ++ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, ++ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, ++ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, ++ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, ++ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, ++ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, ++ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, ++ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, ++ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, ++ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, ++ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, ++ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, ++ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, ++ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, ++ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, ++ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, ++ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, ++ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, ++ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, ++ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, ++ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, ++ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, ++ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, ++ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, ++ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, ++ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, ++ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, ++ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, ++ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, ++ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, ++ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, ++ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, ++ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, ++ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, ++ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, ++ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, ++ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, ++ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, ++ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, ++ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, ++ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, ++ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, ++ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, ++ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, ++ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, ++ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, ++ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, ++ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, ++ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, ++ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, ++ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, ++ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, ++ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, ++ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, ++ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, ++ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, ++ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, ++ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, ++ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, ++ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, ++ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, ++ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, ++ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, ++ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, ++ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, ++ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, ++ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, ++ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, ++ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, ++ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, ++ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, ++ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, ++ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, ++ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, ++ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, ++ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, ++ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, ++ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, ++ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, ++ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, ++ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, ++ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, ++ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, ++ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, ++ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, ++ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, ++ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, ++ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, ++ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, ++ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, ++ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, ++ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, ++ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, ++ {0x380b, 0x00, 0, 0}, {0x3815, 0x02, 0, 0}, {0x302c, 0x60, 0x60, 0}, ++}; ++ ++static struct reg_value ov5642_setting_15fps_XGA_1024_768[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, ++ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, ++ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, ++ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, ++ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, ++ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, ++ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x07, 0, 0}, ++ {0x380f, 0xd0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, ++ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, ++ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0}, ++ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, ++ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, ++ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, ++ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, ++ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, ++ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, ++ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, ++ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, ++ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, ++ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, ++ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, ++ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, ++ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, ++ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, ++ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, ++ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, ++ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, ++ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, ++ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, ++ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, ++ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, ++ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, ++ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, ++ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, ++ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, ++ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, ++ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, ++ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, ++ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, ++ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, ++ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, ++ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, ++ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, ++ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, ++ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, ++ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, ++ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, ++ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, ++ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, ++ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, ++ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, ++ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, ++ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, ++ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, ++ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, ++ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, ++ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, ++ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, ++ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, ++ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, ++ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, ++ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, ++ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, ++ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, ++ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, ++ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, ++ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, ++ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, ++ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, ++ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, ++ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, ++ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, ++ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, ++ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, ++ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, ++ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, ++ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, ++ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, ++ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, ++ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, ++ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, ++ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, ++ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, ++ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, ++ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, ++ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, ++ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, ++ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, ++ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, ++ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, ++ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, ++ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, ++ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, ++ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, ++ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, ++ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, ++ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, ++ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, ++ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, ++ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, ++ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, ++ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, ++ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, ++ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, ++ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, ++ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, ++ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, ++ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, ++ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, ++ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, ++ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, ++ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, ++ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, ++ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, ++ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, ++ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, ++ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, ++ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, ++ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, ++ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, ++ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, ++ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, ++ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, ++ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, ++ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, ++ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, ++ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, ++ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, ++ {0x380b, 0x00, 0, 0}, {0x3815, 0x02, 0, 0}, {0x302c, 0x60, 0x60, 0}, ++}; ++ ++static struct reg_value ov5642_setting_30fps_QVGA_320_240[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, ++ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, ++ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, ++ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, ++ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, ++ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, ++ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0}, ++ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, ++ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, ++ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0}, ++ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, ++ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, ++ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, ++ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, ++ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, ++ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, ++ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, ++ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, ++ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, ++ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, ++ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, ++ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, ++ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, ++ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, ++ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, ++ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, ++ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, ++ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, ++ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, ++ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, ++ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, ++ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, ++ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, ++ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, ++ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, ++ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, ++ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, ++ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, ++ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, ++ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, ++ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, ++ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, ++ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, ++ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, ++ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, ++ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, ++ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, ++ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, ++ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, ++ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, ++ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, ++ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, ++ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, ++ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, ++ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, ++ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, ++ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, ++ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, ++ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, ++ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, ++ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, ++ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, ++ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, ++ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, ++ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, ++ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, ++ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, ++ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, ++ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, ++ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, ++ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, ++ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, ++ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, ++ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, ++ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, ++ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, ++ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, ++ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, ++ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, ++ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, ++ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, ++ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, ++ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, ++ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, ++ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, ++ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, ++ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, ++ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, ++ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, ++ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, ++ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, ++ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, ++ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, ++ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, ++ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, ++ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, ++ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, ++ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, ++ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, ++ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, ++ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, ++ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, ++ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, ++ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, ++ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, ++ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, ++ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, ++ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, ++ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, ++ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, ++ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, ++ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, ++ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, ++ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, ++ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, ++ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, ++ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, ++ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, ++ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, ++ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, ++ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, ++ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, ++ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, ++ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, ++ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, ++ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, ++ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, ++ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3808, 0x01, 0, 0}, ++ {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, ++}; ++ ++static struct reg_value ov5642_setting_30fps_NTSC_720_480[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, ++ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, ++ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, ++ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, ++ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, ++ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, ++ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0}, ++ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, ++ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, ++ {0x3803, 0x08, 0, 0}, {0x3827, 0x3c, 0, 0}, {0x3810, 0x80, 0, 0}, ++ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, ++ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0x58, 0, 0}, ++ {0x5686, 0x03, 0, 0}, {0x5687, 0x58, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, ++ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, ++ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, ++ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, ++ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, ++ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, ++ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, ++ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, ++ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, ++ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, ++ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, ++ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, ++ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, ++ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, ++ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, ++ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, ++ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, ++ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, ++ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, ++ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, ++ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, ++ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, ++ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, ++ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, ++ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, ++ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, ++ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, ++ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, ++ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, ++ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, ++ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, ++ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, ++ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, ++ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, ++ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, ++ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, ++ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, ++ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, ++ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, ++ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, ++ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, ++ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, ++ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, ++ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, ++ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, ++ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, ++ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, ++ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, ++ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, ++ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, ++ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, ++ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, ++ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, ++ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, ++ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, ++ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, ++ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, ++ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, ++ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, ++ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, ++ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, ++ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, ++ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, ++ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, ++ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, ++ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, ++ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, ++ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, ++ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, ++ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, ++ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, ++ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, ++ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, ++ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, ++ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, ++ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, ++ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, ++ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, ++ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, ++ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, ++ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, ++ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, ++ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, ++ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, ++ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, ++ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, ++ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, ++ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, ++ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, ++ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, ++ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, ++ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, ++ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, ++ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, ++ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, ++ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, ++ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, ++ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, ++ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, ++ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, ++ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, ++ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, ++ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, ++ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, ++ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, ++ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, ++ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, ++ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, ++ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, ++ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, ++ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, ++ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, ++ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, ++ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, ++ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, ++ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x302c, 0x60, 0x60, 0}, ++}; ++ ++static struct reg_value ov5642_setting_30fps_PAL_720_576[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, ++ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, ++ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, ++ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, ++ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xd8, 0, 0}, ++ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, ++ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0}, ++ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, ++ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, ++ {0x3803, 0x08, 0, 0}, {0x3827, 0x3c, 0, 0}, {0x3810, 0x80, 0, 0}, ++ {0x3804, 0x04, 0, 0}, {0x3805, 0xb0, 0, 0}, {0x5682, 0x04, 0, 0}, ++ {0x5683, 0xb0, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0x58, 0, 0}, ++ {0x5686, 0x03, 0, 0}, {0x5687, 0x58, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, ++ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, ++ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, ++ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, ++ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, ++ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, ++ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, ++ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, ++ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, ++ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, ++ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, ++ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, ++ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, ++ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, ++ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, ++ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, ++ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, ++ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, ++ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, ++ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, ++ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, ++ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, ++ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, ++ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, ++ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, ++ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, ++ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, ++ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, ++ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, ++ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, ++ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, ++ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, ++ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, ++ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, ++ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, ++ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, ++ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, ++ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, ++ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, ++ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, ++ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, ++ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, ++ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, ++ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, ++ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, ++ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, ++ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, ++ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, ++ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, ++ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, ++ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, ++ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, ++ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, ++ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, ++ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, ++ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, ++ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, ++ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, ++ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, ++ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, ++ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, ++ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, ++ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, ++ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, ++ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, ++ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, ++ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, ++ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, ++ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, ++ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, ++ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, ++ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, ++ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, ++ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, ++ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, ++ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, ++ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, ++ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, ++ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, ++ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, ++ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, ++ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, ++ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, ++ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, ++ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, ++ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, ++ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, ++ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, ++ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, ++ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, ++ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, ++ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, ++ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, ++ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, ++ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, ++ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, ++ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, ++ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, ++ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, ++ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, ++ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, ++ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, ++ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, ++ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, ++ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, ++ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, ++ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, ++ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, ++ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, ++ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, ++ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, ++ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, ++ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, ++ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, ++ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, ++ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, ++ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x302c, 0x60, 0x60, 0}, ++}; ++ ++static struct reg_value ov5642_setting_15fps_720P_1280_720[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, ++ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0}, ++ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3030, 0x2b, 0, 0}, ++ {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3604, 0x60, 0, 0}, ++ {0x3622, 0x60, 0, 0}, {0x3621, 0x09, 0, 0}, {0x3709, 0x00, 0, 0}, ++ {0x4000, 0x21, 0, 0}, {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, ++ {0x3605, 0x04, 0, 0}, {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, ++ {0x300d, 0x22, 0, 0}, {0x3623, 0x22, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5500, 0x0a, 0, 0}, ++ {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0}, ++ {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0}, ++ {0x4708, 0x06, 0, 0}, {0x370c, 0xa0, 0, 0}, {0x3808, 0x0a, 0, 0}, ++ {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, ++ {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0}, ++ {0x380f, 0xd0, 0, 0}, {0x5687, 0x94, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x5001, 0xcf, 0, 0}, {0x4300, 0x30, 0, 0}, ++ {0x4300, 0x30, 0, 0}, {0x460b, 0x35, 0, 0}, {0x471d, 0x00, 0, 0}, ++ {0x3002, 0x0c, 0, 0}, {0x3002, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x471c, 0x50, 0, 0}, {0x4721, 0x02, 0, 0}, {0x4402, 0x90, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x3815, 0x44, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3818, 0xc8, 0, 0}, {0x3801, 0x88, 0, 0}, {0x3824, 0x11, 0, 0}, ++ {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x04, 0, 0}, {0x3a13, 0x30, 0, 0}, ++ {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, ++ {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, ++ {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, {0x3a0d, 0x08, 0, 0}, ++ {0x3a0e, 0x06, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, ++ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x32, 0, 0}, ++ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x32, 0, 0}, {0x3a11, 0x80, 0, 0}, ++ {0x3a1f, 0x20, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, ++ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, ++ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a08, 0x09, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, ++ {0x3a0b, 0xd0, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x589b, 0x00, 0, 0}, ++ {0x589a, 0xc0, 0, 0}, {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, ++ {0x401c, 0x06, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0}, ++ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, ++ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, ++ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, ++ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, ++ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, ++ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, ++ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, ++ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, ++ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, ++ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, ++ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, ++ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, ++ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, ++ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, ++ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, ++ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, ++ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, ++ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, ++ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, ++ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, ++ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, ++ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, ++ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, ++ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, ++ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, ++ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, ++ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, ++ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, ++ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, ++ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, ++ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, ++ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, ++ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, ++ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, ++ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, ++ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, ++ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, ++ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, ++ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, ++ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, ++ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, ++ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, ++ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, ++ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, ++ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, ++ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, ++ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, ++ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, ++ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, ++ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, ++ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, ++ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, ++ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, ++ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, ++ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, ++ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, ++ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, ++ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, ++ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, ++ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, ++ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, ++ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, ++ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, ++ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, ++ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, ++ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, ++ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, ++ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, ++ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, ++ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, ++ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, ++ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, ++ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, ++ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, ++ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, ++ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, ++ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, ++ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, ++ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, ++ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, ++ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, ++ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, ++ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, ++ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, ++ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, ++ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, ++ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, ++ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, ++ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, ++ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, ++ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, ++ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, ++ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, ++ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, ++ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, ++ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, ++ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, ++ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, ++ {0x302b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3011, 0x08, 0, 0}, ++ {0x350c, 0x02, 0, 0}, {0x350d, 0xe4, 0, 0}, {0x3621, 0xc9, 0, 0}, ++ {0x370a, 0x81, 0, 0}, {0x3803, 0x08, 0, 0}, {0x3804, 0x05, 0, 0}, ++ {0x3805, 0x00, 0, 0}, {0x3806, 0x02, 0, 0}, {0x3807, 0xd0, 0, 0}, ++ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, ++ {0x380b, 0xd0, 0, 0}, {0x380c, 0x08, 0, 0}, {0x380d, 0x72, 0, 0}, ++ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0xc0, 0, 0}, ++ {0x3818, 0xc9, 0, 0}, {0x381c, 0x10, 0, 0}, {0x381d, 0xa0, 0, 0}, ++ {0x381e, 0x05, 0, 0}, {0x381f, 0xb0, 0, 0}, {0x3820, 0x00, 0, 0}, ++ {0x3821, 0x00, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3a08, 0x1b, 0, 0}, ++ {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x17, 0, 0}, {0x3a0b, 0x20, 0, 0}, ++ {0x3a0d, 0x02, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x401c, 0x04, 0, 0}, ++ {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, {0x5686, 0x02, 0, 0}, ++ {0x5687, 0xcc, 0, 0}, {0x5001, 0x7f, 0, 0}, {0x589b, 0x06, 0, 0}, ++ {0x589a, 0xc5, 0, 0}, {0x3503, 0x00, 0, 0}, {0x3010, 0x10, 0, 0}, ++ {0x460c, 0x20, 0, 0}, {0x460b, 0x37, 0, 0}, {0x471c, 0xd0, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x3815, 0x01, 0, 0}, {0x3818, 0x00, 0x08, 0}, ++ {0x501f, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3002, 0x1c, 0, 0}, ++ {0x3819, 0x80, 0, 0}, {0x5002, 0xe0, 0, 0}, {0x3010, 0x30, 0, 0}, ++ {0x3a08, 0x06, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x05, 0, 0}, ++ {0x3a0b, 0x50, 0, 0}, {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x07, 0, 0}, ++}; ++ ++static struct reg_value ov5642_setting_30fps_720P_1280_720[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, ++ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0}, ++ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3030, 0x2b, 0, 0}, ++ {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3604, 0x60, 0, 0}, ++ {0x3622, 0x60, 0, 0}, {0x3621, 0x09, 0, 0}, {0x3709, 0x00, 0, 0}, ++ {0x4000, 0x21, 0, 0}, {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, ++ {0x3605, 0x04, 0, 0}, {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, ++ {0x300d, 0x22, 0, 0}, {0x3623, 0x22, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5500, 0x0a, 0, 0}, ++ {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0}, ++ {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0}, ++ {0x4708, 0x06, 0, 0}, {0x370c, 0xa0, 0, 0}, {0x3808, 0x0a, 0, 0}, ++ {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, ++ {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0}, ++ {0x380f, 0xd0, 0, 0}, {0x5687, 0x94, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x5001, 0xcf, 0, 0}, {0x4300, 0x30, 0, 0}, ++ {0x4300, 0x30, 0, 0}, {0x460b, 0x35, 0, 0}, {0x471d, 0x00, 0, 0}, ++ {0x3002, 0x0c, 0, 0}, {0x3002, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x471c, 0x50, 0, 0}, {0x4721, 0x02, 0, 0}, {0x4402, 0x90, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x3815, 0x44, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3818, 0xc8, 0, 0}, {0x3801, 0x88, 0, 0}, {0x3824, 0x11, 0, 0}, ++ {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x04, 0, 0}, {0x3a13, 0x30, 0, 0}, ++ {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, ++ {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, ++ {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, {0x3a0d, 0x08, 0, 0}, ++ {0x3a0e, 0x06, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, ++ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x32, 0, 0}, ++ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x32, 0, 0}, {0x3a11, 0x80, 0, 0}, ++ {0x3a1f, 0x20, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, ++ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, ++ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a08, 0x09, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, ++ {0x3a0b, 0xd0, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x589b, 0x00, 0, 0}, ++ {0x589a, 0xc0, 0, 0}, {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, ++ {0x401c, 0x06, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0}, ++ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, ++ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, ++ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, ++ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, ++ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, ++ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, ++ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, ++ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, ++ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, ++ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, ++ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, ++ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, ++ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, ++ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, ++ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, ++ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, ++ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, ++ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, ++ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, ++ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, ++ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, ++ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, ++ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, ++ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, ++ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, ++ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, ++ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, ++ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, ++ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, ++ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, ++ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, ++ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, ++ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, ++ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, ++ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, ++ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, ++ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, ++ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, ++ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, ++ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, ++ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, ++ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, ++ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, ++ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, ++ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, ++ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, ++ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, ++ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, ++ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, ++ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, ++ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, ++ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, ++ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, ++ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, ++ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, ++ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, ++ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, ++ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, ++ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, ++ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, ++ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, ++ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, ++ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, ++ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, ++ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, ++ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, ++ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, ++ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, ++ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, ++ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, ++ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, ++ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, ++ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, ++ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, ++ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, ++ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, ++ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, ++ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, ++ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, ++ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, ++ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, ++ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, ++ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, ++ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, ++ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, ++ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, ++ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, ++ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, ++ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, ++ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, ++ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, ++ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, ++ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, ++ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, ++ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, ++ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, ++ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, ++ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, ++ {0x302b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3011, 0x08, 0, 0}, ++ {0x350c, 0x02, 0, 0}, {0x350d, 0xe4, 0, 0}, {0x3621, 0xc9, 0, 0}, ++ {0x370a, 0x81, 0, 0}, {0x3803, 0x08, 0, 0}, {0x3804, 0x05, 0, 0}, ++ {0x3805, 0x00, 0, 0}, {0x3806, 0x02, 0, 0}, {0x3807, 0xd0, 0, 0}, ++ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, ++ {0x380b, 0xd0, 0, 0}, {0x380c, 0x08, 0, 0}, {0x380d, 0x72, 0, 0}, ++ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0xc0, 0, 0}, ++ {0x3818, 0xc9, 0, 0}, {0x381c, 0x10, 0, 0}, {0x381d, 0xa0, 0, 0}, ++ {0x381e, 0x05, 0, 0}, {0x381f, 0xb0, 0, 0}, {0x3820, 0x00, 0, 0}, ++ {0x3821, 0x00, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3a08, 0x1b, 0, 0}, ++ {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x17, 0, 0}, {0x3a0b, 0x20, 0, 0}, ++ {0x3a0d, 0x02, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x401c, 0x04, 0, 0}, ++ {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, {0x5686, 0x02, 0, 0}, ++ {0x5687, 0xcc, 0, 0}, {0x5001, 0x7f, 0, 0}, {0x589b, 0x06, 0, 0}, ++ {0x589a, 0xc5, 0, 0}, {0x3503, 0x00, 0, 0}, {0x3010, 0x10, 0, 0}, ++ {0x460c, 0x20, 0, 0}, {0x460b, 0x37, 0, 0}, {0x471c, 0xd0, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x3815, 0x01, 0, 0}, {0x3818, 0x00, 0x08, 0}, ++ {0x501f, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3002, 0x1c, 0, 0}, ++ {0x3819, 0x80, 0, 0}, {0x5002, 0xe0, 0, 0}, ++}; ++ ++static struct reg_value ov5642_setting_15fps_1080P_1920_1080[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, ++ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0}, ++ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3030, 0x2b, 0, 0}, ++ {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3604, 0x60, 0, 0}, ++ {0x3622, 0x60, 0, 0}, {0x3621, 0x09, 0, 0}, {0x3709, 0x00, 0, 0}, ++ {0x4000, 0x21, 0, 0}, {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, ++ {0x3605, 0x04, 0, 0}, {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, ++ {0x300d, 0x22, 0, 0}, {0x3623, 0x22, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5500, 0x0a, 0, 0}, ++ {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0}, ++ {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0}, ++ {0x4708, 0x06, 0, 0}, {0x370c, 0xa0, 0, 0}, {0x3808, 0x0a, 0, 0}, ++ {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, ++ {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0}, ++ {0x380f, 0xd0, 0, 0}, {0x5687, 0x94, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x5001, 0xcf, 0, 0}, {0x4300, 0x30, 0, 0}, ++ {0x4300, 0x30, 0, 0}, {0x460b, 0x35, 0, 0}, {0x471d, 0x00, 0, 0}, ++ {0x3002, 0x0c, 0, 0}, {0x3002, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, ++ {0x471c, 0x50, 0, 0}, {0x4721, 0x02, 0, 0}, {0x4402, 0x90, 0, 0}, ++ {0x460c, 0x22, 0, 0}, {0x3815, 0x44, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3818, 0xc8, 0, 0}, {0x3801, 0x88, 0, 0}, {0x3824, 0x11, 0, 0}, ++ {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x04, 0, 0}, {0x3a13, 0x30, 0, 0}, ++ {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, ++ {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, ++ {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, {0x3a0d, 0x08, 0, 0}, ++ {0x3a0e, 0x06, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, ++ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x32, 0, 0}, ++ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x32, 0, 0}, {0x3a11, 0x80, 0, 0}, ++ {0x3a1f, 0x20, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, ++ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, ++ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, ++ {0x3a08, 0x09, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, ++ {0x3a0b, 0xd0, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x589b, 0x00, 0, 0}, ++ {0x589a, 0xc0, 0, 0}, {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, ++ {0x401c, 0x06, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0}, ++ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, ++ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, ++ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, ++ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, ++ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, ++ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, ++ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, ++ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, ++ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, ++ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, ++ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, ++ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, ++ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, ++ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, ++ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, ++ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, ++ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, ++ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, ++ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, ++ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, ++ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, ++ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, ++ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, ++ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, ++ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, ++ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, ++ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, ++ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, ++ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, ++ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, ++ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, ++ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, ++ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, ++ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, ++ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, ++ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, ++ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, ++ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, ++ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, ++ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, ++ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, ++ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, ++ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, ++ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, ++ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, ++ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, ++ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, ++ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, ++ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, ++ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, ++ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, ++ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, ++ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, ++ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, ++ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, ++ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, ++ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, ++ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, ++ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, ++ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, ++ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, ++ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, ++ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, ++ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, ++ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, ++ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, ++ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, ++ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, ++ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, ++ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, ++ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, ++ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, ++ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, ++ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, ++ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, ++ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, ++ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, ++ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, ++ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, ++ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, ++ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, ++ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, ++ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, ++ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, ++ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, ++ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, ++ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, ++ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, ++ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, ++ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, ++ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, ++ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, ++ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, ++ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, ++ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, ++ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, ++ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, ++ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, ++ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, ++ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, ++ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, ++ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, ++ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, ++ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, ++ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, ++ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, ++ {0x302b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3011, 0x07, 0, 0}, ++ {0x350c, 0x04, 0, 0}, {0x350d, 0x58, 0, 0}, {0x3801, 0x8a, 0, 0}, ++ {0x3803, 0x0a, 0, 0}, {0x3804, 0x07, 0, 0}, {0x3805, 0x80, 0, 0}, ++ {0x3806, 0x04, 0, 0}, {0x3807, 0x39, 0, 0}, {0x3808, 0x07, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, ++ {0x380c, 0x09, 0, 0}, {0x380d, 0xd6, 0, 0}, {0x380e, 0x04, 0, 0}, ++ {0x380f, 0x58, 0, 0}, {0x381c, 0x11, 0, 0}, {0x381d, 0xba, 0, 0}, ++ {0x381e, 0x04, 0, 0}, {0x381f, 0x48, 0, 0}, {0x3820, 0x04, 0, 0}, ++ {0x3821, 0x18, 0, 0}, {0x3a08, 0x14, 0, 0}, {0x3a09, 0xe0, 0, 0}, ++ {0x3a0a, 0x11, 0, 0}, {0x3a0b, 0x60, 0, 0}, {0x3a0d, 0x04, 0, 0}, ++ {0x3a0e, 0x03, 0, 0}, {0x5682, 0x07, 0, 0}, {0x5683, 0x60, 0, 0}, ++ {0x5686, 0x04, 0, 0}, {0x5687, 0x1c, 0, 0}, {0x5001, 0x7f, 0, 0}, ++ {0x3503, 0x00, 0, 0}, {0x3010, 0x10, 0, 0}, {0x460c, 0x20, 0, 0}, ++ {0x460b, 0x37, 0, 0}, {0x471c, 0xd0, 0, 0}, {0x471d, 0x05, 0, 0}, ++ {0x3815, 0x01, 0, 0}, {0x3818, 0x00, 0x08, 0}, {0x501f, 0x00, 0, 0}, ++ {0x4300, 0x30, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3819, 0x80, 0, 0}, ++ {0x5002, 0xe0, 0, 0}, ++}; ++ ++static struct reg_value ov5642_setting_15fps_QVGA_320_240[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, ++ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, ++ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, ++ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0}, ++ {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0}, ++ {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0}, ++ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0}, ++ {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0}, ++ {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, ++ {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0}, ++ {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, ++ {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, ++ {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0}, ++ {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, ++ {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0}, ++ {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0}, ++ {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0}, ++ {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0}, ++ {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0}, ++ {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0}, ++ {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0}, ++ {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0}, ++ {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0}, ++ {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0}, ++ {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0}, ++ {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0}, ++ {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0}, ++ {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0}, ++ {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0}, ++ {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0}, ++ {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0}, ++ {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0}, ++ {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0}, ++ {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0}, ++ {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0}, ++ {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0}, ++ {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0}, ++ {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0}, ++ {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0}, ++ {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0}, ++ {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0}, ++ {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0}, ++ {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0}, ++ {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0}, ++ {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0}, ++ {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0}, ++ {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0}, ++ {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0}, ++ {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0}, ++ {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0}, ++ {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0}, ++ {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0}, ++ {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0}, ++ {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0}, ++ {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0}, ++ {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0}, ++ {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0}, ++ {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0}, ++ {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0}, ++ {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0}, ++ {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0}, ++ {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0}, ++ {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0}, ++ {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0}, ++ {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0}, ++ {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0}, ++ {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0}, ++ {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, ++ {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0}, ++ {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0}, ++ {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0}, ++ {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, ++ {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, ++ {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, ++ {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0}, ++ {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0}, ++ {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0}, ++ {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0}, ++ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0}, ++ {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0}, ++ {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0}, ++ {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0}, ++ {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0}, ++ {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0}, ++ {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0}, ++ {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0}, ++ {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0}, ++ {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0}, ++ {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0}, ++ {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0}, ++ {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0}, ++ {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0}, ++ {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0}, ++ {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0}, ++ {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0}, ++ {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0}, ++ {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0}, ++ {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0}, ++ {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0}, ++ {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0}, ++ {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0}, ++ {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0}, ++ {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0}, ++ {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0}, ++ {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0}, ++ {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0}, ++ {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0}, ++ {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0}, ++ {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0}, ++ {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0}, ++ {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0}, ++ {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0}, ++ {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0}, ++ {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0}, ++ {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0}, ++ {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0}, ++ {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0}, ++ {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0}, ++ {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0}, ++ {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0}, ++ {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0}, ++ {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0}, ++ {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0}, ++ {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0}, ++ {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0}, ++ {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0}, ++ {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0}, ++ {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0}, ++ {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0}, ++ {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0}, ++ {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0}, ++ {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0}, ++ {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0}, ++ {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0}, ++ {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0}, ++ {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0}, ++ {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0}, ++ {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0}, ++ {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, ++ {0x380b, 0xf0, 0, 0}, {0x3a00, 0x78, 0, 0}, ++}; ++ ++static struct reg_value ov5642_setting_15fps_NTSC_720_480[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, ++ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, ++ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, ++ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0}, ++ {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0}, ++ {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0}, ++ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0}, ++ {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0}, ++ {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, ++ {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0}, ++ {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, ++ {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, ++ {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0}, ++ {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, ++ {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0}, ++ {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0}, ++ {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0}, ++ {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0}, ++ {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0}, ++ {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0}, ++ {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0}, ++ {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0}, ++ {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0}, ++ {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0}, ++ {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0}, ++ {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0}, ++ {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0}, ++ {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0}, ++ {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0}, ++ {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0}, ++ {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0}, ++ {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0}, ++ {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0}, ++ {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0}, ++ {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0}, ++ {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0}, ++ {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0}, ++ {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0}, ++ {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0}, ++ {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0}, ++ {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0}, ++ {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0}, ++ {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0}, ++ {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0}, ++ {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0}, ++ {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0}, ++ {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0}, ++ {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0}, ++ {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0}, ++ {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0}, ++ {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0}, ++ {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0}, ++ {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0}, ++ {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0}, ++ {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0}, ++ {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0}, ++ {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0}, ++ {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0}, ++ {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0}, ++ {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0}, ++ {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0}, ++ {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0}, ++ {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0}, ++ {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0}, ++ {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0}, ++ {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0}, ++ {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0}, ++ {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, ++ {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0}, ++ {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0}, ++ {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0}, ++ {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, ++ {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, ++ {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, ++ {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0}, ++ {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0}, ++ {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0}, ++ {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0}, ++ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0}, ++ {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0}, ++ {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0}, ++ {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0}, ++ {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0}, ++ {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0}, ++ {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0}, ++ {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0}, ++ {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0}, ++ {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0}, ++ {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0}, ++ {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0}, ++ {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0}, ++ {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0}, ++ {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0}, ++ {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0}, ++ {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0}, ++ {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0}, ++ {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0}, ++ {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0}, ++ {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0}, ++ {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0}, ++ {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0}, ++ {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0}, ++ {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0}, ++ {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0}, ++ {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0}, ++ {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0}, ++ {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0}, ++ {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0}, ++ {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0}, ++ {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0}, ++ {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0}, ++ {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0}, ++ {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0}, ++ {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0}, ++ {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0}, ++ {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0}, ++ {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0}, ++ {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0}, ++ {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0}, ++ {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0}, ++ {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0}, ++ {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0}, ++ {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0}, ++ {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0}, ++ {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0}, ++ {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0}, ++ {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0}, ++ {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0}, ++ {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0}, ++ {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0}, ++ {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0}, ++ {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0}, ++ {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0}, ++ {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0}, ++ {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0}, ++ {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0}, ++ {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0}, ++ {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0}, ++ {0x3824, 0x11, 0, 0}, {0x3825, 0xb4, 0, 0}, {0x3826, 0x00, 0, 0}, ++ {0x3827, 0x3d, 0, 0}, {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0xd0, 0, 0}, {0x380A, 0x01, 0, 0}, {0x380B, 0xe0, 0, 0}, ++ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, ++ {0x3807, 0x55, 0, 0}, {0x5686, 0x03, 0, 0}, {0x5687, 0x55, 0, 0}, ++ {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, ++}; ++ ++static struct reg_value ov5642_setting_15fps_PAL_720_576[] = { ++ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, ++ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, ++ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, ++ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, ++ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0}, ++ {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, ++ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, ++ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, ++ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, ++ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, ++ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, ++ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, ++ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, ++ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, ++ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, ++ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, ++ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, ++ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, ++ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, ++ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, ++ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0}, ++ {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0}, ++ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, ++ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0}, ++ {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0}, ++ {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, ++ {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0}, ++ {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, ++ {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, ++ {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0}, ++ {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, ++ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, ++ {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, ++ {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0}, ++ {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0}, ++ {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, ++ {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0}, ++ {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0}, ++ {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0}, ++ {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0}, ++ {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0}, ++ {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0}, ++ {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0}, ++ {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0}, ++ {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0}, ++ {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0}, ++ {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0}, ++ {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0}, ++ {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0}, ++ {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0}, ++ {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0}, ++ {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0}, ++ {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0}, ++ {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0}, ++ {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0}, ++ {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0}, ++ {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0}, ++ {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0}, ++ {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0}, ++ {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0}, ++ {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0}, ++ {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0}, ++ {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0}, ++ {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0}, ++ {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0}, ++ {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0}, ++ {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0}, ++ {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0}, ++ {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0}, ++ {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0}, ++ {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0}, ++ {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0}, ++ {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0}, ++ {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0}, ++ {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0}, ++ {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0}, ++ {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0}, ++ {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0}, ++ {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0}, ++ {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0}, ++ {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0}, ++ {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0}, ++ {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0}, ++ {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0}, ++ {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0}, ++ {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0}, ++ {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0}, ++ {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0}, ++ {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0}, ++ {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0}, ++ {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0}, ++ {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0}, ++ {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0}, ++ {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, ++ {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0}, ++ {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0}, ++ {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0}, ++ {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, ++ {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, ++ {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, ++ {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0}, ++ {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0}, ++ {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0}, ++ {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0}, ++ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0}, ++ {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0}, ++ {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0}, ++ {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0}, ++ {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0}, ++ {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0}, ++ {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0}, ++ {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0}, ++ {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0}, ++ {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0}, ++ {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0}, ++ {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0}, ++ {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0}, ++ {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0}, ++ {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0}, ++ {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0}, ++ {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0}, ++ {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0}, ++ {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0}, ++ {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0}, ++ {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0}, ++ {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0}, ++ {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0}, ++ {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0}, ++ {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0}, ++ {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0}, ++ {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0}, ++ {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0}, ++ {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0}, ++ {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0}, ++ {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0}, ++ {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0}, ++ {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0}, ++ {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0}, ++ {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0}, ++ {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0}, ++ {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0}, ++ {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0}, ++ {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0}, ++ {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0}, ++ {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0}, ++ {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0}, ++ {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0}, ++ {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0}, ++ {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0}, ++ {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0}, ++ {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0}, ++ {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0}, ++ {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0}, ++ {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0}, ++ {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0}, ++ {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0}, ++ {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0}, ++ {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0}, ++ {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0}, ++ {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0}, ++ {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0}, ++ {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0}, ++ {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0}, ++ {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0}, ++ {0x3824, 0x11, 0, 0}, {0x3825, 0xdc, 0, 0}, {0x3826, 0x00, 0, 0}, ++ {0x3827, 0x08, 0, 0}, {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, ++ {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, {0x3808, 0x02, 0, 0}, ++ {0x3809, 0xd0, 0, 0}, {0x380A, 0x02, 0, 0}, {0x380B, 0x40, 0, 0}, ++ {0x3804, 0x04, 0, 0}, {0x3805, 0xb0, 0, 0}, {0x3806, 0x03, 0, 0}, ++ {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, {0x5687, 0xc0, 0, 0}, ++ {0x5682, 0x04, 0, 0}, {0x5683, 0xb0, 0, 0}, ++}; ++ ++static struct ov5642_mode_info ov5642_mode_info_data[2][ov5642_mode_MAX + 1] = { ++ { ++ {ov5642_mode_VGA_640_480, 640, 480, ++ ov5642_setting_15fps_VGA_640_480, ++ ARRAY_SIZE(ov5642_setting_15fps_VGA_640_480)}, ++ {ov5642_mode_QVGA_320_240, 320, 240, ++ ov5642_setting_15fps_QVGA_320_240, ++ ARRAY_SIZE(ov5642_setting_15fps_QVGA_320_240)}, ++ {ov5642_mode_NTSC_720_480, 720, 480, ++ ov5642_setting_15fps_NTSC_720_480, ++ ARRAY_SIZE(ov5642_setting_15fps_NTSC_720_480)}, ++ {ov5642_mode_PAL_720_576, 720, 576, ++ ov5642_setting_15fps_PAL_720_576, ++ ARRAY_SIZE(ov5642_setting_15fps_PAL_720_576)}, ++ {ov5642_mode_720P_1280_720, 1280, 720, ++ ov5642_setting_15fps_720P_1280_720, ++ ARRAY_SIZE(ov5642_setting_15fps_720P_1280_720)}, ++ {ov5642_mode_1080P_1920_1080, 1920, 1080, ++ ov5642_setting_15fps_1080P_1920_1080, ++ ARRAY_SIZE(ov5642_setting_15fps_1080P_1920_1080)}, ++ {ov5642_mode_QSXGA_2592_1944, 2592, 1944, ++ ov5642_setting_15fps_QSXGA_2592_1944, ++ ARRAY_SIZE(ov5642_setting_15fps_QSXGA_2592_1944)}, ++ {ov5642_mode_QCIF_176_144, 176, 144, ++ ov5642_setting_15fps_QCIF_176_144, ++ ARRAY_SIZE(ov5642_setting_15fps_QCIF_176_144)}, ++ {ov5642_mode_XGA_1024_768, 1024, 768, ++ ov5642_setting_15fps_XGA_1024_768, ++ ARRAY_SIZE(ov5642_setting_15fps_XGA_1024_768)}, ++ }, ++ { ++ {ov5642_mode_VGA_640_480, 640, 480, ++ ov5642_setting_30fps_VGA_640_480, ++ ARRAY_SIZE(ov5642_setting_30fps_VGA_640_480)}, ++ {ov5642_mode_QVGA_320_240, 320, 240, ++ ov5642_setting_30fps_QVGA_320_240, ++ ARRAY_SIZE(ov5642_setting_30fps_QVGA_320_240)}, ++ {ov5642_mode_NTSC_720_480, 720, 480, ++ ov5642_setting_30fps_NTSC_720_480, ++ ARRAY_SIZE(ov5642_setting_30fps_NTSC_720_480)}, ++ {ov5642_mode_PAL_720_576, 720, 576, ++ ov5642_setting_30fps_PAL_720_576, ++ ARRAY_SIZE(ov5642_setting_30fps_PAL_720_576)}, ++ {ov5642_mode_720P_1280_720, 1280, 720, ++ ov5642_setting_30fps_720P_1280_720, ++ ARRAY_SIZE(ov5642_setting_30fps_720P_1280_720)}, ++ {ov5642_mode_1080P_1920_1080, 0, 0, NULL, 0}, ++ {ov5642_mode_QSXGA_2592_1944, 0, 0, NULL, 0}, ++ {ov5642_mode_QCIF_176_144, 176, 144, ++ ov5642_setting_30fps_QCIF_176_144, ++ ARRAY_SIZE(ov5642_setting_30fps_QCIF_176_144)}, ++ {ov5642_mode_XGA_1024_768, 1024, 768, ++ ov5642_setting_30fps_XGA_1024_768, ++ ARRAY_SIZE(ov5642_setting_30fps_XGA_1024_768)}, ++ }, ++}; ++ ++static struct regulator *io_regulator; ++static struct regulator *core_regulator; ++static struct regulator *analog_regulator; ++static struct regulator *gpo_regulator; ++ ++static int ov5642_probe(struct i2c_client *adapter, ++ const struct i2c_device_id *device_id); ++static int ov5642_remove(struct i2c_client *client); ++ ++static s32 ov5642_read_reg(u16 reg, u8 *val); ++static s32 ov5642_write_reg(u16 reg, u8 val); ++ ++static const struct i2c_device_id ov5642_id[] = { ++ {"ov5642", 0}, ++ {"ov564x", 0}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, ov5642_id); ++ ++static struct i2c_driver ov5642_i2c_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = "ov5642", ++ }, ++ .probe = ov5642_probe, ++ .remove = ov5642_remove, ++ .id_table = ov5642_id, ++}; ++ ++static void ov5642_standby(s32 enable) ++{ ++ if (enable) ++ gpio_set_value(pwn_gpio, 1); ++ else ++ gpio_set_value(pwn_gpio, 0); ++ ++ msleep(2); ++} ++ ++static void ov5642_reset(void) ++{ ++ /* camera reset */ ++ gpio_set_value(rst_gpio, 1); ++ ++ /* camera power down */ ++ gpio_set_value(pwn_gpio, 1); ++ msleep(5); ++ ++ gpio_set_value(pwn_gpio, 0); ++ msleep(5); ++ ++ gpio_set_value(rst_gpio, 0); ++ msleep(1); ++ ++ gpio_set_value(rst_gpio, 1); ++ msleep(5); ++ ++ gpio_set_value(pwn_gpio, 1); ++} ++ ++static int ov5642_power_on(struct device *dev) ++{ ++ int ret = 0; ++ ++ io_regulator = devm_regulator_get(dev, "DOVDD"); ++ if (!IS_ERR(io_regulator)) { ++ regulator_set_voltage(io_regulator, ++ OV5642_VOLTAGE_DIGITAL_IO, ++ OV5642_VOLTAGE_DIGITAL_IO); ++ ret = regulator_enable(io_regulator); ++ if (ret) { ++ pr_err("%s:io set voltage error\n", __func__); ++ return ret; ++ } else { ++ dev_dbg(dev, ++ "%s:io set voltage ok\n", __func__); ++ } ++ } else { ++ pr_err("%s: cannot get io voltage error\n", __func__); ++ io_regulator = NULL; ++ } ++ ++ core_regulator = devm_regulator_get(dev, "DVDD"); ++ if (!IS_ERR(core_regulator)) { ++ regulator_set_voltage(core_regulator, ++ OV5642_VOLTAGE_DIGITAL_CORE, ++ OV5642_VOLTAGE_DIGITAL_CORE); ++ ret = regulator_enable(core_regulator); ++ if (ret) { ++ pr_err("%s:core set voltage error\n", __func__); ++ return ret; ++ } else { ++ dev_dbg(dev, ++ "%s:core set voltage ok\n", __func__); ++ } ++ } else { ++ core_regulator = NULL; ++ pr_err("%s: cannot get core voltage error\n", __func__); ++ } ++ ++ analog_regulator = devm_regulator_get(dev, "AVDD"); ++ if (!IS_ERR(analog_regulator)) { ++ regulator_set_voltage(analog_regulator, ++ OV5642_VOLTAGE_ANALOG, ++ OV5642_VOLTAGE_ANALOG); ++ ret = regulator_enable(analog_regulator); ++ if (ret) { ++ pr_err("%s:analog set voltage error\n", ++ __func__); ++ return ret; ++ } else { ++ dev_dbg(dev, ++ "%s:analog set voltage ok\n", __func__); ++ } ++ } else { ++ analog_regulator = NULL; ++ pr_err("%s: cannot get analog voltage error\n", __func__); ++ } ++ ++ return ret; ++} ++ ++static s32 ov5642_write_reg(u16 reg, u8 val) ++{ ++ u8 au8Buf[3] = {0}; ++ ++ au8Buf[0] = reg >> 8; ++ au8Buf[1] = reg & 0xff; ++ au8Buf[2] = val; ++ ++ if (i2c_master_send(ov5642_data.i2c_client, au8Buf, 3) < 0) { ++ pr_err("%s:write reg error:reg=%x,val=%x\n", ++ __func__, reg, val); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static s32 ov5642_read_reg(u16 reg, u8 *val) ++{ ++ u8 au8RegBuf[2] = {0}; ++ u8 u8RdVal = 0; ++ ++ au8RegBuf[0] = reg >> 8; ++ au8RegBuf[1] = reg & 0xff; ++ ++ if (2 != i2c_master_send(ov5642_data.i2c_client, au8RegBuf, 2)) { ++ pr_err("%s:write reg error:reg=%x\n", ++ __func__, reg); ++ return -1; ++ } ++ ++ if (1 != i2c_master_recv(ov5642_data.i2c_client, &u8RdVal, 1)) { ++ pr_err("%s:read reg error:reg=%x,val=%x\n", ++ __func__, reg, u8RdVal); ++ return -1; ++ } ++ ++ *val = u8RdVal; ++ ++ return u8RdVal; ++} ++ ++static int ov5642_set_rot_mode(struct reg_value *rot_mode) ++{ ++ s32 i = 0; ++ s32 iModeSettingArySize = 2; ++ register u32 Delay_ms = 0; ++ register u16 RegAddr = 0; ++ register u8 Mask = 0; ++ register u8 Val = 0; ++ u8 RegVal = 0; ++ int retval = 0; ++ for (i = 0; i < iModeSettingArySize; ++i, ++rot_mode) { ++ Delay_ms = rot_mode->u32Delay_ms; ++ RegAddr = rot_mode->u16RegAddr; ++ Val = rot_mode->u8Val; ++ Mask = rot_mode->u8Mask; ++ ++ if (Mask) { ++ retval = ov5642_read_reg(RegAddr, &RegVal); ++ if (retval < 0) { ++ pr_err("%s, read reg 0x%x failed\n", ++ __func__, RegAddr); ++ goto err; ++ } ++ ++ Val |= RegVal; ++ Val &= Mask; ++ } ++ ++ retval = ov5642_write_reg(RegAddr, Val); ++ if (retval < 0) { ++ pr_err("%s, write reg 0x%x failed\n", ++ __func__, RegAddr); ++ goto err; ++ } ++ ++ if (Delay_ms) ++ mdelay(Delay_ms); ++ } ++err: ++ return retval; ++} ++static int ov5642_init_mode(enum ov5642_frame_rate frame_rate, ++ enum ov5642_mode mode); ++static int ov5642_write_snapshot_para(enum ov5642_frame_rate frame_rate, ++ enum ov5642_mode mode); ++static int ov5642_change_mode(enum ov5642_frame_rate new_frame_rate, ++ enum ov5642_frame_rate old_frame_rate, ++ enum ov5642_mode new_mode, ++ enum ov5642_mode orig_mode) ++{ ++ struct reg_value *pModeSetting = NULL; ++ s32 i = 0; ++ s32 iModeSettingArySize = 0; ++ register u32 Delay_ms = 0; ++ register u16 RegAddr = 0; ++ register u8 Mask = 0; ++ register u8 Val = 0; ++ u8 RegVal = 0; ++ int retval = 0; ++ ++ if (new_mode > ov5642_mode_MAX || new_mode < ov5642_mode_MIN) { ++ pr_err("Wrong ov5642 mode detected!\n"); ++ return -1; ++ } ++ ++ if ((new_frame_rate == old_frame_rate) && ++ (new_mode == ov5642_mode_VGA_640_480) && ++ (orig_mode == ov5642_mode_QSXGA_2592_1944)) { ++ pModeSetting = ov5642_setting_QSXGA_2_VGA; ++ iModeSettingArySize = ARRAY_SIZE(ov5642_setting_QSXGA_2_VGA); ++ ov5642_data.pix.width = 640; ++ ov5642_data.pix.height = 480; ++ } else if ((new_frame_rate == old_frame_rate) && ++ (new_mode == ov5642_mode_QVGA_320_240) && ++ (orig_mode == ov5642_mode_VGA_640_480)) { ++ pModeSetting = ov5642_setting_VGA_2_QVGA; ++ iModeSettingArySize = ARRAY_SIZE(ov5642_setting_VGA_2_QVGA); ++ ov5642_data.pix.width = 320; ++ ov5642_data.pix.height = 240; ++ } else { ++ retval = ov5642_write_snapshot_para(new_frame_rate, new_mode); ++ goto err; ++ } ++ ++ if (ov5642_data.pix.width == 0 || ov5642_data.pix.height == 0 || ++ pModeSetting == NULL || iModeSettingArySize == 0) ++ return -EINVAL; ++ ++ for (i = 0; i < iModeSettingArySize; ++i, ++pModeSetting) { ++ Delay_ms = pModeSetting->u32Delay_ms; ++ RegAddr = pModeSetting->u16RegAddr; ++ Val = pModeSetting->u8Val; ++ Mask = pModeSetting->u8Mask; ++ ++ if (Mask) { ++ retval = ov5642_read_reg(RegAddr, &RegVal); ++ if (retval < 0) { ++ pr_err("read reg error addr=0x%x", RegAddr); ++ goto err; ++ } ++ ++ RegVal &= ~(u8)Mask; ++ Val &= Mask; ++ Val |= RegVal; ++ } ++ ++ retval = ov5642_write_reg(RegAddr, Val); ++ if (retval < 0) { ++ pr_err("write reg error addr=0x%x", RegAddr); ++ goto err; ++ } ++ ++ if (Delay_ms) ++ msleep(Delay_ms); ++ } ++err: ++ return retval; ++} ++static int ov5642_init_mode(enum ov5642_frame_rate frame_rate, ++ enum ov5642_mode mode) ++{ ++ struct reg_value *pModeSetting = NULL; ++ s32 i = 0; ++ s32 iModeSettingArySize = 0; ++ register u32 Delay_ms = 0; ++ register u16 RegAddr = 0; ++ register u8 Mask = 0; ++ register u8 Val = 0; ++ u8 RegVal = 0; ++ int retval = 0; ++ ++ if (mode > ov5642_mode_MAX || mode < ov5642_mode_MIN) { ++ pr_err("Wrong ov5642 mode detected!\n"); ++ return -1; ++ } ++ ++ pModeSetting = ov5642_mode_info_data[frame_rate][mode].init_data_ptr; ++ iModeSettingArySize = ++ ov5642_mode_info_data[frame_rate][mode].init_data_size; ++ ++ ov5642_data.pix.width = ov5642_mode_info_data[frame_rate][mode].width; ++ ov5642_data.pix.height = ov5642_mode_info_data[frame_rate][mode].height; ++ ++ if (ov5642_data.pix.width == 0 || ov5642_data.pix.height == 0 || ++ pModeSetting == NULL || iModeSettingArySize == 0) ++ return -EINVAL; ++ ++ for (i = 0; i < iModeSettingArySize; ++i, ++pModeSetting) { ++ Delay_ms = pModeSetting->u32Delay_ms; ++ RegAddr = pModeSetting->u16RegAddr; ++ Val = pModeSetting->u8Val; ++ Mask = pModeSetting->u8Mask; ++ ++ if (Mask) { ++ retval = ov5642_read_reg(RegAddr, &RegVal); ++ if (retval < 0) { ++ pr_err("read reg error addr=0x%x", RegAddr); ++ goto err; ++ } ++ ++ RegVal &= ~(u8)Mask; ++ Val &= Mask; ++ Val |= RegVal; ++ } ++ ++ retval = ov5642_write_reg(RegAddr, Val); ++ if (retval < 0) { ++ pr_err("write reg error addr=0x%x", RegAddr); ++ goto err; ++ } ++ ++ if (Delay_ms) ++ msleep(Delay_ms); ++ } ++err: ++ return retval; ++} ++ ++static int ov5642_write_snapshot_para(enum ov5642_frame_rate frame_rate, ++ enum ov5642_mode mode) ++{ ++ int ret = 0; ++ bool m_60Hz = false; ++ u16 cap_frame_rate = 50; ++ u16 g_prev_frame_rate = 225; ++ ++ u8 ev_low, ev_mid, ev_high; ++ u8 ret_l, ret_m, ret_h, gain, lines_10ms; ++ u16 ulcap_ev, icap_gain, prev_maxlines; ++ u32 ulcap_ev_gain, cap_maxlines, g_prev_ev; ++ ++ ov5642_write_reg(0x3503, 0x07); ++ ++ ret_h = ret_m = ret_l = 0; ++ g_prev_ev = 0; ++ ov5642_read_reg(0x3500, &ret_h); ++ ov5642_read_reg(0x3501, &ret_m); ++ ov5642_read_reg(0x3502, &ret_l); ++ g_prev_ev = (ret_h << 12) + (ret_m << 4) + (ret_l >> 4); ++ ++ ret_h = ret_m = ret_l = 0; ++ prev_maxlines = 0; ++ ov5642_read_reg(0x380e, &ret_h); ++ ov5642_read_reg(0x380f, &ret_l); ++ prev_maxlines = (ret_h << 8) + ret_l; ++ /*Read back AGC Gain for preview*/ ++ gain = 0; ++ ov5642_read_reg(0x350b, &gain); ++ ++ ret = ov5642_init_mode(frame_rate, mode); ++ if (ret < 0) ++ return ret; ++ ++ ret_h = ret_m = ret_l = 0; ++ ov5642_read_reg(0x380e, &ret_h); ++ ov5642_read_reg(0x380f, &ret_l); ++ cap_maxlines = (ret_h << 8) + ret_l; ++ if (m_60Hz == true) ++ lines_10ms = cap_frame_rate * cap_maxlines/12000; ++ else ++ lines_10ms = cap_frame_rate * cap_maxlines/10000; ++ ++ if (prev_maxlines == 0) ++ prev_maxlines = 1; ++ ++ ulcap_ev = (g_prev_ev*(cap_frame_rate)*(cap_maxlines))/ ++ (((prev_maxlines)*(g_prev_frame_rate))); ++ icap_gain = (gain & 0x0f) + 16; ++ if (gain & 0x10) ++ icap_gain = icap_gain << 1; ++ ++ if (gain & 0x20) ++ icap_gain = icap_gain << 1; ++ ++ if (gain & 0x40) ++ icap_gain = icap_gain << 1; ++ ++ if (gain & 0x80) ++ icap_gain = icap_gain << 1; ++ ++ ulcap_ev_gain = 2 * ulcap_ev * icap_gain; ++ ++ if (ulcap_ev_gain < cap_maxlines*16) { ++ ulcap_ev = ulcap_ev_gain/16; ++ if (ulcap_ev > lines_10ms) { ++ ulcap_ev /= lines_10ms; ++ ulcap_ev *= lines_10ms; ++ } ++ } else ++ ulcap_ev = cap_maxlines; ++ ++ if (ulcap_ev == 0) ++ ulcap_ev = 1; ++ ++ icap_gain = (ulcap_ev_gain*2/ulcap_ev + 1)/2; ++ ev_low = ((unsigned char)ulcap_ev)<<4; ++ ev_mid = (unsigned char)(ulcap_ev >> 4) & 0xff; ++ ev_high = (unsigned char)(ulcap_ev >> 12); ++ ++ gain = 0; ++ if (icap_gain > 31) { ++ gain |= 0x10; ++ icap_gain = icap_gain >> 1; ++ } ++ if (icap_gain > 31) { ++ gain |= 0x20; ++ icap_gain = icap_gain >> 1; ++ } ++ if (icap_gain > 31) { ++ gain |= 0x40; ++ icap_gain = icap_gain >> 1; ++ } ++ if (icap_gain > 31) { ++ gain |= 0x80; ++ icap_gain = icap_gain >> 1; ++ } ++ if (icap_gain > 16) ++ gain |= ((icap_gain - 16) & 0x0f); ++ ++ if (gain == 0x10) ++ gain = 0x11; ++ ++ ov5642_write_reg(0x350b, gain); ++ ov5642_write_reg(0x3502, ev_low); ++ ov5642_write_reg(0x3501, ev_mid); ++ ov5642_write_reg(0x3500, ev_high); ++ msleep(500); ++ ++ return ret ; ++} ++ ++ ++/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */ ++ ++static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) ++{ ++ if (s == NULL) { ++ pr_err(" ERROR!! no slave device set!\n"); ++ return -1; ++ } ++ ++ memset(p, 0, sizeof(*p)); ++ p->u.bt656.clock_curr = ov5642_data.mclk; ++ pr_debug(" clock_curr=mclk=%d\n", ov5642_data.mclk); ++ p->if_type = V4L2_IF_TYPE_BT656; ++ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; ++ p->u.bt656.clock_min = OV5642_XCLK_MIN; ++ p->u.bt656.clock_max = OV5642_XCLK_MAX; ++ p->u.bt656.bt_sync_correct = 1; /* Indicate external vsync */ ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @on: indicates power mode (on or off) ++ * ++ * Turns the power on or off, depending on the value of on and returns the ++ * appropriate error code. ++ */ ++static int ioctl_s_power(struct v4l2_int_device *s, int on) ++{ ++ struct sensor_data *sensor = s->priv; ++ ++ if (on && !sensor->on) { ++ if (io_regulator) ++ if (regulator_enable(io_regulator) != 0) ++ return -EIO; ++ if (core_regulator) ++ if (regulator_enable(core_regulator) != 0) ++ return -EIO; ++ if (gpo_regulator) ++ if (regulator_enable(gpo_regulator) != 0) ++ return -EIO; ++ if (analog_regulator) ++ if (regulator_enable(analog_regulator) != 0) ++ return -EIO; ++ /* Make sure power on */ ++ ov5642_standby(0); ++ } else if (!on && sensor->on) { ++ if (analog_regulator) ++ regulator_disable(analog_regulator); ++ if (core_regulator) ++ regulator_disable(core_regulator); ++ if (io_regulator) ++ regulator_disable(io_regulator); ++ if (gpo_regulator) ++ regulator_disable(gpo_regulator); ++ ++ ov5642_standby(1); ++ } ++ ++ sensor->on = on; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure ++ * ++ * Returns the sensor's video CAPTURE parameters. ++ */ ++static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) ++{ ++ struct sensor_data *sensor = s->priv; ++ struct v4l2_captureparm *cparm = &a->parm.capture; ++ int ret = 0; ++ ++ switch (a->type) { ++ /* This is the only case currently handled. */ ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ memset(a, 0, sizeof(*a)); ++ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ++ cparm->capability = sensor->streamcap.capability; ++ cparm->timeperframe = sensor->streamcap.timeperframe; ++ cparm->capturemode = sensor->streamcap.capturemode; ++ ret = 0; ++ break; ++ ++ /* These are all the possible cases. */ ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ case V4L2_BUF_TYPE_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_VBI_OUTPUT: ++ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: ++ ret = -EINVAL; ++ break; ++ ++ default: ++ pr_debug(" type is unknown - %d\n", a->type); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure ++ * ++ * Configures the sensor to use the input parameters, if possible. If ++ * not possible, reverts to the old parameters and returns the ++ * appropriate error code. ++ */ ++static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) ++{ ++ struct sensor_data *sensor = s->priv; ++ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; ++ u32 tgt_fps, old_fps; /* target frames per secound */ ++ enum ov5642_frame_rate new_frame_rate, old_frame_rate; ++ int ret = 0; ++ ++ /* Make sure power on */ ++ ov5642_standby(0); ++ ++ switch (a->type) { ++ /* This is the only case currently handled. */ ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE: ++ /* Check that the new frame rate is allowed. */ ++ if ((timeperframe->numerator == 0) || ++ (timeperframe->denominator == 0)) { ++ timeperframe->denominator = DEFAULT_FPS; ++ timeperframe->numerator = 1; ++ } ++ ++ tgt_fps = timeperframe->denominator / ++ timeperframe->numerator; ++ ++ if (tgt_fps > MAX_FPS) { ++ timeperframe->denominator = MAX_FPS; ++ timeperframe->numerator = 1; ++ } else if (tgt_fps < MIN_FPS) { ++ timeperframe->denominator = MIN_FPS; ++ timeperframe->numerator = 1; ++ } ++ ++ /* Actual frame rate we use */ ++ tgt_fps = timeperframe->denominator / ++ timeperframe->numerator; ++ ++ if (tgt_fps == 15) ++ new_frame_rate = ov5642_15_fps; ++ else if (tgt_fps == 30) ++ new_frame_rate = ov5642_30_fps; ++ else { ++ pr_err(" The camera frame rate is not supported!\n"); ++ return -EINVAL; ++ } ++ ++ if (sensor->streamcap.timeperframe.numerator != 0) ++ old_fps = sensor->streamcap.timeperframe.denominator / ++ sensor->streamcap.timeperframe.numerator; ++ else ++ old_fps = 30; ++ ++ if (old_fps == 15) ++ old_frame_rate = ov5642_15_fps; ++ else if (old_fps == 30) ++ old_frame_rate = ov5642_30_fps; ++ else { ++ pr_warning(" No valid frame rate set!\n"); ++ old_frame_rate = ov5642_30_fps; ++ } ++ ++ ret = ov5642_change_mode(new_frame_rate, old_frame_rate, ++ a->parm.capture.capturemode, ++ sensor->streamcap.capturemode); ++ if (ret < 0) ++ return ret; ++ ++ sensor->streamcap.timeperframe = *timeperframe; ++ sensor->streamcap.capturemode = ++ (u32)a->parm.capture.capturemode; ++ break; ++ ++ /* These are all the possible cases. */ ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT: ++ case V4L2_BUF_TYPE_VIDEO_OVERLAY: ++ case V4L2_BUF_TYPE_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_VBI_OUTPUT: ++ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: ++ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: ++ pr_debug(" type is not " \ ++ "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n", ++ a->type); ++ ret = -EINVAL; ++ break; ++ ++ default: ++ pr_debug(" type is unknown - %d\n", a->type); ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap ++ * @s: pointer to standard V4L2 device structure ++ * @f: pointer to standard V4L2 v4l2_format structure ++ * ++ * Returns the sensor's current pixel format in the v4l2_format ++ * parameter. ++ */ ++static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) ++{ ++ struct sensor_data *sensor = s->priv; ++ ++ f->fmt.pix = sensor->pix; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure ++ * ++ * If the requested control is supported, returns the control's current ++ * value from the video_control[] array. Otherwise, returns -EINVAL ++ * if the control is not supported. ++ */ ++static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) ++{ ++ int ret = 0; ++ ++ switch (vc->id) { ++ case V4L2_CID_BRIGHTNESS: ++ vc->value = ov5642_data.brightness; ++ break; ++ case V4L2_CID_HUE: ++ vc->value = ov5642_data.hue; ++ break; ++ case V4L2_CID_CONTRAST: ++ vc->value = ov5642_data.contrast; ++ break; ++ case V4L2_CID_SATURATION: ++ vc->value = ov5642_data.saturation; ++ break; ++ case V4L2_CID_RED_BALANCE: ++ vc->value = ov5642_data.red; ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ vc->value = ov5642_data.blue; ++ break; ++ case V4L2_CID_EXPOSURE: ++ vc->value = ov5642_data.ae_mode; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++/*! ++ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure ++ * ++ * If the requested control is supported, sets the control's current ++ * value in HW (and updates the video_control[] array). Otherwise, ++ * returns -EINVAL if the control is not supported. ++ */ ++static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) ++{ ++ int retval = 0; ++ struct sensor_data *sensor = s->priv; ++ __u32 captureMode = sensor->streamcap.capturemode; ++ struct reg_value *rot_mode = NULL; ++ ++ pr_debug("In ov5642:ioctl_s_ctrl %d\n", ++ vc->id); ++ ++ switch (vc->id) { ++ case V4L2_CID_BRIGHTNESS: ++ break; ++ case V4L2_CID_CONTRAST: ++ break; ++ case V4L2_CID_SATURATION: ++ break; ++ case V4L2_CID_HUE: ++ break; ++ case V4L2_CID_AUTO_WHITE_BALANCE: ++ break; ++ case V4L2_CID_DO_WHITE_BALANCE: ++ break; ++ case V4L2_CID_RED_BALANCE: ++ break; ++ case V4L2_CID_BLUE_BALANCE: ++ break; ++ case V4L2_CID_GAMMA: ++ break; ++ case V4L2_CID_EXPOSURE: ++ break; ++ case V4L2_CID_AUTOGAIN: ++ break; ++ case V4L2_CID_GAIN: ++ break; ++ case V4L2_CID_HFLIP: ++ break; ++ case V4L2_CID_VFLIP: ++ break; ++ case V4L2_CID_MXC_ROT: ++ case V4L2_CID_MXC_VF_ROT: ++ switch (vc->value) { ++ case V4L2_MXC_ROTATE_NONE: ++ if (captureMode == ov5642_mode_QSXGA_2592_1944) ++ rot_mode = ov5642_rot_none_FULL; ++ else ++ rot_mode = ov5642_rot_none_VGA; ++ ++ if (ov5642_set_rot_mode(rot_mode)) ++ retval = -EPERM; ++ break; ++ case V4L2_MXC_ROTATE_VERT_FLIP: ++ if (captureMode == ov5642_mode_QSXGA_2592_1944) ++ rot_mode = ov5642_rot_vert_flip_FULL; ++ else ++ rot_mode = ov5642_rot_vert_flip_VGA ; ++ ++ if (ov5642_set_rot_mode(rot_mode)) ++ retval = -EPERM; ++ break; ++ case V4L2_MXC_ROTATE_HORIZ_FLIP: ++ if (captureMode == ov5642_mode_QSXGA_2592_1944) ++ rot_mode = ov5642_rot_horiz_flip_FULL; ++ else ++ rot_mode = ov5642_rot_horiz_flip_VGA; ++ ++ if (ov5642_set_rot_mode(rot_mode)) ++ retval = -EPERM; ++ break; ++ case V4L2_MXC_ROTATE_180: ++ if (captureMode == ov5642_mode_QSXGA_2592_1944) ++ rot_mode = ov5642_rot_180_FULL; ++ else ++ rot_mode = ov5642_rot_180_VGA; ++ ++ if (ov5642_set_rot_mode(rot_mode)) ++ retval = -EPERM; ++ break; ++ default: ++ retval = -EPERM; ++ break; ++ } ++ break; ++ default: ++ retval = -EPERM; ++ break; ++ } ++ ++ return retval; ++} ++ ++/*! ++ * ioctl_enum_framesizes - V4L2 sensor interface handler for ++ * VIDIOC_ENUM_FRAMESIZES ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure ++ * ++ * Return 0 if successful, otherwise -EINVAL. ++ */ ++static int ioctl_enum_framesizes(struct v4l2_int_device *s, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ if (fsize->index > ov5642_mode_MAX) ++ return -EINVAL; ++ ++ fsize->pixel_format = ov5642_data.pix.pixelformat; ++ fsize->discrete.width = ++ max(ov5642_mode_info_data[0][fsize->index].width, ++ ov5642_mode_info_data[1][fsize->index].width); ++ fsize->discrete.height = ++ max(ov5642_mode_info_data[0][fsize->index].height, ++ ov5642_mode_info_data[1][fsize->index].height); ++ return 0; ++} ++ ++/*! ++ * ioctl_enum_frameintervals - V4L2 sensor interface handler for ++ * VIDIOC_ENUM_FRAMEINTERVALS ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure ++ * ++ * Return 0 if successful, otherwise -EINVAL. ++ */ ++static int ioctl_enum_frameintervals(struct v4l2_int_device *s, ++ struct v4l2_frmivalenum *fival) ++{ ++ int i, j, count; ++ ++ if (fival->index < 0 || fival->index > ov5642_mode_MAX) ++ return -EINVAL; ++ ++ if (fival->pixel_format == 0 || fival->width == 0 || ++ fival->height == 0) { ++ pr_warning("Please assign pixelformat, width and height.\n"); ++ return -EINVAL; ++ } ++ ++ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; ++ fival->discrete.numerator = 1; ++ ++ count = 0; ++ for (i = 0; i < ARRAY_SIZE(ov5642_mode_info_data); i++) { ++ for (j = 0; j < (ov5642_mode_MAX + 1); j++) { ++ if (fival->pixel_format == ov5642_data.pix.pixelformat ++ && fival->width == ov5642_mode_info_data[i][j].width ++ && fival->height == ov5642_mode_info_data[i][j].height ++ && ov5642_mode_info_data[i][j].init_data_ptr != NULL) { ++ count++; ++ } ++ if (fival->index == (count - 1)) { ++ fival->discrete.denominator = ++ ov5642_framerates[i]; ++ return 0; ++ } ++ } ++ } ++ ++ return -EINVAL; ++} ++ ++/*! ++ * ioctl_g_chip_ident - V4L2 sensor interface handler for ++ * VIDIOC_DBG_G_CHIP_IDENT ioctl ++ * @s: pointer to standard V4L2 device structure ++ * @id: pointer to int ++ * ++ * Return 0. ++ */ ++static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id) ++{ ++ ((struct v4l2_dbg_chip_ident *)id)->match.type = ++ V4L2_CHIP_MATCH_I2C_DRIVER; ++ strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, "ov5642_camera"); ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT ++ * @s: pointer to standard V4L2 device structure ++ */ ++static int ioctl_init(struct v4l2_int_device *s) ++{ ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT ++ * @s: pointer to standard V4L2 device structure ++ * @fmt: pointer to standard V4L2 fmt description structure ++ * ++ * Return 0. ++ */ ++static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, ++ struct v4l2_fmtdesc *fmt) ++{ ++ if (fmt->index > 0) /* only 1 pixelformat support so far */ ++ return -EINVAL; ++ ++ fmt->pixelformat = ov5642_data.pix.pixelformat; ++ ++ return 0; ++} ++ ++/*! ++ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num ++ * @s: pointer to standard V4L2 device structure ++ * ++ * Initialise the device when slave attaches to the master. ++ */ ++static int ioctl_dev_init(struct v4l2_int_device *s) ++{ ++ struct reg_value *pModeSetting = NULL; ++ s32 i = 0; ++ s32 iModeSettingArySize = 0; ++ register u32 Delay_ms = 0; ++ register u16 RegAddr = 0; ++ register u8 Mask = 0; ++ register u8 Val = 0; ++ u8 RegVal = 0; ++ int retval = 0; ++ ++ struct sensor_data *sensor = s->priv; ++ u32 tgt_xclk; /* target xclk */ ++ u32 tgt_fps; /* target frames per secound */ ++ enum ov5642_frame_rate frame_rate; ++ ++ ov5642_data.on = true; ++ ++ /* mclk */ ++ tgt_xclk = ov5642_data.mclk; ++ tgt_xclk = min(tgt_xclk, (u32)OV5642_XCLK_MAX); ++ tgt_xclk = max(tgt_xclk, (u32)OV5642_XCLK_MIN); ++ ov5642_data.mclk = tgt_xclk; ++ ++ pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); ++ ++ /* Default camera frame rate is set in probe */ ++ tgt_fps = sensor->streamcap.timeperframe.denominator / ++ sensor->streamcap.timeperframe.numerator; ++ ++ if (tgt_fps == 15) ++ frame_rate = ov5642_15_fps; ++ else if (tgt_fps == 30) ++ frame_rate = ov5642_30_fps; ++ else ++ return -EINVAL; /* Only support 15fps or 30fps now. */ ++ ++ pModeSetting = ov5642_initial_setting; ++ iModeSettingArySize = ARRAY_SIZE(ov5642_initial_setting); ++ ++ for (i = 0; i < iModeSettingArySize; ++i, ++pModeSetting) { ++ Delay_ms = pModeSetting->u32Delay_ms; ++ RegAddr = pModeSetting->u16RegAddr; ++ Val = pModeSetting->u8Val; ++ Mask = pModeSetting->u8Mask; ++ if (Mask) { ++ retval = ov5642_read_reg(RegAddr, &RegVal); ++ if (retval < 0) ++ goto err; ++ ++ RegVal &= ~(u8)Mask; ++ Val &= Mask; ++ Val |= RegVal; ++ } ++ ++ retval = ov5642_write_reg(RegAddr, Val); ++ if (retval < 0) ++ goto err; ++ ++ if (Delay_ms) ++ msleep(Delay_ms); ++ } ++err: ++ return retval; ++} ++ ++/*! ++ * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num ++ * @s: pointer to standard V4L2 device structure ++ * ++ * Delinitialise the device when slave detaches to the master. ++ */ ++static int ioctl_dev_exit(struct v4l2_int_device *s) ++{ ++ return 0; ++} ++ ++/*! ++ * This structure defines all the ioctls for this module and links them to the ++ * enumeration. ++ */ ++static struct v4l2_int_ioctl_desc ov5642_ioctl_desc[] = { ++ { vidioc_int_dev_init_num, ++ (v4l2_int_ioctl_func *)ioctl_dev_init }, ++ { vidioc_int_dev_exit_num, ioctl_dev_exit}, ++ { vidioc_int_s_power_num, ++ (v4l2_int_ioctl_func *)ioctl_s_power }, ++ { vidioc_int_g_ifparm_num, ++ (v4l2_int_ioctl_func *)ioctl_g_ifparm }, ++/* { vidioc_int_g_needs_reset_num, ++ (v4l2_int_ioctl_func *)ioctl_g_needs_reset }, */ ++/* { vidioc_int_reset_num, ++ (v4l2_int_ioctl_func *)ioctl_reset }, */ ++ { vidioc_int_init_num, ++ (v4l2_int_ioctl_func *)ioctl_init }, ++ { vidioc_int_enum_fmt_cap_num, ++ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap }, ++/* { vidioc_int_try_fmt_cap_num, ++ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap }, */ ++ { vidioc_int_g_fmt_cap_num, ++ (v4l2_int_ioctl_func *)ioctl_g_fmt_cap }, ++/* { vidioc_int_s_fmt_cap_num, ++ (v4l2_int_ioctl_func *)ioctl_s_fmt_cap }, */ ++ { vidioc_int_g_parm_num, ++ (v4l2_int_ioctl_func *)ioctl_g_parm }, ++ { vidioc_int_s_parm_num, ++ (v4l2_int_ioctl_func *)ioctl_s_parm }, ++/* { vidioc_int_queryctrl_num, ++ (v4l2_int_ioctl_func *)ioctl_queryctrl }, */ ++ { vidioc_int_g_ctrl_num, ++ (v4l2_int_ioctl_func *)ioctl_g_ctrl }, ++ { vidioc_int_s_ctrl_num, ++ (v4l2_int_ioctl_func *)ioctl_s_ctrl }, ++ { vidioc_int_enum_framesizes_num, ++ (v4l2_int_ioctl_func *)ioctl_enum_framesizes }, ++ { vidioc_int_enum_frameintervals_num, ++ (v4l2_int_ioctl_func *)ioctl_enum_frameintervals }, ++ { vidioc_int_g_chip_ident_num, ++ (v4l2_int_ioctl_func *)ioctl_g_chip_ident }, ++}; ++ ++static struct v4l2_int_slave ov5642_slave = { ++ .ioctls = ov5642_ioctl_desc, ++ .num_ioctls = ARRAY_SIZE(ov5642_ioctl_desc), ++}; ++ ++static struct v4l2_int_device ov5642_int_device = { ++ .module = THIS_MODULE, ++ .name = "ov5642", ++ .type = v4l2_int_type_slave, ++ .u = { ++ .slave = &ov5642_slave, ++ }, ++}; ++ ++/*! ++ * ov5642 I2C probe function ++ * ++ * @param adapter struct i2c_adapter * ++ * @return Error code indicating success or failure ++ */ ++static int ov5642_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct pinctrl *pinctrl; ++ struct device *dev = &client->dev; ++ int retval; ++ u8 chip_id_high, chip_id_low; ++ ++ /* ov5642 pinctrl */ ++ pinctrl = devm_pinctrl_get_select_default(dev); ++ if (IS_ERR(pinctrl)) { ++ dev_err(dev, "ov5642 setup pinctrl failed!"); ++ return PTR_ERR(pinctrl); ++ } ++ ++ /* request power down pin */ ++ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); ++ if (!gpio_is_valid(pwn_gpio)) { ++ dev_warn(dev, "no sensor pwdn pin available"); ++ return -EINVAL; ++ } ++ retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, ++ "ov5642_pwdn"); ++ if (retval < 0) ++ return retval; ++ ++ /* request reset pin */ ++ rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0); ++ if (!gpio_is_valid(rst_gpio)) { ++ dev_warn(dev, "no sensor reset pin available"); ++ return -EINVAL; ++ } ++ retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH, ++ "ov5642_reset"); ++ if (retval < 0) ++ return retval; ++ ++ /* Set initial values for the sensor struct. */ ++ memset(&ov5642_data, 0, sizeof(ov5642_data)); ++ ov5642_data.sensor_clk = devm_clk_get(dev, "csi_mclk"); ++ if (IS_ERR(ov5642_data.sensor_clk)) { ++ /* assuming clock enabled by default */ ++ ov5642_data.sensor_clk = NULL; ++ dev_err(dev, "clock-frequency missing or invalid\n"); ++ return PTR_ERR(ov5642_data.sensor_clk); ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "mclk", ++ (u32 *) &(ov5642_data.mclk)); ++ if (retval) { ++ dev_err(dev, "mclk missing or invalid\n"); ++ return retval; ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "mclk_source", ++ (u32 *) &(ov5642_data.mclk_source)); ++ if (retval) { ++ dev_err(dev, "mclk_source missing or invalid\n"); ++ return retval; ++ } ++ ++ retval = of_property_read_u32(dev->of_node, "csi_id", ++ &(ov5642_data.csi)); ++ if (retval) { ++ dev_err(dev, "csi_id missing or invalid\n"); ++ return retval; ++ } ++ ++ clk_prepare_enable(ov5642_data.sensor_clk); ++ ++ ov5642_data.io_init = ov5642_reset; ++ ov5642_data.i2c_client = client; ++ ov5642_data.pix.pixelformat = V4L2_PIX_FMT_YUYV; ++ ov5642_data.pix.width = 640; ++ ov5642_data.pix.height = 480; ++ ov5642_data.streamcap.capability = V4L2_MODE_HIGHQUALITY | ++ V4L2_CAP_TIMEPERFRAME; ++ ov5642_data.streamcap.capturemode = 0; ++ ov5642_data.streamcap.timeperframe.denominator = DEFAULT_FPS; ++ ov5642_data.streamcap.timeperframe.numerator = 1; ++ ++ ov5642_power_on(&client->dev); ++ ++ ov5642_reset(); ++ ++ ov5642_standby(0); ++ ++ retval = ov5642_read_reg(OV5642_CHIP_ID_HIGH_BYTE, &chip_id_high); ++ if (retval < 0 || chip_id_high != 0x56) { ++ pr_warning("camera ov5642 is not found\n"); ++ clk_disable_unprepare(ov5642_data.sensor_clk); ++ return -ENODEV; ++ } ++ retval = ov5642_read_reg(OV5642_CHIP_ID_LOW_BYTE, &chip_id_low); ++ if (retval < 0 || chip_id_low != 0x42) { ++ pr_warning("camera ov5642 is not found\n"); ++ clk_disable_unprepare(ov5642_data.sensor_clk); ++ return -ENODEV; ++ } ++ ++ ov5642_standby(1); ++ ++ ov5642_int_device.priv = &ov5642_data; ++ retval = v4l2_int_device_register(&ov5642_int_device); ++ ++ clk_disable_unprepare(ov5642_data.sensor_clk); ++ ++ pr_info("camera ov5642 is found\n"); ++ return retval; ++} ++ ++/*! ++ * ov5642 I2C detach function ++ * ++ * @param client struct i2c_client * ++ * @return Error code indicating success or failure ++ */ ++static int ov5642_remove(struct i2c_client *client) ++{ ++ v4l2_int_device_unregister(&ov5642_int_device); ++ ++ if (gpo_regulator) ++ regulator_disable(gpo_regulator); ++ ++ if (analog_regulator) ++ regulator_disable(analog_regulator); ++ ++ if (core_regulator) ++ regulator_disable(core_regulator); ++ ++ if (io_regulator) ++ regulator_disable(io_regulator); ++ ++ return 0; ++} ++ ++/*! ++ * ov5642 init function ++ * Called by insmod ov5642_camera.ko. ++ * ++ * @return Error code indicating success or failure ++ */ ++static __init int ov5642_init(void) ++{ ++ u8 err; ++ ++ err = i2c_add_driver(&ov5642_i2c_driver); ++ if (err != 0) ++ pr_err("%s:driver registration failed, error=%d\n", ++ __func__, err); ++ ++ return err; ++} ++ ++/*! ++ * OV5642 cleanup function ++ * Called on rmmod ov5642_camera.ko ++ * ++ * @return Error code indicating success or failure ++ */ ++static void __exit ov5642_clean(void) ++{ ++ i2c_del_driver(&ov5642_i2c_driver); ++} ++ ++module_init(ov5642_init); ++module_exit(ov5642_clean); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("OV5642 Camera Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION("1.0"); ++MODULE_ALIAS("CSI"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/output/Kconfig linux-3.10.30-cubox-i/drivers/media/platform/mxc/output/Kconfig +--- linux-3.10.30/drivers/media/platform/mxc/output/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/output/Kconfig 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,16 @@ ++config VIDEO_MXC_IPU_OUTPUT ++ tristate "IPU v4l2 output support" ++ depends on VIDEO_MXC_OUTPUT && MXC_IPU ++ ---help--- ++ This is the video4linux2 driver for IPU post processing video output. ++ ++config VIDEO_MXC_PXP_V4L2 ++ tristate "MXC PxP V4L2 driver" ++ depends on VIDEO_DEV && VIDEO_V4L2 ++ select VIDEOBUF_DMA_CONTIG ++ ---help--- ++ This is a video4linux driver for the Freescale PxP ++ (Pixel Pipeline). This module supports output overlay of ++ the MXC framebuffer on a video stream. ++ ++ To compile this driver as a module, choose M here. +diff -Nur linux-3.10.30/drivers/media/platform/mxc/output/Makefile linux-3.10.30-cubox-i/drivers/media/platform/mxc/output/Makefile +--- linux-3.10.30/drivers/media/platform/mxc/output/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/output/Makefile 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,2 @@ ++obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT) += mxc_vout.o ++obj-$(CONFIG_VIDEO_MXC_PXP_V4L2) += mxc_pxp_v4l2.o +diff -Nur linux-3.10.30/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c +--- linux-3.10.30/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,1263 @@ ++/* ++ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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 ++ * ++ */ ++/* ++ * Based on STMP378X PxP driver ++ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "mxc_pxp_v4l2.h" ++ ++#define PXP_DRIVER_NAME "pxp-v4l2" ++#define PXP_DRIVER_MAJOR 2 ++#define PXP_DRIVER_MINOR 0 ++ ++#define PXP_DEF_BUFS 2 ++#define PXP_MIN_PIX 8 ++ ++#define V4L2_OUTPUT_TYPE_INTERNAL 4 ++ ++static int video_nr = -1; /* -1 ==> auto assign */ ++static struct pxp_data_format pxp_s0_formats[] = { ++ { ++ .name = "24-bit RGB", ++ .bpp = 4, ++ .fourcc = V4L2_PIX_FMT_RGB24, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, { ++ .name = "16-bit RGB 5:6:5", ++ .bpp = 2, ++ .fourcc = V4L2_PIX_FMT_RGB565, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, { ++ .name = "16-bit RGB 5:5:5", ++ .bpp = 2, ++ .fourcc = V4L2_PIX_FMT_RGB555, ++ .colorspace = V4L2_COLORSPACE_SRGB, ++ }, { ++ .name = "YUV 4:2:0 Planar", ++ .bpp = 2, ++ .fourcc = V4L2_PIX_FMT_YUV420, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, { ++ .name = "YUV 4:2:2 Planar", ++ .bpp = 2, ++ .fourcc = V4L2_PIX_FMT_YUV422P, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, { ++ .name = "UYVY", ++ .bpp = 2, ++ .fourcc = V4L2_PIX_FMT_UYVY, ++ .colorspace = V4L2_COLORSPACE_JPEG, ++ }, ++}; ++ ++static unsigned int v4l2_fmt_to_pxp_fmt(u32 v4l2_pix_fmt) ++{ ++ u32 pxp_fmt = 0; ++ ++ if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB24) ++ pxp_fmt = PXP_PIX_FMT_RGB24; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB565) ++ pxp_fmt = PXP_PIX_FMT_RGB565; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555) ++ pxp_fmt = PXP_PIX_FMT_RGB555; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555) ++ pxp_fmt = PXP_PIX_FMT_RGB555; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV420) ++ pxp_fmt = PXP_PIX_FMT_YUV420P; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV422P) ++ pxp_fmt = PXP_PIX_FMT_YUV422P; ++ else if (v4l2_pix_fmt == V4L2_PIX_FMT_UYVY) ++ pxp_fmt = PXP_PIX_FMT_UYVY; ++ ++ return pxp_fmt; ++} ++struct v4l2_queryctrl pxp_controls[] = { ++ { ++ .id = V4L2_CID_HFLIP, ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .name = "Horizontal Flip", ++ .minimum = 0, ++ .maximum = 1, ++ .step = 1, ++ .default_value = 0, ++ .flags = 0, ++ }, { ++ .id = V4L2_CID_VFLIP, ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ .name = "Vertical Flip", ++ .minimum = 0, ++ .maximum = 1, ++ .step = 1, ++ .default_value = 0, ++ .flags = 0, ++ }, { ++ .id = V4L2_CID_PRIVATE_BASE, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ .name = "Rotation", ++ .minimum = 0, ++ .maximum = 270, ++ .step = 90, ++ .default_value = 0, ++ .flags = 0, ++ }, { ++ .id = V4L2_CID_PRIVATE_BASE + 1, ++ .name = "Background Color", ++ .minimum = 0, ++ .maximum = 0xFFFFFF, ++ .step = 1, ++ .default_value = 0, ++ .flags = 0, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ }, { ++ .id = V4L2_CID_PRIVATE_BASE + 2, ++ .name = "Set S0 Chromakey", ++ .minimum = -1, ++ .maximum = 0xFFFFFF, ++ .step = 1, ++ .default_value = -1, ++ .flags = 0, ++ .type = V4L2_CTRL_TYPE_INTEGER, ++ }, { ++ .id = V4L2_CID_PRIVATE_BASE + 3, ++ .name = "YUV Colorspace", ++ .minimum = 0, ++ .maximum = 1, ++ .step = 1, ++ .default_value = 0, ++ .flags = 0, ++ .type = V4L2_CTRL_TYPE_BOOLEAN, ++ }, ++}; ++ ++/* callback function */ ++static void video_dma_done(void *arg) ++{ ++ struct pxp_tx_desc *tx_desc = to_tx_desc(arg); ++ struct dma_chan *chan = tx_desc->txd.chan; ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ struct pxps *pxp = pxp_chan->client; ++ struct videobuf_buffer *vb; ++ ++ dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n", ++ tx_desc->txd.cookie, ++ pxp->active ? sg_dma_address(&pxp->active->sg[0]) : 0); ++ ++ spin_lock(&pxp->lock); ++ if (pxp->active) { ++ vb = &pxp->active->vb; ++ ++ list_del_init(&vb->queue); ++ vb->state = VIDEOBUF_DONE; ++ do_gettimeofday(&vb->ts); ++ vb->field_count++; ++ wake_up(&vb->done); ++ } ++ ++ if (list_empty(&pxp->outq)) { ++ pxp->active = NULL; ++ spin_unlock(&pxp->lock); ++ ++ return; ++ } ++ ++ pxp->active = list_entry(pxp->outq.next, ++ struct pxp_buffer, vb.queue); ++ pxp->active->vb.state = VIDEOBUF_ACTIVE; ++ spin_unlock(&pxp->lock); ++} ++ ++static int acquire_dma_channel(struct pxps *pxp) ++{ ++ dma_cap_mask_t mask; ++ struct dma_chan *chan; ++ struct pxp_channel **pchan = &pxp->pxp_channel[0]; ++ ++ if (*pchan) { ++ struct videobuf_buffer *vb, *_vb; ++ dma_release_channel(&(*pchan)->dma_chan); ++ *pchan = NULL; ++ pxp->active = NULL; ++ list_for_each_entry_safe(vb, _vb, &pxp->outq, queue) { ++ list_del_init(&vb->queue); ++ vb->state = VIDEOBUF_ERROR; ++ wake_up(&vb->done); ++ } ++ } ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_SLAVE, mask); ++ dma_cap_set(DMA_PRIVATE, mask); ++ chan = dma_request_channel(mask, NULL, NULL); ++ if (!chan) ++ return -EBUSY; ++ ++ *pchan = to_pxp_channel(chan); ++ (*pchan)->client = pxp; ++ ++ return 0; ++} ++ ++static int _get_fbinfo(struct fb_info **fbi) ++{ ++ int i; ++ for (i = 0; i < num_registered_fb; i++) { ++ char *idstr = registered_fb[i]->fix.id; ++ if (strcmp(idstr, "mxs") == 0) { ++ *fbi = registered_fb[i]; ++ return 0; ++ } ++ } ++ ++ return -ENODEV; ++} ++ ++static int pxp_set_fbinfo(struct pxps *pxp) ++{ ++ struct v4l2_framebuffer *fb = &pxp->fb; ++ int err; ++ ++ err = _get_fbinfo(&pxp->fbi); ++ if (err) ++ return err; ++ ++ fb->fmt.width = pxp->fbi->var.xres; ++ fb->fmt.height = pxp->fbi->var.yres; ++ pxp->pxp_conf.out_param.stride = pxp->fbi->var.xres; ++ if (pxp->fbi->var.bits_per_pixel == 16) ++ fb->fmt.pixelformat = V4L2_PIX_FMT_RGB565; ++ else ++ fb->fmt.pixelformat = V4L2_PIX_FMT_RGB24; ++ ++ fb->base = (void *)pxp->fbi->fix.smem_start; ++ ++ return 0; ++} ++ ++static int _get_cur_fb_blank(struct pxps *pxp) ++{ ++ struct fb_info *fbi; ++ mm_segment_t old_fs; ++ int err = 0; ++ ++ err = _get_fbinfo(&fbi); ++ if (err) ++ return err; ++ ++ if (fbi->fbops->fb_ioctl) { ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_BLANK, ++ (unsigned int)(&pxp->fb_blank)); ++ set_fs(old_fs); ++ } ++ ++ return err; ++} ++ ++static int pxp_show_buf(struct pxps *pxp, bool toshow) ++{ ++ struct fb_info *fbi = pxp->fbi; ++ int ret; ++ ++ console_lock(); ++ fbi->fix.smem_start = toshow ? ++ pxp->outb_phys : (unsigned long)pxp->fb.base; ++ ret = fb_pan_display(fbi, &fbi->var); ++ console_unlock(); ++ ++ return ret; ++} ++ ++static int set_fb_blank(int blank) ++{ ++ struct fb_info *fbi; ++ int err = 0; ++ ++ err = _get_fbinfo(&fbi); ++ if (err) ++ return err; ++ ++ console_lock(); ++ fb_blank(fbi, blank); ++ console_unlock(); ++ ++ return err; ++} ++ ++static int pxp_set_cstate(struct pxps *pxp, struct v4l2_control *vc) ++{ ++ ++ if (vc->id == V4L2_CID_HFLIP) { ++ pxp->pxp_conf.proc_data.hflip = vc->value; ++ } else if (vc->id == V4L2_CID_VFLIP) { ++ pxp->pxp_conf.proc_data.vflip = vc->value; ++ } else if (vc->id == V4L2_CID_PRIVATE_BASE) { ++ if (vc->value % 90) ++ return -ERANGE; ++ pxp->pxp_conf.proc_data.rotate = vc->value; ++ } else if (vc->id == V4L2_CID_PRIVATE_BASE + 1) { ++ pxp->pxp_conf.proc_data.bgcolor = vc->value; ++ } else if (vc->id == V4L2_CID_PRIVATE_BASE + 2) { ++ pxp->pxp_conf.s0_param.color_key = vc->value; ++ } else if (vc->id == V4L2_CID_PRIVATE_BASE + 3) { ++ pxp->pxp_conf.proc_data.yuv = vc->value; ++ } ++ ++ return 0; ++} ++ ++static int pxp_get_cstate(struct pxps *pxp, struct v4l2_control *vc) ++{ ++ if (vc->id == V4L2_CID_HFLIP) ++ vc->value = pxp->pxp_conf.proc_data.hflip; ++ else if (vc->id == V4L2_CID_VFLIP) ++ vc->value = pxp->pxp_conf.proc_data.vflip; ++ else if (vc->id == V4L2_CID_PRIVATE_BASE) ++ vc->value = pxp->pxp_conf.proc_data.rotate; ++ else if (vc->id == V4L2_CID_PRIVATE_BASE + 1) ++ vc->value = pxp->pxp_conf.proc_data.bgcolor; ++ else if (vc->id == V4L2_CID_PRIVATE_BASE + 2) ++ vc->value = pxp->pxp_conf.s0_param.color_key; ++ else if (vc->id == V4L2_CID_PRIVATE_BASE + 3) ++ vc->value = pxp->pxp_conf.proc_data.yuv; ++ ++ return 0; ++} ++ ++static int pxp_enumoutput(struct file *file, void *fh, ++ struct v4l2_output *o) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ if ((o->index < 0) || (o->index > 1)) ++ return -EINVAL; ++ ++ memset(o, 0, sizeof(struct v4l2_output)); ++ if (o->index == 0) { ++ strcpy(o->name, "PxP Display Output"); ++ pxp->output = 0; ++ } else { ++ strcpy(o->name, "PxP Virtual Output"); ++ pxp->output = 1; ++ } ++ o->type = V4L2_OUTPUT_TYPE_INTERNAL; ++ o->std = 0; ++ o->reserved[0] = pxp->outb_phys; ++ ++ return 0; ++} ++ ++static int pxp_g_output(struct file *file, void *fh, ++ unsigned int *i) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ *i = pxp->output; ++ ++ return 0; ++} ++ ++static int pxp_s_output(struct file *file, void *fh, ++ unsigned int i) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct v4l2_pix_format *fmt = &pxp->fb.fmt; ++ int bpp; ++ ++ if ((i < 0) || (i > 1)) ++ return -EINVAL; ++ ++ if (pxp->outb) ++ return 0; ++ ++ /* Output buffer is same format as fbdev */ ++ if (fmt->pixelformat == V4L2_PIX_FMT_RGB24) ++ bpp = 4; ++ else ++ bpp = 2; ++ ++ pxp->outb_size = fmt->width * fmt->height * bpp; ++ pxp->outb = kmalloc(fmt->width * fmt->height * bpp, ++ GFP_KERNEL | GFP_DMA); ++ if (pxp->outb == NULL) { ++ dev_err(&pxp->pdev->dev, "No enough memory!\n"); ++ return -ENOMEM; ++ } ++ pxp->outb_phys = virt_to_phys(pxp->outb); ++ dma_map_single(NULL, pxp->outb, ++ fmt->width * fmt->height * bpp, DMA_TO_DEVICE); ++ ++ pxp->pxp_conf.out_param.width = fmt->width; ++ pxp->pxp_conf.out_param.height = fmt->height; ++ if (fmt->pixelformat == V4L2_PIX_FMT_RGB24) ++ pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB24; ++ else ++ pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB565; ++ ++ return 0; ++} ++ ++static int pxp_enum_fmt_video_output(struct file *file, void *fh, ++ struct v4l2_fmtdesc *fmt) ++{ ++ enum v4l2_buf_type type = fmt->type; ++ int index = fmt->index; ++ ++ if ((fmt->index < 0) || (fmt->index >= ARRAY_SIZE(pxp_s0_formats))) ++ return -EINVAL; ++ ++ memset(fmt, 0, sizeof(struct v4l2_fmtdesc)); ++ fmt->index = index; ++ fmt->type = type; ++ fmt->pixelformat = pxp_s0_formats[index].fourcc; ++ strcpy(fmt->description, pxp_s0_formats[index].name); ++ ++ return 0; ++} ++ ++static int pxp_g_fmt_video_output(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct v4l2_pix_format *pf = &f->fmt.pix; ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct pxp_data_format *fmt = pxp->s0_fmt; ++ ++ pf->width = pxp->pxp_conf.s0_param.width; ++ pf->height = pxp->pxp_conf.s0_param.height; ++ pf->pixelformat = fmt->fourcc; ++ pf->field = V4L2_FIELD_NONE; ++ pf->bytesperline = fmt->bpp * pf->width; ++ pf->sizeimage = pf->bytesperline * pf->height; ++ pf->colorspace = fmt->colorspace; ++ pf->priv = 0; ++ ++ return 0; ++} ++ ++static struct pxp_data_format *pxp_get_format(struct v4l2_format *f) ++{ ++ struct pxp_data_format *fmt; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pxp_s0_formats); i++) { ++ fmt = &pxp_s0_formats[i]; ++ if (fmt->fourcc == f->fmt.pix.pixelformat) ++ break; ++ } ++ ++ if (i == ARRAY_SIZE(pxp_s0_formats)) ++ return NULL; ++ ++ return &pxp_s0_formats[i]; ++} ++ ++static int pxp_try_fmt_video_output(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ int w = f->fmt.pix.width; ++ int h = f->fmt.pix.height; ++ struct pxp_data_format *fmt = pxp_get_format(f); ++ ++ if (!fmt) ++ return -EINVAL; ++ ++ w = min(w, 2040); ++ w = max(w, 8); ++ h = min(h, 2040); ++ h = max(h, 8); ++ f->fmt.pix.field = V4L2_FIELD_NONE; ++ f->fmt.pix.width = w; ++ f->fmt.pix.height = h; ++ f->fmt.pix.pixelformat = fmt->fourcc; ++ ++ return 0; ++} ++ ++static int pxp_s_fmt_video_output(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct v4l2_pix_format *pf = &f->fmt.pix; ++ int ret; ++ ++ ret = acquire_dma_channel(pxp); ++ if (ret < 0) ++ return ret; ++ ++ ret = pxp_try_fmt_video_output(file, fh, f); ++ if (ret == 0) { ++ pxp->s0_fmt = pxp_get_format(f); ++ pxp->pxp_conf.s0_param.pixel_fmt = ++ v4l2_fmt_to_pxp_fmt(pxp->s0_fmt->fourcc); ++ pxp->pxp_conf.s0_param.width = pf->width; ++ pxp->pxp_conf.s0_param.height = pf->height; ++ } ++ ++ ++ return ret; ++} ++ ++static int pxp_g_fmt_output_overlay(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct v4l2_window *wf = &f->fmt.win; ++ ++ memset(wf, 0, sizeof(struct v4l2_window)); ++ wf->chromakey = pxp->s1_chromakey; ++ wf->global_alpha = pxp->global_alpha; ++ wf->field = V4L2_FIELD_NONE; ++ wf->clips = NULL; ++ wf->clipcount = 0; ++ wf->bitmap = NULL; ++ wf->w.left = pxp->pxp_conf.proc_data.srect.left; ++ wf->w.top = pxp->pxp_conf.proc_data.srect.top; ++ wf->w.width = pxp->pxp_conf.proc_data.srect.width; ++ wf->w.height = pxp->pxp_conf.proc_data.srect.height; ++ ++ return 0; ++} ++ ++static int pxp_try_fmt_output_overlay(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct v4l2_window *wf = &f->fmt.win; ++ struct v4l2_rect srect; ++ u32 s1_chromakey = wf->chromakey; ++ u8 global_alpha = wf->global_alpha; ++ ++ memcpy(&srect, &(wf->w), sizeof(struct v4l2_rect)); ++ ++ pxp_g_fmt_output_overlay(file, fh, f); ++ ++ wf->chromakey = s1_chromakey; ++ wf->global_alpha = global_alpha; ++ ++ /* Constrain parameters to the input buffer */ ++ wf->w.left = srect.left; ++ wf->w.top = srect.top; ++ wf->w.width = min(srect.width, ++ ((__s32)pxp->pxp_conf.s0_param.width - wf->w.left)); ++ wf->w.height = min(srect.height, ++ ((__s32)pxp->pxp_conf.s0_param.height - wf->w.top)); ++ ++ return 0; ++} ++ ++static int pxp_s_fmt_output_overlay(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ struct v4l2_window *wf = &f->fmt.win; ++ int ret = pxp_try_fmt_output_overlay(file, fh, f); ++ ++ if (ret == 0) { ++ pxp->global_alpha = wf->global_alpha; ++ pxp->s1_chromakey = wf->chromakey; ++ pxp->pxp_conf.proc_data.srect.left = wf->w.left; ++ pxp->pxp_conf.proc_data.srect.top = wf->w.top; ++ pxp->pxp_conf.proc_data.srect.width = wf->w.width; ++ pxp->pxp_conf.proc_data.srect.height = wf->w.height; ++ pxp->pxp_conf.ol_param[0].global_alpha = pxp->global_alpha; ++ pxp->pxp_conf.ol_param[0].color_key = pxp->s1_chromakey; ++ pxp->pxp_conf.ol_param[0].color_key_enable = ++ pxp->s1_chromakey_state; ++ } ++ ++ return ret; ++} ++ ++static int pxp_reqbufs(struct file *file, void *priv, ++ struct v4l2_requestbuffers *r) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ return videobuf_reqbufs(&pxp->s0_vbq, r); ++} ++ ++static int pxp_querybuf(struct file *file, void *priv, ++ struct v4l2_buffer *b) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ return videobuf_querybuf(&pxp->s0_vbq, b); ++} ++ ++static int pxp_qbuf(struct file *file, void *priv, ++ struct v4l2_buffer *b) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ return videobuf_qbuf(&pxp->s0_vbq, b); ++} ++ ++static int pxp_dqbuf(struct file *file, void *priv, ++ struct v4l2_buffer *b) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ return videobuf_dqbuf(&pxp->s0_vbq, b, file->f_flags & O_NONBLOCK); ++} ++ ++static int pxp_streamon(struct file *file, void *priv, ++ enum v4l2_buf_type t) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ int ret = 0; ++ ++ if (t != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ ++ _get_cur_fb_blank(pxp); ++ set_fb_blank(FB_BLANK_UNBLANK); ++ ++ ret = videobuf_streamon(&pxp->s0_vbq); ++ ++ if (!ret && (pxp->output == 0)) ++ pxp_show_buf(pxp, true); ++ ++ return ret; ++} ++ ++static int pxp_streamoff(struct file *file, void *priv, ++ enum v4l2_buf_type t) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ int ret = 0; ++ ++ if ((t != V4L2_BUF_TYPE_VIDEO_OUTPUT)) ++ return -EINVAL; ++ ++ ret = videobuf_streamoff(&pxp->s0_vbq); ++ ++ if (!ret) ++ pxp_show_buf(pxp, false); ++ ++ if (pxp->fb_blank) ++ set_fb_blank(FB_BLANK_POWERDOWN); ++ ++ return ret; ++} ++ ++static int pxp_buf_setup(struct videobuf_queue *q, ++ unsigned int *count, unsigned *size) ++{ ++ struct pxps *pxp = q->priv_data; ++ ++ *size = pxp->pxp_conf.s0_param.width * ++ pxp->pxp_conf.s0_param.height * pxp->s0_fmt->bpp; ++ ++ if (0 == *count) ++ *count = PXP_DEF_BUFS; ++ ++ return 0; ++} ++ ++static void pxp_buf_free(struct videobuf_queue *q, struct pxp_buffer *buf) ++{ ++ struct videobuf_buffer *vb = &buf->vb; ++ struct dma_async_tx_descriptor *txd = buf->txd; ++ ++ BUG_ON(in_interrupt()); ++ ++ pr_debug("%s (vb=0x%p) 0x%08lx %d\n", __func__, ++ vb, vb->baddr, vb->bsize); ++ ++ /* ++ * This waits until this buffer is out of danger, i.e., until it is no ++ * longer in STATE_QUEUED or STATE_ACTIVE ++ */ ++ videobuf_waiton(q, vb, 0, 0); ++ if (txd) ++ async_tx_ack(txd); ++ ++ videobuf_dma_contig_free(q, vb); ++ buf->txd = NULL; ++ ++ vb->state = VIDEOBUF_NEEDS_INIT; ++} ++ ++static int pxp_buf_prepare(struct videobuf_queue *q, ++ struct videobuf_buffer *vb, ++ enum v4l2_field field) ++{ ++ struct pxps *pxp = q->priv_data; ++ struct pxp_config_data *pxp_conf = &pxp->pxp_conf; ++ struct pxp_proc_data *proc_data = &pxp_conf->proc_data; ++ struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb); ++ struct pxp_tx_desc *desc; ++ int ret = 0; ++ int i, length; ++ ++ vb->width = pxp->pxp_conf.s0_param.width; ++ vb->height = pxp->pxp_conf.s0_param.height; ++ vb->size = vb->width * vb->height * pxp->s0_fmt->bpp; ++ vb->field = V4L2_FIELD_NONE; ++ if (vb->state != VIDEOBUF_NEEDS_INIT) ++ pxp_buf_free(q, buf); ++ ++ if (vb->state == VIDEOBUF_NEEDS_INIT) { ++ struct pxp_channel *pchan = pxp->pxp_channel[0]; ++ struct scatterlist *sg = &buf->sg[0]; ++ ++ /* This actually (allocates and) maps buffers */ ++ ret = videobuf_iolock(q, vb, NULL); ++ if (ret) { ++ pr_err("fail to call videobuf_iolock, ret = %d\n", ret); ++ goto fail; ++ } ++ ++ /* ++ * sg[0] for input(S0) ++ * Sg[1] for output ++ */ ++ sg_init_table(sg, 3); ++ ++ buf->txd = pchan->dma_chan.device->device_prep_slave_sg( ++ &pchan->dma_chan, sg, 3, DMA_FROM_DEVICE, ++ DMA_PREP_INTERRUPT, NULL); ++ if (!buf->txd) { ++ ret = -EIO; ++ goto fail; ++ } ++ ++ buf->txd->callback_param = buf->txd; ++ buf->txd->callback = video_dma_done; ++ ++ desc = to_tx_desc(buf->txd); ++ length = desc->len; ++ for (i = 0; i < length; i++) { ++ if (i == 0) {/* S0 */ ++ memcpy(&desc->proc_data, proc_data, ++ sizeof(struct pxp_proc_data)); ++ pxp_conf->s0_param.paddr = ++ videobuf_to_dma_contig(vb); ++ memcpy(&desc->layer_param.s0_param, ++ &pxp_conf->s0_param, ++ sizeof(struct pxp_layer_param)); ++ } else if (i == 1) { /* Output */ ++ if (proc_data->rotate % 180) { ++ pxp_conf->out_param.width = ++ pxp->fb.fmt.height; ++ pxp_conf->out_param.height = ++ pxp->fb.fmt.width; ++ } else { ++ pxp_conf->out_param.width = ++ pxp->fb.fmt.width; ++ pxp_conf->out_param.height = ++ pxp->fb.fmt.height; ++ } ++ ++ pxp_conf->out_param.paddr = pxp->outb_phys; ++ memcpy(&desc->layer_param.out_param, ++ &pxp_conf->out_param, ++ sizeof(struct pxp_layer_param)); ++ } else if (pxp_conf->ol_param[0].combine_enable) { ++ /* Overlay */ ++ pxp_conf->ol_param[0].paddr = ++ (dma_addr_t)pxp->fb.base; ++ pxp_conf->ol_param[0].width = pxp->fb.fmt.width; ++ pxp_conf->ol_param[0].height = ++ pxp->fb.fmt.height; ++ pxp_conf->ol_param[0].pixel_fmt = ++ pxp_conf->out_param.pixel_fmt; ++ memcpy(&desc->layer_param.ol_param, ++ &pxp_conf->ol_param[0], ++ sizeof(struct pxp_layer_param)); ++ } ++ ++ desc = desc->next; ++ } ++ ++ vb->state = VIDEOBUF_PREPARED; ++ } ++ ++ return 0; ++ ++fail: ++ pxp_buf_free(q, buf); ++ return ret; ++} ++ ++ ++static void pxp_buf_queue(struct videobuf_queue *q, ++ struct videobuf_buffer *vb) ++{ ++ struct pxps *pxp = q->priv_data; ++ struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb); ++ struct dma_async_tx_descriptor *txd = buf->txd; ++ struct pxp_channel *pchan = pxp->pxp_channel[0]; ++ dma_cookie_t cookie; ++ ++ BUG_ON(!irqs_disabled()); ++ ++ list_add_tail(&vb->queue, &pxp->outq); ++ ++ if (!pxp->active) { ++ pxp->active = buf; ++ vb->state = VIDEOBUF_ACTIVE; ++ } else { ++ vb->state = VIDEOBUF_QUEUED; ++ } ++ ++ spin_unlock_irq(&pxp->lock); ++ ++ cookie = txd->tx_submit(txd); ++ dev_dbg(&pxp->pdev->dev, "Submitted cookie %d DMA 0x%08x\n", ++ cookie, sg_dma_address(&buf->sg[0])); ++ mdelay(5); ++ /* trigger ePxP */ ++ dma_async_issue_pending(&pchan->dma_chan); ++ ++ spin_lock_irq(&pxp->lock); ++ ++ if (cookie >= 0) ++ return; ++ ++ /* Submit error */ ++ pr_err("%s: Submit error\n", __func__); ++ vb->state = VIDEOBUF_PREPARED; ++ ++ list_del_init(&vb->queue); ++ ++ if (pxp->active == buf) ++ pxp->active = NULL; ++} ++ ++static void pxp_buf_release(struct videobuf_queue *q, ++ struct videobuf_buffer *vb) ++{ ++ struct pxps *pxp = q->priv_data; ++ struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pxp->lock, flags); ++ if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) && ++ !list_empty(&vb->queue)) { ++ vb->state = VIDEOBUF_ERROR; ++ ++ list_del_init(&vb->queue); ++ if (pxp->active == buf) ++ pxp->active = NULL; ++ } ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ ++ pxp_buf_free(q, buf); ++} ++ ++static struct videobuf_queue_ops pxp_vbq_ops = { ++ .buf_setup = pxp_buf_setup, ++ .buf_prepare = pxp_buf_prepare, ++ .buf_queue = pxp_buf_queue, ++ .buf_release = pxp_buf_release, ++}; ++ ++static int pxp_querycap(struct file *file, void *fh, ++ struct v4l2_capability *cap) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ memset(cap, 0, sizeof(*cap)); ++ strcpy(cap->driver, "pxp"); ++ strcpy(cap->card, "pxp"); ++ strlcpy(cap->bus_info, dev_name(&pxp->pdev->dev), ++ sizeof(cap->bus_info)); ++ ++ cap->version = (PXP_DRIVER_MAJOR << 8) + PXP_DRIVER_MINOR; ++ ++ cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | ++ V4L2_CAP_VIDEO_OUTPUT_OVERLAY | ++ V4L2_CAP_STREAMING; ++ ++ return 0; ++} ++ ++static int pxp_g_fbuf(struct file *file, void *priv, ++ struct v4l2_framebuffer *fb) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ memset(fb, 0, sizeof(*fb)); ++ ++ fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | ++ V4L2_FBUF_CAP_CHROMAKEY | ++ V4L2_FBUF_CAP_LOCAL_ALPHA | ++ V4L2_FBUF_CAP_GLOBAL_ALPHA; ++ ++ if (pxp->global_alpha_state) ++ fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; ++ if (pxp->s1_chromakey_state) ++ fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; ++ ++ return 0; ++} ++ ++static int pxp_s_fbuf(struct file *file, void *priv, ++ const struct v4l2_framebuffer *fb) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ pxp->overlay_state = ++ (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0; ++ pxp->global_alpha_state = ++ (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; ++ pxp->s1_chromakey_state = ++ (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; ++ ++ pxp->pxp_conf.ol_param[0].combine_enable = pxp->overlay_state; ++ pxp->pxp_conf.ol_param[0].global_alpha_enable = pxp->global_alpha_state; ++ ++ return 0; ++} ++ ++static int pxp_g_crop(struct file *file, void *fh, ++ struct v4l2_crop *c) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) ++ return -EINVAL; ++ ++ c->c.left = pxp->pxp_conf.proc_data.drect.left; ++ c->c.top = pxp->pxp_conf.proc_data.drect.top; ++ c->c.width = pxp->pxp_conf.proc_data.drect.width; ++ c->c.height = pxp->pxp_conf.proc_data.drect.height; ++ ++ return 0; ++} ++ ++static int pxp_s_crop(struct file *file, void *fh, ++ const struct v4l2_crop *c) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ int l = c->c.left; ++ int t = c->c.top; ++ int w = c->c.width; ++ int h = c->c.height; ++ int fbw = pxp->fb.fmt.width; ++ int fbh = pxp->fb.fmt.height; ++ ++ if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) ++ return -EINVAL; ++ ++ /* Constrain parameters to FB limits */ ++ w = min(w, fbw); ++ w = max(w, PXP_MIN_PIX); ++ h = min(h, fbh); ++ h = max(h, PXP_MIN_PIX); ++ if ((l + w) > fbw) ++ l = 0; ++ if ((t + h) > fbh) ++ t = 0; ++ ++ /* Round up values to PxP pixel block */ ++ l = roundup(l, PXP_MIN_PIX); ++ t = roundup(t, PXP_MIN_PIX); ++ w = roundup(w, PXP_MIN_PIX); ++ h = roundup(h, PXP_MIN_PIX); ++ ++ pxp->pxp_conf.proc_data.drect.left = l; ++ pxp->pxp_conf.proc_data.drect.top = t; ++ pxp->pxp_conf.proc_data.drect.width = w; ++ pxp->pxp_conf.proc_data.drect.height = h; ++ ++ return 0; ++} ++ ++static int pxp_queryctrl(struct file *file, void *priv, ++ struct v4l2_queryctrl *qc) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) ++ if (qc->id && qc->id == pxp_controls[i].id) { ++ memcpy(qc, &(pxp_controls[i]), sizeof(*qc)); ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int pxp_g_ctrl(struct file *file, void *priv, ++ struct v4l2_control *vc) ++{ ++ int i; ++ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) ++ if (vc->id == pxp_controls[i].id) ++ return pxp_get_cstate(pxp, vc); ++ ++ return -EINVAL; ++} ++ ++static int pxp_s_ctrl(struct file *file, void *priv, ++ struct v4l2_control *vc) ++{ ++ int i; ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++) ++ if (vc->id == pxp_controls[i].id) { ++ if (vc->value < pxp_controls[i].minimum || ++ vc->value > pxp_controls[i].maximum) ++ return -ERANGE; ++ return pxp_set_cstate(pxp, vc); ++ } ++ ++ return -EINVAL; ++} ++ ++void pxp_release(struct video_device *vfd) ++{ ++ struct pxps *pxp = video_get_drvdata(vfd); ++ ++ spin_lock(&pxp->lock); ++ video_device_release(vfd); ++ spin_unlock(&pxp->lock); ++} ++ ++static int pxp_open(struct file *file) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ int ret = 0; ++ ++ mutex_lock(&pxp->mutex); ++ pxp->users++; ++ ++ if (pxp->users > 1) { ++ pxp->users--; ++ ret = -EBUSY; ++ goto out; ++ } ++out: ++ mutex_unlock(&pxp->mutex); ++ if (ret) ++ return ret; ++ ++ ret = pxp_set_fbinfo(pxp); ++ if (ret) { ++ dev_err(&pxp->pdev->dev, "failed to call pxp_set_fbinfo\n"); ++ return ret; ++ } ++ ++ videobuf_queue_dma_contig_init(&pxp->s0_vbq, ++ &pxp_vbq_ops, ++ &pxp->pdev->dev, ++ &pxp->lock, ++ V4L2_BUF_TYPE_VIDEO_OUTPUT, ++ V4L2_FIELD_NONE, ++ sizeof(struct pxp_buffer), ++ pxp, ++ NULL); ++ dev_dbg(&pxp->pdev->dev, "call pxp_open\n"); ++ ++ return 0; ++} ++ ++static int pxp_close(struct file *file) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ ++ videobuf_stop(&pxp->s0_vbq); ++ videobuf_mmap_free(&pxp->s0_vbq); ++ pxp->active = NULL; ++ kfree(pxp->outb); ++ pxp->outb = NULL; ++ ++ mutex_lock(&pxp->mutex); ++ pxp->users--; ++ mutex_unlock(&pxp->mutex); ++ ++ return 0; ++} ++ ++static int pxp_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct pxps *pxp = video_get_drvdata(video_devdata(file)); ++ int ret; ++ ++ ret = videobuf_mmap_mapper(&pxp->s0_vbq, vma); ++ ++ return ret; ++} ++ ++static const struct v4l2_file_operations pxp_fops = { ++ .owner = THIS_MODULE, ++ .open = pxp_open, ++ .release = pxp_close, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = pxp_mmap, ++}; ++ ++static const struct v4l2_ioctl_ops pxp_ioctl_ops = { ++ .vidioc_querycap = pxp_querycap, ++ ++ .vidioc_reqbufs = pxp_reqbufs, ++ .vidioc_querybuf = pxp_querybuf, ++ .vidioc_qbuf = pxp_qbuf, ++ .vidioc_dqbuf = pxp_dqbuf, ++ ++ .vidioc_streamon = pxp_streamon, ++ .vidioc_streamoff = pxp_streamoff, ++ ++ .vidioc_enum_output = pxp_enumoutput, ++ .vidioc_g_output = pxp_g_output, ++ .vidioc_s_output = pxp_s_output, ++ ++ .vidioc_enum_fmt_vid_out = pxp_enum_fmt_video_output, ++ .vidioc_try_fmt_vid_out = pxp_try_fmt_video_output, ++ .vidioc_g_fmt_vid_out = pxp_g_fmt_video_output, ++ .vidioc_s_fmt_vid_out = pxp_s_fmt_video_output, ++ ++ .vidioc_try_fmt_vid_out_overlay = pxp_try_fmt_output_overlay, ++ .vidioc_g_fmt_vid_out_overlay = pxp_g_fmt_output_overlay, ++ .vidioc_s_fmt_vid_out_overlay = pxp_s_fmt_output_overlay, ++ ++ .vidioc_g_fbuf = pxp_g_fbuf, ++ .vidioc_s_fbuf = pxp_s_fbuf, ++ ++ .vidioc_g_crop = pxp_g_crop, ++ .vidioc_s_crop = pxp_s_crop, ++ ++ .vidioc_queryctrl = pxp_queryctrl, ++ .vidioc_g_ctrl = pxp_g_ctrl, ++ .vidioc_s_ctrl = pxp_s_ctrl, ++}; ++ ++static const struct video_device pxp_template = { ++ .name = "PxP", ++ .vfl_type = V4L2_CAP_VIDEO_OUTPUT | ++ V4L2_CAP_VIDEO_OVERLAY | ++ V4L2_CAP_STREAMING, ++ .vfl_dir = VFL_DIR_TX, ++ .fops = &pxp_fops, ++ .release = pxp_release, ++ .minor = -1, ++ .ioctl_ops = &pxp_ioctl_ops, ++}; ++ ++static const struct of_device_id imx_pxpv4l2_dt_ids[] = { ++ { .compatible = "fsl,imx6sl-pxp-v4l2", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, imx_pxpv4l2_dt_ids); ++ ++static int pxp_probe(struct platform_device *pdev) ++{ ++ struct pxps *pxp; ++ int err = 0; ++ ++ pxp = kzalloc(sizeof(*pxp), GFP_KERNEL); ++ if (!pxp) { ++ dev_err(&pdev->dev, "failed to allocate control object\n"); ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ dev_set_drvdata(&pdev->dev, pxp); ++ ++ INIT_LIST_HEAD(&pxp->outq); ++ spin_lock_init(&pxp->lock); ++ mutex_init(&pxp->mutex); ++ ++ pxp->pdev = pdev; ++ ++ pxp->vdev = video_device_alloc(); ++ if (!pxp->vdev) { ++ dev_err(&pdev->dev, "video_device_alloc() failed\n"); ++ err = -ENOMEM; ++ goto freeirq; ++ } ++ ++ memcpy(pxp->vdev, &pxp_template, sizeof(pxp_template)); ++ video_set_drvdata(pxp->vdev, pxp); ++ ++ err = video_register_device(pxp->vdev, VFL_TYPE_GRABBER, video_nr); ++ if (err) { ++ dev_err(&pdev->dev, "failed to register video device\n"); ++ goto freevdev; ++ } ++ ++ dev_info(&pdev->dev, "initialized\n"); ++ ++exit: ++ return err; ++ ++freevdev: ++ video_device_release(pxp->vdev); ++ ++freeirq: ++ kfree(pxp); ++ ++ return err; ++} ++ ++static int pxp_remove(struct platform_device *pdev) ++{ ++ struct pxps *pxp = platform_get_drvdata(pdev); ++ ++ video_unregister_device(pxp->vdev); ++ video_device_release(pxp->vdev); ++ ++ kfree(pxp); ++ ++ return 0; ++} ++ ++static struct platform_driver pxp_driver = { ++ .driver = { ++ .name = PXP_DRIVER_NAME, ++ .of_match_table = of_match_ptr(imx_pxpv4l2_dt_ids), ++ }, ++ .probe = pxp_probe, ++ .remove = pxp_remove, ++}; ++ ++module_platform_driver(pxp_driver); ++ ++module_param(video_nr, int, 0444); ++MODULE_DESCRIPTION("MXC PxP V4L2 driver"); ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h linux-3.10.30-cubox-i/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h +--- linux-3.10.30/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,83 @@ ++/* ++ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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 ++ * ++ */ ++/* ++ * Based on STMP378X PxP driver ++ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved. ++ */ ++ ++#ifndef _MXC_PXP_V4L2_H ++#define _MXC_PXP_V4L2_H ++ ++#include ++#include ++ ++struct pxp_buffer { ++ /* Must be first! */ ++ struct videobuf_buffer vb; ++ ++ /* One descriptor per scatterlist (per frame) */ ++ struct dma_async_tx_descriptor *txd; ++ ++ struct scatterlist sg[3]; ++}; ++ ++struct pxps { ++ struct platform_device *pdev; ++ ++ spinlock_t lock; ++ struct mutex mutex; ++ int users; ++ ++ struct video_device *vdev; ++ ++ struct videobuf_queue s0_vbq; ++ struct pxp_buffer *active; ++ struct list_head outq; ++ struct pxp_channel *pxp_channel[1]; /* We need 1 channel */ ++ struct pxp_config_data pxp_conf; ++ ++ int output; ++ u32 *outb; ++ dma_addr_t outb_phys; ++ u32 outb_size; ++ ++ /* Current S0 configuration */ ++ struct pxp_data_format *s0_fmt; ++ ++ struct fb_info *fbi; ++ struct v4l2_framebuffer fb; ++ ++ /* Output overlay support */ ++ int overlay_state; ++ int global_alpha_state; ++ u8 global_alpha; ++ int s1_chromakey_state; ++ u32 s1_chromakey; ++ ++ int fb_blank; ++}; ++ ++struct pxp_data_format { ++ char *name; ++ unsigned int bpp; ++ u32 fourcc; ++ enum v4l2_colorspace colorspace; ++}; ++ ++#endif +diff -Nur linux-3.10.30/drivers/media/platform/mxc/output/mxc_vout.c linux-3.10.30-cubox-i/drivers/media/platform/mxc/output/mxc_vout.c +--- linux-3.10.30/drivers/media/platform/mxc/output/mxc_vout.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/platform/mxc/output/mxc_vout.c 2014-03-08 20:33:46.000000000 +0100 +@@ -0,0 +1,2265 @@ ++/* ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define UYVY_BLACK (0x00800080) ++#define RGB_BLACK (0x0) ++#define UV_BLACK (0x80) ++#define Y_BLACK (0x0) ++ ++#define MAX_FB_NUM 6 ++#define FB_BUFS 3 ++#define VDOA_FB_BUFS (FB_BUFS - 1) ++#define VALID_HEIGHT_1080P (1080) ++#define FRAME_HEIGHT_1080P (1088) ++#define FRAME_WIDTH_1080P (1920) ++#define CHECK_TILED_1080P_DISPLAY(vout) \ ++ ((((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12) || \ ++ ((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12F)) &&\ ++ ((vout)->task.input.width == FRAME_WIDTH_1080P) && \ ++ ((vout)->task.input.height == FRAME_HEIGHT_1080P) && \ ++ ((vout)->task.input.crop.w == FRAME_WIDTH_1080P) && \ ++ (((vout)->task.input.crop.h == FRAME_HEIGHT_1080P) || \ ++ ((vout)->task.input.crop.h == VALID_HEIGHT_1080P)) && \ ++ ((vout)->task.output.width == FRAME_WIDTH_1080P) && \ ++ ((vout)->task.output.height == VALID_HEIGHT_1080P) && \ ++ ((vout)->task.output.crop.w == FRAME_WIDTH_1080P) && \ ++ ((vout)->task.output.crop.h == VALID_HEIGHT_1080P)) ++#define CHECK_TILED_1080P_STREAM(vout) \ ++ ((((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12) || \ ++ ((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12F)) &&\ ++ ((vout)->task.input.width == FRAME_WIDTH_1080P) && \ ++ ((vout)->task.input.crop.w == FRAME_WIDTH_1080P) && \ ++ ((vout)->task.input.height == FRAME_HEIGHT_1080P) && \ ++ ((vout)->task.input.crop.h == FRAME_HEIGHT_1080P)) ++#define IS_PLANAR_PIXEL_FORMAT(format) \ ++ (format == IPU_PIX_FMT_NV12 || \ ++ format == IPU_PIX_FMT_YUV420P2 || \ ++ format == IPU_PIX_FMT_YUV420P || \ ++ format == IPU_PIX_FMT_YVU420P || \ ++ format == IPU_PIX_FMT_YUV422P || \ ++ format == IPU_PIX_FMT_YVU422P || \ ++ format == IPU_PIX_FMT_YUV444P) ++ ++#define NSEC_PER_FRAME_30FPS (33333333) ++ ++struct mxc_vout_fb { ++ char *name; ++ int ipu_id; ++ struct v4l2_rect crop_bounds; ++ unsigned int disp_fmt; ++ bool disp_support_csc; ++ bool disp_support_windows; ++}; ++ ++struct dma_mem { ++ void *vaddr; ++ dma_addr_t paddr; ++ size_t size; ++}; ++ ++struct mxc_vout_output { ++ int open_cnt; ++ struct fb_info *fbi; ++ unsigned long fb_smem_start; ++ unsigned long fb_smem_len; ++ struct video_device *vfd; ++ struct mutex mutex; ++ struct mutex task_lock; ++ enum v4l2_buf_type type; ++ ++ struct videobuf_queue vbq; ++ spinlock_t vbq_lock; ++ ++ struct list_head queue_list; ++ struct list_head active_list; ++ ++ struct v4l2_rect crop_bounds; ++ unsigned int disp_fmt; ++ struct mxcfb_pos win_pos; ++ bool disp_support_windows; ++ bool disp_support_csc; ++ ++ bool fmt_init; ++ bool release; ++ bool linear_bypass_pp; ++ bool vdoa_1080p; ++ bool tiled_bypass_pp; ++ struct v4l2_rect in_rect; ++ struct ipu_task task; ++ struct ipu_task vdoa_task; ++ struct dma_mem vdoa_work; ++ struct dma_mem vdoa_output[VDOA_FB_BUFS]; ++ ++ bool timer_stop; ++ struct hrtimer timer; ++ struct workqueue_struct *v4l_wq; ++ struct work_struct disp_work; ++ unsigned long frame_count; ++ unsigned long vdi_frame_cnt; ++ ktime_t start_ktime; ++ ++ int ctrl_rotate; ++ int ctrl_vflip; ++ int ctrl_hflip; ++ ++ dma_addr_t disp_bufs[FB_BUFS]; ++ ++ struct videobuf_buffer *pre1_vb; ++ struct videobuf_buffer *pre2_vb; ++}; ++ ++struct mxc_vout_dev { ++ struct device *dev; ++ struct v4l2_device v4l2_dev; ++ struct mxc_vout_output *out[MAX_FB_NUM]; ++ int out_num; ++}; ++ ++/* Driver Configuration macros */ ++#define VOUT_NAME "mxc_vout" ++ ++/* Variables configurable through module params*/ ++static int debug; ++static int vdi_rate_double; ++static int video_nr = 16; ++ ++/* Module parameters */ ++module_param(video_nr, int, S_IRUGO); ++MODULE_PARM_DESC(video_nr, "video device numbers"); ++module_param(debug, int, 0600); ++MODULE_PARM_DESC(debug, "Debug level (0-1)"); ++module_param(vdi_rate_double, int, 0600); ++MODULE_PARM_DESC(vdi_rate_double, "vdi frame rate double on/off"); ++ ++static const struct v4l2_fmtdesc mxc_formats[] = { ++ { ++ .description = "RGB565", ++ .pixelformat = V4L2_PIX_FMT_RGB565, ++ }, ++ { ++ .description = "BGR24", ++ .pixelformat = V4L2_PIX_FMT_BGR24, ++ }, ++ { ++ .description = "RGB24", ++ .pixelformat = V4L2_PIX_FMT_RGB24, ++ }, ++ { ++ .description = "RGB32", ++ .pixelformat = V4L2_PIX_FMT_RGB32, ++ }, ++ { ++ .description = "BGR32", ++ .pixelformat = V4L2_PIX_FMT_BGR32, ++ }, ++ { ++ .description = "NV12", ++ .pixelformat = V4L2_PIX_FMT_NV12, ++ }, ++ { ++ .description = "UYVY", ++ .pixelformat = V4L2_PIX_FMT_UYVY, ++ }, ++ { ++ .description = "YUYV", ++ .pixelformat = V4L2_PIX_FMT_YUYV, ++ }, ++ { ++ .description = "YUV422 planar", ++ .pixelformat = V4L2_PIX_FMT_YUV422P, ++ }, ++ { ++ .description = "YUV444", ++ .pixelformat = V4L2_PIX_FMT_YUV444, ++ }, ++ { ++ .description = "YUV420", ++ .pixelformat = V4L2_PIX_FMT_YUV420, ++ }, ++ { ++ .description = "YVU420", ++ .pixelformat = V4L2_PIX_FMT_YVU420, ++ }, ++ { ++ .description = "TILED NV12P", ++ .pixelformat = IPU_PIX_FMT_TILED_NV12, ++ }, ++ { ++ .description = "TILED NV12F", ++ .pixelformat = IPU_PIX_FMT_TILED_NV12F, ++ }, ++ { ++ .description = "YUV444 planar", ++ .pixelformat = IPU_PIX_FMT_YUV444P, ++ }, ++}; ++ ++#define NUM_MXC_VOUT_FORMATS (ARRAY_SIZE(mxc_formats)) ++ ++#define DEF_INPUT_WIDTH 320 ++#define DEF_INPUT_HEIGHT 240 ++ ++static int mxc_vidioc_streamoff(struct file *file, void *fh, ++ enum v4l2_buf_type i); ++ ++static struct mxc_vout_fb g_fb_setting[MAX_FB_NUM]; ++static int config_disp_output(struct mxc_vout_output *vout); ++static void release_disp_output(struct mxc_vout_output *vout); ++ ++static unsigned int get_frame_size(struct mxc_vout_output *vout) ++{ ++ unsigned int size; ++ ++ if (IPU_PIX_FMT_TILED_NV12 == vout->task.input.format) ++ size = TILED_NV12_FRAME_SIZE(vout->task.input.width, ++ vout->task.input.height); ++ else if (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format) { ++ size = TILED_NV12_FRAME_SIZE(vout->task.input.width, ++ vout->task.input.height/2); ++ size *= 2; ++ } else ++ size = vout->task.input.width * vout->task.input.height * ++ fmt_to_bpp(vout->task.input.format)/8; ++ ++ return size; ++} ++ ++static void free_dma_buf(struct mxc_vout_output *vout, struct dma_mem *buf) ++{ ++ dma_free_coherent(vout->vbq.dev, buf->size, buf->vaddr, buf->paddr); ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "free dma size:0x%x, paddr:0x%x\n", ++ buf->size, buf->paddr); ++ memset(buf, 0, sizeof(*buf)); ++} ++ ++static int alloc_dma_buf(struct mxc_vout_output *vout, struct dma_mem *buf) ++{ ++ ++ buf->vaddr = dma_alloc_coherent(vout->vbq.dev, buf->size, &buf->paddr, ++ GFP_DMA | GFP_KERNEL); ++ if (!buf->vaddr) { ++ v4l2_err(vout->vfd->v4l2_dev, ++ "cannot get dma buf size:0x%x\n", buf->size); ++ return -ENOMEM; ++ } ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "alloc dma buf size:0x%x, paddr:0x%x\n", buf->size, buf->paddr); ++ return 0; ++} ++ ++static ipu_channel_t get_ipu_channel(struct fb_info *fbi) ++{ ++ ipu_channel_t ipu_ch = CHAN_NONE; ++ mm_segment_t old_fs; ++ ++ if (fbi->fbops->fb_ioctl) { ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN, ++ (unsigned long)&ipu_ch); ++ set_fs(old_fs); ++ } ++ ++ return ipu_ch; ++} ++ ++static unsigned int get_ipu_fmt(struct fb_info *fbi) ++{ ++ mm_segment_t old_fs; ++ unsigned int fb_fmt; ++ ++ if (fbi->fbops->fb_ioctl) { ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ fbi->fbops->fb_ioctl(fbi, MXCFB_GET_DIFMT, ++ (unsigned long)&fb_fmt); ++ set_fs(old_fs); ++ } ++ ++ return fb_fmt; ++} ++ ++static void update_display_setting(void) ++{ ++ int i; ++ struct fb_info *fbi; ++ struct v4l2_rect bg_crop_bounds[2]; ++ ++ for (i = 0; i < num_registered_fb; i++) { ++ fbi = registered_fb[i]; ++ ++ memset(&g_fb_setting[i], 0, sizeof(struct mxc_vout_fb)); ++ ++ if (!strncmp(fbi->fix.id, "DISP3", 5)) ++ g_fb_setting[i].ipu_id = 0; ++ else ++ g_fb_setting[i].ipu_id = 1; ++ ++ g_fb_setting[i].name = fbi->fix.id; ++ g_fb_setting[i].crop_bounds.left = 0; ++ g_fb_setting[i].crop_bounds.top = 0; ++ g_fb_setting[i].crop_bounds.width = fbi->var.xres; ++ g_fb_setting[i].crop_bounds.height = fbi->var.yres; ++ g_fb_setting[i].disp_fmt = get_ipu_fmt(fbi); ++ ++ if (get_ipu_channel(fbi) == MEM_BG_SYNC) { ++ bg_crop_bounds[g_fb_setting[i].ipu_id] = ++ g_fb_setting[i].crop_bounds; ++ g_fb_setting[i].disp_support_csc = true; ++ } else if (get_ipu_channel(fbi) == MEM_FG_SYNC) { ++ g_fb_setting[i].disp_support_csc = true; ++ g_fb_setting[i].disp_support_windows = true; ++ } ++ } ++ ++ for (i = 0; i < num_registered_fb; i++) { ++ fbi = registered_fb[i]; ++ ++ if (get_ipu_channel(fbi) == MEM_FG_SYNC) ++ g_fb_setting[i].crop_bounds = ++ bg_crop_bounds[g_fb_setting[i].ipu_id]; ++ } ++} ++ ++/* called after g_fb_setting filled by update_display_setting */ ++static int update_setting_from_fbi(struct mxc_vout_output *vout, ++ struct fb_info *fbi) ++{ ++ int i; ++ bool found = false; ++ ++ for (i = 0; i < MAX_FB_NUM; i++) { ++ if (g_fb_setting[i].name) { ++ if (!strcmp(fbi->fix.id, g_fb_setting[i].name)) { ++ vout->crop_bounds = g_fb_setting[i].crop_bounds; ++ vout->disp_fmt = g_fb_setting[i].disp_fmt; ++ vout->disp_support_csc = ++ g_fb_setting[i].disp_support_csc; ++ vout->disp_support_windows = ++ g_fb_setting[i].disp_support_windows; ++ found = true; ++ break; ++ } ++ } ++ } ++ ++ if (!found) { ++ v4l2_err(vout->vfd->v4l2_dev, "can not find output\n"); ++ return -EINVAL; ++ } ++ strlcpy(vout->vfd->name, fbi->fix.id, sizeof(vout->vfd->name)); ++ ++ memset(&vout->task, 0, sizeof(struct ipu_task)); ++ ++ vout->task.input.width = DEF_INPUT_WIDTH; ++ vout->task.input.height = DEF_INPUT_HEIGHT; ++ vout->task.input.crop.pos.x = 0; ++ vout->task.input.crop.pos.y = 0; ++ vout->task.input.crop.w = DEF_INPUT_WIDTH; ++ vout->task.input.crop.h = DEF_INPUT_HEIGHT; ++ ++ vout->task.output.width = vout->crop_bounds.width; ++ vout->task.output.height = vout->crop_bounds.height; ++ vout->task.output.crop.pos.x = 0; ++ vout->task.output.crop.pos.y = 0; ++ vout->task.output.crop.w = vout->crop_bounds.width; ++ vout->task.output.crop.h = vout->crop_bounds.height; ++ if (colorspaceofpixel(vout->disp_fmt) == YUV_CS) ++ vout->task.output.format = IPU_PIX_FMT_UYVY; ++ else ++ vout->task.output.format = IPU_PIX_FMT_RGB565; ++ ++ return 0; ++} ++ ++static inline unsigned long get_jiffies(struct timeval *t) ++{ ++ struct timeval cur; ++ ++ if (t->tv_usec >= 1000000) { ++ t->tv_sec += t->tv_usec / 1000000; ++ t->tv_usec = t->tv_usec % 1000000; ++ } ++ ++ do_gettimeofday(&cur); ++ if ((t->tv_sec < cur.tv_sec) ++ || ((t->tv_sec == cur.tv_sec) && (t->tv_usec < cur.tv_usec))) ++ return jiffies; ++ ++ if (t->tv_usec < cur.tv_usec) { ++ cur.tv_sec = t->tv_sec - cur.tv_sec - 1; ++ cur.tv_usec = t->tv_usec + 1000000 - cur.tv_usec; ++ } else { ++ cur.tv_sec = t->tv_sec - cur.tv_sec; ++ cur.tv_usec = t->tv_usec - cur.tv_usec; ++ } ++ ++ return jiffies + timeval_to_jiffies(&cur); ++} ++ ++static bool deinterlace_3_field(struct mxc_vout_output *vout) ++{ ++ return (vout->task.input.deinterlace.enable && ++ (vout->task.input.deinterlace.motion != HIGH_MOTION)); ++} ++ ++static int set_field_fmt(struct mxc_vout_output *vout, enum v4l2_field field) ++{ ++ struct ipu_deinterlace *deinterlace = &vout->task.input.deinterlace; ++ ++ switch (field) { ++ /* Images are in progressive format, not interlaced */ ++ case V4L2_FIELD_NONE: ++ case V4L2_FIELD_ANY: ++ deinterlace->enable = false; ++ deinterlace->field_fmt = 0; ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "Progressive frame.\n"); ++ break; ++ case V4L2_FIELD_INTERLACED_TB: ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "Enable deinterlace TB.\n"); ++ deinterlace->enable = true; ++ deinterlace->field_fmt = IPU_DEINTERLACE_FIELD_TOP; ++ break; ++ case V4L2_FIELD_INTERLACED_BT: ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "Enable deinterlace BT.\n"); ++ deinterlace->enable = true; ++ deinterlace->field_fmt = IPU_DEINTERLACE_FIELD_BOTTOM; ++ break; ++ default: ++ v4l2_err(vout->vfd->v4l2_dev, ++ "field format:%d not supported yet!\n", field); ++ return -EINVAL; ++ } ++ ++ if (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format) { ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "tiled fmt enable deinterlace.\n"); ++ deinterlace->enable = true; ++ } ++ ++ if (deinterlace->enable && vdi_rate_double) ++ deinterlace->field_fmt |= IPU_DEINTERLACE_RATE_EN; ++ ++ return 0; ++} ++ ++static bool is_pp_bypass(struct mxc_vout_output *vout) ++{ ++ if ((IPU_PIX_FMT_TILED_NV12 == vout->task.input.format) || ++ (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format)) ++ return false; ++ if ((vout->task.input.width == vout->task.output.width) && ++ (vout->task.input.height == vout->task.output.height) && ++ (vout->task.input.crop.w == vout->task.output.crop.w) && ++ (vout->task.input.crop.h == vout->task.output.crop.h) && ++ (vout->task.output.rotate < IPU_ROTATE_HORIZ_FLIP) && ++ !vout->task.input.deinterlace.enable) { ++ if (vout->disp_support_csc) ++ return true; ++ else if (!need_csc(vout->task.input.format, vout->disp_fmt)) ++ return true; ++ /* ++ * input crop show to full output which can show based on ++ * xres_virtual/yres_virtual ++ */ ++ } else if ((vout->task.input.crop.w == vout->task.output.crop.w) && ++ (vout->task.output.crop.w == vout->task.output.width) && ++ (vout->task.input.crop.h == vout->task.output.crop.h) && ++ (vout->task.output.crop.h == ++ vout->task.output.height) && ++ (vout->task.output.rotate < IPU_ROTATE_HORIZ_FLIP) && ++ !vout->task.input.deinterlace.enable) { ++ if (vout->disp_support_csc) ++ return true; ++ else if (!need_csc(vout->task.input.format, vout->disp_fmt)) ++ return true; ++ } ++ return false; ++} ++ ++static void setup_buf_timer(struct mxc_vout_output *vout, ++ struct videobuf_buffer *vb) ++{ ++ ktime_t expiry_time, now; ++ ++ /* if timestamp is 0, then default to 30fps */ ++ if ((vb->ts.tv_sec == 0) && (vb->ts.tv_usec == 0)) ++ expiry_time = ktime_add_ns(vout->start_ktime, ++ NSEC_PER_FRAME_30FPS * vout->frame_count); ++ else ++ expiry_time = timeval_to_ktime(vb->ts); ++ ++ now = hrtimer_cb_get_time(&vout->timer); ++ if ((now.tv64 > expiry_time.tv64)) { ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "warning: timer timeout already expired.\n"); ++ expiry_time = now; ++ } ++ ++ hrtimer_start(&vout->timer, expiry_time, HRTIMER_MODE_ABS); ++ ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "timer handler next " ++ "schedule: %lldnsecs\n", expiry_time.tv64); ++} ++ ++static int show_buf(struct mxc_vout_output *vout, int idx, ++ struct ipu_pos *ipos) ++{ ++ struct fb_info *fbi = vout->fbi; ++ struct fb_var_screeninfo var; ++ int ret; ++ u32 fb_base = 0; ++ ++ memcpy(&var, &fbi->var, sizeof(var)); ++ ++ if (vout->linear_bypass_pp || vout->tiled_bypass_pp) { ++ /* ++ * crack fb base ++ * NOTE: should not do other fb operation during v4l2 ++ */ ++ console_lock(); ++ fb_base = fbi->fix.smem_start; ++ fbi->fix.smem_start = vout->task.output.paddr; ++ fbi->var.yoffset = ipos->y + 1; ++ var.xoffset = ipos->x; ++ var.yoffset = ipos->y; ++ var.vmode |= FB_VMODE_YWRAP; ++ ret = fb_pan_display(fbi, &var); ++ fbi->fix.smem_start = fb_base; ++ console_unlock(); ++ } else { ++ console_lock(); ++ var.yoffset = idx * fbi->var.yres; ++ var.vmode &= ~FB_VMODE_YWRAP; ++ ret = fb_pan_display(fbi, &var); ++ console_unlock(); ++ } ++ ++ return ret; ++} ++ ++static void disp_work_func(struct work_struct *work) ++{ ++ struct mxc_vout_output *vout = ++ container_of(work, struct mxc_vout_output, disp_work); ++ struct videobuf_queue *q = &vout->vbq; ++ struct videobuf_buffer *vb, *vb_next = NULL; ++ unsigned long flags = 0; ++ struct ipu_pos ipos; ++ int ret = 0; ++ u32 in_fmt = 0; ++ u32 vdi_cnt = 0; ++ u32 vdi_frame; ++ u32 index = 0; ++ u32 ocrop_h = 0; ++ u32 o_height = 0; ++ u32 tiled_interlaced = 0; ++ bool tiled_fmt = false; ++ ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "disp work begin one frame\n"); ++ ++ spin_lock_irqsave(q->irqlock, flags); ++ ++ if (list_empty(&vout->active_list)) { ++ v4l2_warn(vout->vfd->v4l2_dev, ++ "no entry in active_list, should not be here\n"); ++ spin_unlock_irqrestore(q->irqlock, flags); ++ return; ++ } ++ ++ vb = list_first_entry(&vout->active_list, ++ struct videobuf_buffer, queue); ++ ret = set_field_fmt(vout, vb->field); ++ if (ret < 0) { ++ spin_unlock_irqrestore(q->irqlock, flags); ++ return; ++ } ++ if (deinterlace_3_field(vout)) { ++ if (list_is_singular(&vout->active_list)) { ++ if (list_empty(&vout->queue_list)) { ++ vout->timer_stop = true; ++ spin_unlock_irqrestore(q->irqlock, flags); ++ v4l2_warn(vout->vfd->v4l2_dev, ++ "no enough entry for 3 fields " ++ "deinterlacer\n"); ++ return; ++ } ++ ++ /* ++ * We need to use the next vb even if it is ++ * not on the active list. ++ */ ++ vb_next = list_first_entry(&vout->queue_list, ++ struct videobuf_buffer, queue); ++ } else ++ vb_next = list_first_entry(vout->active_list.next, ++ struct videobuf_buffer, queue); ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "cur field_fmt:%d, next field_fmt:%d.\n", ++ vb->field, vb_next->field); ++ /* repeat the last field during field format changing */ ++ if ((vb->field != vb_next->field) && ++ (vb_next->field != V4L2_FIELD_NONE)) ++ vb_next = vb; ++ } ++ ++ spin_unlock_irqrestore(q->irqlock, flags); ++ ++vdi_frame_rate_double: ++ mutex_lock(&vout->task_lock); ++ ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "v4l2 frame_cnt:%ld, vb_field:%d, fmt:%d\n", ++ vout->frame_count, vb->field, ++ vout->task.input.deinterlace.field_fmt); ++ if (vb->memory == V4L2_MEMORY_USERPTR) ++ vout->task.input.paddr = vb->baddr; ++ else ++ vout->task.input.paddr = videobuf_to_dma_contig(vb); ++ ++ if (vout->task.input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN) ++ index = vout->vdi_frame_cnt % FB_BUFS; ++ else ++ index = vout->frame_count % FB_BUFS; ++ if (vout->linear_bypass_pp) { ++ vout->task.output.paddr = vout->task.input.paddr; ++ ipos.x = vout->task.input.crop.pos.x; ++ ipos.y = vout->task.input.crop.pos.y; ++ } else { ++ if (deinterlace_3_field(vout)) { ++ if (vb->memory == V4L2_MEMORY_USERPTR) ++ vout->task.input.paddr_n = vb_next->baddr; ++ else ++ vout->task.input.paddr_n = ++ videobuf_to_dma_contig(vb_next); ++ } ++ vout->task.output.paddr = vout->disp_bufs[index]; ++ if (vout->vdoa_1080p) { ++ o_height = vout->task.output.height; ++ ocrop_h = vout->task.output.crop.h; ++ vout->task.output.height = FRAME_HEIGHT_1080P; ++ vout->task.output.crop.h = FRAME_HEIGHT_1080P; ++ } ++ tiled_fmt = ++ (IPU_PIX_FMT_TILED_NV12 == vout->task.input.format) || ++ (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format); ++ if (vout->tiled_bypass_pp) { ++ ipos.x = vout->task.input.crop.pos.x; ++ ipos.y = vout->task.input.crop.pos.y; ++ } else if (tiled_fmt) { ++ vout->vdoa_task.input.paddr = vout->task.input.paddr; ++ if (deinterlace_3_field(vout)) ++ vout->vdoa_task.input.paddr_n = ++ vout->task.input.paddr_n; ++ vout->vdoa_task.output.paddr = vout->vdoa_work.paddr; ++ ret = ipu_queue_task(&vout->vdoa_task); ++ if (ret < 0) { ++ mutex_unlock(&vout->task_lock); ++ goto err; ++ } ++ vout->task.input.paddr = vout->vdoa_task.output.paddr; ++ in_fmt = vout->task.input.format; ++ vout->task.input.format = vout->vdoa_task.output.format; ++ if (vout->task.input.deinterlace.enable) { ++ tiled_interlaced = 1; ++ vout->task.input.deinterlace.enable = 0; ++ } ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "tiled queue task\n"); ++ } ++ ret = ipu_queue_task(&vout->task); ++ if ((!vout->tiled_bypass_pp) && tiled_fmt) ++ vout->task.input.format = in_fmt; ++ if (tiled_interlaced) ++ vout->task.input.deinterlace.enable = 1; ++ if (ret < 0) { ++ mutex_unlock(&vout->task_lock); ++ goto err; ++ } ++ if (vout->vdoa_1080p) { ++ vout->task.output.crop.h = ocrop_h; ++ vout->task.output.height = o_height; ++ } ++ } ++ ++ mutex_unlock(&vout->task_lock); ++ ++ ret = show_buf(vout, index, &ipos); ++ if (ret < 0) ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "show buf with ret %d\n", ret); ++ ++ if (vout->task.input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN) { ++ vdi_frame = vout->task.input.deinterlace.field_fmt ++ & IPU_DEINTERLACE_RATE_FRAME1; ++ if (vdi_frame) ++ vout->task.input.deinterlace.field_fmt &= ++ ~IPU_DEINTERLACE_RATE_FRAME1; ++ else ++ vout->task.input.deinterlace.field_fmt |= ++ IPU_DEINTERLACE_RATE_FRAME1; ++ vout->vdi_frame_cnt++; ++ vdi_cnt++; ++ if (vdi_cnt < IPU_DEINTERLACE_MAX_FRAME) ++ goto vdi_frame_rate_double; ++ } ++ spin_lock_irqsave(q->irqlock, flags); ++ ++ list_del(&vb->queue); ++ ++ /* ++ * The videobuf before the last one has been shown. Set ++ * VIDEOBUF_DONE state here to avoid tearing issue in ic bypass ++ * case, which makes sure a buffer being shown will not be ++ * dequeued to be overwritten. It also brings side-effect that ++ * the last 2 buffers can not be dequeued correctly, apps need ++ * to take care of it. ++ */ ++ if (vout->pre2_vb) { ++ vout->pre2_vb->state = VIDEOBUF_DONE; ++ wake_up_interruptible(&vout->pre2_vb->done); ++ vout->pre2_vb = NULL; ++ } ++ ++ if (vout->linear_bypass_pp) { ++ vout->pre2_vb = vout->pre1_vb; ++ vout->pre1_vb = vb; ++ } else { ++ if (vout->pre1_vb) { ++ vout->pre1_vb->state = VIDEOBUF_DONE; ++ wake_up_interruptible(&vout->pre1_vb->done); ++ vout->pre1_vb = NULL; ++ } ++ vb->state = VIDEOBUF_DONE; ++ wake_up_interruptible(&vb->done); ++ } ++ ++ vout->frame_count++; ++ ++ /* pick next queue buf to setup timer */ ++ if (list_empty(&vout->queue_list)) ++ vout->timer_stop = true; ++ else { ++ vb = list_first_entry(&vout->queue_list, ++ struct videobuf_buffer, queue); ++ setup_buf_timer(vout, vb); ++ } ++ ++ spin_unlock_irqrestore(q->irqlock, flags); ++ ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "disp work finish one frame\n"); ++ ++ return; ++err: ++ v4l2_err(vout->vfd->v4l2_dev, "display work fail ret = %d\n", ret); ++ vout->timer_stop = true; ++ vb->state = VIDEOBUF_ERROR; ++ return; ++} ++ ++static enum hrtimer_restart mxc_vout_timer_handler(struct hrtimer *timer) ++{ ++ struct mxc_vout_output *vout = container_of(timer, ++ struct mxc_vout_output, ++ timer); ++ struct videobuf_queue *q = &vout->vbq; ++ struct videobuf_buffer *vb; ++ unsigned long flags = 0; ++ ++ spin_lock_irqsave(q->irqlock, flags); ++ ++ /* ++ * put first queued entry into active, if previous entry did not ++ * finish, setup current entry's timer again. ++ */ ++ if (list_empty(&vout->queue_list)) { ++ spin_unlock_irqrestore(q->irqlock, flags); ++ return HRTIMER_NORESTART; ++ } ++ ++ /* move videobuf from queued list to active list */ ++ vb = list_first_entry(&vout->queue_list, ++ struct videobuf_buffer, queue); ++ list_del(&vb->queue); ++ list_add_tail(&vb->queue, &vout->active_list); ++ ++ if (queue_work(vout->v4l_wq, &vout->disp_work) == 0) { ++ v4l2_warn(vout->vfd->v4l2_dev, ++ "disp work was in queue already, queue buf again next time\n"); ++ list_del(&vb->queue); ++ list_add(&vb->queue, &vout->queue_list); ++ spin_unlock_irqrestore(q->irqlock, flags); ++ return HRTIMER_NORESTART; ++ } ++ ++ vb->state = VIDEOBUF_ACTIVE; ++ ++ spin_unlock_irqrestore(q->irqlock, flags); ++ ++ return HRTIMER_NORESTART; ++} ++ ++/* Video buffer call backs */ ++ ++/* ++ * Buffer setup function is called by videobuf layer when REQBUF ioctl is ++ * called. This is used to setup buffers and return size and count of ++ * buffers allocated. After the call to this buffer, videobuf layer will ++ * setup buffer queue depending on the size and count of buffers ++ */ ++static int mxc_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, ++ unsigned int *size) ++{ ++ struct mxc_vout_output *vout = q->priv_data; ++ unsigned int frame_size; ++ ++ if (!vout) ++ return -EINVAL; ++ ++ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type) ++ return -EINVAL; ++ ++ frame_size = get_frame_size(vout); ++ *size = PAGE_ALIGN(frame_size); ++ ++ return 0; ++} ++ ++/* ++ * This function will be called when VIDIOC_QBUF ioctl is called. ++ * It prepare buffers before give out for the display. This function ++ * converts user space virtual address into physical address if userptr memory ++ * exchange mechanism is used. ++ */ ++static int mxc_vout_buffer_prepare(struct videobuf_queue *q, ++ struct videobuf_buffer *vb, ++ enum v4l2_field field) ++{ ++ vb->state = VIDEOBUF_PREPARED; ++ return 0; ++} ++ ++/* ++ * Buffer queue funtion will be called from the videobuf layer when _QBUF ++ * ioctl is called. It is used to enqueue buffer, which is ready to be ++ * displayed. ++ * This function is protected by q->irqlock. ++ */ ++static void mxc_vout_buffer_queue(struct videobuf_queue *q, ++ struct videobuf_buffer *vb) ++{ ++ struct mxc_vout_output *vout = q->priv_data; ++ struct videobuf_buffer *active_vb; ++ ++ list_add_tail(&vb->queue, &vout->queue_list); ++ vb->state = VIDEOBUF_QUEUED; ++ ++ if (vout->timer_stop) { ++ if (deinterlace_3_field(vout) && ++ !list_empty(&vout->active_list)) { ++ active_vb = list_first_entry(&vout->active_list, ++ struct videobuf_buffer, queue); ++ setup_buf_timer(vout, active_vb); ++ } else { ++ setup_buf_timer(vout, vb); ++ } ++ vout->timer_stop = false; ++ } ++} ++ ++/* ++ * Buffer release function is called from videobuf layer to release buffer ++ * which are already allocated ++ */ ++static void mxc_vout_buffer_release(struct videobuf_queue *q, ++ struct videobuf_buffer *vb) ++{ ++ vb->state = VIDEOBUF_NEEDS_INIT; ++} ++ ++static int mxc_vout_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int ret; ++ struct mxc_vout_output *vout = file->private_data; ++ ++ if (!vout) ++ return -ENODEV; ++ ++ ret = videobuf_mmap_mapper(&vout->vbq, vma); ++ if (ret < 0) ++ v4l2_err(vout->vfd->v4l2_dev, ++ "offset invalid [offset=0x%lx]\n", ++ (vma->vm_pgoff << PAGE_SHIFT)); ++ ++ return ret; ++} ++ ++static int mxc_vout_release(struct file *file) ++{ ++ unsigned int ret = 0; ++ struct videobuf_queue *q; ++ struct mxc_vout_output *vout = file->private_data; ++ ++ if (!vout) ++ return 0; ++ ++ if (--vout->open_cnt == 0) { ++ q = &vout->vbq; ++ if (q->streaming) ++ mxc_vidioc_streamoff(file, vout, vout->type); ++ else { ++ release_disp_output(vout); ++ videobuf_queue_cancel(q); ++ } ++ destroy_workqueue(vout->v4l_wq); ++ ret = videobuf_mmap_free(q); ++ } ++ ++ return ret; ++} ++ ++static int mxc_vout_open(struct file *file) ++{ ++ struct mxc_vout_output *vout = NULL; ++ int ret = 0; ++ ++ vout = video_drvdata(file); ++ ++ if (vout == NULL) ++ return -ENODEV; ++ ++ if (vout->open_cnt++ == 0) { ++ vout->ctrl_rotate = 0; ++ vout->ctrl_vflip = 0; ++ vout->ctrl_hflip = 0; ++ update_display_setting(); ++ ret = update_setting_from_fbi(vout, vout->fbi); ++ if (ret < 0) ++ goto err; ++ ++ vout->v4l_wq = create_singlethread_workqueue("v4l2q"); ++ if (!vout->v4l_wq) { ++ v4l2_err(vout->vfd->v4l2_dev, ++ "Could not create work queue\n"); ++ ret = -ENOMEM; ++ goto err; ++ } ++ ++ INIT_WORK(&vout->disp_work, disp_work_func); ++ ++ INIT_LIST_HEAD(&vout->queue_list); ++ INIT_LIST_HEAD(&vout->active_list); ++ ++ vout->fmt_init = false; ++ vout->frame_count = 0; ++ vout->vdi_frame_cnt = 0; ++ ++ vout->win_pos.x = 0; ++ vout->win_pos.y = 0; ++ vout->release = true; ++ } ++ ++ file->private_data = vout; ++ ++err: ++ return ret; ++} ++ ++/* ++ * V4L2 ioctls ++ */ ++static int mxc_vidioc_querycap(struct file *file, void *fh, ++ struct v4l2_capability *cap) ++{ ++ struct mxc_vout_output *vout = fh; ++ ++ strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver)); ++ strlcpy(cap->card, vout->vfd->name, sizeof(cap->card)); ++ cap->bus_info[0] = '\0'; ++ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT; ++ ++ return 0; ++} ++ ++static int mxc_vidioc_enum_fmt_vid_out(struct file *file, void *fh, ++ struct v4l2_fmtdesc *fmt) ++{ ++ if (fmt->index >= NUM_MXC_VOUT_FORMATS) ++ return -EINVAL; ++ ++ strlcpy(fmt->description, mxc_formats[fmt->index].description, ++ sizeof(fmt->description)); ++ fmt->pixelformat = mxc_formats[fmt->index].pixelformat; ++ ++ return 0; ++} ++ ++static int mxc_vidioc_g_fmt_vid_out(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct mxc_vout_output *vout = fh; ++ struct v4l2_rect rect; ++ ++ f->fmt.pix.width = vout->task.input.width; ++ f->fmt.pix.height = vout->task.input.height; ++ f->fmt.pix.pixelformat = vout->task.input.format; ++ f->fmt.pix.sizeimage = get_frame_size(vout); ++ ++ if (f->fmt.pix.priv) { ++ rect.left = vout->task.input.crop.pos.x; ++ rect.top = vout->task.input.crop.pos.y; ++ rect.width = vout->task.input.crop.w; ++ rect.height = vout->task.input.crop.h; ++ if (copy_to_user((void __user *)f->fmt.pix.priv, ++ &rect, sizeof(rect))) ++ return -EFAULT; ++ } ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "frame_size:0x%x, pix_fmt:0x%x\n", ++ f->fmt.pix.sizeimage, ++ vout->task.input.format); ++ ++ return 0; ++} ++ ++static inline int ipu_try_task(struct mxc_vout_output *vout) ++{ ++ int ret; ++ struct ipu_task *task = &vout->task; ++ ++again: ++ ret = ipu_check_task(task); ++ if (ret != IPU_CHECK_OK) { ++ if (ret > IPU_CHECK_ERR_MIN) { ++ if (ret == IPU_CHECK_ERR_SPLIT_INPUTW_OVER || ++ ret == IPU_CHECK_ERR_W_DOWNSIZE_OVER) { ++ task->input.crop.w -= 8; ++ goto again; ++ } ++ if (ret == IPU_CHECK_ERR_SPLIT_INPUTH_OVER || ++ ret == IPU_CHECK_ERR_H_DOWNSIZE_OVER) { ++ task->input.crop.h -= 8; ++ goto again; ++ } ++ if (ret == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) { ++ if (vout->disp_support_windows) { ++ task->output.width -= 8; ++ task->output.crop.w = ++ task->output.width; ++ } else ++ task->output.crop.w -= 8; ++ goto again; ++ } ++ if (ret == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) { ++ if (vout->disp_support_windows) { ++ task->output.height -= 8; ++ task->output.crop.h = ++ task->output.height; ++ } else ++ task->output.crop.h -= 8; ++ goto again; ++ } ++ ret = -EINVAL; ++ } ++ } else ++ ret = 0; ++ ++ return ret; ++} ++ ++static inline int vdoaipu_try_task(struct mxc_vout_output *vout) ++{ ++ int ret; ++ int is_1080p_stream; ++ size_t size; ++ struct ipu_task *ipu_task = &vout->task; ++ struct ipu_crop *icrop = &ipu_task->input.crop; ++ struct ipu_task *vdoa_task = &vout->vdoa_task; ++ u32 deinterlace = 0; ++ u32 in_fmt; ++ ++ if (vout->task.input.deinterlace.enable) ++ deinterlace = 1; ++ ++ memset(vdoa_task, 0, sizeof(*vdoa_task)); ++ vdoa_task->output.format = IPU_PIX_FMT_NV12; ++ memcpy(&vdoa_task->input, &ipu_task->input, ++ sizeof(ipu_task->input)); ++ if ((icrop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) || ++ (icrop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN)) { ++ vdoa_task->input.crop.w = ++ ALIGN(icrop->w, IPU_PIX_FMT_TILED_NV12_MBALIGN); ++ vdoa_task->input.crop.h = ++ ALIGN(icrop->h, IPU_PIX_FMT_TILED_NV12_MBALIGN); ++ } ++ vdoa_task->output.width = vdoa_task->input.crop.w; ++ vdoa_task->output.height = vdoa_task->input.crop.h; ++ vdoa_task->output.crop.w = vdoa_task->input.crop.w; ++ vdoa_task->output.crop.h = vdoa_task->input.crop.h; ++ ++ size = PAGE_ALIGN(vdoa_task->input.crop.w * ++ vdoa_task->input.crop.h * ++ fmt_to_bpp(vdoa_task->output.format)/8); ++ if (size > vout->vdoa_work.size) { ++ if (vout->vdoa_work.vaddr) ++ free_dma_buf(vout, &vout->vdoa_work); ++ vout->vdoa_work.size = size; ++ ret = alloc_dma_buf(vout, &vout->vdoa_work); ++ if (ret < 0) ++ return ret; ++ } ++ ret = ipu_check_task(vdoa_task); ++ if (ret != IPU_CHECK_OK) ++ return -EINVAL; ++ ++ is_1080p_stream = CHECK_TILED_1080P_STREAM(vout); ++ if (is_1080p_stream) ++ ipu_task->input.crop.h = VALID_HEIGHT_1080P; ++ in_fmt = ipu_task->input.format; ++ ipu_task->input.format = vdoa_task->output.format; ++ ipu_task->input.height = vdoa_task->output.height; ++ ipu_task->input.width = vdoa_task->output.width; ++ if (deinterlace) ++ ipu_task->input.deinterlace.enable = 0; ++ ret = ipu_try_task(vout); ++ if (deinterlace) ++ ipu_task->input.deinterlace.enable = 1; ++ ipu_task->input.format = in_fmt; ++ ++ return ret; ++} ++ ++static int mxc_vout_try_task(struct mxc_vout_output *vout) ++{ ++ int ret = 0; ++ struct ipu_output *output = &vout->task.output; ++ struct ipu_input *input = &vout->task.input; ++ struct ipu_crop *crop = &input->crop; ++ u32 o_height = 0; ++ u32 ocrop_h = 0; ++ bool tiled_fmt = false; ++ bool tiled_need_pp = false; ++ ++ vout->vdoa_1080p = CHECK_TILED_1080P_DISPLAY(vout); ++ if (vout->vdoa_1080p) { ++ input->crop.h = FRAME_HEIGHT_1080P; ++ o_height = output->height; ++ ocrop_h = output->crop.h; ++ output->height = FRAME_HEIGHT_1080P; ++ output->crop.h = FRAME_HEIGHT_1080P; ++ } ++ ++ if ((IPU_PIX_FMT_TILED_NV12 == input->format) || ++ (IPU_PIX_FMT_TILED_NV12F == input->format)) { ++ if ((input->width % IPU_PIX_FMT_TILED_NV12_MBALIGN) || ++ (input->height % IPU_PIX_FMT_TILED_NV12_MBALIGN) || ++ (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN) || ++ (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN)) { ++ v4l2_err(vout->vfd->v4l2_dev, ++ "ERR: tiled fmt needs 16 pixel align.\n"); ++ return -EINVAL; ++ } ++ if ((crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) || ++ (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN)) ++ tiled_need_pp = true; ++ } else { ++ crop->w -= crop->w % 8; ++ crop->h -= crop->h % 8; ++ } ++ /* assume task.output already set by S_CROP */ ++ vout->linear_bypass_pp = is_pp_bypass(vout); ++ if (vout->linear_bypass_pp) { ++ v4l2_info(vout->vfd->v4l2_dev, "Bypass IC.\n"); ++ output->format = input->format; ++ } else { ++ /* if need CSC, choose IPU-DP or IPU_IC do it */ ++ if (vout->disp_support_csc) { ++ if (colorspaceofpixel(input->format) == YUV_CS) ++ output->format = IPU_PIX_FMT_UYVY; ++ else ++ output->format = IPU_PIX_FMT_RGB565; ++ } else { ++ if (colorspaceofpixel(vout->disp_fmt) == YUV_CS) ++ output->format = IPU_PIX_FMT_UYVY; ++ else ++ output->format = IPU_PIX_FMT_RGB565; ++ } ++ ++ vout->tiled_bypass_pp = false; ++ if ((IPU_PIX_FMT_TILED_NV12 == input->format) || ++ (IPU_PIX_FMT_TILED_NV12F == input->format)) { ++ /* check resize/rotate/flip, or csc task */ ++ if (!(tiled_need_pp || ++ (IPU_ROTATE_NONE != output->rotate) || ++ (input->crop.w != output->crop.w) || ++ (input->crop.h != output->crop.h) || ++ (!vout->disp_support_csc && ++ (colorspaceofpixel(vout->disp_fmt) == RGB_CS))) ++ ) { ++ /* IC bypass */ ++ output->format = IPU_PIX_FMT_NV12; ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "tiled bypass pp\n"); ++ vout->tiled_bypass_pp = true; ++ } ++ tiled_fmt = true; ++ } ++ ++ if ((!vout->tiled_bypass_pp) && tiled_fmt) ++ ret = vdoaipu_try_task(vout); ++ else ++ ret = ipu_try_task(vout); ++ } ++ ++ if (vout->vdoa_1080p) { ++ output->height = o_height; ++ output->crop.h = ocrop_h; ++ } ++ ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "icrop.w:%u, icrop.h:%u, iw:%u, ih:%u," ++ "ocrop.w:%u, ocrop.h:%u, ow:%u, oh:%u\n", ++ input->crop.w, input->crop.h, ++ input->width, input->height, ++ output->crop.w, output->crop.h, ++ output->width, output->height); ++ return ret; ++} ++ ++static int mxc_vout_try_format(struct mxc_vout_output *vout, ++ struct v4l2_format *f) ++{ ++ int ret = 0; ++ struct v4l2_rect rect; ++ ++ if ((f->fmt.pix.field != V4L2_FIELD_NONE) && ++ (IPU_PIX_FMT_TILED_NV12 == vout->task.input.format)) { ++ v4l2_err(vout->vfd->v4l2_dev, ++ "progressive tiled fmt should used V4L2_FIELD_NONE!\n"); ++ return -EINVAL; ++ } ++ ++ if (f->fmt.pix.priv && copy_from_user(&rect, ++ (void __user *)f->fmt.pix.priv, sizeof(rect))) ++ return -EFAULT; ++ ++ vout->task.input.width = f->fmt.pix.width; ++ vout->task.input.height = f->fmt.pix.height; ++ vout->task.input.format = f->fmt.pix.pixelformat; ++ ++ ret = set_field_fmt(vout, f->fmt.pix.field); ++ if (ret < 0) ++ return ret; ++ ++ if (f->fmt.pix.priv) { ++ vout->task.input.crop.pos.x = rect.left; ++ vout->task.input.crop.pos.y = rect.top; ++ vout->task.input.crop.w = rect.width; ++ vout->task.input.crop.h = rect.height; ++ } else { ++ vout->task.input.crop.pos.x = 0; ++ vout->task.input.crop.pos.y = 0; ++ vout->task.input.crop.w = f->fmt.pix.width; ++ vout->task.input.crop.h = f->fmt.pix.height; ++ } ++ memcpy(&vout->in_rect, &vout->task.input.crop, sizeof(vout->in_rect)); ++ ++ ret = mxc_vout_try_task(vout); ++ if (!ret) { ++ if (f->fmt.pix.priv) { ++ rect.width = vout->task.input.crop.w; ++ rect.height = vout->task.input.crop.h; ++ if (copy_to_user((void __user *)f->fmt.pix.priv, ++ &rect, sizeof(rect))) ++ ret = -EFAULT; ++ } else { ++ f->fmt.pix.width = vout->task.input.crop.w; ++ f->fmt.pix.height = vout->task.input.crop.h; ++ } ++ } ++ ++ return ret; ++} ++ ++static bool mxc_vout_need_fb_reconfig(struct mxc_vout_output *vout, ++ struct mxc_vout_output *pre_vout) ++{ ++ if (!vout->vbq.streaming) ++ return false; ++ ++ if (vout->tiled_bypass_pp) ++ return true; ++ ++ if (vout->linear_bypass_pp != pre_vout->linear_bypass_pp) ++ return true; ++ ++ /* cropped output resolution or format are changed */ ++ if (vout->task.output.format != pre_vout->task.output.format || ++ vout->task.output.crop.w != pre_vout->task.output.crop.w || ++ vout->task.output.crop.h != pre_vout->task.output.crop.h) ++ return true; ++ ++ /* overlay: window position or resolution are changed */ ++ if (vout->disp_support_windows && ++ (vout->win_pos.x != pre_vout->win_pos.x || ++ vout->win_pos.y != pre_vout->win_pos.y || ++ vout->task.output.width != pre_vout->task.output.width || ++ vout->task.output.height != pre_vout->task.output.height)) ++ return true; ++ ++ /* background: cropped position is changed */ ++ if (!vout->disp_support_windows && ++ (vout->task.output.crop.pos.x != ++ pre_vout->task.output.crop.pos.x || ++ vout->task.output.crop.pos.y != ++ pre_vout->task.output.crop.pos.y)) ++ return true; ++ ++ return false; ++} ++ ++static int mxc_vidioc_s_fmt_vid_out(struct file *file, void *fh, ++ struct v4l2_format *f) ++{ ++ struct mxc_vout_output *vout = fh; ++ int ret = 0; ++ ++ if (vout->vbq.streaming) ++ return -EBUSY; ++ ++ mutex_lock(&vout->task_lock); ++ ret = mxc_vout_try_format(vout, f); ++ if (ret >= 0) ++ vout->fmt_init = true; ++ mutex_unlock(&vout->task_lock); ++ ++ return ret; ++} ++ ++static int mxc_vidioc_cropcap(struct file *file, void *fh, ++ struct v4l2_cropcap *cropcap) ++{ ++ struct mxc_vout_output *vout = fh; ++ ++ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ ++ cropcap->bounds = vout->crop_bounds; ++ cropcap->defrect = vout->crop_bounds; ++ ++ return 0; ++} ++ ++static int mxc_vidioc_g_crop(struct file *file, void *fh, ++ struct v4l2_crop *crop) ++{ ++ struct mxc_vout_output *vout = fh; ++ ++ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ ++ if (vout->disp_support_windows) { ++ crop->c.left = vout->win_pos.x; ++ crop->c.top = vout->win_pos.y; ++ crop->c.width = vout->task.output.width; ++ crop->c.height = vout->task.output.height; ++ } else { ++ if (vout->task.output.crop.w && vout->task.output.crop.h) { ++ crop->c.left = vout->task.output.crop.pos.x; ++ crop->c.top = vout->task.output.crop.pos.y; ++ crop->c.width = vout->task.output.crop.w; ++ crop->c.height = vout->task.output.crop.h; ++ } else { ++ crop->c.left = 0; ++ crop->c.top = 0; ++ crop->c.width = vout->task.output.width; ++ crop->c.height = vout->task.output.height; ++ } ++ } ++ ++ return 0; ++} ++ ++static int mxc_vidioc_s_crop(struct file *file, void *fh, ++ const struct v4l2_crop *crop) ++{ ++ struct mxc_vout_output *vout = fh, *pre_vout; ++ struct v4l2_rect *b = &vout->crop_bounds; ++ struct v4l2_crop fix_up_crop; ++ int ret = 0; ++ ++ memcpy(&fix_up_crop, crop, sizeof(*crop)); ++ ++ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ ++ if (crop->c.width < 0 || crop->c.height < 0) ++ return -EINVAL; ++ ++ if (crop->c.width == 0) ++ fix_up_crop.c.width = b->width - b->left; ++ if (crop->c.height == 0) ++ fix_up_crop.c.height = b->height - b->top; ++ ++ if (crop->c.top < b->top) ++ fix_up_crop.c.top = b->top; ++ if (crop->c.top >= b->top + b->height) ++ fix_up_crop.c.top = b->top + b->height - 1; ++ if (crop->c.height > b->top - crop->c.top + b->height) ++ fix_up_crop.c.height = ++ b->top - fix_up_crop.c.top + b->height; ++ ++ if (crop->c.left < b->left) ++ fix_up_crop.c.left = b->left; ++ if (crop->c.left >= b->left + b->width) ++ fix_up_crop.c.left = b->left + b->width - 1; ++ if (crop->c.width > b->left - crop->c.left + b->width) ++ fix_up_crop.c.width = ++ b->left - fix_up_crop.c.left + b->width; ++ ++ /* stride line limitation */ ++ fix_up_crop.c.height -= fix_up_crop.c.height % 8; ++ fix_up_crop.c.width -= fix_up_crop.c.width % 8; ++ if ((fix_up_crop.c.width <= 0) || (fix_up_crop.c.height <= 0) || ++ ((fix_up_crop.c.left + fix_up_crop.c.width) > ++ (b->left + b->width)) || ++ ((fix_up_crop.c.top + fix_up_crop.c.height) > ++ (b->top + b->height))) { ++ v4l2_err(vout->vfd->v4l2_dev, "s_crop err: %d, %d, %d, %d", ++ fix_up_crop.c.left, fix_up_crop.c.top, ++ fix_up_crop.c.width, fix_up_crop.c.height); ++ return -EINVAL; ++ } ++ ++ /* the same setting, return */ ++ if (vout->disp_support_windows) { ++ if ((vout->win_pos.x == fix_up_crop.c.left) && ++ (vout->win_pos.y == fix_up_crop.c.top) && ++ (vout->task.output.crop.w == fix_up_crop.c.width) && ++ (vout->task.output.crop.h == fix_up_crop.c.height)) ++ return 0; ++ } else { ++ if ((vout->task.output.crop.pos.x == fix_up_crop.c.left) && ++ (vout->task.output.crop.pos.y == fix_up_crop.c.top) && ++ (vout->task.output.crop.w == fix_up_crop.c.width) && ++ (vout->task.output.crop.h == fix_up_crop.c.height)) ++ return 0; ++ } ++ ++ pre_vout = vmalloc(sizeof(*pre_vout)); ++ if (!pre_vout) ++ return -ENOMEM; ++ ++ /* wait current work finish */ ++ if (vout->vbq.streaming) ++ flush_workqueue(vout->v4l_wq); ++ ++ mutex_lock(&vout->task_lock); ++ ++ memcpy(pre_vout, vout, sizeof(*vout)); ++ ++ if (vout->disp_support_windows) { ++ vout->task.output.crop.pos.x = 0; ++ vout->task.output.crop.pos.y = 0; ++ vout->win_pos.x = fix_up_crop.c.left; ++ vout->win_pos.y = fix_up_crop.c.top; ++ vout->task.output.width = fix_up_crop.c.width; ++ vout->task.output.height = fix_up_crop.c.height; ++ } else { ++ vout->task.output.crop.pos.x = fix_up_crop.c.left; ++ vout->task.output.crop.pos.y = fix_up_crop.c.top; ++ } ++ ++ vout->task.output.crop.w = fix_up_crop.c.width; ++ vout->task.output.crop.h = fix_up_crop.c.height; ++ ++ /* ++ * must S_CROP before S_FMT, for fist time S_CROP, will not check ++ * ipu task, it will check in S_FMT, after S_FMT, S_CROP should ++ * check ipu task too. ++ */ ++ if (vout->fmt_init) { ++ memcpy(&vout->task.input.crop, &vout->in_rect, ++ sizeof(vout->in_rect)); ++ ret = mxc_vout_try_task(vout); ++ if (ret < 0) { ++ v4l2_err(vout->vfd->v4l2_dev, ++ "vout check task failed\n"); ++ memcpy(vout, pre_vout, sizeof(*vout)); ++ goto done; ++ } ++ ++ if (mxc_vout_need_fb_reconfig(vout, pre_vout)) { ++ ret = config_disp_output(vout); ++ if (ret < 0) ++ v4l2_err(vout->vfd->v4l2_dev, ++ "Config display output failed\n"); ++ } ++ } ++ ++done: ++ vfree(pre_vout); ++ mutex_unlock(&vout->task_lock); ++ ++ return ret; ++} ++ ++static int mxc_vidioc_queryctrl(struct file *file, void *fh, ++ struct v4l2_queryctrl *ctrl) ++{ ++ int ret = 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_ROTATE: ++ ret = v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0); ++ break; ++ case V4L2_CID_VFLIP: ++ ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0); ++ break; ++ case V4L2_CID_HFLIP: ++ ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0); ++ break; ++ case V4L2_CID_MXC_MOTION: ++ ret = v4l2_ctrl_query_fill(ctrl, 0, 2, 1, 0); ++ break; ++ default: ++ ctrl->name[0] = '\0'; ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++static int mxc_vidioc_g_ctrl(struct file *file, void *fh, ++ struct v4l2_control *ctrl) ++{ ++ int ret = 0; ++ struct mxc_vout_output *vout = fh; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_ROTATE: ++ ctrl->value = vout->ctrl_rotate; ++ break; ++ case V4L2_CID_VFLIP: ++ ctrl->value = vout->ctrl_vflip; ++ break; ++ case V4L2_CID_HFLIP: ++ ctrl->value = vout->ctrl_hflip; ++ break; ++ case V4L2_CID_MXC_MOTION: ++ if (vout->task.input.deinterlace.enable) ++ ctrl->value = vout->task.input.deinterlace.motion; ++ else ++ ctrl->value = 0; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ return ret; ++} ++ ++static void setup_task_rotation(struct mxc_vout_output *vout) ++{ ++ if (vout->ctrl_rotate == 0) { ++ if (vout->ctrl_vflip && vout->ctrl_hflip) ++ vout->task.output.rotate = IPU_ROTATE_180; ++ else if (vout->ctrl_vflip) ++ vout->task.output.rotate = IPU_ROTATE_VERT_FLIP; ++ else if (vout->ctrl_hflip) ++ vout->task.output.rotate = IPU_ROTATE_HORIZ_FLIP; ++ else ++ vout->task.output.rotate = IPU_ROTATE_NONE; ++ } else if (vout->ctrl_rotate == 90) { ++ if (vout->ctrl_vflip && vout->ctrl_hflip) ++ vout->task.output.rotate = IPU_ROTATE_90_LEFT; ++ else if (vout->ctrl_vflip) ++ vout->task.output.rotate = IPU_ROTATE_90_RIGHT_VFLIP; ++ else if (vout->ctrl_hflip) ++ vout->task.output.rotate = IPU_ROTATE_90_RIGHT_HFLIP; ++ else ++ vout->task.output.rotate = IPU_ROTATE_90_RIGHT; ++ } else if (vout->ctrl_rotate == 180) { ++ if (vout->ctrl_vflip && vout->ctrl_hflip) ++ vout->task.output.rotate = IPU_ROTATE_NONE; ++ else if (vout->ctrl_vflip) ++ vout->task.output.rotate = IPU_ROTATE_HORIZ_FLIP; ++ else if (vout->ctrl_hflip) ++ vout->task.output.rotate = IPU_ROTATE_VERT_FLIP; ++ else ++ vout->task.output.rotate = IPU_ROTATE_180; ++ } else if (vout->ctrl_rotate == 270) { ++ if (vout->ctrl_vflip && vout->ctrl_hflip) ++ vout->task.output.rotate = IPU_ROTATE_90_RIGHT; ++ else if (vout->ctrl_vflip) ++ vout->task.output.rotate = IPU_ROTATE_90_RIGHT_HFLIP; ++ else if (vout->ctrl_hflip) ++ vout->task.output.rotate = IPU_ROTATE_90_RIGHT_VFLIP; ++ else ++ vout->task.output.rotate = IPU_ROTATE_90_LEFT; ++ } ++} ++ ++static int mxc_vidioc_s_ctrl(struct file *file, void *fh, ++ struct v4l2_control *ctrl) ++{ ++ int ret = 0; ++ struct mxc_vout_output *vout = fh, *pre_vout; ++ ++ pre_vout = vmalloc(sizeof(*pre_vout)); ++ if (!pre_vout) ++ return -ENOMEM; ++ ++ /* wait current work finish */ ++ if (vout->vbq.streaming) ++ flush_workqueue(vout->v4l_wq); ++ ++ mutex_lock(&vout->task_lock); ++ ++ memcpy(pre_vout, vout, sizeof(*vout)); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_ROTATE: ++ { ++ vout->ctrl_rotate = (ctrl->value/90) * 90; ++ if (vout->ctrl_rotate > 270) ++ vout->ctrl_rotate = 270; ++ setup_task_rotation(vout); ++ break; ++ } ++ case V4L2_CID_VFLIP: ++ { ++ vout->ctrl_vflip = ctrl->value; ++ setup_task_rotation(vout); ++ break; ++ } ++ case V4L2_CID_HFLIP: ++ { ++ vout->ctrl_hflip = ctrl->value; ++ setup_task_rotation(vout); ++ break; ++ } ++ case V4L2_CID_MXC_MOTION: ++ { ++ vout->task.input.deinterlace.motion = ctrl->value; ++ break; ++ } ++ default: ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ if (vout->fmt_init) { ++ memcpy(&vout->task.input.crop, &vout->in_rect, ++ sizeof(vout->in_rect)); ++ ret = mxc_vout_try_task(vout); ++ if (ret < 0) { ++ v4l2_err(vout->vfd->v4l2_dev, ++ "vout check task failed\n"); ++ memcpy(vout, pre_vout, sizeof(*vout)); ++ goto done; ++ } ++ ++ if (mxc_vout_need_fb_reconfig(vout, pre_vout)) { ++ ret = config_disp_output(vout); ++ if (ret < 0) ++ v4l2_err(vout->vfd->v4l2_dev, ++ "Config display output failed\n"); ++ } ++ } ++ ++done: ++ vfree(pre_vout); ++ mutex_unlock(&vout->task_lock); ++ ++ return ret; ++} ++ ++static int mxc_vidioc_reqbufs(struct file *file, void *fh, ++ struct v4l2_requestbuffers *req) ++{ ++ int ret = 0; ++ struct mxc_vout_output *vout = fh; ++ struct videobuf_queue *q = &vout->vbq; ++ ++ if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ++ return -EINVAL; ++ ++ /* should not be here after streaming, videobuf_reqbufs will control */ ++ mutex_lock(&vout->task_lock); ++ ++ ret = videobuf_reqbufs(q, req); ++ ++ mutex_unlock(&vout->task_lock); ++ return ret; ++} ++ ++static int mxc_vidioc_querybuf(struct file *file, void *fh, ++ struct v4l2_buffer *b) ++{ ++ int ret; ++ struct mxc_vout_output *vout = fh; ++ ++ ret = videobuf_querybuf(&vout->vbq, b); ++ if (!ret) { ++ /* return physical address */ ++ struct videobuf_buffer *vb = vout->vbq.bufs[b->index]; ++ if (b->flags & V4L2_BUF_FLAG_MAPPED) ++ b->m.offset = videobuf_to_dma_contig(vb); ++ } ++ ++ return ret; ++} ++ ++static int mxc_vidioc_qbuf(struct file *file, void *fh, ++ struct v4l2_buffer *buffer) ++{ ++ struct mxc_vout_output *vout = fh; ++ ++ return videobuf_qbuf(&vout->vbq, buffer); ++} ++ ++static int mxc_vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) ++{ ++ struct mxc_vout_output *vout = fh; ++ ++ if (!vout->vbq.streaming) ++ return -EINVAL; ++ ++ if (file->f_flags & O_NONBLOCK) ++ return videobuf_dqbuf(&vout->vbq, (struct v4l2_buffer *)b, 1); ++ else ++ return videobuf_dqbuf(&vout->vbq, (struct v4l2_buffer *)b, 0); ++} ++ ++static int set_window_position(struct mxc_vout_output *vout, ++ struct mxcfb_pos *pos) ++{ ++ struct fb_info *fbi = vout->fbi; ++ mm_segment_t old_fs; ++ int ret = 0; ++ ++ if (vout->disp_support_windows) { ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ret = fbi->fbops->fb_ioctl(fbi, MXCFB_SET_OVERLAY_POS, ++ (unsigned long)pos); ++ set_fs(old_fs); ++ } ++ ++ return ret; ++} ++ ++static int config_disp_output(struct mxc_vout_output *vout) ++{ ++ struct dma_mem *buf = NULL; ++ struct fb_info *fbi = vout->fbi; ++ struct fb_var_screeninfo var; ++ struct mxcfb_pos pos; ++ int i, fb_num, ret; ++ u32 fb_base; ++ u32 size; ++ u32 display_buf_size; ++ u32 *pixel = NULL; ++ u32 color; ++ int j; ++ ++ memcpy(&var, &fbi->var, sizeof(var)); ++ fb_base = fbi->fix.smem_start; ++ ++ var.xres = vout->task.output.width; ++ var.yres = vout->task.output.height; ++ if (vout->linear_bypass_pp || vout->tiled_bypass_pp) { ++ fb_num = 1; ++ /* input crop */ ++ if (vout->task.input.width > vout->task.output.width) ++ var.xres_virtual = vout->task.input.width; ++ else ++ var.xres_virtual = var.xres; ++ if (vout->task.input.height > vout->task.output.height) ++ var.yres_virtual = vout->task.input.height; ++ else ++ var.yres_virtual = var.yres; ++ var.rotate = vout->task.output.rotate; ++ var.vmode |= FB_VMODE_YWRAP; ++ } else { ++ fb_num = FB_BUFS; ++ var.xres_virtual = var.xres; ++ var.yres_virtual = fb_num * var.yres; ++ var.vmode &= ~FB_VMODE_YWRAP; ++ } ++ var.bits_per_pixel = fmt_to_bpp(vout->task.output.format); ++ var.nonstd = vout->task.output.format; ++ ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "set display fb to %d %d\n", ++ var.xres, var.yres); ++ ++ /* ++ * To setup the overlay fb from scratch without ++ * the last time overlay fb position or resolution's ++ * impact, we take the following steps: ++ * - blank fb ++ * - set fb position to the starting point ++ * - reconfigure fb ++ * - set fb position to a specific point ++ * - unblank fb ++ * This procedure applies to non-overlay fbs as well. ++ */ ++ console_lock(); ++ fbi->flags |= FBINFO_MISC_USEREVENT; ++ fb_blank(fbi, FB_BLANK_POWERDOWN); ++ fbi->flags &= ~FBINFO_MISC_USEREVENT; ++ console_unlock(); ++ ++ pos.x = 0; ++ pos.y = 0; ++ ret = set_window_position(vout, &pos); ++ if (ret < 0) { ++ v4l2_err(vout->vfd->v4l2_dev, "failed to set fb position " ++ "to starting point\n"); ++ return ret; ++ } ++ ++ /* Init display channel through fb API */ ++ var.yoffset = 0; ++ var.activate |= FB_ACTIVATE_FORCE; ++ console_lock(); ++ fbi->flags |= FBINFO_MISC_USEREVENT; ++ ret = fb_set_var(fbi, &var); ++ fbi->flags &= ~FBINFO_MISC_USEREVENT; ++ console_unlock(); ++ if (ret < 0) { ++ v4l2_err(vout->vfd->v4l2_dev, ++ "ERR:%s fb_set_var ret:%d\n", __func__, ret); ++ return ret; ++ } ++ ++ ret = set_window_position(vout, &vout->win_pos); ++ if (ret < 0) { ++ v4l2_err(vout->vfd->v4l2_dev, "failed to set fb position\n"); ++ return ret; ++ } ++ ++ if (vout->linear_bypass_pp || vout->tiled_bypass_pp) ++ display_buf_size = fbi->fix.line_length * fbi->var.yres_virtual; ++ else ++ display_buf_size = fbi->fix.line_length * fbi->var.yres; ++ for (i = 0; i < fb_num; i++) ++ vout->disp_bufs[i] = fbi->fix.smem_start + i * display_buf_size; ++ if (vout->tiled_bypass_pp) { ++ size = PAGE_ALIGN(vout->task.input.crop.w * ++ vout->task.input.crop.h * ++ fmt_to_bpp(vout->task.output.format)/8); ++ if (size > vout->vdoa_output[0].size) { ++ for (i = 0; i < VDOA_FB_BUFS; i++) { ++ buf = &vout->vdoa_output[i]; ++ if (buf->vaddr) ++ free_dma_buf(vout, buf); ++ buf->size = size; ++ ret = alloc_dma_buf(vout, buf); ++ if (ret < 0) ++ goto err; ++ } ++ } ++ for (i = fb_num; i < (fb_num + VDOA_FB_BUFS); i++) ++ vout->disp_bufs[i] = ++ vout->vdoa_output[i - fb_num].paddr; ++ } ++ vout->fb_smem_len = fbi->fix.smem_len; ++ vout->fb_smem_start = fbi->fix.smem_start; ++ if (fb_base != fbi->fix.smem_start) { ++ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, ++ "realloc fb mem size:0x%x@0x%lx,old paddr @0x%x\n", ++ fbi->fix.smem_len, fbi->fix.smem_start, fb_base); ++ } ++ ++ /* fill black when video config changed */ ++ color = colorspaceofpixel(vout->task.output.format) == YUV_CS ? ++ UYVY_BLACK : RGB_BLACK; ++ if (IS_PLANAR_PIXEL_FORMAT(vout->task.output.format)) { ++ size = display_buf_size * 8 / ++ fmt_to_bpp(vout->task.output.format); ++ memset(fbi->screen_base, Y_BLACK, size); ++ memset(fbi->screen_base + size, UV_BLACK, ++ display_buf_size - size); ++ } else { ++ pixel = (u32 *)fbi->screen_base; ++ for (i = 0; i < (display_buf_size >> 2); i++) ++ *pixel++ = color; ++ } ++ console_lock(); ++ fbi->flags |= FBINFO_MISC_USEREVENT; ++ ret = fb_blank(fbi, FB_BLANK_UNBLANK); ++ fbi->flags &= ~FBINFO_MISC_USEREVENT; ++ console_unlock(); ++ vout->release = false; ++ ++ return ret; ++err: ++ for (j = i - 1; j >= 0; j--) { ++ buf = &vout->vdoa_output[j]; ++ if (buf->vaddr) ++ free_dma_buf(vout, buf); ++ } ++ return ret; ++} ++ ++static inline void wait_for_vsync(struct mxc_vout_output *vout) ++{ ++ struct fb_info *fbi = vout->fbi; ++ mm_segment_t old_fs; ++ ++ if (fbi->fbops->fb_ioctl) { ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC, ++ (unsigned long)NULL); ++ set_fs(old_fs); ++ } ++ ++ return; ++} ++ ++static void release_disp_output(struct mxc_vout_output *vout) ++{ ++ struct fb_info *fbi = vout->fbi; ++ struct mxcfb_pos pos; ++ ++ if (vout->release) ++ return; ++ console_lock(); ++ fbi->flags |= FBINFO_MISC_USEREVENT; ++ fb_blank(fbi, FB_BLANK_POWERDOWN); ++ fbi->flags &= ~FBINFO_MISC_USEREVENT; ++ console_unlock(); ++ ++ /* restore pos to 0,0 avoid fb pan display hang? */ ++ pos.x = 0; ++ pos.y = 0; ++ set_window_position(vout, &pos); ++ ++ if (get_ipu_channel(fbi) == MEM_BG_SYNC) { ++ console_lock(); ++ fbi->fix.smem_start = vout->disp_bufs[0]; ++ fbi->flags |= FBINFO_MISC_USEREVENT; ++ fb_blank(fbi, FB_BLANK_UNBLANK); ++ fbi->flags &= ~FBINFO_MISC_USEREVENT; ++ console_unlock(); ++ ++ } ++ ++ vout->release = true; ++} ++ ++static int mxc_vidioc_streamon(struct file *file, void *fh, ++ enum v4l2_buf_type i) ++{ ++ struct mxc_vout_output *vout = fh; ++ struct videobuf_queue *q = &vout->vbq; ++ int ret; ++ ++ if (q->streaming) { ++ v4l2_err(vout->vfd->v4l2_dev, ++ "video output already run\n"); ++ ret = -EBUSY; ++ goto done; ++ } ++ ++ if (deinterlace_3_field(vout) && list_is_singular(&q->stream)) { ++ v4l2_err(vout->vfd->v4l2_dev, ++ "deinterlacing: need queue 2 frame before streamon\n"); ++ ret = -EINVAL; ++ goto done; ++ } ++ ++ ret = config_disp_output(vout); ++ if (ret < 0) { ++ v4l2_err(vout->vfd->v4l2_dev, ++ "Config display output failed\n"); ++ goto done; ++ } ++ ++ hrtimer_init(&vout->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); ++ vout->timer.function = mxc_vout_timer_handler; ++ vout->timer_stop = true; ++ ++ vout->start_ktime = hrtimer_cb_get_time(&vout->timer); ++ ++ vout->pre1_vb = NULL; ++ vout->pre2_vb = NULL; ++ ++ ret = videobuf_streamon(q); ++done: ++ return ret; ++} ++ ++static int mxc_vidioc_streamoff(struct file *file, void *fh, ++ enum v4l2_buf_type i) ++{ ++ struct mxc_vout_output *vout = fh; ++ struct videobuf_queue *q = &vout->vbq; ++ int ret = 0; ++ ++ if (q->streaming) { ++ flush_workqueue(vout->v4l_wq); ++ ++ hrtimer_cancel(&vout->timer); ++ ++ /* ++ * Wait for 2 vsyncs to make sure ++ * frames are drained on triple ++ * buffer. ++ */ ++ wait_for_vsync(vout); ++ wait_for_vsync(vout); ++ ++ release_disp_output(vout); ++ ++ ret = videobuf_streamoff(&vout->vbq); ++ } ++ INIT_LIST_HEAD(&vout->queue_list); ++ INIT_LIST_HEAD(&vout->active_list); ++ ++ return ret; ++} ++ ++static const struct v4l2_ioctl_ops mxc_vout_ioctl_ops = { ++ .vidioc_querycap = mxc_vidioc_querycap, ++ .vidioc_enum_fmt_vid_out = mxc_vidioc_enum_fmt_vid_out, ++ .vidioc_g_fmt_vid_out = mxc_vidioc_g_fmt_vid_out, ++ .vidioc_s_fmt_vid_out = mxc_vidioc_s_fmt_vid_out, ++ .vidioc_cropcap = mxc_vidioc_cropcap, ++ .vidioc_g_crop = mxc_vidioc_g_crop, ++ .vidioc_s_crop = mxc_vidioc_s_crop, ++ .vidioc_queryctrl = mxc_vidioc_queryctrl, ++ .vidioc_g_ctrl = mxc_vidioc_g_ctrl, ++ .vidioc_s_ctrl = mxc_vidioc_s_ctrl, ++ .vidioc_reqbufs = mxc_vidioc_reqbufs, ++ .vidioc_querybuf = mxc_vidioc_querybuf, ++ .vidioc_qbuf = mxc_vidioc_qbuf, ++ .vidioc_dqbuf = mxc_vidioc_dqbuf, ++ .vidioc_streamon = mxc_vidioc_streamon, ++ .vidioc_streamoff = mxc_vidioc_streamoff, ++}; ++ ++static const struct v4l2_file_operations mxc_vout_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = video_ioctl2, ++ .mmap = mxc_vout_mmap, ++ .open = mxc_vout_open, ++ .release = mxc_vout_release, ++}; ++ ++static struct video_device mxc_vout_template = { ++ .name = "MXC Video Output", ++ .fops = &mxc_vout_fops, ++ .ioctl_ops = &mxc_vout_ioctl_ops, ++ .release = video_device_release, ++}; ++ ++static struct videobuf_queue_ops mxc_vout_vbq_ops = { ++ .buf_setup = mxc_vout_buffer_setup, ++ .buf_prepare = mxc_vout_buffer_prepare, ++ .buf_release = mxc_vout_buffer_release, ++ .buf_queue = mxc_vout_buffer_queue, ++}; ++ ++static void mxc_vout_free_output(struct mxc_vout_dev *dev) ++{ ++ int i; ++ int j; ++ struct mxc_vout_output *vout; ++ struct video_device *vfd; ++ ++ for (i = 0; i < dev->out_num; i++) { ++ vout = dev->out[i]; ++ vfd = vout->vfd; ++ if (vout->vdoa_work.vaddr) ++ free_dma_buf(vout, &vout->vdoa_work); ++ for (j = 0; j < VDOA_FB_BUFS; j++) { ++ if (vout->vdoa_output[j].vaddr) ++ free_dma_buf(vout, &vout->vdoa_output[j]); ++ } ++ if (vfd) { ++ if (!video_is_registered(vfd)) ++ video_device_release(vfd); ++ else ++ video_unregister_device(vfd); ++ } ++ kfree(vout); ++ } ++} ++ ++static int mxc_vout_setup_output(struct mxc_vout_dev *dev) ++{ ++ struct videobuf_queue *q; ++ struct fb_info *fbi; ++ struct mxc_vout_output *vout; ++ int i, ret = 0; ++ ++ update_display_setting(); ++ ++ /* all output/overlay based on fb */ ++ for (i = 0; i < num_registered_fb; i++) { ++ fbi = registered_fb[i]; ++ ++ vout = kzalloc(sizeof(struct mxc_vout_output), GFP_KERNEL); ++ if (!vout) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ dev->out[dev->out_num] = vout; ++ dev->out_num++; ++ ++ vout->fbi = fbi; ++ vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ++ vout->vfd = video_device_alloc(); ++ if (!vout->vfd) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ *vout->vfd = mxc_vout_template; ++ vout->vfd->debug = debug; ++ vout->vfd->v4l2_dev = &dev->v4l2_dev; ++ vout->vfd->lock = &vout->mutex; ++ vout->vfd->vfl_dir = VFL_DIR_TX; ++ ++ mutex_init(&vout->mutex); ++ mutex_init(&vout->task_lock); ++ ++ strlcpy(vout->vfd->name, fbi->fix.id, sizeof(vout->vfd->name)); ++ ++ video_set_drvdata(vout->vfd, vout); ++ ++ if (video_register_device(vout->vfd, ++ VFL_TYPE_GRABBER, video_nr + i) < 0) { ++ ret = -ENODEV; ++ break; ++ } ++ ++ q = &vout->vbq; ++ q->dev = dev->dev; ++ spin_lock_init(&vout->vbq_lock); ++ videobuf_queue_dma_contig_init(q, &mxc_vout_vbq_ops, q->dev, ++ &vout->vbq_lock, vout->type, V4L2_FIELD_NONE, ++ sizeof(struct videobuf_buffer), vout, NULL); ++ ++ v4l2_info(vout->vfd->v4l2_dev, "V4L2 device registered as %s\n", ++ video_device_node_name(vout->vfd)); ++ ++ } ++ ++ return ret; ++} ++ ++static int mxc_vout_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct mxc_vout_dev *dev; ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ ++ dev->dev = &pdev->dev; ++ dev->dev->dma_mask = kmalloc(sizeof(*dev->dev->dma_mask), GFP_KERNEL); ++ *dev->dev->dma_mask = DMA_BIT_MASK(32); ++ dev->dev->coherent_dma_mask = DMA_BIT_MASK(32); ++ ++ ret = v4l2_device_register(dev->dev, &dev->v4l2_dev); ++ if (ret) { ++ dev_err(dev->dev, "v4l2_device_register failed\n"); ++ goto free_dev; ++ } ++ ++ ret = mxc_vout_setup_output(dev); ++ if (ret < 0) ++ goto rel_vdev; ++ ++ return 0; ++ ++rel_vdev: ++ mxc_vout_free_output(dev); ++ v4l2_device_unregister(&dev->v4l2_dev); ++free_dev: ++ kfree(dev); ++ return ret; ++} ++ ++static int mxc_vout_remove(struct platform_device *pdev) ++{ ++ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); ++ struct mxc_vout_dev *dev = container_of(v4l2_dev, struct ++ mxc_vout_dev, v4l2_dev); ++ ++ mxc_vout_free_output(dev); ++ v4l2_device_unregister(v4l2_dev); ++ kfree(dev); ++ return 0; ++} ++ ++static const struct of_device_id mxc_v4l2_dt_ids[] = { ++ { .compatible = "fsl,mxc_v4l2_output", }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver mxc_vout_driver = { ++ .driver = { ++ .name = "mxc_v4l2_output", ++ .of_match_table = mxc_v4l2_dt_ids, ++ }, ++ .probe = mxc_vout_probe, ++ .remove = mxc_vout_remove, ++}; ++ ++static int __init mxc_vout_init(void) ++{ ++ if (platform_driver_register(&mxc_vout_driver) != 0) { ++ printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static void mxc_vout_cleanup(void) ++{ ++ platform_driver_unregister(&mxc_vout_driver); ++} ++ ++module_init(mxc_vout_init); ++module_exit(mxc_vout_cleanup); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("V4L2-driver for MXC video output"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.10.30/drivers/media/v4l2-core/videobuf-dma-contig.c linux-3.10.30-cubox-i/drivers/media/v4l2-core/videobuf-dma-contig.c +--- linux-3.10.30/drivers/media/v4l2-core/videobuf-dma-contig.c 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/media/v4l2-core/videobuf-dma-contig.c 2014-03-08 20:33:51.000000000 +0100 +@@ -307,7 +307,7 @@ + size = vma->vm_end - vma->vm_start; + size = (size < mem->size) ? size : mem->size; + +- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + retval = remap_pfn_range(vma, vma->vm_start, + mem->dma_handle >> PAGE_SHIFT, + size, vma->vm_page_prot); +diff -Nur linux-3.10.30/drivers/mfd/Kconfig linux-3.10.30-cubox-i/drivers/mfd/Kconfig +--- linux-3.10.30/drivers/mfd/Kconfig 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/mfd/Kconfig 2014-03-08 20:33:51.000000000 +0100 +@@ -139,6 +139,13 @@ + This driver can be built as a module. If built as a module it will be + called "da9055" + ++config MFD_MXC_HDMI ++ tristate "Freescale HDMI Core" ++ select MFD_CORE ++ help ++ This is the core driver for the Freescale i.MX6 on-chip HDMI. ++ This MFD driver connects with the video and audio drivers for HDMI. ++ + config MFD_MC13783 + tristate + +@@ -277,6 +284,13 @@ + select individual components like voltage regulators, RTC and + battery-charger under the corresponding menus. + ++config MFD_MAX17135 ++ tristate "Maxim MAX17135 EPD PMIC core" ++ depends on I2C ++ help ++ This is the MAX17135 PMIC support. It includes ++ core support for communication with the MAX17135 chip. ++ + config MFD_MAX77686 + bool "Maxim Semiconductor MAX77686 PMIC Support" + depends on I2C=y && GENERIC_HARDIRQS +@@ -1144,7 +1158,16 @@ + endmenu + + config VEXPRESS_CONFIG +- bool ++ bool "ARM Versatile Express platform infrastructure" ++ depends on ARM || ARM64 + help + Platform configuration infrastructure for the ARM Ltd. + Versatile Express. ++ ++config VEXPRESS_SPC ++ bool "Versatile Express SPC driver support" ++ depends on ARM ++ depends on VEXPRESS_CONFIG ++ help ++ Serial Power Controller driver for ARM Ltd. test chips. ++ +diff -Nur linux-3.10.30/drivers/mfd/Makefile linux-3.10.30-cubox-i/drivers/mfd/Makefile +--- linux-3.10.30/drivers/mfd/Makefile 2014-02-13 22:48:15.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/mfd/Makefile 2014-03-08 20:33:51.000000000 +0100 +@@ -104,6 +104,7 @@ + da9055-objs := da9055-core.o da9055-i2c.o + obj-$(CONFIG_MFD_DA9055) += da9055.o + ++obj-$(CONFIG_MFD_MAX17135) += max17135-core.o + obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o + obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o + obj-$(CONFIG_MFD_MAX8907) += max8907.o +@@ -153,5 +154,7 @@ + obj-$(CONFIG_MFD_SYSCON) += syscon.o + obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o + obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o vexpress-sysreg.o ++obj-$(CONFIG_VEXPRESS_SPC) += vexpress-spc.o + obj-$(CONFIG_MFD_RETU) += retu-mfd.o + obj-$(CONFIG_MFD_AS3711) += as3711.o ++obj-$(CONFIG_MFD_MXC_HDMI) += mxc-hdmi-core.o +diff -Nur linux-3.10.30/drivers/mfd/max17135-core.c linux-3.10.30-cubox-i/drivers/mfd/max17135-core.c +--- linux-3.10.30/drivers/mfd/max17135-core.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/mfd/max17135-core.c 2014-03-08 20:33:52.000000000 +0100 +@@ -0,0 +1,295 @@ ++/* ++ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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 ++ * ++ */ ++ ++/*! ++ * @file pmic/core/max17135.c ++ * @brief This file contains MAX17135 specific PMIC code. This implementaion ++ * may differ for each PMIC chip. ++ * ++ * @ingroup PMIC_CORE ++ */ ++ ++/* ++ * Includes ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int max17135_detect(struct i2c_client *client, ++ struct i2c_board_info *info); ++struct i2c_client *max17135_client; ++static struct regulator *gpio_regulator; ++ ++static struct mfd_cell max17135_devs[] = { ++ { .name = "max17135-pmic", }, ++ { .name = "max17135-sns", }, ++}; ++ ++static const unsigned short normal_i2c[] = {0x48, I2C_CLIENT_END}; ++ ++int max17135_reg_read(int reg_num, unsigned int *reg_val) ++{ ++ int result; ++ ++ if (max17135_client == NULL) ++ return PMIC_ERROR; ++ ++ if ((reg_num == REG_MAX17135_EXT_TEMP) || ++ (reg_num == REG_MAX17135_INT_TEMP)) { ++ result = i2c_smbus_read_word_data(max17135_client, reg_num); ++ if (result < 0) { ++ dev_err(&max17135_client->dev, ++ "Unable to read MAX17135 register via I2C\n"); ++ return PMIC_ERROR; ++ } ++ /* Swap bytes for dword read */ ++ result = (result >> 8) | ((result & 0xFF) << 8); ++ } else { ++ result = i2c_smbus_read_byte_data(max17135_client, reg_num); ++ if (result < 0) { ++ dev_err(&max17135_client->dev, ++ "Unable to read MAX17135 register via I2C\n"); ++ return PMIC_ERROR; ++ } ++ } ++ ++ *reg_val = result; ++ return PMIC_SUCCESS; ++} ++ ++int max17135_reg_write(int reg_num, const unsigned int reg_val) ++{ ++ int result; ++ ++ if (max17135_client == NULL) ++ return PMIC_ERROR; ++ ++ result = i2c_smbus_write_byte_data(max17135_client, reg_num, reg_val); ++ if (result < 0) { ++ dev_err(&max17135_client->dev, ++ "Unable to write MAX17135 register via I2C\n"); ++ return PMIC_ERROR; ++ } ++ ++ return PMIC_SUCCESS; ++} ++ ++#ifdef CONFIG_OF ++static struct max17135_platform_data *max17135_i2c_parse_dt_pdata( ++ struct device *dev) ++{ ++ struct max17135_platform_data *pdata; ++ ++ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); ++ if (!pdata) { ++ dev_err(dev, "could not allocate memory for pdata\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ return pdata; ++} ++#else ++static struct max17135_platform_data *max17135_i2c_parse_dt_pdata( ++ struct device *dev) ++{ ++ return NULL; ++} ++#endif /* !CONFIG_OF */ ++ ++static int max17135_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct max17135 *max17135; ++ struct max17135_platform_data *pdata = client->dev.platform_data; ++ struct device_node *np = client->dev.of_node; ++ int ret = 0; ++ ++ if (!np) ++ return -ENODEV; ++ ++ gpio_regulator = devm_regulator_get(&client->dev, "SENSOR"); ++ if (!IS_ERR(gpio_regulator)) { ++ ret = regulator_enable(gpio_regulator); ++ if (ret) { ++ dev_err(&client->dev, "gpio set voltage error\n"); ++ return ret; ++ } ++ } ++ ++ /* Create the PMIC data structure */ ++ max17135 = kzalloc(sizeof(struct max17135), GFP_KERNEL); ++ if (max17135 == NULL) { ++ kfree(client); ++ return -ENOMEM; ++ } ++ ++ /* Initialize the PMIC data structure */ ++ i2c_set_clientdata(client, max17135); ++ max17135->dev = &client->dev; ++ max17135->i2c_client = client; ++ ++ max17135_client = client; ++ ret = max17135_detect(client, NULL); ++ if (ret) ++ goto err1; ++ ++ mfd_add_devices(max17135->dev, -1, max17135_devs, ++ ARRAY_SIZE(max17135_devs), ++ NULL, 0, NULL); ++ ++ if (max17135->dev->of_node) { ++ pdata = max17135_i2c_parse_dt_pdata(max17135->dev); ++ if (IS_ERR(pdata)) { ++ ret = PTR_ERR(pdata); ++ goto err2; ++ } ++ ++ } ++ max17135->pdata = pdata; ++ ++ dev_info(&client->dev, "PMIC MAX17135 for eInk display\n"); ++ ++ return ret; ++err2: ++ mfd_remove_devices(max17135->dev); ++err1: ++ kfree(max17135); ++ ++ return ret; ++} ++ ++ ++static int max17135_remove(struct i2c_client *i2c) ++{ ++ struct max17135 *max17135 = i2c_get_clientdata(i2c); ++ ++ mfd_remove_devices(max17135->dev); ++ return 0; ++} ++ ++static int max17135_suspend(struct i2c_client *client, pm_message_t state) ++{ ++ return 0; ++} ++ ++static int max17135_resume(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++/* Return 0 if detection is successful, -ENODEV otherwise */ ++static int max17135_detect(struct i2c_client *client, ++ struct i2c_board_info *info) ++{ ++ struct i2c_adapter *adapter = client->adapter; ++ u8 chip_rev, chip_id; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) ++ return -ENODEV; ++ ++ /* detection */ ++ if (i2c_smbus_read_byte_data(client, ++ REG_MAX17135_PRODUCT_REV) != 0) { ++ dev_err(&adapter->dev, ++ "Max17135 PMIC not found!\n"); ++ return -ENODEV; ++ } ++ ++ /* identification */ ++ chip_rev = i2c_smbus_read_byte_data(client, ++ REG_MAX17135_PRODUCT_REV); ++ chip_id = i2c_smbus_read_byte_data(client, ++ REG_MAX17135_PRODUCT_ID); ++ ++ if (chip_rev != 0x00 || chip_id != 0x4D) { /* identification failed */ ++ dev_info(&adapter->dev, ++ "Unsupported chip (man_id=0x%02X, " ++ "chip_id=0x%02X).\n", chip_rev, chip_id); ++ return -ENODEV; ++ } ++ ++ if (info) ++ strlcpy(info->type, "max17135_sensor", I2C_NAME_SIZE); ++ ++ return 0; ++} ++ ++static const struct i2c_device_id max17135_id[] = { ++ { "max17135", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max17135_id); ++ ++static const struct of_device_id max17135_dt_ids[] = { ++ { ++ .compatible = "maxim,max17135", ++ .data = (void *) &max17135_id[0], ++ }, { ++ /* sentinel */ ++ } ++}; ++MODULE_DEVICE_TABLE(of, max17135_dt_ids); ++ ++ ++static struct i2c_driver max17135_driver = { ++ .driver = { ++ .name = "max17135", ++ .owner = THIS_MODULE, ++ .of_match_table = max17135_dt_ids, ++ }, ++ .probe = max17135_probe, ++ .remove = max17135_remove, ++ .suspend = max17135_suspend, ++ .resume = max17135_resume, ++ .id_table = max17135_id, ++ .detect = max17135_detect, ++ .address_list = &normal_i2c[0], ++}; ++ ++static int __init max17135_init(void) ++{ ++ return i2c_add_driver(&max17135_driver); ++} ++ ++static void __exit max17135_exit(void) ++{ ++ i2c_del_driver(&max17135_driver); ++} ++ ++/* ++ * Module entry points ++ */ ++subsys_initcall(max17135_init); ++module_exit(max17135_exit); +diff -Nur linux-3.10.30/drivers/mfd/mxc-hdmi-core.c linux-3.10.30-cubox-i/drivers/mfd/mxc-hdmi-core.c +--- linux-3.10.30/drivers/mfd/mxc-hdmi-core.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.10.30-cubox-i/drivers/mfd/mxc-hdmi-core.c 2014-03-08 20:33:52.000000000 +0100 +@@ -0,0 +1,775 @@ ++/* ++ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include