From 5d8760a540ae55c5f01ecc76fa178fe2c8a87b35 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Tue, 11 Mar 2014 19:13:26 +0100 Subject: CONFIG_SLOB makes raspberry hanging without starting userland --- target/linux/kernel.config | 1 - 1 file changed, 1 deletion(-) (limited to 'target') diff --git a/target/linux/kernel.config b/target/linux/kernel.config index a28c2088b..de1324aa1 100644 --- a/target/linux/kernel.config +++ b/target/linux/kernel.config @@ -7,7 +7,6 @@ CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE_SYSCTL=y -CONFIG_SLOB=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y -- cgit v1.2.3 From d6d4d15f6553e758ef6adca22d48210524f39a83 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Tue, 11 Mar 2014 19:13:49 +0100 Subject: remove PREEMPT here, make it choosable via menu later --- target/arm/kernel/raspberry-pi | 3 --- 1 file changed, 3 deletions(-) (limited to 'target') diff --git a/target/arm/kernel/raspberry-pi b/target/arm/kernel/raspberry-pi index 2a1450ca3..486ec929b 100644 --- a/target/arm/kernel/raspberry-pi +++ b/target/arm/kernel/raspberry-pi @@ -2,9 +2,6 @@ CONFIG_ARM=y CONFIG_FIQ=y CONFIG_ARM_PATCH_PHYS_VIRT=y CONFIG_KUSER_HELPERS=y -CONFIG_PREEMPT=y -CONFIG_TREE_PREEMPT_RCU=y -CONFIG_PREEMPT_RCU=y CONFIG_ARCH_BCM2708=y CONFIG_MACH_BCM2708=y CONFIG_BCM2708_GPIO=y -- cgit v1.2.3 From 33e71e01f2f98a1dfac93d75fa7d89e047857aef Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Wed, 12 Mar 2014 15:03:05 +0100 Subject: disable avahi again, requested by joern --- target/packages/pkg-available/mpdbox | 3 --- 1 file changed, 3 deletions(-) (limited to 'target') diff --git a/target/packages/pkg-available/mpdbox b/target/packages/pkg-available/mpdbox index 6e0c29341..b1edc40e1 100644 --- a/target/packages/pkg-available/mpdbox +++ b/target/packages/pkg-available/mpdbox @@ -22,9 +22,6 @@ config ADK_PKG_MPDBOX select ADK_PACKAGE_MPD_WITH_CURL select ADK_PACKAGE_MPD_WITH_SAMPLERATE select ADK_PACKAGE_MPD_WITH_HTTPD - select ADK_PACKAGE_MPD_WITH_AVAHI - select ADK_PACKAGE_AVAHI_DAEMON - select ADK_PACKAGE_AVAHI_DNSCONFD select ADK_PACKAGE_CPUFREQUTILS select ADK_PACKAGE_FILE select ADK_PACKAGE_HTOP -- cgit v1.2.3 From 6f9f6b6ae9fd45b92dbafc21bae053b112573b17 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Thu, 13 Mar 2014 15:18:21 +0100 Subject: copy kernel --- target/microblaze/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'target') diff --git a/target/microblaze/Makefile b/target/microblaze/Makefile index de528f91e..74f8d3dd0 100644 --- a/target/microblaze/Makefile +++ b/target/microblaze/Makefile @@ -57,5 +57,6 @@ endif endif ifeq ($(ADK_TARGET_FS),archive) imageinstall: $(FW_DIR)/$(ROOTFSTARBALL) + @cp $(KERNEL) $(FW_DIR)/$(TARGET_KERNEL) @echo "The RootFS tarball is: $(FW_DIR)/$(ROOTFSTARBALL)" endif -- cgit v1.2.3 From c1e53e7fb3f2a605d8316606a6a793648458e862 Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Thu, 13 Mar 2014 15:51:40 +0100 Subject: update to 3.10.33 - add support for system specific patches, cubox-i and raspberry-pi patches are in conflict - fix hifiberry driver support --- .../cubox-i/patches/3.10.33/solidrun-cubox-i.patch | 584365 ++++++++++++++++++ .../patches/3.10.33/raspberry-pi.patch | 101472 +++ target/linux/config/Config.in.audio | 4 + target/linux/config/Config.in.misc | 14 + .../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 - .../linux/patches/3.10.33/bsd-compatibility.patch | 2538 + target/linux/patches/3.10.33/startup.patch | 12 + 9 files changed, 688405 insertions(+), 586915 deletions(-) create mode 100644 target/arm/cubox-i/patches/3.10.33/solidrun-cubox-i.patch create mode 100644 target/arm/raspberry-pi/patches/3.10.33/raspberry-pi.patch delete mode 100644 target/linux/patches/3.10.30/bsd-compatibility.patch delete mode 100644 target/linux/patches/3.10.30/solidrun-cubox-i.patch delete mode 100644 target/linux/patches/3.10.30/startup.patch create mode 100644 target/linux/patches/3.10.33/bsd-compatibility.patch create mode 100644 target/linux/patches/3.10.33/startup.patch (limited to 'target') diff --git a/target/arm/cubox-i/patches/3.10.33/solidrun-cubox-i.patch b/target/arm/cubox-i/patches/3.10.33/solidrun-cubox-i.patch new file mode 100644 index 000000000..beaa71b4e --- /dev/null +++ b/target/arm/cubox-i/patches/3.10.33/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

++ * ++ * DWC_DEBUGPL( DBG_ANY, "%s(%p)\n", __func__, _reg_base_addr); ++ * ++ *
++ * results in:
++ * ++ * usb-DWC_otg: dwc_otg_cil_init(ca867000) ++ * ++ */ ++#ifdef DEBUG ++ ++# define DWC_DEBUGPL(lvl, x...) do{ if ((lvl)&g_dbg_lvl)__DWC_DEBUG(USB_DWC x ); }while(0) ++# define DWC_DEBUGP(x...) DWC_DEBUGPL(DBG_ANY, x ) ++ ++# define CHK_DEBUG_LEVEL(level) ((level) & g_dbg_lvl) ++ ++#else ++ ++# define DWC_DEBUGPL(lvl, x...) do{}while(0) ++# define DWC_DEBUGP(x...) ++ ++# define CHK_DEBUG_LEVEL(level) (0) ++ ++#endif /*DEBUG*/ ++#endif +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_driver.c linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_driver.c +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_driver.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_driver.c 2014-03-13 12:46:39.516097989 +0100 +@@ -0,0 +1,1742 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.c $ ++ * $Revision: #92 $ ++ * $Date: 2012/08/10 $ ++ * $Change: 2047372 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++/** @file ++ * The dwc_otg_driver module provides the initialization and cleanup entry ++ * points for the DWC_otg driver. This module will be dynamically installed ++ * after Linux is booted using the insmod command. When the module is ++ * installed, the dwc_otg_driver_init function is called. When the module is ++ * removed (using rmmod), the dwc_otg_driver_cleanup function is called. ++ * ++ * This module also defines a data structure for the dwc_otg_driver, which is ++ * used in conjunction with the standard ARM lm_device structure. These ++ * structures allow the OTG driver to comply with the standard Linux driver ++ * model in which devices and drivers are registered with a bus driver. This ++ * has the benefit that Linux can expose attributes of the driver and device ++ * in its special sysfs file system. Users can then read or write files in ++ * this file system to perform diagnostics on the driver components or the ++ * device. ++ */ ++ ++#include "dwc_otg_os_dep.h" ++#include "dwc_os.h" ++#include "dwc_otg_dbg.h" ++#include "dwc_otg_driver.h" ++#include "dwc_otg_attr.h" ++#include "dwc_otg_core_if.h" ++#include "dwc_otg_pcd_if.h" ++#include "dwc_otg_hcd_if.h" ++ ++#define DWC_DRIVER_VERSION "3.00a 10-AUG-2012" ++#define DWC_DRIVER_DESC "HS OTG USB Controller driver" ++ ++bool microframe_schedule=true; ++ ++static const char dwc_driver_name[] = "dwc_otg"; ++ ++extern void* dummy_send; ++ ++extern int pcd_init( ++#ifdef LM_INTERFACE ++ struct lm_device *_dev ++#elif defined(PCI_INTERFACE) ++ struct pci_dev *_dev ++#elif defined(PLATFORM_INTERFACE) ++ struct platform_device *dev ++#endif ++ ); ++extern int hcd_init( ++#ifdef LM_INTERFACE ++ struct lm_device *_dev ++#elif defined(PCI_INTERFACE) ++ struct pci_dev *_dev ++#elif defined(PLATFORM_INTERFACE) ++ struct platform_device *dev ++#endif ++ ); ++ ++extern int pcd_remove( ++#ifdef LM_INTERFACE ++ struct lm_device *_dev ++#elif defined(PCI_INTERFACE) ++ struct pci_dev *_dev ++#elif defined(PLATFORM_INTERFACE) ++ struct platform_device *_dev ++#endif ++ ); ++ ++extern void hcd_remove( ++#ifdef LM_INTERFACE ++ struct lm_device *_dev ++#elif defined(PCI_INTERFACE) ++ struct pci_dev *_dev ++#elif defined(PLATFORM_INTERFACE) ++ struct platform_device *_dev ++#endif ++ ); ++ ++extern void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host); ++ ++/*-------------------------------------------------------------------------*/ ++/* Encapsulate the module parameter settings */ ++ ++struct dwc_otg_driver_module_params { ++ int32_t opt; ++ int32_t otg_cap; ++ int32_t dma_enable; ++ int32_t dma_desc_enable; ++ int32_t dma_burst_size; ++ int32_t speed; ++ int32_t host_support_fs_ls_low_power; ++ int32_t host_ls_low_power_phy_clk; ++ int32_t enable_dynamic_fifo; ++ int32_t data_fifo_size; ++ int32_t dev_rx_fifo_size; ++ int32_t dev_nperio_tx_fifo_size; ++ uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS]; ++ int32_t host_rx_fifo_size; ++ int32_t host_nperio_tx_fifo_size; ++ int32_t host_perio_tx_fifo_size; ++ int32_t max_transfer_size; ++ int32_t max_packet_count; ++ int32_t host_channels; ++ int32_t dev_endpoints; ++ int32_t phy_type; ++ int32_t phy_utmi_width; ++ int32_t phy_ulpi_ddr; ++ int32_t phy_ulpi_ext_vbus; ++ int32_t i2c_enable; ++ int32_t ulpi_fs_ls; ++ int32_t ts_dline; ++ int32_t en_multiple_tx_fifo; ++ uint32_t dev_tx_fifo_size[MAX_TX_FIFOS]; ++ uint32_t thr_ctl; ++ uint32_t tx_thr_length; ++ uint32_t rx_thr_length; ++ int32_t pti_enable; ++ int32_t mpi_enable; ++ int32_t lpm_enable; ++ int32_t ic_usb_cap; ++ int32_t ahb_thr_ratio; ++ int32_t power_down; ++ int32_t reload_ctl; ++ int32_t dev_out_nak; ++ int32_t cont_on_bna; ++ int32_t ahb_single; ++ int32_t otg_ver; ++ int32_t adp_enable; ++}; ++ ++static struct dwc_otg_driver_module_params dwc_otg_module_params = { ++ .opt = -1, ++ .otg_cap = -1, ++ .dma_enable = -1, ++ .dma_desc_enable = -1, ++ .dma_burst_size = -1, ++ .speed = -1, ++ .host_support_fs_ls_low_power = -1, ++ .host_ls_low_power_phy_clk = -1, ++ .enable_dynamic_fifo = -1, ++ .data_fifo_size = -1, ++ .dev_rx_fifo_size = -1, ++ .dev_nperio_tx_fifo_size = -1, ++ .dev_perio_tx_fifo_size = { ++ /* dev_perio_tx_fifo_size_1 */ ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1 ++ /* 15 */ ++ }, ++ .host_rx_fifo_size = -1, ++ .host_nperio_tx_fifo_size = -1, ++ .host_perio_tx_fifo_size = -1, ++ .max_transfer_size = -1, ++ .max_packet_count = -1, ++ .host_channels = -1, ++ .dev_endpoints = -1, ++ .phy_type = -1, ++ .phy_utmi_width = -1, ++ .phy_ulpi_ddr = -1, ++ .phy_ulpi_ext_vbus = -1, ++ .i2c_enable = -1, ++ .ulpi_fs_ls = -1, ++ .ts_dline = -1, ++ .en_multiple_tx_fifo = -1, ++ .dev_tx_fifo_size = { ++ /* dev_tx_fifo_size */ ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1 ++ /* 15 */ ++ }, ++ .thr_ctl = -1, ++ .tx_thr_length = -1, ++ .rx_thr_length = -1, ++ .pti_enable = -1, ++ .mpi_enable = -1, ++ .lpm_enable = 0, ++ .ic_usb_cap = -1, ++ .ahb_thr_ratio = -1, ++ .power_down = -1, ++ .reload_ctl = -1, ++ .dev_out_nak = -1, ++ .cont_on_bna = -1, ++ .ahb_single = -1, ++ .otg_ver = -1, ++ .adp_enable = -1, ++}; ++ ++//Global variable to switch the fiq fix on or off (declared in bcm2708.c) ++extern bool fiq_fix_enable; ++// Global variable to enable the split transaction fix ++bool fiq_split_enable = true; ++//Global variable to switch the nak holdoff on or off ++bool nak_holdoff_enable = true; ++ ++ ++/** ++ * This function shows the Driver Version. ++ */ ++static ssize_t version_show(struct device_driver *dev, char *buf) ++{ ++ return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n", ++ DWC_DRIVER_VERSION); ++} ++ ++static DRIVER_ATTR(version, S_IRUGO, version_show, NULL); ++ ++/** ++ * Global Debug Level Mask. ++ */ ++uint32_t g_dbg_lvl = 0; /* OFF */ ++ ++/** ++ * This function shows the driver Debug Level. ++ */ ++static ssize_t dbg_level_show(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%0x\n", g_dbg_lvl); ++} ++ ++/** ++ * This function stores the driver Debug Level. ++ */ ++static ssize_t dbg_level_store(struct device_driver *drv, const char *buf, ++ size_t count) ++{ ++ g_dbg_lvl = simple_strtoul(buf, NULL, 16); ++ return count; ++} ++ ++static DRIVER_ATTR(debuglevel, S_IRUGO | S_IWUSR, dbg_level_show, ++ dbg_level_store); ++ ++/** ++ * This function is called during module intialization ++ * to pass module parameters to the DWC_OTG CORE. ++ */ ++static int set_parameters(dwc_otg_core_if_t * core_if) ++{ ++ int retval = 0; ++ int i; ++ ++ if (dwc_otg_module_params.otg_cap != -1) { ++ retval += ++ dwc_otg_set_param_otg_cap(core_if, ++ dwc_otg_module_params.otg_cap); ++ } ++ if (dwc_otg_module_params.dma_enable != -1) { ++ retval += ++ dwc_otg_set_param_dma_enable(core_if, ++ dwc_otg_module_params. ++ dma_enable); ++ } ++ if (dwc_otg_module_params.dma_desc_enable != -1) { ++ retval += ++ dwc_otg_set_param_dma_desc_enable(core_if, ++ dwc_otg_module_params. ++ dma_desc_enable); ++ } ++ if (dwc_otg_module_params.opt != -1) { ++ retval += ++ dwc_otg_set_param_opt(core_if, dwc_otg_module_params.opt); ++ } ++ if (dwc_otg_module_params.dma_burst_size != -1) { ++ retval += ++ dwc_otg_set_param_dma_burst_size(core_if, ++ dwc_otg_module_params. ++ dma_burst_size); ++ } ++ if (dwc_otg_module_params.host_support_fs_ls_low_power != -1) { ++ retval += ++ dwc_otg_set_param_host_support_fs_ls_low_power(core_if, ++ dwc_otg_module_params. ++ host_support_fs_ls_low_power); ++ } ++ if (dwc_otg_module_params.enable_dynamic_fifo != -1) { ++ retval += ++ dwc_otg_set_param_enable_dynamic_fifo(core_if, ++ dwc_otg_module_params. ++ enable_dynamic_fifo); ++ } ++ if (dwc_otg_module_params.data_fifo_size != -1) { ++ retval += ++ dwc_otg_set_param_data_fifo_size(core_if, ++ dwc_otg_module_params. ++ data_fifo_size); ++ } ++ if (dwc_otg_module_params.dev_rx_fifo_size != -1) { ++ retval += ++ dwc_otg_set_param_dev_rx_fifo_size(core_if, ++ dwc_otg_module_params. ++ dev_rx_fifo_size); ++ } ++ if (dwc_otg_module_params.dev_nperio_tx_fifo_size != -1) { ++ retval += ++ dwc_otg_set_param_dev_nperio_tx_fifo_size(core_if, ++ dwc_otg_module_params. ++ dev_nperio_tx_fifo_size); ++ } ++ if (dwc_otg_module_params.host_rx_fifo_size != -1) { ++ retval += ++ dwc_otg_set_param_host_rx_fifo_size(core_if, ++ dwc_otg_module_params.host_rx_fifo_size); ++ } ++ if (dwc_otg_module_params.host_nperio_tx_fifo_size != -1) { ++ retval += ++ dwc_otg_set_param_host_nperio_tx_fifo_size(core_if, ++ dwc_otg_module_params. ++ host_nperio_tx_fifo_size); ++ } ++ if (dwc_otg_module_params.host_perio_tx_fifo_size != -1) { ++ retval += ++ dwc_otg_set_param_host_perio_tx_fifo_size(core_if, ++ dwc_otg_module_params. ++ host_perio_tx_fifo_size); ++ } ++ if (dwc_otg_module_params.max_transfer_size != -1) { ++ retval += ++ dwc_otg_set_param_max_transfer_size(core_if, ++ dwc_otg_module_params. ++ max_transfer_size); ++ } ++ if (dwc_otg_module_params.max_packet_count != -1) { ++ retval += ++ dwc_otg_set_param_max_packet_count(core_if, ++ dwc_otg_module_params. ++ max_packet_count); ++ } ++ if (dwc_otg_module_params.host_channels != -1) { ++ retval += ++ dwc_otg_set_param_host_channels(core_if, ++ dwc_otg_module_params. ++ host_channels); ++ } ++ if (dwc_otg_module_params.dev_endpoints != -1) { ++ retval += ++ dwc_otg_set_param_dev_endpoints(core_if, ++ dwc_otg_module_params. ++ dev_endpoints); ++ } ++ if (dwc_otg_module_params.phy_type != -1) { ++ retval += ++ dwc_otg_set_param_phy_type(core_if, ++ dwc_otg_module_params.phy_type); ++ } ++ if (dwc_otg_module_params.speed != -1) { ++ retval += ++ dwc_otg_set_param_speed(core_if, ++ dwc_otg_module_params.speed); ++ } ++ if (dwc_otg_module_params.host_ls_low_power_phy_clk != -1) { ++ retval += ++ dwc_otg_set_param_host_ls_low_power_phy_clk(core_if, ++ dwc_otg_module_params. ++ host_ls_low_power_phy_clk); ++ } ++ if (dwc_otg_module_params.phy_ulpi_ddr != -1) { ++ retval += ++ dwc_otg_set_param_phy_ulpi_ddr(core_if, ++ dwc_otg_module_params. ++ phy_ulpi_ddr); ++ } ++ if (dwc_otg_module_params.phy_ulpi_ext_vbus != -1) { ++ retval += ++ dwc_otg_set_param_phy_ulpi_ext_vbus(core_if, ++ dwc_otg_module_params. ++ phy_ulpi_ext_vbus); ++ } ++ if (dwc_otg_module_params.phy_utmi_width != -1) { ++ retval += ++ dwc_otg_set_param_phy_utmi_width(core_if, ++ dwc_otg_module_params. ++ phy_utmi_width); ++ } ++ if (dwc_otg_module_params.ulpi_fs_ls != -1) { ++ retval += ++ dwc_otg_set_param_ulpi_fs_ls(core_if, ++ dwc_otg_module_params.ulpi_fs_ls); ++ } ++ if (dwc_otg_module_params.ts_dline != -1) { ++ retval += ++ dwc_otg_set_param_ts_dline(core_if, ++ dwc_otg_module_params.ts_dline); ++ } ++ if (dwc_otg_module_params.i2c_enable != -1) { ++ retval += ++ dwc_otg_set_param_i2c_enable(core_if, ++ dwc_otg_module_params. ++ i2c_enable); ++ } ++ if (dwc_otg_module_params.en_multiple_tx_fifo != -1) { ++ retval += ++ dwc_otg_set_param_en_multiple_tx_fifo(core_if, ++ dwc_otg_module_params. ++ en_multiple_tx_fifo); ++ } ++ for (i = 0; i < 15; i++) { ++ if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] != -1) { ++ retval += ++ dwc_otg_set_param_dev_perio_tx_fifo_size(core_if, ++ dwc_otg_module_params. ++ dev_perio_tx_fifo_size ++ [i], i); ++ } ++ } ++ ++ for (i = 0; i < 15; i++) { ++ if (dwc_otg_module_params.dev_tx_fifo_size[i] != -1) { ++ retval += dwc_otg_set_param_dev_tx_fifo_size(core_if, ++ dwc_otg_module_params. ++ dev_tx_fifo_size ++ [i], i); ++ } ++ } ++ if (dwc_otg_module_params.thr_ctl != -1) { ++ retval += ++ dwc_otg_set_param_thr_ctl(core_if, ++ dwc_otg_module_params.thr_ctl); ++ } ++ if (dwc_otg_module_params.mpi_enable != -1) { ++ retval += ++ dwc_otg_set_param_mpi_enable(core_if, ++ dwc_otg_module_params. ++ mpi_enable); ++ } ++ if (dwc_otg_module_params.pti_enable != -1) { ++ retval += ++ dwc_otg_set_param_pti_enable(core_if, ++ dwc_otg_module_params. ++ pti_enable); ++ } ++ if (dwc_otg_module_params.lpm_enable != -1) { ++ retval += ++ dwc_otg_set_param_lpm_enable(core_if, ++ dwc_otg_module_params. ++ lpm_enable); ++ } ++ if (dwc_otg_module_params.ic_usb_cap != -1) { ++ retval += ++ dwc_otg_set_param_ic_usb_cap(core_if, ++ dwc_otg_module_params. ++ ic_usb_cap); ++ } ++ if (dwc_otg_module_params.tx_thr_length != -1) { ++ retval += ++ dwc_otg_set_param_tx_thr_length(core_if, ++ dwc_otg_module_params.tx_thr_length); ++ } ++ if (dwc_otg_module_params.rx_thr_length != -1) { ++ retval += ++ dwc_otg_set_param_rx_thr_length(core_if, ++ dwc_otg_module_params. ++ rx_thr_length); ++ } ++ if (dwc_otg_module_params.ahb_thr_ratio != -1) { ++ retval += ++ dwc_otg_set_param_ahb_thr_ratio(core_if, ++ dwc_otg_module_params.ahb_thr_ratio); ++ } ++ if (dwc_otg_module_params.power_down != -1) { ++ retval += ++ dwc_otg_set_param_power_down(core_if, ++ dwc_otg_module_params.power_down); ++ } ++ if (dwc_otg_module_params.reload_ctl != -1) { ++ retval += ++ dwc_otg_set_param_reload_ctl(core_if, ++ dwc_otg_module_params.reload_ctl); ++ } ++ ++ if (dwc_otg_module_params.dev_out_nak != -1) { ++ retval += ++ dwc_otg_set_param_dev_out_nak(core_if, ++ dwc_otg_module_params.dev_out_nak); ++ } ++ ++ if (dwc_otg_module_params.cont_on_bna != -1) { ++ retval += ++ dwc_otg_set_param_cont_on_bna(core_if, ++ dwc_otg_module_params.cont_on_bna); ++ } ++ ++ if (dwc_otg_module_params.ahb_single != -1) { ++ retval += ++ dwc_otg_set_param_ahb_single(core_if, ++ dwc_otg_module_params.ahb_single); ++ } ++ ++ if (dwc_otg_module_params.otg_ver != -1) { ++ retval += ++ dwc_otg_set_param_otg_ver(core_if, ++ dwc_otg_module_params.otg_ver); ++ } ++ if (dwc_otg_module_params.adp_enable != -1) { ++ retval += ++ dwc_otg_set_param_adp_enable(core_if, ++ dwc_otg_module_params. ++ adp_enable); ++ } ++ return retval; ++} ++ ++/** ++ * This function is the top level interrupt handler for the Common ++ * (Device and host modes) interrupts. ++ */ ++static irqreturn_t dwc_otg_common_irq(int irq, void *dev) ++{ ++ int32_t retval = IRQ_NONE; ++ ++ retval = dwc_otg_handle_common_intr(dev); ++ if (retval != 0) { ++ S3C2410X_CLEAR_EINTPEND(); ++ } ++ return IRQ_RETVAL(retval); ++} ++ ++/** ++ * This function is called when a lm_device is unregistered with the ++ * dwc_otg_driver. This happens, for example, when the rmmod command is ++ * executed. The device may or may not be electrically present. If it is ++ * present, the driver stops device processing. Any resources used on behalf ++ * of this device are freed. ++ * ++ * @param _dev ++ */ ++#ifdef LM_INTERFACE ++#define REM_RETVAL(n) ++static void dwc_otg_driver_remove( struct lm_device *_dev ) ++{ dwc_otg_device_t *otg_dev = lm_get_drvdata(_dev); ++#elif defined(PCI_INTERFACE) ++#define REM_RETVAL(n) ++static void dwc_otg_driver_remove( struct pci_dev *_dev ) ++{ dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev); ++#elif defined(PLATFORM_INTERFACE) ++#define REM_RETVAL(n) n ++static int dwc_otg_driver_remove( struct platform_device *_dev ) ++{ dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev); ++#endif ++ ++ DWC_DEBUGPL(DBG_ANY, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev); ++ ++ if (!otg_dev) { ++ /* Memory allocation for the dwc_otg_device failed. */ ++ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__); ++ return REM_RETVAL(-ENOMEM); ++ } ++#ifndef DWC_DEVICE_ONLY ++ if (otg_dev->hcd) { ++ hcd_remove(_dev); ++ } else { ++ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__); ++ return REM_RETVAL(-EINVAL); ++ } ++#endif ++ ++#ifndef DWC_HOST_ONLY ++ if (otg_dev->pcd) { ++ pcd_remove(_dev); ++ } else { ++ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->pcd NULL!\n", __func__); ++ return REM_RETVAL(-EINVAL); ++ } ++#endif ++ /* ++ * Free the IRQ ++ */ ++ if (otg_dev->common_irq_installed) { ++#ifdef PLATFORM_INTERFACE ++ free_irq(platform_get_irq(_dev, 0), otg_dev); ++#else ++ free_irq(_dev->irq, otg_dev); ++#endif ++ } else { ++ DWC_DEBUGPL(DBG_ANY, "%s: There is no installed irq!\n", __func__); ++ return REM_RETVAL(-ENXIO); ++ } ++ ++ if (otg_dev->core_if) { ++ dwc_otg_cil_remove(otg_dev->core_if); ++ } else { ++ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->core_if NULL!\n", __func__); ++ return REM_RETVAL(-ENXIO); ++ } ++ ++ /* ++ * Remove the device attributes ++ */ ++ dwc_otg_attr_remove(_dev); ++ ++ /* ++ * Return the memory. ++ */ ++ if (otg_dev->os_dep.base) { ++ iounmap(otg_dev->os_dep.base); ++ } ++ DWC_FREE(otg_dev); ++ ++ /* ++ * Clear the drvdata pointer. ++ */ ++#ifdef LM_INTERFACE ++ lm_set_drvdata(_dev, 0); ++#elif defined(PCI_INTERFACE) ++ release_mem_region(otg_dev->os_dep.rsrc_start, ++ otg_dev->os_dep.rsrc_len); ++ pci_set_drvdata(_dev, 0); ++#elif defined(PLATFORM_INTERFACE) ++ platform_set_drvdata(_dev, 0); ++#endif ++ return REM_RETVAL(0); ++} ++ ++/** ++ * This function is called when an lm_device is bound to a ++ * dwc_otg_driver. It creates the driver components required to ++ * control the device (CIL, HCD, and PCD) and it initializes the ++ * device. The driver components are stored in a dwc_otg_device ++ * structure. A reference to the dwc_otg_device is saved in the ++ * lm_device. This allows the driver to access the dwc_otg_device ++ * structure on subsequent calls to driver methods for this device. ++ * ++ * @param _dev Bus device ++ */ ++static int dwc_otg_driver_probe( ++#ifdef LM_INTERFACE ++ struct lm_device *_dev ++#elif defined(PCI_INTERFACE) ++ struct pci_dev *_dev, ++ const struct pci_device_id *id ++#elif defined(PLATFORM_INTERFACE) ++ struct platform_device *_dev ++#endif ++ ) ++{ ++ int retval = 0; ++ dwc_otg_device_t *dwc_otg_device; ++ int devirq; ++ ++ dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev); ++#ifdef LM_INTERFACE ++ dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)_dev->resource.start); ++#elif defined(PCI_INTERFACE) ++ if (!id) { ++ DWC_ERROR("Invalid pci_device_id %p", id); ++ return -EINVAL; ++ } ++ ++ if (!_dev || (pci_enable_device(_dev) < 0)) { ++ DWC_ERROR("Invalid pci_device %p", _dev); ++ return -ENODEV; ++ } ++ dev_dbg(&_dev->dev, "start=0x%08x\n", (unsigned)pci_resource_start(_dev,0)); ++ /* other stuff needed as well? */ ++ ++#elif defined(PLATFORM_INTERFACE) ++ dev_dbg(&_dev->dev, "start=0x%08x (len 0x%x)\n", ++ (unsigned)_dev->resource->start, ++ (unsigned)(_dev->resource->end - _dev->resource->start)); ++#endif ++ ++ dwc_otg_device = DWC_ALLOC(sizeof(dwc_otg_device_t)); ++ ++ if (!dwc_otg_device) { ++ dev_err(&_dev->dev, "kmalloc of dwc_otg_device failed\n"); ++ return -ENOMEM; ++ } ++ ++ memset(dwc_otg_device, 0, sizeof(*dwc_otg_device)); ++ dwc_otg_device->os_dep.reg_offset = 0xFFFFFFFF; ++ ++ /* ++ * Map the DWC_otg Core memory into virtual address space. ++ */ ++#ifdef LM_INTERFACE ++ dwc_otg_device->os_dep.base = ioremap(_dev->resource.start, SZ_256K); ++ ++ if (!dwc_otg_device->os_dep.base) { ++ dev_err(&_dev->dev, "ioremap() failed\n"); ++ DWC_FREE(dwc_otg_device); ++ return -ENOMEM; ++ } ++ dev_dbg(&_dev->dev, "base=0x%08x\n", ++ (unsigned)dwc_otg_device->os_dep.base); ++#elif defined(PCI_INTERFACE) ++ _dev->current_state = PCI_D0; ++ _dev->dev.power.power_state = PMSG_ON; ++ ++ if (!_dev->irq) { ++ DWC_ERROR("Found HC with no IRQ. Check BIOS/PCI %s setup!", ++ pci_name(_dev)); ++ iounmap(dwc_otg_device->os_dep.base); ++ DWC_FREE(dwc_otg_device); ++ return -ENODEV; ++ } ++ ++ dwc_otg_device->os_dep.rsrc_start = pci_resource_start(_dev, 0); ++ dwc_otg_device->os_dep.rsrc_len = pci_resource_len(_dev, 0); ++ DWC_DEBUGPL(DBG_ANY, "PCI resource: start=%08x, len=%08x\n", ++ (unsigned)dwc_otg_device->os_dep.rsrc_start, ++ (unsigned)dwc_otg_device->os_dep.rsrc_len); ++ if (!request_mem_region ++ (dwc_otg_device->os_dep.rsrc_start, dwc_otg_device->os_dep.rsrc_len, ++ "dwc_otg")) { ++ dev_dbg(&_dev->dev, "error requesting memory\n"); ++ iounmap(dwc_otg_device->os_dep.base); ++ DWC_FREE(dwc_otg_device); ++ return -EFAULT; ++ } ++ ++ dwc_otg_device->os_dep.base = ++ ioremap_nocache(dwc_otg_device->os_dep.rsrc_start, ++ dwc_otg_device->os_dep.rsrc_len); ++ if (dwc_otg_device->os_dep.base == NULL) { ++ dev_dbg(&_dev->dev, "error mapping memory\n"); ++ release_mem_region(dwc_otg_device->os_dep.rsrc_start, ++ dwc_otg_device->os_dep.rsrc_len); ++ iounmap(dwc_otg_device->os_dep.base); ++ DWC_FREE(dwc_otg_device); ++ return -EFAULT; ++ } ++ dev_dbg(&_dev->dev, "base=0x%p (before adjust) \n", ++ dwc_otg_device->os_dep.base); ++ dwc_otg_device->os_dep.base = (char *)dwc_otg_device->os_dep.base; ++ dev_dbg(&_dev->dev, "base=0x%p (after adjust) \n", ++ dwc_otg_device->os_dep.base); ++ dev_dbg(&_dev->dev, "%s: mapped PA 0x%x to VA 0x%p\n", __func__, ++ (unsigned)dwc_otg_device->os_dep.rsrc_start, ++ dwc_otg_device->os_dep.base); ++ ++ pci_set_master(_dev); ++ pci_set_drvdata(_dev, dwc_otg_device); ++#elif defined(PLATFORM_INTERFACE) ++ DWC_DEBUGPL(DBG_ANY,"Platform resource: start=%08x, len=%08x\n", ++ _dev->resource->start, ++ _dev->resource->end - _dev->resource->start + 1); ++#if 1 ++ if (!request_mem_region(_dev->resource[0].start, ++ _dev->resource[0].end - _dev->resource[0].start + 1, ++ "dwc_otg")) { ++ dev_dbg(&_dev->dev, "error reserving mapped memory\n"); ++ retval = -EFAULT; ++ goto fail; ++ } ++ ++ dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource[0].start, ++ _dev->resource[0].end - ++ _dev->resource[0].start+1); ++ if (fiq_fix_enable) ++ { ++ if (!request_mem_region(_dev->resource[1].start, ++ _dev->resource[1].end - _dev->resource[1].start + 1, ++ "dwc_otg")) { ++ dev_dbg(&_dev->dev, "error reserving mapped memory\n"); ++ retval = -EFAULT; ++ goto fail; ++ } ++ ++ dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start, ++ _dev->resource[1].end - ++ _dev->resource[1].start + 1); ++ dummy_send = (void *) kmalloc(16, GFP_ATOMIC); ++ } ++ ++#else ++ { ++ struct map_desc desc = { ++ .virtual = IO_ADDRESS((unsigned)_dev->resource->start), ++ .pfn = __phys_to_pfn((unsigned)_dev->resource->start), ++ .length = SZ_128K, ++ .type = MT_DEVICE ++ }; ++ iotable_init(&desc, 1); ++ dwc_otg_device->os_dep.base = (void *)desc.virtual; ++ } ++#endif ++ if (!dwc_otg_device->os_dep.base) { ++ dev_err(&_dev->dev, "ioremap() failed\n"); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ dev_dbg(&_dev->dev, "base=0x%08x\n", ++ (unsigned)dwc_otg_device->os_dep.base); ++#endif ++ ++ /* ++ * Initialize driver data to point to the global DWC_otg ++ * Device structure. ++ */ ++#ifdef LM_INTERFACE ++ lm_set_drvdata(_dev, dwc_otg_device); ++#elif defined(PLATFORM_INTERFACE) ++ platform_set_drvdata(_dev, dwc_otg_device); ++#endif ++ dev_dbg(&_dev->dev, "dwc_otg_device=0x%p\n", dwc_otg_device); ++ ++ dwc_otg_device->core_if = dwc_otg_cil_init(dwc_otg_device->os_dep.base); ++ DWC_DEBUGPL(DBG_HCDV, "probe of device %p given core_if %p\n", ++ dwc_otg_device, dwc_otg_device->core_if);//GRAYG ++ ++ if (!dwc_otg_device->core_if) { ++ dev_err(&_dev->dev, "CIL initialization failed!\n"); ++ retval = -ENOMEM; ++ goto fail; ++ } ++ ++ dev_dbg(&_dev->dev, "Calling get_gsnpsid\n"); ++ /* ++ * Attempt to ensure this device is really a DWC_otg Controller. ++ * Read and verify the SNPSID register contents. The value should be ++ * 0x45F42XXX or 0x45F42XXX, which corresponds to either "OT2" or "OTG3", ++ * as in "OTG version 2.XX" or "OTG version 3.XX". ++ */ ++ ++ if (((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F542000) && ++ ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F543000)) { ++ dev_err(&_dev->dev, "Bad value for SNPSID: 0x%08x\n", ++ dwc_otg_get_gsnpsid(dwc_otg_device->core_if)); ++ retval = -EINVAL; ++ goto fail; ++ } ++ ++ /* ++ * Validate parameter values. ++ */ ++ dev_dbg(&_dev->dev, "Calling set_parameters\n"); ++ if (set_parameters(dwc_otg_device->core_if)) { ++ retval = -EINVAL; ++ goto fail; ++ } ++ ++ /* ++ * Create Device Attributes in sysfs ++ */ ++ dev_dbg(&_dev->dev, "Calling attr_create\n"); ++ dwc_otg_attr_create(_dev); ++ ++ /* ++ * Disable the global interrupt until all the interrupt ++ * handlers are installed. ++ */ ++ dev_dbg(&_dev->dev, "Calling disable_global_interrupts\n"); ++ dwc_otg_disable_global_interrupts(dwc_otg_device->core_if); ++ ++ /* ++ * Install the interrupt handler for the common interrupts before ++ * enabling common interrupts in core_init below. ++ */ ++ ++#if defined(PLATFORM_INTERFACE) ++ devirq = platform_get_irq(_dev, 0); ++#else ++ devirq = _dev->irq; ++#endif ++ DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n", ++ devirq); ++ dev_dbg(&_dev->dev, "Calling request_irq(%d)\n", devirq); ++ retval = request_irq(devirq, dwc_otg_common_irq, ++ IRQF_SHARED, ++ "dwc_otg", dwc_otg_device); ++ if (retval) { ++ DWC_ERROR("request of irq%d failed\n", devirq); ++ retval = -EBUSY; ++ goto fail; ++ } else { ++ dwc_otg_device->common_irq_installed = 1; ++ } ++ ++#ifndef IRQF_TRIGGER_LOW ++#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE) ++ dev_dbg(&_dev->dev, "Calling set_irq_type\n"); ++ set_irq_type(devirq, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) ++ IRQT_LOW ++#else ++ IRQ_TYPE_LEVEL_LOW ++#endif ++ ); ++#endif ++#endif /*IRQF_TRIGGER_LOW*/ ++ ++ /* ++ * Initialize the DWC_otg core. ++ */ ++ dev_dbg(&_dev->dev, "Calling dwc_otg_core_init\n"); ++ dwc_otg_core_init(dwc_otg_device->core_if); ++ ++#ifndef DWC_HOST_ONLY ++ /* ++ * Initialize the PCD ++ */ ++ dev_dbg(&_dev->dev, "Calling pcd_init\n"); ++ retval = pcd_init(_dev); ++ if (retval != 0) { ++ DWC_ERROR("pcd_init failed\n"); ++ dwc_otg_device->pcd = NULL; ++ goto fail; ++ } ++#endif ++#ifndef DWC_DEVICE_ONLY ++ /* ++ * Initialize the HCD ++ */ ++ dev_dbg(&_dev->dev, "Calling hcd_init\n"); ++ retval = hcd_init(_dev); ++ if (retval != 0) { ++ DWC_ERROR("hcd_init failed\n"); ++ dwc_otg_device->hcd = NULL; ++ goto fail; ++ } ++#endif ++ /* Recover from drvdata having been overwritten by hcd_init() */ ++#ifdef LM_INTERFACE ++ lm_set_drvdata(_dev, dwc_otg_device); ++#elif defined(PLATFORM_INTERFACE) ++ platform_set_drvdata(_dev, dwc_otg_device); ++#elif defined(PCI_INTERFACE) ++ pci_set_drvdata(_dev, dwc_otg_device); ++ dwc_otg_device->os_dep.pcidev = _dev; ++#endif ++ ++ /* ++ * Enable the global interrupt after all the interrupt ++ * handlers are installed if there is no ADP support else ++ * perform initial actions required for Internal ADP logic. ++ */ ++ if (!dwc_otg_get_param_adp_enable(dwc_otg_device->core_if)) { ++ dev_dbg(&_dev->dev, "Calling enable_global_interrupts\n"); ++ dwc_otg_enable_global_interrupts(dwc_otg_device->core_if); ++ dev_dbg(&_dev->dev, "Done\n"); ++ } else ++ dwc_otg_adp_start(dwc_otg_device->core_if, ++ dwc_otg_is_host_mode(dwc_otg_device->core_if)); ++ ++ return 0; ++ ++fail: ++ dwc_otg_driver_remove(_dev); ++ return retval; ++} ++ ++/** ++ * This structure defines the methods to be called by a bus driver ++ * during the lifecycle of a device on that bus. Both drivers and ++ * devices are registered with a bus driver. The bus driver matches ++ * devices to drivers based on information in the device and driver ++ * structures. ++ * ++ * The probe function is called when the bus driver matches a device ++ * to this driver. The remove function is called when a device is ++ * unregistered with the bus driver. ++ */ ++#ifdef LM_INTERFACE ++static struct lm_driver dwc_otg_driver = { ++ .drv = {.name = (char *)dwc_driver_name,}, ++ .probe = dwc_otg_driver_probe, ++ .remove = dwc_otg_driver_remove, ++ // 'suspend' and 'resume' absent ++}; ++#elif defined(PCI_INTERFACE) ++static const struct pci_device_id pci_ids[] = { { ++ PCI_DEVICE(0x16c3, 0xabcd), ++ .driver_data = ++ (unsigned long)0xdeadbeef, ++ }, { /* end: all zeroes */ } ++}; ++ ++MODULE_DEVICE_TABLE(pci, pci_ids); ++ ++/* pci driver glue; this is a "new style" PCI driver module */ ++static struct pci_driver dwc_otg_driver = { ++ .name = "dwc_otg", ++ .id_table = pci_ids, ++ ++ .probe = dwc_otg_driver_probe, ++ .remove = dwc_otg_driver_remove, ++ ++ .driver = { ++ .name = (char *)dwc_driver_name, ++ }, ++}; ++#elif defined(PLATFORM_INTERFACE) ++static struct platform_device_id platform_ids[] = { ++ { ++ .name = "bcm2708_usb", ++ .driver_data = (kernel_ulong_t) 0xdeadbeef, ++ }, ++ { /* end: all zeroes */ } ++}; ++MODULE_DEVICE_TABLE(platform, platform_ids); ++ ++static struct platform_driver dwc_otg_driver = { ++ .driver = { ++ .name = (char *)dwc_driver_name, ++ }, ++ .id_table = platform_ids, ++ ++ .probe = dwc_otg_driver_probe, ++ .remove = dwc_otg_driver_remove, ++ // no 'shutdown', 'suspend', 'resume', 'suspend_late' or 'resume_early' ++}; ++#endif ++ ++/** ++ * This function is called when the dwc_otg_driver is installed with the ++ * insmod command. It registers the dwc_otg_driver structure with the ++ * appropriate bus driver. This will cause the dwc_otg_driver_probe function ++ * to be called. In addition, the bus driver will automatically expose ++ * attributes defined for the device and driver in the special sysfs file ++ * system. ++ * ++ * @return ++ */ ++static int __init dwc_otg_driver_init(void) ++{ ++ int retval = 0; ++ int error; ++ struct device_driver *drv; ++ ++ if(fiq_split_enable && !fiq_fix_enable) { ++ printk(KERN_WARNING "dwc_otg: fiq_split_enable was set without fiq_fix_enable! Correcting.\n"); ++ fiq_fix_enable = 1; ++ } ++ ++ printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name, ++ DWC_DRIVER_VERSION, ++#ifdef LM_INTERFACE ++ "logicmodule"); ++ retval = lm_driver_register(&dwc_otg_driver); ++ drv = &dwc_otg_driver.drv; ++#elif defined(PCI_INTERFACE) ++ "pci"); ++ retval = pci_register_driver(&dwc_otg_driver); ++ drv = &dwc_otg_driver.driver; ++#elif defined(PLATFORM_INTERFACE) ++ "platform"); ++ retval = platform_driver_register(&dwc_otg_driver); ++ drv = &dwc_otg_driver.driver; ++#endif ++ if (retval < 0) { ++ printk(KERN_ERR "%s retval=%d\n", __func__, retval); ++ return retval; ++ } ++ printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled"); ++ printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled"); ++ printk(KERN_DEBUG "dwc_otg: FIQ split fix %s\n", fiq_split_enable ? "enabled":"disabled"); ++ ++ error = driver_create_file(drv, &driver_attr_version); ++#ifdef DEBUG ++ error = driver_create_file(drv, &driver_attr_debuglevel); ++#endif ++ return retval; ++} ++ ++module_init(dwc_otg_driver_init); ++ ++/** ++ * This function is called when the driver is removed from the kernel ++ * with the rmmod command. The driver unregisters itself with its bus ++ * driver. ++ * ++ */ ++static void __exit dwc_otg_driver_cleanup(void) ++{ ++ printk(KERN_DEBUG "dwc_otg_driver_cleanup()\n"); ++ ++#ifdef LM_INTERFACE ++ driver_remove_file(&dwc_otg_driver.drv, &driver_attr_debuglevel); ++ driver_remove_file(&dwc_otg_driver.drv, &driver_attr_version); ++ lm_driver_unregister(&dwc_otg_driver); ++#elif defined(PCI_INTERFACE) ++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); ++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); ++ pci_unregister_driver(&dwc_otg_driver); ++#elif defined(PLATFORM_INTERFACE) ++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_debuglevel); ++ driver_remove_file(&dwc_otg_driver.driver, &driver_attr_version); ++ platform_driver_unregister(&dwc_otg_driver); ++#endif ++ ++ printk(KERN_INFO "%s module removed\n", dwc_driver_name); ++} ++ ++module_exit(dwc_otg_driver_cleanup); ++ ++MODULE_DESCRIPTION(DWC_DRIVER_DESC); ++MODULE_AUTHOR("Synopsys Inc."); ++MODULE_LICENSE("GPL"); ++ ++module_param_named(otg_cap, dwc_otg_module_params.otg_cap, int, 0444); ++MODULE_PARM_DESC(otg_cap, "OTG Capabilities 0=HNP&SRP 1=SRP Only 2=None"); ++module_param_named(opt, dwc_otg_module_params.opt, int, 0444); ++MODULE_PARM_DESC(opt, "OPT Mode"); ++module_param_named(dma_enable, dwc_otg_module_params.dma_enable, int, 0444); ++MODULE_PARM_DESC(dma_enable, "DMA Mode 0=Slave 1=DMA enabled"); ++ ++module_param_named(dma_desc_enable, dwc_otg_module_params.dma_desc_enable, int, ++ 0444); ++MODULE_PARM_DESC(dma_desc_enable, ++ "DMA Desc Mode 0=Address DMA 1=DMA Descriptor enabled"); ++ ++module_param_named(dma_burst_size, dwc_otg_module_params.dma_burst_size, int, ++ 0444); ++MODULE_PARM_DESC(dma_burst_size, ++ "DMA Burst Size 1, 4, 8, 16, 32, 64, 128, 256"); ++module_param_named(speed, dwc_otg_module_params.speed, int, 0444); ++MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed"); ++module_param_named(host_support_fs_ls_low_power, ++ dwc_otg_module_params.host_support_fs_ls_low_power, int, ++ 0444); ++MODULE_PARM_DESC(host_support_fs_ls_low_power, ++ "Support Low Power w/FS or LS 0=Support 1=Don't Support"); ++module_param_named(host_ls_low_power_phy_clk, ++ dwc_otg_module_params.host_ls_low_power_phy_clk, int, 0444); ++MODULE_PARM_DESC(host_ls_low_power_phy_clk, ++ "Low Speed Low Power Clock 0=48Mhz 1=6Mhz"); ++module_param_named(enable_dynamic_fifo, ++ dwc_otg_module_params.enable_dynamic_fifo, int, 0444); ++MODULE_PARM_DESC(enable_dynamic_fifo, "0=cC Setting 1=Allow Dynamic Sizing"); ++module_param_named(data_fifo_size, dwc_otg_module_params.data_fifo_size, int, ++ 0444); ++MODULE_PARM_DESC(data_fifo_size, ++ "Total number of words in the data FIFO memory 32-32768"); ++module_param_named(dev_rx_fifo_size, dwc_otg_module_params.dev_rx_fifo_size, ++ int, 0444); ++MODULE_PARM_DESC(dev_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); ++module_param_named(dev_nperio_tx_fifo_size, ++ dwc_otg_module_params.dev_nperio_tx_fifo_size, int, 0444); ++MODULE_PARM_DESC(dev_nperio_tx_fifo_size, ++ "Number of words in the non-periodic Tx FIFO 16-32768"); ++module_param_named(dev_perio_tx_fifo_size_1, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[0], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_1, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_2, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[1], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_2, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_3, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[2], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_3, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_4, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[3], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_4, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_5, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[4], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_5, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_6, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[5], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_6, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_7, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[6], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_7, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_8, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[7], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_8, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_9, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[8], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_9, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_10, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[9], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_10, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_11, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[10], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_11, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_12, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[11], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_12, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_13, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[12], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_13, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_14, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[13], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_14, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(dev_perio_tx_fifo_size_15, ++ dwc_otg_module_params.dev_perio_tx_fifo_size[14], int, 0444); ++MODULE_PARM_DESC(dev_perio_tx_fifo_size_15, ++ "Number of words in the periodic Tx FIFO 4-768"); ++module_param_named(host_rx_fifo_size, dwc_otg_module_params.host_rx_fifo_size, ++ int, 0444); ++MODULE_PARM_DESC(host_rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); ++module_param_named(host_nperio_tx_fifo_size, ++ dwc_otg_module_params.host_nperio_tx_fifo_size, int, 0444); ++MODULE_PARM_DESC(host_nperio_tx_fifo_size, ++ "Number of words in the non-periodic Tx FIFO 16-32768"); ++module_param_named(host_perio_tx_fifo_size, ++ dwc_otg_module_params.host_perio_tx_fifo_size, int, 0444); ++MODULE_PARM_DESC(host_perio_tx_fifo_size, ++ "Number of words in the host periodic Tx FIFO 16-32768"); ++module_param_named(max_transfer_size, dwc_otg_module_params.max_transfer_size, ++ int, 0444); ++/** @todo Set the max to 512K, modify checks */ ++MODULE_PARM_DESC(max_transfer_size, ++ "The maximum transfer size supported in bytes 2047-65535"); ++module_param_named(max_packet_count, dwc_otg_module_params.max_packet_count, ++ int, 0444); ++MODULE_PARM_DESC(max_packet_count, ++ "The maximum number of packets in a transfer 15-511"); ++module_param_named(host_channels, dwc_otg_module_params.host_channels, int, ++ 0444); ++MODULE_PARM_DESC(host_channels, ++ "The number of host channel registers to use 1-16"); ++module_param_named(dev_endpoints, dwc_otg_module_params.dev_endpoints, int, ++ 0444); ++MODULE_PARM_DESC(dev_endpoints, ++ "The number of endpoints in addition to EP0 available for device mode 1-15"); ++module_param_named(phy_type, dwc_otg_module_params.phy_type, int, 0444); ++MODULE_PARM_DESC(phy_type, "0=Reserved 1=UTMI+ 2=ULPI"); ++module_param_named(phy_utmi_width, dwc_otg_module_params.phy_utmi_width, int, ++ 0444); ++MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits"); ++module_param_named(phy_ulpi_ddr, dwc_otg_module_params.phy_ulpi_ddr, int, 0444); ++MODULE_PARM_DESC(phy_ulpi_ddr, ++ "ULPI at double or single data rate 0=Single 1=Double"); ++module_param_named(phy_ulpi_ext_vbus, dwc_otg_module_params.phy_ulpi_ext_vbus, ++ int, 0444); ++MODULE_PARM_DESC(phy_ulpi_ext_vbus, ++ "ULPI PHY using internal or external vbus 0=Internal"); ++module_param_named(i2c_enable, dwc_otg_module_params.i2c_enable, int, 0444); ++MODULE_PARM_DESC(i2c_enable, "FS PHY Interface"); ++module_param_named(ulpi_fs_ls, dwc_otg_module_params.ulpi_fs_ls, int, 0444); ++MODULE_PARM_DESC(ulpi_fs_ls, "ULPI PHY FS/LS mode only"); ++module_param_named(ts_dline, dwc_otg_module_params.ts_dline, int, 0444); ++MODULE_PARM_DESC(ts_dline, "Term select Dline pulsing for all PHYs"); ++module_param_named(debug, g_dbg_lvl, int, 0444); ++MODULE_PARM_DESC(debug, ""); ++ ++module_param_named(en_multiple_tx_fifo, ++ dwc_otg_module_params.en_multiple_tx_fifo, int, 0444); ++MODULE_PARM_DESC(en_multiple_tx_fifo, ++ "Dedicated Non Periodic Tx FIFOs 0=disabled 1=enabled"); ++module_param_named(dev_tx_fifo_size_1, ++ dwc_otg_module_params.dev_tx_fifo_size[0], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_1, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_2, ++ dwc_otg_module_params.dev_tx_fifo_size[1], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_2, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_3, ++ dwc_otg_module_params.dev_tx_fifo_size[2], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_3, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_4, ++ dwc_otg_module_params.dev_tx_fifo_size[3], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_4, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_5, ++ dwc_otg_module_params.dev_tx_fifo_size[4], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_5, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_6, ++ dwc_otg_module_params.dev_tx_fifo_size[5], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_6, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_7, ++ dwc_otg_module_params.dev_tx_fifo_size[6], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_7, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_8, ++ dwc_otg_module_params.dev_tx_fifo_size[7], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_8, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_9, ++ dwc_otg_module_params.dev_tx_fifo_size[8], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_9, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_10, ++ dwc_otg_module_params.dev_tx_fifo_size[9], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_10, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_11, ++ dwc_otg_module_params.dev_tx_fifo_size[10], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_11, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_12, ++ dwc_otg_module_params.dev_tx_fifo_size[11], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_12, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_13, ++ dwc_otg_module_params.dev_tx_fifo_size[12], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_13, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_14, ++ dwc_otg_module_params.dev_tx_fifo_size[13], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_14, "Number of words in the Tx FIFO 4-768"); ++module_param_named(dev_tx_fifo_size_15, ++ dwc_otg_module_params.dev_tx_fifo_size[14], int, 0444); ++MODULE_PARM_DESC(dev_tx_fifo_size_15, "Number of words in the Tx FIFO 4-768"); ++ ++module_param_named(thr_ctl, dwc_otg_module_params.thr_ctl, int, 0444); ++MODULE_PARM_DESC(thr_ctl, ++ "Thresholding enable flag bit 0 - non ISO Tx thr., 1 - ISO Tx thr., 2 - Rx thr.- bit 0=disabled 1=enabled"); ++module_param_named(tx_thr_length, dwc_otg_module_params.tx_thr_length, int, ++ 0444); ++MODULE_PARM_DESC(tx_thr_length, "Tx Threshold length in 32 bit DWORDs"); ++module_param_named(rx_thr_length, dwc_otg_module_params.rx_thr_length, int, ++ 0444); ++MODULE_PARM_DESC(rx_thr_length, "Rx Threshold length in 32 bit DWORDs"); ++ ++module_param_named(pti_enable, dwc_otg_module_params.pti_enable, int, 0444); ++module_param_named(mpi_enable, dwc_otg_module_params.mpi_enable, int, 0444); ++module_param_named(lpm_enable, dwc_otg_module_params.lpm_enable, int, 0444); ++MODULE_PARM_DESC(lpm_enable, "LPM Enable 0=LPM Disabled 1=LPM Enabled"); ++module_param_named(ic_usb_cap, dwc_otg_module_params.ic_usb_cap, int, 0444); ++MODULE_PARM_DESC(ic_usb_cap, ++ "IC_USB Capability 0=IC_USB Disabled 1=IC_USB Enabled"); ++module_param_named(ahb_thr_ratio, dwc_otg_module_params.ahb_thr_ratio, int, ++ 0444); ++MODULE_PARM_DESC(ahb_thr_ratio, "AHB Threshold Ratio"); ++module_param_named(power_down, dwc_otg_module_params.power_down, int, 0444); ++MODULE_PARM_DESC(power_down, "Power Down Mode"); ++module_param_named(reload_ctl, dwc_otg_module_params.reload_ctl, int, 0444); ++MODULE_PARM_DESC(reload_ctl, "HFIR Reload Control"); ++module_param_named(dev_out_nak, dwc_otg_module_params.dev_out_nak, int, 0444); ++MODULE_PARM_DESC(dev_out_nak, "Enable Device OUT NAK"); ++module_param_named(cont_on_bna, dwc_otg_module_params.cont_on_bna, int, 0444); ++MODULE_PARM_DESC(cont_on_bna, "Enable Enable Continue on BNA"); ++module_param_named(ahb_single, dwc_otg_module_params.ahb_single, int, 0444); ++MODULE_PARM_DESC(ahb_single, "Enable AHB Single Support"); ++module_param_named(adp_enable, dwc_otg_module_params.adp_enable, int, 0444); ++MODULE_PARM_DESC(adp_enable, "ADP Enable 0=ADP Disabled 1=ADP Enabled"); ++module_param_named(otg_ver, dwc_otg_module_params.otg_ver, int, 0444); ++MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0"); ++module_param(microframe_schedule, bool, 0444); ++MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler"); ++ ++module_param(fiq_fix_enable, bool, 0444); ++MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix"); ++module_param(nak_holdoff_enable, bool, 0444); ++MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff"); ++module_param(fiq_split_enable, bool, 0444); ++MODULE_PARM_DESC(fiq_split_enable, "Enable the FIQ fix on split transactions"); ++ ++/** @page "Module Parameters" ++ * ++ * The following parameters may be specified when starting the module. ++ * These parameters define how the DWC_otg controller should be ++ * configured. Parameter values are passed to the CIL initialization ++ * function dwc_otg_cil_init ++ * ++ * Example: modprobe dwc_otg speed=1 otg_cap=1 ++ * ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++*/ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_driver.h linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_driver.h +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_driver.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_driver.h 2014-03-13 12:46:39.516097989 +0100 +@@ -0,0 +1,86 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_driver.h $ ++ * $Revision: #19 $ ++ * $Date: 2010/11/15 $ ++ * $Change: 1627671 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#ifndef __DWC_OTG_DRIVER_H__ ++#define __DWC_OTG_DRIVER_H__ ++ ++/** @file ++ * This file contains the interface to the Linux driver. ++ */ ++#include "dwc_otg_os_dep.h" ++#include "dwc_otg_core_if.h" ++ ++/* Type declarations */ ++struct dwc_otg_pcd; ++struct dwc_otg_hcd; ++ ++/** ++ * This structure is a wrapper that encapsulates the driver components used to ++ * manage a single DWC_otg controller. ++ */ ++typedef struct dwc_otg_device { ++ /** Structure containing OS-dependent stuff. KEEP THIS STRUCT AT THE ++ * VERY BEGINNING OF THE DEVICE STRUCT. OSes such as FreeBSD and NetBSD ++ * require this. */ ++ struct os_dependent os_dep; ++ ++ /** Pointer to the core interface structure. */ ++ dwc_otg_core_if_t *core_if; ++ ++ /** Pointer to the PCD structure. */ ++ struct dwc_otg_pcd *pcd; ++ ++ /** Pointer to the HCD structure. */ ++ struct dwc_otg_hcd *hcd; ++ ++ /** Flag to indicate whether the common IRQ handler is installed. */ ++ uint8_t common_irq_installed; ++ ++} dwc_otg_device_t; ++ ++/*We must clear S3C24XX_EINTPEND external interrupt register ++ * because after clearing in this register trigerred IRQ from ++ * H/W core in kernel interrupt can be occured again before OTG ++ * handlers clear all IRQ sources of Core registers because of ++ * timing latencies and Low Level IRQ Type. ++ */ ++#ifdef CONFIG_MACH_IPMATE ++#define S3C2410X_CLEAR_EINTPEND() \ ++do { \ ++ __raw_writel(1UL << 11,S3C24XX_EINTPEND); \ ++} while (0) ++#else ++#define S3C2410X_CLEAR_EINTPEND() do { } while (0) ++#endif ++ ++#endif +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd.c linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd.c +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd.c 2014-03-13 12:46:39.516097989 +0100 +@@ -0,0 +1,3685 @@ ++ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.c $ ++ * $Revision: #104 $ ++ * $Date: 2011/10/24 $ ++ * $Change: 1871159 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++ ++/** @file ++ * This file implements HCD Core. All code in this file is portable and doesn't ++ * use any OS specific functions. ++ * Interface provided by HCD Core is defined in ++ * header file. ++ */ ++ ++#include ++#include ++ ++#include "dwc_otg_hcd.h" ++#include "dwc_otg_regs.h" ++#include "dwc_otg_mphi_fix.h" ++ ++extern bool microframe_schedule, nak_holdoff_enable; ++ ++//#define DEBUG_HOST_CHANNELS ++#ifdef DEBUG_HOST_CHANNELS ++static int last_sel_trans_num_per_scheduled = 0; ++static int last_sel_trans_num_nonper_scheduled = 0; ++static int last_sel_trans_num_avail_hc_at_start = 0; ++static int last_sel_trans_num_avail_hc_at_end = 0; ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++extern int g_next_sched_frame, g_np_count, g_np_sent; ++ ++extern haint_data_t haint_saved; ++extern hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS]; ++extern hcint_data_t hcint_saved[MAX_EPS_CHANNELS]; ++extern gintsts_data_t ginsts_saved; ++ ++dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void) ++{ ++ return DWC_ALLOC(sizeof(dwc_otg_hcd_t)); ++} ++ ++/** ++ * Connection timeout function. An OTG host is required to display a ++ * message if the device does not connect within 10 seconds. ++ */ ++void dwc_otg_hcd_connect_timeout(void *ptr) ++{ ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, ptr); ++ DWC_PRINTF("Connect Timeout\n"); ++ __DWC_ERROR("Device Not Connected/Responding\n"); ++} ++ ++#if defined(DEBUG) ++static void dump_channel_info(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ if (qh->channel != NULL) { ++ dwc_hc_t *hc = qh->channel; ++ dwc_list_link_t *item; ++ dwc_otg_qh_t *qh_item; ++ int num_channels = hcd->core_if->core_params->host_channels; ++ int i; ++ ++ dwc_otg_hc_regs_t *hc_regs; ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ hctsiz_data_t hctsiz; ++ uint32_t hcdma; ++ ++ hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num]; ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt); ++ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz); ++ hcdma = DWC_READ_REG32(&hc_regs->hcdma); ++ ++ DWC_PRINTF(" Assigned to channel %p:\n", hc); ++ DWC_PRINTF(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, ++ hcsplt.d32); ++ DWC_PRINTF(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, ++ hcdma); ++ DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", ++ hc->dev_addr, hc->ep_num, hc->ep_is_in); ++ DWC_PRINTF(" ep_type: %d\n", hc->ep_type); ++ DWC_PRINTF(" max_packet: %d\n", hc->max_packet); ++ DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start); ++ DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started); ++ DWC_PRINTF(" halt_status: %d\n", hc->halt_status); ++ DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff); ++ DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len); ++ DWC_PRINTF(" qh: %p\n", hc->qh); ++ DWC_PRINTF(" NP inactive sched:\n"); ++ DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_inactive) { ++ qh_item = ++ DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry); ++ DWC_PRINTF(" %p\n", qh_item); ++ } ++ DWC_PRINTF(" NP active sched:\n"); ++ DWC_LIST_FOREACH(item, &hcd->non_periodic_sched_active) { ++ qh_item = ++ DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry); ++ DWC_PRINTF(" %p\n", qh_item); ++ } ++ DWC_PRINTF(" Channels: \n"); ++ for (i = 0; i < num_channels; i++) { ++ dwc_hc_t *hc = hcd->hc_ptr_array[i]; ++ DWC_PRINTF(" %2d: %p\n", i, hc); ++ } ++ } ++} ++#else ++#define dump_channel_info(hcd, qh) ++#endif /* DEBUG */ ++ ++/** ++ * Work queue function for starting the HCD when A-Cable is connected. ++ * The hcd_start() must be called in a process context. ++ */ ++static void hcd_start_func(void *_vp) ++{ ++ dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) _vp; ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, hcd); ++ if (hcd) { ++ hcd->fops->start(hcd); ++ } ++} ++ ++static void del_xfer_timers(dwc_otg_hcd_t * hcd) ++{ ++#ifdef DEBUG ++ int i; ++ int num_channels = hcd->core_if->core_params->host_channels; ++ for (i = 0; i < num_channels; i++) { ++ DWC_TIMER_CANCEL(hcd->core_if->hc_xfer_timer[i]); ++ } ++#endif ++} ++ ++static void del_timers(dwc_otg_hcd_t * hcd) ++{ ++ del_xfer_timers(hcd); ++ DWC_TIMER_CANCEL(hcd->conn_timer); ++} ++ ++/** ++ * Processes all the URBs in a single list of QHs. Completes them with ++ * -ESHUTDOWN and frees the QTD. ++ */ ++static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list) ++{ ++ dwc_list_link_t *qh_item, *qh_tmp; ++ dwc_otg_qh_t *qh; ++ dwc_otg_qtd_t *qtd, *qtd_tmp; ++ ++ DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) { ++ qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry); ++ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, ++ &qh->qtd_list, qtd_list_entry) { ++ qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); ++ if (qtd->urb != NULL) { ++ hcd->fops->complete(hcd, qtd->urb->priv, ++ qtd->urb, -DWC_E_SHUTDOWN); ++ dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); ++ } ++ ++ } ++ if(qh->channel) { ++ /* Using hcchar.chen == 1 is not a reliable test. ++ * It is possible that the channel has already halted ++ * but not yet been through the IRQ handler. ++ */ ++ dwc_otg_hc_halt(hcd->core_if, qh->channel, ++ DWC_OTG_HC_XFER_URB_DEQUEUE); ++ if(microframe_schedule) ++ hcd->available_host_channels++; ++ qh->channel = NULL; ++ } ++ dwc_otg_hcd_qh_remove(hcd, qh); ++ } ++} ++ ++/** ++ * Responds with an error status of ESHUTDOWN to all URBs in the non-periodic ++ * and periodic schedules. The QTD associated with each URB is removed from ++ * the schedule and freed. This function may be called when a disconnect is ++ * detected or when the HCD is being stopped. ++ */ ++static void kill_all_urbs(dwc_otg_hcd_t * hcd) ++{ ++ kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive); ++ kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active); ++ kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive); ++ kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready); ++ kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned); ++ kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued); ++} ++ ++/** ++ * Start the connection timer. An OTG host is required to display a ++ * message if the device does not connect within 10 seconds. The ++ * timer is deleted if a port connect interrupt occurs before the ++ * timer expires. ++ */ ++static void dwc_otg_hcd_start_connect_timer(dwc_otg_hcd_t * hcd) ++{ ++ DWC_TIMER_SCHEDULE(hcd->conn_timer, 10000 /* 10 secs */ ); ++} ++ ++/** ++ * HCD Callback function for disconnect of the HCD. ++ * ++ * @param p void pointer to the struct usb_hcd ++ */ ++static int32_t dwc_otg_hcd_session_start_cb(void *p) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd; ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p); ++ dwc_otg_hcd = p; ++ dwc_otg_hcd_start_connect_timer(dwc_otg_hcd); ++ return 1; ++} ++ ++/** ++ * HCD Callback function for starting the HCD when A-Cable is ++ * connected. ++ * ++ * @param p void pointer to the struct usb_hcd ++ */ ++static int32_t dwc_otg_hcd_start_cb(void *p) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = p; ++ dwc_otg_core_if_t *core_if; ++ hprt0_data_t hprt0; ++ ++ core_if = dwc_otg_hcd->core_if; ++ ++ if (core_if->op_state == B_HOST) { ++ /* ++ * Reset the port. During a HNP mode switch the reset ++ * needs to occur within 1ms and have a duration of at ++ * least 50ms. ++ */ ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtrst = 1; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ } ++ DWC_WORKQ_SCHEDULE_DELAYED(core_if->wq_otg, ++ hcd_start_func, dwc_otg_hcd, 50, ++ "start hcd"); ++ ++ return 1; ++} ++ ++/** ++ * HCD Callback function for disconnect of the HCD. ++ * ++ * @param p void pointer to the struct usb_hcd ++ */ ++static int32_t dwc_otg_hcd_disconnect_cb(void *p) ++{ ++ gintsts_data_t intr; ++ dwc_otg_hcd_t *dwc_otg_hcd = p; ++ ++ /* ++ * Set status flags for the hub driver. ++ */ ++ dwc_otg_hcd->flags.b.port_connect_status_change = 1; ++ dwc_otg_hcd->flags.b.port_connect_status = 0; ++ if(fiq_fix_enable) ++ local_fiq_disable(); ++ /* ++ * Shutdown any transfers in process by clearing the Tx FIFO Empty ++ * interrupt mask and status bits and disabling subsequent host ++ * channel interrupts. ++ */ ++ intr.d32 = 0; ++ intr.b.nptxfempty = 1; ++ intr.b.ptxfempty = 1; ++ intr.b.hcintr = 1; ++ DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk, ++ intr.d32, 0); ++ DWC_MODIFY_REG32(&dwc_otg_hcd->core_if->core_global_regs->gintsts, ++ intr.d32, 0); ++ ++ del_timers(dwc_otg_hcd); ++ ++ /* ++ * Turn off the vbus power only if the core has transitioned to device ++ * mode. If still in host mode, need to keep power on to detect a ++ * reconnection. ++ */ ++ if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) { ++ if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) { ++ hprt0_data_t hprt0 = {.d32 = 0 }; ++ DWC_PRINTF("Disconnect: PortPower off\n"); ++ hprt0.b.prtpwr = 0; ++ DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, ++ hprt0.d32); ++ } ++ ++ dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if); ++ } ++ ++ /* Respond with an error status to all URBs in the schedule. */ ++ kill_all_urbs(dwc_otg_hcd); ++ ++ if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) { ++ /* Clean up any host channels that were in use. */ ++ int num_channels; ++ int i; ++ dwc_hc_t *channel; ++ dwc_otg_hc_regs_t *hc_regs; ++ hcchar_data_t hcchar; ++ ++ num_channels = dwc_otg_hcd->core_if->core_params->host_channels; ++ ++ if (!dwc_otg_hcd->core_if->dma_enable) { ++ /* Flush out any channel requests in slave mode. */ ++ for (i = 0; i < num_channels; i++) { ++ channel = dwc_otg_hcd->hc_ptr_array[i]; ++ if (DWC_CIRCLEQ_EMPTY_ENTRY ++ (channel, hc_list_entry)) { ++ hc_regs = ++ dwc_otg_hcd->core_if-> ++ host_if->hc_regs[i]; ++ hcchar.d32 = ++ DWC_READ_REG32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ hcchar.b.chen = 0; ++ hcchar.b.chdis = 1; ++ hcchar.b.epdir = 0; ++ DWC_WRITE_REG32 ++ (&hc_regs->hcchar, ++ hcchar.d32); ++ } ++ } ++ } ++ } ++ ++ for (i = 0; i < num_channels; i++) { ++ channel = dwc_otg_hcd->hc_ptr_array[i]; ++ if (DWC_CIRCLEQ_EMPTY_ENTRY(channel, hc_list_entry)) { ++ hc_regs = ++ dwc_otg_hcd->core_if->host_if->hc_regs[i]; ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ /* Halt the channel. */ ++ hcchar.b.chdis = 1; ++ DWC_WRITE_REG32(&hc_regs->hcchar, ++ hcchar.d32); ++ } ++ ++ dwc_otg_hc_cleanup(dwc_otg_hcd->core_if, ++ channel); ++ DWC_CIRCLEQ_INSERT_TAIL ++ (&dwc_otg_hcd->free_hc_list, channel, ++ hc_list_entry); ++ /* ++ * Added for Descriptor DMA to prevent channel double cleanup ++ * in release_channel_ddma(). Which called from ep_disable ++ * when device disconnect. ++ */ ++ channel->qh = NULL; ++ } ++ } ++ if(fiq_split_enable) { ++ for(i=0; i < 128; i++) { ++ dwc_otg_hcd->hub_port[i] = 0; ++ } ++ haint_saved.d32 = 0; ++ for(i=0; i < MAX_EPS_CHANNELS; i++) { ++ hcint_saved[i].d32 = 0; ++ hcintmsk_saved[i].d32 = 0; ++ } ++ } ++ ++ } ++ ++ if(fiq_fix_enable) ++ local_fiq_enable(); ++ ++ if (dwc_otg_hcd->fops->disconnect) { ++ dwc_otg_hcd->fops->disconnect(dwc_otg_hcd); ++ } ++ ++ return 1; ++} ++ ++/** ++ * HCD Callback function for stopping the HCD. ++ * ++ * @param p void pointer to the struct usb_hcd ++ */ ++static int32_t dwc_otg_hcd_stop_cb(void *p) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = p; ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, p); ++ dwc_otg_hcd_stop(dwc_otg_hcd); ++ return 1; ++} ++ ++#ifdef CONFIG_USB_DWC_OTG_LPM ++/** ++ * HCD Callback function for sleep of HCD. ++ * ++ * @param p void pointer to the struct usb_hcd ++ */ ++static int dwc_otg_hcd_sleep_cb(void *p) ++{ ++ dwc_otg_hcd_t *hcd = p; ++ ++ dwc_otg_hcd_free_hc_from_lpm(hcd); ++ ++ return 0; ++} ++#endif ++ ++ ++/** ++ * HCD Callback function for Remote Wakeup. ++ * ++ * @param p void pointer to the struct usb_hcd ++ */ ++static int dwc_otg_hcd_rem_wakeup_cb(void *p) ++{ ++ dwc_otg_hcd_t *hcd = p; ++ ++ if (hcd->core_if->lx_state == DWC_OTG_L2) { ++ hcd->flags.b.port_suspend_change = 1; ++ } ++#ifdef CONFIG_USB_DWC_OTG_LPM ++ else { ++ hcd->flags.b.port_l1_change = 1; ++ } ++#endif ++ return 0; ++} ++ ++/** ++ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are ++ * stopped. ++ */ ++void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd) ++{ ++ hprt0_data_t hprt0 = {.d32 = 0 }; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n"); ++ ++ /* ++ * The root hub should be disconnected before this function is called. ++ * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue) ++ * and the QH lists (via ..._hcd_endpoint_disable). ++ */ ++ ++ /* Turn off all host-specific interrupts. */ ++ dwc_otg_disable_host_interrupts(hcd->core_if); ++ ++ /* Turn off the vbus power */ ++ DWC_PRINTF("PortPower off\n"); ++ hprt0.b.prtpwr = 0; ++ DWC_WRITE_REG32(hcd->core_if->host_if->hprt0, hprt0.d32); ++ dwc_mdelay(1); ++} ++ ++int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * hcd, ++ dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle, ++ int atomic_alloc) ++{ ++ int retval = 0; ++ uint8_t needs_scheduling = 0; ++ dwc_otg_transaction_type_e tr_type; ++ dwc_otg_qtd_t *qtd; ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ hprt0_data_t hprt0 = { .d32 = 0 }; ++ ++#ifdef DEBUG /* integrity checks (Broadcom) */ ++ if (NULL == hcd->core_if) { ++ DWC_ERROR("**** DWC OTG HCD URB Enqueue - HCD has NULL core_if\n"); ++ /* No longer connected. */ ++ return -DWC_E_INVALID; ++ } ++#endif ++ if (!hcd->flags.b.port_connect_status) { ++ /* No longer connected. */ ++ DWC_ERROR("Not connected\n"); ++ return -DWC_E_NO_DEVICE; ++ } ++ ++ /* Some core configurations cannot support LS traffic on a FS root port */ ++ if ((hcd->fops->speed(hcd, dwc_otg_urb->priv) == USB_SPEED_LOW) && ++ (hcd->core_if->hwcfg2.b.fs_phy_type == 1) && ++ (hcd->core_if->hwcfg2.b.hs_phy_type == 1)) { ++ hprt0.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0); ++ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_FULL_SPEED) { ++ return -DWC_E_NO_DEVICE; ++ } ++ } ++ ++ qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc); ++ if (qtd == NULL) { ++ DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n"); ++ return -DWC_E_NO_MEMORY; ++ } ++#ifdef DEBUG /* integrity checks (Broadcom) */ ++ if (qtd->urb == NULL) { ++ DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD with no URBs\n"); ++ return -DWC_E_NO_MEMORY; ++ } ++ if (qtd->urb->priv == NULL) { ++ DWC_ERROR("**** DWC OTG HCD URB Enqueue created QTD URB with no URB handle\n"); ++ return -DWC_E_NO_MEMORY; ++ } ++#endif ++ intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk); ++ if(!intr_mask.b.sofintr) needs_scheduling = 1; ++ if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) ++ /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */ ++ needs_scheduling = 0; ++ ++ retval = dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc); ++ // creates a new queue in ep_handle if it doesn't exist already ++ if (retval < 0) { ++ DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. " ++ "Error status %d\n", retval); ++ dwc_otg_hcd_qtd_free(qtd); ++ return retval; ++ } ++ ++ if(needs_scheduling) { ++ tr_type = dwc_otg_hcd_select_transactions(hcd); ++ if (tr_type != DWC_OTG_TRANSACTION_NONE) { ++ dwc_otg_hcd_queue_transactions(hcd, tr_type); ++ } ++ } ++ return retval; ++} ++ ++int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * hcd, ++ dwc_otg_hcd_urb_t * dwc_otg_urb) ++{ ++ dwc_otg_qh_t *qh; ++ dwc_otg_qtd_t *urb_qtd; ++ BUG_ON(!hcd); ++ BUG_ON(!dwc_otg_urb); ++ ++#ifdef DEBUG /* integrity checks (Broadcom) */ ++ ++ if (hcd == NULL) { ++ DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL HCD\n"); ++ return -DWC_E_INVALID; ++ } ++ if (dwc_otg_urb == NULL) { ++ DWC_ERROR("**** DWC OTG HCD URB Dequeue has NULL URB\n"); ++ return -DWC_E_INVALID; ++ } ++ if (dwc_otg_urb->qtd == NULL) { ++ DWC_ERROR("**** DWC OTG HCD URB Dequeue with NULL QTD\n"); ++ return -DWC_E_INVALID; ++ } ++ urb_qtd = dwc_otg_urb->qtd; ++ BUG_ON(!urb_qtd); ++ if (urb_qtd->qh == NULL) { ++ DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n"); ++ return -DWC_E_INVALID; ++ } ++#else ++ urb_qtd = dwc_otg_urb->qtd; ++ BUG_ON(!urb_qtd); ++#endif ++ qh = urb_qtd->qh; ++ BUG_ON(!qh); ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ if (urb_qtd->in_process) { ++ dump_channel_info(hcd, qh); ++ } ++ } ++#ifdef DEBUG /* integrity checks (Broadcom) */ ++ if (hcd->core_if == NULL) { ++ DWC_ERROR("**** DWC OTG HCD URB Dequeue HCD has NULL core_if\n"); ++ return -DWC_E_INVALID; ++ } ++#endif ++ if (urb_qtd->in_process && qh->channel) { ++ /* The QTD is in process (it has been assigned to a channel). */ ++ if (hcd->flags.b.port_connect_status) { ++ /* ++ * If still connected (i.e. in host mode), halt the ++ * channel so it can be used for other transfers. If ++ * no longer connected, the host registers can't be ++ * written to halt the channel since the core is in ++ * device mode. ++ */ ++ dwc_otg_hc_halt(hcd->core_if, qh->channel, ++ DWC_OTG_HC_XFER_URB_DEQUEUE); ++ ++ dwc_otg_hcd_release_port(hcd, qh); ++ } ++ } ++ ++ /* ++ * Free the QTD and clean up the associated QH. Leave the QH in the ++ * schedule if it has any remaining QTDs. ++ */ ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue - " ++ "delete %sQueue handler\n", ++ hcd->core_if->dma_desc_enable?"DMA ":""); ++ if (!hcd->core_if->dma_desc_enable) { ++ uint8_t b = urb_qtd->in_process; ++ dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh); ++ if (b) { ++ dwc_otg_hcd_qh_deactivate(hcd, qh, 0); ++ qh->channel = NULL; ++ } else if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { ++ dwc_otg_hcd_qh_remove(hcd, qh); ++ } ++ } else { ++ dwc_otg_hcd_qtd_remove_and_free(hcd, urb_qtd, qh); ++ } ++ return 0; ++} ++ ++int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle, ++ int retry) ++{ ++ dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle; ++ int retval = 0; ++ dwc_irqflags_t flags; ++ ++ if (retry < 0) { ++ retval = -DWC_E_INVALID; ++ goto done; ++ } ++ ++ if (!qh) { ++ retval = -DWC_E_INVALID; ++ goto done; ++ } ++ ++ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); ++ ++ while (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list) && retry) { ++ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); ++ retry--; ++ dwc_msleep(5); ++ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); ++ } ++ ++ dwc_otg_hcd_qh_remove(hcd, qh); ++ ++ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); ++ /* ++ * Split dwc_otg_hcd_qh_remove_and_free() into qh_remove ++ * and qh_free to prevent stack dump on DWC_DMA_FREE() with ++ * irq_disabled (spinlock_irqsave) in dwc_otg_hcd_desc_list_free() ++ * and dwc_otg_hcd_frame_list_alloc(). ++ */ ++ dwc_otg_hcd_qh_free(hcd, qh); ++ ++done: ++ return retval; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) ++int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle) ++{ ++ int retval = 0; ++ dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle; ++ if (!qh) ++ return -DWC_E_INVALID; ++ ++ qh->data_toggle = DWC_OTG_HC_PID_DATA0; ++ return retval; ++} ++#endif ++ ++/** ++ * HCD Callback structure for handling mode switching. ++ */ ++static dwc_otg_cil_callbacks_t hcd_cil_callbacks = { ++ .start = dwc_otg_hcd_start_cb, ++ .stop = dwc_otg_hcd_stop_cb, ++ .disconnect = dwc_otg_hcd_disconnect_cb, ++ .session_start = dwc_otg_hcd_session_start_cb, ++ .resume_wakeup = dwc_otg_hcd_rem_wakeup_cb, ++#ifdef CONFIG_USB_DWC_OTG_LPM ++ .sleep = dwc_otg_hcd_sleep_cb, ++#endif ++ .p = 0, ++}; ++ ++/** ++ * Reset tasklet function ++ */ ++static void reset_tasklet_func(void *data) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *) data; ++ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; ++ hprt0_data_t hprt0; ++ ++ DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n"); ++ ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtrst = 1; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ dwc_mdelay(60); ++ ++ hprt0.b.prtrst = 0; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ dwc_otg_hcd->flags.b.port_reset_change = 1; ++} ++ ++static void completion_tasklet_func(void *ptr) ++{ ++ dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) ptr; ++ struct urb *urb; ++ urb_tq_entry_t *item; ++ dwc_irqflags_t flags; ++ ++ /* This could just be spin_lock_irq */ ++ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); ++ while (!DWC_TAILQ_EMPTY(&hcd->completed_urb_list)) { ++ item = DWC_TAILQ_FIRST(&hcd->completed_urb_list); ++ urb = item->urb; ++ DWC_TAILQ_REMOVE(&hcd->completed_urb_list, item, ++ urb_tq_entries); ++ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); ++ DWC_FREE(item); ++ ++ usb_hcd_giveback_urb(hcd->priv, urb, urb->status); ++ ++ fiq_print(FIQDBG_PORTHUB, "COMPLETE"); ++ ++ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); ++ } ++ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); ++ return; ++} ++ ++static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list) ++{ ++ dwc_list_link_t *item; ++ dwc_otg_qh_t *qh; ++ dwc_irqflags_t flags; ++ ++ if (!qh_list->next) { ++ /* The list hasn't been initialized yet. */ ++ return; ++ } ++ /* ++ * Hold spinlock here. Not needed in that case if bellow ++ * function is being called from ISR ++ */ ++ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); ++ /* Ensure there are no QTDs or URBs left. */ ++ kill_urbs_in_qh_list(hcd, qh_list); ++ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); ++ ++ DWC_LIST_FOREACH(item, qh_list) { ++ qh = DWC_LIST_ENTRY(item, dwc_otg_qh_t, qh_list_entry); ++ dwc_otg_hcd_qh_remove_and_free(hcd, qh); ++ } ++} ++ ++/** ++ * Exit from Hibernation if Host did not detect SRP from connected SRP capable ++ * Device during SRP time by host power up. ++ */ ++void dwc_otg_hcd_power_up(void *ptr) ++{ ++ gpwrdn_data_t gpwrdn = {.d32 = 0 }; ++ dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr; ++ ++ DWC_PRINTF("%s called\n", __FUNCTION__); ++ ++ if (!core_if->hibernation_suspend) { ++ DWC_PRINTF("Already exited from Hibernation\n"); ++ return; ++ } ++ ++ /* Switch on the voltage to the core */ ++ gpwrdn.b.pwrdnswtch = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0); ++ dwc_udelay(10); ++ ++ /* Reset the core */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.pwrdnrstn = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0); ++ dwc_udelay(10); ++ ++ /* Disable power clamps */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.pwrdnclmp = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0); ++ ++ /* Remove reset the core signal */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.pwrdnrstn = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32); ++ dwc_udelay(10); ++ ++ /* Disable PMU interrupt */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.pmuintsel = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0); ++ ++ core_if->hibernation_suspend = 0; ++ ++ /* Disable PMU */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.pmuactv = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0); ++ dwc_udelay(10); ++ ++ /* Enable VBUS */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.dis_vbus = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0); ++ ++ core_if->op_state = A_HOST; ++ dwc_otg_core_init(core_if); ++ dwc_otg_enable_global_interrupts(core_if); ++ cil_hcd_start(core_if); ++} ++ ++/** ++ * Frees secondary storage associated with the dwc_otg_hcd structure contained ++ * in the struct usb_hcd field. ++ */ ++static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd) ++{ ++ int i; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n"); ++ ++ del_timers(dwc_otg_hcd); ++ ++ /* Free memory for QH/QTD lists */ ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned); ++ qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued); ++ ++ /* Free memory for the host channels. */ ++ for (i = 0; i < MAX_EPS_CHANNELS; i++) { ++ dwc_hc_t *hc = dwc_otg_hcd->hc_ptr_array[i]; ++ ++#ifdef DEBUG ++ if (dwc_otg_hcd->core_if->hc_xfer_timer[i]) { ++ DWC_TIMER_FREE(dwc_otg_hcd->core_if->hc_xfer_timer[i]); ++ } ++#endif ++ if (hc != NULL) { ++ DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n", ++ i, hc); ++ DWC_FREE(hc); ++ } ++ } ++ ++ if (dwc_otg_hcd->core_if->dma_enable) { ++ if (dwc_otg_hcd->status_buf_dma) { ++ DWC_DMA_FREE(DWC_OTG_HCD_STATUS_BUF_SIZE, ++ dwc_otg_hcd->status_buf, ++ dwc_otg_hcd->status_buf_dma); ++ } ++ } else if (dwc_otg_hcd->status_buf != NULL) { ++ DWC_FREE(dwc_otg_hcd->status_buf); ++ } ++ DWC_SPINLOCK_FREE(dwc_otg_hcd->channel_lock); ++ DWC_SPINLOCK_FREE(dwc_otg_hcd->lock); ++ /* Set core_if's lock pointer to NULL */ ++ dwc_otg_hcd->core_if->lock = NULL; ++ ++ DWC_TIMER_FREE(dwc_otg_hcd->conn_timer); ++ DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet); ++ DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet); ++ ++#ifdef DWC_DEV_SRPCAP ++ if (dwc_otg_hcd->core_if->power_down == 2 && ++ dwc_otg_hcd->core_if->pwron_timer) { ++ DWC_TIMER_FREE(dwc_otg_hcd->core_if->pwron_timer); ++ } ++#endif ++ DWC_FREE(dwc_otg_hcd); ++} ++ ++int init_hcd_usecs(dwc_otg_hcd_t *_hcd); ++ ++int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) ++{ ++ int retval = 0; ++ int num_channels; ++ int i; ++ dwc_hc_t *channel; ++ ++ hcd->lock = DWC_SPINLOCK_ALLOC(); ++ hcd->channel_lock = DWC_SPINLOCK_ALLOC(); ++ DWC_DEBUGPL(DBG_HCDV, "init of HCD %p given core_if %p\n", ++ hcd, core_if); ++ if (!hcd->lock) { ++ DWC_ERROR("Could not allocate lock for pcd"); ++ DWC_FREE(hcd); ++ retval = -DWC_E_NO_MEMORY; ++ goto out; ++ } ++ hcd->core_if = core_if; ++ ++ /* Register the HCD CIL Callbacks */ ++ dwc_otg_cil_register_hcd_callbacks(hcd->core_if, ++ &hcd_cil_callbacks, hcd); ++ ++ /* Initialize the non-periodic schedule. */ ++ DWC_LIST_INIT(&hcd->non_periodic_sched_inactive); ++ DWC_LIST_INIT(&hcd->non_periodic_sched_active); ++ ++ /* Initialize the periodic schedule. */ ++ DWC_LIST_INIT(&hcd->periodic_sched_inactive); ++ DWC_LIST_INIT(&hcd->periodic_sched_ready); ++ DWC_LIST_INIT(&hcd->periodic_sched_assigned); ++ DWC_LIST_INIT(&hcd->periodic_sched_queued); ++ DWC_TAILQ_INIT(&hcd->completed_urb_list); ++ /* ++ * Create a host channel descriptor for each host channel implemented ++ * in the controller. Initialize the channel descriptor array. ++ */ ++ DWC_CIRCLEQ_INIT(&hcd->free_hc_list); ++ num_channels = hcd->core_if->core_params->host_channels; ++ DWC_MEMSET(hcd->hc_ptr_array, 0, sizeof(hcd->hc_ptr_array)); ++ for (i = 0; i < num_channels; i++) { ++ channel = DWC_ALLOC(sizeof(dwc_hc_t)); ++ if (channel == NULL) { ++ retval = -DWC_E_NO_MEMORY; ++ DWC_ERROR("%s: host channel allocation failed\n", ++ __func__); ++ dwc_otg_hcd_free(hcd); ++ goto out; ++ } ++ channel->hc_num = i; ++ hcd->hc_ptr_array[i] = channel; ++#ifdef DEBUG ++ hcd->core_if->hc_xfer_timer[i] = ++ DWC_TIMER_ALLOC("hc timer", hc_xfer_timeout, ++ &hcd->core_if->hc_xfer_info[i]); ++#endif ++ DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i, ++ channel); ++ } ++ ++ /* Initialize the Connection timeout timer. */ ++ hcd->conn_timer = DWC_TIMER_ALLOC("Connection timer", ++ dwc_otg_hcd_connect_timeout, 0); ++ ++ printk(KERN_DEBUG "dwc_otg: Microframe scheduler %s\n", microframe_schedule ? "enabled":"disabled"); ++ if (microframe_schedule) ++ init_hcd_usecs(hcd); ++ ++ /* Initialize reset tasklet. */ ++ hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd); ++ ++ hcd->completion_tasklet = DWC_TASK_ALLOC("completion_tasklet", ++ completion_tasklet_func, hcd); ++#ifdef DWC_DEV_SRPCAP ++ if (hcd->core_if->power_down == 2) { ++ /* Initialize Power on timer for Host power up in case hibernation */ ++ hcd->core_if->pwron_timer = DWC_TIMER_ALLOC("PWRON TIMER", ++ dwc_otg_hcd_power_up, core_if); ++ } ++#endif ++ ++ /* ++ * Allocate space for storing data on status transactions. Normally no ++ * data is sent, but this space acts as a bit bucket. This must be ++ * done after usb_add_hcd since that function allocates the DMA buffer ++ * pool. ++ */ ++ if (hcd->core_if->dma_enable) { ++ hcd->status_buf = ++ DWC_DMA_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE, ++ &hcd->status_buf_dma); ++ } else { ++ hcd->status_buf = DWC_ALLOC(DWC_OTG_HCD_STATUS_BUF_SIZE); ++ } ++ if (!hcd->status_buf) { ++ retval = -DWC_E_NO_MEMORY; ++ DWC_ERROR("%s: status_buf allocation failed\n", __func__); ++ dwc_otg_hcd_free(hcd); ++ goto out; ++ } ++ ++ hcd->otg_port = 1; ++ hcd->frame_list = NULL; ++ hcd->frame_list_dma = 0; ++ hcd->periodic_qh_count = 0; ++ ++ DWC_MEMSET(hcd->hub_port, 0, sizeof(hcd->hub_port)); ++#ifdef FIQ_DEBUG ++ DWC_MEMSET(hcd->hub_port_alloc, -1, sizeof(hcd->hub_port_alloc)); ++#endif ++ ++out: ++ return retval; ++} ++ ++void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd) ++{ ++ /* Turn off all host-specific interrupts. */ ++ dwc_otg_disable_host_interrupts(hcd->core_if); ++ ++ dwc_otg_hcd_free(hcd); ++} ++ ++/** ++ * Initializes dynamic portions of the DWC_otg HCD state. ++ */ ++static void dwc_otg_hcd_reinit(dwc_otg_hcd_t * hcd) ++{ ++ int num_channels; ++ int i; ++ dwc_hc_t *channel; ++ dwc_hc_t *channel_tmp; ++ ++ hcd->flags.d32 = 0; ++ ++ hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active; ++ if (!microframe_schedule) { ++ hcd->non_periodic_channels = 0; ++ hcd->periodic_channels = 0; ++ } else { ++ hcd->available_host_channels = hcd->core_if->core_params->host_channels; ++ } ++ /* ++ * Put all channels in the free channel list and clean up channel ++ * states. ++ */ ++ DWC_CIRCLEQ_FOREACH_SAFE(channel, channel_tmp, ++ &hcd->free_hc_list, hc_list_entry) { ++ DWC_CIRCLEQ_REMOVE(&hcd->free_hc_list, channel, hc_list_entry); ++ } ++ ++ num_channels = hcd->core_if->core_params->host_channels; ++ for (i = 0; i < num_channels; i++) { ++ channel = hcd->hc_ptr_array[i]; ++ DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, channel, ++ hc_list_entry); ++ dwc_otg_hc_cleanup(hcd->core_if, channel); ++ } ++ ++ /* Initialize the DWC core for host mode operation. */ ++ dwc_otg_core_host_init(hcd->core_if); ++ ++ /* Set core_if's lock pointer to the hcd->lock */ ++ hcd->core_if->lock = hcd->lock; ++} ++ ++/** ++ * Assigns transactions from a QTD to a free host channel and initializes the ++ * host channel to perform the transactions. The host channel is removed from ++ * the free list. ++ * ++ * @param hcd The HCD state structure. ++ * @param qh Transactions from the first QTD for this QH are selected and ++ * assigned to a free host channel. ++ */ ++static void assign_and_init_hc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ dwc_hc_t *hc; ++ dwc_otg_qtd_t *qtd; ++ dwc_otg_hcd_urb_t *urb; ++ void* ptr = NULL; ++ ++ qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); ++ ++ urb = qtd->urb; ++ ++ DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p) - urb %x, actual_length %d\n", __func__, hcd, qh, (unsigned int)urb, urb->actual_length); ++ ++ if (((urb->actual_length < 0) || (urb->actual_length > urb->length)) && !dwc_otg_hcd_is_pipe_in(&urb->pipe_info)) ++ urb->actual_length = urb->length; ++ ++ ++ hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list); ++ ++ /* Remove the host channel from the free list. */ ++ DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry); ++ ++ qh->channel = hc; ++ ++ qtd->in_process = 1; ++ ++ /* ++ * Use usb_pipedevice to determine device address. This address is ++ * 0 before the SET_ADDRESS command and the correct address afterward. ++ */ ++ hc->dev_addr = dwc_otg_hcd_get_dev_addr(&urb->pipe_info); ++ hc->ep_num = dwc_otg_hcd_get_ep_num(&urb->pipe_info); ++ hc->speed = qh->dev_speed; ++ hc->max_packet = dwc_max_packet(qh->maxp); ++ ++ hc->xfer_started = 0; ++ hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS; ++ hc->error_state = (qtd->error_count > 0); ++ hc->halt_on_queue = 0; ++ hc->halt_pending = 0; ++ hc->requests = 0; ++ ++ /* ++ * The following values may be modified in the transfer type section ++ * below. The xfer_len value may be reduced when the transfer is ++ * started to accommodate the max widths of the XferSize and PktCnt ++ * fields in the HCTSIZn register. ++ */ ++ ++ hc->ep_is_in = (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) != 0); ++ if (hc->ep_is_in) { ++ hc->do_ping = 0; ++ } else { ++ hc->do_ping = qh->ping_state; ++ } ++ ++ hc->data_pid_start = qh->data_toggle; ++ hc->multi_count = 1; ++ ++ if (hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *) urb->dma + urb->actual_length; ++ ++ /* For non-dword aligned case */ ++ if (((unsigned long)hc->xfer_buff & 0x3) ++ && !hcd->core_if->dma_desc_enable) { ++ ptr = (uint8_t *) urb->buf + urb->actual_length; ++ } ++ } else { ++ hc->xfer_buff = (uint8_t *) urb->buf + urb->actual_length; ++ } ++ hc->xfer_len = urb->length - urb->actual_length; ++ hc->xfer_count = 0; ++ ++ /* ++ * Set the split attributes ++ */ ++ hc->do_split = 0; ++ if (qh->do_split) { ++ uint32_t hub_addr, port_addr; ++ hc->do_split = 1; ++ hc->xact_pos = qtd->isoc_split_pos; ++ /* We don't need to do complete splits anymore */ ++ if(fiq_split_enable) ++ hc->complete_split = qtd->complete_split = 0; ++ else ++ hc->complete_split = qtd->complete_split; ++ ++ hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr); ++ hc->hub_addr = (uint8_t) hub_addr; ++ hc->port_addr = (uint8_t) port_addr; ++ } ++ ++ switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) { ++ case UE_CONTROL: ++ hc->ep_type = DWC_OTG_EP_TYPE_CONTROL; ++ switch (qtd->control_phase) { ++ case DWC_OTG_CONTROL_SETUP: ++ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction\n"); ++ hc->do_ping = 0; ++ hc->ep_is_in = 0; ++ hc->data_pid_start = DWC_OTG_HC_PID_SETUP; ++ if (hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *) urb->setup_dma; ++ } else { ++ hc->xfer_buff = (uint8_t *) urb->setup_packet; ++ } ++ hc->xfer_len = 8; ++ ptr = NULL; ++ break; ++ case DWC_OTG_CONTROL_DATA: ++ DWC_DEBUGPL(DBG_HCDV, " Control data transaction\n"); ++ hc->data_pid_start = qtd->data_toggle; ++ break; ++ case DWC_OTG_CONTROL_STATUS: ++ /* ++ * Direction is opposite of data direction or IN if no ++ * data. ++ */ ++ DWC_DEBUGPL(DBG_HCDV, " Control status transaction\n"); ++ if (urb->length == 0) { ++ hc->ep_is_in = 1; ++ } else { ++ hc->ep_is_in = ++ dwc_otg_hcd_is_pipe_out(&urb->pipe_info); ++ } ++ if (hc->ep_is_in) { ++ hc->do_ping = 0; ++ } ++ ++ hc->data_pid_start = DWC_OTG_HC_PID_DATA1; ++ ++ hc->xfer_len = 0; ++ if (hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *) hcd->status_buf_dma; ++ } else { ++ hc->xfer_buff = (uint8_t *) hcd->status_buf; ++ } ++ ptr = NULL; ++ break; ++ } ++ break; ++ case UE_BULK: ++ hc->ep_type = DWC_OTG_EP_TYPE_BULK; ++ break; ++ case UE_INTERRUPT: ++ hc->ep_type = DWC_OTG_EP_TYPE_INTR; ++ break; ++ case UE_ISOCHRONOUS: ++ { ++ struct dwc_otg_hcd_iso_packet_desc *frame_desc; ++ ++ hc->ep_type = DWC_OTG_EP_TYPE_ISOC; ++ ++ if (hcd->core_if->dma_desc_enable) ++ break; ++ ++ frame_desc = &urb->iso_descs[qtd->isoc_frame_index]; ++ ++ frame_desc->status = 0; ++ ++ if (hcd->core_if->dma_enable) { ++ hc->xfer_buff = (uint8_t *) urb->dma; ++ } else { ++ hc->xfer_buff = (uint8_t *) urb->buf; ++ } ++ hc->xfer_buff += ++ frame_desc->offset + qtd->isoc_split_offset; ++ hc->xfer_len = ++ frame_desc->length - qtd->isoc_split_offset; ++ ++ /* For non-dword aligned buffers */ ++ if (((unsigned long)hc->xfer_buff & 0x3) ++ && hcd->core_if->dma_enable) { ++ ptr = ++ (uint8_t *) urb->buf + frame_desc->offset + ++ qtd->isoc_split_offset; ++ } else ++ ptr = NULL; ++ ++ if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) { ++ if (hc->xfer_len <= 188) { ++ hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL; ++ } else { ++ hc->xact_pos = ++ DWC_HCSPLIT_XACTPOS_BEGIN; ++ } ++ } ++ } ++ break; ++ } ++ /* non DWORD-aligned buffer case */ ++ if (ptr) { ++ uint32_t buf_size; ++ if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) { ++ buf_size = hcd->core_if->core_params->max_transfer_size; ++ } else { ++ buf_size = 4096; ++ } ++ if (!qh->dw_align_buf) { ++ qh->dw_align_buf = DWC_DMA_ALLOC_ATOMIC(buf_size, ++ &qh->dw_align_buf_dma); ++ if (!qh->dw_align_buf) { ++ DWC_ERROR ++ ("%s: Failed to allocate memory to handle " ++ "non-dword aligned buffer case\n", ++ __func__); ++ return; ++ } ++ } ++ if (!hc->ep_is_in) { ++ dwc_memcpy(qh->dw_align_buf, ptr, hc->xfer_len); ++ } ++ hc->align_buff = qh->dw_align_buf_dma; ++ } else { ++ hc->align_buff = 0; ++ } ++ ++ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * This value may be modified when the transfer is started to ++ * reflect the actual transfer length. ++ */ ++ hc->multi_count = dwc_hb_mult(qh->maxp); ++ } ++ ++ if (hcd->core_if->dma_desc_enable) ++ hc->desc_list_addr = qh->desc_list_dma; ++ ++ dwc_otg_hc_init(hcd->core_if, hc); ++ hc->qh = qh; ++} ++ ++/* ++** Check the transaction to see if the port / hub has already been assigned for ++** a split transaction ++** ++** Return 0 - Port is already in use ++*/ ++int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh) ++{ ++ uint32_t hub_addr, port_addr; ++ ++ if(!fiq_split_enable) ++ return 0; ++ ++ hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); ++ ++ if(hcd->hub_port[hub_addr] & (1 << port_addr)) ++ { ++ fiq_print(FIQDBG_PORTHUB, "H%dP%d:S%02d", hub_addr, port_addr, qh->skip_count); ++ ++ qh->skip_count++; ++ ++ if(qh->skip_count > 40000) ++ { ++ printk_once(KERN_ERR "Error: Having to skip port allocation"); ++ local_fiq_disable(); ++ BUG(); ++ return 0; ++ } ++ return 1; ++ } ++ else ++ { ++ qh->skip_count = 0; ++ hcd->hub_port[hub_addr] |= 1 << port_addr; ++ fiq_print(FIQDBG_PORTHUB, "H%dP%d:A %d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); ++#ifdef FIQ_DEBUG ++ hcd->hub_port_alloc[hub_addr * 16 + port_addr] = dwc_otg_hcd_get_frame_number(hcd); ++#endif ++ return 0; ++ } ++} ++void dwc_otg_hcd_release_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh) ++{ ++ uint32_t hub_addr, port_addr; ++ ++ if(!fiq_split_enable) ++ return; ++ ++ hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr); ++ ++ hcd->hub_port[hub_addr] &= ~(1 << port_addr); ++#ifdef FIQ_DEBUG ++ hcd->hub_port_alloc[hub_addr * 16 + port_addr] = -1; ++#endif ++ fiq_print(FIQDBG_PORTHUB, "H%dP%d:RO%d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num); ++ ++} ++ ++ ++/** ++ * This function selects transactions from the HCD transfer schedule and ++ * assigns them to available host channels. It is called from HCD interrupt ++ * handler functions. ++ * ++ * @param hcd The HCD state structure. ++ * ++ * @return The types of new transactions that were assigned to host channels. ++ */ ++dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t * hcd) ++{ ++ dwc_list_link_t *qh_ptr; ++ dwc_otg_qh_t *qh; ++ dwc_otg_qtd_t *qtd; ++ int num_channels; ++ dwc_irqflags_t flags; ++ dwc_spinlock_t *channel_lock = hcd->channel_lock; ++ dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE; ++ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCD, " Select Transactions\n"); ++#endif ++ ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_per_scheduled = 0; ++ last_sel_trans_num_nonper_scheduled = 0; ++ last_sel_trans_num_avail_hc_at_start = hcd->available_host_channels; ++#endif /* DEBUG_HOST_CHANNELS */ ++ ++ /* Process entries in the periodic ready list. */ ++ qh_ptr = DWC_LIST_FIRST(&hcd->periodic_sched_ready); ++ ++ while (qh_ptr != &hcd->periodic_sched_ready && ++ !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { ++ ++ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ ++ if(qh->do_split) { ++ qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); ++ if(!(qh->ep_type == UE_ISOCHRONOUS && ++ (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID || ++ qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END))) { ++ if(dwc_otg_hcd_allocate_port(hcd, qh)) ++ { ++ qh_ptr = DWC_LIST_NEXT(qh_ptr); ++ g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1); ++ continue; ++ } ++ } ++ } ++ ++ if (microframe_schedule) { ++ // Make sure we leave one channel for non periodic transactions. ++ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); ++ if (hcd->available_host_channels <= 1) { ++ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); ++ if(qh->do_split) dwc_otg_hcd_release_port(hcd, qh); ++ break; ++ } ++ hcd->available_host_channels--; ++ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_per_scheduled++; ++#endif /* DEBUG_HOST_CHANNELS */ ++ } ++ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ assign_and_init_hc(hcd, qh); ++ ++ /* ++ * Move the QH from the periodic ready schedule to the ++ * periodic assigned schedule. ++ */ ++ qh_ptr = DWC_LIST_NEXT(qh_ptr); ++ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); ++ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned, ++ &qh->qh_list_entry); ++ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); ++ } ++ ++ /* ++ * Process entries in the inactive portion of the non-periodic ++ * schedule. Some free host channels may not be used if they are ++ * reserved for periodic transfers. ++ */ ++ qh_ptr = hcd->non_periodic_sched_inactive.next; ++ num_channels = hcd->core_if->core_params->host_channels; ++ while (qh_ptr != &hcd->non_periodic_sched_inactive && ++ (microframe_schedule || hcd->non_periodic_channels < ++ num_channels - hcd->periodic_channels) && ++ !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { ++ ++ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ ++ /* ++ * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission ++ * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed ++ * cheeky devices that just hold off using NAKs ++ */ ++ if (nak_holdoff_enable && qh->do_split) { ++ if (qh->nak_frame != 0xffff && ++ dwc_full_frame_num(qh->nak_frame) == ++ dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) { ++ /* ++ * Revisit: Need to avoid trampling on periodic scheduling. ++ * Currently we are safe because g_np_count != g_np_sent whenever we hit this, ++ * but if this behaviour is changed then periodic endpoints will get a slower ++ * polling rate. ++ */ ++ g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM; ++ qh_ptr = DWC_LIST_NEXT(qh_ptr); ++ continue; ++ } else { ++ qh->nak_frame = 0xffff; ++ } ++ } ++ ++ if (microframe_schedule) { ++ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); ++ if (hcd->available_host_channels < 1) { ++ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); ++ break; ++ } ++ hcd->available_host_channels--; ++ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_nonper_scheduled++; ++#endif /* DEBUG_HOST_CHANNELS */ ++ } ++ ++ assign_and_init_hc(hcd, qh); ++ ++ /* ++ * Move the QH from the non-periodic inactive schedule to the ++ * non-periodic active schedule. ++ */ ++ qh_ptr = DWC_LIST_NEXT(qh_ptr); ++ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); ++ DWC_LIST_MOVE_HEAD(&hcd->non_periodic_sched_active, ++ &qh->qh_list_entry); ++ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); ++ ++ g_np_sent++; ++ ++ if (!microframe_schedule) ++ hcd->non_periodic_channels++; ++ } ++ ++ if(!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) ++ ret_val |= DWC_OTG_TRANSACTION_PERIODIC; ++ ++ if(!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) ++ ret_val |= DWC_OTG_TRANSACTION_NON_PERIODIC; ++ ++ ++#ifdef DEBUG_HOST_CHANNELS ++ last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels; ++#endif /* DEBUG_HOST_CHANNELS */ ++ return ret_val; ++} ++ ++/** ++ * Attempts to queue a single transaction request for a host channel ++ * associated with either a periodic or non-periodic transfer. This function ++ * assumes that there is space available in the appropriate request queue. For ++ * an OUT transfer or SETUP transaction in Slave mode, it checks whether space ++ * is available in the appropriate Tx FIFO. ++ * ++ * @param hcd The HCD state structure. ++ * @param hc Host channel descriptor associated with either a periodic or ++ * non-periodic transfer. ++ * @param fifo_dwords_avail Number of DWORDs available in the periodic Tx ++ * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic ++ * transfers. ++ * ++ * @return 1 if a request is queued and more requests may be needed to ++ * complete the transfer, 0 if no more requests are required for this ++ * transfer, -1 if there is insufficient space in the Tx FIFO. ++ */ ++static int queue_transaction(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, uint16_t fifo_dwords_avail) ++{ ++ int retval; ++ ++ if (hcd->core_if->dma_enable) { ++ if (hcd->core_if->dma_desc_enable) { ++ if (!hc->xfer_started ++ || (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) { ++ dwc_otg_hcd_start_xfer_ddma(hcd, hc->qh); ++ hc->qh->ping_state = 0; ++ } ++ } else if (!hc->xfer_started) { ++ dwc_otg_hc_start_transfer(hcd->core_if, hc); ++ hc->qh->ping_state = 0; ++ } ++ retval = 0; ++ } else if (hc->halt_pending) { ++ /* Don't queue a request if the channel has been halted. */ ++ retval = 0; ++ } else if (hc->halt_on_queue) { ++ dwc_otg_hc_halt(hcd->core_if, hc, hc->halt_status); ++ retval = 0; ++ } else if (hc->do_ping) { ++ if (!hc->xfer_started) { ++ dwc_otg_hc_start_transfer(hcd->core_if, hc); ++ } ++ retval = 0; ++ } else if (!hc->ep_is_in || hc->data_pid_start == DWC_OTG_HC_PID_SETUP) { ++ if ((fifo_dwords_avail * 4) >= hc->max_packet) { ++ if (!hc->xfer_started) { ++ dwc_otg_hc_start_transfer(hcd->core_if, hc); ++ retval = 1; ++ } else { ++ retval = ++ dwc_otg_hc_continue_transfer(hcd->core_if, ++ hc); ++ } ++ } else { ++ retval = -1; ++ } ++ } else { ++ if (!hc->xfer_started) { ++ dwc_otg_hc_start_transfer(hcd->core_if, hc); ++ retval = 1; ++ } else { ++ retval = dwc_otg_hc_continue_transfer(hcd->core_if, hc); ++ } ++ } ++ ++ return retval; ++} ++ ++/** ++ * Processes periodic channels for the next frame and queues transactions for ++ * these channels to the DWC_otg controller. After queueing transactions, the ++ * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions ++ * to queue as Periodic Tx FIFO or request queue space becomes available. ++ * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled. ++ */ ++static void process_periodic_channels(dwc_otg_hcd_t * hcd) ++{ ++ hptxsts_data_t tx_status; ++ dwc_list_link_t *qh_ptr; ++ dwc_otg_qh_t *qh; ++ int status; ++ int no_queue_space = 0; ++ int no_fifo_space = 0; ++ ++ dwc_otg_host_global_regs_t *host_regs; ++ host_regs = hcd->core_if->host_if->host_global_regs; ++ ++ DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n"); ++#ifdef DEBUG ++ tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts); ++ DWC_DEBUGPL(DBG_HCDV, ++ " P Tx Req Queue Space Avail (before queue): %d\n", ++ tx_status.b.ptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, " P Tx FIFO Space Avail (before queue): %d\n", ++ tx_status.b.ptxfspcavail); ++#endif ++ ++ qh_ptr = hcd->periodic_sched_assigned.next; ++ while (qh_ptr != &hcd->periodic_sched_assigned) { ++ tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts); ++ if (tx_status.b.ptxqspcavail == 0) { ++ no_queue_space = 1; ++ break; ++ } ++ ++ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry); ++ ++ // Do not send a split start transaction any later than frame .6 ++ // Note, we have to schedule a periodic in .5 to make it go in .6 ++ if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6) ++ { ++ qh_ptr = qh_ptr->next; ++ g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7; ++ continue; ++ } ++ ++ /* ++ * Set a flag if we're queuing high-bandwidth in slave mode. ++ * The flag prevents any halts to get into the request queue in ++ * the middle of multiple high-bandwidth packets getting queued. ++ */ ++ if (!hcd->core_if->dma_enable && qh->channel->multi_count > 1) { ++ hcd->core_if->queuing_high_bandwidth = 1; ++ } ++ status = ++ queue_transaction(hcd, qh->channel, ++ tx_status.b.ptxfspcavail); ++ if (status < 0) { ++ no_fifo_space = 1; ++ break; ++ } ++ ++ /* ++ * In Slave mode, stay on the current transfer until there is ++ * nothing more to do or the high-bandwidth request count is ++ * reached. In DMA mode, only need to queue one request. The ++ * controller automatically handles multiple packets for ++ * high-bandwidth transfers. ++ */ ++ if (hcd->core_if->dma_enable || status == 0 || ++ qh->channel->requests == qh->channel->multi_count) { ++ qh_ptr = qh_ptr->next; ++ /* ++ * Move the QH from the periodic assigned schedule to ++ * the periodic queued schedule. ++ */ ++ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_queued, ++ &qh->qh_list_entry); ++ ++ /* done queuing high bandwidth */ ++ hcd->core_if->queuing_high_bandwidth = 0; ++ } ++ } ++ ++ if (!hcd->core_if->dma_enable) { ++ dwc_otg_core_global_regs_t *global_regs; ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ ++ global_regs = hcd->core_if->core_global_regs; ++ intr_mask.b.ptxfempty = 1; ++#ifdef DEBUG ++ tx_status.d32 = DWC_READ_REG32(&host_regs->hptxsts); ++ DWC_DEBUGPL(DBG_HCDV, ++ " P Tx Req Queue Space Avail (after queue): %d\n", ++ tx_status.b.ptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, ++ " P Tx FIFO Space Avail (after queue): %d\n", ++ tx_status.b.ptxfspcavail); ++#endif ++ if (!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned) || ++ no_queue_space || no_fifo_space) { ++ /* ++ * May need to queue more transactions as the request ++ * queue or Tx FIFO empties. Enable the periodic Tx ++ * FIFO empty interrupt. (Always use the half-empty ++ * level to ensure that new requests are loaded as ++ * soon as possible.) ++ */ ++ DWC_MODIFY_REG32(&global_regs->gintmsk, 0, ++ intr_mask.d32); ++ } else { ++ /* ++ * Disable the Tx FIFO empty interrupt since there are ++ * no more transactions that need to be queued right ++ * now. This function is called from interrupt ++ * handlers to queue more transactions as transfer ++ * states change. ++ */ ++ DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, ++ 0); ++ } ++ } ++} ++ ++/** ++ * Processes active non-periodic channels and queues transactions for these ++ * channels to the DWC_otg controller. After queueing transactions, the NP Tx ++ * FIFO Empty interrupt is enabled if there are more transactions to queue as ++ * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx ++ * FIFO Empty interrupt is disabled. ++ */ ++static void process_non_periodic_channels(dwc_otg_hcd_t * hcd) ++{ ++ gnptxsts_data_t tx_status; ++ dwc_list_link_t *orig_qh_ptr; ++ dwc_otg_qh_t *qh; ++ int status; ++ int no_queue_space = 0; ++ int no_fifo_space = 0; ++ int more_to_do = 0; ++ ++ dwc_otg_core_global_regs_t *global_regs = ++ hcd->core_if->core_global_regs; ++ ++ DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n"); ++#ifdef DEBUG ++ tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts); ++ DWC_DEBUGPL(DBG_HCDV, ++ " NP Tx Req Queue Space Avail (before queue): %d\n", ++ tx_status.b.nptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, " NP Tx FIFO Space Avail (before queue): %d\n", ++ tx_status.b.nptxfspcavail); ++#endif ++ /* ++ * Keep track of the starting point. Skip over the start-of-list ++ * entry. ++ */ ++ if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) { ++ hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next; ++ } ++ orig_qh_ptr = hcd->non_periodic_qh_ptr; ++ ++ /* ++ * Process once through the active list or until no more space is ++ * available in the request queue or the Tx FIFO. ++ */ ++ do { ++ tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts); ++ if (!hcd->core_if->dma_enable && tx_status.b.nptxqspcavail == 0) { ++ no_queue_space = 1; ++ break; ++ } ++ ++ qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t, ++ qh_list_entry); ++ ++ // Do not send a split start transaction any later than frame .5 ++ // non periodic transactions will start immediately in this uframe ++ if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6) ++ { ++ g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7; ++ break; ++ } ++ ++ status = ++ queue_transaction(hcd, qh->channel, ++ tx_status.b.nptxfspcavail); ++ ++ if (status > 0) { ++ more_to_do = 1; ++ } else if (status < 0) { ++ no_fifo_space = 1; ++ break; ++ } ++ ++ /* Advance to next QH, skipping start-of-list entry. */ ++ hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next; ++ if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active) { ++ hcd->non_periodic_qh_ptr = ++ hcd->non_periodic_qh_ptr->next; ++ } ++ ++ } while (hcd->non_periodic_qh_ptr != orig_qh_ptr); ++ ++ if (!hcd->core_if->dma_enable) { ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ intr_mask.b.nptxfempty = 1; ++ ++#ifdef DEBUG ++ tx_status.d32 = DWC_READ_REG32(&global_regs->gnptxsts); ++ DWC_DEBUGPL(DBG_HCDV, ++ " NP Tx Req Queue Space Avail (after queue): %d\n", ++ tx_status.b.nptxqspcavail); ++ DWC_DEBUGPL(DBG_HCDV, ++ " NP Tx FIFO Space Avail (after queue): %d\n", ++ tx_status.b.nptxfspcavail); ++#endif ++ if (more_to_do || no_queue_space || no_fifo_space) { ++ /* ++ * May need to queue more transactions as the request ++ * queue or Tx FIFO empties. Enable the non-periodic ++ * Tx FIFO empty interrupt. (Always use the half-empty ++ * level to ensure that new requests are loaded as ++ * soon as possible.) ++ */ ++ DWC_MODIFY_REG32(&global_regs->gintmsk, 0, ++ intr_mask.d32); ++ } else { ++ /* ++ * Disable the Tx FIFO empty interrupt since there are ++ * no more transactions that need to be queued right ++ * now. This function is called from interrupt ++ * handlers to queue more transactions as transfer ++ * states change. ++ */ ++ DWC_MODIFY_REG32(&global_regs->gintmsk, intr_mask.d32, ++ 0); ++ } ++ } ++} ++ ++/** ++ * This function processes the currently active host channels and queues ++ * transactions for these channels to the DWC_otg controller. It is called ++ * from HCD interrupt handler functions. ++ * ++ * @param hcd The HCD state structure. ++ * @param tr_type The type(s) of transactions to queue (non-periodic, ++ * periodic, or both). ++ */ ++void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd, ++ dwc_otg_transaction_type_e tr_type) ++{ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n"); ++#endif ++ /* Process host channels associated with periodic transfers. */ ++ if ((tr_type == DWC_OTG_TRANSACTION_PERIODIC || ++ tr_type == DWC_OTG_TRANSACTION_ALL) && ++ !DWC_LIST_EMPTY(&hcd->periodic_sched_assigned)) { ++ ++ process_periodic_channels(hcd); ++ } ++ ++ /* Process host channels associated with non-periodic transfers. */ ++ if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC || ++ tr_type == DWC_OTG_TRANSACTION_ALL) { ++ if (!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active)) { ++ process_non_periodic_channels(hcd); ++ } else { ++ /* ++ * Ensure NP Tx FIFO empty interrupt is disabled when ++ * there are no non-periodic transfers to process. ++ */ ++ gintmsk_data_t gintmsk = {.d32 = 0 }; ++ gintmsk.b.nptxfempty = 1; ++ DWC_MODIFY_REG32(&hcd->core_if-> ++ core_global_regs->gintmsk, gintmsk.d32, ++ 0); ++ } ++ } ++} ++ ++#ifdef DWC_HS_ELECT_TST ++/* ++ * Quick and dirty hack to implement the HS Electrical Test ++ * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature. ++ * ++ * This code was copied from our userspace app "hset". It sends a ++ * Get Device Descriptor control sequence in two parts, first the ++ * Setup packet by itself, followed some time later by the In and ++ * Ack packets. Rather than trying to figure out how to add this ++ * functionality to the normal driver code, we just hijack the ++ * hardware, using these two function to drive the hardware ++ * directly. ++ */ ++ ++static dwc_otg_core_global_regs_t *global_regs; ++static dwc_otg_host_global_regs_t *hc_global_regs; ++static dwc_otg_hc_regs_t *hc_regs; ++static uint32_t *data_fifo; ++ ++static void do_setup(void) ++{ ++ gintsts_data_t gintsts; ++ hctsiz_data_t hctsiz; ++ hcchar_data_t hcchar; ++ haint_data_t haint; ++ hcint_data_t hcint; ++ ++ /* Enable HAINTs */ ++ DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001); ++ ++ /* Enable HCINTs */ ++ DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* Read HAINT */ ++ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint); ++ ++ /* Read HCINT */ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ ++ /* Clear HCINT */ ++ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* ++ * Send Setup packet (Get Device Descriptor) ++ */ ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ hcchar.b.chdis = 1; ++// hcchar.b.chen = 1; ++ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ dwc_mdelay(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* Read HAINT */ ++ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint); ++ ++ /* Read HCINT */ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ ++ /* Clear HCINT */ ++ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 8; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = DWC_OTG_HC_PID_SETUP; ++ DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; ++ hcchar.b.epdir = 0; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32); ++ ++ /* Fill FIFO with Setup data for Get Device Descriptor */ ++ data_fifo = (uint32_t *) ((char *)global_regs + 0x1000); ++ DWC_WRITE_REG32(data_fifo++, 0x01000680); ++ DWC_WRITE_REG32(data_fifo++, 0x00080000); ++ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ /* Disable HCINTs */ ++ DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000); ++ ++ /* Disable HAINTs */ ++ DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000); ++ ++ /* Read HAINT */ ++ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint); ++ ++ /* Read HCINT */ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ ++ /* Clear HCINT */ ++ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++} ++ ++static void do_in_ack(void) ++{ ++ gintsts_data_t gintsts; ++ hctsiz_data_t hctsiz; ++ hcchar_data_t hcchar; ++ haint_data_t haint; ++ hcint_data_t hcint; ++ host_grxsts_data_t grxsts; ++ ++ /* Enable HAINTs */ ++ DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0001); ++ ++ /* Enable HCINTs */ ++ DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x04a3); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* Read HAINT */ ++ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint); ++ ++ /* Read HCINT */ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ ++ /* Clear HCINT */ ++ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* ++ * Receive Control In packet ++ */ ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ hcchar.b.chdis = 1; ++ hcchar.b.chen = 1; ++ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ dwc_mdelay(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* Read HAINT */ ++ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint); ++ ++ /* Read HCINT */ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ ++ /* Clear HCINT */ ++ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 8; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = DWC_OTG_HC_PID_DATA1; ++ DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; ++ hcchar.b.epdir = 1; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32); ++ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* Wait for receive status queue interrupt */ ++ do { ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ } while (gintsts.b.rxstsqlvl == 0); ++ ++ /* Read RXSTS */ ++ grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp); ++ ++ /* Clear RXSTSQLVL in GINTSTS */ ++ gintsts.d32 = 0; ++ gintsts.b.rxstsqlvl = 1; ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ switch (grxsts.b.pktsts) { ++ case DWC_GRXSTS_PKTSTS_IN: ++ /* Read the data into the host buffer */ ++ if (grxsts.b.bcnt > 0) { ++ int i; ++ int word_count = (grxsts.b.bcnt + 3) / 4; ++ ++ data_fifo = (uint32_t *) ((char *)global_regs + 0x1000); ++ ++ for (i = 0; i < word_count; i++) { ++ (void)DWC_READ_REG32(data_fifo++); ++ } ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* Wait for receive status queue interrupt */ ++ do { ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ } while (gintsts.b.rxstsqlvl == 0); ++ ++ /* Read RXSTS */ ++ grxsts.d32 = DWC_READ_REG32(&global_regs->grxstsp); ++ ++ /* Clear RXSTSQLVL in GINTSTS */ ++ gintsts.d32 = 0; ++ gintsts.b.rxstsqlvl = 1; ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ switch (grxsts.b.pktsts) { ++ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: ++ break; ++ ++ default: ++ break; ++ } ++ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ /* Read HAINT */ ++ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint); ++ ++ /* Read HCINT */ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ ++ /* Clear HCINT */ ++ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++// usleep(100000); ++// mdelay(100); ++ dwc_mdelay(1); ++ ++ /* ++ * Send handshake packet ++ */ ++ ++ /* Read HAINT */ ++ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint); ++ ++ /* Read HCINT */ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ ++ /* Clear HCINT */ ++ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* Make sure channel is disabled */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ if (hcchar.b.chen) { ++ hcchar.b.chdis = 1; ++ hcchar.b.chen = 1; ++ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32); ++ //sleep(1); ++ dwc_mdelay(1000); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* Read HAINT */ ++ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint); ++ ++ /* Read HCINT */ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ ++ /* Clear HCINT */ ++ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ } ++ ++ /* Set HCTSIZ */ ++ hctsiz.d32 = 0; ++ hctsiz.b.xfersize = 0; ++ hctsiz.b.pktcnt = 1; ++ hctsiz.b.pid = DWC_OTG_HC_PID_DATA1; ++ DWC_WRITE_REG32(&hc_regs->hctsiz, hctsiz.d32); ++ ++ /* Set HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; ++ hcchar.b.epdir = 0; ++ hcchar.b.epnum = 0; ++ hcchar.b.mps = 8; ++ hcchar.b.chen = 1; ++ DWC_WRITE_REG32(&hc_regs->hcchar, hcchar.d32); ++ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ ++ /* Wait for host channel interrupt */ ++ do { ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++ } while (gintsts.b.hcintr == 0); ++ ++ /* Disable HCINTs */ ++ DWC_WRITE_REG32(&hc_regs->hcintmsk, 0x0000); ++ ++ /* Disable HAINTs */ ++ DWC_WRITE_REG32(&hc_global_regs->haintmsk, 0x0000); ++ ++ /* Read HAINT */ ++ haint.d32 = DWC_READ_REG32(&hc_global_regs->haint); ++ ++ /* Read HCINT */ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ ++ /* Read HCCHAR */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ ++ /* Clear HCINT */ ++ DWC_WRITE_REG32(&hc_regs->hcint, hcint.d32); ++ ++ /* Clear HAINT */ ++ DWC_WRITE_REG32(&hc_global_regs->haint, haint.d32); ++ ++ /* Clear GINTSTS */ ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ /* Read GINTSTS */ ++ gintsts.d32 = DWC_READ_REG32(&global_regs->gintsts); ++} ++#endif ++ ++/** Handles hub class-specific requests. */ ++int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd, ++ uint16_t typeReq, ++ uint16_t wValue, ++ uint16_t wIndex, uint8_t * buf, uint16_t wLength) ++{ ++ int retval = 0; ++ ++ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; ++ usb_hub_descriptor_t *hub_desc; ++ hprt0_data_t hprt0 = {.d32 = 0 }; ++ ++ uint32_t port_status; ++ ++ switch (typeReq) { ++ case UCR_CLEAR_HUB_FEATURE: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearHubFeature 0x%x\n", wValue); ++ switch (wValue) { ++ case UHF_C_HUB_LOCAL_POWER: ++ case UHF_C_HUB_OVER_CURRENT: ++ /* Nothing required here */ ++ break; ++ default: ++ retval = -DWC_E_INVALID; ++ DWC_ERROR("DWC OTG HCD - " ++ "ClearHubFeature request %xh unknown\n", ++ wValue); ++ } ++ break; ++ case UCR_CLEAR_PORT_FEATURE: ++#ifdef CONFIG_USB_DWC_OTG_LPM ++ if (wValue != UHF_PORT_L1) ++#endif ++ if (!wIndex || wIndex > 1) ++ goto error; ++ ++ switch (wValue) { ++ case UHF_PORT_ENABLE: ++ DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_ENABLE\n"); ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtena = 1; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ case UHF_PORT_SUSPEND: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); ++ ++ if (core_if->power_down == 2) { ++ dwc_otg_host_hibernation_restore(core_if, 0, 0); ++ } else { ++ DWC_WRITE_REG32(core_if->pcgcctl, 0); ++ dwc_mdelay(5); ++ ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtres = 1; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ hprt0.b.prtsusp = 0; ++ /* Clear Resume bit */ ++ dwc_mdelay(100); ++ hprt0.b.prtres = 0; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ } ++ break; ++#ifdef CONFIG_USB_DWC_OTG_LPM ++ case UHF_PORT_L1: ++ { ++ pcgcctl_data_t pcgcctl = {.d32 = 0 }; ++ glpmcfg_data_t lpmcfg = {.d32 = 0 }; ++ ++ lpmcfg.d32 = ++ DWC_READ_REG32(&core_if-> ++ core_global_regs->glpmcfg); ++ lpmcfg.b.en_utmi_sleep = 0; ++ lpmcfg.b.hird_thres &= (~(1 << 4)); ++ lpmcfg.b.prt_sleep_sts = 1; ++ DWC_WRITE_REG32(&core_if-> ++ core_global_regs->glpmcfg, ++ lpmcfg.d32); ++ ++ /* Clear Enbl_L1Gating bit. */ ++ pcgcctl.b.enbl_sleep_gating = 1; ++ DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, ++ 0); ++ ++ dwc_mdelay(5); ++ ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtres = 1; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, ++ hprt0.d32); ++ /* This bit will be cleared in wakeup interrupt handle */ ++ break; ++ } ++#endif ++ case UHF_PORT_POWER: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_POWER\n"); ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtpwr = 0; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ case UHF_PORT_INDICATOR: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_INDICATOR\n"); ++ /* Port inidicator not supported */ ++ break; ++ case UHF_C_PORT_CONNECTION: ++ /* Clears drivers internal connect status change ++ * flag */ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n"); ++ dwc_otg_hcd->flags.b.port_connect_status_change = 0; ++ break; ++ case UHF_C_PORT_RESET: ++ /* Clears the driver's internal Port Reset Change ++ * flag */ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_RESET\n"); ++ dwc_otg_hcd->flags.b.port_reset_change = 0; ++ break; ++ case UHF_C_PORT_ENABLE: ++ /* Clears the driver's internal Port ++ * Enable/Disable Change flag */ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n"); ++ dwc_otg_hcd->flags.b.port_enable_change = 0; ++ break; ++ case UHF_C_PORT_SUSPEND: ++ /* Clears the driver's internal Port Suspend ++ * Change flag, which is set when resume signaling on ++ * the host port is complete */ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n"); ++ dwc_otg_hcd->flags.b.port_suspend_change = 0; ++ break; ++#ifdef CONFIG_USB_DWC_OTG_LPM ++ case UHF_C_PORT_L1: ++ dwc_otg_hcd->flags.b.port_l1_change = 0; ++ break; ++#endif ++ case UHF_C_PORT_OVER_CURRENT: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n"); ++ dwc_otg_hcd->flags.b.port_over_current_change = 0; ++ break; ++ default: ++ retval = -DWC_E_INVALID; ++ DWC_ERROR("DWC OTG HCD - " ++ "ClearPortFeature request %xh " ++ "unknown or unsupported\n", wValue); ++ } ++ break; ++ case UCR_GET_HUB_DESCRIPTOR: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "GetHubDescriptor\n"); ++ hub_desc = (usb_hub_descriptor_t *) buf; ++ hub_desc->bDescLength = 9; ++ hub_desc->bDescriptorType = 0x29; ++ hub_desc->bNbrPorts = 1; ++ USETW(hub_desc->wHubCharacteristics, 0x08); ++ hub_desc->bPwrOn2PwrGood = 1; ++ hub_desc->bHubContrCurrent = 0; ++ hub_desc->DeviceRemovable[0] = 0; ++ hub_desc->DeviceRemovable[1] = 0xff; ++ break; ++ case UCR_GET_HUB_STATUS: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "GetHubStatus\n"); ++ DWC_MEMSET(buf, 0, 4); ++ break; ++ case UCR_GET_PORT_STATUS: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "GetPortStatus wIndex = 0x%04x FLAGS=0x%08x\n", ++ wIndex, dwc_otg_hcd->flags.d32); ++ if (!wIndex || wIndex > 1) ++ goto error; ++ ++ port_status = 0; ++ ++ if (dwc_otg_hcd->flags.b.port_connect_status_change) ++ port_status |= (1 << UHF_C_PORT_CONNECTION); ++ ++ if (dwc_otg_hcd->flags.b.port_enable_change) ++ port_status |= (1 << UHF_C_PORT_ENABLE); ++ ++ if (dwc_otg_hcd->flags.b.port_suspend_change) ++ port_status |= (1 << UHF_C_PORT_SUSPEND); ++ ++ if (dwc_otg_hcd->flags.b.port_l1_change) ++ port_status |= (1 << UHF_C_PORT_L1); ++ ++ if (dwc_otg_hcd->flags.b.port_reset_change) { ++ port_status |= (1 << UHF_C_PORT_RESET); ++ } ++ ++ if (dwc_otg_hcd->flags.b.port_over_current_change) { ++ DWC_WARN("Overcurrent change detected\n"); ++ port_status |= (1 << UHF_C_PORT_OVER_CURRENT); ++ } ++ ++ if (!dwc_otg_hcd->flags.b.port_connect_status) { ++ /* ++ * The port is disconnected, which means the core is ++ * either in device mode or it soon will be. Just ++ * return 0's for the remainder of the port status ++ * since the port register can't be read if the core ++ * is in device mode. ++ */ ++ *((__le32 *) buf) = dwc_cpu_to_le32(&port_status); ++ break; ++ } ++ ++ hprt0.d32 = DWC_READ_REG32(core_if->host_if->hprt0); ++ DWC_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32); ++ ++ if (hprt0.b.prtconnsts) ++ port_status |= (1 << UHF_PORT_CONNECTION); ++ ++ if (hprt0.b.prtena) ++ port_status |= (1 << UHF_PORT_ENABLE); ++ ++ if (hprt0.b.prtsusp) ++ port_status |= (1 << UHF_PORT_SUSPEND); ++ ++ if (hprt0.b.prtovrcurract) ++ port_status |= (1 << UHF_PORT_OVER_CURRENT); ++ ++ if (hprt0.b.prtrst) ++ port_status |= (1 << UHF_PORT_RESET); ++ ++ if (hprt0.b.prtpwr) ++ port_status |= (1 << UHF_PORT_POWER); ++ ++ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) ++ port_status |= (1 << UHF_PORT_HIGH_SPEED); ++ else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED) ++ port_status |= (1 << UHF_PORT_LOW_SPEED); ++ ++ if (hprt0.b.prttstctl) ++ port_status |= (1 << UHF_PORT_TEST); ++ if (dwc_otg_get_lpm_portsleepstatus(dwc_otg_hcd->core_if)) { ++ port_status |= (1 << UHF_PORT_L1); ++ } ++ /* ++ For Synopsys HW emulation of Power down wkup_control asserts the ++ hreset_n and prst_n on suspned. This causes the HPRT0 to be zero. ++ We intentionally tell the software that port is in L2Suspend state. ++ Only for STE. ++ */ ++ if ((core_if->power_down == 2) ++ && (core_if->hibernation_suspend == 1)) { ++ port_status |= (1 << UHF_PORT_SUSPEND); ++ } ++ /* USB_PORT_FEAT_INDICATOR unsupported always 0 */ ++ ++ *((__le32 *) buf) = dwc_cpu_to_le32(&port_status); ++ ++ break; ++ case UCR_SET_HUB_FEATURE: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetHubFeature\n"); ++ /* No HUB features supported */ ++ break; ++ case UCR_SET_PORT_FEATURE: ++ if (wValue != UHF_PORT_TEST && (!wIndex || wIndex > 1)) ++ goto error; ++ ++ if (!dwc_otg_hcd->flags.b.port_connect_status) { ++ /* ++ * The port is disconnected, which means the core is ++ * either in device mode or it soon will be. Just ++ * return without doing anything since the port ++ * register can't be written if the core is in device ++ * mode. ++ */ ++ break; ++ } ++ ++ switch (wValue) { ++ case UHF_PORT_SUSPEND: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); ++ if (dwc_otg_hcd_otg_port(dwc_otg_hcd) != wIndex) { ++ goto error; ++ } ++ if (core_if->power_down == 2) { ++ int timeout = 300; ++ dwc_irqflags_t flags; ++ pcgcctl_data_t pcgcctl = {.d32 = 0 }; ++ gpwrdn_data_t gpwrdn = {.d32 = 0 }; ++ gusbcfg_data_t gusbcfg = {.d32 = 0 }; ++#ifdef DWC_DEV_SRPCAP ++ int32_t otg_cap_param = core_if->core_params->otg_cap; ++#endif ++ DWC_PRINTF("Preparing for complete power-off\n"); ++ ++ /* Save registers before hibernation */ ++ dwc_otg_save_global_regs(core_if); ++ dwc_otg_save_host_regs(core_if); ++ ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtsusp = 1; ++ hprt0.b.prtena = 0; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ /* Spin hprt0.b.prtsusp to became 1 */ ++ do { ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ if (hprt0.b.prtsusp) { ++ break; ++ } ++ dwc_mdelay(1); ++ } while (--timeout); ++ if (!timeout) { ++ DWC_WARN("Suspend wasn't genereted\n"); ++ } ++ dwc_udelay(10); ++ ++ /* ++ * We need to disable interrupts to prevent servicing of any IRQ ++ * during going to hibernation ++ */ ++ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags); ++ core_if->lx_state = DWC_OTG_L2; ++#ifdef DWC_DEV_SRPCAP ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtpwr = 0; ++ hprt0.b.prtena = 0; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, ++ hprt0.d32); ++#endif ++ gusbcfg.d32 = ++ DWC_READ_REG32(&core_if->core_global_regs-> ++ gusbcfg); ++ if (gusbcfg.b.ulpi_utmi_sel == 1) { ++ /* ULPI interface */ ++ /* Suspend the Phy Clock */ ++ pcgcctl.d32 = 0; ++ pcgcctl.b.stoppclk = 1; ++ DWC_MODIFY_REG32(core_if->pcgcctl, 0, ++ pcgcctl.d32); ++ dwc_udelay(10); ++ gpwrdn.b.pmuactv = 1; ++ DWC_MODIFY_REG32(&core_if-> ++ core_global_regs-> ++ gpwrdn, 0, gpwrdn.d32); ++ } else { ++ /* UTMI+ Interface */ ++ gpwrdn.b.pmuactv = 1; ++ DWC_MODIFY_REG32(&core_if-> ++ core_global_regs-> ++ gpwrdn, 0, gpwrdn.d32); ++ dwc_udelay(10); ++ pcgcctl.b.stoppclk = 1; ++ DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32); ++ dwc_udelay(10); ++ } ++#ifdef DWC_DEV_SRPCAP ++ gpwrdn.d32 = 0; ++ gpwrdn.b.dis_vbus = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs-> ++ gpwrdn, 0, gpwrdn.d32); ++#endif ++ gpwrdn.d32 = 0; ++ gpwrdn.b.pmuintsel = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs-> ++ gpwrdn, 0, gpwrdn.d32); ++ dwc_udelay(10); ++ ++ gpwrdn.d32 = 0; ++#ifdef DWC_DEV_SRPCAP ++ gpwrdn.b.srp_det_msk = 1; ++#endif ++ gpwrdn.b.disconn_det_msk = 1; ++ gpwrdn.b.lnstchng_msk = 1; ++ gpwrdn.b.sts_chngint_msk = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs-> ++ gpwrdn, 0, gpwrdn.d32); ++ dwc_udelay(10); ++ ++ /* Enable Power Down Clamp and all interrupts in GPWRDN */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.pwrdnclmp = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs-> ++ gpwrdn, 0, gpwrdn.d32); ++ dwc_udelay(10); ++ ++ /* Switch off VDD */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.pwrdnswtch = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs-> ++ gpwrdn, 0, gpwrdn.d32); ++ ++#ifdef DWC_DEV_SRPCAP ++ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) ++ { ++ core_if->pwron_timer_started = 1; ++ DWC_TIMER_SCHEDULE(core_if->pwron_timer, 6000 /* 6 secs */ ); ++ } ++#endif ++ /* Save gpwrdn register for further usage if stschng interrupt */ ++ core_if->gr_backup->gpwrdn_local = ++ DWC_READ_REG32(&core_if->core_global_regs->gpwrdn); ++ ++ /* Set flag to indicate that we are in hibernation */ ++ core_if->hibernation_suspend = 1; ++ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock,flags); ++ ++ DWC_PRINTF("Host hibernation completed\n"); ++ // Exit from case statement ++ break; ++ ++ } ++ if (dwc_otg_hcd_otg_port(dwc_otg_hcd) == wIndex && ++ dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) { ++ gotgctl_data_t gotgctl = {.d32 = 0 }; ++ gotgctl.b.hstsethnpen = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs-> ++ gotgctl, 0, gotgctl.d32); ++ core_if->op_state = A_SUSPEND; ++ } ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtsusp = 1; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ { ++ dwc_irqflags_t flags; ++ /* Update lx_state */ ++ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags); ++ core_if->lx_state = DWC_OTG_L2; ++ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags); ++ } ++ /* Suspend the Phy Clock */ ++ { ++ pcgcctl_data_t pcgcctl = {.d32 = 0 }; ++ pcgcctl.b.stoppclk = 1; ++ DWC_MODIFY_REG32(core_if->pcgcctl, 0, ++ pcgcctl.d32); ++ dwc_udelay(10); ++ } ++ ++ /* For HNP the bus must be suspended for at least 200ms. */ ++ if (dwc_otg_hcd->fops->get_b_hnp_enable(dwc_otg_hcd)) { ++ pcgcctl_data_t pcgcctl = {.d32 = 0 }; ++ pcgcctl.b.stoppclk = 1; ++ DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0); ++ dwc_mdelay(200); ++ } ++ ++ /** @todo - check how sw can wait for 1 sec to check asesvld??? */ ++#if 0 //vahrama !!!!!!!!!!!!!!!!!! ++ if (core_if->adp_enable) { ++ gotgctl_data_t gotgctl = {.d32 = 0 }; ++ gpwrdn_data_t gpwrdn; ++ ++ while (gotgctl.b.asesvld == 1) { ++ gotgctl.d32 = ++ DWC_READ_REG32(&core_if-> ++ core_global_regs-> ++ gotgctl); ++ dwc_mdelay(100); ++ } ++ ++ /* Enable Power Down Logic */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.pmuactv = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs-> ++ gpwrdn, 0, gpwrdn.d32); ++ ++ /* Unmask SRP detected interrupt from Power Down Logic */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.srp_det_msk = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs-> ++ gpwrdn, 0, gpwrdn.d32); ++ ++ dwc_otg_adp_probe_start(core_if); ++ } ++#endif ++ break; ++ case UHF_PORT_POWER: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_POWER\n"); ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtpwr = 1; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ break; ++ case UHF_PORT_RESET: ++ if ((core_if->power_down == 2) ++ && (core_if->hibernation_suspend == 1)) { ++ /* If we are going to exit from Hibernated ++ * state via USB RESET. ++ */ ++ dwc_otg_host_hibernation_restore(core_if, 0, 1); ++ } else { ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ ++ DWC_DEBUGPL(DBG_HCD, ++ "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_RESET\n"); ++ { ++ pcgcctl_data_t pcgcctl = {.d32 = 0 }; ++ pcgcctl.b.enbl_sleep_gating = 1; ++ pcgcctl.b.stoppclk = 1; ++ DWC_MODIFY_REG32(core_if->pcgcctl, pcgcctl.d32, 0); ++ DWC_WRITE_REG32(core_if->pcgcctl, 0); ++ } ++#ifdef CONFIG_USB_DWC_OTG_LPM ++ { ++ glpmcfg_data_t lpmcfg; ++ lpmcfg.d32 = ++ DWC_READ_REG32(&core_if->core_global_regs->glpmcfg); ++ if (lpmcfg.b.prt_sleep_sts) { ++ lpmcfg.b.en_utmi_sleep = 0; ++ lpmcfg.b.hird_thres &= (~(1 << 4)); ++ DWC_WRITE_REG32 ++ (&core_if->core_global_regs->glpmcfg, ++ lpmcfg.d32); ++ dwc_mdelay(1); ++ } ++ } ++#endif ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ /* Clear suspend bit if resetting from suspended state. */ ++ hprt0.b.prtsusp = 0; ++ /* When B-Host the Port reset bit is set in ++ * the Start HCD Callback function, so that ++ * the reset is started within 1ms of the HNP ++ * success interrupt. */ ++ if (!dwc_otg_hcd_is_b_host(dwc_otg_hcd)) { ++ hprt0.b.prtpwr = 1; ++ hprt0.b.prtrst = 1; ++ DWC_PRINTF("Indeed it is in host mode hprt0 = %08x\n",hprt0.d32); ++ DWC_WRITE_REG32(core_if->host_if->hprt0, ++ hprt0.d32); ++ } ++ /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ ++ dwc_mdelay(60); ++ hprt0.b.prtrst = 0; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ core_if->lx_state = DWC_OTG_L0; /* Now back to the on state */ ++ } ++ break; ++#ifdef DWC_HS_ELECT_TST ++ case UHF_PORT_TEST: ++ { ++ uint32_t t; ++ gintmsk_data_t gintmsk; ++ ++ t = (wIndex >> 8); /* MSB wIndex USB */ ++ DWC_DEBUGPL(DBG_HCD, ++ "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_TEST %d\n", ++ t); ++ DWC_WARN("USB_PORT_FEAT_TEST %d\n", t); ++ if (t < 6) { ++ hprt0.d32 = dwc_otg_read_hprt0(core_if); ++ hprt0.b.prttstctl = t; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, ++ hprt0.d32); ++ } else { ++ /* Setup global vars with reg addresses (quick and ++ * dirty hack, should be cleaned up) ++ */ ++ global_regs = core_if->core_global_regs; ++ hc_global_regs = ++ core_if->host_if->host_global_regs; ++ hc_regs = ++ (dwc_otg_hc_regs_t *) ((char *) ++ global_regs + ++ 0x500); ++ data_fifo = ++ (uint32_t *) ((char *)global_regs + ++ 0x1000); ++ ++ if (t == 6) { /* HS_HOST_PORT_SUSPEND_RESUME */ ++ /* Save current interrupt mask */ ++ gintmsk.d32 = ++ DWC_READ_REG32 ++ (&global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ DWC_WRITE_REG32(&global_regs->gintmsk, 0); ++ ++ /* 15 second delay per the test spec */ ++ dwc_mdelay(15000); ++ ++ /* Drive suspend on the root port */ ++ hprt0.d32 = ++ dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtsusp = 1; ++ hprt0.b.prtres = 0; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ ++ /* 15 second delay per the test spec */ ++ dwc_mdelay(15000); ++ ++ /* Drive resume on the root port */ ++ hprt0.d32 = ++ dwc_otg_read_hprt0(core_if); ++ hprt0.b.prtsusp = 0; ++ hprt0.b.prtres = 1; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ dwc_mdelay(100); ++ ++ /* Clear the resume bit */ ++ hprt0.b.prtres = 0; ++ DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32); ++ ++ /* Restore interrupts */ ++ DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32); ++ } else if (t == 7) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */ ++ /* Save current interrupt mask */ ++ gintmsk.d32 = ++ DWC_READ_REG32 ++ (&global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ DWC_WRITE_REG32(&global_regs->gintmsk, 0); ++ ++ /* 15 second delay per the test spec */ ++ dwc_mdelay(15000); ++ ++ /* Send the Setup packet */ ++ do_setup(); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ dwc_mdelay(15000); ++ ++ /* Restore interrupts */ ++ DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32); ++ } else if (t == 8) { /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */ ++ /* Save current interrupt mask */ ++ gintmsk.d32 = ++ DWC_READ_REG32 ++ (&global_regs->gintmsk); ++ ++ /* Disable all interrupts while we muck with ++ * the hardware directly ++ */ ++ DWC_WRITE_REG32(&global_regs->gintmsk, 0); ++ ++ /* Send the Setup packet */ ++ do_setup(); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ dwc_mdelay(15000); ++ ++ /* Send the In and Ack packets */ ++ do_in_ack(); ++ ++ /* 15 second delay so nothing else happens for awhile */ ++ dwc_mdelay(15000); ++ ++ /* Restore interrupts */ ++ DWC_WRITE_REG32(&global_regs->gintmsk, gintmsk.d32); ++ } ++ } ++ break; ++ } ++#endif /* DWC_HS_ELECT_TST */ ++ ++ case UHF_PORT_INDICATOR: ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - " ++ "SetPortFeature - USB_PORT_FEAT_INDICATOR\n"); ++ /* Not supported */ ++ break; ++ default: ++ retval = -DWC_E_INVALID; ++ DWC_ERROR("DWC OTG HCD - " ++ "SetPortFeature request %xh " ++ "unknown or unsupported\n", wValue); ++ break; ++ } ++ break; ++#ifdef CONFIG_USB_DWC_OTG_LPM ++ case UCR_SET_AND_TEST_PORT_FEATURE: ++ if (wValue != UHF_PORT_L1) { ++ goto error; ++ } ++ { ++ int portnum, hird, devaddr, remwake; ++ glpmcfg_data_t lpmcfg; ++ uint32_t time_usecs; ++ gintsts_data_t gintsts; ++ gintmsk_data_t gintmsk; ++ ++ if (!dwc_otg_get_param_lpm_enable(core_if)) { ++ goto error; ++ } ++ if (wValue != UHF_PORT_L1 || wLength != 1) { ++ goto error; ++ } ++ /* Check if the port currently is in SLEEP state */ ++ lpmcfg.d32 = ++ DWC_READ_REG32(&core_if->core_global_regs->glpmcfg); ++ if (lpmcfg.b.prt_sleep_sts) { ++ DWC_INFO("Port is already in sleep mode\n"); ++ buf[0] = 0; /* Return success */ ++ break; ++ } ++ ++ portnum = wIndex & 0xf; ++ hird = (wIndex >> 4) & 0xf; ++ devaddr = (wIndex >> 8) & 0x7f; ++ remwake = (wIndex >> 15); ++ ++ if (portnum != 1) { ++ retval = -DWC_E_INVALID; ++ DWC_WARN ++ ("Wrong port number(%d) in SetandTestPortFeature request\n", ++ portnum); ++ break; ++ } ++ ++ DWC_PRINTF ++ ("SetandTestPortFeature request: portnum = %d, hird = %d, devaddr = %d, rewake = %d\n", ++ portnum, hird, devaddr, remwake); ++ /* Disable LPM interrupt */ ++ gintmsk.d32 = 0; ++ gintmsk.b.lpmtranrcvd = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, ++ gintmsk.d32, 0); ++ ++ if (dwc_otg_hcd_send_lpm ++ (dwc_otg_hcd, devaddr, hird, remwake)) { ++ retval = -DWC_E_INVALID; ++ break; ++ } ++ ++ time_usecs = 10 * (lpmcfg.b.retry_count + 1); ++ /* We will consider timeout if time_usecs microseconds pass, ++ * and we don't receive LPM transaction status. ++ * After receiving non-error responce(ACK/NYET/STALL) from device, ++ * core will set lpmtranrcvd bit. ++ */ ++ do { ++ gintsts.d32 = ++ DWC_READ_REG32(&core_if->core_global_regs->gintsts); ++ if (gintsts.b.lpmtranrcvd) { ++ break; ++ } ++ dwc_udelay(1); ++ } while (--time_usecs); ++ /* lpm_int bit will be cleared in LPM interrupt handler */ ++ ++ /* Now fill status ++ * 0x00 - Success ++ * 0x10 - NYET ++ * 0x11 - Timeout ++ */ ++ if (!gintsts.b.lpmtranrcvd) { ++ buf[0] = 0x3; /* Completion code is Timeout */ ++ dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd); ++ } else { ++ lpmcfg.d32 = ++ DWC_READ_REG32(&core_if->core_global_regs->glpmcfg); ++ if (lpmcfg.b.lpm_resp == 0x3) { ++ /* ACK responce from the device */ ++ buf[0] = 0x00; /* Success */ ++ } else if (lpmcfg.b.lpm_resp == 0x2) { ++ /* NYET responce from the device */ ++ buf[0] = 0x2; ++ } else { ++ /* Otherwise responce with Timeout */ ++ buf[0] = 0x3; ++ } ++ } ++ DWC_PRINTF("Device responce to LPM trans is %x\n", ++ lpmcfg.b.lpm_resp); ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, ++ gintmsk.d32); ++ ++ break; ++ } ++#endif /* CONFIG_USB_DWC_OTG_LPM */ ++ default: ++error: ++ retval = -DWC_E_INVALID; ++ DWC_WARN("DWC OTG HCD - " ++ "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n", ++ typeReq, wIndex, wValue); ++ break; ++ } ++ ++ return retval; ++} ++ ++#ifdef CONFIG_USB_DWC_OTG_LPM ++/** Returns index of host channel to perform LPM transaction. */ ++int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, uint8_t devaddr) ++{ ++ dwc_otg_core_if_t *core_if = hcd->core_if; ++ dwc_hc_t *hc; ++ hcchar_data_t hcchar; ++ gintmsk_data_t gintmsk = {.d32 = 0 }; ++ ++ if (DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) { ++ DWC_PRINTF("No free channel to select for LPM transaction\n"); ++ return -1; ++ } ++ ++ hc = DWC_CIRCLEQ_FIRST(&hcd->free_hc_list); ++ ++ /* Mask host channel interrupts. */ ++ gintmsk.b.hcintr = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0); ++ ++ /* Fill fields that core needs for LPM transaction */ ++ hcchar.b.devaddr = devaddr; ++ hcchar.b.epnum = 0; ++ hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL; ++ hcchar.b.mps = 64; ++ hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW); ++ hcchar.b.epdir = 0; /* OUT */ ++ DWC_WRITE_REG32(&core_if->host_if->hc_regs[hc->hc_num]->hcchar, ++ hcchar.d32); ++ ++ /* Remove the host channel from the free list. */ ++ DWC_CIRCLEQ_REMOVE_INIT(&hcd->free_hc_list, hc, hc_list_entry); ++ ++ DWC_PRINTF("hcnum = %d devaddr = %d\n", hc->hc_num, devaddr); ++ ++ return hc->hc_num; ++} ++ ++/** Release hc after performing LPM transaction */ ++void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd) ++{ ++ dwc_hc_t *hc; ++ glpmcfg_data_t lpmcfg; ++ uint8_t hc_num; ++ ++ lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg); ++ hc_num = lpmcfg.b.lpm_chan_index; ++ ++ hc = hcd->hc_ptr_array[hc_num]; ++ ++ DWC_PRINTF("Freeing channel %d after LPM\n", hc_num); ++ /* Return host channel to free list */ ++ DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry); ++} ++ ++int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, uint8_t hird, ++ uint8_t bRemoteWake) ++{ ++ glpmcfg_data_t lpmcfg; ++ pcgcctl_data_t pcgcctl = {.d32 = 0 }; ++ int channel; ++ ++ channel = dwc_otg_hcd_get_hc_for_lpm_tran(hcd, devaddr); ++ if (channel < 0) { ++ return channel; ++ } ++ ++ pcgcctl.b.enbl_sleep_gating = 1; ++ DWC_MODIFY_REG32(hcd->core_if->pcgcctl, 0, pcgcctl.d32); ++ ++ /* Read LPM config register */ ++ lpmcfg.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->glpmcfg); ++ ++ /* Program LPM transaction fields */ ++ lpmcfg.b.rem_wkup_en = bRemoteWake; ++ lpmcfg.b.hird = hird; ++ lpmcfg.b.hird_thres = 0x1c; ++ lpmcfg.b.lpm_chan_index = channel; ++ lpmcfg.b.en_utmi_sleep = 1; ++ /* Program LPM config register */ ++ DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32); ++ ++ /* Send LPM transaction */ ++ lpmcfg.b.send_lpm = 1; ++ DWC_WRITE_REG32(&hcd->core_if->core_global_regs->glpmcfg, lpmcfg.d32); ++ ++ return 0; ++} ++ ++#endif /* CONFIG_USB_DWC_OTG_LPM */ ++ ++int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port) ++{ ++ int retval; ++ ++ if (port != 1) { ++ return -DWC_E_INVALID; ++ } ++ ++ retval = (hcd->flags.b.port_connect_status_change || ++ hcd->flags.b.port_reset_change || ++ hcd->flags.b.port_enable_change || ++ hcd->flags.b.port_suspend_change || ++ hcd->flags.b.port_over_current_change); ++#ifdef DEBUG ++ if (retval) { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:" ++ " Root port status changed\n"); ++ DWC_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n", ++ hcd->flags.b.port_connect_status_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n", ++ hcd->flags.b.port_reset_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n", ++ hcd->flags.b.port_enable_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n", ++ hcd->flags.b.port_suspend_change); ++ DWC_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n", ++ hcd->flags.b.port_over_current_change); ++ } ++#endif ++ return retval; ++} ++ ++int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * dwc_otg_hcd) ++{ ++ hfnum_data_t hfnum; ++ hfnum.d32 = ++ DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs-> ++ hfnum); ++ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n", ++ hfnum.b.frnum); ++#endif ++ return hfnum.b.frnum; ++} ++ ++int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd, ++ struct dwc_otg_hcd_function_ops *fops) ++{ ++ int retval = 0; ++ ++ hcd->fops = fops; ++ if (!dwc_otg_is_device_mode(hcd->core_if) && ++ (!hcd->core_if->adp_enable || hcd->core_if->adp.adp_started)) { ++ dwc_otg_hcd_reinit(hcd); ++ } else { ++ retval = -DWC_E_NO_DEVICE; ++ } ++ ++ return retval; ++} ++ ++void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd) ++{ ++ return hcd->priv; ++} ++ ++void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data) ++{ ++ hcd->priv = priv_data; ++} ++ ++uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd) ++{ ++ return hcd->otg_port; ++} ++ ++uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd) ++{ ++ uint32_t is_b_host; ++ if (hcd->core_if->op_state == B_HOST) { ++ is_b_host = 1; ++ } else { ++ is_b_host = 0; ++ } ++ ++ return is_b_host; ++} ++ ++dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd, ++ int iso_desc_count, int atomic_alloc) ++{ ++ dwc_otg_hcd_urb_t *dwc_otg_urb; ++ uint32_t size; ++ ++ size = ++ sizeof(*dwc_otg_urb) + ++ iso_desc_count * sizeof(struct dwc_otg_hcd_iso_packet_desc); ++ if (atomic_alloc) ++ dwc_otg_urb = DWC_ALLOC_ATOMIC(size); ++ else ++ dwc_otg_urb = DWC_ALLOC(size); ++ ++ if (dwc_otg_urb) ++ dwc_otg_urb->packet_count = iso_desc_count; ++ else { ++ DWC_ERROR("**** DWC OTG HCD URB alloc - " ++ "%salloc of %db failed\n", ++ atomic_alloc?"atomic ":"", size); ++ } ++ return dwc_otg_urb; ++} ++ ++void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * dwc_otg_urb, ++ uint8_t dev_addr, uint8_t ep_num, ++ uint8_t ep_type, uint8_t ep_dir, uint16_t mps) ++{ ++ dwc_otg_hcd_fill_pipe(&dwc_otg_urb->pipe_info, dev_addr, ep_num, ++ ep_type, ep_dir, mps); ++#if 0 ++ DWC_PRINTF ++ ("addr = %d, ep_num = %d, ep_dir = 0x%x, ep_type = 0x%x, mps = %d\n", ++ dev_addr, ep_num, ep_dir, ep_type, mps); ++#endif ++} ++ ++void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * dwc_otg_urb, ++ void *urb_handle, void *buf, dwc_dma_t dma, ++ uint32_t buflen, void *setup_packet, ++ dwc_dma_t setup_dma, uint32_t flags, ++ uint16_t interval) ++{ ++ dwc_otg_urb->priv = urb_handle; ++ dwc_otg_urb->buf = buf; ++ dwc_otg_urb->dma = dma; ++ dwc_otg_urb->length = buflen; ++ dwc_otg_urb->setup_packet = setup_packet; ++ dwc_otg_urb->setup_dma = setup_dma; ++ dwc_otg_urb->flags = flags; ++ dwc_otg_urb->interval = interval; ++ dwc_otg_urb->status = -DWC_E_IN_PROGRESS; ++} ++ ++uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb) ++{ ++ return dwc_otg_urb->status; ++} ++ ++uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * dwc_otg_urb) ++{ ++ return dwc_otg_urb->actual_length; ++} ++ ++uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * dwc_otg_urb) ++{ ++ return dwc_otg_urb->error_count; ++} ++ ++void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb, ++ int desc_num, uint32_t offset, ++ uint32_t length) ++{ ++ dwc_otg_urb->iso_descs[desc_num].offset = offset; ++ dwc_otg_urb->iso_descs[desc_num].length = length; ++} ++ ++uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * dwc_otg_urb, ++ int desc_num) ++{ ++ return dwc_otg_urb->iso_descs[desc_num].status; ++} ++ ++uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t * ++ dwc_otg_urb, int desc_num) ++{ ++ return dwc_otg_urb->iso_descs[desc_num].actual_length; ++} ++ ++int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, void *ep_handle) ++{ ++ int allocated = 0; ++ dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle; ++ ++ if (qh) { ++ if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) { ++ allocated = 1; ++ } ++ } ++ return allocated; ++} ++ ++int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle) ++{ ++ dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle; ++ int freed = 0; ++ DWC_ASSERT(qh, "qh is not allocated\n"); ++ ++ if (DWC_LIST_EMPTY(&qh->qh_list_entry)) { ++ freed = 1; ++ } ++ ++ return freed; ++} ++ ++uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, void *ep_handle) ++{ ++ dwc_otg_qh_t *qh = (dwc_otg_qh_t *) ep_handle; ++ DWC_ASSERT(qh, "qh is not allocated\n"); ++ return qh->usecs; ++} ++ ++void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd) ++{ ++#ifdef DEBUG ++ int num_channels; ++ int i; ++ gnptxsts_data_t np_tx_status; ++ hptxsts_data_t p_tx_status; ++ ++ num_channels = hcd->core_if->core_params->host_channels; ++ DWC_PRINTF("\n"); ++ DWC_PRINTF ++ ("************************************************************\n"); ++ DWC_PRINTF("HCD State:\n"); ++ DWC_PRINTF(" Num channels: %d\n", num_channels); ++ for (i = 0; i < num_channels; i++) { ++ dwc_hc_t *hc = hcd->hc_ptr_array[i]; ++ DWC_PRINTF(" Channel %d:\n", i); ++ DWC_PRINTF(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", ++ hc->dev_addr, hc->ep_num, hc->ep_is_in); ++ DWC_PRINTF(" speed: %d\n", hc->speed); ++ DWC_PRINTF(" ep_type: %d\n", hc->ep_type); ++ DWC_PRINTF(" max_packet: %d\n", hc->max_packet); ++ DWC_PRINTF(" data_pid_start: %d\n", hc->data_pid_start); ++ DWC_PRINTF(" multi_count: %d\n", hc->multi_count); ++ DWC_PRINTF(" xfer_started: %d\n", hc->xfer_started); ++ DWC_PRINTF(" xfer_buff: %p\n", hc->xfer_buff); ++ DWC_PRINTF(" xfer_len: %d\n", hc->xfer_len); ++ DWC_PRINTF(" xfer_count: %d\n", hc->xfer_count); ++ DWC_PRINTF(" halt_on_queue: %d\n", hc->halt_on_queue); ++ DWC_PRINTF(" halt_pending: %d\n", hc->halt_pending); ++ DWC_PRINTF(" halt_status: %d\n", hc->halt_status); ++ DWC_PRINTF(" do_split: %d\n", hc->do_split); ++ DWC_PRINTF(" complete_split: %d\n", hc->complete_split); ++ DWC_PRINTF(" hub_addr: %d\n", hc->hub_addr); ++ DWC_PRINTF(" port_addr: %d\n", hc->port_addr); ++ DWC_PRINTF(" xact_pos: %d\n", hc->xact_pos); ++ DWC_PRINTF(" requests: %d\n", hc->requests); ++ DWC_PRINTF(" qh: %p\n", hc->qh); ++ if (hc->xfer_started) { ++ hfnum_data_t hfnum; ++ hcchar_data_t hcchar; ++ hctsiz_data_t hctsiz; ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; ++ hfnum.d32 = ++ DWC_READ_REG32(&hcd->core_if-> ++ host_if->host_global_regs->hfnum); ++ hcchar.d32 = ++ DWC_READ_REG32(&hcd->core_if->host_if-> ++ hc_regs[i]->hcchar); ++ hctsiz.d32 = ++ DWC_READ_REG32(&hcd->core_if->host_if-> ++ hc_regs[i]->hctsiz); ++ hcint.d32 = ++ DWC_READ_REG32(&hcd->core_if->host_if-> ++ hc_regs[i]->hcint); ++ hcintmsk.d32 = ++ DWC_READ_REG32(&hcd->core_if->host_if-> ++ hc_regs[i]->hcintmsk); ++ DWC_PRINTF(" hfnum: 0x%08x\n", hfnum.d32); ++ DWC_PRINTF(" hcchar: 0x%08x\n", hcchar.d32); ++ DWC_PRINTF(" hctsiz: 0x%08x\n", hctsiz.d32); ++ DWC_PRINTF(" hcint: 0x%08x\n", hcint.d32); ++ DWC_PRINTF(" hcintmsk: 0x%08x\n", hcintmsk.d32); ++ } ++ if (hc->xfer_started && hc->qh) { ++ dwc_otg_qtd_t *qtd; ++ dwc_otg_hcd_urb_t *urb; ++ ++ DWC_CIRCLEQ_FOREACH(qtd, &hc->qh->qtd_list, qtd_list_entry) { ++ if (!qtd->in_process) ++ break; ++ ++ urb = qtd->urb; ++ DWC_PRINTF(" URB Info:\n"); ++ DWC_PRINTF(" qtd: %p, urb: %p\n", qtd, urb); ++ if (urb) { ++ DWC_PRINTF(" Dev: %d, EP: %d %s\n", ++ dwc_otg_hcd_get_dev_addr(&urb-> ++ pipe_info), ++ dwc_otg_hcd_get_ep_num(&urb-> ++ pipe_info), ++ dwc_otg_hcd_is_pipe_in(&urb-> ++ pipe_info) ? ++ "IN" : "OUT"); ++ DWC_PRINTF(" Max packet size: %d\n", ++ dwc_otg_hcd_get_mps(&urb-> ++ pipe_info)); ++ DWC_PRINTF(" transfer_buffer: %p\n", ++ urb->buf); ++ DWC_PRINTF(" transfer_dma: %p\n", ++ (void *)urb->dma); ++ DWC_PRINTF(" transfer_buffer_length: %d\n", ++ urb->length); ++ DWC_PRINTF(" actual_length: %d\n", ++ urb->actual_length); ++ } ++ } ++ } ++ } ++ DWC_PRINTF(" non_periodic_channels: %d\n", hcd->non_periodic_channels); ++ DWC_PRINTF(" periodic_channels: %d\n", hcd->periodic_channels); ++ DWC_PRINTF(" periodic_usecs: %d\n", hcd->periodic_usecs); ++ np_tx_status.d32 = ++ DWC_READ_REG32(&hcd->core_if->core_global_regs->gnptxsts); ++ DWC_PRINTF(" NP Tx Req Queue Space Avail: %d\n", ++ np_tx_status.b.nptxqspcavail); ++ DWC_PRINTF(" NP Tx FIFO Space Avail: %d\n", ++ np_tx_status.b.nptxfspcavail); ++ p_tx_status.d32 = ++ DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hptxsts); ++ DWC_PRINTF(" P Tx Req Queue Space Avail: %d\n", ++ p_tx_status.b.ptxqspcavail); ++ DWC_PRINTF(" P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail); ++ dwc_otg_hcd_dump_frrem(hcd); ++ dwc_otg_dump_global_registers(hcd->core_if); ++ dwc_otg_dump_host_registers(hcd->core_if); ++ DWC_PRINTF ++ ("************************************************************\n"); ++ DWC_PRINTF("\n"); ++#endif ++} ++ ++#ifdef DEBUG ++void dwc_print_setup_data(uint8_t * setup) ++{ ++ int i; ++ if (CHK_DEBUG_LEVEL(DBG_HCD)) { ++ DWC_PRINTF("Setup Data = MSB "); ++ for (i = 7; i >= 0; i--) ++ DWC_PRINTF("%02x ", setup[i]); ++ DWC_PRINTF("\n"); ++ DWC_PRINTF(" bmRequestType Tranfer = %s\n", ++ (setup[0] & 0x80) ? "Device-to-Host" : ++ "Host-to-Device"); ++ DWC_PRINTF(" bmRequestType Type = "); ++ switch ((setup[0] & 0x60) >> 5) { ++ case 0: ++ DWC_PRINTF("Standard\n"); ++ break; ++ case 1: ++ DWC_PRINTF("Class\n"); ++ break; ++ case 2: ++ DWC_PRINTF("Vendor\n"); ++ break; ++ case 3: ++ DWC_PRINTF("Reserved\n"); ++ break; ++ } ++ DWC_PRINTF(" bmRequestType Recipient = "); ++ switch (setup[0] & 0x1f) { ++ case 0: ++ DWC_PRINTF("Device\n"); ++ break; ++ case 1: ++ DWC_PRINTF("Interface\n"); ++ break; ++ case 2: ++ DWC_PRINTF("Endpoint\n"); ++ break; ++ case 3: ++ DWC_PRINTF("Other\n"); ++ break; ++ default: ++ DWC_PRINTF("Reserved\n"); ++ break; ++ } ++ DWC_PRINTF(" bRequest = 0x%0x\n", setup[1]); ++ DWC_PRINTF(" wValue = 0x%0x\n", *((uint16_t *) & setup[2])); ++ DWC_PRINTF(" wIndex = 0x%0x\n", *((uint16_t *) & setup[4])); ++ DWC_PRINTF(" wLength = 0x%0x\n\n", *((uint16_t *) & setup[6])); ++ } ++} ++#endif ++ ++void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd) ++{ ++#if 0 ++ DWC_PRINTF("Frame remaining at SOF:\n"); ++ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", ++ hcd->frrem_samples, hcd->frrem_accum, ++ (hcd->frrem_samples > 0) ? ++ hcd->frrem_accum / hcd->frrem_samples : 0); ++ ++ DWC_PRINTF("\n"); ++ DWC_PRINTF("Frame remaining at start_transfer (uframe 7):\n"); ++ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", ++ hcd->core_if->hfnum_7_samples, ++ hcd->core_if->hfnum_7_frrem_accum, ++ (hcd->core_if->hfnum_7_samples > ++ 0) ? hcd->core_if->hfnum_7_frrem_accum / ++ hcd->core_if->hfnum_7_samples : 0); ++ DWC_PRINTF("Frame remaining at start_transfer (uframe 0):\n"); ++ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", ++ hcd->core_if->hfnum_0_samples, ++ hcd->core_if->hfnum_0_frrem_accum, ++ (hcd->core_if->hfnum_0_samples > ++ 0) ? hcd->core_if->hfnum_0_frrem_accum / ++ hcd->core_if->hfnum_0_samples : 0); ++ DWC_PRINTF("Frame remaining at start_transfer (uframe 1-6):\n"); ++ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", ++ hcd->core_if->hfnum_other_samples, ++ hcd->core_if->hfnum_other_frrem_accum, ++ (hcd->core_if->hfnum_other_samples > ++ 0) ? hcd->core_if->hfnum_other_frrem_accum / ++ hcd->core_if->hfnum_other_samples : 0); ++ ++ DWC_PRINTF("\n"); ++ DWC_PRINTF("Frame remaining at sample point A (uframe 7):\n"); ++ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", ++ hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a, ++ (hcd->hfnum_7_samples_a > 0) ? ++ hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0); ++ DWC_PRINTF("Frame remaining at sample point A (uframe 0):\n"); ++ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", ++ hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a, ++ (hcd->hfnum_0_samples_a > 0) ? ++ hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0); ++ DWC_PRINTF("Frame remaining at sample point A (uframe 1-6):\n"); ++ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", ++ hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a, ++ (hcd->hfnum_other_samples_a > 0) ? ++ hcd->hfnum_other_frrem_accum_a / ++ hcd->hfnum_other_samples_a : 0); ++ ++ DWC_PRINTF("\n"); ++ DWC_PRINTF("Frame remaining at sample point B (uframe 7):\n"); ++ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", ++ hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b, ++ (hcd->hfnum_7_samples_b > 0) ? ++ hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0); ++ DWC_PRINTF("Frame remaining at sample point B (uframe 0):\n"); ++ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", ++ hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b, ++ (hcd->hfnum_0_samples_b > 0) ? ++ hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0); ++ DWC_PRINTF("Frame remaining at sample point B (uframe 1-6):\n"); ++ DWC_PRINTF(" samples %u, accum %llu, avg %llu\n", ++ hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b, ++ (hcd->hfnum_other_samples_b > 0) ? ++ hcd->hfnum_other_frrem_accum_b / ++ hcd->hfnum_other_samples_b : 0); ++#endif ++} ++ ++#endif /* DWC_DEVICE_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c 2014-03-13 12:46:39.516097989 +0100 +@@ -0,0 +1,1132 @@ ++/*========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_ddma.c $ ++ * $Revision: #10 $ ++ * $Date: 2011/10/20 $ ++ * $Change: 1869464 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++ ++/** @file ++ * This file contains Descriptor DMA support implementation for host mode. ++ */ ++ ++#include "dwc_otg_hcd.h" ++#include "dwc_otg_regs.h" ++ ++extern bool microframe_schedule; ++ ++static inline uint8_t frame_list_idx(uint16_t frame) ++{ ++ return (frame & (MAX_FRLIST_EN_NUM - 1)); ++} ++ ++static inline uint16_t desclist_idx_inc(uint16_t idx, uint16_t inc, uint8_t speed) ++{ ++ return (idx + inc) & ++ (((speed == ++ DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC : ++ MAX_DMA_DESC_NUM_GENERIC) - 1); ++} ++ ++static inline uint16_t desclist_idx_dec(uint16_t idx, uint16_t inc, uint8_t speed) ++{ ++ return (idx - inc) & ++ (((speed == ++ DWC_OTG_EP_SPEED_HIGH) ? MAX_DMA_DESC_NUM_HS_ISOC : ++ MAX_DMA_DESC_NUM_GENERIC) - 1); ++} ++ ++static inline uint16_t max_desc_num(dwc_otg_qh_t * qh) ++{ ++ return (((qh->ep_type == UE_ISOCHRONOUS) ++ && (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH)) ++ ? MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC); ++} ++static inline uint16_t frame_incr_val(dwc_otg_qh_t * qh) ++{ ++ return ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) ++ ? ((qh->interval + 8 - 1) / 8) ++ : qh->interval); ++} ++ ++static int desc_list_alloc(dwc_otg_qh_t * qh) ++{ ++ int retval = 0; ++ ++ qh->desc_list = (dwc_otg_host_dma_desc_t *) ++ DWC_DMA_ALLOC(sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh), ++ &qh->desc_list_dma); ++ ++ if (!qh->desc_list) { ++ retval = -DWC_E_NO_MEMORY; ++ DWC_ERROR("%s: DMA descriptor list allocation failed\n", __func__); ++ ++ } ++ ++ dwc_memset(qh->desc_list, 0x00, ++ sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh)); ++ ++ qh->n_bytes = ++ (uint32_t *) DWC_ALLOC(sizeof(uint32_t) * max_desc_num(qh)); ++ ++ if (!qh->n_bytes) { ++ retval = -DWC_E_NO_MEMORY; ++ DWC_ERROR ++ ("%s: Failed to allocate array for descriptors' size actual values\n", ++ __func__); ++ ++ } ++ return retval; ++ ++} ++ ++static void desc_list_free(dwc_otg_qh_t * qh) ++{ ++ if (qh->desc_list) { ++ DWC_DMA_FREE(max_desc_num(qh), qh->desc_list, ++ qh->desc_list_dma); ++ qh->desc_list = NULL; ++ } ++ ++ if (qh->n_bytes) { ++ DWC_FREE(qh->n_bytes); ++ qh->n_bytes = NULL; ++ } ++} ++ ++static int frame_list_alloc(dwc_otg_hcd_t * hcd) ++{ ++ int retval = 0; ++ if (hcd->frame_list) ++ return 0; ++ ++ hcd->frame_list = DWC_DMA_ALLOC(4 * MAX_FRLIST_EN_NUM, ++ &hcd->frame_list_dma); ++ if (!hcd->frame_list) { ++ retval = -DWC_E_NO_MEMORY; ++ DWC_ERROR("%s: Frame List allocation failed\n", __func__); ++ } ++ ++ dwc_memset(hcd->frame_list, 0x00, 4 * MAX_FRLIST_EN_NUM); ++ ++ return retval; ++} ++ ++static void frame_list_free(dwc_otg_hcd_t * hcd) ++{ ++ if (!hcd->frame_list) ++ return; ++ ++ DWC_DMA_FREE(4 * MAX_FRLIST_EN_NUM, hcd->frame_list, hcd->frame_list_dma); ++ hcd->frame_list = NULL; ++} ++ ++static void per_sched_enable(dwc_otg_hcd_t * hcd, uint16_t fr_list_en) ++{ ++ ++ hcfg_data_t hcfg; ++ ++ hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg); ++ ++ if (hcfg.b.perschedena) { ++ /* already enabled */ ++ return; ++ } ++ ++ DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hflbaddr, ++ hcd->frame_list_dma); ++ ++ switch (fr_list_en) { ++ case 64: ++ hcfg.b.frlisten = 3; ++ break; ++ case 32: ++ hcfg.b.frlisten = 2; ++ break; ++ case 16: ++ hcfg.b.frlisten = 1; ++ break; ++ case 8: ++ hcfg.b.frlisten = 0; ++ break; ++ default: ++ break; ++ } ++ ++ hcfg.b.perschedena = 1; ++ ++ DWC_DEBUGPL(DBG_HCD, "Enabling Periodic schedule\n"); ++ DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32); ++ ++} ++ ++static void per_sched_disable(dwc_otg_hcd_t * hcd) ++{ ++ hcfg_data_t hcfg; ++ ++ hcfg.d32 = DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hcfg); ++ ++ if (!hcfg.b.perschedena) { ++ /* already disabled */ ++ return; ++ } ++ hcfg.b.perschedena = 0; ++ ++ DWC_DEBUGPL(DBG_HCD, "Disabling Periodic schedule\n"); ++ DWC_WRITE_REG32(&hcd->core_if->host_if->host_global_regs->hcfg, hcfg.d32); ++} ++ ++/* ++ * Activates/Deactivates FrameList entries for the channel ++ * based on endpoint servicing period. ++ */ ++void update_frame_list(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, uint8_t enable) ++{ ++ uint16_t i, j, inc; ++ dwc_hc_t *hc = NULL; ++ ++ if (!qh->channel) { ++ DWC_ERROR("qh->channel = %p", qh->channel); ++ return; ++ } ++ ++ if (!hcd) { ++ DWC_ERROR("------hcd = %p", hcd); ++ return; ++ } ++ ++ if (!hcd->frame_list) { ++ DWC_ERROR("-------hcd->frame_list = %p", hcd->frame_list); ++ return; ++ } ++ ++ hc = qh->channel; ++ inc = frame_incr_val(qh); ++ if (qh->ep_type == UE_ISOCHRONOUS) ++ i = frame_list_idx(qh->sched_frame); ++ else ++ i = 0; ++ ++ j = i; ++ do { ++ if (enable) ++ hcd->frame_list[j] |= (1 << hc->hc_num); ++ else ++ hcd->frame_list[j] &= ~(1 << hc->hc_num); ++ j = (j + inc) & (MAX_FRLIST_EN_NUM - 1); ++ } ++ while (j != i); ++ if (!enable) ++ return; ++ hc->schinfo = 0; ++ if (qh->channel->speed == DWC_OTG_EP_SPEED_HIGH) { ++ j = 1; ++ /* TODO - check this */ ++ inc = (8 + qh->interval - 1) / qh->interval; ++ for (i = 0; i < inc; i++) { ++ hc->schinfo |= j; ++ j = j << qh->interval; ++ } ++ } else { ++ hc->schinfo = 0xff; ++ } ++} ++ ++#if 1 ++void dump_frame_list(dwc_otg_hcd_t * hcd) ++{ ++ int i = 0; ++ DWC_PRINTF("--FRAME LIST (hex) --\n"); ++ for (i = 0; i < MAX_FRLIST_EN_NUM; i++) { ++ DWC_PRINTF("%x\t", hcd->frame_list[i]); ++ if (!(i % 8) && i) ++ DWC_PRINTF("\n"); ++ } ++ DWC_PRINTF("\n----\n"); ++ ++} ++#endif ++ ++static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ dwc_irqflags_t flags; ++ dwc_spinlock_t *channel_lock = hcd->channel_lock; ++ ++ dwc_hc_t *hc = qh->channel; ++ if (dwc_qh_is_non_per(qh)) { ++ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); ++ if (!microframe_schedule) ++ hcd->non_periodic_channels--; ++ else ++ hcd->available_host_channels++; ++ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); ++ } else ++ update_frame_list(hcd, qh, 0); ++ ++ /* ++ * The condition is added to prevent double cleanup try in case of device ++ * disconnect. See channel cleanup in dwc_otg_hcd_disconnect_cb(). ++ */ ++ if (hc->qh) { ++ dwc_otg_hc_cleanup(hcd->core_if, hc); ++ DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry); ++ hc->qh = NULL; ++ } ++ ++ qh->channel = NULL; ++ qh->ntd = 0; ++ ++ if (qh->desc_list) { ++ dwc_memset(qh->desc_list, 0x00, ++ sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh)); ++ } ++} ++ ++/** ++ * Initializes a QH structure's Descriptor DMA related members. ++ * Allocates memory for descriptor list. ++ * On first periodic QH, allocates memory for FrameList ++ * and enables periodic scheduling. ++ * ++ * @param hcd The HCD state structure for the DWC OTG controller. ++ * @param qh The QH to init. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ int retval = 0; ++ ++ if (qh->do_split) { ++ DWC_ERROR("SPLIT Transfers are not supported in Descriptor DMA.\n"); ++ return -1; ++ } ++ ++ retval = desc_list_alloc(qh); ++ ++ if ((retval == 0) ++ && (qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)) { ++ if (!hcd->frame_list) { ++ retval = frame_list_alloc(hcd); ++ /* Enable periodic schedule on first periodic QH */ ++ if (retval == 0) ++ per_sched_enable(hcd, MAX_FRLIST_EN_NUM); ++ } ++ } ++ ++ qh->ntd = 0; ++ ++ return retval; ++} ++ ++/** ++ * Frees descriptor list memory associated with the QH. ++ * If QH is periodic and the last, frees FrameList memory ++ * and disables periodic scheduling. ++ * ++ * @param hcd The HCD state structure for the DWC OTG controller. ++ * @param qh The QH to init. ++ */ ++void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ desc_list_free(qh); ++ ++ /* ++ * Channel still assigned due to some reasons. ++ * Seen on Isoc URB dequeue. Channel halted but no subsequent ++ * ChHalted interrupt to release the channel. Afterwards ++ * when it comes here from endpoint disable routine ++ * channel remains assigned. ++ */ ++ if (qh->channel) ++ release_channel_ddma(hcd, qh); ++ ++ if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT) ++ && (microframe_schedule || !hcd->periodic_channels) && hcd->frame_list) { ++ ++ per_sched_disable(hcd); ++ frame_list_free(hcd); ++ } ++} ++ ++static uint8_t frame_to_desc_idx(dwc_otg_qh_t * qh, uint16_t frame_idx) ++{ ++ if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) { ++ /* ++ * Descriptor set(8 descriptors) index ++ * which is 8-aligned. ++ */ ++ return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8; ++ } else { ++ return (frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1)); ++ } ++} ++ ++/* ++ * Determine starting frame for Isochronous transfer. ++ * Few frames skipped to prevent race condition with HC. ++ */ ++static uint8_t calc_starting_frame(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, ++ uint8_t * skip_frames) ++{ ++ uint16_t frame = 0; ++ hcd->frame_number = dwc_otg_hcd_get_frame_number(hcd); ++ ++ /* sched_frame is always frame number(not uFrame) both in FS and HS !! */ ++ ++ /* ++ * skip_frames is used to limit activated descriptors number ++ * to avoid the situation when HC services the last activated ++ * descriptor firstly. ++ * Example for FS: ++ * Current frame is 1, scheduled frame is 3. Since HC always fetches the descriptor ++ * corresponding to curr_frame+1, the descriptor corresponding to frame 2 ++ * will be fetched. If the number of descriptors is max=64 (or greather) the ++ * list will be fully programmed with Active descriptors and it is possible ++ * case(rare) that the latest descriptor(considering rollback) corresponding ++ * to frame 2 will be serviced first. HS case is more probable because, in fact, ++ * up to 11 uframes(16 in the code) may be skipped. ++ */ ++ if (qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) { ++ /* ++ * Consider uframe counter also, to start xfer asap. ++ * If half of the frame elapsed skip 2 frames otherwise ++ * just 1 frame. ++ * Starting descriptor index must be 8-aligned, so ++ * if the current frame is near to complete the next one ++ * is skipped as well. ++ */ ++ ++ if (dwc_micro_frame_num(hcd->frame_number) >= 5) { ++ *skip_frames = 2 * 8; ++ frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames); ++ } else { ++ *skip_frames = 1 * 8; ++ frame = dwc_frame_num_inc(hcd->frame_number, *skip_frames); ++ } ++ ++ frame = dwc_full_frame_num(frame); ++ } else { ++ /* ++ * Two frames are skipped for FS - the current and the next. ++ * But for descriptor programming, 1 frame(descriptor) is enough, ++ * see example above. ++ */ ++ *skip_frames = 1; ++ frame = dwc_frame_num_inc(hcd->frame_number, 2); ++ } ++ ++ return frame; ++} ++ ++/* ++ * Calculate initial descriptor index for isochronous transfer ++ * based on scheduled frame. ++ */ ++static uint8_t recalc_initial_desc_idx(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ uint16_t frame = 0, fr_idx, fr_idx_tmp; ++ uint8_t skip_frames = 0; ++ /* ++ * With current ISOC processing algorithm the channel is being ++ * released when no more QTDs in the list(qh->ntd == 0). ++ * Thus this function is called only when qh->ntd == 0 and qh->channel == 0. ++ * ++ * So qh->channel != NULL branch is not used and just not removed from the ++ * source file. It is required for another possible approach which is, ++ * do not disable and release the channel when ISOC session completed, ++ * just move QH to inactive schedule until new QTD arrives. ++ * On new QTD, the QH moved back to 'ready' schedule, ++ * starting frame and therefore starting desc_index are recalculated. ++ * In this case channel is released only on ep_disable. ++ */ ++ ++ /* Calculate starting descriptor index. For INTERRUPT endpoint it is always 0. */ ++ if (qh->channel) { ++ frame = calc_starting_frame(hcd, qh, &skip_frames); ++ /* ++ * Calculate initial descriptor index based on FrameList current bitmap ++ * and servicing period. ++ */ ++ fr_idx_tmp = frame_list_idx(frame); ++ fr_idx = ++ (MAX_FRLIST_EN_NUM + frame_list_idx(qh->sched_frame) - ++ fr_idx_tmp) ++ % frame_incr_val(qh); ++ fr_idx = (fr_idx + fr_idx_tmp) % MAX_FRLIST_EN_NUM; ++ } else { ++ qh->sched_frame = calc_starting_frame(hcd, qh, &skip_frames); ++ fr_idx = frame_list_idx(qh->sched_frame); ++ } ++ ++ qh->td_first = qh->td_last = frame_to_desc_idx(qh, fr_idx); ++ ++ return skip_frames; ++} ++ ++#define ISOC_URB_GIVEBACK_ASAP ++ ++#define MAX_ISOC_XFER_SIZE_FS 1023 ++#define MAX_ISOC_XFER_SIZE_HS 3072 ++#define DESCNUM_THRESHOLD 4 ++ ++static void init_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, ++ uint8_t skip_frames) ++{ ++ struct dwc_otg_hcd_iso_packet_desc *frame_desc; ++ dwc_otg_qtd_t *qtd; ++ dwc_otg_host_dma_desc_t *dma_desc; ++ uint16_t idx, inc, n_desc, ntd_max, max_xfer_size; ++ ++ idx = qh->td_last; ++ inc = qh->interval; ++ n_desc = 0; ++ ++ ntd_max = (max_desc_num(qh) + qh->interval - 1) / qh->interval; ++ if (skip_frames && !qh->channel) ++ ntd_max = ntd_max - skip_frames / qh->interval; ++ ++ max_xfer_size = ++ (qh->dev_speed == ++ DWC_OTG_EP_SPEED_HIGH) ? MAX_ISOC_XFER_SIZE_HS : ++ MAX_ISOC_XFER_SIZE_FS; ++ ++ DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) { ++ while ((qh->ntd < ntd_max) ++ && (qtd->isoc_frame_index_last < ++ qtd->urb->packet_count)) { ++ ++ dma_desc = &qh->desc_list[idx]; ++ dwc_memset(dma_desc, 0x00, sizeof(dwc_otg_host_dma_desc_t)); ++ ++ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last]; ++ ++ if (frame_desc->length > max_xfer_size) ++ qh->n_bytes[idx] = max_xfer_size; ++ else ++ qh->n_bytes[idx] = frame_desc->length; ++ dma_desc->status.b_isoc.n_bytes = qh->n_bytes[idx]; ++ dma_desc->status.b_isoc.a = 1; ++ dma_desc->status.b_isoc.sts = 0; ++ ++ dma_desc->buf = qtd->urb->dma + frame_desc->offset; ++ ++ qh->ntd++; ++ ++ qtd->isoc_frame_index_last++; ++ ++#ifdef ISOC_URB_GIVEBACK_ASAP ++ /* ++ * Set IOC for each descriptor corresponding to the ++ * last frame of the URB. ++ */ ++ if (qtd->isoc_frame_index_last == ++ qtd->urb->packet_count) ++ dma_desc->status.b_isoc.ioc = 1; ++ ++#endif ++ idx = desclist_idx_inc(idx, inc, qh->dev_speed); ++ n_desc++; ++ ++ } ++ qtd->in_process = 1; ++ } ++ ++ qh->td_last = idx; ++ ++#ifdef ISOC_URB_GIVEBACK_ASAP ++ /* Set IOC for the last descriptor if descriptor list is full */ ++ if (qh->ntd == ntd_max) { ++ idx = desclist_idx_dec(qh->td_last, inc, qh->dev_speed); ++ qh->desc_list[idx].status.b_isoc.ioc = 1; ++ } ++#else ++ /* ++ * Set IOC bit only for one descriptor. ++ * Always try to be ahead of HW processing, ++ * i.e. on IOC generation driver activates next descriptors but ++ * core continues to process descriptors followed the one with IOC set. ++ */ ++ ++ if (n_desc > DESCNUM_THRESHOLD) { ++ /* ++ * Move IOC "up". Required even if there is only one QTD ++ * in the list, cause QTDs migth continue to be queued, ++ * but during the activation it was only one queued. ++ * Actually more than one QTD might be in the list if this function called ++ * from XferCompletion - QTDs was queued during HW processing of the previous ++ * descriptor chunk. ++ */ ++ idx = dwc_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), qh->dev_speed); ++ } else { ++ /* ++ * Set the IOC for the latest descriptor ++ * if either number of descriptor is not greather than threshold ++ * or no more new descriptors activated. ++ */ ++ idx = dwc_desclist_idx_dec(qh->td_last, inc, qh->dev_speed); ++ } ++ ++ qh->desc_list[idx].status.b_isoc.ioc = 1; ++#endif ++} ++ ++static void init_non_isoc_dma_desc(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ ++ dwc_hc_t *hc; ++ dwc_otg_host_dma_desc_t *dma_desc; ++ dwc_otg_qtd_t *qtd; ++ int num_packets, len, n_desc = 0; ++ ++ hc = qh->channel; ++ ++ /* ++ * Start with hc->xfer_buff initialized in ++ * assign_and_init_hc(), then if SG transfer consists of multiple URBs, ++ * this pointer re-assigned to the buffer of the currently processed QTD. ++ * For non-SG request there is always one QTD active. ++ */ ++ ++ DWC_CIRCLEQ_FOREACH(qtd, &qh->qtd_list, qtd_list_entry) { ++ ++ if (n_desc) { ++ /* SG request - more than 1 QTDs */ ++ hc->xfer_buff = (uint8_t *)qtd->urb->dma + qtd->urb->actual_length; ++ hc->xfer_len = qtd->urb->length - qtd->urb->actual_length; ++ } ++ ++ qtd->n_desc = 0; ++ ++ do { ++ dma_desc = &qh->desc_list[n_desc]; ++ len = hc->xfer_len; ++ ++ if (len > MAX_DMA_DESC_SIZE) ++ len = MAX_DMA_DESC_SIZE - hc->max_packet + 1; ++ ++ if (hc->ep_is_in) { ++ if (len > 0) { ++ num_packets = (len + hc->max_packet - 1) / hc->max_packet; ++ } else { ++ /* Need 1 packet for transfer length of 0. */ ++ num_packets = 1; ++ } ++ /* Always program an integral # of max packets for IN transfers. */ ++ len = num_packets * hc->max_packet; ++ } ++ ++ dma_desc->status.b.n_bytes = len; ++ ++ qh->n_bytes[n_desc] = len; ++ ++ if ((qh->ep_type == UE_CONTROL) ++ && (qtd->control_phase == DWC_OTG_CONTROL_SETUP)) ++ dma_desc->status.b.sup = 1; /* Setup Packet */ ++ ++ dma_desc->status.b.a = 1; /* Active descriptor */ ++ dma_desc->status.b.sts = 0; ++ ++ dma_desc->buf = ++ ((unsigned long)hc->xfer_buff & 0xffffffff); ++ ++ /* ++ * Last descriptor(or single) of IN transfer ++ * with actual size less than MaxPacket. ++ */ ++ if (len > hc->xfer_len) { ++ hc->xfer_len = 0; ++ } else { ++ hc->xfer_buff += len; ++ hc->xfer_len -= len; ++ } ++ ++ qtd->n_desc++; ++ n_desc++; ++ } ++ while ((hc->xfer_len > 0) && (n_desc != MAX_DMA_DESC_NUM_GENERIC)); ++ ++ ++ qtd->in_process = 1; ++ ++ if (qh->ep_type == UE_CONTROL) ++ break; ++ ++ if (n_desc == MAX_DMA_DESC_NUM_GENERIC) ++ break; ++ } ++ ++ if (n_desc) { ++ /* Request Transfer Complete interrupt for the last descriptor */ ++ qh->desc_list[n_desc - 1].status.b.ioc = 1; ++ /* End of List indicator */ ++ qh->desc_list[n_desc - 1].status.b.eol = 1; ++ ++ hc->ntd = n_desc; ++ } ++} ++ ++/** ++ * For Control and Bulk endpoints initializes descriptor list ++ * and starts the transfer. ++ * ++ * For Interrupt and Isochronous endpoints initializes descriptor list ++ * then updates FrameList, marking appropriate entries as active. ++ * In case of Isochronous, the starting descriptor index is calculated based ++ * on the scheduled frame, but only on the first transfer descriptor within a session. ++ * Then starts the transfer via enabling the channel. ++ * For Isochronous endpoint the channel is not halted on XferComplete ++ * interrupt so remains assigned to the endpoint(QH) until session is done. ++ * ++ * @param hcd The HCD state structure for the DWC OTG controller. ++ * @param qh The QH to init. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ /* Channel is already assigned */ ++ dwc_hc_t *hc = qh->channel; ++ uint8_t skip_frames = 0; ++ ++ switch (hc->ep_type) { ++ case DWC_OTG_EP_TYPE_CONTROL: ++ case DWC_OTG_EP_TYPE_BULK: ++ init_non_isoc_dma_desc(hcd, qh); ++ ++ dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc); ++ break; ++ case DWC_OTG_EP_TYPE_INTR: ++ init_non_isoc_dma_desc(hcd, qh); ++ ++ update_frame_list(hcd, qh, 1); ++ ++ dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc); ++ break; ++ case DWC_OTG_EP_TYPE_ISOC: ++ ++ if (!qh->ntd) ++ skip_frames = recalc_initial_desc_idx(hcd, qh); ++ ++ init_isoc_dma_desc(hcd, qh, skip_frames); ++ ++ if (!hc->xfer_started) { ++ ++ update_frame_list(hcd, qh, 1); ++ ++ /* ++ * Always set to max, instead of actual size. ++ * Otherwise ntd will be changed with ++ * channel being enabled. Not recommended. ++ * ++ */ ++ hc->ntd = max_desc_num(qh); ++ /* Enable channel only once for ISOC */ ++ dwc_otg_hc_start_transfer_ddma(hcd->core_if, hc); ++ } ++ ++ break; ++ default: ++ ++ break; ++ } ++} ++ ++static void complete_isoc_xfer_ddma(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_halt_status_e halt_status) ++{ ++ struct dwc_otg_hcd_iso_packet_desc *frame_desc; ++ dwc_otg_qtd_t *qtd, *qtd_tmp; ++ dwc_otg_qh_t *qh; ++ dwc_otg_host_dma_desc_t *dma_desc; ++ uint16_t idx, remain; ++ uint8_t urb_compl; ++ ++ qh = hc->qh; ++ idx = qh->td_first; ++ ++ if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) { ++ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) ++ qtd->in_process = 0; ++ return; ++ } else if ((halt_status == DWC_OTG_HC_XFER_AHB_ERR) || ++ (halt_status == DWC_OTG_HC_XFER_BABBLE_ERR)) { ++ /* ++ * Channel is halted in these error cases. ++ * Considered as serious issues. ++ * Complete all URBs marking all frames as failed, ++ * irrespective whether some of the descriptors(frames) succeeded or no. ++ * Pass error code to completion routine as well, to ++ * update urb->status, some of class drivers might use it to stop ++ * queing transfer requests. ++ */ ++ int err = (halt_status == DWC_OTG_HC_XFER_AHB_ERR) ++ ? (-DWC_E_IO) ++ : (-DWC_E_OVERFLOW); ++ ++ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) { ++ for (idx = 0; idx < qtd->urb->packet_count; idx++) { ++ frame_desc = &qtd->urb->iso_descs[idx]; ++ frame_desc->status = err; ++ } ++ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, err); ++ dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); ++ } ++ return; ++ } ++ ++ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) { ++ ++ if (!qtd->in_process) ++ break; ++ ++ urb_compl = 0; ++ ++ do { ++ ++ dma_desc = &qh->desc_list[idx]; ++ ++ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; ++ remain = hc->ep_is_in ? dma_desc->status.b_isoc.n_bytes : 0; ++ ++ if (dma_desc->status.b_isoc.sts == DMA_DESC_STS_PKTERR) { ++ /* ++ * XactError or, unable to complete all the transactions ++ * in the scheduled micro-frame/frame, ++ * both indicated by DMA_DESC_STS_PKTERR. ++ */ ++ qtd->urb->error_count++; ++ frame_desc->actual_length = qh->n_bytes[idx] - remain; ++ frame_desc->status = -DWC_E_PROTOCOL; ++ } else { ++ /* Success */ ++ ++ frame_desc->actual_length = qh->n_bytes[idx] - remain; ++ frame_desc->status = 0; ++ } ++ ++ if (++qtd->isoc_frame_index == qtd->urb->packet_count) { ++ /* ++ * urb->status is not used for isoc transfers here. ++ * The individual frame_desc status are used instead. ++ */ ++ ++ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); ++ dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); ++ ++ /* ++ * This check is necessary because urb_dequeue can be called ++ * from urb complete callback(sound driver example). ++ * All pending URBs are dequeued there, so no need for ++ * further processing. ++ */ ++ if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) { ++ return; ++ } ++ ++ urb_compl = 1; ++ ++ } ++ ++ qh->ntd--; ++ ++ /* Stop if IOC requested descriptor reached */ ++ if (dma_desc->status.b_isoc.ioc) { ++ idx = desclist_idx_inc(idx, qh->interval, hc->speed); ++ goto stop_scan; ++ } ++ ++ idx = desclist_idx_inc(idx, qh->interval, hc->speed); ++ ++ if (urb_compl) ++ break; ++ } ++ while (idx != qh->td_first); ++ } ++stop_scan: ++ qh->td_first = idx; ++} ++ ++uint8_t update_non_isoc_urb_state_ddma(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_qtd_t * qtd, ++ dwc_otg_host_dma_desc_t * dma_desc, ++ dwc_otg_halt_status_e halt_status, ++ uint32_t n_bytes, uint8_t * xfer_done) ++{ ++ ++ uint16_t remain = hc->ep_is_in ? dma_desc->status.b.n_bytes : 0; ++ dwc_otg_hcd_urb_t *urb = qtd->urb; ++ ++ if (halt_status == DWC_OTG_HC_XFER_AHB_ERR) { ++ urb->status = -DWC_E_IO; ++ return 1; ++ } ++ if (dma_desc->status.b.sts == DMA_DESC_STS_PKTERR) { ++ switch (halt_status) { ++ case DWC_OTG_HC_XFER_STALL: ++ urb->status = -DWC_E_PIPE; ++ break; ++ case DWC_OTG_HC_XFER_BABBLE_ERR: ++ urb->status = -DWC_E_OVERFLOW; ++ break; ++ case DWC_OTG_HC_XFER_XACT_ERR: ++ urb->status = -DWC_E_PROTOCOL; ++ break; ++ default: ++ DWC_ERROR("%s: Unhandled descriptor error status (%d)\n", __func__, ++ halt_status); ++ break; ++ } ++ return 1; ++ } ++ ++ if (dma_desc->status.b.a == 1) { ++ DWC_DEBUGPL(DBG_HCDV, ++ "Active descriptor encountered on channel %d\n", ++ hc->hc_num); ++ return 0; ++ } ++ ++ if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL) { ++ if (qtd->control_phase == DWC_OTG_CONTROL_DATA) { ++ urb->actual_length += n_bytes - remain; ++ if (remain || urb->actual_length == urb->length) { ++ /* ++ * For Control Data stage do not set urb->status=0 to prevent ++ * URB callback. Set it when Status phase done. See below. ++ */ ++ *xfer_done = 1; ++ } ++ ++ } else if (qtd->control_phase == DWC_OTG_CONTROL_STATUS) { ++ urb->status = 0; ++ *xfer_done = 1; ++ } ++ /* No handling for SETUP stage */ ++ } else { ++ /* BULK and INTR */ ++ urb->actual_length += n_bytes - remain; ++ if (remain || urb->actual_length == urb->length) { ++ urb->status = 0; ++ *xfer_done = 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static void complete_non_isoc_xfer_ddma(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_halt_status_e halt_status) ++{ ++ dwc_otg_hcd_urb_t *urb = NULL; ++ dwc_otg_qtd_t *qtd, *qtd_tmp; ++ dwc_otg_qh_t *qh; ++ dwc_otg_host_dma_desc_t *dma_desc; ++ uint32_t n_bytes, n_desc, i; ++ uint8_t failed = 0, xfer_done; ++ ++ n_desc = 0; ++ ++ qh = hc->qh; ++ ++ if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) { ++ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &hc->qh->qtd_list, qtd_list_entry) { ++ qtd->in_process = 0; ++ } ++ return; ++ } ++ ++ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) { ++ ++ urb = qtd->urb; ++ ++ n_bytes = 0; ++ xfer_done = 0; ++ ++ for (i = 0; i < qtd->n_desc; i++) { ++ dma_desc = &qh->desc_list[n_desc]; ++ ++ n_bytes = qh->n_bytes[n_desc]; ++ ++ failed = ++ update_non_isoc_urb_state_ddma(hcd, hc, qtd, ++ dma_desc, ++ halt_status, n_bytes, ++ &xfer_done); ++ ++ if (failed ++ || (xfer_done ++ && (urb->status != -DWC_E_IN_PROGRESS))) { ++ ++ hcd->fops->complete(hcd, urb->priv, urb, ++ urb->status); ++ dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); ++ ++ if (failed) ++ goto stop_scan; ++ } else if (qh->ep_type == UE_CONTROL) { ++ if (qtd->control_phase == DWC_OTG_CONTROL_SETUP) { ++ if (urb->length > 0) { ++ qtd->control_phase = DWC_OTG_CONTROL_DATA; ++ } else { ++ qtd->control_phase = DWC_OTG_CONTROL_STATUS; ++ } ++ DWC_DEBUGPL(DBG_HCDV, " Control setup transaction done\n"); ++ } else if (qtd->control_phase == DWC_OTG_CONTROL_DATA) { ++ if (xfer_done) { ++ qtd->control_phase = DWC_OTG_CONTROL_STATUS; ++ DWC_DEBUGPL(DBG_HCDV, " Control data transfer done\n"); ++ } else if (i + 1 == qtd->n_desc) { ++ /* ++ * Last descriptor for Control data stage which is ++ * not completed yet. ++ */ ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ } ++ } ++ } ++ ++ n_desc++; ++ } ++ ++ } ++ ++stop_scan: ++ ++ if (qh->ep_type != UE_CONTROL) { ++ /* ++ * Resetting the data toggle for bulk ++ * and interrupt endpoints in case of stall. See handle_hc_stall_intr() ++ */ ++ if (halt_status == DWC_OTG_HC_XFER_STALL) ++ qh->data_toggle = DWC_OTG_HC_PID_DATA0; ++ else ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ } ++ ++ if (halt_status == DWC_OTG_HC_XFER_COMPLETE) { ++ hcint_data_t hcint; ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ if (hcint.b.nyet) { ++ /* ++ * Got a NYET on the last transaction of the transfer. It ++ * means that the endpoint should be in the PING state at the ++ * beginning of the next transfer. ++ */ ++ qh->ping_state = 1; ++ clear_hc_int(hc_regs, nyet); ++ } ++ ++ } ++ ++} ++ ++/** ++ * This function is called from interrupt handlers. ++ * Scans the descriptor list, updates URB's status and ++ * calls completion routine for the URB if it's done. ++ * Releases the channel to be used by other transfers. ++ * In case of Isochronous endpoint the channel is not halted until ++ * the end of the session, i.e. QTD list is empty. ++ * If periodic channel released the FrameList is updated accordingly. ++ * ++ * Calls transaction selection routines to activate pending transfers. ++ * ++ * @param hcd The HCD state structure for the DWC OTG controller. ++ * @param hc Host channel, the transfer is completed on. ++ * @param hc_regs Host channel registers. ++ * @param halt_status Reason the channel is being halted, ++ * or just XferComplete for isochronous transfer ++ */ ++void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_halt_status_e halt_status) ++{ ++ uint8_t continue_isoc_xfer = 0; ++ dwc_otg_transaction_type_e tr_type; ++ dwc_otg_qh_t *qh = hc->qh; ++ ++ if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ ++ complete_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status); ++ ++ /* Release the channel if halted or session completed */ ++ if (halt_status != DWC_OTG_HC_XFER_COMPLETE || ++ DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { ++ ++ /* Halt the channel if session completed */ ++ if (halt_status == DWC_OTG_HC_XFER_COMPLETE) { ++ dwc_otg_hc_halt(hcd->core_if, hc, halt_status); ++ } ++ ++ release_channel_ddma(hcd, qh); ++ dwc_otg_hcd_qh_remove(hcd, qh); ++ } else { ++ /* Keep in assigned schedule to continue transfer */ ++ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned, ++ &qh->qh_list_entry); ++ continue_isoc_xfer = 1; ++ ++ } ++ /** @todo Consider the case when period exceeds FrameList size. ++ * Frame Rollover interrupt should be used. ++ */ ++ } else { ++ /* Scan descriptor list to complete the URB(s), then release the channel */ ++ complete_non_isoc_xfer_ddma(hcd, hc, hc_regs, halt_status); ++ ++ release_channel_ddma(hcd, qh); ++ dwc_otg_hcd_qh_remove(hcd, qh); ++ ++ if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { ++ /* Add back to inactive non-periodic schedule on normal completion */ ++ dwc_otg_hcd_qh_add(hcd, qh); ++ } ++ ++ } ++ tr_type = dwc_otg_hcd_select_transactions(hcd); ++ if (tr_type != DWC_OTG_TRANSACTION_NONE || continue_isoc_xfer) { ++ if (continue_isoc_xfer) { ++ if (tr_type == DWC_OTG_TRANSACTION_NONE) { ++ tr_type = DWC_OTG_TRANSACTION_PERIODIC; ++ } else if (tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC) { ++ tr_type = DWC_OTG_TRANSACTION_ALL; ++ } ++ } ++ dwc_otg_hcd_queue_transactions(hcd, tr_type); ++ } ++} ++ ++#endif /* DWC_DEVICE_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd.h linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd.h +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd.h 2014-03-13 12:46:39.516097989 +0100 +@@ -0,0 +1,851 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd.h $ ++ * $Revision: #58 $ ++ * $Date: 2011/09/15 $ ++ * $Change: 1846647 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++#ifndef __DWC_HCD_H__ ++#define __DWC_HCD_H__ ++ ++#include "dwc_otg_os_dep.h" ++#include "usb.h" ++#include "dwc_otg_hcd_if.h" ++#include "dwc_otg_core_if.h" ++#include "dwc_list.h" ++#include "dwc_otg_cil.h" ++ ++/** ++ * @file ++ * ++ * This file contains the structures, constants, and interfaces for ++ * the Host Contoller Driver (HCD). ++ * ++ * The Host Controller Driver (HCD) is responsible for translating requests ++ * from the USB Driver into the appropriate actions on the DWC_otg controller. ++ * It isolates the USBD from the specifics of the controller by providing an ++ * API to the USBD. ++ */ ++ ++struct dwc_otg_hcd_pipe_info { ++ uint8_t dev_addr; ++ uint8_t ep_num; ++ uint8_t pipe_type; ++ uint8_t pipe_dir; ++ uint16_t mps; ++}; ++ ++struct dwc_otg_hcd_iso_packet_desc { ++ uint32_t offset; ++ uint32_t length; ++ uint32_t actual_length; ++ uint32_t status; ++}; ++ ++struct dwc_otg_qtd; ++ ++struct dwc_otg_hcd_urb { ++ void *priv; ++ struct dwc_otg_qtd *qtd; ++ void *buf; ++ dwc_dma_t dma; ++ void *setup_packet; ++ dwc_dma_t setup_dma; ++ uint32_t length; ++ uint32_t actual_length; ++ uint32_t status; ++ uint32_t error_count; ++ uint32_t packet_count; ++ uint32_t flags; ++ uint16_t interval; ++ struct dwc_otg_hcd_pipe_info pipe_info; ++ struct dwc_otg_hcd_iso_packet_desc iso_descs[0]; ++}; ++ ++static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe) ++{ ++ return pipe->ep_num; ++} ++ ++static inline uint8_t dwc_otg_hcd_get_pipe_type(struct dwc_otg_hcd_pipe_info ++ *pipe) ++{ ++ return pipe->pipe_type; ++} ++ ++static inline uint16_t dwc_otg_hcd_get_mps(struct dwc_otg_hcd_pipe_info *pipe) ++{ ++ return pipe->mps; ++} ++ ++static inline uint8_t dwc_otg_hcd_get_dev_addr(struct dwc_otg_hcd_pipe_info ++ *pipe) ++{ ++ return pipe->dev_addr; ++} ++ ++static inline uint8_t dwc_otg_hcd_is_pipe_isoc(struct dwc_otg_hcd_pipe_info ++ *pipe) ++{ ++ return (pipe->pipe_type == UE_ISOCHRONOUS); ++} ++ ++static inline uint8_t dwc_otg_hcd_is_pipe_int(struct dwc_otg_hcd_pipe_info ++ *pipe) ++{ ++ return (pipe->pipe_type == UE_INTERRUPT); ++} ++ ++static inline uint8_t dwc_otg_hcd_is_pipe_bulk(struct dwc_otg_hcd_pipe_info ++ *pipe) ++{ ++ return (pipe->pipe_type == UE_BULK); ++} ++ ++static inline uint8_t dwc_otg_hcd_is_pipe_control(struct dwc_otg_hcd_pipe_info ++ *pipe) ++{ ++ return (pipe->pipe_type == UE_CONTROL); ++} ++ ++static inline uint8_t dwc_otg_hcd_is_pipe_in(struct dwc_otg_hcd_pipe_info *pipe) ++{ ++ return (pipe->pipe_dir == UE_DIR_IN); ++} ++ ++static inline uint8_t dwc_otg_hcd_is_pipe_out(struct dwc_otg_hcd_pipe_info ++ *pipe) ++{ ++ return (!dwc_otg_hcd_is_pipe_in(pipe)); ++} ++ ++static inline void dwc_otg_hcd_fill_pipe(struct dwc_otg_hcd_pipe_info *pipe, ++ uint8_t devaddr, uint8_t ep_num, ++ uint8_t pipe_type, uint8_t pipe_dir, ++ uint16_t mps) ++{ ++ pipe->dev_addr = devaddr; ++ pipe->ep_num = ep_num; ++ pipe->pipe_type = pipe_type; ++ pipe->pipe_dir = pipe_dir; ++ pipe->mps = mps; ++} ++ ++/** ++ * Phases for control transfers. ++ */ ++typedef enum dwc_otg_control_phase { ++ DWC_OTG_CONTROL_SETUP, ++ DWC_OTG_CONTROL_DATA, ++ DWC_OTG_CONTROL_STATUS ++} dwc_otg_control_phase_e; ++ ++/** Transaction types. */ ++typedef enum dwc_otg_transaction_type { ++ DWC_OTG_TRANSACTION_NONE = 0, ++ DWC_OTG_TRANSACTION_PERIODIC = 1, ++ DWC_OTG_TRANSACTION_NON_PERIODIC = 2, ++ DWC_OTG_TRANSACTION_ALL = DWC_OTG_TRANSACTION_PERIODIC + DWC_OTG_TRANSACTION_NON_PERIODIC ++} dwc_otg_transaction_type_e; ++ ++struct dwc_otg_qh; ++ ++/** ++ * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, ++ * interrupt, or isochronous transfer. A single QTD is created for each URB ++ * (of one of these types) submitted to the HCD. The transfer associated with ++ * a QTD may require one or multiple transactions. ++ * ++ * A QTD is linked to a Queue Head, which is entered in either the ++ * non-periodic or periodic schedule for execution. When a QTD is chosen for ++ * execution, some or all of its transactions may be executed. After ++ * execution, the state of the QTD is updated. The QTD may be retired if all ++ * its transactions are complete or if an error occurred. Otherwise, it ++ * remains in the schedule so more transactions can be executed later. ++ */ ++typedef struct dwc_otg_qtd { ++ /** ++ * Determines the PID of the next data packet for the data phase of ++ * control transfers. Ignored for other transfer types.
++ * One of the following values: ++ * - DWC_OTG_HC_PID_DATA0 ++ * - DWC_OTG_HC_PID_DATA1 ++ */ ++ uint8_t data_toggle; ++ ++ /** Current phase for control transfers (Setup, Data, or Status). */ ++ dwc_otg_control_phase_e control_phase; ++ ++ /** Keep track of the current split type ++ * for FS/LS endpoints on a HS Hub */ ++ uint8_t complete_split; ++ ++ /** How many bytes transferred during SSPLIT OUT */ ++ uint32_t ssplit_out_xfer_count; ++ ++ /** ++ * Holds the number of bus errors that have occurred for a transaction ++ * within this transfer. ++ */ ++ uint8_t error_count; ++ ++ /** ++ * Index of the next frame descriptor for an isochronous transfer. A ++ * frame descriptor describes the buffer position and length of the ++ * data to be transferred in the next scheduled (micro)frame of an ++ * isochronous transfer. It also holds status for that transaction. ++ * The frame index starts at 0. ++ */ ++ uint16_t isoc_frame_index; ++ ++ /** Position of the ISOC split on full/low speed */ ++ uint8_t isoc_split_pos; ++ ++ /** Position of the ISOC split in the buffer for the current frame */ ++ uint16_t isoc_split_offset; ++ ++ /** URB for this transfer */ ++ struct dwc_otg_hcd_urb *urb; ++ ++ struct dwc_otg_qh *qh; ++ ++ /** This list of QTDs */ ++ DWC_CIRCLEQ_ENTRY(dwc_otg_qtd) qtd_list_entry; ++ ++ /** Indicates if this QTD is currently processed by HW. */ ++ uint8_t in_process; ++ ++ /** Number of DMA descriptors for this QTD */ ++ uint8_t n_desc; ++ ++ /** ++ * Last activated frame(packet) index. ++ * Used in Descriptor DMA mode only. ++ */ ++ uint16_t isoc_frame_index_last; ++ ++} dwc_otg_qtd_t; ++ ++DWC_CIRCLEQ_HEAD(dwc_otg_qtd_list, dwc_otg_qtd); ++ ++/** ++ * A Queue Head (QH) holds the static characteristics of an endpoint and ++ * maintains a list of transfers (QTDs) for that endpoint. A QH structure may ++ * be entered in either the non-periodic or periodic schedule. ++ */ ++typedef struct dwc_otg_qh { ++ /** ++ * Endpoint type. ++ * One of the following values: ++ * - UE_CONTROL ++ * - UE_BULK ++ * - UE_INTERRUPT ++ * - UE_ISOCHRONOUS ++ */ ++ uint8_t ep_type; ++ uint8_t ep_is_in; ++ ++ /** wMaxPacketSize Field of Endpoint Descriptor. */ ++ uint16_t maxp; ++ ++ /** ++ * Device speed. ++ * One of the following values: ++ * - DWC_OTG_EP_SPEED_LOW ++ * - DWC_OTG_EP_SPEED_FULL ++ * - DWC_OTG_EP_SPEED_HIGH ++ */ ++ uint8_t dev_speed; ++ ++ /** ++ * Determines the PID of the next data packet for non-control ++ * transfers. Ignored for control transfers.
++ * One of the following values: ++ * - DWC_OTG_HC_PID_DATA0 ++ * - DWC_OTG_HC_PID_DATA1 ++ */ ++ uint8_t data_toggle; ++ ++ /** Ping state if 1. */ ++ uint8_t ping_state; ++ ++ /** ++ * List of QTDs for this QH. ++ */ ++ struct dwc_otg_qtd_list qtd_list; ++ ++ /** Host channel currently processing transfers for this QH. */ ++ struct dwc_hc *channel; ++ ++ /** Full/low speed endpoint on high-speed hub requires split. */ ++ uint8_t do_split; ++ ++ /** @name Periodic schedule information */ ++ /** @{ */ ++ ++ /** Bandwidth in microseconds per (micro)frame. */ ++ uint16_t usecs; ++ ++ /** Interval between transfers in (micro)frames. */ ++ uint16_t interval; ++ ++ /** ++ * (micro)frame to initialize a periodic transfer. The transfer ++ * executes in the following (micro)frame. ++ */ ++ uint16_t sched_frame; ++ ++ /* ++ ** Frame a NAK was received on this queue head, used to minimise NAK retransmission ++ */ ++ uint16_t nak_frame; ++ ++ /** (micro)frame at which last start split was initialized. */ ++ uint16_t start_split_frame; ++ ++ /** @} */ ++ ++ /** ++ * Used instead of original buffer if ++ * it(physical address) is not dword-aligned. ++ */ ++ uint8_t *dw_align_buf; ++ dwc_dma_t dw_align_buf_dma; ++ ++ /** Entry for QH in either the periodic or non-periodic schedule. */ ++ dwc_list_link_t qh_list_entry; ++ ++ /** @name Descriptor DMA support */ ++ /** @{ */ ++ ++ /** Descriptor List. */ ++ dwc_otg_host_dma_desc_t *desc_list; ++ ++ /** Descriptor List physical address. */ ++ dwc_dma_t desc_list_dma; ++ ++ /** ++ * Xfer Bytes array. ++ * Each element corresponds to a descriptor and indicates ++ * original XferSize size value for the descriptor. ++ */ ++ uint32_t *n_bytes; ++ ++ /** Actual number of transfer descriptors in a list. */ ++ uint16_t ntd; ++ ++ /** First activated isochronous transfer descriptor index. */ ++ uint8_t td_first; ++ /** Last activated isochronous transfer descriptor index. */ ++ uint8_t td_last; ++ ++ /** @} */ ++ ++ ++ uint16_t speed; ++ uint16_t frame_usecs[8]; ++ ++ uint32_t skip_count; ++} dwc_otg_qh_t; ++ ++DWC_CIRCLEQ_HEAD(hc_list, dwc_hc); ++ ++typedef struct urb_tq_entry { ++ struct urb *urb; ++ DWC_TAILQ_ENTRY(urb_tq_entry) urb_tq_entries; ++} urb_tq_entry_t; ++ ++DWC_TAILQ_HEAD(urb_list, urb_tq_entry); ++ ++/** ++ * This structure holds the state of the HCD, including the non-periodic and ++ * periodic schedules. ++ */ ++struct dwc_otg_hcd { ++ /** The DWC otg device pointer */ ++ struct dwc_otg_device *otg_dev; ++ /** DWC OTG Core Interface Layer */ ++ dwc_otg_core_if_t *core_if; ++ ++ /** Function HCD driver callbacks */ ++ struct dwc_otg_hcd_function_ops *fops; ++ ++ /** Internal DWC HCD Flags */ ++ volatile union dwc_otg_hcd_internal_flags { ++ uint32_t d32; ++ struct { ++ unsigned port_connect_status_change:1; ++ unsigned port_connect_status:1; ++ unsigned port_reset_change:1; ++ unsigned port_enable_change:1; ++ unsigned port_suspend_change:1; ++ unsigned port_over_current_change:1; ++ unsigned port_l1_change:1; ++ unsigned reserved:26; ++ } b; ++ } flags; ++ ++ /** ++ * Inactive items in the non-periodic schedule. This is a list of ++ * Queue Heads. Transfers associated with these Queue Heads are not ++ * currently assigned to a host channel. ++ */ ++ dwc_list_link_t non_periodic_sched_inactive; ++ ++ /** ++ * Active items in the non-periodic schedule. This is a list of ++ * Queue Heads. Transfers associated with these Queue Heads are ++ * currently assigned to a host channel. ++ */ ++ dwc_list_link_t non_periodic_sched_active; ++ ++ /** ++ * Pointer to the next Queue Head to process in the active ++ * non-periodic schedule. ++ */ ++ dwc_list_link_t *non_periodic_qh_ptr; ++ ++ /** ++ * Inactive items in the periodic schedule. This is a list of QHs for ++ * periodic transfers that are _not_ scheduled for the next frame. ++ * Each QH in the list has an interval counter that determines when it ++ * needs to be scheduled for execution. This scheduling mechanism ++ * allows only a simple calculation for periodic bandwidth used (i.e. ++ * must assume that all periodic transfers may need to execute in the ++ * same frame). However, it greatly simplifies scheduling and should ++ * be sufficient for the vast majority of OTG hosts, which need to ++ * connect to a small number of peripherals at one time. ++ * ++ * Items move from this list to periodic_sched_ready when the QH ++ * interval counter is 0 at SOF. ++ */ ++ dwc_list_link_t periodic_sched_inactive; ++ ++ /** ++ * List of periodic QHs that are ready for execution in the next ++ * frame, but have not yet been assigned to host channels. ++ * ++ * Items move from this list to periodic_sched_assigned as host ++ * channels become available during the current frame. ++ */ ++ dwc_list_link_t periodic_sched_ready; ++ ++ /** ++ * List of periodic QHs to be executed in the next frame that are ++ * assigned to host channels. ++ * ++ * Items move from this list to periodic_sched_queued as the ++ * transactions for the QH are queued to the DWC_otg controller. ++ */ ++ dwc_list_link_t periodic_sched_assigned; ++ ++ /** ++ * List of periodic QHs that have been queued for execution. ++ * ++ * Items move from this list to either periodic_sched_inactive or ++ * periodic_sched_ready when the channel associated with the transfer ++ * is released. If the interval for the QH is 1, the item moves to ++ * periodic_sched_ready because it must be rescheduled for the next ++ * frame. Otherwise, the item moves to periodic_sched_inactive. ++ */ ++ dwc_list_link_t periodic_sched_queued; ++ ++ /** ++ * Total bandwidth claimed so far for periodic transfers. This value ++ * is in microseconds per (micro)frame. The assumption is that all ++ * periodic transfers may occur in the same (micro)frame. ++ */ ++ uint16_t periodic_usecs; ++ ++ /** ++ * Total bandwidth claimed so far for all periodic transfers ++ * in a frame. ++ * This will include a mixture of HS and FS transfers. ++ * Units are microseconds per (micro)frame. ++ * We have a budget per frame and have to schedule ++ * transactions accordingly. ++ * Watch out for the fact that things are actually scheduled for the ++ * "next frame". ++ */ ++ uint16_t frame_usecs[8]; ++ ++ ++ /** ++ * Frame number read from the core at SOF. The value ranges from 0 to ++ * DWC_HFNUM_MAX_FRNUM. ++ */ ++ uint16_t frame_number; ++ ++ /** ++ * Count of periodic QHs, if using several eps. For SOF enable/disable. ++ */ ++ uint16_t periodic_qh_count; ++ ++ /** ++ * Free host channels in the controller. This is a list of ++ * dwc_hc_t items. ++ */ ++ struct hc_list free_hc_list; ++ /** ++ * Number of host channels assigned to periodic transfers. Currently ++ * assuming that there is a dedicated host channel for each periodic ++ * transaction and at least one host channel available for ++ * non-periodic transactions. ++ */ ++ int periodic_channels; /* microframe_schedule==0 */ ++ ++ /** ++ * Number of host channels assigned to non-periodic transfers. ++ */ ++ int non_periodic_channels; /* microframe_schedule==0 */ ++ ++ /** ++ * Number of host channels assigned to non-periodic transfers. ++ */ ++ int available_host_channels; ++ ++ /** ++ * Array of pointers to the host channel descriptors. Allows accessing ++ * a host channel descriptor given the host channel number. This is ++ * useful in interrupt handlers. ++ */ ++ struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS]; ++ ++ /** ++ * Buffer to use for any data received during the status phase of a ++ * control transfer. Normally no data is transferred during the status ++ * phase. This buffer is used as a bit bucket. ++ */ ++ uint8_t *status_buf; ++ ++ /** ++ * DMA address for status_buf. ++ */ ++ dma_addr_t status_buf_dma; ++#define DWC_OTG_HCD_STATUS_BUF_SIZE 64 ++ ++ /** ++ * Connection timer. An OTG host must display a message if the device ++ * does not connect. Started when the VBus power is turned on via ++ * sysfs attribute "buspower". ++ */ ++ dwc_timer_t *conn_timer; ++ ++ /* Tasket to do a reset */ ++ dwc_tasklet_t *reset_tasklet; ++ ++ dwc_tasklet_t *completion_tasklet; ++ struct urb_list completed_urb_list; ++ ++ /* */ ++ dwc_spinlock_t *lock; ++ dwc_spinlock_t *channel_lock; ++ /** ++ * Private data that could be used by OS wrapper. ++ */ ++ void *priv; ++ ++ uint8_t otg_port; ++ ++ /** Frame List */ ++ uint32_t *frame_list; ++ ++ /** Hub - Port assignment */ ++ int hub_port[128]; ++#ifdef FIQ_DEBUG ++ int hub_port_alloc[2048]; ++#endif ++ ++ /** Frame List DMA address */ ++ dma_addr_t frame_list_dma; ++ ++#ifdef DEBUG ++ uint32_t frrem_samples; ++ uint64_t frrem_accum; ++ ++ uint32_t hfnum_7_samples_a; ++ uint64_t hfnum_7_frrem_accum_a; ++ uint32_t hfnum_0_samples_a; ++ uint64_t hfnum_0_frrem_accum_a; ++ uint32_t hfnum_other_samples_a; ++ uint64_t hfnum_other_frrem_accum_a; ++ ++ uint32_t hfnum_7_samples_b; ++ uint64_t hfnum_7_frrem_accum_b; ++ uint32_t hfnum_0_samples_b; ++ uint64_t hfnum_0_frrem_accum_b; ++ uint32_t hfnum_other_samples_b; ++ uint64_t hfnum_other_frrem_accum_b; ++#endif ++}; ++ ++/** @name Transaction Execution Functions */ ++/** @{ */ ++extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t ++ * hcd); ++extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd, ++ dwc_otg_transaction_type_e tr_type); ++ ++int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh); ++void dwc_otg_hcd_release_port(dwc_otg_hcd_t * dwc_otg_hcd, dwc_otg_qh_t *qh); ++ ++ ++/** @} */ ++ ++/** @name Interrupt Handler Functions */ ++/** @{ */ ++extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * ++ dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * ++ dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * ++ dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(dwc_otg_hcd_t * ++ dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(dwc_otg_hcd_t * ++ dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_disconnect_intr(dwc_otg_hcd_t * dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, ++ uint32_t num); ++extern int32_t dwc_otg_hcd_handle_session_req_intr(dwc_otg_hcd_t * dwc_otg_hcd); ++extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(dwc_otg_hcd_t * ++ dwc_otg_hcd); ++/** @} */ ++ ++/** @name Schedule Queue Functions */ ++/** @{ */ ++ ++/* Implemented in dwc_otg_hcd_queue.c */ ++extern dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd, ++ dwc_otg_hcd_urb_t * urb, int atomic_alloc); ++extern void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); ++extern int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); ++extern void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); ++extern void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, ++ int sched_csplit); ++ ++/** Remove and free a QH */ ++static inline void dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd_t * hcd, ++ dwc_otg_qh_t * qh) ++{ ++ dwc_irqflags_t flags; ++ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags); ++ dwc_otg_hcd_qh_remove(hcd, qh); ++ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags); ++ dwc_otg_hcd_qh_free(hcd, qh); ++} ++ ++/** Allocates memory for a QH structure. ++ * @return Returns the memory allocate or NULL on error. */ ++static inline dwc_otg_qh_t *dwc_otg_hcd_qh_alloc(int atomic_alloc) ++{ ++ if (atomic_alloc) ++ return (dwc_otg_qh_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qh_t)); ++ else ++ return (dwc_otg_qh_t *) DWC_ALLOC(sizeof(dwc_otg_qh_t)); ++} ++ ++extern dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, ++ int atomic_alloc); ++extern void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb); ++extern int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, dwc_otg_hcd_t * dwc_otg_hcd, ++ dwc_otg_qh_t ** qh, int atomic_alloc); ++ ++/** Allocates memory for a QTD structure. ++ * @return Returns the memory allocate or NULL on error. */ ++static inline dwc_otg_qtd_t *dwc_otg_hcd_qtd_alloc(int atomic_alloc) ++{ ++ if (atomic_alloc) ++ return (dwc_otg_qtd_t *) DWC_ALLOC_ATOMIC(sizeof(dwc_otg_qtd_t)); ++ else ++ return (dwc_otg_qtd_t *) DWC_ALLOC(sizeof(dwc_otg_qtd_t)); ++} ++ ++/** Frees the memory for a QTD structure. QTD should already be removed from ++ * list. ++ * @param qtd QTD to free.*/ ++static inline void dwc_otg_hcd_qtd_free(dwc_otg_qtd_t * qtd) ++{ ++ DWC_FREE(qtd); ++} ++ ++/** Removes a QTD from list. ++ * @param hcd HCD instance. ++ * @param qtd QTD to remove from list. ++ * @param qh QTD belongs to. ++ */ ++static inline void dwc_otg_hcd_qtd_remove(dwc_otg_hcd_t * hcd, ++ dwc_otg_qtd_t * qtd, ++ dwc_otg_qh_t * qh) ++{ ++ DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry); ++} ++ ++/** Remove and free a QTD ++ * Need to disable IRQ and hold hcd lock while calling this function out of ++ * interrupt servicing chain */ ++static inline void dwc_otg_hcd_qtd_remove_and_free(dwc_otg_hcd_t * hcd, ++ dwc_otg_qtd_t * qtd, ++ dwc_otg_qh_t * qh) ++{ ++ dwc_otg_hcd_qtd_remove(hcd, qtd, qh); ++ dwc_otg_hcd_qtd_free(qtd); ++} ++ ++/** @} */ ++ ++/** @name Descriptor DMA Supporting Functions */ ++/** @{ */ ++ ++extern void dwc_otg_hcd_start_xfer_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); ++extern void dwc_otg_hcd_complete_xfer_ddma(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_halt_status_e halt_status); ++ ++extern int dwc_otg_hcd_qh_init_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); ++extern void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh); ++ ++/** @} */ ++ ++/** @name Internal Functions */ ++/** @{ */ ++dwc_otg_qh_t *dwc_urb_to_qh(dwc_otg_hcd_urb_t * urb); ++/** @} */ ++ ++#ifdef CONFIG_USB_DWC_OTG_LPM ++extern int dwc_otg_hcd_get_hc_for_lpm_tran(dwc_otg_hcd_t * hcd, ++ uint8_t devaddr); ++extern void dwc_otg_hcd_free_hc_from_lpm(dwc_otg_hcd_t * hcd); ++#endif ++ ++/** Gets the QH that contains the list_head */ ++#define dwc_list_to_qh(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qh_t, qh_list_entry) ++ ++/** Gets the QTD that contains the list_head */ ++#define dwc_list_to_qtd(_list_head_ptr_) container_of(_list_head_ptr_, dwc_otg_qtd_t, qtd_list_entry) ++ ++/** Check if QH is non-periodic */ ++#define dwc_qh_is_non_per(_qh_ptr_) ((_qh_ptr_->ep_type == UE_BULK) || \ ++ (_qh_ptr_->ep_type == UE_CONTROL)) ++ ++/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */ ++#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) ++ ++/** Packet size for any kind of endpoint descriptor */ ++#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) ++ ++/** ++ * Returns true if _frame1 is less than or equal to _frame2. The comparison is ++ * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the ++ * frame number when the max frame number is reached. ++ */ ++static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2) ++{ ++ return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <= ++ (DWC_HFNUM_MAX_FRNUM >> 1); ++} ++ ++/** ++ * Returns true if _frame1 is greater than _frame2. The comparison is done ++ * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame ++ * number when the max frame number is reached. ++ */ ++static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2) ++{ ++ return (frame1 != frame2) && ++ (((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) < ++ (DWC_HFNUM_MAX_FRNUM >> 1)); ++} ++ ++/** ++ * Increments _frame by the amount specified by _inc. The addition is done ++ * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value. ++ */ ++static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc) ++{ ++ return (frame + inc) & DWC_HFNUM_MAX_FRNUM; ++} ++ ++static inline uint16_t dwc_full_frame_num(uint16_t frame) ++{ ++ return (frame & DWC_HFNUM_MAX_FRNUM) >> 3; ++} ++ ++static inline uint16_t dwc_micro_frame_num(uint16_t frame) ++{ ++ return frame & 0x7; ++} ++ ++void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd); ++ ++#ifdef DEBUG ++/** ++ * Macro to sample the remaining PHY clocks left in the current frame. This ++ * may be used during debugging to determine the average time it takes to ++ * execute sections of code. There are two possible sample points, "a" and ++ * "b", so the _letter argument must be one of these values. ++ * ++ * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For ++ * example, "cat /sys/devices/lm0/hcd_frrem". ++ */ ++#define dwc_sample_frrem(_hcd, _qh, _letter) \ ++{ \ ++ hfnum_data_t hfnum; \ ++ dwc_otg_qtd_t *qtd; \ ++ qtd = list_entry(_qh->qtd_list.next, dwc_otg_qtd_t, qtd_list_entry); \ ++ if (usb_pipeint(qtd->urb->pipe) && _qh->start_split_frame != 0 && !qtd->complete_split) { \ ++ hfnum.d32 = DWC_READ_REG32(&_hcd->core_if->host_if->host_global_regs->hfnum); \ ++ switch (hfnum.b.frnum & 0x7) { \ ++ case 7: \ ++ _hcd->hfnum_7_samples_##_letter++; \ ++ _hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \ ++ break; \ ++ case 0: \ ++ _hcd->hfnum_0_samples_##_letter++; \ ++ _hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \ ++ break; \ ++ default: \ ++ _hcd->hfnum_other_samples_##_letter++; \ ++ _hcd->hfnum_other_frrem_accum_##_letter += hfnum.b.frrem; \ ++ break; \ ++ } \ ++ } \ ++} ++#else ++#define dwc_sample_frrem(_hcd, _qh, _letter) ++#endif ++#endif ++#endif /* DWC_DEVICE_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h 2014-03-13 12:46:39.516097989 +0100 +@@ -0,0 +1,417 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_if.h $ ++ * $Revision: #12 $ ++ * $Date: 2011/10/26 $ ++ * $Change: 1873028 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++#ifndef __DWC_HCD_IF_H__ ++#define __DWC_HCD_IF_H__ ++ ++#include "dwc_otg_core_if.h" ++ ++/** @file ++ * This file defines DWC_OTG HCD Core API. ++ */ ++ ++struct dwc_otg_hcd; ++typedef struct dwc_otg_hcd dwc_otg_hcd_t; ++ ++struct dwc_otg_hcd_urb; ++typedef struct dwc_otg_hcd_urb dwc_otg_hcd_urb_t; ++ ++/** @name HCD Function Driver Callbacks */ ++/** @{ */ ++ ++/** This function is called whenever core switches to host mode. */ ++typedef int (*dwc_otg_hcd_start_cb_t) (dwc_otg_hcd_t * hcd); ++ ++/** This function is called when device has been disconnected */ ++typedef int (*dwc_otg_hcd_disconnect_cb_t) (dwc_otg_hcd_t * hcd); ++ ++/** Wrapper provides this function to HCD to core, so it can get hub information to which device is connected */ ++typedef int (*dwc_otg_hcd_hub_info_from_urb_cb_t) (dwc_otg_hcd_t * hcd, ++ void *urb_handle, ++ uint32_t * hub_addr, ++ uint32_t * port_addr); ++/** Via this function HCD core gets device speed */ ++typedef int (*dwc_otg_hcd_speed_from_urb_cb_t) (dwc_otg_hcd_t * hcd, ++ void *urb_handle); ++ ++/** This function is called when urb is completed */ ++typedef int (*dwc_otg_hcd_complete_urb_cb_t) (dwc_otg_hcd_t * hcd, ++ void *urb_handle, ++ dwc_otg_hcd_urb_t * dwc_otg_urb, ++ int32_t status); ++ ++/** Via this function HCD core gets b_hnp_enable parameter */ ++typedef int (*dwc_otg_hcd_get_b_hnp_enable) (dwc_otg_hcd_t * hcd); ++ ++struct dwc_otg_hcd_function_ops { ++ dwc_otg_hcd_start_cb_t start; ++ dwc_otg_hcd_disconnect_cb_t disconnect; ++ dwc_otg_hcd_hub_info_from_urb_cb_t hub_info; ++ dwc_otg_hcd_speed_from_urb_cb_t speed; ++ dwc_otg_hcd_complete_urb_cb_t complete; ++ dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable; ++}; ++/** @} */ ++ ++/** @name HCD Core API */ ++/** @{ */ ++/** This function allocates dwc_otg_hcd structure and returns pointer on it. */ ++extern dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void); ++ ++/** This function should be called to initiate HCD Core. ++ * ++ * @param hcd The HCD ++ * @param core_if The DWC_OTG Core ++ * ++ * Returns -DWC_E_NO_MEMORY if no enough memory. ++ * Returns 0 on success ++ */ ++extern int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if); ++ ++/** Frees HCD ++ * ++ * @param hcd The HCD ++ */ ++extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd); ++ ++/** This function should be called on every hardware interrupt. ++ * ++ * @param dwc_otg_hcd The HCD ++ * ++ * Returns non zero if interrupt is handled ++ * Return 0 if interrupt is not handled ++ */ ++extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd); ++ ++/** This function is used to handle the fast interrupt ++ * ++ */ ++extern void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void); ++ ++/** ++ * Returns private data set by ++ * dwc_otg_hcd_set_priv_data function. ++ * ++ * @param hcd The HCD ++ */ ++extern void *dwc_otg_hcd_get_priv_data(dwc_otg_hcd_t * hcd); ++ ++/** ++ * Set private data. ++ * ++ * @param hcd The HCD ++ * @param priv_data pointer to be stored in private data ++ */ ++extern void dwc_otg_hcd_set_priv_data(dwc_otg_hcd_t * hcd, void *priv_data); ++ ++/** ++ * This function initializes the HCD Core. ++ * ++ * @param hcd The HCD ++ * @param fops The Function Driver Operations data structure containing pointers to all callbacks. ++ * ++ * Returns -DWC_E_NO_DEVICE if Core is currently is in device mode. ++ * Returns 0 on success ++ */ ++extern int dwc_otg_hcd_start(dwc_otg_hcd_t * hcd, ++ struct dwc_otg_hcd_function_ops *fops); ++ ++/** ++ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are ++ * stopped. ++ * ++ * @param hcd The HCD ++ */ ++extern void dwc_otg_hcd_stop(dwc_otg_hcd_t * hcd); ++ ++/** ++ * Handles hub class-specific requests. ++ * ++ * @param dwc_otg_hcd The HCD ++ * @param typeReq Request Type ++ * @param wValue wValue from control request ++ * @param wIndex wIndex from control request ++ * @param buf data buffer ++ * @param wLength data buffer length ++ * ++ * Returns -DWC_E_INVALID if invalid argument is passed ++ * Returns 0 on success ++ */ ++extern int dwc_otg_hcd_hub_control(dwc_otg_hcd_t * dwc_otg_hcd, ++ uint16_t typeReq, uint16_t wValue, ++ uint16_t wIndex, uint8_t * buf, ++ uint16_t wLength); ++ ++/** ++ * Returns otg port number. ++ * ++ * @param hcd The HCD ++ */ ++extern uint32_t dwc_otg_hcd_otg_port(dwc_otg_hcd_t * hcd); ++ ++/** ++ * Returns OTG version - either 1.3 or 2.0. ++ * ++ * @param core_if The core_if structure pointer ++ */ ++extern uint16_t dwc_otg_get_otg_version(dwc_otg_core_if_t * core_if); ++ ++/** ++ * Returns 1 if currently core is acting as B host, and 0 otherwise. ++ * ++ * @param hcd The HCD ++ */ ++extern uint32_t dwc_otg_hcd_is_b_host(dwc_otg_hcd_t * hcd); ++ ++/** ++ * Returns current frame number. ++ * ++ * @param hcd The HCD ++ */ ++extern int dwc_otg_hcd_get_frame_number(dwc_otg_hcd_t * hcd); ++ ++/** ++ * Dumps hcd state. ++ * ++ * @param hcd The HCD ++ */ ++extern void dwc_otg_hcd_dump_state(dwc_otg_hcd_t * hcd); ++ ++/** ++ * Dump the average frame remaining at SOF. This can be used to ++ * determine average interrupt latency. Frame remaining is also shown for ++ * start transfer and two additional sample points. ++ * Currently this function is not implemented. ++ * ++ * @param hcd The HCD ++ */ ++extern void dwc_otg_hcd_dump_frrem(dwc_otg_hcd_t * hcd); ++ ++/** ++ * Sends LPM transaction to the local device. ++ * ++ * @param hcd The HCD ++ * @param devaddr Device Address ++ * @param hird Host initiated resume duration ++ * @param bRemoteWake Value of bRemoteWake field in LPM transaction ++ * ++ * Returns negative value if sending LPM transaction was not succeeded. ++ * Returns 0 on success. ++ */ ++extern int dwc_otg_hcd_send_lpm(dwc_otg_hcd_t * hcd, uint8_t devaddr, ++ uint8_t hird, uint8_t bRemoteWake); ++ ++/* URB interface */ ++ ++/** ++ * Allocates memory for dwc_otg_hcd_urb structure. ++ * Allocated memory should be freed by call of DWC_FREE. ++ * ++ * @param hcd The HCD ++ * @param iso_desc_count Count of ISOC descriptors ++ * @param atomic_alloc Specefies whether to perform atomic allocation. ++ */ ++extern dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc(dwc_otg_hcd_t * hcd, ++ int iso_desc_count, ++ int atomic_alloc); ++ ++/** ++ * Set pipe information in URB. ++ * ++ * @param hcd_urb DWC_OTG URB ++ * @param devaddr Device Address ++ * @param ep_num Endpoint Number ++ * @param ep_type Endpoint Type ++ * @param ep_dir Endpoint Direction ++ * @param mps Max Packet Size ++ */ ++extern void dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_hcd_urb_t * hcd_urb, ++ uint8_t devaddr, uint8_t ep_num, ++ uint8_t ep_type, uint8_t ep_dir, ++ uint16_t mps); ++ ++/* Transfer flags */ ++#define URB_GIVEBACK_ASAP 0x1 ++#define URB_SEND_ZERO_PACKET 0x2 ++ ++/** ++ * Sets dwc_otg_hcd_urb parameters. ++ * ++ * @param urb DWC_OTG URB allocated by dwc_otg_hcd_urb_alloc function. ++ * @param urb_handle Unique handle for request, this will be passed back ++ * to function driver in completion callback. ++ * @param buf The buffer for the data ++ * @param dma The DMA buffer for the data ++ * @param buflen Transfer length ++ * @param sp Buffer for setup data ++ * @param sp_dma DMA address of setup data buffer ++ * @param flags Transfer flags ++ * @param interval Polling interval for interrupt or isochronous transfers. ++ */ ++extern void dwc_otg_hcd_urb_set_params(dwc_otg_hcd_urb_t * urb, ++ void *urb_handle, void *buf, ++ dwc_dma_t dma, uint32_t buflen, void *sp, ++ dwc_dma_t sp_dma, uint32_t flags, ++ uint16_t interval); ++ ++/** Gets status from dwc_otg_hcd_urb ++ * ++ * @param dwc_otg_urb DWC_OTG URB ++ */ ++extern uint32_t dwc_otg_hcd_urb_get_status(dwc_otg_hcd_urb_t * dwc_otg_urb); ++ ++/** Gets actual length from dwc_otg_hcd_urb ++ * ++ * @param dwc_otg_urb DWC_OTG URB ++ */ ++extern uint32_t dwc_otg_hcd_urb_get_actual_length(dwc_otg_hcd_urb_t * ++ dwc_otg_urb); ++ ++/** Gets error count from dwc_otg_hcd_urb. Only for ISOC URBs ++ * ++ * @param dwc_otg_urb DWC_OTG URB ++ */ ++extern uint32_t dwc_otg_hcd_urb_get_error_count(dwc_otg_hcd_urb_t * ++ dwc_otg_urb); ++ ++/** Set ISOC descriptor offset and length ++ * ++ * @param dwc_otg_urb DWC_OTG URB ++ * @param desc_num ISOC descriptor number ++ * @param offset Offset from beginig of buffer. ++ * @param length Transaction length ++ */ ++extern void dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_hcd_urb_t * dwc_otg_urb, ++ int desc_num, uint32_t offset, ++ uint32_t length); ++ ++/** Get status of ISOC descriptor, specified by desc_num ++ * ++ * @param dwc_otg_urb DWC_OTG URB ++ * @param desc_num ISOC descriptor number ++ */ ++extern uint32_t dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_hcd_urb_t * ++ dwc_otg_urb, int desc_num); ++ ++/** Get actual length of ISOC descriptor, specified by desc_num ++ * ++ * @param dwc_otg_urb DWC_OTG URB ++ * @param desc_num ISOC descriptor number ++ */ ++extern uint32_t dwc_otg_hcd_urb_get_iso_desc_actual_length(dwc_otg_hcd_urb_t * ++ dwc_otg_urb, ++ int desc_num); ++ ++/** Queue URB. After transfer is completes, the complete callback will be called with the URB status ++ * ++ * @param dwc_otg_hcd The HCD ++ * @param dwc_otg_urb DWC_OTG URB ++ * @param ep_handle Out parameter for returning endpoint handle ++ * @param atomic_alloc Flag to do atomic allocation if needed ++ * ++ * Returns -DWC_E_NO_DEVICE if no device is connected. ++ * Returns -DWC_E_NO_MEMORY if there is no enough memory. ++ * Returns 0 on success. ++ */ ++extern int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_t * dwc_otg_hcd, ++ dwc_otg_hcd_urb_t * dwc_otg_urb, ++ void **ep_handle, int atomic_alloc); ++ ++/** De-queue the specified URB ++ * ++ * @param dwc_otg_hcd The HCD ++ * @param dwc_otg_urb DWC_OTG URB ++ */ ++extern int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_t * dwc_otg_hcd, ++ dwc_otg_hcd_urb_t * dwc_otg_urb); ++ ++/** Frees resources in the DWC_otg controller related to a given endpoint. ++ * Any URBs for the endpoint must already be dequeued. ++ * ++ * @param hcd The HCD ++ * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function ++ * @param retry Number of retries if there are queued transfers. ++ * ++ * Returns -DWC_E_INVALID if invalid arguments are passed. ++ * Returns 0 on success ++ */ ++extern int dwc_otg_hcd_endpoint_disable(dwc_otg_hcd_t * hcd, void *ep_handle, ++ int retry); ++ ++/* Resets the data toggle in qh structure. This function can be called from ++ * usb_clear_halt routine. ++ * ++ * @param hcd The HCD ++ * @param ep_handle Endpoint handle, returned by dwc_otg_hcd_urb_enqueue function ++ * ++ * Returns -DWC_E_INVALID if invalid arguments are passed. ++ * Returns 0 on success ++ */ ++extern int dwc_otg_hcd_endpoint_reset(dwc_otg_hcd_t * hcd, void *ep_handle); ++ ++/** Returns 1 if status of specified port is changed and 0 otherwise. ++ * ++ * @param hcd The HCD ++ * @param port Port number ++ */ ++extern int dwc_otg_hcd_is_status_changed(dwc_otg_hcd_t * hcd, int port); ++ ++/** Call this function to check if bandwidth was allocated for specified endpoint. ++ * Only for ISOC and INTERRUPT endpoints. ++ * ++ * @param hcd The HCD ++ * @param ep_handle Endpoint handle ++ */ ++extern int dwc_otg_hcd_is_bandwidth_allocated(dwc_otg_hcd_t * hcd, ++ void *ep_handle); ++ ++/** Call this function to check if bandwidth was freed for specified endpoint. ++ * ++ * @param hcd The HCD ++ * @param ep_handle Endpoint handle ++ */ ++extern int dwc_otg_hcd_is_bandwidth_freed(dwc_otg_hcd_t * hcd, void *ep_handle); ++ ++/** Returns bandwidth allocated for specified endpoint in microseconds. ++ * Only for ISOC and INTERRUPT endpoints. ++ * ++ * @param hcd The HCD ++ * @param ep_handle Endpoint handle ++ */ ++extern uint8_t dwc_otg_hcd_get_ep_bandwidth(dwc_otg_hcd_t * hcd, ++ void *ep_handle); ++ ++/** @} */ ++ ++#endif /* __DWC_HCD_IF_H__ */ ++#endif /* DWC_DEVICE_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c 2014-03-13 12:46:39.516097989 +0100 +@@ -0,0 +1,2741 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_intr.c $ ++ * $Revision: #89 $ ++ * $Date: 2011/10/20 $ ++ * $Change: 1869487 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++ ++#include "dwc_otg_hcd.h" ++#include "dwc_otg_regs.h" ++#include "dwc_otg_mphi_fix.h" ++ ++#include ++#include ++#include ++ ++ ++extern bool microframe_schedule; ++ ++/** @file ++ * This file contains the implementation of the HCD Interrupt handlers. ++ */ ++ ++/* ++ * Some globals to communicate between the FIQ and INTERRUPT ++ */ ++ ++void * dummy_send; ++mphi_regs_t c_mphi_regs; ++volatile void *dwc_regs_base; ++int fiq_done, int_done; ++ ++gintsts_data_t gintsts_saved = {.d32 = 0}; ++hcint_data_t hcint_saved[MAX_EPS_CHANNELS]; ++hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS]; ++int split_out_xfersize[MAX_EPS_CHANNELS]; ++haint_data_t haint_saved; ++ ++int g_next_sched_frame, g_np_count, g_np_sent; ++static int mphi_int_count = 0 ; ++ ++hcchar_data_t nak_hcchar; ++hctsiz_data_t nak_hctsiz; ++hcsplt_data_t nak_hcsplt; ++int nak_count; ++ ++int complete_sched[MAX_EPS_CHANNELS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; ++int split_start_frame[MAX_EPS_CHANNELS]; ++int queued_port[MAX_EPS_CHANNELS]; ++ ++#ifdef FIQ_DEBUG ++char buffer[1000*16]; ++int wptr; ++void notrace _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...) ++{ ++ FIQDBG_T dbg_lvl_req = FIQDBG_PORTHUB; ++ va_list args; ++ char text[17]; ++ hfnum_data_t hfnum = { .d32 = FIQ_READ(dwc_regs_base + 0x408) }; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ local_fiq_disable(); ++ if(dbg_lvl & dbg_lvl_req || dbg_lvl == FIQDBG_ERR) ++ { ++ snprintf(text, 9, "%4d%d:%d ", hfnum.b.frnum/8, hfnum.b.frnum%8, 8 - hfnum.b.frrem/937); ++ va_start(args, fmt); ++ vsnprintf(text+8, 9, fmt, args); ++ va_end(args); ++ ++ memcpy(buffer + wptr, text, 16); ++ wptr = (wptr + 16) % sizeof(buffer); ++ } ++ local_irq_restore(flags); ++} ++#endif ++ ++void notrace fiq_queue_request(int channel, int odd_frame) ++{ ++ hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; ++ hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; ++ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10) }; ++ ++ if(hcsplt.b.spltena == 0) ++ { ++ fiq_print(FIQDBG_ERR, "SPLTENA "); ++ BUG(); ++ } ++ ++ if(hcchar.b.epdir == 1) ++ { ++ fiq_print(FIQDBG_SCHED, "IN Ch %d", channel); ++ } ++ else ++ { ++ hctsiz.b.xfersize = 0; ++ fiq_print(FIQDBG_SCHED, "OUT Ch %d", channel); ++ } ++ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x10), hctsiz.d32); ++ ++ hcsplt.b.compsplt = 1; ++ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x4), hcsplt.d32); ++ ++ // Send the Split complete ++ hcchar.b.chen = 1; ++ hcchar.b.oddfrm = odd_frame ? 1 : 0; ++ ++ // Post this for transmit on the next frame for periodic or this frame for non-periodic ++ fiq_print(FIQDBG_SCHED, "SND_%s", odd_frame ? "ODD " : "EVEN"); ++ ++ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x0), hcchar.d32); ++} ++ ++static int last_sof = -1; ++ ++/* ++** Function to handle the start of frame interrupt, choose whether we need to do anything and ++** therefore trigger the main interrupt ++** ++** returns int != 0 - interrupt has been handled ++*/ ++int diff; ++ ++int notrace fiq_sof_handle(hfnum_data_t hfnum) ++{ ++ int handled = 0; ++ int i; ++ ++ // Just check that once we're running we don't miss a SOF ++ /*if(last_sof != -1 && (hfnum.b.frnum != ((last_sof + 1) & 0x3fff))) ++ { ++ fiq_print(FIQDBG_ERR, "LASTSOF "); ++ fiq_print(FIQDBG_ERR, "%4d%d ", last_sof / 8, last_sof & 7); ++ fiq_print(FIQDBG_ERR, "%4d%d ", hfnum.b.frnum / 8, hfnum.b.frnum & 7); ++ BUG(); ++ }*/ ++ ++ // Only start remembering the last sof when the interrupt has been ++ // enabled (we don't check the mask to come in here...) ++ if(last_sof != -1 || FIQ_READ(dwc_regs_base + 0x18) & (1<<3)) ++ last_sof = hfnum.b.frnum; ++ ++ for(i = 0; i < MAX_EPS_CHANNELS; i++) ++ { ++ if(complete_sched[i] != -1) ++ { ++ if(complete_sched[i] <= hfnum.b.frnum || (complete_sched[i] > 0x3f00 && hfnum.b.frnum < 0xf0)) ++ { ++ fiq_queue_request(i, hfnum.b.frnum & 1); ++ complete_sched[i] = -1; ++ } ++ } ++ ++ if(complete_sched[i] != -1) ++ { ++ // This is because we've seen a split complete occur with no start... ++ // most likely because missed the complete 0x3fff frames ago! ++ ++ diff = (hfnum.b.frnum + 0x3fff - complete_sched[i]) & 0x3fff ; ++ if(diff > 32 && diff < 0x3f00) ++ { ++ fiq_print(FIQDBG_ERR, "SPLTMISS"); ++ BUG(); ++ } ++ } ++ } ++ ++ if(g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) ++ { ++ /* ++ * If np_count != np_sent that means we need to queue non-periodic (bulk) packets this packet ++ * g_next_sched_frame is the next frame we have periodic packets for ++ * ++ * if neither of these are required for this frame then just clear the interrupt ++ */ ++ handled = 1; ++ ++ } ++ ++ return handled; ++} ++ ++int notrace port_id(hcsplt_data_t hcsplt) ++{ ++ return hcsplt.b.prtaddr + (hcsplt.b.hubaddr << 8); ++} ++ ++int notrace fiq_hcintr_handle(int channel, hfnum_data_t hfnum) ++{ ++ hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) }; ++ hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) }; ++ hcint_data_t hcint = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x8) }; ++ hcintmsk_data_t hcintmsk = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0xc) }; ++ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10)}; ++ ++ hcint_saved[channel].d32 |= hcint.d32; ++ hcintmsk_saved[channel].d32 = hcintmsk.d32; ++ ++ if(hcsplt.b.spltena) ++ { ++ fiq_print(FIQDBG_PORTHUB, "ph: %4x", port_id(hcsplt)); ++ if(hcint.b.chhltd) ++ { ++ fiq_print(FIQDBG_SCHED, "CH HLT %d", channel); ++ fiq_print(FIQDBG_SCHED, "%08x", hcint_saved[channel]); ++ } ++ if(hcint.b.stall || hcint.b.xacterr || hcint.b.bblerr || hcint.b.frmovrun || hcint.b.datatglerr) ++ { ++ queued_port[channel] = 0; ++ fiq_print(FIQDBG_ERR, "CHAN ERR"); ++ } ++ if(hcint.b.xfercomp) ++ { ++ // Clear the port allocation and transmit anything also on this port ++ queued_port[channel] = 0; ++ fiq_print(FIQDBG_SCHED, "XFERCOMP"); ++ } ++ if(hcint.b.nak) ++ { ++ queued_port[channel] = 0; ++ fiq_print(FIQDBG_SCHED, "NAK"); ++ } ++ if(hcint.b.ack && !hcsplt.b.compsplt) ++ { ++ int i; ++ ++ // Do not complete isochronous out transactions ++ if(hcchar.b.eptype == 1 && hcchar.b.epdir == 0) ++ { ++ queued_port[channel] = 0; ++ fiq_print(FIQDBG_SCHED, "ISOC_OUT"); ++ } ++ else ++ { ++ // Make sure we check the port / hub combination that we sent this split on. ++ // Do not queue a second request to the same port ++ for(i = 0; i < MAX_EPS_CHANNELS; i++) ++ { ++ if(port_id(hcsplt) == queued_port[i]) ++ { ++ fiq_print(FIQDBG_ERR, "PORTERR "); ++ //BUG(); ++ } ++ } ++ ++ split_start_frame[channel] = (hfnum.b.frnum + 1) & ~7; ++ ++ // Note, the size of an OUT is in the start split phase, not ++ // the complete split ++ split_out_xfersize[channel] = hctsiz.b.xfersize; ++ ++ hcint_saved[channel].b.chhltd = 0; ++ hcint_saved[channel].b.ack = 0; ++ ++ queued_port[channel] = port_id(hcsplt); ++ ++ if(hcchar.b.eptype & 1) ++ { ++ // Send the periodic complete in the same oddness frame as the ACK went... ++ fiq_queue_request(channel, !(hfnum.b.frnum & 1)); ++ // complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1); ++ } ++ else ++ { ++ // Schedule the split complete to occur later ++ complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 2); ++ fiq_print(FIQDBG_SCHED, "ACK%04d%d", complete_sched[channel]/8, complete_sched[channel]%8); ++ } ++ } ++ } ++ if(hcint.b.nyet) ++ { ++ fiq_print(FIQDBG_ERR, "NYETERR1"); ++ //BUG(); ++ // Can transmit a split complete up to uframe .0 of the next frame ++ if(hfnum.b.frnum <= dwc_frame_num_inc(split_start_frame[channel], 8)) ++ { ++ // Send it next frame ++ if(hcchar.b.eptype & 1) // type 1 & 3 are interrupt & isoc ++ { ++ fiq_print(FIQDBG_SCHED, "NYT:SEND"); ++ fiq_queue_request(channel, !(hfnum.b.frnum & 1)); ++ } ++ else ++ { ++ // Schedule non-periodic access for next frame (the odd-even bit doesn't effect NP) ++ complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1); ++ fiq_print(FIQDBG_SCHED, "NYT%04d%d", complete_sched[channel]/8, complete_sched[channel]%8); ++ } ++ hcint_saved[channel].b.chhltd = 0; ++ hcint_saved[channel].b.nyet = 0; ++ } ++ else ++ { ++ queued_port[channel] = 0; ++ fiq_print(FIQDBG_ERR, "NYETERR2"); ++ //BUG(); ++ } ++ } ++ } ++ else ++ { ++ /* ++ * If we have any of NAK, ACK, Datatlgerr active on a ++ * non-split channel, the sole reason is to reset error ++ * counts for a previously broken transaction. The FIQ ++ * will thrash on NAK IN and ACK OUT in particular so ++ * handle it "once" and allow the IRQ to do the rest. ++ */ ++ hcint.d32 &= hcintmsk.d32; ++ if(hcint.b.nak) ++ { ++ hcintmsk.b.nak = 0; ++ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32); ++ } ++ if (hcint.b.ack) ++ { ++ hcintmsk.b.ack = 0; ++ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32); ++ } ++ } ++ ++ // Clear the interrupt, this will also clear the HAINT bit ++ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x8), hcint.d32); ++ return hcint_saved[channel].d32 == 0; ++} ++ ++gintsts_data_t gintsts; ++gintmsk_data_t gintmsk; ++// triggered: The set of interrupts that were triggered ++// handled: The set of interrupts that have been handled (no IRQ is ++// required) ++// keep: The set of interrupts we want to keep unmasked even though we ++// want to trigger an IRQ to handle it (SOF and HCINTR) ++gintsts_data_t triggered, handled, keep; ++hfnum_data_t hfnum; ++ ++void __attribute__ ((naked)) notrace dwc_otg_hcd_handle_fiq(void) ++{ ++ ++ /* entry takes care to store registers we will be treading on here */ ++ asm __volatile__ ( ++ "mov ip, sp ;" ++ /* stash FIQ and normal regs */ ++ "stmdb sp!, {r0-r12, lr};" ++ /* !! THIS SETS THE FRAME, adjust to > sizeof locals */ ++ "sub fp, ip, #512 ;" ++ ); ++ ++ // Cannot put local variables at the beginning of the function ++ // because otherwise 'C' will play with the stack pointer. any locals ++ // need to be inside the following block ++ do ++ { ++ fiq_done++; ++ gintsts.d32 = FIQ_READ(dwc_regs_base + 0x14); ++ gintmsk.d32 = FIQ_READ(dwc_regs_base + 0x18); ++ hfnum.d32 = FIQ_READ(dwc_regs_base + 0x408); ++ triggered.d32 = gintsts.d32 & gintmsk.d32; ++ handled.d32 = 0; ++ keep.d32 = 0; ++ fiq_print(FIQDBG_INT, "FIQ "); ++ fiq_print(FIQDBG_INT, "%08x", gintsts.d32); ++ fiq_print(FIQDBG_INT, "%08x", gintmsk.d32); ++ if(gintsts.d32) ++ { ++ // If port enabled ++ if((FIQ_READ(dwc_regs_base + 0x440) & 0xf) == 0x5) ++ { ++ if(gintsts.b.sofintr) ++ { ++ if(fiq_sof_handle(hfnum)) ++ { ++ handled.b.sofintr = 1; /* Handled in FIQ */ ++ } ++ else ++ { ++ /* Keer interrupt unmasked */ ++ keep.b.sofintr = 1; ++ } ++ { ++ // Need to make sure the read and clearing of the SOF interrupt is as close as possible to avoid the possibility of missing ++ // a start of frame interrupt ++ gintsts_data_t gintsts = { .b.sofintr = 1 }; ++ FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32); ++ } ++ } ++ ++ if(fiq_split_enable && gintsts.b.hcintr) ++ { ++ int i; ++ haint_data_t haint; ++ haintmsk_data_t haintmsk; ++ ++ haint.d32 = FIQ_READ(dwc_regs_base + 0x414); ++ haintmsk.d32 = FIQ_READ(dwc_regs_base + 0x418); ++ haint.d32 &= haintmsk.d32; ++ haint_saved.d32 |= haint.d32; ++ ++ fiq_print(FIQDBG_INT, "hcintr"); ++ fiq_print(FIQDBG_INT, "%08x", FIQ_READ(dwc_regs_base + 0x414)); ++ ++ // Go through each channel that has an enabled interrupt ++ for(i = 0; i < 16; i++) ++ if((haint.d32 >> i) & 1) ++ if(fiq_hcintr_handle(i, hfnum)) ++ haint_saved.d32 &= ~(1 << i); /* this was handled */ ++ ++ /* If we've handled all host channel interrupts then don't trigger the interrupt */ ++ if(haint_saved.d32 == 0) ++ { ++ handled.b.hcintr = 1; ++ } ++ else ++ { ++ /* Make sure we keep the channel interrupt unmasked when triggering the IRQ */ ++ keep.b.hcintr = 1; ++ } ++ ++ { ++ gintsts_data_t gintsts = { .b.hcintr = 1 }; ++ ++ // Always clear the channel interrupt ++ FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32); ++ } ++ } ++ } ++ else ++ { ++ last_sof = -1; ++ } ++ } ++ ++ // Mask out the interrupts triggered - those handled - don't mask out the ones we want to keep ++ gintmsk.d32 = keep.d32 | (gintmsk.d32 & ~(triggered.d32 & ~handled.d32)); ++ // Save those that were triggered but not handled ++ gintsts_saved.d32 |= triggered.d32 & ~handled.d32; ++ FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32); ++ ++ // Clear and save any unhandled interrupts and trigger the interrupt ++ if(gintsts_saved.d32) ++ { ++ /* To enable the MPHI interrupt (INT 32) ++ */ ++ FIQ_WRITE( c_mphi_regs.outdda, (int) dummy_send); ++ FIQ_WRITE( c_mphi_regs.outddb, (1 << 29)); ++ ++ mphi_int_count++; ++ } ++ } ++ while(0); ++ ++ mb(); ++ ++ /* exit back to normal mode restoring everything */ ++ asm __volatile__ ( ++ /* return FIQ regs back to pristine state ++ * and get normal regs back ++ */ ++ "ldmia sp!, {r0-r12, lr};" ++ ++ /* return */ ++ "subs pc, lr, #4;" ++ ); ++} ++ ++/** This function handles interrupts for the HCD. */ ++int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd) ++{ ++ int retval = 0; ++ static int last_time; ++ ++ dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if; ++ gintsts_data_t gintsts; ++ gintmsk_data_t gintmsk; ++ hfnum_data_t hfnum; ++ ++#ifdef DEBUG ++ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; ++ ++#endif ++ ++ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts); ++ gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk); ++ ++ /* Exit from ISR if core is hibernated */ ++ if (core_if->hibernation_suspend == 1) { ++ goto exit_handler_routine; ++ } ++ DWC_SPINLOCK(dwc_otg_hcd->lock); ++ /* Check if HOST Mode */ ++ if (dwc_otg_is_host_mode(core_if)) { ++ local_fiq_disable(); ++ gintmsk.d32 |= gintsts_saved.d32; ++ gintsts.d32 |= gintsts_saved.d32; ++ gintsts_saved.d32 = 0; ++ local_fiq_enable(); ++ if (!gintsts.d32) { ++ goto exit_handler_routine; ++ } ++ gintsts.d32 &= gintmsk.d32; ++ ++#ifdef DEBUG ++ // We should be OK doing this because the common interrupts should already have been serviced ++ /* Don't print debug message in the interrupt handler on SOF */ ++#ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++#endif ++ DWC_DEBUGPL(DBG_HCDI, "\n"); ++#endif ++ ++#ifdef DEBUG ++#ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++#endif ++ DWC_DEBUGPL(DBG_HCDI, ++ "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n", ++ gintsts.d32, core_if); ++#endif ++ hfnum.d32 = DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->hfnum); ++ if (gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum)) ++ { ++ /* Note, we should never get here if the FIQ is doing it's job properly*/ ++ retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); ++ } ++ else if (gintsts.b.sofintr) { ++ retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd); ++ } ++ ++ if (gintsts.b.rxstsqlvl) { ++ retval |= ++ dwc_otg_hcd_handle_rx_status_q_level_intr ++ (dwc_otg_hcd); ++ } ++ if (gintsts.b.nptxfempty) { ++ retval |= ++ dwc_otg_hcd_handle_np_tx_fifo_empty_intr ++ (dwc_otg_hcd); ++ } ++ if (gintsts.b.i2cintr) { ++ /** @todo Implement i2cintr handler. */ ++ } ++ if (gintsts.b.portintr) { ++ ++ gintmsk_data_t gintmsk = { .b.portintr = 1}; ++ retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd); ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32); ++ } ++ if (gintsts.b.hcintr) { ++ retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd); ++ } ++ if (gintsts.b.ptxfempty) { ++ retval |= ++ dwc_otg_hcd_handle_perio_tx_fifo_empty_intr ++ (dwc_otg_hcd); ++ } ++#ifdef DEBUG ++#ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++#endif ++ { ++ DWC_DEBUGPL(DBG_HCDI, ++ "DWC OTG HCD Finished Servicing Interrupts\n"); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n", ++ DWC_READ_REG32(&global_regs->gintsts)); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n", ++ DWC_READ_REG32(&global_regs->gintmsk)); ++ } ++#endif ++ ++#ifdef DEBUG ++#ifndef DEBUG_SOF ++ if (gintsts.d32 != DWC_SOF_INTR_MASK) ++#endif ++ DWC_DEBUGPL(DBG_HCDI, "\n"); ++#endif ++ ++ } ++ ++exit_handler_routine: ++ ++ if (fiq_fix_enable) ++ { ++ local_fiq_disable(); ++ // Make sure that we don't clear the interrupt if we've still got pending work to do ++ if(gintsts_saved.d32 == 0) ++ { ++ /* Clear the MPHI interrupt */ ++ DWC_WRITE_REG32(c_mphi_regs.intstat, (1<<16)); ++ if (mphi_int_count >= 60) ++ { ++ DWC_WRITE_REG32(c_mphi_regs.ctrl, ((1<<31) + (1<<16))); ++ while(!(DWC_READ_REG32(c_mphi_regs.ctrl) & (1 << 17))) ++ ; ++ DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31)); ++ mphi_int_count = 0; ++ } ++ int_done++; ++ } ++ ++ // Unmask handled interrupts ++ FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32); ++ //DWC_MODIFY_REG32((uint32_t *)IO_ADDRESS(USB_BASE + 0x8), 0 , 1); ++ ++ local_fiq_enable(); ++ ++ if((jiffies / HZ) > last_time) ++ { ++ /* Once a second output the fiq and irq numbers, useful for debug */ ++ last_time = jiffies / HZ; ++ DWC_DEBUGPL(DBG_USER, "int_done = %d fiq_done = %d\n", int_done, fiq_done); ++ } ++ } ++ ++ DWC_SPINUNLOCK(dwc_otg_hcd->lock); ++ return retval; ++} ++ ++#ifdef DWC_TRACK_MISSED_SOFS ++ ++#warning Compiling code to track missed SOFs ++#define FRAME_NUM_ARRAY_SIZE 1000 ++/** ++ * This function is for debug only. ++ */ ++static inline void track_missed_sofs(uint16_t curr_frame_number) ++{ ++ static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE]; ++ static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE]; ++ static int frame_num_idx = 0; ++ static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM; ++ static int dumped_frame_num_array = 0; ++ ++ if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) { ++ if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) != ++ curr_frame_number) { ++ frame_num_array[frame_num_idx] = curr_frame_number; ++ last_frame_num_array[frame_num_idx++] = last_frame_num; ++ } ++ } else if (!dumped_frame_num_array) { ++ int i; ++ DWC_PRINTF("Frame Last Frame\n"); ++ DWC_PRINTF("----- ----------\n"); ++ for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) { ++ DWC_PRINTF("0x%04x 0x%04x\n", ++ frame_num_array[i], last_frame_num_array[i]); ++ } ++ dumped_frame_num_array = 1; ++ } ++ last_frame_num = curr_frame_number; ++} ++#endif ++ ++/** ++ * Handles the start-of-frame interrupt in host mode. Non-periodic ++ * transactions may be queued to the DWC_otg controller for the current ++ * (micro)frame. Periodic transactions may be queued to the controller for the ++ * next (micro)frame. ++ */ ++int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd) ++{ ++ hfnum_data_t hfnum; ++ dwc_list_link_t *qh_entry; ++ dwc_otg_qh_t *qh; ++ dwc_otg_transaction_type_e tr_type; ++ int did_something = 0; ++ int32_t next_sched_frame = -1; ++ ++ hfnum.d32 = ++ DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum); ++ ++#ifdef DEBUG_SOF ++ DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n"); ++#endif ++ hcd->frame_number = hfnum.b.frnum; ++ ++#ifdef DEBUG ++ hcd->frrem_accum += hfnum.b.frrem; ++ hcd->frrem_samples++; ++#endif ++ ++#ifdef DWC_TRACK_MISSED_SOFS ++ track_missed_sofs(hcd->frame_number); ++#endif ++ /* Determine whether any periodic QHs should be executed. */ ++ qh_entry = DWC_LIST_FIRST(&hcd->periodic_sched_inactive); ++ while (qh_entry != &hcd->periodic_sched_inactive) { ++ qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry); ++ qh_entry = qh_entry->next; ++ if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) { ++ ++ /* ++ * Move QH to the ready list to be executed next ++ * (micro)frame. ++ */ ++ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, ++ &qh->qh_list_entry); ++ ++ did_something = 1; ++ } ++ else ++ { ++ if(next_sched_frame < 0 || dwc_frame_num_le(qh->sched_frame, next_sched_frame)) ++ { ++ next_sched_frame = qh->sched_frame; ++ } ++ } ++ } ++ ++ g_next_sched_frame = next_sched_frame; ++ ++ tr_type = dwc_otg_hcd_select_transactions(hcd); ++ if (tr_type != DWC_OTG_TRANSACTION_NONE) { ++ dwc_otg_hcd_queue_transactions(hcd, tr_type); ++ did_something = 1; ++ } ++ ++ /* Clear interrupt */ ++ gintsts.b.sofintr = 1; ++ DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** Handles the Rx Status Queue Level Interrupt, which indicates that there is at ++ * least one packet in the Rx FIFO. The packets are moved from the FIFO to ++ * memory if the DWC_otg controller is operating in Slave mode. */ ++int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd_t * dwc_otg_hcd) ++{ ++ host_grxsts_data_t grxsts; ++ dwc_hc_t *hc = NULL; ++ ++ DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n"); ++ ++ grxsts.d32 = ++ DWC_READ_REG32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp); ++ ++ hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum]; ++ if (!hc) { ++ DWC_ERROR("Unable to get corresponding channel\n"); ++ return 0; ++ } ++ ++ /* Packet Status */ ++ DWC_DEBUGPL(DBG_HCDV, " Ch num = %d\n", grxsts.b.chnum); ++ DWC_DEBUGPL(DBG_HCDV, " Count = %d\n", grxsts.b.bcnt); ++ DWC_DEBUGPL(DBG_HCDV, " DPID = %d, hc.dpid = %d\n", grxsts.b.dpid, ++ hc->data_pid_start); ++ DWC_DEBUGPL(DBG_HCDV, " PStatus = %d\n", grxsts.b.pktsts); ++ ++ switch (grxsts.b.pktsts) { ++ case DWC_GRXSTS_PKTSTS_IN: ++ /* Read the data into the host buffer. */ ++ if (grxsts.b.bcnt > 0) { ++ dwc_otg_read_packet(dwc_otg_hcd->core_if, ++ hc->xfer_buff, grxsts.b.bcnt); ++ ++ /* Update the HC fields for the next packet received. */ ++ hc->xfer_count += grxsts.b.bcnt; ++ hc->xfer_buff += grxsts.b.bcnt; ++ } ++ ++ case DWC_GRXSTS_PKTSTS_IN_XFER_COMP: ++ case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR: ++ case DWC_GRXSTS_PKTSTS_CH_HALTED: ++ /* Handled in interrupt, just ignore data */ ++ break; ++ default: ++ DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n", ++ grxsts.b.pktsts); ++ break; ++ } ++ ++ return 1; ++} ++ ++/** This interrupt occurs when the non-periodic Tx FIFO is half-empty. More ++ * data packets may be written to the FIFO for OUT transfers. More requests ++ * may be written to the non-periodic request queue for IN transfers. This ++ * interrupt is enabled only in Slave mode. */ ++int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n"); ++ dwc_otg_hcd_queue_transactions(dwc_otg_hcd, ++ DWC_OTG_TRANSACTION_NON_PERIODIC); ++ return 1; ++} ++ ++/** This interrupt occurs when the periodic Tx FIFO is half-empty. More data ++ * packets may be written to the FIFO for OUT transfers. More requests may be ++ * written to the periodic request queue for IN transfers. This interrupt is ++ * enabled only in Slave mode. */ ++int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(dwc_otg_hcd_t * dwc_otg_hcd) ++{ ++ DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n"); ++ dwc_otg_hcd_queue_transactions(dwc_otg_hcd, ++ DWC_OTG_TRANSACTION_PERIODIC); ++ return 1; ++} ++ ++/** There are multiple conditions that can cause a port interrupt. This function ++ * determines which interrupt conditions have occurred and handles them ++ * appropriately. */ ++int32_t dwc_otg_hcd_handle_port_intr(dwc_otg_hcd_t * dwc_otg_hcd) ++{ ++ int retval = 0; ++ hprt0_data_t hprt0; ++ hprt0_data_t hprt0_modify; ++ ++ hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0); ++ hprt0_modify.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0); ++ ++ /* Clear appropriate bits in HPRT0 to clear the interrupt bit in ++ * GINTSTS */ ++ ++ hprt0_modify.b.prtena = 0; ++ hprt0_modify.b.prtconndet = 0; ++ hprt0_modify.b.prtenchng = 0; ++ hprt0_modify.b.prtovrcurrchng = 0; ++ ++ /* Port Connect Detected ++ * Set flag and clear if detected */ ++ if (dwc_otg_hcd->core_if->hibernation_suspend == 1) { ++ // Dont modify port status if we are in hibernation state ++ hprt0_modify.b.prtconndet = 1; ++ hprt0_modify.b.prtenchng = 1; ++ DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32); ++ hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0); ++ return retval; ++ } ++ ++ if (hprt0.b.prtconndet) { ++ /** @todo - check if steps performed in 'else' block should be perfromed regardles adp */ ++ if (dwc_otg_hcd->core_if->adp_enable && ++ dwc_otg_hcd->core_if->adp.vbuson_timer_started == 1) { ++ DWC_PRINTF("PORT CONNECT DETECTED ----------------\n"); ++ DWC_TIMER_CANCEL(dwc_otg_hcd->core_if->adp.vbuson_timer); ++ dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0; ++ /* TODO - check if this is required, as ++ * host initialization was already performed ++ * after initial ADP probing ++ */ ++ /*dwc_otg_hcd->core_if->adp.vbuson_timer_started = 0; ++ dwc_otg_core_init(dwc_otg_hcd->core_if); ++ dwc_otg_enable_global_interrupts(dwc_otg_hcd->core_if); ++ cil_hcd_start(dwc_otg_hcd->core_if);*/ ++ } else { ++ ++ DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x " ++ "Port Connect Detected--\n", hprt0.d32); ++ dwc_otg_hcd->flags.b.port_connect_status_change = 1; ++ dwc_otg_hcd->flags.b.port_connect_status = 1; ++ hprt0_modify.b.prtconndet = 1; ++ ++ /* B-Device has connected, Delete the connection timer. */ ++ DWC_TIMER_CANCEL(dwc_otg_hcd->conn_timer); ++ } ++ /* The Hub driver asserts a reset when it sees port connect ++ * status change flag */ ++ retval |= 1; ++ } ++ ++ /* Port Enable Changed ++ * Clear if detected - Set internal flag if disabled */ ++ if (hprt0.b.prtenchng) { ++ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " ++ "Port Enable Changed--\n", hprt0.d32); ++ hprt0_modify.b.prtenchng = 1; ++ if (hprt0.b.prtena == 1) { ++ hfir_data_t hfir; ++ int do_reset = 0; ++ dwc_otg_core_params_t *params = ++ dwc_otg_hcd->core_if->core_params; ++ dwc_otg_core_global_regs_t *global_regs = ++ dwc_otg_hcd->core_if->core_global_regs; ++ dwc_otg_host_if_t *host_if = ++ dwc_otg_hcd->core_if->host_if; ++ ++ /* Every time when port enables calculate ++ * HFIR.FrInterval ++ */ ++ hfir.d32 = DWC_READ_REG32(&host_if->host_global_regs->hfir); ++ hfir.b.frint = calc_frame_interval(dwc_otg_hcd->core_if); ++ DWC_WRITE_REG32(&host_if->host_global_regs->hfir, hfir.d32); ++ ++ /* Check if we need to adjust the PHY clock speed for ++ * low power and adjust it */ ++ if (params->host_support_fs_ls_low_power) { ++ gusbcfg_data_t usbcfg; ++ ++ usbcfg.d32 = ++ DWC_READ_REG32(&global_regs->gusbcfg); ++ ++ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED ++ || hprt0.b.prtspd == ++ DWC_HPRT0_PRTSPD_FULL_SPEED) { ++ /* ++ * Low power ++ */ ++ hcfg_data_t hcfg; ++ if (usbcfg.b.phylpwrclksel == 0) { ++ /* Set PHY low power clock select for FS/LS devices */ ++ usbcfg.b.phylpwrclksel = 1; ++ DWC_WRITE_REG32 ++ (&global_regs->gusbcfg, ++ usbcfg.d32); ++ do_reset = 1; ++ } ++ ++ hcfg.d32 = ++ DWC_READ_REG32 ++ (&host_if->host_global_regs->hcfg); ++ ++ if (hprt0.b.prtspd == ++ DWC_HPRT0_PRTSPD_LOW_SPEED ++ && params->host_ls_low_power_phy_clk ++ == ++ DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ) ++ { ++ /* 6 MHZ */ ++ DWC_DEBUGPL(DBG_CIL, ++ "FS_PHY programming HCFG to 6 MHz (Low Power)\n"); ++ if (hcfg.b.fslspclksel != ++ DWC_HCFG_6_MHZ) { ++ hcfg.b.fslspclksel = ++ DWC_HCFG_6_MHZ; ++ DWC_WRITE_REG32 ++ (&host_if->host_global_regs->hcfg, ++ hcfg.d32); ++ do_reset = 1; ++ } ++ } else { ++ /* 48 MHZ */ ++ DWC_DEBUGPL(DBG_CIL, ++ "FS_PHY programming HCFG to 48 MHz ()\n"); ++ if (hcfg.b.fslspclksel != ++ DWC_HCFG_48_MHZ) { ++ hcfg.b.fslspclksel = ++ DWC_HCFG_48_MHZ; ++ DWC_WRITE_REG32 ++ (&host_if->host_global_regs->hcfg, ++ hcfg.d32); ++ do_reset = 1; ++ } ++ } ++ } else { ++ /* ++ * Not low power ++ */ ++ if (usbcfg.b.phylpwrclksel == 1) { ++ usbcfg.b.phylpwrclksel = 0; ++ DWC_WRITE_REG32 ++ (&global_regs->gusbcfg, ++ usbcfg.d32); ++ do_reset = 1; ++ } ++ } ++ ++ if (do_reset) { ++ DWC_TASK_SCHEDULE(dwc_otg_hcd->reset_tasklet); ++ } ++ } ++ ++ if (!do_reset) { ++ /* Port has been enabled set the reset change flag */ ++ dwc_otg_hcd->flags.b.port_reset_change = 1; ++ } ++ } else { ++ dwc_otg_hcd->flags.b.port_enable_change = 1; ++ } ++ retval |= 1; ++ } ++ ++ /** Overcurrent Change Interrupt */ ++ if (hprt0.b.prtovrcurrchng) { ++ DWC_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " ++ "Port Overcurrent Changed--\n", hprt0.d32); ++ dwc_otg_hcd->flags.b.port_over_current_change = 1; ++ hprt0_modify.b.prtovrcurrchng = 1; ++ retval |= 1; ++ } ++ ++ /* Clear Port Interrupts */ ++ DWC_WRITE_REG32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0_modify.d32); ++ ++ return retval; ++} ++ ++/** This interrupt indicates that one or more host channels has a pending ++ * interrupt. There are multiple conditions that can cause each host channel ++ * interrupt. This function determines which conditions have occurred for each ++ * host channel interrupt and handles them appropriately. */ ++int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd) ++{ ++ int i; ++ int retval = 0; ++ haint_data_t haint; ++ ++ /* Clear appropriate bits in HCINTn to clear the interrupt bit in ++ * GINTSTS */ ++ ++ haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if); ++ ++ // Overwrite with saved interrupts from fiq handler ++ if(fiq_split_enable) ++ { ++ local_fiq_disable(); ++ haint.d32 = haint_saved.d32; ++ haint_saved.d32 = 0; ++ local_fiq_enable(); ++ } ++ ++ for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) { ++ if (haint.b2.chint & (1 << i)) { ++ retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i); ++ } ++ } ++ ++ return retval; ++} ++ ++/** ++ * Gets the actual length of a transfer after the transfer halts. _halt_status ++ * holds the reason for the halt. ++ * ++ * For IN transfers where halt_status is DWC_OTG_HC_XFER_COMPLETE, ++ * *short_read is set to 1 upon return if less than the requested ++ * number of bytes were transferred. Otherwise, *short_read is set to 0 upon ++ * return. short_read may also be NULL on entry, in which case it remains ++ * unchanged. ++ */ ++static uint32_t get_actual_xfer_length(dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd, ++ dwc_otg_halt_status_e halt_status, ++ int *short_read) ++{ ++ hctsiz_data_t hctsiz; ++ uint32_t length; ++ ++ if (short_read != NULL) { ++ *short_read = 0; ++ } ++ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz); ++ ++ if (halt_status == DWC_OTG_HC_XFER_COMPLETE) { ++ if (hc->ep_is_in) { ++ length = hc->xfer_len - hctsiz.b.xfersize; ++ if (short_read != NULL) { ++ *short_read = (hctsiz.b.xfersize != 0); ++ } ++ } else if (hc->qh->do_split) { ++ if(fiq_split_enable) ++ length = split_out_xfersize[hc->hc_num]; ++ else ++ length = qtd->ssplit_out_xfer_count; ++ } else { ++ length = hc->xfer_len; ++ } ++ } else { ++ /* ++ * Must use the hctsiz.pktcnt field to determine how much data ++ * has been transferred. This field reflects the number of ++ * packets that have been transferred via the USB. This is ++ * always an integral number of packets if the transfer was ++ * halted before its normal completion. (Can't use the ++ * hctsiz.xfersize field because that reflects the number of ++ * bytes transferred via the AHB, not the USB). ++ */ ++ length = ++ (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet; ++ } ++ ++ return length; ++} ++ ++/** ++ * Updates the state of the URB after a Transfer Complete interrupt on the ++ * host channel. Updates the actual_length field of the URB based on the ++ * number of bytes transferred via the host channel. Sets the URB status ++ * if the data transfer is finished. ++ * ++ * @return 1 if the data transfer specified by the URB is completely finished, ++ * 0 otherwise. ++ */ ++static int update_urb_state_xfer_comp(dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_hcd_urb_t * urb, ++ dwc_otg_qtd_t * qtd) ++{ ++ int xfer_done = 0; ++ int short_read = 0; ++ ++ int xfer_length; ++ ++ xfer_length = get_actual_xfer_length(hc, hc_regs, qtd, ++ DWC_OTG_HC_XFER_COMPLETE, ++ &short_read); ++ ++ /* non DWORD-aligned buffer case handling. */ ++ if (hc->align_buff && xfer_length && hc->ep_is_in) { ++ dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, ++ xfer_length); ++ } ++ ++ urb->actual_length += xfer_length; ++ ++ if (xfer_length && (hc->ep_type == DWC_OTG_EP_TYPE_BULK) && ++ (urb->flags & URB_SEND_ZERO_PACKET) ++ && (urb->actual_length == urb->length) ++ && !(urb->length % hc->max_packet)) { ++ xfer_done = 0; ++ } else if (short_read || urb->actual_length >= urb->length) { ++ xfer_done = 1; ++ urb->status = 0; ++ } ++ ++#ifdef DEBUG ++ { ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz); ++ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n", ++ __func__, (hc->ep_is_in ? "IN" : "OUT"), ++ hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", hc->xfer_len); ++ DWC_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n", ++ hctsiz.b.xfersize); ++ DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", ++ urb->length); ++ DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", ++ urb->actual_length); ++ DWC_DEBUGPL(DBG_HCDV, " short_read %d, xfer_done %d\n", ++ short_read, xfer_done); ++ } ++#endif ++ ++ return xfer_done; ++} ++ ++/* ++ * Save the starting data toggle for the next transfer. The data toggle is ++ * saved in the QH for non-control transfers and it's saved in the QTD for ++ * control transfers. ++ */ ++void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, dwc_otg_qtd_t * qtd) ++{ ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz); ++ ++ if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) { ++ dwc_otg_qh_t *qh = hc->qh; ++ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) { ++ qh->data_toggle = DWC_OTG_HC_PID_DATA0; ++ } else { ++ qh->data_toggle = DWC_OTG_HC_PID_DATA1; ++ } ++ } else { ++ if (hctsiz.b.pid == DWC_HCTSIZ_DATA0) { ++ qtd->data_toggle = DWC_OTG_HC_PID_DATA0; ++ } else { ++ qtd->data_toggle = DWC_OTG_HC_PID_DATA1; ++ } ++ } ++} ++ ++/** ++ * Updates the state of an Isochronous URB when the transfer is stopped for ++ * any reason. The fields of the current entry in the frame descriptor array ++ * are set based on the transfer state and the input _halt_status. Completes ++ * the Isochronous URB if all the URB frames have been completed. ++ * ++ * @return DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be ++ * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE. ++ */ ++static dwc_otg_halt_status_e ++update_isoc_urb_state(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status) ++{ ++ dwc_otg_hcd_urb_t *urb = qtd->urb; ++ dwc_otg_halt_status_e ret_val = halt_status; ++ struct dwc_otg_hcd_iso_packet_desc *frame_desc; ++ ++ frame_desc = &urb->iso_descs[qtd->isoc_frame_index]; ++ switch (halt_status) { ++ case DWC_OTG_HC_XFER_COMPLETE: ++ frame_desc->status = 0; ++ frame_desc->actual_length = ++ get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL); ++ ++ /* non DWORD-aligned buffer case handling. */ ++ if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) { ++ dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset, ++ hc->qh->dw_align_buf, frame_desc->actual_length); ++ } ++ ++ break; ++ case DWC_OTG_HC_XFER_FRAME_OVERRUN: ++ urb->error_count++; ++ if (hc->ep_is_in) { ++ frame_desc->status = -DWC_E_NO_STREAM_RES; ++ } else { ++ frame_desc->status = -DWC_E_COMMUNICATION; ++ } ++ frame_desc->actual_length = 0; ++ break; ++ case DWC_OTG_HC_XFER_BABBLE_ERR: ++ urb->error_count++; ++ frame_desc->status = -DWC_E_OVERFLOW; ++ /* Don't need to update actual_length in this case. */ ++ break; ++ case DWC_OTG_HC_XFER_XACT_ERR: ++ urb->error_count++; ++ frame_desc->status = -DWC_E_PROTOCOL; ++ frame_desc->actual_length = ++ get_actual_xfer_length(hc, hc_regs, qtd, halt_status, NULL); ++ ++ /* non DWORD-aligned buffer case handling. */ ++ if (hc->align_buff && frame_desc->actual_length && hc->ep_is_in) { ++ dwc_memcpy(urb->buf + frame_desc->offset + qtd->isoc_split_offset, ++ hc->qh->dw_align_buf, frame_desc->actual_length); ++ } ++ /* Skip whole frame */ ++ if (hc->qh->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && ++ hc->ep_is_in && hcd->core_if->dma_enable) { ++ qtd->complete_split = 0; ++ qtd->isoc_split_offset = 0; ++ } ++ ++ break; ++ default: ++ DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status); ++ break; ++ } ++ if (++qtd->isoc_frame_index == urb->packet_count) { ++ /* ++ * urb->status is not used for isoc transfers. ++ * The individual frame_desc statuses are used instead. ++ */ ++ hcd->fops->complete(hcd, urb->priv, urb, 0); ++ ret_val = DWC_OTG_HC_XFER_URB_COMPLETE; ++ } else { ++ ret_val = DWC_OTG_HC_XFER_COMPLETE; ++ } ++ return ret_val; ++} ++ ++/** ++ * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic ++ * QHs, removes the QH from the active non-periodic schedule. If any QTDs are ++ * still linked to the QH, the QH is added to the end of the inactive ++ * non-periodic schedule. For periodic QHs, removes the QH from the periodic ++ * schedule if no more QTDs are linked to the QH. ++ */ ++static void deactivate_qh(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, int free_qtd) ++{ ++ int continue_split = 0; ++ dwc_otg_qtd_t *qtd; ++ ++ DWC_DEBUGPL(DBG_HCDV, " %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd); ++ ++ qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list); ++ ++ if (qtd->complete_split) { ++ continue_split = 1; ++ } else if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID || ++ qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END) { ++ continue_split = 1; ++ } ++ ++ if (free_qtd) { ++ dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh); ++ continue_split = 0; ++ } ++ ++ qh->channel = NULL; ++ dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split); ++} ++ ++/** ++ * Releases a host channel for use by other transfers. Attempts to select and ++ * queue more transactions since at least one host channel is available. ++ * ++ * @param hcd The HCD state structure. ++ * @param hc The host channel to release. ++ * @param qtd The QTD associated with the host channel. This QTD may be freed ++ * if the transfer is complete or an error has occurred. ++ * @param halt_status Reason the channel is being released. This status ++ * determines the actions taken by this function. ++ */ ++static void release_channel(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_qtd_t * qtd, ++ dwc_otg_halt_status_e halt_status) ++{ ++ dwc_otg_transaction_type_e tr_type; ++ int free_qtd; ++ dwc_irqflags_t flags; ++ dwc_spinlock_t *channel_lock = hcd->channel_lock; ++#ifdef FIQ_DEBUG ++ int endp = qtd->urb ? qtd->urb->pipe_info.ep_num : 0; ++#endif ++ int hog_port = 0; ++ ++ DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n", ++ __func__, hc->hc_num, halt_status, hc->xfer_len); ++ ++ if(fiq_split_enable && hc->do_split) { ++ if(!hc->ep_is_in && hc->ep_type == UE_ISOCHRONOUS) { ++ if(hc->xact_pos == DWC_HCSPLIT_XACTPOS_MID || ++ hc->xact_pos == DWC_HCSPLIT_XACTPOS_BEGIN) { ++ hog_port = 1; ++ } ++ } ++ } ++ ++ switch (halt_status) { ++ case DWC_OTG_HC_XFER_URB_COMPLETE: ++ free_qtd = 1; ++ break; ++ case DWC_OTG_HC_XFER_AHB_ERR: ++ case DWC_OTG_HC_XFER_STALL: ++ case DWC_OTG_HC_XFER_BABBLE_ERR: ++ free_qtd = 1; ++ break; ++ case DWC_OTG_HC_XFER_XACT_ERR: ++ if (qtd->error_count >= 3) { ++ DWC_DEBUGPL(DBG_HCDV, ++ " Complete URB with transaction error\n"); ++ free_qtd = 1; ++ qtd->urb->status = -DWC_E_PROTOCOL; ++ hcd->fops->complete(hcd, qtd->urb->priv, ++ qtd->urb, -DWC_E_PROTOCOL); ++ } else { ++ free_qtd = 0; ++ } ++ break; ++ case DWC_OTG_HC_XFER_URB_DEQUEUE: ++ /* ++ * The QTD has already been removed and the QH has been ++ * deactivated. Don't want to do anything except release the ++ * host channel and try to queue more transfers. ++ */ ++ goto cleanup; ++ case DWC_OTG_HC_XFER_NO_HALT_STATUS: ++ free_qtd = 0; ++ break; ++ case DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE: ++ DWC_DEBUGPL(DBG_HCDV, ++ " Complete URB with I/O error\n"); ++ free_qtd = 1; ++ qtd->urb->status = -DWC_E_IO; ++ hcd->fops->complete(hcd, qtd->urb->priv, ++ qtd->urb, -DWC_E_IO); ++ break; ++ default: ++ free_qtd = 0; ++ break; ++ } ++ ++ deactivate_qh(hcd, hc->qh, free_qtd); ++ ++cleanup: ++ /* ++ * Release the host channel for use by other transfers. The cleanup ++ * function clears the channel interrupt enables and conditions, so ++ * there's no need to clear the Channel Halted interrupt separately. ++ */ ++ dwc_otg_hc_cleanup(hcd->core_if, hc); ++ DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry); ++ ++ if (!microframe_schedule) { ++ switch (hc->ep_type) { ++ case DWC_OTG_EP_TYPE_CONTROL: ++ case DWC_OTG_EP_TYPE_BULK: ++ hcd->non_periodic_channels--; ++ break; ++ ++ default: ++ /* ++ * Don't release reservations for periodic channels here. ++ * That's done when a periodic transfer is descheduled (i.e. ++ * when the QH is removed from the periodic schedule). ++ */ ++ break; ++ } ++ } else { ++ ++ DWC_SPINLOCK_IRQSAVE(channel_lock, &flags); ++ hcd->available_host_channels++; ++ fiq_print(FIQDBG_PORTHUB, "AHC = %d ", hcd->available_host_channels); ++ DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags); ++ } ++ ++ if(fiq_split_enable && hc->do_split) ++ { ++ if(!(hcd->hub_port[hc->hub_addr] & (1 << hc->port_addr))) ++ { ++ fiq_print(FIQDBG_ERR, "PRTNOTAL"); ++ //BUG(); ++ } ++ if(!hog_port && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC || ++ hc->ep_type == DWC_OTG_EP_TYPE_INTR)) { ++ hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr); ++#ifdef FIQ_DEBUG ++ hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1; ++#endif ++ fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp); ++ } ++ } ++ ++ /* Try to queue more transfers now that there's a free channel. */ ++ tr_type = dwc_otg_hcd_select_transactions(hcd); ++ if (tr_type != DWC_OTG_TRANSACTION_NONE) { ++ dwc_otg_hcd_queue_transactions(hcd, tr_type); ++ } ++} ++ ++/** ++ * Halts a host channel. If the channel cannot be halted immediately because ++ * the request queue is full, this function ensures that the FIFO empty ++ * interrupt for the appropriate queue is enabled so that the halt request can ++ * be queued when there is space in the request queue. ++ * ++ * This function may also be called in DMA mode. In that case, the channel is ++ * simply released since the core always halts the channel automatically in ++ * DMA mode. ++ */ ++static void halt_channel(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_qtd_t * qtd, dwc_otg_halt_status_e halt_status) ++{ ++ if (hcd->core_if->dma_enable) { ++ release_channel(hcd, hc, qtd, halt_status); ++ return; ++ } ++ ++ /* Slave mode processing... */ ++ dwc_otg_hc_halt(hcd->core_if, hc, halt_status); ++ ++ if (hc->halt_on_queue) { ++ gintmsk_data_t gintmsk = {.d32 = 0 }; ++ dwc_otg_core_global_regs_t *global_regs; ++ global_regs = hcd->core_if->core_global_regs; ++ ++ if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || ++ hc->ep_type == DWC_OTG_EP_TYPE_BULK) { ++ /* ++ * Make sure the Non-periodic Tx FIFO empty interrupt ++ * is enabled so that the non-periodic schedule will ++ * be processed. ++ */ ++ gintmsk.b.nptxfempty = 1; ++ DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32); ++ } else { ++ /* ++ * Move the QH from the periodic queued schedule to ++ * the periodic assigned schedule. This allows the ++ * halt to be queued when the periodic schedule is ++ * processed. ++ */ ++ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned, ++ &hc->qh->qh_list_entry); ++ ++ /* ++ * Make sure the Periodic Tx FIFO Empty interrupt is ++ * enabled so that the periodic schedule will be ++ * processed. ++ */ ++ gintmsk.b.ptxfempty = 1; ++ DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmsk.d32); ++ } ++ } ++} ++ ++/** ++ * Performs common cleanup for non-periodic transfers after a Transfer ++ * Complete interrupt. This function should be called after any endpoint type ++ * specific handling is finished to release the host channel. ++ */ ++static void complete_non_periodic_xfer(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd, ++ dwc_otg_halt_status_e halt_status) ++{ ++ hcint_data_t hcint; ++ ++ qtd->error_count = 0; ++ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ if (hcint.b.nyet) { ++ /* ++ * Got a NYET on the last transaction of the transfer. This ++ * means that the endpoint should be in the PING state at the ++ * beginning of the next transfer. ++ */ ++ hc->qh->ping_state = 1; ++ clear_hc_int(hc_regs, nyet); ++ } ++ ++ /* ++ * Always halt and release the host channel to make it available for ++ * more transfers. There may still be more phases for a control ++ * transfer or more data packets for a bulk transfer at this point, ++ * but the host channel is still halted. A channel will be reassigned ++ * to the transfer when the non-periodic schedule is processed after ++ * the channel is released. This allows transactions to be queued ++ * properly via dwc_otg_hcd_queue_transactions, which also enables the ++ * Tx FIFO Empty interrupt if necessary. ++ */ ++ if (hc->ep_is_in) { ++ /* ++ * IN transfers in Slave mode require an explicit disable to ++ * halt the channel. (In DMA mode, this call simply releases ++ * the channel.) ++ */ ++ halt_channel(hcd, hc, qtd, halt_status); ++ } else { ++ /* ++ * The channel is automatically disabled by the core for OUT ++ * transfers in Slave mode. ++ */ ++ release_channel(hcd, hc, qtd, halt_status); ++ } ++} ++ ++/** ++ * Performs common cleanup for periodic transfers after a Transfer Complete ++ * interrupt. This function should be called after any endpoint type specific ++ * handling is finished to release the host channel. ++ */ ++static void complete_periodic_xfer(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd, ++ dwc_otg_halt_status_e halt_status) ++{ ++ hctsiz_data_t hctsiz; ++ qtd->error_count = 0; ++ ++ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz); ++ if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) { ++ /* Core halts channel in these cases. */ ++ release_channel(hcd, hc, qtd, halt_status); ++ } else { ++ /* Flush any outstanding requests from the Tx queue. */ ++ halt_channel(hcd, hc, qtd, halt_status); ++ } ++} ++ ++static int32_t handle_xfercomp_isoc_split_in(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ uint32_t len; ++ struct dwc_otg_hcd_iso_packet_desc *frame_desc; ++ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; ++ ++ len = get_actual_xfer_length(hc, hc_regs, qtd, ++ DWC_OTG_HC_XFER_COMPLETE, NULL); ++ ++ if (!len) { ++ qtd->complete_split = 0; ++ qtd->isoc_split_offset = 0; ++ return 0; ++ } ++ frame_desc->actual_length += len; ++ ++ if (hc->align_buff && len) ++ dwc_memcpy(qtd->urb->buf + frame_desc->offset + ++ qtd->isoc_split_offset, hc->qh->dw_align_buf, len); ++ qtd->isoc_split_offset += len; ++ ++ if (frame_desc->length == frame_desc->actual_length) { ++ frame_desc->status = 0; ++ qtd->isoc_frame_index++; ++ qtd->complete_split = 0; ++ qtd->isoc_split_offset = 0; ++ } ++ ++ if (qtd->isoc_frame_index == qtd->urb->packet_count) { ++ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); ++ } else { ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); ++ } ++ ++ return 1; /* Indicates that channel released */ ++} ++ ++/** ++ * Handles a host channel Transfer Complete interrupt. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ int urb_xfer_done; ++ dwc_otg_halt_status_e halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ dwc_otg_hcd_urb_t *urb = qtd->urb; ++ int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info); ++ ++ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " ++ "Transfer Complete--\n", hc->hc_num); ++ ++ if (hcd->core_if->dma_desc_enable) { ++ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, halt_status); ++ if (pipe_type == UE_ISOCHRONOUS) { ++ /* Do not disable the interrupt, just clear it */ ++ clear_hc_int(hc_regs, xfercomp); ++ return 1; ++ } ++ goto handle_xfercomp_done; ++ } ++ ++ /* ++ * Handle xfer complete on CSPLIT. ++ */ ++ ++ if (hc->qh->do_split) { ++ if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in ++ && hcd->core_if->dma_enable) { ++ if (qtd->complete_split ++ && handle_xfercomp_isoc_split_in(hcd, hc, hc_regs, ++ qtd)) ++ goto handle_xfercomp_done; ++ } else { ++ qtd->complete_split = 0; ++ } ++ } ++ ++ /* Update the QTD and URB states. */ ++ switch (pipe_type) { ++ case UE_CONTROL: ++ switch (qtd->control_phase) { ++ case DWC_OTG_CONTROL_SETUP: ++ if (urb->length > 0) { ++ qtd->control_phase = DWC_OTG_CONTROL_DATA; ++ } else { ++ qtd->control_phase = DWC_OTG_CONTROL_STATUS; ++ } ++ DWC_DEBUGPL(DBG_HCDV, ++ " Control setup transaction done\n"); ++ halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ break; ++ case DWC_OTG_CONTROL_DATA:{ ++ urb_xfer_done = ++ update_urb_state_xfer_comp(hc, hc_regs, urb, ++ qtd); ++ if (urb_xfer_done) { ++ qtd->control_phase = ++ DWC_OTG_CONTROL_STATUS; ++ DWC_DEBUGPL(DBG_HCDV, ++ " Control data transfer done\n"); ++ } else { ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ } ++ halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ break; ++ } ++ case DWC_OTG_CONTROL_STATUS: ++ DWC_DEBUGPL(DBG_HCDV, " Control transfer complete\n"); ++ if (urb->status == -DWC_E_IN_PROGRESS) { ++ urb->status = 0; ++ } ++ hcd->fops->complete(hcd, urb->priv, urb, urb->status); ++ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE; ++ break; ++ } ++ ++ complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status); ++ break; ++ case UE_BULK: ++ DWC_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n"); ++ urb_xfer_done = ++ update_urb_state_xfer_comp(hc, hc_regs, urb, qtd); ++ if (urb_xfer_done) { ++ hcd->fops->complete(hcd, urb->priv, urb, urb->status); ++ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE; ++ } else { ++ halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ } ++ ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ complete_non_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status); ++ break; ++ case UE_INTERRUPT: ++ DWC_DEBUGPL(DBG_HCDV, " Interrupt transfer complete\n"); ++ urb_xfer_done = ++ update_urb_state_xfer_comp(hc, hc_regs, urb, qtd); ++ ++ /* ++ * Interrupt URB is done on the first transfer complete ++ * interrupt. ++ */ ++ if (urb_xfer_done) { ++ hcd->fops->complete(hcd, urb->priv, urb, urb->status); ++ halt_status = DWC_OTG_HC_XFER_URB_COMPLETE; ++ } else { ++ halt_status = DWC_OTG_HC_XFER_COMPLETE; ++ } ++ ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status); ++ break; ++ case UE_ISOCHRONOUS: ++ DWC_DEBUGPL(DBG_HCDV, " Isochronous transfer complete\n"); ++ if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) { ++ halt_status = ++ update_isoc_urb_state(hcd, hc, hc_regs, qtd, ++ DWC_OTG_HC_XFER_COMPLETE); ++ } ++ complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status); ++ break; ++ } ++ ++handle_xfercomp_done: ++ disable_hc_int(hc_regs, xfercompl); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel STALL interrupt. This handler may be called in ++ * either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ dwc_otg_hcd_urb_t *urb = qtd->urb; ++ int pipe_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info); ++ ++ DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " ++ "STALL Received--\n", hc->hc_num); ++ ++ if (hcd->core_if->dma_desc_enable) { ++ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, DWC_OTG_HC_XFER_STALL); ++ goto handle_stall_done; ++ } ++ ++ if (pipe_type == UE_CONTROL) { ++ hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE); ++ } ++ ++ if (pipe_type == UE_BULK || pipe_type == UE_INTERRUPT) { ++ hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE); ++ /* ++ * USB protocol requires resetting the data toggle for bulk ++ * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT) ++ * setup command is issued to the endpoint. Anticipate the ++ * CLEAR_FEATURE command since a STALL has occurred and reset ++ * the data toggle now. ++ */ ++ hc->qh->data_toggle = 0; ++ } ++ ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL); ++ ++handle_stall_done: ++ disable_hc_int(hc_regs, stall); ++ ++ return 1; ++} ++ ++/* ++ * Updates the state of the URB when a transfer has been stopped due to an ++ * abnormal condition before the transfer completes. Modifies the ++ * actual_length field of the URB to reflect the number of bytes that have ++ * actually been transferred via the host channel. ++ */ ++static void update_urb_state_xfer_intr(dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_hcd_urb_t * urb, ++ dwc_otg_qtd_t * qtd, ++ dwc_otg_halt_status_e halt_status) ++{ ++ uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd, ++ halt_status, NULL); ++ /* non DWORD-aligned buffer case handling. */ ++ if (hc->align_buff && bytes_transferred && hc->ep_is_in) { ++ dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf, ++ bytes_transferred); ++ } ++ ++ urb->actual_length += bytes_transferred; ++ ++#ifdef DEBUG ++ { ++ hctsiz_data_t hctsiz; ++ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz); ++ DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n", ++ __func__, (hc->ep_is_in ? "IN" : "OUT"), ++ hc->hc_num); ++ DWC_DEBUGPL(DBG_HCDV, " hc->start_pkt_count %d\n", ++ hc->start_pkt_count); ++ DWC_DEBUGPL(DBG_HCDV, " hctsiz.pktcnt %d\n", hctsiz.b.pktcnt); ++ DWC_DEBUGPL(DBG_HCDV, " hc->max_packet %d\n", hc->max_packet); ++ DWC_DEBUGPL(DBG_HCDV, " bytes_transferred %d\n", ++ bytes_transferred); ++ DWC_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", ++ urb->actual_length); ++ DWC_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", ++ urb->length); ++ } ++#endif ++} ++ ++/** ++ * Handles a host channel NAK interrupt. This handler may be called in either ++ * DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " ++ "NAK Received--\n", hc->hc_num); ++ ++ /* ++ * When we get bulk NAKs then remember this so we holdoff on this qh until ++ * the beginning of the next frame ++ */ ++ switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { ++ case UE_BULK: ++ case UE_CONTROL: ++ if (nak_holdoff_enable) ++ hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd); ++ } ++ ++ /* ++ * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and ++ * interrupt. Re-start the SSPLIT transfer. ++ */ ++ if (hc->do_split) { ++ if (hc->complete_split) { ++ qtd->error_count = 0; ++ } ++ qtd->complete_split = 0; ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK); ++ goto handle_nak_done; ++ } ++ ++ switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { ++ case UE_CONTROL: ++ case UE_BULK: ++ if (hcd->core_if->dma_enable && hc->ep_is_in) { ++ /* ++ * NAK interrupts are enabled on bulk/control IN ++ * transfers in DMA mode for the sole purpose of ++ * resetting the error count after a transaction error ++ * occurs. The core will continue transferring data. ++ * Disable other interrupts unmasked for the same ++ * reason. ++ */ ++ disable_hc_int(hc_regs, datatglerr); ++ disable_hc_int(hc_regs, ack); ++ qtd->error_count = 0; ++ goto handle_nak_done; ++ } ++ ++ /* ++ * NAK interrupts normally occur during OUT transfers in DMA ++ * or Slave mode. For IN transfers, more requests will be ++ * queued as request queue space is available. ++ */ ++ qtd->error_count = 0; ++ ++ if (!hc->qh->ping_state) { ++ update_urb_state_xfer_intr(hc, hc_regs, ++ qtd->urb, qtd, ++ DWC_OTG_HC_XFER_NAK); ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ ++ if (hc->speed == DWC_OTG_EP_SPEED_HIGH) ++ hc->qh->ping_state = 1; ++ } ++ ++ /* ++ * Halt the channel so the transfer can be re-started from ++ * the appropriate point or the PING protocol will ++ * start/continue. ++ */ ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK); ++ break; ++ case UE_INTERRUPT: ++ qtd->error_count = 0; ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK); ++ break; ++ case UE_ISOCHRONOUS: ++ /* Should never get called for isochronous transfers. */ ++ DWC_ASSERT(1, "NACK interrupt for ISOC transfer\n"); ++ break; ++ } ++ ++handle_nak_done: ++ disable_hc_int(hc_regs, nak); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel ACK interrupt. This interrupt is enabled when ++ * performing the PING protocol in Slave mode, when errors occur during ++ * either Slave mode or DMA mode, and during Start Split transactions. ++ */ ++static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " ++ "ACK Received--\n", hc->hc_num); ++ ++ if (hc->do_split) { ++ /* ++ * Handle ACK on SSPLIT. ++ * ACK should not occur in CSPLIT. ++ */ ++ if (!hc->ep_is_in && hc->data_pid_start != DWC_OTG_HC_PID_SETUP) { ++ qtd->ssplit_out_xfer_count = hc->xfer_len; ++ } ++ if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) { ++ /* Don't need complete for isochronous out transfers. */ ++ qtd->complete_split = 1; ++ } ++ ++ /* ISOC OUT */ ++ if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) { ++ switch (hc->xact_pos) { ++ case DWC_HCSPLIT_XACTPOS_ALL: ++ break; ++ case DWC_HCSPLIT_XACTPOS_END: ++ qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL; ++ qtd->isoc_split_offset = 0; ++ break; ++ case DWC_HCSPLIT_XACTPOS_BEGIN: ++ case DWC_HCSPLIT_XACTPOS_MID: ++ /* ++ * For BEGIN or MID, calculate the length for ++ * the next microframe to determine the correct ++ * SSPLIT token, either MID or END. ++ */ ++ { ++ struct dwc_otg_hcd_iso_packet_desc ++ *frame_desc; ++ ++ frame_desc = ++ &qtd->urb-> ++ iso_descs[qtd->isoc_frame_index]; ++ qtd->isoc_split_offset += 188; ++ ++ if ((frame_desc->length - ++ qtd->isoc_split_offset) <= 188) { ++ qtd->isoc_split_pos = ++ DWC_HCSPLIT_XACTPOS_END; ++ } else { ++ qtd->isoc_split_pos = ++ DWC_HCSPLIT_XACTPOS_MID; ++ } ++ ++ } ++ break; ++ } ++ } else { ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK); ++ } ++ } else { ++ /* ++ * An unmasked ACK on a non-split DMA transaction is ++ * for the sole purpose of resetting error counts. Disable other ++ * interrupts unmasked for the same reason. ++ */ ++ if(hcd->core_if->dma_enable) { ++ disable_hc_int(hc_regs, datatglerr); ++ disable_hc_int(hc_regs, nak); ++ } ++ qtd->error_count = 0; ++ ++ if (hc->qh->ping_state) { ++ hc->qh->ping_state = 0; ++ /* ++ * Halt the channel so the transfer can be re-started ++ * from the appropriate point. This only happens in ++ * Slave mode. In DMA mode, the ping_state is cleared ++ * when the transfer is started because the core ++ * automatically executes the PING, then the transfer. ++ */ ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK); ++ } ++ } ++ ++ /* ++ * If the ACK occurred when _not_ in the PING state, let the channel ++ * continue transferring data after clearing the error count. ++ */ ++ ++ disable_hc_int(hc_regs, ack); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel NYET interrupt. This interrupt should only occur on ++ * Bulk and Control OUT endpoints and for complete split transactions. If a ++ * NYET occurs at the same time as a Transfer Complete interrupt, it is ++ * handled in the xfercomp interrupt handler, not here. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " ++ "NYET Received--\n", hc->hc_num); ++ ++ /* ++ * NYET on CSPLIT ++ * re-do the CSPLIT immediately on non-periodic ++ */ ++ if (hc->do_split && hc->complete_split) { ++ if (hc->ep_is_in && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) ++ && hcd->core_if->dma_enable) { ++ qtd->complete_split = 0; ++ qtd->isoc_split_offset = 0; ++ if (++qtd->isoc_frame_index == qtd->urb->packet_count) { ++ hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0); ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE); ++ } ++ else ++ release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS); ++ goto handle_nyet_done; ++ } ++ ++ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ int frnum = dwc_otg_hcd_get_frame_number(hcd); ++ ++ // With the FIQ running we only ever see the failed NYET ++ if (dwc_full_frame_num(frnum) != ++ dwc_full_frame_num(hc->qh->sched_frame) || ++ fiq_split_enable) { ++ /* ++ * No longer in the same full speed frame. ++ * Treat this as a transaction error. ++ */ ++#if 0 ++ /** @todo Fix system performance so this can ++ * be treated as an error. Right now complete ++ * splits cannot be scheduled precisely enough ++ * due to other system activity, so this error ++ * occurs regularly in Slave mode. ++ */ ++ qtd->error_count++; ++#endif ++ qtd->complete_split = 0; ++ halt_channel(hcd, hc, qtd, ++ DWC_OTG_HC_XFER_XACT_ERR); ++ /** @todo add support for isoc release */ ++ goto handle_nyet_done; ++ } ++ } ++ ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET); ++ goto handle_nyet_done; ++ } ++ ++ hc->qh->ping_state = 1; ++ qtd->error_count = 0; ++ ++ update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd, ++ DWC_OTG_HC_XFER_NYET); ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ ++ /* ++ * Halt the channel and re-start the transfer so the PING ++ * protocol will start. ++ */ ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET); ++ ++handle_nyet_done: ++ disable_hc_int(hc_regs, nyet); ++ return 1; ++} ++ ++/** ++ * Handles a host channel babble interrupt. This handler may be called in ++ * either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_babble_intr(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " ++ "Babble Error--\n", hc->hc_num); ++ ++ if (hcd->core_if->dma_desc_enable) { ++ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, ++ DWC_OTG_HC_XFER_BABBLE_ERR); ++ goto handle_babble_done; ++ } ++ ++ if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) { ++ hcd->fops->complete(hcd, qtd->urb->priv, ++ qtd->urb, -DWC_E_OVERFLOW); ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR); ++ } else { ++ dwc_otg_halt_status_e halt_status; ++ halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd, ++ DWC_OTG_HC_XFER_BABBLE_ERR); ++ halt_channel(hcd, hc, qtd, halt_status); ++ } ++ ++handle_babble_done: ++ disable_hc_int(hc_regs, bblerr); ++ return 1; ++} ++ ++/** ++ * Handles a host channel AHB error interrupt. This handler is only called in ++ * DMA mode. ++ */ ++static int32_t handle_hc_ahberr_intr(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ hcchar_data_t hcchar; ++ hcsplt_data_t hcsplt; ++ hctsiz_data_t hctsiz; ++ uint32_t hcdma; ++ char *pipetype, *speed; ++ ++ dwc_otg_hcd_urb_t *urb = qtd->urb; ++ ++ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " ++ "AHB Error--\n", hc->hc_num); ++ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt); ++ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz); ++ hcdma = DWC_READ_REG32(&hc_regs->hcdma); ++ ++ DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num); ++ DWC_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); ++ DWC_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n"); ++ DWC_ERROR(" Device address: %d\n", ++ dwc_otg_hcd_get_dev_addr(&urb->pipe_info)); ++ DWC_ERROR(" Endpoint: %d, %s\n", ++ dwc_otg_hcd_get_ep_num(&urb->pipe_info), ++ (dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT")); ++ ++ switch (dwc_otg_hcd_get_pipe_type(&urb->pipe_info)) { ++ case UE_CONTROL: ++ pipetype = "CONTROL"; ++ break; ++ case UE_BULK: ++ pipetype = "BULK"; ++ break; ++ case UE_INTERRUPT: ++ pipetype = "INTERRUPT"; ++ break; ++ case UE_ISOCHRONOUS: ++ pipetype = "ISOCHRONOUS"; ++ break; ++ default: ++ pipetype = "UNKNOWN"; ++ break; ++ } ++ ++ DWC_ERROR(" Endpoint type: %s\n", pipetype); ++ ++ switch (hc->speed) { ++ case DWC_OTG_EP_SPEED_HIGH: ++ speed = "HIGH"; ++ break; ++ case DWC_OTG_EP_SPEED_FULL: ++ speed = "FULL"; ++ break; ++ case DWC_OTG_EP_SPEED_LOW: ++ speed = "LOW"; ++ break; ++ default: ++ speed = "UNKNOWN"; ++ break; ++ }; ++ ++ DWC_ERROR(" Speed: %s\n", speed); ++ ++ DWC_ERROR(" Max packet size: %d\n", ++ dwc_otg_hcd_get_mps(&urb->pipe_info)); ++ DWC_ERROR(" Data buffer length: %d\n", urb->length); ++ DWC_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n", ++ urb->buf, (void *)urb->dma); ++ DWC_ERROR(" Setup buffer: %p, Setup DMA: %p\n", ++ urb->setup_packet, (void *)urb->setup_dma); ++ DWC_ERROR(" Interval: %d\n", urb->interval); ++ ++ /* Core haltes the channel for Descriptor DMA mode */ ++ if (hcd->core_if->dma_desc_enable) { ++ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, ++ DWC_OTG_HC_XFER_AHB_ERR); ++ goto handle_ahberr_done; ++ } ++ ++ hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_IO); ++ ++ /* ++ * Force a channel halt. Don't call halt_channel because that won't ++ * write to the HCCHARn register in DMA mode to force the halt. ++ */ ++ dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR); ++handle_ahberr_done: ++ disable_hc_int(hc_regs, ahberr); ++ return 1; ++} ++ ++/** ++ * Handles a host channel transaction error interrupt. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " ++ "Transaction Error--\n", hc->hc_num); ++ ++ if (hcd->core_if->dma_desc_enable) { ++ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, ++ DWC_OTG_HC_XFER_XACT_ERR); ++ goto handle_xacterr_done; ++ } ++ ++ switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { ++ case UE_CONTROL: ++ case UE_BULK: ++ qtd->error_count++; ++ if (!hc->qh->ping_state) { ++ ++ update_urb_state_xfer_intr(hc, hc_regs, ++ qtd->urb, qtd, ++ DWC_OTG_HC_XFER_XACT_ERR); ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ if (!hc->ep_is_in && hc->speed == DWC_OTG_EP_SPEED_HIGH) { ++ hc->qh->ping_state = 1; ++ } ++ } ++ ++ /* ++ * Halt the channel so the transfer can be re-started from ++ * the appropriate point or the PING protocol will start. ++ */ ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ break; ++ case UE_INTERRUPT: ++ qtd->error_count++; ++ if (hc->do_split && hc->complete_split) { ++ qtd->complete_split = 0; ++ } ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ break; ++ case UE_ISOCHRONOUS: ++ { ++ dwc_otg_halt_status_e halt_status; ++ halt_status = ++ update_isoc_urb_state(hcd, hc, hc_regs, qtd, ++ DWC_OTG_HC_XFER_XACT_ERR); ++ ++ halt_channel(hcd, hc, qtd, halt_status); ++ } ++ break; ++ } ++handle_xacterr_done: ++ disable_hc_int(hc_regs, xacterr); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel frame overrun interrupt. This handler may be called ++ * in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_frmovrun_intr(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " ++ "Frame Overrun--\n", hc->hc_num); ++ ++ switch (dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) { ++ case UE_CONTROL: ++ case UE_BULK: ++ break; ++ case UE_INTERRUPT: ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN); ++ break; ++ case UE_ISOCHRONOUS: ++ { ++ dwc_otg_halt_status_e halt_status; ++ halt_status = ++ update_isoc_urb_state(hcd, hc, hc_regs, qtd, ++ DWC_OTG_HC_XFER_FRAME_OVERRUN); ++ ++ halt_channel(hcd, hc, qtd, halt_status); ++ } ++ break; ++ } ++ ++ disable_hc_int(hc_regs, frmovrun); ++ ++ return 1; ++} ++ ++/** ++ * Handles a host channel data toggle error interrupt. This handler may be ++ * called in either DMA mode or Slave mode. ++ */ ++static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " ++ "Data Toggle Error on %s transfer--\n", ++ hc->hc_num, (hc->ep_is_in ? "IN" : "OUT")); ++ ++ /* Data toggles on split transactions cause the hc to halt. ++ * restart transfer */ ++ if(hc->qh->do_split) ++ { ++ qtd->error_count++; ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ update_urb_state_xfer_intr(hc, hc_regs, ++ qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ } else if (hc->ep_is_in) { ++ /* An unmasked data toggle error on a non-split DMA transaction is ++ * for the sole purpose of resetting error counts. Disable other ++ * interrupts unmasked for the same reason. ++ */ ++ if(hcd->core_if->dma_enable) { ++ disable_hc_int(hc_regs, ack); ++ disable_hc_int(hc_regs, nak); ++ } ++ qtd->error_count = 0; ++ } ++ ++ disable_hc_int(hc_regs, datatglerr); ++ ++ return 1; ++} ++ ++#ifdef DEBUG ++/** ++ * This function is for debug only. It checks that a valid halt status is set ++ * and that HCCHARn.chdis is clear. If there's a problem, corrective action is ++ * taken and a warning is issued. ++ * @return 1 if halt status is ok, 0 otherwise. ++ */ ++static inline int halt_status_ok(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd) ++{ ++ hcchar_data_t hcchar; ++ hctsiz_data_t hctsiz; ++ hcint_data_t hcint; ++ hcintmsk_data_t hcintmsk; ++ hcsplt_data_t hcsplt; ++ ++ if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) { ++ /* ++ * This code is here only as a check. This condition should ++ * never happen. Ignore the halt if it does occur. ++ */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ hctsiz.d32 = DWC_READ_REG32(&hc_regs->hctsiz); ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); ++ hcsplt.d32 = DWC_READ_REG32(&hc_regs->hcsplt); ++ DWC_WARN ++ ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, " ++ "channel %d, hcchar 0x%08x, hctsiz 0x%08x, " ++ "hcint 0x%08x, hcintmsk 0x%08x, " ++ "hcsplt 0x%08x, qtd->complete_split %d\n", __func__, ++ hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32, ++ hcintmsk.d32, hcsplt.d32, qtd->complete_split); ++ ++ DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n", ++ __func__, hc->hc_num); ++ DWC_WARN("\n"); ++ clear_hc_int(hc_regs, chhltd); ++ return 0; ++ } ++ ++ /* ++ * This code is here only as a check. hcchar.chdis should ++ * never be set when the halt interrupt occurs. Halt the ++ * channel again if it does occur. ++ */ ++ hcchar.d32 = DWC_READ_REG32(&hc_regs->hcchar); ++ if (hcchar.b.chdis) { ++ DWC_WARN("%s: hcchar.chdis set unexpectedly, " ++ "hcchar 0x%08x, trying to halt again\n", ++ __func__, hcchar.d32); ++ clear_hc_int(hc_regs, chhltd); ++ hc->halt_pending = 0; ++ halt_channel(hcd, hc, qtd, hc->halt_status); ++ return 0; ++ } ++ ++ return 1; ++} ++#endif ++ ++/** ++ * Handles a host Channel Halted interrupt in DMA mode. This handler ++ * determines the reason the channel halted and proceeds accordingly. ++ */ ++static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd, ++ hcint_data_t hcint, ++ hcintmsk_data_t hcintmsk) ++{ ++ int out_nak_enh = 0; ++ ++ /* For core with OUT NAK enhancement, the flow for high- ++ * speed CONTROL/BULK OUT is handled a little differently. ++ */ ++ if (hcd->core_if->snpsid >= OTG_CORE_REV_2_71a) { ++ if (hc->speed == DWC_OTG_EP_SPEED_HIGH && !hc->ep_is_in && ++ (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL || ++ hc->ep_type == DWC_OTG_EP_TYPE_BULK)) { ++ out_nak_enh = 1; ++ } ++ } ++ ++ if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE || ++ (hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR ++ && !hcd->core_if->dma_desc_enable)) { ++ /* ++ * Just release the channel. A dequeue can happen on a ++ * transfer timeout. In the case of an AHB Error, the channel ++ * was forced to halt because there's no way to gracefully ++ * recover. ++ */ ++ if (hcd->core_if->dma_desc_enable) ++ dwc_otg_hcd_complete_xfer_ddma(hcd, hc, hc_regs, ++ hc->halt_status); ++ else ++ release_channel(hcd, hc, qtd, hc->halt_status); ++ return; ++ } ++ ++ /* Read the HCINTn register to determine the cause for the halt. */ ++ if(!fiq_split_enable) ++ { ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); ++ } ++ ++ if (hcint.b.xfercomp) { ++ /** @todo This is here because of a possible hardware bug. Spec ++ * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT ++ * interrupt w/ACK bit set should occur, but I only see the ++ * XFERCOMP bit, even with it masked out. This is a workaround ++ * for that behavior. Should fix this when hardware is fixed. ++ */ ++ if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in) { ++ handle_hc_ack_intr(hcd, hc, hc_regs, qtd); ++ } ++ handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.stall) { ++ handle_hc_stall_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.xacterr && !hcd->core_if->dma_desc_enable) { ++ if (out_nak_enh) { ++ if (hcint.b.nyet || hcint.b.nak || hcint.b.ack) { ++ DWC_DEBUGPL(DBG_HCD, "XactErr with NYET/NAK/ACK\n"); ++ qtd->error_count = 0; ++ } else { ++ DWC_DEBUGPL(DBG_HCD, "XactErr without NYET/NAK/ACK\n"); ++ } ++ } ++ ++ /* ++ * Must handle xacterr before nak or ack. Could get a xacterr ++ * at the same time as either of these on a BULK/CONTROL OUT ++ * that started with a PING. The xacterr takes precedence. ++ */ ++ handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.xcs_xact && hcd->core_if->dma_desc_enable) { ++ handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.ahberr && hcd->core_if->dma_desc_enable) { ++ handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.bblerr) { ++ handle_hc_babble_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.frmovrun) { ++ handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.datatglerr) { ++ handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd); ++ } else if (!out_nak_enh) { ++ if (hcint.b.nyet) { ++ /* ++ * Must handle nyet before nak or ack. Could get a nyet at the ++ * same time as either of those on a BULK/CONTROL OUT that ++ * started with a PING. The nyet takes precedence. ++ */ ++ handle_hc_nyet_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.nak && !hcintmsk.b.nak) { ++ /* ++ * If nak is not masked, it's because a non-split IN transfer ++ * is in an error state. In that case, the nak is handled by ++ * the nak interrupt handler, not here. Handle nak here for ++ * BULK/CONTROL OUT transfers, which halt on a NAK to allow ++ * rewinding the buffer pointer. ++ */ ++ handle_hc_nak_intr(hcd, hc, hc_regs, qtd); ++ } else if (hcint.b.ack && !hcintmsk.b.ack) { ++ /* ++ * If ack is not masked, it's because a non-split IN transfer ++ * is in an error state. In that case, the ack is handled by ++ * the ack interrupt handler, not here. Handle ack here for ++ * split transfers. Start splits halt on ACK. ++ */ ++ handle_hc_ack_intr(hcd, hc, hc_regs, qtd); ++ } else { ++ if (hc->ep_type == DWC_OTG_EP_TYPE_INTR || ++ hc->ep_type == DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * A periodic transfer halted with no other channel ++ * interrupts set. Assume it was halted by the core ++ * because it could not be completed in its scheduled ++ * (micro)frame. ++ */ ++#ifdef DEBUG ++ DWC_PRINTF ++ ("%s: Halt channel %d (assume incomplete periodic transfer)\n", ++ __func__, hc->hc_num); ++#endif ++ halt_channel(hcd, hc, qtd, ++ DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE); ++ } else { ++ DWC_ERROR ++ ("%s: Channel %d, DMA Mode -- ChHltd set, but reason " ++ "for halting is unknown, hcint 0x%08x, intsts 0x%08x\n", ++ __func__, hc->hc_num, hcint.d32, ++ DWC_READ_REG32(&hcd-> ++ core_if->core_global_regs-> ++ gintsts)); ++ /* Failthrough: use 3-strikes rule */ ++ qtd->error_count++; ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ update_urb_state_xfer_intr(hc, hc_regs, ++ qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ } ++ ++ } ++ } else { ++ DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n", ++ hcint.d32); ++ /* Failthrough: use 3-strikes rule */ ++ qtd->error_count++; ++ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd); ++ update_urb_state_xfer_intr(hc, hc_regs, ++ qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR); ++ } ++} ++ ++/** ++ * Handles a host channel Channel Halted interrupt. ++ * ++ * In slave mode, this handler is called only when the driver specifically ++ * requests a halt. This occurs during handling other host channel interrupts ++ * (e.g. nak, xacterr, stall, nyet, etc.). ++ * ++ * In DMA mode, this is the interrupt that occurs when the core has finished ++ * processing a transfer on a channel. Other host channel interrupts (except ++ * ahberr) are disabled in DMA mode. ++ */ ++static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd, ++ dwc_hc_t * hc, ++ dwc_otg_hc_regs_t * hc_regs, ++ dwc_otg_qtd_t * qtd, ++ hcint_data_t hcint, ++ hcintmsk_data_t hcintmsk) ++{ ++ DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: " ++ "Channel Halted--\n", hc->hc_num); ++ ++ if (hcd->core_if->dma_enable) { ++ handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd, hcint, hcintmsk); ++ } else { ++#ifdef DEBUG ++ if (!halt_status_ok(hcd, hc, hc_regs, qtd)) { ++ return 1; ++ } ++#endif ++ release_channel(hcd, hc, qtd, hc->halt_status); ++ } ++ ++ return 1; ++} ++ ++/** Handles interrupt for a specific Host Channel */ ++int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num) ++{ ++ int retval = 0; ++ hcint_data_t hcint, hcint_orig; ++ hcintmsk_data_t hcintmsk; ++ dwc_hc_t *hc; ++ dwc_otg_hc_regs_t *hc_regs; ++ dwc_otg_qtd_t *qtd; ++ ++ DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", num); ++ ++ hc = dwc_otg_hcd->hc_ptr_array[num]; ++ hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num]; ++ if(hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) { ++ /* We are responding to a channel disable. Driver ++ * state is cleared - our qtd has gone away. ++ */ ++ release_channel(dwc_otg_hcd, hc, NULL, hc->halt_status); ++ return 1; ++ } ++ qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list); ++ ++ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint); ++ hcint_orig = hcint; ++ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk); ++ DWC_DEBUGPL(DBG_HCDV, ++ " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", ++ hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32)); ++ hcint.d32 = hcint.d32 & hcintmsk.d32; ++ ++ if(fiq_split_enable) ++ { ++ // replace with the saved interrupts from the fiq handler ++ local_fiq_disable(); ++ hcint_orig.d32 = hcint_saved[num].d32; ++ hcint.d32 = hcint_orig.d32 & hcintmsk_saved[num].d32; ++ hcint_saved[num].d32 = 0; ++ local_fiq_enable(); ++ } ++ ++ if (!dwc_otg_hcd->core_if->dma_enable) { ++ if (hcint.b.chhltd && hcint.d32 != 0x2) { ++ hcint.b.chhltd = 0; ++ } ++ } ++ ++ if (hcint.b.xfercomp) { ++ retval |= ++ handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ /* ++ * If NYET occurred at same time as Xfer Complete, the NYET is ++ * handled by the Xfer Complete interrupt handler. Don't want ++ * to call the NYET interrupt handler in this case. ++ */ ++ hcint.b.nyet = 0; ++ } ++ if (hcint.b.chhltd) { ++ retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd, hcint_orig, hcintmsk_saved[num]); ++ } ++ if (hcint.b.ahberr) { ++ retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ } ++ if (hcint.b.stall) { ++ retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ } ++ if (hcint.b.nak) { ++ retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ } ++ if (hcint.b.ack) { ++ if(!hcint.b.chhltd) ++ retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ } ++ if (hcint.b.nyet) { ++ retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ } ++ if (hcint.b.xacterr) { ++ retval |= handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ } ++ if (hcint.b.bblerr) { ++ retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ } ++ if (hcint.b.frmovrun) { ++ retval |= ++ handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ } ++ if (hcint.b.datatglerr) { ++ retval |= ++ handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd); ++ } ++ ++ return retval; ++} ++#endif /* DWC_DEVICE_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c 2014-03-13 12:46:39.520097997 +0100 +@@ -0,0 +1,972 @@ ++ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $ ++ * $Revision: #20 $ ++ * $Date: 2011/10/26 $ ++ * $Change: 1872981 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++ ++/** ++ * @file ++ * ++ * This file contains the implementation of the HCD. In Linux, the HCD ++ * implements the hc_driver API. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) ++#include <../drivers/usb/core/hcd.h> ++#else ++#include ++#endif ++ ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) ++#define USB_URB_EP_LINKING 1 ++#else ++#define USB_URB_EP_LINKING 0 ++#endif ++ ++#include "dwc_otg_hcd_if.h" ++#include "dwc_otg_dbg.h" ++#include "dwc_otg_driver.h" ++#include "dwc_otg_hcd.h" ++#include "dwc_otg_mphi_fix.h" ++ ++/** ++ * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is ++ * qualified with its direction (possible 32 endpoints per device). ++ */ ++#define dwc_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \ ++ ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4) ++ ++static const char dwc_otg_hcd_name[] = "dwc_otg_hcd"; ++ ++extern bool fiq_fix_enable; ++ ++/** @name Linux HC Driver API Functions */ ++/** @{ */ ++/* manage i/o requests, device state */ ++static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++ struct usb_host_endpoint *ep, ++#endif ++ struct urb *urb, gfp_t mem_flags); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb); ++#endif ++#else /* kernels at or post 2.6.30 */ ++static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, ++ struct urb *urb, int status); ++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) */ ++ ++static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) ++static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep); ++#endif ++static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd); ++extern int hcd_start(struct usb_hcd *hcd); ++extern void hcd_stop(struct usb_hcd *hcd); ++static int get_frame_number(struct usb_hcd *hcd); ++extern int hub_status_data(struct usb_hcd *hcd, char *buf); ++extern int hub_control(struct usb_hcd *hcd, ++ u16 typeReq, ++ u16 wValue, u16 wIndex, char *buf, u16 wLength); ++ ++struct wrapper_priv_data { ++ dwc_otg_hcd_t *dwc_otg_hcd; ++}; ++ ++/** @} */ ++ ++static struct hc_driver dwc_otg_hc_driver = { ++ ++ .description = dwc_otg_hcd_name, ++ .product_desc = "DWC OTG Controller", ++ .hcd_priv_size = sizeof(struct wrapper_priv_data), ++ ++ .irq = dwc_otg_hcd_irq, ++ ++ .flags = HCD_MEMORY | HCD_USB2, ++ ++ //.reset = ++ .start = hcd_start, ++ //.suspend = ++ //.resume = ++ .stop = hcd_stop, ++ ++ .urb_enqueue = dwc_otg_urb_enqueue, ++ .urb_dequeue = dwc_otg_urb_dequeue, ++ .endpoint_disable = endpoint_disable, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) ++ .endpoint_reset = endpoint_reset, ++#endif ++ .get_frame_number = get_frame_number, ++ ++ .hub_status_data = hub_status_data, ++ .hub_control = hub_control, ++ //.bus_suspend = ++ //.bus_resume = ++}; ++ ++/** Gets the dwc_otg_hcd from a struct usb_hcd */ ++static inline dwc_otg_hcd_t *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd) ++{ ++ struct wrapper_priv_data *p; ++ p = (struct wrapper_priv_data *)(hcd->hcd_priv); ++ return p->dwc_otg_hcd; ++} ++ ++/** Gets the struct usb_hcd that contains a dwc_otg_hcd_t. */ ++static inline struct usb_hcd *dwc_otg_hcd_to_hcd(dwc_otg_hcd_t * dwc_otg_hcd) ++{ ++ return dwc_otg_hcd_get_priv_data(dwc_otg_hcd); ++} ++ ++/** Gets the usb_host_endpoint associated with an URB. */ ++inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb) ++{ ++ struct usb_device *dev = urb->dev; ++ int ep_num = usb_pipeendpoint(urb->pipe); ++ ++ if (usb_pipein(urb->pipe)) ++ return dev->ep_in[ep_num]; ++ else ++ return dev->ep_out[ep_num]; ++} ++ ++static int _disconnect(dwc_otg_hcd_t * hcd) ++{ ++ struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd); ++ ++ usb_hcd->self.is_b_host = 0; ++ return 0; ++} ++ ++static int _start(dwc_otg_hcd_t * hcd) ++{ ++ struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd); ++ ++ usb_hcd->self.is_b_host = dwc_otg_hcd_is_b_host(hcd); ++ hcd_start(usb_hcd); ++ ++ return 0; ++} ++ ++static int _hub_info(dwc_otg_hcd_t * hcd, void *urb_handle, uint32_t * hub_addr, ++ uint32_t * port_addr) ++{ ++ struct urb *urb = (struct urb *)urb_handle; ++ struct usb_bus *bus; ++#if 1 //GRAYG - temporary ++ if (NULL == urb_handle) ++ DWC_ERROR("**** %s - NULL URB handle\n", __func__);//GRAYG ++ if (NULL == urb->dev) ++ DWC_ERROR("**** %s - URB has no device\n", __func__);//GRAYG ++ if (NULL == port_addr) ++ DWC_ERROR("**** %s - NULL port_address\n", __func__);//GRAYG ++#endif ++ if (urb->dev->tt) { ++ if (NULL == urb->dev->tt->hub) { ++ DWC_ERROR("**** %s - (URB's transactor has no TT - giving no hub)\n", ++ __func__); //GRAYG ++ //*hub_addr = (u8)usb_pipedevice(urb->pipe); //GRAYG ++ *hub_addr = 0; //GRAYG ++ // we probably shouldn't have a transaction translator if ++ // there's no associated hub? ++ } else { ++ bus = hcd_to_bus(dwc_otg_hcd_to_hcd(hcd)); ++ if (urb->dev->tt->hub == bus->root_hub) ++ *hub_addr = 0; ++ else ++ *hub_addr = urb->dev->tt->hub->devnum; ++ } ++ *port_addr = urb->dev->tt->multi ? urb->dev->ttport : 1; ++ } else { ++ *hub_addr = 0; ++ *port_addr = urb->dev->ttport; ++ } ++ return 0; ++} ++ ++static int _speed(dwc_otg_hcd_t * hcd, void *urb_handle) ++{ ++ struct urb *urb = (struct urb *)urb_handle; ++ return urb->dev->speed; ++} ++ ++static int _get_b_hnp_enable(dwc_otg_hcd_t * hcd) ++{ ++ struct usb_hcd *usb_hcd = dwc_otg_hcd_to_hcd(hcd); ++ return usb_hcd->self.b_hnp_enable; ++} ++ ++static void allocate_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw, ++ struct urb *urb) ++{ ++ hcd_to_bus(hcd)->bandwidth_allocated += bw / urb->interval; ++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { ++ hcd_to_bus(hcd)->bandwidth_isoc_reqs++; ++ } else { ++ hcd_to_bus(hcd)->bandwidth_int_reqs++; ++ } ++} ++ ++static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw, ++ struct urb *urb) ++{ ++ hcd_to_bus(hcd)->bandwidth_allocated -= bw / urb->interval; ++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { ++ hcd_to_bus(hcd)->bandwidth_isoc_reqs--; ++ } else { ++ hcd_to_bus(hcd)->bandwidth_int_reqs--; ++ } ++} ++ ++/** ++ * Sets the final status of an URB and returns it to the device driver. Any ++ * required cleanup of the URB is performed. The HCD lock should be held on ++ * entry. ++ */ ++static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle, ++ dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status) ++{ ++ struct urb *urb = (struct urb *)urb_handle; ++ urb_tq_entry_t *new_entry; ++ int rc = 0; ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n", ++ __func__, urb, usb_pipedevice(urb->pipe), ++ usb_pipeendpoint(urb->pipe), ++ usb_pipein(urb->pipe) ? "IN" : "OUT", status); ++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { ++ int i; ++ for (i = 0; i < urb->number_of_packets; i++) { ++ DWC_PRINTF(" ISO Desc %d status: %d\n", ++ i, urb->iso_frame_desc[i].status); ++ } ++ } ++ } ++ new_entry = DWC_ALLOC_ATOMIC(sizeof(urb_tq_entry_t)); ++ urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb); ++ /* Convert status value. */ ++ switch (status) { ++ case -DWC_E_PROTOCOL: ++ status = -EPROTO; ++ break; ++ case -DWC_E_IN_PROGRESS: ++ status = -EINPROGRESS; ++ break; ++ case -DWC_E_PIPE: ++ status = -EPIPE; ++ break; ++ case -DWC_E_IO: ++ status = -EIO; ++ break; ++ case -DWC_E_TIMEOUT: ++ status = -ETIMEDOUT; ++ break; ++ case -DWC_E_OVERFLOW: ++ status = -EOVERFLOW; ++ break; ++ case -DWC_E_SHUTDOWN: ++ status = -ESHUTDOWN; ++ break; ++ default: ++ if (status) { ++ DWC_PRINTF("Uknown urb status %d\n", status); ++ ++ } ++ } ++ ++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { ++ int i; ++ ++ urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb); ++ for (i = 0; i < urb->number_of_packets; ++i) { ++ urb->iso_frame_desc[i].actual_length = ++ dwc_otg_hcd_urb_get_iso_desc_actual_length ++ (dwc_otg_urb, i); ++ urb->iso_frame_desc[i].status = ++ dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i); ++ } ++ } ++ ++ urb->status = status; ++ urb->hcpriv = NULL; ++ if (!status) { ++ if ((urb->transfer_flags & URB_SHORT_NOT_OK) && ++ (urb->actual_length < urb->transfer_buffer_length)) { ++ urb->status = -EREMOTEIO; ++ } ++ } ++ ++ if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) || ++ (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) { ++ struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb); ++ if (ep) { ++ free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd), ++ dwc_otg_hcd_get_ep_bandwidth(hcd, ++ ep->hcpriv), ++ urb); ++ } ++ } ++ ++ DWC_FREE(dwc_otg_urb); ++ if (!new_entry) { ++ DWC_ERROR("dwc_otg_hcd: complete: cannot allocate URB TQ entry\n"); ++ urb->status = -EPROTO; ++ /* don't schedule the tasklet - ++ * directly return the packet here with error. */ ++#if USB_URB_EP_LINKING ++ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); ++#endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb); ++#else ++ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status); ++#endif ++ } else { ++ new_entry->urb = urb; ++#if USB_URB_EP_LINKING ++ rc = usb_hcd_check_unlink_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status); ++ if(0 == rc) { ++ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb); ++ } ++#endif ++ if(0 == rc) { ++ DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry, ++ urb_tq_entries); ++ DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet); ++ } ++ } ++ return 0; ++} ++ ++static struct dwc_otg_hcd_function_ops hcd_fops = { ++ .start = _start, ++ .disconnect = _disconnect, ++ .hub_info = _hub_info, ++ .speed = _speed, ++ .complete = _complete, ++ .get_b_hnp_enable = _get_b_hnp_enable, ++}; ++ ++static struct fiq_handler fh = { ++ .name = "usb_fiq", ++}; ++struct fiq_stack_s { ++ int magic1; ++ uint8_t stack[2048]; ++ int magic2; ++} fiq_stack; ++ ++extern mphi_regs_t c_mphi_regs; ++/** ++ * Initializes the HCD. This function allocates memory for and initializes the ++ * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the ++ * USB bus with the core and calls the hc_driver->start() function. It returns ++ * a negative error on failure. ++ */ ++int hcd_init(dwc_bus_dev_t *_dev) ++{ ++ struct usb_hcd *hcd = NULL; ++ dwc_otg_hcd_t *dwc_otg_hcd = NULL; ++ dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev); ++ int retval = 0; ++ u64 dmamask; ++ struct pt_regs regs; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev); ++ ++ /* Set device flags indicating whether the HCD supports DMA. */ ++ if (dwc_otg_is_dma_enable(otg_dev->core_if)) ++ dmamask = DMA_BIT_MASK(32); ++ else ++ dmamask = 0; ++ ++#if defined(LM_INTERFACE) || defined(PLATFORM_INTERFACE) ++ dma_set_mask(&_dev->dev, dmamask); ++ dma_set_coherent_mask(&_dev->dev, dmamask); ++#elif defined(PCI_INTERFACE) ++ pci_set_dma_mask(_dev, dmamask); ++ pci_set_consistent_dma_mask(_dev, dmamask); ++#endif ++ ++ if (fiq_fix_enable) ++ { ++ // Set up fiq ++ claim_fiq(&fh); ++ set_fiq_handler(__FIQ_Branch, 4); ++ memset(®s,0,sizeof(regs)); ++ regs.ARM_r8 = (long)dwc_otg_hcd_handle_fiq; ++ regs.ARM_r9 = (long)0; ++ regs.ARM_sp = (long)fiq_stack.stack + sizeof(fiq_stack.stack) - 4; ++ set_fiq_regs(®s); ++ fiq_stack.magic1 = 0xdeadbeef; ++ fiq_stack.magic2 = 0xaa995566; ++ } ++ ++ /* ++ * Allocate memory for the base HCD plus the DWC OTG HCD. ++ * Initialize the base HCD. ++ */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) ++ hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, _dev->dev.bus_id); ++#else ++ hcd = usb_create_hcd(&dwc_otg_hc_driver, &_dev->dev, dev_name(&_dev->dev)); ++ hcd->has_tt = 1; ++// hcd->uses_new_polling = 1; ++// hcd->poll_rh = 0; ++#endif ++ if (!hcd) { ++ retval = -ENOMEM; ++ goto error1; ++ } ++ ++ hcd->regs = otg_dev->os_dep.base; ++ ++ if (fiq_fix_enable) ++ { ++ volatile extern void *dwc_regs_base; ++ ++ //Set the mphi periph to the required registers ++ c_mphi_regs.base = otg_dev->os_dep.mphi_base; ++ c_mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c; ++ c_mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28; ++ c_mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c; ++ c_mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50; ++ ++ dwc_regs_base = otg_dev->os_dep.base; ++ ++ //Enable mphi peripheral ++ writel((1<<31),c_mphi_regs.ctrl); ++#ifdef DEBUG ++ if (readl(c_mphi_regs.ctrl) & 0x80000000) ++ DWC_DEBUGPL(DBG_USER, "MPHI periph has been enabled\n"); ++ else ++ DWC_DEBUGPL(DBG_USER, "MPHI periph has NOT been enabled\n"); ++#endif ++ // Enable FIQ interrupt from USB peripheral ++ enable_fiq(INTERRUPT_VC_USB); ++ } ++ /* Initialize the DWC OTG HCD. */ ++ dwc_otg_hcd = dwc_otg_hcd_alloc_hcd(); ++ if (!dwc_otg_hcd) { ++ goto error2; ++ } ++ ((struct wrapper_priv_data *)(hcd->hcd_priv))->dwc_otg_hcd = ++ dwc_otg_hcd; ++ otg_dev->hcd = dwc_otg_hcd; ++ ++ if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) { ++ goto error2; ++ } ++ ++ otg_dev->hcd->otg_dev = otg_dev; ++ hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) //version field absent later ++ hcd->self.otg_version = dwc_otg_get_otg_version(otg_dev->core_if); ++#endif ++ /* Don't support SG list at this point */ ++ hcd->self.sg_tablesize = 0; ++#endif ++ /* ++ * Finish generic HCD initialization and start the HCD. This function ++ * allocates the DMA buffer pool, registers the USB bus, requests the ++ * IRQ line, and calls hcd_start method. ++ */ ++#ifdef PLATFORM_INTERFACE ++ retval = usb_add_hcd(hcd, platform_get_irq(_dev, 0), IRQF_SHARED | IRQF_DISABLED); ++#else ++ retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED); ++#endif ++ if (retval < 0) { ++ goto error2; ++ } ++ ++ dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd); ++ return 0; ++ ++error2: ++ usb_put_hcd(hcd); ++error1: ++ return retval; ++} ++ ++/** ++ * Removes the HCD. ++ * Frees memory and resources associated with the HCD and deregisters the bus. ++ */ ++void hcd_remove(dwc_bus_dev_t *_dev) ++{ ++ dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev); ++ dwc_otg_hcd_t *dwc_otg_hcd; ++ struct usb_hcd *hcd; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE otg_dev=%p\n", otg_dev); ++ ++ if (!otg_dev) { ++ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev NULL!\n", __func__); ++ return; ++ } ++ ++ dwc_otg_hcd = otg_dev->hcd; ++ ++ if (!dwc_otg_hcd) { ++ DWC_DEBUGPL(DBG_ANY, "%s: otg_dev->hcd NULL!\n", __func__); ++ return; ++ } ++ ++ hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd); ++ ++ if (!hcd) { ++ DWC_DEBUGPL(DBG_ANY, ++ "%s: dwc_otg_hcd_to_hcd(dwc_otg_hcd) NULL!\n", ++ __func__); ++ return; ++ } ++ usb_remove_hcd(hcd); ++ dwc_otg_hcd_set_priv_data(dwc_otg_hcd, NULL); ++ dwc_otg_hcd_remove(dwc_otg_hcd); ++ usb_put_hcd(hcd); ++} ++ ++/* ========================================================================= ++ * Linux HC Driver Functions ++ * ========================================================================= */ ++ ++/** Initializes the DWC_otg controller and its root hub and prepares it for host ++ * mode operation. Activates the root port. Returns 0 on success and a negative ++ * error code on failure. */ ++int hcd_start(struct usb_hcd *hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); ++ struct usb_bus *bus; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n"); ++ bus = hcd_to_bus(hcd); ++ ++ hcd->state = HC_STATE_RUNNING; ++ if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) { ++ return 0; ++ } ++ ++ /* Initialize and connect root hub if one is not already attached */ ++ if (bus->root_hub) { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n"); ++ /* Inform the HUB driver to resume. */ ++ usb_hcd_resume_root_hub(hcd); ++ } ++ ++ return 0; ++} ++ ++/** ++ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are ++ * stopped. ++ */ ++void hcd_stop(struct usb_hcd *hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); ++ ++ dwc_otg_hcd_stop(dwc_otg_hcd); ++} ++ ++/** Returns the current frame number. */ ++static int get_frame_number(struct usb_hcd *hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); ++ ++ return dwc_otg_hcd_get_frame_number(dwc_otg_hcd); ++} ++ ++#ifdef DEBUG ++static void dump_urb_info(struct urb *urb, char *fn_name) ++{ ++ DWC_PRINTF("%s, urb %p\n", fn_name, urb); ++ DWC_PRINTF(" Device address: %d\n", usb_pipedevice(urb->pipe)); ++ DWC_PRINTF(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), ++ (usb_pipein(urb->pipe) ? "IN" : "OUT")); ++ DWC_PRINTF(" Endpoint type: %s\n", ( { ++ char *pipetype; ++ switch (usb_pipetype(urb->pipe)) { ++case PIPE_CONTROL: ++pipetype = "CONTROL"; break; case PIPE_BULK: ++pipetype = "BULK"; break; case PIPE_INTERRUPT: ++pipetype = "INTERRUPT"; break; case PIPE_ISOCHRONOUS: ++pipetype = "ISOCHRONOUS"; break; default: ++ pipetype = "UNKNOWN"; break;}; ++ pipetype;} ++ )) ; ++ DWC_PRINTF(" Speed: %s\n", ( { ++ char *speed; switch (urb->dev->speed) { ++case USB_SPEED_HIGH: ++speed = "HIGH"; break; case USB_SPEED_FULL: ++speed = "FULL"; break; case USB_SPEED_LOW: ++speed = "LOW"; break; default: ++ speed = "UNKNOWN"; break;}; ++ speed;} ++ )) ; ++ DWC_PRINTF(" Max packet size: %d\n", ++ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); ++ DWC_PRINTF(" Data buffer length: %d\n", urb->transfer_buffer_length); ++ DWC_PRINTF(" Transfer buffer: %p, Transfer DMA: %p\n", ++ urb->transfer_buffer, (void *)urb->transfer_dma); ++ DWC_PRINTF(" Setup buffer: %p, Setup DMA: %p\n", ++ urb->setup_packet, (void *)urb->setup_dma); ++ DWC_PRINTF(" Interval: %d\n", urb->interval); ++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { ++ int i; ++ for (i = 0; i < urb->number_of_packets; i++) { ++ DWC_PRINTF(" ISO Desc %d:\n", i); ++ DWC_PRINTF(" offset: %d, length %d\n", ++ urb->iso_frame_desc[i].offset, ++ urb->iso_frame_desc[i].length); ++ } ++ } ++} ++#endif ++ ++/** Starts processing a USB transfer request specified by a USB Request Block ++ * (URB). mem_flags indicates the type of memory allocation to use while ++ * processing this URB. */ ++static int dwc_otg_urb_enqueue(struct usb_hcd *hcd, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++ struct usb_host_endpoint *ep, ++#endif ++ struct urb *urb, gfp_t mem_flags) ++{ ++ int retval = 0; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) ++ struct usb_host_endpoint *ep = urb->ep; ++#endif ++ dwc_irqflags_t irqflags; ++ void **ref_ep_hcpriv = &ep->hcpriv; ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); ++ dwc_otg_hcd_urb_t *dwc_otg_urb; ++ int i; ++ int alloc_bandwidth = 0; ++ uint8_t ep_type = 0; ++ uint32_t flags = 0; ++ void *buf; ++ ++#ifdef DEBUG ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ dump_urb_info(urb, "dwc_otg_urb_enqueue"); ++ } ++#endif ++ ++ if (!urb->transfer_buffer && urb->transfer_buffer_length) ++ return -EINVAL; ++ ++ if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ++ || (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) { ++ if (!dwc_otg_hcd_is_bandwidth_allocated ++ (dwc_otg_hcd, ref_ep_hcpriv)) { ++ alloc_bandwidth = 1; ++ } ++ } ++ ++ switch (usb_pipetype(urb->pipe)) { ++ case PIPE_CONTROL: ++ ep_type = USB_ENDPOINT_XFER_CONTROL; ++ break; ++ case PIPE_ISOCHRONOUS: ++ ep_type = USB_ENDPOINT_XFER_ISOC; ++ break; ++ case PIPE_BULK: ++ ep_type = USB_ENDPOINT_XFER_BULK; ++ break; ++ case PIPE_INTERRUPT: ++ ep_type = USB_ENDPOINT_XFER_INT; ++ break; ++ default: ++ DWC_WARN("Wrong EP type - %d\n", usb_pipetype(urb->pipe)); ++ } ++ ++ /* # of packets is often 0 - do we really need to call this then? */ ++ dwc_otg_urb = dwc_otg_hcd_urb_alloc(dwc_otg_hcd, ++ urb->number_of_packets, ++ mem_flags == GFP_ATOMIC ? 1 : 0); ++ ++ if(dwc_otg_urb == NULL) ++ return -ENOMEM; ++ ++ if (!dwc_otg_urb && urb->number_of_packets) ++ return -ENOMEM; ++ ++ dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe), ++ usb_pipeendpoint(urb->pipe), ep_type, ++ usb_pipein(urb->pipe), ++ usb_maxpacket(urb->dev, urb->pipe, ++ !(usb_pipein(urb->pipe)))); ++ ++ buf = urb->transfer_buffer; ++ if (hcd->self.uses_dma) { ++ /* ++ * Calculate virtual address from physical address, ++ * because some class driver may not fill transfer_buffer. ++ * In Buffer DMA mode virual address is used, ++ * when handling non DWORD aligned buffers. ++ */ ++ //buf = phys_to_virt(urb->transfer_dma); ++ // DMA addresses are bus addresses not physical addresses! ++ buf = dma_to_virt(&urb->dev->dev, urb->transfer_dma); ++ } ++ ++ if (!(urb->transfer_flags & URB_NO_INTERRUPT)) ++ flags |= URB_GIVEBACK_ASAP; ++ if (urb->transfer_flags & URB_ZERO_PACKET) ++ flags |= URB_SEND_ZERO_PACKET; ++ ++ dwc_otg_hcd_urb_set_params(dwc_otg_urb, urb, buf, ++ urb->transfer_dma, ++ urb->transfer_buffer_length, ++ urb->setup_packet, ++ urb->setup_dma, flags, urb->interval); ++ ++ for (i = 0; i < urb->number_of_packets; ++i) { ++ dwc_otg_hcd_urb_set_iso_desc_params(dwc_otg_urb, i, ++ urb-> ++ iso_frame_desc[i].offset, ++ urb-> ++ iso_frame_desc[i].length); ++ } ++ ++ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags); ++ urb->hcpriv = dwc_otg_urb; ++#if USB_URB_EP_LINKING ++ retval = usb_hcd_link_urb_to_ep(hcd, urb); ++ if (0 == retval) ++#endif ++ { ++ retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb, ++ /*(dwc_otg_qh_t **)*/ ++ ref_ep_hcpriv, 1); ++ if (0 == retval) { ++ if (alloc_bandwidth) { ++ allocate_bus_bandwidth(hcd, ++ dwc_otg_hcd_get_ep_bandwidth( ++ dwc_otg_hcd, *ref_ep_hcpriv), ++ urb); ++ } ++ } else { ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval); ++#if USB_URB_EP_LINKING ++ usb_hcd_unlink_urb_from_ep(hcd, urb); ++#endif ++ DWC_FREE(dwc_otg_urb); ++ urb->hcpriv = NULL; ++ if (retval == -DWC_E_NO_DEVICE) ++ retval = -ENODEV; ++ } ++ } ++#if USB_URB_EP_LINKING ++ else ++ { ++ DWC_FREE(dwc_otg_urb); ++ urb->hcpriv = NULL; ++ } ++#endif ++ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags); ++ return retval; ++} ++ ++/** Aborts/cancels a USB transfer request. Always returns 0 to indicate ++ * success. */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ++#else ++static int dwc_otg_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) ++#endif ++{ ++ dwc_irqflags_t flags; ++ dwc_otg_hcd_t *dwc_otg_hcd; ++ int rc; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n"); ++ ++ dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); ++ ++#ifdef DEBUG ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ dump_urb_info(urb, "dwc_otg_urb_dequeue"); ++ } ++#endif ++ ++ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags); ++ rc = usb_hcd_check_unlink_urb(hcd, urb, status); ++ if (0 == rc) { ++ if(urb->hcpriv != NULL) { ++ dwc_otg_hcd_urb_dequeue(dwc_otg_hcd, ++ (dwc_otg_hcd_urb_t *)urb->hcpriv); ++ ++ DWC_FREE(urb->hcpriv); ++ urb->hcpriv = NULL; ++ } ++ } ++ ++ if (0 == rc) { ++ /* Higher layer software sets URB status. */ ++#if USB_URB_EP_LINKING ++ usb_hcd_unlink_urb_from_ep(hcd, urb); ++#endif ++ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags); ++ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++ usb_hcd_giveback_urb(hcd, urb); ++#else ++ usb_hcd_giveback_urb(hcd, urb, status); ++#endif ++ if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) { ++ DWC_PRINTF("Called usb_hcd_giveback_urb() \n"); ++ DWC_PRINTF(" 1urb->status = %d\n", urb->status); ++ } ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue OK\n"); ++ } else { ++ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags); ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue failed - rc %d\n", ++ rc); ++ } ++ ++ return rc; ++} ++ ++/* Frees resources in the DWC_otg controller related to a given endpoint. Also ++ * clears state in the HCD related to the endpoint. Any URBs for the endpoint ++ * must already be dequeued. */ ++static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); ++ ++ DWC_DEBUGPL(DBG_HCD, ++ "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, " ++ "endpoint=%d\n", ep->desc.bEndpointAddress, ++ dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress)); ++ dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250); ++ ep->hcpriv = NULL; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) ++/* Resets endpoint specific parameter values, in current version used to reset ++ * the data toggle(as a WA). This function can be called from usb_clear_halt routine */ ++static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) ++{ ++ dwc_irqflags_t flags; ++ struct usb_device *udev = NULL; ++ int epnum = usb_endpoint_num(&ep->desc); ++ int is_out = usb_endpoint_dir_out(&ep->desc); ++ int is_control = usb_endpoint_xfer_control(&ep->desc); ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); ++ struct device *dev = DWC_OTG_OS_GETDEV(dwc_otg_hcd->otg_dev->os_dep); ++ ++ if (dev) ++ udev = to_usb_device(dev); ++ else ++ return; ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP RESET: Endpoint Num=0x%02d\n", epnum); ++ ++ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags); ++ usb_settoggle(udev, epnum, is_out, 0); ++ if (is_control) ++ usb_settoggle(udev, epnum, !is_out, 0); ++ ++ if (ep->hcpriv) { ++ dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv); ++ } ++ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags); ++} ++#endif ++ ++/** Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if ++ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid ++ * interrupt. ++ * ++ * This function is called by the USB core when an interrupt occurs */ ++static irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); ++ int32_t retval = dwc_otg_hcd_handle_intr(dwc_otg_hcd); ++ if (retval != 0) { ++ S3C2410X_CLEAR_EINTPEND(); ++ } ++ return IRQ_RETVAL(retval); ++} ++ ++/** Creates Status Change bitmap for the root hub and root port. The bitmap is ++ * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1 ++ * is the status change indicator for the single root port. Returns 1 if either ++ * change indicator is 1, otherwise returns 0. */ ++int hub_status_data(struct usb_hcd *hcd, char *buf) ++{ ++ dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd); ++ ++ buf[0] = 0; ++ buf[0] |= (dwc_otg_hcd_is_status_changed(dwc_otg_hcd, 1)) << 1; ++ ++ return (buf[0] != 0); ++} ++ ++/** Handles hub class-specific requests. */ ++int hub_control(struct usb_hcd *hcd, ++ u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) ++{ ++ int retval; ++ ++ retval = dwc_otg_hcd_hub_control(hcd_to_dwc_otg_hcd(hcd), ++ typeReq, wValue, wIndex, buf, wLength); ++ ++ switch (retval) { ++ case -DWC_E_INVALID: ++ retval = -EINVAL; ++ break; ++ } ++ ++ return retval; ++} ++ ++#endif /* DWC_DEVICE_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c 2014-03-13 12:46:39.520097997 +0100 +@@ -0,0 +1,959 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_queue.c $ ++ * $Revision: #44 $ ++ * $Date: 2011/10/26 $ ++ * $Change: 1873028 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_DEVICE_ONLY ++ ++/** ++ * @file ++ * ++ * This file contains the functions to manage Queue Heads and Queue ++ * Transfer Descriptors. ++ */ ++ ++#include "dwc_otg_hcd.h" ++#include "dwc_otg_regs.h" ++#include "dwc_otg_mphi_fix.h" ++ ++extern bool microframe_schedule; ++ ++/** ++ * Free each QTD in the QH's QTD-list then free the QH. QH should already be ++ * removed from a list. QTD list should already be empty if called from URB ++ * Dequeue. ++ * ++ * @param hcd HCD instance. ++ * @param qh The QH to free. ++ */ ++void dwc_otg_hcd_qh_free(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ dwc_otg_qtd_t *qtd, *qtd_tmp; ++ ++ /* Free each QTD in the QTD list */ ++ DWC_SPINLOCK(hcd->lock); ++ DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) { ++ DWC_CIRCLEQ_REMOVE(&qh->qtd_list, qtd, qtd_list_entry); ++ dwc_otg_hcd_qtd_free(qtd); ++ } ++ ++ if (hcd->core_if->dma_desc_enable) { ++ dwc_otg_hcd_qh_free_ddma(hcd, qh); ++ } else if (qh->dw_align_buf) { ++ uint32_t buf_size; ++ if (qh->ep_type == UE_ISOCHRONOUS) { ++ buf_size = 4096; ++ } else { ++ buf_size = hcd->core_if->core_params->max_transfer_size; ++ } ++ DWC_DMA_FREE(buf_size, qh->dw_align_buf, qh->dw_align_buf_dma); ++ } ++ ++ DWC_FREE(qh); ++ DWC_SPINUNLOCK(hcd->lock); ++ return; ++} ++ ++#define BitStuffTime(bytecount) ((8 * 7* bytecount) / 6) ++#define HS_HOST_DELAY 5 /* nanoseconds */ ++#define FS_LS_HOST_DELAY 1000 /* nanoseconds */ ++#define HUB_LS_SETUP 333 /* nanoseconds */ ++#define NS_TO_US(ns) ((ns + 500) / 1000) ++ /* convert & round nanoseconds to microseconds */ ++ ++static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount) ++{ ++ unsigned long retval; ++ ++ switch (speed) { ++ case USB_SPEED_HIGH: ++ if (is_isoc) { ++ retval = ++ ((38 * 8 * 2083) + ++ (2083 * (3 + BitStuffTime(bytecount)))) / 1000 + ++ HS_HOST_DELAY; ++ } else { ++ retval = ++ ((55 * 8 * 2083) + ++ (2083 * (3 + BitStuffTime(bytecount)))) / 1000 + ++ HS_HOST_DELAY; ++ } ++ break; ++ case USB_SPEED_FULL: ++ if (is_isoc) { ++ retval = ++ (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000; ++ if (is_in) { ++ retval = 7268 + FS_LS_HOST_DELAY + retval; ++ } else { ++ retval = 6265 + FS_LS_HOST_DELAY + retval; ++ } ++ } else { ++ retval = ++ (8354 * (31 + 10 * BitStuffTime(bytecount))) / 1000; ++ retval = 9107 + FS_LS_HOST_DELAY + retval; ++ } ++ break; ++ case USB_SPEED_LOW: ++ if (is_in) { ++ retval = ++ (67667 * (31 + 10 * BitStuffTime(bytecount))) / ++ 1000; ++ retval = ++ 64060 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY + ++ retval; ++ } else { ++ retval = ++ (66700 * (31 + 10 * BitStuffTime(bytecount))) / ++ 1000; ++ retval = ++ 64107 + (2 * HUB_LS_SETUP) + FS_LS_HOST_DELAY + ++ retval; ++ } ++ break; ++ default: ++ DWC_WARN("Unknown device speed\n"); ++ retval = -1; ++ } ++ ++ return NS_TO_US(retval); ++} ++ ++/** ++ * Initializes a QH structure. ++ * ++ * @param hcd The HCD state structure for the DWC OTG controller. ++ * @param qh The QH to init. ++ * @param urb Holds the information about the device/endpoint that we need ++ * to initialize the QH. ++ */ ++#define SCHEDULE_SLOP 10 ++void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb) ++{ ++ char *speed, *type; ++ int dev_speed; ++ uint32_t hub_addr, hub_port; ++ ++ dwc_memset(qh, 0, sizeof(dwc_otg_qh_t)); ++ ++ /* Initialize QH */ ++ qh->ep_type = dwc_otg_hcd_get_pipe_type(&urb->pipe_info); ++ qh->ep_is_in = dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0; ++ ++ qh->data_toggle = DWC_OTG_HC_PID_DATA0; ++ qh->maxp = dwc_otg_hcd_get_mps(&urb->pipe_info); ++ DWC_CIRCLEQ_INIT(&qh->qtd_list); ++ DWC_LIST_INIT(&qh->qh_list_entry); ++ qh->channel = NULL; ++ ++ /* FS/LS Enpoint on HS Hub ++ * NOT virtual root hub */ ++ dev_speed = hcd->fops->speed(hcd, urb->priv); ++ ++ hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port); ++ qh->do_split = 0; ++ if (microframe_schedule) ++ qh->speed = dev_speed; ++ ++ qh->nak_frame = 0xffff; ++ ++ if (((dev_speed == USB_SPEED_LOW) || ++ (dev_speed == USB_SPEED_FULL)) && ++ (hub_addr != 0 && hub_addr != 1)) { ++ DWC_DEBUGPL(DBG_HCD, ++ "QH init: EP %d: TT found at hub addr %d, for port %d\n", ++ dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr, ++ hub_port); ++ qh->do_split = 1; ++ qh->skip_count = 0; ++ } ++ ++ if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) { ++ /* Compute scheduling parameters once and save them. */ ++ hprt0_data_t hprt; ++ ++ /** @todo Account for split transfers in the bus time. */ ++ int bytecount = ++ dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp); ++ ++ qh->usecs = ++ calc_bus_time((qh->do_split ? USB_SPEED_HIGH : dev_speed), ++ qh->ep_is_in, (qh->ep_type == UE_ISOCHRONOUS), ++ bytecount); ++ /* Start in a slightly future (micro)frame. */ ++ qh->sched_frame = dwc_frame_num_inc(hcd->frame_number, ++ SCHEDULE_SLOP); ++ qh->interval = urb->interval; ++ ++#if 0 ++ /* Increase interrupt polling rate for debugging. */ ++ if (qh->ep_type == UE_INTERRUPT) { ++ qh->interval = 8; ++ } ++#endif ++ hprt.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0); ++ if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) && ++ ((dev_speed == USB_SPEED_LOW) || ++ (dev_speed == USB_SPEED_FULL))) { ++ qh->interval *= 8; ++ qh->sched_frame |= 0x7; ++ qh->start_split_frame = qh->sched_frame; ++ } ++ ++ } ++ ++ DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n"); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - qh = %p\n", qh); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Device Address = %d\n", ++ dwc_otg_hcd_get_dev_addr(&urb->pipe_info)); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Endpoint %d, %s\n", ++ dwc_otg_hcd_get_ep_num(&urb->pipe_info), ++ dwc_otg_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"); ++ switch (dev_speed) { ++ case USB_SPEED_LOW: ++ qh->dev_speed = DWC_OTG_EP_SPEED_LOW; ++ speed = "low"; ++ break; ++ case USB_SPEED_FULL: ++ qh->dev_speed = DWC_OTG_EP_SPEED_FULL; ++ speed = "full"; ++ break; ++ case USB_SPEED_HIGH: ++ qh->dev_speed = DWC_OTG_EP_SPEED_HIGH; ++ speed = "high"; ++ break; ++ default: ++ speed = "?"; ++ break; ++ } ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Speed = %s\n", speed); ++ ++ switch (qh->ep_type) { ++ case UE_ISOCHRONOUS: ++ type = "isochronous"; ++ break; ++ case UE_INTERRUPT: ++ type = "interrupt"; ++ break; ++ case UE_CONTROL: ++ type = "control"; ++ break; ++ case UE_BULK: ++ type = "bulk"; ++ break; ++ default: ++ type = "?"; ++ break; ++ } ++ ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - Type = %s\n", type); ++ ++#ifdef DEBUG ++ if (qh->ep_type == UE_INTERRUPT) { ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n", ++ qh->usecs); ++ DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n", ++ qh->interval); ++ } ++#endif ++ ++} ++ ++/** ++ * This function allocates and initializes a QH. ++ * ++ * @param hcd The HCD state structure for the DWC OTG controller. ++ * @param urb Holds the information about the device/endpoint that we need ++ * to initialize the QH. ++ * @param atomic_alloc Flag to do atomic allocation if needed ++ * ++ * @return Returns pointer to the newly allocated QH, or NULL on error. */ ++dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd, ++ dwc_otg_hcd_urb_t * urb, int atomic_alloc) ++{ ++ dwc_otg_qh_t *qh; ++ ++ /* Allocate memory */ ++ /** @todo add memflags argument */ ++ qh = dwc_otg_hcd_qh_alloc(atomic_alloc); ++ if (qh == NULL) { ++ DWC_ERROR("qh allocation failed"); ++ return NULL; ++ } ++ ++ qh_init(hcd, qh, urb); ++ ++ if (hcd->core_if->dma_desc_enable ++ && (dwc_otg_hcd_qh_init_ddma(hcd, qh) < 0)) { ++ dwc_otg_hcd_qh_free(hcd, qh); ++ return NULL; ++ } ++ ++ return qh; ++} ++ ++/* microframe_schedule=0 start */ ++ ++/** ++ * Checks that a channel is available for a periodic transfer. ++ * ++ * @return 0 if successful, negative error code otherise. ++ */ ++static int periodic_channel_available(dwc_otg_hcd_t * hcd) ++{ ++ /* ++ * Currently assuming that there is a dedicated host channnel for each ++ * periodic transaction plus at least one host channel for ++ * non-periodic transactions. ++ */ ++ int status; ++ int num_channels; ++ ++ num_channels = hcd->core_if->core_params->host_channels; ++ if ((hcd->periodic_channels + hcd->non_periodic_channels < num_channels) ++ && (hcd->periodic_channels < num_channels - 1)) { ++ status = 0; ++ } else { ++ DWC_INFO("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n", ++ __func__, num_channels, hcd->periodic_channels, hcd->non_periodic_channels); //NOTICE ++ status = -DWC_E_NO_SPACE; ++ } ++ ++ return status; ++} ++ ++/** ++ * Checks that there is sufficient bandwidth for the specified QH in the ++ * periodic schedule. For simplicity, this calculation assumes that all the ++ * transfers in the periodic schedule may occur in the same (micro)frame. ++ * ++ * @param hcd The HCD state structure for the DWC OTG controller. ++ * @param qh QH containing periodic bandwidth required. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ int status; ++ int16_t max_claimed_usecs; ++ ++ status = 0; ++ ++ if ((qh->dev_speed == DWC_OTG_EP_SPEED_HIGH) || qh->do_split) { ++ /* ++ * High speed mode. ++ * Max periodic usecs is 80% x 125 usec = 100 usec. ++ */ ++ ++ max_claimed_usecs = 100 - qh->usecs; ++ } else { ++ /* ++ * Full speed mode. ++ * Max periodic usecs is 90% x 1000 usec = 900 usec. ++ */ ++ max_claimed_usecs = 900 - qh->usecs; ++ } ++ ++ if (hcd->periodic_usecs > max_claimed_usecs) { ++ DWC_INFO("%s: already claimed usecs %d, required usecs %d\n", __func__, hcd->periodic_usecs, qh->usecs); //NOTICE ++ status = -DWC_E_NO_SPACE; ++ } ++ ++ return status; ++} ++ ++/* microframe_schedule=0 end */ ++ ++/** ++ * Microframe scheduler ++ * track the total use in hcd->frame_usecs ++ * keep each qh use in qh->frame_usecs ++ * when surrendering the qh then donate the time back ++ */ ++const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 }; ++ ++/* ++ * called from dwc_otg_hcd.c:dwc_otg_hcd_init ++ */ ++int init_hcd_usecs(dwc_otg_hcd_t *_hcd) ++{ ++ int i; ++ for (i=0; i<8; i++) { ++ _hcd->frame_usecs[i] = max_uframe_usecs[i]; ++ } ++ return 0; ++} ++ ++static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) ++{ ++ int i; ++ unsigned short utime; ++ int t_left; ++ int ret; ++ int done; ++ ++ ret = -1; ++ utime = _qh->usecs; ++ t_left = utime; ++ i = 0; ++ done = 0; ++ while (done == 0) { ++ /* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */ ++ if (utime <= _hcd->frame_usecs[i]) { ++ _hcd->frame_usecs[i] -= utime; ++ _qh->frame_usecs[i] += utime; ++ t_left -= utime; ++ ret = i; ++ done = 1; ++ return ret; ++ } else { ++ i++; ++ if (i == 8) { ++ done = 1; ++ ret = -1; ++ } ++ } ++ } ++ return ret; ++ } ++ ++/* ++ * use this for FS apps that can span multiple uframes ++ */ ++static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) ++{ ++ int i; ++ int j; ++ unsigned short utime; ++ int t_left; ++ int ret; ++ int done; ++ unsigned short xtime; ++ ++ ret = -1; ++ utime = _qh->usecs; ++ t_left = utime; ++ i = 0; ++ done = 0; ++loop: ++ while (done == 0) { ++ if(_hcd->frame_usecs[i] <= 0) { ++ i++; ++ if (i == 8) { ++ done = 1; ++ ret = -1; ++ } ++ goto loop; ++ } ++ ++ /* ++ * we need n consecutive slots ++ * so use j as a start slot j plus j+1 must be enough time (for now) ++ */ ++ xtime= _hcd->frame_usecs[i]; ++ for (j = i+1 ; j < 8 ; j++ ) { ++ /* ++ * if we add this frame remaining time to xtime we may ++ * be OK, if not we need to test j for a complete frame ++ */ ++ if ((xtime+_hcd->frame_usecs[j]) < utime) { ++ if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) { ++ j = 8; ++ ret = -1; ++ continue; ++ } ++ } ++ if (xtime >= utime) { ++ ret = i; ++ j = 8; /* stop loop with a good value ret */ ++ continue; ++ } ++ /* add the frame time to x time */ ++ xtime += _hcd->frame_usecs[j]; ++ /* we must have a fully available next frame or break */ ++ if ((xtime < utime) ++ && (_hcd->frame_usecs[j] == max_uframe_usecs[j])) { ++ ret = -1; ++ j = 8; /* stop loop with a bad value ret */ ++ continue; ++ } ++ } ++ if (ret >= 0) { ++ t_left = utime; ++ for (j = i; (t_left>0) && (j < 8); j++ ) { ++ t_left -= _hcd->frame_usecs[j]; ++ if ( t_left <= 0 ) { ++ _qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left; ++ _hcd->frame_usecs[j]= -t_left; ++ ret = i; ++ done = 1; ++ } else { ++ _qh->frame_usecs[j] += _hcd->frame_usecs[j]; ++ _hcd->frame_usecs[j] = 0; ++ } ++ } ++ } else { ++ i++; ++ if (i == 8) { ++ done = 1; ++ ret = -1; ++ } ++ } ++ } ++ return ret; ++} ++ ++static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh) ++{ ++ int ret; ++ ret = -1; ++ ++ if (_qh->speed == USB_SPEED_HIGH) { ++ /* if this is a hs transaction we need a full frame */ ++ ret = find_single_uframe(_hcd, _qh); ++ } else { ++ /* if this is a fs transaction we may need a sequence of frames */ ++ ret = find_multi_uframe(_hcd, _qh); ++ } ++ return ret; ++} ++ ++/** ++ * Checks that the max transfer size allowed in a host channel is large enough ++ * to handle the maximum data transfer in a single (micro)frame for a periodic ++ * transfer. ++ * ++ * @param hcd The HCD state structure for the DWC OTG controller. ++ * @param qh QH for a periodic endpoint. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ int status; ++ uint32_t max_xfer_size; ++ uint32_t max_channel_xfer_size; ++ ++ status = 0; ++ ++ max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp); ++ max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size; ++ ++ if (max_xfer_size > max_channel_xfer_size) { ++ DWC_INFO("%s: Periodic xfer length %d > " "max xfer length for channel %d\n", ++ __func__, max_xfer_size, max_channel_xfer_size); //NOTICE ++ status = -DWC_E_NO_SPACE; ++ } ++ ++ return status; ++} ++ ++ ++extern int g_next_sched_frame, g_np_count, g_np_sent; ++ ++/** ++ * Schedules an interrupt or isochronous transfer in the periodic schedule. ++ * ++ * @param hcd The HCD state structure for the DWC OTG controller. ++ * @param qh QH for the periodic transfer. The QH should already contain the ++ * scheduling information. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ int status = 0; ++ ++ if (microframe_schedule) { ++ int frame; ++ status = find_uframe(hcd, qh); ++ frame = -1; ++ if (status == 0) { ++ frame = 7; ++ } else { ++ if (status > 0 ) ++ frame = status-1; ++ } ++ ++ /* Set the new frame up */ ++ if (frame > -1) { ++ qh->sched_frame &= ~0x7; ++ qh->sched_frame |= (frame & 7); ++ } ++ ++ if (status != -1) ++ status = 0; ++ } else { ++ status = periodic_channel_available(hcd); ++ if (status) { ++ DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE ++ return status; ++ } ++ ++ status = check_periodic_bandwidth(hcd, qh); ++ } ++ if (status) { ++ DWC_INFO("%s: Insufficient periodic bandwidth for " ++ "periodic transfer.\n", __func__); ++ return status; ++ } ++ status = check_max_xfer_size(hcd, qh); ++ if (status) { ++ DWC_INFO("%s: Channel max transfer size too small " ++ "for periodic transfer.\n", __func__); ++ return status; ++ } ++ ++ if (hcd->core_if->dma_desc_enable) { ++ /* Don't rely on SOF and start in ready schedule */ ++ DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry); ++ } ++ else { ++ if(DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, g_next_sched_frame)) ++ { ++ g_next_sched_frame = qh->sched_frame; ++ ++ } ++ /* Always start in the inactive schedule. */ ++ DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry); ++ } ++ ++ if (!microframe_schedule) { ++ /* Reserve the periodic channel. */ ++ hcd->periodic_channels++; ++ } ++ ++ /* Update claimed usecs per (micro)frame. */ ++ hcd->periodic_usecs += qh->usecs; ++ ++ return status; ++} ++ ++ ++/** ++ * This function adds a QH to either the non periodic or periodic schedule if ++ * it is not already in the schedule. If the QH is already in the schedule, no ++ * action is taken. ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ int status = 0; ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ ++ if (!DWC_LIST_EMPTY(&qh->qh_list_entry)) { ++ /* QH already in a schedule. */ ++ return status; ++ } ++ ++ /* Add the new QH to the appropriate schedule */ ++ if (dwc_qh_is_non_per(qh)) { ++ /* Always start in the inactive schedule. */ ++ DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive, ++ &qh->qh_list_entry); ++ g_np_count++; ++ } else { ++ status = schedule_periodic(hcd, qh); ++ if ( !hcd->periodic_qh_count ) { ++ intr_mask.b.sofintr = 1; ++ DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, ++ intr_mask.d32, intr_mask.d32); ++ } ++ hcd->periodic_qh_count++; ++ } ++ ++ return status; ++} ++ ++/** ++ * Removes an interrupt or isochronous transfer from the periodic schedule. ++ * ++ * @param hcd The HCD state structure for the DWC OTG controller. ++ * @param qh QH for the periodic transfer. ++ */ ++static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ int i; ++ DWC_LIST_REMOVE_INIT(&qh->qh_list_entry); ++ ++ /* Update claimed usecs per (micro)frame. */ ++ hcd->periodic_usecs -= qh->usecs; ++ ++ if (!microframe_schedule) { ++ /* Release the periodic channel reservation. */ ++ hcd->periodic_channels--; ++ } else { ++ for (i = 0; i < 8; i++) { ++ hcd->frame_usecs[i] += qh->frame_usecs[i]; ++ qh->frame_usecs[i] = 0; ++ } ++ } ++} ++ ++/** ++ * Removes a QH from either the non-periodic or periodic schedule. Memory is ++ * not freed. ++ * ++ * @param hcd The HCD state structure. ++ * @param qh QH to remove from schedule. */ ++void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh) ++{ ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ ++ if (DWC_LIST_EMPTY(&qh->qh_list_entry)) { ++ /* QH is not in a schedule. */ ++ return; ++ } ++ ++ if (dwc_qh_is_non_per(qh)) { ++ if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) { ++ hcd->non_periodic_qh_ptr = ++ hcd->non_periodic_qh_ptr->next; ++ } ++ DWC_LIST_REMOVE_INIT(&qh->qh_list_entry); ++ ++ // If we've removed the last non-periodic entry then there are none left! ++ g_np_count = g_np_sent; ++ } else { ++ deschedule_periodic(hcd, qh); ++ hcd->periodic_qh_count--; ++ if( !hcd->periodic_qh_count ) { ++ intr_mask.b.sofintr = 1; ++ DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk, ++ intr_mask.d32, 0); ++ } ++ } ++} ++ ++/** ++ * Deactivates a QH. For non-periodic QHs, removes the QH from the active ++ * non-periodic schedule. The QH is added to the inactive non-periodic ++ * schedule if any QTDs are still attached to the QH. ++ * ++ * For periodic QHs, the QH is removed from the periodic queued schedule. If ++ * there are any QTDs still attached to the QH, the QH is added to either the ++ * periodic inactive schedule or the periodic ready schedule and its next ++ * scheduled frame is calculated. The QH is placed in the ready schedule if ++ * the scheduled frame has been reached already. Otherwise it's placed in the ++ * inactive schedule. If there are no QTDs attached to the QH, the QH is ++ * completely removed from the periodic schedule. ++ */ ++void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, ++ int sched_next_periodic_split) ++{ ++ if (dwc_qh_is_non_per(qh)) { ++ ++ dwc_otg_qh_t *qh_tmp; ++ dwc_list_link_t *qh_list; ++ DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive) ++ { ++ qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry); ++ if(qh_tmp == qh) ++ { ++ /* ++ * FIQ is being disabled because this one nevers gets a np_count increment ++ * This is still not absolutely correct, but it should fix itself with ++ * just an unnecessary extra interrupt ++ */ ++ g_np_sent = g_np_count; ++ } ++ } ++ ++ ++ dwc_otg_hcd_qh_remove(hcd, qh); ++ if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { ++ /* Add back to inactive non-periodic schedule. */ ++ dwc_otg_hcd_qh_add(hcd, qh); ++ } ++ } else { ++ uint16_t frame_number = dwc_otg_hcd_get_frame_number(hcd); ++ ++ if (qh->do_split) { ++ /* Schedule the next continuing periodic split transfer */ ++ if (sched_next_periodic_split) { ++ ++ qh->sched_frame = frame_number; ++ ++ if (dwc_frame_num_le(frame_number, ++ dwc_frame_num_inc ++ (qh->start_split_frame, ++ 1))) { ++ /* ++ * Allow one frame to elapse after start ++ * split microframe before scheduling ++ * complete split, but DONT if we are ++ * doing the next start split in the ++ * same frame for an ISOC out. ++ */ ++ if ((qh->ep_type != UE_ISOCHRONOUS) || ++ (qh->ep_is_in != 0)) { ++ qh->sched_frame = ++ dwc_frame_num_inc(qh->sched_frame, 1); ++ } ++ } ++ } else { ++ qh->sched_frame = ++ dwc_frame_num_inc(qh->start_split_frame, ++ qh->interval); ++ if (dwc_frame_num_le ++ (qh->sched_frame, frame_number)) { ++ qh->sched_frame = frame_number; ++ } ++ qh->sched_frame |= 0x7; ++ qh->start_split_frame = qh->sched_frame; ++ } ++ } else { ++ qh->sched_frame = ++ dwc_frame_num_inc(qh->sched_frame, qh->interval); ++ if (dwc_frame_num_le(qh->sched_frame, frame_number)) { ++ qh->sched_frame = frame_number; ++ } ++ } ++ ++ if (DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) { ++ dwc_otg_hcd_qh_remove(hcd, qh); ++ } else { ++ /* ++ * Remove from periodic_sched_queued and move to ++ * appropriate queue. ++ */ ++ if ((microframe_schedule && dwc_frame_num_le(qh->sched_frame, frame_number)) || ++ (!microframe_schedule && qh->sched_frame == frame_number)) { ++ DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready, ++ &qh->qh_list_entry); ++ } else { ++ if(!dwc_frame_num_le(g_next_sched_frame, qh->sched_frame)) ++ { ++ g_next_sched_frame = qh->sched_frame; ++ } ++ ++ DWC_LIST_MOVE_HEAD ++ (&hcd->periodic_sched_inactive, ++ &qh->qh_list_entry); ++ } ++ } ++ } ++} ++ ++/** ++ * This function allocates and initializes a QTD. ++ * ++ * @param urb The URB to create a QTD from. Each URB-QTD pair will end up ++ * pointing to each other so each pair should have a unique correlation. ++ * @param atomic_alloc Flag to do atomic alloc if needed ++ * ++ * @return Returns pointer to the newly allocated QTD, or NULL on error. */ ++dwc_otg_qtd_t *dwc_otg_hcd_qtd_create(dwc_otg_hcd_urb_t * urb, int atomic_alloc) ++{ ++ dwc_otg_qtd_t *qtd; ++ ++ qtd = dwc_otg_hcd_qtd_alloc(atomic_alloc); ++ if (qtd == NULL) { ++ return NULL; ++ } ++ ++ dwc_otg_hcd_qtd_init(qtd, urb); ++ return qtd; ++} ++ ++/** ++ * Initializes a QTD structure. ++ * ++ * @param qtd The QTD to initialize. ++ * @param urb The URB to use for initialization. */ ++void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb) ++{ ++ dwc_memset(qtd, 0, sizeof(dwc_otg_qtd_t)); ++ qtd->urb = urb; ++ if (dwc_otg_hcd_get_pipe_type(&urb->pipe_info) == UE_CONTROL) { ++ /* ++ * The only time the QTD data toggle is used is on the data ++ * phase of control transfers. This phase always starts with ++ * DATA1. ++ */ ++ qtd->data_toggle = DWC_OTG_HC_PID_DATA1; ++ qtd->control_phase = DWC_OTG_CONTROL_SETUP; ++ } ++ ++ /* start split */ ++ qtd->complete_split = 0; ++ qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL; ++ qtd->isoc_split_offset = 0; ++ qtd->in_process = 0; ++ ++ /* Store the qtd ptr in the urb to reference what QTD. */ ++ urb->qtd = qtd; ++ return; ++} ++ ++/** ++ * This function adds a QTD to the QTD-list of a QH. It will find the correct ++ * QH to place the QTD into. If it does not find a QH, then it will create a ++ * new QH. If the QH to which the QTD is added is not currently scheduled, it ++ * is placed into the proper schedule based on its EP type. ++ * HCD lock must be held and interrupts must be disabled on entry ++ * ++ * @param[in] qtd The QTD to add ++ * @param[in] hcd The DWC HCD structure ++ * @param[out] qh out parameter to return queue head ++ * @param atomic_alloc Flag to do atomic alloc if needed ++ * ++ * @return 0 if successful, negative error code otherwise. ++ */ ++int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd, ++ dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc) ++{ ++ int retval = 0; ++ dwc_otg_hcd_urb_t *urb = qtd->urb; ++ ++ /* ++ * Get the QH which holds the QTD-list to insert to. Create QH if it ++ * doesn't exist. ++ */ ++ if (*qh == NULL) { ++ *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc); ++ if (*qh == NULL) { ++ retval = -DWC_E_NO_MEMORY; ++ goto done; ++ } ++ } ++ retval = dwc_otg_hcd_qh_add(hcd, *qh); ++ if (retval == 0) { ++ DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd, ++ qtd_list_entry); ++ qtd->qh = *qh; ++ } ++done: ++ ++ return retval; ++} ++ ++#endif /* DWC_DEVICE_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c 2014-03-13 12:46:39.520097997 +0100 +@@ -0,0 +1,113 @@ ++#include "dwc_otg_regs.h" ++#include "dwc_otg_dbg.h" ++ ++void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name) ++{ ++ DWC_DEBUGPL(DBG_USER, "*** Debugging from within the %s function: ***\n" ++ "curmode: %1i Modemismatch: %1i otgintr: %1i sofintr: %1i\n" ++ "rxstsqlvl: %1i nptxfempty : %1i ginnakeff: %1i goutnakeff: %1i\n" ++ "ulpickint: %1i i2cintr: %1i erlysuspend:%1i usbsuspend: %1i\n" ++ "usbreset: %1i enumdone: %1i isooutdrop: %1i eopframe: %1i\n" ++ "restoredone: %1i epmismatch: %1i inepint: %1i outepintr: %1i\n" ++ "incomplisoin:%1i incomplisoout:%1i fetsusp: %1i resetdet: %1i\n" ++ "portintr: %1i hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i\n" ++ "conidstschng:%1i disconnect: %1i sessreqintr:%1i wkupintr: %1i\n", ++ function_name, ++ gintsts.b.curmode, ++ gintsts.b.modemismatch, ++ gintsts.b.otgintr, ++ gintsts.b.sofintr, ++ gintsts.b.rxstsqlvl, ++ gintsts.b.nptxfempty, ++ gintsts.b.ginnakeff, ++ gintsts.b.goutnakeff, ++ gintsts.b.ulpickint, ++ gintsts.b.i2cintr, ++ gintsts.b.erlysuspend, ++ gintsts.b.usbsuspend, ++ gintsts.b.usbreset, ++ gintsts.b.enumdone, ++ gintsts.b.isooutdrop, ++ gintsts.b.eopframe, ++ gintsts.b.restoredone, ++ gintsts.b.epmismatch, ++ gintsts.b.inepint, ++ gintsts.b.outepintr, ++ gintsts.b.incomplisoin, ++ gintsts.b.incomplisoout, ++ gintsts.b.fetsusp, ++ gintsts.b.resetdet, ++ gintsts.b.portintr, ++ gintsts.b.hcintr, ++ gintsts.b.ptxfempty, ++ gintsts.b.lpmtranrcvd, ++ gintsts.b.conidstschng, ++ gintsts.b.disconnect, ++ gintsts.b.sessreqintr, ++ gintsts.b.wkupintr); ++ return; ++} ++ ++void dwc_debug_core_int_mask(gintmsk_data_t gintmsk, const char* function_name) ++{ ++ DWC_DEBUGPL(DBG_USER, "Interrupt Mask status (called from %s) :\n" ++ "modemismatch: %1i otgintr: %1i sofintr: %1i rxstsqlvl: %1i\n" ++ "nptxfempty: %1i ginnakeff: %1i goutnakeff: %1i ulpickint: %1i\n" ++ "i2cintr: %1i erlysuspend:%1i usbsuspend: %1i usbreset: %1i\n" ++ "enumdone: %1i isooutdrop: %1i eopframe: %1i restoredone: %1i\n" ++ "epmismatch: %1i inepintr: %1i outepintr: %1i incomplisoin:%1i\n" ++ "incomplisoout:%1i fetsusp: %1i resetdet: %1i portintr: %1i\n" ++ "hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i conidstschng:%1i\n" ++ "disconnect: %1i sessreqintr:%1i wkupintr: %1i\n", ++ function_name, ++ gintmsk.b.modemismatch, ++ gintmsk.b.otgintr, ++ gintmsk.b.sofintr, ++ gintmsk.b.rxstsqlvl, ++ gintmsk.b.nptxfempty, ++ gintmsk.b.ginnakeff, ++ gintmsk.b.goutnakeff, ++ gintmsk.b.ulpickint, ++ gintmsk.b.i2cintr, ++ gintmsk.b.erlysuspend, ++ gintmsk.b.usbsuspend, ++ gintmsk.b.usbreset, ++ gintmsk.b.enumdone, ++ gintmsk.b.isooutdrop, ++ gintmsk.b.eopframe, ++ gintmsk.b.restoredone, ++ gintmsk.b.epmismatch, ++ gintmsk.b.inepintr, ++ gintmsk.b.outepintr, ++ gintmsk.b.incomplisoin, ++ gintmsk.b.incomplisoout, ++ gintmsk.b.fetsusp, ++ gintmsk.b.resetdet, ++ gintmsk.b.portintr, ++ gintmsk.b.hcintr, ++ gintmsk.b.ptxfempty, ++ gintmsk.b.lpmtranrcvd, ++ gintmsk.b.conidstschng, ++ gintmsk.b.disconnect, ++ gintmsk.b.sessreqintr, ++ gintmsk.b.wkupintr); ++ return; ++} ++ ++void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name) ++{ ++ DWC_DEBUGPL(DBG_USER, "otg int register (from %s function):\n" ++ "sesenddet:%1i sesreqsucstschung:%2i hstnegsucstschng:%1i\n" ++ "hstnegdet:%1i adevtoutchng: %2i debdone: %1i\n" ++ "mvic: %1i\n", ++ function_name, ++ gotgint.b.sesenddet, ++ gotgint.b.sesreqsucstschng, ++ gotgint.b.hstnegsucstschng, ++ gotgint.b.hstnegdet, ++ gotgint.b.adevtoutchng, ++ gotgint.b.debdone, ++ gotgint.b.mvic); ++ ++ return; ++} +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h 2014-03-13 12:46:39.520097997 +0100 +@@ -0,0 +1,48 @@ ++#ifndef __DWC_OTG_MPHI_FIX_H__ ++#define __DWC_OTG_MPHI_FIX_H__ ++#define FIQ_WRITE(_addr_,_data_) (*(volatile uint32_t *) (_addr_) = (_data_)) ++#define FIQ_READ(_addr_) (*(volatile uint32_t *) (_addr_)) ++ ++typedef struct { ++ volatile void* base; ++ volatile void* ctrl; ++ volatile void* outdda; ++ volatile void* outddb; ++ volatile void* intstat; ++} mphi_regs_t; ++ ++void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name); ++void dwc_debug_core_int_mask(gintsts_data_t gintmsk, const char* function_name); ++void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name); ++ ++extern gintsts_data_t gintsts_saved; ++ ++#ifdef DEBUG ++#define DWC_DBG_PRINT_CORE_INT(_arg_) dwc_debug_print_core_int_reg(_arg_,__func__) ++#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) dwc_debug_core_int_mask(_arg_,__func__) ++#define DWC_DBG_PRINT_OTG_INT(_arg_) dwc_debug_otg_int(_arg_,__func__) ++ ++#else ++#define DWC_DBG_PRINT_CORE_INT(_arg_) ++#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) ++#define DWC_DBG_PRINT_OTG_INT(_arg_) ++ ++#endif ++ ++typedef enum { ++ FIQDBG_SCHED = (1 << 0), ++ FIQDBG_INT = (1 << 1), ++ FIQDBG_ERR = (1 << 2), ++ FIQDBG_PORTHUB = (1 << 3), ++} FIQDBG_T; ++ ++void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...); ++#ifdef FIQ_DEBUG ++#define fiq_print _fiq_print ++#else ++#define fiq_print(x, y, ...) ++#endif ++ ++extern bool fiq_fix_enable, nak_holdoff_enable, fiq_split_enable; ++ ++#endif +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h 2014-03-13 12:46:39.520097997 +0100 +@@ -0,0 +1,188 @@ ++#ifndef _DWC_OS_DEP_H_ ++#define _DWC_OS_DEP_H_ ++ ++/** ++ * @file ++ * ++ * This file contains OS dependent structures. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++# include ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21) ++# include ++#else ++# include ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++# include ++#else ++# include ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++# include ++#endif ++ ++#ifdef PCI_INTERFACE ++# include ++#endif ++ ++#ifdef LM_INTERFACE ++# include ++# include ++# include ++# include ++# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) ++# include ++# include ++# include ++# include ++# else ++/* in 2.6.31, at least, we seem to have lost the generic LM infrastructure - ++ here we assume that the machine architecture provides definitions ++ in its own header ++*/ ++# include ++# include ++# endif ++#endif ++ ++#ifdef PLATFORM_INTERFACE ++#include ++#include ++#endif ++ ++/** The OS page size */ ++#define DWC_OS_PAGE_SIZE PAGE_SIZE ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) ++typedef int gfp_t; ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++# define IRQF_SHARED SA_SHIRQ ++#endif ++ ++typedef struct os_dependent { ++ /** Base address returned from ioremap() */ ++ void *base; ++ ++ /** Register offset for Diagnostic API */ ++ uint32_t reg_offset; ++ ++ /** Base address for MPHI peripheral */ ++ void *mphi_base; ++ ++#ifdef LM_INTERFACE ++ struct lm_device *lmdev; ++#elif defined(PCI_INTERFACE) ++ struct pci_dev *pcidev; ++ ++ /** Start address of a PCI region */ ++ resource_size_t rsrc_start; ++ ++ /** Length address of a PCI region */ ++ resource_size_t rsrc_len; ++#elif defined(PLATFORM_INTERFACE) ++ struct platform_device *platformdev; ++#endif ++ ++} os_dependent_t; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++ ++/* Type for the our device on the chosen bus */ ++#if defined(LM_INTERFACE) ++typedef struct lm_device dwc_bus_dev_t; ++#elif defined(PCI_INTERFACE) ++typedef struct pci_dev dwc_bus_dev_t; ++#elif defined(PLATFORM_INTERFACE) ++typedef struct platform_device dwc_bus_dev_t; ++#endif ++ ++/* Helper macro to retrieve drvdata from the device on the chosen bus */ ++#if defined(LM_INTERFACE) ++#define DWC_OTG_BUSDRVDATA(_dev) lm_get_drvdata(_dev) ++#elif defined(PCI_INTERFACE) ++#define DWC_OTG_BUSDRVDATA(_dev) pci_get_drvdata(_dev) ++#elif defined(PLATFORM_INTERFACE) ++#define DWC_OTG_BUSDRVDATA(_dev) platform_get_drvdata(_dev) ++#endif ++ ++/** ++ * Helper macro returning the otg_device structure of a given struct device ++ * ++ * c.f. static dwc_otg_device_t *dwc_otg_drvdev(struct device *_dev) ++ */ ++#ifdef LM_INTERFACE ++#define DWC_OTG_GETDRVDEV(_var, _dev) do { \ ++ struct lm_device *lm_dev = \ ++ container_of(_dev, struct lm_device, dev); \ ++ _var = lm_get_drvdata(lm_dev); \ ++ } while (0) ++ ++#elif defined(PCI_INTERFACE) ++#define DWC_OTG_GETDRVDEV(_var, _dev) do { \ ++ _var = dev_get_drvdata(_dev); \ ++ } while (0) ++ ++#elif defined(PLATFORM_INTERFACE) ++#define DWC_OTG_GETDRVDEV(_var, _dev) do { \ ++ struct platform_device *platform_dev = \ ++ container_of(_dev, struct platform_device, dev); \ ++ _var = platform_get_drvdata(platform_dev); \ ++ } while (0) ++#endif ++ ++ ++/** ++ * Helper macro returning the struct dev of the given struct os_dependent ++ * ++ * c.f. static struct device *dwc_otg_getdev(struct os_dependent *osdep) ++ */ ++#ifdef LM_INTERFACE ++#define DWC_OTG_OS_GETDEV(_osdep) \ ++ ((_osdep).lmdev == NULL? NULL: &(_osdep).lmdev->dev) ++#elif defined(PCI_INTERFACE) ++#define DWC_OTG_OS_GETDEV(_osdep) \ ++ ((_osdep).pci_dev == NULL? NULL: &(_osdep).pci_dev->dev) ++#elif defined(PLATFORM_INTERFACE) ++#define DWC_OTG_OS_GETDEV(_osdep) \ ++ ((_osdep).platformdev == NULL? NULL: &(_osdep).platformdev->dev) ++#endif ++ ++ ++ ++ ++#endif /* _DWC_OS_DEP_H_ */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_pcd.c linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_pcd.c +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_pcd.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_pcd.c 2014-03-13 12:46:39.520097997 +0100 +@@ -0,0 +1,2708 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.c $ ++ * $Revision: #101 $ ++ * $Date: 2012/08/10 $ ++ * $Change: 2047372 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_HOST_ONLY ++ ++/** @file ++ * This file implements PCD Core. All code in this file is portable and doesn't ++ * use any OS specific functions. ++ * PCD Core provides Interface, defined in ++ * header file, which can be used to implement OS specific PCD interface. ++ * ++ * An important function of the PCD is managing interrupts generated ++ * by the DWC_otg controller. The implementation of the DWC_otg device ++ * mode interrupt service routines is in dwc_otg_pcd_intr.c. ++ * ++ * @todo Add Device Mode test modes (Test J mode, Test K mode, etc). ++ * @todo Does it work when the request size is greater than DEPTSIZ ++ * transfer size ++ * ++ */ ++ ++#include "dwc_otg_pcd.h" ++ ++#ifdef DWC_UTE_CFI ++#include "dwc_otg_cfi.h" ++ ++extern int init_cfi(cfiobject_t * cfiobj); ++#endif ++ ++/** ++ * Choose endpoint from ep arrays using usb_ep structure. ++ */ ++static dwc_otg_pcd_ep_t *get_ep_from_handle(dwc_otg_pcd_t * pcd, void *handle) ++{ ++ int i; ++ if (pcd->ep0.priv == handle) { ++ return &pcd->ep0; ++ } ++ for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) { ++ if (pcd->in_ep[i].priv == handle) ++ return &pcd->in_ep[i]; ++ if (pcd->out_ep[i].priv == handle) ++ return &pcd->out_ep[i]; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * This function completes a request. It call's the request call back. ++ */ ++void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req, ++ int32_t status) ++{ ++ unsigned stopped = ep->stopped; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(ep %p req %p)\n", __func__, ep, req); ++ DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry); ++ ++ /* don't modify queue heads during completion callback */ ++ ep->stopped = 1; ++ /* spin_unlock/spin_lock now done in fops->complete() */ ++ ep->pcd->fops->complete(ep->pcd, ep->priv, req->priv, status, ++ req->actual); ++ ++ if (ep->pcd->request_pending > 0) { ++ --ep->pcd->request_pending; ++ } ++ ++ ep->stopped = stopped; ++ DWC_FREE(req); ++} ++ ++/** ++ * This function terminates all the requsts in the EP request queue. ++ */ ++void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep) ++{ ++ dwc_otg_pcd_request_t *req; ++ ++ ep->stopped = 1; ++ ++ /* called with irqs blocked?? */ ++ while (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ req = DWC_CIRCLEQ_FIRST(&ep->queue); ++ dwc_otg_request_done(ep, req, -DWC_E_SHUTDOWN); ++ } ++} ++ ++void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd, ++ const struct dwc_otg_pcd_function_ops *fops) ++{ ++ pcd->fops = fops; ++} ++ ++/** ++ * PCD Callback function for initializing the PCD when switching to ++ * device mode. ++ * ++ * @param p void pointer to the dwc_otg_pcd_t ++ */ ++static int32_t dwc_otg_pcd_start_cb(void *p) ++{ ++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p; ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ ++ /* ++ * Initialized the Core for Device mode. ++ */ ++ if (dwc_otg_is_device_mode(core_if)) { ++ dwc_otg_core_dev_init(core_if); ++ /* Set core_if's lock pointer to the pcd->lock */ ++ core_if->lock = pcd->lock; ++ } ++ return 1; ++} ++ ++/** CFI-specific buffer allocation function for EP */ ++#ifdef DWC_UTE_CFI ++uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr, ++ size_t buflen, int flags) ++{ ++ dwc_otg_pcd_ep_t *ep; ++ ep = get_ep_from_handle(pcd, pep); ++ if (!ep) { ++ DWC_WARN("bad ep\n"); ++ return -DWC_E_INVALID; ++ } ++ ++ return pcd->cfi->ops.ep_alloc_buf(pcd->cfi, pcd, ep, addr, buflen, ++ flags); ++} ++#else ++uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, dwc_dma_t * addr, ++ size_t buflen, int flags); ++#endif ++ ++/** ++ * PCD Callback function for notifying the PCD when resuming from ++ * suspend. ++ * ++ * @param p void pointer to the dwc_otg_pcd_t ++ */ ++static int32_t dwc_otg_pcd_resume_cb(void *p) ++{ ++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p; ++ ++ if (pcd->fops->resume) { ++ pcd->fops->resume(pcd); ++ } ++ ++ /* Stop the SRP timeout timer. */ ++ if ((GET_CORE_IF(pcd)->core_params->phy_type != DWC_PHY_TYPE_PARAM_FS) ++ || (!GET_CORE_IF(pcd)->core_params->i2c_enable)) { ++ if (GET_CORE_IF(pcd)->srp_timer_started) { ++ GET_CORE_IF(pcd)->srp_timer_started = 0; ++ DWC_TIMER_CANCEL(GET_CORE_IF(pcd)->srp_timer); ++ } ++ } ++ return 1; ++} ++ ++/** ++ * PCD Callback function for notifying the PCD device is suspended. ++ * ++ * @param p void pointer to the dwc_otg_pcd_t ++ */ ++static int32_t dwc_otg_pcd_suspend_cb(void *p) ++{ ++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p; ++ ++ if (pcd->fops->suspend) { ++ DWC_SPINUNLOCK(pcd->lock); ++ pcd->fops->suspend(pcd); ++ DWC_SPINLOCK(pcd->lock); ++ } ++ ++ return 1; ++} ++ ++/** ++ * PCD Callback function for stopping the PCD when switching to Host ++ * mode. ++ * ++ * @param p void pointer to the dwc_otg_pcd_t ++ */ ++static int32_t dwc_otg_pcd_stop_cb(void *p) ++{ ++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) p; ++ extern void dwc_otg_pcd_stop(dwc_otg_pcd_t * _pcd); ++ ++ dwc_otg_pcd_stop(pcd); ++ return 1; ++} ++ ++/** ++ * PCD Callback structure for handling mode switching. ++ */ ++static dwc_otg_cil_callbacks_t pcd_callbacks = { ++ .start = dwc_otg_pcd_start_cb, ++ .stop = dwc_otg_pcd_stop_cb, ++ .suspend = dwc_otg_pcd_suspend_cb, ++ .resume_wakeup = dwc_otg_pcd_resume_cb, ++ .p = 0, /* Set at registration */ ++}; ++ ++/** ++ * This function allocates a DMA Descriptor chain for the Endpoint ++ * buffer to be used for a transfer to/from the specified endpoint. ++ */ ++dwc_otg_dev_dma_desc_t *dwc_otg_ep_alloc_desc_chain(dwc_dma_t * dma_desc_addr, ++ uint32_t count) ++{ ++ return DWC_DMA_ALLOC_ATOMIC(count * sizeof(dwc_otg_dev_dma_desc_t), ++ dma_desc_addr); ++} ++ ++/** ++ * This function frees a DMA Descriptor chain that was allocated by ep_alloc_desc. ++ */ ++void dwc_otg_ep_free_desc_chain(dwc_otg_dev_dma_desc_t * desc_addr, ++ uint32_t dma_desc_addr, uint32_t count) ++{ ++ DWC_DMA_FREE(count * sizeof(dwc_otg_dev_dma_desc_t), desc_addr, ++ dma_desc_addr); ++} ++ ++#ifdef DWC_EN_ISOC ++ ++/** ++ * This function initializes a descriptor chain for Isochronous transfer ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ * @param dwc_ep The EP to start the transfer on. ++ * ++ */ ++void dwc_otg_iso_ep_start_ddma_transfer(dwc_otg_core_if_t * core_if, ++ dwc_ep_t * dwc_ep) ++{ ++ ++ dsts_data_t dsts = {.d32 = 0 }; ++ depctl_data_t depctl = {.d32 = 0 }; ++ volatile uint32_t *addr; ++ int i, j; ++ uint32_t len; ++ ++ if (dwc_ep->is_in) ++ dwc_ep->desc_cnt = dwc_ep->buf_proc_intrvl / dwc_ep->bInterval; ++ else ++ dwc_ep->desc_cnt = ++ dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm / ++ dwc_ep->bInterval; ++ ++ /** Allocate descriptors for double buffering */ ++ dwc_ep->iso_desc_addr = ++ dwc_otg_ep_alloc_desc_chain(&dwc_ep->iso_dma_desc_addr, ++ dwc_ep->desc_cnt * 2); ++ if (dwc_ep->desc_addr) { ++ DWC_WARN("%s, can't allocate DMA descriptor chain\n", __func__); ++ return; ++ } ++ ++ dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts); ++ ++ /** ISO OUT EP */ ++ if (dwc_ep->is_in == 0) { ++ dev_dma_desc_sts_t sts = {.d32 = 0 }; ++ dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr; ++ dma_addr_t dma_ad; ++ uint32_t data_per_desc; ++ dwc_otg_dev_out_ep_regs_t *out_regs = ++ core_if->dev_if->out_ep_regs[dwc_ep->num]; ++ int offset; ++ ++ addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl; ++ dma_ad = (dma_addr_t) DWC_READ_REG32(&(out_regs->doepdma)); ++ ++ /** Buffer 0 descriptors setup */ ++ dma_ad = dwc_ep->dma_addr0; ++ ++ sts.b_iso_out.bs = BS_HOST_READY; ++ sts.b_iso_out.rxsts = 0; ++ sts.b_iso_out.l = 0; ++ sts.b_iso_out.sp = 0; ++ sts.b_iso_out.ioc = 0; ++ sts.b_iso_out.pid = 0; ++ sts.b_iso_out.framenum = 0; ++ ++ offset = 0; ++ for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; ++ i += dwc_ep->pkt_per_frm) { ++ ++ for (j = 0; j < dwc_ep->pkt_per_frm; ++j) { ++ uint32_t len = (j + 1) * dwc_ep->maxpacket; ++ if (len > dwc_ep->data_per_frame) ++ data_per_desc = ++ dwc_ep->data_per_frame - ++ j * dwc_ep->maxpacket; ++ else ++ data_per_desc = dwc_ep->maxpacket; ++ len = data_per_desc % 4; ++ if (len) ++ data_per_desc += 4 - len; ++ ++ sts.b_iso_out.rxbytes = data_per_desc; ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ ++ offset += data_per_desc; ++ dma_desc++; ++ dma_ad += data_per_desc; ++ } ++ } ++ ++ for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) { ++ uint32_t len = (j + 1) * dwc_ep->maxpacket; ++ if (len > dwc_ep->data_per_frame) ++ data_per_desc = ++ dwc_ep->data_per_frame - ++ j * dwc_ep->maxpacket; ++ else ++ data_per_desc = dwc_ep->maxpacket; ++ len = data_per_desc % 4; ++ if (len) ++ data_per_desc += 4 - len; ++ sts.b_iso_out.rxbytes = data_per_desc; ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ ++ offset += data_per_desc; ++ dma_desc++; ++ dma_ad += data_per_desc; ++ } ++ ++ sts.b_iso_out.ioc = 1; ++ len = (j + 1) * dwc_ep->maxpacket; ++ if (len > dwc_ep->data_per_frame) ++ data_per_desc = ++ dwc_ep->data_per_frame - j * dwc_ep->maxpacket; ++ else ++ data_per_desc = dwc_ep->maxpacket; ++ len = data_per_desc % 4; ++ if (len) ++ data_per_desc += 4 - len; ++ sts.b_iso_out.rxbytes = data_per_desc; ++ ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ dma_desc++; ++ ++ /** Buffer 1 descriptors setup */ ++ sts.b_iso_out.ioc = 0; ++ dma_ad = dwc_ep->dma_addr1; ++ ++ offset = 0; ++ for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; ++ i += dwc_ep->pkt_per_frm) { ++ for (j = 0; j < dwc_ep->pkt_per_frm; ++j) { ++ uint32_t len = (j + 1) * dwc_ep->maxpacket; ++ if (len > dwc_ep->data_per_frame) ++ data_per_desc = ++ dwc_ep->data_per_frame - ++ j * dwc_ep->maxpacket; ++ else ++ data_per_desc = dwc_ep->maxpacket; ++ len = data_per_desc % 4; ++ if (len) ++ data_per_desc += 4 - len; ++ ++ data_per_desc = ++ sts.b_iso_out.rxbytes = data_per_desc; ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ ++ offset += data_per_desc; ++ dma_desc++; ++ dma_ad += data_per_desc; ++ } ++ } ++ for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) { ++ data_per_desc = ++ ((j + 1) * dwc_ep->maxpacket > ++ dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - ++ j * dwc_ep->maxpacket : dwc_ep->maxpacket; ++ data_per_desc += ++ (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; ++ sts.b_iso_out.rxbytes = data_per_desc; ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ ++ offset += data_per_desc; ++ dma_desc++; ++ dma_ad += data_per_desc; ++ } ++ ++ sts.b_iso_out.ioc = 1; ++ sts.b_iso_out.l = 1; ++ data_per_desc = ++ ((j + 1) * dwc_ep->maxpacket > ++ dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - ++ j * dwc_ep->maxpacket : dwc_ep->maxpacket; ++ data_per_desc += ++ (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; ++ sts.b_iso_out.rxbytes = data_per_desc; ++ ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ ++ dwc_ep->next_frame = 0; ++ ++ /** Write dma_ad into DOEPDMA register */ ++ DWC_WRITE_REG32(&(out_regs->doepdma), ++ (uint32_t) dwc_ep->iso_dma_desc_addr); ++ ++ } ++ /** ISO IN EP */ ++ else { ++ dev_dma_desc_sts_t sts = {.d32 = 0 }; ++ dwc_otg_dev_dma_desc_t *dma_desc = dwc_ep->iso_desc_addr; ++ dma_addr_t dma_ad; ++ dwc_otg_dev_in_ep_regs_t *in_regs = ++ core_if->dev_if->in_ep_regs[dwc_ep->num]; ++ unsigned int frmnumber; ++ fifosize_data_t txfifosize, rxfifosize; ++ ++ txfifosize.d32 = ++ DWC_READ_REG32(&core_if->dev_if->in_ep_regs[dwc_ep->num]-> ++ dtxfsts); ++ rxfifosize.d32 = ++ DWC_READ_REG32(&core_if->core_global_regs->grxfsiz); ++ ++ addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl; ++ ++ dma_ad = dwc_ep->dma_addr0; ++ ++ dsts.d32 = ++ DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts); ++ ++ sts.b_iso_in.bs = BS_HOST_READY; ++ sts.b_iso_in.txsts = 0; ++ sts.b_iso_in.sp = ++ (dwc_ep->data_per_frame % dwc_ep->maxpacket) ? 1 : 0; ++ sts.b_iso_in.ioc = 0; ++ sts.b_iso_in.pid = dwc_ep->pkt_per_frm; ++ ++ frmnumber = dwc_ep->next_frame; ++ ++ sts.b_iso_in.framenum = frmnumber; ++ sts.b_iso_in.txbytes = dwc_ep->data_per_frame; ++ sts.b_iso_in.l = 0; ++ ++ /** Buffer 0 descriptors setup */ ++ for (i = 0; i < dwc_ep->desc_cnt - 1; i++) { ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ dma_desc++; ++ ++ dma_ad += dwc_ep->data_per_frame; ++ sts.b_iso_in.framenum += dwc_ep->bInterval; ++ } ++ ++ sts.b_iso_in.ioc = 1; ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ ++dma_desc; ++ ++ /** Buffer 1 descriptors setup */ ++ sts.b_iso_in.ioc = 0; ++ dma_ad = dwc_ep->dma_addr1; ++ ++ for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; ++ i += dwc_ep->pkt_per_frm) { ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ dma_desc++; ++ ++ dma_ad += dwc_ep->data_per_frame; ++ sts.b_iso_in.framenum += dwc_ep->bInterval; ++ ++ sts.b_iso_in.ioc = 0; ++ } ++ sts.b_iso_in.ioc = 1; ++ sts.b_iso_in.l = 1; ++ ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ ++ dwc_ep->next_frame = sts.b_iso_in.framenum + dwc_ep->bInterval; ++ ++ /** Write dma_ad into diepdma register */ ++ DWC_WRITE_REG32(&(in_regs->diepdma), ++ (uint32_t) dwc_ep->iso_dma_desc_addr); ++ } ++ /** Enable endpoint, clear nak */ ++ depctl.d32 = 0; ++ depctl.b.epena = 1; ++ depctl.b.usbactep = 1; ++ depctl.b.cnak = 1; ++ ++ DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32); ++ depctl.d32 = DWC_READ_REG32(addr); ++} ++ ++/** ++ * This function initializes a descriptor chain for Isochronous transfer ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ * @param ep The EP to start the transfer on. ++ * ++ */ ++void dwc_otg_iso_ep_start_buf_transfer(dwc_otg_core_if_t * core_if, ++ dwc_ep_t * ep) ++{ ++ depctl_data_t depctl = {.d32 = 0 }; ++ volatile uint32_t *addr; ++ ++ if (ep->is_in) { ++ addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl; ++ } else { ++ addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl; ++ } ++ ++ if (core_if->dma_enable == 0 || core_if->dma_desc_enable != 0) { ++ return; ++ } else { ++ deptsiz_data_t deptsiz = {.d32 = 0 }; ++ ++ ep->xfer_len = ++ ep->data_per_frame * ep->buf_proc_intrvl / ep->bInterval; ++ ep->pkt_cnt = ++ (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket; ++ ep->xfer_count = 0; ++ ep->xfer_buff = ++ (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0; ++ ep->dma_addr = ++ (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0; ++ ++ if (ep->is_in) { ++ /* Program the transfer size and packet count ++ * as follows: xfersize = N * maxpacket + ++ * short_packet pktcnt = N + (short_packet ++ * exist ? 1 : 0) ++ */ ++ deptsiz.b.mc = ep->pkt_per_frm; ++ deptsiz.b.xfersize = ep->xfer_len; ++ deptsiz.b.pktcnt = ++ (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket; ++ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[ep->num]-> ++ dieptsiz, deptsiz.d32); ++ ++ /* Write the DMA register */ ++ DWC_WRITE_REG32(& ++ (core_if->dev_if->in_ep_regs[ep->num]-> ++ diepdma), (uint32_t) ep->dma_addr); ++ ++ } else { ++ deptsiz.b.pktcnt = ++ (ep->xfer_len + (ep->maxpacket - 1)) / ++ ep->maxpacket; ++ deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket; ++ ++ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[ep->num]-> ++ doeptsiz, deptsiz.d32); ++ ++ /* Write the DMA register */ ++ DWC_WRITE_REG32(& ++ (core_if->dev_if->out_ep_regs[ep->num]-> ++ doepdma), (uint32_t) ep->dma_addr); ++ ++ } ++ /** Enable endpoint, clear nak */ ++ depctl.d32 = 0; ++ depctl.b.epena = 1; ++ depctl.b.cnak = 1; ++ ++ DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32); ++ } ++} ++ ++/** ++ * This function does the setup for a data transfer for an EP and ++ * starts the transfer. For an IN transfer, the packets will be ++ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers, ++ * the packets are unloaded from the Rx FIFO in the ISR. ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ * @param ep The EP to start the transfer on. ++ */ ++ ++static void dwc_otg_iso_ep_start_transfer(dwc_otg_core_if_t * core_if, ++ dwc_ep_t * ep) ++{ ++ if (core_if->dma_enable) { ++ if (core_if->dma_desc_enable) { ++ if (ep->is_in) { ++ ep->desc_cnt = ep->pkt_cnt / ep->pkt_per_frm; ++ } else { ++ ep->desc_cnt = ep->pkt_cnt; ++ } ++ dwc_otg_iso_ep_start_ddma_transfer(core_if, ep); ++ } else { ++ if (core_if->pti_enh_enable) { ++ dwc_otg_iso_ep_start_buf_transfer(core_if, ep); ++ } else { ++ ep->cur_pkt_addr = ++ (ep->proc_buf_num) ? ep->xfer_buff1 : ep-> ++ xfer_buff0; ++ ep->cur_pkt_dma_addr = ++ (ep->proc_buf_num) ? ep->dma_addr1 : ep-> ++ dma_addr0; ++ dwc_otg_iso_ep_start_frm_transfer(core_if, ep); ++ } ++ } ++ } else { ++ ep->cur_pkt_addr = ++ (ep->proc_buf_num) ? ep->xfer_buff1 : ep->xfer_buff0; ++ ep->cur_pkt_dma_addr = ++ (ep->proc_buf_num) ? ep->dma_addr1 : ep->dma_addr0; ++ dwc_otg_iso_ep_start_frm_transfer(core_if, ep); ++ } ++} ++ ++/** ++ * This function stops transfer for an EP and ++ * resets the ep's variables. ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ * @param ep The EP to start the transfer on. ++ */ ++ ++void dwc_otg_iso_ep_stop_transfer(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) ++{ ++ depctl_data_t depctl = {.d32 = 0 }; ++ volatile uint32_t *addr; ++ ++ if (ep->is_in == 1) { ++ addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl; ++ } else { ++ addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl; ++ } ++ ++ /* disable the ep */ ++ depctl.d32 = DWC_READ_REG32(addr); ++ ++ depctl.b.epdis = 1; ++ depctl.b.snak = 1; ++ ++ DWC_WRITE_REG32(addr, depctl.d32); ++ ++ if (core_if->dma_desc_enable && ++ ep->iso_desc_addr && ep->iso_dma_desc_addr) { ++ dwc_otg_ep_free_desc_chain(ep->iso_desc_addr, ++ ep->iso_dma_desc_addr, ++ ep->desc_cnt * 2); ++ } ++ ++ /* reset varibales */ ++ ep->dma_addr0 = 0; ++ ep->dma_addr1 = 0; ++ ep->xfer_buff0 = 0; ++ ep->xfer_buff1 = 0; ++ ep->data_per_frame = 0; ++ ep->data_pattern_frame = 0; ++ ep->sync_frame = 0; ++ ep->buf_proc_intrvl = 0; ++ ep->bInterval = 0; ++ ep->proc_buf_num = 0; ++ ep->pkt_per_frm = 0; ++ ep->pkt_per_frm = 0; ++ ep->desc_cnt = 0; ++ ep->iso_desc_addr = 0; ++ ep->iso_dma_desc_addr = 0; ++} ++ ++int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle, ++ uint8_t * buf0, uint8_t * buf1, dwc_dma_t dma0, ++ dwc_dma_t dma1, int sync_frame, int dp_frame, ++ int data_per_frame, int start_frame, ++ int buf_proc_intrvl, void *req_handle, ++ int atomic_alloc) ++{ ++ dwc_otg_pcd_ep_t *ep; ++ dwc_irqflags_t flags = 0; ++ dwc_ep_t *dwc_ep; ++ int32_t frm_data; ++ dsts_data_t dsts; ++ dwc_otg_core_if_t *core_if; ++ ++ ep = get_ep_from_handle(pcd, ep_handle); ++ ++ if (!ep || !ep->desc || ep->dwc_ep.num == 0) { ++ DWC_WARN("bad ep\n"); ++ return -DWC_E_INVALID; ++ } ++ ++ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++ core_if = GET_CORE_IF(pcd); ++ dwc_ep = &ep->dwc_ep; ++ ++ if (ep->iso_req_handle) { ++ DWC_WARN("ISO request in progress\n"); ++ } ++ ++ dwc_ep->dma_addr0 = dma0; ++ dwc_ep->dma_addr1 = dma1; ++ ++ dwc_ep->xfer_buff0 = buf0; ++ dwc_ep->xfer_buff1 = buf1; ++ ++ dwc_ep->data_per_frame = data_per_frame; ++ ++ /** @todo - pattern data support is to be implemented in the future */ ++ dwc_ep->data_pattern_frame = dp_frame; ++ dwc_ep->sync_frame = sync_frame; ++ ++ dwc_ep->buf_proc_intrvl = buf_proc_intrvl; ++ ++ dwc_ep->bInterval = 1 << (ep->desc->bInterval - 1); ++ ++ dwc_ep->proc_buf_num = 0; ++ ++ dwc_ep->pkt_per_frm = 0; ++ frm_data = ep->dwc_ep.data_per_frame; ++ while (frm_data > 0) { ++ dwc_ep->pkt_per_frm++; ++ frm_data -= ep->dwc_ep.maxpacket; ++ } ++ ++ dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts); ++ ++ if (start_frame == -1) { ++ dwc_ep->next_frame = dsts.b.soffn + 1; ++ if (dwc_ep->bInterval != 1) { ++ dwc_ep->next_frame = ++ dwc_ep->next_frame + (dwc_ep->bInterval - 1 - ++ dwc_ep->next_frame % ++ dwc_ep->bInterval); ++ } ++ } else { ++ dwc_ep->next_frame = start_frame; ++ } ++ ++ if (!core_if->pti_enh_enable) { ++ dwc_ep->pkt_cnt = ++ dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm / ++ dwc_ep->bInterval; ++ } else { ++ dwc_ep->pkt_cnt = ++ (dwc_ep->data_per_frame * ++ (dwc_ep->buf_proc_intrvl / dwc_ep->bInterval) ++ - 1 + dwc_ep->maxpacket) / dwc_ep->maxpacket; ++ } ++ ++ if (core_if->dma_desc_enable) { ++ dwc_ep->desc_cnt = ++ dwc_ep->buf_proc_intrvl * dwc_ep->pkt_per_frm / ++ dwc_ep->bInterval; ++ } ++ ++ if (atomic_alloc) { ++ dwc_ep->pkt_info = ++ DWC_ALLOC_ATOMIC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt); ++ } else { ++ dwc_ep->pkt_info = ++ DWC_ALLOC(sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt); ++ } ++ if (!dwc_ep->pkt_info) { ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ return -DWC_E_NO_MEMORY; ++ } ++ if (core_if->pti_enh_enable) { ++ dwc_memset(dwc_ep->pkt_info, 0, ++ sizeof(iso_pkt_info_t) * dwc_ep->pkt_cnt); ++ } ++ ++ dwc_ep->cur_pkt = 0; ++ ep->iso_req_handle = req_handle; ++ ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ dwc_otg_iso_ep_start_transfer(core_if, dwc_ep); ++ return 0; ++} ++ ++int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *req_handle) ++{ ++ dwc_irqflags_t flags = 0; ++ dwc_otg_pcd_ep_t *ep; ++ dwc_ep_t *dwc_ep; ++ ++ ep = get_ep_from_handle(pcd, ep_handle); ++ if (!ep || !ep->desc || ep->dwc_ep.num == 0) { ++ DWC_WARN("bad ep\n"); ++ return -DWC_E_INVALID; ++ } ++ dwc_ep = &ep->dwc_ep; ++ ++ dwc_otg_iso_ep_stop_transfer(GET_CORE_IF(pcd), dwc_ep); ++ ++ DWC_FREE(dwc_ep->pkt_info); ++ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++ if (ep->iso_req_handle != req_handle) { ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ return -DWC_E_INVALID; ++ } ++ ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ ++ ep->iso_req_handle = 0; ++ return 0; ++} ++ ++/** ++ * This function is used for perodical data exchnage between PCD and gadget drivers. ++ * for Isochronous EPs ++ * ++ * - Every time a sync period completes this function is called to ++ * perform data exchange between PCD and gadget ++ */ ++void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep, ++ void *req_handle) ++{ ++ int i; ++ dwc_ep_t *dwc_ep; ++ ++ dwc_ep = &ep->dwc_ep; ++ ++ DWC_SPINUNLOCK(ep->pcd->lock); ++ pcd->fops->isoc_complete(pcd, ep->priv, ep->iso_req_handle, ++ dwc_ep->proc_buf_num ^ 0x1); ++ DWC_SPINLOCK(ep->pcd->lock); ++ ++ for (i = 0; i < dwc_ep->pkt_cnt; ++i) { ++ dwc_ep->pkt_info[i].status = 0; ++ dwc_ep->pkt_info[i].offset = 0; ++ dwc_ep->pkt_info[i].length = 0; ++ } ++} ++ ++int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *iso_req_handle) ++{ ++ dwc_otg_pcd_ep_t *ep; ++ dwc_ep_t *dwc_ep; ++ ++ ep = get_ep_from_handle(pcd, ep_handle); ++ if (!ep->desc || ep->dwc_ep.num == 0) { ++ DWC_WARN("bad ep\n"); ++ return -DWC_E_INVALID; ++ } ++ dwc_ep = &ep->dwc_ep; ++ ++ return dwc_ep->pkt_cnt; ++} ++ ++void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *iso_req_handle, int packet, ++ int *status, int *actual, int *offset) ++{ ++ dwc_otg_pcd_ep_t *ep; ++ dwc_ep_t *dwc_ep; ++ ++ ep = get_ep_from_handle(pcd, ep_handle); ++ if (!ep) ++ DWC_WARN("bad ep\n"); ++ ++ dwc_ep = &ep->dwc_ep; ++ ++ *status = dwc_ep->pkt_info[packet].status; ++ *actual = dwc_ep->pkt_info[packet].length; ++ *offset = dwc_ep->pkt_info[packet].offset; ++} ++ ++#endif /* DWC_EN_ISOC */ ++ ++static void dwc_otg_pcd_init_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * pcd_ep, ++ uint32_t is_in, uint32_t ep_num) ++{ ++ /* Init EP structure */ ++ pcd_ep->desc = 0; ++ pcd_ep->pcd = pcd; ++ pcd_ep->stopped = 1; ++ pcd_ep->queue_sof = 0; ++ ++ /* Init DWC ep structure */ ++ pcd_ep->dwc_ep.is_in = is_in; ++ pcd_ep->dwc_ep.num = ep_num; ++ pcd_ep->dwc_ep.active = 0; ++ pcd_ep->dwc_ep.tx_fifo_num = 0; ++ /* Control until ep is actvated */ ++ pcd_ep->dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL; ++ pcd_ep->dwc_ep.maxpacket = MAX_PACKET_SIZE; ++ pcd_ep->dwc_ep.dma_addr = 0; ++ pcd_ep->dwc_ep.start_xfer_buff = 0; ++ pcd_ep->dwc_ep.xfer_buff = 0; ++ pcd_ep->dwc_ep.xfer_len = 0; ++ pcd_ep->dwc_ep.xfer_count = 0; ++ pcd_ep->dwc_ep.sent_zlp = 0; ++ pcd_ep->dwc_ep.total_len = 0; ++ pcd_ep->dwc_ep.desc_addr = 0; ++ pcd_ep->dwc_ep.dma_desc_addr = 0; ++ DWC_CIRCLEQ_INIT(&pcd_ep->queue); ++} ++ ++/** ++ * Initialize ep's ++ */ ++static void dwc_otg_pcd_reinit(dwc_otg_pcd_t * pcd) ++{ ++ int i; ++ uint32_t hwcfg1; ++ dwc_otg_pcd_ep_t *ep; ++ int in_ep_cntr, out_ep_cntr; ++ uint32_t num_in_eps = (GET_CORE_IF(pcd))->dev_if->num_in_eps; ++ uint32_t num_out_eps = (GET_CORE_IF(pcd))->dev_if->num_out_eps; ++ ++ /** ++ * Initialize the EP0 structure. ++ */ ++ ep = &pcd->ep0; ++ dwc_otg_pcd_init_ep(pcd, ep, 0, 0); ++ ++ in_ep_cntr = 0; ++ hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 3; ++ for (i = 1; in_ep_cntr < num_in_eps; i++) { ++ if ((hwcfg1 & 0x1) == 0) { ++ dwc_otg_pcd_ep_t *ep = &pcd->in_ep[in_ep_cntr]; ++ in_ep_cntr++; ++ /** ++ * @todo NGS: Add direction to EP, based on contents ++ * of HWCFG1. Need a copy of HWCFG1 in pcd structure? ++ * sprintf(";r ++ */ ++ dwc_otg_pcd_init_ep(pcd, ep, 1 /* IN */ , i); ++ ++ DWC_CIRCLEQ_INIT(&ep->queue); ++ } ++ hwcfg1 >>= 2; ++ } ++ ++ out_ep_cntr = 0; ++ hwcfg1 = (GET_CORE_IF(pcd))->hwcfg1.d32 >> 2; ++ for (i = 1; out_ep_cntr < num_out_eps; i++) { ++ if ((hwcfg1 & 0x1) == 0) { ++ dwc_otg_pcd_ep_t *ep = &pcd->out_ep[out_ep_cntr]; ++ out_ep_cntr++; ++ /** ++ * @todo NGS: Add direction to EP, based on contents ++ * of HWCFG1. Need a copy of HWCFG1 in pcd structure? ++ * sprintf(";r ++ */ ++ dwc_otg_pcd_init_ep(pcd, ep, 0 /* OUT */ , i); ++ DWC_CIRCLEQ_INIT(&ep->queue); ++ } ++ hwcfg1 >>= 2; ++ } ++ ++ pcd->ep0state = EP0_DISCONNECT; ++ pcd->ep0.dwc_ep.maxpacket = MAX_EP0_SIZE; ++ pcd->ep0.dwc_ep.type = DWC_OTG_EP_TYPE_CONTROL; ++} ++ ++/** ++ * This function is called when the SRP timer expires. The SRP should ++ * complete within 6 seconds. ++ */ ++static void srp_timeout(void *ptr) ++{ ++ gotgctl_data_t gotgctl; ++ dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr; ++ volatile uint32_t *addr = &core_if->core_global_regs->gotgctl; ++ ++ gotgctl.d32 = DWC_READ_REG32(addr); ++ ++ core_if->srp_timer_started = 0; ++ ++ if (core_if->adp_enable) { ++ if (gotgctl.b.bsesvld == 0) { ++ gpwrdn_data_t gpwrdn = {.d32 = 0 }; ++ DWC_PRINTF("SRP Timeout BSESSVLD = 0\n"); ++ /* Power off the core */ ++ if (core_if->power_down == 2) { ++ gpwrdn.b.pwrdnswtch = 1; ++ DWC_MODIFY_REG32(&core_if-> ++ core_global_regs->gpwrdn, ++ gpwrdn.d32, 0); ++ } ++ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.pmuintsel = 1; ++ gpwrdn.b.pmuactv = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, ++ gpwrdn.d32); ++ dwc_otg_adp_probe_start(core_if); ++ } else { ++ DWC_PRINTF("SRP Timeout BSESSVLD = 1\n"); ++ core_if->op_state = B_PERIPHERAL; ++ dwc_otg_core_init(core_if); ++ dwc_otg_enable_global_interrupts(core_if); ++ cil_pcd_start(core_if); ++ } ++ } ++ ++ if ((core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS) && ++ (core_if->core_params->i2c_enable)) { ++ DWC_PRINTF("SRP Timeout\n"); ++ ++ if ((core_if->srp_success) && (gotgctl.b.bsesvld)) { ++ if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup) { ++ core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p); ++ } ++ ++ /* Clear Session Request */ ++ gotgctl.d32 = 0; ++ gotgctl.b.sesreq = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gotgctl, ++ gotgctl.d32, 0); ++ ++ core_if->srp_success = 0; ++ } else { ++ __DWC_ERROR("Device not connected/responding\n"); ++ gotgctl.b.sesreq = 0; ++ DWC_WRITE_REG32(addr, gotgctl.d32); ++ } ++ } else if (gotgctl.b.sesreq) { ++ DWC_PRINTF("SRP Timeout\n"); ++ ++ __DWC_ERROR("Device not connected/responding\n"); ++ gotgctl.b.sesreq = 0; ++ DWC_WRITE_REG32(addr, gotgctl.d32); ++ } else { ++ DWC_PRINTF(" SRP GOTGCTL=%0x\n", gotgctl.d32); ++ } ++} ++ ++/** ++ * Tasklet ++ * ++ */ ++extern void start_next_request(dwc_otg_pcd_ep_t * ep); ++ ++static void start_xfer_tasklet_func(void *data) ++{ ++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data; ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ ++ int i; ++ depctl_data_t diepctl; ++ ++ DWC_DEBUGPL(DBG_PCDV, "Start xfer tasklet\n"); ++ ++ diepctl.d32 = DWC_READ_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl); ++ ++ if (pcd->ep0.queue_sof) { ++ pcd->ep0.queue_sof = 0; ++ start_next_request(&pcd->ep0); ++ // break; ++ } ++ ++ for (i = 0; i < core_if->dev_if->num_in_eps; i++) { ++ depctl_data_t diepctl; ++ diepctl.d32 = ++ DWC_READ_REG32(&core_if->dev_if->in_ep_regs[i]->diepctl); ++ ++ if (pcd->in_ep[i].queue_sof) { ++ pcd->in_ep[i].queue_sof = 0; ++ start_next_request(&pcd->in_ep[i]); ++ // break; ++ } ++ } ++ ++ return; ++} ++ ++/** ++ * This function initialized the PCD portion of the driver. ++ * ++ */ ++dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if) ++{ ++ dwc_otg_pcd_t *pcd = NULL; ++ dwc_otg_dev_if_t *dev_if; ++ int i; ++ ++ /* ++ * Allocate PCD structure ++ */ ++ pcd = DWC_ALLOC(sizeof(dwc_otg_pcd_t)); ++ ++ if (pcd == NULL) { ++ return NULL; ++ } ++ ++ pcd->lock = DWC_SPINLOCK_ALLOC(); ++ DWC_DEBUGPL(DBG_HCDV, "Init of PCD %p given core_if %p\n", ++ pcd, core_if);//GRAYG ++ if (!pcd->lock) { ++ DWC_ERROR("Could not allocate lock for pcd"); ++ DWC_FREE(pcd); ++ return NULL; ++ } ++ /* Set core_if's lock pointer to hcd->lock */ ++ core_if->lock = pcd->lock; ++ pcd->core_if = core_if; ++ ++ dev_if = core_if->dev_if; ++ dev_if->isoc_ep = NULL; ++ ++ if (core_if->hwcfg4.b.ded_fifo_en) { ++ DWC_PRINTF("Dedicated Tx FIFOs mode\n"); ++ } else { ++ DWC_PRINTF("Shared Tx FIFO mode\n"); ++ } ++ ++ /* ++ * Initialized the Core for Device mode here if there is nod ADP support. ++ * Otherwise it will be done later in dwc_otg_adp_start routine. ++ */ ++ if (dwc_otg_is_device_mode(core_if) /*&& !core_if->adp_enable*/) { ++ dwc_otg_core_dev_init(core_if); ++ } ++ ++ /* ++ * Register the PCD Callbacks. ++ */ ++ dwc_otg_cil_register_pcd_callbacks(core_if, &pcd_callbacks, pcd); ++ ++ /* ++ * Initialize the DMA buffer for SETUP packets ++ */ ++ if (GET_CORE_IF(pcd)->dma_enable) { ++ pcd->setup_pkt = ++ DWC_DMA_ALLOC(sizeof(*pcd->setup_pkt) * 5, ++ &pcd->setup_pkt_dma_handle); ++ if (pcd->setup_pkt == NULL) { ++ DWC_FREE(pcd); ++ return NULL; ++ } ++ ++ pcd->status_buf = ++ DWC_DMA_ALLOC(sizeof(uint16_t), ++ &pcd->status_buf_dma_handle); ++ if (pcd->status_buf == NULL) { ++ DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, ++ pcd->setup_pkt, pcd->setup_pkt_dma_handle); ++ DWC_FREE(pcd); ++ return NULL; ++ } ++ ++ if (GET_CORE_IF(pcd)->dma_desc_enable) { ++ dev_if->setup_desc_addr[0] = ++ dwc_otg_ep_alloc_desc_chain ++ (&dev_if->dma_setup_desc_addr[0], 1); ++ dev_if->setup_desc_addr[1] = ++ dwc_otg_ep_alloc_desc_chain ++ (&dev_if->dma_setup_desc_addr[1], 1); ++ dev_if->in_desc_addr = ++ dwc_otg_ep_alloc_desc_chain ++ (&dev_if->dma_in_desc_addr, 1); ++ dev_if->out_desc_addr = ++ dwc_otg_ep_alloc_desc_chain ++ (&dev_if->dma_out_desc_addr, 1); ++ pcd->data_terminated = 0; ++ ++ if (dev_if->setup_desc_addr[0] == 0 ++ || dev_if->setup_desc_addr[1] == 0 ++ || dev_if->in_desc_addr == 0 ++ || dev_if->out_desc_addr == 0) { ++ ++ if (dev_if->out_desc_addr) ++ dwc_otg_ep_free_desc_chain ++ (dev_if->out_desc_addr, ++ dev_if->dma_out_desc_addr, 1); ++ if (dev_if->in_desc_addr) ++ dwc_otg_ep_free_desc_chain ++ (dev_if->in_desc_addr, ++ dev_if->dma_in_desc_addr, 1); ++ if (dev_if->setup_desc_addr[1]) ++ dwc_otg_ep_free_desc_chain ++ (dev_if->setup_desc_addr[1], ++ dev_if->dma_setup_desc_addr[1], 1); ++ if (dev_if->setup_desc_addr[0]) ++ dwc_otg_ep_free_desc_chain ++ (dev_if->setup_desc_addr[0], ++ dev_if->dma_setup_desc_addr[0], 1); ++ ++ DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, ++ pcd->setup_pkt, ++ pcd->setup_pkt_dma_handle); ++ DWC_DMA_FREE(sizeof(*pcd->status_buf), ++ pcd->status_buf, ++ pcd->status_buf_dma_handle); ++ ++ DWC_FREE(pcd); ++ ++ return NULL; ++ } ++ } ++ } else { ++ pcd->setup_pkt = DWC_ALLOC(sizeof(*pcd->setup_pkt) * 5); ++ if (pcd->setup_pkt == NULL) { ++ DWC_FREE(pcd); ++ return NULL; ++ } ++ ++ pcd->status_buf = DWC_ALLOC(sizeof(uint16_t)); ++ if (pcd->status_buf == NULL) { ++ DWC_FREE(pcd->setup_pkt); ++ DWC_FREE(pcd); ++ return NULL; ++ } ++ } ++ ++ dwc_otg_pcd_reinit(pcd); ++ ++ /* Allocate the cfi object for the PCD */ ++#ifdef DWC_UTE_CFI ++ pcd->cfi = DWC_ALLOC(sizeof(cfiobject_t)); ++ if (NULL == pcd->cfi) ++ goto fail; ++ if (init_cfi(pcd->cfi)) { ++ CFI_INFO("%s: Failed to init the CFI object\n", __func__); ++ goto fail; ++ } ++#endif ++ ++ /* Initialize tasklets */ ++ pcd->start_xfer_tasklet = DWC_TASK_ALLOC("xfer_tasklet", ++ start_xfer_tasklet_func, pcd); ++ pcd->test_mode_tasklet = DWC_TASK_ALLOC("test_mode_tasklet", ++ do_test_mode, pcd); ++ ++ /* Initialize SRP timer */ ++ core_if->srp_timer = DWC_TIMER_ALLOC("SRP TIMER", srp_timeout, core_if); ++ ++ if (core_if->core_params->dev_out_nak) { ++ /** ++ * Initialize xfer timeout timer. Implemented for ++ * 2.93a feature "Device DDMA OUT NAK Enhancement" ++ */ ++ for(i = 0; i < MAX_EPS_CHANNELS; i++) { ++ pcd->core_if->ep_xfer_timer[i] = ++ DWC_TIMER_ALLOC("ep timer", ep_xfer_timeout, ++ &pcd->core_if->ep_xfer_info[i]); ++ } ++ } ++ ++ return pcd; ++#ifdef DWC_UTE_CFI ++fail: ++#endif ++ if (pcd->setup_pkt) ++ DWC_FREE(pcd->setup_pkt); ++ if (pcd->status_buf) ++ DWC_FREE(pcd->status_buf); ++#ifdef DWC_UTE_CFI ++ if (pcd->cfi) ++ DWC_FREE(pcd->cfi); ++#endif ++ if (pcd) ++ DWC_FREE(pcd); ++ return NULL; ++ ++} ++ ++/** ++ * Remove PCD specific data ++ */ ++void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if; ++ int i; ++ if (pcd->core_if->core_params->dev_out_nak) { ++ for (i = 0; i < MAX_EPS_CHANNELS; i++) { ++ DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[i]); ++ pcd->core_if->ep_xfer_info[i].state = 0; ++ } ++ } ++ ++ if (GET_CORE_IF(pcd)->dma_enable) { ++ DWC_DMA_FREE(sizeof(*pcd->setup_pkt) * 5, pcd->setup_pkt, ++ pcd->setup_pkt_dma_handle); ++ DWC_DMA_FREE(sizeof(uint16_t), pcd->status_buf, ++ pcd->status_buf_dma_handle); ++ if (GET_CORE_IF(pcd)->dma_desc_enable) { ++ dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[0], ++ dev_if->dma_setup_desc_addr ++ [0], 1); ++ dwc_otg_ep_free_desc_chain(dev_if->setup_desc_addr[1], ++ dev_if->dma_setup_desc_addr ++ [1], 1); ++ dwc_otg_ep_free_desc_chain(dev_if->in_desc_addr, ++ dev_if->dma_in_desc_addr, 1); ++ dwc_otg_ep_free_desc_chain(dev_if->out_desc_addr, ++ dev_if->dma_out_desc_addr, ++ 1); ++ } ++ } else { ++ DWC_FREE(pcd->setup_pkt); ++ DWC_FREE(pcd->status_buf); ++ } ++ DWC_SPINLOCK_FREE(pcd->lock); ++ /* Set core_if's lock pointer to NULL */ ++ pcd->core_if->lock = NULL; ++ ++ DWC_TASK_FREE(pcd->start_xfer_tasklet); ++ DWC_TASK_FREE(pcd->test_mode_tasklet); ++ if (pcd->core_if->core_params->dev_out_nak) { ++ for (i = 0; i < MAX_EPS_CHANNELS; i++) { ++ if (pcd->core_if->ep_xfer_timer[i]) { ++ DWC_TIMER_FREE(pcd->core_if->ep_xfer_timer[i]); ++ } ++ } ++ } ++ ++/* Release the CFI object's dynamic memory */ ++#ifdef DWC_UTE_CFI ++ if (pcd->cfi->ops.release) { ++ pcd->cfi->ops.release(pcd->cfi); ++ } ++#endif ++ ++ DWC_FREE(pcd); ++} ++ ++/** ++ * Returns whether registered pcd is dual speed or not ++ */ ++uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ ++ if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) || ++ ((core_if->hwcfg2.b.hs_phy_type == 2) && ++ (core_if->hwcfg2.b.fs_phy_type == 1) && ++ (core_if->core_params->ulpi_fs_ls))) { ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/** ++ * Returns whether registered pcd is OTG capable or not ++ */ ++uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ gusbcfg_data_t usbcfg = {.d32 = 0 }; ++ ++ usbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gusbcfg); ++ if (!usbcfg.b.srpcap || !usbcfg.b.hnpcap) { ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/** ++ * This function assigns periodic Tx FIFO to an periodic EP ++ * in shared Tx FIFO mode ++ */ ++static uint32_t assign_tx_fifo(dwc_otg_core_if_t * core_if) ++{ ++ uint32_t TxMsk = 1; ++ int i; ++ ++ for (i = 0; i < core_if->hwcfg4.b.num_in_eps; ++i) { ++ if ((TxMsk & core_if->tx_msk) == 0) { ++ core_if->tx_msk |= TxMsk; ++ return i + 1; ++ } ++ TxMsk <<= 1; ++ } ++ return 0; ++} ++ ++/** ++ * This function assigns periodic Tx FIFO to an periodic EP ++ * in shared Tx FIFO mode ++ */ ++static uint32_t assign_perio_tx_fifo(dwc_otg_core_if_t * core_if) ++{ ++ uint32_t PerTxMsk = 1; ++ int i; ++ for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; ++i) { ++ if ((PerTxMsk & core_if->p_tx_msk) == 0) { ++ core_if->p_tx_msk |= PerTxMsk; ++ return i + 1; ++ } ++ PerTxMsk <<= 1; ++ } ++ return 0; ++} ++ ++/** ++ * This function releases periodic Tx FIFO ++ * in shared Tx FIFO mode ++ */ ++static void release_perio_tx_fifo(dwc_otg_core_if_t * core_if, ++ uint32_t fifo_num) ++{ ++ core_if->p_tx_msk = ++ (core_if->p_tx_msk & (1 << (fifo_num - 1))) ^ core_if->p_tx_msk; ++} ++ ++/** ++ * This function releases periodic Tx FIFO ++ * in shared Tx FIFO mode ++ */ ++static void release_tx_fifo(dwc_otg_core_if_t * core_if, uint32_t fifo_num) ++{ ++ core_if->tx_msk = ++ (core_if->tx_msk & (1 << (fifo_num - 1))) ^ core_if->tx_msk; ++} ++ ++/** ++ * This function is being called from gadget ++ * to enable PCD endpoint. ++ */ ++int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd, ++ const uint8_t * ep_desc, void *usb_ep) ++{ ++ int num, dir; ++ dwc_otg_pcd_ep_t *ep = NULL; ++ const usb_endpoint_descriptor_t *desc; ++ dwc_irqflags_t flags; ++ fifosize_data_t dptxfsiz = {.d32 = 0 }; ++ gdfifocfg_data_t gdfifocfg = {.d32 = 0 }; ++ gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 }; ++ int retval = 0; ++ int i, epcount; ++ ++ desc = (const usb_endpoint_descriptor_t *)ep_desc; ++ ++ if (!desc) { ++ pcd->ep0.priv = usb_ep; ++ ep = &pcd->ep0; ++ retval = -DWC_E_INVALID; ++ goto out; ++ } ++ ++ num = UE_GET_ADDR(desc->bEndpointAddress); ++ dir = UE_GET_DIR(desc->bEndpointAddress); ++ ++ if (!desc->wMaxPacketSize) { ++ DWC_WARN("bad maxpacketsize\n"); ++ retval = -DWC_E_INVALID; ++ goto out; ++ } ++ ++ if (dir == UE_DIR_IN) { ++ epcount = pcd->core_if->dev_if->num_in_eps; ++ for (i = 0; i < epcount; i++) { ++ if (num == pcd->in_ep[i].dwc_ep.num) { ++ ep = &pcd->in_ep[i]; ++ break; ++ } ++ } ++ } else { ++ epcount = pcd->core_if->dev_if->num_out_eps; ++ for (i = 0; i < epcount; i++) { ++ if (num == pcd->out_ep[i].dwc_ep.num) { ++ ep = &pcd->out_ep[i]; ++ break; ++ } ++ } ++ } ++ ++ if (!ep) { ++ DWC_WARN("bad address\n"); ++ retval = -DWC_E_INVALID; ++ goto out; ++ } ++ ++ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++ ++ ep->desc = desc; ++ ep->priv = usb_ep; ++ ++ /* ++ * Activate the EP ++ */ ++ ep->stopped = 0; ++ ++ ep->dwc_ep.is_in = (dir == UE_DIR_IN); ++ ep->dwc_ep.maxpacket = UGETW(desc->wMaxPacketSize); ++ ++ ep->dwc_ep.type = desc->bmAttributes & UE_XFERTYPE; ++ ++ if (ep->dwc_ep.is_in) { ++ if (!GET_CORE_IF(pcd)->en_multiple_tx_fifo) { ++ ep->dwc_ep.tx_fifo_num = 0; ++ ++ if (ep->dwc_ep.type == UE_ISOCHRONOUS) { ++ /* ++ * if ISOC EP then assign a Periodic Tx FIFO. ++ */ ++ ep->dwc_ep.tx_fifo_num = ++ assign_perio_tx_fifo(GET_CORE_IF(pcd)); ++ } ++ } else { ++ /* ++ * if Dedicated FIFOs mode is on then assign a Tx FIFO. ++ */ ++ ep->dwc_ep.tx_fifo_num = ++ assign_tx_fifo(GET_CORE_IF(pcd)); ++ } ++ ++ /* Calculating EP info controller base address */ ++ if (ep->dwc_ep.tx_fifo_num ++ && GET_CORE_IF(pcd)->en_multiple_tx_fifo) { ++ gdfifocfg.d32 = ++ DWC_READ_REG32(&GET_CORE_IF(pcd)-> ++ core_global_regs->gdfifocfg); ++ gdfifocfgbase.d32 = gdfifocfg.d32 >> 16; ++ dptxfsiz.d32 = ++ (DWC_READ_REG32 ++ (&GET_CORE_IF(pcd)->core_global_regs-> ++ dtxfsiz[ep->dwc_ep.tx_fifo_num - 1]) >> 16); ++ gdfifocfg.b.epinfobase = ++ gdfifocfgbase.d32 + dptxfsiz.d32; ++ if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) { ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)-> ++ core_global_regs->gdfifocfg, ++ gdfifocfg.d32); ++ } ++ } ++ } ++ /* Set initial data PID. */ ++ if (ep->dwc_ep.type == UE_BULK) { ++ ep->dwc_ep.data_pid_start = 0; ++ } ++ ++ /* Alloc DMA Descriptors */ ++ if (GET_CORE_IF(pcd)->dma_desc_enable) { ++#ifndef DWC_UTE_PER_IO ++ if (ep->dwc_ep.type != UE_ISOCHRONOUS) { ++#endif ++ ep->dwc_ep.desc_addr = ++ dwc_otg_ep_alloc_desc_chain(&ep-> ++ dwc_ep.dma_desc_addr, ++ MAX_DMA_DESC_CNT); ++ if (!ep->dwc_ep.desc_addr) { ++ DWC_WARN("%s, can't allocate DMA descriptor\n", ++ __func__); ++ retval = -DWC_E_SHUTDOWN; ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ goto out; ++ } ++#ifndef DWC_UTE_PER_IO ++ } ++#endif ++ } ++ ++ DWC_DEBUGPL(DBG_PCD, "Activate %s: type=%d, mps=%d desc=%p\n", ++ (ep->dwc_ep.is_in ? "IN" : "OUT"), ++ ep->dwc_ep.type, ep->dwc_ep.maxpacket, ep->desc); ++#ifdef DWC_UTE_PER_IO ++ ep->dwc_ep.xiso_bInterval = 1 << (ep->desc->bInterval - 1); ++#endif ++ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) { ++ ep->dwc_ep.bInterval = 1 << (ep->desc->bInterval - 1); ++ ep->dwc_ep.frame_num = 0xFFFFFFFF; ++ } ++ ++ dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep); ++ ++#ifdef DWC_UTE_CFI ++ if (pcd->cfi->ops.ep_enable) { ++ pcd->cfi->ops.ep_enable(pcd->cfi, pcd, ep); ++ } ++#endif ++ ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ ++out: ++ return retval; ++} ++ ++/** ++ * This function is being called from gadget ++ * to disable PCD endpoint. ++ */ ++int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle) ++{ ++ dwc_otg_pcd_ep_t *ep; ++ dwc_irqflags_t flags; ++ dwc_otg_dev_dma_desc_t *desc_addr; ++ dwc_dma_t dma_desc_addr; ++ gdfifocfg_data_t gdfifocfgbase = {.d32 = 0 }; ++ gdfifocfg_data_t gdfifocfg = {.d32 = 0 }; ++ fifosize_data_t dptxfsiz = {.d32 = 0 }; ++ ++ ep = get_ep_from_handle(pcd, ep_handle); ++ ++ if (!ep || !ep->desc) { ++ DWC_DEBUGPL(DBG_PCD, "bad ep address\n"); ++ return -DWC_E_INVALID; ++ } ++ ++ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++ ++ dwc_otg_request_nuke(ep); ++ ++ dwc_otg_ep_deactivate(GET_CORE_IF(pcd), &ep->dwc_ep); ++ if (pcd->core_if->core_params->dev_out_nak) { ++ DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[ep->dwc_ep.num]); ++ pcd->core_if->ep_xfer_info[ep->dwc_ep.num].state = 0; ++ } ++ ep->desc = NULL; ++ ep->stopped = 1; ++ ++ gdfifocfg.d32 = ++ DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg); ++ gdfifocfgbase.d32 = gdfifocfg.d32 >> 16; ++ ++ if (ep->dwc_ep.is_in) { ++ if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) { ++ /* Flush the Tx FIFO */ ++ dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), ++ ep->dwc_ep.tx_fifo_num); ++ } ++ release_perio_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num); ++ release_tx_fifo(GET_CORE_IF(pcd), ep->dwc_ep.tx_fifo_num); ++ if (GET_CORE_IF(pcd)->en_multiple_tx_fifo) { ++ /* Decreasing EPinfo Base Addr */ ++ dptxfsiz.d32 = ++ (DWC_READ_REG32 ++ (&GET_CORE_IF(pcd)-> ++ core_global_regs->dtxfsiz[ep->dwc_ep.tx_fifo_num-1]) >> 16); ++ gdfifocfg.b.epinfobase = gdfifocfgbase.d32 - dptxfsiz.d32; ++ if (GET_CORE_IF(pcd)->snpsid <= OTG_CORE_REV_2_94a) { ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gdfifocfg, ++ gdfifocfg.d32); ++ } ++ } ++ } ++ ++ /* Free DMA Descriptors */ ++ if (GET_CORE_IF(pcd)->dma_desc_enable) { ++ if (ep->dwc_ep.type != UE_ISOCHRONOUS) { ++ desc_addr = ep->dwc_ep.desc_addr; ++ dma_desc_addr = ep->dwc_ep.dma_desc_addr; ++ ++ /* Cannot call dma_free_coherent() with IRQs disabled */ ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ dwc_otg_ep_free_desc_chain(desc_addr, dma_desc_addr, ++ MAX_DMA_DESC_CNT); ++ ++ goto out_unlocked; ++ } ++ } ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ ++out_unlocked: ++ DWC_DEBUGPL(DBG_PCD, "%d %s disabled\n", ep->dwc_ep.num, ++ ep->dwc_ep.is_in ? "IN" : "OUT"); ++ return 0; ++ ++} ++ ++/******************************************************************************/ ++#ifdef DWC_UTE_PER_IO ++ ++/** ++ * Free the request and its extended parts ++ * ++ */ ++void dwc_pcd_xiso_ereq_free(dwc_otg_pcd_ep_t * ep, dwc_otg_pcd_request_t * req) ++{ ++ DWC_FREE(req->ext_req.per_io_frame_descs); ++ DWC_FREE(req); ++} ++ ++/** ++ * Start the next request in the endpoint's queue. ++ * ++ */ ++int dwc_otg_pcd_xiso_start_next_request(dwc_otg_pcd_t * pcd, ++ dwc_otg_pcd_ep_t * ep) ++{ ++ int i; ++ dwc_otg_pcd_request_t *req = NULL; ++ dwc_ep_t *dwcep = NULL; ++ struct dwc_iso_xreq_port *ereq = NULL; ++ struct dwc_iso_pkt_desc_port *ddesc_iso; ++ uint16_t nat; ++ depctl_data_t diepctl; ++ ++ dwcep = &ep->dwc_ep; ++ ++ if (dwcep->xiso_active_xfers > 0) { ++#if 0 //Disable this to decrease s/w overhead that is crucial for Isoc transfers ++ DWC_WARN("There are currently active transfers for EP%d \ ++ (active=%d; queued=%d)", dwcep->num, dwcep->xiso_active_xfers, ++ dwcep->xiso_queued_xfers); ++#endif ++ return 0; ++ } ++ ++ nat = UGETW(ep->desc->wMaxPacketSize); ++ nat = (nat >> 11) & 0x03; ++ ++ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ req = DWC_CIRCLEQ_FIRST(&ep->queue); ++ ereq = &req->ext_req; ++ ep->stopped = 0; ++ ++ /* Get the frame number */ ++ dwcep->xiso_frame_num = ++ dwc_otg_get_frame_number(GET_CORE_IF(pcd)); ++ DWC_DEBUG("FRM_NUM=%d", dwcep->xiso_frame_num); ++ ++ ddesc_iso = ereq->per_io_frame_descs; ++ ++ if (dwcep->is_in) { ++ /* Setup DMA Descriptor chain for IN Isoc request */ ++ for (i = 0; i < ereq->pio_pkt_count; i++) { ++ //if ((i % (nat + 1)) == 0) ++ if ( i > 0 ) ++ dwcep->xiso_frame_num = ++ (dwcep->xiso_bInterval + ++ dwcep->xiso_frame_num) & 0x3FFF; ++ dwcep->desc_addr[i].buf = ++ req->dma + ddesc_iso[i].offset; ++ dwcep->desc_addr[i].status.b_iso_in.txbytes = ++ ddesc_iso[i].length; ++ dwcep->desc_addr[i].status.b_iso_in.framenum = ++ dwcep->xiso_frame_num; ++ dwcep->desc_addr[i].status.b_iso_in.bs = ++ BS_HOST_READY; ++ dwcep->desc_addr[i].status.b_iso_in.txsts = 0; ++ dwcep->desc_addr[i].status.b_iso_in.sp = ++ (ddesc_iso[i].length % ++ dwcep->maxpacket) ? 1 : 0; ++ dwcep->desc_addr[i].status.b_iso_in.ioc = 0; ++ dwcep->desc_addr[i].status.b_iso_in.pid = nat + 1; ++ dwcep->desc_addr[i].status.b_iso_in.l = 0; ++ ++ /* Process the last descriptor */ ++ if (i == ereq->pio_pkt_count - 1) { ++ dwcep->desc_addr[i].status.b_iso_in.ioc = 1; ++ dwcep->desc_addr[i].status.b_iso_in.l = 1; ++ } ++ } ++ ++ /* Setup and start the transfer for this endpoint */ ++ dwcep->xiso_active_xfers++; ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->dev_if-> ++ in_ep_regs[dwcep->num]->diepdma, ++ dwcep->dma_desc_addr); ++ diepctl.d32 = 0; ++ diepctl.b.epena = 1; ++ diepctl.b.cnak = 1; ++ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->dev_if-> ++ in_ep_regs[dwcep->num]->diepctl, 0, ++ diepctl.d32); ++ } else { ++ /* Setup DMA Descriptor chain for OUT Isoc request */ ++ for (i = 0; i < ereq->pio_pkt_count; i++) { ++ //if ((i % (nat + 1)) == 0) ++ dwcep->xiso_frame_num = (dwcep->xiso_bInterval + ++ dwcep->xiso_frame_num) & 0x3FFF; ++ dwcep->desc_addr[i].buf = ++ req->dma + ddesc_iso[i].offset; ++ dwcep->desc_addr[i].status.b_iso_out.rxbytes = ++ ddesc_iso[i].length; ++ dwcep->desc_addr[i].status.b_iso_out.framenum = ++ dwcep->xiso_frame_num; ++ dwcep->desc_addr[i].status.b_iso_out.bs = ++ BS_HOST_READY; ++ dwcep->desc_addr[i].status.b_iso_out.rxsts = 0; ++ dwcep->desc_addr[i].status.b_iso_out.sp = ++ (ddesc_iso[i].length % ++ dwcep->maxpacket) ? 1 : 0; ++ dwcep->desc_addr[i].status.b_iso_out.ioc = 0; ++ dwcep->desc_addr[i].status.b_iso_out.pid = nat + 1; ++ dwcep->desc_addr[i].status.b_iso_out.l = 0; ++ ++ /* Process the last descriptor */ ++ if (i == ereq->pio_pkt_count - 1) { ++ dwcep->desc_addr[i].status.b_iso_out.ioc = 1; ++ dwcep->desc_addr[i].status.b_iso_out.l = 1; ++ } ++ } ++ ++ /* Setup and start the transfer for this endpoint */ ++ dwcep->xiso_active_xfers++; ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)-> ++ dev_if->out_ep_regs[dwcep->num]-> ++ doepdma, dwcep->dma_desc_addr); ++ diepctl.d32 = 0; ++ diepctl.b.epena = 1; ++ diepctl.b.cnak = 1; ++ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)-> ++ dev_if->out_ep_regs[dwcep->num]-> ++ doepctl, 0, diepctl.d32); ++ } ++ ++ } else { ++ ep->stopped = 1; ++ } ++ ++ return 0; ++} ++ ++/** ++ * - Remove the request from the queue ++ */ ++void complete_xiso_ep(dwc_otg_pcd_ep_t * ep) ++{ ++ dwc_otg_pcd_request_t *req = NULL; ++ struct dwc_iso_xreq_port *ereq = NULL; ++ struct dwc_iso_pkt_desc_port *ddesc_iso = NULL; ++ dwc_ep_t *dwcep = NULL; ++ int i; ++ ++ //DWC_DEBUG(); ++ dwcep = &ep->dwc_ep; ++ ++ /* Get the first pending request from the queue */ ++ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ req = DWC_CIRCLEQ_FIRST(&ep->queue); ++ if (!req) { ++ DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep); ++ return; ++ } ++ dwcep->xiso_active_xfers--; ++ dwcep->xiso_queued_xfers--; ++ /* Remove this request from the queue */ ++ DWC_CIRCLEQ_REMOVE_INIT(&ep->queue, req, queue_entry); ++ } else { ++ DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep); ++ return; ++ } ++ ++ ep->stopped = 1; ++ ereq = &req->ext_req; ++ ddesc_iso = ereq->per_io_frame_descs; ++ ++ if (dwcep->xiso_active_xfers < 0) { ++ DWC_WARN("EP#%d (xiso_active_xfers=%d)", dwcep->num, ++ dwcep->xiso_active_xfers); ++ } ++ ++ /* Fill the Isoc descs of portable extended req from dma descriptors */ ++ for (i = 0; i < ereq->pio_pkt_count; i++) { ++ if (dwcep->is_in) { /* IN endpoints */ ++ ddesc_iso[i].actual_length = ddesc_iso[i].length - ++ dwcep->desc_addr[i].status.b_iso_in.txbytes; ++ ddesc_iso[i].status = ++ dwcep->desc_addr[i].status.b_iso_in.txsts; ++ } else { /* OUT endpoints */ ++ ddesc_iso[i].actual_length = ddesc_iso[i].length - ++ dwcep->desc_addr[i].status.b_iso_out.rxbytes; ++ ddesc_iso[i].status = ++ dwcep->desc_addr[i].status.b_iso_out.rxsts; ++ } ++ } ++ ++ DWC_SPINUNLOCK(ep->pcd->lock); ++ ++ /* Call the completion function in the non-portable logic */ ++ ep->pcd->fops->xisoc_complete(ep->pcd, ep->priv, req->priv, 0, ++ &req->ext_req); ++ ++ DWC_SPINLOCK(ep->pcd->lock); ++ ++ /* Free the request - specific freeing needed for extended request object */ ++ dwc_pcd_xiso_ereq_free(ep, req); ++ ++ /* Start the next request */ ++ dwc_otg_pcd_xiso_start_next_request(ep->pcd, ep); ++ ++ return; ++} ++ ++/** ++ * Create and initialize the Isoc pkt descriptors of the extended request. ++ * ++ */ ++static int dwc_otg_pcd_xiso_create_pkt_descs(dwc_otg_pcd_request_t * req, ++ void *ereq_nonport, ++ int atomic_alloc) ++{ ++ struct dwc_iso_xreq_port *ereq = NULL; ++ struct dwc_iso_xreq_port *req_mapped = NULL; ++ struct dwc_iso_pkt_desc_port *ipds = NULL; /* To be created in this function */ ++ uint32_t pkt_count; ++ int i; ++ ++ ereq = &req->ext_req; ++ req_mapped = (struct dwc_iso_xreq_port *)ereq_nonport; ++ pkt_count = req_mapped->pio_pkt_count; ++ ++ /* Create the isoc descs */ ++ if (atomic_alloc) { ++ ipds = DWC_ALLOC_ATOMIC(sizeof(*ipds) * pkt_count); ++ } else { ++ ipds = DWC_ALLOC(sizeof(*ipds) * pkt_count); ++ } ++ ++ if (!ipds) { ++ DWC_ERROR("Failed to allocate isoc descriptors"); ++ return -DWC_E_NO_MEMORY; ++ } ++ ++ /* Initialize the extended request fields */ ++ ereq->per_io_frame_descs = ipds; ++ ereq->error_count = 0; ++ ereq->pio_alloc_pkt_count = pkt_count; ++ ereq->pio_pkt_count = pkt_count; ++ ereq->tr_sub_flags = req_mapped->tr_sub_flags; ++ ++ /* Init the Isoc descriptors */ ++ for (i = 0; i < pkt_count; i++) { ++ ipds[i].length = req_mapped->per_io_frame_descs[i].length; ++ ipds[i].offset = req_mapped->per_io_frame_descs[i].offset; ++ ipds[i].status = req_mapped->per_io_frame_descs[i].status; /* 0 */ ++ ipds[i].actual_length = ++ req_mapped->per_io_frame_descs[i].actual_length; ++ } ++ ++ return 0; ++} ++ ++static void prn_ext_request(struct dwc_iso_xreq_port *ereq) ++{ ++ struct dwc_iso_pkt_desc_port *xfd = NULL; ++ int i; ++ ++ DWC_DEBUG("per_io_frame_descs=%p", ereq->per_io_frame_descs); ++ DWC_DEBUG("tr_sub_flags=%d", ereq->tr_sub_flags); ++ DWC_DEBUG("error_count=%d", ereq->error_count); ++ DWC_DEBUG("pio_alloc_pkt_count=%d", ereq->pio_alloc_pkt_count); ++ DWC_DEBUG("pio_pkt_count=%d", ereq->pio_pkt_count); ++ DWC_DEBUG("res=%d", ereq->res); ++ ++ for (i = 0; i < ereq->pio_pkt_count; i++) { ++ xfd = &ereq->per_io_frame_descs[0]; ++ DWC_DEBUG("FD #%d", i); ++ ++ DWC_DEBUG("xfd->actual_length=%d", xfd->actual_length); ++ DWC_DEBUG("xfd->length=%d", xfd->length); ++ DWC_DEBUG("xfd->offset=%d", xfd->offset); ++ DWC_DEBUG("xfd->status=%d", xfd->status); ++ } ++} ++ ++/** ++ * ++ */ ++int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle, ++ uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen, ++ int zero, void *req_handle, int atomic_alloc, ++ void *ereq_nonport) ++{ ++ dwc_otg_pcd_request_t *req = NULL; ++ dwc_otg_pcd_ep_t *ep; ++ dwc_irqflags_t flags; ++ int res; ++ ++ ep = get_ep_from_handle(pcd, ep_handle); ++ if (!ep) { ++ DWC_WARN("bad ep\n"); ++ return -DWC_E_INVALID; ++ } ++ ++ /* We support this extension only for DDMA mode */ ++ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ++ if (!GET_CORE_IF(pcd)->dma_desc_enable) ++ return -DWC_E_INVALID; ++ ++ /* Create a dwc_otg_pcd_request_t object */ ++ if (atomic_alloc) { ++ req = DWC_ALLOC_ATOMIC(sizeof(*req)); ++ } else { ++ req = DWC_ALLOC(sizeof(*req)); ++ } ++ ++ if (!req) { ++ return -DWC_E_NO_MEMORY; ++ } ++ ++ /* Create the Isoc descs for this request which shall be the exact match ++ * of the structure sent to us from the non-portable logic */ ++ res = ++ dwc_otg_pcd_xiso_create_pkt_descs(req, ereq_nonport, atomic_alloc); ++ if (res) { ++ DWC_WARN("Failed to init the Isoc descriptors"); ++ DWC_FREE(req); ++ return res; ++ } ++ ++ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++ ++ DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry); ++ req->buf = buf; ++ req->dma = dma_buf; ++ req->length = buflen; ++ req->sent_zlp = zero; ++ req->priv = req_handle; ++ ++ //DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++ ep->dwc_ep.dma_addr = dma_buf; ++ ep->dwc_ep.start_xfer_buff = buf; ++ ep->dwc_ep.xfer_buff = buf; ++ ep->dwc_ep.xfer_len = 0; ++ ep->dwc_ep.xfer_count = 0; ++ ep->dwc_ep.sent_zlp = 0; ++ ep->dwc_ep.total_len = buflen; ++ ++ /* Add this request to the tail */ ++ DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry); ++ ep->dwc_ep.xiso_queued_xfers++; ++ ++//DWC_DEBUG("CP_0"); ++//DWC_DEBUG("req->ext_req.tr_sub_flags=%d", req->ext_req.tr_sub_flags); ++//prn_ext_request((struct dwc_iso_xreq_port *) ereq_nonport); ++//prn_ext_request(&req->ext_req); ++ ++ //DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ ++ /* If the req->status == ASAP then check if there is any active transfer ++ * for this endpoint. If no active transfers, then get the first entry ++ * from the queue and start that transfer ++ */ ++ if (req->ext_req.tr_sub_flags == DWC_EREQ_TF_ASAP) { ++ res = dwc_otg_pcd_xiso_start_next_request(pcd, ep); ++ if (res) { ++ DWC_WARN("Failed to start the next Isoc transfer"); ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ DWC_FREE(req); ++ return res; ++ } ++ } ++ ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ return 0; ++} ++ ++#endif ++/* END ifdef DWC_UTE_PER_IO ***************************************************/ ++int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle, ++ uint8_t * buf, dwc_dma_t dma_buf, uint32_t buflen, ++ int zero, void *req_handle, int atomic_alloc) ++{ ++ dwc_irqflags_t flags; ++ dwc_otg_pcd_request_t *req; ++ dwc_otg_pcd_ep_t *ep; ++ uint32_t max_transfer; ++ ++ ep = get_ep_from_handle(pcd, ep_handle); ++ if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) { ++ DWC_WARN("bad ep\n"); ++ return -DWC_E_INVALID; ++ } ++ ++ if (atomic_alloc) { ++ req = DWC_ALLOC_ATOMIC(sizeof(*req)); ++ } else { ++ req = DWC_ALLOC(sizeof(*req)); ++ } ++ ++ if (!req) { ++ return -DWC_E_NO_MEMORY; ++ } ++ DWC_CIRCLEQ_INIT_ENTRY(req, queue_entry); ++ if (!GET_CORE_IF(pcd)->core_params->opt) { ++ if (ep->dwc_ep.num != 0) { ++ DWC_ERROR("queue req %p, len %d buf %p\n", ++ req_handle, buflen, buf); ++ } ++ } ++ ++ req->buf = buf; ++ req->dma = dma_buf; ++ req->length = buflen; ++ req->sent_zlp = zero; ++ req->priv = req_handle; ++ req->dw_align_buf = NULL; ++ if ((dma_buf & 0x3) && GET_CORE_IF(pcd)->dma_enable ++ && !GET_CORE_IF(pcd)->dma_desc_enable) ++ req->dw_align_buf = DWC_DMA_ALLOC(buflen, ++ &req->dw_align_buf_dma); ++ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++ ++ /* ++ * After adding request to the queue for IN ISOC wait for In Token Received ++ * when TX FIFO is empty interrupt and for OUT ISOC wait for OUT Token ++ * Received when EP is disabled interrupt to obtain starting microframe ++ * (odd/even) start transfer ++ */ ++ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) { ++ if (req != 0) { ++ depctl_data_t depctl = {.d32 = ++ DWC_READ_REG32(&pcd->core_if->dev_if-> ++ in_ep_regs[ep->dwc_ep.num]-> ++ diepctl) }; ++ ++pcd->request_pending; ++ ++ DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry); ++ if (ep->dwc_ep.is_in) { ++ depctl.b.cnak = 1; ++ DWC_WRITE_REG32(&pcd->core_if->dev_if-> ++ in_ep_regs[ep->dwc_ep.num]-> ++ diepctl, depctl.d32); ++ } ++ ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ } ++ return 0; ++ } ++ ++ /* ++ * For EP0 IN without premature status, zlp is required? ++ */ ++ if (ep->dwc_ep.num == 0 && ep->dwc_ep.is_in) { ++ DWC_DEBUGPL(DBG_PCDV, "%d-OUT ZLP\n", ep->dwc_ep.num); ++ //_req->zero = 1; ++ } ++ ++ /* Start the transfer */ ++ if (DWC_CIRCLEQ_EMPTY(&ep->queue) && !ep->stopped) { ++ /* EP0 Transfer? */ ++ if (ep->dwc_ep.num == 0) { ++ switch (pcd->ep0state) { ++ case EP0_IN_DATA_PHASE: ++ DWC_DEBUGPL(DBG_PCD, ++ "%s ep0: EP0_IN_DATA_PHASE\n", ++ __func__); ++ break; ++ ++ case EP0_OUT_DATA_PHASE: ++ DWC_DEBUGPL(DBG_PCD, ++ "%s ep0: EP0_OUT_DATA_PHASE\n", ++ __func__); ++ if (pcd->request_config) { ++ /* Complete STATUS PHASE */ ++ ep->dwc_ep.is_in = 1; ++ pcd->ep0state = EP0_IN_STATUS_PHASE; ++ } ++ break; ++ ++ case EP0_IN_STATUS_PHASE: ++ DWC_DEBUGPL(DBG_PCD, ++ "%s ep0: EP0_IN_STATUS_PHASE\n", ++ __func__); ++ break; ++ ++ default: ++ DWC_DEBUGPL(DBG_ANY, "ep0: odd state %d\n", ++ pcd->ep0state); ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ return -DWC_E_SHUTDOWN; ++ } ++ ++ ep->dwc_ep.dma_addr = dma_buf; ++ ep->dwc_ep.start_xfer_buff = buf; ++ ep->dwc_ep.xfer_buff = buf; ++ ep->dwc_ep.xfer_len = buflen; ++ ep->dwc_ep.xfer_count = 0; ++ ep->dwc_ep.sent_zlp = 0; ++ ep->dwc_ep.total_len = ep->dwc_ep.xfer_len; ++ ++ if (zero) { ++ if ((ep->dwc_ep.xfer_len % ++ ep->dwc_ep.maxpacket == 0) ++ && (ep->dwc_ep.xfer_len != 0)) { ++ ep->dwc_ep.sent_zlp = 1; ++ } ++ ++ } ++ ++ dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), ++ &ep->dwc_ep); ++ } // non-ep0 endpoints ++ else { ++#ifdef DWC_UTE_CFI ++ if (ep->dwc_ep.buff_mode != BM_STANDARD) { ++ /* store the request length */ ++ ep->dwc_ep.cfi_req_len = buflen; ++ pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ++ ep, req); ++ } else { ++#endif ++ max_transfer = ++ GET_CORE_IF(ep->pcd)->core_params-> ++ max_transfer_size; ++ ++ /* Setup and start the Transfer */ ++ if (req->dw_align_buf){ ++ if (ep->dwc_ep.is_in) ++ dwc_memcpy(req->dw_align_buf, ++ buf, buflen); ++ ep->dwc_ep.dma_addr = ++ req->dw_align_buf_dma; ++ ep->dwc_ep.start_xfer_buff = ++ req->dw_align_buf; ++ ep->dwc_ep.xfer_buff = ++ req->dw_align_buf; ++ } else { ++ ep->dwc_ep.dma_addr = dma_buf; ++ ep->dwc_ep.start_xfer_buff = buf; ++ ep->dwc_ep.xfer_buff = buf; ++ } ++ ep->dwc_ep.xfer_len = 0; ++ ep->dwc_ep.xfer_count = 0; ++ ep->dwc_ep.sent_zlp = 0; ++ ep->dwc_ep.total_len = buflen; ++ ++ ep->dwc_ep.maxxfer = max_transfer; ++ if (GET_CORE_IF(pcd)->dma_desc_enable) { ++ uint32_t out_max_xfer = ++ DDMA_MAX_TRANSFER_SIZE - ++ (DDMA_MAX_TRANSFER_SIZE % 4); ++ if (ep->dwc_ep.is_in) { ++ if (ep->dwc_ep.maxxfer > ++ DDMA_MAX_TRANSFER_SIZE) { ++ ep->dwc_ep.maxxfer = ++ DDMA_MAX_TRANSFER_SIZE; ++ } ++ } else { ++ if (ep->dwc_ep.maxxfer > ++ out_max_xfer) { ++ ep->dwc_ep.maxxfer = ++ out_max_xfer; ++ } ++ } ++ } ++ if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) { ++ ep->dwc_ep.maxxfer -= ++ (ep->dwc_ep.maxxfer % ++ ep->dwc_ep.maxpacket); ++ } ++ ++ if (zero) { ++ if ((ep->dwc_ep.total_len % ++ ep->dwc_ep.maxpacket == 0) ++ && (ep->dwc_ep.total_len != 0)) { ++ ep->dwc_ep.sent_zlp = 1; ++ } ++ } ++#ifdef DWC_UTE_CFI ++ } ++#endif ++ dwc_otg_ep_start_transfer(GET_CORE_IF(pcd), ++ &ep->dwc_ep); ++ } ++ } ++ ++ if (req != 0) { ++ ++pcd->request_pending; ++ DWC_CIRCLEQ_INSERT_TAIL(&ep->queue, req, queue_entry); ++ if (ep->dwc_ep.is_in && ep->stopped ++ && !(GET_CORE_IF(pcd)->dma_enable)) { ++ /** @todo NGS Create a function for this. */ ++ diepmsk_data_t diepmsk = {.d32 = 0 }; ++ diepmsk.b.intktxfemp = 1; ++ if (GET_CORE_IF(pcd)->multiproc_int_enable) { ++ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)-> ++ dev_if->dev_global_regs->diepeachintmsk ++ [ep->dwc_ep.num], 0, ++ diepmsk.d32); ++ } else { ++ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)-> ++ dev_if->dev_global_regs-> ++ diepmsk, 0, diepmsk.d32); ++ } ++ ++ } ++ } ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ ++ return 0; ++} ++ ++int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *req_handle) ++{ ++ dwc_irqflags_t flags; ++ dwc_otg_pcd_request_t *req; ++ dwc_otg_pcd_ep_t *ep; ++ ++ ep = get_ep_from_handle(pcd, ep_handle); ++ if (!ep || (!ep->desc && ep->dwc_ep.num != 0)) { ++ DWC_WARN("bad argument\n"); ++ return -DWC_E_INVALID; ++ } ++ ++ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++ ++ /* make sure it's actually queued on this endpoint */ ++ DWC_CIRCLEQ_FOREACH(req, &ep->queue, queue_entry) { ++ if (req->priv == (void *)req_handle) { ++ break; ++ } ++ } ++ ++ if (req->priv != (void *)req_handle) { ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ return -DWC_E_INVALID; ++ } ++ ++ if (!DWC_CIRCLEQ_EMPTY_ENTRY(req, queue_entry)) { ++ dwc_otg_request_done(ep, req, -DWC_E_RESTART); ++ } else { ++ req = NULL; ++ } ++ ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ ++ return req ? 0 : -DWC_E_SHUTDOWN; ++ ++} ++ ++/** ++ * dwc_otg_pcd_ep_wedge - sets the halt feature and ignores clear requests ++ * ++ * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) ++ * requests. If the gadget driver clears the halt status, it will ++ * automatically unwedge the endpoint. ++ * ++ * Returns zero on success, else negative DWC error code. ++ */ ++int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle) ++{ ++ dwc_otg_pcd_ep_t *ep; ++ dwc_irqflags_t flags; ++ int retval = 0; ++ ++ ep = get_ep_from_handle(pcd, ep_handle); ++ ++ if ((!ep->desc && ep != &pcd->ep0) || ++ (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) { ++ DWC_WARN("%s, bad ep\n", __func__); ++ return -DWC_E_INVALID; ++ } ++ ++ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num, ++ ep->dwc_ep.is_in ? "IN" : "OUT"); ++ retval = -DWC_E_AGAIN; ++ } else { ++ /* This code needs to be reviewed */ ++ if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) { ++ dtxfsts_data_t txstatus; ++ fifosize_data_t txfifosize; ++ ++ txfifosize.d32 = ++ DWC_READ_REG32(&GET_CORE_IF(pcd)-> ++ core_global_regs->dtxfsiz[ep->dwc_ep. ++ tx_fifo_num]); ++ txstatus.d32 = ++ DWC_READ_REG32(&GET_CORE_IF(pcd)-> ++ dev_if->in_ep_regs[ep->dwc_ep.num]-> ++ dtxfsts); ++ ++ if (txstatus.b.txfspcavail < txfifosize.b.depth) { ++ DWC_WARN("%s() Data In Tx Fifo\n", __func__); ++ retval = -DWC_E_AGAIN; ++ } else { ++ if (ep->dwc_ep.num == 0) { ++ pcd->ep0state = EP0_STALL; ++ } ++ ++ ep->stopped = 1; ++ dwc_otg_ep_set_stall(GET_CORE_IF(pcd), ++ &ep->dwc_ep); ++ } ++ } else { ++ if (ep->dwc_ep.num == 0) { ++ pcd->ep0state = EP0_STALL; ++ } ++ ++ ep->stopped = 1; ++ dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep); ++ } ++ } ++ ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ ++ return retval; ++} ++ ++int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value) ++{ ++ dwc_otg_pcd_ep_t *ep; ++ dwc_irqflags_t flags; ++ int retval = 0; ++ ++ ep = get_ep_from_handle(pcd, ep_handle); ++ ++ if (!ep || (!ep->desc && ep != &pcd->ep0) || ++ (ep->desc && (ep->desc->bmAttributes == UE_ISOCHRONOUS))) { ++ DWC_WARN("%s, bad ep\n", __func__); ++ return -DWC_E_INVALID; ++ } ++ ++ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ DWC_WARN("%d %s XFer In process\n", ep->dwc_ep.num, ++ ep->dwc_ep.is_in ? "IN" : "OUT"); ++ retval = -DWC_E_AGAIN; ++ } else if (value == 0) { ++ dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep); ++ } else if (value == 1) { ++ if (ep->dwc_ep.is_in == 1 && GET_CORE_IF(pcd)->dma_desc_enable) { ++ dtxfsts_data_t txstatus; ++ fifosize_data_t txfifosize; ++ ++ txfifosize.d32 = ++ DWC_READ_REG32(&GET_CORE_IF(pcd)->core_global_regs-> ++ dtxfsiz[ep->dwc_ep.tx_fifo_num]); ++ txstatus.d32 = ++ DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if-> ++ in_ep_regs[ep->dwc_ep.num]->dtxfsts); ++ ++ if (txstatus.b.txfspcavail < txfifosize.b.depth) { ++ DWC_WARN("%s() Data In Tx Fifo\n", __func__); ++ retval = -DWC_E_AGAIN; ++ } else { ++ if (ep->dwc_ep.num == 0) { ++ pcd->ep0state = EP0_STALL; ++ } ++ ++ ep->stopped = 1; ++ dwc_otg_ep_set_stall(GET_CORE_IF(pcd), ++ &ep->dwc_ep); ++ } ++ } else { ++ if (ep->dwc_ep.num == 0) { ++ pcd->ep0state = EP0_STALL; ++ } ++ ++ ep->stopped = 1; ++ dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep->dwc_ep); ++ } ++ } else if (value == 2) { ++ ep->dwc_ep.stall_clear_flag = 0; ++ } else if (value == 3) { ++ ep->dwc_ep.stall_clear_flag = 1; ++ } ++ ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ ++ return retval; ++} ++ ++/** ++ * This function initiates remote wakeup of the host from suspend state. ++ */ ++void dwc_otg_pcd_rem_wkup_from_suspend(dwc_otg_pcd_t * pcd, int set) ++{ ++ dctl_data_t dctl = { 0 }; ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dsts_data_t dsts; ++ ++ dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts); ++ if (!dsts.b.suspsts) { ++ DWC_WARN("Remote wakeup while is not in suspend state\n"); ++ } ++ /* Check if DEVICE_REMOTE_WAKEUP feature enabled */ ++ if (pcd->remote_wakeup_enable) { ++ if (set) { ++ ++ if (core_if->adp_enable) { ++ gpwrdn_data_t gpwrdn; ++ ++ dwc_otg_adp_probe_stop(core_if); ++ ++ /* Mask SRP detected interrupt from Power Down Logic */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.srp_det_msk = 1; ++ DWC_MODIFY_REG32(&core_if-> ++ core_global_regs->gpwrdn, ++ gpwrdn.d32, 0); ++ ++ /* Disable Power Down Logic */ ++ gpwrdn.d32 = 0; ++ gpwrdn.b.pmuactv = 1; ++ DWC_MODIFY_REG32(&core_if-> ++ core_global_regs->gpwrdn, ++ gpwrdn.d32, 0); ++ ++ /* ++ * Initialize the Core for Device mode. ++ */ ++ core_if->op_state = B_PERIPHERAL; ++ dwc_otg_core_init(core_if); ++ dwc_otg_enable_global_interrupts(core_if); ++ cil_pcd_start(core_if); ++ ++ dwc_otg_initiate_srp(core_if); ++ } ++ ++ dctl.b.rmtwkupsig = 1; ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs-> ++ dctl, 0, dctl.d32); ++ DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n"); ++ ++ dwc_mdelay(2); ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs-> ++ dctl, dctl.d32, 0); ++ DWC_DEBUGPL(DBG_PCD, "Clear Remote Wakeup\n"); ++ } ++ } else { ++ DWC_DEBUGPL(DBG_PCD, "Remote Wakeup is disabled\n"); ++ } ++} ++ ++#ifdef CONFIG_USB_DWC_OTG_LPM ++/** ++ * This function initiates remote wakeup of the host from L1 sleep state. ++ */ ++void dwc_otg_pcd_rem_wkup_from_sleep(dwc_otg_pcd_t * pcd, int set) ++{ ++ glpmcfg_data_t lpmcfg; ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ ++ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg); ++ ++ /* Check if we are in L1 state */ ++ if (!lpmcfg.b.prt_sleep_sts) { ++ DWC_DEBUGPL(DBG_PCD, "Device is not in sleep state\n"); ++ return; ++ } ++ ++ /* Check if host allows remote wakeup */ ++ if (!lpmcfg.b.rem_wkup_en) { ++ DWC_DEBUGPL(DBG_PCD, "Host does not allow remote wakeup\n"); ++ return; ++ } ++ ++ /* Check if Resume OK */ ++ if (!lpmcfg.b.sleep_state_resumeok) { ++ DWC_DEBUGPL(DBG_PCD, "Sleep state resume is not OK\n"); ++ return; ++ } ++ ++ lpmcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->glpmcfg); ++ lpmcfg.b.en_utmi_sleep = 0; ++ lpmcfg.b.hird_thres &= (~(1 << 4)); ++ DWC_WRITE_REG32(&core_if->core_global_regs->glpmcfg, lpmcfg.d32); ++ ++ if (set) { ++ dctl_data_t dctl = {.d32 = 0 }; ++ dctl.b.rmtwkupsig = 1; ++ /* Set RmtWkUpSig bit to start remote wakup signaling. ++ * Hardware will automatically clear this bit. ++ */ ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, ++ 0, dctl.d32); ++ DWC_DEBUGPL(DBG_PCD, "Set Remote Wakeup\n"); ++ } ++ ++} ++#endif ++ ++/** ++ * Performs remote wakeup. ++ */ ++void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dwc_irqflags_t flags; ++ if (dwc_otg_is_device_mode(core_if)) { ++ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++#ifdef CONFIG_USB_DWC_OTG_LPM ++ if (core_if->lx_state == DWC_OTG_L1) { ++ dwc_otg_pcd_rem_wkup_from_sleep(pcd, set); ++ } else { ++#endif ++ dwc_otg_pcd_rem_wkup_from_suspend(pcd, set); ++#ifdef CONFIG_USB_DWC_OTG_LPM ++ } ++#endif ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++ } ++ return; ++} ++ ++void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dctl_data_t dctl = { 0 }; ++ ++ if (dwc_otg_is_device_mode(core_if)) { ++ dctl.b.sftdiscon = 1; ++ DWC_PRINTF("Soft disconnect for %d useconds\n",no_of_usecs); ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, 0, dctl.d32); ++ dwc_udelay(no_of_usecs); ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32,0); ++ ++ } else{ ++ DWC_PRINTF("NOT SUPPORTED IN HOST MODE\n"); ++ } ++ return; ++ ++} ++ ++int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd) ++{ ++ dsts_data_t dsts; ++ gotgctl_data_t gotgctl; ++ ++ /* ++ * This function starts the Protocol if no session is in progress. If ++ * a session is already in progress, but the device is suspended, ++ * remote wakeup signaling is started. ++ */ ++ ++ /* Check if valid session */ ++ gotgctl.d32 = ++ DWC_READ_REG32(&(GET_CORE_IF(pcd)->core_global_regs->gotgctl)); ++ if (gotgctl.b.bsesvld) { ++ /* Check if suspend state */ ++ dsts.d32 = ++ DWC_READ_REG32(& ++ (GET_CORE_IF(pcd)->dev_if-> ++ dev_global_regs->dsts)); ++ if (dsts.b.suspsts) { ++ dwc_otg_pcd_remote_wakeup(pcd, 1); ++ } ++ } else { ++ dwc_otg_pcd_initiate_srp(pcd); ++ } ++ ++ return 0; ++ ++} ++ ++/** ++ * Start the SRP timer to detect when the SRP does not complete within ++ * 6 seconds. ++ * ++ * @param pcd the pcd structure. ++ */ ++void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd) ++{ ++ dwc_irqflags_t flags; ++ DWC_SPINLOCK_IRQSAVE(pcd->lock, &flags); ++ dwc_otg_initiate_srp(GET_CORE_IF(pcd)); ++ DWC_SPINUNLOCK_IRQRESTORE(pcd->lock, flags); ++} ++ ++int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd) ++{ ++ return dwc_otg_get_frame_number(GET_CORE_IF(pcd)); ++} ++ ++int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd) ++{ ++ return GET_CORE_IF(pcd)->core_params->lpm_enable; ++} ++ ++uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd) ++{ ++ return pcd->b_hnp_enable; ++} ++ ++uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd) ++{ ++ return pcd->a_hnp_support; ++} ++ ++uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd) ++{ ++ return pcd->a_alt_hnp_support; ++} ++ ++int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd) ++{ ++ return pcd->remote_wakeup_enable; ++} ++ ++#endif /* DWC_HOST_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_pcd.h linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_pcd.h +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_pcd.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_pcd.h 2014-03-13 12:46:39.520097997 +0100 +@@ -0,0 +1,266 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd.h $ ++ * $Revision: #48 $ ++ * $Date: 2012/08/10 $ ++ * $Change: 2047372 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_HOST_ONLY ++#if !defined(__DWC_PCD_H__) ++#define __DWC_PCD_H__ ++ ++#include "dwc_otg_os_dep.h" ++#include "usb.h" ++#include "dwc_otg_cil.h" ++#include "dwc_otg_pcd_if.h" ++struct cfiobject; ++ ++/** ++ * @file ++ * ++ * This file contains the structures, constants, and interfaces for ++ * the Perpherial Contoller Driver (PCD). ++ * ++ * The Peripheral Controller Driver (PCD) for Linux will implement the ++ * Gadget API, so that the existing Gadget drivers can be used. For ++ * the Mass Storage Function driver the File-backed USB Storage Gadget ++ * (FBS) driver will be used. The FBS driver supports the ++ * Control-Bulk (CB), Control-Bulk-Interrupt (CBI), and Bulk-Only ++ * transports. ++ * ++ */ ++ ++/** Invalid DMA Address */ ++#define DWC_DMA_ADDR_INVALID (~(dwc_dma_t)0) ++ ++/** Max Transfer size for any EP */ ++#define DDMA_MAX_TRANSFER_SIZE 65535 ++ ++/** ++ * Get the pointer to the core_if from the pcd pointer. ++ */ ++#define GET_CORE_IF( _pcd ) (_pcd->core_if) ++ ++/** ++ * States of EP0. ++ */ ++typedef enum ep0_state { ++ EP0_DISCONNECT, /* no host */ ++ EP0_IDLE, ++ EP0_IN_DATA_PHASE, ++ EP0_OUT_DATA_PHASE, ++ EP0_IN_STATUS_PHASE, ++ EP0_OUT_STATUS_PHASE, ++ EP0_STALL, ++} ep0state_e; ++ ++/** Fordward declaration.*/ ++struct dwc_otg_pcd; ++ ++/** DWC_otg iso request structure. ++ * ++ */ ++typedef struct usb_iso_request dwc_otg_pcd_iso_request_t; ++ ++#ifdef DWC_UTE_PER_IO ++ ++/** ++ * This shall be the exact analogy of the same type structure defined in the ++ * usb_gadget.h. Each descriptor contains ++ */ ++struct dwc_iso_pkt_desc_port { ++ uint32_t offset; ++ uint32_t length; /* expected length */ ++ uint32_t actual_length; ++ uint32_t status; ++}; ++ ++struct dwc_iso_xreq_port { ++ /** transfer/submission flag */ ++ uint32_t tr_sub_flags; ++ /** Start the request ASAP */ ++#define DWC_EREQ_TF_ASAP 0x00000002 ++ /** Just enqueue the request w/o initiating a transfer */ ++#define DWC_EREQ_TF_ENQUEUE 0x00000004 ++ ++ /** ++ * count of ISO packets attached to this request - shall ++ * not exceed the pio_alloc_pkt_count ++ */ ++ uint32_t pio_pkt_count; ++ /** count of ISO packets allocated for this request */ ++ uint32_t pio_alloc_pkt_count; ++ /** number of ISO packet errors */ ++ uint32_t error_count; ++ /** reserved for future extension */ ++ uint32_t res; ++ /** Will be allocated and freed in the UTE gadget and based on the CFC value */ ++ struct dwc_iso_pkt_desc_port *per_io_frame_descs; ++}; ++#endif ++/** DWC_otg request structure. ++ * This structure is a list of requests. ++ */ ++typedef struct dwc_otg_pcd_request { ++ void *priv; ++ void *buf; ++ dwc_dma_t dma; ++ uint32_t length; ++ uint32_t actual; ++ unsigned sent_zlp:1; ++ /** ++ * Used instead of original buffer if ++ * it(physical address) is not dword-aligned. ++ **/ ++ uint8_t *dw_align_buf; ++ dwc_dma_t dw_align_buf_dma; ++ ++ DWC_CIRCLEQ_ENTRY(dwc_otg_pcd_request) queue_entry; ++#ifdef DWC_UTE_PER_IO ++ struct dwc_iso_xreq_port ext_req; ++ //void *priv_ereq_nport; /* */ ++#endif ++} dwc_otg_pcd_request_t; ++ ++DWC_CIRCLEQ_HEAD(req_list, dwc_otg_pcd_request); ++ ++/** PCD EP structure. ++ * This structure describes an EP, there is an array of EPs in the PCD ++ * structure. ++ */ ++typedef struct dwc_otg_pcd_ep { ++ /** USB EP Descriptor */ ++ const usb_endpoint_descriptor_t *desc; ++ ++ /** queue of dwc_otg_pcd_requests. */ ++ struct req_list queue; ++ unsigned stopped:1; ++ unsigned disabling:1; ++ unsigned dma:1; ++ unsigned queue_sof:1; ++ ++#ifdef DWC_EN_ISOC ++ /** ISOC req handle passed */ ++ void *iso_req_handle; ++#endif //_EN_ISOC_ ++ ++ /** DWC_otg ep data. */ ++ dwc_ep_t dwc_ep; ++ ++ /** Pointer to PCD */ ++ struct dwc_otg_pcd *pcd; ++ ++ void *priv; ++} dwc_otg_pcd_ep_t; ++ ++/** DWC_otg PCD Structure. ++ * This structure encapsulates the data for the dwc_otg PCD. ++ */ ++struct dwc_otg_pcd { ++ const struct dwc_otg_pcd_function_ops *fops; ++ /** The DWC otg device pointer */ ++ struct dwc_otg_device *otg_dev; ++ /** Core Interface */ ++ dwc_otg_core_if_t *core_if; ++ /** State of EP0 */ ++ ep0state_e ep0state; ++ /** EP0 Request is pending */ ++ unsigned ep0_pending:1; ++ /** Indicates when SET CONFIGURATION Request is in process */ ++ unsigned request_config:1; ++ /** The state of the Remote Wakeup Enable. */ ++ unsigned remote_wakeup_enable:1; ++ /** The state of the B-Device HNP Enable. */ ++ unsigned b_hnp_enable:1; ++ /** The state of A-Device HNP Support. */ ++ unsigned a_hnp_support:1; ++ /** The state of the A-Device Alt HNP support. */ ++ unsigned a_alt_hnp_support:1; ++ /** Count of pending Requests */ ++ unsigned request_pending; ++ ++ /** SETUP packet for EP0 ++ * This structure is allocated as a DMA buffer on PCD initialization ++ * with enough space for up to 3 setup packets. ++ */ ++ union { ++ usb_device_request_t req; ++ uint32_t d32[2]; ++ } *setup_pkt; ++ ++ dwc_dma_t setup_pkt_dma_handle; ++ ++ /* Additional buffer and flag for CTRL_WR premature case */ ++ uint8_t *backup_buf; ++ unsigned data_terminated; ++ ++ /** 2-byte dma buffer used to return status from GET_STATUS */ ++ uint16_t *status_buf; ++ dwc_dma_t status_buf_dma_handle; ++ ++ /** EP0 */ ++ dwc_otg_pcd_ep_t ep0; ++ ++ /** Array of IN EPs. */ ++ dwc_otg_pcd_ep_t in_ep[MAX_EPS_CHANNELS - 1]; ++ /** Array of OUT EPs. */ ++ dwc_otg_pcd_ep_t out_ep[MAX_EPS_CHANNELS - 1]; ++ /** number of valid EPs in the above array. */ ++// unsigned num_eps : 4; ++ dwc_spinlock_t *lock; ++ ++ /** Tasklet to defer starting of TEST mode transmissions until ++ * Status Phase has been completed. ++ */ ++ dwc_tasklet_t *test_mode_tasklet; ++ ++ /** Tasklet to delay starting of xfer in DMA mode */ ++ dwc_tasklet_t *start_xfer_tasklet; ++ ++ /** The test mode to enter when the tasklet is executed. */ ++ unsigned test_mode; ++ /** The cfi_api structure that implements most of the CFI API ++ * and OTG specific core configuration functionality ++ */ ++#ifdef DWC_UTE_CFI ++ struct cfiobject *cfi; ++#endif ++ ++}; ++ ++//FIXME this functions should be static, and this prototypes should be removed ++extern void dwc_otg_request_nuke(dwc_otg_pcd_ep_t * ep); ++extern void dwc_otg_request_done(dwc_otg_pcd_ep_t * ep, ++ dwc_otg_pcd_request_t * req, int32_t status); ++ ++void dwc_otg_iso_buffer_done(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep, ++ void *req_handle); ++ ++extern void do_test_mode(void *data); ++#endif ++#endif /* DWC_HOST_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h 2014-03-13 12:46:39.520097997 +0100 +@@ -0,0 +1,360 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_if.h $ ++ * $Revision: #11 $ ++ * $Date: 2011/10/26 $ ++ * $Change: 1873028 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_HOST_ONLY ++ ++#if !defined(__DWC_PCD_IF_H__) ++#define __DWC_PCD_IF_H__ ++ ++//#include "dwc_os.h" ++#include "dwc_otg_core_if.h" ++ ++/** @file ++ * This file defines DWC_OTG PCD Core API. ++ */ ++ ++struct dwc_otg_pcd; ++typedef struct dwc_otg_pcd dwc_otg_pcd_t; ++ ++/** Maxpacket size for EP0 */ ++#define MAX_EP0_SIZE 64 ++/** Maxpacket size for any EP */ ++#define MAX_PACKET_SIZE 1024 ++ ++/** @name Function Driver Callbacks */ ++/** @{ */ ++ ++/** This function will be called whenever a previously queued request has ++ * completed. The status value will be set to -DWC_E_SHUTDOWN to indicated a ++ * failed or aborted transfer, or -DWC_E_RESTART to indicate the device was reset, ++ * or -DWC_E_TIMEOUT to indicate it timed out, or -DWC_E_INVALID to indicate invalid ++ * parameters. */ ++typedef int (*dwc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *req_handle, int32_t status, ++ uint32_t actual); ++/** ++ * This function will be called whenever a previousle queued ISOC request has ++ * completed. Count of ISOC packets could be read using dwc_otg_pcd_get_iso_packet_count ++ * function. ++ * The status of each ISOC packet could be read using dwc_otg_pcd_get_iso_packet_* ++ * functions. ++ */ ++typedef int (*dwc_isoc_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *req_handle, int proc_buf_num); ++/** This function should handle any SETUP request that cannot be handled by the ++ * PCD Core. This includes most GET_DESCRIPTORs, SET_CONFIGS, Any ++ * class-specific requests, etc. The function must non-blocking. ++ * ++ * Returns 0 on success. ++ * Returns -DWC_E_NOT_SUPPORTED if the request is not supported. ++ * Returns -DWC_E_INVALID if the setup request had invalid parameters or bytes. ++ * Returns -DWC_E_SHUTDOWN on any other error. */ ++typedef int (*dwc_setup_cb_t) (dwc_otg_pcd_t * pcd, uint8_t * bytes); ++/** This is called whenever the device has been disconnected. The function ++ * driver should take appropriate action to clean up all pending requests in the ++ * PCD Core, remove all endpoints (except ep0), and initialize back to reset ++ * state. */ ++typedef int (*dwc_disconnect_cb_t) (dwc_otg_pcd_t * pcd); ++/** This function is called when device has been connected. */ ++typedef int (*dwc_connect_cb_t) (dwc_otg_pcd_t * pcd, int speed); ++/** This function is called when device has been suspended */ ++typedef int (*dwc_suspend_cb_t) (dwc_otg_pcd_t * pcd); ++/** This function is called when device has received LPM tokens, i.e. ++ * device has been sent to sleep state. */ ++typedef int (*dwc_sleep_cb_t) (dwc_otg_pcd_t * pcd); ++/** This function is called when device has been resumed ++ * from suspend(L2) or L1 sleep state. */ ++typedef int (*dwc_resume_cb_t) (dwc_otg_pcd_t * pcd); ++/** This function is called whenever hnp params has been changed. ++ * User can call get_b_hnp_enable, get_a_hnp_support, get_a_alt_hnp_support functions ++ * to get hnp parameters. */ ++typedef int (*dwc_hnp_params_changed_cb_t) (dwc_otg_pcd_t * pcd); ++/** This function is called whenever USB RESET is detected. */ ++typedef int (*dwc_reset_cb_t) (dwc_otg_pcd_t * pcd); ++ ++typedef int (*cfi_setup_cb_t) (dwc_otg_pcd_t * pcd, void *ctrl_req_bytes); ++ ++/** ++ * ++ * @param ep_handle Void pointer to the usb_ep structure ++ * @param ereq_port Pointer to the extended request structure created in the ++ * portable part. ++ */ ++typedef int (*xiso_completion_cb_t) (dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *req_handle, int32_t status, ++ void *ereq_port); ++/** Function Driver Ops Data Structure */ ++struct dwc_otg_pcd_function_ops { ++ dwc_connect_cb_t connect; ++ dwc_disconnect_cb_t disconnect; ++ dwc_setup_cb_t setup; ++ dwc_completion_cb_t complete; ++ dwc_isoc_completion_cb_t isoc_complete; ++ dwc_suspend_cb_t suspend; ++ dwc_sleep_cb_t sleep; ++ dwc_resume_cb_t resume; ++ dwc_reset_cb_t reset; ++ dwc_hnp_params_changed_cb_t hnp_changed; ++ cfi_setup_cb_t cfi_setup; ++#ifdef DWC_UTE_PER_IO ++ xiso_completion_cb_t xisoc_complete; ++#endif ++}; ++/** @} */ ++ ++/** @name Function Driver Functions */ ++/** @{ */ ++ ++/** Call this function to get pointer on dwc_otg_pcd_t, ++ * this pointer will be used for all PCD API functions. ++ * ++ * @param core_if The DWC_OTG Core ++ */ ++extern dwc_otg_pcd_t *dwc_otg_pcd_init(dwc_otg_core_if_t * core_if); ++ ++/** Frees PCD allocated by dwc_otg_pcd_init ++ * ++ * @param pcd The PCD ++ */ ++extern void dwc_otg_pcd_remove(dwc_otg_pcd_t * pcd); ++ ++/** Call this to bind the function driver to the PCD Core. ++ * ++ * @param pcd Pointer on dwc_otg_pcd_t returned by dwc_otg_pcd_init function. ++ * @param fops The Function Driver Ops data structure containing pointers to all callbacks. ++ */ ++extern void dwc_otg_pcd_start(dwc_otg_pcd_t * pcd, ++ const struct dwc_otg_pcd_function_ops *fops); ++ ++/** Enables an endpoint for use. This function enables an endpoint in ++ * the PCD. The endpoint is described by the ep_desc which has the ++ * same format as a USB ep descriptor. The ep_handle parameter is used to refer ++ * to the endpoint from other API functions and in callbacks. Normally this ++ * should be called after a SET_CONFIGURATION/SET_INTERFACE to configure the ++ * core for that interface. ++ * ++ * Returns -DWC_E_INVALID if invalid parameters were passed. ++ * Returns -DWC_E_SHUTDOWN if any other error ocurred. ++ * Returns 0 on success. ++ * ++ * @param pcd The PCD ++ * @param ep_desc Endpoint descriptor ++ * @param usb_ep Handle on endpoint, that will be used to identify endpoint. ++ */ ++extern int dwc_otg_pcd_ep_enable(dwc_otg_pcd_t * pcd, ++ const uint8_t * ep_desc, void *usb_ep); ++ ++/** Disable the endpoint referenced by ep_handle. ++ * ++ * Returns -DWC_E_INVALID if invalid parameters were passed. ++ * Returns -DWC_E_SHUTDOWN if any other error occurred. ++ * Returns 0 on success. */ ++extern int dwc_otg_pcd_ep_disable(dwc_otg_pcd_t * pcd, void *ep_handle); ++ ++/** Queue a data transfer request on the endpoint referenced by ep_handle. ++ * After the transfer is completes, the complete callback will be called with ++ * the request status. ++ * ++ * @param pcd The PCD ++ * @param ep_handle The handle of the endpoint ++ * @param buf The buffer for the data ++ * @param dma_buf The DMA buffer for the data ++ * @param buflen The length of the data transfer ++ * @param zero Specifies whether to send zero length last packet. ++ * @param req_handle Set this handle to any value to use to reference this ++ * request in the ep_dequeue function or from the complete callback ++ * @param atomic_alloc If driver need to perform atomic allocations ++ * for internal data structures. ++ * ++ * Returns -DWC_E_INVALID if invalid parameters were passed. ++ * Returns -DWC_E_SHUTDOWN if any other error ocurred. ++ * Returns 0 on success. */ ++extern int dwc_otg_pcd_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle, ++ uint8_t * buf, dwc_dma_t dma_buf, ++ uint32_t buflen, int zero, void *req_handle, ++ int atomic_alloc); ++#ifdef DWC_UTE_PER_IO ++/** ++ * ++ * @param ereq_nonport Pointer to the extended request part of the ++ * usb_request structure defined in usb_gadget.h file. ++ */ ++extern int dwc_otg_pcd_xiso_ep_queue(dwc_otg_pcd_t * pcd, void *ep_handle, ++ uint8_t * buf, dwc_dma_t dma_buf, ++ uint32_t buflen, int zero, ++ void *req_handle, int atomic_alloc, ++ void *ereq_nonport); ++ ++#endif ++ ++/** De-queue the specified data transfer that has not yet completed. ++ * ++ * Returns -DWC_E_INVALID if invalid parameters were passed. ++ * Returns -DWC_E_SHUTDOWN if any other error ocurred. ++ * Returns 0 on success. */ ++extern int dwc_otg_pcd_ep_dequeue(dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *req_handle); ++ ++/** Halt (STALL) an endpoint or clear it. ++ * ++ * Returns -DWC_E_INVALID if invalid parameters were passed. ++ * Returns -DWC_E_SHUTDOWN if any other error ocurred. ++ * Returns -DWC_E_AGAIN if the STALL cannot be sent and must be tried again later ++ * Returns 0 on success. */ ++extern int dwc_otg_pcd_ep_halt(dwc_otg_pcd_t * pcd, void *ep_handle, int value); ++ ++/** This function */ ++extern int dwc_otg_pcd_ep_wedge(dwc_otg_pcd_t * pcd, void *ep_handle); ++ ++/** This function should be called on every hardware interrupt */ ++extern int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd); ++ ++/** This function returns current frame number */ ++extern int dwc_otg_pcd_get_frame_number(dwc_otg_pcd_t * pcd); ++ ++/** ++ * Start isochronous transfers on the endpoint referenced by ep_handle. ++ * For isochronous transfers duble buffering is used. ++ * After processing each of buffers comlete callback will be called with ++ * status for each transaction. ++ * ++ * @param pcd The PCD ++ * @param ep_handle The handle of the endpoint ++ * @param buf0 The virtual address of first data buffer ++ * @param buf1 The virtual address of second data buffer ++ * @param dma0 The DMA address of first data buffer ++ * @param dma1 The DMA address of second data buffer ++ * @param sync_frame Data pattern frame number ++ * @param dp_frame Data size for pattern frame ++ * @param data_per_frame Data size for regular frame ++ * @param start_frame Frame number to start transfers, if -1 then start transfers ASAP. ++ * @param buf_proc_intrvl Interval of ISOC Buffer processing ++ * @param req_handle Handle of ISOC request ++ * @param atomic_alloc Specefies whether to perform atomic allocation for ++ * internal data structures. ++ * ++ * Returns -DWC_E_NO_MEMORY if there is no enough memory. ++ * Returns -DWC_E_INVALID if incorrect arguments are passed to the function. ++ * Returns -DW_E_SHUTDOWN for any other error. ++ * Returns 0 on success ++ */ ++extern int dwc_otg_pcd_iso_ep_start(dwc_otg_pcd_t * pcd, void *ep_handle, ++ uint8_t * buf0, uint8_t * buf1, ++ dwc_dma_t dma0, dwc_dma_t dma1, ++ int sync_frame, int dp_frame, ++ int data_per_frame, int start_frame, ++ int buf_proc_intrvl, void *req_handle, ++ int atomic_alloc); ++ ++/** Stop ISOC transfers on endpoint referenced by ep_handle. ++ * ++ * @param pcd The PCD ++ * @param ep_handle The handle of the endpoint ++ * @param req_handle Handle of ISOC request ++ * ++ * Returns -DWC_E_INVALID if incorrect arguments are passed to the function ++ * Returns 0 on success ++ */ ++int dwc_otg_pcd_iso_ep_stop(dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *req_handle); ++ ++/** Get ISOC packet status. ++ * ++ * @param pcd The PCD ++ * @param ep_handle The handle of the endpoint ++ * @param iso_req_handle Isochronoush request handle ++ * @param packet Number of packet ++ * @param status Out parameter for returning status ++ * @param actual Out parameter for returning actual length ++ * @param offset Out parameter for returning offset ++ * ++ */ ++extern void dwc_otg_pcd_get_iso_packet_params(dwc_otg_pcd_t * pcd, ++ void *ep_handle, ++ void *iso_req_handle, int packet, ++ int *status, int *actual, ++ int *offset); ++ ++/** Get ISOC packet count. ++ * ++ * @param pcd The PCD ++ * @param ep_handle The handle of the endpoint ++ * @param iso_req_handle ++ */ ++extern int dwc_otg_pcd_get_iso_packet_count(dwc_otg_pcd_t * pcd, ++ void *ep_handle, ++ void *iso_req_handle); ++ ++/** This function starts the SRP Protocol if no session is in progress. If ++ * a session is already in progress, but the device is suspended, ++ * remote wakeup signaling is started. ++ */ ++extern int dwc_otg_pcd_wakeup(dwc_otg_pcd_t * pcd); ++ ++/** This function returns 1 if LPM support is enabled, and 0 otherwise. */ ++extern int dwc_otg_pcd_is_lpm_enabled(dwc_otg_pcd_t * pcd); ++ ++/** This function returns 1 if remote wakeup is allowed and 0, otherwise. */ ++extern int dwc_otg_pcd_get_rmwkup_enable(dwc_otg_pcd_t * pcd); ++ ++/** Initiate SRP */ ++extern void dwc_otg_pcd_initiate_srp(dwc_otg_pcd_t * pcd); ++ ++/** Starts remote wakeup signaling. */ ++extern void dwc_otg_pcd_remote_wakeup(dwc_otg_pcd_t * pcd, int set); ++ ++/** Starts micorsecond soft disconnect. */ ++extern void dwc_otg_pcd_disconnect_us(dwc_otg_pcd_t * pcd, int no_of_usecs); ++/** This function returns whether device is dualspeed.*/ ++extern uint32_t dwc_otg_pcd_is_dualspeed(dwc_otg_pcd_t * pcd); ++ ++/** This function returns whether device is otg. */ ++extern uint32_t dwc_otg_pcd_is_otg(dwc_otg_pcd_t * pcd); ++ ++/** These functions allow to get hnp parameters */ ++extern uint32_t get_b_hnp_enable(dwc_otg_pcd_t * pcd); ++extern uint32_t get_a_hnp_support(dwc_otg_pcd_t * pcd); ++extern uint32_t get_a_alt_hnp_support(dwc_otg_pcd_t * pcd); ++ ++/** CFI specific Interface functions */ ++/** Allocate a cfi buffer */ ++extern uint8_t *cfiw_ep_alloc_buffer(dwc_otg_pcd_t * pcd, void *pep, ++ dwc_dma_t * addr, size_t buflen, ++ int flags); ++ ++/******************************************************************************/ ++ ++/** @} */ ++ ++#endif /* __DWC_PCD_IF_H__ */ ++ ++#endif /* DWC_HOST_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c 2014-03-13 12:46:39.520097997 +0100 +@@ -0,0 +1,5147 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_intr.c $ ++ * $Revision: #116 $ ++ * $Date: 2012/08/10 $ ++ * $Change: 2047372 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_HOST_ONLY ++ ++#include "dwc_otg_pcd.h" ++ ++#ifdef DWC_UTE_CFI ++#include "dwc_otg_cfi.h" ++#endif ++ ++#ifdef DWC_UTE_PER_IO ++extern void complete_xiso_ep(dwc_otg_pcd_ep_t * ep); ++#endif ++//#define PRINT_CFI_DMA_DESCS ++ ++#define DEBUG_EP0 ++ ++/** ++ * This function updates OTG. ++ */ ++static void dwc_otg_pcd_update_otg(dwc_otg_pcd_t * pcd, const unsigned reset) ++{ ++ ++ if (reset) { ++ pcd->b_hnp_enable = 0; ++ pcd->a_hnp_support = 0; ++ pcd->a_alt_hnp_support = 0; ++ } ++ ++ if (pcd->fops->hnp_changed) { ++ pcd->fops->hnp_changed(pcd); ++ } ++} ++ ++/** @file ++ * This file contains the implementation of the PCD Interrupt handlers. ++ * ++ * The PCD handles the device interrupts. Many conditions can cause a ++ * device interrupt. When an interrupt occurs, the device interrupt ++ * service routine determines the cause of the interrupt and ++ * dispatches handling to the appropriate function. These interrupt ++ * handling functions are described below. ++ * All interrupt registers are processed from LSB to MSB. ++ */ ++ ++/** ++ * This function prints the ep0 state for debug purposes. ++ */ ++static inline void print_ep0_state(dwc_otg_pcd_t * pcd) ++{ ++#ifdef DEBUG ++ char str[40]; ++ ++ switch (pcd->ep0state) { ++ case EP0_DISCONNECT: ++ dwc_strcpy(str, "EP0_DISCONNECT"); ++ break; ++ case EP0_IDLE: ++ dwc_strcpy(str, "EP0_IDLE"); ++ break; ++ case EP0_IN_DATA_PHASE: ++ dwc_strcpy(str, "EP0_IN_DATA_PHASE"); ++ break; ++ case EP0_OUT_DATA_PHASE: ++ dwc_strcpy(str, "EP0_OUT_DATA_PHASE"); ++ break; ++ case EP0_IN_STATUS_PHASE: ++ dwc_strcpy(str, "EP0_IN_STATUS_PHASE"); ++ break; ++ case EP0_OUT_STATUS_PHASE: ++ dwc_strcpy(str, "EP0_OUT_STATUS_PHASE"); ++ break; ++ case EP0_STALL: ++ dwc_strcpy(str, "EP0_STALL"); ++ break; ++ default: ++ dwc_strcpy(str, "EP0_INVALID"); ++ } ++ ++ DWC_DEBUGPL(DBG_ANY, "%s(%d)\n", str, pcd->ep0state); ++#endif ++} ++ ++/** ++ * This function calculate the size of the payload in the memory ++ * for out endpoints and prints size for debug purposes(used in ++ * 2.93a DevOutNak feature). ++ */ ++static inline void print_memory_payload(dwc_otg_pcd_t * pcd, dwc_ep_t * ep) ++{ ++#ifdef DEBUG ++ deptsiz_data_t deptsiz_init = {.d32 = 0 }; ++ deptsiz_data_t deptsiz_updt = {.d32 = 0 }; ++ int pack_num; ++ unsigned payload; ++ ++ deptsiz_init.d32 = pcd->core_if->start_doeptsiz_val[ep->num]; ++ deptsiz_updt.d32 = ++ DWC_READ_REG32(&pcd->core_if->dev_if-> ++ out_ep_regs[ep->num]->doeptsiz); ++ /* Payload will be */ ++ payload = deptsiz_init.b.xfersize - deptsiz_updt.b.xfersize; ++ /* Packet count is decremented every time a packet ++ * is written to the RxFIFO not in to the external memory ++ * So, if payload == 0, then it means no packet was sent to ext memory*/ ++ pack_num = (!payload) ? 0 : (deptsiz_init.b.pktcnt - deptsiz_updt.b.pktcnt); ++ DWC_DEBUGPL(DBG_PCDV, ++ "Payload for EP%d-%s\n", ++ ep->num, (ep->is_in ? "IN" : "OUT")); ++ DWC_DEBUGPL(DBG_PCDV, ++ "Number of transfered bytes = 0x%08x\n", payload); ++ DWC_DEBUGPL(DBG_PCDV, ++ "Number of transfered packets = %d\n", pack_num); ++#endif ++} ++ ++ ++#ifdef DWC_UTE_CFI ++static inline void print_desc(struct dwc_otg_dma_desc *ddesc, ++ const uint8_t * epname, int descnum) ++{ ++ CFI_INFO ++ ("%s DMA_DESC(%d) buf=0x%08x bytes=0x%04x; sp=0x%x; l=0x%x; sts=0x%02x; bs=0x%02x\n", ++ epname, descnum, ddesc->buf, ddesc->status.b.bytes, ++ ddesc->status.b.sp, ddesc->status.b.l, ddesc->status.b.sts, ++ ddesc->status.b.bs); ++} ++#endif ++ ++/** ++ * This function returns pointer to in ep struct with number ep_num ++ */ ++static inline dwc_otg_pcd_ep_t *get_in_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num) ++{ ++ int i; ++ int num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps; ++ if (ep_num == 0) { ++ return &pcd->ep0; ++ } else { ++ for (i = 0; i < num_in_eps; ++i) { ++ if (pcd->in_ep[i].dwc_ep.num == ep_num) ++ return &pcd->in_ep[i]; ++ } ++ return 0; ++ } ++} ++ ++/** ++ * This function returns pointer to out ep struct with number ep_num ++ */ ++static inline dwc_otg_pcd_ep_t *get_out_ep(dwc_otg_pcd_t * pcd, uint32_t ep_num) ++{ ++ int i; ++ int num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps; ++ if (ep_num == 0) { ++ return &pcd->ep0; ++ } else { ++ for (i = 0; i < num_out_eps; ++i) { ++ if (pcd->out_ep[i].dwc_ep.num == ep_num) ++ return &pcd->out_ep[i]; ++ } ++ return 0; ++ } ++} ++ ++/** ++ * This functions gets a pointer to an EP from the wIndex address ++ * value of the control request. ++ */ ++dwc_otg_pcd_ep_t *get_ep_by_addr(dwc_otg_pcd_t * pcd, u16 wIndex) ++{ ++ dwc_otg_pcd_ep_t *ep; ++ uint32_t ep_num = UE_GET_ADDR(wIndex); ++ ++ if (ep_num == 0) { ++ ep = &pcd->ep0; ++ } else if (UE_GET_DIR(wIndex) == UE_DIR_IN) { /* in ep */ ++ ep = &pcd->in_ep[ep_num - 1]; ++ } else { ++ ep = &pcd->out_ep[ep_num - 1]; ++ } ++ ++ return ep; ++} ++ ++/** ++ * This function checks the EP request queue, if the queue is not ++ * empty the next request is started. ++ */ ++void start_next_request(dwc_otg_pcd_ep_t * ep) ++{ ++ dwc_otg_pcd_request_t *req = 0; ++ uint32_t max_transfer = ++ GET_CORE_IF(ep->pcd)->core_params->max_transfer_size; ++ ++#ifdef DWC_UTE_CFI ++ struct dwc_otg_pcd *pcd; ++ pcd = ep->pcd; ++#endif ++ ++ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ req = DWC_CIRCLEQ_FIRST(&ep->queue); ++ ++#ifdef DWC_UTE_CFI ++ if (ep->dwc_ep.buff_mode != BM_STANDARD) { ++ ep->dwc_ep.cfi_req_len = req->length; ++ pcd->cfi->ops.build_descriptors(pcd->cfi, pcd, ep, req); ++ } else { ++#endif ++ /* Setup and start the Transfer */ ++ if (req->dw_align_buf) { ++ ep->dwc_ep.dma_addr = req->dw_align_buf_dma; ++ ep->dwc_ep.start_xfer_buff = req->dw_align_buf; ++ ep->dwc_ep.xfer_buff = req->dw_align_buf; ++ } else { ++ ep->dwc_ep.dma_addr = req->dma; ++ ep->dwc_ep.start_xfer_buff = req->buf; ++ ep->dwc_ep.xfer_buff = req->buf; ++ } ++ ep->dwc_ep.sent_zlp = 0; ++ ep->dwc_ep.total_len = req->length; ++ ep->dwc_ep.xfer_len = 0; ++ ep->dwc_ep.xfer_count = 0; ++ ++ ep->dwc_ep.maxxfer = max_transfer; ++ if (GET_CORE_IF(ep->pcd)->dma_desc_enable) { ++ uint32_t out_max_xfer = DDMA_MAX_TRANSFER_SIZE ++ - (DDMA_MAX_TRANSFER_SIZE % 4); ++ if (ep->dwc_ep.is_in) { ++ if (ep->dwc_ep.maxxfer > ++ DDMA_MAX_TRANSFER_SIZE) { ++ ep->dwc_ep.maxxfer = ++ DDMA_MAX_TRANSFER_SIZE; ++ } ++ } else { ++ if (ep->dwc_ep.maxxfer > out_max_xfer) { ++ ep->dwc_ep.maxxfer = ++ out_max_xfer; ++ } ++ } ++ } ++ if (ep->dwc_ep.maxxfer < ep->dwc_ep.total_len) { ++ ep->dwc_ep.maxxfer -= ++ (ep->dwc_ep.maxxfer % ep->dwc_ep.maxpacket); ++ } ++ if (req->sent_zlp) { ++ if ((ep->dwc_ep.total_len % ++ ep->dwc_ep.maxpacket == 0) ++ && (ep->dwc_ep.total_len != 0)) { ++ ep->dwc_ep.sent_zlp = 1; ++ } ++ ++ } ++#ifdef DWC_UTE_CFI ++ } ++#endif ++ dwc_otg_ep_start_transfer(GET_CORE_IF(ep->pcd), &ep->dwc_ep); ++ } else if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) { ++ DWC_PRINTF("There are no more ISOC requests \n"); ++ ep->dwc_ep.frame_num = 0xFFFFFFFF; ++ } ++} ++ ++/** ++ * This function handles the SOF Interrupts. At this time the SOF ++ * Interrupt is disabled. ++ */ ++int32_t dwc_otg_pcd_handle_sof_intr(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ ++ gintsts_data_t gintsts; ++ ++ DWC_DEBUGPL(DBG_PCD, "SOF\n"); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.sofintr = 1; ++ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * This function handles the Rx Status Queue Level Interrupt, which ++ * indicates that there is a least one packet in the Rx FIFO. The ++ * packets are moved from the FIFO to memory, where they will be ++ * processed when the Endpoint Interrupt Register indicates Transfer ++ * Complete or SETUP Phase Done. ++ * ++ * Repeat the following until the Rx Status Queue is empty: ++ * -# Read the Receive Status Pop Register (GRXSTSP) to get Packet ++ * info ++ * -# If Receive FIFO is empty then skip to step Clear the interrupt ++ * and exit ++ * -# If SETUP Packet call dwc_otg_read_setup_packet to copy the ++ * SETUP data to the buffer ++ * -# If OUT Data Packet call dwc_otg_read_packet to copy the data ++ * to the destination buffer ++ */ ++int32_t dwc_otg_pcd_handle_rx_status_q_level_intr(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; ++ gintmsk_data_t gintmask = {.d32 = 0 }; ++ device_grxsts_data_t status; ++ dwc_otg_pcd_ep_t *ep; ++ gintsts_data_t gintsts; ++#ifdef DEBUG ++ static char *dpid_str[] = { "D0", "D2", "D1", "MDATA" }; ++#endif ++ ++ //DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _pcd); ++ /* Disable the Rx Status Queue Level interrupt */ ++ gintmask.b.rxstsqlvl = 1; ++ DWC_MODIFY_REG32(&global_regs->gintmsk, gintmask.d32, 0); ++ ++ /* Get the Status from the top of the FIFO */ ++ status.d32 = DWC_READ_REG32(&global_regs->grxstsp); ++ ++ DWC_DEBUGPL(DBG_PCD, "EP:%d BCnt:%d DPID:%s " ++ "pktsts:%x Frame:%d(0x%0x)\n", ++ status.b.epnum, status.b.bcnt, ++ dpid_str[status.b.dpid], ++ status.b.pktsts, status.b.fn, status.b.fn); ++ /* Get pointer to EP structure */ ++ ep = get_out_ep(pcd, status.b.epnum); ++ ++ switch (status.b.pktsts) { ++ case DWC_DSTS_GOUT_NAK: ++ DWC_DEBUGPL(DBG_PCDV, "Global OUT NAK\n"); ++ break; ++ case DWC_STS_DATA_UPDT: ++ DWC_DEBUGPL(DBG_PCDV, "OUT Data Packet\n"); ++ if (status.b.bcnt && ep->dwc_ep.xfer_buff) { ++ /** @todo NGS Check for buffer overflow? */ ++ dwc_otg_read_packet(core_if, ++ ep->dwc_ep.xfer_buff, ++ status.b.bcnt); ++ ep->dwc_ep.xfer_count += status.b.bcnt; ++ ep->dwc_ep.xfer_buff += status.b.bcnt; ++ } ++ break; ++ case DWC_STS_XFER_COMP: ++ DWC_DEBUGPL(DBG_PCDV, "OUT Complete\n"); ++ break; ++ case DWC_DSTS_SETUP_COMP: ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCDV, "Setup Complete\n"); ++#endif ++ break; ++ case DWC_DSTS_SETUP_UPDT: ++ dwc_otg_read_setup_packet(core_if, pcd->setup_pkt->d32); ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCD, ++ "SETUP PKT: %02x.%02x v%04x i%04x l%04x\n", ++ pcd->setup_pkt->req.bmRequestType, ++ pcd->setup_pkt->req.bRequest, ++ UGETW(pcd->setup_pkt->req.wValue), ++ UGETW(pcd->setup_pkt->req.wIndex), ++ UGETW(pcd->setup_pkt->req.wLength)); ++#endif ++ ep->dwc_ep.xfer_count += status.b.bcnt; ++ break; ++ default: ++ DWC_DEBUGPL(DBG_PCDV, "Invalid Packet Status (0x%0x)\n", ++ status.b.pktsts); ++ break; ++ } ++ ++ /* Enable the Rx Status Queue Level interrupt */ ++ DWC_MODIFY_REG32(&global_regs->gintmsk, 0, gintmask.d32); ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.rxstsqlvl = 1; ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ //DWC_DEBUGPL(DBG_PCDV, "EXIT: %s\n", __func__); ++ return 1; ++} ++ ++/** ++ * This function examines the Device IN Token Learning Queue to ++ * determine the EP number of the last IN token received. This ++ * implementation is for the Mass Storage device where there are only ++ * 2 IN EPs (Control-IN and BULK-IN). ++ * ++ * The EP numbers for the first six IN Tokens are in DTKNQR1 and there ++ * are 8 EP Numbers in each of the other possible DTKNQ Registers. ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ * ++ */ ++static inline int get_ep_of_last_in_token(dwc_otg_core_if_t * core_if) ++{ ++ dwc_otg_device_global_regs_t *dev_global_regs = ++ core_if->dev_if->dev_global_regs; ++ const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth; ++ /* Number of Token Queue Registers */ ++ const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8; ++ dtknq1_data_t dtknqr1; ++ uint32_t in_tkn_epnums[4]; ++ int ndx = 0; ++ int i = 0; ++ volatile uint32_t *addr = &dev_global_regs->dtknqr1; ++ int epnum = 0; ++ ++ //DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH); ++ ++ /* Read the DTKNQ Registers */ ++ for (i = 0; i < DTKNQ_REG_CNT; i++) { ++ in_tkn_epnums[i] = DWC_READ_REG32(addr); ++ DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1, ++ in_tkn_epnums[i]); ++ if (addr == &dev_global_regs->dvbusdis) { ++ addr = &dev_global_regs->dtknqr3_dthrctl; ++ } else { ++ ++addr; ++ } ++ ++ } ++ ++ /* Copy the DTKNQR1 data to the bit field. */ ++ dtknqr1.d32 = in_tkn_epnums[0]; ++ /* Get the EP numbers */ ++ in_tkn_epnums[0] = dtknqr1.b.epnums0_5; ++ ndx = dtknqr1.b.intknwptr - 1; ++ ++ //DWC_DEBUGPL(DBG_PCDV,"ndx=%d\n",ndx); ++ if (ndx == -1) { ++ /** @todo Find a simpler way to calculate the max ++ * queue position.*/ ++ int cnt = TOKEN_Q_DEPTH; ++ if (TOKEN_Q_DEPTH <= 6) { ++ cnt = TOKEN_Q_DEPTH - 1; ++ } else if (TOKEN_Q_DEPTH <= 14) { ++ cnt = TOKEN_Q_DEPTH - 7; ++ } else if (TOKEN_Q_DEPTH <= 22) { ++ cnt = TOKEN_Q_DEPTH - 15; ++ } else { ++ cnt = TOKEN_Q_DEPTH - 23; ++ } ++ epnum = (in_tkn_epnums[DTKNQ_REG_CNT - 1] >> (cnt * 4)) & 0xF; ++ } else { ++ if (ndx <= 5) { ++ epnum = (in_tkn_epnums[0] >> (ndx * 4)) & 0xF; ++ } else if (ndx <= 13) { ++ ndx -= 6; ++ epnum = (in_tkn_epnums[1] >> (ndx * 4)) & 0xF; ++ } else if (ndx <= 21) { ++ ndx -= 14; ++ epnum = (in_tkn_epnums[2] >> (ndx * 4)) & 0xF; ++ } else if (ndx <= 29) { ++ ndx -= 22; ++ epnum = (in_tkn_epnums[3] >> (ndx * 4)) & 0xF; ++ } ++ } ++ //DWC_DEBUGPL(DBG_PCD,"epnum=%d\n",epnum); ++ return epnum; ++} ++ ++/** ++ * This interrupt occurs when the non-periodic Tx FIFO is half-empty. ++ * The active request is checked for the next packet to be loaded into ++ * the non-periodic Tx FIFO. ++ */ ++int32_t dwc_otg_pcd_handle_np_tx_fifo_empty_intr(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; ++ dwc_otg_dev_in_ep_regs_t *ep_regs; ++ gnptxsts_data_t txstatus = {.d32 = 0 }; ++ gintsts_data_t gintsts; ++ ++ int epnum = 0; ++ dwc_otg_pcd_ep_t *ep = 0; ++ uint32_t len = 0; ++ int dwords; ++ ++ /* Get the epnum from the IN Token Learning Queue. */ ++ epnum = get_ep_of_last_in_token(core_if); ++ ep = get_in_ep(pcd, epnum); ++ ++ DWC_DEBUGPL(DBG_PCD, "NP TxFifo Empty: %d \n", epnum); ++ ++ ep_regs = core_if->dev_if->in_ep_regs[epnum]; ++ ++ len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count; ++ if (len > ep->dwc_ep.maxpacket) { ++ len = ep->dwc_ep.maxpacket; ++ } ++ dwords = (len + 3) / 4; ++ ++ /* While there is space in the queue and space in the FIFO and ++ * More data to tranfer, Write packets to the Tx FIFO */ ++ txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts); ++ DWC_DEBUGPL(DBG_PCDV, "b4 GNPTXSTS=0x%08x\n", txstatus.d32); ++ ++ while (txstatus.b.nptxqspcavail > 0 && ++ txstatus.b.nptxfspcavail > dwords && ++ ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len) { ++ /* Write the FIFO */ ++ dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0); ++ len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count; ++ ++ if (len > ep->dwc_ep.maxpacket) { ++ len = ep->dwc_ep.maxpacket; ++ } ++ ++ dwords = (len + 3) / 4; ++ txstatus.d32 = DWC_READ_REG32(&global_regs->gnptxsts); ++ DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", txstatus.d32); ++ } ++ ++ DWC_DEBUGPL(DBG_PCDV, "GNPTXSTS=0x%08x\n", ++ DWC_READ_REG32(&global_regs->gnptxsts)); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.nptxfempty = 1; ++ DWC_WRITE_REG32(&global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * This function is called when dedicated Tx FIFO Empty interrupt occurs. ++ * The active request is checked for the next packet to be loaded into ++ * apropriate Tx FIFO. ++ */ ++static int32_t write_empty_tx_fifo(dwc_otg_pcd_t * pcd, uint32_t epnum) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dwc_otg_dev_if_t *dev_if = core_if->dev_if; ++ dwc_otg_dev_in_ep_regs_t *ep_regs; ++ dtxfsts_data_t txstatus = {.d32 = 0 }; ++ dwc_otg_pcd_ep_t *ep = 0; ++ uint32_t len = 0; ++ int dwords; ++ ++ ep = get_in_ep(pcd, epnum); ++ ++ DWC_DEBUGPL(DBG_PCD, "Dedicated TxFifo Empty: %d \n", epnum); ++ ++ ep_regs = core_if->dev_if->in_ep_regs[epnum]; ++ ++ len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count; ++ ++ if (len > ep->dwc_ep.maxpacket) { ++ len = ep->dwc_ep.maxpacket; ++ } ++ ++ dwords = (len + 3) / 4; ++ ++ /* While there is space in the queue and space in the FIFO and ++ * More data to tranfer, Write packets to the Tx FIFO */ ++ txstatus.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts); ++ DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, txstatus.d32); ++ ++ while (txstatus.b.txfspcavail > dwords && ++ ep->dwc_ep.xfer_count < ep->dwc_ep.xfer_len && ++ ep->dwc_ep.xfer_len != 0) { ++ /* Write the FIFO */ ++ dwc_otg_ep_write_packet(core_if, &ep->dwc_ep, 0); ++ ++ len = ep->dwc_ep.xfer_len - ep->dwc_ep.xfer_count; ++ if (len > ep->dwc_ep.maxpacket) { ++ len = ep->dwc_ep.maxpacket; ++ } ++ ++ dwords = (len + 3) / 4; ++ txstatus.d32 = ++ DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts); ++ DWC_DEBUGPL(DBG_PCDV, "dtxfsts[%d]=0x%08x\n", epnum, ++ txstatus.d32); ++ } ++ ++ DWC_DEBUGPL(DBG_PCDV, "b4 dtxfsts[%d]=0x%08x\n", epnum, ++ DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dtxfsts)); ++ ++ return 1; ++} ++ ++/** ++ * This function is called when the Device is disconnected. It stops ++ * any active requests and informs the Gadget driver of the ++ * disconnect. ++ */ ++void dwc_otg_pcd_stop(dwc_otg_pcd_t * pcd) ++{ ++ int i, num_in_eps, num_out_eps; ++ dwc_otg_pcd_ep_t *ep; ++ ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ ++ DWC_SPINLOCK(pcd->lock); ++ ++ num_in_eps = GET_CORE_IF(pcd)->dev_if->num_in_eps; ++ num_out_eps = GET_CORE_IF(pcd)->dev_if->num_out_eps; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s() \n", __func__); ++ /* don't disconnect drivers more than once */ ++ if (pcd->ep0state == EP0_DISCONNECT) { ++ DWC_DEBUGPL(DBG_ANY, "%s() Already Disconnected\n", __func__); ++ DWC_SPINUNLOCK(pcd->lock); ++ return; ++ } ++ pcd->ep0state = EP0_DISCONNECT; ++ ++ /* Reset the OTG state. */ ++ dwc_otg_pcd_update_otg(pcd, 1); ++ ++ /* Disable the NP Tx Fifo Empty Interrupt. */ ++ intr_mask.b.nptxfempty = 1; ++ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, ++ intr_mask.d32, 0); ++ ++ /* Flush the FIFOs */ ++ /**@todo NGS Flush Periodic FIFOs */ ++ dwc_otg_flush_tx_fifo(GET_CORE_IF(pcd), 0x10); ++ dwc_otg_flush_rx_fifo(GET_CORE_IF(pcd)); ++ ++ /* prevent new request submissions, kill any outstanding requests */ ++ ep = &pcd->ep0; ++ dwc_otg_request_nuke(ep); ++ /* prevent new request submissions, kill any outstanding requests */ ++ for (i = 0; i < num_in_eps; i++) { ++ dwc_otg_pcd_ep_t *ep = &pcd->in_ep[i]; ++ dwc_otg_request_nuke(ep); ++ } ++ /* prevent new request submissions, kill any outstanding requests */ ++ for (i = 0; i < num_out_eps; i++) { ++ dwc_otg_pcd_ep_t *ep = &pcd->out_ep[i]; ++ dwc_otg_request_nuke(ep); ++ } ++ ++ /* report disconnect; the driver is already quiesced */ ++ if (pcd->fops->disconnect) { ++ DWC_SPINUNLOCK(pcd->lock); ++ pcd->fops->disconnect(pcd); ++ DWC_SPINLOCK(pcd->lock); ++ } ++ DWC_SPINUNLOCK(pcd->lock); ++} ++ ++/** ++ * This interrupt indicates that ... ++ */ ++int32_t dwc_otg_pcd_handle_i2c_intr(dwc_otg_pcd_t * pcd) ++{ ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ gintsts_data_t gintsts; ++ ++ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "i2cintr"); ++ intr_mask.b.i2cintr = 1; ++ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, ++ intr_mask.d32, 0); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.i2cintr = 1; ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, ++ gintsts.d32); ++ return 1; ++} ++ ++/** ++ * This interrupt indicates that ... ++ */ ++int32_t dwc_otg_pcd_handle_early_suspend_intr(dwc_otg_pcd_t * pcd) ++{ ++ gintsts_data_t gintsts; ++#if defined(VERBOSE) ++ DWC_PRINTF("Early Suspend Detected\n"); ++#endif ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.erlysuspend = 1; ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, ++ gintsts.d32); ++ return 1; ++} ++ ++/** ++ * This function configures EPO to receive SETUP packets. ++ * ++ * @todo NGS: Update the comments from the HW FS. ++ * ++ * -# Program the following fields in the endpoint specific registers ++ * for Control OUT EP 0, in order to receive a setup packet ++ * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back ++ * setup packets) ++ * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back ++ * to back setup packets) ++ * - In DMA mode, DOEPDMA0 Register with a memory address to ++ * store any setup packets received ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ * @param pcd Programming view of the PCD. ++ */ ++static inline void ep0_out_start(dwc_otg_core_if_t * core_if, ++ dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_dev_if_t *dev_if = core_if->dev_if; ++ deptsiz0_data_t doeptsize0 = {.d32 = 0 }; ++ dwc_otg_dev_dma_desc_t *dma_desc; ++ depctl_data_t doepctl = {.d32 = 0 }; ++ ++#ifdef VERBOSE ++ DWC_DEBUGPL(DBG_PCDV, "%s() doepctl0=%0x\n", __func__, ++ DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl)); ++#endif ++ if (core_if->snpsid >= OTG_CORE_REV_3_00a) { ++ doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl); ++ if (doepctl.b.epena) { ++ return; ++ } ++ } ++ ++ doeptsize0.b.supcnt = 3; ++ doeptsize0.b.pktcnt = 1; ++ doeptsize0.b.xfersize = 8 * 3; ++ ++ if (core_if->dma_enable) { ++ if (!core_if->dma_desc_enable) { ++ /** put here as for Hermes mode deptisz register should not be written */ ++ DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz, ++ doeptsize0.d32); ++ ++ /** @todo dma needs to handle multiple setup packets (up to 3) */ ++ DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma, ++ pcd->setup_pkt_dma_handle); ++ } else { ++ dev_if->setup_desc_index = ++ (dev_if->setup_desc_index + 1) & 1; ++ dma_desc = ++ dev_if->setup_desc_addr[dev_if->setup_desc_index]; ++ ++ /** DMA Descriptor Setup */ ++ dma_desc->status.b.bs = BS_HOST_BUSY; ++ if (core_if->snpsid >= OTG_CORE_REV_3_00a) { ++ dma_desc->status.b.sr = 0; ++ dma_desc->status.b.mtrf = 0; ++ } ++ dma_desc->status.b.l = 1; ++ dma_desc->status.b.ioc = 1; ++ dma_desc->status.b.bytes = pcd->ep0.dwc_ep.maxpacket; ++ dma_desc->buf = pcd->setup_pkt_dma_handle; ++ dma_desc->status.b.sts = 0; ++ dma_desc->status.b.bs = BS_HOST_READY; ++ ++ /** DOEPDMA0 Register write */ ++ DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepdma, ++ dev_if->dma_setup_desc_addr ++ [dev_if->setup_desc_index]); ++ } ++ ++ } else { ++ /** put here as for Hermes mode deptisz register should not be written */ ++ DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doeptsiz, ++ doeptsize0.d32); ++ } ++ ++ /** DOEPCTL0 Register write cnak will be set after setup interrupt */ ++ doepctl.d32 = 0; ++ doepctl.b.epena = 1; ++ if (core_if->snpsid <= OTG_CORE_REV_2_94a) { ++ doepctl.b.cnak = 1; ++ DWC_WRITE_REG32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32); ++ } else { ++ DWC_MODIFY_REG32(&dev_if->out_ep_regs[0]->doepctl, 0, doepctl.d32); ++ } ++ ++#ifdef VERBOSE ++ DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n", ++ DWC_READ_REG32(&dev_if->out_ep_regs[0]->doepctl)); ++ DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n", ++ DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl)); ++#endif ++} ++ ++/** ++ * This interrupt occurs when a USB Reset is detected. When the USB ++ * Reset Interrupt occurs the device state is set to DEFAULT and the ++ * EP0 state is set to IDLE. ++ * -# Set the NAK bit for all OUT endpoints (DOEPCTLn.SNAK = 1) ++ * -# Unmask the following interrupt bits ++ * - DAINTMSK.INEP0 = 1 (Control 0 IN endpoint) ++ * - DAINTMSK.OUTEP0 = 1 (Control 0 OUT endpoint) ++ * - DOEPMSK.SETUP = 1 ++ * - DOEPMSK.XferCompl = 1 ++ * - DIEPMSK.XferCompl = 1 ++ * - DIEPMSK.TimeOut = 1 ++ * -# Program the following fields in the endpoint specific registers ++ * for Control OUT EP 0, in order to receive a setup packet ++ * - DOEPTSIZ0.Packet Count = 3 (To receive up to 3 back to back ++ * setup packets) ++ * - DOEPTSIZE0.Transfer Size = 24 Bytes (To receive up to 3 back ++ * to back setup packets) ++ * - In DMA mode, DOEPDMA0 Register with a memory address to ++ * store any setup packets received ++ * At this point, all the required initialization, except for enabling ++ * the control 0 OUT endpoint is done, for receiving SETUP packets. ++ */ ++int32_t dwc_otg_pcd_handle_usb_reset_intr(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dwc_otg_dev_if_t *dev_if = core_if->dev_if; ++ depctl_data_t doepctl = {.d32 = 0 }; ++ depctl_data_t diepctl = {.d32 = 0 }; ++ daint_data_t daintmsk = {.d32 = 0 }; ++ doepmsk_data_t doepmsk = {.d32 = 0 }; ++ diepmsk_data_t diepmsk = {.d32 = 0 }; ++ dcfg_data_t dcfg = {.d32 = 0 }; ++ grstctl_t resetctl = {.d32 = 0 }; ++ dctl_data_t dctl = {.d32 = 0 }; ++ int i = 0; ++ gintsts_data_t gintsts; ++ pcgcctl_data_t power = {.d32 = 0 }; ++ ++ power.d32 = DWC_READ_REG32(core_if->pcgcctl); ++ if (power.b.stoppclk) { ++ power.d32 = 0; ++ power.b.stoppclk = 1; ++ DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0); ++ ++ power.b.pwrclmp = 1; ++ DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0); ++ ++ power.b.rstpdwnmodule = 1; ++ DWC_MODIFY_REG32(core_if->pcgcctl, power.d32, 0); ++ } ++ ++ core_if->lx_state = DWC_OTG_L0; ++ ++ DWC_PRINTF("USB RESET\n"); ++#ifdef DWC_EN_ISOC ++ for (i = 1; i < 16; ++i) { ++ dwc_otg_pcd_ep_t *ep; ++ dwc_ep_t *dwc_ep; ++ ep = get_in_ep(pcd, i); ++ if (ep != 0) { ++ dwc_ep = &ep->dwc_ep; ++ dwc_ep->next_frame = 0xffffffff; ++ } ++ } ++#endif /* DWC_EN_ISOC */ ++ ++ /* reset the HNP settings */ ++ dwc_otg_pcd_update_otg(pcd, 1); ++ ++ /* Clear the Remote Wakeup Signalling */ ++ dctl.b.rmtwkupsig = 1; ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, 0); ++ ++ /* Set NAK for all OUT EPs */ ++ doepctl.b.snak = 1; ++ for (i = 0; i <= dev_if->num_out_eps; i++) { ++ DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32); ++ } ++ ++ /* Flush the NP Tx FIFO */ ++ dwc_otg_flush_tx_fifo(core_if, 0x10); ++ /* Flush the Learning Queue */ ++ resetctl.b.intknqflsh = 1; ++ DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32); ++ ++ if (!core_if->core_params->en_multiple_tx_fifo && core_if->dma_enable) { ++ core_if->start_predict = 0; ++ for (i = 0; i<= core_if->dev_if->num_in_eps; ++i) { ++ core_if->nextep_seq[i] = 0xff; // 0xff - EP not active ++ } ++ core_if->nextep_seq[0] = 0; ++ core_if->first_in_nextep_seq = 0; ++ diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[0]->diepctl); ++ diepctl.b.nextep = 0; ++ DWC_WRITE_REG32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32); ++ ++ /* Update IN Endpoint Mismatch Count by active IN NP EP count + 1 */ ++ dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg); ++ dcfg.b.epmscnt = 2; ++ DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32); ++ ++ DWC_DEBUGPL(DBG_PCDV, ++ "%s first_in_nextep_seq= %2d; nextep_seq[]:\n", ++ __func__, core_if->first_in_nextep_seq); ++ for (i=0; i <= core_if->dev_if->num_in_eps; i++) { ++ DWC_DEBUGPL(DBG_PCDV, "%2d\n", core_if->nextep_seq[i]); ++ } ++ } ++ ++ if (core_if->multiproc_int_enable) { ++ daintmsk.b.inep0 = 1; ++ daintmsk.b.outep0 = 1; ++ DWC_WRITE_REG32(&dev_if->dev_global_regs->deachintmsk, ++ daintmsk.d32); ++ ++ doepmsk.b.setup = 1; ++ doepmsk.b.xfercompl = 1; ++ doepmsk.b.ahberr = 1; ++ doepmsk.b.epdisabled = 1; ++ ++ if ((core_if->dma_desc_enable) || ++ (core_if->dma_enable ++ && core_if->snpsid >= OTG_CORE_REV_3_00a)) { ++ doepmsk.b.stsphsercvd = 1; ++ } ++ if (core_if->dma_desc_enable) ++ doepmsk.b.bna = 1; ++/* ++ doepmsk.b.babble = 1; ++ doepmsk.b.nyet = 1; ++ ++ if (core_if->dma_enable) { ++ doepmsk.b.nak = 1; ++ } ++*/ ++ DWC_WRITE_REG32(&dev_if->dev_global_regs->doepeachintmsk[0], ++ doepmsk.d32); ++ ++ diepmsk.b.xfercompl = 1; ++ diepmsk.b.timeout = 1; ++ diepmsk.b.epdisabled = 1; ++ diepmsk.b.ahberr = 1; ++ diepmsk.b.intknepmis = 1; ++ if (!core_if->en_multiple_tx_fifo && core_if->dma_enable) ++ diepmsk.b.intknepmis = 0; ++ ++/* if (core_if->dma_desc_enable) { ++ diepmsk.b.bna = 1; ++ } ++*/ ++/* ++ if (core_if->dma_enable) { ++ diepmsk.b.nak = 1; ++ } ++*/ ++ DWC_WRITE_REG32(&dev_if->dev_global_regs->diepeachintmsk[0], ++ diepmsk.d32); ++ } else { ++ daintmsk.b.inep0 = 1; ++ daintmsk.b.outep0 = 1; ++ DWC_WRITE_REG32(&dev_if->dev_global_regs->daintmsk, ++ daintmsk.d32); ++ ++ doepmsk.b.setup = 1; ++ doepmsk.b.xfercompl = 1; ++ doepmsk.b.ahberr = 1; ++ doepmsk.b.epdisabled = 1; ++ ++ if ((core_if->dma_desc_enable) || ++ (core_if->dma_enable ++ && core_if->snpsid >= OTG_CORE_REV_3_00a)) { ++ doepmsk.b.stsphsercvd = 1; ++ } ++ if (core_if->dma_desc_enable) ++ doepmsk.b.bna = 1; ++ DWC_WRITE_REG32(&dev_if->dev_global_regs->doepmsk, doepmsk.d32); ++ ++ diepmsk.b.xfercompl = 1; ++ diepmsk.b.timeout = 1; ++ diepmsk.b.epdisabled = 1; ++ diepmsk.b.ahberr = 1; ++ if (!core_if->en_multiple_tx_fifo && core_if->dma_enable) ++ diepmsk.b.intknepmis = 0; ++/* ++ if (core_if->dma_desc_enable) { ++ diepmsk.b.bna = 1; ++ } ++*/ ++ ++ DWC_WRITE_REG32(&dev_if->dev_global_regs->diepmsk, diepmsk.d32); ++ } ++ ++ /* Reset Device Address */ ++ dcfg.d32 = DWC_READ_REG32(&dev_if->dev_global_regs->dcfg); ++ dcfg.b.devaddr = 0; ++ DWC_WRITE_REG32(&dev_if->dev_global_regs->dcfg, dcfg.d32); ++ ++ /* setup EP0 to receive SETUP packets */ ++ if (core_if->snpsid <= OTG_CORE_REV_2_94a) ++ ep0_out_start(core_if, pcd); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.usbreset = 1; ++ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * Get the device speed from the device status register and convert it ++ * to USB speed constant. ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ */ ++static int get_device_speed(dwc_otg_core_if_t * core_if) ++{ ++ dsts_data_t dsts; ++ int speed = 0; ++ dsts.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dsts); ++ ++ switch (dsts.b.enumspd) { ++ case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: ++ speed = USB_SPEED_HIGH; ++ break; ++ case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: ++ case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ: ++ speed = USB_SPEED_FULL; ++ break; ++ ++ case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ: ++ speed = USB_SPEED_LOW; ++ break; ++ } ++ ++ return speed; ++} ++ ++/** ++ * Read the device status register and set the device speed in the ++ * data structure. ++ * Set up EP0 to receive SETUP packets by calling dwc_ep0_activate. ++ */ ++int32_t dwc_otg_pcd_handle_enum_done_intr(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; ++ gintsts_data_t gintsts; ++ gusbcfg_data_t gusbcfg; ++ dwc_otg_core_global_regs_t *global_regs = ++ GET_CORE_IF(pcd)->core_global_regs; ++ uint8_t utmi16b, utmi8b; ++ int speed; ++ DWC_DEBUGPL(DBG_PCD, "SPEED ENUM\n"); ++ ++ if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_2_60a) { ++ utmi16b = 6; //vahrama old value was 6; ++ utmi8b = 9; ++ } else { ++ utmi16b = 4; ++ utmi8b = 8; ++ } ++ dwc_otg_ep0_activate(GET_CORE_IF(pcd), &ep0->dwc_ep); ++ if (GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a) { ++ ep0_out_start(GET_CORE_IF(pcd), pcd); ++ } ++ ++#ifdef DEBUG_EP0 ++ print_ep0_state(pcd); ++#endif ++ ++ if (pcd->ep0state == EP0_DISCONNECT) { ++ pcd->ep0state = EP0_IDLE; ++ } else if (pcd->ep0state == EP0_STALL) { ++ pcd->ep0state = EP0_IDLE; ++ } ++ ++ pcd->ep0state = EP0_IDLE; ++ ++ ep0->stopped = 0; ++ ++ speed = get_device_speed(GET_CORE_IF(pcd)); ++ pcd->fops->connect(pcd, speed); ++ ++ /* Set USB turnaround time based on device speed and PHY interface. */ ++ gusbcfg.d32 = DWC_READ_REG32(&global_regs->gusbcfg); ++ if (speed == USB_SPEED_HIGH) { ++ if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type == ++ DWC_HWCFG2_HS_PHY_TYPE_ULPI) { ++ /* ULPI interface */ ++ gusbcfg.b.usbtrdtim = 9; ++ } ++ if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type == ++ DWC_HWCFG2_HS_PHY_TYPE_UTMI) { ++ /* UTMI+ interface */ ++ if (GET_CORE_IF(pcd)->hwcfg4.b.utmi_phy_data_width == 0) { ++ gusbcfg.b.usbtrdtim = utmi8b; ++ } else if (GET_CORE_IF(pcd)->hwcfg4. ++ b.utmi_phy_data_width == 1) { ++ gusbcfg.b.usbtrdtim = utmi16b; ++ } else if (GET_CORE_IF(pcd)-> ++ core_params->phy_utmi_width == 8) { ++ gusbcfg.b.usbtrdtim = utmi8b; ++ } else { ++ gusbcfg.b.usbtrdtim = utmi16b; ++ } ++ } ++ if (GET_CORE_IF(pcd)->hwcfg2.b.hs_phy_type == ++ DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI) { ++ /* UTMI+ OR ULPI interface */ ++ if (gusbcfg.b.ulpi_utmi_sel == 1) { ++ /* ULPI interface */ ++ gusbcfg.b.usbtrdtim = 9; ++ } else { ++ /* UTMI+ interface */ ++ if (GET_CORE_IF(pcd)-> ++ core_params->phy_utmi_width == 16) { ++ gusbcfg.b.usbtrdtim = utmi16b; ++ } else { ++ gusbcfg.b.usbtrdtim = utmi8b; ++ } ++ } ++ } ++ } else { ++ /* Full or low speed */ ++ gusbcfg.b.usbtrdtim = 9; ++ } ++ DWC_WRITE_REG32(&global_regs->gusbcfg, gusbcfg.d32); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.enumdone = 1; ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, ++ gintsts.d32); ++ return 1; ++} ++ ++/** ++ * This interrupt indicates that the ISO OUT Packet was dropped due to ++ * Rx FIFO full or Rx Status Queue Full. If this interrupt occurs ++ * read all the data from the Rx FIFO. ++ */ ++int32_t dwc_otg_pcd_handle_isoc_out_packet_dropped_intr(dwc_otg_pcd_t * pcd) ++{ ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ gintsts_data_t gintsts; ++ ++ DWC_WARN("INTERRUPT Handler not implemented for %s\n", ++ "ISOC Out Dropped"); ++ ++ intr_mask.b.isooutdrop = 1; ++ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, ++ intr_mask.d32, 0); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.isooutdrop = 1; ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, ++ gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * This interrupt indicates the end of the portion of the micro-frame ++ * for periodic transactions. If there is a periodic transaction for ++ * the next frame, load the packets into the EP periodic Tx FIFO. ++ */ ++int32_t dwc_otg_pcd_handle_end_periodic_frame_intr(dwc_otg_pcd_t * pcd) ++{ ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ gintsts_data_t gintsts; ++ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "EOP"); ++ ++ intr_mask.b.eopframe = 1; ++ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, ++ intr_mask.d32, 0); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.eopframe = 1; ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, ++ gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * This interrupt indicates that EP of the packet on the top of the ++ * non-periodic Tx FIFO does not match EP of the IN Token received. ++ * ++ * The "Device IN Token Queue" Registers are read to determine the ++ * order the IN Tokens have been received. The non-periodic Tx FIFO ++ * is flushed, so it can be reloaded in the order seen in the IN Token ++ * Queue. ++ */ ++int32_t dwc_otg_pcd_handle_ep_mismatch_intr(dwc_otg_pcd_t * pcd) ++{ ++ gintsts_data_t gintsts; ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dctl_data_t dctl; ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ ++ if (!core_if->en_multiple_tx_fifo && core_if->dma_enable) { ++ core_if->start_predict = 1; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if); ++ ++ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts); ++ if (!gintsts.b.ginnakeff) { ++ /* Disable EP Mismatch interrupt */ ++ intr_mask.d32 = 0; ++ intr_mask.b.epmismatch = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32, 0); ++ /* Enable the Global IN NAK Effective Interrupt */ ++ intr_mask.d32 = 0; ++ intr_mask.b.ginnakeff = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32); ++ /* Set the global non-periodic IN NAK handshake */ ++ dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl); ++ dctl.b.sgnpinnak = 1; ++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32); ++ } else { ++ DWC_PRINTF("gintsts.b.ginnakeff = 1! dctl.b.sgnpinnak not set\n"); ++ } ++ /* Disabling of all EP's will be done in dwc_otg_pcd_handle_in_nak_effective() ++ * handler after Global IN NAK Effective interrupt will be asserted */ ++ } ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.epmismatch = 1; ++ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * This interrupt is valid only in DMA mode. This interrupt indicates that the ++ * core has stopped fetching data for IN endpoints due to the unavailability of ++ * TxFIFO space or Request Queue space. This interrupt is used by the ++ * application for an endpoint mismatch algorithm. ++ * ++ * @param pcd The PCD ++ */ ++int32_t dwc_otg_pcd_handle_ep_fetsusp_intr(dwc_otg_pcd_t * pcd) ++{ ++ gintsts_data_t gintsts; ++ gintmsk_data_t gintmsk_data; ++ dctl_data_t dctl; ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, core_if); ++ ++ /* Clear the global non-periodic IN NAK handshake */ ++ dctl.d32 = 0; ++ dctl.b.cgnpinnak = 1; ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); ++ ++ /* Mask GINTSTS.FETSUSP interrupt */ ++ gintmsk_data.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk); ++ gintmsk_data.b.fetsusp = 0; ++ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_data.d32); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.fetsusp = 1; ++ DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts.d32); ++ ++ return 1; ++} ++/** ++ * This funcion stalls EP0. ++ */ ++static inline void ep0_do_stall(dwc_otg_pcd_t * pcd, const int err_val) ++{ ++ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; ++ usb_device_request_t *ctrl = &pcd->setup_pkt->req; ++ DWC_WARN("req %02x.%02x protocol STALL; err %d\n", ++ ctrl->bmRequestType, ctrl->bRequest, err_val); ++ ++ ep0->dwc_ep.is_in = 1; ++ dwc_otg_ep_set_stall(GET_CORE_IF(pcd), &ep0->dwc_ep); ++ pcd->ep0.stopped = 1; ++ pcd->ep0state = EP0_IDLE; ++ ep0_out_start(GET_CORE_IF(pcd), pcd); ++} ++ ++/** ++ * This functions delegates the setup command to the gadget driver. ++ */ ++static inline void do_gadget_setup(dwc_otg_pcd_t * pcd, ++ usb_device_request_t * ctrl) ++{ ++ int ret = 0; ++ DWC_SPINUNLOCK(pcd->lock); ++ ret = pcd->fops->setup(pcd, (uint8_t *) ctrl); ++ DWC_SPINLOCK(pcd->lock); ++ if (ret < 0) { ++ ep0_do_stall(pcd, ret); ++ } ++ ++ /** @todo This is a g_file_storage gadget driver specific ++ * workaround: a DELAYED_STATUS result from the fsg_setup ++ * routine will result in the gadget queueing a EP0 IN status ++ * phase for a two-stage control transfer. Exactly the same as ++ * a SET_CONFIGURATION/SET_INTERFACE except that this is a class ++ * specific request. Need a generic way to know when the gadget ++ * driver will queue the status phase. Can we assume when we ++ * call the gadget driver setup() function that it will always ++ * queue and require the following flag? Need to look into ++ * this. ++ */ ++ ++ if (ret == 256 + 999) { ++ pcd->request_config = 1; ++ } ++} ++ ++#ifdef DWC_UTE_CFI ++/** ++ * This functions delegates the CFI setup commands to the gadget driver. ++ * This function will return a negative value to indicate a failure. ++ */ ++static inline int cfi_gadget_setup(dwc_otg_pcd_t * pcd, ++ struct cfi_usb_ctrlrequest *ctrl_req) ++{ ++ int ret = 0; ++ ++ if (pcd->fops && pcd->fops->cfi_setup) { ++ DWC_SPINUNLOCK(pcd->lock); ++ ret = pcd->fops->cfi_setup(pcd, ctrl_req); ++ DWC_SPINLOCK(pcd->lock); ++ if (ret < 0) { ++ ep0_do_stall(pcd, ret); ++ return ret; ++ } ++ } ++ ++ return ret; ++} ++#endif ++ ++/** ++ * This function starts the Zero-Length Packet for the IN status phase ++ * of a 2 stage control transfer. ++ */ ++static inline void do_setup_in_status_phase(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; ++ if (pcd->ep0state == EP0_STALL) { ++ return; ++ } ++ ++ pcd->ep0state = EP0_IN_STATUS_PHASE; ++ ++ /* Prepare for more SETUP Packets */ ++ DWC_DEBUGPL(DBG_PCD, "EP0 IN ZLP\n"); ++ if ((GET_CORE_IF(pcd)->snpsid >= OTG_CORE_REV_3_00a) ++ && (pcd->core_if->dma_desc_enable) ++ && (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len)) { ++ DWC_DEBUGPL(DBG_PCDV, ++ "Data terminated wait next packet in out_desc_addr\n"); ++ pcd->backup_buf = phys_to_virt(ep0->dwc_ep.dma_addr); ++ pcd->data_terminated = 1; ++ } ++ ep0->dwc_ep.xfer_len = 0; ++ ep0->dwc_ep.xfer_count = 0; ++ ep0->dwc_ep.is_in = 1; ++ ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle; ++ dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep); ++ ++ /* Prepare for more SETUP Packets */ ++ //ep0_out_start(GET_CORE_IF(pcd), pcd); ++} ++ ++/** ++ * This function starts the Zero-Length Packet for the OUT status phase ++ * of a 2 stage control transfer. ++ */ ++static inline void do_setup_out_status_phase(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; ++ if (pcd->ep0state == EP0_STALL) { ++ DWC_DEBUGPL(DBG_PCD, "EP0 STALLED\n"); ++ return; ++ } ++ pcd->ep0state = EP0_OUT_STATUS_PHASE; ++ ++ DWC_DEBUGPL(DBG_PCD, "EP0 OUT ZLP\n"); ++ ep0->dwc_ep.xfer_len = 0; ++ ep0->dwc_ep.xfer_count = 0; ++ ep0->dwc_ep.is_in = 0; ++ ep0->dwc_ep.dma_addr = pcd->setup_pkt_dma_handle; ++ dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep); ++ ++ /* Prepare for more SETUP Packets */ ++ if (GET_CORE_IF(pcd)->dma_enable == 0) { ++ ep0_out_start(GET_CORE_IF(pcd), pcd); ++ } ++} ++ ++/** ++ * Clear the EP halt (STALL) and if pending requests start the ++ * transfer. ++ */ ++static inline void pcd_clear_halt(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep) ++{ ++ if (ep->dwc_ep.stall_clear_flag == 0) ++ dwc_otg_ep_clear_stall(GET_CORE_IF(pcd), &ep->dwc_ep); ++ ++ /* Reactive the EP */ ++ dwc_otg_ep_activate(GET_CORE_IF(pcd), &ep->dwc_ep); ++ if (ep->stopped) { ++ ep->stopped = 0; ++ /* If there is a request in the EP queue start it */ ++ ++ /** @todo FIXME: this causes an EP mismatch in DMA mode. ++ * epmismatch not yet implemented. */ ++ ++ /* ++ * Above fixme is solved by implmenting a tasklet to call the ++ * start_next_request(), outside of interrupt context at some ++ * time after the current time, after a clear-halt setup packet. ++ * Still need to implement ep mismatch in the future if a gadget ++ * ever uses more than one endpoint at once ++ */ ++ ep->queue_sof = 1; ++ DWC_TASK_SCHEDULE(pcd->start_xfer_tasklet); ++ } ++ /* Start Control Status Phase */ ++ do_setup_in_status_phase(pcd); ++} ++ ++/** ++ * This function is called when the SET_FEATURE TEST_MODE Setup packet ++ * is sent from the host. The Device Control register is written with ++ * the Test Mode bits set to the specified Test Mode. This is done as ++ * a tasklet so that the "Status" phase of the control transfer ++ * completes before transmitting the TEST packets. ++ * ++ * @todo This has not been tested since the tasklet struct was put ++ * into the PCD struct! ++ * ++ */ ++void do_test_mode(void *data) ++{ ++ dctl_data_t dctl; ++ dwc_otg_pcd_t *pcd = (dwc_otg_pcd_t *) data; ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ int test_mode = pcd->test_mode; ++ ++// DWC_WARN("%s() has not been tested since being rewritten!\n", __func__); ++ ++ dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl); ++ switch (test_mode) { ++ case 1: // TEST_J ++ dctl.b.tstctl = 1; ++ break; ++ ++ case 2: // TEST_K ++ dctl.b.tstctl = 2; ++ break; ++ ++ case 3: // TEST_SE0_NAK ++ dctl.b.tstctl = 3; ++ break; ++ ++ case 4: // TEST_PACKET ++ dctl.b.tstctl = 4; ++ break; ++ ++ case 5: // TEST_FORCE_ENABLE ++ dctl.b.tstctl = 5; ++ break; ++ } ++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32); ++} ++ ++/** ++ * This function process the GET_STATUS Setup Commands. ++ */ ++static inline void do_get_status(dwc_otg_pcd_t * pcd) ++{ ++ usb_device_request_t ctrl = pcd->setup_pkt->req; ++ dwc_otg_pcd_ep_t *ep; ++ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; ++ uint16_t *status = pcd->status_buf; ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCD, ++ "GET_STATUS %02x.%02x v%04x i%04x l%04x\n", ++ ctrl.bmRequestType, ctrl.bRequest, ++ UGETW(ctrl.wValue), UGETW(ctrl.wIndex), ++ UGETW(ctrl.wLength)); ++#endif ++ ++ switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) { ++ case UT_DEVICE: ++ if(UGETW(ctrl.wIndex) == 0xF000) { /* OTG Status selector */ ++ DWC_PRINTF("wIndex - %d\n", UGETW(ctrl.wIndex)); ++ DWC_PRINTF("OTG VERSION - %d\n", core_if->otg_ver); ++ DWC_PRINTF("OTG CAP - %d, %d\n", ++ core_if->core_params->otg_cap, ++ DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE); ++ if (core_if->otg_ver == 1 ++ && core_if->core_params->otg_cap == ++ DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) { ++ uint8_t *otgsts = (uint8_t*)pcd->status_buf; ++ *otgsts = (core_if->otg_sts & 0x1); ++ pcd->ep0_pending = 1; ++ ep0->dwc_ep.start_xfer_buff = ++ (uint8_t *) otgsts; ++ ep0->dwc_ep.xfer_buff = (uint8_t *) otgsts; ++ ep0->dwc_ep.dma_addr = ++ pcd->status_buf_dma_handle; ++ ep0->dwc_ep.xfer_len = 1; ++ ep0->dwc_ep.xfer_count = 0; ++ ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len; ++ dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), ++ &ep0->dwc_ep); ++ return; ++ } else { ++ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); ++ return; ++ } ++ break; ++ } else { ++ *status = 0x1; /* Self powered */ ++ *status |= pcd->remote_wakeup_enable << 1; ++ break; ++ } ++ case UT_INTERFACE: ++ *status = 0; ++ break; ++ ++ case UT_ENDPOINT: ++ ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex)); ++ if (ep == 0 || UGETW(ctrl.wLength) > 2) { ++ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); ++ return; ++ } ++ /** @todo check for EP stall */ ++ *status = ep->stopped; ++ break; ++ } ++ pcd->ep0_pending = 1; ++ ep0->dwc_ep.start_xfer_buff = (uint8_t *) status; ++ ep0->dwc_ep.xfer_buff = (uint8_t *) status; ++ ep0->dwc_ep.dma_addr = pcd->status_buf_dma_handle; ++ ep0->dwc_ep.xfer_len = 2; ++ ep0->dwc_ep.xfer_count = 0; ++ ep0->dwc_ep.total_len = ep0->dwc_ep.xfer_len; ++ dwc_otg_ep0_start_transfer(GET_CORE_IF(pcd), &ep0->dwc_ep); ++} ++ ++/** ++ * This function process the SET_FEATURE Setup Commands. ++ */ ++static inline void do_set_feature(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; ++ usb_device_request_t ctrl = pcd->setup_pkt->req; ++ dwc_otg_pcd_ep_t *ep = 0; ++ int32_t otg_cap_param = core_if->core_params->otg_cap; ++ gotgctl_data_t gotgctl = {.d32 = 0 }; ++ ++ DWC_DEBUGPL(DBG_PCD, "SET_FEATURE:%02x.%02x v%04x i%04x l%04x\n", ++ ctrl.bmRequestType, ctrl.bRequest, ++ UGETW(ctrl.wValue), UGETW(ctrl.wIndex), ++ UGETW(ctrl.wLength)); ++ DWC_DEBUGPL(DBG_PCD, "otg_cap=%d\n", otg_cap_param); ++ ++ switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) { ++ case UT_DEVICE: ++ switch (UGETW(ctrl.wValue)) { ++ case UF_DEVICE_REMOTE_WAKEUP: ++ pcd->remote_wakeup_enable = 1; ++ break; ++ ++ case UF_TEST_MODE: ++ /* Setup the Test Mode tasklet to do the Test ++ * Packet generation after the SETUP Status ++ * phase has completed. */ ++ ++ /** @todo This has not been tested since the ++ * tasklet struct was put into the PCD ++ * struct! */ ++ pcd->test_mode = UGETW(ctrl.wIndex) >> 8; ++ DWC_TASK_SCHEDULE(pcd->test_mode_tasklet); ++ break; ++ ++ case UF_DEVICE_B_HNP_ENABLE: ++ DWC_DEBUGPL(DBG_PCDV, ++ "SET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n"); ++ ++ /* dev may initiate HNP */ ++ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) { ++ pcd->b_hnp_enable = 1; ++ dwc_otg_pcd_update_otg(pcd, 0); ++ DWC_DEBUGPL(DBG_PCD, "Request B HNP\n"); ++ /**@todo Is the gotgctl.devhnpen cleared ++ * by a USB Reset? */ ++ gotgctl.b.devhnpen = 1; ++ gotgctl.b.hnpreq = 1; ++ DWC_WRITE_REG32(&global_regs->gotgctl, ++ gotgctl.d32); ++ } else { ++ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); ++ return; ++ } ++ break; ++ ++ case UF_DEVICE_A_HNP_SUPPORT: ++ /* RH port supports HNP */ ++ DWC_DEBUGPL(DBG_PCDV, ++ "SET_FEATURE: USB_DEVICE_A_HNP_SUPPORT\n"); ++ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) { ++ pcd->a_hnp_support = 1; ++ dwc_otg_pcd_update_otg(pcd, 0); ++ } else { ++ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); ++ return; ++ } ++ break; ++ ++ case UF_DEVICE_A_ALT_HNP_SUPPORT: ++ /* other RH port does */ ++ DWC_DEBUGPL(DBG_PCDV, ++ "SET_FEATURE: USB_DEVICE_A_ALT_HNP_SUPPORT\n"); ++ if (otg_cap_param == DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE) { ++ pcd->a_alt_hnp_support = 1; ++ dwc_otg_pcd_update_otg(pcd, 0); ++ } else { ++ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); ++ return; ++ } ++ break; ++ ++ default: ++ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); ++ return; ++ ++ } ++ do_setup_in_status_phase(pcd); ++ break; ++ ++ case UT_INTERFACE: ++ do_gadget_setup(pcd, &ctrl); ++ break; ++ ++ case UT_ENDPOINT: ++ if (UGETW(ctrl.wValue) == UF_ENDPOINT_HALT) { ++ ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex)); ++ if (ep == 0) { ++ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); ++ return; ++ } ++ ep->stopped = 1; ++ dwc_otg_ep_set_stall(core_if, &ep->dwc_ep); ++ } ++ do_setup_in_status_phase(pcd); ++ break; ++ } ++} ++ ++/** ++ * This function process the CLEAR_FEATURE Setup Commands. ++ */ ++static inline void do_clear_feature(dwc_otg_pcd_t * pcd) ++{ ++ usb_device_request_t ctrl = pcd->setup_pkt->req; ++ dwc_otg_pcd_ep_t *ep = 0; ++ ++ DWC_DEBUGPL(DBG_PCD, ++ "CLEAR_FEATURE:%02x.%02x v%04x i%04x l%04x\n", ++ ctrl.bmRequestType, ctrl.bRequest, ++ UGETW(ctrl.wValue), UGETW(ctrl.wIndex), ++ UGETW(ctrl.wLength)); ++ ++ switch (UT_GET_RECIPIENT(ctrl.bmRequestType)) { ++ case UT_DEVICE: ++ switch (UGETW(ctrl.wValue)) { ++ case UF_DEVICE_REMOTE_WAKEUP: ++ pcd->remote_wakeup_enable = 0; ++ break; ++ ++ case UF_TEST_MODE: ++ /** @todo Add CLEAR_FEATURE for TEST modes. */ ++ break; ++ ++ default: ++ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); ++ return; ++ } ++ do_setup_in_status_phase(pcd); ++ break; ++ ++ case UT_ENDPOINT: ++ ep = get_ep_by_addr(pcd, UGETW(ctrl.wIndex)); ++ if (ep == 0) { ++ ep0_do_stall(pcd, -DWC_E_NOT_SUPPORTED); ++ return; ++ } ++ ++ pcd_clear_halt(pcd, ep); ++ ++ break; ++ } ++} ++ ++/** ++ * This function process the SET_ADDRESS Setup Commands. ++ */ ++static inline void do_set_address(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if; ++ usb_device_request_t ctrl = pcd->setup_pkt->req; ++ ++ if (ctrl.bmRequestType == UT_DEVICE) { ++ dcfg_data_t dcfg = {.d32 = 0 }; ++ ++#ifdef DEBUG_EP0 ++// DWC_DEBUGPL(DBG_PCDV, "SET_ADDRESS:%d\n", ctrl.wValue); ++#endif ++ dcfg.b.devaddr = UGETW(ctrl.wValue); ++ DWC_MODIFY_REG32(&dev_if->dev_global_regs->dcfg, 0, dcfg.d32); ++ do_setup_in_status_phase(pcd); ++ } ++} ++ ++/** ++ * This function processes SETUP commands. In Linux, the USB Command ++ * processing is done in two places - the first being the PCD and the ++ * second in the Gadget Driver (for example, the File-Backed Storage ++ * Gadget Driver). ++ * ++ *
Parameter NameMeaning
otg_capSpecifies the OTG capabilities. The driver will automatically detect the ++ value for this parameter if none is specified. ++ - 0: HNP and SRP capable (default, if available) ++ - 1: SRP Only capable ++ - 2: No HNP/SRP capable ++
dma_enableSpecifies whether to use slave or DMA mode for accessing the data FIFOs. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: Slave ++ - 1: DMA (default, if available) ++
dma_burst_sizeThe DMA Burst size (applicable only for External DMA Mode). ++ - Values: 1, 4, 8 16, 32, 64, 128, 256 (default 32) ++
speedSpecifies the maximum speed of operation in host and device mode. The ++ actual speed depends on the speed of the attached device and the value of ++ phy_type. ++ - 0: High Speed (default) ++ - 1: Full Speed ++
host_support_fs_ls_low_powerSpecifies whether low power mode is supported when attached to a Full ++ Speed or Low Speed device in host mode. ++ - 0: Don't support low power mode (default) ++ - 1: Support low power mode ++
host_ls_low_power_phy_clkSpecifies the PHY clock rate in low power mode when connected to a Low ++ Speed device in host mode. This parameter is applicable only if ++ HOST_SUPPORT_FS_LS_LOW_POWER is enabled. ++ - 0: 48 MHz (default) ++ - 1: 6 MHz ++
enable_dynamic_fifo Specifies whether FIFOs may be resized by the driver software. ++ - 0: Use cC FIFO size parameters ++ - 1: Allow dynamic FIFO sizing (default) ++
data_fifo_sizeTotal number of 4-byte words in the data FIFO memory. This memory ++ includes the Rx FIFO, non-periodic Tx FIFO, and periodic Tx FIFOs. ++ - Values: 32 to 32768 (default 8192) ++ ++ Note: The total FIFO memory depth in the FPGA configuration is 8192. ++
dev_rx_fifo_sizeNumber of 4-byte words in the Rx FIFO in device mode when dynamic ++ FIFO sizing is enabled. ++ - Values: 16 to 32768 (default 1064) ++
dev_nperio_tx_fifo_sizeNumber of 4-byte words in the non-periodic Tx FIFO in device mode when ++ dynamic FIFO sizing is enabled. ++ - Values: 16 to 32768 (default 1024) ++
dev_perio_tx_fifo_size_n (n = 1 to 15)Number of 4-byte words in each of the periodic Tx FIFOs in device mode ++ when dynamic FIFO sizing is enabled. ++ - Values: 4 to 768 (default 256) ++
host_rx_fifo_sizeNumber of 4-byte words in the Rx FIFO in host mode when dynamic FIFO ++ sizing is enabled. ++ - Values: 16 to 32768 (default 1024) ++
host_nperio_tx_fifo_sizeNumber of 4-byte words in the non-periodic Tx FIFO in host mode when ++ dynamic FIFO sizing is enabled in the core. ++ - Values: 16 to 32768 (default 1024) ++
host_perio_tx_fifo_sizeNumber of 4-byte words in the host periodic Tx FIFO when dynamic FIFO ++ sizing is enabled. ++ - Values: 16 to 32768 (default 1024) ++
max_transfer_sizeThe maximum transfer size supported in bytes. ++ - Values: 2047 to 65,535 (default 65,535) ++
max_packet_countThe maximum number of packets in a transfer. ++ - Values: 15 to 511 (default 511) ++
host_channelsThe number of host channel registers to use. ++ - Values: 1 to 16 (default 12) ++ ++ Note: The FPGA configuration supports a maximum of 12 host channels. ++
dev_endpointsThe number of endpoints in addition to EP0 available for device mode ++ operations. ++ - Values: 1 to 15 (default 6 IN and OUT) ++ ++ Note: The FPGA configuration supports a maximum of 6 IN and OUT endpoints in ++ addition to EP0. ++
phy_typeSpecifies the type of PHY interface to use. By default, the driver will ++ automatically detect the phy_type. ++ - 0: Full Speed ++ - 1: UTMI+ (default, if available) ++ - 2: ULPI ++
phy_utmi_widthSpecifies the UTMI+ Data Width. This parameter is applicable for a ++ phy_type of UTMI+. Also, this parameter is applicable only if the ++ OTG_HSPHY_WIDTH cC parameter was set to "8 and 16 bits", meaning that the ++ core has been configured to work at either data path width. ++ - Values: 8 or 16 bits (default 16) ++
phy_ulpi_ddrSpecifies whether the ULPI operates at double or single data rate. This ++ parameter is only applicable if phy_type is ULPI. ++ - 0: single data rate ULPI interface with 8 bit wide data bus (default) ++ - 1: double data rate ULPI interface with 4 bit wide data bus ++
i2c_enableSpecifies whether to use the I2C interface for full speed PHY. This ++ parameter is only applicable if PHY_TYPE is FS. ++ - 0: Disabled (default) ++ - 1: Enabled ++
ulpi_fs_lsSpecifies whether to use ULPI FS/LS mode only. ++ - 0: Disabled (default) ++ - 1: Enabled ++
ts_dlineSpecifies whether term select D-Line pulsing for all PHYs is enabled. ++ - 0: Disabled (default) ++ - 1: Enabled ++
en_multiple_tx_fifoSpecifies whether dedicatedto tx fifos are enabled for non periodic IN EPs. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: Disabled ++ - 1: Enabled (default, if available) ++
dev_tx_fifo_size_n (n = 1 to 15)Number of 4-byte words in each of the Tx FIFOs in device mode ++ when dynamic FIFO sizing is enabled. ++ - Values: 4 to 768 (default 256) ++
tx_thr_lengthTransmit Threshold length in 32 bit double words ++ - Values: 8 to 128 (default 64) ++
rx_thr_lengthReceive Threshold length in 32 bit double words ++ - Values: 8 to 128 (default 64) ++
thr_ctlSpecifies whether to enable Thresholding for Device mode. Bits 0, 1, 2 of ++ this parmater specifies if thresholding is enabled for non-Iso Tx, Iso Tx and ++ Rx transfers accordingly. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - Values: 0 to 7 (default 0) ++ Bit values indicate: ++ - 0: Thresholding disabled ++ - 1: Thresholding enabled ++
dma_desc_enableSpecifies whether to enable Descriptor DMA mode. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: Descriptor DMA disabled ++ - 1: Descriptor DMA (default, if available) ++
mpi_enableSpecifies whether to enable MPI enhancement mode. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: MPI disabled (default) ++ - 1: MPI enable ++
pti_enableSpecifies whether to enable PTI enhancement support. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: PTI disabled (default) ++ - 1: PTI enable ++
lpm_enableSpecifies whether to enable LPM support. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: LPM disabled ++ - 1: LPM enable (default, if available) ++
ic_usb_capSpecifies whether to enable IC_USB capability. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: IC_USB disabled (default, if available) ++ - 1: IC_USB enable ++
ahb_thr_ratioSpecifies AHB Threshold ratio. ++ - Values: 0 to 3 (default 0) ++
power_downSpecifies Power Down(Hibernation) Mode. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: Power Down disabled (default) ++ - 2: Power Down enabled ++
reload_ctlSpecifies whether dynamic reloading of the HFIR register is allowed during ++ run time. The driver will automatically detect the value for this parameter if ++ none is specified. In case the HFIR value is reloaded when HFIR.RldCtrl == 1'b0 ++ the core might misbehave. ++ - 0: Reload Control disabled (default) ++ - 1: Reload Control enabled ++
dev_out_nakSpecifies whether Device OUT NAK enhancement enabled or no. ++ The driver will automatically detect the value for this parameter if ++ none is specified. This parameter is valid only when OTG_EN_DESC_DMA == 1b1. ++ - 0: The core does not set NAK after Bulk OUT transfer complete (default) ++ - 1: The core sets NAK after Bulk OUT transfer complete ++
cont_on_bnaSpecifies whether Enable Continue on BNA enabled or no. ++ After receiving BNA interrupt the core disables the endpoint,when the ++ endpoint is re-enabled by the application the ++ - 0: Core starts processing from the DOEPDMA descriptor (default) ++ - 1: Core starts processing from the descriptor which received the BNA. ++ This parameter is valid only when OTG_EN_DESC_DMA == 1b1. ++
ahb_singleThis bit when programmed supports SINGLE transfers for remainder data ++ in a transfer for DMA mode of operation. ++ - 0: The remainder data will be sent using INCR burst size (default) ++ - 1: The remainder data will be sent using SINGLE burst size. ++
adp_enableSpecifies whether ADP feature is enabled. ++ The driver will automatically detect the value for this parameter if none is ++ specified. ++ - 0: ADP feature disabled (default) ++ - 1: ADP feature enabled ++
otg_verSpecifies whether OTG is performing as USB OTG Revision 2.0 or Revision 1.3 ++ USB OTG device. ++ - 0: OTG 2.0 support disabled (default) ++ - 1: OTG 2.0 support enabled ++
++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ * ++ *
Command Driver Description
GET_STATUS PCD Command is processed as ++ * defined in chapter 9 of the USB 2.0 Specification chapter 9 ++ *
CLEAR_FEATURE PCD The Device and Endpoint ++ * requests are the ENDPOINT_HALT feature is procesed, all others the ++ * interface requests are ignored.
SET_FEATURE PCD The Device and Endpoint ++ * requests are processed by the PCD. Interface requests are passed ++ * to the Gadget Driver.
SET_ADDRESS PCD Program the DCFG reg, ++ * with device address received
GET_DESCRIPTOR Gadget Driver Return the ++ * requested descriptor
SET_DESCRIPTOR Gadget Driver Optional - ++ * not implemented by any of the existing Gadget Drivers.
SET_CONFIGURATION Gadget Driver Disable ++ * all EPs and enable EPs for new configuration.
GET_CONFIGURATION Gadget Driver Return ++ * the current configuration
SET_INTERFACE Gadget Driver Disable all ++ * EPs and enable EPs for new configuration.
GET_INTERFACE Gadget Driver Return the ++ * current interface.
SYNC_FRAME PCD Display debug ++ * message.
++ * ++ * When the SETUP Phase Done interrupt occurs, the PCD SETUP commands are ++ * processed by pcd_setup. Calling the Function Driver's setup function from ++ * pcd_setup processes the gadget SETUP commands. ++ */ ++static inline void pcd_setup(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dwc_otg_dev_if_t *dev_if = core_if->dev_if; ++ usb_device_request_t ctrl = pcd->setup_pkt->req; ++ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; ++ ++ deptsiz0_data_t doeptsize0 = {.d32 = 0 }; ++ ++#ifdef DWC_UTE_CFI ++ int retval = 0; ++ struct cfi_usb_ctrlrequest cfi_req; ++#endif ++ ++ doeptsize0.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[0]->doeptsiz); ++ ++ /** In BDMA more then 1 setup packet is not supported till 3.00a */ ++ if (core_if->dma_enable && core_if->dma_desc_enable == 0 ++ && (doeptsize0.b.supcnt < 2) ++ && (core_if->snpsid < OTG_CORE_REV_2_94a)) { ++ DWC_ERROR ++ ("\n\n----------- CANNOT handle > 1 setup packet in DMA mode\n\n"); ++ } ++ if ((core_if->snpsid >= OTG_CORE_REV_3_00a) ++ && (core_if->dma_enable == 1) && (core_if->dma_desc_enable == 0)) { ++ ctrl = ++ (pcd->setup_pkt + ++ (3 - doeptsize0.b.supcnt - 1 + ++ ep0->dwc_ep.stp_rollover))->req; ++ } ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCD, "SETUP %02x.%02x v%04x i%04x l%04x\n", ++ ctrl.bmRequestType, ctrl.bRequest, ++ UGETW(ctrl.wValue), UGETW(ctrl.wIndex), ++ UGETW(ctrl.wLength)); ++#endif ++ ++ /* Clean up the request queue */ ++ dwc_otg_request_nuke(ep0); ++ ep0->stopped = 0; ++ ++ if (ctrl.bmRequestType & UE_DIR_IN) { ++ ep0->dwc_ep.is_in = 1; ++ pcd->ep0state = EP0_IN_DATA_PHASE; ++ } else { ++ ep0->dwc_ep.is_in = 0; ++ pcd->ep0state = EP0_OUT_DATA_PHASE; ++ } ++ ++ if (UGETW(ctrl.wLength) == 0) { ++ ep0->dwc_ep.is_in = 1; ++ pcd->ep0state = EP0_IN_STATUS_PHASE; ++ } ++ ++ if (UT_GET_TYPE(ctrl.bmRequestType) != UT_STANDARD) { ++ ++#ifdef DWC_UTE_CFI ++ DWC_MEMCPY(&cfi_req, &ctrl, sizeof(usb_device_request_t)); ++ ++ //printk(KERN_ALERT "CFI: req_type=0x%02x; req=0x%02x\n", ++ ctrl.bRequestType, ctrl.bRequest); ++ if (UT_GET_TYPE(cfi_req.bRequestType) == UT_VENDOR) { ++ if (cfi_req.bRequest > 0xB0 && cfi_req.bRequest < 0xBF) { ++ retval = cfi_setup(pcd, &cfi_req); ++ if (retval < 0) { ++ ep0_do_stall(pcd, retval); ++ pcd->ep0_pending = 0; ++ return; ++ } ++ ++ /* if need gadget setup then call it and check the retval */ ++ if (pcd->cfi->need_gadget_att) { ++ retval = ++ cfi_gadget_setup(pcd, ++ &pcd-> ++ cfi->ctrl_req); ++ if (retval < 0) { ++ pcd->ep0_pending = 0; ++ return; ++ } ++ } ++ ++ if (pcd->cfi->need_status_in_complete) { ++ do_setup_in_status_phase(pcd); ++ } ++ return; ++ } ++ } ++#endif ++ ++ /* handle non-standard (class/vendor) requests in the gadget driver */ ++ do_gadget_setup(pcd, &ctrl); ++ return; ++ } ++ ++ /** @todo NGS: Handle bad setup packet? */ ++ ++/////////////////////////////////////////// ++//// --- Standard Request handling --- //// ++ ++ switch (ctrl.bRequest) { ++ case UR_GET_STATUS: ++ do_get_status(pcd); ++ break; ++ ++ case UR_CLEAR_FEATURE: ++ do_clear_feature(pcd); ++ break; ++ ++ case UR_SET_FEATURE: ++ do_set_feature(pcd); ++ break; ++ ++ case UR_SET_ADDRESS: ++ do_set_address(pcd); ++ break; ++ ++ case UR_SET_INTERFACE: ++ case UR_SET_CONFIG: ++// _pcd->request_config = 1; /* Configuration changed */ ++ do_gadget_setup(pcd, &ctrl); ++ break; ++ ++ case UR_SYNCH_FRAME: ++ do_gadget_setup(pcd, &ctrl); ++ break; ++ ++ default: ++ /* Call the Gadget Driver's setup functions */ ++ do_gadget_setup(pcd, &ctrl); ++ break; ++ } ++} ++ ++/** ++ * This function completes the ep0 control transfer. ++ */ ++static int32_t ep0_complete_request(dwc_otg_pcd_ep_t * ep) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd); ++ dwc_otg_dev_if_t *dev_if = core_if->dev_if; ++ dwc_otg_dev_in_ep_regs_t *in_ep_regs = ++ dev_if->in_ep_regs[ep->dwc_ep.num]; ++#ifdef DEBUG_EP0 ++ dwc_otg_dev_out_ep_regs_t *out_ep_regs = ++ dev_if->out_ep_regs[ep->dwc_ep.num]; ++#endif ++ deptsiz0_data_t deptsiz; ++ dev_dma_desc_sts_t desc_sts; ++ dwc_otg_pcd_request_t *req; ++ int is_last = 0; ++ dwc_otg_pcd_t *pcd = ep->pcd; ++ ++#ifdef DWC_UTE_CFI ++ struct cfi_usb_ctrlrequest *ctrlreq; ++ int retval = -DWC_E_NOT_SUPPORTED; ++#endif ++ ++ desc_sts.b.bytes = 0; ++ ++ if (pcd->ep0_pending && DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ if (ep->dwc_ep.is_in) { ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCDV, "Do setup OUT status phase\n"); ++#endif ++ do_setup_out_status_phase(pcd); ++ } else { ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCDV, "Do setup IN status phase\n"); ++#endif ++ ++#ifdef DWC_UTE_CFI ++ ctrlreq = &pcd->cfi->ctrl_req; ++ ++ if (UT_GET_TYPE(ctrlreq->bRequestType) == UT_VENDOR) { ++ if (ctrlreq->bRequest > 0xB0 ++ && ctrlreq->bRequest < 0xBF) { ++ ++ /* Return if the PCD failed to handle the request */ ++ if ((retval = ++ pcd->cfi->ops. ++ ctrl_write_complete(pcd->cfi, ++ pcd)) < 0) { ++ CFI_INFO ++ ("ERROR setting a new value in the PCD(%d)\n", ++ retval); ++ ep0_do_stall(pcd, retval); ++ pcd->ep0_pending = 0; ++ return 0; ++ } ++ ++ /* If the gadget needs to be notified on the request */ ++ if (pcd->cfi->need_gadget_att == 1) { ++ //retval = do_gadget_setup(pcd, &pcd->cfi->ctrl_req); ++ retval = ++ cfi_gadget_setup(pcd, ++ &pcd->cfi-> ++ ctrl_req); ++ ++ /* Return from the function if the gadget failed to process ++ * the request properly - this should never happen !!! ++ */ ++ if (retval < 0) { ++ CFI_INFO ++ ("ERROR setting a new value in the gadget(%d)\n", ++ retval); ++ pcd->ep0_pending = 0; ++ return 0; ++ } ++ } ++ ++ CFI_INFO("%s: RETVAL=%d\n", __func__, ++ retval); ++ /* If we hit here then the PCD and the gadget has properly ++ * handled the request - so send the ZLP IN to the host. ++ */ ++ /* @todo: MAS - decide whether we need to start the setup ++ * stage based on the need_setup value of the cfi object ++ */ ++ do_setup_in_status_phase(pcd); ++ pcd->ep0_pending = 0; ++ return 1; ++ } ++ } ++#endif ++ ++ do_setup_in_status_phase(pcd); ++ } ++ pcd->ep0_pending = 0; ++ return 1; ++ } ++ ++ if (DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ return 0; ++ } ++ req = DWC_CIRCLEQ_FIRST(&ep->queue); ++ ++ if (pcd->ep0state == EP0_OUT_STATUS_PHASE ++ || pcd->ep0state == EP0_IN_STATUS_PHASE) { ++ is_last = 1; ++ } else if (ep->dwc_ep.is_in) { ++ deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz); ++ if (core_if->dma_desc_enable != 0) ++ desc_sts = dev_if->in_desc_addr->status; ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCDV, "%d len=%d xfersize=%d pktcnt=%d\n", ++ ep->dwc_ep.num, ep->dwc_ep.xfer_len, ++ deptsiz.b.xfersize, deptsiz.b.pktcnt); ++#endif ++ ++ if (((core_if->dma_desc_enable == 0) ++ && (deptsiz.b.xfersize == 0)) ++ || ((core_if->dma_desc_enable != 0) ++ && (desc_sts.b.bytes == 0))) { ++ req->actual = ep->dwc_ep.xfer_count; ++ /* Is a Zero Len Packet needed? */ ++ if (req->sent_zlp) { ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCD, "Setup Rx ZLP\n"); ++#endif ++ req->sent_zlp = 0; ++ } ++ do_setup_out_status_phase(pcd); ++ } ++ } else { ++ /* ep0-OUT */ ++#ifdef DEBUG_EP0 ++ deptsiz.d32 = DWC_READ_REG32(&out_ep_regs->doeptsiz); ++ DWC_DEBUGPL(DBG_PCDV, "%d len=%d xsize=%d pktcnt=%d\n", ++ ep->dwc_ep.num, ep->dwc_ep.xfer_len, ++ deptsiz.b.xfersize, deptsiz.b.pktcnt); ++#endif ++ req->actual = ep->dwc_ep.xfer_count; ++ ++ /* Is a Zero Len Packet needed? */ ++ if (req->sent_zlp) { ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCDV, "Setup Tx ZLP\n"); ++#endif ++ req->sent_zlp = 0; ++ } ++ /* For older cores do setup in status phase in Slave/BDMA modes, ++ * starting from 3.00 do that only in slave, and for DMA modes ++ * just re-enable ep 0 OUT here*/ ++ if (core_if->dma_enable == 0 ++ || (core_if->dma_desc_enable == 0 ++ && core_if->snpsid <= OTG_CORE_REV_2_94a)) { ++ do_setup_in_status_phase(pcd); ++ } else if (core_if->snpsid >= OTG_CORE_REV_3_00a) { ++ DWC_DEBUGPL(DBG_PCDV, ++ "Enable out ep before in status phase\n"); ++ ep0_out_start(core_if, pcd); ++ } ++ } ++ ++ /* Complete the request */ ++ if (is_last) { ++ dwc_otg_request_done(ep, req, 0); ++ ep->dwc_ep.start_xfer_buff = 0; ++ ep->dwc_ep.xfer_buff = 0; ++ ep->dwc_ep.xfer_len = 0; ++ return 1; ++ } ++ return 0; ++} ++ ++#ifdef DWC_UTE_CFI ++/** ++ * This function calculates traverses all the CFI DMA descriptors and ++ * and accumulates the bytes that are left to be transfered. ++ * ++ * @return The total bytes left to transfered, or a negative value as failure ++ */ ++static inline int cfi_calc_desc_residue(dwc_otg_pcd_ep_t * ep) ++{ ++ int32_t ret = 0; ++ int i; ++ struct dwc_otg_dma_desc *ddesc = NULL; ++ struct cfi_ep *cfiep; ++ ++ /* See if the pcd_ep has its respective cfi_ep mapped */ ++ cfiep = get_cfi_ep_by_pcd_ep(ep->pcd->cfi, ep); ++ if (!cfiep) { ++ CFI_INFO("%s: Failed to find ep\n", __func__); ++ return -1; ++ } ++ ++ ddesc = ep->dwc_ep.descs; ++ ++ for (i = 0; (i < cfiep->desc_count) && (i < MAX_DMA_DESCS_PER_EP); i++) { ++ ++#if defined(PRINT_CFI_DMA_DESCS) ++ print_desc(ddesc, ep->ep.name, i); ++#endif ++ ret += ddesc->status.b.bytes; ++ ddesc++; ++ } ++ ++ if (ret) ++ CFI_INFO("!!!!!!!!!! WARNING (%s) - residue=%d\n", __func__, ++ ret); ++ ++ return ret; ++} ++#endif ++ ++/** ++ * This function completes the request for the EP. If there are ++ * additional requests for the EP in the queue they will be started. ++ */ ++static void complete_ep(dwc_otg_pcd_ep_t * ep) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd); ++ dwc_otg_dev_if_t *dev_if = core_if->dev_if; ++ dwc_otg_dev_in_ep_regs_t *in_ep_regs = ++ dev_if->in_ep_regs[ep->dwc_ep.num]; ++ deptsiz_data_t deptsiz; ++ dev_dma_desc_sts_t desc_sts; ++ dwc_otg_pcd_request_t *req = 0; ++ dwc_otg_dev_dma_desc_t *dma_desc; ++ uint32_t byte_count = 0; ++ int is_last = 0; ++ int i; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s() %d-%s\n", __func__, ep->dwc_ep.num, ++ (ep->dwc_ep.is_in ? "IN" : "OUT")); ++ ++ /* Get any pending requests */ ++ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ req = DWC_CIRCLEQ_FIRST(&ep->queue); ++ if (!req) { ++ DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep); ++ return; ++ } ++ } else { ++ DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep); ++ return; ++ } ++ ++ DWC_DEBUGPL(DBG_PCD, "Requests %d\n", ep->pcd->request_pending); ++ ++ if (ep->dwc_ep.is_in) { ++ deptsiz.d32 = DWC_READ_REG32(&in_ep_regs->dieptsiz); ++ ++ if (core_if->dma_enable) { ++ if (core_if->dma_desc_enable == 0) { ++ if (deptsiz.b.xfersize == 0 ++ && deptsiz.b.pktcnt == 0) { ++ byte_count = ++ ep->dwc_ep.xfer_len - ++ ep->dwc_ep.xfer_count; ++ ++ ep->dwc_ep.xfer_buff += byte_count; ++ ep->dwc_ep.dma_addr += byte_count; ++ ep->dwc_ep.xfer_count += byte_count; ++ ++ DWC_DEBUGPL(DBG_PCDV, ++ "%d-%s len=%d xfersize=%d pktcnt=%d\n", ++ ep->dwc_ep.num, ++ (ep->dwc_ep. ++ is_in ? "IN" : "OUT"), ++ ep->dwc_ep.xfer_len, ++ deptsiz.b.xfersize, ++ deptsiz.b.pktcnt); ++ ++ if (ep->dwc_ep.xfer_len < ++ ep->dwc_ep.total_len) { ++ dwc_otg_ep_start_transfer ++ (core_if, &ep->dwc_ep); ++ } else if (ep->dwc_ep.sent_zlp) { ++ /* ++ * This fragment of code should initiate 0 ++ * length transfer in case if it is queued ++ * a transfer with size divisible to EPs max ++ * packet size and with usb_request zero field ++ * is set, which means that after data is transfered, ++ * it is also should be transfered ++ * a 0 length packet at the end. For Slave and ++ * Buffer DMA modes in this case SW has ++ * to initiate 2 transfers one with transfer size, ++ * and the second with 0 size. For Descriptor ++ * DMA mode SW is able to initiate a transfer, ++ * which will handle all the packets including ++ * the last 0 length. ++ */ ++ ep->dwc_ep.sent_zlp = 0; ++ dwc_otg_ep_start_zl_transfer ++ (core_if, &ep->dwc_ep); ++ } else { ++ is_last = 1; ++ } ++ } else { ++ if (ep->dwc_ep.type == ++ DWC_OTG_EP_TYPE_ISOC) { ++ req->actual = 0; ++ dwc_otg_request_done(ep, req, 0); ++ ++ ep->dwc_ep.start_xfer_buff = 0; ++ ep->dwc_ep.xfer_buff = 0; ++ ep->dwc_ep.xfer_len = 0; ++ ++ /* If there is a request in the queue start it. */ ++ start_next_request(ep); ++ } else ++ DWC_WARN ++ ("Incomplete transfer (%d - %s [siz=%d pkt=%d])\n", ++ ep->dwc_ep.num, ++ (ep->dwc_ep.is_in ? "IN" : "OUT"), ++ deptsiz.b.xfersize, ++ deptsiz.b.pktcnt); ++ } ++ } else { ++ dma_desc = ep->dwc_ep.desc_addr; ++ byte_count = 0; ++ ep->dwc_ep.sent_zlp = 0; ++ ++#ifdef DWC_UTE_CFI ++ CFI_INFO("%s: BUFFER_MODE=%d\n", __func__, ++ ep->dwc_ep.buff_mode); ++ if (ep->dwc_ep.buff_mode != BM_STANDARD) { ++ int residue; ++ ++ residue = cfi_calc_desc_residue(ep); ++ if (residue < 0) ++ return; ++ ++ byte_count = residue; ++ } else { ++#endif ++ for (i = 0; i < ep->dwc_ep.desc_cnt; ++ ++i) { ++ desc_sts = dma_desc->status; ++ byte_count += desc_sts.b.bytes; ++ dma_desc++; ++ } ++#ifdef DWC_UTE_CFI ++ } ++#endif ++ if (byte_count == 0) { ++ ep->dwc_ep.xfer_count = ++ ep->dwc_ep.total_len; ++ is_last = 1; ++ } else { ++ DWC_WARN("Incomplete transfer\n"); ++ } ++ } ++ } else { ++ if (deptsiz.b.xfersize == 0 && deptsiz.b.pktcnt == 0) { ++ DWC_DEBUGPL(DBG_PCDV, ++ "%d-%s len=%d xfersize=%d pktcnt=%d\n", ++ ep->dwc_ep.num, ++ ep->dwc_ep.is_in ? "IN" : "OUT", ++ ep->dwc_ep.xfer_len, ++ deptsiz.b.xfersize, ++ deptsiz.b.pktcnt); ++ ++ /* Check if the whole transfer was completed, ++ * if no, setup transfer for next portion of data ++ */ ++ if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) { ++ dwc_otg_ep_start_transfer(core_if, ++ &ep->dwc_ep); ++ } else if (ep->dwc_ep.sent_zlp) { ++ /* ++ * This fragment of code should initiate 0 ++ * length trasfer in case if it is queued ++ * a trasfer with size divisible to EPs max ++ * packet size and with usb_request zero field ++ * is set, which means that after data is transfered, ++ * it is also should be transfered ++ * a 0 length packet at the end. For Slave and ++ * Buffer DMA modes in this case SW has ++ * to initiate 2 transfers one with transfer size, ++ * and the second with 0 size. For Desriptor ++ * DMA mode SW is able to initiate a transfer, ++ * which will handle all the packets including ++ * the last 0 legth. ++ */ ++ ep->dwc_ep.sent_zlp = 0; ++ dwc_otg_ep_start_zl_transfer(core_if, ++ &ep->dwc_ep); ++ } else { ++ is_last = 1; ++ } ++ } else { ++ DWC_WARN ++ ("Incomplete transfer (%d-%s [siz=%d pkt=%d])\n", ++ ep->dwc_ep.num, ++ (ep->dwc_ep.is_in ? "IN" : "OUT"), ++ deptsiz.b.xfersize, deptsiz.b.pktcnt); ++ } ++ } ++ } else { ++ dwc_otg_dev_out_ep_regs_t *out_ep_regs = ++ dev_if->out_ep_regs[ep->dwc_ep.num]; ++ desc_sts.d32 = 0; ++ if (core_if->dma_enable) { ++ if (core_if->dma_desc_enable) { ++ dma_desc = ep->dwc_ep.desc_addr; ++ byte_count = 0; ++ ep->dwc_ep.sent_zlp = 0; ++ ++#ifdef DWC_UTE_CFI ++ CFI_INFO("%s: BUFFER_MODE=%d\n", __func__, ++ ep->dwc_ep.buff_mode); ++ if (ep->dwc_ep.buff_mode != BM_STANDARD) { ++ int residue; ++ residue = cfi_calc_desc_residue(ep); ++ if (residue < 0) ++ return; ++ byte_count = residue; ++ } else { ++#endif ++ ++ for (i = 0; i < ep->dwc_ep.desc_cnt; ++ ++i) { ++ desc_sts = dma_desc->status; ++ byte_count += desc_sts.b.bytes; ++ dma_desc++; ++ } ++ ++#ifdef DWC_UTE_CFI ++ } ++#endif ++ /* Checking for interrupt Out transfers with not ++ * dword aligned mps sizes ++ */ ++ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_INTR && ++ (ep->dwc_ep.maxpacket%4)) { ++ ep->dwc_ep.xfer_count = ++ ep->dwc_ep.total_len - byte_count; ++ if ((ep->dwc_ep.xfer_len % ++ ep->dwc_ep.maxpacket) ++ && (ep->dwc_ep.xfer_len / ++ ep->dwc_ep.maxpacket < ++ MAX_DMA_DESC_CNT)) ++ ep->dwc_ep.xfer_len -= ++ (ep->dwc_ep.desc_cnt - ++ 1) * ep->dwc_ep.maxpacket + ++ ep->dwc_ep.xfer_len % ++ ep->dwc_ep.maxpacket; ++ else ++ ep->dwc_ep.xfer_len -= ++ ep->dwc_ep.desc_cnt * ++ ep->dwc_ep.maxpacket; ++ if (ep->dwc_ep.xfer_len > 0) { ++ dwc_otg_ep_start_transfer ++ (core_if, &ep->dwc_ep); ++ } else { ++ is_last = 1; ++ } ++ } else { ++ ep->dwc_ep.xfer_count = ++ ep->dwc_ep.total_len - byte_count + ++ ((4 - ++ (ep->dwc_ep. ++ total_len & 0x3)) & 0x3); ++ is_last = 1; ++ } ++ } else { ++ deptsiz.d32 = 0; ++ deptsiz.d32 = ++ DWC_READ_REG32(&out_ep_regs->doeptsiz); ++ ++ byte_count = (ep->dwc_ep.xfer_len - ++ ep->dwc_ep.xfer_count - ++ deptsiz.b.xfersize); ++ ep->dwc_ep.xfer_buff += byte_count; ++ ep->dwc_ep.dma_addr += byte_count; ++ ep->dwc_ep.xfer_count += byte_count; ++ ++ /* Check if the whole transfer was completed, ++ * if no, setup transfer for next portion of data ++ */ ++ if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) { ++ dwc_otg_ep_start_transfer(core_if, ++ &ep->dwc_ep); ++ } else if (ep->dwc_ep.sent_zlp) { ++ /* ++ * This fragment of code should initiate 0 ++ * length trasfer in case if it is queued ++ * a trasfer with size divisible to EPs max ++ * packet size and with usb_request zero field ++ * is set, which means that after data is transfered, ++ * it is also should be transfered ++ * a 0 length packet at the end. For Slave and ++ * Buffer DMA modes in this case SW has ++ * to initiate 2 transfers one with transfer size, ++ * and the second with 0 size. For Desriptor ++ * DMA mode SW is able to initiate a transfer, ++ * which will handle all the packets including ++ * the last 0 legth. ++ */ ++ ep->dwc_ep.sent_zlp = 0; ++ dwc_otg_ep_start_zl_transfer(core_if, ++ &ep->dwc_ep); ++ } else { ++ is_last = 1; ++ } ++ } ++ } else { ++ /* Check if the whole transfer was completed, ++ * if no, setup transfer for next portion of data ++ */ ++ if (ep->dwc_ep.xfer_len < ep->dwc_ep.total_len) { ++ dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep); ++ } else if (ep->dwc_ep.sent_zlp) { ++ /* ++ * This fragment of code should initiate 0 ++ * length transfer in case if it is queued ++ * a transfer with size divisible to EPs max ++ * packet size and with usb_request zero field ++ * is set, which means that after data is transfered, ++ * it is also should be transfered ++ * a 0 length packet at the end. For Slave and ++ * Buffer DMA modes in this case SW has ++ * to initiate 2 transfers one with transfer size, ++ * and the second with 0 size. For Descriptor ++ * DMA mode SW is able to initiate a transfer, ++ * which will handle all the packets including ++ * the last 0 length. ++ */ ++ ep->dwc_ep.sent_zlp = 0; ++ dwc_otg_ep_start_zl_transfer(core_if, ++ &ep->dwc_ep); ++ } else { ++ is_last = 1; ++ } ++ } ++ ++ DWC_DEBUGPL(DBG_PCDV, ++ "addr %p, %d-%s len=%d cnt=%d xsize=%d pktcnt=%d\n", ++ &out_ep_regs->doeptsiz, ep->dwc_ep.num, ++ ep->dwc_ep.is_in ? "IN" : "OUT", ++ ep->dwc_ep.xfer_len, ep->dwc_ep.xfer_count, ++ deptsiz.b.xfersize, deptsiz.b.pktcnt); ++ } ++ ++ /* Complete the request */ ++ if (is_last) { ++#ifdef DWC_UTE_CFI ++ if (ep->dwc_ep.buff_mode != BM_STANDARD) { ++ req->actual = ep->dwc_ep.cfi_req_len - byte_count; ++ } else { ++#endif ++ req->actual = ep->dwc_ep.xfer_count; ++#ifdef DWC_UTE_CFI ++ } ++#endif ++ if (req->dw_align_buf) { ++ if (!ep->dwc_ep.is_in) { ++ dwc_memcpy(req->buf, req->dw_align_buf, req->length); ++ } ++ DWC_DMA_FREE(req->length, req->dw_align_buf, ++ req->dw_align_buf_dma); ++ } ++ ++ dwc_otg_request_done(ep, req, 0); ++ ++ ep->dwc_ep.start_xfer_buff = 0; ++ ep->dwc_ep.xfer_buff = 0; ++ ep->dwc_ep.xfer_len = 0; ++ ++ /* If there is a request in the queue start it. */ ++ start_next_request(ep); ++ } ++} ++ ++#ifdef DWC_EN_ISOC ++ ++/** ++ * This function BNA interrupt for Isochronous EPs ++ * ++ */ ++static void dwc_otg_pcd_handle_iso_bna(dwc_otg_pcd_ep_t * ep) ++{ ++ dwc_ep_t *dwc_ep = &ep->dwc_ep; ++ volatile uint32_t *addr; ++ depctl_data_t depctl = {.d32 = 0 }; ++ dwc_otg_pcd_t *pcd = ep->pcd; ++ dwc_otg_dev_dma_desc_t *dma_desc; ++ int i; ++ ++ dma_desc = ++ dwc_ep->iso_desc_addr + dwc_ep->desc_cnt * (dwc_ep->proc_buf_num); ++ ++ if (dwc_ep->is_in) { ++ dev_dma_desc_sts_t sts = {.d32 = 0 }; ++ for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) { ++ sts.d32 = dma_desc->status.d32; ++ sts.b_iso_in.bs = BS_HOST_READY; ++ dma_desc->status.d32 = sts.d32; ++ } ++ } else { ++ dev_dma_desc_sts_t sts = {.d32 = 0 }; ++ for (i = 0; i < dwc_ep->desc_cnt; ++i, ++dma_desc) { ++ sts.d32 = dma_desc->status.d32; ++ sts.b_iso_out.bs = BS_HOST_READY; ++ dma_desc->status.d32 = sts.d32; ++ } ++ } ++ ++ if (dwc_ep->is_in == 0) { ++ addr = ++ &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep-> ++ num]->doepctl; ++ } else { ++ addr = ++ &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl; ++ } ++ depctl.b.epena = 1; ++ DWC_MODIFY_REG32(addr, depctl.d32, depctl.d32); ++} ++ ++/** ++ * This function sets latest iso packet information(non-PTI mode) ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ * @param ep The EP to start the transfer on. ++ * ++ */ ++void set_current_pkt_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) ++{ ++ deptsiz_data_t deptsiz = {.d32 = 0 }; ++ dma_addr_t dma_addr; ++ uint32_t offset; ++ ++ if (ep->proc_buf_num) ++ dma_addr = ep->dma_addr1; ++ else ++ dma_addr = ep->dma_addr0; ++ ++ if (ep->is_in) { ++ deptsiz.d32 = ++ DWC_READ_REG32(&core_if->dev_if-> ++ in_ep_regs[ep->num]->dieptsiz); ++ offset = ep->data_per_frame; ++ } else { ++ deptsiz.d32 = ++ DWC_READ_REG32(&core_if->dev_if-> ++ out_ep_regs[ep->num]->doeptsiz); ++ offset = ++ ep->data_per_frame + ++ (0x4 & (0x4 - (ep->data_per_frame & 0x3))); ++ } ++ ++ if (!deptsiz.b.xfersize) { ++ ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame; ++ ep->pkt_info[ep->cur_pkt].offset = ++ ep->cur_pkt_dma_addr - dma_addr; ++ ep->pkt_info[ep->cur_pkt].status = 0; ++ } else { ++ ep->pkt_info[ep->cur_pkt].length = ep->data_per_frame; ++ ep->pkt_info[ep->cur_pkt].offset = ++ ep->cur_pkt_dma_addr - dma_addr; ++ ep->pkt_info[ep->cur_pkt].status = -DWC_E_NO_DATA; ++ } ++ ep->cur_pkt_addr += offset; ++ ep->cur_pkt_dma_addr += offset; ++ ep->cur_pkt++; ++} ++ ++/** ++ * This function sets latest iso packet information(DDMA mode) ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ * @param dwc_ep The EP to start the transfer on. ++ * ++ */ ++static void set_ddma_iso_pkts_info(dwc_otg_core_if_t * core_if, ++ dwc_ep_t * dwc_ep) ++{ ++ dwc_otg_dev_dma_desc_t *dma_desc; ++ dev_dma_desc_sts_t sts = {.d32 = 0 }; ++ iso_pkt_info_t *iso_packet; ++ uint32_t data_per_desc; ++ uint32_t offset; ++ int i, j; ++ ++ iso_packet = dwc_ep->pkt_info; ++ ++ /** Reinit closed DMA Descriptors*/ ++ /** ISO OUT EP */ ++ if (dwc_ep->is_in == 0) { ++ dma_desc = ++ dwc_ep->iso_desc_addr + ++ dwc_ep->desc_cnt * dwc_ep->proc_buf_num; ++ offset = 0; ++ ++ for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; ++ i += dwc_ep->pkt_per_frm) { ++ for (j = 0; j < dwc_ep->pkt_per_frm; ++j) { ++ data_per_desc = ++ ((j + 1) * dwc_ep->maxpacket > ++ dwc_ep-> ++ data_per_frame) ? dwc_ep->data_per_frame - ++ j * dwc_ep->maxpacket : dwc_ep->maxpacket; ++ data_per_desc += ++ (data_per_desc % 4) ? (4 - ++ data_per_desc % ++ 4) : 0; ++ ++ sts.d32 = dma_desc->status.d32; ++ ++ /* Write status in iso_packet_decsriptor */ ++ iso_packet->status = ++ sts.b_iso_out.rxsts + ++ (sts.b_iso_out.bs ^ BS_DMA_DONE); ++ if (iso_packet->status) { ++ iso_packet->status = -DWC_E_NO_DATA; ++ } ++ ++ /* Received data length */ ++ if (!sts.b_iso_out.rxbytes) { ++ iso_packet->length = ++ data_per_desc - ++ sts.b_iso_out.rxbytes; ++ } else { ++ iso_packet->length = ++ data_per_desc - ++ sts.b_iso_out.rxbytes + (4 - ++ dwc_ep->data_per_frame ++ % 4); ++ } ++ ++ iso_packet->offset = offset; ++ ++ offset += data_per_desc; ++ dma_desc++; ++ iso_packet++; ++ } ++ } ++ ++ for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) { ++ data_per_desc = ++ ((j + 1) * dwc_ep->maxpacket > ++ dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - ++ j * dwc_ep->maxpacket : dwc_ep->maxpacket; ++ data_per_desc += ++ (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; ++ ++ sts.d32 = dma_desc->status.d32; ++ ++ /* Write status in iso_packet_decsriptor */ ++ iso_packet->status = ++ sts.b_iso_out.rxsts + ++ (sts.b_iso_out.bs ^ BS_DMA_DONE); ++ if (iso_packet->status) { ++ iso_packet->status = -DWC_E_NO_DATA; ++ } ++ ++ /* Received data length */ ++ iso_packet->length = ++ dwc_ep->data_per_frame - sts.b_iso_out.rxbytes; ++ ++ iso_packet->offset = offset; ++ ++ offset += data_per_desc; ++ iso_packet++; ++ dma_desc++; ++ } ++ ++ sts.d32 = dma_desc->status.d32; ++ ++ /* Write status in iso_packet_decsriptor */ ++ iso_packet->status = ++ sts.b_iso_out.rxsts + (sts.b_iso_out.bs ^ BS_DMA_DONE); ++ if (iso_packet->status) { ++ iso_packet->status = -DWC_E_NO_DATA; ++ } ++ /* Received data length */ ++ if (!sts.b_iso_out.rxbytes) { ++ iso_packet->length = ++ dwc_ep->data_per_frame - sts.b_iso_out.rxbytes; ++ } else { ++ iso_packet->length = ++ dwc_ep->data_per_frame - sts.b_iso_out.rxbytes + ++ (4 - dwc_ep->data_per_frame % 4); ++ } ++ ++ iso_packet->offset = offset; ++ } else { ++/** ISO IN EP */ ++ ++ dma_desc = ++ dwc_ep->iso_desc_addr + ++ dwc_ep->desc_cnt * dwc_ep->proc_buf_num; ++ ++ for (i = 0; i < dwc_ep->desc_cnt - 1; i++) { ++ sts.d32 = dma_desc->status.d32; ++ ++ /* Write status in iso packet descriptor */ ++ iso_packet->status = ++ sts.b_iso_in.txsts + ++ (sts.b_iso_in.bs ^ BS_DMA_DONE); ++ if (iso_packet->status != 0) { ++ iso_packet->status = -DWC_E_NO_DATA; ++ ++ } ++ /* Bytes has been transfered */ ++ iso_packet->length = ++ dwc_ep->data_per_frame - sts.b_iso_in.txbytes; ++ ++ dma_desc++; ++ iso_packet++; ++ } ++ ++ sts.d32 = dma_desc->status.d32; ++ while (sts.b_iso_in.bs == BS_DMA_BUSY) { ++ sts.d32 = dma_desc->status.d32; ++ } ++ ++ /* Write status in iso packet descriptor ??? do be done with ERROR codes */ ++ iso_packet->status = ++ sts.b_iso_in.txsts + (sts.b_iso_in.bs ^ BS_DMA_DONE); ++ if (iso_packet->status != 0) { ++ iso_packet->status = -DWC_E_NO_DATA; ++ } ++ ++ /* Bytes has been transfered */ ++ iso_packet->length = ++ dwc_ep->data_per_frame - sts.b_iso_in.txbytes; ++ } ++} ++ ++/** ++ * This function reinitialize DMA Descriptors for Isochronous transfer ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ * @param dwc_ep The EP to start the transfer on. ++ * ++ */ ++static void reinit_ddma_iso_xfer(dwc_otg_core_if_t * core_if, dwc_ep_t * dwc_ep) ++{ ++ int i, j; ++ dwc_otg_dev_dma_desc_t *dma_desc; ++ dma_addr_t dma_ad; ++ volatile uint32_t *addr; ++ dev_dma_desc_sts_t sts = {.d32 = 0 }; ++ uint32_t data_per_desc; ++ ++ if (dwc_ep->is_in == 0) { ++ addr = &core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl; ++ } else { ++ addr = &core_if->dev_if->in_ep_regs[dwc_ep->num]->diepctl; ++ } ++ ++ if (dwc_ep->proc_buf_num == 0) { ++ /** Buffer 0 descriptors setup */ ++ dma_ad = dwc_ep->dma_addr0; ++ } else { ++ /** Buffer 1 descriptors setup */ ++ dma_ad = dwc_ep->dma_addr1; ++ } ++ ++ /** Reinit closed DMA Descriptors*/ ++ /** ISO OUT EP */ ++ if (dwc_ep->is_in == 0) { ++ dma_desc = ++ dwc_ep->iso_desc_addr + ++ dwc_ep->desc_cnt * dwc_ep->proc_buf_num; ++ ++ sts.b_iso_out.bs = BS_HOST_READY; ++ sts.b_iso_out.rxsts = 0; ++ sts.b_iso_out.l = 0; ++ sts.b_iso_out.sp = 0; ++ sts.b_iso_out.ioc = 0; ++ sts.b_iso_out.pid = 0; ++ sts.b_iso_out.framenum = 0; ++ ++ for (i = 0; i < dwc_ep->desc_cnt - dwc_ep->pkt_per_frm; ++ i += dwc_ep->pkt_per_frm) { ++ for (j = 0; j < dwc_ep->pkt_per_frm; ++j) { ++ data_per_desc = ++ ((j + 1) * dwc_ep->maxpacket > ++ dwc_ep-> ++ data_per_frame) ? dwc_ep->data_per_frame - ++ j * dwc_ep->maxpacket : dwc_ep->maxpacket; ++ data_per_desc += ++ (data_per_desc % 4) ? (4 - ++ data_per_desc % ++ 4) : 0; ++ sts.b_iso_out.rxbytes = data_per_desc; ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ ++ dma_ad += data_per_desc; ++ dma_desc++; ++ } ++ } ++ ++ for (j = 0; j < dwc_ep->pkt_per_frm - 1; ++j) { ++ ++ data_per_desc = ++ ((j + 1) * dwc_ep->maxpacket > ++ dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - ++ j * dwc_ep->maxpacket : dwc_ep->maxpacket; ++ data_per_desc += ++ (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; ++ sts.b_iso_out.rxbytes = data_per_desc; ++ ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ ++ dma_desc++; ++ dma_ad += data_per_desc; ++ } ++ ++ sts.b_iso_out.ioc = 1; ++ sts.b_iso_out.l = dwc_ep->proc_buf_num; ++ ++ data_per_desc = ++ ((j + 1) * dwc_ep->maxpacket > ++ dwc_ep->data_per_frame) ? dwc_ep->data_per_frame - ++ j * dwc_ep->maxpacket : dwc_ep->maxpacket; ++ data_per_desc += ++ (data_per_desc % 4) ? (4 - data_per_desc % 4) : 0; ++ sts.b_iso_out.rxbytes = data_per_desc; ++ ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ } else { ++/** ISO IN EP */ ++ ++ dma_desc = ++ dwc_ep->iso_desc_addr + ++ dwc_ep->desc_cnt * dwc_ep->proc_buf_num; ++ ++ sts.b_iso_in.bs = BS_HOST_READY; ++ sts.b_iso_in.txsts = 0; ++ sts.b_iso_in.sp = 0; ++ sts.b_iso_in.ioc = 0; ++ sts.b_iso_in.pid = dwc_ep->pkt_per_frm; ++ sts.b_iso_in.framenum = dwc_ep->next_frame; ++ sts.b_iso_in.txbytes = dwc_ep->data_per_frame; ++ sts.b_iso_in.l = 0; ++ ++ for (i = 0; i < dwc_ep->desc_cnt - 1; i++) { ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ ++ sts.b_iso_in.framenum += dwc_ep->bInterval; ++ dma_ad += dwc_ep->data_per_frame; ++ dma_desc++; ++ } ++ ++ sts.b_iso_in.ioc = 1; ++ sts.b_iso_in.l = dwc_ep->proc_buf_num; ++ ++ dma_desc->buf = dma_ad; ++ dma_desc->status.d32 = sts.d32; ++ ++ dwc_ep->next_frame = ++ sts.b_iso_in.framenum + dwc_ep->bInterval * 1; ++ } ++ dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1; ++} ++ ++/** ++ * This function is to handle Iso EP transfer complete interrupt ++ * in case Iso out packet was dropped ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ * @param dwc_ep The EP for wihich transfer complete was asserted ++ * ++ */ ++static uint32_t handle_iso_out_pkt_dropped(dwc_otg_core_if_t * core_if, ++ dwc_ep_t * dwc_ep) ++{ ++ uint32_t dma_addr; ++ uint32_t drp_pkt; ++ uint32_t drp_pkt_cnt; ++ deptsiz_data_t deptsiz = {.d32 = 0 }; ++ depctl_data_t depctl = {.d32 = 0 }; ++ int i; ++ ++ deptsiz.d32 = ++ DWC_READ_REG32(&core_if->dev_if-> ++ out_ep_regs[dwc_ep->num]->doeptsiz); ++ ++ drp_pkt = dwc_ep->pkt_cnt - deptsiz.b.pktcnt; ++ drp_pkt_cnt = dwc_ep->pkt_per_frm - (drp_pkt % dwc_ep->pkt_per_frm); ++ ++ /* Setting dropped packets status */ ++ for (i = 0; i < drp_pkt_cnt; ++i) { ++ dwc_ep->pkt_info[drp_pkt].status = -DWC_E_NO_DATA; ++ drp_pkt++; ++ deptsiz.b.pktcnt--; ++ } ++ ++ if (deptsiz.b.pktcnt > 0) { ++ deptsiz.b.xfersize = ++ dwc_ep->xfer_len - (dwc_ep->pkt_cnt - ++ deptsiz.b.pktcnt) * dwc_ep->maxpacket; ++ } else { ++ deptsiz.b.xfersize = 0; ++ deptsiz.b.pktcnt = 0; ++ } ++ ++ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz, ++ deptsiz.d32); ++ ++ if (deptsiz.b.pktcnt > 0) { ++ if (dwc_ep->proc_buf_num) { ++ dma_addr = ++ dwc_ep->dma_addr1 + dwc_ep->xfer_len - ++ deptsiz.b.xfersize; ++ } else { ++ dma_addr = ++ dwc_ep->dma_addr0 + dwc_ep->xfer_len - ++ deptsiz.b.xfersize;; ++ } ++ ++ DWC_WRITE_REG32(&core_if->dev_if-> ++ out_ep_regs[dwc_ep->num]->doepdma, dma_addr); ++ ++ /** Re-enable endpoint, clear nak */ ++ depctl.d32 = 0; ++ depctl.b.epena = 1; ++ depctl.b.cnak = 1; ++ ++ DWC_MODIFY_REG32(&core_if->dev_if-> ++ out_ep_regs[dwc_ep->num]->doepctl, depctl.d32, ++ depctl.d32); ++ return 0; ++ } else { ++ return 1; ++ } ++} ++ ++/** ++ * This function sets iso packets information(PTI mode) ++ * ++ * @param core_if Programming view of DWC_otg controller. ++ * @param ep The EP to start the transfer on. ++ * ++ */ ++static uint32_t set_iso_pkts_info(dwc_otg_core_if_t * core_if, dwc_ep_t * ep) ++{ ++ int i, j; ++ dma_addr_t dma_ad; ++ iso_pkt_info_t *packet_info = ep->pkt_info; ++ uint32_t offset; ++ uint32_t frame_data; ++ deptsiz_data_t deptsiz; ++ ++ if (ep->proc_buf_num == 0) { ++ /** Buffer 0 descriptors setup */ ++ dma_ad = ep->dma_addr0; ++ } else { ++ /** Buffer 1 descriptors setup */ ++ dma_ad = ep->dma_addr1; ++ } ++ ++ if (ep->is_in) { ++ deptsiz.d32 = ++ DWC_READ_REG32(&core_if->dev_if->in_ep_regs[ep->num]-> ++ dieptsiz); ++ } else { ++ deptsiz.d32 = ++ DWC_READ_REG32(&core_if->dev_if->out_ep_regs[ep->num]-> ++ doeptsiz); ++ } ++ ++ if (!deptsiz.b.xfersize) { ++ offset = 0; ++ for (i = 0; i < ep->pkt_cnt; i += ep->pkt_per_frm) { ++ frame_data = ep->data_per_frame; ++ for (j = 0; j < ep->pkt_per_frm; ++j) { ++ ++ /* Packet status - is not set as initially ++ * it is set to 0 and if packet was sent ++ successfully, status field will remain 0*/ ++ ++ /* Bytes has been transfered */ ++ packet_info->length = ++ (ep->maxpacket < ++ frame_data) ? ep->maxpacket : frame_data; ++ ++ /* Received packet offset */ ++ packet_info->offset = offset; ++ offset += packet_info->length; ++ frame_data -= packet_info->length; ++ ++ packet_info++; ++ } ++ } ++ return 1; ++ } else { ++ /* This is a workaround for in case of Transfer Complete with ++ * PktDrpSts interrupts merging - in this case Transfer complete ++ * interrupt for Isoc Out Endpoint is asserted without PktDrpSts ++ * set and with DOEPTSIZ register non zero. Investigations showed, ++ * that this happens when Out packet is dropped, but because of ++ * interrupts merging during first interrupt handling PktDrpSts ++ * bit is cleared and for next merged interrupts it is not reset. ++ * In this case SW hadles the interrupt as if PktDrpSts bit is set. ++ */ ++ if (ep->is_in) { ++ return 1; ++ } else { ++ return handle_iso_out_pkt_dropped(core_if, ep); ++ } ++ } ++} ++ ++/** ++ * This function is to handle Iso EP transfer complete interrupt ++ * ++ * @param pcd The PCD ++ * @param ep The EP for which transfer complete was asserted ++ * ++ */ ++static void complete_iso_ep(dwc_otg_pcd_t * pcd, dwc_otg_pcd_ep_t * ep) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(ep->pcd); ++ dwc_ep_t *dwc_ep = &ep->dwc_ep; ++ uint8_t is_last = 0; ++ ++ if (ep->dwc_ep.next_frame == 0xffffffff) { ++ DWC_WARN("Next frame is not set!\n"); ++ return; ++ } ++ ++ if (core_if->dma_enable) { ++ if (core_if->dma_desc_enable) { ++ set_ddma_iso_pkts_info(core_if, dwc_ep); ++ reinit_ddma_iso_xfer(core_if, dwc_ep); ++ is_last = 1; ++ } else { ++ if (core_if->pti_enh_enable) { ++ if (set_iso_pkts_info(core_if, dwc_ep)) { ++ dwc_ep->proc_buf_num = ++ (dwc_ep->proc_buf_num ^ 1) & 0x1; ++ dwc_otg_iso_ep_start_buf_transfer ++ (core_if, dwc_ep); ++ is_last = 1; ++ } ++ } else { ++ set_current_pkt_info(core_if, dwc_ep); ++ if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) { ++ is_last = 1; ++ dwc_ep->cur_pkt = 0; ++ dwc_ep->proc_buf_num = ++ (dwc_ep->proc_buf_num ^ 1) & 0x1; ++ if (dwc_ep->proc_buf_num) { ++ dwc_ep->cur_pkt_addr = ++ dwc_ep->xfer_buff1; ++ dwc_ep->cur_pkt_dma_addr = ++ dwc_ep->dma_addr1; ++ } else { ++ dwc_ep->cur_pkt_addr = ++ dwc_ep->xfer_buff0; ++ dwc_ep->cur_pkt_dma_addr = ++ dwc_ep->dma_addr0; ++ } ++ ++ } ++ dwc_otg_iso_ep_start_frm_transfer(core_if, ++ dwc_ep); ++ } ++ } ++ } else { ++ set_current_pkt_info(core_if, dwc_ep); ++ if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) { ++ is_last = 1; ++ dwc_ep->cur_pkt = 0; ++ dwc_ep->proc_buf_num = (dwc_ep->proc_buf_num ^ 1) & 0x1; ++ if (dwc_ep->proc_buf_num) { ++ dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff1; ++ dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr1; ++ } else { ++ dwc_ep->cur_pkt_addr = dwc_ep->xfer_buff0; ++ dwc_ep->cur_pkt_dma_addr = dwc_ep->dma_addr0; ++ } ++ ++ } ++ dwc_otg_iso_ep_start_frm_transfer(core_if, dwc_ep); ++ } ++ if (is_last) ++ dwc_otg_iso_buffer_done(pcd, ep, ep->iso_req_handle); ++} ++#endif /* DWC_EN_ISOC */ ++ ++/** ++ * This function handle BNA interrupt for Non Isochronous EPs ++ * ++ */ ++static void dwc_otg_pcd_handle_noniso_bna(dwc_otg_pcd_ep_t * ep) ++{ ++ dwc_ep_t *dwc_ep = &ep->dwc_ep; ++ volatile uint32_t *addr; ++ depctl_data_t depctl = {.d32 = 0 }; ++ dwc_otg_pcd_t *pcd = ep->pcd; ++ dwc_otg_dev_dma_desc_t *dma_desc; ++ dev_dma_desc_sts_t sts = {.d32 = 0 }; ++ dwc_otg_core_if_t *core_if = ep->pcd->core_if; ++ int i, start; ++ ++ if (!dwc_ep->desc_cnt) ++ DWC_WARN("Ep%d %s Descriptor count = %d \n", dwc_ep->num, ++ (dwc_ep->is_in ? "IN" : "OUT"), dwc_ep->desc_cnt); ++ ++ if (core_if->core_params->cont_on_bna && !dwc_ep->is_in ++ && dwc_ep->type != DWC_OTG_EP_TYPE_CONTROL) { ++ uint32_t doepdma; ++ dwc_otg_dev_out_ep_regs_t *out_regs = ++ core_if->dev_if->out_ep_regs[dwc_ep->num]; ++ doepdma = DWC_READ_REG32(&(out_regs->doepdma)); ++ start = (doepdma - dwc_ep->dma_desc_addr)/sizeof(dwc_otg_dev_dma_desc_t); ++ dma_desc = &(dwc_ep->desc_addr[start]); ++ } else { ++ start = 0; ++ dma_desc = dwc_ep->desc_addr; ++ } ++ ++ ++ for (i = start; i < dwc_ep->desc_cnt; ++i, ++dma_desc) { ++ sts.d32 = dma_desc->status.d32; ++ sts.b.bs = BS_HOST_READY; ++ dma_desc->status.d32 = sts.d32; ++ } ++ ++ if (dwc_ep->is_in == 0) { ++ addr = ++ &GET_CORE_IF(pcd)->dev_if->out_ep_regs[dwc_ep->num]-> ++ doepctl; ++ } else { ++ addr = ++ &GET_CORE_IF(pcd)->dev_if->in_ep_regs[dwc_ep->num]->diepctl; ++ } ++ depctl.b.epena = 1; ++ depctl.b.cnak = 1; ++ DWC_MODIFY_REG32(addr, 0, depctl.d32); ++} ++ ++/** ++ * This function handles EP0 Control transfers. ++ * ++ * The state of the control transfers are tracked in ++ * ep0state. ++ */ ++static void handle_ep0(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dwc_otg_pcd_ep_t *ep0 = &pcd->ep0; ++ dev_dma_desc_sts_t desc_sts; ++ deptsiz0_data_t deptsiz; ++ uint32_t byte_count; ++ ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__); ++ print_ep0_state(pcd); ++#endif ++ ++// DWC_PRINTF("HANDLE EP0\n"); ++ ++ switch (pcd->ep0state) { ++ case EP0_DISCONNECT: ++ break; ++ ++ case EP0_IDLE: ++ pcd->request_config = 0; ++ ++ pcd_setup(pcd); ++ break; ++ ++ case EP0_IN_DATA_PHASE: ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCD, "DATA_IN EP%d-%s: type=%d, mps=%d\n", ++ ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"), ++ ep0->dwc_ep.type, ep0->dwc_ep.maxpacket); ++#endif ++ ++ if (core_if->dma_enable != 0) { ++ /* ++ * For EP0 we can only program 1 packet at a time so we ++ * need to do the make calculations after each complete. ++ * Call write_packet to make the calculations, as in ++ * slave mode, and use those values to determine if we ++ * can complete. ++ */ ++ if (core_if->dma_desc_enable == 0) { ++ deptsiz.d32 = ++ DWC_READ_REG32(&core_if-> ++ dev_if->in_ep_regs[0]-> ++ dieptsiz); ++ byte_count = ++ ep0->dwc_ep.xfer_len - deptsiz.b.xfersize; ++ } else { ++ desc_sts = ++ core_if->dev_if->in_desc_addr->status; ++ byte_count = ++ ep0->dwc_ep.xfer_len - desc_sts.b.bytes; ++ } ++ ep0->dwc_ep.xfer_count += byte_count; ++ ep0->dwc_ep.xfer_buff += byte_count; ++ ep0->dwc_ep.dma_addr += byte_count; ++ } ++ if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) { ++ dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd), ++ &ep0->dwc_ep); ++ DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n"); ++ } else if (ep0->dwc_ep.sent_zlp) { ++ dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd), ++ &ep0->dwc_ep); ++ ep0->dwc_ep.sent_zlp = 0; ++ DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n"); ++ } else { ++ ep0_complete_request(ep0); ++ DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n"); ++ } ++ break; ++ case EP0_OUT_DATA_PHASE: ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCD, "DATA_OUT EP%d-%s: type=%d, mps=%d\n", ++ ep0->dwc_ep.num, (ep0->dwc_ep.is_in ? "IN" : "OUT"), ++ ep0->dwc_ep.type, ep0->dwc_ep.maxpacket); ++#endif ++ if (core_if->dma_enable != 0) { ++ if (core_if->dma_desc_enable == 0) { ++ deptsiz.d32 = ++ DWC_READ_REG32(&core_if-> ++ dev_if->out_ep_regs[0]-> ++ doeptsiz); ++ byte_count = ++ ep0->dwc_ep.maxpacket - deptsiz.b.xfersize; ++ } else { ++ desc_sts = ++ core_if->dev_if->out_desc_addr->status; ++ byte_count = ++ ep0->dwc_ep.maxpacket - desc_sts.b.bytes; ++ } ++ ep0->dwc_ep.xfer_count += byte_count; ++ ep0->dwc_ep.xfer_buff += byte_count; ++ ep0->dwc_ep.dma_addr += byte_count; ++ } ++ if (ep0->dwc_ep.xfer_count < ep0->dwc_ep.total_len) { ++ dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd), ++ &ep0->dwc_ep); ++ DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER\n"); ++ } else if (ep0->dwc_ep.sent_zlp) { ++ dwc_otg_ep0_continue_transfer(GET_CORE_IF(pcd), ++ &ep0->dwc_ep); ++ ep0->dwc_ep.sent_zlp = 0; ++ DWC_DEBUGPL(DBG_PCD, "CONTINUE TRANSFER sent zlp\n"); ++ } else { ++ ep0_complete_request(ep0); ++ DWC_DEBUGPL(DBG_PCD, "COMPLETE TRANSFER\n"); ++ } ++ break; ++ ++ case EP0_IN_STATUS_PHASE: ++ case EP0_OUT_STATUS_PHASE: ++ DWC_DEBUGPL(DBG_PCD, "CASE: EP0_STATUS\n"); ++ ep0_complete_request(ep0); ++ pcd->ep0state = EP0_IDLE; ++ ep0->stopped = 1; ++ ep0->dwc_ep.is_in = 0; /* OUT for next SETUP */ ++ ++ /* Prepare for more SETUP Packets */ ++ if (core_if->dma_enable) { ++ ep0_out_start(core_if, pcd); ++ } ++ break; ++ ++ case EP0_STALL: ++ DWC_ERROR("EP0 STALLed, should not get here pcd_setup()\n"); ++ break; ++ } ++#ifdef DEBUG_EP0 ++ print_ep0_state(pcd); ++#endif ++} ++ ++/** ++ * Restart transfer ++ */ ++static void restart_transfer(dwc_otg_pcd_t * pcd, const uint32_t epnum) ++{ ++ dwc_otg_core_if_t *core_if; ++ dwc_otg_dev_if_t *dev_if; ++ deptsiz_data_t dieptsiz = {.d32 = 0 }; ++ dwc_otg_pcd_ep_t *ep; ++ ++ ep = get_in_ep(pcd, epnum); ++ ++#ifdef DWC_EN_ISOC ++ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) { ++ return; ++ } ++#endif /* DWC_EN_ISOC */ ++ ++ core_if = GET_CORE_IF(pcd); ++ dev_if = core_if->dev_if; ++ ++ dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz); ++ ++ DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x xfer_len=%0x" ++ " stopped=%d\n", ep->dwc_ep.xfer_buff, ++ ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ep->stopped); ++ /* ++ * If xfersize is 0 and pktcnt in not 0, resend the last packet. ++ */ ++ if (dieptsiz.b.pktcnt && dieptsiz.b.xfersize == 0 && ++ ep->dwc_ep.start_xfer_buff != 0) { ++ if (ep->dwc_ep.total_len <= ep->dwc_ep.maxpacket) { ++ ep->dwc_ep.xfer_count = 0; ++ ep->dwc_ep.xfer_buff = ep->dwc_ep.start_xfer_buff; ++ ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count; ++ } else { ++ ep->dwc_ep.xfer_count -= ep->dwc_ep.maxpacket; ++ /* convert packet size to dwords. */ ++ ep->dwc_ep.xfer_buff -= ep->dwc_ep.maxpacket; ++ ep->dwc_ep.xfer_len = ep->dwc_ep.xfer_count; ++ } ++ ep->stopped = 0; ++ DWC_DEBUGPL(DBG_PCD, "xfer_buff=%p xfer_count=%0x " ++ "xfer_len=%0x stopped=%d\n", ++ ep->dwc_ep.xfer_buff, ++ ep->dwc_ep.xfer_count, ep->dwc_ep.xfer_len, ++ ep->stopped); ++ if (epnum == 0) { ++ dwc_otg_ep0_start_transfer(core_if, &ep->dwc_ep); ++ } else { ++ dwc_otg_ep_start_transfer(core_if, &ep->dwc_ep); ++ } ++ } ++} ++ ++/* ++ * This function create new nextep sequnce based on Learn Queue. ++ * ++ * @param core_if Programming view of DWC_otg controller ++ */ ++void predict_nextep_seq( dwc_otg_core_if_t * core_if) ++{ ++ dwc_otg_device_global_regs_t *dev_global_regs = ++ core_if->dev_if->dev_global_regs; ++ const uint32_t TOKEN_Q_DEPTH = core_if->hwcfg2.b.dev_token_q_depth; ++ /* Number of Token Queue Registers */ ++ const int DTKNQ_REG_CNT = (TOKEN_Q_DEPTH + 7) / 8; ++ dtknq1_data_t dtknqr1; ++ uint32_t in_tkn_epnums[4]; ++ uint8_t seqnum[MAX_EPS_CHANNELS]; ++ uint8_t intkn_seq[TOKEN_Q_DEPTH]; ++ grstctl_t resetctl = {.d32 = 0 }; ++ uint8_t temp; ++ int ndx = 0; ++ int start = 0; ++ int end = 0; ++ int sort_done = 0; ++ int i = 0; ++ volatile uint32_t *addr = &dev_global_regs->dtknqr1; ++ ++ ++ DWC_DEBUGPL(DBG_PCD,"dev_token_q_depth=%d\n",TOKEN_Q_DEPTH); ++ ++ /* Read the DTKNQ Registers */ ++ for (i = 0; i < DTKNQ_REG_CNT; i++) { ++ in_tkn_epnums[i] = DWC_READ_REG32(addr); ++ DWC_DEBUGPL(DBG_PCDV, "DTKNQR%d=0x%08x\n", i + 1, ++ in_tkn_epnums[i]); ++ if (addr == &dev_global_regs->dvbusdis) { ++ addr = &dev_global_regs->dtknqr3_dthrctl; ++ } else { ++ ++addr; ++ } ++ ++ } ++ ++ /* Copy the DTKNQR1 data to the bit field. */ ++ dtknqr1.d32 = in_tkn_epnums[0]; ++ if (dtknqr1.b.wrap_bit) { ++ ndx = dtknqr1.b.intknwptr; ++ end = ndx -1; ++ if (end < 0) ++ end = TOKEN_Q_DEPTH -1; ++ } else { ++ ndx = 0; ++ end = dtknqr1.b.intknwptr -1; ++ if (end < 0) ++ end = 0; ++ } ++ start = ndx; ++ ++ /* Fill seqnum[] by initial values: EP number + 31 */ ++ for (i=0; i <= core_if->dev_if->num_in_eps; i++) { ++ seqnum[i] = i +31; ++ } ++ ++ /* Fill intkn_seq[] from in_tkn_epnums[0] */ ++ for (i=0; i < 6; i++) ++ intkn_seq[i] = (in_tkn_epnums[0] >> ((7-i) * 4)) & 0xf; ++ ++ if (TOKEN_Q_DEPTH > 6) { ++ /* Fill intkn_seq[] from in_tkn_epnums[1] */ ++ for (i=6; i < 14; i++) ++ intkn_seq[i] = ++ (in_tkn_epnums[1] >> ((7 - (i - 6)) * 4)) & 0xf; ++ } ++ ++ if (TOKEN_Q_DEPTH > 14) { ++ /* Fill intkn_seq[] from in_tkn_epnums[1] */ ++ for (i=14; i < 22; i++) ++ intkn_seq[i] = ++ (in_tkn_epnums[2] >> ((7 - (i - 14)) * 4)) & 0xf; ++ } ++ ++ if (TOKEN_Q_DEPTH > 22) { ++ /* Fill intkn_seq[] from in_tkn_epnums[1] */ ++ for (i=22; i < 30; i++) ++ intkn_seq[i] = ++ (in_tkn_epnums[3] >> ((7 - (i - 22)) * 4)) & 0xf; ++ } ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s start=%d end=%d intkn_seq[]:\n", __func__, ++ start, end); ++ for (i=0; idev_if->num_in_eps; i++) { ++ if (core_if->nextep_seq[i] == 0xff ) ++ seqnum[i] = 0xff; ++ } ++ ++ /* Sort seqnum[] */ ++ sort_done = 0; ++ while (!sort_done) { ++ sort_done = 1; ++ for (i=0; idev_if->num_in_eps; i++) { ++ if (seqnum[i] > seqnum[i+1]) { ++ temp = seqnum[i]; ++ seqnum[i] = seqnum[i+1]; ++ seqnum[i+1] = temp; ++ sort_done = 0; ++ } ++ } ++ } ++ ++ ndx = start + seqnum[0]; ++ if (ndx >= TOKEN_Q_DEPTH) ++ ndx = ndx % TOKEN_Q_DEPTH; ++ core_if->first_in_nextep_seq = intkn_seq[ndx]; ++ ++ /* Update seqnum[] by EP numbers */ ++ for (i=0; i<=core_if->dev_if->num_in_eps; i++) { ++ ndx = start + i; ++ if (seqnum[i] < 31) { ++ ndx = start + seqnum[i]; ++ if (ndx >= TOKEN_Q_DEPTH) ++ ndx = ndx % TOKEN_Q_DEPTH; ++ seqnum[i] = intkn_seq[ndx]; ++ } else { ++ if (seqnum[i] < 0xff) { ++ seqnum[i] = seqnum[i] - 31; ++ } else { ++ break; ++ } ++ } ++ } ++ ++ /* Update nextep_seq[] based on seqnum[] */ ++ for (i=0; idev_if->num_in_eps; i++) { ++ if (seqnum[i] != 0xff) { ++ if (seqnum[i+1] != 0xff) { ++ core_if->nextep_seq[seqnum[i]] = seqnum[i+1]; ++ } else { ++ core_if->nextep_seq[seqnum[i]] = core_if->first_in_nextep_seq; ++ break; ++ } ++ } else { ++ break; ++ } ++ } ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s first_in_nextep_seq= %2d; nextep_seq[]:\n", ++ __func__, core_if->first_in_nextep_seq); ++ for (i=0; i <= core_if->dev_if->num_in_eps; i++) { ++ DWC_DEBUGPL(DBG_PCDV,"%2d\n", core_if->nextep_seq[i]); ++ } ++ ++ /* Flush the Learning Queue */ ++ resetctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->grstctl); ++ resetctl.b.intknqflsh = 1; ++ DWC_WRITE_REG32(&core_if->core_global_regs->grstctl, resetctl.d32); ++ ++ ++} ++ ++/** ++ * handle the IN EP disable interrupt. ++ */ ++static inline void handle_in_ep_disable_intr(dwc_otg_pcd_t * pcd, ++ const uint32_t epnum) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dwc_otg_dev_if_t *dev_if = core_if->dev_if; ++ deptsiz_data_t dieptsiz = {.d32 = 0 }; ++ dctl_data_t dctl = {.d32 = 0 }; ++ dwc_otg_pcd_ep_t *ep; ++ dwc_ep_t *dwc_ep; ++ gintmsk_data_t gintmsk_data; ++ depctl_data_t depctl; ++ uint32_t diepdma; ++ uint32_t remain_to_transfer = 0; ++ uint8_t i; ++ uint32_t xfer_size; ++ ++ ep = get_in_ep(pcd, epnum); ++ dwc_ep = &ep->dwc_ep; ++ ++ if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num); ++ complete_ep(ep); ++ return; ++ } ++ ++ DWC_DEBUGPL(DBG_PCD, "diepctl%d=%0x\n", epnum, ++ DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl)); ++ dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->dieptsiz); ++ depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl); ++ ++ DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n", ++ dieptsiz.b.pktcnt, dieptsiz.b.xfersize); ++ ++ if ((core_if->start_predict == 0) || (depctl.b.eptype & 1)) { ++ if (ep->stopped) { ++ if (core_if->en_multiple_tx_fifo) ++ /* Flush the Tx FIFO */ ++ dwc_otg_flush_tx_fifo(core_if, dwc_ep->tx_fifo_num); ++ /* Clear the Global IN NP NAK */ ++ dctl.d32 = 0; ++ dctl.b.cgnpinnak = 1; ++ DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); ++ /* Restart the transaction */ ++ if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) { ++ restart_transfer(pcd, epnum); ++ } ++ } else { ++ /* Restart the transaction */ ++ if (dieptsiz.b.pktcnt != 0 || dieptsiz.b.xfersize != 0) { ++ restart_transfer(pcd, epnum); ++ } ++ DWC_DEBUGPL(DBG_ANY, "STOPPED!!!\n"); ++ } ++ return; ++ } ++ ++ if (core_if->start_predict > 2) { // NP IN EP ++ core_if->start_predict--; ++ return; ++ } ++ ++ core_if->start_predict--; ++ ++ if (core_if->start_predict == 1) { // All NP IN Ep's disabled now ++ ++ predict_nextep_seq(core_if); ++ ++ /* Update all active IN EP's NextEP field based of nextep_seq[] */ ++ for ( i = 0; i <= core_if->dev_if->num_in_eps; i++) { ++ depctl.d32 = ++ DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl); ++ if (core_if->nextep_seq[i] != 0xff) { // Active NP IN EP ++ depctl.b.nextep = core_if->nextep_seq[i]; ++ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32); ++ } ++ } ++ /* Flush Shared NP TxFIFO */ ++ dwc_otg_flush_tx_fifo(core_if, 0); ++ /* Rewind buffers */ ++ if (!core_if->dma_desc_enable) { ++ i = core_if->first_in_nextep_seq; ++ do { ++ ep = get_in_ep(pcd, i); ++ dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz); ++ xfer_size = ep->dwc_ep.total_len - ep->dwc_ep.xfer_count; ++ if (xfer_size > ep->dwc_ep.maxxfer) ++ xfer_size = ep->dwc_ep.maxxfer; ++ depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl); ++ if (dieptsiz.b.pktcnt != 0) { ++ if (xfer_size == 0) { ++ remain_to_transfer = 0; ++ } else { ++ if ((xfer_size % ep->dwc_ep.maxpacket) == 0) { ++ remain_to_transfer = ++ dieptsiz.b.pktcnt * ep->dwc_ep.maxpacket; ++ } else { ++ remain_to_transfer = ((dieptsiz.b.pktcnt -1) * ep->dwc_ep.maxpacket) ++ + (xfer_size % ep->dwc_ep.maxpacket); ++ } ++ } ++ diepdma = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepdma); ++ dieptsiz.b.xfersize = remain_to_transfer; ++ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->dieptsiz, dieptsiz.d32); ++ diepdma = ep->dwc_ep.dma_addr + (xfer_size - remain_to_transfer); ++ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepdma, diepdma); ++ } ++ i = core_if->nextep_seq[i]; ++ } while (i != core_if->first_in_nextep_seq); ++ } else { // dma_desc_enable ++ DWC_PRINTF("%s Learning Queue not supported in DDMA\n", __func__); ++ } ++ ++ /* Restart transfers in predicted sequences */ ++ i = core_if->first_in_nextep_seq; ++ do { ++ dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz); ++ depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl); ++ if (dieptsiz.b.pktcnt != 0) { ++ depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl); ++ depctl.b.epena = 1; ++ depctl.b.cnak = 1; ++ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32); ++ } ++ i = core_if->nextep_seq[i]; ++ } while (i != core_if->first_in_nextep_seq); ++ ++ /* Clear the global non-periodic IN NAK handshake */ ++ dctl.d32 = 0; ++ dctl.b.cgnpinnak = 1; ++ DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); ++ ++ /* Unmask EP Mismatch interrupt */ ++ gintmsk_data.d32 = 0; ++ gintmsk_data.b.epmismatch = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk_data.d32); ++ ++ core_if->start_predict = 0; ++ ++ } ++} ++ ++/** ++ * Handler for the IN EP timeout handshake interrupt. ++ */ ++static inline void handle_in_ep_timeout_intr(dwc_otg_pcd_t * pcd, ++ const uint32_t epnum) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dwc_otg_dev_if_t *dev_if = core_if->dev_if; ++ ++#ifdef DEBUG ++ deptsiz_data_t dieptsiz = {.d32 = 0 }; ++ uint32_t num = 0; ++#endif ++ dctl_data_t dctl = {.d32 = 0 }; ++ dwc_otg_pcd_ep_t *ep; ++ ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ ++ ep = get_in_ep(pcd, epnum); ++ ++ /* Disable the NP Tx Fifo Empty Interrrupt */ ++ if (!core_if->dma_enable) { ++ intr_mask.b.nptxfempty = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, ++ intr_mask.d32, 0); ++ } ++ /** @todo NGS Check EP type. ++ * Implement for Periodic EPs */ ++ /* ++ * Non-periodic EP ++ */ ++ /* Enable the Global IN NAK Effective Interrupt */ ++ intr_mask.b.ginnakeff = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, intr_mask.d32); ++ ++ /* Set Global IN NAK */ ++ dctl.b.sgnpinnak = 1; ++ DWC_MODIFY_REG32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32); ++ ++ ep->stopped = 1; ++ ++#ifdef DEBUG ++ dieptsiz.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[num]->dieptsiz); ++ DWC_DEBUGPL(DBG_ANY, "pktcnt=%d size=%d\n", ++ dieptsiz.b.pktcnt, dieptsiz.b.xfersize); ++#endif ++ ++#ifdef DISABLE_PERIODIC_EP ++ /* ++ * Set the NAK bit for this EP to ++ * start the disable process. ++ */ ++ diepctl.d32 = 0; ++ diepctl.b.snak = 1; ++ DWC_MODIFY_REG32(&dev_if->in_ep_regs[num]->diepctl, diepctl.d32, ++ diepctl.d32); ++ ep->disabling = 1; ++ ep->stopped = 1; ++#endif ++} ++ ++/** ++ * Handler for the IN EP NAK interrupt. ++ */ ++static inline int32_t handle_in_ep_nak_intr(dwc_otg_pcd_t * pcd, ++ const uint32_t epnum) ++{ ++ /** @todo implement ISR */ ++ dwc_otg_core_if_t *core_if; ++ diepmsk_data_t intr_mask = {.d32 = 0 }; ++ ++ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "IN EP NAK"); ++ core_if = GET_CORE_IF(pcd); ++ intr_mask.b.nak = 1; ++ ++ if (core_if->multiproc_int_enable) { ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs-> ++ diepeachintmsk[epnum], intr_mask.d32, 0); ++ } else { ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->diepmsk, ++ intr_mask.d32, 0); ++ } ++ ++ return 1; ++} ++ ++/** ++ * Handler for the OUT EP Babble interrupt. ++ */ ++static inline int32_t handle_out_ep_babble_intr(dwc_otg_pcd_t * pcd, ++ const uint32_t epnum) ++{ ++ /** @todo implement ISR */ ++ dwc_otg_core_if_t *core_if; ++ doepmsk_data_t intr_mask = {.d32 = 0 }; ++ ++ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", ++ "OUT EP Babble"); ++ core_if = GET_CORE_IF(pcd); ++ intr_mask.b.babble = 1; ++ ++ if (core_if->multiproc_int_enable) { ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs-> ++ doepeachintmsk[epnum], intr_mask.d32, 0); ++ } else { ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk, ++ intr_mask.d32, 0); ++ } ++ ++ return 1; ++} ++ ++/** ++ * Handler for the OUT EP NAK interrupt. ++ */ ++static inline int32_t handle_out_ep_nak_intr(dwc_otg_pcd_t * pcd, ++ const uint32_t epnum) ++{ ++ /** @todo implement ISR */ ++ dwc_otg_core_if_t *core_if; ++ doepmsk_data_t intr_mask = {.d32 = 0 }; ++ ++ DWC_DEBUGPL(DBG_ANY, "INTERRUPT Handler not implemented for %s\n", "OUT EP NAK"); ++ core_if = GET_CORE_IF(pcd); ++ intr_mask.b.nak = 1; ++ ++ if (core_if->multiproc_int_enable) { ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs-> ++ doepeachintmsk[epnum], intr_mask.d32, 0); ++ } else { ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk, ++ intr_mask.d32, 0); ++ } ++ ++ return 1; ++} ++ ++/** ++ * Handler for the OUT EP NYET interrupt. ++ */ ++static inline int32_t handle_out_ep_nyet_intr(dwc_otg_pcd_t * pcd, ++ const uint32_t epnum) ++{ ++ /** @todo implement ISR */ ++ dwc_otg_core_if_t *core_if; ++ doepmsk_data_t intr_mask = {.d32 = 0 }; ++ ++ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", "OUT EP NYET"); ++ core_if = GET_CORE_IF(pcd); ++ intr_mask.b.nyet = 1; ++ ++ if (core_if->multiproc_int_enable) { ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs-> ++ doepeachintmsk[epnum], intr_mask.d32, 0); ++ } else { ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk, ++ intr_mask.d32, 0); ++ } ++ ++ return 1; ++} ++ ++/** ++ * This interrupt indicates that an IN EP has a pending Interrupt. ++ * The sequence for handling the IN EP interrupt is shown below: ++ * -# Read the Device All Endpoint Interrupt register ++ * -# Repeat the following for each IN EP interrupt bit set (from ++ * LSB to MSB). ++ * -# Read the Device Endpoint Interrupt (DIEPINTn) register ++ * -# If "Transfer Complete" call the request complete function ++ * -# If "Endpoint Disabled" complete the EP disable procedure. ++ * -# If "AHB Error Interrupt" log error ++ * -# If "Time-out Handshake" log error ++ * -# If "IN Token Received when TxFIFO Empty" write packet to Tx ++ * FIFO. ++ * -# If "IN Token EP Mismatch" (disable, this is handled by EP ++ * Mismatch Interrupt) ++ */ ++static int32_t dwc_otg_pcd_handle_in_ep_intr(dwc_otg_pcd_t * pcd) ++{ ++#define CLEAR_IN_EP_INTR(__core_if,__epnum,__intr) \ ++do { \ ++ diepint_data_t diepint = {.d32=0}; \ ++ diepint.b.__intr = 1; \ ++ DWC_WRITE_REG32(&__core_if->dev_if->in_ep_regs[__epnum]->diepint, \ ++ diepint.d32); \ ++} while (0) ++ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ dwc_otg_dev_if_t *dev_if = core_if->dev_if; ++ diepint_data_t diepint = {.d32 = 0 }; ++ depctl_data_t depctl = {.d32 = 0 }; ++ uint32_t ep_intr; ++ uint32_t epnum = 0; ++ dwc_otg_pcd_ep_t *ep; ++ dwc_ep_t *dwc_ep; ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, pcd); ++ ++ /* Read in the device interrupt bits */ ++ ep_intr = dwc_otg_read_dev_all_in_ep_intr(core_if); ++ ++ /* Service the Device IN interrupts for each endpoint */ ++ while (ep_intr) { ++ if (ep_intr & 0x1) { ++ uint32_t empty_msk; ++ /* Get EP pointer */ ++ ep = get_in_ep(pcd, epnum); ++ dwc_ep = &ep->dwc_ep; ++ ++ depctl.d32 = ++ DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl); ++ empty_msk = ++ DWC_READ_REG32(&dev_if-> ++ dev_global_regs->dtknqr4_fifoemptymsk); ++ ++ DWC_DEBUGPL(DBG_PCDV, ++ "IN EP INTERRUPT - %d\nepmty_msk - %8x diepctl - %8x\n", ++ epnum, empty_msk, depctl.d32); ++ ++ DWC_DEBUGPL(DBG_PCD, ++ "EP%d-%s: type=%d, mps=%d\n", ++ dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"), ++ dwc_ep->type, dwc_ep->maxpacket); ++ ++ diepint.d32 = ++ dwc_otg_read_dev_in_ep_intr(core_if, dwc_ep); ++ ++ DWC_DEBUGPL(DBG_PCDV, ++ "EP %d Interrupt Register - 0x%x\n", epnum, ++ diepint.d32); ++ /* Transfer complete */ ++ if (diepint.b.xfercompl) { ++ /* Disable the NP Tx FIFO Empty ++ * Interrupt */ ++ if (core_if->en_multiple_tx_fifo == 0) { ++ intr_mask.b.nptxfempty = 1; ++ DWC_MODIFY_REG32 ++ (&core_if->core_global_regs->gintmsk, ++ intr_mask.d32, 0); ++ } else { ++ /* Disable the Tx FIFO Empty Interrupt for this EP */ ++ uint32_t fifoemptymsk = ++ 0x1 << dwc_ep->num; ++ DWC_MODIFY_REG32(&core_if-> ++ dev_if->dev_global_regs->dtknqr4_fifoemptymsk, ++ fifoemptymsk, 0); ++ } ++ /* Clear the bit in DIEPINTn for this interrupt */ ++ CLEAR_IN_EP_INTR(core_if, epnum, xfercompl); ++ ++ /* Complete the transfer */ ++ if (epnum == 0) { ++ handle_ep0(pcd); ++ } ++#ifdef DWC_EN_ISOC ++ else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ if (!ep->stopped) ++ complete_iso_ep(pcd, ep); ++ } ++#endif /* DWC_EN_ISOC */ ++#ifdef DWC_UTE_PER_IO ++ else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ if (!ep->stopped) ++ complete_xiso_ep(ep); ++ } ++#endif /* DWC_UTE_PER_IO */ ++ else { ++ if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC && ++ dwc_ep->bInterval > 1) { ++ dwc_ep->frame_num += dwc_ep->bInterval; ++ if (dwc_ep->frame_num > 0x3FFF) ++ { ++ dwc_ep->frm_overrun = 1; ++ dwc_ep->frame_num &= 0x3FFF; ++ } else ++ dwc_ep->frm_overrun = 0; ++ } ++ complete_ep(ep); ++ if(diepint.b.nak) ++ CLEAR_IN_EP_INTR(core_if, epnum, nak); ++ } ++ } ++ /* Endpoint disable */ ++ if (diepint.b.epdisabled) { ++ DWC_DEBUGPL(DBG_ANY, "EP%d IN disabled\n", ++ epnum); ++ handle_in_ep_disable_intr(pcd, epnum); ++ ++ /* Clear the bit in DIEPINTn for this interrupt */ ++ CLEAR_IN_EP_INTR(core_if, epnum, epdisabled); ++ } ++ /* AHB Error */ ++ if (diepint.b.ahberr) { ++ DWC_ERROR("EP%d IN AHB Error\n", epnum); ++ /* Clear the bit in DIEPINTn for this interrupt */ ++ CLEAR_IN_EP_INTR(core_if, epnum, ahberr); ++ } ++ /* TimeOUT Handshake (non-ISOC IN EPs) */ ++ if (diepint.b.timeout) { ++ DWC_ERROR("EP%d IN Time-out\n", epnum); ++ handle_in_ep_timeout_intr(pcd, epnum); ++ ++ CLEAR_IN_EP_INTR(core_if, epnum, timeout); ++ } ++ /** IN Token received with TxF Empty */ ++ if (diepint.b.intktxfemp) { ++ DWC_DEBUGPL(DBG_ANY, ++ "EP%d IN TKN TxFifo Empty\n", ++ epnum); ++ if (!ep->stopped && epnum != 0) { ++ ++ diepmsk_data_t diepmsk = {.d32 = 0 }; ++ diepmsk.b.intktxfemp = 1; ++ ++ if (core_if->multiproc_int_enable) { ++ DWC_MODIFY_REG32 ++ (&dev_if->dev_global_regs->diepeachintmsk ++ [epnum], diepmsk.d32, 0); ++ } else { ++ DWC_MODIFY_REG32 ++ (&dev_if->dev_global_regs->diepmsk, ++ diepmsk.d32, 0); ++ } ++ } else if (core_if->dma_desc_enable ++ && epnum == 0 ++ && pcd->ep0state == ++ EP0_OUT_STATUS_PHASE) { ++ // EP0 IN set STALL ++ depctl.d32 = ++ DWC_READ_REG32(&dev_if->in_ep_regs ++ [epnum]->diepctl); ++ ++ /* set the disable and stall bits */ ++ if (depctl.b.epena) { ++ depctl.b.epdis = 1; ++ } ++ depctl.b.stall = 1; ++ DWC_WRITE_REG32(&dev_if->in_ep_regs ++ [epnum]->diepctl, ++ depctl.d32); ++ } ++ CLEAR_IN_EP_INTR(core_if, epnum, intktxfemp); ++ } ++ /** IN Token Received with EP mismatch */ ++ if (diepint.b.intknepmis) { ++ DWC_DEBUGPL(DBG_ANY, ++ "EP%d IN TKN EP Mismatch\n", epnum); ++ CLEAR_IN_EP_INTR(core_if, epnum, intknepmis); ++ } ++ /** IN Endpoint NAK Effective */ ++ if (diepint.b.inepnakeff) { ++ DWC_DEBUGPL(DBG_ANY, ++ "EP%d IN EP NAK Effective\n", ++ epnum); ++ /* Periodic EP */ ++ if (ep->disabling) { ++ depctl.d32 = 0; ++ depctl.b.snak = 1; ++ depctl.b.epdis = 1; ++ DWC_MODIFY_REG32(&dev_if->in_ep_regs ++ [epnum]->diepctl, ++ depctl.d32, ++ depctl.d32); ++ } ++ CLEAR_IN_EP_INTR(core_if, epnum, inepnakeff); ++ ++ } ++ ++ /** IN EP Tx FIFO Empty Intr */ ++ if (diepint.b.emptyintr) { ++ DWC_DEBUGPL(DBG_ANY, ++ "EP%d Tx FIFO Empty Intr \n", ++ epnum); ++ write_empty_tx_fifo(pcd, epnum); ++ ++ CLEAR_IN_EP_INTR(core_if, epnum, emptyintr); ++ ++ } ++ ++ /** IN EP BNA Intr */ ++ if (diepint.b.bna) { ++ CLEAR_IN_EP_INTR(core_if, epnum, bna); ++ if (core_if->dma_desc_enable) { ++#ifdef DWC_EN_ISOC ++ if (dwc_ep->type == ++ DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * This checking is performed to prevent first "false" BNA ++ * handling occuring right after reconnect ++ */ ++ if (dwc_ep->next_frame != ++ 0xffffffff) ++ dwc_otg_pcd_handle_iso_bna(ep); ++ } else ++#endif /* DWC_EN_ISOC */ ++ { ++ dwc_otg_pcd_handle_noniso_bna(ep); ++ } ++ } ++ } ++ /* NAK Interrutp */ ++ if (diepint.b.nak) { ++ DWC_DEBUGPL(DBG_ANY, "EP%d IN NAK Interrupt\n", ++ epnum); ++ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) { ++ depctl_data_t depctl; ++ if (ep->dwc_ep.frame_num == 0xFFFFFFFF) { ++ ep->dwc_ep.frame_num = core_if->frame_num; ++ if (ep->dwc_ep.bInterval > 1) { ++ depctl.d32 = 0; ++ depctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[epnum]->diepctl); ++ if (ep->dwc_ep.frame_num & 0x1) { ++ depctl.b.setd1pid = 1; ++ depctl.b.setd0pid = 0; ++ } else { ++ depctl.b.setd0pid = 1; ++ depctl.b.setd1pid = 0; ++ } ++ DWC_WRITE_REG32(&dev_if->in_ep_regs[epnum]->diepctl, depctl.d32); ++ } ++ start_next_request(ep); ++ } ++ ep->dwc_ep.frame_num += ep->dwc_ep.bInterval; ++ if (dwc_ep->frame_num > 0x3FFF) { ++ dwc_ep->frm_overrun = 1; ++ dwc_ep->frame_num &= 0x3FFF; ++ } else ++ dwc_ep->frm_overrun = 0; ++ } ++ ++ CLEAR_IN_EP_INTR(core_if, epnum, nak); ++ } ++ } ++ epnum++; ++ ep_intr >>= 1; ++ } ++ ++ return 1; ++#undef CLEAR_IN_EP_INTR ++} ++ ++/** ++ * This interrupt indicates that an OUT EP has a pending Interrupt. ++ * The sequence for handling the OUT EP interrupt is shown below: ++ * -# Read the Device All Endpoint Interrupt register ++ * -# Repeat the following for each OUT EP interrupt bit set (from ++ * LSB to MSB). ++ * -# Read the Device Endpoint Interrupt (DOEPINTn) register ++ * -# If "Transfer Complete" call the request complete function ++ * -# If "Endpoint Disabled" complete the EP disable procedure. ++ * -# If "AHB Error Interrupt" log error ++ * -# If "Setup Phase Done" process Setup Packet (See Standard USB ++ * Command Processing) ++ */ ++static int32_t dwc_otg_pcd_handle_out_ep_intr(dwc_otg_pcd_t * pcd) ++{ ++#define CLEAR_OUT_EP_INTR(__core_if,__epnum,__intr) \ ++do { \ ++ doepint_data_t doepint = {.d32=0}; \ ++ doepint.b.__intr = 1; \ ++ DWC_WRITE_REG32(&__core_if->dev_if->out_ep_regs[__epnum]->doepint, \ ++ doepint.d32); \ ++} while (0) ++ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ uint32_t ep_intr; ++ doepint_data_t doepint = {.d32 = 0 }; ++ uint32_t epnum = 0; ++ dwc_otg_pcd_ep_t *ep; ++ dwc_ep_t *dwc_ep; ++ dctl_data_t dctl = {.d32 = 0 }; ++ gintmsk_data_t gintmsk = {.d32 = 0 }; ++ ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s()\n", __func__); ++ ++ /* Read in the device interrupt bits */ ++ ep_intr = dwc_otg_read_dev_all_out_ep_intr(core_if); ++ ++ while (ep_intr) { ++ if (ep_intr & 0x1) { ++ /* Get EP pointer */ ++ ep = get_out_ep(pcd, epnum); ++ dwc_ep = &ep->dwc_ep; ++ ++#ifdef VERBOSE ++ DWC_DEBUGPL(DBG_PCDV, ++ "EP%d-%s: type=%d, mps=%d\n", ++ dwc_ep->num, (dwc_ep->is_in ? "IN" : "OUT"), ++ dwc_ep->type, dwc_ep->maxpacket); ++#endif ++ doepint.d32 = ++ dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep); ++ /* Moved this interrupt upper due to core deffect of asserting ++ * OUT EP 0 xfercompl along with stsphsrcvd in BDMA */ ++ if (doepint.b.stsphsercvd) { ++ deptsiz0_data_t deptsiz; ++ CLEAR_OUT_EP_INTR(core_if, epnum, stsphsercvd); ++ deptsiz.d32 = ++ DWC_READ_REG32(&core_if->dev_if-> ++ out_ep_regs[0]->doeptsiz); ++ if (core_if->snpsid >= OTG_CORE_REV_3_00a ++ && core_if->dma_enable ++ && core_if->dma_desc_enable == 0 ++ && doepint.b.xfercompl ++ && deptsiz.b.xfersize == 24) { ++ CLEAR_OUT_EP_INTR(core_if, epnum, ++ xfercompl); ++ doepint.b.xfercompl = 0; ++ ep0_out_start(core_if, pcd); ++ } ++ if ((core_if->dma_desc_enable) || ++ (core_if->dma_enable ++ && core_if->snpsid >= ++ OTG_CORE_REV_3_00a)) { ++ do_setup_in_status_phase(pcd); ++ } ++ } ++ /* Transfer complete */ ++ if (doepint.b.xfercompl) { ++ ++ if (epnum == 0) { ++ /* Clear the bit in DOEPINTn for this interrupt */ ++ CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl); ++ if (core_if->snpsid >= OTG_CORE_REV_3_00a) { ++ DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n", ++ DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepint), ++ doepint.d32); ++ DWC_DEBUGPL(DBG_PCDV, "DOEPCTL=%x \n", ++ DWC_READ_REG32(&core_if->dev_if->out_ep_regs[0]->doepctl)); ++ ++ if (core_if->snpsid >= OTG_CORE_REV_3_00a ++ && core_if->dma_enable == 0) { ++ doepint_data_t doepint; ++ doepint.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ out_ep_regs[0]->doepint); ++ if (pcd->ep0state == EP0_IDLE && doepint.b.sr) { ++ CLEAR_OUT_EP_INTR(core_if, epnum, sr); ++ goto exit_xfercompl; ++ } ++ } ++ /* In case of DDMA look at SR bit to go to the Data Stage */ ++ if (core_if->dma_desc_enable) { ++ dev_dma_desc_sts_t status = {.d32 = 0}; ++ if (pcd->ep0state == EP0_IDLE) { ++ status.d32 = core_if->dev_if->setup_desc_addr[core_if-> ++ dev_if->setup_desc_index]->status.d32; ++ if(pcd->data_terminated) { ++ pcd->data_terminated = 0; ++ status.d32 = core_if->dev_if->out_desc_addr->status.d32; ++ dwc_memcpy(&pcd->setup_pkt->req, pcd->backup_buf, 8); ++ } ++ if (status.b.sr) { ++ if (doepint.b.setup) { ++ DWC_DEBUGPL(DBG_PCDV, "DMA DESC EP0_IDLE SR=1 setup=1\n"); ++ /* Already started data stage, clear setup */ ++ CLEAR_OUT_EP_INTR(core_if, epnum, setup); ++ doepint.b.setup = 0; ++ handle_ep0(pcd); ++ /* Prepare for more setup packets */ ++ if (pcd->ep0state == EP0_IN_STATUS_PHASE || ++ pcd->ep0state == EP0_IN_DATA_PHASE) { ++ ep0_out_start(core_if, pcd); ++ } ++ ++ goto exit_xfercompl; ++ } else { ++ /* Prepare for more setup packets */ ++ DWC_DEBUGPL(DBG_PCDV, ++ "EP0_IDLE SR=1 setup=0 new setup comes\n"); ++ ep0_out_start(core_if, pcd); ++ } ++ } ++ } else { ++ dwc_otg_pcd_request_t *req; ++ dev_dma_desc_sts_t status = {.d32 = 0}; ++ diepint_data_t diepint0; ++ diepint0.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ in_ep_regs[0]->diepint); ++ ++ if (pcd->ep0state == EP0_STALL || pcd->ep0state == EP0_DISCONNECT) { ++ DWC_ERROR("EP0 is stalled/disconnected\n"); ++ } ++ ++ /* Clear IN xfercompl if set */ ++ if (diepint0.b.xfercompl && (pcd->ep0state == EP0_IN_STATUS_PHASE ++ || pcd->ep0state == EP0_IN_DATA_PHASE)) { ++ DWC_WRITE_REG32(&core_if->dev_if-> ++ in_ep_regs[0]->diepint, diepint0.d32); ++ } ++ ++ status.d32 = core_if->dev_if->setup_desc_addr[core_if-> ++ dev_if->setup_desc_index]->status.d32; ++ ++ if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len ++ && (pcd->ep0state == EP0_OUT_DATA_PHASE)) ++ status.d32 = core_if->dev_if->out_desc_addr->status.d32; ++ if (pcd->ep0state == EP0_OUT_STATUS_PHASE) ++ status.d32 = core_if->dev_if-> ++ out_desc_addr->status.d32; ++ ++ if (status.b.sr) { ++ if (DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n"); ++ } else { ++ DWC_DEBUGPL(DBG_PCDV, "complete req!!\n"); ++ req = DWC_CIRCLEQ_FIRST(&ep->queue); ++ if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len && ++ pcd->ep0state == EP0_OUT_DATA_PHASE) { ++ /* Read arrived setup packet from req->buf */ ++ dwc_memcpy(&pcd->setup_pkt->req, ++ req->buf + ep->dwc_ep.xfer_count, 8); ++ } ++ req->actual = ep->dwc_ep.xfer_count; ++ dwc_otg_request_done(ep, req, -ECONNRESET); ++ ep->dwc_ep.start_xfer_buff = 0; ++ ep->dwc_ep.xfer_buff = 0; ++ ep->dwc_ep.xfer_len = 0; ++ } ++ pcd->ep0state = EP0_IDLE; ++ if (doepint.b.setup) { ++ DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n"); ++ /* Data stage started, clear setup */ ++ CLEAR_OUT_EP_INTR(core_if, epnum, setup); ++ doepint.b.setup = 0; ++ handle_ep0(pcd); ++ /* Prepare for setup packets if ep0in was enabled*/ ++ if (pcd->ep0state == EP0_IN_STATUS_PHASE) { ++ ep0_out_start(core_if, pcd); ++ } ++ ++ goto exit_xfercompl; ++ } else { ++ /* Prepare for more setup packets */ ++ DWC_DEBUGPL(DBG_PCDV, ++ "EP0_IDLE SR=1 setup=0 new setup comes 2\n"); ++ ep0_out_start(core_if, pcd); ++ } ++ } ++ } ++ } ++ if (core_if->snpsid >= OTG_CORE_REV_2_94a && core_if->dma_enable ++ && core_if->dma_desc_enable == 0) { ++ doepint_data_t doepint_temp = {.d32 = 0}; ++ deptsiz0_data_t doeptsize0 = {.d32 = 0 }; ++ doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ out_ep_regs[ep->dwc_ep.num]->doepint); ++ doeptsize0.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ out_ep_regs[ep->dwc_ep.num]->doeptsiz); ++ if (pcd->ep0state == EP0_IDLE) { ++ if (doepint_temp.b.sr) { ++ CLEAR_OUT_EP_INTR(core_if, epnum, sr); ++ } ++ doepint.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ out_ep_regs[0]->doepint); ++ if (doeptsize0.b.supcnt == 3) { ++ DWC_DEBUGPL(DBG_ANY, "Rolling over!!!!!!!\n"); ++ ep->dwc_ep.stp_rollover = 1; ++ } ++ if (doepint.b.setup) { ++retry: ++ /* Already started data stage, clear setup */ ++ CLEAR_OUT_EP_INTR(core_if, epnum, setup); ++ doepint.b.setup = 0; ++ handle_ep0(pcd); ++ ep->dwc_ep.stp_rollover = 0; ++ /* Prepare for more setup packets */ ++ if (pcd->ep0state == EP0_IN_STATUS_PHASE || ++ pcd->ep0state == EP0_IN_DATA_PHASE) { ++ ep0_out_start(core_if, pcd); ++ } ++ goto exit_xfercompl; ++ } else { ++ /* Prepare for more setup packets */ ++ DWC_DEBUGPL(DBG_ANY, ++ "EP0_IDLE SR=1 setup=0 new setup comes\n"); ++ doepint.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ out_ep_regs[0]->doepint); ++ if(doepint.b.setup) ++ goto retry; ++ ep0_out_start(core_if, pcd); ++ } ++ } else { ++ dwc_otg_pcd_request_t *req; ++ diepint_data_t diepint0 = {.d32 = 0}; ++ doepint_data_t doepint_temp = {.d32 = 0}; ++ depctl_data_t diepctl0; ++ diepint0.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ in_ep_regs[0]->diepint); ++ diepctl0.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ in_ep_regs[0]->diepctl); ++ ++ if (pcd->ep0state == EP0_IN_DATA_PHASE ++ || pcd->ep0state == EP0_IN_STATUS_PHASE) { ++ if (diepint0.b.xfercompl) { ++ DWC_WRITE_REG32(&core_if->dev_if-> ++ in_ep_regs[0]->diepint, diepint0.d32); ++ } ++ if (diepctl0.b.epena) { ++ diepint_data_t diepint = {.d32 = 0}; ++ diepctl0.b.snak = 1; ++ DWC_WRITE_REG32(&core_if->dev_if-> ++ in_ep_regs[0]->diepctl, diepctl0.d32); ++ do { ++ dwc_udelay(10); ++ diepint.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ in_ep_regs[0]->diepint); ++ } while (!diepint.b.inepnakeff); ++ diepint.b.inepnakeff = 1; ++ DWC_WRITE_REG32(&core_if->dev_if-> ++ in_ep_regs[0]->diepint, diepint.d32); ++ diepctl0.d32 = 0; ++ diepctl0.b.epdis = 1; ++ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepctl, ++ diepctl0.d32); ++ do { ++ dwc_udelay(10); ++ diepint.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ in_ep_regs[0]->diepint); ++ } while (!diepint.b.epdisabled); ++ diepint.b.epdisabled = 1; ++ DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[0]->diepint, ++ diepint.d32); ++ } ++ } ++ doepint_temp.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ out_ep_regs[ep->dwc_ep.num]->doepint); ++ if (doepint_temp.b.sr) { ++ CLEAR_OUT_EP_INTR(core_if, epnum, sr); ++ if (DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ DWC_DEBUGPL(DBG_PCDV, "Request queue empty!!\n"); ++ } else { ++ DWC_DEBUGPL(DBG_PCDV, "complete req!!\n"); ++ req = DWC_CIRCLEQ_FIRST(&ep->queue); ++ if (ep->dwc_ep.xfer_count != ep->dwc_ep.total_len && ++ pcd->ep0state == EP0_OUT_DATA_PHASE) { ++ /* Read arrived setup packet from req->buf */ ++ dwc_memcpy(&pcd->setup_pkt->req, ++ req->buf + ep->dwc_ep.xfer_count, 8); ++ } ++ req->actual = ep->dwc_ep.xfer_count; ++ dwc_otg_request_done(ep, req, -ECONNRESET); ++ ep->dwc_ep.start_xfer_buff = 0; ++ ep->dwc_ep.xfer_buff = 0; ++ ep->dwc_ep.xfer_len = 0; ++ } ++ pcd->ep0state = EP0_IDLE; ++ if (doepint.b.setup) { ++ DWC_DEBUGPL(DBG_PCDV, "EP0_IDLE SR=1 setup=1\n"); ++ /* Data stage started, clear setup */ ++ CLEAR_OUT_EP_INTR(core_if, epnum, setup); ++ doepint.b.setup = 0; ++ handle_ep0(pcd); ++ /* Prepare for setup packets if ep0in was enabled*/ ++ if (pcd->ep0state == EP0_IN_STATUS_PHASE) { ++ ep0_out_start(core_if, pcd); ++ } ++ goto exit_xfercompl; ++ } else { ++ /* Prepare for more setup packets */ ++ DWC_DEBUGPL(DBG_PCDV, ++ "EP0_IDLE SR=1 setup=0 new setup comes 2\n"); ++ ep0_out_start(core_if, pcd); ++ } ++ } ++ } ++ } ++ if (core_if->dma_enable == 0 || pcd->ep0state != EP0_IDLE) ++ handle_ep0(pcd); ++exit_xfercompl: ++ DWC_DEBUGPL(DBG_PCDV, "DOEPINT=%x doepint=%x\n", ++ dwc_otg_read_dev_out_ep_intr(core_if, dwc_ep), doepint.d32); ++ } else { ++ if (core_if->dma_desc_enable == 0 ++ || pcd->ep0state != EP0_IDLE) ++ handle_ep0(pcd); ++ } ++#ifdef DWC_EN_ISOC ++ } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ if (doepint.b.pktdrpsts == 0) { ++ /* Clear the bit in DOEPINTn for this interrupt */ ++ CLEAR_OUT_EP_INTR(core_if, ++ epnum, ++ xfercompl); ++ complete_iso_ep(pcd, ep); ++ } else { ++ ++ doepint_data_t doepint = {.d32 = 0 }; ++ doepint.b.xfercompl = 1; ++ doepint.b.pktdrpsts = 1; ++ DWC_WRITE_REG32 ++ (&core_if->dev_if->out_ep_regs ++ [epnum]->doepint, ++ doepint.d32); ++ if (handle_iso_out_pkt_dropped ++ (core_if, dwc_ep)) { ++ complete_iso_ep(pcd, ++ ep); ++ } ++ } ++#endif /* DWC_EN_ISOC */ ++#ifdef DWC_UTE_PER_IO ++ } else if (dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ CLEAR_OUT_EP_INTR(core_if, epnum, xfercompl); ++ if (!ep->stopped) ++ complete_xiso_ep(ep); ++#endif /* DWC_UTE_PER_IO */ ++ } else { ++ /* Clear the bit in DOEPINTn for this interrupt */ ++ CLEAR_OUT_EP_INTR(core_if, epnum, ++ xfercompl); ++ ++ if (core_if->core_params->dev_out_nak) { ++ DWC_TIMER_CANCEL(pcd->core_if->ep_xfer_timer[epnum]); ++ pcd->core_if->ep_xfer_info[epnum].state = 0; ++#ifdef DEBUG ++ print_memory_payload(pcd, dwc_ep); ++#endif ++ } ++ complete_ep(ep); ++ } ++ ++ } ++ ++ /* Endpoint disable */ ++ if (doepint.b.epdisabled) { ++ ++ /* Clear the bit in DOEPINTn for this interrupt */ ++ CLEAR_OUT_EP_INTR(core_if, epnum, epdisabled); ++ if (core_if->core_params->dev_out_nak) { ++#ifdef DEBUG ++ print_memory_payload(pcd, dwc_ep); ++#endif ++ /* In case of timeout condition */ ++ if (core_if->ep_xfer_info[epnum].state == 2) { ++ dctl.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ dev_global_regs->dctl); ++ dctl.b.cgoutnak = 1; ++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, ++ dctl.d32); ++ /* Unmask goutnakeff interrupt which was masked ++ * during handle nak out interrupt */ ++ gintmsk.b.goutnakeff = 1; ++ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, ++ 0, gintmsk.d32); ++ ++ complete_ep(ep); ++ } ++ } ++ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ++ { ++ dctl_data_t dctl; ++ gintmsk_data_t intr_mask = {.d32 = 0}; ++ dwc_otg_pcd_request_t *req = 0; ++ ++ dctl.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ dev_global_regs->dctl); ++ dctl.b.cgoutnak = 1; ++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, ++ dctl.d32); ++ ++ intr_mask.d32 = 0; ++ intr_mask.b.incomplisoout = 1; ++ ++ /* Get any pending requests */ ++ if (!DWC_CIRCLEQ_EMPTY(&ep->queue)) { ++ req = DWC_CIRCLEQ_FIRST(&ep->queue); ++ if (!req) { ++ DWC_PRINTF("complete_ep 0x%p, req = NULL!\n", ep); ++ } else { ++ dwc_otg_request_done(ep, req, 0); ++ start_next_request(ep); ++ } ++ } else { ++ DWC_PRINTF("complete_ep 0x%p, ep->queue empty!\n", ep); ++ } ++ } ++ } ++ /* AHB Error */ ++ if (doepint.b.ahberr) { ++ DWC_ERROR("EP%d OUT AHB Error\n", epnum); ++ DWC_ERROR("EP%d DEPDMA=0x%08x \n", ++ epnum, core_if->dev_if->out_ep_regs[epnum]->doepdma); ++ CLEAR_OUT_EP_INTR(core_if, epnum, ahberr); ++ } ++ /* Setup Phase Done (contorl EPs) */ ++ if (doepint.b.setup) { ++#ifdef DEBUG_EP0 ++ DWC_DEBUGPL(DBG_PCD, "EP%d SETUP Done\n", epnum); ++#endif ++ CLEAR_OUT_EP_INTR(core_if, epnum, setup); ++ ++ handle_ep0(pcd); ++ } ++ ++ /** OUT EP BNA Intr */ ++ if (doepint.b.bna) { ++ CLEAR_OUT_EP_INTR(core_if, epnum, bna); ++ if (core_if->dma_desc_enable) { ++#ifdef DWC_EN_ISOC ++ if (dwc_ep->type == ++ DWC_OTG_EP_TYPE_ISOC) { ++ /* ++ * This checking is performed to prevent first "false" BNA ++ * handling occuring right after reconnect ++ */ ++ if (dwc_ep->next_frame != ++ 0xffffffff) ++ dwc_otg_pcd_handle_iso_bna(ep); ++ } else ++#endif /* DWC_EN_ISOC */ ++ { ++ dwc_otg_pcd_handle_noniso_bna(ep); ++ } ++ } ++ } ++ /* Babble Interrupt */ ++ if (doepint.b.babble) { ++ DWC_DEBUGPL(DBG_ANY, "EP%d OUT Babble\n", ++ epnum); ++ handle_out_ep_babble_intr(pcd, epnum); ++ ++ CLEAR_OUT_EP_INTR(core_if, epnum, babble); ++ } ++ if (doepint.b.outtknepdis) { ++ DWC_DEBUGPL(DBG_ANY, "EP%d OUT Token received when EP is \ ++ disabled\n",epnum); ++ if (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) { ++ doepmsk_data_t doepmsk = {.d32 = 0}; ++ ep->dwc_ep.frame_num = core_if->frame_num; ++ if (ep->dwc_ep.bInterval > 1) { ++ depctl_data_t depctl; ++ depctl.d32 = DWC_READ_REG32(&core_if->dev_if-> ++ out_ep_regs[epnum]->doepctl); ++ if (ep->dwc_ep.frame_num & 0x1) { ++ depctl.b.setd1pid = 1; ++ depctl.b.setd0pid = 0; ++ } else { ++ depctl.b.setd0pid = 1; ++ depctl.b.setd1pid = 0; ++ } ++ DWC_WRITE_REG32(&core_if->dev_if-> ++ out_ep_regs[epnum]->doepctl, depctl.d32); ++ } ++ start_next_request(ep); ++ doepmsk.b.outtknepdis = 1; ++ DWC_MODIFY_REG32(&core_if->dev_if->dev_global_regs->doepmsk, ++ doepmsk.d32, 0); ++ } ++ CLEAR_OUT_EP_INTR(core_if, epnum, outtknepdis); ++ } ++ ++ /* NAK Interrutp */ ++ if (doepint.b.nak) { ++ DWC_DEBUGPL(DBG_ANY, "EP%d OUT NAK\n", epnum); ++ handle_out_ep_nak_intr(pcd, epnum); ++ ++ CLEAR_OUT_EP_INTR(core_if, epnum, nak); ++ } ++ /* NYET Interrutp */ ++ if (doepint.b.nyet) { ++ DWC_DEBUGPL(DBG_ANY, "EP%d OUT NYET\n", epnum); ++ handle_out_ep_nyet_intr(pcd, epnum); ++ ++ CLEAR_OUT_EP_INTR(core_if, epnum, nyet); ++ } ++ } ++ ++ epnum++; ++ ep_intr >>= 1; ++ } ++ ++ return 1; ++ ++#undef CLEAR_OUT_EP_INTR ++} ++static int drop_transfer(uint32_t trgt_fr, uint32_t curr_fr, uint8_t frm_overrun) ++{ ++ int retval = 0; ++ if(!frm_overrun && curr_fr >= trgt_fr) ++ retval = 1; ++ else if (frm_overrun ++ && (curr_fr >= trgt_fr && ((curr_fr - trgt_fr) < 0x3FFF / 2))) ++ retval = 1; ++ return retval; ++} ++/** ++ * Incomplete ISO IN Transfer Interrupt. ++ * This interrupt indicates one of the following conditions occurred ++ * while transmitting an ISOC transaction. ++ * - Corrupted IN Token for ISOC EP. ++ * - Packet not complete in FIFO. ++ * The follow actions will be taken: ++ * -# Determine the EP ++ * -# Set incomplete flag in dwc_ep structure ++ * -# Disable EP; when "Endpoint Disabled" interrupt is received ++ * Flush FIFO ++ */ ++int32_t dwc_otg_pcd_handle_incomplete_isoc_in_intr(dwc_otg_pcd_t * pcd) ++{ ++ gintsts_data_t gintsts; ++ ++#ifdef DWC_EN_ISOC ++ dwc_otg_dev_if_t *dev_if; ++ deptsiz_data_t deptsiz = {.d32 = 0 }; ++ depctl_data_t depctl = {.d32 = 0 }; ++ dsts_data_t dsts = {.d32 = 0 }; ++ dwc_ep_t *dwc_ep; ++ int i; ++ ++ dev_if = GET_CORE_IF(pcd)->dev_if; ++ ++ for (i = 1; i <= dev_if->num_in_eps; ++i) { ++ dwc_ep = &pcd->in_ep[i].dwc_ep; ++ if (dwc_ep->active && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ deptsiz.d32 = ++ DWC_READ_REG32(&dev_if->in_ep_regs[i]->dieptsiz); ++ depctl.d32 = ++ DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl); ++ ++ if (depctl.b.epdis && deptsiz.d32) { ++ set_current_pkt_info(GET_CORE_IF(pcd), dwc_ep); ++ if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) { ++ dwc_ep->cur_pkt = 0; ++ dwc_ep->proc_buf_num = ++ (dwc_ep->proc_buf_num ^ 1) & 0x1; ++ ++ if (dwc_ep->proc_buf_num) { ++ dwc_ep->cur_pkt_addr = ++ dwc_ep->xfer_buff1; ++ dwc_ep->cur_pkt_dma_addr = ++ dwc_ep->dma_addr1; ++ } else { ++ dwc_ep->cur_pkt_addr = ++ dwc_ep->xfer_buff0; ++ dwc_ep->cur_pkt_dma_addr = ++ dwc_ep->dma_addr0; ++ } ++ ++ } ++ ++ dsts.d32 = ++ DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if-> ++ dev_global_regs->dsts); ++ dwc_ep->next_frame = dsts.b.soffn; ++ ++ dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF ++ (pcd), ++ dwc_ep); ++ } ++ } ++ } ++ ++#else ++ depctl_data_t depctl = {.d32 = 0 }; ++ dwc_ep_t *dwc_ep; ++ dwc_otg_dev_if_t *dev_if; ++ int i; ++ dev_if = GET_CORE_IF(pcd)->dev_if; ++ ++ DWC_DEBUGPL(DBG_PCD,"Incomplete ISO IN \n"); ++ ++ for (i = 1; i <= dev_if->num_in_eps; ++i) { ++ dwc_ep = &pcd->in_ep[i-1].dwc_ep; ++ depctl.d32 = ++ DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl); ++ if (depctl.b.epena && dwc_ep->type == DWC_OTG_EP_TYPE_ISOC) { ++ if (drop_transfer(dwc_ep->frame_num, GET_CORE_IF(pcd)->frame_num, ++ dwc_ep->frm_overrun)) ++ { ++ depctl.d32 = ++ DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl); ++ depctl.b.snak = 1; ++ depctl.b.epdis = 1; ++ DWC_MODIFY_REG32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32, depctl.d32); ++ } ++ } ++ } ++ ++ /*intr_mask.b.incomplisoin = 1; ++ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, ++ intr_mask.d32, 0); */ ++#endif //DWC_EN_ISOC ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.incomplisoin = 1; ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, ++ gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * Incomplete ISO OUT Transfer Interrupt. ++ * ++ * This interrupt indicates that the core has dropped an ISO OUT ++ * packet. The following conditions can be the cause: ++ * - FIFO Full, the entire packet would not fit in the FIFO. ++ * - CRC Error ++ * - Corrupted Token ++ * The follow actions will be taken: ++ * -# Determine the EP ++ * -# Set incomplete flag in dwc_ep structure ++ * -# Read any data from the FIFO ++ * -# Disable EP. When "Endpoint Disabled" interrupt is received ++ * re-enable EP. ++ */ ++int32_t dwc_otg_pcd_handle_incomplete_isoc_out_intr(dwc_otg_pcd_t * pcd) ++{ ++ ++ gintsts_data_t gintsts; ++ ++#ifdef DWC_EN_ISOC ++ dwc_otg_dev_if_t *dev_if; ++ deptsiz_data_t deptsiz = {.d32 = 0 }; ++ depctl_data_t depctl = {.d32 = 0 }; ++ dsts_data_t dsts = {.d32 = 0 }; ++ dwc_ep_t *dwc_ep; ++ int i; ++ ++ dev_if = GET_CORE_IF(pcd)->dev_if; ++ ++ for (i = 1; i <= dev_if->num_out_eps; ++i) { ++ dwc_ep = &pcd->in_ep[i].dwc_ep; ++ if (pcd->out_ep[i].dwc_ep.active && ++ pcd->out_ep[i].dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) { ++ deptsiz.d32 = ++ DWC_READ_REG32(&dev_if->out_ep_regs[i]->doeptsiz); ++ depctl.d32 = ++ DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl); ++ ++ if (depctl.b.epdis && deptsiz.d32) { ++ set_current_pkt_info(GET_CORE_IF(pcd), ++ &pcd->out_ep[i].dwc_ep); ++ if (dwc_ep->cur_pkt >= dwc_ep->pkt_cnt) { ++ dwc_ep->cur_pkt = 0; ++ dwc_ep->proc_buf_num = ++ (dwc_ep->proc_buf_num ^ 1) & 0x1; ++ ++ if (dwc_ep->proc_buf_num) { ++ dwc_ep->cur_pkt_addr = ++ dwc_ep->xfer_buff1; ++ dwc_ep->cur_pkt_dma_addr = ++ dwc_ep->dma_addr1; ++ } else { ++ dwc_ep->cur_pkt_addr = ++ dwc_ep->xfer_buff0; ++ dwc_ep->cur_pkt_dma_addr = ++ dwc_ep->dma_addr0; ++ } ++ ++ } ++ ++ dsts.d32 = ++ DWC_READ_REG32(&GET_CORE_IF(pcd)->dev_if-> ++ dev_global_regs->dsts); ++ dwc_ep->next_frame = dsts.b.soffn; ++ ++ dwc_otg_iso_ep_start_frm_transfer(GET_CORE_IF ++ (pcd), ++ dwc_ep); ++ } ++ } ++ } ++#else ++ /** @todo implement ISR */ ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ dwc_otg_core_if_t *core_if; ++ deptsiz_data_t deptsiz = {.d32 = 0 }; ++ depctl_data_t depctl = {.d32 = 0 }; ++ dctl_data_t dctl = {.d32 = 0 }; ++ dwc_ep_t *dwc_ep = NULL; ++ int i; ++ core_if = GET_CORE_IF(pcd); ++ ++ for (i = 0; i < core_if->dev_if->num_out_eps; ++i) { ++ dwc_ep = &pcd->out_ep[i].dwc_ep; ++ depctl.d32 = ++ DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl); ++ if (depctl.b.epena && depctl.b.dpid == (core_if->frame_num & 0x1)) { ++ core_if->dev_if->isoc_ep = dwc_ep; ++ deptsiz.d32 = ++ DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doeptsiz); ++ break; ++ } ++ } ++ dctl.d32 = DWC_READ_REG32(&core_if->dev_if->dev_global_regs->dctl); ++ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts); ++ intr_mask.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk); ++ ++ if (!intr_mask.b.goutnakeff) { ++ /* Unmask it */ ++ intr_mask.b.goutnakeff = 1; ++ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, intr_mask.d32); ++ } ++ if (!gintsts.b.goutnakeff) { ++ dctl.b.sgoutnak = 1; ++ } ++ DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->dctl, dctl.d32); ++ ++ depctl.d32 = DWC_READ_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl); ++ if (depctl.b.epena) { ++ depctl.b.epdis = 1; ++ depctl.b.snak = 1; ++ } ++ DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[dwc_ep->num]->doepctl, depctl.d32); ++ ++ intr_mask.d32 = 0; ++ intr_mask.b.incomplisoout = 1; ++ ++#endif /* DWC_EN_ISOC */ ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.incomplisoout = 1; ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, ++ gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * This function handles the Global IN NAK Effective interrupt. ++ * ++ */ ++int32_t dwc_otg_pcd_handle_in_nak_effective(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if; ++ depctl_data_t diepctl = {.d32 = 0 }; ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ gintsts_data_t gintsts; ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++ int i; ++ ++ DWC_DEBUGPL(DBG_PCD, "Global IN NAK Effective\n"); ++ ++ /* Disable all active IN EPs */ ++ for (i = 0; i <= dev_if->num_in_eps; i++) { ++ diepctl.d32 = DWC_READ_REG32(&dev_if->in_ep_regs[i]->diepctl); ++ if (!(diepctl.b.eptype & 1) && diepctl.b.epena) { ++ if (core_if->start_predict > 0) ++ core_if->start_predict++; ++ diepctl.b.epdis = 1; ++ diepctl.b.snak = 1; ++ DWC_WRITE_REG32(&dev_if->in_ep_regs[i]->diepctl, diepctl.d32); ++ } ++ } ++ ++ ++ /* Disable the Global IN NAK Effective Interrupt */ ++ intr_mask.b.ginnakeff = 1; ++ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, ++ intr_mask.d32, 0); ++ ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.ginnakeff = 1; ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, ++ gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * OUT NAK Effective. ++ * ++ */ ++int32_t dwc_otg_pcd_handle_out_nak_effective(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_dev_if_t *dev_if = GET_CORE_IF(pcd)->dev_if; ++ gintmsk_data_t intr_mask = {.d32 = 0 }; ++ gintsts_data_t gintsts; ++ depctl_data_t doepctl; ++ int i; ++ ++ /* Disable the Global OUT NAK Effective Interrupt */ ++ intr_mask.b.goutnakeff = 1; ++ DWC_MODIFY_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintmsk, ++ intr_mask.d32, 0); ++ ++ /* If DEV OUT NAK enabled*/ ++ if (pcd->core_if->core_params->dev_out_nak) { ++ /* Run over all out endpoints to determine the ep number on ++ * which the timeout has happened ++ */ ++ for (i = 0; i <= dev_if->num_out_eps; i++) { ++ if ( pcd->core_if->ep_xfer_info[i].state == 2 ) ++ break; ++ } ++ if (i > dev_if->num_out_eps) { ++ dctl_data_t dctl; ++ dctl.d32 = ++ DWC_READ_REG32(&dev_if->dev_global_regs->dctl); ++ dctl.b.cgoutnak = 1; ++ DWC_WRITE_REG32(&dev_if->dev_global_regs->dctl, ++ dctl.d32); ++ goto out; ++ } ++ ++ /* Disable the endpoint */ ++ doepctl.d32 = DWC_READ_REG32(&dev_if->out_ep_regs[i]->doepctl); ++ if (doepctl.b.epena) { ++ doepctl.b.epdis = 1; ++ doepctl.b.snak = 1; ++ } ++ DWC_WRITE_REG32(&dev_if->out_ep_regs[i]->doepctl, doepctl.d32); ++ return 1; ++ } ++ /* We come here from Incomplete ISO OUT handler */ ++ if (dev_if->isoc_ep) { ++ dwc_ep_t *dwc_ep = (dwc_ep_t *)dev_if->isoc_ep; ++ uint32_t epnum = dwc_ep->num; ++ doepint_data_t doepint; ++ doepint.d32 = ++ DWC_READ_REG32(&dev_if->out_ep_regs[dwc_ep->num]->doepint); ++ dev_if->isoc_ep = NULL; ++ doepctl.d32 = ++ DWC_READ_REG32(&dev_if->out_ep_regs[epnum]->doepctl); ++ DWC_PRINTF("Before disable DOEPCTL = %08x\n", doepctl.d32); ++ if (doepctl.b.epena) { ++ doepctl.b.epdis = 1; ++ doepctl.b.snak = 1; ++ } ++ DWC_WRITE_REG32(&dev_if->out_ep_regs[epnum]->doepctl, ++ doepctl.d32); ++ return 1; ++ } else ++ DWC_PRINTF("INTERRUPT Handler not implemented for %s\n", ++ "Global OUT NAK Effective\n"); ++ ++out: ++ /* Clear interrupt */ ++ gintsts.d32 = 0; ++ gintsts.b.goutnakeff = 1; ++ DWC_WRITE_REG32(&GET_CORE_IF(pcd)->core_global_regs->gintsts, ++ gintsts.d32); ++ ++ return 1; ++} ++ ++/** ++ * PCD interrupt handler. ++ * ++ * The PCD handles the device interrupts. Many conditions can cause a ++ * device interrupt. When an interrupt occurs, the device interrupt ++ * service routine determines the cause of the interrupt and ++ * dispatches handling to the appropriate function. These interrupt ++ * handling functions are described below. ++ * ++ * All interrupt registers are processed from LSB to MSB. ++ * ++ */ ++int32_t dwc_otg_pcd_handle_intr(dwc_otg_pcd_t * pcd) ++{ ++ dwc_otg_core_if_t *core_if = GET_CORE_IF(pcd); ++#ifdef VERBOSE ++ dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs; ++#endif ++ gintsts_data_t gintr_status; ++ int32_t retval = 0; ++ ++ /* Exit from ISR if core is hibernated */ ++ if (core_if->hibernation_suspend == 1) { ++ return retval; ++ } ++#ifdef VERBOSE ++ DWC_DEBUGPL(DBG_ANY, "%s() gintsts=%08x gintmsk=%08x\n", ++ __func__, ++ DWC_READ_REG32(&global_regs->gintsts), ++ DWC_READ_REG32(&global_regs->gintmsk)); ++#endif ++ ++ if (dwc_otg_is_device_mode(core_if)) { ++ DWC_SPINLOCK(pcd->lock); ++#ifdef VERBOSE ++ DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%08x gintmsk=%08x\n", ++ __func__, ++ DWC_READ_REG32(&global_regs->gintsts), ++ DWC_READ_REG32(&global_regs->gintmsk)); ++#endif ++ ++ gintr_status.d32 = dwc_otg_read_core_intr(core_if); ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s: gintsts&gintmsk=%08x\n", ++ __func__, gintr_status.d32); ++ ++ if (gintr_status.b.sofintr) { ++ retval |= dwc_otg_pcd_handle_sof_intr(pcd); ++ } ++ if (gintr_status.b.rxstsqlvl) { ++ retval |= ++ dwc_otg_pcd_handle_rx_status_q_level_intr(pcd); ++ } ++ if (gintr_status.b.nptxfempty) { ++ retval |= dwc_otg_pcd_handle_np_tx_fifo_empty_intr(pcd); ++ } ++ if (gintr_status.b.goutnakeff) { ++ retval |= dwc_otg_pcd_handle_out_nak_effective(pcd); ++ } ++ if (gintr_status.b.i2cintr) { ++ retval |= dwc_otg_pcd_handle_i2c_intr(pcd); ++ } ++ if (gintr_status.b.erlysuspend) { ++ retval |= dwc_otg_pcd_handle_early_suspend_intr(pcd); ++ } ++ if (gintr_status.b.usbreset) { ++ retval |= dwc_otg_pcd_handle_usb_reset_intr(pcd); ++ } ++ if (gintr_status.b.enumdone) { ++ retval |= dwc_otg_pcd_handle_enum_done_intr(pcd); ++ } ++ if (gintr_status.b.isooutdrop) { ++ retval |= ++ dwc_otg_pcd_handle_isoc_out_packet_dropped_intr ++ (pcd); ++ } ++ if (gintr_status.b.eopframe) { ++ retval |= ++ dwc_otg_pcd_handle_end_periodic_frame_intr(pcd); ++ } ++ if (gintr_status.b.inepint) { ++ if (!core_if->multiproc_int_enable) { ++ retval |= dwc_otg_pcd_handle_in_ep_intr(pcd); ++ } ++ } ++ if (gintr_status.b.outepintr) { ++ if (!core_if->multiproc_int_enable) { ++ retval |= dwc_otg_pcd_handle_out_ep_intr(pcd); ++ } ++ } ++ if (gintr_status.b.epmismatch) { ++ retval |= dwc_otg_pcd_handle_ep_mismatch_intr(pcd); ++ } ++ if (gintr_status.b.fetsusp) { ++ retval |= dwc_otg_pcd_handle_ep_fetsusp_intr(pcd); ++ } ++ if (gintr_status.b.ginnakeff) { ++ retval |= dwc_otg_pcd_handle_in_nak_effective(pcd); ++ } ++ if (gintr_status.b.incomplisoin) { ++ retval |= ++ dwc_otg_pcd_handle_incomplete_isoc_in_intr(pcd); ++ } ++ if (gintr_status.b.incomplisoout) { ++ retval |= ++ dwc_otg_pcd_handle_incomplete_isoc_out_intr(pcd); ++ } ++ ++ /* In MPI mode Device Endpoints interrupts are asserted ++ * without setting outepintr and inepint bits set, so these ++ * Interrupt handlers are called without checking these bit-fields ++ */ ++ if (core_if->multiproc_int_enable) { ++ retval |= dwc_otg_pcd_handle_in_ep_intr(pcd); ++ retval |= dwc_otg_pcd_handle_out_ep_intr(pcd); ++ } ++#ifdef VERBOSE ++ DWC_DEBUGPL(DBG_PCDV, "%s() gintsts=%0x\n", __func__, ++ DWC_READ_REG32(&global_regs->gintsts)); ++#endif ++ DWC_SPINUNLOCK(pcd->lock); ++ } ++ return retval; ++} ++ ++#endif /* DWC_HOST_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c 2014-03-13 12:46:39.520097997 +0100 +@@ -0,0 +1,1358 @@ ++ /* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_pcd_linux.c $ ++ * $Revision: #21 $ ++ * $Date: 2012/08/10 $ ++ * $Change: 2047372 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++#ifndef DWC_HOST_ONLY ++ ++/** @file ++ * This file implements the Peripheral Controller Driver. ++ * ++ * The Peripheral Controller Driver (PCD) is responsible for ++ * translating requests from the Function Driver into the appropriate ++ * actions on the DWC_otg controller. It isolates the Function Driver ++ * from the specifics of the controller by providing an API to the ++ * Function Driver. ++ * ++ * The Peripheral Controller Driver for Linux will implement the ++ * Gadget API, so that the existing Gadget drivers can be used. ++ * (Gadget Driver is the Linux terminology for a Function Driver.) ++ * ++ * The Linux Gadget API is defined in the header file ++ * . The USB EP operations API is ++ * defined in the structure usb_ep_ops and the USB ++ * Controller API is defined in the structure ++ * usb_gadget_ops. ++ * ++ */ ++ ++#include "dwc_otg_os_dep.h" ++#include "dwc_otg_pcd_if.h" ++#include "dwc_otg_pcd.h" ++#include "dwc_otg_driver.h" ++#include "dwc_otg_dbg.h" ++ ++static struct gadget_wrapper { ++ dwc_otg_pcd_t *pcd; ++ ++ struct usb_gadget gadget; ++ struct usb_gadget_driver *driver; ++ ++ struct usb_ep ep0; ++ struct usb_ep in_ep[16]; ++ struct usb_ep out_ep[16]; ++ ++} *gadget_wrapper; ++ ++/* Display the contents of the buffer */ ++extern void dump_msg(const u8 * buf, unsigned int length); ++/** ++ * Get the dwc_otg_pcd_ep_t* from usb_ep* pointer - NULL in case ++ * if the endpoint is not found ++ */ ++static struct dwc_otg_pcd_ep *ep_from_handle(dwc_otg_pcd_t * pcd, void *handle) ++{ ++ int i; ++ if (pcd->ep0.priv == handle) { ++ return &pcd->ep0; ++ } ++ ++ for (i = 0; i < MAX_EPS_CHANNELS - 1; i++) { ++ if (pcd->in_ep[i].priv == handle) ++ return &pcd->in_ep[i]; ++ if (pcd->out_ep[i].priv == handle) ++ return &pcd->out_ep[i]; ++ } ++ ++ return NULL; ++} ++ ++/* USB Endpoint Operations */ ++/* ++ * The following sections briefly describe the behavior of the Gadget ++ * API endpoint operations implemented in the DWC_otg driver ++ * software. Detailed descriptions of the generic behavior of each of ++ * these functions can be found in the Linux header file ++ * include/linux/usb_gadget.h. ++ * ++ * The Gadget API provides wrapper functions for each of the function ++ * pointers defined in usb_ep_ops. The Gadget Driver calls the wrapper ++ * function, which then calls the underlying PCD function. The ++ * following sections are named according to the wrapper ++ * functions. Within each section, the corresponding DWC_otg PCD ++ * function name is specified. ++ * ++ */ ++ ++/** ++ * This function is called by the Gadget Driver for each EP to be ++ * configured for the current configuration (SET_CONFIGURATION). ++ * ++ * This function initializes the dwc_otg_ep_t data structure, and then ++ * calls dwc_otg_ep_activate. ++ */ ++static int ep_enable(struct usb_ep *usb_ep, ++ const struct usb_endpoint_descriptor *ep_desc) ++{ ++ int retval; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc); ++ ++ if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) { ++ DWC_WARN("%s, bad ep or descriptor\n", __func__); ++ return -EINVAL; ++ } ++ if (usb_ep == &gadget_wrapper->ep0) { ++ DWC_WARN("%s, bad ep(0)\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* Check FIFO size? */ ++ if (!ep_desc->wMaxPacketSize) { ++ DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name); ++ return -ERANGE; ++ } ++ ++ if (!gadget_wrapper->driver || ++ gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) { ++ DWC_WARN("%s, bogus device state\n", __func__); ++ return -ESHUTDOWN; ++ } ++ ++ /* Delete after check - MAS */ ++#if 0 ++ nat = (uint32_t) ep_desc->wMaxPacketSize; ++ printk(KERN_ALERT "%s: nat (before) =%d\n", __func__, nat); ++ nat = (nat >> 11) & 0x03; ++ printk(KERN_ALERT "%s: nat (after) =%d\n", __func__, nat); ++#endif ++ retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd, ++ (const uint8_t *)ep_desc, ++ (void *)usb_ep); ++ if (retval) { ++ DWC_WARN("dwc_otg_pcd_ep_enable failed\n"); ++ return -EINVAL; ++ } ++ ++ usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize); ++ ++ return 0; ++} ++ ++/** ++ * This function is called when an EP is disabled due to disconnect or ++ * change in configuration. Any pending requests will terminate with a ++ * status of -ESHUTDOWN. ++ * ++ * This function modifies the dwc_otg_ep_t data structure for this EP, ++ * and then calls dwc_otg_ep_deactivate. ++ */ ++static int ep_disable(struct usb_ep *usb_ep) ++{ ++ int retval; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, usb_ep); ++ if (!usb_ep) { ++ DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__, ++ usb_ep ? usb_ep->name : NULL); ++ return -EINVAL; ++ } ++ ++ retval = dwc_otg_pcd_ep_disable(gadget_wrapper->pcd, usb_ep); ++ if (retval) { ++ retval = -EINVAL; ++ } ++ ++ return retval; ++} ++ ++/** ++ * This function allocates a request object to use with the specified ++ * endpoint. ++ * ++ * @param ep The endpoint to be used with with the request ++ * @param gfp_flags the GFP_* flags to use. ++ */ ++static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep, ++ gfp_t gfp_flags) ++{ ++ struct usb_request *usb_req; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags); ++ if (0 == ep) { ++ DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n"); ++ return 0; ++ } ++ usb_req = kmalloc(sizeof(*usb_req), gfp_flags); ++ if (0 == usb_req) { ++ DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n"); ++ return 0; ++ } ++ memset(usb_req, 0, sizeof(*usb_req)); ++ usb_req->dma = DWC_DMA_ADDR_INVALID; ++ ++ return usb_req; ++} ++ ++/** ++ * This function frees a request object. ++ * ++ * @param ep The endpoint associated with the request ++ * @param req The request being freed ++ */ ++static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req) ++{ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req); ++ ++ if (0 == ep || 0 == req) { ++ DWC_WARN("%s() %s\n", __func__, ++ "Invalid ep or req argument!\n"); ++ return; ++ } ++ ++ kfree(req); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++/** ++ * This function allocates an I/O buffer to be used for a transfer ++ * to/from the specified endpoint. ++ * ++ * @param usb_ep The endpoint to be used with with the request ++ * @param bytes The desired number of bytes for the buffer ++ * @param dma Pointer to the buffer's DMA address; must be valid ++ * @param gfp_flags the GFP_* flags to use. ++ * @return address of a new buffer or null is buffer could not be allocated. ++ */ ++static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *usb_ep, unsigned bytes, ++ dma_addr_t * dma, gfp_t gfp_flags) ++{ ++ void *buf; ++ dwc_otg_pcd_t *pcd = 0; ++ ++ pcd = gadget_wrapper->pcd; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d,%p,%0x)\n", __func__, usb_ep, bytes, ++ dma, gfp_flags); ++ ++ /* Check dword alignment */ ++ if ((bytes & 0x3UL) != 0) { ++ DWC_WARN("%s() Buffer size is not a multiple of" ++ "DWORD size (%d)", __func__, bytes); ++ } ++ ++ buf = dma_alloc_coherent(NULL, bytes, dma, gfp_flags); ++ ++ /* Check dword alignment */ ++ if (((int)buf & 0x3UL) != 0) { ++ DWC_WARN("%s() Buffer is not DWORD aligned (%p)", ++ __func__, buf); ++ } ++ ++ return buf; ++} ++ ++/** ++ * This function frees an I/O buffer that was allocated by alloc_buffer. ++ * ++ * @param usb_ep the endpoint associated with the buffer ++ * @param buf address of the buffer ++ * @param dma The buffer's DMA address ++ * @param bytes The number of bytes of the buffer ++ */ ++static void dwc_otg_pcd_free_buffer(struct usb_ep *usb_ep, void *buf, ++ dma_addr_t dma, unsigned bytes) ++{ ++ dwc_otg_pcd_t *pcd = 0; ++ ++ pcd = gadget_wrapper->pcd; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%0x,%d)\n", __func__, buf, dma, bytes); ++ ++ dma_free_coherent(NULL, bytes, buf, dma); ++} ++#endif ++ ++/** ++ * This function is used to submit an I/O Request to an EP. ++ * ++ * - When the request completes the request's completion callback ++ * is called to return the request to the driver. ++ * - An EP, except control EPs, may have multiple requests ++ * pending. ++ * - Once submitted the request cannot be examined or modified. ++ * - Each request is turned into one or more packets. ++ * - A BULK EP can queue any amount of data; the transfer is ++ * packetized. ++ * - Zero length Packets are specified with the request 'zero' ++ * flag. ++ */ ++static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req, ++ gfp_t gfp_flags) ++{ ++ dwc_otg_pcd_t *pcd; ++ struct dwc_otg_pcd_ep *ep = NULL; ++ int retval = 0, is_isoc_ep = 0; ++ dma_addr_t dma_addr = DWC_DMA_ADDR_INVALID; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n", ++ __func__, usb_ep, usb_req, gfp_flags); ++ ++ if (!usb_req || !usb_req->complete || !usb_req->buf) { ++ DWC_WARN("bad params\n"); ++ return -EINVAL; ++ } ++ ++ if (!usb_ep) { ++ DWC_WARN("bad ep\n"); ++ return -EINVAL; ++ } ++ ++ pcd = gadget_wrapper->pcd; ++ if (!gadget_wrapper->driver || ++ gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) { ++ DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n", ++ gadget_wrapper->gadget.speed); ++ DWC_WARN("bogus device state\n"); ++ return -ESHUTDOWN; ++ } ++ ++ DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n", ++ usb_ep->name, usb_req, usb_req->length, usb_req->buf); ++ ++ usb_req->status = -EINPROGRESS; ++ usb_req->actual = 0; ++ ++ ep = ep_from_handle(pcd, usb_ep); ++ if (ep == NULL) ++ is_isoc_ep = 0; ++ else ++ is_isoc_ep = (ep->dwc_ep.type == DWC_OTG_EP_TYPE_ISOC) ? 1 : 0; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++ dma_addr = usb_req->dma; ++#else ++ if (GET_CORE_IF(pcd)->dma_enable) { ++ dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev; ++ struct device *dev = NULL; ++ ++ if (otg_dev != NULL) ++ dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep); ++ ++ if (usb_req->length != 0 && ++ usb_req->dma == DWC_DMA_ADDR_INVALID) { ++ dma_addr = dma_map_single(dev, usb_req->buf, ++ usb_req->length, ++ ep->dwc_ep.is_in ? ++ DMA_TO_DEVICE: ++ DMA_FROM_DEVICE); ++ } ++ } ++#endif ++ ++#ifdef DWC_UTE_PER_IO ++ if (is_isoc_ep == 1) { ++ retval = dwc_otg_pcd_xiso_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr, ++ usb_req->length, usb_req->zero, usb_req, ++ gfp_flags == GFP_ATOMIC ? 1 : 0, &usb_req->ext_req); ++ if (retval) ++ return -EINVAL; ++ ++ return 0; ++ } ++#endif ++ retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, dma_addr, ++ usb_req->length, usb_req->zero, usb_req, ++ gfp_flags == GFP_ATOMIC ? 1 : 0); ++ if (retval) { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/** ++ * This function cancels an I/O request from an EP. ++ */ ++static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req) ++{ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req); ++ ++ if (!usb_ep || !usb_req) { ++ DWC_WARN("bad argument\n"); ++ return -EINVAL; ++ } ++ if (!gadget_wrapper->driver || ++ gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) { ++ DWC_WARN("bogus device state\n"); ++ return -ESHUTDOWN; ++ } ++ if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/** ++ * usb_ep_set_halt stalls an endpoint. ++ * ++ * usb_ep_clear_halt clears an endpoint halt and resets its data ++ * toggle. ++ * ++ * Both of these functions are implemented with the same underlying ++ * function. The behavior depends on the value argument. ++ * ++ * @param[in] usb_ep the Endpoint to halt or clear halt. ++ * @param[in] value ++ * - 0 means clear_halt. ++ * - 1 means set_halt, ++ * - 2 means clear stall lock flag. ++ * - 3 means set stall lock flag. ++ */ ++static int ep_halt(struct usb_ep *usb_ep, int value) ++{ ++ int retval = 0; ++ ++ DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value); ++ ++ if (!usb_ep) { ++ DWC_WARN("bad ep\n"); ++ return -EINVAL; ++ } ++ ++ retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value); ++ if (retval == -DWC_E_AGAIN) { ++ return -EAGAIN; ++ } else if (retval) { ++ retval = -EINVAL; ++ } ++ ++ return retval; ++} ++ ++//#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) ++#if 0 ++/** ++ * ep_wedge: sets the halt feature and ignores clear requests ++ * ++ * @usb_ep: the endpoint being wedged ++ * ++ * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT) ++ * requests. If the gadget driver clears the halt status, it will ++ * automatically unwedge the endpoint. ++ * ++ * Returns zero on success, else negative errno. * ++ * Check usb_ep_set_wedge() at "usb_gadget.h" for details ++ */ ++static int ep_wedge(struct usb_ep *usb_ep) ++{ ++ int retval = 0; ++ ++ DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name); ++ ++ if (!usb_ep) { ++ DWC_WARN("bad ep\n"); ++ return -EINVAL; ++ } ++ ++ retval = dwc_otg_pcd_ep_wedge(gadget_wrapper->pcd, usb_ep); ++ if (retval == -DWC_E_AGAIN) { ++ retval = -EAGAIN; ++ } else if (retval) { ++ retval = -EINVAL; ++ } ++ ++ return retval; ++} ++#endif ++ ++#ifdef DWC_EN_ISOC ++/** ++ * This function is used to submit an ISOC Transfer Request to an EP. ++ * ++ * - Every time a sync period completes the request's completion callback ++ * is called to provide data to the gadget driver. ++ * - Once submitted the request cannot be modified. ++ * - Each request is turned into periodic data packets untill ISO ++ * Transfer is stopped.. ++ */ ++static int iso_ep_start(struct usb_ep *usb_ep, struct usb_iso_request *req, ++ gfp_t gfp_flags) ++{ ++ int retval = 0; ++ ++ if (!req || !req->process_buffer || !req->buf0 || !req->buf1) { ++ DWC_WARN("bad params\n"); ++ return -EINVAL; ++ } ++ ++ if (!usb_ep) { ++ DWC_PRINTF("bad params\n"); ++ return -EINVAL; ++ } ++ ++ req->status = -EINPROGRESS; ++ ++ retval = ++ dwc_otg_pcd_iso_ep_start(gadget_wrapper->pcd, usb_ep, req->buf0, ++ req->buf1, req->dma0, req->dma1, ++ req->sync_frame, req->data_pattern_frame, ++ req->data_per_frame, ++ req-> ++ flags & USB_REQ_ISO_ASAP ? -1 : ++ req->start_frame, req->buf_proc_intrvl, ++ req, gfp_flags == GFP_ATOMIC ? 1 : 0); ++ ++ if (retval) { ++ return -EINVAL; ++ } ++ ++ return retval; ++} ++ ++/** ++ * This function stops ISO EP Periodic Data Transfer. ++ */ ++static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req) ++{ ++ int retval = 0; ++ if (!usb_ep) { ++ DWC_WARN("bad ep\n"); ++ } ++ ++ if (!gadget_wrapper->driver || ++ gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) { ++ DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n", ++ gadget_wrapper->gadget.speed); ++ DWC_WARN("bogus device state\n"); ++ } ++ ++ dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req); ++ if (retval) { ++ retval = -EINVAL; ++ } ++ ++ return retval; ++} ++ ++static struct usb_iso_request *alloc_iso_request(struct usb_ep *ep, ++ int packets, gfp_t gfp_flags) ++{ ++ struct usb_iso_request *pReq = NULL; ++ uint32_t req_size; ++ ++ req_size = sizeof(struct usb_iso_request); ++ req_size += ++ (2 * packets * (sizeof(struct usb_gadget_iso_packet_descriptor))); ++ ++ pReq = kmalloc(req_size, gfp_flags); ++ if (!pReq) { ++ DWC_WARN("Can't allocate Iso Request\n"); ++ return 0; ++ } ++ pReq->iso_packet_desc0 = (void *)(pReq + 1); ++ ++ pReq->iso_packet_desc1 = pReq->iso_packet_desc0 + packets; ++ ++ return pReq; ++} ++ ++static void free_iso_request(struct usb_ep *ep, struct usb_iso_request *req) ++{ ++ kfree(req); ++} ++ ++static struct usb_isoc_ep_ops dwc_otg_pcd_ep_ops = { ++ .ep_ops = { ++ .enable = ep_enable, ++ .disable = ep_disable, ++ ++ .alloc_request = dwc_otg_pcd_alloc_request, ++ .free_request = dwc_otg_pcd_free_request, ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++ .alloc_buffer = dwc_otg_pcd_alloc_buffer, ++ .free_buffer = dwc_otg_pcd_free_buffer, ++#endif ++ ++ .queue = ep_queue, ++ .dequeue = ep_dequeue, ++ ++ .set_halt = ep_halt, ++ .fifo_status = 0, ++ .fifo_flush = 0, ++ }, ++ .iso_ep_start = iso_ep_start, ++ .iso_ep_stop = iso_ep_stop, ++ .alloc_iso_request = alloc_iso_request, ++ .free_iso_request = free_iso_request, ++}; ++ ++#else ++ ++ int (*enable) (struct usb_ep *ep, ++ const struct usb_endpoint_descriptor *desc); ++ int (*disable) (struct usb_ep *ep); ++ ++ struct usb_request *(*alloc_request) (struct usb_ep *ep, ++ gfp_t gfp_flags); ++ void (*free_request) (struct usb_ep *ep, struct usb_request *req); ++ ++ int (*queue) (struct usb_ep *ep, struct usb_request *req, ++ gfp_t gfp_flags); ++ int (*dequeue) (struct usb_ep *ep, struct usb_request *req); ++ ++ int (*set_halt) (struct usb_ep *ep, int value); ++ int (*set_wedge) (struct usb_ep *ep); ++ ++ int (*fifo_status) (struct usb_ep *ep); ++ void (*fifo_flush) (struct usb_ep *ep); ++static struct usb_ep_ops dwc_otg_pcd_ep_ops = { ++ .enable = ep_enable, ++ .disable = ep_disable, ++ ++ .alloc_request = dwc_otg_pcd_alloc_request, ++ .free_request = dwc_otg_pcd_free_request, ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++ .alloc_buffer = dwc_otg_pcd_alloc_buffer, ++ .free_buffer = dwc_otg_pcd_free_buffer, ++#else ++ /* .set_wedge = ep_wedge, */ ++ .set_wedge = NULL, /* uses set_halt instead */ ++#endif ++ ++ .queue = ep_queue, ++ .dequeue = ep_dequeue, ++ ++ .set_halt = ep_halt, ++ .fifo_status = 0, ++ .fifo_flush = 0, ++ ++}; ++ ++#endif /* _EN_ISOC_ */ ++/* Gadget Operations */ ++/** ++ * The following gadget operations will be implemented in the DWC_otg ++ * PCD. Functions in the API that are not described below are not ++ * implemented. ++ * ++ * The Gadget API provides wrapper functions for each of the function ++ * pointers defined in usb_gadget_ops. The Gadget Driver calls the ++ * wrapper function, which then calls the underlying PCD function. The ++ * following sections are named according to the wrapper functions ++ * (except for ioctl, which doesn't have a wrapper function). Within ++ * each section, the corresponding DWC_otg PCD function name is ++ * specified. ++ * ++ */ ++ ++/** ++ *Gets the USB Frame number of the last SOF. ++ */ ++static int get_frame_number(struct usb_gadget *gadget) ++{ ++ struct gadget_wrapper *d; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget); ++ ++ if (gadget == 0) { ++ return -ENODEV; ++ } ++ ++ d = container_of(gadget, struct gadget_wrapper, gadget); ++ return dwc_otg_pcd_get_frame_number(d->pcd); ++} ++ ++#ifdef CONFIG_USB_DWC_OTG_LPM ++static int test_lpm_enabled(struct usb_gadget *gadget) ++{ ++ struct gadget_wrapper *d; ++ ++ d = container_of(gadget, struct gadget_wrapper, gadget); ++ ++ return dwc_otg_pcd_is_lpm_enabled(d->pcd); ++} ++#endif ++ ++/** ++ * Initiates Session Request Protocol (SRP) to wakeup the host if no ++ * session is in progress. If a session is already in progress, but ++ * the device is suspended, remote wakeup signaling is started. ++ * ++ */ ++static int wakeup(struct usb_gadget *gadget) ++{ ++ struct gadget_wrapper *d; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget); ++ ++ if (gadget == 0) { ++ return -ENODEV; ++ } else { ++ d = container_of(gadget, struct gadget_wrapper, gadget); ++ } ++ dwc_otg_pcd_wakeup(d->pcd); ++ return 0; ++} ++ ++static const struct usb_gadget_ops dwc_otg_pcd_ops = { ++ .get_frame = get_frame_number, ++ .wakeup = wakeup, ++#ifdef CONFIG_USB_DWC_OTG_LPM ++ .lpm_support = test_lpm_enabled, ++#endif ++ // current versions must always be self-powered ++}; ++ ++static int _setup(dwc_otg_pcd_t * pcd, uint8_t * bytes) ++{ ++ int retval = -DWC_E_NOT_SUPPORTED; ++ if (gadget_wrapper->driver && gadget_wrapper->driver->setup) { ++ retval = gadget_wrapper->driver->setup(&gadget_wrapper->gadget, ++ (struct usb_ctrlrequest ++ *)bytes); ++ } ++ ++ if (retval == -ENOTSUPP) { ++ retval = -DWC_E_NOT_SUPPORTED; ++ } else if (retval < 0) { ++ retval = -DWC_E_INVALID; ++ } ++ ++ return retval; ++} ++ ++#ifdef DWC_EN_ISOC ++static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *req_handle, int proc_buf_num) ++{ ++ int i, packet_count; ++ struct usb_gadget_iso_packet_descriptor *iso_packet = 0; ++ struct usb_iso_request *iso_req = req_handle; ++ ++ if (proc_buf_num) { ++ iso_packet = iso_req->iso_packet_desc1; ++ } else { ++ iso_packet = iso_req->iso_packet_desc0; ++ } ++ packet_count = ++ dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle); ++ for (i = 0; i < packet_count; ++i) { ++ int status; ++ int actual; ++ int offset; ++ dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle, ++ i, &status, &actual, &offset); ++ switch (status) { ++ case -DWC_E_NO_DATA: ++ status = -ENODATA; ++ break; ++ default: ++ if (status) { ++ DWC_PRINTF("unknown status in isoc packet\n"); ++ } ++ ++ } ++ iso_packet[i].status = status; ++ iso_packet[i].offset = offset; ++ iso_packet[i].actual_length = actual; ++ } ++ ++ iso_req->status = 0; ++ iso_req->process_buffer(ep_handle, iso_req); ++ ++ return 0; ++} ++#endif /* DWC_EN_ISOC */ ++ ++#ifdef DWC_UTE_PER_IO ++/** ++ * Copy the contents of the extended request to the Linux usb_request's ++ * extended part and call the gadget's completion. ++ * ++ * @param pcd Pointer to the pcd structure ++ * @param ep_handle Void pointer to the usb_ep structure ++ * @param req_handle Void pointer to the usb_request structure ++ * @param status Request status returned from the portable logic ++ * @param ereq_port Void pointer to the extended request structure ++ * created in the the portable part that contains the ++ * results of the processed iso packets. ++ */ ++static int _xisoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *req_handle, int32_t status, void *ereq_port) ++{ ++ struct dwc_ute_iso_req_ext *ereqorg = NULL; ++ struct dwc_iso_xreq_port *ereqport = NULL; ++ struct dwc_ute_iso_packet_descriptor *desc_org = NULL; ++ int i; ++ struct usb_request *req; ++ //struct dwc_ute_iso_packet_descriptor * ++ //int status = 0; ++ ++ req = (struct usb_request *)req_handle; ++ ereqorg = &req->ext_req; ++ ereqport = (struct dwc_iso_xreq_port *)ereq_port; ++ desc_org = ereqorg->per_io_frame_descs; ++ ++ if (req && req->complete) { ++ /* Copy the request data from the portable logic to our request */ ++ for (i = 0; i < ereqport->pio_pkt_count; i++) { ++ desc_org[i].actual_length = ++ ereqport->per_io_frame_descs[i].actual_length; ++ desc_org[i].status = ++ ereqport->per_io_frame_descs[i].status; ++ } ++ ++ switch (status) { ++ case -DWC_E_SHUTDOWN: ++ req->status = -ESHUTDOWN; ++ break; ++ case -DWC_E_RESTART: ++ req->status = -ECONNRESET; ++ break; ++ case -DWC_E_INVALID: ++ req->status = -EINVAL; ++ break; ++ case -DWC_E_TIMEOUT: ++ req->status = -ETIMEDOUT; ++ break; ++ default: ++ req->status = status; ++ } ++ ++ /* And call the gadget's completion */ ++ req->complete(ep_handle, req); ++ } ++ ++ return 0; ++} ++#endif /* DWC_UTE_PER_IO */ ++ ++static int _complete(dwc_otg_pcd_t * pcd, void *ep_handle, ++ void *req_handle, int32_t status, uint32_t actual) ++{ ++ struct usb_request *req = (struct usb_request *)req_handle; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27) ++ struct dwc_otg_pcd_ep *ep = NULL; ++#endif ++ ++ if (req && req->complete) { ++ switch (status) { ++ case -DWC_E_SHUTDOWN: ++ req->status = -ESHUTDOWN; ++ break; ++ case -DWC_E_RESTART: ++ req->status = -ECONNRESET; ++ break; ++ case -DWC_E_INVALID: ++ req->status = -EINVAL; ++ break; ++ case -DWC_E_TIMEOUT: ++ req->status = -ETIMEDOUT; ++ break; ++ default: ++ req->status = status; ++ ++ } ++ ++ req->actual = actual; ++ DWC_SPINUNLOCK(pcd->lock); ++ req->complete(ep_handle, req); ++ DWC_SPINLOCK(pcd->lock); ++ } ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,27) ++ ep = ep_from_handle(pcd, ep_handle); ++ if (GET_CORE_IF(pcd)->dma_enable) { ++ if (req->length != 0) { ++ dwc_otg_device_t *otg_dev = gadget_wrapper->pcd->otg_dev; ++ struct device *dev = NULL; ++ ++ if (otg_dev != NULL) ++ dev = DWC_OTG_OS_GETDEV(otg_dev->os_dep); ++ ++ dma_unmap_single(dev, req->dma, req->length, ++ ep->dwc_ep.is_in ? ++ DMA_TO_DEVICE: DMA_FROM_DEVICE); ++ } ++ } ++#endif ++ ++ return 0; ++} ++ ++static int _connect(dwc_otg_pcd_t * pcd, int speed) ++{ ++ gadget_wrapper->gadget.speed = speed; ++ return 0; ++} ++ ++static int _disconnect(dwc_otg_pcd_t * pcd) ++{ ++ if (gadget_wrapper->driver && gadget_wrapper->driver->disconnect) { ++ gadget_wrapper->driver->disconnect(&gadget_wrapper->gadget); ++ } ++ return 0; ++} ++ ++static int _resume(dwc_otg_pcd_t * pcd) ++{ ++ if (gadget_wrapper->driver && gadget_wrapper->driver->resume) { ++ gadget_wrapper->driver->resume(&gadget_wrapper->gadget); ++ } ++ ++ return 0; ++} ++ ++static int _suspend(dwc_otg_pcd_t * pcd) ++{ ++ if (gadget_wrapper->driver && gadget_wrapper->driver->suspend) { ++ gadget_wrapper->driver->suspend(&gadget_wrapper->gadget); ++ } ++ return 0; ++} ++ ++/** ++ * This function updates the otg values in the gadget structure. ++ */ ++static int _hnp_changed(dwc_otg_pcd_t * pcd) ++{ ++ ++ if (!gadget_wrapper->gadget.is_otg) ++ return 0; ++ ++ gadget_wrapper->gadget.b_hnp_enable = get_b_hnp_enable(pcd); ++ gadget_wrapper->gadget.a_hnp_support = get_a_hnp_support(pcd); ++ gadget_wrapper->gadget.a_alt_hnp_support = get_a_alt_hnp_support(pcd); ++ return 0; ++} ++ ++static int _reset(dwc_otg_pcd_t * pcd) ++{ ++ return 0; ++} ++ ++#ifdef DWC_UTE_CFI ++static int _cfi_setup(dwc_otg_pcd_t * pcd, void *cfi_req) ++{ ++ int retval = -DWC_E_INVALID; ++ if (gadget_wrapper->driver->cfi_feature_setup) { ++ retval = ++ gadget_wrapper->driver-> ++ cfi_feature_setup(&gadget_wrapper->gadget, ++ (struct cfi_usb_ctrlrequest *)cfi_req); ++ } ++ ++ return retval; ++} ++#endif ++ ++static const struct dwc_otg_pcd_function_ops fops = { ++ .complete = _complete, ++#ifdef DWC_EN_ISOC ++ .isoc_complete = _isoc_complete, ++#endif ++ .setup = _setup, ++ .disconnect = _disconnect, ++ .connect = _connect, ++ .resume = _resume, ++ .suspend = _suspend, ++ .hnp_changed = _hnp_changed, ++ .reset = _reset, ++#ifdef DWC_UTE_CFI ++ .cfi_setup = _cfi_setup, ++#endif ++#ifdef DWC_UTE_PER_IO ++ .xisoc_complete = _xisoc_complete, ++#endif ++}; ++ ++/** ++ * This function is the top level PCD interrupt handler. ++ */ ++static irqreturn_t dwc_otg_pcd_irq(int irq, void *dev) ++{ ++ dwc_otg_pcd_t *pcd = dev; ++ int32_t retval = IRQ_NONE; ++ ++ retval = dwc_otg_pcd_handle_intr(pcd); ++ if (retval != 0) { ++ S3C2410X_CLEAR_EINTPEND(); ++ } ++ return IRQ_RETVAL(retval); ++} ++ ++/** ++ * This function initialized the usb_ep structures to there default ++ * state. ++ * ++ * @param d Pointer on gadget_wrapper. ++ */ ++void gadget_add_eps(struct gadget_wrapper *d) ++{ ++ static const char *names[] = { ++ ++ "ep0", ++ "ep1in", ++ "ep2in", ++ "ep3in", ++ "ep4in", ++ "ep5in", ++ "ep6in", ++ "ep7in", ++ "ep8in", ++ "ep9in", ++ "ep10in", ++ "ep11in", ++ "ep12in", ++ "ep13in", ++ "ep14in", ++ "ep15in", ++ "ep1out", ++ "ep2out", ++ "ep3out", ++ "ep4out", ++ "ep5out", ++ "ep6out", ++ "ep7out", ++ "ep8out", ++ "ep9out", ++ "ep10out", ++ "ep11out", ++ "ep12out", ++ "ep13out", ++ "ep14out", ++ "ep15out" ++ }; ++ ++ int i; ++ struct usb_ep *ep; ++ int8_t dev_endpoints; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__); ++ ++ INIT_LIST_HEAD(&d->gadget.ep_list); ++ d->gadget.ep0 = &d->ep0; ++ d->gadget.speed = USB_SPEED_UNKNOWN; ++ ++ INIT_LIST_HEAD(&d->gadget.ep0->ep_list); ++ ++ /** ++ * Initialize the EP0 structure. ++ */ ++ ep = &d->ep0; ++ ++ /* Init the usb_ep structure. */ ++ ep->name = names[0]; ++ ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops; ++ ++ /** ++ * @todo NGS: What should the max packet size be set to ++ * here? Before EP type is set? ++ */ ++ ep->maxpacket = MAX_PACKET_SIZE; ++ dwc_otg_pcd_ep_enable(d->pcd, NULL, ep); ++ ++ list_add_tail(&ep->ep_list, &d->gadget.ep_list); ++ ++ /** ++ * Initialize the EP structures. ++ */ ++ dev_endpoints = d->pcd->core_if->dev_if->num_in_eps; ++ ++ for (i = 0; i < dev_endpoints; i++) { ++ ep = &d->in_ep[i]; ++ ++ /* Init the usb_ep structure. */ ++ ep->name = names[d->pcd->in_ep[i].dwc_ep.num]; ++ ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops; ++ ++ /** ++ * @todo NGS: What should the max packet size be set to ++ * here? Before EP type is set? ++ */ ++ ep->maxpacket = MAX_PACKET_SIZE; ++ list_add_tail(&ep->ep_list, &d->gadget.ep_list); ++ } ++ ++ dev_endpoints = d->pcd->core_if->dev_if->num_out_eps; ++ ++ for (i = 0; i < dev_endpoints; i++) { ++ ep = &d->out_ep[i]; ++ ++ /* Init the usb_ep structure. */ ++ ep->name = names[15 + d->pcd->out_ep[i].dwc_ep.num]; ++ ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops; ++ ++ /** ++ * @todo NGS: What should the max packet size be set to ++ * here? Before EP type is set? ++ */ ++ ep->maxpacket = MAX_PACKET_SIZE; ++ ++ list_add_tail(&ep->ep_list, &d->gadget.ep_list); ++ } ++ ++ /* remove ep0 from the list. There is a ep0 pointer. */ ++ list_del_init(&d->ep0.ep_list); ++ ++ d->ep0.maxpacket = MAX_EP0_SIZE; ++} ++ ++/** ++ * This function releases the Gadget device. ++ * required by device_unregister(). ++ * ++ * @todo Should this do something? Should it free the PCD? ++ */ ++static void dwc_otg_pcd_gadget_release(struct device *dev) ++{ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev); ++} ++ ++static struct gadget_wrapper *alloc_wrapper(dwc_bus_dev_t *_dev) ++{ ++ static char pcd_name[] = "dwc_otg_pcd"; ++ dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev); ++ struct gadget_wrapper *d; ++ int retval; ++ ++ d = DWC_ALLOC(sizeof(*d)); ++ if (d == NULL) { ++ return NULL; ++ } ++ ++ memset(d, 0, sizeof(*d)); ++ ++ d->gadget.name = pcd_name; ++ d->pcd = otg_dev->pcd; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) ++ strcpy(d->gadget.dev.bus_id, "gadget"); ++#else ++ dev_set_name(&d->gadget.dev, "%s", "gadget"); ++#endif ++ ++ d->gadget.dev.parent = &_dev->dev; ++ d->gadget.dev.release = dwc_otg_pcd_gadget_release; ++ d->gadget.ops = &dwc_otg_pcd_ops; ++ d->gadget.max_speed = dwc_otg_pcd_is_dualspeed(otg_dev->pcd) ? USB_SPEED_HIGH:USB_SPEED_FULL; ++ d->gadget.is_otg = dwc_otg_pcd_is_otg(otg_dev->pcd); ++ ++ d->driver = 0; ++ /* Register the gadget device */ ++ retval = device_register(&d->gadget.dev); ++ if (retval != 0) { ++ DWC_ERROR("device_register failed\n"); ++ DWC_FREE(d); ++ return NULL; ++ } ++ ++ return d; ++} ++ ++static void free_wrapper(struct gadget_wrapper *d) ++{ ++ if (d->driver) { ++ /* should have been done already by driver model core */ ++ DWC_WARN("driver '%s' is still registered\n", ++ d->driver->driver.name); ++ usb_gadget_unregister_driver(d->driver); ++ } ++ ++ device_unregister(&d->gadget.dev); ++ DWC_FREE(d); ++} ++ ++/** ++ * This function initialized the PCD portion of the driver. ++ * ++ */ ++int pcd_init(dwc_bus_dev_t *_dev) ++{ ++ dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev); ++ int retval = 0; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev=%p\n", __func__, _dev, otg_dev); ++ ++ otg_dev->pcd = dwc_otg_pcd_init(otg_dev->core_if); ++ ++ if (!otg_dev->pcd) { ++ DWC_ERROR("dwc_otg_pcd_init failed\n"); ++ return -ENOMEM; ++ } ++ ++ otg_dev->pcd->otg_dev = otg_dev; ++ gadget_wrapper = alloc_wrapper(_dev); ++ ++ /* ++ * Initialize EP structures ++ */ ++ gadget_add_eps(gadget_wrapper); ++ /* ++ * Setup interupt handler ++ */ ++#ifdef PLATFORM_INTERFACE ++ DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", ++ platform_get_irq(_dev, 0)); ++ retval = request_irq(platform_get_irq(_dev, 0), dwc_otg_pcd_irq, ++ IRQF_SHARED, gadget_wrapper->gadget.name, ++ otg_dev->pcd); ++ if (retval != 0) { ++ DWC_ERROR("request of irq%d failed\n", ++ platform_get_irq(_dev, 0)); ++ free_wrapper(gadget_wrapper); ++ return -EBUSY; ++ } ++#else ++ DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", ++ _dev->irq); ++ retval = request_irq(_dev->irq, dwc_otg_pcd_irq, ++ IRQF_SHARED | IRQF_DISABLED, ++ gadget_wrapper->gadget.name, otg_dev->pcd); ++ if (retval != 0) { ++ DWC_ERROR("request of irq%d failed\n", _dev->irq); ++ free_wrapper(gadget_wrapper); ++ return -EBUSY; ++ } ++#endif ++ ++ dwc_otg_pcd_start(gadget_wrapper->pcd, &fops); ++ ++ return retval; ++} ++ ++/** ++ * Cleanup the PCD. ++ */ ++void pcd_remove(dwc_bus_dev_t *_dev) ++{ ++ dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev); ++ dwc_otg_pcd_t *pcd = otg_dev->pcd; ++ ++ DWC_DEBUGPL(DBG_PCDV, "%s(%p) otg_dev %p\n", __func__, _dev, otg_dev); ++ ++ /* ++ * Free the IRQ ++ */ ++#ifdef PLATFORM_INTERFACE ++ free_irq(platform_get_irq(_dev, 0), pcd); ++#else ++ free_irq(_dev->irq, pcd); ++#endif ++ dwc_otg_pcd_remove(otg_dev->pcd); ++ free_wrapper(gadget_wrapper); ++ otg_dev->pcd = 0; ++} ++ ++/** ++ * This function registers a gadget driver with the PCD. ++ * ++ * When a driver is successfully registered, it will receive control ++ * requests including set_configuration(), which enables non-control ++ * requests. then usb traffic follows until a disconnect is reported. ++ * then a host may connect again, or the driver might get unbound. ++ * ++ * @param driver The driver being registered ++ * @param bind The bind function of gadget driver ++ */ ++ ++int usb_gadget_probe_driver(struct usb_gadget_driver *driver) ++{ ++ int retval; ++ ++ DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n", ++ driver->driver.name); ++ ++ if (!driver || driver->max_speed == USB_SPEED_UNKNOWN || ++ !driver->bind || ++ !driver->unbind || !driver->disconnect || !driver->setup) { ++ DWC_DEBUGPL(DBG_PCDV, "EINVAL\n"); ++ return -EINVAL; ++ } ++ if (gadget_wrapper == 0) { ++ DWC_DEBUGPL(DBG_PCDV, "ENODEV\n"); ++ return -ENODEV; ++ } ++ if (gadget_wrapper->driver != 0) { ++ DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver); ++ return -EBUSY; ++ } ++ ++ /* hook up the driver */ ++ gadget_wrapper->driver = driver; ++ gadget_wrapper->gadget.dev.driver = &driver->driver; ++ ++ DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name); ++ retval = driver->bind(&gadget_wrapper->gadget, gadget_wrapper->driver); ++ if (retval) { ++ DWC_ERROR("bind to driver %s --> error %d\n", ++ driver->driver.name, retval); ++ gadget_wrapper->driver = 0; ++ gadget_wrapper->gadget.dev.driver = 0; ++ return retval; ++ } ++ DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n", ++ driver->driver.name); ++ return 0; ++} ++EXPORT_SYMBOL(usb_gadget_probe_driver); ++ ++/** ++ * This function unregisters a gadget driver ++ * ++ * @param driver The driver being unregistered ++ */ ++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ++{ ++ //DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver); ++ ++ if (gadget_wrapper == 0) { ++ DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__, ++ -ENODEV); ++ return -ENODEV; ++ } ++ if (driver == 0 || driver != gadget_wrapper->driver) { ++ DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__, ++ -EINVAL); ++ return -EINVAL; ++ } ++ ++ driver->unbind(&gadget_wrapper->gadget); ++ gadget_wrapper->driver = 0; ++ ++ DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name); ++ return 0; ++} ++ ++EXPORT_SYMBOL(usb_gadget_unregister_driver); ++ ++#endif /* DWC_HOST_ONLY */ +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_regs.h linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_regs.h +--- linux-3.10.33/drivers/usb/host/dwc_otg/dwc_otg_regs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/dwc_otg_regs.h 2014-03-13 12:46:39.524098005 +0100 +@@ -0,0 +1,2550 @@ ++/* ========================================================================== ++ * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_regs.h $ ++ * $Revision: #98 $ ++ * $Date: 2012/08/10 $ ++ * $Change: 2047372 $ ++ * ++ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, ++ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless ++ * otherwise expressly agreed to in writing between Synopsys and you. ++ * ++ * The Software IS NOT an item of Licensed Software or Licensed Product under ++ * any End User Software License Agreement or Agreement for Licensed Product ++ * with Synopsys or any supplement thereto. You are permitted to use and ++ * redistribute this Software in source and binary forms, with or without ++ * modification, provided that redistributions of source code must retain this ++ * notice. You may not view, use, disclose, copy or distribute this file or ++ * any information contained herein except pursuant to this license grant from ++ * Synopsys. If you do not agree with this notice, including the disclaimer ++ * below, then you are not authorized to use the Software. ++ * ++ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, ++ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ++ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER ++ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ========================================================================== */ ++ ++#ifndef __DWC_OTG_REGS_H__ ++#define __DWC_OTG_REGS_H__ ++ ++#include "dwc_otg_core_if.h" ++ ++/** ++ * @file ++ * ++ * This file contains the data structures for accessing the DWC_otg core registers. ++ * ++ * The application interfaces with the HS OTG core by reading from and ++ * writing to the Control and Status Register (CSR) space through the ++ * AHB Slave interface. These registers are 32 bits wide, and the ++ * addresses are 32-bit-block aligned. ++ * CSRs are classified as follows: ++ * - Core Global Registers ++ * - Device Mode Registers ++ * - Device Global Registers ++ * - Device Endpoint Specific Registers ++ * - Host Mode Registers ++ * - Host Global Registers ++ * - Host Port CSRs ++ * - Host Channel Specific Registers ++ * ++ * Only the Core Global registers can be accessed in both Device and ++ * Host modes. When the HS OTG core is operating in one mode, either ++ * Device or Host, the application must not access registers from the ++ * other mode. When the core switches from one mode to another, the ++ * registers in the new mode of operation must be reprogrammed as they ++ * would be after a power-on reset. ++ */ ++ ++/****************************************************************************/ ++/** DWC_otg Core registers . ++ * The dwc_otg_core_global_regs structure defines the size ++ * and relative field offsets for the Core Global registers. ++ */ ++typedef struct dwc_otg_core_global_regs { ++ /** OTG Control and Status Register. Offset: 000h */ ++ volatile uint32_t gotgctl; ++ /** OTG Interrupt Register. Offset: 004h */ ++ volatile uint32_t gotgint; ++ /**Core AHB Configuration Register. Offset: 008h */ ++ volatile uint32_t gahbcfg; ++ ++#define DWC_GLBINTRMASK 0x0001 ++#define DWC_DMAENABLE 0x0020 ++#define DWC_NPTXEMPTYLVL_EMPTY 0x0080 ++#define DWC_NPTXEMPTYLVL_HALFEMPTY 0x0000 ++#define DWC_PTXEMPTYLVL_EMPTY 0x0100 ++#define DWC_PTXEMPTYLVL_HALFEMPTY 0x0000 ++ ++ /**Core USB Configuration Register. Offset: 00Ch */ ++ volatile uint32_t gusbcfg; ++ /**Core Reset Register. Offset: 010h */ ++ volatile uint32_t grstctl; ++ /**Core Interrupt Register. Offset: 014h */ ++ volatile uint32_t gintsts; ++ /**Core Interrupt Mask Register. Offset: 018h */ ++ volatile uint32_t gintmsk; ++ /**Receive Status Queue Read Register (Read Only). Offset: 01Ch */ ++ volatile uint32_t grxstsr; ++ /**Receive Status Queue Read & POP Register (Read Only). Offset: 020h*/ ++ volatile uint32_t grxstsp; ++ /**Receive FIFO Size Register. Offset: 024h */ ++ volatile uint32_t grxfsiz; ++ /**Non Periodic Transmit FIFO Size Register. Offset: 028h */ ++ volatile uint32_t gnptxfsiz; ++ /**Non Periodic Transmit FIFO/Queue Status Register (Read ++ * Only). Offset: 02Ch */ ++ volatile uint32_t gnptxsts; ++ /**I2C Access Register. Offset: 030h */ ++ volatile uint32_t gi2cctl; ++ /**PHY Vendor Control Register. Offset: 034h */ ++ volatile uint32_t gpvndctl; ++ /**General Purpose Input/Output Register. Offset: 038h */ ++ volatile uint32_t ggpio; ++ /**User ID Register. Offset: 03Ch */ ++ volatile uint32_t guid; ++ /**Synopsys ID Register (Read Only). Offset: 040h */ ++ volatile uint32_t gsnpsid; ++ /**User HW Config1 Register (Read Only). Offset: 044h */ ++ volatile uint32_t ghwcfg1; ++ /**User HW Config2 Register (Read Only). Offset: 048h */ ++ volatile uint32_t ghwcfg2; ++#define DWC_SLAVE_ONLY_ARCH 0 ++#define DWC_EXT_DMA_ARCH 1 ++#define DWC_INT_DMA_ARCH 2 ++ ++#define DWC_MODE_HNP_SRP_CAPABLE 0 ++#define DWC_MODE_SRP_ONLY_CAPABLE 1 ++#define DWC_MODE_NO_HNP_SRP_CAPABLE 2 ++#define DWC_MODE_SRP_CAPABLE_DEVICE 3 ++#define DWC_MODE_NO_SRP_CAPABLE_DEVICE 4 ++#define DWC_MODE_SRP_CAPABLE_HOST 5 ++#define DWC_MODE_NO_SRP_CAPABLE_HOST 6 ++ ++ /**User HW Config3 Register (Read Only). Offset: 04Ch */ ++ volatile uint32_t ghwcfg3; ++ /**User HW Config4 Register (Read Only). Offset: 050h*/ ++ volatile uint32_t ghwcfg4; ++ /** Core LPM Configuration register Offset: 054h*/ ++ volatile uint32_t glpmcfg; ++ /** Global PowerDn Register Offset: 058h */ ++ volatile uint32_t gpwrdn; ++ /** Global DFIFO SW Config Register Offset: 05Ch */ ++ volatile uint32_t gdfifocfg; ++ /** ADP Control Register Offset: 060h */ ++ volatile uint32_t adpctl; ++ /** Reserved Offset: 064h-0FFh */ ++ volatile uint32_t reserved39[39]; ++ /** Host Periodic Transmit FIFO Size Register. Offset: 100h */ ++ volatile uint32_t hptxfsiz; ++ /** Device Periodic Transmit FIFO#n Register if dedicated fifos are disabled, ++ otherwise Device Transmit FIFO#n Register. ++ * Offset: 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15 (1<=n<=15). */ ++ volatile uint32_t dtxfsiz[15]; ++} dwc_otg_core_global_regs_t; ++ ++/** ++ * This union represents the bit fields of the Core OTG Control ++ * and Status Register (GOTGCTL). Set the bits using the bit ++ * fields then write the d32 value to the register. ++ */ ++typedef union gotgctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned sesreqscs:1; ++ unsigned sesreq:1; ++ unsigned vbvalidoven:1; ++ unsigned vbvalidovval:1; ++ unsigned avalidoven:1; ++ unsigned avalidovval:1; ++ unsigned bvalidoven:1; ++ unsigned bvalidovval:1; ++ unsigned hstnegscs:1; ++ unsigned hnpreq:1; ++ unsigned hstsethnpen:1; ++ unsigned devhnpen:1; ++ unsigned reserved12_15:4; ++ unsigned conidsts:1; ++ unsigned dbnctime:1; ++ unsigned asesvld:1; ++ unsigned bsesvld:1; ++ unsigned otgver:1; ++ unsigned reserved1:1; ++ unsigned multvalidbc:5; ++ unsigned chirpen:1; ++ unsigned reserved28_31:4; ++ } b; ++} gotgctl_data_t; ++ ++/** ++ * This union represents the bit fields of the Core OTG Interrupt Register ++ * (GOTGINT). Set/clear the bits using the bit fields then write the d32 ++ * value to the register. ++ */ ++typedef union gotgint_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Current Mode */ ++ unsigned reserved0_1:2; ++ ++ /** Session End Detected */ ++ unsigned sesenddet:1; ++ ++ unsigned reserved3_7:5; ++ ++ /** Session Request Success Status Change */ ++ unsigned sesreqsucstschng:1; ++ /** Host Negotiation Success Status Change */ ++ unsigned hstnegsucstschng:1; ++ ++ unsigned reserved10_16:7; ++ ++ /** Host Negotiation Detected */ ++ unsigned hstnegdet:1; ++ /** A-Device Timeout Change */ ++ unsigned adevtoutchng:1; ++ /** Debounce Done */ ++ unsigned debdone:1; ++ /** Multi-Valued input changed */ ++ unsigned mvic:1; ++ ++ unsigned reserved31_21:11; ++ ++ } b; ++} gotgint_data_t; ++ ++/** ++ * This union represents the bit fields of the Core AHB Configuration ++ * Register (GAHBCFG). Set/clear the bits using the bit fields then ++ * write the d32 value to the register. ++ */ ++typedef union gahbcfg_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned glblintrmsk:1; ++#define DWC_GAHBCFG_GLBINT_ENABLE 1 ++ ++ unsigned hburstlen:4; ++#define DWC_GAHBCFG_INT_DMA_BURST_SINGLE 0 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR 1 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR4 3 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR8 5 ++#define DWC_GAHBCFG_INT_DMA_BURST_INCR16 7 ++ ++ unsigned dmaenable:1; ++#define DWC_GAHBCFG_DMAENABLE 1 ++ unsigned reserved:1; ++ unsigned nptxfemplvl_txfemplvl:1; ++ unsigned ptxfemplvl:1; ++#define DWC_GAHBCFG_TXFEMPTYLVL_EMPTY 1 ++#define DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 ++ unsigned reserved9_20:12; ++ unsigned remmemsupp:1; ++ unsigned notialldmawrit:1; ++ unsigned ahbsingle:1; ++ unsigned reserved24_31:8; ++ } b; ++} gahbcfg_data_t; ++ ++/** ++ * This union represents the bit fields of the Core USB Configuration ++ * Register (GUSBCFG). Set the bits using the bit fields then write ++ * the d32 value to the register. ++ */ ++typedef union gusbcfg_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned toutcal:3; ++ unsigned phyif:1; ++ unsigned ulpi_utmi_sel:1; ++ unsigned fsintf:1; ++ unsigned physel:1; ++ unsigned ddrsel:1; ++ unsigned srpcap:1; ++ unsigned hnpcap:1; ++ unsigned usbtrdtim:4; ++ unsigned reserved1:1; ++ unsigned phylpwrclksel:1; ++ unsigned otgutmifssel:1; ++ unsigned ulpi_fsls:1; ++ unsigned ulpi_auto_res:1; ++ unsigned ulpi_clk_sus_m:1; ++ unsigned ulpi_ext_vbus_drv:1; ++ unsigned ulpi_int_vbus_indicator:1; ++ unsigned term_sel_dl_pulse:1; ++ unsigned indicator_complement:1; ++ unsigned indicator_pass_through:1; ++ unsigned ulpi_int_prot_dis:1; ++ unsigned ic_usb_cap:1; ++ unsigned ic_traffic_pull_remove:1; ++ unsigned tx_end_delay:1; ++ unsigned force_host_mode:1; ++ unsigned force_dev_mode:1; ++ unsigned reserved31:1; ++ } b; ++} gusbcfg_data_t; ++ ++/** ++ * This union represents the bit fields of the Core Reset Register ++ * (GRSTCTL). Set/clear the bits using the bit fields then write the ++ * d32 value to the register. ++ */ ++typedef union grstctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Core Soft Reset (CSftRst) (Device and Host) ++ * ++ * The application can flush the control logic in the ++ * entire core using this bit. This bit resets the ++ * pipelines in the AHB Clock domain as well as the ++ * PHY Clock domain. ++ * ++ * The state machines are reset to an IDLE state, the ++ * control bits in the CSRs are cleared, all the ++ * transmit FIFOs and the receive FIFO are flushed. ++ * ++ * The status mask bits that control the generation of ++ * the interrupt, are cleared, to clear the ++ * interrupt. The interrupt status bits are not ++ * cleared, so the application can get the status of ++ * any events that occurred in the core after it has ++ * set this bit. ++ * ++ * Any transactions on the AHB are terminated as soon ++ * as possible following the protocol. Any ++ * transactions on the USB are terminated immediately. ++ * ++ * The configuration settings in the CSRs are ++ * unchanged, so the software doesn't have to ++ * reprogram these registers (Device ++ * Configuration/Host Configuration/Core System ++ * Configuration/Core PHY Configuration). ++ * ++ * The application can write to this bit, any time it ++ * wants to reset the core. This is a self clearing ++ * bit and the core clears this bit after all the ++ * necessary logic is reset in the core, which may ++ * take several clocks, depending on the current state ++ * of the core. ++ */ ++ unsigned csftrst:1; ++ /** Hclk Soft Reset ++ * ++ * The application uses this bit to reset the control logic in ++ * the AHB clock domain. Only AHB clock domain pipelines are ++ * reset. ++ */ ++ unsigned hsftrst:1; ++ /** Host Frame Counter Reset (Host Only)
++ * ++ * The application can reset the (micro)frame number ++ * counter inside the core, using this bit. When the ++ * (micro)frame counter is reset, the subsequent SOF ++ * sent out by the core, will have a (micro)frame ++ * number of 0. ++ */ ++ unsigned hstfrm:1; ++ /** In Token Sequence Learning Queue Flush ++ * (INTknQFlsh) (Device Only) ++ */ ++ unsigned intknqflsh:1; ++ /** RxFIFO Flush (RxFFlsh) (Device and Host) ++ * ++ * The application can flush the entire Receive FIFO ++ * using this bit. The application must first ++ * ensure that the core is not in the middle of a ++ * transaction. The application should write into ++ * this bit, only after making sure that neither the ++ * DMA engine is reading from the RxFIFO nor the MAC ++ * is writing the data in to the FIFO. The ++ * application should wait until the bit is cleared ++ * before performing any other operations. This bit ++ * will takes 8 clocks (slowest of PHY or AHB clock) ++ * to clear. ++ */ ++ unsigned rxfflsh:1; ++ /** TxFIFO Flush (TxFFlsh) (Device and Host). ++ * ++ * This bit is used to selectively flush a single or ++ * all transmit FIFOs. The application must first ++ * ensure that the core is not in the middle of a ++ * transaction. The application should write into ++ * this bit, only after making sure that neither the ++ * DMA engine is writing into the TxFIFO nor the MAC ++ * is reading the data out of the FIFO. The ++ * application should wait until the core clears this ++ * bit, before performing any operations. This bit ++ * will takes 8 clocks (slowest of PHY or AHB clock) ++ * to clear. ++ */ ++ unsigned txfflsh:1; ++ ++ /** TxFIFO Number (TxFNum) (Device and Host). ++ * ++ * This is the FIFO number which needs to be flushed, ++ * using the TxFIFO Flush bit. This field should not ++ * be changed until the TxFIFO Flush bit is cleared by ++ * the core. ++ * - 0x0 : Non Periodic TxFIFO Flush ++ * - 0x1 : Periodic TxFIFO #1 Flush in device mode ++ * or Periodic TxFIFO in host mode ++ * - 0x2 : Periodic TxFIFO #2 Flush in device mode. ++ * - ... ++ * - 0xF : Periodic TxFIFO #15 Flush in device mode ++ * - 0x10: Flush all the Transmit NonPeriodic and ++ * Transmit Periodic FIFOs in the core ++ */ ++ unsigned txfnum:5; ++ /** Reserved */ ++ unsigned reserved11_29:19; ++ /** DMA Request Signal. Indicated DMA request is in ++ * probress. Used for debug purpose. */ ++ unsigned dmareq:1; ++ /** AHB Master Idle. Indicates the AHB Master State ++ * Machine is in IDLE condition. */ ++ unsigned ahbidle:1; ++ } b; ++} grstctl_t; ++ ++/** ++ * This union represents the bit fields of the Core Interrupt Mask ++ * Register (GINTMSK). Set/clear the bits using the bit fields then ++ * write the d32 value to the register. ++ */ ++typedef union gintmsk_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved0:1; ++ unsigned modemismatch:1; ++ unsigned otgintr:1; ++ unsigned sofintr:1; ++ unsigned rxstsqlvl:1; ++ unsigned nptxfempty:1; ++ unsigned ginnakeff:1; ++ unsigned goutnakeff:1; ++ unsigned ulpickint:1; ++ unsigned i2cintr:1; ++ unsigned erlysuspend:1; ++ unsigned usbsuspend:1; ++ unsigned usbreset:1; ++ unsigned enumdone:1; ++ unsigned isooutdrop:1; ++ unsigned eopframe:1; ++ unsigned restoredone:1; ++ unsigned epmismatch:1; ++ unsigned inepintr:1; ++ unsigned outepintr:1; ++ unsigned incomplisoin:1; ++ unsigned incomplisoout:1; ++ unsigned fetsusp:1; ++ unsigned resetdet:1; ++ unsigned portintr:1; ++ unsigned hcintr:1; ++ unsigned ptxfempty:1; ++ unsigned lpmtranrcvd:1; ++ unsigned conidstschng:1; ++ unsigned disconnect:1; ++ unsigned sessreqintr:1; ++ unsigned wkupintr:1; ++ } b; ++} gintmsk_data_t; ++/** ++ * This union represents the bit fields of the Core Interrupt Register ++ * (GINTSTS). Set/clear the bits using the bit fields then write the ++ * d32 value to the register. ++ */ ++typedef union gintsts_data { ++ /** raw register data */ ++ uint32_t d32; ++#define DWC_SOF_INTR_MASK 0x0008 ++ /** register bits */ ++ struct { ++#define DWC_HOST_MODE 1 ++ unsigned curmode:1; ++ unsigned modemismatch:1; ++ unsigned otgintr:1; ++ unsigned sofintr:1; ++ unsigned rxstsqlvl:1; ++ unsigned nptxfempty:1; ++ unsigned ginnakeff:1; ++ unsigned goutnakeff:1; ++ unsigned ulpickint:1; ++ unsigned i2cintr:1; ++ unsigned erlysuspend:1; ++ unsigned usbsuspend:1; ++ unsigned usbreset:1; ++ unsigned enumdone:1; ++ unsigned isooutdrop:1; ++ unsigned eopframe:1; ++ unsigned restoredone:1; ++ unsigned epmismatch:1; ++ unsigned inepint:1; ++ unsigned outepintr:1; ++ unsigned incomplisoin:1; ++ unsigned incomplisoout:1; ++ unsigned fetsusp:1; ++ unsigned resetdet:1; ++ unsigned portintr:1; ++ unsigned hcintr:1; ++ unsigned ptxfempty:1; ++ unsigned lpmtranrcvd:1; ++ unsigned conidstschng:1; ++ unsigned disconnect:1; ++ unsigned sessreqintr:1; ++ unsigned wkupintr:1; ++ } b; ++} gintsts_data_t; ++ ++/** ++ * This union represents the bit fields in the Device Receive Status Read and ++ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 ++ * element then read out the bits using the bit elements. ++ */ ++typedef union device_grxsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned epnum:4; ++ unsigned bcnt:11; ++ unsigned dpid:2; ++ ++#define DWC_STS_DATA_UPDT 0x2 // OUT Data Packet ++#define DWC_STS_XFER_COMP 0x3 // OUT Data Transfer Complete ++ ++#define DWC_DSTS_GOUT_NAK 0x1 // Global OUT NAK ++#define DWC_DSTS_SETUP_COMP 0x4 // Setup Phase Complete ++#define DWC_DSTS_SETUP_UPDT 0x6 // SETUP Packet ++ unsigned pktsts:4; ++ unsigned fn:4; ++ unsigned reserved25_31:7; ++ } b; ++} device_grxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Receive Status Read and ++ * Pop Registers (GRXSTSR, GRXSTSP) Read the register into the d32 ++ * element then read out the bits using the bit elements. ++ */ ++typedef union host_grxsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned chnum:4; ++ unsigned bcnt:11; ++ unsigned dpid:2; ++ ++ unsigned pktsts:4; ++#define DWC_GRXSTS_PKTSTS_IN 0x2 ++#define DWC_GRXSTS_PKTSTS_IN_XFER_COMP 0x3 ++#define DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR 0x5 ++#define DWC_GRXSTS_PKTSTS_CH_HALTED 0x7 ++ ++ unsigned reserved21_31:11; ++ } b; ++} host_grxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the FIFO Size Registers (HPTXFSIZ, ++ * GNPTXFSIZ, DPTXFSIZn, DIEPTXFn). Read the register into the d32 element ++ * then read out the bits using the bit elements. ++ */ ++typedef union fifosize_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned startaddr:16; ++ unsigned depth:16; ++ } b; ++} fifosize_data_t; ++ ++/** ++ * This union represents the bit fields in the Non-Periodic Transmit ++ * FIFO/Queue Status Register (GNPTXSTS). Read the register into the ++ * d32 element then read out the bits using the bit ++ * elements. ++ */ ++typedef union gnptxsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned nptxfspcavail:16; ++ unsigned nptxqspcavail:8; ++ /** Top of the Non-Periodic Transmit Request Queue ++ * - bit 24 - Terminate (Last entry for the selected ++ * channel/EP) ++ * - bits 26:25 - Token Type ++ * - 2'b00 - IN/OUT ++ * - 2'b01 - Zero Length OUT ++ * - 2'b10 - PING/Complete Split ++ * - 2'b11 - Channel Halt ++ * - bits 30:27 - Channel/EP Number ++ */ ++ unsigned nptxqtop_terminate:1; ++ unsigned nptxqtop_token:2; ++ unsigned nptxqtop_chnep:4; ++ unsigned reserved:1; ++ } b; ++} gnptxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the Transmit ++ * FIFO Status Register (DTXFSTS). Read the register into the ++ * d32 element then read out the bits using the bit ++ * elements. ++ */ ++typedef union dtxfsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned txfspcavail:16; ++ unsigned reserved:16; ++ } b; ++} dtxfsts_data_t; ++ ++/** ++ * This union represents the bit fields in the I2C Control Register ++ * (I2CCTL). Read the register into the d32 element then read out the ++ * bits using the bit elements. ++ */ ++typedef union gi2cctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned rwdata:8; ++ unsigned regaddr:8; ++ unsigned addr:7; ++ unsigned i2cen:1; ++ unsigned ack:1; ++ unsigned i2csuspctl:1; ++ unsigned i2cdevaddr:2; ++ unsigned i2cdatse0:1; ++ unsigned reserved:1; ++ unsigned rw:1; ++ unsigned bsydne:1; ++ } b; ++} gi2cctl_data_t; ++ ++/** ++ * This union represents the bit fields in the PHY Vendor Control Register ++ * (GPVNDCTL). Read the register into the d32 element then read out the ++ * bits using the bit elements. ++ */ ++typedef union gpvndctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned regdata:8; ++ unsigned vctrl:8; ++ unsigned regaddr16_21:6; ++ unsigned regwr:1; ++ unsigned reserved23_24:2; ++ unsigned newregreq:1; ++ unsigned vstsbsy:1; ++ unsigned vstsdone:1; ++ unsigned reserved28_30:3; ++ unsigned disulpidrvr:1; ++ } b; ++} gpvndctl_data_t; ++ ++/** ++ * This union represents the bit fields in the General Purpose ++ * Input/Output Register (GGPIO). ++ * Read the register into the d32 element then read out the ++ * bits using the bit elements. ++ */ ++typedef union ggpio_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned gpi:16; ++ unsigned gpo:16; ++ } b; ++} ggpio_data_t; ++ ++/** ++ * This union represents the bit fields in the User ID Register ++ * (GUID). Read the register into the d32 element then read out the ++ * bits using the bit elements. ++ */ ++typedef union guid_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned rwdata:32; ++ } b; ++} guid_data_t; ++ ++/** ++ * This union represents the bit fields in the Synopsys ID Register ++ * (GSNPSID). Read the register into the d32 element then read out the ++ * bits using the bit elements. ++ */ ++typedef union gsnpsid_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned rwdata:32; ++ } b; ++} gsnpsid_data_t; ++ ++/** ++ * This union represents the bit fields in the User HW Config1 ++ * Register. Read the register into the d32 element then read ++ * out the bits using the bit elements. ++ */ ++typedef union hwcfg1_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned ep_dir0:2; ++ unsigned ep_dir1:2; ++ unsigned ep_dir2:2; ++ unsigned ep_dir3:2; ++ unsigned ep_dir4:2; ++ unsigned ep_dir5:2; ++ unsigned ep_dir6:2; ++ unsigned ep_dir7:2; ++ unsigned ep_dir8:2; ++ unsigned ep_dir9:2; ++ unsigned ep_dir10:2; ++ unsigned ep_dir11:2; ++ unsigned ep_dir12:2; ++ unsigned ep_dir13:2; ++ unsigned ep_dir14:2; ++ unsigned ep_dir15:2; ++ } b; ++} hwcfg1_data_t; ++ ++/** ++ * This union represents the bit fields in the User HW Config2 ++ * Register. Read the register into the d32 element then read ++ * out the bits using the bit elements. ++ */ ++typedef union hwcfg2_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /* GHWCFG2 */ ++ unsigned op_mode:3; ++#define DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 ++#define DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 ++#define DWC_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 ++#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 ++#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 ++#define DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 ++#define DWC_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 ++ ++ unsigned architecture:2; ++ unsigned point2point:1; ++ unsigned hs_phy_type:2; ++#define DWC_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 ++#define DWC_HWCFG2_HS_PHY_TYPE_UTMI 1 ++#define DWC_HWCFG2_HS_PHY_TYPE_ULPI 2 ++#define DWC_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 ++ ++ unsigned fs_phy_type:2; ++ unsigned num_dev_ep:4; ++ unsigned num_host_chan:4; ++ unsigned perio_ep_supported:1; ++ unsigned dynamic_fifo:1; ++ unsigned multi_proc_int:1; ++ unsigned reserved21:1; ++ unsigned nonperio_tx_q_depth:2; ++ unsigned host_perio_tx_q_depth:2; ++ unsigned dev_token_q_depth:5; ++ unsigned otg_enable_ic_usb:1; ++ } b; ++} hwcfg2_data_t; ++ ++/** ++ * This union represents the bit fields in the User HW Config3 ++ * Register. Read the register into the d32 element then read ++ * out the bits using the bit elements. ++ */ ++typedef union hwcfg3_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /* GHWCFG3 */ ++ unsigned xfer_size_cntr_width:4; ++ unsigned packet_size_cntr_width:3; ++ unsigned otg_func:1; ++ unsigned i2c:1; ++ unsigned vendor_ctrl_if:1; ++ unsigned optional_features:1; ++ unsigned synch_reset_type:1; ++ unsigned adp_supp:1; ++ unsigned otg_enable_hsic:1; ++ unsigned bc_support:1; ++ unsigned otg_lpm_en:1; ++ unsigned dfifo_depth:16; ++ } b; ++} hwcfg3_data_t; ++ ++/** ++ * This union represents the bit fields in the User HW Config4 ++ * Register. Read the register into the d32 element then read ++ * out the bits using the bit elements. ++ */ ++typedef union hwcfg4_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned num_dev_perio_in_ep:4; ++ unsigned power_optimiz:1; ++ unsigned min_ahb_freq:1; ++ unsigned hiber:1; ++ unsigned xhiber:1; ++ unsigned reserved:6; ++ unsigned utmi_phy_data_width:2; ++ unsigned num_dev_mode_ctrl_ep:4; ++ unsigned iddig_filt_en:1; ++ unsigned vbus_valid_filt_en:1; ++ unsigned a_valid_filt_en:1; ++ unsigned b_valid_filt_en:1; ++ unsigned session_end_filt_en:1; ++ unsigned ded_fifo_en:1; ++ unsigned num_in_eps:4; ++ unsigned desc_dma:1; ++ unsigned desc_dma_dyn:1; ++ } b; ++} hwcfg4_data_t; ++ ++/** ++ * This union represents the bit fields of the Core LPM Configuration ++ * Register (GLPMCFG). Set the bits using bit fields then write ++ * the d32 value to the register. ++ */ ++typedef union glpmctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** LPM-Capable (LPMCap) (Device and Host) ++ * The application uses this bit to control ++ * the DWC_otg core LPM capabilities. ++ */ ++ unsigned lpm_cap_en:1; ++ /** LPM response programmed by application (AppL1Res) (Device) ++ * Handshake response to LPM token pre-programmed ++ * by device application software. ++ */ ++ unsigned appl_resp:1; ++ /** Host Initiated Resume Duration (HIRD) (Device and Host) ++ * In Host mode this field indicates the value of HIRD ++ * to be sent in an LPM transaction. ++ * In Device mode this field is updated with the ++ * Received LPM Token HIRD bmAttribute ++ * when an ACK/NYET/STALL response is sent ++ * to an LPM transaction. ++ */ ++ unsigned hird:4; ++ /** RemoteWakeEnable (bRemoteWake) (Device and Host) ++ * In Host mode this bit indicates the value of remote ++ * wake up to be sent in wIndex field of LPM transaction. ++ * In Device mode this field is updated with the ++ * Received LPM Token bRemoteWake bmAttribute ++ * when an ACK/NYET/STALL response is sent ++ * to an LPM transaction. ++ */ ++ unsigned rem_wkup_en:1; ++ /** Enable utmi_sleep_n (EnblSlpM) (Device and Host) ++ * The application uses this bit to control ++ * the utmi_sleep_n assertion to the PHY when in L1 state. ++ */ ++ unsigned en_utmi_sleep:1; ++ /** HIRD Threshold (HIRD_Thres) (Device and Host) ++ */ ++ unsigned hird_thres:5; ++ /** LPM Response (CoreL1Res) (Device and Host) ++ * In Host mode this bit contains handsake response to ++ * LPM transaction. ++ * In Device mode the response of the core to ++ * LPM transaction received is reflected in these two bits. ++ - 0x0 : ERROR (No handshake response) ++ - 0x1 : STALL ++ - 0x2 : NYET ++ - 0x3 : ACK ++ */ ++ unsigned lpm_resp:2; ++ /** Port Sleep Status (SlpSts) (Device and Host) ++ * This bit is set as long as a Sleep condition ++ * is present on the USB bus. ++ */ ++ unsigned prt_sleep_sts:1; ++ /** Sleep State Resume OK (L1ResumeOK) (Device and Host) ++ * Indicates that the application or host ++ * can start resume from Sleep state. ++ */ ++ unsigned sleep_state_resumeok:1; ++ /** LPM channel Index (LPM_Chnl_Indx) (Host) ++ * The channel number on which the LPM transaction ++ * has to be applied while sending ++ * an LPM transaction to the local device. ++ */ ++ unsigned lpm_chan_index:4; ++ /** LPM Retry Count (LPM_Retry_Cnt) (Host) ++ * Number host retries that would be performed ++ * if the device response was not valid response. ++ */ ++ unsigned retry_count:3; ++ /** Send LPM Transaction (SndLPM) (Host) ++ * When set by application software, ++ * an LPM transaction containing two tokens ++ * is sent. ++ */ ++ unsigned send_lpm:1; ++ /** LPM Retry status (LPM_RetryCnt_Sts) (Host) ++ * Number of LPM Host Retries still remaining ++ * to be transmitted for the current LPM sequence ++ */ ++ unsigned retry_count_sts:3; ++ unsigned reserved28_29:2; ++ /** In host mode once this bit is set, the host ++ * configures to drive the HSIC Idle state on the bus. ++ * It then waits for the device to initiate the Connect sequence. ++ * In device mode once this bit is set, the device waits for ++ * the HSIC Idle line state on the bus. Upon receving the Idle ++ * line state, it initiates the HSIC Connect sequence. ++ */ ++ unsigned hsic_connect:1; ++ /** This bit overrides and functionally inverts ++ * the if_select_hsic input port signal. ++ */ ++ unsigned inv_sel_hsic:1; ++ } b; ++} glpmcfg_data_t; ++ ++/** ++ * This union represents the bit fields of the Core ADP Timer, Control and ++ * Status Register (ADPTIMCTLSTS). Set the bits using bit fields then write ++ * the d32 value to the register. ++ */ ++typedef union adpctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Probe Discharge (PRB_DSCHG) ++ * These bits set the times for TADP_DSCHG. ++ * These bits are defined as follows: ++ * 2'b00 - 4 msec ++ * 2'b01 - 8 msec ++ * 2'b10 - 16 msec ++ * 2'b11 - 32 msec ++ */ ++ unsigned prb_dschg:2; ++ /** Probe Delta (PRB_DELTA) ++ * These bits set the resolution for RTIM value. ++ * The bits are defined in units of 32 kHz clock cycles as follows: ++ * 2'b00 - 1 cycles ++ * 2'b01 - 2 cycles ++ * 2'b10 - 3 cycles ++ * 2'b11 - 4 cycles ++ * For example if this value is chosen to 2'b01, it means that RTIM ++ * increments for every 3(three) 32Khz clock cycles. ++ */ ++ unsigned prb_delta:2; ++ /** Probe Period (PRB_PER) ++ * These bits sets the TADP_PRD as shown in Figure 4 as follows: ++ * 2'b00 - 0.625 to 0.925 sec (typical 0.775 sec) ++ * 2'b01 - 1.25 to 1.85 sec (typical 1.55 sec) ++ * 2'b10 - 1.9 to 2.6 sec (typical 2.275 sec) ++ * 2'b11 - Reserved ++ */ ++ unsigned prb_per:2; ++ /** These bits capture the latest time it took for VBUS to ramp from ++ * VADP_SINK to VADP_PRB. ++ * 0x000 - 1 cycles ++ * 0x001 - 2 cycles ++ * 0x002 - 3 cycles ++ * etc ++ * 0x7FF - 2048 cycles ++ * A time of 1024 cycles at 32 kHz corresponds to a time of 32 msec. ++ */ ++ unsigned rtim:11; ++ /** Enable Probe (EnaPrb) ++ * When programmed to 1'b1, the core performs a probe operation. ++ * This bit is valid only if OTG_Ver = 1'b1. ++ */ ++ unsigned enaprb:1; ++ /** Enable Sense (EnaSns) ++ * When programmed to 1'b1, the core performs a Sense operation. ++ * This bit is valid only if OTG_Ver = 1'b1. ++ */ ++ unsigned enasns:1; ++ /** ADP Reset (ADPRes) ++ * When set, ADP controller is reset. ++ * This bit is valid only if OTG_Ver = 1'b1. ++ */ ++ unsigned adpres:1; ++ /** ADP Enable (ADPEn) ++ * When set, the core performs either ADP probing or sensing ++ * based on EnaPrb or EnaSns. ++ * This bit is valid only if OTG_Ver = 1'b1. ++ */ ++ unsigned adpen:1; ++ /** ADP Probe Interrupt (ADP_PRB_INT) ++ * When this bit is set, it means that the VBUS ++ * voltage is greater than VADP_PRB or VADP_PRB is reached. ++ * This bit is valid only if OTG_Ver = 1'b1. ++ */ ++ unsigned adp_prb_int:1; ++ /** ++ * ADP Sense Interrupt (ADP_SNS_INT) ++ * When this bit is set, it means that the VBUS voltage is greater than ++ * VADP_SNS value or VADP_SNS is reached. ++ * This bit is valid only if OTG_Ver = 1'b1. ++ */ ++ unsigned adp_sns_int:1; ++ /** ADP Tomeout Interrupt (ADP_TMOUT_INT) ++ * This bit is relevant only for an ADP probe. ++ * When this bit is set, it means that the ramp time has ++ * completed ie ADPCTL.RTIM has reached its terminal value ++ * of 0x7FF. This is a debug feature that allows software ++ * to read the ramp time after each cycle. ++ * This bit is valid only if OTG_Ver = 1'b1. ++ */ ++ unsigned adp_tmout_int:1; ++ /** ADP Probe Interrupt Mask (ADP_PRB_INT_MSK) ++ * When this bit is set, it unmasks the interrupt due to ADP_PRB_INT. ++ * This bit is valid only if OTG_Ver = 1'b1. ++ */ ++ unsigned adp_prb_int_msk:1; ++ /** ADP Sense Interrupt Mask (ADP_SNS_INT_MSK) ++ * When this bit is set, it unmasks the interrupt due to ADP_SNS_INT. ++ * This bit is valid only if OTG_Ver = 1'b1. ++ */ ++ unsigned adp_sns_int_msk:1; ++ /** ADP Timoeout Interrupt Mask (ADP_TMOUT_MSK) ++ * When this bit is set, it unmasks the interrupt due to ADP_TMOUT_INT. ++ * This bit is valid only if OTG_Ver = 1'b1. ++ */ ++ unsigned adp_tmout_int_msk:1; ++ /** Access Request ++ * 2'b00 - Read/Write Valid (updated by the core) ++ * 2'b01 - Read ++ * 2'b00 - Write ++ * 2'b00 - Reserved ++ */ ++ unsigned ar:2; ++ /** Reserved */ ++ unsigned reserved29_31:3; ++ } b; ++} adpctl_data_t; ++ ++//////////////////////////////////////////// ++// Device Registers ++/** ++ * Device Global Registers. Offsets 800h-BFFh ++ * ++ * The following structures define the size and relative field offsets ++ * for the Device Mode Registers. ++ * ++ * These registers are visible only in Device mode and must not be ++ * accessed in Host mode, as the results are unknown. ++ */ ++typedef struct dwc_otg_dev_global_regs { ++ /** Device Configuration Register. Offset 800h */ ++ volatile uint32_t dcfg; ++ /** Device Control Register. Offset: 804h */ ++ volatile uint32_t dctl; ++ /** Device Status Register (Read Only). Offset: 808h */ ++ volatile uint32_t dsts; ++ /** Reserved. Offset: 80Ch */ ++ uint32_t unused; ++ /** Device IN Endpoint Common Interrupt Mask ++ * Register. Offset: 810h */ ++ volatile uint32_t diepmsk; ++ /** Device OUT Endpoint Common Interrupt Mask ++ * Register. Offset: 814h */ ++ volatile uint32_t doepmsk; ++ /** Device All Endpoints Interrupt Register. Offset: 818h */ ++ volatile uint32_t daint; ++ /** Device All Endpoints Interrupt Mask Register. Offset: ++ * 81Ch */ ++ volatile uint32_t daintmsk; ++ /** Device IN Token Queue Read Register-1 (Read Only). ++ * Offset: 820h */ ++ volatile uint32_t dtknqr1; ++ /** Device IN Token Queue Read Register-2 (Read Only). ++ * Offset: 824h */ ++ volatile uint32_t dtknqr2; ++ /** Device VBUS discharge Register. Offset: 828h */ ++ volatile uint32_t dvbusdis; ++ /** Device VBUS Pulse Register. Offset: 82Ch */ ++ volatile uint32_t dvbuspulse; ++ /** Device IN Token Queue Read Register-3 (Read Only). / ++ * Device Thresholding control register (Read/Write) ++ * Offset: 830h */ ++ volatile uint32_t dtknqr3_dthrctl; ++ /** Device IN Token Queue Read Register-4 (Read Only). / ++ * Device IN EPs empty Inr. Mask Register (Read/Write) ++ * Offset: 834h */ ++ volatile uint32_t dtknqr4_fifoemptymsk; ++ /** Device Each Endpoint Interrupt Register (Read Only). / ++ * Offset: 838h */ ++ volatile uint32_t deachint; ++ /** Device Each Endpoint Interrupt mask Register (Read/Write). / ++ * Offset: 83Ch */ ++ volatile uint32_t deachintmsk; ++ /** Device Each In Endpoint Interrupt mask Register (Read/Write). / ++ * Offset: 840h */ ++ volatile uint32_t diepeachintmsk[MAX_EPS_CHANNELS]; ++ /** Device Each Out Endpoint Interrupt mask Register (Read/Write). / ++ * Offset: 880h */ ++ volatile uint32_t doepeachintmsk[MAX_EPS_CHANNELS]; ++} dwc_otg_device_global_regs_t; ++ ++/** ++ * This union represents the bit fields in the Device Configuration ++ * Register. Read the register into the d32 member then ++ * set/clear the bits using the bit elements. Write the ++ * d32 member to the dcfg register. ++ */ ++typedef union dcfg_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Device Speed */ ++ unsigned devspd:2; ++ /** Non Zero Length Status OUT Handshake */ ++ unsigned nzstsouthshk:1; ++#define DWC_DCFG_SEND_STALL 1 ++ ++ unsigned ena32khzs:1; ++ /** Device Addresses */ ++ unsigned devaddr:7; ++ /** Periodic Frame Interval */ ++ unsigned perfrint:2; ++#define DWC_DCFG_FRAME_INTERVAL_80 0 ++#define DWC_DCFG_FRAME_INTERVAL_85 1 ++#define DWC_DCFG_FRAME_INTERVAL_90 2 ++#define DWC_DCFG_FRAME_INTERVAL_95 3 ++ ++ /** Enable Device OUT NAK for bulk in DDMA mode */ ++ unsigned endevoutnak:1; ++ ++ unsigned reserved14_17:4; ++ /** In Endpoint Mis-match count */ ++ unsigned epmscnt:5; ++ /** Enable Descriptor DMA in Device mode */ ++ unsigned descdma:1; ++ unsigned perschintvl:2; ++ unsigned resvalid:6; ++ } b; ++} dcfg_data_t; ++ ++/** ++ * This union represents the bit fields in the Device Control ++ * Register. Read the register into the d32 member then ++ * set/clear the bits using the bit elements. ++ */ ++typedef union dctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Remote Wakeup */ ++ unsigned rmtwkupsig:1; ++ /** Soft Disconnect */ ++ unsigned sftdiscon:1; ++ /** Global Non-Periodic IN NAK Status */ ++ unsigned gnpinnaksts:1; ++ /** Global OUT NAK Status */ ++ unsigned goutnaksts:1; ++ /** Test Control */ ++ unsigned tstctl:3; ++ /** Set Global Non-Periodic IN NAK */ ++ unsigned sgnpinnak:1; ++ /** Clear Global Non-Periodic IN NAK */ ++ unsigned cgnpinnak:1; ++ /** Set Global OUT NAK */ ++ unsigned sgoutnak:1; ++ /** Clear Global OUT NAK */ ++ unsigned cgoutnak:1; ++ /** Power-On Programming Done */ ++ unsigned pwronprgdone:1; ++ /** Reserved */ ++ unsigned reserved:1; ++ /** Global Multi Count */ ++ unsigned gmc:2; ++ /** Ignore Frame Number for ISOC EPs */ ++ unsigned ifrmnum:1; ++ /** NAK on Babble */ ++ unsigned nakonbble:1; ++ /** Enable Continue on BNA */ ++ unsigned encontonbna:1; ++ ++ unsigned reserved18_31:14; ++ } b; ++} dctl_data_t; ++ ++/** ++ * This union represents the bit fields in the Device Status ++ * Register. Read the register into the d32 member then ++ * set/clear the bits using the bit elements. ++ */ ++typedef union dsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Suspend Status */ ++ unsigned suspsts:1; ++ /** Enumerated Speed */ ++ unsigned enumspd:2; ++#define DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 ++#define DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 ++#define DWC_DSTS_ENUMSPD_LS_PHY_6MHZ 2 ++#define DWC_DSTS_ENUMSPD_FS_PHY_48MHZ 3 ++ /** Erratic Error */ ++ unsigned errticerr:1; ++ unsigned reserved4_7:4; ++ /** Frame or Microframe Number of the received SOF */ ++ unsigned soffn:14; ++ unsigned reserved22_31:10; ++ } b; ++} dsts_data_t; ++ ++/** ++ * This union represents the bit fields in the Device IN EP Interrupt ++ * Register and the Device IN EP Common Mask Register. ++ * ++ * - Read the register into the d32 member then set/clear the ++ * bits using the bit elements. ++ */ ++typedef union diepint_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Transfer complete mask */ ++ unsigned xfercompl:1; ++ /** Endpoint disable mask */ ++ unsigned epdisabled:1; ++ /** AHB Error mask */ ++ unsigned ahberr:1; ++ /** TimeOUT Handshake mask (non-ISOC EPs) */ ++ unsigned timeout:1; ++ /** IN Token received with TxF Empty mask */ ++ unsigned intktxfemp:1; ++ /** IN Token Received with EP mismatch mask */ ++ unsigned intknepmis:1; ++ /** IN Endpoint NAK Effective mask */ ++ unsigned inepnakeff:1; ++ /** Reserved */ ++ unsigned emptyintr:1; ++ ++ unsigned txfifoundrn:1; ++ ++ /** BNA Interrupt mask */ ++ unsigned bna:1; ++ ++ unsigned reserved10_12:3; ++ /** BNA Interrupt mask */ ++ unsigned nak:1; ++ ++ unsigned reserved14_31:18; ++ } b; ++} diepint_data_t; ++ ++/** ++ * This union represents the bit fields in the Device IN EP ++ * Common/Dedicated Interrupt Mask Register. ++ */ ++typedef union diepint_data diepmsk_data_t; ++ ++/** ++ * This union represents the bit fields in the Device OUT EP Interrupt ++ * Registerand Device OUT EP Common Interrupt Mask Register. ++ * ++ * - Read the register into the d32 member then set/clear the ++ * bits using the bit elements. ++ */ ++typedef union doepint_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Transfer complete */ ++ unsigned xfercompl:1; ++ /** Endpoint disable */ ++ unsigned epdisabled:1; ++ /** AHB Error */ ++ unsigned ahberr:1; ++ /** Setup Phase Done (contorl EPs) */ ++ unsigned setup:1; ++ /** OUT Token Received when Endpoint Disabled */ ++ unsigned outtknepdis:1; ++ ++ unsigned stsphsercvd:1; ++ /** Back-to-Back SETUP Packets Received */ ++ unsigned back2backsetup:1; ++ ++ unsigned reserved7:1; ++ /** OUT packet Error */ ++ unsigned outpkterr:1; ++ /** BNA Interrupt */ ++ unsigned bna:1; ++ ++ unsigned reserved10:1; ++ /** Packet Drop Status */ ++ unsigned pktdrpsts:1; ++ /** Babble Interrupt */ ++ unsigned babble:1; ++ /** NAK Interrupt */ ++ unsigned nak:1; ++ /** NYET Interrupt */ ++ unsigned nyet:1; ++ /** Bit indicating setup packet received */ ++ unsigned sr:1; ++ ++ unsigned reserved16_31:16; ++ } b; ++} doepint_data_t; ++ ++/** ++ * This union represents the bit fields in the Device OUT EP ++ * Common/Dedicated Interrupt Mask Register. ++ */ ++typedef union doepint_data doepmsk_data_t; ++ ++/** ++ * This union represents the bit fields in the Device All EP Interrupt ++ * and Mask Registers. ++ * - Read the register into the d32 member then set/clear the ++ * bits using the bit elements. ++ */ ++typedef union daint_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** IN Endpoint bits */ ++ unsigned in:16; ++ /** OUT Endpoint bits */ ++ unsigned out:16; ++ } ep; ++ struct { ++ /** IN Endpoint bits */ ++ unsigned inep0:1; ++ unsigned inep1:1; ++ unsigned inep2:1; ++ unsigned inep3:1; ++ unsigned inep4:1; ++ unsigned inep5:1; ++ unsigned inep6:1; ++ unsigned inep7:1; ++ unsigned inep8:1; ++ unsigned inep9:1; ++ unsigned inep10:1; ++ unsigned inep11:1; ++ unsigned inep12:1; ++ unsigned inep13:1; ++ unsigned inep14:1; ++ unsigned inep15:1; ++ /** OUT Endpoint bits */ ++ unsigned outep0:1; ++ unsigned outep1:1; ++ unsigned outep2:1; ++ unsigned outep3:1; ++ unsigned outep4:1; ++ unsigned outep5:1; ++ unsigned outep6:1; ++ unsigned outep7:1; ++ unsigned outep8:1; ++ unsigned outep9:1; ++ unsigned outep10:1; ++ unsigned outep11:1; ++ unsigned outep12:1; ++ unsigned outep13:1; ++ unsigned outep14:1; ++ unsigned outep15:1; ++ } b; ++} daint_data_t; ++ ++/** ++ * This union represents the bit fields in the Device IN Token Queue ++ * Read Registers. ++ * - Read the register into the d32 member. ++ * - READ-ONLY Register ++ */ ++typedef union dtknq1_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** In Token Queue Write Pointer */ ++ unsigned intknwptr:5; ++ /** Reserved */ ++ unsigned reserved05_06:2; ++ /** write pointer has wrapped. */ ++ unsigned wrap_bit:1; ++ /** EP Numbers of IN Tokens 0 ... 4 */ ++ unsigned epnums0_5:24; ++ } b; ++} dtknq1_data_t; ++ ++/** ++ * This union represents Threshold control Register ++ * - Read and write the register into the d32 member. ++ * - READ-WRITABLE Register ++ */ ++typedef union dthrctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** non ISO Tx Thr. Enable */ ++ unsigned non_iso_thr_en:1; ++ /** ISO Tx Thr. Enable */ ++ unsigned iso_thr_en:1; ++ /** Tx Thr. Length */ ++ unsigned tx_thr_len:9; ++ /** AHB Threshold ratio */ ++ unsigned ahb_thr_ratio:2; ++ /** Reserved */ ++ unsigned reserved13_15:3; ++ /** Rx Thr. Enable */ ++ unsigned rx_thr_en:1; ++ /** Rx Thr. Length */ ++ unsigned rx_thr_len:9; ++ unsigned reserved26:1; ++ /** Arbiter Parking Enable*/ ++ unsigned arbprken:1; ++ /** Reserved */ ++ unsigned reserved28_31:4; ++ } b; ++} dthrctl_data_t; ++ ++/** ++ * Device Logical IN Endpoint-Specific Registers. Offsets ++ * 900h-AFCh ++ * ++ * There will be one set of endpoint registers per logical endpoint ++ * implemented. ++ * ++ * These registers are visible only in Device mode and must not be ++ * accessed in Host mode, as the results are unknown. ++ */ ++typedef struct dwc_otg_dev_in_ep_regs { ++ /** Device IN Endpoint Control Register. Offset:900h + ++ * (ep_num * 20h) + 00h */ ++ volatile uint32_t diepctl; ++ /** Reserved. Offset:900h + (ep_num * 20h) + 04h */ ++ uint32_t reserved04; ++ /** Device IN Endpoint Interrupt Register. Offset:900h + ++ * (ep_num * 20h) + 08h */ ++ volatile uint32_t diepint; ++ /** Reserved. Offset:900h + (ep_num * 20h) + 0Ch */ ++ uint32_t reserved0C; ++ /** Device IN Endpoint Transfer Size ++ * Register. Offset:900h + (ep_num * 20h) + 10h */ ++ volatile uint32_t dieptsiz; ++ /** Device IN Endpoint DMA Address Register. Offset:900h + ++ * (ep_num * 20h) + 14h */ ++ volatile uint32_t diepdma; ++ /** Device IN Endpoint Transmit FIFO Status Register. Offset:900h + ++ * (ep_num * 20h) + 18h */ ++ volatile uint32_t dtxfsts; ++ /** Device IN Endpoint DMA Buffer Register. Offset:900h + ++ * (ep_num * 20h) + 1Ch */ ++ volatile uint32_t diepdmab; ++} dwc_otg_dev_in_ep_regs_t; ++ ++/** ++ * Device Logical OUT Endpoint-Specific Registers. Offsets: ++ * B00h-CFCh ++ * ++ * There will be one set of endpoint registers per logical endpoint ++ * implemented. ++ * ++ * These registers are visible only in Device mode and must not be ++ * accessed in Host mode, as the results are unknown. ++ */ ++typedef struct dwc_otg_dev_out_ep_regs { ++ /** Device OUT Endpoint Control Register. Offset:B00h + ++ * (ep_num * 20h) + 00h */ ++ volatile uint32_t doepctl; ++ /** Reserved. Offset:B00h + (ep_num * 20h) + 04h */ ++ uint32_t reserved04; ++ /** Device OUT Endpoint Interrupt Register. Offset:B00h + ++ * (ep_num * 20h) + 08h */ ++ volatile uint32_t doepint; ++ /** Reserved. Offset:B00h + (ep_num * 20h) + 0Ch */ ++ uint32_t reserved0C; ++ /** Device OUT Endpoint Transfer Size Register. Offset: ++ * B00h + (ep_num * 20h) + 10h */ ++ volatile uint32_t doeptsiz; ++ /** Device OUT Endpoint DMA Address Register. Offset:B00h ++ * + (ep_num * 20h) + 14h */ ++ volatile uint32_t doepdma; ++ /** Reserved. Offset:B00h + * (ep_num * 20h) + 18h */ ++ uint32_t unused; ++ /** Device OUT Endpoint DMA Buffer Register. Offset:B00h ++ * + (ep_num * 20h) + 1Ch */ ++ uint32_t doepdmab; ++} dwc_otg_dev_out_ep_regs_t; ++ ++/** ++ * This union represents the bit fields in the Device EP Control ++ * Register. Read the register into the d32 member then ++ * set/clear the bits using the bit elements. ++ */ ++typedef union depctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Maximum Packet Size ++ * IN/OUT EPn ++ * IN/OUT EP0 - 2 bits ++ * 2'b00: 64 Bytes ++ * 2'b01: 32 ++ * 2'b10: 16 ++ * 2'b11: 8 */ ++ unsigned mps:11; ++#define DWC_DEP0CTL_MPS_64 0 ++#define DWC_DEP0CTL_MPS_32 1 ++#define DWC_DEP0CTL_MPS_16 2 ++#define DWC_DEP0CTL_MPS_8 3 ++ ++ /** Next Endpoint ++ * IN EPn/IN EP0 ++ * OUT EPn/OUT EP0 - reserved */ ++ unsigned nextep:4; ++ ++ /** USB Active Endpoint */ ++ unsigned usbactep:1; ++ ++ /** Endpoint DPID (INTR/Bulk IN and OUT endpoints) ++ * This field contains the PID of the packet going to ++ * be received or transmitted on this endpoint. The ++ * application should program the PID of the first ++ * packet going to be received or transmitted on this ++ * endpoint , after the endpoint is ++ * activated. Application use the SetD1PID and ++ * SetD0PID fields of this register to program either ++ * D0 or D1 PID. ++ * ++ * The encoding for this field is ++ * - 0: D0 ++ * - 1: D1 ++ */ ++ unsigned dpid:1; ++ ++ /** NAK Status */ ++ unsigned naksts:1; ++ ++ /** Endpoint Type ++ * 2'b00: Control ++ * 2'b01: Isochronous ++ * 2'b10: Bulk ++ * 2'b11: Interrupt */ ++ unsigned eptype:2; ++ ++ /** Snoop Mode ++ * OUT EPn/OUT EP0 ++ * IN EPn/IN EP0 - reserved */ ++ unsigned snp:1; ++ ++ /** Stall Handshake */ ++ unsigned stall:1; ++ ++ /** Tx Fifo Number ++ * IN EPn/IN EP0 ++ * OUT EPn/OUT EP0 - reserved */ ++ unsigned txfnum:4; ++ ++ /** Clear NAK */ ++ unsigned cnak:1; ++ /** Set NAK */ ++ unsigned snak:1; ++ /** Set DATA0 PID (INTR/Bulk IN and OUT endpoints) ++ * Writing to this field sets the Endpoint DPID (DPID) ++ * field in this register to DATA0. Set Even ++ * (micro)frame (SetEvenFr) (ISO IN and OUT Endpoints) ++ * Writing to this field sets the Even/Odd ++ * (micro)frame (EO_FrNum) field to even (micro) ++ * frame. ++ */ ++ unsigned setd0pid:1; ++ /** Set DATA1 PID (INTR/Bulk IN and OUT endpoints) ++ * Writing to this field sets the Endpoint DPID (DPID) ++ * field in this register to DATA1 Set Odd ++ * (micro)frame (SetOddFr) (ISO IN and OUT Endpoints) ++ * Writing to this field sets the Even/Odd ++ * (micro)frame (EO_FrNum) field to odd (micro) frame. ++ */ ++ unsigned setd1pid:1; ++ ++ /** Endpoint Disable */ ++ unsigned epdis:1; ++ /** Endpoint Enable */ ++ unsigned epena:1; ++ } b; ++} depctl_data_t; ++ ++/** ++ * This union represents the bit fields in the Device EP Transfer ++ * Size Register. Read the register into the d32 member then ++ * set/clear the bits using the bit elements. ++ */ ++typedef union deptsiz_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Transfer size */ ++ unsigned xfersize:19; ++/** Max packet count for EP (pow(2,10)-1) */ ++#define MAX_PKT_CNT 1023 ++ /** Packet Count */ ++ unsigned pktcnt:10; ++ /** Multi Count - Periodic IN endpoints */ ++ unsigned mc:2; ++ unsigned reserved:1; ++ } b; ++} deptsiz_data_t; ++ ++/** ++ * This union represents the bit fields in the Device EP 0 Transfer ++ * Size Register. Read the register into the d32 member then ++ * set/clear the bits using the bit elements. ++ */ ++typedef union deptsiz0_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Transfer size */ ++ unsigned xfersize:7; ++ /** Reserved */ ++ unsigned reserved7_18:12; ++ /** Packet Count */ ++ unsigned pktcnt:2; ++ /** Reserved */ ++ unsigned reserved21_28:8; ++ /**Setup Packet Count (DOEPTSIZ0 Only) */ ++ unsigned supcnt:2; ++ unsigned reserved31; ++ } b; ++} deptsiz0_data_t; ++ ++///////////////////////////////////////////////// ++// DMA Descriptor Specific Structures ++// ++ ++/** Buffer status definitions */ ++ ++#define BS_HOST_READY 0x0 ++#define BS_DMA_BUSY 0x1 ++#define BS_DMA_DONE 0x2 ++#define BS_HOST_BUSY 0x3 ++ ++/** Receive/Transmit status definitions */ ++ ++#define RTS_SUCCESS 0x0 ++#define RTS_BUFFLUSH 0x1 ++#define RTS_RESERVED 0x2 ++#define RTS_BUFERR 0x3 ++ ++/** ++ * This union represents the bit fields in the DMA Descriptor ++ * status quadlet. Read the quadlet into the d32 member then ++ * set/clear the bits using the bit, b_iso_out and ++ * b_iso_in elements. ++ */ ++typedef union dev_dma_desc_sts { ++ /** raw register data */ ++ uint32_t d32; ++ /** quadlet bits */ ++ struct { ++ /** Received number of bytes */ ++ unsigned bytes:16; ++ /** NAK bit - only for OUT EPs */ ++ unsigned nak:1; ++ unsigned reserved17_22:6; ++ /** Multiple Transfer - only for OUT EPs */ ++ unsigned mtrf:1; ++ /** Setup Packet received - only for OUT EPs */ ++ unsigned sr:1; ++ /** Interrupt On Complete */ ++ unsigned ioc:1; ++ /** Short Packet */ ++ unsigned sp:1; ++ /** Last */ ++ unsigned l:1; ++ /** Receive Status */ ++ unsigned sts:2; ++ /** Buffer Status */ ++ unsigned bs:2; ++ } b; ++ ++//#ifdef DWC_EN_ISOC ++ /** iso out quadlet bits */ ++ struct { ++ /** Received number of bytes */ ++ unsigned rxbytes:11; ++ ++ unsigned reserved11:1; ++ /** Frame Number */ ++ unsigned framenum:11; ++ /** Received ISO Data PID */ ++ unsigned pid:2; ++ /** Interrupt On Complete */ ++ unsigned ioc:1; ++ /** Short Packet */ ++ unsigned sp:1; ++ /** Last */ ++ unsigned l:1; ++ /** Receive Status */ ++ unsigned rxsts:2; ++ /** Buffer Status */ ++ unsigned bs:2; ++ } b_iso_out; ++ ++ /** iso in quadlet bits */ ++ struct { ++ /** Transmited number of bytes */ ++ unsigned txbytes:12; ++ /** Frame Number */ ++ unsigned framenum:11; ++ /** Transmited ISO Data PID */ ++ unsigned pid:2; ++ /** Interrupt On Complete */ ++ unsigned ioc:1; ++ /** Short Packet */ ++ unsigned sp:1; ++ /** Last */ ++ unsigned l:1; ++ /** Transmit Status */ ++ unsigned txsts:2; ++ /** Buffer Status */ ++ unsigned bs:2; ++ } b_iso_in; ++//#endif /* DWC_EN_ISOC */ ++} dev_dma_desc_sts_t; ++ ++/** ++ * DMA Descriptor structure ++ * ++ * DMA Descriptor structure contains two quadlets: ++ * Status quadlet and Data buffer pointer. ++ */ ++typedef struct dwc_otg_dev_dma_desc { ++ /** DMA Descriptor status quadlet */ ++ dev_dma_desc_sts_t status; ++ /** DMA Descriptor data buffer pointer */ ++ uint32_t buf; ++} dwc_otg_dev_dma_desc_t; ++ ++/** ++ * The dwc_otg_dev_if structure contains information needed to manage ++ * the DWC_otg controller acting in device mode. It represents the ++ * programming view of the device-specific aspects of the controller. ++ */ ++typedef struct dwc_otg_dev_if { ++ /** Pointer to device Global registers. ++ * Device Global Registers starting at offset 800h ++ */ ++ dwc_otg_device_global_regs_t *dev_global_regs; ++#define DWC_DEV_GLOBAL_REG_OFFSET 0x800 ++ ++ /** ++ * Device Logical IN Endpoint-Specific Registers 900h-AFCh ++ */ ++ dwc_otg_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS]; ++#define DWC_DEV_IN_EP_REG_OFFSET 0x900 ++#define DWC_EP_REG_OFFSET 0x20 ++ ++ /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */ ++ dwc_otg_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS]; ++#define DWC_DEV_OUT_EP_REG_OFFSET 0xB00 ++ ++ /* Device configuration information */ ++ uint8_t speed; /**< Device Speed 0: Unknown, 1: LS, 2:FS, 3: HS */ ++ uint8_t num_in_eps; /**< Number # of Tx EP range: 0-15 exept ep0 */ ++ uint8_t num_out_eps; /**< Number # of Rx EP range: 0-15 exept ep 0*/ ++ ++ /** Size of periodic FIFOs (Bytes) */ ++ uint16_t perio_tx_fifo_size[MAX_PERIO_FIFOS]; ++ ++ /** Size of Tx FIFOs (Bytes) */ ++ uint16_t tx_fifo_size[MAX_TX_FIFOS]; ++ ++ /** Thresholding enable flags and length varaiables **/ ++ uint16_t rx_thr_en; ++ uint16_t iso_tx_thr_en; ++ uint16_t non_iso_tx_thr_en; ++ ++ uint16_t rx_thr_length; ++ uint16_t tx_thr_length; ++ ++ /** ++ * Pointers to the DMA Descriptors for EP0 Control ++ * transfers (virtual and physical) ++ */ ++ ++ /** 2 descriptors for SETUP packets */ ++ dwc_dma_t dma_setup_desc_addr[2]; ++ dwc_otg_dev_dma_desc_t *setup_desc_addr[2]; ++ ++ /** Pointer to Descriptor with latest SETUP packet */ ++ dwc_otg_dev_dma_desc_t *psetup; ++ ++ /** Index of current SETUP handler descriptor */ ++ uint32_t setup_desc_index; ++ ++ /** Descriptor for Data In or Status In phases */ ++ dwc_dma_t dma_in_desc_addr; ++ dwc_otg_dev_dma_desc_t *in_desc_addr; ++ ++ /** Descriptor for Data Out or Status Out phases */ ++ dwc_dma_t dma_out_desc_addr; ++ dwc_otg_dev_dma_desc_t *out_desc_addr; ++ ++ /** Setup Packet Detected - if set clear NAK when queueing */ ++ uint32_t spd; ++ /** Isoc ep pointer on which incomplete happens */ ++ void *isoc_ep; ++ ++} dwc_otg_dev_if_t; ++ ++///////////////////////////////////////////////// ++// Host Mode Register Structures ++// ++/** ++ * The Host Global Registers structure defines the size and relative ++ * field offsets for the Host Mode Global Registers. Host Global ++ * Registers offsets 400h-7FFh. ++*/ ++typedef struct dwc_otg_host_global_regs { ++ /** Host Configuration Register. Offset: 400h */ ++ volatile uint32_t hcfg; ++ /** Host Frame Interval Register. Offset: 404h */ ++ volatile uint32_t hfir; ++ /** Host Frame Number / Frame Remaining Register. Offset: 408h */ ++ volatile uint32_t hfnum; ++ /** Reserved. Offset: 40Ch */ ++ uint32_t reserved40C; ++ /** Host Periodic Transmit FIFO/ Queue Status Register. Offset: 410h */ ++ volatile uint32_t hptxsts; ++ /** Host All Channels Interrupt Register. Offset: 414h */ ++ volatile uint32_t haint; ++ /** Host All Channels Interrupt Mask Register. Offset: 418h */ ++ volatile uint32_t haintmsk; ++ /** Host Frame List Base Address Register . Offset: 41Ch */ ++ volatile uint32_t hflbaddr; ++} dwc_otg_host_global_regs_t; ++ ++/** ++ * This union represents the bit fields in the Host Configuration Register. ++ * Read the register into the d32 member then set/clear the bits using ++ * the bit elements. Write the d32 member to the hcfg register. ++ */ ++typedef union hcfg_data { ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** FS/LS Phy Clock Select */ ++ unsigned fslspclksel:2; ++#define DWC_HCFG_30_60_MHZ 0 ++#define DWC_HCFG_48_MHZ 1 ++#define DWC_HCFG_6_MHZ 2 ++ ++ /** FS/LS Only Support */ ++ unsigned fslssupp:1; ++ unsigned reserved3_6:4; ++ /** Enable 32-KHz Suspend Mode */ ++ unsigned ena32khzs:1; ++ /** Resume Validation Periiod */ ++ unsigned resvalid:8; ++ unsigned reserved16_22:7; ++ /** Enable Scatter/gather DMA in Host mode */ ++ unsigned descdma:1; ++ /** Frame List Entries */ ++ unsigned frlisten:2; ++ /** Enable Periodic Scheduling */ ++ unsigned perschedena:1; ++ unsigned reserved27_30:4; ++ unsigned modechtimen:1; ++ } b; ++} hcfg_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Frame Remaing/Number ++ * Register. ++ */ ++typedef union hfir_data { ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned frint:16; ++ unsigned hfirrldctrl:1; ++ unsigned reserved:15; ++ } b; ++} hfir_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Frame Remaing/Number ++ * Register. ++ */ ++typedef union hfnum_data { ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned frnum:16; ++#define DWC_HFNUM_MAX_FRNUM 0x3FFF ++ unsigned frrem:16; ++ } b; ++} hfnum_data_t; ++ ++typedef union hptxsts_data { ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned ptxfspcavail:16; ++ unsigned ptxqspcavail:8; ++ /** Top of the Periodic Transmit Request Queue ++ * - bit 24 - Terminate (last entry for the selected channel) ++ * - bits 26:25 - Token Type ++ * - 2'b00 - Zero length ++ * - 2'b01 - Ping ++ * - 2'b10 - Disable ++ * - bits 30:27 - Channel Number ++ * - bit 31 - Odd/even microframe ++ */ ++ unsigned ptxqtop_terminate:1; ++ unsigned ptxqtop_token:2; ++ unsigned ptxqtop_chnum:4; ++ unsigned ptxqtop_odd:1; ++ } b; ++} hptxsts_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Port Control and Status ++ * Register. Read the register into the d32 member then set/clear the ++ * bits using the bit elements. Write the d32 member to the ++ * hprt0 register. ++ */ ++typedef union hprt0_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned prtconnsts:1; ++ unsigned prtconndet:1; ++ unsigned prtena:1; ++ unsigned prtenchng:1; ++ unsigned prtovrcurract:1; ++ unsigned prtovrcurrchng:1; ++ unsigned prtres:1; ++ unsigned prtsusp:1; ++ unsigned prtrst:1; ++ unsigned reserved9:1; ++ unsigned prtlnsts:2; ++ unsigned prtpwr:1; ++ unsigned prttstctl:4; ++ unsigned prtspd:2; ++#define DWC_HPRT0_PRTSPD_HIGH_SPEED 0 ++#define DWC_HPRT0_PRTSPD_FULL_SPEED 1 ++#define DWC_HPRT0_PRTSPD_LOW_SPEED 2 ++ unsigned reserved19_31:13; ++ } b; ++} hprt0_data_t; ++ ++/** ++ * This union represents the bit fields in the Host All Interrupt ++ * Register. ++ */ ++typedef union haint_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned ch0:1; ++ unsigned ch1:1; ++ unsigned ch2:1; ++ unsigned ch3:1; ++ unsigned ch4:1; ++ unsigned ch5:1; ++ unsigned ch6:1; ++ unsigned ch7:1; ++ unsigned ch8:1; ++ unsigned ch9:1; ++ unsigned ch10:1; ++ unsigned ch11:1; ++ unsigned ch12:1; ++ unsigned ch13:1; ++ unsigned ch14:1; ++ unsigned ch15:1; ++ unsigned reserved:16; ++ } b; ++ ++ struct { ++ unsigned chint:16; ++ unsigned reserved:16; ++ } b2; ++} haint_data_t; ++ ++/** ++ * This union represents the bit fields in the Host All Interrupt ++ * Register. ++ */ ++typedef union haintmsk_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned ch0:1; ++ unsigned ch1:1; ++ unsigned ch2:1; ++ unsigned ch3:1; ++ unsigned ch4:1; ++ unsigned ch5:1; ++ unsigned ch6:1; ++ unsigned ch7:1; ++ unsigned ch8:1; ++ unsigned ch9:1; ++ unsigned ch10:1; ++ unsigned ch11:1; ++ unsigned ch12:1; ++ unsigned ch13:1; ++ unsigned ch14:1; ++ unsigned ch15:1; ++ unsigned reserved:16; ++ } b; ++ ++ struct { ++ unsigned chint:16; ++ unsigned reserved:16; ++ } b2; ++} haintmsk_data_t; ++ ++/** ++ * Host Channel Specific Registers. 500h-5FCh ++ */ ++typedef struct dwc_otg_hc_regs { ++ /** Host Channel 0 Characteristic Register. Offset: 500h + (chan_num * 20h) + 00h */ ++ volatile uint32_t hcchar; ++ /** Host Channel 0 Split Control Register. Offset: 500h + (chan_num * 20h) + 04h */ ++ volatile uint32_t hcsplt; ++ /** Host Channel 0 Interrupt Register. Offset: 500h + (chan_num * 20h) + 08h */ ++ volatile uint32_t hcint; ++ /** Host Channel 0 Interrupt Mask Register. Offset: 500h + (chan_num * 20h) + 0Ch */ ++ volatile uint32_t hcintmsk; ++ /** Host Channel 0 Transfer Size Register. Offset: 500h + (chan_num * 20h) + 10h */ ++ volatile uint32_t hctsiz; ++ /** Host Channel 0 DMA Address Register. Offset: 500h + (chan_num * 20h) + 14h */ ++ volatile uint32_t hcdma; ++ volatile uint32_t reserved; ++ /** Host Channel 0 DMA Buffer Address Register. Offset: 500h + (chan_num * 20h) + 1Ch */ ++ volatile uint32_t hcdmab; ++} dwc_otg_hc_regs_t; ++ ++/** ++ * This union represents the bit fields in the Host Channel Characteristics ++ * Register. Read the register into the d32 member then set/clear the ++ * bits using the bit elements. Write the d32 member to the ++ * hcchar register. ++ */ ++typedef union hcchar_data { ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Maximum packet size in bytes */ ++ unsigned mps:11; ++ ++ /** Endpoint number */ ++ unsigned epnum:4; ++ ++ /** 0: OUT, 1: IN */ ++ unsigned epdir:1; ++ ++ unsigned reserved:1; ++ ++ /** 0: Full/high speed device, 1: Low speed device */ ++ unsigned lspddev:1; ++ ++ /** 0: Control, 1: Isoc, 2: Bulk, 3: Intr */ ++ unsigned eptype:2; ++ ++ /** Packets per frame for periodic transfers. 0 is reserved. */ ++ unsigned multicnt:2; ++ ++ /** Device address */ ++ unsigned devaddr:7; ++ ++ /** ++ * Frame to transmit periodic transaction. ++ * 0: even, 1: odd ++ */ ++ unsigned oddfrm:1; ++ ++ /** Channel disable */ ++ unsigned chdis:1; ++ ++ /** Channel enable */ ++ unsigned chen:1; ++ } b; ++} hcchar_data_t; ++ ++typedef union hcsplt_data { ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Port Address */ ++ unsigned prtaddr:7; ++ ++ /** Hub Address */ ++ unsigned hubaddr:7; ++ ++ /** Transaction Position */ ++ unsigned xactpos:2; ++#define DWC_HCSPLIT_XACTPOS_MID 0 ++#define DWC_HCSPLIT_XACTPOS_END 1 ++#define DWC_HCSPLIT_XACTPOS_BEGIN 2 ++#define DWC_HCSPLIT_XACTPOS_ALL 3 ++ ++ /** Do Complete Split */ ++ unsigned compsplt:1; ++ ++ /** Reserved */ ++ unsigned reserved:14; ++ ++ /** Split Enble */ ++ unsigned spltena:1; ++ } b; ++} hcsplt_data_t; ++ ++/** ++ * This union represents the bit fields in the Host All Interrupt ++ * Register. ++ */ ++typedef union hcint_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** Transfer Complete */ ++ unsigned xfercomp:1; ++ /** Channel Halted */ ++ unsigned chhltd:1; ++ /** AHB Error */ ++ unsigned ahberr:1; ++ /** STALL Response Received */ ++ unsigned stall:1; ++ /** NAK Response Received */ ++ unsigned nak:1; ++ /** ACK Response Received */ ++ unsigned ack:1; ++ /** NYET Response Received */ ++ unsigned nyet:1; ++ /** Transaction Err */ ++ unsigned xacterr:1; ++ /** Babble Error */ ++ unsigned bblerr:1; ++ /** Frame Overrun */ ++ unsigned frmovrun:1; ++ /** Data Toggle Error */ ++ unsigned datatglerr:1; ++ /** Buffer Not Available (only for DDMA mode) */ ++ unsigned bna:1; ++ /** Exessive transaction error (only for DDMA mode) */ ++ unsigned xcs_xact:1; ++ /** Frame List Rollover interrupt */ ++ unsigned frm_list_roll:1; ++ /** Reserved */ ++ unsigned reserved14_31:18; ++ } b; ++} hcint_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Channel Interrupt Mask ++ * Register. Read the register into the d32 member then set/clear the ++ * bits using the bit elements. Write the d32 member to the ++ * hcintmsk register. ++ */ ++typedef union hcintmsk_data { ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ unsigned xfercompl:1; ++ unsigned chhltd:1; ++ unsigned ahberr:1; ++ unsigned stall:1; ++ unsigned nak:1; ++ unsigned ack:1; ++ unsigned nyet:1; ++ unsigned xacterr:1; ++ unsigned bblerr:1; ++ unsigned frmovrun:1; ++ unsigned datatglerr:1; ++ unsigned bna:1; ++ unsigned xcs_xact:1; ++ unsigned frm_list_roll:1; ++ unsigned reserved14_31:18; ++ } b; ++} hcintmsk_data_t; ++ ++/** ++ * This union represents the bit fields in the Host Channel Transfer Size ++ * Register. Read the register into the d32 member then set/clear the ++ * bits using the bit elements. Write the d32 member to the ++ * hcchar register. ++ */ ++ ++typedef union hctsiz_data { ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Total transfer size in bytes */ ++ unsigned xfersize:19; ++ ++ /** Data packets to transfer */ ++ unsigned pktcnt:10; ++ ++ /** ++ * Packet ID for next data packet ++ * 0: DATA0 ++ * 1: DATA2 ++ * 2: DATA1 ++ * 3: MDATA (non-Control), SETUP (Control) ++ */ ++ unsigned pid:2; ++#define DWC_HCTSIZ_DATA0 0 ++#define DWC_HCTSIZ_DATA1 2 ++#define DWC_HCTSIZ_DATA2 1 ++#define DWC_HCTSIZ_MDATA 3 ++#define DWC_HCTSIZ_SETUP 3 ++ ++ /** Do PING protocol when 1 */ ++ unsigned dopng:1; ++ } b; ++ ++ /** register bits */ ++ struct { ++ /** Scheduling information */ ++ unsigned schinfo:8; ++ ++ /** Number of transfer descriptors. ++ * Max value: ++ * 64 in general, ++ * 256 only for HS isochronous endpoint. ++ */ ++ unsigned ntd:8; ++ ++ /** Data packets to transfer */ ++ unsigned reserved16_28:13; ++ ++ /** ++ * Packet ID for next data packet ++ * 0: DATA0 ++ * 1: DATA2 ++ * 2: DATA1 ++ * 3: MDATA (non-Control) ++ */ ++ unsigned pid:2; ++ ++ /** Do PING protocol when 1 */ ++ unsigned dopng:1; ++ } b_ddma; ++} hctsiz_data_t; ++ ++/** ++ * This union represents the bit fields in the Host DMA Address ++ * Register used in Descriptor DMA mode. ++ */ ++typedef union hcdma_data { ++ /** raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ unsigned reserved0_2:3; ++ /** Current Transfer Descriptor. Not used for ISOC */ ++ unsigned ctd:8; ++ /** Start Address of Descriptor List */ ++ unsigned dma_addr:21; ++ } b; ++} hcdma_data_t; ++ ++/** ++ * This union represents the bit fields in the DMA Descriptor ++ * status quadlet for host mode. Read the quadlet into the d32 member then ++ * set/clear the bits using the bit elements. ++ */ ++typedef union host_dma_desc_sts { ++ /** raw register data */ ++ uint32_t d32; ++ /** quadlet bits */ ++ ++ /* for non-isochronous */ ++ struct { ++ /** Number of bytes */ ++ unsigned n_bytes:17; ++ /** QTD offset to jump when Short Packet received - only for IN EPs */ ++ unsigned qtd_offset:6; ++ /** ++ * Set to request the core to jump to alternate QTD if ++ * Short Packet received - only for IN EPs ++ */ ++ unsigned a_qtd:1; ++ /** ++ * Setup Packet bit. When set indicates that buffer contains ++ * setup packet. ++ */ ++ unsigned sup:1; ++ /** Interrupt On Complete */ ++ unsigned ioc:1; ++ /** End of List */ ++ unsigned eol:1; ++ unsigned reserved27:1; ++ /** Rx/Tx Status */ ++ unsigned sts:2; ++#define DMA_DESC_STS_PKTERR 1 ++ unsigned reserved30:1; ++ /** Active Bit */ ++ unsigned a:1; ++ } b; ++ /* for isochronous */ ++ struct { ++ /** Number of bytes */ ++ unsigned n_bytes:12; ++ unsigned reserved12_24:13; ++ /** Interrupt On Complete */ ++ unsigned ioc:1; ++ unsigned reserved26_27:2; ++ /** Rx/Tx Status */ ++ unsigned sts:2; ++ unsigned reserved30:1; ++ /** Active Bit */ ++ unsigned a:1; ++ } b_isoc; ++} host_dma_desc_sts_t; ++ ++#define MAX_DMA_DESC_SIZE 131071 ++#define MAX_DMA_DESC_NUM_GENERIC 64 ++#define MAX_DMA_DESC_NUM_HS_ISOC 256 ++#define MAX_FRLIST_EN_NUM 64 ++/** ++ * Host-mode DMA Descriptor structure ++ * ++ * DMA Descriptor structure contains two quadlets: ++ * Status quadlet and Data buffer pointer. ++ */ ++typedef struct dwc_otg_host_dma_desc { ++ /** DMA Descriptor status quadlet */ ++ host_dma_desc_sts_t status; ++ /** DMA Descriptor data buffer pointer */ ++ uint32_t buf; ++} dwc_otg_host_dma_desc_t; ++ ++/** OTG Host Interface Structure. ++ * ++ * The OTG Host Interface Structure structure contains information ++ * needed to manage the DWC_otg controller acting in host mode. It ++ * represents the programming view of the host-specific aspects of the ++ * controller. ++ */ ++typedef struct dwc_otg_host_if { ++ /** Host Global Registers starting at offset 400h.*/ ++ dwc_otg_host_global_regs_t *host_global_regs; ++#define DWC_OTG_HOST_GLOBAL_REG_OFFSET 0x400 ++ ++ /** Host Port 0 Control and Status Register */ ++ volatile uint32_t *hprt0; ++#define DWC_OTG_HOST_PORT_REGS_OFFSET 0x440 ++ ++ /** Host Channel Specific Registers at offsets 500h-5FCh. */ ++ dwc_otg_hc_regs_t *hc_regs[MAX_EPS_CHANNELS]; ++#define DWC_OTG_HOST_CHAN_REGS_OFFSET 0x500 ++#define DWC_OTG_CHAN_REGS_OFFSET 0x20 ++ ++ /* Host configuration information */ ++ /** Number of Host Channels (range: 1-16) */ ++ uint8_t num_host_channels; ++ /** Periodic EPs supported (0: no, 1: yes) */ ++ uint8_t perio_eps_supported; ++ /** Periodic Tx FIFO Size (Only 1 host periodic Tx FIFO) */ ++ uint16_t perio_tx_fifo_size; ++ ++} dwc_otg_host_if_t; ++ ++/** ++ * This union represents the bit fields in the Power and Clock Gating Control ++ * Register. Read the register into the d32 member then set/clear the ++ * bits using the bit elements. ++ */ ++typedef union pcgcctl_data { ++ /** raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** Stop Pclk */ ++ unsigned stoppclk:1; ++ /** Gate Hclk */ ++ unsigned gatehclk:1; ++ /** Power Clamp */ ++ unsigned pwrclmp:1; ++ /** Reset Power Down Modules */ ++ unsigned rstpdwnmodule:1; ++ /** Reserved */ ++ unsigned reserved:1; ++ /** Enable Sleep Clock Gating (Enbl_L1Gating) */ ++ unsigned enbl_sleep_gating:1; ++ /** PHY In Sleep (PhySleep) */ ++ unsigned phy_in_sleep:1; ++ /** Deep Sleep*/ ++ unsigned deep_sleep:1; ++ unsigned resetaftsusp:1; ++ unsigned restoremode:1; ++ unsigned enbl_extnd_hiber:1; ++ unsigned extnd_hiber_pwrclmp:1; ++ unsigned extnd_hiber_switch:1; ++ unsigned ess_reg_restored:1; ++ unsigned prt_clk_sel:2; ++ unsigned port_power:1; ++ unsigned max_xcvrselect:2; ++ unsigned max_termsel:1; ++ unsigned mac_dev_addr:7; ++ unsigned p2hd_dev_enum_spd:2; ++ unsigned p2hd_prt_spd:2; ++ unsigned if_dev_mode:1; ++ } b; ++} pcgcctl_data_t; ++ ++/** ++ * This union represents the bit fields in the Global Data FIFO Software ++ * Configuration Register. Read the register into the d32 member then ++ * set/clear the bits using the bit elements. ++ */ ++typedef union gdfifocfg_data { ++ /* raw register data */ ++ uint32_t d32; ++ /** register bits */ ++ struct { ++ /** OTG Data FIFO depth */ ++ unsigned gdfifocfg:16; ++ /** Start address of EP info controller */ ++ unsigned epinfobase:16; ++ } b; ++} gdfifocfg_data_t; ++ ++/** ++ * This union represents the bit fields in the Global Power Down Register ++ * Register. Read the register into the d32 member then set/clear the ++ * bits using the bit elements. ++ */ ++typedef union gpwrdn_data { ++ /* raw register data */ ++ uint32_t d32; ++ ++ /** register bits */ ++ struct { ++ /** PMU Interrupt Select */ ++ unsigned pmuintsel:1; ++ /** PMU Active */ ++ unsigned pmuactv:1; ++ /** Restore */ ++ unsigned restore:1; ++ /** Power Down Clamp */ ++ unsigned pwrdnclmp:1; ++ /** Power Down Reset */ ++ unsigned pwrdnrstn:1; ++ /** Power Down Switch */ ++ unsigned pwrdnswtch:1; ++ /** Disable VBUS */ ++ unsigned dis_vbus:1; ++ /** Line State Change */ ++ unsigned lnstschng:1; ++ /** Line state change mask */ ++ unsigned lnstchng_msk:1; ++ /** Reset Detected */ ++ unsigned rst_det:1; ++ /** Reset Detect mask */ ++ unsigned rst_det_msk:1; ++ /** Disconnect Detected */ ++ unsigned disconn_det:1; ++ /** Disconnect Detect mask */ ++ unsigned disconn_det_msk:1; ++ /** Connect Detected*/ ++ unsigned connect_det:1; ++ /** Connect Detected Mask*/ ++ unsigned connect_det_msk:1; ++ /** SRP Detected */ ++ unsigned srp_det:1; ++ /** SRP Detect mask */ ++ unsigned srp_det_msk:1; ++ /** Status Change Interrupt */ ++ unsigned sts_chngint:1; ++ /** Status Change Interrupt Mask */ ++ unsigned sts_chngint_msk:1; ++ /** Line State */ ++ unsigned linestate:2; ++ /** Indicates current mode(status of IDDIG signal) */ ++ unsigned idsts:1; ++ /** B Session Valid signal status*/ ++ unsigned bsessvld:1; ++ /** ADP Event Detected */ ++ unsigned adp_int:1; ++ /** Multi Valued ID pin */ ++ unsigned mult_val_id_bc:5; ++ /** Reserved 24_31 */ ++ unsigned reserved29_31:3; ++ } b; ++} gpwrdn_data_t; ++ ++#endif +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/Makefile linux-raspberry-pi/drivers/usb/host/dwc_otg/Makefile +--- linux-3.10.33/drivers/usb/host/dwc_otg/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/Makefile 2014-03-13 12:46:39.512097981 +0100 +@@ -0,0 +1,81 @@ ++# ++# Makefile for DWC_otg Highspeed USB controller driver ++# ++ ++ifneq ($(KERNELRELEASE),) ++ ++# Use the BUS_INTERFACE variable to compile the software for either ++# PCI(PCI_INTERFACE) or LM(LM_INTERFACE) bus. ++ifeq ($(BUS_INTERFACE),) ++# BUS_INTERFACE = -DPCI_INTERFACE ++# BUS_INTERFACE = -DLM_INTERFACE ++ BUS_INTERFACE = -DPLATFORM_INTERFACE ++endif ++ ++#ccflags-y += -DDEBUG ++#ccflags-y += -DDWC_OTG_DEBUGLEV=1 # reduce common debug msgs ++ ++# Use one of the following flags to compile the software in host-only or ++# device-only mode. ++#ccflags-y += -DDWC_HOST_ONLY ++#ccflags-y += -DDWC_DEVICE_ONLY ++ ++ccflags-y += -Dlinux -DDWC_HS_ELECT_TST ++#ccflags-y += -DDWC_EN_ISOC ++ccflags-y += -I$(obj)/../dwc_common_port ++#ccflags-y += -I$(PORTLIB) ++ccflags-y += -DDWC_LINUX ++ccflags-y += $(CFI) ++ccflags-y += $(BUS_INTERFACE) ++#ccflags-y += -DDWC_DEV_SRPCAP ++ ++obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o ++ ++dwc_otg-objs := dwc_otg_driver.o dwc_otg_attr.o ++dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o ++dwc_otg-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o ++dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o ++dwc_otg-objs += dwc_otg_adp.o ++dwc_otg-objs += dwc_otg_mphi_fix.o ++ifneq ($(CFI),) ++dwc_otg-objs += dwc_otg_cfi.o ++endif ++ ++kernrelwd := $(subst ., ,$(KERNELRELEASE)) ++kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd)) ++ ++ifneq ($(kernrel3),2.6.20) ++ccflags-y += $(CPPFLAGS) ++endif ++ ++else ++ ++PWD := $(shell pwd) ++PORTLIB := $(PWD)/../dwc_common_port ++ ++# Command paths ++CTAGS := $(CTAGS) ++DOXYGEN := $(DOXYGEN) ++ ++default: portlib ++ $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules ++ ++install: default ++ $(MAKE) -C$(KDIR) M=$(PORTLIB) modules_install ++ $(MAKE) -C$(KDIR) M=$(PWD) modules_install ++ ++portlib: ++ $(MAKE) -C$(KDIR) M=$(PORTLIB) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules ++ cp $(PORTLIB)/Module.symvers $(PWD)/ ++ ++docs: $(wildcard *.[hc]) doc/doxygen.cfg ++ $(DOXYGEN) doc/doxygen.cfg ++ ++tags: $(wildcard *.[hc]) ++ $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h) ++ ++ ++clean: ++ rm -rf *.o *.ko .*cmd *.mod.c .tmp_versions Module.symvers ++ ++endif +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm linux-raspberry-pi/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm +--- linux-3.10.33/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/test/dwc_otg_test.pm 2014-03-13 12:46:39.560098077 +0100 +@@ -0,0 +1,337 @@ ++package dwc_otg_test; ++ ++use strict; ++use Exporter (); ++ ++use vars qw(@ISA @EXPORT ++$sysfsdir $paramdir $errors $params ++); ++ ++@ISA = qw(Exporter); ++ ++# ++# Globals ++# ++$sysfsdir = "/sys/devices/lm0"; ++$paramdir = "/sys/module/dwc_otg"; ++$errors = 0; ++ ++$params = [ ++ { ++ NAME => "otg_cap", ++ DEFAULT => 0, ++ ENUM => [], ++ LOW => 0, ++ HIGH => 2 ++ }, ++ { ++ NAME => "dma_enable", ++ DEFAULT => 0, ++ ENUM => [], ++ LOW => 0, ++ HIGH => 1 ++ }, ++ { ++ NAME => "dma_burst_size", ++ DEFAULT => 32, ++ ENUM => [1, 4, 8, 16, 32, 64, 128, 256], ++ LOW => 1, ++ HIGH => 256 ++ }, ++ { ++ NAME => "host_speed", ++ DEFAULT => 0, ++ ENUM => [], ++ LOW => 0, ++ HIGH => 1 ++ }, ++ { ++ NAME => "host_support_fs_ls_low_power", ++ DEFAULT => 0, ++ ENUM => [], ++ LOW => 0, ++ HIGH => 1 ++ }, ++ { ++ NAME => "host_ls_low_power_phy_clk", ++ DEFAULT => 0, ++ ENUM => [], ++ LOW => 0, ++ HIGH => 1 ++ }, ++ { ++ NAME => "dev_speed", ++ DEFAULT => 0, ++ ENUM => [], ++ LOW => 0, ++ HIGH => 1 ++ }, ++ { ++ NAME => "enable_dynamic_fifo", ++ DEFAULT => 1, ++ ENUM => [], ++ LOW => 0, ++ HIGH => 1 ++ }, ++ { ++ NAME => "data_fifo_size", ++ DEFAULT => 8192, ++ ENUM => [], ++ LOW => 32, ++ HIGH => 32768 ++ }, ++ { ++ NAME => "dev_rx_fifo_size", ++ DEFAULT => 1064, ++ ENUM => [], ++ LOW => 16, ++ HIGH => 32768 ++ }, ++ { ++ NAME => "dev_nperio_tx_fifo_size", ++ DEFAULT => 1024, ++ ENUM => [], ++ LOW => 16, ++ HIGH => 32768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_1", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_2", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_3", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_4", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_5", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_6", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_7", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_8", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_9", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_10", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_11", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_12", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_13", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_14", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "dev_perio_tx_fifo_size_15", ++ DEFAULT => 256, ++ ENUM => [], ++ LOW => 4, ++ HIGH => 768 ++ }, ++ { ++ NAME => "host_rx_fifo_size", ++ DEFAULT => 1024, ++ ENUM => [], ++ LOW => 16, ++ HIGH => 32768 ++ }, ++ { ++ NAME => "host_nperio_tx_fifo_size", ++ DEFAULT => 1024, ++ ENUM => [], ++ LOW => 16, ++ HIGH => 32768 ++ }, ++ { ++ NAME => "host_perio_tx_fifo_size", ++ DEFAULT => 1024, ++ ENUM => [], ++ LOW => 16, ++ HIGH => 32768 ++ }, ++ { ++ NAME => "max_transfer_size", ++ DEFAULT => 65535, ++ ENUM => [], ++ LOW => 2047, ++ HIGH => 65535 ++ }, ++ { ++ NAME => "max_packet_count", ++ DEFAULT => 511, ++ ENUM => [], ++ LOW => 15, ++ HIGH => 511 ++ }, ++ { ++ NAME => "host_channels", ++ DEFAULT => 12, ++ ENUM => [], ++ LOW => 1, ++ HIGH => 16 ++ }, ++ { ++ NAME => "dev_endpoints", ++ DEFAULT => 6, ++ ENUM => [], ++ LOW => 1, ++ HIGH => 15 ++ }, ++ { ++ NAME => "phy_type", ++ DEFAULT => 1, ++ ENUM => [], ++ LOW => 0, ++ HIGH => 2 ++ }, ++ { ++ NAME => "phy_utmi_width", ++ DEFAULT => 16, ++ ENUM => [8, 16], ++ LOW => 8, ++ HIGH => 16 ++ }, ++ { ++ NAME => "phy_ulpi_ddr", ++ DEFAULT => 0, ++ ENUM => [], ++ LOW => 0, ++ HIGH => 1 ++ }, ++ ]; ++ ++ ++# ++# ++sub check_arch { ++ $_ = `uname -m`; ++ chomp; ++ unless (m/armv4tl/) { ++ warn "# \n# Can't execute on $_. Run on integrator platform.\n# \n"; ++ return 0; ++ } ++ return 1; ++} ++ ++# ++# ++sub load_module { ++ my $params = shift; ++ print "\nRemoving Module\n"; ++ system "rmmod dwc_otg"; ++ print "Loading Module\n"; ++ if ($params ne "") { ++ print "Module Parameters: $params\n"; ++ } ++ if (system("modprobe dwc_otg $params")) { ++ warn "Unable to load module\n"; ++ return 0; ++ } ++ return 1; ++} ++ ++# ++# ++sub test_status { ++ my $arg = shift; ++ ++ print "\n"; ++ ++ if (defined $arg) { ++ warn "WARNING: $arg\n"; ++ } ++ ++ if ($errors > 0) { ++ warn "TEST FAILED with $errors errors\n"; ++ return 0; ++ } else { ++ print "TEST PASSED\n"; ++ return 0 if (defined $arg); ++ } ++ return 1; ++} ++ ++# ++# ++@EXPORT = qw( ++$sysfsdir ++$paramdir ++$params ++$errors ++check_arch ++load_module ++test_status ++); ++ ++1; +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/test/Makefile linux-raspberry-pi/drivers/usb/host/dwc_otg/test/Makefile +--- linux-3.10.33/drivers/usb/host/dwc_otg/test/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/test/Makefile 2014-03-13 12:46:39.560098077 +0100 +@@ -0,0 +1,16 @@ ++ ++PERL=/usr/bin/perl ++PL_TESTS=test_sysfs.pl test_mod_param.pl ++ ++.PHONY : test ++test : perl_tests ++ ++perl_tests : ++ @echo ++ @echo Running perl tests ++ @for test in $(PL_TESTS); do \ ++ if $(PERL) ./$$test ; then \ ++ echo "=======> $$test, PASSED" ; \ ++ else echo "=======> $$test, FAILED" ; \ ++ fi \ ++ done +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/test/test_mod_param.pl linux-raspberry-pi/drivers/usb/host/dwc_otg/test/test_mod_param.pl +--- linux-3.10.33/drivers/usb/host/dwc_otg/test/test_mod_param.pl 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/test/test_mod_param.pl 2014-03-13 12:46:39.560098077 +0100 +@@ -0,0 +1,133 @@ ++#!/usr/bin/perl -w ++# ++# Run this program on the integrator. ++# ++# - Tests module parameter default values. ++# - Tests setting of valid module parameter values via modprobe. ++# - Tests invalid module parameter values. ++# ----------------------------------------------------------------------------- ++use strict; ++use dwc_otg_test; ++ ++check_arch() or die; ++ ++# ++# ++sub test { ++ my ($param,$expected) = @_; ++ my $value = get($param); ++ ++ if ($value == $expected) { ++ print "$param = $value, okay\n"; ++ } ++ ++ else { ++ warn "ERROR: value of $param != $expected, $value\n"; ++ $errors ++; ++ } ++} ++ ++# ++# ++sub get { ++ my $param = shift; ++ my $tmp = `cat $paramdir/$param`; ++ chomp $tmp; ++ return $tmp; ++} ++ ++# ++# ++sub test_main { ++ ++ print "\nTesting Module Parameters\n"; ++ ++ load_module("") or die; ++ ++ # Test initial values ++ print "\nTesting Default Values\n"; ++ foreach (@{$params}) { ++ test ($_->{NAME}, $_->{DEFAULT}); ++ } ++ ++ # Test low value ++ print "\nTesting Low Value\n"; ++ my $cmd_params = ""; ++ foreach (@{$params}) { ++ $cmd_params = $cmd_params . "$_->{NAME}=$_->{LOW} "; ++ } ++ load_module($cmd_params) or die; ++ ++ foreach (@{$params}) { ++ test ($_->{NAME}, $_->{LOW}); ++ } ++ ++ # Test high value ++ print "\nTesting High Value\n"; ++ $cmd_params = ""; ++ foreach (@{$params}) { ++ $cmd_params = $cmd_params . "$_->{NAME}=$_->{HIGH} "; ++ } ++ load_module($cmd_params) or die; ++ ++ foreach (@{$params}) { ++ test ($_->{NAME}, $_->{HIGH}); ++ } ++ ++ # Test Enum ++ print "\nTesting Enumerated\n"; ++ foreach (@{$params}) { ++ if (defined $_->{ENUM}) { ++ my $value; ++ foreach $value (@{$_->{ENUM}}) { ++ $cmd_params = "$_->{NAME}=$value"; ++ load_module($cmd_params) or die; ++ test ($_->{NAME}, $value); ++ } ++ } ++ } ++ ++ # Test Invalid Values ++ print "\nTesting Invalid Values\n"; ++ $cmd_params = ""; ++ foreach (@{$params}) { ++ $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{LOW}-1; ++ } ++ load_module($cmd_params) or die; ++ ++ foreach (@{$params}) { ++ test ($_->{NAME}, $_->{DEFAULT}); ++ } ++ ++ $cmd_params = ""; ++ foreach (@{$params}) { ++ $cmd_params = $cmd_params . sprintf "$_->{NAME}=%d ", $_->{HIGH}+1; ++ } ++ load_module($cmd_params) or die; ++ ++ foreach (@{$params}) { ++ test ($_->{NAME}, $_->{DEFAULT}); ++ } ++ ++ print "\nTesting Enumerated\n"; ++ foreach (@{$params}) { ++ if (defined $_->{ENUM}) { ++ my $value; ++ foreach $value (@{$_->{ENUM}}) { ++ $value = $value + 1; ++ $cmd_params = "$_->{NAME}=$value"; ++ load_module($cmd_params) or die; ++ test ($_->{NAME}, $_->{DEFAULT}); ++ $value = $value - 2; ++ $cmd_params = "$_->{NAME}=$value"; ++ load_module($cmd_params) or die; ++ test ($_->{NAME}, $_->{DEFAULT}); ++ } ++ } ++ } ++ ++ test_status() or die; ++} ++ ++test_main(); ++0; +diff -Nur linux-3.10.33/drivers/usb/host/dwc_otg/test/test_sysfs.pl linux-raspberry-pi/drivers/usb/host/dwc_otg/test/test_sysfs.pl +--- linux-3.10.33/drivers/usb/host/dwc_otg/test/test_sysfs.pl 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/dwc_otg/test/test_sysfs.pl 2014-03-13 12:46:39.560098077 +0100 +@@ -0,0 +1,193 @@ ++#!/usr/bin/perl -w ++# ++# Run this program on the integrator ++# - Tests select sysfs attributes. ++# - Todo ... test more attributes, hnp/srp, buspower/bussuspend, etc. ++# ----------------------------------------------------------------------------- ++use strict; ++use dwc_otg_test; ++ ++check_arch() or die; ++ ++# ++# ++sub test { ++ my ($attr,$expected) = @_; ++ my $string = get($attr); ++ ++ if ($string eq $expected) { ++ printf("$attr = $string, okay\n"); ++ } ++ else { ++ warn "ERROR: value of $attr != $expected, $string\n"; ++ $errors ++; ++ } ++} ++ ++# ++# ++sub set { ++ my ($reg, $value) = @_; ++ system "echo $value > $sysfsdir/$reg"; ++} ++ ++# ++# ++sub get { ++ my $attr = shift; ++ my $string = `cat $sysfsdir/$attr`; ++ chomp $string; ++ if ($string =~ m/\s\=\s/) { ++ my $tmp; ++ ($tmp, $string) = split /\s=\s/, $string; ++ } ++ return $string; ++} ++ ++# ++# ++sub test_main { ++ print("\nTesting Sysfs Attributes\n"); ++ ++ load_module("") or die; ++ ++ # Test initial values of regoffset/regvalue/guid/gsnpsid ++ print("\nTesting Default Values\n"); ++ ++ test("regoffset", "0xffffffff"); ++ test("regvalue", "invalid offset"); ++ test("guid", "0x12345678"); # this will fail if it has been changed ++ test("gsnpsid", "0x4f54200a"); ++ ++ # Test operation of regoffset/regvalue ++ print("\nTesting regoffset\n"); ++ set('regoffset', '5a5a5a5a'); ++ test("regoffset", "0xffffffff"); ++ ++ set('regoffset', '0'); ++ test("regoffset", "0x00000000"); ++ ++ set('regoffset', '40000'); ++ test("regoffset", "0x00000000"); ++ ++ set('regoffset', '3ffff'); ++ test("regoffset", "0x0003ffff"); ++ ++ set('regoffset', '1'); ++ test("regoffset", "0x00000001"); ++ ++ print("\nTesting regvalue\n"); ++ set('regoffset', '3c'); ++ test("regvalue", "0x12345678"); ++ set('regvalue', '5a5a5a5a'); ++ test("regvalue", "0x5a5a5a5a"); ++ set('regvalue','a5a5a5a5'); ++ test("regvalue", "0xa5a5a5a5"); ++ set('guid','12345678'); ++ ++ # Test HNP Capable ++ print("\nTesting HNP Capable bit\n"); ++ set('hnpcapable', '1'); ++ test("hnpcapable", "0x1"); ++ set('hnpcapable','0'); ++ test("hnpcapable", "0x0"); ++ ++ set('regoffset','0c'); ++ ++ my $old = get('gusbcfg'); ++ print("setting hnpcapable\n"); ++ set('hnpcapable', '1'); ++ test("hnpcapable", "0x1"); ++ test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<9))); ++ test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<9))); ++ ++ $old = get('gusbcfg'); ++ print("clearing hnpcapable\n"); ++ set('hnpcapable', '0'); ++ test("hnpcapable", "0x0"); ++ test ('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<9))); ++ test ('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<9))); ++ ++ # Test SRP Capable ++ print("\nTesting SRP Capable bit\n"); ++ set('srpcapable', '1'); ++ test("srpcapable", "0x1"); ++ set('srpcapable','0'); ++ test("srpcapable", "0x0"); ++ ++ set('regoffset','0c'); ++ ++ $old = get('gusbcfg'); ++ print("setting srpcapable\n"); ++ set('srpcapable', '1'); ++ test("srpcapable", "0x1"); ++ test('gusbcfg', sprintf "0x%08x", (oct ($old) | (1<<8))); ++ test('regvalue', sprintf "0x%08x", (oct ($old) | (1<<8))); ++ ++ $old = get('gusbcfg'); ++ print("clearing srpcapable\n"); ++ set('srpcapable', '0'); ++ test("srpcapable", "0x0"); ++ test('gusbcfg', sprintf "0x%08x", oct ($old) & (~(1<<8))); ++ test('regvalue', sprintf "0x%08x", oct ($old) & (~(1<<8))); ++ ++ # Test GGPIO ++ print("\nTesting GGPIO\n"); ++ set('ggpio','5a5a5a5a'); ++ test('ggpio','0x5a5a0000'); ++ set('ggpio','a5a5a5a5'); ++ test('ggpio','0xa5a50000'); ++ set('ggpio','11110000'); ++ test('ggpio','0x11110000'); ++ set('ggpio','00001111'); ++ test('ggpio','0x00000000'); ++ ++ # Test DEVSPEED ++ print("\nTesting DEVSPEED\n"); ++ set('regoffset','800'); ++ $old = get('regvalue'); ++ set('devspeed','0'); ++ test('devspeed','0x0'); ++ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3))); ++ set('devspeed','1'); ++ test('devspeed','0x1'); ++ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1)); ++ set('devspeed','2'); ++ test('devspeed','0x2'); ++ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 2)); ++ set('devspeed','3'); ++ test('devspeed','0x3'); ++ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 3)); ++ set('devspeed','4'); ++ test('devspeed','0x0'); ++ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3))); ++ set('devspeed','5'); ++ test('devspeed','0x1'); ++ test('regvalue',sprintf("0x%08x", oct($old) & ~(0x3) | 1)); ++ ++ ++ # mode Returns the current mode:0 for device mode1 for host mode Read ++ # hnp Initiate the Host Negotiation Protocol. Read returns the status. Read/Write ++ # srp Initiate the Session Request Protocol. Read returns the status. Read/Write ++ # buspower Get or Set the Power State of the bus (0 - Off or 1 - On) Read/Write ++ # bussuspend Suspend the USB bus. Read/Write ++ # busconnected Get the connection status of the bus Read ++ ++ # gotgctl Get or set the Core Control Status Register. Read/Write ++ ## gusbcfg Get or set the Core USB Configuration Register Read/Write ++ # grxfsiz Get or set the Receive FIFO Size Register Read/Write ++ # gnptxfsiz Get or set the non-periodic Transmit Size Register Read/Write ++ # gpvndctl Get or set the PHY Vendor Control Register Read/Write ++ ## ggpio Get the value in the lower 16-bits of the General Purpose IO Register or Set the upper 16 bits. Read/Write ++ ## guid Get or set the value of the User ID Register Read/Write ++ ## gsnpsid Get the value of the Synopsys ID Regester Read ++ ## devspeed Get or set the device speed setting in the DCFG register Read/Write ++ # enumspeed Gets the device enumeration Speed. Read ++ # hptxfsiz Get the value of the Host Periodic Transmit FIFO Read ++ # hprt0 Get or Set the value in the Host Port Control and Status Register Read/Write ++ ++ test_status("TEST NYI") or die; ++} ++ ++test_main(); ++0; +diff -Nur linux-3.10.33/drivers/usb/host/Kconfig linux-raspberry-pi/drivers/usb/host/Kconfig +--- linux-3.10.33/drivers/usb/host/Kconfig 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/Kconfig 2014-03-13 12:46:38.980096914 +0100 +@@ -663,6 +663,19 @@ + To compile this driver a module, choose M here: the module + will be called "hwa-hc". + ++config USB_DWCOTG ++ tristate "Synopsis DWC host support" ++ depends on USB ++ help ++ The Synopsis DWC controller is a dual-role ++ host/peripheral/OTG ("On The Go") USB controllers. ++ ++ Enable this option to support this IP in host controller mode. ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ modules built will be called dwc_otg and dwc_common_port. ++ + config USB_IMX21_HCD + tristate "i.MX21 HCD support" + depends on ARM && ARCH_MXC +diff -Nur linux-3.10.33/drivers/usb/host/Makefile linux-raspberry-pi/drivers/usb/host/Makefile +--- linux-3.10.33/drivers/usb/host/Makefile 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/host/Makefile 2014-03-13 12:46:38.980096914 +0100 +@@ -47,6 +47,8 @@ + obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o + obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o + obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o ++ ++obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/ + obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o + obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o + obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o +diff -Nur linux-3.10.33/drivers/usb/Makefile linux-raspberry-pi/drivers/usb/Makefile +--- linux-3.10.33/drivers/usb/Makefile 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/usb/Makefile 2014-03-13 12:46:38.904096761 +0100 +@@ -23,6 +23,7 @@ + obj-$(CONFIG_USB_R8A66597_HCD) += host/ + obj-$(CONFIG_USB_HWA_HCD) += host/ + obj-$(CONFIG_USB_ISP1760_HCD) += host/ ++obj-$(CONFIG_USB_DWCOTG) += host/ + obj-$(CONFIG_USB_IMX21_HCD) += host/ + obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/ + +diff -Nur linux-3.10.33/drivers/video/bcm2708_fb.c linux-raspberry-pi/drivers/video/bcm2708_fb.c +--- linux-3.10.33/drivers/video/bcm2708_fb.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/video/bcm2708_fb.c 2014-03-13 12:46:40.304099570 +0100 +@@ -0,0 +1,763 @@ ++/* ++ * linux/drivers/video/bcm2708_fb.c ++ * ++ * Copyright (C) 2010 Broadcom ++ * ++ * 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. ++ * ++ * Broadcom simple framebuffer driver ++ * ++ * This file is derived from cirrusfb.c ++ * Copyright 1999-2001 Jeff Garzik ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#ifdef BCM2708_FB_DEBUG ++#define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__) ++#else ++#define print_debug(fmt,...) ++#endif ++ ++/* This is limited to 16 characters when displayed by X startup */ ++static const char *bcm2708_name = "BCM2708 FB"; ++ ++#define DRIVER_NAME "bcm2708_fb" ++ ++static u32 dma_busy_wait_threshold = 1<<15; ++module_param(dma_busy_wait_threshold, int, 0644); ++MODULE_PARM_DESC(dma_busy_wait_threshold, "Busy-wait for DMA completion below this area"); ++ ++static int fbswap = 0; /* module parameter */ ++ ++/* this data structure describes each frame buffer device we find */ ++ ++struct fbinfo_s { ++ u32 xres, yres, xres_virtual, yres_virtual; ++ u32 pitch, bpp; ++ u32 xoffset, yoffset; ++ u32 base; ++ u32 screen_size; ++ u16 cmap[256]; ++}; ++ ++struct bcm2708_fb_stats { ++ struct debugfs_regset32 regset; ++ u32 dma_copies; ++ u32 dma_irqs; ++}; ++ ++struct bcm2708_fb { ++ struct fb_info fb; ++ struct platform_device *dev; ++ struct fbinfo_s *info; ++ dma_addr_t dma; ++ u32 cmap[16]; ++ int dma_chan; ++ int dma_irq; ++ void __iomem *dma_chan_base; ++ void *cb_base; /* DMA control blocks */ ++ dma_addr_t cb_handle; ++ struct dentry *debugfs_dir; ++ wait_queue_head_t dma_waitq; ++ struct bcm2708_fb_stats stats; ++}; ++ ++#define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb) ++ ++static void bcm2708_fb_debugfs_deinit(struct bcm2708_fb *fb) ++{ ++ debugfs_remove_recursive(fb->debugfs_dir); ++ fb->debugfs_dir = NULL; ++} ++ ++static int bcm2708_fb_debugfs_init(struct bcm2708_fb *fb) ++{ ++ static struct debugfs_reg32 stats_registers[] = { ++ { ++ "dma_copies", ++ offsetof(struct bcm2708_fb_stats, dma_copies) ++ }, ++ { ++ "dma_irqs", ++ offsetof(struct bcm2708_fb_stats, dma_irqs) ++ }, ++ }; ++ ++ fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL); ++ if (!fb->debugfs_dir) { ++ pr_warn("%s: could not create debugfs entry\n", ++ __func__); ++ return -EFAULT; ++ } ++ ++ fb->stats.regset.regs = stats_registers; ++ fb->stats.regset.nregs = ARRAY_SIZE(stats_registers); ++ fb->stats.regset.base = &fb->stats; ++ ++ if (!debugfs_create_regset32( ++ "stats", 0444, fb->debugfs_dir, &fb->stats.regset)) { ++ pr_warn("%s: could not create statistics registers\n", ++ __func__); ++ goto fail; ++ } ++ return 0; ++ ++fail: ++ bcm2708_fb_debugfs_deinit(fb); ++ return -EFAULT; ++} ++ ++static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var) ++{ ++ int ret = 0; ++ ++ memset(&var->transp, 0, sizeof(var->transp)); ++ ++ var->red.msb_right = 0; ++ var->green.msb_right = 0; ++ var->blue.msb_right = 0; ++ ++ switch (var->bits_per_pixel) { ++ case 1: ++ case 2: ++ case 4: ++ case 8: ++ var->red.length = var->bits_per_pixel; ++ var->red.offset = 0; ++ var->green.length = var->bits_per_pixel; ++ var->green.offset = 0; ++ var->blue.length = var->bits_per_pixel; ++ var->blue.offset = 0; ++ break; ++ case 16: ++ var->red.length = 5; ++ var->blue.length = 5; ++ /* ++ * Green length can be 5 or 6 depending whether ++ * we're operating in RGB555 or RGB565 mode. ++ */ ++ if (var->green.length != 5 && var->green.length != 6) ++ var->green.length = 6; ++ break; ++ case 24: ++ var->red.length = 8; ++ var->blue.length = 8; ++ var->green.length = 8; ++ break; ++ case 32: ++ var->red.length = 8; ++ var->green.length = 8; ++ var->blue.length = 8; ++ var->transp.length = 8; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ /* ++ * >= 16bpp displays have separate colour component bitfields ++ * encoded in the pixel data. Calculate their position from ++ * the bitfield length defined above. ++ */ ++ if (ret == 0 && var->bits_per_pixel >= 24 && fbswap) { ++ var->blue.offset = 0; ++ var->green.offset = var->blue.offset + var->blue.length; ++ var->red.offset = var->green.offset + var->green.length; ++ var->transp.offset = var->red.offset + var->red.length; ++ } else if (ret == 0 && var->bits_per_pixel >= 24) { ++ var->red.offset = 0; ++ var->green.offset = var->red.offset + var->red.length; ++ var->blue.offset = var->green.offset + var->green.length; ++ var->transp.offset = var->blue.offset + var->blue.length; ++ } else if (ret == 0 && var->bits_per_pixel >= 16) { ++ var->blue.offset = 0; ++ var->green.offset = var->blue.offset + var->blue.length; ++ var->red.offset = var->green.offset + var->green.length; ++ var->transp.offset = var->red.offset + var->red.length; ++ } ++ ++ return ret; ++} ++ ++static int bcm2708_fb_check_var(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ /* info input, var output */ ++ int yres; ++ ++ /* info input, var output */ ++ print_debug("bcm2708_fb_check_var info(%p) %dx%d (%dx%d), %d, %d\n", info, ++ info->var.xres, info->var.yres, info->var.xres_virtual, ++ info->var.yres_virtual, (int)info->screen_size, ++ info->var.bits_per_pixel); ++ print_debug("bcm2708_fb_check_var var(%p) %dx%d (%dx%d), %d\n", var, ++ var->xres, var->yres, var->xres_virtual, var->yres_virtual, ++ var->bits_per_pixel); ++ ++ if (!var->bits_per_pixel) ++ var->bits_per_pixel = 16; ++ ++ if (bcm2708_fb_set_bitfields(var) != 0) { ++ pr_err("bcm2708_fb_check_var: invalid bits_per_pixel %d\n", ++ var->bits_per_pixel); ++ return -EINVAL; ++ } ++ ++ ++ if (var->xres_virtual < var->xres) ++ var->xres_virtual = var->xres; ++ /* use highest possible virtual resolution */ ++ if (var->yres_virtual == -1) { ++ var->yres_virtual = 480; ++ ++ pr_err ++ ("bcm2708_fb_check_var: virtual resolution set to maximum of %dx%d\n", ++ var->xres_virtual, var->yres_virtual); ++ } ++ if (var->yres_virtual < var->yres) ++ var->yres_virtual = var->yres; ++ ++ if (var->xoffset < 0) ++ var->xoffset = 0; ++ if (var->yoffset < 0) ++ var->yoffset = 0; ++ ++ /* truncate xoffset and yoffset to maximum if too high */ ++ if (var->xoffset > var->xres_virtual - var->xres) ++ var->xoffset = var->xres_virtual - var->xres - 1; ++ if (var->yoffset > var->yres_virtual - var->yres) ++ var->yoffset = var->yres_virtual - var->yres - 1; ++ ++ yres = var->yres; ++ if (var->vmode & FB_VMODE_DOUBLE) ++ yres *= 2; ++ else if (var->vmode & FB_VMODE_INTERLACED) ++ yres = (yres + 1) / 2; ++ ++ if (var->xres * yres > 1920 * 1200) { ++ pr_err("bcm2708_fb_check_var: ERROR: Pixel size >= 1920x1200; " ++ "special treatment required! (TODO)\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int bcm2708_fb_set_par(struct fb_info *info) ++{ ++ uint32_t val = 0; ++ struct bcm2708_fb *fb = to_bcm2708(info); ++ volatile struct fbinfo_s *fbinfo = fb->info; ++ fbinfo->xres = info->var.xres; ++ fbinfo->yres = info->var.yres; ++ fbinfo->xres_virtual = info->var.xres_virtual; ++ fbinfo->yres_virtual = info->var.yres_virtual; ++ fbinfo->bpp = info->var.bits_per_pixel; ++ fbinfo->xoffset = info->var.xoffset; ++ fbinfo->yoffset = info->var.yoffset; ++ fbinfo->base = 0; /* filled in by VC */ ++ fbinfo->pitch = 0; /* filled in by VC */ ++ ++ print_debug("bcm2708_fb_set_par info(%p) %dx%d (%dx%d), %d, %d\n", info, ++ info->var.xres, info->var.yres, info->var.xres_virtual, ++ info->var.yres_virtual, (int)info->screen_size, ++ info->var.bits_per_pixel); ++ ++ /* ensure last write to fbinfo is visible to GPU */ ++ wmb(); ++ ++ /* inform vc about new framebuffer */ ++ bcm_mailbox_write(MBOX_CHAN_FB, fb->dma); ++ ++ /* TODO: replace fb driver with vchiq version */ ++ /* wait for response */ ++ bcm_mailbox_read(MBOX_CHAN_FB, &val); ++ ++ /* ensure GPU writes are visible to us */ ++ rmb(); ++ ++ if (val == 0) { ++ fb->fb.fix.line_length = fbinfo->pitch; ++ ++ if (info->var.bits_per_pixel <= 8) ++ fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ else ++ fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; ++ ++ fb->fb.fix.smem_start = fbinfo->base; ++ fb->fb.fix.smem_len = fbinfo->pitch * fbinfo->yres_virtual; ++ fb->fb.screen_size = fbinfo->screen_size; ++ if (fb->fb.screen_base) ++ iounmap(fb->fb.screen_base); ++ fb->fb.screen_base = ++ (void *)ioremap_wc(fb->fb.fix.smem_start, fb->fb.screen_size); ++ if (!fb->fb.screen_base) { ++ /* the console may currently be locked */ ++ console_trylock(); ++ console_unlock(); ++ ++ BUG(); /* what can we do here */ ++ } ++ } ++ print_debug ++ ("BCM2708FB: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d success=%d\n", ++ (void *)fb->fb.screen_base, (void *)fb->fb.fix.smem_start, ++ fbinfo->xres, fbinfo->yres, fbinfo->bpp, ++ fbinfo->pitch, (int)fb->fb.screen_size, val); ++ ++ return val; ++} ++ ++static inline u32 convert_bitfield(int val, struct fb_bitfield *bf) ++{ ++ unsigned int mask = (1 << bf->length) - 1; ++ ++ return (val >> (16 - bf->length) & mask) << bf->offset; ++} ++ ++ ++static int bcm2708_fb_setcolreg(unsigned int regno, unsigned int red, ++ unsigned int green, unsigned int blue, ++ unsigned int transp, struct fb_info *info) ++{ ++ struct bcm2708_fb *fb = to_bcm2708(info); ++ ++ /*print_debug("BCM2708FB: setcolreg %d:(%02x,%02x,%02x,%02x) %x\n", regno, red, green, blue, transp, fb->fb.fix.visual);*/ ++ if (fb->fb.var.bits_per_pixel <= 8) { ++ if (regno < 256) { ++ /* blue [0:4], green [5:10], red [11:15] */ ++ fb->info->cmap[regno] = ((red >> (16-5)) & 0x1f) << 11 | ++ ((green >> (16-6)) & 0x3f) << 5 | ++ ((blue >> (16-5)) & 0x1f) << 0; ++ } ++ /* Hack: we need to tell GPU the palette has changed, but currently bcm2708_fb_set_par takes noticable time when called for every (256) colour */ ++ /* So just call it for what looks like the last colour in a list for now. */ ++ if (regno == 15 || regno == 255) ++ bcm2708_fb_set_par(info); ++ } else if (regno < 16) { ++ fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) | ++ convert_bitfield(blue, &fb->fb.var.blue) | ++ convert_bitfield(green, &fb->fb.var.green) | ++ convert_bitfield(red, &fb->fb.var.red); ++ } ++ return regno > 255; ++} ++ ++static int bcm2708_fb_blank(int blank_mode, struct fb_info *info) ++{ ++ /*print_debug("bcm2708_fb_blank\n"); */ ++ return -1; ++} ++ ++static void bcm2708_fb_fillrect(struct fb_info *info, ++ const struct fb_fillrect *rect) ++{ ++ /* (is called) print_debug("bcm2708_fb_fillrect\n"); */ ++ cfb_fillrect(info, rect); ++} ++ ++/* A helper function for configuring dma control block */ ++static void set_dma_cb(struct bcm2708_dma_cb *cb, ++ int burst_size, ++ dma_addr_t dst, ++ int dst_stride, ++ dma_addr_t src, ++ int src_stride, ++ int w, ++ int h) ++{ ++ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH | ++ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH | ++ BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE; ++ cb->dst = dst; ++ cb->src = src; ++ /* ++ * This is not really obvious from the DMA documentation, ++ * but the top 16 bits must be programmmed to "height -1" ++ * and not "height" in 2D mode. ++ */ ++ cb->length = ((h - 1) << 16) | w; ++ cb->stride = ((dst_stride - w) << 16) | (u16)(src_stride - w); ++ cb->pad[0] = 0; ++ cb->pad[1] = 0; ++} ++ ++static void bcm2708_fb_copyarea(struct fb_info *info, ++ const struct fb_copyarea *region) ++{ ++ struct bcm2708_fb *fb = to_bcm2708(info); ++ struct bcm2708_dma_cb *cb = fb->cb_base; ++ int bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3; ++ /* Channel 0 supports larger bursts and is a bit faster */ ++ int burst_size = (fb->dma_chan == 0) ? 8 : 2; ++ int pixels = region->width * region->height; ++ ++ /* Fallback to cfb_copyarea() if we don't like something */ ++ if (bytes_per_pixel > 4 || ++ info->var.xres * info->var.yres > 1920 * 1200 || ++ region->width <= 0 || region->width > info->var.xres || ++ region->height <= 0 || region->height > info->var.yres || ++ region->sx < 0 || region->sx >= info->var.xres || ++ region->sy < 0 || region->sy >= info->var.yres || ++ region->dx < 0 || region->dx >= info->var.xres || ++ region->dy < 0 || region->dy >= info->var.yres || ++ region->sx + region->width > info->var.xres || ++ region->dx + region->width > info->var.xres || ++ region->sy + region->height > info->var.yres || ++ region->dy + region->height > info->var.yres) { ++ cfb_copyarea(info, region); ++ return; ++ } ++ ++ if (region->dy == region->sy && region->dx > region->sx) { ++ /* ++ * A difficult case of overlapped copy. Because DMA can't ++ * copy individual scanlines in backwards direction, we need ++ * two-pass processing. We do it by programming a chain of dma ++ * control blocks in the first 16K part of the buffer and use ++ * the remaining 48K as the intermediate temporary scratch ++ * buffer. The buffer size is sufficient to handle up to ++ * 1920x1200 resolution at 32bpp pixel depth. ++ */ ++ int y; ++ dma_addr_t control_block_pa = fb->cb_handle; ++ dma_addr_t scratchbuf = fb->cb_handle + 16 * 1024; ++ int scanline_size = bytes_per_pixel * region->width; ++ int scanlines_per_cb = (64 * 1024 - 16 * 1024) / scanline_size; ++ ++ for (y = 0; y < region->height; y += scanlines_per_cb) { ++ dma_addr_t src = ++ fb->fb.fix.smem_start + ++ bytes_per_pixel * region->sx + ++ (region->sy + y) * fb->fb.fix.line_length; ++ dma_addr_t dst = ++ fb->fb.fix.smem_start + ++ bytes_per_pixel * region->dx + ++ (region->dy + y) * fb->fb.fix.line_length; ++ ++ if (region->height - y < scanlines_per_cb) ++ scanlines_per_cb = region->height - y; ++ ++ set_dma_cb(cb, burst_size, scratchbuf, scanline_size, ++ src, fb->fb.fix.line_length, ++ scanline_size, scanlines_per_cb); ++ control_block_pa += sizeof(struct bcm2708_dma_cb); ++ cb->next = control_block_pa; ++ cb++; ++ ++ set_dma_cb(cb, burst_size, dst, fb->fb.fix.line_length, ++ scratchbuf, scanline_size, ++ scanline_size, scanlines_per_cb); ++ control_block_pa += sizeof(struct bcm2708_dma_cb); ++ cb->next = control_block_pa; ++ cb++; ++ } ++ /* move the pointer back to the last dma control block */ ++ cb--; ++ } else { ++ /* A single dma control block is enough. */ ++ int sy, dy, stride; ++ if (region->dy <= region->sy) { ++ /* processing from top to bottom */ ++ dy = region->dy; ++ sy = region->sy; ++ stride = fb->fb.fix.line_length; ++ } else { ++ /* processing from bottom to top */ ++ dy = region->dy + region->height - 1; ++ sy = region->sy + region->height - 1; ++ stride = -fb->fb.fix.line_length; ++ } ++ set_dma_cb(cb, burst_size, ++ fb->fb.fix.smem_start + dy * fb->fb.fix.line_length + ++ bytes_per_pixel * region->dx, ++ stride, ++ fb->fb.fix.smem_start + sy * fb->fb.fix.line_length + ++ bytes_per_pixel * region->sx, ++ stride, ++ region->width * bytes_per_pixel, ++ region->height); ++ } ++ ++ /* end of dma control blocks chain */ ++ cb->next = 0; ++ ++ ++ if (pixels < dma_busy_wait_threshold) { ++ bcm_dma_start(fb->dma_chan_base, fb->cb_handle); ++ bcm_dma_wait_idle(fb->dma_chan_base); ++ } else { ++ void __iomem *dma_chan = fb->dma_chan_base; ++ cb->info |= BCM2708_DMA_INT_EN; ++ bcm_dma_start(fb->dma_chan_base, fb->cb_handle); ++ while (bcm_dma_is_busy(dma_chan)) { ++ wait_event_interruptible( ++ fb->dma_waitq, ++ !bcm_dma_is_busy(dma_chan)); ++ } ++ fb->stats.dma_irqs++; ++ } ++ fb->stats.dma_copies++; ++} ++ ++static void bcm2708_fb_imageblit(struct fb_info *info, ++ const struct fb_image *image) ++{ ++ /* (is called) print_debug("bcm2708_fb_imageblit\n"); */ ++ cfb_imageblit(info, image); ++} ++ ++static irqreturn_t bcm2708_fb_dma_irq(int irq, void *cxt) ++{ ++ struct bcm2708_fb *fb = cxt; ++ ++ /* FIXME: should read status register to check if this is ++ * actually interrupting us or not, in case this interrupt ++ * ever becomes shared amongst several DMA channels ++ * ++ * readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_IRQ; ++ */ ++ ++ /* acknowledge the interrupt */ ++ writel(BCM2708_DMA_INT, fb->dma_chan_base + BCM2708_DMA_CS); ++ ++ wake_up(&fb->dma_waitq); ++ return IRQ_HANDLED; ++} ++ ++static struct fb_ops bcm2708_fb_ops = { ++ .owner = THIS_MODULE, ++ .fb_check_var = bcm2708_fb_check_var, ++ .fb_set_par = bcm2708_fb_set_par, ++ .fb_setcolreg = bcm2708_fb_setcolreg, ++ .fb_blank = bcm2708_fb_blank, ++ .fb_fillrect = bcm2708_fb_fillrect, ++ .fb_copyarea = bcm2708_fb_copyarea, ++ .fb_imageblit = bcm2708_fb_imageblit, ++}; ++ ++static int fbwidth = 800; /* module parameter */ ++static int fbheight = 480; /* module parameter */ ++static int fbdepth = 16; /* module parameter */ ++ ++static int bcm2708_fb_register(struct bcm2708_fb *fb) ++{ ++ int ret; ++ dma_addr_t dma; ++ void *mem; ++ ++ mem = ++ dma_alloc_coherent(NULL, PAGE_ALIGN(sizeof(*fb->info)), &dma, ++ GFP_KERNEL); ++ ++ if (NULL == mem) { ++ pr_err(": unable to allocate fbinfo buffer\n"); ++ ret = -ENOMEM; ++ } else { ++ fb->info = (struct fbinfo_s *)mem; ++ fb->dma = dma; ++ } ++ fb->fb.fbops = &bcm2708_fb_ops; ++ fb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_COPYAREA; ++ fb->fb.pseudo_palette = fb->cmap; ++ ++ strncpy(fb->fb.fix.id, bcm2708_name, sizeof(fb->fb.fix.id)); ++ fb->fb.fix.type = FB_TYPE_PACKED_PIXELS; ++ fb->fb.fix.type_aux = 0; ++ fb->fb.fix.xpanstep = 0; ++ fb->fb.fix.ypanstep = 0; ++ fb->fb.fix.ywrapstep = 0; ++ fb->fb.fix.accel = FB_ACCEL_NONE; ++ ++ fb->fb.var.xres = fbwidth; ++ fb->fb.var.yres = fbheight; ++ fb->fb.var.xres_virtual = fbwidth; ++ fb->fb.var.yres_virtual = fbheight; ++ fb->fb.var.bits_per_pixel = fbdepth; ++ fb->fb.var.vmode = FB_VMODE_NONINTERLACED; ++ fb->fb.var.activate = FB_ACTIVATE_NOW; ++ fb->fb.var.nonstd = 0; ++ fb->fb.var.height = -1; /* height of picture in mm */ ++ fb->fb.var.width = -1; /* width of picture in mm */ ++ fb->fb.var.accel_flags = 0; ++ ++ fb->fb.monspecs.hfmin = 0; ++ fb->fb.monspecs.hfmax = 100000; ++ fb->fb.monspecs.vfmin = 0; ++ fb->fb.monspecs.vfmax = 400; ++ fb->fb.monspecs.dclkmin = 1000000; ++ fb->fb.monspecs.dclkmax = 100000000; ++ ++ bcm2708_fb_set_bitfields(&fb->fb.var); ++ init_waitqueue_head(&fb->dma_waitq); ++ ++ /* ++ * Allocate colourmap. ++ */ ++ ++ fb_set_var(&fb->fb, &fb->fb.var); ++ ++ print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n", fbwidth ++ fbheight, fbdepth, fbswap); ++ ++ ret = register_framebuffer(&fb->fb); ++ print_debug("BCM2708FB: register framebuffer (%d)\n", ret); ++ if (ret == 0) ++ goto out; ++ ++ print_debug("BCM2708FB: cannot register framebuffer (%d)\n", ret); ++out: ++ return ret; ++} ++ ++static int bcm2708_fb_probe(struct platform_device *dev) ++{ ++ struct bcm2708_fb *fb; ++ int ret; ++ ++ fb = kzalloc(sizeof(struct bcm2708_fb), GFP_KERNEL); ++ if (!fb) { ++ dev_err(&dev->dev, ++ "could not allocate new bcm2708_fb struct\n"); ++ ret = -ENOMEM; ++ goto free_region; ++ } ++ ++ bcm2708_fb_debugfs_init(fb); ++ ++ fb->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K, ++ &fb->cb_handle, GFP_KERNEL); ++ if (!fb->cb_base) { ++ dev_err(&dev->dev, "cannot allocate DMA CBs\n"); ++ ret = -ENOMEM; ++ goto free_fb; ++ } ++ ++ pr_info("BCM2708FB: allocated DMA memory %08x\n", ++ fb->cb_handle); ++ ++ ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK, ++ &fb->dma_chan_base, &fb->dma_irq); ++ if (ret < 0) { ++ dev_err(&dev->dev, "couldn't allocate a DMA channel\n"); ++ goto free_cb; ++ } ++ fb->dma_chan = ret; ++ ++ ret = request_irq(fb->dma_irq, bcm2708_fb_dma_irq, ++ 0, "bcm2708_fb dma", fb); ++ if (ret) { ++ pr_err("%s: failed to request DMA irq\n", __func__); ++ goto free_dma_chan; ++ } ++ ++ ++ pr_info("BCM2708FB: allocated DMA channel %d @ %p\n", ++ fb->dma_chan, fb->dma_chan_base); ++ ++ fb->dev = dev; ++ ++ ret = bcm2708_fb_register(fb); ++ if (ret == 0) { ++ platform_set_drvdata(dev, fb); ++ goto out; ++ } ++ ++free_dma_chan: ++ bcm_dma_chan_free(fb->dma_chan); ++free_cb: ++ dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle); ++free_fb: ++ kfree(fb); ++free_region: ++ dev_err(&dev->dev, "probe failed, err %d\n", ret); ++out: ++ return ret; ++} ++ ++static int bcm2708_fb_remove(struct platform_device *dev) ++{ ++ struct bcm2708_fb *fb = platform_get_drvdata(dev); ++ ++ platform_set_drvdata(dev, NULL); ++ ++ if (fb->fb.screen_base) ++ iounmap(fb->fb.screen_base); ++ unregister_framebuffer(&fb->fb); ++ ++ dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle); ++ bcm_dma_chan_free(fb->dma_chan); ++ ++ dma_free_coherent(NULL, PAGE_ALIGN(sizeof(*fb->info)), (void *)fb->info, ++ fb->dma); ++ bcm2708_fb_debugfs_deinit(fb); ++ ++ free_irq(fb->dma_irq, fb); ++ ++ kfree(fb); ++ ++ return 0; ++} ++ ++static struct platform_driver bcm2708_fb_driver = { ++ .probe = bcm2708_fb_probe, ++ .remove = bcm2708_fb_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init bcm2708_fb_init(void) ++{ ++ return platform_driver_register(&bcm2708_fb_driver); ++} ++ ++module_init(bcm2708_fb_init); ++ ++static void __exit bcm2708_fb_exit(void) ++{ ++ platform_driver_unregister(&bcm2708_fb_driver); ++} ++ ++module_exit(bcm2708_fb_exit); ++ ++module_param(fbwidth, int, 0644); ++module_param(fbheight, int, 0644); ++module_param(fbdepth, int, 0644); ++module_param(fbswap, int, 0644); ++ ++MODULE_DESCRIPTION("BCM2708 framebuffer driver"); ++MODULE_LICENSE("GPL"); ++ ++MODULE_PARM_DESC(fbwidth, "Width of ARM Framebuffer"); ++MODULE_PARM_DESC(fbheight, "Height of ARM Framebuffer"); ++MODULE_PARM_DESC(fbdepth, "Bit depth of ARM Framebuffer"); ++MODULE_PARM_DESC(fbswap, "Swap order of red and blue in 24 and 32 bit modes"); +diff -Nur linux-3.10.33/drivers/video/cfbimgblt.c linux-raspberry-pi/drivers/video/cfbimgblt.c +--- linux-3.10.33/drivers/video/cfbimgblt.c 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/video/cfbimgblt.c 2014-03-13 12:46:40.308099578 +0100 +@@ -28,6 +28,11 @@ + * + * Also need to add code to deal with cards endians that are different than + * the native cpu endians. I also need to deal with MSB position in the word. ++ * Modified by Harm Hanemaaijer (fgenfb@yahoo.com) 2013: ++ * - Provide optimized versions of fast_imageblit for 16 and 32bpp that are ++ * significantly faster than the previous implementation. ++ * - Simplify the fast/slow_imageblit selection code, avoiding integer ++ * divides. + */ + #include + #include +@@ -262,6 +267,133 @@ + } + } + ++/* ++ * Optimized fast_imageblit for bpp == 16. ppw = 2, bit_mask = 3 folded ++ * into the code, main loop unrolled. ++ */ ++ ++static inline void fast_imageblit16(const struct fb_image *image, ++ struct fb_info *p, u8 __iomem * dst1, ++ u32 fgcolor, u32 bgcolor) ++{ ++ u32 fgx = fgcolor, bgx = bgcolor; ++ u32 spitch = (image->width + 7) / 8; ++ u32 end_mask, eorx; ++ const char *s = image->data, *src; ++ u32 __iomem *dst; ++ const u32 *tab = NULL; ++ int i, j, k; ++ ++ tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; ++ ++ fgx <<= 16; ++ bgx <<= 16; ++ fgx |= fgcolor; ++ bgx |= bgcolor; ++ ++ eorx = fgx ^ bgx; ++ k = image->width / 2; ++ ++ for (i = image->height; i--;) { ++ dst = (u32 __iomem *) dst1; ++ src = s; ++ ++ j = k; ++ while (j >= 4) { ++ u8 bits = *src; ++ end_mask = tab[(bits >> 6) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 4) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 2) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[bits & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ src++; ++ j -= 4; ++ } ++ if (j != 0) { ++ u8 bits = *src; ++ end_mask = tab[(bits >> 6) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ if (j >= 2) { ++ end_mask = tab[(bits >> 4) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ if (j == 3) { ++ end_mask = tab[(bits >> 2) & 3]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst); ++ } ++ } ++ } ++ dst1 += p->fix.line_length; ++ s += spitch; ++ } ++} ++ ++/* ++ * Optimized fast_imageblit for bpp == 32. ppw = 1, bit_mask = 1 folded ++ * into the code, main loop unrolled. ++ */ ++ ++static inline void fast_imageblit32(const struct fb_image *image, ++ struct fb_info *p, u8 __iomem * dst1, ++ u32 fgcolor, u32 bgcolor) ++{ ++ u32 fgx = fgcolor, bgx = bgcolor; ++ u32 spitch = (image->width + 7) / 8; ++ u32 end_mask, eorx; ++ const char *s = image->data, *src; ++ u32 __iomem *dst; ++ const u32 *tab = NULL; ++ int i, j, k; ++ ++ tab = cfb_tab32; ++ ++ eorx = fgx ^ bgx; ++ k = image->width; ++ ++ for (i = image->height; i--;) { ++ dst = (u32 __iomem *) dst1; ++ src = s; ++ ++ j = k; ++ while (j >= 8) { ++ u8 bits = *src; ++ end_mask = tab[(bits >> 7) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 6) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 5) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 4) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 3) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 2) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[(bits >> 1) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ end_mask = tab[bits & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ src++; ++ j -= 8; ++ } ++ if (j != 0) { ++ u32 bits = (u32) * src; ++ while (j > 1) { ++ end_mask = tab[(bits >> 7) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst++); ++ bits <<= 1; ++ j--; ++ } ++ end_mask = tab[(bits >> 7) & 1]; ++ FB_WRITEL((end_mask & eorx) ^ bgx, dst); ++ } ++ dst1 += p->fix.line_length; ++ s += spitch; ++ } ++} ++ + void cfb_imageblit(struct fb_info *p, const struct fb_image *image) + { + u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; +@@ -294,11 +426,21 @@ + bgcolor = image->bg_color; + } + +- if (32 % bpp == 0 && !start_index && !pitch_index && +- ((width & (32/bpp-1)) == 0) && +- bpp >= 8 && bpp <= 32) +- fast_imageblit(image, p, dst1, fgcolor, bgcolor); +- else ++ if (!start_index && !pitch_index) { ++ if (bpp == 32) ++ fast_imageblit32(image, p, dst1, fgcolor, ++ bgcolor); ++ else if (bpp == 16 && (width & 1) == 0) ++ fast_imageblit16(image, p, dst1, fgcolor, ++ bgcolor); ++ else if (bpp == 8 && (width & 3) == 0) ++ fast_imageblit(image, p, dst1, fgcolor, ++ bgcolor); ++ else ++ slow_imageblit(image, p, dst1, fgcolor, ++ bgcolor, ++ start_index, pitch_index); ++ } else + slow_imageblit(image, p, dst1, fgcolor, bgcolor, + start_index, pitch_index); + } else +diff -Nur linux-3.10.33/drivers/video/fbmem.c linux-raspberry-pi/drivers/video/fbmem.c +--- linux-3.10.33/drivers/video/fbmem.c 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/video/fbmem.c 2014-03-13 12:46:40.316099594 +0100 +@@ -1074,6 +1074,25 @@ + return ret; + } + ++static int fb_copyarea_user(struct fb_info *info, ++ struct fb_copyarea *copy) ++{ ++ int ret = 0; ++ if (!lock_fb_info(info)) ++ return -ENODEV; ++ if (copy->dx + copy->width > info->var.xres || ++ copy->sx + copy->width > info->var.xres || ++ copy->dy + copy->height > info->var.yres || ++ copy->sy + copy->height > info->var.yres) { ++ ret = -EINVAL; ++ goto out; ++ } ++ info->fbops->fb_copyarea(info, copy); ++out: ++ unlock_fb_info(info); ++ return ret; ++} ++ + static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) + { +@@ -1084,6 +1103,7 @@ + struct fb_cmap cmap_from; + struct fb_cmap_user cmap; + struct fb_event event; ++ struct fb_copyarea copy; + void __user *argp = (void __user *)arg; + long ret = 0; + +@@ -1193,6 +1213,15 @@ + console_unlock(); + unlock_fb_info(info); + break; ++ case FBIOCOPYAREA: ++ if (info->flags & FBINFO_HWACCEL_COPYAREA) { ++ /* only provide this ioctl if it is accelerated */ ++ if (copy_from_user(©, argp, sizeof(copy))) ++ return -EFAULT; ++ ret = fb_copyarea_user(info, ©); ++ break; ++ } ++ /* fall through */ + default: + if (!lock_fb_info(info)) + return -ENODEV; +@@ -1345,6 +1374,7 @@ + case FBIOPAN_DISPLAY: + case FBIOGET_CON2FBMAP: + case FBIOPUT_CON2FBMAP: ++ case FBIOCOPYAREA: + arg = (unsigned long) compat_ptr(arg); + case FBIOBLANK: + ret = do_fb_ioctl(info, cmd, arg); +diff -Nur linux-3.10.33/drivers/video/Kconfig linux-raspberry-pi/drivers/video/Kconfig +--- linux-3.10.33/drivers/video/Kconfig 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/video/Kconfig 2014-03-13 12:46:40.288099538 +0100 +@@ -310,6 +310,20 @@ + help + Support the Permedia2 FIFO disconnect feature. + ++config FB_BCM2708 ++ tristate "BCM2708 framebuffer support" ++ depends on FB && ARM ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ This framebuffer device driver is for the BCM2708 framebuffer. ++ ++ If you want to compile this as a module (=code which can be ++ inserted into and removed from the running kernel), say M ++ here and read . The module ++ will be called bcm2708_fb. ++ + config FB_ARMCLCD + tristate "ARM PrimeCell PL110 support" + depends on FB && ARM && ARM_AMBA +diff -Nur linux-3.10.33/drivers/video/logo/logo_linux_clut224.ppm linux-raspberry-pi/drivers/video/logo/logo_linux_clut224.ppm +--- linux-3.10.33/drivers/video/logo/logo_linux_clut224.ppm 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/video/logo/logo_linux_clut224.ppm 2014-03-13 12:46:40.328099618 +0100 +@@ -1,1604 +1,883 @@ + P3 +-# Standard 224-color Linux logo +-80 80 ++63 80 + 255 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 6 6 6 6 6 6 10 10 10 10 10 10 +- 10 10 10 6 6 6 6 6 6 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 6 6 6 10 10 10 14 14 14 +- 22 22 22 26 26 26 30 30 30 34 34 34 +- 30 30 30 30 30 30 26 26 26 18 18 18 +- 14 14 14 10 10 10 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 1 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 6 6 6 14 14 14 26 26 26 42 42 42 +- 54 54 54 66 66 66 78 78 78 78 78 78 +- 78 78 78 74 74 74 66 66 66 54 54 54 +- 42 42 42 26 26 26 18 18 18 10 10 10 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 1 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 22 22 22 42 42 42 66 66 66 86 86 86 +- 66 66 66 38 38 38 38 38 38 22 22 22 +- 26 26 26 34 34 34 54 54 54 66 66 66 +- 86 86 86 70 70 70 46 46 46 26 26 26 +- 14 14 14 6 6 6 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 1 0 0 1 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 10 10 10 26 26 26 +- 50 50 50 82 82 82 58 58 58 6 6 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 6 6 6 54 54 54 86 86 86 66 66 66 +- 38 38 38 18 18 18 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 6 6 6 22 22 22 50 50 50 +- 78 78 78 34 34 34 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 6 6 6 70 70 70 +- 78 78 78 46 46 46 22 22 22 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 1 0 0 1 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 6 6 6 18 18 18 42 42 42 82 82 82 +- 26 26 26 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 14 14 14 +- 46 46 46 34 34 34 6 6 6 2 2 6 +- 42 42 42 78 78 78 42 42 42 18 18 18 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 1 0 0 0 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 10 10 10 30 30 30 66 66 66 58 58 58 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 26 26 26 +- 86 86 86 101 101 101 46 46 46 10 10 10 +- 2 2 6 58 58 58 70 70 70 34 34 34 +- 10 10 10 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 1 0 0 1 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 14 14 14 42 42 42 86 86 86 10 10 10 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 30 30 30 +- 94 94 94 94 94 94 58 58 58 26 26 26 +- 2 2 6 6 6 6 78 78 78 54 54 54 +- 22 22 22 6 6 6 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 22 22 22 62 62 62 62 62 62 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 26 26 26 +- 54 54 54 38 38 38 18 18 18 10 10 10 +- 2 2 6 2 2 6 34 34 34 82 82 82 +- 38 38 38 14 14 14 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 1 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 30 30 30 78 78 78 30 30 30 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 10 10 10 +- 10 10 10 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 78 78 78 +- 50 50 50 18 18 18 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 1 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 38 38 38 86 86 86 14 14 14 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 54 54 54 +- 66 66 66 26 26 26 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 1 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 42 42 42 82 82 82 2 2 6 2 2 6 +- 2 2 6 6 6 6 10 10 10 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 6 6 6 +- 14 14 14 10 10 10 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 18 18 18 +- 82 82 82 34 34 34 10 10 10 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 1 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 46 46 46 86 86 86 2 2 6 2 2 6 +- 6 6 6 6 6 6 22 22 22 34 34 34 +- 6 6 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 18 18 18 34 34 34 +- 10 10 10 50 50 50 22 22 22 2 2 6 +- 2 2 6 2 2 6 2 2 6 10 10 10 +- 86 86 86 42 42 42 14 14 14 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 1 0 0 1 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 46 46 46 86 86 86 2 2 6 2 2 6 +- 38 38 38 116 116 116 94 94 94 22 22 22 +- 22 22 22 2 2 6 2 2 6 2 2 6 +- 14 14 14 86 86 86 138 138 138 162 162 162 +-154 154 154 38 38 38 26 26 26 6 6 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 86 86 86 46 46 46 14 14 14 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 46 46 46 86 86 86 2 2 6 14 14 14 +-134 134 134 198 198 198 195 195 195 116 116 116 +- 10 10 10 2 2 6 2 2 6 6 6 6 +-101 98 89 187 187 187 210 210 210 218 218 218 +-214 214 214 134 134 134 14 14 14 6 6 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 86 86 86 50 50 50 18 18 18 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 1 0 0 0 +- 0 0 1 0 0 1 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 46 46 46 86 86 86 2 2 6 54 54 54 +-218 218 218 195 195 195 226 226 226 246 246 246 +- 58 58 58 2 2 6 2 2 6 30 30 30 +-210 210 210 253 253 253 174 174 174 123 123 123 +-221 221 221 234 234 234 74 74 74 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 70 70 70 58 58 58 22 22 22 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 46 46 46 82 82 82 2 2 6 106 106 106 +-170 170 170 26 26 26 86 86 86 226 226 226 +-123 123 123 10 10 10 14 14 14 46 46 46 +-231 231 231 190 190 190 6 6 6 70 70 70 +- 90 90 90 238 238 238 158 158 158 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 70 70 70 58 58 58 22 22 22 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 1 0 0 0 +- 0 0 1 0 0 1 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 42 42 42 86 86 86 6 6 6 116 116 116 +-106 106 106 6 6 6 70 70 70 149 149 149 +-128 128 128 18 18 18 38 38 38 54 54 54 +-221 221 221 106 106 106 2 2 6 14 14 14 +- 46 46 46 190 190 190 198 198 198 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 74 74 74 62 62 62 22 22 22 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 1 0 0 0 +- 0 0 1 0 0 0 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 42 42 42 94 94 94 14 14 14 101 101 101 +-128 128 128 2 2 6 18 18 18 116 116 116 +-118 98 46 121 92 8 121 92 8 98 78 10 +-162 162 162 106 106 106 2 2 6 2 2 6 +- 2 2 6 195 195 195 195 195 195 6 6 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 74 74 74 62 62 62 22 22 22 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 1 0 0 1 +- 0 0 1 0 0 0 0 0 1 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 38 38 38 90 90 90 14 14 14 58 58 58 +-210 210 210 26 26 26 54 38 6 154 114 10 +-226 170 11 236 186 11 225 175 15 184 144 12 +-215 174 15 175 146 61 37 26 9 2 2 6 +- 70 70 70 246 246 246 138 138 138 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 70 70 70 66 66 66 26 26 26 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 38 38 38 86 86 86 14 14 14 10 10 10 +-195 195 195 188 164 115 192 133 9 225 175 15 +-239 182 13 234 190 10 232 195 16 232 200 30 +-245 207 45 241 208 19 232 195 16 184 144 12 +-218 194 134 211 206 186 42 42 42 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 50 50 50 74 74 74 30 30 30 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 34 34 34 86 86 86 14 14 14 2 2 6 +-121 87 25 192 133 9 219 162 10 239 182 13 +-236 186 11 232 195 16 241 208 19 244 214 54 +-246 218 60 246 218 38 246 215 20 241 208 19 +-241 208 19 226 184 13 121 87 25 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 50 50 50 82 82 82 34 34 34 10 10 10 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 34 34 34 82 82 82 30 30 30 61 42 6 +-180 123 7 206 145 10 230 174 11 239 182 13 +-234 190 10 238 202 15 241 208 19 246 218 74 +-246 218 38 246 215 20 246 215 20 246 215 20 +-226 184 13 215 174 15 184 144 12 6 6 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 26 26 26 94 94 94 42 42 42 14 14 14 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 30 30 30 78 78 78 50 50 50 104 69 6 +-192 133 9 216 158 10 236 178 12 236 186 11 +-232 195 16 241 208 19 244 214 54 245 215 43 +-246 215 20 246 215 20 241 208 19 198 155 10 +-200 144 11 216 158 10 156 118 10 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 6 6 6 90 90 90 54 54 54 18 18 18 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 30 30 30 78 78 78 46 46 46 22 22 22 +-137 92 6 210 162 10 239 182 13 238 190 10 +-238 202 15 241 208 19 246 215 20 246 215 20 +-241 208 19 203 166 17 185 133 11 210 150 10 +-216 158 10 210 150 10 102 78 10 2 2 6 +- 6 6 6 54 54 54 14 14 14 2 2 6 +- 2 2 6 62 62 62 74 74 74 30 30 30 +- 10 10 10 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 34 34 34 78 78 78 50 50 50 6 6 6 +- 94 70 30 139 102 15 190 146 13 226 184 13 +-232 200 30 232 195 16 215 174 15 190 146 13 +-168 122 10 192 133 9 210 150 10 213 154 11 +-202 150 34 182 157 106 101 98 89 2 2 6 +- 2 2 6 78 78 78 116 116 116 58 58 58 +- 2 2 6 22 22 22 90 90 90 46 46 46 +- 18 18 18 6 6 6 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 38 38 38 86 86 86 50 50 50 6 6 6 +-128 128 128 174 154 114 156 107 11 168 122 10 +-198 155 10 184 144 12 197 138 11 200 144 11 +-206 145 10 206 145 10 197 138 11 188 164 115 +-195 195 195 198 198 198 174 174 174 14 14 14 +- 2 2 6 22 22 22 116 116 116 116 116 116 +- 22 22 22 2 2 6 74 74 74 70 70 70 +- 30 30 30 10 10 10 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 6 6 6 18 18 18 +- 50 50 50 101 101 101 26 26 26 10 10 10 +-138 138 138 190 190 190 174 154 114 156 107 11 +-197 138 11 200 144 11 197 138 11 192 133 9 +-180 123 7 190 142 34 190 178 144 187 187 187 +-202 202 202 221 221 221 214 214 214 66 66 66 +- 2 2 6 2 2 6 50 50 50 62 62 62 +- 6 6 6 2 2 6 10 10 10 90 90 90 +- 50 50 50 18 18 18 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 10 10 10 34 34 34 +- 74 74 74 74 74 74 2 2 6 6 6 6 +-144 144 144 198 198 198 190 190 190 178 166 146 +-154 121 60 156 107 11 156 107 11 168 124 44 +-174 154 114 187 187 187 190 190 190 210 210 210 +-246 246 246 253 253 253 253 253 253 182 182 182 +- 6 6 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 62 62 62 +- 74 74 74 34 34 34 14 14 14 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 10 10 10 22 22 22 54 54 54 +- 94 94 94 18 18 18 2 2 6 46 46 46 +-234 234 234 221 221 221 190 190 190 190 190 190 +-190 190 190 187 187 187 187 187 187 190 190 190 +-190 190 190 195 195 195 214 214 214 242 242 242 +-253 253 253 253 253 253 253 253 253 253 253 253 +- 82 82 82 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 14 14 14 +- 86 86 86 54 54 54 22 22 22 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 6 6 6 18 18 18 46 46 46 90 90 90 +- 46 46 46 18 18 18 6 6 6 182 182 182 +-253 253 253 246 246 246 206 206 206 190 190 190 +-190 190 190 190 190 190 190 190 190 190 190 190 +-206 206 206 231 231 231 250 250 250 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-202 202 202 14 14 14 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 42 42 42 86 86 86 42 42 42 18 18 18 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 14 14 14 38 38 38 74 74 74 66 66 66 +- 2 2 6 6 6 6 90 90 90 250 250 250 +-253 253 253 253 253 253 238 238 238 198 198 198 +-190 190 190 190 190 190 195 195 195 221 221 221 +-246 246 246 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 82 82 82 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 78 78 78 70 70 70 34 34 34 +- 14 14 14 6 6 6 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 34 34 34 66 66 66 78 78 78 6 6 6 +- 2 2 6 18 18 18 218 218 218 253 253 253 +-253 253 253 253 253 253 253 253 253 246 246 246 +-226 226 226 231 231 231 246 246 246 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 178 178 178 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 18 18 18 90 90 90 62 62 62 +- 30 30 30 10 10 10 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 10 10 10 26 26 26 +- 58 58 58 90 90 90 18 18 18 2 2 6 +- 2 2 6 110 110 110 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-250 250 250 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 231 231 231 18 18 18 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 18 18 18 94 94 94 +- 54 54 54 26 26 26 10 10 10 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 6 6 6 22 22 22 50 50 50 +- 90 90 90 26 26 26 2 2 6 2 2 6 +- 14 14 14 195 195 195 250 250 250 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-250 250 250 242 242 242 54 54 54 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 38 38 38 +- 86 86 86 50 50 50 22 22 22 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 6 6 6 14 14 14 38 38 38 82 82 82 +- 34 34 34 2 2 6 2 2 6 2 2 6 +- 42 42 42 195 195 195 246 246 246 253 253 253 +-253 253 253 253 253 253 253 253 253 250 250 250 +-242 242 242 242 242 242 250 250 250 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 250 250 250 246 246 246 238 238 238 +-226 226 226 231 231 231 101 101 101 6 6 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 38 38 38 82 82 82 42 42 42 14 14 14 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 10 10 10 26 26 26 62 62 62 66 66 66 +- 2 2 6 2 2 6 2 2 6 6 6 6 +- 70 70 70 170 170 170 206 206 206 234 234 234 +-246 246 246 250 250 250 250 250 250 238 238 238 +-226 226 226 231 231 231 238 238 238 250 250 250 +-250 250 250 250 250 250 246 246 246 231 231 231 +-214 214 214 206 206 206 202 202 202 202 202 202 +-198 198 198 202 202 202 182 182 182 18 18 18 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 62 62 62 66 66 66 30 30 30 +- 10 10 10 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 14 14 14 42 42 42 82 82 82 18 18 18 +- 2 2 6 2 2 6 2 2 6 10 10 10 +- 94 94 94 182 182 182 218 218 218 242 242 242 +-250 250 250 253 253 253 253 253 253 250 250 250 +-234 234 234 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 246 246 246 +-238 238 238 226 226 226 210 210 210 202 202 202 +-195 195 195 195 195 195 210 210 210 158 158 158 +- 6 6 6 14 14 14 50 50 50 14 14 14 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 6 6 6 86 86 86 46 46 46 +- 18 18 18 6 6 6 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 22 22 22 54 54 54 70 70 70 2 2 6 +- 2 2 6 10 10 10 2 2 6 22 22 22 +-166 166 166 231 231 231 250 250 250 253 253 253 +-253 253 253 253 253 253 253 253 253 250 250 250 +-242 242 242 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 246 246 246 +-231 231 231 206 206 206 198 198 198 226 226 226 +- 94 94 94 2 2 6 6 6 6 38 38 38 +- 30 30 30 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 62 62 62 66 66 66 +- 26 26 26 10 10 10 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 30 30 30 74 74 74 50 50 50 2 2 6 +- 26 26 26 26 26 26 2 2 6 106 106 106 +-238 238 238 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 246 246 246 218 218 218 202 202 202 +-210 210 210 14 14 14 2 2 6 2 2 6 +- 30 30 30 22 22 22 2 2 6 2 2 6 +- 2 2 6 2 2 6 18 18 18 86 86 86 +- 42 42 42 14 14 14 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 42 42 42 90 90 90 22 22 22 2 2 6 +- 42 42 42 2 2 6 18 18 18 218 218 218 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 250 250 250 221 221 221 +-218 218 218 101 101 101 2 2 6 14 14 14 +- 18 18 18 38 38 38 10 10 10 2 2 6 +- 2 2 6 2 2 6 2 2 6 78 78 78 +- 58 58 58 22 22 22 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 6 6 6 18 18 18 +- 54 54 54 82 82 82 2 2 6 26 26 26 +- 22 22 22 2 2 6 123 123 123 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 250 250 250 +-238 238 238 198 198 198 6 6 6 38 38 38 +- 58 58 58 26 26 26 38 38 38 2 2 6 +- 2 2 6 2 2 6 2 2 6 46 46 46 +- 78 78 78 30 30 30 10 10 10 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 10 10 10 30 30 30 +- 74 74 74 58 58 58 2 2 6 42 42 42 +- 2 2 6 22 22 22 231 231 231 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 250 250 250 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 246 246 246 46 46 46 38 38 38 +- 42 42 42 14 14 14 38 38 38 14 14 14 +- 2 2 6 2 2 6 2 2 6 6 6 6 +- 86 86 86 46 46 46 14 14 14 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 6 6 6 14 14 14 42 42 42 +- 90 90 90 18 18 18 18 18 18 26 26 26 +- 2 2 6 116 116 116 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 250 250 250 238 238 238 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 94 94 94 6 6 6 +- 2 2 6 2 2 6 10 10 10 34 34 34 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 74 74 74 58 58 58 22 22 22 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 10 10 10 26 26 26 66 66 66 +- 82 82 82 2 2 6 38 38 38 6 6 6 +- 14 14 14 210 210 210 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 246 246 246 242 242 242 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 144 144 144 2 2 6 +- 2 2 6 2 2 6 2 2 6 46 46 46 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 42 42 42 74 74 74 30 30 30 10 10 10 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 6 6 6 14 14 14 42 42 42 90 90 90 +- 26 26 26 6 6 6 42 42 42 2 2 6 +- 74 74 74 250 250 250 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 242 242 242 242 242 242 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 182 182 182 2 2 6 +- 2 2 6 2 2 6 2 2 6 46 46 46 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 10 10 10 86 86 86 38 38 38 10 10 10 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 10 10 10 26 26 26 66 66 66 82 82 82 +- 2 2 6 22 22 22 18 18 18 2 2 6 +-149 149 149 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 234 234 234 242 242 242 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 206 206 206 2 2 6 +- 2 2 6 2 2 6 2 2 6 38 38 38 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 6 6 6 86 86 86 46 46 46 14 14 14 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 18 18 18 46 46 46 86 86 86 18 18 18 +- 2 2 6 34 34 34 10 10 10 6 6 6 +-210 210 210 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 234 234 234 242 242 242 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 221 221 221 6 6 6 +- 2 2 6 2 2 6 6 6 6 30 30 30 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 82 82 82 54 54 54 18 18 18 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 26 26 26 66 66 66 62 62 62 2 2 6 +- 2 2 6 38 38 38 10 10 10 26 26 26 +-238 238 238 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 231 231 231 238 238 238 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 231 231 231 6 6 6 +- 2 2 6 2 2 6 10 10 10 30 30 30 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 66 66 66 58 58 58 22 22 22 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 38 38 38 78 78 78 6 6 6 2 2 6 +- 2 2 6 46 46 46 14 14 14 42 42 42 +-246 246 246 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 231 231 231 242 242 242 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 234 234 234 10 10 10 +- 2 2 6 2 2 6 22 22 22 14 14 14 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 66 66 66 62 62 62 22 22 22 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 6 6 6 18 18 18 +- 50 50 50 74 74 74 2 2 6 2 2 6 +- 14 14 14 70 70 70 34 34 34 62 62 62 +-250 250 250 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 231 231 231 246 246 246 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 234 234 234 14 14 14 +- 2 2 6 2 2 6 30 30 30 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 66 66 66 62 62 62 22 22 22 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 6 6 6 18 18 18 +- 54 54 54 62 62 62 2 2 6 2 2 6 +- 2 2 6 30 30 30 46 46 46 70 70 70 +-250 250 250 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 231 231 231 246 246 246 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 226 226 226 10 10 10 +- 2 2 6 6 6 6 30 30 30 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 66 66 66 58 58 58 22 22 22 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 6 6 6 22 22 22 +- 58 58 58 62 62 62 2 2 6 2 2 6 +- 2 2 6 2 2 6 30 30 30 78 78 78 +-250 250 250 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 231 231 231 246 246 246 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 206 206 206 2 2 6 +- 22 22 22 34 34 34 18 14 6 22 22 22 +- 26 26 26 18 18 18 6 6 6 2 2 6 +- 2 2 6 82 82 82 54 54 54 18 18 18 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 6 6 6 26 26 26 +- 62 62 62 106 106 106 74 54 14 185 133 11 +-210 162 10 121 92 8 6 6 6 62 62 62 +-238 238 238 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 231 231 231 246 246 246 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 158 158 158 18 18 18 +- 14 14 14 2 2 6 2 2 6 2 2 6 +- 6 6 6 18 18 18 66 66 66 38 38 38 +- 6 6 6 94 94 94 50 50 50 18 18 18 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 10 10 10 10 10 10 18 18 18 38 38 38 +- 78 78 78 142 134 106 216 158 10 242 186 14 +-246 190 14 246 190 14 156 118 10 10 10 10 +- 90 90 90 238 238 238 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 231 231 231 250 250 250 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 246 230 190 +-238 204 91 238 204 91 181 142 44 37 26 9 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 38 38 38 46 46 46 +- 26 26 26 106 106 106 54 54 54 18 18 18 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 6 6 6 14 14 14 22 22 22 +- 30 30 30 38 38 38 50 50 50 70 70 70 +-106 106 106 190 142 34 226 170 11 242 186 14 +-246 190 14 246 190 14 246 190 14 154 114 10 +- 6 6 6 74 74 74 226 226 226 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 231 231 231 250 250 250 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 228 184 62 +-241 196 14 241 208 19 232 195 16 38 30 10 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 6 6 6 30 30 30 26 26 26 +-203 166 17 154 142 90 66 66 66 26 26 26 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 6 6 6 18 18 18 38 38 38 58 58 58 +- 78 78 78 86 86 86 101 101 101 123 123 123 +-175 146 61 210 150 10 234 174 13 246 186 14 +-246 190 14 246 190 14 246 190 14 238 190 10 +-102 78 10 2 2 6 46 46 46 198 198 198 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 234 234 234 242 242 242 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 224 178 62 +-242 186 14 241 196 14 210 166 10 22 18 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 6 6 6 121 92 8 +-238 202 15 232 195 16 82 82 82 34 34 34 +- 10 10 10 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 14 14 14 38 38 38 70 70 70 154 122 46 +-190 142 34 200 144 11 197 138 11 197 138 11 +-213 154 11 226 170 11 242 186 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-225 175 15 46 32 6 2 2 6 22 22 22 +-158 158 158 250 250 250 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 250 250 250 242 242 242 224 178 62 +-239 182 13 236 186 11 213 154 11 46 32 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 61 42 6 225 175 15 +-238 190 10 236 186 11 112 100 78 42 42 42 +- 14 14 14 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 22 22 22 54 54 54 154 122 46 213 154 11 +-226 170 11 230 174 11 226 170 11 226 170 11 +-236 178 12 242 186 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-241 196 14 184 144 12 10 10 10 2 2 6 +- 6 6 6 116 116 116 242 242 242 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 231 231 231 198 198 198 214 170 54 +-236 178 12 236 178 12 210 150 10 137 92 6 +- 18 14 6 2 2 6 2 2 6 2 2 6 +- 6 6 6 70 47 6 200 144 11 236 178 12 +-239 182 13 239 182 13 124 112 88 58 58 58 +- 22 22 22 6 6 6 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 30 30 30 70 70 70 180 133 36 226 170 11 +-239 182 13 242 186 14 242 186 14 246 186 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 232 195 16 98 70 6 2 2 6 +- 2 2 6 2 2 6 66 66 66 221 221 221 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 206 206 206 198 198 198 214 166 58 +-230 174 11 230 174 11 216 158 10 192 133 9 +-163 110 8 116 81 8 102 78 10 116 81 8 +-167 114 7 197 138 11 226 170 11 239 182 13 +-242 186 14 242 186 14 162 146 94 78 78 78 +- 34 34 34 14 14 14 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 30 30 30 78 78 78 190 142 34 226 170 11 +-239 182 13 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 241 196 14 203 166 17 22 18 6 +- 2 2 6 2 2 6 2 2 6 38 38 38 +-218 218 218 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-250 250 250 206 206 206 198 198 198 202 162 69 +-226 170 11 236 178 12 224 166 10 210 150 10 +-200 144 11 197 138 11 192 133 9 197 138 11 +-210 150 10 226 170 11 242 186 14 246 190 14 +-246 190 14 246 186 14 225 175 15 124 112 88 +- 62 62 62 30 30 30 14 14 14 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 30 30 30 78 78 78 174 135 50 224 166 10 +-239 182 13 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 241 196 14 139 102 15 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 78 78 78 250 250 250 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-250 250 250 214 214 214 198 198 198 190 150 46 +-219 162 10 236 178 12 234 174 13 224 166 10 +-216 158 10 213 154 11 213 154 11 216 158 10 +-226 170 11 239 182 13 246 190 14 246 190 14 +-246 190 14 246 190 14 242 186 14 206 162 42 +-101 101 101 58 58 58 30 30 30 14 14 14 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 30 30 30 74 74 74 174 135 50 216 158 10 +-236 178 12 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 241 196 14 226 184 13 +- 61 42 6 2 2 6 2 2 6 2 2 6 +- 22 22 22 238 238 238 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 226 226 226 187 187 187 180 133 36 +-216 158 10 236 178 12 239 182 13 236 178 12 +-230 174 11 226 170 11 226 170 11 230 174 11 +-236 178 12 242 186 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 186 14 239 182 13 +-206 162 42 106 106 106 66 66 66 34 34 34 +- 14 14 14 6 6 6 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 26 26 26 70 70 70 163 133 67 213 154 11 +-236 178 12 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 241 196 14 +-190 146 13 18 14 6 2 2 6 2 2 6 +- 46 46 46 246 246 246 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 221 221 221 86 86 86 156 107 11 +-216 158 10 236 178 12 242 186 14 246 186 14 +-242 186 14 239 182 13 239 182 13 242 186 14 +-242 186 14 246 186 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-242 186 14 225 175 15 142 122 72 66 66 66 +- 30 30 30 10 10 10 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 26 26 26 70 70 70 163 133 67 210 150 10 +-236 178 12 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-232 195 16 121 92 8 34 34 34 106 106 106 +-221 221 221 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-242 242 242 82 82 82 18 14 6 163 110 8 +-216 158 10 236 178 12 242 186 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 242 186 14 163 133 67 +- 46 46 46 18 18 18 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 10 10 10 +- 30 30 30 78 78 78 163 133 67 210 150 10 +-236 178 12 246 186 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-241 196 14 215 174 15 190 178 144 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 218 218 218 +- 58 58 58 2 2 6 22 18 6 167 114 7 +-216 158 10 236 178 12 246 186 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 186 14 242 186 14 190 150 46 +- 54 54 54 22 22 22 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 38 38 38 86 86 86 180 133 36 213 154 11 +-236 178 12 246 186 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 232 195 16 190 146 13 214 214 214 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 250 250 250 170 170 170 26 26 26 +- 2 2 6 2 2 6 37 26 9 163 110 8 +-219 162 10 239 182 13 246 186 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 186 14 236 178 12 224 166 10 142 122 72 +- 46 46 46 18 18 18 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 6 6 6 18 18 18 +- 50 50 50 109 106 95 192 133 9 224 166 10 +-242 186 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-242 186 14 226 184 13 210 162 10 142 110 46 +-226 226 226 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-253 253 253 253 253 253 253 253 253 253 253 253 +-198 198 198 66 66 66 2 2 6 2 2 6 +- 2 2 6 2 2 6 50 34 6 156 107 11 +-219 162 10 239 182 13 246 186 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 242 186 14 +-234 174 13 213 154 11 154 122 46 66 66 66 +- 30 30 30 10 10 10 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 6 6 6 22 22 22 +- 58 58 58 154 121 60 206 145 10 234 174 13 +-242 186 14 246 186 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 186 14 236 178 12 210 162 10 163 110 8 +- 61 42 6 138 138 138 218 218 218 250 250 250 +-253 253 253 253 253 253 253 253 253 250 250 250 +-242 242 242 210 210 210 144 144 144 66 66 66 +- 6 6 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 61 42 6 163 110 8 +-216 158 10 236 178 12 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 239 182 13 230 174 11 216 158 10 +-190 142 34 124 112 88 70 70 70 38 38 38 +- 18 18 18 6 6 6 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 6 6 6 22 22 22 +- 62 62 62 168 124 44 206 145 10 224 166 10 +-236 178 12 239 182 13 242 186 14 242 186 14 +-246 186 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 236 178 12 216 158 10 175 118 6 +- 80 54 7 2 2 6 6 6 6 30 30 30 +- 54 54 54 62 62 62 50 50 50 38 38 38 +- 14 14 14 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 6 6 6 80 54 7 167 114 7 +-213 154 11 236 178 12 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 190 14 242 186 14 239 182 13 239 182 13 +-230 174 11 210 150 10 174 135 50 124 112 88 +- 82 82 82 54 54 54 34 34 34 18 18 18 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 6 6 6 18 18 18 +- 50 50 50 158 118 36 192 133 9 200 144 11 +-216 158 10 219 162 10 224 166 10 226 170 11 +-230 174 11 236 178 12 239 182 13 239 182 13 +-242 186 14 246 186 14 246 190 14 246 190 14 +-246 190 14 246 190 14 246 190 14 246 190 14 +-246 186 14 230 174 11 210 150 10 163 110 8 +-104 69 6 10 10 10 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 6 6 6 91 60 6 167 114 7 +-206 145 10 230 174 11 242 186 14 246 190 14 +-246 190 14 246 190 14 246 186 14 242 186 14 +-239 182 13 230 174 11 224 166 10 213 154 11 +-180 133 36 124 112 88 86 86 86 58 58 58 +- 38 38 38 22 22 22 10 10 10 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 14 14 14 +- 34 34 34 70 70 70 138 110 50 158 118 36 +-167 114 7 180 123 7 192 133 9 197 138 11 +-200 144 11 206 145 10 213 154 11 219 162 10 +-224 166 10 230 174 11 239 182 13 242 186 14 +-246 186 14 246 186 14 246 186 14 246 186 14 +-239 182 13 216 158 10 185 133 11 152 99 6 +-104 69 6 18 14 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 2 2 6 2 2 6 2 2 6 +- 2 2 6 6 6 6 80 54 7 152 99 6 +-192 133 9 219 162 10 236 178 12 239 182 13 +-246 186 14 242 186 14 239 182 13 236 178 12 +-224 166 10 206 145 10 192 133 9 154 121 60 +- 94 94 94 62 62 62 42 42 42 22 22 22 +- 14 14 14 6 6 6 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 18 18 18 34 34 34 58 58 58 78 78 78 +-101 98 89 124 112 88 142 110 46 156 107 11 +-163 110 8 167 114 7 175 118 6 180 123 7 +-185 133 11 197 138 11 210 150 10 219 162 10 +-226 170 11 236 178 12 236 178 12 234 174 13 +-219 162 10 197 138 11 163 110 8 130 83 6 +- 91 60 6 10 10 10 2 2 6 2 2 6 +- 18 18 18 38 38 38 38 38 38 38 38 38 +- 38 38 38 38 38 38 38 38 38 38 38 38 +- 38 38 38 38 38 38 26 26 26 2 2 6 +- 2 2 6 6 6 6 70 47 6 137 92 6 +-175 118 6 200 144 11 219 162 10 230 174 11 +-234 174 13 230 174 11 219 162 10 210 150 10 +-192 133 9 163 110 8 124 112 88 82 82 82 +- 50 50 50 30 30 30 14 14 14 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 6 6 6 14 14 14 22 22 22 34 34 34 +- 42 42 42 58 58 58 74 74 74 86 86 86 +-101 98 89 122 102 70 130 98 46 121 87 25 +-137 92 6 152 99 6 163 110 8 180 123 7 +-185 133 11 197 138 11 206 145 10 200 144 11 +-180 123 7 156 107 11 130 83 6 104 69 6 +- 50 34 6 54 54 54 110 110 110 101 98 89 +- 86 86 86 82 82 82 78 78 78 78 78 78 +- 78 78 78 78 78 78 78 78 78 78 78 78 +- 78 78 78 82 82 82 86 86 86 94 94 94 +-106 106 106 101 101 101 86 66 34 124 80 6 +-156 107 11 180 123 7 192 133 9 200 144 11 +-206 145 10 200 144 11 192 133 9 175 118 6 +-139 102 15 109 106 95 70 70 70 42 42 42 +- 22 22 22 10 10 10 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 6 6 6 10 10 10 +- 14 14 14 22 22 22 30 30 30 38 38 38 +- 50 50 50 62 62 62 74 74 74 90 90 90 +-101 98 89 112 100 78 121 87 25 124 80 6 +-137 92 6 152 99 6 152 99 6 152 99 6 +-138 86 6 124 80 6 98 70 6 86 66 30 +-101 98 89 82 82 82 58 58 58 46 46 46 +- 38 38 38 34 34 34 34 34 34 34 34 34 +- 34 34 34 34 34 34 34 34 34 34 34 34 +- 34 34 34 34 34 34 38 38 38 42 42 42 +- 54 54 54 82 82 82 94 86 76 91 60 6 +-134 86 6 156 107 11 167 114 7 175 118 6 +-175 118 6 167 114 7 152 99 6 121 87 25 +-101 98 89 62 62 62 34 34 34 18 18 18 +- 6 6 6 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 6 6 6 6 6 6 10 10 10 +- 18 18 18 22 22 22 30 30 30 42 42 42 +- 50 50 50 66 66 66 86 86 86 101 98 89 +-106 86 58 98 70 6 104 69 6 104 69 6 +-104 69 6 91 60 6 82 62 34 90 90 90 +- 62 62 62 38 38 38 22 22 22 14 14 14 +- 10 10 10 10 10 10 10 10 10 10 10 10 +- 10 10 10 10 10 10 6 6 6 10 10 10 +- 10 10 10 10 10 10 10 10 10 14 14 14 +- 22 22 22 42 42 42 70 70 70 89 81 66 +- 80 54 7 104 69 6 124 80 6 137 92 6 +-134 86 6 116 81 8 100 82 52 86 86 86 +- 58 58 58 30 30 30 14 14 14 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 6 6 6 10 10 10 14 14 14 +- 18 18 18 26 26 26 38 38 38 54 54 54 +- 70 70 70 86 86 86 94 86 76 89 81 66 +- 89 81 66 86 86 86 74 74 74 50 50 50 +- 30 30 30 14 14 14 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 6 6 6 18 18 18 34 34 34 58 58 58 +- 82 82 82 89 81 66 89 81 66 89 81 66 +- 94 86 66 94 86 76 74 74 74 50 50 50 +- 26 26 26 14 14 14 6 6 6 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 6 6 6 6 6 6 14 14 14 18 18 18 +- 30 30 30 38 38 38 46 46 46 54 54 54 +- 50 50 50 42 42 42 30 30 30 18 18 18 +- 10 10 10 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 6 6 6 14 14 14 26 26 26 +- 38 38 38 50 50 50 58 58 58 58 58 58 +- 54 54 54 42 42 42 30 30 30 18 18 18 +- 10 10 10 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 6 6 6 10 10 10 14 14 14 18 18 18 +- 18 18 18 14 14 14 10 10 10 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 6 6 6 +- 14 14 14 18 18 18 22 22 22 22 22 22 +- 18 18 18 14 14 14 10 10 10 6 6 6 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 +- 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 ++0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 ++0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 ++10 15 3 2 3 1 12 18 4 42 61 14 19 27 6 11 16 4 ++38 55 13 10 15 3 3 4 1 10 15 3 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 ++12 18 4 1 1 0 23 34 8 31 45 11 10 15 3 32 47 11 ++34 49 12 3 4 1 3 4 1 3 4 1 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 10 15 3 29 42 10 26 37 9 12 18 4 ++55 80 19 81 118 28 55 80 19 92 132 31 106 153 36 69 100 23 ++100 144 34 80 116 27 42 61 14 81 118 28 23 34 8 27 40 9 ++15 21 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 1 1 0 29 42 10 15 21 5 50 72 17 ++74 107 25 45 64 15 102 148 35 80 116 27 84 121 28 111 160 38 ++69 100 23 65 94 22 81 118 28 29 42 10 17 25 6 29 42 10 ++23 34 8 2 3 1 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 ++15 21 5 15 21 5 34 49 12 101 146 34 111 161 38 97 141 33 ++97 141 33 119 172 41 117 170 40 116 167 40 118 170 40 118 171 40 ++117 169 40 118 170 40 111 160 38 118 170 40 96 138 32 89 128 30 ++81 118 28 11 16 4 10 15 3 1 1 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++3 4 1 3 4 1 34 49 12 101 146 34 79 115 27 111 160 38 ++114 165 39 113 163 39 118 170 40 117 169 40 118 171 40 117 169 40 ++116 167 40 119 172 41 113 163 39 92 132 31 105 151 36 113 163 39 ++75 109 26 19 27 6 16 23 5 11 16 4 0 1 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 ++80 116 27 106 153 36 105 151 36 114 165 39 118 170 40 118 171 40 ++118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 170 40 117 169 40 118 170 40 118 170 40 ++117 170 40 75 109 26 75 109 26 34 49 12 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 4 1 ++64 92 22 65 94 22 100 144 34 118 171 40 118 170 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 118 171 41 118 170 40 117 169 40 ++109 158 37 105 151 36 104 150 35 47 69 16 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++42 61 14 115 167 39 118 170 40 117 169 40 117 169 40 117 169 40 ++117 170 40 117 170 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 118 170 40 96 138 32 17 25 6 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 47 69 16 ++114 165 39 117 168 40 117 170 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 118 170 40 117 169 40 117 169 40 117 169 40 ++117 170 40 119 172 41 96 138 32 12 18 4 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 ++32 47 11 105 151 36 118 170 40 117 169 40 117 169 40 116 168 40 ++109 157 37 111 160 38 117 169 40 118 171 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 118 171 40 69 100 23 2 3 1 ++0 0 0 0 0 0 0 0 0 0 0 0 19 27 6 101 146 34 ++118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 170 40 ++118 171 40 115 166 39 107 154 36 111 161 38 117 169 40 117 169 40 ++117 169 40 118 171 40 75 109 26 19 27 6 2 3 1 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 23 5 ++89 128 30 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++111 160 38 92 132 31 79 115 27 96 138 32 115 166 39 119 171 41 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 118 170 40 109 157 37 26 37 9 ++0 0 0 0 0 0 0 0 0 0 0 0 64 92 22 118 171 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 118 170 40 118 171 40 109 157 37 ++89 128 30 81 118 28 100 144 34 115 166 39 117 169 40 117 169 40 ++117 169 40 117 170 40 113 163 39 60 86 20 1 1 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++27 40 9 96 138 32 118 170 40 117 169 40 117 169 40 117 169 40 ++117 170 40 117 169 40 101 146 34 67 96 23 55 80 19 84 121 28 ++113 163 39 119 171 41 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 119 171 41 65 94 22 ++0 0 0 0 0 0 0 0 0 15 21 5 101 146 34 118 171 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 118 170 40 118 171 40 104 150 35 69 100 23 53 76 18 ++81 118 28 111 160 38 118 170 40 117 169 40 117 169 40 117 169 40 ++117 169 40 114 165 39 69 100 23 10 15 3 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 ++31 45 11 77 111 26 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 118 170 40 116 168 40 92 132 31 47 69 16 ++38 55 13 81 118 28 113 163 39 119 171 41 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 118 171 41 92 132 31 ++10 15 3 0 0 0 0 0 0 36 52 12 115 166 39 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 ++118 171 40 102 148 35 64 92 22 34 49 12 65 94 22 106 153 36 ++118 171 40 117 170 40 117 169 40 117 169 40 117 169 40 117 169 40 ++118 170 40 107 154 36 55 80 19 15 21 5 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++29 42 10 101 146 34 118 171 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 118 171 40 113 163 39 ++75 109 26 27 40 9 36 52 12 89 128 30 116 167 40 118 171 40 ++117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 104 150 35 ++16 23 5 0 0 0 0 0 0 53 76 18 118 171 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 119 171 41 109 157 37 ++67 96 23 23 34 8 42 61 14 96 138 32 118 170 40 118 170 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 74 107 25 10 15 3 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 31 45 11 101 146 34 118 170 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++119 171 41 102 148 35 47 69 16 14 20 5 50 72 17 102 148 35 ++118 171 40 117 169 40 117 169 40 117 169 40 118 170 40 102 148 35 ++15 21 5 0 0 0 0 0 0 50 72 17 118 170 40 117 169 40 ++117 169 40 117 169 40 118 170 40 116 167 40 84 121 28 27 40 9 ++19 27 6 74 107 25 114 165 39 118 171 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 75 109 26 10 15 4 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 38 55 13 102 148 35 118 171 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 118 170 40 115 167 39 77 111 26 17 25 6 19 27 6 ++77 111 26 115 166 39 118 170 40 117 169 40 119 172 41 81 118 28 ++3 4 1 0 0 0 0 0 0 27 40 9 111 160 38 118 170 40 ++117 169 40 118 171 40 105 151 36 50 72 17 10 15 3 38 55 13 ++100 144 34 118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 79 115 27 15 21 5 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 10 15 3 64 92 22 111 160 38 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 118 171 40 96 138 32 32 47 11 ++3 4 1 50 72 17 107 154 36 120 173 41 105 151 36 31 45 11 ++0 0 0 0 0 0 0 0 0 3 4 1 65 94 22 117 169 40 ++118 170 40 89 128 30 26 37 9 3 4 1 60 86 20 111 161 38 ++118 171 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++97 141 33 36 52 12 1 1 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 14 20 5 75 109 26 117 168 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 118 171 40 107 154 36 ++45 64 15 2 3 1 31 45 11 75 109 26 32 47 11 0 1 0 ++0 0 0 0 0 0 0 0 0 0 0 0 10 15 3 55 80 19 ++65 94 22 11 16 4 11 16 4 75 109 26 116 168 40 118 170 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 107 154 36 ++47 69 16 3 4 1 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 12 18 4 69 100 23 111 161 38 118 171 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 118 170 40 ++111 160 38 50 72 17 2 3 1 2 3 1 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 ++1 1 0 12 18 4 81 118 28 118 170 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 170 40 118 171 40 101 146 34 ++42 61 14 2 3 1 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 3 4 1 36 52 12 89 128 30 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++118 171 41 101 146 34 14 20 5 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 47 69 16 118 170 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 170 40 111 160 38 69 100 23 19 27 6 ++0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 11 16 4 69 100 23 ++115 167 39 119 172 41 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++119 172 41 75 109 26 3 4 1 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 23 34 8 106 153 36 118 170 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++117 169 40 118 170 40 119 172 41 105 151 36 42 61 14 2 3 1 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 15 21 5 ++45 64 15 80 116 27 114 165 39 118 170 40 117 169 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 119 172 41 ++97 141 33 20 30 7 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 1 1 0 53 76 18 114 165 39 118 171 40 117 169 40 ++117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 117 169 40 ++118 171 40 104 150 35 64 92 22 31 45 11 10 15 3 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 36 52 12 97 141 33 109 158 37 113 163 39 116 168 40 ++117 169 40 117 170 40 118 170 40 119 172 41 115 167 39 84 121 28 ++23 34 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 3 4 1 50 72 17 102 148 35 118 171 40 ++119 171 41 118 170 40 117 169 40 117 169 40 115 166 39 111 161 38 ++109 157 37 79 115 27 12 18 4 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 3 4 1 15 21 5 23 34 8 45 64 15 106 153 36 ++116 167 40 111 160 38 101 146 34 79 115 27 42 61 14 10 15 3 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 1 1 0 20 30 7 60 86 20 ++89 128 30 106 153 36 113 163 39 117 169 40 84 121 28 29 42 10 ++19 27 6 10 15 3 2 3 1 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 16 23 5 38 55 13 ++36 52 12 26 37 9 12 18 4 2 3 1 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 1 0 0 19 2 7 52 5 18 ++78 7 27 88 8 31 81 7 29 56 5 19 25 2 9 3 0 1 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++3 4 1 19 27 6 31 45 11 38 55 13 32 47 11 3 4 1 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 ++9 0 3 12 1 4 9 0 3 4 0 1 0 0 0 0 0 0 ++0 0 0 0 0 0 28 3 10 99 9 35 156 14 55 182 16 64 ++189 17 66 190 17 67 189 17 66 184 17 65 166 15 58 118 13 41 ++45 4 16 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 11 1 4 52 5 18 101 9 35 134 12 47 ++151 14 53 154 14 54 151 14 53 113 10 40 11 1 4 0 0 0 ++3 0 1 67 6 24 159 14 56 190 17 67 190 17 67 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 191 17 67 ++174 16 61 101 9 35 14 1 5 0 0 0 35 3 12 108 10 38 ++122 11 43 122 11 43 112 10 39 87 8 30 50 5 17 13 1 5 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++3 0 1 56 5 19 141 13 49 182 16 64 191 17 67 191 17 67 ++190 17 67 190 17 67 191 17 67 113 10 40 3 0 1 1 0 0 ++79 7 28 180 16 63 190 17 67 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++189 17 66 188 17 66 122 11 43 11 1 4 41 4 14 176 16 62 ++191 17 67 191 17 67 191 17 67 190 17 67 181 16 63 146 13 51 ++75 7 26 10 1 4 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 1 2 ++90 8 32 178 16 62 191 17 67 188 17 66 188 17 66 188 17 66 ++188 17 66 190 17 67 141 13 49 22 2 8 0 0 0 41 4 14 ++173 16 61 190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 88 8 31 1 0 0 89 8 31 ++185 17 65 189 17 66 188 17 66 188 17 66 189 17 66 191 17 67 ++186 17 65 124 11 43 25 2 9 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 89 8 31 ++184 17 65 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++190 17 67 151 14 53 34 3 12 0 0 0 0 0 0 79 7 28 ++190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 191 17 67 146 13 51 9 1 3 7 1 2 ++108 10 38 187 17 66 189 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 190 17 67 141 13 49 22 2 8 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 52 5 18 176 16 62 ++189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 ++151 14 53 38 3 13 0 0 0 0 0 0 0 0 0 50 5 17 ++180 16 63 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 191 17 67 141 13 49 7 1 3 0 0 0 ++11 1 4 112 10 39 187 17 66 189 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 190 17 67 113 10 40 5 0 2 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 7 1 3 132 12 46 191 17 67 ++188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 146 13 51 ++35 3 12 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 ++101 9 35 185 17 65 190 17 67 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 190 17 67 180 16 63 67 6 24 0 0 0 0 0 0 ++0 0 0 11 1 4 108 10 38 186 17 65 189 17 66 188 17 66 ++188 17 66 188 17 66 189 17 66 180 16 63 56 5 19 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 44 4 15 177 16 62 189 17 66 ++188 17 66 188 17 66 189 17 66 189 17 66 134 12 47 28 3 10 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++8 1 3 79 7 28 159 14 56 188 17 66 191 17 67 190 17 67 ++189 17 66 189 17 66 189 17 66 189 17 66 190 17 67 191 17 67 ++188 17 66 158 14 55 72 7 25 4 0 1 0 0 0 0 0 0 ++0 0 0 0 0 0 8 1 3 95 9 33 182 16 64 189 17 67 ++188 17 66 188 17 66 188 17 66 191 17 67 122 11 43 3 0 1 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 88 8 31 190 17 67 188 17 66 ++188 17 66 189 17 66 185 17 65 113 10 40 18 2 6 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 1 0 0 24 2 8 77 7 27 124 11 43 154 14 54 ++168 15 59 173 16 61 173 16 61 168 15 59 154 14 54 124 11 43 ++77 7 27 22 2 8 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 5 0 2 77 7 27 173 16 61 ++190 17 67 188 17 66 188 17 66 190 17 67 164 15 57 23 2 8 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 1 0 0 118 13 41 191 17 67 188 17 66 ++190 17 67 174 16 61 87 8 30 8 1 3 0 0 0 0 0 0 ++0 0 0 0 0 0 10 1 4 29 3 10 40 4 14 36 3 13 ++18 2 6 2 0 1 0 0 0 0 0 0 3 0 1 14 1 5 ++26 2 9 33 3 11 32 3 11 25 2 9 13 1 5 3 0 1 ++0 0 0 14 1 5 56 5 19 95 9 33 109 10 38 101 9 35 ++77 7 27 35 3 12 5 0 2 0 0 0 1 0 0 56 5 19 ++156 14 55 190 17 67 188 17 66 188 17 66 182 16 64 50 5 17 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 5 0 2 134 12 47 191 17 67 189 17 66 ++151 14 53 52 5 18 2 0 1 0 0 0 0 0 0 1 0 0 ++28 3 10 90 8 32 146 13 51 170 15 60 178 16 62 174 16 61 ++158 14 55 112 10 39 40 4 14 1 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 ++56 5 19 146 13 51 183 17 64 191 17 67 191 17 67 191 17 67 ++188 17 66 173 16 61 122 11 43 41 4 14 1 0 0 0 0 0 ++30 3 10 124 11 43 185 17 65 190 17 67 187 17 66 67 6 24 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 6 1 2 134 12 47 168 15 59 99 9 35 ++21 2 7 0 0 0 0 0 0 0 0 0 6 1 2 77 7 27 ++162 15 57 190 17 67 191 17 67 189 17 66 189 17 66 189 17 66 ++190 17 67 191 17 67 169 15 59 75 7 26 3 0 1 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 79 7 28 ++178 16 62 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 189 17 66 191 17 67 170 15 60 79 7 28 5 0 2 ++0 0 0 10 1 3 78 7 27 159 14 56 188 17 66 75 7 26 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 1 0 0 35 3 12 29 3 10 2 0 1 ++0 0 0 0 0 0 0 0 0 9 1 3 101 9 35 183 17 64 ++190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 190 17 67 178 16 63 67 6 23 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 52 5 18 174 16 61 ++190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 190 17 67 182 16 64 89 8 31 ++4 0 1 0 0 0 0 0 0 25 2 9 73 7 26 31 3 11 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 4 0 1 98 9 34 187 17 66 189 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 190 17 67 158 14 55 25 2 9 ++0 0 0 0 0 0 0 0 0 8 1 3 134 12 47 191 17 67 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 180 16 63 ++68 6 24 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 6 1 2 19 2 7 3 0 1 0 0 0 0 0 0 ++0 0 0 0 0 0 65 6 23 180 16 63 189 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 83 8 29 ++0 0 0 0 0 0 0 0 0 41 4 14 177 16 62 189 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 ++159 14 56 28 3 10 0 0 0 0 0 0 0 0 0 23 2 8 ++41 4 14 5 0 2 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++23 2 8 113 10 40 159 14 56 65 6 23 0 0 0 0 0 0 ++0 0 0 16 1 6 146 13 51 191 17 67 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 132 12 46 ++5 0 2 0 0 0 0 0 0 77 7 27 189 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++190 17 67 98 9 34 0 0 0 0 0 0 12 1 4 134 12 47 ++178 16 63 108 10 38 16 1 6 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 30 3 10 ++141 13 49 190 17 67 191 17 67 134 12 47 6 1 2 0 0 0 ++0 0 0 68 6 24 186 17 65 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 156 14 55 ++14 1 5 0 0 0 0 0 0 98 9 34 191 17 67 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++190 17 67 156 14 55 19 2 7 0 0 0 47 4 16 181 16 63 ++190 17 67 189 17 66 126 14 44 17 2 6 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 16 1 6 134 12 47 ++191 17 67 188 17 66 190 17 67 162 15 57 19 2 7 0 0 0 ++3 0 1 123 11 43 191 17 67 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 163 15 57 ++20 2 7 0 0 0 0 0 0 101 9 35 191 17 67 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 182 16 64 52 5 18 0 0 0 73 7 26 188 17 66 ++188 17 66 188 17 66 189 17 66 109 10 38 5 0 2 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 95 9 33 189 17 66 ++188 17 66 188 17 66 189 17 66 171 15 60 29 3 10 0 0 0 ++16 1 6 156 14 55 190 17 67 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 158 14 55 ++17 2 6 0 0 0 0 0 0 85 8 30 190 17 67 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 189 17 66 81 7 29 0 0 0 85 8 30 190 17 67 ++188 17 66 188 17 66 189 17 66 180 16 63 56 5 19 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 25 2 9 162 15 57 190 17 67 ++188 17 66 188 17 66 189 17 66 173 16 61 31 3 11 0 0 0 ++30 3 10 171 15 60 189 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 141 13 49 ++7 1 2 0 0 0 0 0 0 56 5 19 183 17 64 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 191 17 67 98 9 34 0 0 0 88 8 31 190 17 67 ++188 17 66 188 17 66 188 17 66 191 17 67 124 11 43 5 0 2 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 68 6 24 187 17 66 188 17 66 ++188 17 66 188 17 66 189 17 66 170 15 60 28 3 10 0 0 0 ++34 3 12 174 16 61 189 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 101 9 35 ++0 0 0 0 0 0 0 0 0 21 2 7 159 14 56 190 17 67 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 191 17 67 98 9 34 0 0 0 81 7 29 189 17 66 ++188 17 66 188 17 66 188 17 66 189 17 66 168 15 59 28 3 10 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 109 10 38 191 17 67 188 17 66 ++188 17 66 188 17 66 190 17 67 163 15 57 21 2 7 0 0 0 ++26 2 9 168 15 59 189 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 189 17 66 180 16 63 47 4 16 ++0 0 0 0 0 0 0 0 0 0 0 0 108 10 38 190 17 67 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 189 17 66 78 7 27 0 0 0 68 6 24 187 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 183 17 64 56 5 19 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 3 0 1 131 12 46 191 17 67 188 17 66 ++188 17 66 188 17 66 190 17 67 151 14 53 12 1 4 0 0 0 ++11 1 4 146 13 51 190 17 67 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 191 17 67 126 14 44 7 1 2 ++0 0 0 0 0 0 0 0 0 0 0 0 32 3 11 164 15 58 ++190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++189 17 66 178 16 62 44 4 15 0 0 0 50 5 17 182 16 64 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 72 7 25 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 5 0 2 134 12 47 191 17 67 188 17 66 ++188 17 66 188 17 66 191 17 67 131 12 46 3 0 1 0 0 0 ++0 0 0 101 9 35 190 17 67 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 190 17 67 170 15 60 44 4 15 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 77 7 27 ++183 17 64 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++191 17 67 134 12 47 9 1 3 0 0 0 31 3 11 171 15 60 ++189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 72 7 25 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 2 0 1 124 11 43 191 17 67 188 17 66 ++188 17 66 188 17 66 191 17 67 101 9 35 0 0 0 0 0 0 ++0 0 0 35 3 12 168 15 59 190 17 67 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 189 17 66 182 16 64 77 7 27 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 1 2 ++99 9 35 185 17 65 189 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 ++177 16 62 56 5 19 0 0 0 0 0 0 13 1 5 151 14 53 ++190 17 67 188 17 66 188 17 66 188 17 66 185 17 65 56 5 19 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 99 9 35 191 17 67 188 17 66 ++188 17 66 188 17 66 186 17 65 65 6 23 0 0 0 0 0 0 ++0 0 0 0 0 0 79 7 28 182 16 64 190 17 67 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++191 17 67 177 16 62 83 8 29 4 0 1 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++8 1 3 89 8 31 175 16 62 191 17 67 189 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 181 16 63 ++85 8 30 3 0 1 0 0 0 0 0 0 1 0 0 118 13 41 ++191 17 67 188 17 66 188 17 66 189 17 66 173 16 61 34 3 12 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 56 5 19 183 17 64 188 17 66 ++188 17 66 189 17 66 169 15 59 30 3 10 0 0 0 0 0 0 ++0 0 0 0 0 0 5 0 2 83 8 29 173 16 61 191 17 67 ++190 17 67 189 17 66 189 17 66 190 17 67 191 17 67 187 17 66 ++151 14 53 56 5 19 3 0 1 0 0 0 16 1 6 50 5 17 ++79 7 28 95 9 33 95 9 33 75 7 26 41 4 14 10 1 4 ++0 0 0 2 0 1 50 5 17 132 12 46 178 16 62 190 17 67 ++191 17 67 191 17 67 191 17 67 186 17 65 154 14 54 68 6 24 ++4 0 1 0 0 0 0 0 0 0 0 0 0 0 0 72 7 25 ++187 17 66 188 17 66 188 17 66 191 17 67 141 13 49 9 1 3 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 14 1 5 151 14 53 190 17 67 ++188 17 66 191 17 67 131 12 46 5 0 2 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 2 0 1 44 4 15 113 10 40 ++156 14 55 173 16 61 174 16 61 164 15 58 134 12 47 77 7 27 ++18 2 6 0 0 0 16 1 6 85 8 30 151 14 53 182 16 64 ++189 17 66 191 17 67 190 17 67 188 17 66 177 16 62 141 13 49 ++68 6 24 8 1 3 0 0 0 8 1 3 44 4 15 88 8 31 ++113 10 40 122 11 43 108 10 38 67 6 24 20 2 7 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 28 3 10 ++166 15 58 190 17 67 188 17 66 187 17 66 79 7 28 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 73 7 26 185 17 65 ++189 17 66 184 17 65 65 6 23 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 ++17 2 6 32 3 11 34 3 12 22 2 8 6 1 2 0 0 0 ++0 0 0 38 3 13 141 13 49 188 17 66 190 17 67 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 191 17 67 ++184 17 65 122 11 43 21 2 7 0 0 0 0 0 0 0 0 0 ++0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 ++108 10 38 191 17 67 191 17 67 141 13 49 16 1 6 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 8 1 3 112 10 39 ++186 17 65 124 11 43 10 1 4 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++36 3 13 156 14 55 191 17 67 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++189 17 66 190 17 67 134 12 47 18 2 6 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 7 1 2 41 4 14 75 7 26 66 5 23 19 2 7 ++26 2 9 144 13 50 154 14 54 40 4 14 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 5 ++56 5 19 19 2 7 0 0 0 7 1 2 29 3 10 35 3 12 ++19 2 7 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 13 1 5 ++134 12 47 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 189 17 67 108 10 38 3 0 1 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 ++40 4 14 124 11 43 177 16 62 188 17 66 187 17 66 144 13 50 ++24 2 8 17 2 6 22 2 8 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 19 2 7 122 11 43 171 15 60 175 16 62 ++159 14 56 112 10 39 40 4 14 2 0 1 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 72 7 25 ++186 17 65 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 189 17 66 174 16 61 41 4 14 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 3 0 1 72 7 25 ++168 15 59 191 17 67 189 17 66 188 17 66 188 17 66 190 17 67 ++95 9 33 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 95 9 33 191 17 67 189 17 66 189 17 66 ++190 17 67 191 17 67 171 15 60 90 8 32 12 1 4 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 132 12 46 ++191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 190 17 67 98 9 34 0 0 0 ++0 0 0 0 0 0 0 0 0 5 0 2 88 8 31 180 16 63 ++190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 191 17 67 ++146 13 51 11 1 4 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 9 1 3 144 13 50 191 17 67 188 17 66 188 17 66 ++188 17 66 188 17 66 189 17 66 187 17 66 123 11 43 20 2 7 ++0 0 0 0 0 0 0 0 0 0 0 0 21 2 7 163 15 57 ++190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 191 17 67 134 12 47 5 0 2 ++0 0 0 0 0 0 3 0 1 88 8 31 182 16 64 189 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 ++171 15 60 31 3 11 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 20 2 7 162 15 57 190 17 67 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 132 12 46 ++20 2 7 0 0 0 0 0 0 0 0 0 32 3 11 173 16 61 ++189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 190 17 67 151 14 53 12 1 4 ++0 0 0 0 0 0 72 7 25 180 16 63 189 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++181 16 63 47 4 16 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 21 2 7 163 15 57 190 17 67 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 ++122 11 43 9 1 3 0 0 0 0 0 0 30 3 10 171 15 60 ++189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 190 17 67 146 13 51 10 1 4 ++0 0 0 38 3 13 166 15 58 190 17 67 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++183 17 64 52 5 18 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 13 1 5 154 14 54 190 17 67 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++186 17 65 79 7 28 0 0 0 0 0 0 14 1 5 156 14 54 ++190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 191 17 67 124 11 43 2 0 1 ++5 0 2 122 11 43 191 17 67 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++182 16 64 47 4 16 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 3 0 1 126 14 44 191 17 67 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++190 17 67 158 14 55 23 2 8 0 0 0 1 0 0 113 10 40 ++191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 78 7 27 0 0 0 ++47 4 16 177 16 62 189 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 189 17 66 ++173 16 61 34 3 12 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 85 8 30 189 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 79 7 28 0 0 0 0 0 0 47 4 16 ++175 16 62 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 190 17 67 156 14 55 22 2 8 0 0 0 ++109 10 38 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 ++151 14 53 13 1 5 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 35 3 12 173 16 61 189 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 191 17 67 134 12 47 7 1 2 0 0 0 3 0 1 ++99 9 35 188 17 66 189 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 189 17 66 181 16 63 68 6 24 0 0 0 18 2 6 ++156 14 55 190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 ++101 9 35 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 3 0 1 118 13 41 191 17 67 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 189 17 66 168 15 59 28 3 10 0 0 0 0 0 0 ++12 1 4 113 10 40 187 17 66 189 17 67 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++190 17 67 180 16 63 88 8 31 4 0 1 0 0 0 47 4 16 ++180 16 63 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 190 17 67 168 15 59 ++36 3 13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 38 3 13 164 15 58 190 17 67 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 182 16 64 50 5 17 0 0 0 0 0 0 ++0 0 0 11 1 4 90 8 32 169 15 59 190 17 67 190 17 67 ++189 17 66 189 17 66 189 17 66 189 17 66 191 17 67 189 17 66 ++158 14 55 68 6 24 4 0 1 0 0 0 0 0 0 73 7 26 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 189 17 66 185 17 65 83 8 29 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 65 6 23 174 16 61 ++190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 185 17 65 56 5 19 0 0 0 0 0 0 ++0 0 0 0 0 0 2 0 1 35 3 12 99 9 35 146 13 51 ++170 15 60 177 16 62 177 16 62 166 15 58 141 13 49 85 8 30 ++24 2 8 0 0 0 0 0 0 0 0 0 0 0 0 85 8 30 ++190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 189 17 66 112 10 39 8 1 3 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 68 6 24 ++170 15 60 191 17 67 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 182 16 64 50 5 17 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 11 1 4 ++28 3 10 40 4 14 38 3 13 25 2 9 8 1 3 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 7 27 ++189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 189 17 66 187 17 66 113 10 40 14 1 5 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 ++47 4 16 141 13 49 186 17 65 191 17 67 190 17 67 189 17 66 ++189 17 66 191 17 67 156 14 55 20 2 7 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 4 15 ++178 16 62 190 17 67 188 17 66 188 17 66 188 17 66 190 17 67 ++191 17 67 173 16 61 90 8 32 10 1 4 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 14 1 5 68 6 24 131 12 46 162 15 57 174 16 61 ++171 15 60 146 13 51 56 5 19 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 3 0 1 14 1 5 29 3 10 ++41 4 14 47 4 16 50 5 17 45 4 16 34 3 12 18 2 6 ++5 0 2 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 ++90 8 32 169 15 59 185 17 65 187 17 66 182 16 64 163 15 57 ++113 10 40 41 4 14 2 0 1 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 5 0 2 21 2 7 34 3 12 ++29 3 10 11 1 4 0 0 0 0 0 0 0 0 0 0 0 0 ++3 0 1 32 3 11 79 7 28 124 11 43 154 14 54 171 15 60 ++180 16 63 182 16 64 182 16 64 180 16 63 174 16 61 159 14 56 ++132 12 46 88 8 31 34 3 12 3 0 1 0 0 0 0 0 0 ++3 0 1 29 3 10 56 5 19 65 6 23 50 5 17 23 2 8 ++3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 2 9 ++109 10 38 169 15 59 189 17 66 191 17 67 190 17 67 189 17 66 ++189 17 66 188 17 66 188 17 66 188 17 66 189 17 66 190 17 67 ++191 17 67 190 17 67 171 15 60 98 9 34 10 1 3 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 14 1 5 141 13 49 ++191 17 67 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 189 17 67 186 17 65 65 6 23 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 23 2 8 166 15 58 ++190 17 67 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 189 17 66 176 16 62 45 4 16 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 83 8 29 ++183 17 64 189 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++188 17 66 189 17 66 185 17 65 95 9 33 3 0 1 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 ++85 8 30 176 16 62 191 17 67 188 17 66 188 17 66 188 17 66 ++188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 188 17 66 ++191 17 67 180 16 63 95 9 33 7 1 3 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++2 0 1 52 5 18 141 13 49 185 17 65 191 17 67 189 17 67 ++189 17 66 188 17 66 188 17 66 189 17 66 191 17 67 187 17 66 ++146 13 51 56 5 19 4 0 1 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 14 1 5 68 6 24 131 12 46 166 15 58 ++180 16 63 183 17 64 180 16 63 168 15 59 134 12 47 75 7 26 ++17 2 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 5 0 2 24 2 8 ++44 4 15 52 5 18 45 4 16 26 2 9 6 1 2 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ++0 0 0 0 0 0 0 0 0 +diff -Nur linux-3.10.33/drivers/video/Makefile linux-raspberry-pi/drivers/video/Makefile +--- linux-3.10.33/drivers/video/Makefile 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/video/Makefile 2014-03-13 12:46:40.288099538 +0100 +@@ -100,6 +100,7 @@ + obj-$(CONFIG_FB_VOODOO1) += sstfb.o + obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o + obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o ++obj-$(CONFIG_FB_BCM2708) += bcm2708_fb.o + obj-$(CONFIG_FB_68328) += 68328fb.o + obj-$(CONFIG_FB_GBE) += gbefb.o + obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o +diff -Nur linux-3.10.33/drivers/w1/masters/w1-gpio.c linux-raspberry-pi/drivers/w1/masters/w1-gpio.c +--- linux-3.10.33/drivers/w1/masters/w1-gpio.c 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/w1/masters/w1-gpio.c 2014-03-13 12:46:40.752100469 +0100 +@@ -23,6 +23,9 @@ + #include "../w1.h" + #include "../w1_int.h" + ++static int w1_gpio_pullup = 0; ++module_param_named(pullup, w1_gpio_pullup, int, 0); ++ + static void w1_gpio_write_bit_dir(void *data, u8 bit) + { + struct w1_gpio_platform_data *pdata = data; +@@ -47,6 +50,16 @@ + return gpio_get_value(pdata->pin) ? 1 : 0; + } + ++static void w1_gpio_bitbang_pullup(void *data, u8 on) ++{ ++ struct w1_gpio_platform_data *pdata = data; ++ ++ if (on) ++ gpio_direction_output(pdata->pin, 1); ++ else ++ gpio_direction_input(pdata->pin); ++} ++ + #if defined(CONFIG_OF) + static struct of_device_id w1_gpio_dt_ids[] = { + { .compatible = "w1-gpio" }, +@@ -133,6 +146,13 @@ + master->write_bit = w1_gpio_write_bit_dir; + } + ++ if (w1_gpio_pullup) ++ if (pdata->is_open_drain) ++ printk(KERN_ERR "w1-gpio 'pullup' option " ++ "doesn't work with open drain GPIO\n"); ++ else ++ master->bitbang_pullup = w1_gpio_bitbang_pullup; ++ + err = w1_add_master_device(master); + if (err) { + dev_err(&pdev->dev, "w1_add_master device failed\n"); +diff -Nur linux-3.10.33/drivers/w1/w1.h linux-raspberry-pi/drivers/w1/w1.h +--- linux-3.10.33/drivers/w1/w1.h 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/w1/w1.h 2014-03-13 12:46:40.756100477 +0100 +@@ -148,6 +148,12 @@ + */ + u8 (*set_pullup)(void *, int); + ++ /** ++ * Turns the pullup on/off in bitbanging mode, takes an on/off argument. ++ * @return -1=Error, 0=completed ++ */ ++ void (*bitbang_pullup) (void *, u8); ++ + /** Really nice hardware can handles the different types of ROM search + * w1_master* is passed to the slave found callback. + */ +diff -Nur linux-3.10.33/drivers/w1/w1_int.c linux-raspberry-pi/drivers/w1/w1_int.c +--- linux-3.10.33/drivers/w1/w1_int.c 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/w1/w1_int.c 2014-03-13 12:46:40.756100477 +0100 +@@ -117,19 +117,21 @@ + printk(KERN_ERR "w1_add_master_device: invalid function set\n"); + return(-EINVAL); + } +- /* While it would be electrically possible to make a device that +- * generated a strong pullup in bit bang mode, only hardware that +- * controls 1-wire time frames are even expected to support a strong +- * pullup. w1_io.c would need to support calling set_pullup before +- * the last write_bit operation of a w1_write_8 which it currently +- * doesn't. +- */ ++ ++ /* bitbanging hardware uses bitbang_pullup, other hardware uses set_pullup ++ * and takes care of timing itself */ + if (!master->write_byte && !master->touch_bit && master->set_pullup) { + printk(KERN_ERR "w1_add_master_device: set_pullup requires " + "write_byte or touch_bit, disabling\n"); + master->set_pullup = NULL; + } + ++ if (master->set_pullup && master->bitbang_pullup) { ++ printk(KERN_ERR "w1_add_master_device: set_pullup should not " ++ "be set when bitbang_pullup is used, disabling\n"); ++ master->set_pullup = NULL; ++ } ++ + /* Lock until the device is added (or not) to w1_masters. */ + mutex_lock(&w1_mlock); + /* Search for the first available id (starting at 1). */ +diff -Nur linux-3.10.33/drivers/w1/w1_io.c linux-raspberry-pi/drivers/w1/w1_io.c +--- linux-3.10.33/drivers/w1/w1_io.c 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/w1/w1_io.c 2014-03-13 12:46:40.756100477 +0100 +@@ -127,10 +127,22 @@ + static void w1_post_write(struct w1_master *dev) + { + if (dev->pullup_duration) { +- if (dev->enable_pullup && dev->bus_master->set_pullup) +- dev->bus_master->set_pullup(dev->bus_master->data, 0); +- else ++ if (dev->enable_pullup) { ++ if (dev->bus_master->set_pullup) { ++ dev->bus_master->set_pullup(dev-> ++ bus_master->data, ++ 0); ++ } else if (dev->bus_master->bitbang_pullup) { ++ dev->bus_master-> ++ bitbang_pullup(dev->bus_master->data, 1); + msleep(dev->pullup_duration); ++ dev->bus_master-> ++ bitbang_pullup(dev->bus_master->data, 0); ++ } ++ } else { ++ msleep(dev->pullup_duration); ++ } ++ + dev->pullup_duration = 0; + } + } +diff -Nur linux-3.10.33/drivers/watchdog/bcm2708_wdog.c linux-raspberry-pi/drivers/watchdog/bcm2708_wdog.c +--- linux-3.10.33/drivers/watchdog/bcm2708_wdog.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/drivers/watchdog/bcm2708_wdog.c 2014-03-13 12:46:40.756100477 +0100 +@@ -0,0 +1,385 @@ ++/* ++ * Broadcom BCM2708 watchdog driver. ++ * ++ * (c) Copyright 2010 Broadcom Europe 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. ++ * ++ * BCM2708 watchdog driver. Loosely based on wdt driver. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define SECS_TO_WDOG_TICKS(x) ((x) << 16) ++#define WDOG_TICKS_TO_SECS(x) ((x) >> 16) ++ ++static unsigned long wdog_is_open; ++static uint32_t wdog_ticks; /* Ticks to load into wdog timer */ ++static char expect_close; ++ ++/* ++ * Module parameters ++ */ ++ ++#define WD_TIMO 10 /* Default heartbeat = 60 seconds */ ++static int heartbeat = WD_TIMO; /* Heartbeat in seconds */ ++ ++module_param(heartbeat, int, 0); ++MODULE_PARM_DESC(heartbeat, ++ "Watchdog heartbeat in seconds. (0 < heartbeat < 65536, default=" ++ __MODULE_STRING(WD_TIMO) ")"); ++ ++static int nowayout = WATCHDOG_NOWAYOUT; ++module_param(nowayout, int, 0); ++MODULE_PARM_DESC(nowayout, ++ "Watchdog cannot be stopped once started (default=" ++ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); ++ ++static DEFINE_SPINLOCK(wdog_lock); ++ ++/** ++ * Start the watchdog driver. ++ */ ++ ++static int wdog_start(unsigned long timeout) ++{ ++ uint32_t cur; ++ unsigned long flags; ++ spin_lock_irqsave(&wdog_lock, flags); ++ ++ /* enable the watchdog */ ++ iowrite32(PM_PASSWORD | (timeout & PM_WDOG_TIME_SET), ++ __io_address(PM_WDOG)); ++ cur = ioread32(__io_address(PM_RSTC)); ++ iowrite32(PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) | ++ PM_RSTC_WRCFG_FULL_RESET, __io_address(PM_RSTC)); ++ ++ spin_unlock_irqrestore(&wdog_lock, flags); ++ return 0; ++} ++ ++/** ++ * Stop the watchdog driver. ++ */ ++ ++static int wdog_stop(void) ++{ ++ iowrite32(PM_PASSWORD | PM_RSTC_RESET, __io_address(PM_RSTC)); ++ printk(KERN_INFO "watchdog stopped\n"); ++ return 0; ++} ++ ++/** ++ * Reload counter one with the watchdog heartbeat. We don't bother ++ * reloading the cascade counter. ++ */ ++ ++static void wdog_ping(void) ++{ ++ wdog_start(wdog_ticks); ++} ++ ++/** ++ * @t: the new heartbeat value that needs to be set. ++ * ++ * Set a new heartbeat value for the watchdog device. If the heartbeat ++ * value is incorrect we keep the old value and return -EINVAL. If ++ * successful we return 0. ++ */ ++ ++static int wdog_set_heartbeat(int t) ++{ ++ if (t < 1 || t > WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET)) ++ return -EINVAL; ++ ++ heartbeat = t; ++ wdog_ticks = SECS_TO_WDOG_TICKS(t); ++ return 0; ++} ++ ++/** ++ * @file: file handle to the watchdog ++ * @buf: buffer to write (unused as data does not matter here ++ * @count: count of bytes ++ * @ppos: pointer to the position to write. No seeks allowed ++ * ++ * A write to a watchdog device is defined as a keepalive signal. ++ * ++ * if 'nowayout' is set then normally a close() is ignored. But ++ * if you write 'V' first then the close() will stop the timer. ++ */ ++ ++static ssize_t wdog_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ if (count) { ++ if (!nowayout) { ++ size_t i; ++ ++ /* In case it was set long ago */ ++ expect_close = 0; ++ ++ for (i = 0; i != count; i++) { ++ char c; ++ if (get_user(c, buf + i)) ++ return -EFAULT; ++ if (c == 'V') ++ expect_close = 42; ++ } ++ } ++ wdog_ping(); ++ } ++ return count; ++} ++ ++static int wdog_get_status(void) ++{ ++ unsigned long flags; ++ int status = 0; ++ spin_lock_irqsave(&wdog_lock, flags); ++ /* FIXME: readback reset reason */ ++ spin_unlock_irqrestore(&wdog_lock, flags); ++ return status; ++} ++ ++static uint32_t wdog_get_remaining(void) ++{ ++ uint32_t ret = ioread32(__io_address(PM_WDOG)); ++ return ret & PM_WDOG_TIME_SET; ++} ++ ++/** ++ * @file: file handle to the device ++ * @cmd: watchdog command ++ * @arg: argument pointer ++ * ++ * The watchdog API defines a common set of functions for all watchdogs ++ * according to their available features. We only actually usefully support ++ * querying capabilities and current status. ++ */ ++ ++static long wdog_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ int __user *p = argp; ++ int new_heartbeat; ++ int status; ++ int options; ++ uint32_t remaining; ++ ++ struct watchdog_info ident = { ++ .options = WDIOF_SETTIMEOUT| ++ WDIOF_MAGICCLOSE| ++ WDIOF_KEEPALIVEPING, ++ .firmware_version = 1, ++ .identity = "BCM2708", ++ }; ++ ++ switch (cmd) { ++ case WDIOC_GETSUPPORT: ++ return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; ++ case WDIOC_GETSTATUS: ++ status = wdog_get_status(); ++ return put_user(status, p); ++ case WDIOC_GETBOOTSTATUS: ++ return put_user(0, p); ++ case WDIOC_KEEPALIVE: ++ wdog_ping(); ++ return 0; ++ case WDIOC_SETTIMEOUT: ++ if (get_user(new_heartbeat, p)) ++ return -EFAULT; ++ if (wdog_set_heartbeat(new_heartbeat)) ++ return -EINVAL; ++ wdog_ping(); ++ /* Fall */ ++ case WDIOC_GETTIMEOUT: ++ return put_user(heartbeat, p); ++ case WDIOC_GETTIMELEFT: ++ remaining = WDOG_TICKS_TO_SECS(wdog_get_remaining()); ++ return put_user(remaining, p); ++ case WDIOC_SETOPTIONS: ++ if (get_user(options, p)) ++ return -EFAULT; ++ if (options & WDIOS_DISABLECARD) ++ wdog_stop(); ++ if (options & WDIOS_ENABLECARD) ++ wdog_start(wdog_ticks); ++ return 0; ++ default: ++ return -ENOTTY; ++ } ++} ++ ++/** ++ * @inode: inode of device ++ * @file: file handle to device ++ * ++ * The watchdog device has been opened. The watchdog device is single ++ * open and on opening we load the counters. ++ */ ++ ++static int wdog_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(0, &wdog_is_open)) ++ return -EBUSY; ++ /* ++ * Activate ++ */ ++ wdog_start(wdog_ticks); ++ return nonseekable_open(inode, file); ++} ++ ++/** ++ * @inode: inode to board ++ * @file: file handle to board ++ * ++ * The watchdog has a configurable API. There is a religious dispute ++ * between people who want their watchdog to be able to shut down and ++ * those who want to be sure if the watchdog manager dies the machine ++ * reboots. In the former case we disable the counters, in the latter ++ * case you have to open it again very soon. ++ */ ++ ++static int wdog_release(struct inode *inode, struct file *file) ++{ ++ if (expect_close == 42) { ++ wdog_stop(); ++ } else { ++ printk(KERN_CRIT ++ "wdt: WDT device closed unexpectedly. WDT will not stop!\n"); ++ wdog_ping(); ++ } ++ clear_bit(0, &wdog_is_open); ++ expect_close = 0; ++ return 0; ++} ++ ++/** ++ * @this: our notifier block ++ * @code: the event being reported ++ * @unused: unused ++ * ++ * Our notifier is called on system shutdowns. Turn the watchdog ++ * off so that it does not fire during the next reboot. ++ */ ++ ++static int wdog_notify_sys(struct notifier_block *this, unsigned long code, ++ void *unused) ++{ ++ if (code == SYS_DOWN || code == SYS_HALT) ++ wdog_stop(); ++ return NOTIFY_DONE; ++} ++ ++/* ++ * Kernel Interfaces ++ */ ++ ++ ++static const struct file_operations wdog_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .write = wdog_write, ++ .unlocked_ioctl = wdog_ioctl, ++ .open = wdog_open, ++ .release = wdog_release, ++}; ++ ++static struct miscdevice wdog_miscdev = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = &wdog_fops, ++}; ++ ++/* ++ * The WDT card needs to learn about soft shutdowns in order to ++ * turn the timebomb registers off. ++ */ ++ ++static struct notifier_block wdog_notifier = { ++ .notifier_call = wdog_notify_sys, ++}; ++ ++/** ++ * cleanup_module: ++ * ++ * Unload the watchdog. You cannot do this with any file handles open. ++ * If your watchdog is set to continue ticking on close and you unload ++ * it, well it keeps ticking. We won't get the interrupt but the board ++ * will not touch PC memory so all is fine. You just have to load a new ++ * module in 60 seconds or reboot. ++ */ ++ ++static void __exit wdog_exit(void) ++{ ++ misc_deregister(&wdog_miscdev); ++ unregister_reboot_notifier(&wdog_notifier); ++} ++ ++static int __init wdog_init(void) ++{ ++ int ret; ++ ++ /* Check that the heartbeat value is within it's range; ++ if not reset to the default */ ++ if (wdog_set_heartbeat(heartbeat)) { ++ wdog_set_heartbeat(WD_TIMO); ++ printk(KERN_INFO "bcm2708_wdog: heartbeat value must be " ++ "0 < heartbeat < %d, using %d\n", ++ WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET), ++ WD_TIMO); ++ } ++ ++ ret = register_reboot_notifier(&wdog_notifier); ++ if (ret) { ++ printk(KERN_ERR ++ "wdt: cannot register reboot notifier (err=%d)\n", ret); ++ goto out_reboot; ++ } ++ ++ ret = misc_register(&wdog_miscdev); ++ if (ret) { ++ printk(KERN_ERR ++ "wdt: cannot register miscdev on minor=%d (err=%d)\n", ++ WATCHDOG_MINOR, ret); ++ goto out_misc; ++ } ++ ++ printk(KERN_INFO "bcm2708 watchdog, heartbeat=%d sec (nowayout=%d)\n", ++ heartbeat, nowayout); ++ return 0; ++ ++out_misc: ++ unregister_reboot_notifier(&wdog_notifier); ++out_reboot: ++ return ret; ++} ++ ++module_init(wdog_init); ++module_exit(wdog_exit); ++ ++MODULE_AUTHOR("Luke Diamand"); ++MODULE_DESCRIPTION("Driver for BCM2708 watchdog"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ++MODULE_ALIAS_MISCDEV(TEMP_MINOR); ++MODULE_LICENSE("GPL"); ++ +diff -Nur linux-3.10.33/drivers/watchdog/Kconfig linux-raspberry-pi/drivers/watchdog/Kconfig +--- linux-3.10.33/drivers/watchdog/Kconfig 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/watchdog/Kconfig 2014-03-13 12:46:40.756100477 +0100 +@@ -391,6 +391,12 @@ + To compile this driver as a module, choose M here: the + module will be called retu_wdt. + ++config BCM2708_WDT ++ tristate "BCM2708 Watchdog" ++ depends on ARCH_BCM2708 ++ help ++ Enables BCM2708 watchdog support. ++ + # AVR32 Architecture + + config AT32AP700X_WDT +diff -Nur linux-3.10.33/drivers/watchdog/Makefile linux-raspberry-pi/drivers/watchdog/Makefile +--- linux-3.10.33/drivers/watchdog/Makefile 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/drivers/watchdog/Makefile 2014-03-13 12:46:40.756100477 +0100 +@@ -54,6 +54,7 @@ + obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o + obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o + obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o ++obj-$(CONFIG_BCM2708_WDT) += bcm2708_wdog.o + + # AVR32 Architecture + obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o +diff -Nur linux-3.10.33/include/linux/broadcom/vc_cma.h linux-raspberry-pi/include/linux/broadcom/vc_cma.h +--- linux-3.10.33/include/linux/broadcom/vc_cma.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/include/linux/broadcom/vc_cma.h 2014-03-13 12:46:41.852102677 +0100 +@@ -0,0 +1,30 @@ ++/***************************************************************************** ++* Copyright 2012 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++#if !defined( VC_CMA_H ) ++#define VC_CMA_H ++ ++#include ++ ++#define VC_CMA_IOC_MAGIC 0xc5 ++ ++#define VC_CMA_IOC_RESERVE _IO(VC_CMA_IOC_MAGIC, 0) ++ ++#ifdef __KERNEL__ ++extern void __init vc_cma_early_init(void); ++extern void __init vc_cma_reserve(void); ++#endif ++ ++#endif /* VC_CMA_H */ ++ +diff -Nur linux-3.10.33/include/linux/mmc/host.h linux-raspberry-pi/include/linux/mmc/host.h +--- linux-3.10.33/include/linux/mmc/host.h 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/include/linux/mmc/host.h 2014-03-13 12:46:42.008102990 +0100 +@@ -281,6 +281,7 @@ + #define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \ + MMC_CAP2_PACKED_WR) + #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */ ++#define MMC_CAP2_FORCE_MULTIBLOCK (1 << 31) /* Always use multiblock transfers */ + + mmc_pm_flag_t pm_caps; /* supported pm features */ + +diff -Nur linux-3.10.33/include/linux/mmc/sdhci.h linux-raspberry-pi/include/linux/mmc/sdhci.h +--- linux-3.10.33/include/linux/mmc/sdhci.h 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/include/linux/mmc/sdhci.h 2014-03-13 12:46:42.008102990 +0100 +@@ -97,6 +97,7 @@ + #define SDHCI_QUIRK2_PRESET_VALUE_BROKEN (1<<3) + + int irq; /* Device IRQ */ ++ int second_irq; /* Additional IRQ to disable/enable in low-latency mode */ + void __iomem *ioaddr; /* Mapped address */ + + const struct sdhci_ops *ops; /* Low level hw interface */ +@@ -128,6 +129,7 @@ + #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */ + #define SDHCI_HS200_NEEDS_TUNING (1<<10) /* HS200 needs tuning */ + #define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */ ++#define SDHCI_USE_PLATDMA (1<<12) /* Host uses 3rd party DMA */ + + unsigned int version; /* SDHCI spec. version */ + +@@ -142,6 +144,7 @@ + + struct mmc_request *mrq; /* Current request */ + struct mmc_command *cmd; /* Current command */ ++ int last_cmdop; /* Opcode of last cmd sent */ + struct mmc_data *data; /* Current data request */ + unsigned int data_early:1; /* Data finished before cmd */ + +diff -Nur linux-3.10.33/include/sound/soc-dai.h linux-raspberry-pi/include/sound/soc-dai.h +--- linux-3.10.33/include/sound/soc-dai.h 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/include/sound/soc-dai.h 2014-03-13 12:46:42.236103447 +0100 +@@ -105,6 +105,8 @@ + int snd_soc_dai_set_pll(struct snd_soc_dai *dai, + int pll_id, int source, unsigned int freq_in, unsigned int freq_out); + ++int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio); ++ + /* Digital Audio interface formatting */ + int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); + +@@ -131,6 +133,7 @@ + int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out); + int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div); ++ int (*set_bclk_ratio)(struct snd_soc_dai *dai, unsigned int ratio); + + /* + * DAI format configuration +diff -Nur linux-3.10.33/include/uapi/linux/fb.h linux-raspberry-pi/include/uapi/linux/fb.h +--- linux-3.10.33/include/uapi/linux/fb.h 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/include/uapi/linux/fb.h 2014-03-13 12:46:42.300103576 +0100 +@@ -34,6 +34,11 @@ + #define FBIOPUT_MODEINFO 0x4617 + #define FBIOGET_DISPINFO 0x4618 + #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) ++/* ++ * HACK: use 'z' in order not to clash with any other ioctl numbers which might ++ * be concurrently added to the mainline kernel ++ */ ++#define FBIOCOPYAREA _IOW('z', 0x21, struct fb_copyarea) + + #define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */ + #define FB_TYPE_PLANES 1 /* Non interleaved planes */ +diff -Nur linux-3.10.33/kernel/cgroup.c linux-raspberry-pi/kernel/cgroup.c +--- linux-3.10.33/kernel/cgroup.c 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/kernel/cgroup.c 2014-03-13 12:46:42.456103889 +0100 +@@ -5127,6 +5127,37 @@ + } + __setup("cgroup_disable=", cgroup_disable); + ++static int __init cgroup_enable(char *str) ++{ ++ int i; ++ char *token; ++ ++ while ((token = strsep(&str, ",")) != NULL) { ++ if (!*token) ++ continue; ++ for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { ++ struct cgroup_subsys *ss = subsys[i]; ++ ++ /* ++ * cgroup_enable, being at boot time, can't ++ * know about module subsystems, so we don't ++ * worry about them. ++ */ ++ if (!ss || ss->module) ++ continue; ++ ++ if (!strcmp(token, ss->name)) { ++ ss->disabled = 0; ++ printk(KERN_INFO "Enabling %s control group" ++ " subsystem\n", ss->name); ++ break; ++ } ++ } ++ } ++ return 1; ++} ++__setup("cgroup_enable=", cgroup_enable); ++ + /* + * Functons for CSS ID. + */ +diff -Nur linux-3.10.33/mm/memcontrol.c linux-raspberry-pi/mm/memcontrol.c +--- linux-3.10.33/mm/memcontrol.c 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/mm/memcontrol.c 2014-03-13 12:46:42.696104370 +0100 +@@ -6956,6 +6956,7 @@ + .base_cftypes = mem_cgroup_files, + .early_init = 0, + .use_id = 1, ++ .disabled = 1, + }; + + #ifdef CONFIG_MEMCG_SWAP +diff -Nur linux-3.10.33/sound/arm/bcm2835.c linux-raspberry-pi/sound/arm/bcm2835.c +--- linux-3.10.33/sound/arm/bcm2835.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/arm/bcm2835.c 2014-03-13 12:46:44.060107108 +0100 +@@ -0,0 +1,413 @@ ++/***************************************************************************** ++* Copyright 2011 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include "bcm2835.h" ++ ++/* module parameters (see "Module Parameters") */ ++/* SNDRV_CARDS: maximum number of cards supported by this module */ ++static int index[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = -1 }; ++static char *id[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = NULL }; ++static int enable[MAX_SUBSTREAMS] = {[0 ... (MAX_SUBSTREAMS - 1)] = 1 }; ++ ++/* HACKY global pointers needed for successive probes to work : ssp ++ * But compared against the changes we will have to do in VC audio_ipc code ++ * to export 8 audio_ipc devices as a single IPC device and then monitor all ++ * four devices in a thread, this gets things done quickly and should be easier ++ * to debug if we run into issues ++ */ ++ ++static struct snd_card *g_card = NULL; ++static bcm2835_chip_t *g_chip = NULL; ++ ++static int snd_bcm2835_free(bcm2835_chip_t * chip) ++{ ++ kfree(chip); ++ return 0; ++} ++ ++/* component-destructor ++ * (see "Management of Cards and Components") ++ */ ++static int snd_bcm2835_dev_free(struct snd_device *device) ++{ ++ return snd_bcm2835_free(device->device_data); ++} ++ ++/* chip-specific constructor ++ * (see "Management of Cards and Components") ++ */ ++static int snd_bcm2835_create(struct snd_card *card, ++ struct platform_device *pdev, ++ bcm2835_chip_t ** rchip) ++{ ++ bcm2835_chip_t *chip; ++ int err; ++ static struct snd_device_ops ops = { ++ .dev_free = snd_bcm2835_dev_free, ++ }; ++ ++ *rchip = NULL; ++ ++ chip = kzalloc(sizeof(*chip), GFP_KERNEL); ++ if (chip == NULL) ++ return -ENOMEM; ++ ++ chip->card = card; ++ ++ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); ++ if (err < 0) { ++ snd_bcm2835_free(chip); ++ return err; ++ } ++ ++ *rchip = chip; ++ return 0; ++} ++ ++static int snd_bcm2835_alsa_probe(struct platform_device *pdev) ++{ ++ static int dev; ++ bcm2835_chip_t *chip; ++ struct snd_card *card; ++ int err; ++ ++ if (dev >= MAX_SUBSTREAMS) ++ return -ENODEV; ++ ++ if (!enable[dev]) { ++ dev++; ++ return -ENOENT; ++ } ++ ++ if (dev > 0) ++ goto add_register_map; ++ ++ err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &g_card); ++ if (err < 0) ++ goto out; ++ ++ snd_card_set_dev(g_card, &pdev->dev); ++ strcpy(g_card->driver, "BRCM bcm2835 ALSA Driver"); ++ strcpy(g_card->shortname, "bcm2835 ALSA"); ++ sprintf(g_card->longname, "%s", g_card->shortname); ++ ++ err = snd_bcm2835_create(g_card, pdev, &chip); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Failed to create bcm2835 chip\n"); ++ goto out_bcm2835_create; ++ } ++ ++ g_chip = chip; ++ err = snd_bcm2835_new_pcm(chip); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n"); ++ goto out_bcm2835_new_pcm; ++ } ++ ++ err = snd_bcm2835_new_ctl(chip); ++ if (err < 0) { ++ dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n"); ++ goto out_bcm2835_new_ctl; ++ } ++ ++add_register_map: ++ card = g_card; ++ chip = g_chip; ++ ++ BUG_ON(!(card && chip)); ++ ++ chip->avail_substreams |= (1 << dev); ++ chip->pdev[dev] = pdev; ++ ++ if (dev == 0) { ++ err = snd_card_register(card); ++ if (err < 0) { ++ dev_err(&pdev->dev, ++ "Failed to register bcm2835 ALSA card \n"); ++ goto out_card_register; ++ } ++ platform_set_drvdata(pdev, card); ++ audio_info("bcm2835 ALSA card created!\n"); ++ } else { ++ audio_info("bcm2835 ALSA chip created!\n"); ++ platform_set_drvdata(pdev, (void *)dev); ++ } ++ ++ dev++; ++ ++ return 0; ++ ++out_card_register: ++out_bcm2835_new_ctl: ++out_bcm2835_new_pcm: ++out_bcm2835_create: ++ BUG_ON(!g_card); ++ if (snd_card_free(g_card)) ++ dev_err(&pdev->dev, "Failed to free Registered alsa card\n"); ++ g_card = NULL; ++out: ++ dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */ ++ dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n"); ++ return err; ++} ++ ++static int snd_bcm2835_alsa_remove(struct platform_device *pdev) ++{ ++ uint32_t idx; ++ void *drv_data; ++ ++ drv_data = platform_get_drvdata(pdev); ++ ++ if (drv_data == (void *)g_card) { ++ /* This is the card device */ ++ snd_card_free((struct snd_card *)drv_data); ++ g_card = NULL; ++ g_chip = NULL; ++ } else { ++ idx = (uint32_t) drv_data; ++ if (g_card != NULL) { ++ BUG_ON(!g_chip); ++ /* We pass chip device numbers in audio ipc devices ++ * other than the one we registered our card with ++ */ ++ idx = (uint32_t) drv_data; ++ BUG_ON(!idx || idx > MAX_SUBSTREAMS); ++ g_chip->avail_substreams &= ~(1 << idx); ++ /* There should be atleast one substream registered ++ * after we are done here, as it wil be removed when ++ * the *remove* is called for the card device ++ */ ++ BUG_ON(!g_chip->avail_substreams); ++ } ++ } ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int snd_bcm2835_alsa_suspend(struct platform_device *pdev, ++ pm_message_t state) ++{ ++ return 0; ++} ++ ++static int snd_bcm2835_alsa_resume(struct platform_device *pdev) ++{ ++ return 0; ++} ++ ++#endif ++ ++static struct platform_driver bcm2835_alsa0_driver = { ++ .probe = snd_bcm2835_alsa_probe, ++ .remove = snd_bcm2835_alsa_remove, ++#ifdef CONFIG_PM ++ .suspend = snd_bcm2835_alsa_suspend, ++ .resume = snd_bcm2835_alsa_resume, ++#endif ++ .driver = { ++ .name = "bcm2835_AUD0", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static struct platform_driver bcm2835_alsa1_driver = { ++ .probe = snd_bcm2835_alsa_probe, ++ .remove = snd_bcm2835_alsa_remove, ++#ifdef CONFIG_PM ++ .suspend = snd_bcm2835_alsa_suspend, ++ .resume = snd_bcm2835_alsa_resume, ++#endif ++ .driver = { ++ .name = "bcm2835_AUD1", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static struct platform_driver bcm2835_alsa2_driver = { ++ .probe = snd_bcm2835_alsa_probe, ++ .remove = snd_bcm2835_alsa_remove, ++#ifdef CONFIG_PM ++ .suspend = snd_bcm2835_alsa_suspend, ++ .resume = snd_bcm2835_alsa_resume, ++#endif ++ .driver = { ++ .name = "bcm2835_AUD2", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static struct platform_driver bcm2835_alsa3_driver = { ++ .probe = snd_bcm2835_alsa_probe, ++ .remove = snd_bcm2835_alsa_remove, ++#ifdef CONFIG_PM ++ .suspend = snd_bcm2835_alsa_suspend, ++ .resume = snd_bcm2835_alsa_resume, ++#endif ++ .driver = { ++ .name = "bcm2835_AUD3", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static struct platform_driver bcm2835_alsa4_driver = { ++ .probe = snd_bcm2835_alsa_probe, ++ .remove = snd_bcm2835_alsa_remove, ++#ifdef CONFIG_PM ++ .suspend = snd_bcm2835_alsa_suspend, ++ .resume = snd_bcm2835_alsa_resume, ++#endif ++ .driver = { ++ .name = "bcm2835_AUD4", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static struct platform_driver bcm2835_alsa5_driver = { ++ .probe = snd_bcm2835_alsa_probe, ++ .remove = snd_bcm2835_alsa_remove, ++#ifdef CONFIG_PM ++ .suspend = snd_bcm2835_alsa_suspend, ++ .resume = snd_bcm2835_alsa_resume, ++#endif ++ .driver = { ++ .name = "bcm2835_AUD5", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static struct platform_driver bcm2835_alsa6_driver = { ++ .probe = snd_bcm2835_alsa_probe, ++ .remove = snd_bcm2835_alsa_remove, ++#ifdef CONFIG_PM ++ .suspend = snd_bcm2835_alsa_suspend, ++ .resume = snd_bcm2835_alsa_resume, ++#endif ++ .driver = { ++ .name = "bcm2835_AUD6", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static struct platform_driver bcm2835_alsa7_driver = { ++ .probe = snd_bcm2835_alsa_probe, ++ .remove = snd_bcm2835_alsa_remove, ++#ifdef CONFIG_PM ++ .suspend = snd_bcm2835_alsa_suspend, ++ .resume = snd_bcm2835_alsa_resume, ++#endif ++ .driver = { ++ .name = "bcm2835_AUD7", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int bcm2835_alsa_device_init(void) ++{ ++ int err; ++ err = platform_driver_register(&bcm2835_alsa0_driver); ++ if (err) { ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); ++ goto out; ++ } ++ ++ err = platform_driver_register(&bcm2835_alsa1_driver); ++ if (err) { ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); ++ goto unregister_0; ++ } ++ ++ err = platform_driver_register(&bcm2835_alsa2_driver); ++ if (err) { ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); ++ goto unregister_1; ++ } ++ ++ err = platform_driver_register(&bcm2835_alsa3_driver); ++ if (err) { ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); ++ goto unregister_2; ++ } ++ ++ err = platform_driver_register(&bcm2835_alsa4_driver); ++ if (err) { ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); ++ goto unregister_3; ++ } ++ ++ err = platform_driver_register(&bcm2835_alsa5_driver); ++ if (err) { ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); ++ goto unregister_4; ++ } ++ ++ err = platform_driver_register(&bcm2835_alsa6_driver); ++ if (err) { ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); ++ goto unregister_5; ++ } ++ ++ err = platform_driver_register(&bcm2835_alsa7_driver); ++ if (err) { ++ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err); ++ goto unregister_6; ++ } ++ ++ return 0; ++ ++unregister_6: ++ platform_driver_unregister(&bcm2835_alsa6_driver); ++unregister_5: ++ platform_driver_unregister(&bcm2835_alsa5_driver); ++unregister_4: ++ platform_driver_unregister(&bcm2835_alsa4_driver); ++unregister_3: ++ platform_driver_unregister(&bcm2835_alsa3_driver); ++unregister_2: ++ platform_driver_unregister(&bcm2835_alsa2_driver); ++unregister_1: ++ platform_driver_unregister(&bcm2835_alsa1_driver); ++unregister_0: ++ platform_driver_unregister(&bcm2835_alsa0_driver); ++out: ++ return err; ++} ++ ++static void bcm2835_alsa_device_exit(void) ++{ ++ platform_driver_unregister(&bcm2835_alsa0_driver); ++ platform_driver_unregister(&bcm2835_alsa1_driver); ++ platform_driver_unregister(&bcm2835_alsa2_driver); ++ platform_driver_unregister(&bcm2835_alsa3_driver); ++ platform_driver_unregister(&bcm2835_alsa4_driver); ++ platform_driver_unregister(&bcm2835_alsa5_driver); ++ platform_driver_unregister(&bcm2835_alsa6_driver); ++ platform_driver_unregister(&bcm2835_alsa7_driver); ++} ++ ++late_initcall(bcm2835_alsa_device_init); ++module_exit(bcm2835_alsa_device_exit); ++ ++MODULE_AUTHOR("Dom Cobley"); ++MODULE_DESCRIPTION("Alsa driver for BCM2835 chip"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:bcm2835_alsa"); +diff -Nur linux-3.10.33/sound/arm/bcm2835-ctl.c linux-raspberry-pi/sound/arm/bcm2835-ctl.c +--- linux-3.10.33/sound/arm/bcm2835-ctl.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/arm/bcm2835-ctl.c 2014-03-13 12:46:44.052107092 +0100 +@@ -0,0 +1,200 @@ ++/***************************************************************************** ++* Copyright 2011 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "bcm2835.h" ++ ++/* volume maximum and minimum in terms of 0.01dB */ ++#define CTRL_VOL_MAX 400 ++#define CTRL_VOL_MIN -10239 /* originally -10240 */ ++ ++ ++static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_info *uinfo) ++{ ++ audio_info(" ... IN\n"); ++ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) { ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = CTRL_VOL_MIN; ++ uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */ ++ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) { ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; ++ uinfo->count = 1; ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = 1; ++ } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) { ++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; ++ uinfo->count = 1; ++ uinfo->value.integer.min = 0; ++ uinfo->value.integer.max = AUDIO_DEST_MAX-1; ++ } ++ audio_info(" ... OUT\n"); ++ return 0; ++} ++ ++/* toggles mute on or off depending on the value of nmute, and returns ++ * 1 if the mute value was changed, otherwise 0 ++ */ ++static int toggle_mute(struct bcm2835_chip *chip, int nmute) ++{ ++ /* if settings are ok, just return 0 */ ++ if(chip->mute == nmute) ++ return 0; ++ ++ /* if the sound is muted then we need to unmute */ ++ if(chip->mute == CTRL_VOL_MUTE) ++ { ++ chip->volume = chip->old_volume; /* copy the old volume back */ ++ audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume); ++ } ++ else /* otherwise we mute */ ++ { ++ chip->old_volume = chip->volume; ++ chip->volume = 26214; /* set volume to minimum level AKA mute */ ++ audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume); ++ } ++ ++ chip->mute = nmute; ++ return 1; ++} ++ ++static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); ++ ++ BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK)); ++ ++ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) ++ ucontrol->value.integer.value[0] = chip2alsa(chip->volume); ++ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) ++ ucontrol->value.integer.value[0] = chip->mute; ++ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) ++ ucontrol->value.integer.value[0] = chip->dest; ++ ++ return 0; ++} ++ ++static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol); ++ int changed = 0; ++ ++ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) { ++ audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int)ucontrol->value.integer.value[0]); ++ if (chip->mute == CTRL_VOL_MUTE) { ++ /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */ ++ return 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */ ++ } ++ if (changed ++ || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) { ++ ++ chip->volume = alsa2chip(ucontrol->value.integer.value[0]); ++ changed = 1; ++ } ++ ++ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) { ++ /* Now implemented */ ++ audio_info(" Mute attempted\n"); ++ changed = toggle_mute(chip, ucontrol->value.integer.value[0]); ++ ++ } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) { ++ if (ucontrol->value.integer.value[0] != chip->dest) { ++ chip->dest = ucontrol->value.integer.value[0]; ++ changed = 1; ++ } ++ } ++ ++ if (changed) { ++ if (bcm2835_audio_set_ctls(chip)) ++ printk(KERN_ERR "Failed to set ALSA controls..\n"); ++ } ++ ++ return changed; ++} ++ ++static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1); ++ ++static struct snd_kcontrol_new snd_bcm2835_ctl[] = { ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "PCM Playback Volume", ++ .index = 0, ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, ++ .private_value = PCM_PLAYBACK_VOLUME, ++ .info = snd_bcm2835_ctl_info, ++ .get = snd_bcm2835_ctl_get, ++ .put = snd_bcm2835_ctl_put, ++ .count = 1, ++ .tlv = {.p = snd_bcm2835_db_scale} ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "PCM Playback Switch", ++ .index = 0, ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, ++ .private_value = PCM_PLAYBACK_MUTE, ++ .info = snd_bcm2835_ctl_info, ++ .get = snd_bcm2835_ctl_get, ++ .put = snd_bcm2835_ctl_put, ++ .count = 1, ++ }, ++ { ++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, ++ .name = "PCM Playback Route", ++ .index = 0, ++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, ++ .private_value = PCM_PLAYBACK_DEVICE, ++ .info = snd_bcm2835_ctl_info, ++ .get = snd_bcm2835_ctl_get, ++ .put = snd_bcm2835_ctl_put, ++ .count = 1, ++ }, ++}; ++ ++int snd_bcm2835_new_ctl(bcm2835_chip_t * chip) ++{ ++ int err; ++ unsigned int idx; ++ ++ strcpy(chip->card->mixername, "Broadcom Mixer"); ++ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) { ++ err = ++ snd_ctl_add(chip->card, ++ snd_ctl_new1(&snd_bcm2835_ctl[idx], chip)); ++ if (err < 0) ++ return err; ++ } ++ return 0; ++} +diff -Nur linux-3.10.33/sound/arm/bcm2835.h linux-raspberry-pi/sound/arm/bcm2835.h +--- linux-3.10.33/sound/arm/bcm2835.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/arm/bcm2835.h 2014-03-13 12:46:44.060107108 +0100 +@@ -0,0 +1,157 @@ ++/***************************************************************************** ++* Copyright 2011 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++#ifndef __SOUND_ARM_BCM2835_H ++#define __SOUND_ARM_BCM2835_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++#define AUDIO_DEBUG_ENABLE ++#define AUDIO_VERBOSE_DEBUG_ENABLE ++*/ ++ ++/* Debug macros */ ++ ++#ifdef AUDIO_DEBUG_ENABLE ++#ifdef AUDIO_VERBOSE_DEBUG_ENABLE ++ ++#define audio_debug(fmt, arg...) \ ++ printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg) ++ ++#define audio_info(fmt, arg...) \ ++ printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg) ++ ++#else ++ ++#define audio_debug(fmt, arg...) ++ ++#define audio_info(fmt, arg...) ++ ++#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */ ++ ++#else ++ ++#define audio_debug(fmt, arg...) ++ ++#define audio_info(fmt, arg...) ++ ++#endif /* AUDIO_DEBUG_ENABLE */ ++ ++#define audio_error(fmt, arg...) \ ++ printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg) ++ ++#define audio_warning(fmt, arg...) \ ++ printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg) ++ ++#define audio_alert(fmt, arg...) \ ++ printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg) ++ ++#define MAX_SUBSTREAMS (8) ++#define AVAIL_SUBSTREAMS_MASK (0xff) ++enum { ++ CTRL_VOL_MUTE, ++ CTRL_VOL_UNMUTE ++}; ++ ++/* macros for alsa2chip and chip2alsa, instead of functions */ ++ ++#define alsa2chip(vol) (uint)(-((vol << 8) / 100)) /* convert alsa to chip volume (defined as macro rather than function call) */ ++#define chip2alsa(vol) -((vol * 100) >> 8) /* convert chip to alsa volume */ ++ ++/* Some constants for values .. */ ++typedef enum { ++ AUDIO_DEST_AUTO = 0, ++ AUDIO_DEST_HEADPHONES = 1, ++ AUDIO_DEST_HDMI = 2, ++ AUDIO_DEST_MAX, ++} SND_BCM2835_ROUTE_T; ++ ++typedef enum { ++ PCM_PLAYBACK_VOLUME, ++ PCM_PLAYBACK_MUTE, ++ PCM_PLAYBACK_DEVICE, ++} SND_BCM2835_CTRL_T; ++ ++/* definition of the chip-specific record */ ++typedef struct bcm2835_chip { ++ struct snd_card *card; ++ struct snd_pcm *pcm; ++ /* Bitmat for valid reg_base and irq numbers */ ++ uint32_t avail_substreams; ++ struct platform_device *pdev[MAX_SUBSTREAMS]; ++ struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS]; ++ ++ int volume; ++ int old_volume; /* stores the volume value whist muted */ ++ int dest; ++ int mute; ++} bcm2835_chip_t; ++ ++typedef struct bcm2835_alsa_stream { ++ bcm2835_chip_t *chip; ++ struct snd_pcm_substream *substream; ++ struct snd_pcm_indirect pcm_indirect; ++ ++ struct semaphore buffers_update_sem; ++ struct semaphore control_sem; ++ spinlock_t lock; ++ volatile uint32_t control; ++ volatile uint32_t status; ++ ++ int open; ++ int running; ++ int draining; ++ ++ unsigned int pos; ++ unsigned int buffer_size; ++ unsigned int period_size; ++ ++ uint32_t enable_fifo_irq; ++ irq_handler_t fifo_irq_handler; ++ ++ atomic_t retrieved; ++ struct opaque_AUDIO_INSTANCE_T *instance; ++ struct workqueue_struct *my_wq; ++ int idx; ++} bcm2835_alsa_stream_t; ++ ++int snd_bcm2835_new_ctl(bcm2835_chip_t * chip); ++int snd_bcm2835_new_pcm(bcm2835_chip_t * chip); ++ ++int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream); ++int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream); ++int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream, ++ uint32_t channels, uint32_t samplerate, ++ uint32_t bps); ++int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream); ++int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream); ++int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream); ++int bcm2835_audio_set_ctls(bcm2835_chip_t * chip); ++int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count, ++ void *src); ++uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream); ++void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream); ++void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream); ++ ++#endif /* __SOUND_ARM_BCM2835_H */ +diff -Nur linux-3.10.33/sound/arm/bcm2835-pcm.c linux-raspberry-pi/sound/arm/bcm2835-pcm.c +--- linux-3.10.33/sound/arm/bcm2835-pcm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/arm/bcm2835-pcm.c 2014-03-13 12:46:44.052107092 +0100 +@@ -0,0 +1,426 @@ ++/***************************************************************************** ++* Copyright 2011 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++#include ++#include ++ ++#include "bcm2835.h" ++ ++/* hardware definition */ ++static struct snd_pcm_hardware snd_bcm2835_playback_hw = { ++ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | ++ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), ++ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, ++ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, ++ .rate_min = 8000, ++ .rate_max = 48000, ++ .channels_min = 1, ++ .channels_max = 2, ++ .buffer_bytes_max = 128 * 1024, ++ .period_bytes_min = 1 * 1024, ++ .period_bytes_max = 128 * 1024, ++ .periods_min = 1, ++ .periods_max = 128, ++}; ++ ++static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime) ++{ ++ audio_info("Freeing up alsa stream here ..\n"); ++ if (runtime->private_data) ++ kfree(runtime->private_data); ++ runtime->private_data = NULL; ++} ++ ++static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id) ++{ ++ bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id; ++ uint32_t consumed = 0; ++ int new_period = 0; ++ ++ audio_info(" .. IN\n"); ++ ++ audio_info("alsa_stream=%p substream=%p\n", alsa_stream, ++ alsa_stream ? alsa_stream->substream : 0); ++ ++ if (alsa_stream->open) ++ consumed = bcm2835_audio_retrieve_buffers(alsa_stream); ++ ++ /* We get called only if playback was triggered, So, the number of buffers we retrieve in ++ * each iteration are the buffers that have been played out already ++ */ ++ ++ if (alsa_stream->period_size) { ++ if ((alsa_stream->pos / alsa_stream->period_size) != ++ ((alsa_stream->pos + consumed) / alsa_stream->period_size)) ++ new_period = 1; ++ } ++ audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n", ++ alsa_stream->pos, ++ consumed, ++ alsa_stream->buffer_size, ++ (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods), ++ frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr), ++ new_period); ++ if (alsa_stream->buffer_size) { ++ alsa_stream->pos += consumed &~ (1<<30); ++ alsa_stream->pos %= alsa_stream->buffer_size; ++ } ++ ++ if (alsa_stream->substream) { ++ if (new_period) ++ snd_pcm_period_elapsed(alsa_stream->substream); ++ } else { ++ audio_warning(" unexpected NULL substream\n"); ++ } ++ audio_info(" .. OUT\n"); ++ ++ return IRQ_HANDLED; ++} ++ ++/* open callback */ ++static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) ++{ ++ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream); ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ bcm2835_alsa_stream_t *alsa_stream; ++ int idx; ++ int err; ++ ++ audio_info(" .. IN (%d)\n", substream->number); ++ ++ audio_info("Alsa open (%d)\n", substream->number); ++ idx = substream->number; ++ ++ if (idx > MAX_SUBSTREAMS) { ++ audio_error ++ ("substream(%d) device doesn't exist max(%d) substreams allowed\n", ++ idx, MAX_SUBSTREAMS); ++ err = -ENODEV; ++ goto out; ++ } ++ ++ /* Check if we are ready */ ++ if (!(chip->avail_substreams & (1 << idx))) { ++ /* We are not ready yet */ ++ audio_error("substream(%d) device is not ready yet\n", idx); ++ err = -EAGAIN; ++ goto out; ++ } ++ ++ alsa_stream = kzalloc(sizeof(bcm2835_alsa_stream_t), GFP_KERNEL); ++ if (alsa_stream == NULL) { ++ return -ENOMEM; ++ } ++ ++ /* Initialise alsa_stream */ ++ alsa_stream->chip = chip; ++ alsa_stream->substream = substream; ++ alsa_stream->idx = idx; ++ ++ sema_init(&alsa_stream->buffers_update_sem, 0); ++ sema_init(&alsa_stream->control_sem, 0); ++ spin_lock_init(&alsa_stream->lock); ++ ++ /* Enabled in start trigger, called on each "fifo irq" after that */ ++ alsa_stream->enable_fifo_irq = 0; ++ alsa_stream->fifo_irq_handler = bcm2835_playback_fifo_irq; ++ ++ runtime->private_data = alsa_stream; ++ runtime->private_free = snd_bcm2835_playback_free; ++ runtime->hw = snd_bcm2835_playback_hw; ++ /* minimum 16 bytes alignment (for vchiq bulk transfers) */ ++ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, ++ 16); ++ ++ err = bcm2835_audio_open(alsa_stream); ++ if (err != 0) { ++ kfree(alsa_stream); ++ return err; ++ } ++ chip->alsa_stream[idx] = alsa_stream; ++ ++ alsa_stream->open = 1; ++ alsa_stream->draining = 1; ++ ++out: ++ audio_info(" .. OUT =%d\n", err); ++ ++ return err; ++} ++ ++/* close callback */ ++static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream) ++{ ++ /* the hardware-specific codes will be here */ ++ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; ++ ++ audio_info(" .. IN\n"); ++ audio_info("Alsa close\n"); ++ ++ /* ++ * Call stop if it's still running. This happens when app ++ * is force killed and we don't get a stop trigger. ++ */ ++ if (alsa_stream->running) { ++ int err; ++ err = bcm2835_audio_stop(alsa_stream); ++ alsa_stream->running = 0; ++ if (err != 0) ++ audio_error(" Failed to STOP alsa device\n"); ++ } ++ ++ alsa_stream->period_size = 0; ++ alsa_stream->buffer_size = 0; ++ ++ if (alsa_stream->open) { ++ alsa_stream->open = 0; ++ bcm2835_audio_close(alsa_stream); ++ } ++ if (alsa_stream->chip) ++ alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL; ++ /* ++ * Do not free up alsa_stream here, it will be freed up by ++ * runtime->private_free callback we registered in *_open above ++ */ ++ ++ audio_info(" .. OUT\n"); ++ ++ return 0; ++} ++ ++/* hw_params callback */ ++static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ int err; ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ bcm2835_alsa_stream_t *alsa_stream = ++ (bcm2835_alsa_stream_t *) runtime->private_data; ++ ++ audio_info(" .. IN\n"); ++ ++ err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); ++ if (err < 0) { ++ audio_error ++ (" pcm_lib_malloc failed to allocated pages for buffers\n"); ++ return err; ++ } ++ ++ err = bcm2835_audio_set_params(alsa_stream, params_channels(params), ++ params_rate(params), ++ snd_pcm_format_width(params_format ++ (params))); ++ if (err < 0) { ++ audio_error(" error setting hw params\n"); ++ } ++ ++ bcm2835_audio_setup(alsa_stream); ++ ++ /* in preparation of the stream, set the controls (volume level) of the stream */ ++ bcm2835_audio_set_ctls(alsa_stream->chip); ++ ++ audio_info(" .. OUT\n"); ++ ++ return err; ++} ++ ++/* hw_free callback */ ++static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream) ++{ ++ audio_info(" .. IN\n"); ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++/* prepare callback */ ++static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; ++ ++ audio_info(" .. IN\n"); ++ ++ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect)); ++ ++ alsa_stream->pcm_indirect.hw_buffer_size = ++ alsa_stream->pcm_indirect.sw_buffer_size = ++ snd_pcm_lib_buffer_bytes(substream); ++ ++ alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); ++ alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); ++ alsa_stream->pos = 0; ++ ++ audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n", ++ alsa_stream->buffer_size, alsa_stream->period_size, ++ alsa_stream->pos, runtime->frame_bits); ++ ++ audio_info(" .. OUT\n"); ++ return 0; ++} ++ ++static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream, ++ struct snd_pcm_indirect *rec, size_t bytes) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; ++ void *src = (void *)(substream->runtime->dma_area + rec->sw_data); ++ int err; ++ ++ err = bcm2835_audio_write(alsa_stream, bytes, src); ++ if (err) ++ audio_error(" Failed to transfer to alsa device (%d)\n", err); ++ ++} ++ ++static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; ++ struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect; ++ ++ pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max; ++ snd_pcm_indirect_playback_transfer(substream, pcm_indirect, ++ snd_bcm2835_pcm_transfer); ++ return 0; ++} ++ ++/* trigger callback */ ++static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; ++ int err = 0; ++ ++ audio_info(" .. IN\n"); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n", ++ alsa_stream->running); ++ if (!alsa_stream->running) { ++ err = bcm2835_audio_start(alsa_stream); ++ if (err == 0) { ++ alsa_stream->pcm_indirect.hw_io = ++ alsa_stream->pcm_indirect.hw_data = ++ bytes_to_frames(runtime, ++ alsa_stream->pos); ++ substream->ops->ack(substream); ++ alsa_stream->running = 1; ++ alsa_stream->draining = 1; ++ } else { ++ audio_error(" Failed to START alsa device (%d)\n", err); ++ } ++ } ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ audio_debug ++ ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n", ++ alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING); ++ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { ++ audio_info("DRAINING\n"); ++ alsa_stream->draining = 1; ++ } else { ++ audio_info("DROPPING\n"); ++ alsa_stream->draining = 0; ++ } ++ if (alsa_stream->running) { ++ err = bcm2835_audio_stop(alsa_stream); ++ if (err != 0) ++ audio_error(" Failed to STOP alsa device (%d)\n", err); ++ alsa_stream->running = 0; ++ } ++ break; ++ default: ++ err = -EINVAL; ++ } ++ ++ audio_info(" .. OUT\n"); ++ return err; ++} ++ ++/* pointer callback */ ++static snd_pcm_uframes_t ++snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; ++ ++ audio_info(" .. IN\n"); ++ ++ audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0, ++ frames_to_bytes(runtime, runtime->status->hw_ptr), ++ frames_to_bytes(runtime, runtime->control->appl_ptr), ++ alsa_stream->pos); ++ ++ audio_info(" .. OUT\n"); ++ return snd_pcm_indirect_playback_pointer(substream, ++ &alsa_stream->pcm_indirect, ++ alsa_stream->pos); ++} ++ ++static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream, ++ unsigned int cmd, void *arg) ++{ ++ int ret = snd_pcm_lib_ioctl(substream, cmd, arg); ++ audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream, ++ cmd, arg, arg ? *(unsigned *)arg : 0, ret); ++ return ret; ++} ++ ++/* operators */ ++static struct snd_pcm_ops snd_bcm2835_playback_ops = { ++ .open = snd_bcm2835_playback_open, ++ .close = snd_bcm2835_playback_close, ++ .ioctl = snd_bcm2835_pcm_lib_ioctl, ++ .hw_params = snd_bcm2835_pcm_hw_params, ++ .hw_free = snd_bcm2835_pcm_hw_free, ++ .prepare = snd_bcm2835_pcm_prepare, ++ .trigger = snd_bcm2835_pcm_trigger, ++ .pointer = snd_bcm2835_pcm_pointer, ++ .ack = snd_bcm2835_pcm_ack, ++}; ++ ++/* create a pcm device */ ++int snd_bcm2835_new_pcm(bcm2835_chip_t * chip) ++{ ++ struct snd_pcm *pcm; ++ int err; ++ ++ audio_info(" .. IN\n"); ++ err = ++ snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm); ++ if (err < 0) ++ return err; ++ pcm->private_data = chip; ++ strcpy(pcm->name, "bcm2835 ALSA"); ++ chip->pcm = pcm; ++ chip->dest = AUDIO_DEST_AUTO; ++ chip->volume = alsa2chip(0); ++ chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */ ++ /* set operators */ ++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, ++ &snd_bcm2835_playback_ops); ++ ++ /* pre-allocation of buffers */ ++ /* NOTE: this may fail */ ++ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, ++ snd_dma_continuous_data ++ (GFP_KERNEL), 64 * 1024, ++ 64 * 1024); ++ ++ audio_info(" .. OUT\n"); ++ ++ return 0; ++} +diff -Nur linux-3.10.33/sound/arm/bcm2835-vchiq.c linux-raspberry-pi/sound/arm/bcm2835-vchiq.c +--- linux-3.10.33/sound/arm/bcm2835-vchiq.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/arm/bcm2835-vchiq.c 2014-03-13 12:46:44.060107108 +0100 +@@ -0,0 +1,879 @@ ++/***************************************************************************** ++* Copyright 2011 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "bcm2835.h" ++ ++/* ---- Include Files -------------------------------------------------------- */ ++ ++#include "interface/vchi/vchi.h" ++#include "vc_vchi_audioserv_defs.h" ++ ++/* ---- Private Constants and Types ------------------------------------------ */ ++ ++#define BCM2835_AUDIO_STOP 0 ++#define BCM2835_AUDIO_START 1 ++#define BCM2835_AUDIO_WRITE 2 ++ ++/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */ ++#ifdef AUDIO_DEBUG_ENABLE ++ #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg) ++ #define LOG_WARN( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg) ++ #define LOG_INFO( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg) ++ #define LOG_DBG( fmt, arg... ) pr_info( "%s:%d " fmt, __func__, __LINE__, ##arg) ++#else ++ #define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg) ++ #define LOG_WARN( fmt, arg... ) ++ #define LOG_INFO( fmt, arg... ) ++ #define LOG_DBG( fmt, arg... ) ++#endif ++ ++typedef struct opaque_AUDIO_INSTANCE_T { ++ uint32_t num_connections; ++ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS]; ++ struct completion msg_avail_comp; ++ struct mutex vchi_mutex; ++ bcm2835_alsa_stream_t *alsa_stream; ++ int32_t result; ++ short peer_version; ++} AUDIO_INSTANCE_T; ++ ++bool force_bulk = false; ++ ++/* ---- Private Variables ---------------------------------------------------- */ ++ ++/* ---- Private Function Prototypes ------------------------------------------ */ ++ ++/* ---- Private Functions ---------------------------------------------------- */ ++ ++static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream); ++static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream); ++static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream, ++ uint32_t count, void *src); ++ ++typedef struct { ++ struct work_struct my_work; ++ bcm2835_alsa_stream_t *alsa_stream; ++ int cmd; ++ void *src; ++ uint32_t count; ++} my_work_t; ++ ++static void my_wq_function(struct work_struct *work) ++{ ++ my_work_t *w = (my_work_t *) work; ++ int ret = -9; ++ LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd); ++ switch (w->cmd) { ++ case BCM2835_AUDIO_START: ++ ret = bcm2835_audio_start_worker(w->alsa_stream); ++ break; ++ case BCM2835_AUDIO_STOP: ++ ret = bcm2835_audio_stop_worker(w->alsa_stream); ++ break; ++ case BCM2835_AUDIO_WRITE: ++ ret = bcm2835_audio_write_worker(w->alsa_stream, w->count, ++ w->src); ++ break; ++ default: ++ LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd); ++ break; ++ } ++ kfree((void *)work); ++ LOG_DBG(" .. OUT %d\n", ret); ++} ++ ++int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ int ret = -1; ++ LOG_DBG(" .. IN\n"); ++ if (alsa_stream->my_wq) { ++ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC); ++ /*--- Queue some work (item 1) ---*/ ++ if (work) { ++ INIT_WORK((struct work_struct *)work, my_wq_function); ++ work->alsa_stream = alsa_stream; ++ work->cmd = BCM2835_AUDIO_START; ++ if (queue_work ++ (alsa_stream->my_wq, (struct work_struct *)work)) ++ ret = 0; ++ } else ++ LOG_ERR(" .. Error: NULL work kmalloc\n"); ++ } ++ LOG_DBG(" .. OUT %d\n", ret); ++ return ret; ++} ++ ++int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ int ret = -1; ++ LOG_DBG(" .. IN\n"); ++ if (alsa_stream->my_wq) { ++ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC); ++ /*--- Queue some work (item 1) ---*/ ++ if (work) { ++ INIT_WORK((struct work_struct *)work, my_wq_function); ++ work->alsa_stream = alsa_stream; ++ work->cmd = BCM2835_AUDIO_STOP; ++ if (queue_work ++ (alsa_stream->my_wq, (struct work_struct *)work)) ++ ret = 0; ++ } else ++ LOG_ERR(" .. Error: NULL work kmalloc\n"); ++ } ++ LOG_DBG(" .. OUT %d\n", ret); ++ return ret; ++} ++ ++int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream, ++ uint32_t count, void *src) ++{ ++ int ret = -1; ++ LOG_DBG(" .. IN\n"); ++ if (alsa_stream->my_wq) { ++ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC); ++ /*--- Queue some work (item 1) ---*/ ++ if (work) { ++ INIT_WORK((struct work_struct *)work, my_wq_function); ++ work->alsa_stream = alsa_stream; ++ work->cmd = BCM2835_AUDIO_WRITE; ++ work->src = src; ++ work->count = count; ++ if (queue_work ++ (alsa_stream->my_wq, (struct work_struct *)work)) ++ ret = 0; ++ } else ++ LOG_ERR(" .. Error: NULL work kmalloc\n"); ++ } ++ LOG_DBG(" .. OUT %d\n", ret); ++ return ret; ++} ++ ++void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1); ++ return; ++} ++ ++void my_workqueue_quit(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ if (alsa_stream->my_wq) { ++ flush_workqueue(alsa_stream->my_wq); ++ destroy_workqueue(alsa_stream->my_wq); ++ alsa_stream->my_wq = NULL; ++ } ++ return; ++} ++ ++static void audio_vchi_callback(void *param, ++ const VCHI_CALLBACK_REASON_T reason, ++ void *msg_handle) ++{ ++ AUDIO_INSTANCE_T *instance = (AUDIO_INSTANCE_T *) param; ++ int32_t status; ++ int32_t msg_len; ++ VC_AUDIO_MSG_T m; ++ bcm2835_alsa_stream_t *alsa_stream = 0; ++ LOG_DBG(" .. IN instance=%p, param=%p, reason=%d, handle=%p\n", ++ instance, param, reason, msg_handle); ++ ++ if (!instance || reason != VCHI_CALLBACK_MSG_AVAILABLE) { ++ return; ++ } ++ alsa_stream = instance->alsa_stream; ++ status = vchi_msg_dequeue(instance->vchi_handle[0], ++ &m, sizeof m, &msg_len, VCHI_FLAGS_NONE); ++ if (m.type == VC_AUDIO_MSG_TYPE_RESULT) { ++ LOG_DBG ++ (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n", ++ instance, m.u.result.success); ++ instance->result = m.u.result.success; ++ complete(&instance->msg_avail_comp); ++ } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) { ++ irq_handler_t callback = (irq_handler_t) m.u.complete.callback; ++ LOG_DBG ++ (" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n", ++ instance, m.u.complete.count); ++ if (alsa_stream && callback) { ++ atomic_add(m.u.complete.count, &alsa_stream->retrieved); ++ callback(0, alsa_stream); ++ } else { ++ LOG_DBG(" .. unexpected alsa_stream=%p, callback=%p\n", ++ alsa_stream, callback); ++ } ++ } else { ++ LOG_DBG(" .. unexpected m.type=%d\n", m.type); ++ } ++ LOG_DBG(" .. OUT\n"); ++} ++ ++static AUDIO_INSTANCE_T *vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance, ++ VCHI_CONNECTION_T ** ++ vchi_connections, ++ uint32_t num_connections) ++{ ++ uint32_t i; ++ AUDIO_INSTANCE_T *instance; ++ int status; ++ ++ LOG_DBG("%s: start", __func__); ++ ++ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) { ++ LOG_ERR("%s: unsupported number of connections %u (max=%u)\n", ++ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS); ++ ++ return NULL; ++ } ++ /* Allocate memory for this instance */ ++ instance = kmalloc(sizeof(*instance), GFP_KERNEL); ++ ++ memset(instance, 0, sizeof(*instance)); ++ instance->num_connections = num_connections; ++ ++ /* Create a lock for exclusive, serialized VCHI connection access */ ++ mutex_init(&instance->vchi_mutex); ++ /* Open the VCHI service connections */ ++ for (i = 0; i < num_connections; i++) { ++ SERVICE_CREATION_T params = { ++ VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER), ++ VC_AUDIO_SERVER_NAME, // 4cc service code ++ vchi_connections[i], // passed in fn pointers ++ 0, // rx fifo size (unused) ++ 0, // tx fifo size (unused) ++ audio_vchi_callback, // service callback ++ instance, // service callback parameter ++ 1, //TODO: remove VCOS_FALSE, // unaligned bulk recieves ++ 1, //TODO: remove VCOS_FALSE, // unaligned bulk transmits ++ 0 // want crc check on bulk transfers ++ }; ++ ++ status = vchi_service_open(vchi_instance, ¶ms, ++ &instance->vchi_handle[i]); ++ if (status) { ++ LOG_ERR ++ ("%s: failed to open VCHI service connection (status=%d)\n", ++ __func__, status); ++ ++ goto err_close_services; ++ } ++ /* Finished with the service for now */ ++ vchi_service_release(instance->vchi_handle[i]); ++ } ++ ++ return instance; ++ ++err_close_services: ++ for (i = 0; i < instance->num_connections; i++) { ++ vchi_service_close(instance->vchi_handle[i]); ++ } ++ ++ kfree(instance); ++ ++ return NULL; ++} ++ ++static int32_t vc_vchi_audio_deinit(AUDIO_INSTANCE_T * instance) ++{ ++ uint32_t i; ++ ++ LOG_DBG(" .. IN\n"); ++ ++ if (instance == NULL) { ++ LOG_ERR("%s: invalid handle %p\n", __func__, instance); ++ ++ return -1; ++ } ++ ++ LOG_DBG(" .. about to lock (%d)\n", instance->num_connections); ++ if(mutex_lock_interruptible(&instance->vchi_mutex)) ++ { ++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections); ++ return -EINTR; ++ } ++ ++ /* Close all VCHI service connections */ ++ for (i = 0; i < instance->num_connections; i++) { ++ int32_t success; ++ LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]); ++ vchi_service_use(instance->vchi_handle[i]); ++ ++ success = vchi_service_close(instance->vchi_handle[i]); ++ if (success != 0) { ++ LOG_ERR ++ ("%s: failed to close VCHI service connection (status=%d)\n", ++ __func__, success); ++ } ++ } ++ ++ mutex_unlock(&instance->vchi_mutex); ++ ++ kfree(instance); ++ ++ LOG_DBG(" .. OUT\n"); ++ ++ return 0; ++} ++ ++static int bcm2835_audio_open_connection(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ static VCHI_INSTANCE_T vchi_instance; ++ static VCHI_CONNECTION_T *vchi_connection; ++ AUDIO_INSTANCE_T *instance = alsa_stream->instance; ++ int ret; ++ LOG_DBG(" .. IN\n"); ++ ++ LOG_INFO("%s: start", __func__); ++ //BUG_ON(instance); ++ if (instance) { ++ LOG_ERR("%s: VCHI instance already open (%p)\n", ++ __func__, instance); ++ instance->alsa_stream = alsa_stream; ++ alsa_stream->instance = instance; ++ ret = 0; // xxx todo -1; ++ goto err_free_mem; ++ } ++ ++ /* Initialize and create a VCHI connection */ ++ ret = vchi_initialise(&vchi_instance); ++ if (ret != 0) { ++ LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n", ++ __func__, ret); ++ ++ ret = -EIO; ++ goto err_free_mem; ++ } ++ ret = vchi_connect(NULL, 0, vchi_instance); ++ if (ret != 0) { ++ LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n", ++ __func__, ret); ++ ++ ret = -EIO; ++ goto err_free_mem; ++ } ++ ++ /* Initialize an instance of the audio service */ ++ instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1); ++ ++ if (instance == NULL /*|| audio_handle != instance */ ) { ++ LOG_ERR("%s: failed to initialize audio service\n", __func__); ++ ++ ret = -EPERM; ++ goto err_free_mem; ++ } ++ ++ instance->alsa_stream = alsa_stream; ++ alsa_stream->instance = instance; ++ ++ LOG_DBG(" success !\n"); ++err_free_mem: ++ LOG_DBG(" .. OUT\n"); ++ ++ return ret; ++} ++ ++int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ AUDIO_INSTANCE_T *instance; ++ VC_AUDIO_MSG_T m; ++ int32_t success; ++ int ret; ++ LOG_DBG(" .. IN\n"); ++ ++ my_workqueue_init(alsa_stream); ++ ++ ret = bcm2835_audio_open_connection(alsa_stream); ++ if (ret != 0) { ++ ret = -1; ++ goto exit; ++ } ++ instance = alsa_stream->instance; ++ ++ if(mutex_lock_interruptible(&instance->vchi_mutex)) ++ { ++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections); ++ return -EINTR; ++ } ++ vchi_service_use(instance->vchi_handle[0]); ++ ++ m.type = VC_AUDIO_MSG_TYPE_OPEN; ++ ++ /* Send the message to the videocore */ ++ success = vchi_msg_queue(instance->vchi_handle[0], ++ &m, sizeof m, ++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); ++ ++ if (success != 0) { ++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n", ++ __func__, success); ++ ++ ret = -1; ++ goto unlock; ++ } ++ ++ ret = 0; ++ ++unlock: ++ vchi_service_release(instance->vchi_handle[0]); ++ mutex_unlock(&instance->vchi_mutex); ++exit: ++ LOG_DBG(" .. OUT\n"); ++ return ret; ++} ++ ++static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream, ++ bcm2835_chip_t * chip) ++{ ++ VC_AUDIO_MSG_T m; ++ AUDIO_INSTANCE_T *instance = alsa_stream->instance; ++ int32_t success; ++ int ret; ++ LOG_DBG(" .. IN\n"); ++ ++ LOG_INFO ++ (" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume); ++ ++ if(mutex_lock_interruptible(&instance->vchi_mutex)) ++ { ++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections); ++ return -EINTR; ++ } ++ vchi_service_use(instance->vchi_handle[0]); ++ ++ instance->result = -1; ++ ++ m.type = VC_AUDIO_MSG_TYPE_CONTROL; ++ m.u.control.dest = chip->dest; ++ m.u.control.volume = chip->volume; ++ ++ /* Create the message available completion */ ++ init_completion(&instance->msg_avail_comp); ++ ++ /* Send the message to the videocore */ ++ success = vchi_msg_queue(instance->vchi_handle[0], ++ &m, sizeof m, ++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); ++ ++ if (success != 0) { ++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n", ++ __func__, success); ++ ++ ret = -1; ++ goto unlock; ++ } ++ ++ /* We are expecting a reply from the videocore */ ++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp); ++ if (ret) { ++ LOG_ERR("%s: failed on waiting for event (status=%d)\n", ++ __func__, success); ++ goto unlock; ++ } ++ ++ if (instance->result != 0) { ++ LOG_ERR("%s: result=%d\n", __func__, instance->result); ++ ++ ret = -1; ++ goto unlock; ++ } ++ ++ ret = 0; ++ ++unlock: ++ vchi_service_release(instance->vchi_handle[0]); ++ mutex_unlock(&instance->vchi_mutex); ++ ++ LOG_DBG(" .. OUT\n"); ++ return ret; ++} ++ ++int bcm2835_audio_set_ctls(bcm2835_chip_t * chip) ++{ ++ int i; ++ int ret = 0; ++ LOG_DBG(" .. IN\n"); ++ ++ /* change ctls for all substreams */ ++ for (i = 0; i < MAX_SUBSTREAMS; i++) { ++ if (chip->avail_substreams & (1 << i)) { ++ if (!chip->alsa_stream[i]) ++ { ++ LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams); ++ ret = 0; ++ } ++ else if (bcm2835_audio_set_ctls_chan /* returns 0 on success */ ++ (chip->alsa_stream[i], chip) != 0) ++ { ++ LOG_DBG("Couldn't set the controls for stream %d\n", i); ++ ret = -1; ++ } ++ else LOG_DBG(" Controls set for stream %d\n", i); ++ } ++ } ++ LOG_DBG(" .. OUT ret=%d\n", ret); ++ return ret; ++} ++ ++int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream, ++ uint32_t channels, uint32_t samplerate, ++ uint32_t bps) ++{ ++ VC_AUDIO_MSG_T m; ++ AUDIO_INSTANCE_T *instance = alsa_stream->instance; ++ int32_t success; ++ int ret; ++ LOG_DBG(" .. IN\n"); ++ ++ LOG_INFO ++ (" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n", ++ channels, samplerate, bps); ++ ++ /* resend ctls - alsa_stream may not have been open when first send */ ++ ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip); ++ if (ret != 0) { ++ LOG_ERR(" Alsa controls not supported\n"); ++ return -EINVAL; ++ } ++ ++ if(mutex_lock_interruptible(&instance->vchi_mutex)) ++ { ++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections); ++ return -EINTR; ++ } ++ vchi_service_use(instance->vchi_handle[0]); ++ ++ instance->result = -1; ++ ++ m.type = VC_AUDIO_MSG_TYPE_CONFIG; ++ m.u.config.channels = channels; ++ m.u.config.samplerate = samplerate; ++ m.u.config.bps = bps; ++ ++ /* Create the message available completion */ ++ init_completion(&instance->msg_avail_comp); ++ ++ /* Send the message to the videocore */ ++ success = vchi_msg_queue(instance->vchi_handle[0], ++ &m, sizeof m, ++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); ++ ++ if (success != 0) { ++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n", ++ __func__, success); ++ ++ ret = -1; ++ goto unlock; ++ } ++ ++ /* We are expecting a reply from the videocore */ ++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp); ++ if (ret) { ++ LOG_ERR("%s: failed on waiting for event (status=%d)\n", ++ __func__, success); ++ goto unlock; ++ } ++ ++ if (instance->result != 0) { ++ LOG_ERR("%s: result=%d", __func__, instance->result); ++ ++ ret = -1; ++ goto unlock; ++ } ++ ++ ret = 0; ++ ++unlock: ++ vchi_service_release(instance->vchi_handle[0]); ++ mutex_unlock(&instance->vchi_mutex); ++ ++ LOG_DBG(" .. OUT\n"); ++ return ret; ++} ++ ++int bcm2835_audio_setup(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ LOG_DBG(" .. IN\n"); ++ ++ LOG_DBG(" .. OUT\n"); ++ ++ return 0; ++} ++ ++static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ VC_AUDIO_MSG_T m; ++ AUDIO_INSTANCE_T *instance = alsa_stream->instance; ++ int32_t success; ++ int ret; ++ LOG_DBG(" .. IN\n"); ++ ++ if(mutex_lock_interruptible(&instance->vchi_mutex)) ++ { ++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections); ++ return -EINTR; ++ } ++ vchi_service_use(instance->vchi_handle[0]); ++ ++ m.type = VC_AUDIO_MSG_TYPE_START; ++ ++ /* Send the message to the videocore */ ++ success = vchi_msg_queue(instance->vchi_handle[0], ++ &m, sizeof m, ++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); ++ ++ if (success != 0) { ++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", ++ __func__, success); ++ ++ ret = -1; ++ goto unlock; ++ } ++ ++ ret = 0; ++ ++unlock: ++ vchi_service_release(instance->vchi_handle[0]); ++ mutex_unlock(&instance->vchi_mutex); ++ LOG_DBG(" .. OUT\n"); ++ return ret; ++} ++ ++static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ VC_AUDIO_MSG_T m; ++ AUDIO_INSTANCE_T *instance = alsa_stream->instance; ++ int32_t success; ++ int ret; ++ LOG_DBG(" .. IN\n"); ++ ++ if(mutex_lock_interruptible(&instance->vchi_mutex)) ++ { ++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections); ++ return -EINTR; ++ } ++ vchi_service_use(instance->vchi_handle[0]); ++ ++ m.type = VC_AUDIO_MSG_TYPE_STOP; ++ m.u.stop.draining = alsa_stream->draining; ++ ++ /* Send the message to the videocore */ ++ success = vchi_msg_queue(instance->vchi_handle[0], ++ &m, sizeof m, ++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); ++ ++ if (success != 0) { ++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", ++ __func__, success); ++ ++ ret = -1; ++ goto unlock; ++ } ++ ++ ret = 0; ++ ++unlock: ++ vchi_service_release(instance->vchi_handle[0]); ++ mutex_unlock(&instance->vchi_mutex); ++ LOG_DBG(" .. OUT\n"); ++ return ret; ++} ++ ++int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ VC_AUDIO_MSG_T m; ++ AUDIO_INSTANCE_T *instance = alsa_stream->instance; ++ int32_t success; ++ int ret; ++ LOG_DBG(" .. IN\n"); ++ ++ my_workqueue_quit(alsa_stream); ++ ++ if(mutex_lock_interruptible(&instance->vchi_mutex)) ++ { ++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections); ++ return -EINTR; ++ } ++ vchi_service_use(instance->vchi_handle[0]); ++ ++ m.type = VC_AUDIO_MSG_TYPE_CLOSE; ++ ++ /* Create the message available completion */ ++ init_completion(&instance->msg_avail_comp); ++ ++ /* Send the message to the videocore */ ++ success = vchi_msg_queue(instance->vchi_handle[0], ++ &m, sizeof m, ++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); ++ ++ if (success != 0) { ++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", ++ __func__, success); ++ ret = -1; ++ goto unlock; ++ } ++ ++ ret = wait_for_completion_interruptible(&instance->msg_avail_comp); ++ if (ret) { ++ LOG_ERR("%s: failed on waiting for event (status=%d)", ++ __func__, success); ++ goto unlock; ++ } ++ if (instance->result != 0) { ++ LOG_ERR("%s: failed result (status=%d)", ++ __func__, instance->result); ++ ++ ret = -1; ++ goto unlock; ++ } ++ ++ ret = 0; ++ ++unlock: ++ vchi_service_release(instance->vchi_handle[0]); ++ mutex_unlock(&instance->vchi_mutex); ++ ++ /* Stop the audio service */ ++ if (instance) { ++ vc_vchi_audio_deinit(instance); ++ alsa_stream->instance = NULL; ++ } ++ LOG_DBG(" .. OUT\n"); ++ return ret; ++} ++ ++int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream, ++ uint32_t count, void *src) ++{ ++ VC_AUDIO_MSG_T m; ++ AUDIO_INSTANCE_T *instance = alsa_stream->instance; ++ int32_t success; ++ int ret; ++ ++ LOG_DBG(" .. IN\n"); ++ ++ LOG_INFO(" Writing %d bytes from %p\n", count, src); ++ ++ if(mutex_lock_interruptible(&instance->vchi_mutex)) ++ { ++ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",instance->num_connections); ++ return -EINTR; ++ } ++ vchi_service_use(instance->vchi_handle[0]); ++ ++ if ( instance->peer_version==0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0 ) { ++ LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version); ++ } ++ m.type = VC_AUDIO_MSG_TYPE_WRITE; ++ m.u.write.count = count; ++ // old version uses bulk, new version uses control ++ m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0:4000; ++ m.u.write.callback = alsa_stream->fifo_irq_handler; ++ m.u.write.cookie = alsa_stream; ++ m.u.write.silence = src == NULL; ++ ++ /* Send the message to the videocore */ ++ success = vchi_msg_queue(instance->vchi_handle[0], ++ &m, sizeof m, ++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); ++ ++ if (success != 0) { ++ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)", ++ __func__, success); ++ ++ ret = -1; ++ goto unlock; ++ } ++ if (!m.u.write.silence) { ++ if (m.u.write.max_packet == 0) { ++ /* Send the message to the videocore */ ++ success = vchi_bulk_queue_transmit(instance->vchi_handle[0], ++ src, count, ++ 0 * ++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED ++ + ++ 1 * ++ VCHI_FLAGS_BLOCK_UNTIL_DATA_READ, ++ NULL); ++ } else { ++ while (count > 0) { ++ int bytes = min((int)m.u.write.max_packet, (int)count); ++ success = vchi_msg_queue(instance->vchi_handle[0], ++ src, bytes, ++ VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL); ++ src = (char *)src + bytes; ++ count -= bytes; ++ } ++ } ++ if (success != 0) { ++ LOG_ERR ++ ("%s: failed on vchi_bulk_queue_transmit (status=%d)", ++ __func__, success); ++ ++ ret = -1; ++ goto unlock; ++ } ++ } ++ ret = 0; ++ ++unlock: ++ vchi_service_release(instance->vchi_handle[0]); ++ mutex_unlock(&instance->vchi_mutex); ++ LOG_DBG(" .. OUT\n"); ++ return ret; ++} ++ ++/** ++ * Returns all buffers from arm->vc ++ */ ++void bcm2835_audio_flush_buffers(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ LOG_DBG(" .. IN\n"); ++ LOG_DBG(" .. OUT\n"); ++ return; ++} ++ ++/** ++ * Forces VC to flush(drop) its filled playback buffers and ++ * return them the us. (VC->ARM) ++ */ ++void bcm2835_audio_flush_playback_buffers(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ LOG_DBG(" .. IN\n"); ++ LOG_DBG(" .. OUT\n"); ++} ++ ++uint32_t bcm2835_audio_retrieve_buffers(bcm2835_alsa_stream_t * alsa_stream) ++{ ++ uint32_t count = atomic_read(&alsa_stream->retrieved); ++ atomic_sub(count, &alsa_stream->retrieved); ++ return count; ++} ++ ++module_param(force_bulk, bool, 0444); ++MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio"); +diff -Nur linux-3.10.33/sound/arm/Kconfig linux-raspberry-pi/sound/arm/Kconfig +--- linux-3.10.33/sound/arm/Kconfig 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/sound/arm/Kconfig 2014-03-13 12:46:44.052107092 +0100 +@@ -39,5 +39,12 @@ + Say Y or M if you want to support any AC97 codec attached to + the PXA2xx AC97 interface. + ++config SND_BCM2835 ++ tristate "BCM2835 ALSA driver" ++ depends on ARCH_BCM2708 && BCM2708_VCHIQ && SND ++ select SND_PCM ++ help ++ Say Y or M if you want to support BCM2835 Alsa pcm card driver ++ + endif # SND_ARM + +diff -Nur linux-3.10.33/sound/arm/Makefile linux-raspberry-pi/sound/arm/Makefile +--- linux-3.10.33/sound/arm/Makefile 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/sound/arm/Makefile 2014-03-13 12:46:44.052107092 +0100 +@@ -14,3 +14,9 @@ + + obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o + snd-pxa2xx-ac97-objs := pxa2xx-ac97.o ++ ++obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o ++snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o ++ ++ccflags-y += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000 ++ +diff -Nur linux-3.10.33/sound/arm/vc_vchi_audioserv_defs.h linux-raspberry-pi/sound/arm/vc_vchi_audioserv_defs.h +--- linux-3.10.33/sound/arm/vc_vchi_audioserv_defs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/arm/vc_vchi_audioserv_defs.h 2014-03-13 12:46:44.060107108 +0100 +@@ -0,0 +1,116 @@ ++/***************************************************************************** ++* Copyright 2011 Broadcom Corporation. All rights reserved. ++* ++* Unless you and Broadcom execute a separate written software license ++* agreement governing use of this software, this software is licensed to you ++* under the terms of the GNU General Public License version 2, available at ++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL"). ++* ++* Notwithstanding the above, under no circumstances may you combine this ++* software in any way with any other Broadcom software provided under a ++* license other than the GPL, without Broadcom's express prior written ++* consent. ++*****************************************************************************/ ++ ++#ifndef _VC_AUDIO_DEFS_H_ ++#define _VC_AUDIO_DEFS_H_ ++ ++#define VC_AUDIOSERV_MIN_VER 1 ++#define VC_AUDIOSERV_VER 2 ++ ++// FourCC code used for VCHI connection ++#define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS") ++ ++// Maximum message length ++#define VC_AUDIO_MAX_MSG_LEN (sizeof( VC_AUDIO_MSG_T )) ++ ++// List of screens that are currently supported ++// All message types supported for HOST->VC direction ++typedef enum { ++ VC_AUDIO_MSG_TYPE_RESULT, // Generic result ++ VC_AUDIO_MSG_TYPE_COMPLETE, // Generic result ++ VC_AUDIO_MSG_TYPE_CONFIG, // Configure audio ++ VC_AUDIO_MSG_TYPE_CONTROL, // Configure audio ++ VC_AUDIO_MSG_TYPE_OPEN, // Configure audio ++ VC_AUDIO_MSG_TYPE_CLOSE, // Configure audio ++ VC_AUDIO_MSG_TYPE_START, // Configure audio ++ VC_AUDIO_MSG_TYPE_STOP, // Configure audio ++ VC_AUDIO_MSG_TYPE_WRITE, // Configure audio ++ VC_AUDIO_MSG_TYPE_MAX ++} VC_AUDIO_MSG_TYPE; ++ ++// configure the audio ++typedef struct { ++ uint32_t channels; ++ uint32_t samplerate; ++ uint32_t bps; ++ ++} VC_AUDIO_CONFIG_T; ++ ++typedef struct { ++ uint32_t volume; ++ uint32_t dest; ++ ++} VC_AUDIO_CONTROL_T; ++ ++// audio ++typedef struct { ++ uint32_t dummy; ++ ++} VC_AUDIO_OPEN_T; ++ ++// audio ++typedef struct { ++ uint32_t dummy; ++ ++} VC_AUDIO_CLOSE_T; ++// audio ++typedef struct { ++ uint32_t dummy; ++ ++} VC_AUDIO_START_T; ++// audio ++typedef struct { ++ uint32_t draining; ++ ++} VC_AUDIO_STOP_T; ++ ++// configure the write audio samples ++typedef struct { ++ uint32_t count; // in bytes ++ void *callback; ++ void *cookie; ++ uint16_t silence; ++ uint16_t max_packet; ++} VC_AUDIO_WRITE_T; ++ ++// Generic result for a request (VC->HOST) ++typedef struct { ++ int32_t success; // Success value ++ ++} VC_AUDIO_RESULT_T; ++ ++// Generic result for a request (VC->HOST) ++typedef struct { ++ int32_t count; // Success value ++ void *callback; ++ void *cookie; ++} VC_AUDIO_COMPLETE_T; ++ ++// Message header for all messages in HOST->VC direction ++typedef struct { ++ int32_t type; // Message type (VC_AUDIO_MSG_TYPE) ++ union { ++ VC_AUDIO_CONFIG_T config; ++ VC_AUDIO_CONTROL_T control; ++ VC_AUDIO_OPEN_T open; ++ VC_AUDIO_CLOSE_T close; ++ VC_AUDIO_START_T start; ++ VC_AUDIO_STOP_T stop; ++ VC_AUDIO_WRITE_T write; ++ VC_AUDIO_RESULT_T result; ++ VC_AUDIO_COMPLETE_T complete; ++ } u; ++} VC_AUDIO_MSG_T; ++ ++#endif // _VC_AUDIO_DEFS_H_ +diff -Nur linux-3.10.33/sound/soc/bcm/bcm2708-i2s.c linux-raspberry-pi/sound/soc/bcm/bcm2708-i2s.c +--- linux-3.10.33/sound/soc/bcm/bcm2708-i2s.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/bcm/bcm2708-i2s.c 2014-03-13 12:46:44.480107952 +0100 +@@ -0,0 +1,945 @@ ++/* ++ * ALSA SoC I2S Audio Layer for Broadcom BCM2708 SoC ++ * ++ * Author: Florian Meier ++ * Copyright 2013 ++ * ++ * Based on ++ * Raspberry Pi PCM I2S ALSA Driver ++ * Copyright (c) by Phil Poole 2013 ++ * ++ * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor ++ * Vladimir Barinov, ++ * Copyright (C) 2007 MontaVista Software, Inc., ++ * ++ * OMAP ALSA SoC DAI driver using McBSP port ++ * Copyright (C) 2008 Nokia Corporation ++ * Contact: Jarkko Nikula ++ * Peter Ujfalusi ++ * ++ * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver ++ * Author: Timur Tabi ++ * Copyright 2007-2010 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. ++ * ++ * 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 ++#include ++ ++/* Clock registers */ ++#define BCM2708_CLK_PCMCTL_REG 0x00 ++#define BCM2708_CLK_PCMDIV_REG 0x04 ++ ++/* Clock register settings */ ++#define BCM2708_CLK_PASSWD (0x5a000000) ++#define BCM2708_CLK_PASSWD_MASK (0xff000000) ++#define BCM2708_CLK_MASH(v) ((v) << 9) ++#define BCM2708_CLK_FLIP BIT(8) ++#define BCM2708_CLK_BUSY BIT(7) ++#define BCM2708_CLK_KILL BIT(5) ++#define BCM2708_CLK_ENAB BIT(4) ++#define BCM2708_CLK_SRC(v) (v) ++ ++#define BCM2708_CLK_SHIFT (12) ++#define BCM2708_CLK_DIVI(v) ((v) << BCM2708_CLK_SHIFT) ++#define BCM2708_CLK_DIVF(v) (v) ++#define BCM2708_CLK_DIVF_MASK (0xFFF) ++ ++enum { ++ BCM2708_CLK_MASH_0 = 0, ++ BCM2708_CLK_MASH_1, ++ BCM2708_CLK_MASH_2, ++ BCM2708_CLK_MASH_3, ++}; ++ ++enum { ++ BCM2708_CLK_SRC_GND = 0, ++ BCM2708_CLK_SRC_OSC, ++ BCM2708_CLK_SRC_DBG0, ++ BCM2708_CLK_SRC_DBG1, ++ BCM2708_CLK_SRC_PLLA, ++ BCM2708_CLK_SRC_PLLC, ++ BCM2708_CLK_SRC_PLLD, ++ BCM2708_CLK_SRC_HDMI, ++}; ++ ++/* Most clocks are not useable (freq = 0) */ ++static const unsigned int bcm2708_clk_freq[BCM2708_CLK_SRC_HDMI+1] = { ++ [BCM2708_CLK_SRC_GND] = 0, ++ [BCM2708_CLK_SRC_OSC] = 19200000, ++ [BCM2708_CLK_SRC_DBG0] = 0, ++ [BCM2708_CLK_SRC_DBG1] = 0, ++ [BCM2708_CLK_SRC_PLLA] = 0, ++ [BCM2708_CLK_SRC_PLLC] = 0, ++ [BCM2708_CLK_SRC_PLLD] = 500000000, ++ [BCM2708_CLK_SRC_HDMI] = 0, ++}; ++ ++/* I2S registers */ ++#define BCM2708_I2S_CS_A_REG 0x00 ++#define BCM2708_I2S_FIFO_A_REG 0x04 ++#define BCM2708_I2S_MODE_A_REG 0x08 ++#define BCM2708_I2S_RXC_A_REG 0x0c ++#define BCM2708_I2S_TXC_A_REG 0x10 ++#define BCM2708_I2S_DREQ_A_REG 0x14 ++#define BCM2708_I2S_INTEN_A_REG 0x18 ++#define BCM2708_I2S_INTSTC_A_REG 0x1c ++#define BCM2708_I2S_GRAY_REG 0x20 ++ ++/* I2S register settings */ ++#define BCM2708_I2S_STBY BIT(25) ++#define BCM2708_I2S_SYNC BIT(24) ++#define BCM2708_I2S_RXSEX BIT(23) ++#define BCM2708_I2S_RXF BIT(22) ++#define BCM2708_I2S_TXE BIT(21) ++#define BCM2708_I2S_RXD BIT(20) ++#define BCM2708_I2S_TXD BIT(19) ++#define BCM2708_I2S_RXR BIT(18) ++#define BCM2708_I2S_TXW BIT(17) ++#define BCM2708_I2S_CS_RXERR BIT(16) ++#define BCM2708_I2S_CS_TXERR BIT(15) ++#define BCM2708_I2S_RXSYNC BIT(14) ++#define BCM2708_I2S_TXSYNC BIT(13) ++#define BCM2708_I2S_DMAEN BIT(9) ++#define BCM2708_I2S_RXTHR(v) ((v) << 7) ++#define BCM2708_I2S_TXTHR(v) ((v) << 5) ++#define BCM2708_I2S_RXCLR BIT(4) ++#define BCM2708_I2S_TXCLR BIT(3) ++#define BCM2708_I2S_TXON BIT(2) ++#define BCM2708_I2S_RXON BIT(1) ++#define BCM2708_I2S_EN (1) ++ ++#define BCM2708_I2S_CLKDIS BIT(28) ++#define BCM2708_I2S_PDMN BIT(27) ++#define BCM2708_I2S_PDME BIT(26) ++#define BCM2708_I2S_FRXP BIT(25) ++#define BCM2708_I2S_FTXP BIT(24) ++#define BCM2708_I2S_CLKM BIT(23) ++#define BCM2708_I2S_CLKI BIT(22) ++#define BCM2708_I2S_FSM BIT(21) ++#define BCM2708_I2S_FSI BIT(20) ++#define BCM2708_I2S_FLEN(v) ((v) << 10) ++#define BCM2708_I2S_FSLEN(v) (v) ++ ++#define BCM2708_I2S_CHWEX BIT(15) ++#define BCM2708_I2S_CHEN BIT(14) ++#define BCM2708_I2S_CHPOS(v) ((v) << 4) ++#define BCM2708_I2S_CHWID(v) (v) ++#define BCM2708_I2S_CH1(v) ((v) << 16) ++#define BCM2708_I2S_CH2(v) (v) ++ ++#define BCM2708_I2S_TX_PANIC(v) ((v) << 24) ++#define BCM2708_I2S_RX_PANIC(v) ((v) << 16) ++#define BCM2708_I2S_TX(v) ((v) << 8) ++#define BCM2708_I2S_RX(v) (v) ++ ++#define BCM2708_I2S_INT_RXERR BIT(3) ++#define BCM2708_I2S_INT_TXERR BIT(2) ++#define BCM2708_I2S_INT_RXR BIT(1) ++#define BCM2708_I2S_INT_TXW BIT(0) ++ ++/* I2S DMA interface */ ++#define BCM2708_I2S_FIFO_PHYSICAL_ADDR 0x7E203004 ++#define BCM2708_DMA_DREQ_PCM_TX 2 ++#define BCM2708_DMA_DREQ_PCM_RX 3 ++ ++/* General device struct */ ++struct bcm2708_i2s_dev { ++ struct device *dev; ++ struct snd_dmaengine_dai_dma_data dma_data[2]; ++ unsigned int fmt; ++ unsigned int bclk_ratio; ++ ++ struct regmap *i2s_regmap; ++ struct regmap *clk_regmap; ++}; ++ ++static void bcm2708_i2s_start_clock(struct bcm2708_i2s_dev *dev) ++{ ++ /* Start the clock if in master mode */ ++ unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; ++ ++ switch (master) { ++ case SND_SOC_DAIFMT_CBS_CFS: ++ case SND_SOC_DAIFMT_CBS_CFM: ++ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, ++ BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, ++ BCM2708_CLK_PASSWD | BCM2708_CLK_ENAB); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void bcm2708_i2s_stop_clock(struct bcm2708_i2s_dev *dev) ++{ ++ uint32_t clkreg; ++ int timeout = 1000; ++ ++ /* Stop clock */ ++ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, ++ BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, ++ BCM2708_CLK_PASSWD); ++ ++ /* Wait for the BUSY flag going down */ ++ while (--timeout) { ++ regmap_read(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, &clkreg); ++ if (!(clkreg & BCM2708_CLK_BUSY)) ++ break; ++ } ++ ++ if (!timeout) { ++ /* KILL the clock */ ++ dev_err(dev->dev, "I2S clock didn't stop. Kill the clock!\n"); ++ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, ++ BCM2708_CLK_KILL | BCM2708_CLK_PASSWD_MASK, ++ BCM2708_CLK_KILL | BCM2708_CLK_PASSWD); ++ } ++} ++ ++static void bcm2708_i2s_clear_fifos(struct bcm2708_i2s_dev *dev, ++ bool tx, bool rx) ++{ ++ int timeout = 1000; ++ uint32_t syncval; ++ uint32_t csreg; ++ uint32_t i2s_active_state; ++ uint32_t clkreg; ++ uint32_t clk_active_state; ++ uint32_t off; ++ uint32_t clr; ++ ++ off = tx ? BCM2708_I2S_TXON : 0; ++ off |= rx ? BCM2708_I2S_RXON : 0; ++ ++ clr = tx ? BCM2708_I2S_TXCLR : 0; ++ clr |= rx ? BCM2708_I2S_RXCLR : 0; ++ ++ /* Backup the current state */ ++ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &csreg); ++ i2s_active_state = csreg & (BCM2708_I2S_RXON | BCM2708_I2S_TXON); ++ ++ regmap_read(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, &clkreg); ++ clk_active_state = clkreg & BCM2708_CLK_ENAB; ++ ++ /* Start clock if not running */ ++ if (!clk_active_state) { ++ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, ++ BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, ++ BCM2708_CLK_PASSWD | BCM2708_CLK_ENAB); ++ } ++ ++ /* Stop I2S module */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, off, 0); ++ ++ /* ++ * Clear the FIFOs ++ * Requires at least 2 PCM clock cycles to take effect ++ */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, clr, clr); ++ ++ /* Wait for 2 PCM clock cycles */ ++ ++ /* ++ * Toggle the SYNC flag. After 2 PCM clock cycles it can be read back ++ * FIXME: This does not seem to work for slave mode! ++ */ ++ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &syncval); ++ syncval &= BCM2708_I2S_SYNC; ++ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_SYNC, ~syncval); ++ ++ /* Wait for the SYNC flag changing it's state */ ++ while (--timeout) { ++ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &csreg); ++ if ((csreg & BCM2708_I2S_SYNC) != syncval) ++ break; ++ } ++ ++ if (!timeout) ++ dev_err(dev->dev, "I2S SYNC error!\n"); ++ ++ /* Stop clock if it was not running before */ ++ if (!clk_active_state) ++ bcm2708_i2s_stop_clock(dev); ++ ++ /* Restore I2S state */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_RXON | BCM2708_I2S_TXON, i2s_active_state); ++} ++ ++static int bcm2708_i2s_set_dai_fmt(struct snd_soc_dai *dai, ++ unsigned int fmt) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ dev->fmt = fmt; ++ return 0; ++} ++ ++static int bcm2708_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai, ++ unsigned int ratio) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ dev->bclk_ratio = ratio; ++ return 0; ++} ++ ++static int bcm2708_i2s_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ ++ unsigned int sampling_rate = params_rate(params); ++ unsigned int data_length, data_delay, bclk_ratio; ++ unsigned int ch1pos, ch2pos, mode, format; ++ unsigned int mash = BCM2708_CLK_MASH_1; ++ unsigned int divi, divf, target_frequency; ++ int clk_src = -1; ++ unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; ++ bool bit_master = (master == SND_SOC_DAIFMT_CBS_CFS ++ || master == SND_SOC_DAIFMT_CBS_CFM); ++ ++ bool frame_master = (master == SND_SOC_DAIFMT_CBS_CFS ++ || master == SND_SOC_DAIFMT_CBM_CFS); ++ uint32_t csreg; ++ ++ /* ++ * If a stream is already enabled, ++ * the registers are already set properly. ++ */ ++ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &csreg); ++ ++ if (csreg & (BCM2708_I2S_TXON | BCM2708_I2S_RXON)) ++ return 0; ++ ++ /* ++ * Adjust the data length according to the format. ++ * We prefill the half frame length with an integer ++ * divider of 2400 as explained at the clock settings. ++ * Maybe it is overwritten there, if the Integer mode ++ * does not apply. ++ */ ++ switch (params_format(params)) { ++ case SNDRV_PCM_FORMAT_S16_LE: ++ data_length = 16; ++ bclk_ratio = 40; ++ break; ++ case SNDRV_PCM_FORMAT_S24_LE: ++ data_length = 24; ++ bclk_ratio = 40; ++ break; ++ case SNDRV_PCM_FORMAT_S32_LE: ++ data_length = 32; ++ bclk_ratio = 80; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* If bclk_ratio already set, use that one. */ ++ if (dev->bclk_ratio) ++ bclk_ratio = dev->bclk_ratio; ++ ++ /* ++ * Clock Settings ++ * ++ * The target frequency of the bit clock is ++ * sampling rate * frame length ++ * ++ * Integer mode: ++ * Sampling rates that are multiples of 8000 kHz ++ * can be driven by the oscillator of 19.2 MHz ++ * with an integer divider as long as the frame length ++ * is an integer divider of 19200000/8000=2400 as set up above. ++ * This is no longer possible if the sampling rate ++ * is too high (e.g. 192 kHz), because the oscillator is too slow. ++ * ++ * MASH mode: ++ * For all other sampling rates, it is not possible to ++ * have an integer divider. Approximate the clock ++ * with the MASH module that induces a slight frequency ++ * variance. To minimize that it is best to have the fastest ++ * clock here. That is PLLD with 500 MHz. ++ */ ++ target_frequency = sampling_rate * bclk_ratio; ++ clk_src = BCM2708_CLK_SRC_OSC; ++ mash = BCM2708_CLK_MASH_0; ++ ++ if (bcm2708_clk_freq[clk_src] % target_frequency == 0 ++ && bit_master && frame_master) { ++ divi = bcm2708_clk_freq[clk_src] / target_frequency; ++ divf = 0; ++ } else { ++ uint64_t dividend; ++ ++ if (!dev->bclk_ratio) { ++ /* ++ * Overwrite bclk_ratio, because the ++ * above trick is not needed or can ++ * not be used. ++ */ ++ bclk_ratio = 2 * data_length; ++ } ++ ++ target_frequency = sampling_rate * bclk_ratio; ++ ++ clk_src = BCM2708_CLK_SRC_PLLD; ++ mash = BCM2708_CLK_MASH_1; ++ ++ dividend = bcm2708_clk_freq[clk_src]; ++ dividend <<= BCM2708_CLK_SHIFT; ++ do_div(dividend, target_frequency); ++ divi = dividend >> BCM2708_CLK_SHIFT; ++ divf = dividend & BCM2708_CLK_DIVF_MASK; ++ } ++ ++ /* Set clock divider */ ++ regmap_write(dev->clk_regmap, BCM2708_CLK_PCMDIV_REG, BCM2708_CLK_PASSWD ++ | BCM2708_CLK_DIVI(divi) ++ | BCM2708_CLK_DIVF(divf)); ++ ++ /* Setup clock, but don't start it yet */ ++ regmap_write(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, BCM2708_CLK_PASSWD ++ | BCM2708_CLK_MASH(mash) ++ | BCM2708_CLK_SRC(clk_src)); ++ ++ /* Setup the frame format */ ++ format = BCM2708_I2S_CHEN; ++ ++ if (data_length >= 24) ++ format |= BCM2708_I2S_CHWEX; ++ ++ format |= BCM2708_I2S_CHWID((data_length-8)&0xf); ++ ++ switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ data_delay = 1; ++ break; ++ default: ++ /* ++ * TODO ++ * Others are possible but are not implemented at the moment. ++ */ ++ dev_err(dev->dev, "%s:bad format\n", __func__); ++ return -EINVAL; ++ } ++ ++ ch1pos = data_delay; ++ ch2pos = bclk_ratio / 2 + data_delay; ++ ++ switch (params_channels(params)) { ++ case 2: ++ format = BCM2708_I2S_CH1(format) | BCM2708_I2S_CH2(format); ++ format |= BCM2708_I2S_CH1(BCM2708_I2S_CHPOS(ch1pos)); ++ format |= BCM2708_I2S_CH2(BCM2708_I2S_CHPOS(ch2pos)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* ++ * Set format for both streams. ++ * We cannot set another frame length ++ * (and therefore word length) anyway, ++ * so the format will be the same. ++ */ ++ regmap_write(dev->i2s_regmap, BCM2708_I2S_RXC_A_REG, format); ++ regmap_write(dev->i2s_regmap, BCM2708_I2S_TXC_A_REG, format); ++ ++ /* Setup the I2S mode */ ++ mode = 0; ++ ++ if (data_length <= 16) { ++ /* ++ * Use frame packed mode (2 channels per 32 bit word) ++ * We cannot set another frame length in the second stream ++ * (and therefore word length) anyway, ++ * so the format will be the same. ++ */ ++ mode |= BCM2708_I2S_FTXP | BCM2708_I2S_FRXP; ++ } ++ ++ mode |= BCM2708_I2S_FLEN(bclk_ratio - 1); ++ mode |= BCM2708_I2S_FSLEN(bclk_ratio / 2); ++ ++ /* Master or slave? */ ++ switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBS_CFS: ++ /* CPU is master */ ++ break; ++ case SND_SOC_DAIFMT_CBM_CFS: ++ /* ++ * CODEC is bit clock master ++ * CPU is frame master ++ */ ++ mode |= BCM2708_I2S_CLKM; ++ break; ++ case SND_SOC_DAIFMT_CBS_CFM: ++ /* ++ * CODEC is frame master ++ * CPU is bit clock master ++ */ ++ mode |= BCM2708_I2S_FSM; ++ break; ++ case SND_SOC_DAIFMT_CBM_CFM: ++ /* CODEC is master */ ++ mode |= BCM2708_I2S_CLKM; ++ mode |= BCM2708_I2S_FSM; ++ break; ++ default: ++ dev_err(dev->dev, "%s:bad master\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* ++ * Invert clocks? ++ * ++ * The BCM approach seems to be inverted to the classical I2S approach. ++ */ ++ switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_NF: ++ /* None. Therefore, both for BCM */ ++ mode |= BCM2708_I2S_CLKI; ++ mode |= BCM2708_I2S_FSI; ++ break; ++ case SND_SOC_DAIFMT_IB_IF: ++ /* Both. Therefore, none for BCM */ ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ /* ++ * Invert only frame sync. Therefore, ++ * invert only bit clock for BCM ++ */ ++ mode |= BCM2708_I2S_CLKI; ++ break; ++ case SND_SOC_DAIFMT_IB_NF: ++ /* ++ * Invert only bit clock. Therefore, ++ * invert only frame sync for BCM ++ */ ++ mode |= BCM2708_I2S_FSI; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_write(dev->i2s_regmap, BCM2708_I2S_MODE_A_REG, mode); ++ ++ /* Setup the DMA parameters */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_RXTHR(1) ++ | BCM2708_I2S_TXTHR(1) ++ | BCM2708_I2S_DMAEN, 0xffffffff); ++ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_DREQ_A_REG, ++ BCM2708_I2S_TX_PANIC(0x10) ++ | BCM2708_I2S_RX_PANIC(0x30) ++ | BCM2708_I2S_TX(0x30) ++ | BCM2708_I2S_RX(0x20), 0xffffffff); ++ ++ /* Clear FIFOs */ ++ bcm2708_i2s_clear_fifos(dev, true, true); ++ ++ return 0; ++} ++ ++static int bcm2708_i2s_prepare(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ uint32_t cs_reg; ++ ++ bcm2708_i2s_start_clock(dev); ++ ++ /* ++ * Clear both FIFOs if the one that should be started ++ * is not empty at the moment. This should only happen ++ * after overrun. Otherwise, hw_params would have cleared ++ * the FIFO. ++ */ ++ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &cs_reg); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ++ && !(cs_reg & BCM2708_I2S_TXE)) ++ bcm2708_i2s_clear_fifos(dev, true, false); ++ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE ++ && (cs_reg & BCM2708_I2S_RXD)) ++ bcm2708_i2s_clear_fifos(dev, false, true); ++ ++ return 0; ++} ++ ++static void bcm2708_i2s_stop(struct bcm2708_i2s_dev *dev, ++ struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ uint32_t mask; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ++ mask = BCM2708_I2S_RXON; ++ else ++ mask = BCM2708_I2S_TXON; ++ ++ regmap_update_bits(dev->i2s_regmap, ++ BCM2708_I2S_CS_A_REG, mask, 0); ++ ++ /* Stop also the clock when not SND_SOC_DAIFMT_CONT */ ++ if (!dai->active && !(dev->fmt & SND_SOC_DAIFMT_CONT)) ++ bcm2708_i2s_stop_clock(dev); ++} ++ ++static int bcm2708_i2s_trigger(struct snd_pcm_substream *substream, int cmd, ++ struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ uint32_t mask; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ bcm2708_i2s_start_clock(dev); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ++ mask = BCM2708_I2S_RXON; ++ else ++ mask = BCM2708_I2S_TXON; ++ ++ regmap_update_bits(dev->i2s_regmap, ++ BCM2708_I2S_CS_A_REG, mask, mask); ++ break; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ bcm2708_i2s_stop(dev, substream, dai); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int bcm2708_i2s_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ ++ if (dai->active) ++ return 0; ++ ++ /* Should this still be running stop it */ ++ bcm2708_i2s_stop_clock(dev); ++ ++ /* Enable PCM block */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_EN, BCM2708_I2S_EN); ++ ++ /* ++ * Disable STBY. ++ * Requires at least 4 PCM clock cycles to take effect. ++ */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_STBY, BCM2708_I2S_STBY); ++ ++ return 0; ++} ++ ++static void bcm2708_i2s_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ ++ bcm2708_i2s_stop(dev, substream, dai); ++ ++ /* If both streams are stopped, disable module and clock */ ++ if (dai->active) ++ return; ++ ++ /* Disable the module */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_EN, 0); ++ ++ /* ++ * Stopping clock is necessary, because stop does ++ * not stop the clock when SND_SOC_DAIFMT_CONT ++ */ ++ bcm2708_i2s_stop_clock(dev); ++} ++ ++static const struct snd_soc_dai_ops bcm2708_i2s_dai_ops = { ++ .startup = bcm2708_i2s_startup, ++ .shutdown = bcm2708_i2s_shutdown, ++ .prepare = bcm2708_i2s_prepare, ++ .trigger = bcm2708_i2s_trigger, ++ .hw_params = bcm2708_i2s_hw_params, ++ .set_fmt = bcm2708_i2s_set_dai_fmt, ++ .set_bclk_ratio = bcm2708_i2s_set_dai_bclk_ratio ++}; ++ ++static int bcm2708_i2s_dai_probe(struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ ++ dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; ++ dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; ++ ++ return 0; ++} ++ ++static struct snd_soc_dai_driver bcm2708_i2s_dai = { ++ .name = "bcm2708-i2s", ++ .probe = bcm2708_i2s_dai_probe, ++ .playback = { ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE ++ | SNDRV_PCM_FMTBIT_S24_LE ++ | SNDRV_PCM_FMTBIT_S32_LE ++ }, ++ .capture = { ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE ++ | SNDRV_PCM_FMTBIT_S24_LE ++ | SNDRV_PCM_FMTBIT_S32_LE ++ }, ++ .ops = &bcm2708_i2s_dai_ops, ++ .symmetric_rates = 1 ++}; ++ ++static bool bcm2708_i2s_volatile_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case BCM2708_I2S_CS_A_REG: ++ case BCM2708_I2S_FIFO_A_REG: ++ case BCM2708_I2S_INTSTC_A_REG: ++ case BCM2708_I2S_GRAY_REG: ++ return true; ++ default: ++ return false; ++ }; ++} ++ ++static bool bcm2708_i2s_precious_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case BCM2708_I2S_FIFO_A_REG: ++ return true; ++ default: ++ return false; ++ }; ++} ++ ++static bool bcm2708_clk_volatile_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case BCM2708_CLK_PCMCTL_REG: ++ return true; ++ default: ++ return false; ++ }; ++} ++ ++static const struct regmap_config bcm2708_regmap_config[] = { ++ { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = BCM2708_I2S_GRAY_REG, ++ .precious_reg = bcm2708_i2s_precious_reg, ++ .volatile_reg = bcm2708_i2s_volatile_reg, ++ .cache_type = REGCACHE_RBTREE, ++ }, ++ { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = BCM2708_CLK_PCMDIV_REG, ++ .volatile_reg = bcm2708_clk_volatile_reg, ++ .cache_type = REGCACHE_RBTREE, ++ }, ++}; ++ ++static const struct snd_soc_component_driver bcm2708_i2s_component = { ++ .name = "bcm2708-i2s-comp", ++}; ++ ++ ++static void bcm2708_i2s_setup_gpio(void) ++{ ++ /* ++ * This is the common way to handle the GPIO pins for ++ * the Raspberry Pi. ++ * TODO Better way would be to handle ++ * this in the device tree! ++ */ ++#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3)) ++#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) ++ ++ unsigned int *gpio; ++ int pin; ++ gpio = ioremap(GPIO_BASE, SZ_16K); ++ ++ /* SPI is on GPIO 7..11 */ ++ for (pin = 28; pin <= 31; pin++) { ++ INP_GPIO(pin); /* set mode to GPIO input first */ ++ SET_GPIO_ALT(pin, 2); /* set mode to ALT 0 */ ++ } ++#undef INP_GPIO ++#undef SET_GPIO_ALT ++} ++ ++static const struct snd_pcm_hardware bcm2708_pcm_hardware = { ++ .info = SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_JOINT_DUPLEX, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE, ++ .period_bytes_min = 32, ++ .period_bytes_max = 64 * PAGE_SIZE, ++ .periods_min = 2, ++ .periods_max = 255, ++ .buffer_bytes_max = 128 * PAGE_SIZE, ++}; ++ ++static const struct snd_dmaengine_pcm_config bcm2708_dmaengine_pcm_config = { ++ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, ++ .pcm_hardware = &bcm2708_pcm_hardware, ++ .prealloc_buffer_size = 256 * PAGE_SIZE, ++}; ++ ++ ++static int bcm2708_i2s_probe(struct platform_device *pdev) ++{ ++ struct bcm2708_i2s_dev *dev; ++ int i; ++ int ret; ++ struct regmap *regmap[2]; ++ struct resource *mem[2]; ++ ++ /* Request both ioareas */ ++ for (i = 0; i <= 1; i++) { ++ void __iomem *base; ++ ++ mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i); ++ base = devm_ioremap_resource(&pdev->dev, mem[i]); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ regmap[i] = devm_regmap_init_mmio(&pdev->dev, base, ++ &bcm2708_regmap_config[i]); ++ if (IS_ERR(regmap[i])) { ++ dev_err(&pdev->dev, "I2S probe: regmap init failed\n"); ++ return PTR_ERR(regmap[i]); ++ } ++ } ++ ++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), ++ GFP_KERNEL); ++ if (IS_ERR(dev)) ++ return PTR_ERR(dev); ++ ++ bcm2708_i2s_setup_gpio(); ++ ++ dev->i2s_regmap = regmap[0]; ++ dev->clk_regmap = regmap[1]; ++ ++ /* Set the DMA address */ ++ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = ++ (dma_addr_t)BCM2708_I2S_FIFO_PHYSICAL_ADDR; ++ ++ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = ++ (dma_addr_t)BCM2708_I2S_FIFO_PHYSICAL_ADDR; ++ ++ /* Set the DREQ */ ++ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].slave_id = ++ BCM2708_DMA_DREQ_PCM_TX; ++ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].slave_id = ++ BCM2708_DMA_DREQ_PCM_RX; ++ ++ /* Set the bus width */ ++ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width = ++ DMA_SLAVE_BUSWIDTH_4_BYTES; ++ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr_width = ++ DMA_SLAVE_BUSWIDTH_4_BYTES; ++ ++ /* Set burst */ ++ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2; ++ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2; ++ ++ /* BCLK ratio - use default */ ++ dev->bclk_ratio = 0; ++ ++ /* Store the pdev */ ++ dev->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, dev); ++ ++ ret = snd_soc_register_component(&pdev->dev, ++ &bcm2708_i2s_component, &bcm2708_i2s_dai, 1); ++ ++ if (ret) { ++ dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ++ ret = -ENOMEM; ++ return ret; ++ } ++ ++ ret = snd_dmaengine_pcm_register(&pdev->dev, ++ &bcm2708_dmaengine_pcm_config, ++ SND_DMAENGINE_PCM_FLAG_COMPAT); ++ if (ret) { ++ dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); ++ snd_soc_unregister_component(&pdev->dev); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int bcm2708_i2s_remove(struct platform_device *pdev) ++{ ++ snd_dmaengine_pcm_unregister(&pdev->dev); ++ snd_soc_unregister_component(&pdev->dev); ++ return 0; ++} ++ ++static struct platform_driver bcm2708_i2s_driver = { ++ .probe = bcm2708_i2s_probe, ++ .remove = bcm2708_i2s_remove, ++ .driver = { ++ .name = "bcm2708-i2s", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(bcm2708_i2s_driver); ++ ++MODULE_ALIAS("platform:bcm2708-i2s"); ++MODULE_DESCRIPTION("BCM2708 I2S interface"); ++MODULE_AUTHOR("Florian Meier "); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.10.33/sound/soc/bcm/hifiberry_dac.c linux-raspberry-pi/sound/soc/bcm/hifiberry_dac.c +--- linux-3.10.33/sound/soc/bcm/hifiberry_dac.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/bcm/hifiberry_dac.c 2014-03-13 12:46:44.480107952 +0100 +@@ -0,0 +1,100 @@ ++/* ++ * ASoC Driver for HifiBerry DAC ++ * ++ * Author: Florian Meier ++ * Copyright 2013 ++ * ++ * This program is free software; you can 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. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int snd_rpi_hifiberry_dac_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ return 0; ++} ++ ++static int snd_rpi_hifiberry_dac_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ ++ unsigned int sample_bits = ++ snd_pcm_format_physical_width(params_format(params)); ++ ++ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2); ++} ++ ++/* machine stream operations */ ++static struct snd_soc_ops snd_rpi_hifiberry_dac_ops = { ++ .hw_params = snd_rpi_hifiberry_dac_hw_params, ++}; ++ ++static struct snd_soc_dai_link snd_rpi_hifiberry_dac_dai[] = { ++{ ++ .name = "HifiBerry DAC", ++ .stream_name = "HifiBerry DAC HiFi", ++ .cpu_dai_name = "bcm2708-i2s.0", ++ .codec_dai_name = "pcm5102a-hifi", ++ .platform_name = "bcm2708-i2s.0", ++ .codec_name = "pcm5102a-codec", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .ops = &snd_rpi_hifiberry_dac_ops, ++ .init = snd_rpi_hifiberry_dac_init, ++}, ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_hifiberry_dac = { ++ .name = "snd_rpi_hifiberry_dac", ++ .dai_link = snd_rpi_hifiberry_dac_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dac_dai), ++}; ++ ++static int snd_rpi_hifiberry_dac_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ snd_rpi_hifiberry_dac.dev = &pdev->dev; ++ ret = snd_soc_register_card(&snd_rpi_hifiberry_dac); ++ if (ret) ++ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static int snd_rpi_hifiberry_dac_remove(struct platform_device *pdev) ++{ ++ return snd_soc_unregister_card(&snd_rpi_hifiberry_dac); ++} ++ ++static struct platform_driver snd_rpi_hifiberry_dac_driver = { ++ .driver = { ++ .name = "snd-hifiberry-dac", ++ .owner = THIS_MODULE, ++ }, ++ .probe = snd_rpi_hifiberry_dac_probe, ++ .remove = snd_rpi_hifiberry_dac_remove, ++}; ++ ++module_platform_driver(snd_rpi_hifiberry_dac_driver); ++ ++MODULE_AUTHOR("Florian Meier "); ++MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.10.33/sound/soc/bcm/hifiberry_digi.c linux-raspberry-pi/sound/soc/bcm/hifiberry_digi.c +--- linux-3.10.33/sound/soc/bcm/hifiberry_digi.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/bcm/hifiberry_digi.c 2014-03-13 12:46:44.480107952 +0100 +@@ -0,0 +1,153 @@ ++/* ++ * ASoC Driver for HifiBerry Digi ++ * ++ * Author: Daniel Matuschek ++ * based on the HifiBerry DAC driver by Florian Meier ++ * Copyright 2013 ++ * ++ * This program is free software; you can 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. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "../codecs/wm8804.h" ++ ++static int samplerate=44100; ++ ++static int snd_rpi_hifiberry_digi_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_soc_codec *codec = rtd->codec; ++ ++ /* enable TX output */ ++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0); ++ ++ return 0; ++} ++ ++static int snd_rpi_hifiberry_digi_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *codec_dai = rtd->codec_dai; ++ struct snd_soc_codec *codec = rtd->codec; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ ++ int sysclk = 27000000; /* This is fixed on this board */ ++ ++ long mclk_freq=0; ++ int mclk_div=1; ++ ++ int ret; ++ ++ samplerate = params_rate(params); ++ ++ switch (samplerate) { ++ case 44100: ++ case 48000: ++ case 88200: ++ case 96000: ++ mclk_freq=samplerate*256; ++ mclk_div=WM8804_MCLKDIV_256FS; ++ break; ++ case 176400: ++ case 192000: ++ mclk_freq=samplerate*128; ++ mclk_div=WM8804_MCLKDIV_128FS; ++ break; ++ default: ++ dev_err(substream->pcm->dev, ++ "Failed to set WM8804 SYSCLK, unsupported samplerate\n"); ++ } ++ ++ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div); ++ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq); ++ ++ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL, ++ sysclk, SND_SOC_CLOCK_OUT); ++ if (ret < 0) { ++ dev_err(substream->pcm->dev, ++ "Failed to set WM8804 SYSCLK: %d\n", ret); ++ return ret; ++ } ++ ++ /* Enable TX output */ ++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0); ++ ++ /* Power on */ ++ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0); ++ ++ return snd_soc_dai_set_bclk_ratio(cpu_dai,64); ++} ++ ++/* machine stream operations */ ++static struct snd_soc_ops snd_rpi_hifiberry_digi_ops = { ++ .hw_params = snd_rpi_hifiberry_digi_hw_params, ++}; ++ ++static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = { ++{ ++ .name = "HifiBerry Digi", ++ .stream_name = "HifiBerry Digi HiFi", ++ .cpu_dai_name = "bcm2708-i2s.0", ++ .codec_dai_name = "wm8804-spdif", ++ .platform_name = "bcm2708-i2s.0", ++ .codec_name = "wm8804.1-003b", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBM_CFM, ++ .ops = &snd_rpi_hifiberry_digi_ops, ++ .init = snd_rpi_hifiberry_digi_init, ++}, ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_hifiberry_digi = { ++ .name = "snd_rpi_hifiberry_digi", ++ .dai_link = snd_rpi_hifiberry_digi_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_digi_dai), ++}; ++ ++static int snd_rpi_hifiberry_digi_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ snd_rpi_hifiberry_digi.dev = &pdev->dev; ++ ret = snd_soc_register_card(&snd_rpi_hifiberry_digi); ++ if (ret) ++ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static int snd_rpi_hifiberry_digi_remove(struct platform_device *pdev) ++{ ++ return snd_soc_unregister_card(&snd_rpi_hifiberry_digi); ++} ++ ++static struct platform_driver snd_rpi_hifiberry_digi_driver = { ++ .driver = { ++ .name = "snd-hifiberry-digi", ++ .owner = THIS_MODULE, ++ }, ++ .probe = snd_rpi_hifiberry_digi_probe, ++ .remove = snd_rpi_hifiberry_digi_remove, ++}; ++ ++module_platform_driver(snd_rpi_hifiberry_digi_driver); ++ ++MODULE_AUTHOR("Daniel Matuschek "); ++MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.10.33/sound/soc/bcm/Kconfig linux-raspberry-pi/sound/soc/bcm/Kconfig +--- linux-3.10.33/sound/soc/bcm/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/bcm/Kconfig 2014-03-13 12:46:44.480107952 +0100 +@@ -0,0 +1,31 @@ ++config SND_BCM2708_SOC_I2S ++ tristate "SoC Audio support for the Broadcom BCM2708 I2S module" ++ depends on MACH_BCM2708 ++ select REGMAP_MMIO ++ select SND_SOC_DMAENGINE_PCM ++ select SND_SOC_GENERIC_DMAENGINE_PCM ++ help ++ Say Y or M if you want to add support for codecs attached to ++ the BCM2708 I2S interface. You will also need ++ to select the audio interfaces to support below. ++ ++config SND_BCM2708_SOC_HIFIBERRY_DAC ++ tristate "Support for HifiBerry DAC" ++ depends on SND_BCM2708_SOC_I2S ++ select SND_SOC_PCM5102A ++ help ++ Say Y or M if you want to add support for HifiBerry DAC. ++ ++config SND_BCM2708_SOC_HIFIBERRY_DIGI ++ tristate "Support for HifiBerry Digi" ++ depends on SND_BCM2708_SOC_I2S ++ select SND_SOC_WM8804 ++ help ++ Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board. ++ ++config SND_BCM2708_SOC_RPI_DAC ++ tristate "Support for RPi-DAC" ++ depends on SND_BCM2708_SOC_I2S ++ select SND_SOC_PCM1794A ++ help ++ Say Y or M if you want to add support for RPi-DAC. +diff -Nur linux-3.10.33/sound/soc/bcm/Makefile linux-raspberry-pi/sound/soc/bcm/Makefile +--- linux-3.10.33/sound/soc/bcm/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/bcm/Makefile 2014-03-13 12:46:44.480107952 +0100 +@@ -0,0 +1,13 @@ ++# BCM2708 Platform Support ++snd-soc-bcm2708-i2s-objs := bcm2708-i2s.o ++ ++obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd-soc-bcm2708-i2s.o ++ ++# BCM2708 Machine Support ++snd-soc-hifiberry-dac-objs := hifiberry_dac.o ++snd-soc-hifiberry-digi-objs := hifiberry_digi.o ++snd-soc-rpi-dac-objs := rpi-dac.o ++ ++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o ++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o ++obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o +diff -Nur linux-3.10.33/sound/soc/bcm/rpi-dac.c linux-raspberry-pi/sound/soc/bcm/rpi-dac.c +--- linux-3.10.33/sound/soc/bcm/rpi-dac.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/bcm/rpi-dac.c 2014-03-13 12:46:44.480107952 +0100 +@@ -0,0 +1,97 @@ ++/* ++ * ASoC Driver for RPi-DAC. ++ * ++ * Author: Florian Meier ++ * Copyright 2013 ++ * ++ * This program is free software; you can 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. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int snd_rpi_rpi_dac_init(struct snd_soc_pcm_runtime *rtd) ++{ ++ return 0; ++} ++ ++static int snd_rpi_rpi_dac_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ ++ return snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2); ++} ++ ++/* machine stream operations */ ++static struct snd_soc_ops snd_rpi_rpi_dac_ops = { ++ .hw_params = snd_rpi_rpi_dac_hw_params, ++}; ++ ++static struct snd_soc_dai_link snd_rpi_rpi_dac_dai[] = { ++{ ++ .name = "HifiBerry Mini", ++ .stream_name = "HifiBerry Mini HiFi", ++ .cpu_dai_name = "bcm2708-i2s.0", ++ .codec_dai_name = "pcm1794a-hifi", ++ .platform_name = "bcm2708-i2s.0", ++ .codec_name = "pcm1794a-codec", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .ops = &snd_rpi_rpi_dac_ops, ++ .init = snd_rpi_rpi_dac_init, ++}, ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_rpi_dac = { ++ .name = "snd_rpi_rpi_dac", ++ .dai_link = snd_rpi_rpi_dac_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_rpi_dac_dai), ++}; ++ ++static int snd_rpi_rpi_dac_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ snd_rpi_rpi_dac.dev = &pdev->dev; ++ ret = snd_soc_register_card(&snd_rpi_rpi_dac); ++ if (ret) ++ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static int snd_rpi_rpi_dac_remove(struct platform_device *pdev) ++{ ++ return snd_soc_unregister_card(&snd_rpi_rpi_dac); ++} ++ ++static struct platform_driver snd_rpi_rpi_dac_driver = { ++ .driver = { ++ .name = "snd-rpi-dac", ++ .owner = THIS_MODULE, ++ }, ++ .probe = snd_rpi_rpi_dac_probe, ++ .remove = snd_rpi_rpi_dac_remove, ++}; ++ ++module_platform_driver(snd_rpi_rpi_dac_driver); ++ ++MODULE_AUTHOR("Florian Meier "); ++MODULE_DESCRIPTION("ASoC Driver for RPi-DAC"); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.10.33/sound/soc/codecs/Kconfig linux-raspberry-pi/sound/soc/codecs/Kconfig +--- linux-3.10.33/sound/soc/codecs/Kconfig 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/codecs/Kconfig 2014-03-13 12:46:44.524108040 +0100 +@@ -55,6 +55,8 @@ + select SND_SOC_ML26124 if I2C + select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI + select SND_SOC_PCM3008 ++ select SND_SOC_PCM1794A ++ select SND_SOC_PCM5102A + select SND_SOC_RT5631 if I2C + select SND_SOC_SGTL5000 if I2C + select SND_SOC_SI476X if MFD_SI476X_CORE +@@ -293,6 +295,12 @@ + config SND_SOC_PCM3008 + tristate + ++config SND_SOC_PCM1794A ++ tristate ++ ++config SND_SOC_PCM5102A ++ tristate ++ + config SND_SOC_RT5631 + tristate + +diff -Nur linux-3.10.33/sound/soc/codecs/Makefile linux-raspberry-pi/sound/soc/codecs/Makefile +--- linux-3.10.33/sound/soc/codecs/Makefile 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/codecs/Makefile 2014-03-13 12:46:44.524108040 +0100 +@@ -43,6 +43,8 @@ + snd-soc-ml26124-objs := ml26124.o + snd-soc-omap-hdmi-codec-objs := omap-hdmi.o + snd-soc-pcm3008-objs := pcm3008.o ++snd-soc-pcm1794a-objs := pcm1794a.o ++snd-soc-pcm5102a-objs := pcm5102a.o + snd-soc-rt5631-objs := rt5631.o + snd-soc-sgtl5000-objs := sgtl5000.o + snd-soc-alc5623-objs := alc5623.o +@@ -170,6 +172,8 @@ + obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o + obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o + obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o ++obj-$(CONFIG_SND_SOC_PCM1794A) += snd-soc-pcm1794a.o ++obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o + obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o + obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o + obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o +diff -Nur linux-3.10.33/sound/soc/codecs/pcm1794a.c linux-raspberry-pi/sound/soc/codecs/pcm1794a.c +--- linux-3.10.33/sound/soc/codecs/pcm1794a.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/codecs/pcm1794a.c 2014-03-13 12:46:44.540108072 +0100 +@@ -0,0 +1,62 @@ ++/* ++ * Driver for the PCM1794A codec ++ * ++ * Author: Florian Meier ++ * Copyright 2013 ++ * ++ * This program is free software; you can 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. ++ */ ++ ++ ++#include ++#include ++#include ++ ++#include ++ ++static struct snd_soc_dai_driver pcm1794a_dai = { ++ .name = "pcm1794a-hifi", ++ .playback = { ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE ++ }, ++}; ++ ++static struct snd_soc_codec_driver soc_codec_dev_pcm1794a; ++ ++static int pcm1794a_probe(struct platform_device *pdev) ++{ ++ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm1794a, ++ &pcm1794a_dai, 1); ++} ++ ++static int pcm1794a_remove(struct platform_device *pdev) ++{ ++ snd_soc_unregister_codec(&pdev->dev); ++ return 0; ++} ++ ++static struct platform_driver pcm1794a_codec_driver = { ++ .probe = pcm1794a_probe, ++ .remove = pcm1794a_remove, ++ .driver = { ++ .name = "pcm1794a-codec", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(pcm1794a_codec_driver); ++ ++MODULE_DESCRIPTION("ASoC PCM1794A codec driver"); ++MODULE_AUTHOR("Florian Meier "); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.10.33/sound/soc/codecs/pcm5102a.c linux-raspberry-pi/sound/soc/codecs/pcm5102a.c +--- linux-3.10.33/sound/soc/codecs/pcm5102a.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/codecs/pcm5102a.c 2014-03-13 12:46:44.540108072 +0100 +@@ -0,0 +1,63 @@ ++/* ++ * Driver for the PCM5102A codec ++ * ++ * Author: Florian Meier ++ * Copyright 2013 ++ * ++ * This program is free software; you can 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. ++ */ ++ ++ ++#include ++#include ++#include ++ ++#include ++ ++static struct snd_soc_dai_driver pcm5102a_dai = { ++ .name = "pcm5102a-hifi", ++ .playback = { ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | ++ // SNDRV_PCM_FMTBIT_S24_LE | : disable for now, it causes white noise with xbmc ++ SNDRV_PCM_FMTBIT_S32_LE ++ }, ++}; ++ ++static struct snd_soc_codec_driver soc_codec_dev_pcm5102a; ++ ++static int pcm5102a_probe(struct platform_device *pdev) ++{ ++ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm5102a, ++ &pcm5102a_dai, 1); ++} ++ ++static int pcm5102a_remove(struct platform_device *pdev) ++{ ++ snd_soc_unregister_codec(&pdev->dev); ++ return 0; ++} ++ ++static struct platform_driver pcm5102a_codec_driver = { ++ .probe = pcm5102a_probe, ++ .remove = pcm5102a_remove, ++ .driver = { ++ .name = "pcm5102a-codec", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(pcm5102a_codec_driver); ++ ++MODULE_DESCRIPTION("ASoC PCM5102A codec driver"); ++MODULE_AUTHOR("Florian Meier "); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.10.33/sound/soc/codecs/wm8804.c linux-raspberry-pi/sound/soc/codecs/wm8804.c +--- linux-3.10.33/sound/soc/codecs/wm8804.c 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/codecs/wm8804.c 2014-03-13 12:46:44.660108313 +0100 +@@ -63,6 +63,7 @@ + struct regmap *regmap; + struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES]; + struct notifier_block disable_nb[WM8804_NUM_SUPPLIES]; ++ int mclk_div; + }; + + static int txsrc_get(struct snd_kcontrol *kcontrol, +@@ -277,6 +278,7 @@ + blen = 0x1; + break; + case SNDRV_PCM_FORMAT_S24_LE: ++ case SNDRV_PCM_FORMAT_S32_LE: + blen = 0x2; + break; + default: +@@ -318,7 +320,7 @@ + + #define FIXED_PLL_SIZE ((1ULL << 22) * 10) + static int pll_factors(struct pll_div *pll_div, unsigned int target, +- unsigned int source) ++ unsigned int source, unsigned int mclk_div) + { + u64 Kpart; + unsigned long int K, Ndiv, Nmod, tmp; +@@ -330,7 +332,8 @@ + */ + for (i = 0; i < ARRAY_SIZE(post_table); i++) { + tmp = target * post_table[i].div; +- if (tmp >= 90000000 && tmp <= 100000000) { ++ if ((tmp >= 90000000 && tmp <= 100000000) && ++ (mclk_div == post_table[i].mclkdiv)) { + pll_div->freqmode = post_table[i].freqmode; + pll_div->mclkdiv = post_table[i].mclkdiv; + target *= post_table[i].div; +@@ -387,8 +390,11 @@ + } else { + int ret; + struct pll_div pll_div; ++ struct wm8804_priv *wm8804; + +- ret = pll_factors(&pll_div, freq_out, freq_in); ++ wm8804 = snd_soc_codec_get_drvdata(codec); ++ ++ ret = pll_factors(&pll_div, freq_out, freq_in, wm8804->mclk_div); + if (ret) + return ret; + +@@ -452,6 +458,7 @@ + int div_id, int div) + { + struct snd_soc_codec *codec; ++ struct wm8804_priv *wm8804; + + codec = dai->codec; + switch (div_id) { +@@ -459,6 +466,10 @@ + snd_soc_update_bits(codec, WM8804_PLL5, 0x30, + (div & 0x3) << 4); + break; ++ case WM8804_MCLK_DIV: ++ wm8804 = snd_soc_codec_get_drvdata(codec); ++ wm8804->mclk_div = div; ++ break; + default: + dev_err(dai->dev, "Unknown clock divider: %d\n", div_id); + return -EINVAL; +@@ -641,7 +652,7 @@ + }; + + #define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ +- SNDRV_PCM_FMTBIT_S24_LE) ++ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) + + #define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ +@@ -674,7 +685,7 @@ + .suspend = wm8804_suspend, + .resume = wm8804_resume, + .set_bias_level = wm8804_set_bias_level, +- .idle_bias_off = true, ++ .idle_bias_off = false, + + .controls = wm8804_snd_controls, + .num_controls = ARRAY_SIZE(wm8804_snd_controls), +diff -Nur linux-3.10.33/sound/soc/codecs/wm8804.h linux-raspberry-pi/sound/soc/codecs/wm8804.h +--- linux-3.10.33/sound/soc/codecs/wm8804.h 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/codecs/wm8804.h 2014-03-13 12:46:44.660108313 +0100 +@@ -57,5 +57,9 @@ + #define WM8804_CLKOUT_SRC_OSCCLK 4 + + #define WM8804_CLKOUT_DIV 1 ++#define WM8804_MCLK_DIV 2 ++ ++#define WM8804_MCLKDIV_256FS 0 ++#define WM8804_MCLKDIV_128FS 1 + + #endif /* _WM8804_H */ +diff -Nur linux-3.10.33/sound/soc/Kconfig linux-raspberry-pi/sound/soc/Kconfig +--- linux-3.10.33/sound/soc/Kconfig 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/Kconfig 2014-03-13 12:46:44.420107831 +0100 +@@ -36,6 +36,7 @@ + # All the supported SoCs + source "sound/soc/atmel/Kconfig" + source "sound/soc/au1x/Kconfig" ++source "sound/soc/bcm/Kconfig" + source "sound/soc/blackfin/Kconfig" + source "sound/soc/cirrus/Kconfig" + source "sound/soc/davinci/Kconfig" +diff -Nur linux-3.10.33/sound/soc/Makefile linux-raspberry-pi/sound/soc/Makefile +--- linux-3.10.33/sound/soc/Makefile 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/Makefile 2014-03-13 12:46:44.420107831 +0100 +@@ -14,6 +14,7 @@ + obj-$(CONFIG_SND_SOC) += generic/ + obj-$(CONFIG_SND_SOC) += atmel/ + obj-$(CONFIG_SND_SOC) += au1x/ ++obj-$(CONFIG_SND_SOC) += bcm/ + obj-$(CONFIG_SND_SOC) += blackfin/ + obj-$(CONFIG_SND_SOC) += cirrus/ + obj-$(CONFIG_SND_SOC) += davinci/ +diff -Nur linux-3.10.33/sound/soc/soc-core.c linux-raspberry-pi/sound/soc/soc-core.c +--- linux-3.10.33/sound/soc/soc-core.c 2014-03-07 06:58:45.000000000 +0100 ++++ linux-raspberry-pi/sound/soc/soc-core.c 2014-03-13 12:46:44.888108771 +0100 +@@ -3463,6 +3463,22 @@ + EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll); + + /** ++ * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. ++ * @dai: DAI ++ * @ratio Ratio of BCLK to Sample rate. ++ * ++ * Configures the DAI for a preset BCLK to sample rate ratio. ++ */ ++int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) ++{ ++ if (dai->driver && dai->driver->ops->set_bclk_ratio) ++ return dai->driver->ops->set_bclk_ratio(dai, ratio); ++ else ++ return -EINVAL; ++} ++EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); ++ ++/** + * snd_soc_dai_set_fmt - configure DAI hardware audio format. + * @dai: DAI + * @fmt: SND_SOC_DAIFMT_ format value. diff --git a/target/linux/config/Config.in.audio b/target/linux/config/Config.in.audio index 8a4198aee..e924902e3 100644 --- a/target/linux/config/Config.in.audio +++ b/target/linux/config/Config.in.audio @@ -146,6 +146,8 @@ config ADK_KPACKAGE_KMOD_SND_BCM2708_SOC_I2S config ADK_KPACKAGE_KMOD_SND_BCM2708_SOC_HIFIBERRY_DAC prompt "kmod-snd-bcm2708-hifiberry-dac.... ALSA for Raspberry PI with hifiberry DAC" tristate + select ADK_KPACKAGE_KMOD_DMA_BCM2708 + select ADK_KPACKAGE_KMOD_REGMAP_MMIO select ADK_KPACKAGE_KMOD_SND_BCM2708_SOC_I2S depends on ADK_TARGET_SYSTEM_RASPBERRY_PI default n @@ -153,6 +155,8 @@ config ADK_KPACKAGE_KMOD_SND_BCM2708_SOC_HIFIBERRY_DAC config ADK_KPACKAGE_KMOD_SND_BCM2708_SOC_HIFIBERRY_DIGI prompt "kmod-snd-bcm2708-hifiberry-digi... ALSA for Raspberry PI with hifiberry DIGI" tristate + select ADK_KPACKAGE_KMOD_DMA_BCM2708 + select ADK_KPACKAGE_KMOD_REGMAP_MMIO select ADK_KPACKAGE_KMOD_SND_BCM2708_SOC_I2S depends on ADK_TARGET_SYSTEM_RASPBERRY_PI default n diff --git a/target/linux/config/Config.in.misc b/target/linux/config/Config.in.misc index 64eb8d38b..4302b6313 100644 --- a/target/linux/config/Config.in.misc +++ b/target/linux/config/Config.in.misc @@ -1,3 +1,17 @@ +config ADK_KERNEL_DMADEVICES + boolean + +config ADK_KPACKAGE_KMOD_DMA_BCM2708 + select ADK_KERNEL_DMADEVICES + boolean + +config ADK_KERNEL_REGMAP + boolean + +config ADK_KPACKAGE_KMOD_REGMAP_MMIO + select ADK_KERNEL_REGMAP + boolean + config ADK_KERNEL_KEYS boolean diff --git a/target/linux/patches/3.10.30/bsd-compatibility.patch b/target/linux/patches/3.10.30/bsd-compatibility.patch deleted file mode 100644 index b954b658f..000000000 --- a/target/linux/patches/3.10.30/bsd-compatibility.patch +++ /dev/null @@ -1,2538 +0,0 @@ -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 deleted file mode 100644 index beaa71b4e..000000000 --- a/target/linux/patches/3.10.30/solidrun-cubox-i.patch +++ /dev/null @@ -1,584365 +0,0 @@ -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