From cc0c042aafec40d93b06be3b6d7e94f38c5ac69f Mon Sep 17 00:00:00 2001 From: Waldemar Brodkorb Date: Mon, 25 May 2015 10:58:22 -0500 Subject: update kernel to 3.14.43 --- .../solidrun-imx6/patches/3.14.43/solidrun.patch | 324878 ++++++++++++++++++ 1 file changed, 324878 insertions(+) create mode 100644 target/arm/solidrun-imx6/patches/3.14.43/solidrun.patch (limited to 'target/arm/solidrun-imx6/patches/3.14.43/solidrun.patch') diff --git a/target/arm/solidrun-imx6/patches/3.14.43/solidrun.patch b/target/arm/solidrun-imx6/patches/3.14.43/solidrun.patch new file mode 100644 index 000000000..871a870e1 --- /dev/null +++ b/target/arm/solidrun-imx6/patches/3.14.43/solidrun.patch @@ -0,0 +1,324878 @@ +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/clcd-panels.dtsi linux-3.14.40/arch/arm/boot/dts/clcd-panels.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/clcd-panels.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/clcd-panels.dtsi 2015-05-01 14:57:57.319427001 -0500 +@@ -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.14.40.orig/arch/arm/boot/dts/efm32gg-dk3750.dts linux-3.14.40/arch/arm/boot/dts/efm32gg-dk3750.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/efm32gg-dk3750.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/efm32gg-dk3750.dts 2015-05-01 14:57:57.335427001 -0500 +@@ -26,7 +26,7 @@ + }; + + i2c@4000a000 { +- location = <3>; ++ efm32,location = <3>; + status = "ok"; + + temp@48 { +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx23.dtsi linux-3.14.40/arch/arm/boot/dts/imx23.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx23.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx23.dtsi 2015-05-01 14:57:57.351427001 -0500 +@@ -363,7 +363,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.14.40.orig/arch/arm/boot/dts/imx25.dtsi linux-3.14.40/arch/arm/boot/dts/imx25.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx25.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx25.dtsi 2015-05-01 14:57:57.359427001 -0500 +@@ -13,6 +13,7 @@ + + / { + aliases { ++ ethernet0 = &fec; + gpio0 = &gpio1; + gpio1 = &gpio2; + gpio2 = &gpio3; +@@ -56,6 +57,7 @@ + + osc { + compatible = "fsl,imx-osc", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <24000000>; + }; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx25-karo-tx25.dts linux-3.14.40/arch/arm/boot/dts/imx25-karo-tx25.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx25-karo-tx25.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx25-karo-tx25.dts 2015-05-01 14:57:57.363427001 -0500 +@@ -16,6 +16,10 @@ + model = "Ka-Ro TX25"; + compatible = "karo,imx25-tx25", "fsl,imx25"; + ++ chosen { ++ stdout-path = &uart1; ++ }; ++ + memory { + reg = <0x80000000 0x02000000 0x90000000 0x02000000>; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx27-apf27.dts linux-3.14.40/arch/arm/boot/dts/imx27-apf27.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx27-apf27.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx27-apf27.dts 2015-05-01 14:57:57.379427001 -0500 +@@ -29,6 +29,7 @@ + + osc26m { + compatible = "fsl,imx-osc26m", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <0>; + }; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx27.dtsi linux-3.14.40/arch/arm/boot/dts/imx27.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx27.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx27.dtsi 2015-05-01 14:57:57.379427001 -0500 +@@ -13,6 +13,7 @@ + + / { + aliases { ++ ethernet0 = &fec; + gpio0 = &gpio1; + gpio1 = &gpio2; + gpio2 = &gpio3; +@@ -46,6 +47,7 @@ + + osc26m { + compatible = "fsl,imx-osc26m", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <26000000>; + }; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts linux-3.14.40/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx27-phytec-phycard-s-rdk.dts 2015-05-01 14:57:57.411427001 -0500 +@@ -15,6 +15,10 @@ + model = "Phytec pca100 rapid development kit"; + compatible = "phytec,imx27-pca100-rdk", "phytec,imx27-pca100", "fsl,imx27"; + ++ chosen { ++ stdout-path = &uart1; ++ }; ++ + display: display { + model = "Primeview-PD050VL1"; + native-mode = <&timing0>; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx28.dtsi linux-3.14.40/arch/arm/boot/dts/imx28.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx28.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx28.dtsi 2015-05-01 14:57:57.411427001 -0500 +@@ -840,7 +840,8 @@ + compatible = "fsl,imx28-lcdif"; + reg = <0x80030000 0x2000>; + interrupts = <38>; +- 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.14.40.orig/arch/arm/boot/dts/imx51-babbage.dts linux-3.14.40/arch/arm/boot/dts/imx51-babbage.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx51-babbage.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx51-babbage.dts 2015-05-01 14:57:57.415427001 -0500 +@@ -17,6 +17,10 @@ + model = "Freescale i.MX51 Babbage Board"; + compatible = "fsl,imx51-babbage", "fsl,imx51"; + ++ chosen { ++ stdout-path = &uart1; ++ }; ++ + memory { + reg = <0x90000000 0x20000000>; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx51.dtsi linux-3.14.40/arch/arm/boot/dts/imx51.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx51.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx51.dtsi 2015-05-01 14:57:57.419427001 -0500 +@@ -15,6 +15,7 @@ + + / { + aliases { ++ ethernet0 = &fec; + gpio0 = &gpio1; + gpio1 = &gpio2; + gpio2 = &gpio3; +@@ -43,21 +44,25 @@ + + ckil { + compatible = "fsl,imx-ckil", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <32768>; + }; + + ckih1 { + compatible = "fsl,imx-ckih1", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <0>; + }; + + ckih2 { + compatible = "fsl,imx-ckih2", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <0>; + }; + + osc { + compatible = "fsl,imx-osc", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <24000000>; + }; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx53.dtsi linux-3.14.40/arch/arm/boot/dts/imx53.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx53.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx53.dtsi 2015-05-01 14:57:57.427427001 -0500 +@@ -15,6 +15,7 @@ + + / { + aliases { ++ ethernet0 = &fec; + gpio0 = &gpio1; + gpio1 = &gpio2; + gpio2 = &gpio3; +@@ -59,21 +60,25 @@ + + ckil { + compatible = "fsl,imx-ckil", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <32768>; + }; + + ckih1 { + compatible = "fsl,imx-ckih1", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <22579200>; + }; + + ckih2 { + compatible = "fsl,imx-ckih2", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <0>; + }; + + osc { + compatible = "fsl,imx-osc", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <24000000>; + }; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx53-mba53.dts linux-3.14.40/arch/arm/boot/dts/imx53-mba53.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx53-mba53.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx53-mba53.dts 2015-05-01 14:57:57.431427001 -0500 +@@ -25,6 +25,10 @@ + enable-active-low; + }; + ++ chosen { ++ stdout-path = &uart2; ++ }; ++ + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm2 0 50000>; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-dfi-fs700-m60.dts 2015-05-01 14:57:57.431427001 -0500 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright 2013 Sascha Hauer ++ * ++ * 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 ++ */ ++ ++#ifndef __DTS_V1__ ++#define __DTS_V1__ ++/dts-v1/; ++#endif ++ ++#include "imx6dl.dtsi" ++#include "imx6qdl-dfi-fs700-m60.dtsi" ++ ++/ { ++ model = "DFI FS700-M60-6DL i.MX6dl Q7 Board"; ++ compatible = "dfi,fs700-m60-6dl", "dfi,fs700e-m60", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl.dtsi linux-3.14.40/arch/arm/boot/dts/imx6dl.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl.dtsi 2015-05-01 14:57:57.431427001 -0500 +@@ -8,6 +8,7 @@ + * + */ + ++#include + #include "imx6dl-pinfunc.h" + #include "imx6qdl.dtsi" + +@@ -21,6 +22,26 @@ + 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 { +@@ -32,40 +53,124 @@ + }; + + 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>, <&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@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 23 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>; ++ interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks 133>; ++ clock-names = "pxp-axi"; ++ status = "disabled"; + }; + + epdc: epdc@020f4000 { + reg = <0x020f4000 0x4000>; +- interrupts = <0 97 0x04>; ++ interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>; + }; + + lcdif: lcdif@020f8000 { + reg = <0x020f8000 0x4000>; +- interrupts = <0 39 0x04>; ++ interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + 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 209>; ++ clock-names = "mipi_pllref_clk", "mipi_cfg_clk"; ++ status = "disabled"; ++ }; ++ + i2c4: i2c@021f8000 { + #address-cells = <1>; + #size-cells = <0>; +- compatible = "fsl,imx1-i2c"; ++ compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; + reg = <0x021f8000 0x4000>; +- interrupts = <0 35 0x04>; ++ interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks 116>; + status = "disabled"; + }; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-gw51xx.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-gw51xx.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-gw51xx.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-gw51xx.dts 2015-05-01 14:57:57.431427001 -0500 +@@ -0,0 +1,19 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6dl.dtsi" ++#include "imx6qdl-gw51xx.dtsi" ++ ++/ { ++ model = "Gateworks Ventana i.MX6 DualLite GW51XX"; ++ compatible = "gw,imx6dl-gw51xx", "gw,ventana", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-gw52xx.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-gw52xx.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-gw52xx.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-gw52xx.dts 2015-05-01 14:57:57.431427001 -0500 +@@ -0,0 +1,19 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6dl.dtsi" ++#include "imx6qdl-gw52xx.dtsi" ++ ++/ { ++ model = "Gateworks Ventana i.MX6 DualLite GW52XX"; ++ compatible = "gw,imx6dl-gw52xx", "gw,ventana", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-gw53xx.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-gw53xx.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-gw53xx.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-gw53xx.dts 2015-05-01 14:57:57.431427001 -0500 +@@ -0,0 +1,19 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6dl.dtsi" ++#include "imx6qdl-gw53xx.dtsi" ++ ++/ { ++ model = "Gateworks Ventana i.MX6 DualLite GW53XX"; ++ compatible = "gw,imx6dl-gw53xx", "gw,ventana", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-gw54xx.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-gw54xx.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-gw54xx.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-gw54xx.dts 2015-05-01 14:57:57.431427001 -0500 +@@ -0,0 +1,19 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6dl.dtsi" ++#include "imx6qdl-gw54xx.dtsi" ++ ++/ { ++ model = "Gateworks Ventana i.MX6 DualLite GW54XX"; ++ compatible = "gw,imx6dl-gw54xx", "gw,ventana", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-hummingboard.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-hummingboard.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-hummingboard.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-hummingboard.dts 2015-05-01 14:57:57.435427001 -0500 +@@ -1,163 +1,13 @@ + /* +- * Copyright (C) 2013,2014 Russell King ++ * Copyright (C) 2014 Rabeeh Khoury (rabeeh@solid-run.com) ++ * Based on work by Russell King + */ + /dts-v1/; + + #include "imx6dl.dtsi" +-#include "imx6qdl-microsom.dtsi" +-#include "imx6qdl-microsom-ar8035.dtsi" ++#include "imx6qdl-hummingboard.dtsi" + + / { +- model = "SolidRun HummingBoard DL/Solo"; +- compatible = "solidrun,hummingboard", "fsl,imx6dl"; +- +- 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>; +- }; +- }; +- +- sound-spdif { +- compatible = "fsl,imx-audio-spdif"; +- model = "imx-spdif"; +- /* IMX6 doesn't implement this yet */ +- spdif-controller = <&spdif>; +- spdif-out; +- }; +-}; +- +-&can1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_hummingboard_flexcan1>; +- status = "okay"; +-}; +- +-&i2c1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_hummingboard_i2c1>; +- +- /* +- * Not fitted on Carrier-1 board... yet +- status = "okay"; +- +- rtc: pcf8523@68 { +- compatible = "nxp,pcf8523"; +- reg = <0x68>; +- }; +- */ +-}; +- +-&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_i2c1: hummingboard-i2c1 { +- fsl,pins = < +- MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 +- MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 +- >; +- }; +- +- 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 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_hummingboard_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"; ++ model = "SolidRun HummingBoard Solo/DualLite"; ++ compatible = "solidrun,hummingboard/dl", "fsl,imx6dl"; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-nitrogen6x.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-nitrogen6x.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-nitrogen6x.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-nitrogen6x.dts 2015-05-01 14:57:57.439427001 -0500 +@@ -0,0 +1,21 @@ ++/* ++ * Copyright 2013 Boundary Devices, Inc. ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6dl.dtsi" ++#include "imx6qdl-nitrogen6x.dtsi" ++ ++/ { ++ model = "Freescale i.MX6 DualLite Nitrogen6x Board"; ++ compatible = "fsl,imx6dl-nitrogen6x", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-phytec-pbab01.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-phytec-pbab01.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-phytec-pbab01.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-phytec-pbab01.dts 2015-05-01 14:57:57.439427001 -0500 +@@ -0,0 +1,19 @@ ++/* ++ * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6dl-phytec-pfla02.dtsi" ++#include "imx6qdl-phytec-pbab01.dtsi" ++ ++/ { ++ model = "Phytec phyFLEX-i.MX6 DualLite/Solo Carrier-Board"; ++ compatible = "phytec,imx6dl-pbab01", "phytec,imx6dl-pfla02", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi linux-3.14.40/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-phytec-pfla02.dtsi 2015-05-01 14:57:57.439427001 -0500 +@@ -0,0 +1,22 @@ ++/* ++ * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH ++ * ++ * 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 "imx6dl.dtsi" ++#include "imx6qdl-phytec-pfla02.dtsi" ++ ++/ { ++ model = "Phytec phyFLEX-i.MX6 DualLite/Solo"; ++ compatible = "phytec,imx6dl-pfla02", "fsl,imx6dl"; ++ ++ memory { ++ reg = <0x10000000 0x20000000>; ++ }; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-pinfunc.h linux-3.14.40/arch/arm/boot/dts/imx6dl-pinfunc.h +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-pinfunc.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-pinfunc.h 2015-05-01 14:57:57.439427001 -0500 +@@ -755,6 +755,7 @@ + #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__ENET_IRQ 0x234 0x604 0x03c 0x11 0xff000609 + #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 +@@ -950,6 +951,7 @@ + #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__OSC32K_32K_OUT 0x2dc 0x6c4 0x000 0x2 0x0 + #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 +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-sabreauto.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-sabreauto.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-sabreauto.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-sabreauto.dts 2015-05-01 14:57:57.443427001 -0500 +@@ -15,3 +15,16 @@ + model = "Freescale i.MX6 DualLite/Solo SABRE Automotive Board"; + compatible = "fsl,imx6dl-sabreauto", "fsl,imx6dl"; + }; ++ ++&ldb { ++ ipu_id = <0>; ++ sec_ipu_id = <0>; ++}; ++ ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-sabrelite.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-sabrelite.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-sabrelite.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-sabrelite.dts 2015-05-01 14:57:57.443427001 -0500 +@@ -0,0 +1,20 @@ ++/* ++ * Copyright 2011 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 ++ */ ++ ++/dts-v1/; ++#include "imx6dl.dtsi" ++#include "imx6qdl-sabrelite.dtsi" ++ ++/ { ++ model = "Freescale i.MX6 DualLite SABRE Lite Board"; ++ compatible = "fsl,imx6dl-sabrelite", "fsl,imx6dl"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-sabresd.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-sabresd.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-sabresd.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-sabresd.dts 2015-05-01 14:57:57.443427001 -0500 +@@ -15,3 +15,20 @@ + model = "Freescale i.MX6 DualLite SABRE Smart Device Board"; + compatible = "fsl,imx6dl-sabresd", "fsl,imx6dl"; + }; ++ ++&ldb { ++ ipu_id = <0>; ++ sec_ipu_id = <0>; ++}; ++ ++&pxp { ++ status = "okay"; ++}; ++ ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts linux-3.14.40/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6dl-sabresd-hdcp.dts 2015-05-01 14:57:57.443427001 -0500 +@@ -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>; ++ fsl,hdcp; ++}; ++ ++&i2c2 { ++ status = "disable"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-arm2.dts linux-3.14.40/arch/arm/boot/dts/imx6q-arm2.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-arm2.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-arm2.dts 2015-05-01 14:57:57.443427001 -0500 +@@ -23,14 +23,27 @@ + + regulators { + compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; + +- reg_3p3v: 3p3v { ++ reg_3p3v: regulator@0 { + compatible = "regulator-fixed"; ++ reg = <0>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; ++ ++ reg_usb_otg_vbus: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio3 22 0>; ++ enable-active-high; ++ }; + }; + + leds { +@@ -46,7 +59,7 @@ + + &gpmi { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_gpmi_nand_1>; ++ pinctrl-0 = <&pinctrl_gpmi_nand>; + status = "disabled"; /* gpmi nand conflicts with SD */ + }; + +@@ -54,28 +67,131 @@ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + +- hog { ++ imx6q-arm2 { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_EIM_D25__GPIO3_IO25 0x80000000 + >; + }; +- }; + +- arm2 { +- pinctrl_usdhc3_arm2: usdhc3grp-arm2 { ++ pinctrl_enet: enetgrp { ++ 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_6__ENET_IRQ 0x000b1 ++ >; ++ }; ++ ++ pinctrl_gpmi_nand: gpminandgrp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_uart2: uart2grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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_cdwp: usdhc3cdwp { + fsl,pins = < + MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x80000000 + MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x80000000 + >; + }; ++ ++ pinctrl_usdhc4: usdhc4grp { ++ 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 ++ >; ++ }; + }; + }; + + &fec { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_2>; ++ pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; ++ interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; + status = "okay"; + }; + +@@ -84,8 +200,8 @@ + wp-gpios = <&gpio6 14 0>; + vmmc-supply = <®_3p3v>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc3_1 +- &pinctrl_usdhc3_arm2>; ++ pinctrl-0 = <&pinctrl_usdhc3 ++ &pinctrl_usdhc3_cdwp>; + status = "okay"; + }; + +@@ -93,13 +209,13 @@ + non-removable; + vmmc-supply = <®_3p3v>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc4_1>; ++ pinctrl-0 = <&pinctrl_usdhc4>; + status = "okay"; + }; + + &uart2 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart2_2>; ++ pinctrl-0 = <&pinctrl_uart2>; + fsl,dte-mode; + fsl,uart-has-rtscts; + status = "okay"; +@@ -107,6 +223,6 @@ + + &uart4 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart4_1>; ++ pinctrl-0 = <&pinctrl_uart4>; + status = "okay"; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-arm2-hsic.dts linux-3.14.40/arch/arm/boot/dts/imx6q-arm2-hsic.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-arm2-hsic.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-arm2-hsic.dts 2015-05-01 14:57:57.443427001 -0500 +@@ -0,0 +1,32 @@ ++/* ++ * Copyright 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 "imx6q-arm2.dts" ++ ++&fec { ++ status = "disabled"; ++}; ++ ++&usbh2 { ++ pinctrl-names = "idle", "active"; ++ pinctrl-0 = <&pinctrl_usbh2_1>; ++ pinctrl-1 = <&pinctrl_usbh2_2>; ++ osc-clkgate-delay = <0x3>; ++ status = "okay"; ++}; ++ ++&usbh3 { ++ pinctrl-names = "idle", "active"; ++ pinctrl-0 = <&pinctrl_usbh3_1>; ++ pinctrl-1 = <&pinctrl_usbh3_2>; ++ osc-clkgate-delay = <0x3>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-cm-fx6.dts linux-3.14.40/arch/arm/boot/dts/imx6q-cm-fx6.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-cm-fx6.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-cm-fx6.dts 2015-05-01 14:57:57.443427001 -0500 +@@ -0,0 +1,107 @@ ++/* ++ * Copyright 2013 CompuLab Ltd. ++ * ++ * Author: Valentin Raevsky ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6q.dtsi" ++ ++/ { ++ model = "CompuLab CM-FX6"; ++ compatible = "compulab,cm-fx6", "fsl,imx6q"; ++ ++ memory { ++ reg = <0x10000000 0x80000000>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ heartbeat-led { ++ label = "Heartbeat"; ++ gpios = <&gpio2 31 0>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ }; ++}; ++ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ status = "okay"; ++}; ++ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand>; ++ status = "okay"; ++}; ++ ++&iomuxc { ++ imx6q-cm-fx6 { ++ pinctrl_enet: enetgrp { ++ fsl,pins = < ++ 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_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_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_gpmi_nand: gpminandgrp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 ++ >; ++ }; ++ }; ++}; ++ ++&uart4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart4>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-cubox-i.dts linux-3.14.40/arch/arm/boot/dts/imx6q-cubox-i.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-cubox-i.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-cubox-i.dts 2015-05-01 14:57:57.443427001 -0500 +@@ -13,4 +13,8 @@ + + &sata { + status = "okay"; ++ fsl,transmit-level-mV = <1104>; ++ fsl,transmit-boost-mdB = <0>; ++ fsl,transmit-atten-16ths = <9>; ++ fsl,no-spread-spectrum; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts linux-3.14.40/arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-dfi-fs700-m60.dts 2015-05-01 14:57:57.443427001 -0500 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright 2013 Sascha Hauer ++ * ++ * 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 ++ */ ++ ++#ifndef __DTS_V1__ ++#define __DTS_V1__ ++/dts-v1/; ++#endif ++ ++#include "imx6q.dtsi" ++#include "imx6qdl-dfi-fs700-m60.dtsi" ++ ++/ { ++ model = "DFI FS700-M60-6QD i.MX6qd Q7 Board"; ++ compatible = "dfi,fs700-m60-6qd", "dfi,fs700e-m60", "fsl,imx6q"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi 2015-05-01 14:57:57.443427001 -0500 +@@ -5,11 +5,33 @@ + #include "imx6qdl-microsom-ar8035.dtsi" + + / { ++ chosen { ++ bootargs = "quiet console=ttymxc0,115200 root=/dev/mmcblk0p2 rw"; ++ }; ++ ++ aliases { ++ mxcfb0 = &mxcfb1; ++ }; ++ + ir_recv: ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio3 9 1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_ir>; ++ linux,rc-map-name = "rc-rc6-mce"; ++ }; ++ ++ pwmleds { ++ compatible = "pwm-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_pwm1>; ++ ++ front { ++ active-low; ++ label = "imx6:red:front"; ++ max-brightness = <248>; ++ pwms = <&pwm1 0 50000>; ++ }; + }; + + regulators { +@@ -49,10 +71,62 @@ + 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: fb@0 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "hdmi"; ++ interface_pix_fmt = "RGB24"; ++ mode_str ="1920x1080M@60"; ++ default_bpp = <32>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "okay"; ++ }; ++}; ++ ++&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_cubox_i_hdmi>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_i2c2>; ++ ++ status = "okay"; ++ ++ ddc: imx6_hdmi_i2c@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; + }; + + &i2c3 { +@@ -69,6 +143,19 @@ + + &iomuxc { + cubox_i { ++ pinctrl_cubox_i_hdmi: cubox-i-hdmi { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ ++ pinctrl_cubox_i_i2c2: cubox-i-i2c2 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ + pinctrl_cubox_i_i2c3: cubox-i-i2c3 { + fsl,pins = < + MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 +@@ -82,16 +169,35 @@ + >; + }; + ++ pinctrl_cubox_i_pwm1: cubox-i-pwm1-front-led { ++ fsl,pins = ; ++ }; ++ + pinctrl_cubox_i_spdif: cubox-i-spdif { + fsl,pins = ; + }; + ++ pinctrl_cubox_i_usbh1: cubox-i-usbh1 { ++ fsl,pins = ; ++ }; ++ + pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus { +- fsl,pins = ; ++ fsl,pins = ; ++ }; ++ ++ pinctrl_cubox_i_usbotg: cubox-i-usbotg { ++ /* ++ * The Cubox-i pulls ID low, but as it's pointless ++ * leaving it as a pull-up, even if it is just 10uA. ++ */ ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059 ++ MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 ++ >; + }; + + pinctrl_cubox_i_usbotg_vbus: cubox-i-usbotg-vbus { +- fsl,pins = ; ++ fsl,pins = ; + }; + + pinctrl_cubox_i_usdhc2_aux: cubox-i-usdhc2-aux { +@@ -111,29 +217,76 @@ + 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 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cubox_i_spdif>; ++ clocks = <&clks 197>, <&clks 0>, ++ <&clks 197>, <&clks 0>, ++ <&clks 0>, <&clks 0>, ++ <&clks 0>, <&clks 0>, ++ <&clks 0>; ++ clock-names = "core", "rxtx0", ++ "rxtx1", "rxtx2", ++ "rxtx3", "rxtx4", ++ "rxtx5", "rxtx6", ++ "rxtx7"; + status = "okay"; + }; + + &usbh1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_usbh1>; + vbus-supply = <®_usbh1_vbus>; + status = "okay"; + }; + + &usbotg { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_cubox_i_usbotg>; + vbus-supply = <®_usbotg_vbus>; + status = "okay"; + }; + + &usdhc2 { +- pinctrl-names = "default"; ++ 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"; + }; ++ ++ ++&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.14.40.orig/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi 2015-05-01 14:57:57.443427001 -0500 +@@ -0,0 +1,199 @@ ++/ { ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ dummy_reg: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "dummy-supply"; ++ }; ++ ++ reg_usb_otg_vbus: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio3 22 0>; ++ enable-active-high; ++ }; ++ }; ++ ++ chosen { ++ stdout-path = &uart1; ++ }; ++}; ++ ++&ecspi3 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio4 24 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi3>; ++ status = "okay"; ++ ++ flash: m25p80@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "sst,sst25vf040b", "m25p80"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ status = "okay"; ++ phy-mode = "rgmii"; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6qdl-dfi-fs700-m60 { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x80000000 ++ MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x80000000 /* PMIC irq */ ++ MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x80000000 /* MAX11801 irq */ ++ MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x000030b0 /* Backlight enable */ ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ fsl,pins = < ++ 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_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_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc2: usdhc2grp { ++ 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_D2__GPIO2_IO02 0x80000000 /* card detect */ ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_usdhc4: usdhc4grp { ++ 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_ecspi3: ecspi3grp { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 ++ MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 ++ MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 ++ MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */ ++ >; ++ }; ++ }; ++}; ++ ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ dr_mode = "host"; ++ status = "okay"; ++}; ++ ++&usdhc2 { /* module slot */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc2>; ++ cd-gpios = <&gpio2 2 0>; ++ status = "okay"; ++}; ++ ++&usdhc3 { /* baseboard slot */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++}; ++ ++&usdhc4 { /* eMMC */ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4>; ++ bus-width = <8>; ++ non-removable; ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl.dtsi 2015-05-01 14:57:57.447427001 -0500 +@@ -10,10 +10,16 @@ + * http://www.gnu.org/copyleft/gpl.html + */ + ++#include ++ + #include "skeleton.dtsi" ++#include + + / { + aliases { ++ ethernet0 = &fec; ++ can0 = &can1; ++ can1 = &can2; + gpio0 = &gpio1; + gpio1 = &gpio2; + gpio2 = &gpio3; +@@ -24,6 +30,11 @@ + i2c0 = &i2c1; + i2c1 = &i2c2; + i2c2 = &i2c3; ++ ipu0 = &ipu1; ++ mmc0 = &usdhc1; ++ mmc1 = &usdhc2; ++ mmc2 = &usdhc3; ++ mmc3 = &usdhc4; + serial0 = &uart1; + serial1 = &uart2; + serial2 = &uart3; +@@ -33,13 +44,13 @@ + spi1 = &ecspi2; + spi2 = &ecspi3; + spi3 = &ecspi4; ++ usbphy0 = &usbphy1; ++ usbphy1 = &usbphy2; + }; + + 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>; +@@ -51,20 +62,27 @@ + + ckil { + compatible = "fsl,imx-ckil", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <32768>; + }; + + ckih1 { + compatible = "fsl,imx-ckih1", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <0>; + }; + + osc { + compatible = "fsl,imx-osc", "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <24000000>; + }; + }; + ++ pu_dummy: pudummy_reg { ++ compatible = "fsl,imx6-dummy-pureg"; /* only used in ldo-bypass */ ++ }; ++ + soc { + #address-cells = <1>; + #size-cells = <1>; +@@ -75,7 +93,10 @@ + dma_apbh: dma-apbh@00110000 { + compatible = "fsl,imx6q-dma-apbh", "fsl,imx28-dma-apbh"; + reg = <0x00110000 0x2000>; +- interrupts = <0 13 0x04>, <0 13 0x04>, <0 13 0x04>, <0 13 0x04>; ++ interrupts = <0 13 IRQ_TYPE_LEVEL_HIGH>, ++ <0 13 IRQ_TYPE_LEVEL_HIGH>, ++ <0 13 IRQ_TYPE_LEVEL_HIGH>, ++ <0 13 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "gpmi0", "gpmi1", "gpmi2", "gpmi3"; + #dma-cells = <1>; + dma-channels = <4>; +@@ -88,7 +109,7 @@ + #size-cells = <1>; + reg = <0x00112000 0x2000>, <0x00114000 0x2000>; + reg-names = "gpmi-nand", "bch"; +- interrupts = <0 15 0x04>; ++ interrupts = <0 15 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "bch"; + clocks = <&clks 152>, <&clks 153>, <&clks 151>, + <&clks 150>, <&clks 149>; +@@ -109,11 +130,13 @@ + L2: l2-cache@00a02000 { + compatible = "arm,pl310-cache"; + reg = <0x00a02000 0x1000>; +- interrupts = <0 92 0x04>; ++ interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>; + cache-unified; + cache-level = <2>; + arm,tag-latency = <4 2 3>; + arm,data-latency = <4 2 3>; ++ arm,dynamic-clk-gating; ++ arm,standby-mode; + }; + + pcie: pcie@0x01000000 { +@@ -126,15 +149,22 @@ + 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 206>, <&clks 144>; +- clock-names = "pcie_ref_125m", "sata_ref_100m", "lvds_gate", "pcie_axi"; ++ interrupts = ; ++ interrupt-names = "pme"; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 0x7>; ++ interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>, ++ <0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks 144>, <&clks 221>, <&clks 189>, <&clks 187>; ++ clock-names = "pcie_axi", "lvds_gate", "pcie_ref_125m", "sata_ref_100m"; + status = "disabled"; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; +- interrupts = <0 94 0x04>; ++ interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>; + }; + + aips-bus@02000000 { /* AIPS1 */ +@@ -154,7 +184,7 @@ + spdif: spdif@02004000 { + compatible = "fsl,imx35-spdif"; + reg = <0x02004000 0x4000>; +- interrupts = <0 52 0x04>; ++ interrupts = <0 52 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&sdma 14 18 0>, + <&sdma 15 18 0>; + dma-names = "rx", "tx"; +@@ -176,9 +206,11 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02008000 0x4000>; +- interrupts = <0 31 0x04>; ++ interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 112>, <&clks 112>; + clock-names = "ipg", "per"; ++ dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -187,9 +219,11 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x0200c000 0x4000>; +- interrupts = <0 32 0x04>; ++ interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 113>, <&clks 113>; + clock-names = "ipg", "per"; ++ dmas = <&sdma 5 7 1>, <&sdma 6 7 2>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -198,9 +232,11 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02010000 0x4000>; +- interrupts = <0 33 0x04>; ++ interrupts = <0 33 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 114>, <&clks 114>; + clock-names = "ipg", "per"; ++ dmas = <&sdma 7 7 1>, <&sdma 8 7 2>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + +@@ -209,16 +245,18 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02014000 0x4000>; +- interrupts = <0 34 0x04>; ++ interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 115>, <&clks 115>; + clock-names = "ipg", "per"; ++ dmas = <&sdma 9 7 1>, <&sdma 10 7 2>; ++ dma-names = "rx", "tx"; + status = "disabled"; + }; + + uart1: serial@02020000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02020000 0x4000>; +- interrupts = <0 26 0x04>; ++ interrupts = <0 26 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; + dmas = <&sdma 25 4 0>, <&sdma 26 4 0>; +@@ -227,15 +265,23 @@ + }; + + esai: esai@02024000 { ++ compatible = "fsl,imx6q-esai"; + reg = <0x02024000 0x4000>; +- interrupts = <0 51 0x04>; ++ interrupts = <0 51 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks 118>; ++ fsl,esai-dma-events = <24 23>; ++ fsl,flags = <1>; ++ status = "disabled"; + }; + + ssi1: ssi@02028000 { +- compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; ++ compatible = "fsl,imx6q-ssi", ++ "fsl,imx51-ssi", ++ "fsl,imx21-ssi"; + reg = <0x02028000 0x4000>; +- interrupts = <0 46 0x04>; +- clocks = <&clks 178>; ++ interrupts = <0 46 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks 178>, <&clks 157>; ++ clock-names = "ipg", "baud"; + dmas = <&sdma 37 1 0>, + <&sdma 38 1 0>; + dma-names = "rx", "tx"; +@@ -245,10 +291,13 @@ + }; + + ssi2: ssi@0202c000 { +- compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; ++ compatible = "fsl,imx6q-ssi", ++ "fsl,imx51-ssi", ++ "fsl,imx21-ssi"; + reg = <0x0202c000 0x4000>; +- interrupts = <0 47 0x04>; +- clocks = <&clks 179>; ++ interrupts = <0 47 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks 179>, <&clks 158>; ++ clock-names = "ipg", "baud"; + dmas = <&sdma 41 1 0>, + <&sdma 42 1 0>; + dma-names = "rx", "tx"; +@@ -258,10 +307,13 @@ + }; + + ssi3: ssi@02030000 { +- compatible = "fsl,imx6q-ssi","fsl,imx21-ssi"; ++ compatible = "fsl,imx6q-ssi", ++ "fsl,imx51-ssi", ++ "fsl,imx21-ssi"; + reg = <0x02030000 0x4000>; +- interrupts = <0 48 0x04>; +- clocks = <&clks 180>; ++ interrupts = <0 48 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks 180>, <&clks 159>; ++ clock-names = "ipg", "baud"; + dmas = <&sdma 45 1 0>, + <&sdma 46 1 0>; + dma-names = "rx", "tx"; +@@ -271,8 +323,25 @@ + }; + + asrc: asrc@02034000 { ++ compatible = "fsl,imx53-asrc"; + reg = <0x02034000 0x4000>; +- interrupts = <0 50 0x04>; ++ interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>; ++ 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 { +@@ -281,8 +350,19 @@ + }; + + vpu: vpu@02040000 { ++ compatible = "fsl,imx6-vpu"; + reg = <0x02040000 0x3c000>; +- interrupts = <0 3 0x04 0 12 0x04>; ++ reg-names = "vpu_regs"; ++ interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>, ++ <0 12 IRQ_TYPE_LEVEL_HIGH>; ++ 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 */ +@@ -293,7 +373,7 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; + reg = <0x02080000 0x4000>; +- interrupts = <0 83 0x04>; ++ interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 62>, <&clks 145>; + clock-names = "ipg", "per"; + }; +@@ -302,7 +382,7 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; + reg = <0x02084000 0x4000>; +- interrupts = <0 84 0x04>; ++ interrupts = <0 84 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 62>, <&clks 146>; + clock-names = "ipg", "per"; + }; +@@ -311,7 +391,7 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; + reg = <0x02088000 0x4000>; +- interrupts = <0 85 0x04>; ++ interrupts = <0 85 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 62>, <&clks 147>; + clock-names = "ipg", "per"; + }; +@@ -320,7 +400,7 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6q-pwm", "fsl,imx27-pwm"; + reg = <0x0208c000 0x4000>; +- interrupts = <0 86 0x04>; ++ interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 62>, <&clks 148>; + clock-names = "ipg", "per"; + }; +@@ -328,23 +408,25 @@ + can1: flexcan@02090000 { + compatible = "fsl,imx6q-flexcan"; + reg = <0x02090000 0x4000>; +- interrupts = <0 110 0x04>; ++ interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 108>, <&clks 109>; + clock-names = "ipg", "per"; ++ status = "disabled"; + }; + + can2: flexcan@02094000 { + compatible = "fsl,imx6q-flexcan"; + reg = <0x02094000 0x4000>; +- interrupts = <0 111 0x04>; ++ interrupts = <0 111 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 110>, <&clks 111>; + clock-names = "ipg", "per"; ++ status = "disabled"; + }; + + gpt: gpt@02098000 { + compatible = "fsl,imx6q-gpt", "fsl,imx31-gpt"; + reg = <0x02098000 0x4000>; +- interrupts = <0 55 0x04>; ++ interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 119>, <&clks 120>; + clock-names = "ipg", "per"; + }; +@@ -352,7 +434,8 @@ + gpio1: gpio@0209c000 { + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; + reg = <0x0209c000 0x4000>; +- interrupts = <0 66 0x04 0 67 0x04>; ++ interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>, ++ <0 67 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -362,7 +445,8 @@ + gpio2: gpio@020a0000 { + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; + reg = <0x020a0000 0x4000>; +- interrupts = <0 68 0x04 0 69 0x04>; ++ interrupts = <0 68 IRQ_TYPE_LEVEL_HIGH>, ++ <0 69 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -372,7 +456,8 @@ + gpio3: gpio@020a4000 { + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; + reg = <0x020a4000 0x4000>; +- interrupts = <0 70 0x04 0 71 0x04>; ++ interrupts = <0 70 IRQ_TYPE_LEVEL_HIGH>, ++ <0 71 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -382,7 +467,8 @@ + gpio4: gpio@020a8000 { + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; + reg = <0x020a8000 0x4000>; +- interrupts = <0 72 0x04 0 73 0x04>; ++ interrupts = <0 72 IRQ_TYPE_LEVEL_HIGH>, ++ <0 73 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -392,7 +478,8 @@ + gpio5: gpio@020ac000 { + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; + reg = <0x020ac000 0x4000>; +- interrupts = <0 74 0x04 0 75 0x04>; ++ interrupts = <0 74 IRQ_TYPE_LEVEL_HIGH>, ++ <0 75 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -402,7 +489,8 @@ + gpio6: gpio@020b0000 { + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; + reg = <0x020b0000 0x4000>; +- interrupts = <0 76 0x04 0 77 0x04>; ++ interrupts = <0 76 IRQ_TYPE_LEVEL_HIGH>, ++ <0 77 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -412,7 +500,8 @@ + gpio7: gpio@020b4000 { + compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; + reg = <0x020b4000 0x4000>; +- interrupts = <0 78 0x04 0 79 0x04>; ++ interrupts = <0 78 IRQ_TYPE_LEVEL_HIGH>, ++ <0 79 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -421,20 +510,20 @@ + + kpp: kpp@020b8000 { + reg = <0x020b8000 0x4000>; +- interrupts = <0 82 0x04>; ++ interrupts = <0 82 IRQ_TYPE_LEVEL_HIGH>; + }; + + wdog1: wdog@020bc000 { + compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt"; + reg = <0x020bc000 0x4000>; +- interrupts = <0 80 0x04>; ++ interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 0>; + }; + + wdog2: wdog@020c0000 { + compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt"; + reg = <0x020c0000 0x4000>; +- interrupts = <0 81 0x04>; ++ interrupts = <0 81 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 0>; + status = "disabled"; + }; +@@ -442,14 +531,17 @@ + clks: ccm@020c4000 { + compatible = "fsl,imx6q-ccm"; + reg = <0x020c4000 0x4000>; +- interrupts = <0 87 0x04 0 88 0x04>; ++ interrupts = <0 87 IRQ_TYPE_LEVEL_HIGH>, ++ <0 88 IRQ_TYPE_LEVEL_HIGH>; + #clock-cells = <1>; + }; + + anatop: anatop@020c8000 { + compatible = "fsl,imx6q-anatop", "syscon", "simple-bus"; + reg = <0x020c8000 0x1000>; +- interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>; ++ interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>, ++ <0 54 IRQ_TYPE_LEVEL_HIGH>, ++ <0 127 IRQ_TYPE_LEVEL_HIGH>; + + regulator-1p1@110 { + compatible = "fsl,anatop-regulator"; +@@ -495,7 +587,7 @@ + + reg_arm: regulator-vddcore@140 { + compatible = "fsl,anatop-regulator"; +- regulator-name = "cpu"; ++ regulator-name = "vddarm"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1450000>; + regulator-always-on; +@@ -515,7 +607,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>; +@@ -547,23 +638,38 @@ + + tempmon: tempmon { + compatible = "fsl,imx6q-tempmon"; +- interrupts = <0 49 0x04>; ++ interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>; + 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>; ++ interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 182>; ++ fsl,anatop = <&anatop>; + }; + + usbphy2: usbphy@020ca000 { + compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; + reg = <0x020ca000 0x1000>; +- interrupts = <0 45 0x04>; ++ interrupts = <0 45 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 183>; ++ fsl,anatop = <&anatop>; ++ }; ++ ++ usbphy_nop1: usbphy_nop1 { ++ compatible = "usb-nop-xceiv"; ++ clocks = <&clks 182>; ++ clock-names = "main_clk"; ++ }; ++ ++ usbphy_nop2: usbphy_nop2 { ++ compatible = "usb-nop-xceiv"; ++ clocks = <&clks 182>; ++ clock-names = "main_clk"; + }; + + snvs@020cc000 { +@@ -575,31 +681,39 @@ + snvs-rtc-lp@34 { + compatible = "fsl,sec-v4.0-mon-rtc-lp"; + reg = <0x34 0x58>; +- interrupts = <0 19 0x04 0 20 0x04>; ++ interrupts = <0 19 IRQ_TYPE_LEVEL_HIGH>, ++ <0 20 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + epit1: epit@020d0000 { /* EPIT1 */ + reg = <0x020d0000 0x4000>; +- interrupts = <0 56 0x04>; ++ interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; + }; + + epit2: epit@020d4000 { /* EPIT2 */ + reg = <0x020d4000 0x4000>; +- interrupts = <0 57 0x04>; ++ interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; + }; + + src: src@020d8000 { + compatible = "fsl,imx6q-src", "fsl,imx51-src"; + reg = <0x020d8000 0x4000>; +- interrupts = <0 91 0x04 0 96 0x04>; ++ interrupts = <0 91 IRQ_TYPE_LEVEL_HIGH>, ++ <0 96 IRQ_TYPE_LEVEL_HIGH>; + #reset-cells = <1>; + }; + + gpc: gpc@020dc000 { + compatible = "fsl,imx6q-gpc"; + reg = <0x020dc000 0x4000>; +- interrupts = <0 89 0x04 0 90 0x04>; ++ interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>, ++ <0 90 IRQ_TYPE_LEVEL_HIGH>; ++ 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 { +@@ -610,778 +724,40 @@ + 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 0x80000000 +- MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x80000000 +- MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x80000000 +- MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x80000000 +- >; +- }; +- +- pinctrl_audmux_2: audmux-2 { +- fsl,pins = < +- MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x80000000 +- MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x80000000 +- MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x80000000 +- MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x80000000 +- >; +- }; +- +- pinctrl_audmux_3: audmux-3 { +- fsl,pins = < +- MX6QDL_PAD_DISP0_DAT16__AUD5_TXC 0x80000000 +- MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS 0x80000000 +- MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x80000000 +- >; +- }; +- }; +- +- 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 +- >; +- }; +- +- 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 0x71 +- MX6QDL_PAD_GPIO_6__MLB_SIG 0x71 +- MX6QDL_PAD_GPIO_2__MLB_DATA 0x71 +- >; +- }; +- }; +- +- pwm0 { +- pinctrl_pwm0_1: pwm0grp-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 210>, <&clks 211>, ++ <&clks 212>, <&clks 213>; ++ 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>; +- status = "disabled"; +- }; +- +- lvds-channel@1 { +- reg = <1>; +- status = "disabled"; +- }; + }; + + dcic1: dcic@020e4000 { + reg = <0x020e4000 0x4000>; +- interrupts = <0 124 0x04>; ++ interrupts = <0 124 IRQ_TYPE_LEVEL_HIGH>; + }; + + dcic2: dcic@020e8000 { + reg = <0x020e8000 0x4000>; +- interrupts = <0 125 0x04>; ++ interrupts = <0 125 IRQ_TYPE_LEVEL_HIGH>; + }; + + sdma: sdma@020ec000 { + compatible = "fsl,imx6q-sdma", "fsl,imx35-sdma"; + reg = <0x020ec000 0x4000>; +- interrupts = <0 2 0x04>; ++ interrupts = <0 2 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 155>, <&clks 155>; + clock-names = "ipg", "ahb"; + #dma-cells = <3>; +@@ -1396,9 +772,29 @@ + reg = <0x02100000 0x100000>; + ranges; + +- caam@02100000 { +- reg = <0x02100000 0x40000>; +- interrupts = <0 105 0x04 0 106 0x04>; ++ crypto: caam@02100000 { ++ 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 214>, <&clks 215>, <&clks 216>, <&clks 196>; ++ clock-names = "caam_mem", "caam_aclk", "caam_ipg", "caam_emi_slow"; ++ ++ sec_jr0: jr0@1000 { ++ compatible = "fsl,sec-v4.0-job-ring"; ++ reg = <0x1000 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ sec_jr1: jr1@2000 { ++ compatible = "fsl,sec-v4.0-job-ring"; ++ reg = <0x2000 0x1000>; ++ interrupt-parent = <&intc>; ++ interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>; ++ }; + }; + + aipstz@0217c000 { /* AIPSTZ2 */ +@@ -1408,7 +804,7 @@ + usbotg: usb@02184000 { + compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; + reg = <0x02184000 0x200>; +- interrupts = <0 43 0x04>; ++ interrupts = <0 43 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 162>; + fsl,usbphy = <&usbphy1>; + fsl,usbmisc = <&usbmisc 0>; +@@ -1418,7 +814,7 @@ + usbh1: usb@02184200 { + compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; + reg = <0x02184200 0x200>; +- interrupts = <0 40 0x04>; ++ interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 162>; + fsl,usbphy = <&usbphy2>; + fsl,usbmisc = <&usbmisc 1>; +@@ -1428,18 +824,24 @@ + usbh2: usb@02184400 { + compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; + reg = <0x02184400 0x200>; +- interrupts = <0 41 0x04>; ++ interrupts = <0 41 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 162>; + fsl,usbmisc = <&usbmisc 2>; ++ phy_type = "hsic"; ++ fsl,usbphy = <&usbphy_nop1>; ++ fsl,anatop = <&anatop>; + status = "disabled"; + }; + + usbh3: usb@02184600 { + compatible = "fsl,imx6q-usb", "fsl,imx27-usb"; + reg = <0x02184600 0x200>; +- interrupts = <0 42 0x04>; ++ interrupts = <0 42 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 162>; + fsl,usbmisc = <&usbmisc 3>; ++ phy_type = "hsic"; ++ fsl,usbphy = <&usbphy_nop2>; ++ fsl,anatop = <&anatop>; + status = "disabled"; + }; + +@@ -1453,7 +855,9 @@ + fec: ethernet@02188000 { + compatible = "fsl,imx6q-fec"; + reg = <0x02188000 0x4000>; +- interrupts = <0 118 0x04 0 119 0x04>; ++ interrupts-extended = ++ <&intc 0 118 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 117>, <&clks 117>, <&clks 190>; + clock-names = "ipg", "ahb", "ptp"; + status = "disabled"; +@@ -1461,13 +865,15 @@ + + mlb@0218c000 { + reg = <0x0218c000 0x4000>; +- interrupts = <0 53 0x04 0 117 0x04 0 126 0x04>; ++ interrupts = <0 53 IRQ_TYPE_LEVEL_HIGH>, ++ <0 117 IRQ_TYPE_LEVEL_HIGH>, ++ <0 126 IRQ_TYPE_LEVEL_HIGH>; + }; + + usdhc1: usdhc@02190000 { + compatible = "fsl,imx6q-usdhc"; + reg = <0x02190000 0x4000>; +- interrupts = <0 22 0x04>; ++ interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 163>, <&clks 163>, <&clks 163>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; +@@ -1477,7 +883,7 @@ + usdhc2: usdhc@02194000 { + compatible = "fsl,imx6q-usdhc"; + reg = <0x02194000 0x4000>; +- interrupts = <0 23 0x04>; ++ interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 164>, <&clks 164>, <&clks 164>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; +@@ -1487,7 +893,7 @@ + usdhc3: usdhc@02198000 { + compatible = "fsl,imx6q-usdhc"; + reg = <0x02198000 0x4000>; +- interrupts = <0 24 0x04>; ++ interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 165>, <&clks 165>, <&clks 165>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; +@@ -1497,7 +903,7 @@ + usdhc4: usdhc@0219c000 { + compatible = "fsl,imx6q-usdhc"; + reg = <0x0219c000 0x4000>; +- interrupts = <0 25 0x04>; ++ interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 166>, <&clks 166>, <&clks 166>; + clock-names = "ipg", "ahb", "per"; + bus-width = <4>; +@@ -1509,7 +915,7 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; + reg = <0x021a0000 0x4000>; +- interrupts = <0 36 0x04>; ++ interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 125>; + status = "disabled"; + }; +@@ -1519,7 +925,7 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; + reg = <0x021a4000 0x4000>; +- interrupts = <0 37 0x04>; ++ interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 126>; + status = "disabled"; + }; +@@ -1529,7 +935,7 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; + reg = <0x021a8000 0x4000>; +- interrupts = <0 38 0x04>; ++ interrupts = <0 38 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 127>; + status = "disabled"; + }; +@@ -1538,6 +944,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>; +@@ -1550,23 +961,29 @@ + weim: weim@021b8000 { + compatible = "fsl,imx6q-weim"; + reg = <0x021b8000 0x4000>; +- interrupts = <0 14 0x04>; ++ interrupts = <0 14 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 196>; + }; + +- ocotp: ocotp@021bc000 { +- compatible = "fsl,imx6q-ocotp", "syscon"; ++ ocotp: ocotp-ctrl@021bc000 { ++ compatible = "syscon"; + reg = <0x021bc000 0x4000>; + }; + ++ ocotp-fuse@021bc000 { ++ compatible = "fsl,imx6q-ocotp"; ++ reg = <0x021bc000 0x4000>; ++ clocks = <&clks 128>; ++ }; ++ + tzasc@021d0000 { /* TZASC1 */ + reg = <0x021d0000 0x4000>; +- interrupts = <0 108 0x04>; ++ interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; + }; + + tzasc@021d4000 { /* TZASC2 */ + reg = <0x021d4000 0x4000>; +- interrupts = <0 109 0x04>; ++ interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH>; + }; + + audmux: audmux@021d8000 { +@@ -1575,23 +992,32 @@ + 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>, <&clks 204>; ++ /* 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", "cfg_clk"; ++ status = "disabled"; + }; + + vdoa@021e4000 { ++ compatible = "fsl,imx6q-vdoa"; + reg = <0x021e4000 0x4000>; +- interrupts = <0 18 0x04>; ++ interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks 202>; ++ iram = <&ocram>; + }; + + uart2: serial@021e8000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021e8000 0x4000>; +- interrupts = <0 27 0x04>; ++ interrupts = <0 27 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; + dmas = <&sdma 27 4 0>, <&sdma 28 4 0>; +@@ -1602,7 +1028,7 @@ + uart3: serial@021ec000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021ec000 0x4000>; +- interrupts = <0 28 0x04>; ++ interrupts = <0 28 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; + dmas = <&sdma 29 4 0>, <&sdma 30 4 0>; +@@ -1613,7 +1039,7 @@ + uart4: serial@021f0000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021f0000 0x4000>; +- interrupts = <0 29 0x04>; ++ interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; + dmas = <&sdma 31 4 0>, <&sdma 32 4 0>; +@@ -1624,7 +1050,7 @@ + uart5: serial@021f4000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x021f4000 0x4000>; +- interrupts = <0 30 0x04>; ++ interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 160>, <&clks 161>; + clock-names = "ipg", "per"; + dmas = <&sdma 33 4 0>, <&sdma 34 4 0>; +@@ -1634,13 +1060,18 @@ + }; + + 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"; ++ interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>, ++ <0 5 IRQ_TYPE_LEVEL_HIGH>; ++ 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.14.40.orig/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi 2015-05-01 14:57:57.447427001 -0500 +@@ -0,0 +1,374 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/ { ++ /* these are used by bootloader for disabling nodes */ ++ aliases { ++ can0 = &can1; ++ ethernet0 = &fec; ++ led0 = &led0; ++ led1 = &led1; ++ nand = &gpmi; ++ usb0 = &usbh1; ++ usb1 = &usbotg; ++ }; ++ ++ chosen { ++ bootargs = "console=ttymxc1,115200"; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led0: user1 { ++ label = "user1"; ++ gpios = <&gpio4 6 0>; /* 102 -> MX6_PANLEDG */ ++ default-state = "on"; ++ linux,default-trigger = "heartbeat"; ++ }; ++ ++ led1: user2 { ++ label = "user2"; ++ gpios = <&gpio4 7 0>; /* 103 -> MX6_PANLEDR */ ++ default-state = "off"; ++ }; ++ }; ++ ++ memory { ++ reg = <0x10000000 0x20000000>; ++ }; ++ ++ pps { ++ compatible = "pps-gpio"; ++ gpios = <&gpio1 26 0>; ++ status = "okay"; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_3p3v: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_5p0v: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "5P0V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_otg_vbus: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio3 22 0>; ++ enable-active-high; ++ }; ++ }; ++}; ++ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ phy-reset-gpios = <&gpio1 30 0>; ++ status = "okay"; ++}; ++ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "okay"; ++ ++ eeprom1: eeprom@50 { ++ compatible = "atmel,24c02"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++ ++ eeprom2: eeprom@51 { ++ compatible = "atmel,24c02"; ++ reg = <0x51>; ++ pagesize = <16>; ++ }; ++ ++ eeprom3: eeprom@52 { ++ compatible = "atmel,24c02"; ++ reg = <0x52>; ++ pagesize = <16>; ++ }; ++ ++ eeprom4: eeprom@53 { ++ compatible = "atmel,24c02"; ++ reg = <0x53>; ++ pagesize = <16>; ++ }; ++ ++ gpio: pca9555@23 { ++ compatible = "nxp,pca9555"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ hwmon: gsc@29 { ++ compatible = "gw,gsp"; ++ reg = <0x29>; ++ }; ++ ++ rtc: ds1672@68 { ++ compatible = "dallas,ds1672"; ++ reg = <0x68>; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ status = "okay"; ++ ++ pmic: ltc3676@3c { ++ compatible = "ltc,ltc3676"; ++ reg = <0x3c>; ++ ++ regulators { ++ sw1_reg: ltc3676__sw1 { ++ regulator-min-microvolt = <1175000>; ++ regulator-max-microvolt = <1175000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw2_reg: ltc3676__sw2 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw3_reg: ltc3676__sw3 { ++ regulator-min-microvolt = <1175000>; ++ regulator-max-microvolt = <1175000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw4_reg: ltc3676__sw4 { ++ regulator-min-microvolt = <1500000>; ++ regulator-max-microvolt = <1500000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ ldo2_reg: ltc3676__ldo2 { ++ regulator-min-microvolt = <2500000>; ++ regulator-max-microvolt = <2500000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ ldo4_reg: ltc3676__ldo4 { ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3000000>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ status = "okay"; ++ ++ videoin: adv7180@20 { ++ compatible = "adi,adv7180"; ++ reg = <0x20>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6qdl-gw51xx { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x80000000 /* MEZZ_DIO0 */ ++ MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x80000000 /* MEZZ_DIO1 */ ++ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 /* OTG_PWR_EN */ ++ MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x80000000 /* GPS_PPS */ ++ MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* PHY Reset */ ++ MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x80000000 /* PCIE_RST# */ ++ MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x80000000 /* user1 led */ ++ MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x80000000 /* user2 led */ ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ fsl,pins = < ++ 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_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_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_gpmi_nand: gpminandgrp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart3: uart3grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5: uart5grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ >; ++ }; ++ }; ++}; ++ ++&pcie { ++ reset-gpio = <&gpio1 0 0>; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; ++ status = "okay"; ++}; ++ ++&uart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart3>; ++ status = "okay"; ++}; ++ ++&uart5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart5>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi 2015-05-01 14:57:57.447427001 -0500 +@@ -0,0 +1,527 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/ { ++ /* these are used by bootloader for disabling nodes */ ++ aliases { ++ ethernet0 = &fec; ++ led0 = &led0; ++ led1 = &led1; ++ led2 = &led2; ++ nand = &gpmi; ++ ssi0 = &ssi1; ++ usb0 = &usbh1; ++ usb1 = &usbotg; ++ usdhc2 = &usdhc3; ++ }; ++ ++ chosen { ++ bootargs = "console=ttymxc1,115200"; ++ }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm4 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led0: user1 { ++ label = "user1"; ++ gpios = <&gpio4 6 0>; /* 102 -> MX6_PANLEDG */ ++ default-state = "on"; ++ linux,default-trigger = "heartbeat"; ++ }; ++ ++ led1: user2 { ++ label = "user2"; ++ gpios = <&gpio4 7 0>; /* 103 -> MX6_PANLEDR */ ++ default-state = "off"; ++ }; ++ ++ led2: user3 { ++ label = "user3"; ++ gpios = <&gpio4 15 1>; /* 111 - MX6_LOCLED# */ ++ default-state = "off"; ++ }; ++ }; ++ ++ memory { ++ reg = <0x10000000 0x20000000>; ++ }; ++ ++ pps { ++ compatible = "pps-gpio"; ++ gpios = <&gpio1 26 0>; ++ status = "okay"; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_1p0v: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "1P0V"; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1000000>; ++ regulator-always-on; ++ }; ++ ++ /* remove this fixed regulator once ltc3676__sw2 driver available */ ++ reg_1p8v: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "1P8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_5p0v: regulator@3 { ++ compatible = "regulator-fixed"; ++ reg = <3>; ++ regulator-name = "5P0V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_otg_vbus: regulator@4 { ++ compatible = "regulator-fixed"; ++ reg = <4>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio3 22 0>; ++ enable-active-high; ++ }; ++ }; ++ ++ sound { ++ compatible = "fsl,imx6q-sabrelite-sgtl5000", ++ "fsl,imx-audio-sgtl5000"; ++ model = "imx6q-sabrelite-sgtl5000"; ++ ssi-controller = <&ssi1>; ++ audio-codec = <&codec>; ++ audio-routing = ++ "MIC_IN", "Mic Jack", ++ "Mic Jack", "Mic Bias", ++ "Headphone Jack", "HP_OUT"; ++ mux-int-port = <1>; ++ mux-ext-port = <4>; ++ }; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux>; ++ status = "okay"; ++}; ++ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ phy-reset-gpios = <&gpio1 30 0>; ++ status = "okay"; ++}; ++ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "okay"; ++ ++ eeprom1: eeprom@50 { ++ compatible = "atmel,24c02"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++ ++ eeprom2: eeprom@51 { ++ compatible = "atmel,24c02"; ++ reg = <0x51>; ++ pagesize = <16>; ++ }; ++ ++ eeprom3: eeprom@52 { ++ compatible = "atmel,24c02"; ++ reg = <0x52>; ++ pagesize = <16>; ++ }; ++ ++ eeprom4: eeprom@53 { ++ compatible = "atmel,24c02"; ++ reg = <0x53>; ++ pagesize = <16>; ++ }; ++ ++ gpio: pca9555@23 { ++ compatible = "nxp,pca9555"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ hwmon: gsc@29 { ++ compatible = "gw,gsp"; ++ reg = <0x29>; ++ }; ++ ++ rtc: ds1672@68 { ++ compatible = "dallas,ds1672"; ++ reg = <0x68>; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ status = "okay"; ++ ++ pciswitch: pex8609@3f { ++ compatible = "plx,pex8609"; ++ reg = <0x3f>; ++ }; ++ ++ pmic: ltc3676@3c { ++ compatible = "ltc,ltc3676"; ++ reg = <0x3c>; ++ ++ regulators { ++ sw1_reg: ltc3676__sw1 { ++ regulator-min-microvolt = <1175000>; ++ regulator-max-microvolt = <1175000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw2_reg: ltc3676__sw2 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw3_reg: ltc3676__sw3 { ++ regulator-min-microvolt = <1175000>; ++ regulator-max-microvolt = <1175000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ sw4_reg: ltc3676__sw4 { ++ regulator-min-microvolt = <1500000>; ++ regulator-max-microvolt = <1500000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ ldo2_reg: ltc3676__ldo2 { ++ regulator-min-microvolt = <2500000>; ++ regulator-max-microvolt = <2500000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ ldo3_reg: ltc3676__ldo3 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ ldo4_reg: ltc3676__ldo4 { ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3000000>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ status = "okay"; ++ ++ accelerometer: fxos8700@1e { ++ compatible = "fsl,fxos8700"; ++ reg = <0x13>; ++ }; ++ ++ codec: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&clks 169>; ++ VDDA-supply = <®_1p8v>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++ ++ touchscreen: egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ interrupt-parent = <&gpio7>; ++ interrupts = <12 2>; /* gpio7_12 active low */ ++ wakeup-gpios = <&gpio7 12 0>; ++ }; ++ ++ videoin: adv7180@20 { ++ compatible = "adi,adv7180"; ++ reg = <0x20>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6qdl-gw52xx { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x80000000 /* MEZZ_DIO0 */ ++ MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x80000000 /* MEZZ_DIO1 */ ++ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 /* OTG_PWR_EN */ ++ MX6QDL_PAD_EIM_D31__GPIO3_IO31 0x80000000 /* VIDDEC_PDN# */ ++ MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* PHY Reset */ ++ MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* PCIE_RST# */ ++ MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 /* GPS_PWDN */ ++ MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x80000000 /* GPS_PPS */ ++ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000130b0 /* AUD4_MCK */ ++ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* USB_SEL_PCI */ ++ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 /* TOUCH_IRQ# */ ++ MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x80000000 /* user1 led */ ++ MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x80000000 /* user2 led */ ++ MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 /* user3 led */ ++ MX6QDL_PAD_SD2_CMD__GPIO1_IO11 0x80000000 /* LVDS_TCH# */ ++ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 /* SD3_CD# */ ++ MX6QDL_PAD_SD4_DAT3__GPIO2_IO11 0x80000000 /* UART2_EN# */ ++ >; ++ }; ++ ++ pinctrl_audmux: audmuxgrp { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 ++ MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 ++ MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 ++ MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ fsl,pins = < ++ 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_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_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_gpmi_nand: gpminandgrp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_pwm4: pwm4grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5: uart5grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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 ++ >; ++ }; ++ }; ++}; ++ ++&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>; ++ }; ++ }; ++ }; ++}; ++ ++&pcie { ++ reset-gpio = <&gpio1 29 0>; ++ status = "okay"; ++}; ++ ++&pwm4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm4>; ++ status = "okay"; ++}; ++ ++&ssi1 { ++ fsl,mode = "i2s-slave"; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; ++ status = "okay"; ++}; ++ ++&uart5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart5>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ cd-gpios = <&gpio7 0 0>; ++ vmmc-supply = <®_3p3v>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi 2015-05-01 14:57:57.447427001 -0500 +@@ -0,0 +1,572 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/ { ++ /* these are used by bootloader for disabling nodes */ ++ aliases { ++ can0 = &can1; ++ ethernet0 = &fec; ++ ethernet1 = ð1; ++ led0 = &led0; ++ led1 = &led1; ++ led2 = &led2; ++ nand = &gpmi; ++ sky2 = ð1; ++ ssi0 = &ssi1; ++ usb0 = &usbh1; ++ usb1 = &usbotg; ++ usdhc2 = &usdhc3; ++ }; ++ ++ chosen { ++ bootargs = "console=ttymxc1,115200"; ++ }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm4 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led0: user1 { ++ label = "user1"; ++ gpios = <&gpio4 6 0>; /* 102 -> MX6_PANLEDG */ ++ default-state = "on"; ++ linux,default-trigger = "heartbeat"; ++ }; ++ ++ led1: user2 { ++ label = "user2"; ++ gpios = <&gpio4 7 0>; /* 103 -> MX6_PANLEDR */ ++ default-state = "off"; ++ }; ++ ++ led2: user3 { ++ label = "user3"; ++ gpios = <&gpio4 15 1>; /* 111 -> MX6_LOCLED# */ ++ default-state = "off"; ++ }; ++ }; ++ ++ memory { ++ reg = <0x10000000 0x40000000>; ++ }; ++ ++ pps { ++ compatible = "pps-gpio"; ++ gpios = <&gpio1 26 0>; ++ status = "okay"; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_1p0v: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "1P0V"; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1000000>; ++ regulator-always-on; ++ }; ++ ++ /* remove when pmic 1p8 regulator available */ ++ reg_1p8v: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "1P8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_h1_vbus: regulator@3 { ++ compatible = "regulator-fixed"; ++ reg = <3>; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_otg_vbus: regulator@4 { ++ compatible = "regulator-fixed"; ++ reg = <4>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio3 22 0>; ++ enable-active-high; ++ }; ++ }; ++ ++ sound { ++ compatible = "fsl,imx6q-sabrelite-sgtl5000", ++ "fsl,imx-audio-sgtl5000"; ++ model = "imx6q-sabrelite-sgtl5000"; ++ ssi-controller = <&ssi1>; ++ audio-codec = <&codec>; ++ audio-routing = ++ "MIC_IN", "Mic Jack", ++ "Mic Jack", "Mic Bias", ++ "Headphone Jack", "HP_OUT"; ++ mux-int-port = <1>; ++ mux-ext-port = <4>; ++ }; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux>; ++ status = "okay"; ++}; ++ ++&can1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan1>; ++ status = "okay"; ++}; ++ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ phy-reset-gpios = <&gpio1 30 0>; ++ status = "okay"; ++}; ++ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "okay"; ++ ++ eeprom1: eeprom@50 { ++ compatible = "atmel,24c02"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++ ++ eeprom2: eeprom@51 { ++ compatible = "atmel,24c02"; ++ reg = <0x51>; ++ pagesize = <16>; ++ }; ++ ++ eeprom3: eeprom@52 { ++ compatible = "atmel,24c02"; ++ reg = <0x52>; ++ pagesize = <16>; ++ }; ++ ++ eeprom4: eeprom@53 { ++ compatible = "atmel,24c02"; ++ reg = <0x53>; ++ pagesize = <16>; ++ }; ++ ++ gpio: pca9555@23 { ++ compatible = "nxp,pca9555"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ hwmon: gsc@29 { ++ compatible = "gw,gsp"; ++ reg = <0x29>; ++ }; ++ ++ rtc: ds1672@68 { ++ compatible = "dallas,ds1672"; ++ reg = <0x68>; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ status = "okay"; ++ ++ pciclkgen: si53156@6b { ++ compatible = "sil,si53156"; ++ reg = <0x6b>; ++ }; ++ ++ pciswitch: pex8606@3f { ++ compatible = "plx,pex8606"; ++ reg = <0x3f>; ++ }; ++ ++ pmic: ltc3676@3c { ++ compatible = "ltc,ltc3676"; ++ reg = <0x3c>; ++ ++ regulators { ++ /* VDD_SOC */ ++ sw1_reg: ltc3676__sw1 { ++ regulator-min-microvolt = <1175000>; ++ regulator-max-microvolt = <1175000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ /* VDD_1P8 */ ++ sw2_reg: ltc3676__sw2 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ /* VDD_ARM */ ++ sw3_reg: ltc3676__sw3 { ++ regulator-min-microvolt = <1175000>; ++ regulator-max-microvolt = <1175000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ /* VDD_DDR */ ++ sw4_reg: ltc3676__sw4 { ++ regulator-min-microvolt = <1500000>; ++ regulator-max-microvolt = <1500000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ /* VDD_2P5 */ ++ ldo2_reg: ltc3676__ldo2 { ++ regulator-min-microvolt = <2500000>; ++ regulator-max-microvolt = <2500000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ /* VDD_1P8 */ ++ ldo3_reg: ltc3676__ldo3 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ /* VDD_HIGH */ ++ ldo4_reg: ltc3676__ldo4 { ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3000000>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ status = "okay"; ++ ++ accelerometer: fxos8700@1e { ++ compatible = "fsl,fxos8700"; ++ reg = <0x1e>; ++ }; ++ ++ codec: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&clks 201>; ++ VDDA-supply = <®_1p8v>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++ ++ hdmiin: adv7611@4c { ++ compatible = "adi,adv7611"; ++ reg = <0x4c>; ++ }; ++ ++ touchscreen: egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <11 2>; /* gpio1_11 active low */ ++ wakeup-gpios = <&gpio1 11 0>; ++ }; ++ ++ videoout: adv7393@2a { ++ compatible = "adi,adv7393"; ++ reg = <0x2a>; ++ }; ++ ++ videoin: adv7180@20 { ++ compatible = "adi,adv7180"; ++ reg = <0x20>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6qdl-gw53xx { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_A19__GPIO2_IO19 0x80000000 /* PCIE6EXP_DIO0 */ ++ MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x80000000 /* PCIE6EXP_DIO1 */ ++ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 /* OTG_PWR_EN */ ++ MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 /* GPS_SHDN */ ++ MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x80000000 /* GPS_PPS */ ++ MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x80000000 /* PCIE IRQ */ ++ MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* PCIE RST */ ++ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000130b0 /* AUD4_MCK */ ++ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* CAN_STBY */ ++ MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x80000000 /* PMIC_IRQ# */ ++ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x80000000 /* HUB_RST# */ ++ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 /* PCIE_WDIS# */ ++ MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x80000000 /* ACCEL_IRQ# */ ++ MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x80000000 /* user1 led */ ++ MX6QDL_PAD_KEY_COL4__GPIO4_IO14 0x80000000 /* USBOTG_OC# */ ++ MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x80000000 /* user2 led */ ++ MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 /* user3 led */ ++ MX6QDL_PAD_SD2_CMD__GPIO1_IO11 0x80000000 /* TOUCH_IRQ# */ ++ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x80000000 /* SD3_DET# */ ++ >; ++ }; ++ ++ pinctrl_audmux: audmuxgrp { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 ++ MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 ++ MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 ++ MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ fsl,pins = < ++ 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_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_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_flexcan1: flexcan1grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x80000000 ++ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x80000000 ++ >; ++ }; ++ ++ pinctrl_gpmi_nand: gpminandgrp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_pwm4: pwm4grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5: uart5grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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 ++ >; ++ }; ++ }; ++}; ++ ++&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>; ++ }; ++ }; ++ }; ++}; ++ ++&pcie { ++ reset-gpio = <&gpio1 29 0>; ++ status = "okay"; ++ ++ eth1: sky2@8 { /* MAC/PHY on bus 8 */ ++ compatible = "marvell,sky2"; ++ }; ++}; ++ ++&pwm4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm4>; ++ status = "okay"; ++}; ++ ++&ssi1 { ++ fsl,mode = "i2s-slave"; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; ++ status = "okay"; ++}; ++ ++&uart5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart5>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ vbus-supply = <®_usb_h1_vbus>; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ cd-gpios = <&gpio7 0 0>; ++ vmmc-supply = <®_3p3v>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi 2015-05-01 14:57:57.447427001 -0500 +@@ -0,0 +1,599 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/ { ++ /* these are used by bootloader for disabling nodes */ ++ aliases { ++ can0 = &can1; ++ ethernet0 = &fec; ++ ethernet1 = ð1; ++ led0 = &led0; ++ led1 = &led1; ++ led2 = &led2; ++ nand = &gpmi; ++ sky2 = ð1; ++ ssi0 = &ssi1; ++ usb0 = &usbh1; ++ usb1 = &usbotg; ++ usdhc2 = &usdhc3; ++ }; ++ ++ chosen { ++ bootargs = "console=ttymxc1,115200"; ++ }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm4 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led0: user1 { ++ label = "user1"; ++ gpios = <&gpio4 6 0>; /* 102 -> MX6_PANLEDG */ ++ default-state = "on"; ++ linux,default-trigger = "heartbeat"; ++ }; ++ ++ led1: user2 { ++ label = "user2"; ++ gpios = <&gpio4 7 0>; /* 103 -> MX6_PANLEDR */ ++ default-state = "off"; ++ }; ++ ++ led2: user3 { ++ label = "user3"; ++ gpios = <&gpio4 15 1>; /* 111 -> MX6_LOCLED# */ ++ default-state = "off"; ++ }; ++ }; ++ ++ memory { ++ reg = <0x10000000 0x40000000>; ++ }; ++ ++ pps { ++ compatible = "pps-gpio"; ++ gpios = <&gpio1 26 0>; ++ status = "okay"; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_1p0v: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "1P0V"; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1000000>; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_h1_vbus: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_otg_vbus: regulator@3 { ++ compatible = "regulator-fixed"; ++ reg = <3>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio3 22 0>; ++ enable-active-high; ++ }; ++ }; ++ ++ sound { ++ compatible = "fsl,imx6q-sabrelite-sgtl5000", ++ "fsl,imx-audio-sgtl5000"; ++ model = "imx6q-sabrelite-sgtl5000"; ++ ssi-controller = <&ssi1>; ++ audio-codec = <&codec>; ++ audio-routing = ++ "MIC_IN", "Mic Jack", ++ "Mic Jack", "Mic Bias", ++ "Headphone Jack", "HP_OUT"; ++ mux-int-port = <1>; ++ mux-ext-port = <4>; ++ }; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux>; /* AUD4<->sgtl5000 */ ++ status = "okay"; ++}; ++ ++&can1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_flexcan1>; ++ status = "okay"; ++}; ++ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ phy-reset-gpios = <&gpio1 30 0>; ++ status = "okay"; ++}; ++ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "okay"; ++ ++ eeprom1: eeprom@50 { ++ compatible = "atmel,24c02"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++ ++ eeprom2: eeprom@51 { ++ compatible = "atmel,24c02"; ++ reg = <0x51>; ++ pagesize = <16>; ++ }; ++ ++ eeprom3: eeprom@52 { ++ compatible = "atmel,24c02"; ++ reg = <0x52>; ++ pagesize = <16>; ++ }; ++ ++ eeprom4: eeprom@53 { ++ compatible = "atmel,24c02"; ++ reg = <0x53>; ++ pagesize = <16>; ++ }; ++ ++ gpio: pca9555@23 { ++ compatible = "nxp,pca9555"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ hwmon: gsc@29 { ++ compatible = "gw,gsp"; ++ reg = <0x29>; ++ }; ++ ++ rtc: ds1672@68 { ++ compatible = "dallas,ds1672"; ++ reg = <0x68>; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ 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 = <3950000>; ++ 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; ++ }; ++ }; ++ }; ++ ++ pciswitch: pex8609@3f { ++ compatible = "plx,pex8609"; ++ reg = <0x3f>; ++ }; ++ ++ pciclkgen: si52147@6b { ++ compatible = "sil,si52147"; ++ reg = <0x6b>; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ status = "okay"; ++ ++ accelerometer: fxos8700@1e { ++ compatible = "fsl,fxos8700"; ++ reg = <0x1e>; ++ }; ++ ++ codec: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&clks 201>; ++ VDDA-supply = <&sw4_reg>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++ ++ hdmiin: adv7611@4c { ++ compatible = "adi,adv7611"; ++ reg = <0x4c>; ++ }; ++ ++ touchscreen: egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ interrupt-parent = <&gpio7>; ++ interrupts = <12 2>; /* gpio7_12 active low */ ++ wakeup-gpios = <&gpio7 12 0>; ++ }; ++ ++ videoout: adv7393@2a { ++ compatible = "adi,adv7393"; ++ reg = <0x2a>; ++ }; ++ ++ videoin: adv7180@20 { ++ compatible = "adi,adv7180"; ++ reg = <0x20>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6qdl-gw54xx { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 /* OTG_PWR_EN */ ++ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 /* SPINOR_CS0# */ ++ MX6QDL_PAD_ENET_RXD1__GPIO1_IO26 0x80000000 /* GPS_PPS */ ++ MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x80000000 /* PCIE IRQ */ ++ MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* PCIE RST */ ++ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000130b0 /* AUD4_MCK */ ++ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 /* CAN_STBY */ ++ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 /* TOUCH_IRQ# */ ++ MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x80000000 /* user1 led */ ++ MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x80000000 /* user2 led */ ++ MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 /* user3 led */ ++ MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x80000000 /* USBHUB_RST# */ ++ MX6QDL_PAD_SD1_DAT3__GPIO1_IO21 0x80000000 /* MIPI_DIO */ ++ >; ++ }; ++ ++ pinctrl_audmux: audmuxgrp { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 ++ MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 ++ MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 ++ MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ fsl,pins = < ++ 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_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_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_flexcan1: flexcan1grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x80000000 ++ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x80000000 ++ >; ++ }; ++ ++ pinctrl_gpmi_nand: gpminandgrp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_pwm4: pwm4grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5: uart5grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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 ++ >; ++ }; ++ }; ++}; ++ ++&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>; ++ }; ++ }; ++ }; ++}; ++ ++&pcie { ++ reset-gpio = <&gpio1 29 0>; ++ status = "okay"; ++ ++ eth1: sky2@8 { /* MAC/PHY on bus 8 */ ++ compatible = "marvell,sky2"; ++ }; ++}; ++ ++&pwm4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm4>; ++ status = "okay"; ++}; ++ ++&ssi1 { ++ fsl,mode = "i2s-slave"; ++ status = "okay"; ++}; ++ ++&ssi2 { ++ fsl,mode = "i2s-slave"; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; ++ status = "okay"; ++}; ++ ++&uart5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart5>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ vbus-supply = <®_usb_h1_vbus>; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ cd-gpios = <&gpio7 0 0>; ++ vmmc-supply = <®_3p3v>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-hummingboard.dtsi 2015-05-01 14:57:57.447427001 -0500 +@@ -0,0 +1,367 @@ ++/* ++ * Copyright (C) 2013,2014 Russell King ++ */ ++#include "imx6qdl-microsom.dtsi" ++#include "imx6qdl-microsom-ar8035.dtsi" ++ ++/ { ++ chosen { ++ bootargs = "quiet console=ttymxc0,115200 root=/dev/mmcblk0p2 rw"; ++ }; ++ ++ aliases { ++ mxcfb0 = &mxcfb1; ++ }; ++ ++ ir_recv: ir-receiver { ++ compatible = "gpio-ir-receiver"; ++ gpios = <&gpio3 5 1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_gpio3_5>; ++ linux,rc-map-name = "rc-rc6-mce"; ++ }; ++ ++ 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>; ++ }; ++ }; ++ ++ sound-sgtl5000 { ++ audio-codec = <&sgtl5000>; ++ audio-routing = ++ "MIC_IN", "Mic Jack", ++ "Mic Jack", "Mic Bias", ++ "Headphone Jack", "HP_OUT"; ++ compatible = "fsl,imx-audio-sgtl5000"; ++ model = "On-board Codec"; ++ mux-ext-port = <5>; ++ mux-int-port = <1>; ++ ssi-controller = <&ssi1>; ++ }; ++ ++ 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: fb@0 { ++ compatible = "fsl,mxc_sdc_fb"; ++ disp_dev = "hdmi"; ++ interface_pix_fmt = "RGB24"; ++ mode_str ="1920x1080M@60"; ++ default_bpp = <32>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "okay"; ++ }; ++}; ++ ++&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_hummingboard_hdmi>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_i2c2>; ++ status = "okay"; ++ ++ ddc: imx6_hdmi_i2c@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; ++}; ++ ++&audmux { ++ status = "okay"; ++}; ++ ++&can1 { ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_i2c1>; ++ status = "okay"; ++ ++ /* Pro model */ ++ rtc: pcf8523@68 { ++ compatible = "nxp,pcf8523"; ++ reg = <0x68>; ++ }; ++ ++ /* Pro model */ ++ sgtl5000: sgtl5000@0a { ++ clocks = <&clks 201>; ++ compatible = "fsl,sgtl5000"; ++ pinctrl-0 = <&pinctrl_hummingboard_sgtl5000>; ++ pinctrl-names = "default"; ++ reg = <0x0a>; ++ VDDA-supply = <®_3p3v>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ hummingboard { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ /* ++ * 26 pin header GPIO description. The pins ++ * numbering as following - ++ * GPIO number | GPIO (bank,num) | PIN number ++ * ------------+-----------------+------------ ++ * gpio1 | (1,1) | IO7 ++ * gpio73 | (3,9) | IO11 ++ * gpio72 | (3,8) | IO12 ++ * gpio71 | (3,7) | IO13 ++ * gpio70 | (3,6) | IO15 ++ * gpio194 | (7,2) | IO16 ++ * gpio195 | (7,3) | IO18 ++ * gpio67 | (3,3) | IO22 ++ * ++ * Notice the gpioX and GPIO (Y,Z) mapping forumla : ++ * X = (Y-1) * 32 + Z ++ */ ++ MX6QDL_PAD_GPIO_1__GPIO1_IO01 0x400130b1 ++ MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x400130b1 ++ MX6QDL_PAD_EIM_DA8__GPIO3_IO08 0x400130b1 ++ MX6QDL_PAD_EIM_DA7__GPIO3_IO07 0x400130b1 ++ MX6QDL_PAD_EIM_DA6__GPIO3_IO06 0x400130b1 ++ MX6QDL_PAD_SD3_CMD__GPIO7_IO02 0x400130b1 ++ MX6QDL_PAD_SD3_CLK__GPIO7_IO03 0x400130b1 ++ MX6QDL_PAD_EIM_DA3__GPIO3_IO03 0x400130b1 ++ >; ++ }; ++ ++ pinctrl_hummingboard_gpio3_5: hummingboard-gpio3_5 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_DA5__GPIO3_IO05 0x80000000 ++ >; ++ }; ++ ++ pinctrl_hummingboard_hdmi: hummingboard-hdmi { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ ++ pinctrl_hummingboard_i2c1: hummingboard-i2c1 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_hummingboard_i2c2: hummingboard-i2c2 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_hummingboard_sgtl5000: hummingboard-sgtl5000 { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0 /*brk*/ ++ MX6QDL_PAD_KEY_COL0__AUD5_TXC 0x130b0 /*ok*/ ++ MX6QDL_PAD_KEY_ROW0__AUD5_TXD 0x110b0 /*brk*/ ++ MX6QDL_PAD_KEY_COL1__AUD5_TXFS 0x130b0 /*ok*/ ++ MX6QDL_PAD_GPIO_5__CCM_CLKO1 0x130b0 ++ >; ++ }; ++ ++ pinctrl_hummingboard_spdif: hummingboard-spdif { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard_usbh1_vbus: hummingboard-usbh1-vbus { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_hummingboard_usbotg_id: hummingboard-usbotg-id { ++ /* ++ * Similar to pinctrl_usbotg_2, but we want it ++ * pulled down for a fixed host connection. ++ */ ++ 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 ++ >; ++ }; ++ ++ pinctrl_hummingboard_pcie_reset: hummingboard-pcie-reset { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x80000000 ++ >; ++ }; ++ ++ pinctrl_pwm1: pwm1grp { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b1 ++ >; ++ }; ++ ++ }; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_spdif>; ++ clocks = <&clks 197>, <&clks 0>, ++ <&clks 197>, <&clks 0>, ++ <&clks 0>, <&clks 0>, ++ <&clks 0>, <&clks 0>, ++ <&clks 0>; ++ clock-names = "core", "rxtx0", ++ "rxtx1", "rxtx2", ++ "rxtx3", "rxtx4", ++ "rxtx5", "rxtx6", ++ "rxtx7"; ++ status = "okay"; ++}; ++ ++&ssi1 { ++ fsl,mode = "i2s-slave"; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ disable-over-current; ++ vbus-supply = <®_usbh1_vbus>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ disable-over-current; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hummingboard_usbotg_id>; ++ 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"; ++}; ++ ++&gpc { ++ fsl,cpu_pupscr_sw2iso = <0xf>; ++ fsl,cpu_pupscr_sw = <0xf>; ++ fsl,cpu_pdnscr_iso2sw = <0x1>; ++ fsl,cpu_pdnscr_iso = <0x1>; ++}; ++ ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = < ++ &pinctrl_hummingboard_pcie_reset ++ >; ++ reset-gpio = <&gpio3 4 0>; ++ status = "okay"; ++ no-msi; ++}; ++ ++&pwm1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm1>; ++ status = "okay"; ++}; ++ ++&pwm2 { ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&pwm3 { ++ status = "disabled"; ++}; ++ ++&pwm4 { ++ status = "disabled"; ++}; ++ +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi 2015-05-01 14:57:57.447427001 -0500 +@@ -17,7 +17,7 @@ + enet { + pinctrl_microsom_enet_ar8035: microsom-enet-ar8035 { + fsl,pins = < +- MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b8b0 + MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 + /* AR8035 reset */ + MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x130b0 +@@ -26,25 +26,25 @@ + /* 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 ++ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b030 ++ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b030 ++ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b030 ++ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b030 ++ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b030 + /* 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 ++ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b030 + /* AR8035 pin strapping: PHYADDR#0: pull down */ +- MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x130b0 ++ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x13030 + /* AR8035 pin strapping: PHYADDR#1: pull down */ +- MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x130b0 ++ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x13030 + /* AR8035 pin strapping: MODE#1: pull up */ +- MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b030 + /* AR8035 pin strapping: MODE#3: pull up */ +- MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0 ++ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b030 + /* AR8035 pin strapping: MODE#0: pull down */ +- MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x130b0 ++ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x13030 + + /* + * As the RMII pins are also connected to RGMII +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-microsom.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-microsom.dtsi 2015-05-01 14:57:57.447427001 -0500 +@@ -1,9 +1,69 @@ + /* + * 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_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_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_uart1: microsom-uart1 { + fsl,pins = < + MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 +@@ -11,12 +71,24 @@ + >; + }; + +- pinctrl_microsom_usbotg: microsom-usbotg { +- /* +- * Similar to pinctrl_usbotg_2, but we want it +- * pulled down for a fixed host connection. +- */ +- fsl,pins = ; ++ 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_usdhc1: microsom-usdhc1 { ++ 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 ++ >; + }; + }; + }; +@@ -27,7 +99,23 @@ + status = "okay"; + }; + +-&usbotg { ++/* 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; ++ status = "okay"; ++}; ++ ++/* 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_usbotg>; ++ pinctrl-0 = <&pinctrl_microsom_brcm_wifi &pinctrl_microsom_usdhc1>; ++ vmmc-supply = <®_brcm>; ++ status = "okay"; + }; ++ +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi 2015-05-01 14:57:57.447427001 -0500 +@@ -0,0 +1,426 @@ ++/* ++ * Copyright 2013 Boundary Devices, Inc. ++ * Copyright 2011 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 ++ ++/ { ++ chosen { ++ stdout-path = &uart2; ++ }; ++ ++ memory { ++ reg = <0x10000000 0x40000000>; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_2p5v: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "2P5V"; ++ regulator-min-microvolt = <2500000>; ++ regulator-max-microvolt = <2500000>; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_otg_vbus: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio3 22 0>; ++ enable-active-high; ++ }; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_keys>; ++ ++ power { ++ label = "Power Button"; ++ gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ gpio-key,wakeup; ++ }; ++ ++ menu { ++ label = "Menu"; ++ gpios = <&gpio2 1 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ home { ++ label = "Home"; ++ gpios = <&gpio2 4 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ back { ++ label = "Back"; ++ gpios = <&gpio2 2 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ volume-up { ++ label = "Volume Up"; ++ gpios = <&gpio7 13 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ volume-down { ++ label = "Volume Down"; ++ gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ }; ++ ++ sound { ++ compatible = "fsl,imx6q-nitrogen6x-sgtl5000", ++ "fsl,imx-audio-sgtl5000"; ++ model = "imx6q-nitrogen6x-sgtl5000"; ++ ssi-controller = <&ssi1>; ++ audio-codec = <&codec>; ++ audio-routing = ++ "MIC_IN", "Mic Jack", ++ "Mic Jack", "Mic Bias", ++ "Headphone Jack", "HP_OUT"; ++ mux-int-port = <1>; ++ mux-ext-port = <3>; ++ }; ++ ++ backlight_lcd { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm1 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ power-supply = <®_3p3v>; ++ status = "okay"; ++ }; ++ ++ backlight_lvds { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm4 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ power-supply = <®_3p3v>; ++ status = "okay"; ++ }; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux>; ++ status = "okay"; ++}; ++ ++&ecspi1 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio3 19 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi1>; ++ status = "okay"; ++ ++ flash: m25p80@0 { ++ compatible = "sst,sst25vf016b"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ phy-reset-gpios = <&gpio1 27 0>; ++ txen-skew-ps = <0>; ++ txc-skew-ps = <3000>; ++ rxdv-skew-ps = <0>; ++ rxc-skew-ps = <3000>; ++ rxd0-skew-ps = <0>; ++ rxd1-skew-ps = <0>; ++ rxd2-skew-ps = <0>; ++ rxd3-skew-ps = <0>; ++ txd0-skew-ps = <0>; ++ txd1-skew-ps = <0>; ++ txd2-skew-ps = <0>; ++ txd3-skew-ps = <0>; ++ interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "okay"; ++ ++ codec: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&clks 201>; ++ VDDA-supply = <®_2p5v>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6q-nitrogen6x { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ /* SGTL5000 sys_mclk */ ++ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x030b0 ++ >; ++ }; ++ ++ pinctrl_audmux: audmuxgrp { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 ++ MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 ++ MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 ++ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 ++ >; ++ }; ++ ++ pinctrl_ecspi1: ecspi1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 ++ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 ++ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 ++ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 /* CS */ ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 ++ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0 ++ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0 ++ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0 ++ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0 ++ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0 ++ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0 ++ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 ++ 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 ++ /* Phy reset */ ++ MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x000b0 ++ MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 ++ >; ++ }; ++ ++ pinctrl_gpio_keys: gpio_keysgrp { ++ fsl,pins = < ++ /* Power Button */ ++ MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 ++ /* Menu Button */ ++ MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 ++ /* Home Button */ ++ MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 ++ /* Back Button */ ++ MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 ++ /* Volume Up Button */ ++ MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 ++ /* Volume Down Button */ ++ MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_pwm1: pwm1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_pwm3: pwm3grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_pwm4: pwm4grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 ++ /* power enable, high active */ ++ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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_DAT5__GPIO7_IO00 0x1b0b0 /* CD */ ++ >; ++ }; ++ ++ pinctrl_usdhc4: usdhc4grp { ++ 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_NANDF_D6__GPIO2_IO06 0x1b0b0 /* CD */ ++ >; ++ }; ++ }; ++}; ++ ++&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>; ++ }; ++ }; ++ }; ++}; ++ ++&pcie { ++ status = "okay"; ++}; ++ ++&pwm1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm1>; ++ status = "okay"; ++}; ++ ++&pwm3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm3>; ++ status = "okay"; ++}; ++ ++&pwm4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm4>; ++ status = "okay"; ++}; ++ ++&ssi1 { ++ fsl,mode = "i2s-slave"; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ cd-gpios = <&gpio7 0 0>; ++ vmmc-supply = <®_3p3v>; ++ status = "okay"; ++}; ++ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4>; ++ cd-gpios = <&gpio2 6 0>; ++ vmmc-supply = <®_3p3v>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi 2015-05-01 14:57:57.447427001 -0500 +@@ -0,0 +1,98 @@ ++/* ++ * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH ++ * ++ * 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 ++ */ ++ ++/ { ++ chosen { ++ linux,stdout-path = &uart4; ++ }; ++}; ++ ++&fec { ++ status = "okay"; ++}; ++ ++&gpmi { ++ status = "okay"; ++}; ++ ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ clock-frequency = <100000>; ++ status = "okay"; ++ ++ tlv320@18 { ++ compatible = "ti,tlv320aic3x"; ++ reg = <0x18>; ++ }; ++ ++ stmpe@41 { ++ compatible = "st,stmpe811"; ++ reg = <0x41>; ++ }; ++ ++ rtc@51 { ++ compatible = "nxp,rtc8564"; ++ reg = <0x51>; ++ }; ++ ++ adc@64 { ++ compatible = "maxim,max1037"; ++ reg = <0x64>; ++ }; ++}; ++ ++&i2c3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ clock-frequency = <100000>; ++ status = "okay"; ++}; ++ ++&uart3 { ++ status = "okay"; ++}; ++ ++&uart4 { ++ status = "okay"; ++}; ++ ++&usbh1 { ++ status = "okay"; ++}; ++ ++&usbotg { ++ status = "okay"; ++}; ++ ++&usdhc2 { ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ status = "okay"; ++}; ++ ++&iomuxc { ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi 2015-05-01 14:57:57.447427001 -0500 +@@ -0,0 +1,356 @@ ++/* ++ * Copyright 2013 Christian Hemp, Phytec Messtechnik GmbH ++ * ++ * 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 ++ ++/ { ++ model = "Phytec phyFLEX-i.MX6 Ouad"; ++ compatible = "phytec,imx6q-pfla02", "fsl,imx6q"; ++ ++ memory { ++ reg = <0x10000000 0x80000000>; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_usb_otg_vbus: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio4 15 0>; ++ }; ++ ++ reg_usb_h1_vbus: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio1 0 0>; ++ }; ++ }; ++ ++ gpio_leds: leds { ++ compatible = "gpio-leds"; ++ ++ green { ++ label = "phyflex:green"; ++ gpios = <&gpio1 30 0>; ++ }; ++ ++ red { ++ label = "phyflex:red"; ++ gpios = <&gpio2 31 0>; ++ }; ++ }; ++}; ++ ++&ecspi3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi3>; ++ status = "okay"; ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio4 24 0>; ++ ++ flash@0 { ++ compatible = "m25p80"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++&i2c1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "okay"; ++ ++ eeprom@50 { ++ compatible = "atmel,24c32"; ++ reg = <0x50>; ++ }; ++ ++ pmic@58 { ++ compatible = "dialog,da9063"; ++ reg = <0x58>; ++ interrupt-parent = <&gpio4>; ++ interrupts = <17 0x8>; /* active-low GPIO4_17 */ ++ ++ regulators { ++ vddcore_reg: bcore1 { ++ regulator-min-microvolt = <730000>; ++ regulator-max-microvolt = <1380000>; ++ regulator-always-on; ++ }; ++ ++ vddsoc_reg: bcore2 { ++ regulator-min-microvolt = <730000>; ++ regulator-max-microvolt = <1380000>; ++ regulator-always-on; ++ }; ++ ++ vdd_ddr3_reg: bpro { ++ regulator-min-microvolt = <1500000>; ++ regulator-max-microvolt = <1500000>; ++ regulator-always-on; ++ }; ++ ++ vdd_3v3_reg: bperi { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vdd_buckmem_reg: bmem { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vdd_eth_reg: bio { ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1200000>; ++ regulator-always-on; ++ }; ++ ++ vdd_eth_io_reg: ldo4 { ++ regulator-min-microvolt = <2500000>; ++ regulator-max-microvolt = <2500000>; ++ regulator-always-on; ++ }; ++ ++ vdd_mx6_snvs_reg: ldo5 { ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3000000>; ++ regulator-always-on; ++ }; ++ ++ vdd_3v3_pmic_io_reg: ldo6 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ vdd_sd0_reg: ldo9 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ vdd_sd1_reg: ldo10 { ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ ++ vdd_mx6_high_reg: ldo11 { ++ regulator-min-microvolt = <3000000>; ++ regulator-max-microvolt = <3000000>; ++ regulator-always-on; ++ }; ++ }; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6q-phytec-pfla02 { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 ++ MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */ ++ MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x80000000 /* PMIC interrupt */ ++ MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* Green LED */ ++ MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x80000000 /* Red LED */ ++ >; ++ }; ++ ++ pinctrl_ecspi3: ecspi3grp { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1 ++ MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1 ++ MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x100b1 ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_gpmi_nand: gpminandgrp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_uart3: uart3grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D30__UART3_RTS_B 0x1b0b1 ++ MX6QDL_PAD_EIM_D31__UART3_CTS_B 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbh1: usbh1grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_0__USB_H1_PWR 0x80000000 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 ++ MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 ++ >; ++ }; ++ ++ pinctrl_usdhc2: usdhc2grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_usdhc3_cdwp: usdhc3cdwp { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 ++ MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 ++ >; ++ }; ++ }; ++}; ++ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ phy-reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>; ++ status = "disabled"; ++}; ++ ++&gpmi { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpmi_nand>; ++ nand-on-flash-bbt; ++ status = "disabled"; ++}; ++ ++&uart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart3>; ++ status = "disabled"; ++}; ++ ++&uart4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart4>; ++ status = "disabled"; ++}; ++ ++&usbh1 { ++ vbus-supply = <®_usb_h1_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbh1>; ++ status = "disabled"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ status = "disabled"; ++}; ++ ++&usdhc2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc2>; ++ cd-gpios = <&gpio1 4 0>; ++ wp-gpios = <&gpio1 2 0>; ++ status = "disabled"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3 ++ &pinctrl_usdhc3_cdwp>; ++ cd-gpios = <&gpio1 27 0>; ++ wp-gpios = <&gpio1 29 0>; ++ status = "disabled"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi 2015-05-01 14:57:57.451427001 -0500 +@@ -10,17 +10,146 @@ + * http://www.gnu.org/copyleft/gpl.html + */ + ++#include ++ + / { ++ aliases { ++ mxcfb0 = &mxcfb1; ++ mxcfb1 = &mxcfb2; ++ mxcfb2 = &mxcfb3; ++ mxcfb3 = &mxcfb4; ++ }; ++ + memory { + reg = <0x10000000 0x80000000>; + }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_leds>; ++ ++ user { ++ label = "debug"; ++ gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ sound-spdif { ++ compatible = "fsl,imx-audio-spdif", ++ "fsl,imx-sabreauto-spdif"; ++ model = "imx-spdif"; ++ spdif-controller = <&spdif>; ++ spdif-in; ++ }; ++ ++ backlight { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm3 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ status = "okay"; ++ }; ++ ++ 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; ++ }; ++ }; ++ ++ sound-cs42888 { ++ compatible = "fsl,imx6-sabreauto-cs42888", ++ "fsl,imx-audio-cs42888"; ++ model = "imx-cs42888"; ++ esai-controller = <&esai>; ++ asrc-controller = <&asrc_p2p>; ++ audio-codec = <&codec>; ++ }; ++ ++ sound-hdmi { ++ compatible = "fsl,imx6q-audio-hdmi", ++ "fsl,imx-audio-hdmi"; ++ model = "imx-audio-hdmi"; ++ hdmi-controller = <&hdmi_audio>; ++ }; ++ ++ clocks { ++ codec_osc: anaclk2 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24576000>; ++ }; ++ }; + }; + + &ecspi1 { + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio3 19 0>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_ecspi1_1 &pinctrl_ecspi1_sabreauto>; ++ pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_ecspi1_cs>; + status = "disabled"; /* pin conflict with WEIM NOR */ + + flash: m25p80@0 { +@@ -34,51 +163,481 @@ + + &fec { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_2>; ++ pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; ++ interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; + status = "okay"; + }; + + &gpmi { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_gpmi_nand_1>; ++ pinctrl-0 = <&pinctrl_gpmi_nand>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ 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>; ++ }; ++}; ++ ++&i2c3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ 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>; ++ }; + }; + + &iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + +- hog { ++ imx6qdl-sabreauto { + 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_GPIO_18__SD3_VSELECT 0x17059 + >; + }; +- }; + +- ecspi1 { +- pinctrl_ecspi1_sabreauto: ecspi1-sabreauto { ++ pinctrl_esai1: esai1grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_ecspi1: ecspi1grp { ++ 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_cs: ecspi1cs { + fsl,pins = < + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 + >; + }; ++ ++ pinctrl_enet: enetgrp { ++ 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_6__ENET_IRQ 0x000b1 ++ >; ++ }; ++ ++ pinctrl_gpio_leds: gpioledsgrp { ++ fsl,pins = < ++ MX6QDL_PAD_DISP0_DAT21__GPIO5_IO15 0x80000000 ++ >; ++ }; ++ ++ pinctrl_gpmi_nand: gpminandgrp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_hdmi_cec_2: hdmicecgrp-2 { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_pwm1: pwm1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_spdif: spdifgrp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__SPDIF_IN 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_uart3: uart3grp { ++ 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_uart4: uart4grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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_100mhz: usdhc3grp100mhz { ++ 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_200mhz: usdhc3grp200mhz { ++ 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_weim_cs0: weimcs0grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_CS0__EIM_CS0_B 0xb0b1 ++ >; ++ }; ++ ++ pinctrl_weim_nor: weimnorgrp { ++ 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 ++ 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 ++ 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 { ++ 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>; ++ }; ++ }; + }; + }; + ++&pcie { ++ status = "okay"; ++}; ++ ++&pwm3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm1>; ++ status = "okay"; ++}; ++ ++&spdif { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_spdif>; ++ status = "okay"; ++}; ++ ++&uart3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart3>; ++ 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"; ++}; ++ + &uart4 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart4_1>; ++ pinctrl-0 = <&pinctrl_uart4>; + 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>; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ pinctrl-1 = <&pinctrl_usdhc3_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + cd-gpios = <&gpio6 15 0>; + wp-gpios = <&gpio1 13 0>; + status = "okay"; +@@ -86,7 +645,7 @@ + + &weim { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_weim_nor_1 &pinctrl_weim_cs0_1>; ++ pinctrl-0 = <&pinctrl_weim_nor &pinctrl_weim_cs0>; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x08000000 0x08000000>; +@@ -102,3 +661,48 @@ + 0x0000c000 0x1404a38e 0x00000000>; + }; + }; ++ ++&ldb { ++ ipu_id = <1>; ++ disp_id = <0>; ++ ext_ref = <1>; ++ mode = "sep0"; ++ sec_ipu_id = <1>; ++ sec_disp_id = <1>; ++ status = "okay"; ++}; ++ ++&esai { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_esai1>; ++ 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_2>; ++ 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.14.40.orig/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi 2015-05-01 14:57:57.451427001 -0500 +@@ -0,0 +1,427 @@ ++/* ++ * Copyright 2011 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 ++ ++/ { ++ chosen { ++ stdout-path = &uart2; ++ }; ++ ++ memory { ++ reg = <0x10000000 0x40000000>; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_2p5v: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "2P5V"; ++ regulator-min-microvolt = <2500000>; ++ regulator-max-microvolt = <2500000>; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_otg_vbus: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio3 22 0>; ++ enable-active-high; ++ }; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_keys>; ++ ++ power { ++ label = "Power Button"; ++ gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ gpio-key,wakeup; ++ }; ++ ++ menu { ++ label = "Menu"; ++ gpios = <&gpio2 1 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ home { ++ label = "Home"; ++ gpios = <&gpio2 4 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ back { ++ label = "Back"; ++ gpios = <&gpio2 2 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ volume-up { ++ label = "Volume Up"; ++ gpios = <&gpio7 13 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ ++ volume-down { ++ label = "Volume Down"; ++ gpios = <&gpio4 5 GPIO_ACTIVE_LOW>; ++ linux,code = ; ++ }; ++ }; ++ ++ sound { ++ compatible = "fsl,imx6q-sabrelite-sgtl5000", ++ "fsl,imx-audio-sgtl5000"; ++ model = "imx6q-sabrelite-sgtl5000"; ++ ssi-controller = <&ssi1>; ++ audio-codec = <&codec>; ++ audio-routing = ++ "MIC_IN", "Mic Jack", ++ "Mic Jack", "Mic Bias", ++ "Headphone Jack", "HP_OUT"; ++ mux-int-port = <1>; ++ mux-ext-port = <4>; ++ }; ++ ++ backlight_lcd { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm1 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ power-supply = <®_3p3v>; ++ status = "okay"; ++ }; ++ ++ backlight_lvds { ++ compatible = "pwm-backlight"; ++ pwms = <&pwm4 0 5000000>; ++ brightness-levels = <0 4 8 16 32 64 128 255>; ++ default-brightness-level = <7>; ++ power-supply = <®_3p3v>; ++ status = "okay"; ++ }; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux>; ++ status = "okay"; ++}; ++ ++&ecspi1 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio3 19 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi1>; ++ status = "okay"; ++ ++ flash: m25p80@0 { ++ compatible = "sst,sst25vf016b"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ phy-reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>; ++ txen-skew-ps = <0>; ++ txc-skew-ps = <3000>; ++ rxdv-skew-ps = <0>; ++ rxc-skew-ps = <3000>; ++ rxd0-skew-ps = <0>; ++ rxd1-skew-ps = <0>; ++ rxd2-skew-ps = <0>; ++ rxd3-skew-ps = <0>; ++ txd0-skew-ps = <0>; ++ txd1-skew-ps = <0>; ++ txd2-skew-ps = <0>; ++ txd3-skew-ps = <0>; ++ interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "okay"; ++ ++ codec: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&clks 201>; ++ VDDA-supply = <®_2p5v>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6q-sabrelite { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ /* SGTL5000 sys_mclk */ ++ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x030b0 ++ >; ++ }; ++ ++ pinctrl_audmux: audmuxgrp { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 ++ MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 ++ MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 ++ MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 ++ >; ++ }; ++ ++ pinctrl_ecspi1: ecspi1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 ++ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 ++ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 ++ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1 /* CS */ ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0 ++ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0 ++ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0 ++ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0 ++ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0 ++ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0 ++ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0 ++ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0 ++ 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 ++ /* Phy reset */ ++ MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x000b0 ++ MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 ++ >; ++ }; ++ ++ pinctrl_gpio_keys: gpio_keysgrp { ++ fsl,pins = < ++ /* Power Button */ ++ MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0 ++ /* Menu Button */ ++ MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0 ++ /* Home Button */ ++ MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0 ++ /* Back Button */ ++ MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0 ++ /* Volume Up Button */ ++ MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0 ++ /* Volume Down Button */ ++ MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_pwm1: pwm1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_pwm3: pwm3grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_pwm4: pwm4grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0 ++ /* power enable, high active */ ++ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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_DAT5__GPIO7_IO00 0x1b0b0 /* CD */ ++ MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1f0b0 /* WP */ ++ >; ++ }; ++ ++ pinctrl_usdhc4: usdhc4grp { ++ 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_NANDF_D6__GPIO2_IO06 0x1b0b0 /* CD */ ++ >; ++ }; ++ }; ++}; ++ ++&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>; ++ }; ++ }; ++ }; ++}; ++ ++&pcie { ++ status = "okay"; ++}; ++ ++&pwm1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm1>; ++ status = "okay"; ++}; ++ ++&pwm3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm3>; ++ status = "okay"; ++}; ++ ++&pwm4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pwm4>; ++ status = "okay"; ++}; ++ ++&ssi1 { ++ fsl,mode = "i2s-slave"; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ cd-gpios = <&gpio7 0 0>; ++ wp-gpios = <&gpio7 1 0>; ++ vmmc-supply = <®_3p3v>; ++ status = "okay"; ++}; ++ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4>; ++ cd-gpios = <&gpio2 6 0>; ++ vmmc-supply = <®_3p3v>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-sabresd.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-sabresd.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-sabresd.dtsi 2015-05-01 14:57:57.451427001 -0500 +@@ -10,16 +10,33 @@ + * http://www.gnu.org/copyleft/gpl.html + */ + ++#include ++#include ++ + / { ++ aliases { ++ mxcfb0 = &mxcfb1; ++ mxcfb1 = &mxcfb2; ++ mxcfb2 = &mxcfb3; ++ mxcfb3 = &mxcfb4; ++ }; ++ ++ chosen { ++ stdout-path = &uart1; ++ }; ++ + memory { + reg = <0x10000000 0x40000000>; + }; + + regulators { + compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; + +- reg_usb_otg_vbus: usb_otg_vbus { ++ reg_usb_otg_vbus: regulator@0 { + compatible = "regulator-fixed"; ++ reg = <0>; + regulator-name = "usb_otg_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; +@@ -27,8 +44,9 @@ + enable-active-high; + }; + +- reg_usb_h1_vbus: usb_h1_vbus { ++ reg_usb_h1_vbus: regulator@1 { + compatible = "regulator-fixed"; ++ reg = <1>; + regulator-name = "usb_h1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; +@@ -36,29 +54,46 @@ + enable-active-high; + }; + +- reg_audio: wm8962_supply { ++ reg_audio: regulator@2 { + compatible = "regulator-fixed"; ++ reg = <2>; + 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; ++ }; + }; + + gpio-keys { + compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_keys>; ++ ++ power { ++ label = "Power Button"; ++ gpios = <&gpio3 29 GPIO_ACTIVE_LOW>; ++ gpio-key,wakeup; ++ linux,code = ; ++ }; + + volume-up { + label = "Volume Up"; +- gpios = <&gpio1 4 0>; ++ gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + gpio-key,wakeup; +- linux,code = <115>; /* KEY_VOLUMEUP */ ++ linux,code = ; + }; + + volume-down { + label = "Volume Down"; +- gpios = <&gpio1 5 0>; ++ gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; + gpio-key,wakeup; +- linux,code = <114>; /* KEY_VOLUMEDOWN */ ++ linux,code = ; + }; + }; + +@@ -88,11 +123,107 @@ + default-brightness-level = <7>; + status = "okay"; + }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_gpio_leds>; ++ ++ red { ++ gpios = <&gpio1 2 0>; ++ default-state = "on"; ++ }; ++ }; ++ ++ 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>; ++ 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_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>; ++ pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; + }; + +@@ -100,7 +231,7 @@ + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio4 9 0>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_ecspi1_2>; ++ pinctrl-0 = <&pinctrl_ecspi1>; + status = "okay"; + + flash: m25p80@0 { +@@ -114,7 +245,7 @@ + + &fec { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_1>; ++ pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio1 25 0>; + status = "okay"; +@@ -123,7 +254,7 @@ + &i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_i2c1_2>; ++ pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + codec: wm8962@1a { +@@ -149,10 +280,121 @@ + }; + }; + ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ status = "okay"; ++ ++ hdmi: edid@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; ++ ++ 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; ++ }; ++ }; ++ }; ++}; ++ + &i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_i2c3_2>; ++ pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + egalax_ts@04 { +@@ -168,11 +410,9 @@ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + +- hog { ++ imx6qdl-sabresd { + pinctrl_hog: hoggrp { + 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 +@@ -182,6 +422,202 @@ + MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 + MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 + MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x80000000 ++ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000 ++ MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x80000000 ++ MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x80000000 ++ MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x80000000 ++ >; ++ }; ++ ++ pinctrl_audmux: audmuxgrp { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 ++ MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 ++ MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 ++ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 ++ >; ++ }; ++ ++ pinctrl_ecspi1: ecspi1grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL1__ECSPI1_MISO 0x100b1 ++ MX6QDL_PAD_KEY_ROW0__ECSPI1_MOSI 0x100b1 ++ MX6QDL_PAD_KEY_COL0__ECSPI1_SCLK 0x100b1 ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ 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_gpio_keys: gpio_keysgrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x80000000 ++ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x80000000 ++ MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x80000000 ++ >; ++ }; ++ ++ pinctrl_hdmi_cec: hdmi_cecgrp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0 ++ >; ++ }; ++ ++ pinctrl_hdmi_hdcp: hdmi_hdcpgrp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__HDMI_TX_DDC_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1 ++ MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_ipu1: ipu1grp { ++ 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_pcie: pciegrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 ++ >; ++ }; ++ ++ pinctrl_pwm1: pwm1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc2: usdhc2grp { ++ 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_usdhc3: usdhc3grp { ++ 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_usdhc4: usdhc4grp { ++ 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 ++ >; ++ }; ++ }; ++ ++ gpio_leds { ++ pinctrl_gpio_leds: gpioledsgrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000 + >; + }; + }; +@@ -212,9 +648,33 @@ + }; + }; + ++&pcie { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_pcie>; ++ reset-gpio = <&gpio7 12 0>; ++ status = "okay"; ++}; ++ ++&pcie { ++ power-on-gpio = <&gpio3 19 0>; ++ reset-gpio = <&gpio7 12 0>; ++ status = "okay"; ++}; ++ ++ + &pwm1 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_pwm0_1>; ++ pinctrl-0 = <&pinctrl_pwm1>; ++ status = "okay"; ++}; ++ ++&ldb { ++ ipu_id = <1>; ++ disp_id = <1>; ++ ext_ref = <1>; ++ mode = "sep1"; ++ sec_ipu_id = <1>; ++ sec_disp_id = <0>; + status = "okay"; + }; + +@@ -225,7 +685,16 @@ + + &uart1 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart1_1>; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&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"; + }; + +@@ -237,14 +706,14 @@ + &usbotg { + vbus-supply = <®_usb_otg_vbus>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usbotg_2>; ++ pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; + }; + + &usdhc2 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc2_1>; ++ pinctrl-0 = <&pinctrl_usdhc2>; + bus-width = <8>; + cd-gpios = <&gpio2 2 0>; + wp-gpios = <&gpio2 3 0>; +@@ -253,9 +722,47 @@ + + &usdhc3 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc3_1>; ++ pinctrl-0 = <&pinctrl_usdhc3>; + bus-width = <8>; + cd-gpios = <&gpio2 0 0>; + wp-gpios = <&gpio2 1 0>; + status = "okay"; + }; ++ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4>; ++ bus-width = <8>; ++ non-removable; ++ no-1-8-v; ++ status = "okay"; ++}; ++ ++&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>; ++ 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.14.40.orig/arch/arm/boot/dts/imx6qdl-wandboard.dtsi linux-3.14.40/arch/arm/boot/dts/imx6qdl-wandboard.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6qdl-wandboard.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6qdl-wandboard.dtsi 2015-05-01 14:57:57.491427001 -0500 +@@ -12,17 +12,21 @@ + / { + regulators { + compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; + +- reg_2p5v: 2p5v { ++ reg_2p5v: regulator@0 { + compatible = "regulator-fixed"; ++ reg = <0>; + regulator-name = "2P5V"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + +- reg_3p3v: 3p3v { ++ reg_3p3v: regulator@1 { + compatible = "regulator-fixed"; ++ reg = <1>; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; +@@ -54,14 +58,14 @@ + + &audmux { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_audmux_2>; ++ pinctrl-0 = <&pinctrl_audmux>; + status = "okay"; + }; + + &i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_i2c2_2>; ++ pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + codec: sgtl5000@0a { +@@ -77,7 +81,7 @@ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_hog>; + +- hog { ++ imx6qdl-wandboard { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0 +@@ -91,20 +95,121 @@ + MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x80000000 + >; + }; ++ ++ pinctrl_audmux: audmuxgrp { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0 ++ MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0 ++ MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0 ++ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0 ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ 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 ++ MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_spdif: spdifgrp { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_RXD0__SPDIF_OUT 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart3: uart3grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc1: usdhc1grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_usdhc2: usdhc2grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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 ++ >; ++ }; + }; + }; + + &fec { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_1>; ++ pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + phy-reset-gpios = <&gpio3 29 0>; ++ interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>, ++ <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>; + status = "okay"; + }; + + &spdif { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_spdif_3>; ++ pinctrl-0 = <&pinctrl_spdif>; + status = "okay"; + }; + +@@ -115,13 +220,13 @@ + + &uart1 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart1_1>; ++ pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; + }; + + &uart3 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart3_2>; ++ pinctrl-0 = <&pinctrl_uart3>; + fsl,uart-has-rtscts; + status = "okay"; + }; +@@ -132,7 +237,7 @@ + + &usbotg { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usbotg_1>; ++ pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + dr_mode = "peripheral"; + status = "okay"; +@@ -140,21 +245,21 @@ + + &usdhc1 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc1_2>; ++ pinctrl-0 = <&pinctrl_usdhc1>; + cd-gpios = <&gpio1 2 0>; + status = "okay"; + }; + + &usdhc2 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc2_2>; ++ pinctrl-0 = <&pinctrl_usdhc2>; + non-removable; + status = "okay"; + }; + + &usdhc3 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc3_2>; ++ pinctrl-0 = <&pinctrl_usdhc3>; + cd-gpios = <&gpio3 9 0>; + status = "okay"; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts linux-3.14.40/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts 2015-05-01 14:57:57.491427001 -0500 +@@ -0,0 +1,432 @@ ++/* ++ * Copyright 2013 Data Modul AG ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++ ++#include ++#include "imx6q.dtsi" ++ ++/ { ++ model = "Data Modul eDM-QMX6 Board"; ++ compatible = "dmo,imx6q-edmqmx6", "fsl,imx6q"; ++ ++ chosen { ++ stdout-path = &uart2; ++ }; ++ ++ aliases { ++ gpio7 = &stmpe_gpio1; ++ gpio8 = &stmpe_gpio2; ++ stmpe-i2c0 = &stmpe1; ++ stmpe-i2c1 = &stmpe2; ++ }; ++ ++ memory { ++ reg = <0x10000000 0x80000000>; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_3p3v: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_otg_switch: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "usb_otg_switch"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio7 12 0>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ reg_usb_host1: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "usb_host1_en"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ gpio = <&gpio3 31 0>; ++ enable-active-high; ++ }; ++ }; ++ ++ gpio-leds { ++ compatible = "gpio-leds"; ++ ++ led-blue { ++ label = "blue"; ++ gpios = <&stmpe_gpio1 8 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ ++ led-green { ++ label = "green"; ++ gpios = <&stmpe_gpio1 9 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ led-pink { ++ label = "pink"; ++ gpios = <&stmpe_gpio1 10 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ led-red { ++ label = "red"; ++ gpios = <&stmpe_gpio1 11 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++}; ++ ++&ecspi5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi5>; ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio1 12 0>; ++ status = "okay"; ++ ++ flash: m25p80@0 { ++ compatible = "m25p80"; ++ spi-max-frequency = <40000000>; ++ reg = <0>; ++ }; ++}; ++ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ phy-reset-gpios = <&gpio3 23 0>; ++ phy-supply = <&vgen2_1v2_eth>; ++ status = "okay"; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2 ++ &pinctrl_stmpe1 ++ &pinctrl_stmpe2 ++ &pinctrl_pfuze>; ++ status = "okay"; ++ ++ pmic: pfuze100@08 { ++ compatible = "fsl,pfuze100"; ++ reg = <0x08>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <20 8>; ++ ++ regulators { ++ sw1a_reg: sw1ab { ++ regulator-min-microvolt = <300000>; ++ regulator-max-microvolt = <1875000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ 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 = <400000>; ++ regulator-max-microvolt = <1975000>; ++ regulator-always-on; ++ }; ++ ++ swbst_reg: swbst { ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5150000>; ++ regulator-always-on; ++ }; ++ ++ 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_1v2_eth: vgen2 { ++ regulator-min-microvolt = <800000>; ++ regulator-max-microvolt = <1550000>; ++ }; ++ ++ vdd_high_in: vgen3 { ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ 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; ++ }; ++ }; ++ }; ++ ++ stmpe1: stmpe1601@40 { ++ compatible = "st,stmpe1601"; ++ reg = <0x40>; ++ interrupts = <30 0>; ++ interrupt-parent = <&gpio3>; ++ vcc-supply = <&sw2_reg>; ++ vio-supply = <&sw2_reg>; ++ ++ stmpe_gpio1: stmpe_gpio { ++ #gpio-cells = <2>; ++ compatible = "st,stmpe-gpio"; ++ }; ++ }; ++ ++ stmpe2: stmpe1601@44 { ++ compatible = "st,stmpe1601"; ++ reg = <0x44>; ++ interrupts = <2 0>; ++ interrupt-parent = <&gpio5>; ++ vcc-supply = <&sw2_reg>; ++ vio-supply = <&sw2_reg>; ++ ++ stmpe_gpio2: stmpe_gpio { ++ #gpio-cells = <2>; ++ compatible = "st,stmpe-gpio"; ++ }; ++ }; ++ ++ temp1: ad7414@4c { ++ compatible = "ad,ad7414"; ++ reg = <0x4c>; ++ }; ++ ++ temp2: ad7414@4d { ++ compatible = "ad,ad7414"; ++ reg = <0x4d>; ++ }; ++ ++ rtc: m41t62@68 { ++ compatible = "stm,m41t62"; ++ reg = <0x68>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6q-dmo-edmqmx6 { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x80000000 ++ MX6QDL_PAD_EIM_A17__GPIO2_IO21 0x80000000 ++ >; ++ }; ++ ++ pinctrl_ecspi5: ecspi5rp-1 { ++ fsl,pins = < ++ MX6QDL_PAD_SD1_DAT0__ECSPI5_MISO 0x80000000 ++ MX6QDL_PAD_SD1_CMD__ECSPI5_MOSI 0x80000000 ++ MX6QDL_PAD_SD1_CLK__ECSPI5_SCLK 0x80000000 ++ MX6QDL_PAD_SD2_DAT3__GPIO1_IO12 0x80000000 ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ fsl,pins = < ++ 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_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_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_pfuze: pfuze100grp1 { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x80000000 ++ >; ++ }; ++ ++ pinctrl_stmpe1: stmpe1grp { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_stmpe2: stmpe2grp { ++ fsl,pins = ; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_usdhc4: usdhc4grp { ++ 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 ++ >; ++ }; ++ }; ++}; ++ ++&sata { ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ vbus-supply = <®_usb_host1>; ++ disable-over-current; ++ dr_mode = "host"; ++ status = "okay"; ++}; ++ ++&usbotg { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ vmmc-supply = <®_3p3v>; ++ status = "okay"; ++}; ++ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4>; ++ vmmc-supply = <®_3p3v>; ++ non-removable; ++ bus-width = <8>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q.dtsi linux-3.14.40/arch/arm/boot/dts/imx6q.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q.dtsi 2015-05-01 14:57:57.491427001 -0500 +@@ -8,10 +8,16 @@ + * + */ + ++#include + #include "imx6q-pinfunc.h" + #include "imx6qdl.dtsi" + + / { ++ aliases { ++ ipu1 = &ipu2; ++ spi4 = &ecspi5; ++ }; ++ + cpus { + #address-cells = <1>; + #size-cells = <0>; +@@ -25,8 +31,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,12 +76,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@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 23 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 { +@@ -74,13 +154,17 @@ + #size-cells = <0>; + compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi"; + reg = <0x02018000 0x4000>; +- interrupts = <0 35 0x04>; ++ interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 116>, <&clks 116>; + clock-names = "ipg", "per"; + status = "disabled"; + }; + }; + ++ vpu@02040000 { ++ status = "okay"; ++ }; ++ + iomuxc: iomuxc@020e0000 { + compatible = "fsl,imx6q-iomuxc"; + +@@ -122,40 +206,40 @@ + }; + }; + ++ 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 209>; ++ clock-names = "mipi_pllref_clk", "mipi_cfg_clk"; ++ status = "disabled"; ++ }; ++ }; ++ + sata: sata@02200000 { + compatible = "fsl,imx6q-ahci"; + reg = <0x02200000 0x4000>; +- interrupts = <0 39 0x04>; ++ interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; + 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"; ++ interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>, ++ <0 7 IRQ_TYPE_LEVEL_HIGH>; ++ 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>; +- }; +- +- lvds-channel@1 { +- crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; +- }; +-}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gk802.dts linux-3.14.40/arch/arm/boot/dts/imx6q-gk802.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gk802.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-gk802.dts 2015-05-01 14:57:57.491427001 -0500 +@@ -0,0 +1,229 @@ ++/* ++ * Copyright (C) 2013 Philipp Zabel ++ * ++ * 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. ++ */ ++ ++/dts-v1/; ++#include "imx6q.dtsi" ++ ++/ { ++ model = "Zealz GK802"; ++ compatible = "zealz,imx6q-gk802", "fsl,imx6q"; ++ ++ aliases { ++ mxcfb0 = &mxcfb1; ++ }; ++ ++ chosen { ++ stdout-path = &uart4; ++ }; ++ ++ memory { ++ reg = <0x10000000 0x40000000>; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_3p3v: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ 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 = <&gpio2 0 0>; ++ }; ++ }; ++ ++ gpio-keys { ++ compatible = "gpio-keys"; ++ ++ recovery-button { ++ label = "recovery"; ++ gpios = <&gpio3 16 1>; ++ linux,code = <0x198>; /* KEY_RESTART */ ++ gpio-key,wakeup; ++ }; ++ ++ }; ++ ++ 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 = "hdmi"; ++ interface_pix_fmt = "RGB24"; ++ mode_str ="1920x1080M@60"; ++ default_bpp = <32>; ++ int_clk = <0>; ++ late_init = <0>; ++ status = "okay"; ++ }; ++}; ++ ++&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"; ++}; ++ ++ ++/* Internal I2C */ ++&i2c2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ clock-frequency = <100000>; ++ status = "okay"; ++ ++ /* SDMC DM2016 1024 bit EEPROM + 128 bit OTP */ ++ eeprom: dm2016@51 { ++ compatible = "sdmc,dm2016"; ++ reg = <0x51>; ++ }; ++}; ++ ++/* External I2C via HDMI */ ++&i2c3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ clock-frequency = <100000>; ++ status = "okay"; ++ ++ ddc: imx6_hdmi_i2c@50 { ++ compatible = "fsl,imx6-hdmi-i2c"; ++ reg = <0x50>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6q-gk802 { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ /* Recovery button, active-low */ ++ MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x100b1 ++ /* RTL8192CU enable GPIO, active-low */ ++ MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_uart4: uart4grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL0__UART4_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW0__UART4_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_usdhc4: usdhc4grp { ++ 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 ++ >; ++ }; ++ }; ++}; ++ ++&uart2 { ++ status = "okay"; ++}; ++ ++&uart4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart4>; ++ status = "okay"; ++}; ++ ++/* External USB-A port (USBOTG) */ ++&usbotg { ++ phy_type = "utmi"; ++ dr_mode = "host"; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++/* Internal USB port (USBH1), connected to RTL8192CU */ ++&usbh1 { ++ phy_type = "utmi"; ++ dr_mode = "host"; ++ vbus-supply = <®_usb_h1_vbus>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++/* External microSD */ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ bus-width = <4>; ++ cd-gpios = <&gpio6 11 0>; ++ vmmc-supply = <®_3p3v>; ++ status = "okay"; ++}; ++ ++/* Internal microSD */ ++&usdhc4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc4>; ++ bus-width = <4>; ++ vmmc-supply = <®_3p3v>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gw51xx.dts linux-3.14.40/arch/arm/boot/dts/imx6q-gw51xx.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gw51xx.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-gw51xx.dts 2015-05-01 14:57:57.491427001 -0500 +@@ -0,0 +1,19 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6q.dtsi" ++#include "imx6qdl-gw54xx.dtsi" ++ ++/ { ++ model = "Gateworks Ventana i.MX6 Quad GW51XX"; ++ compatible = "gw,imx6q-gw51xx", "gw,ventana", "fsl,imx6q"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gw52xx.dts linux-3.14.40/arch/arm/boot/dts/imx6q-gw52xx.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gw52xx.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-gw52xx.dts 2015-05-01 14:57:57.491427001 -0500 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6q.dtsi" ++#include "imx6qdl-gw52xx.dtsi" ++ ++/ { ++ model = "Gateworks Ventana i.MX6 Quad GW52XX"; ++ compatible = "gw,imx6q-gw52xx", "gw,ventana", "fsl,imx6q"; ++}; ++ ++&sata { ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gw53xx.dts linux-3.14.40/arch/arm/boot/dts/imx6q-gw53xx.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gw53xx.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-gw53xx.dts 2015-05-01 14:57:57.491427001 -0500 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6q.dtsi" ++#include "imx6qdl-gw53xx.dtsi" ++ ++/ { ++ model = "Gateworks Ventana i.MX6 Quad GW53XX"; ++ compatible = "gw,imx6q-gw53xx", "gw,ventana", "fsl,imx6q"; ++}; ++ ++&sata { ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gw5400-a.dts linux-3.14.40/arch/arm/boot/dts/imx6q-gw5400-a.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gw5400-a.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-gw5400-a.dts 2015-05-01 14:57:57.491427001 -0500 +@@ -0,0 +1,543 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6q.dtsi" ++ ++/ { ++ model = "Gateworks Ventana GW5400-A"; ++ compatible = "gw,imx6q-gw5400-a", "gw,ventana", "fsl,imx6q"; ++ ++ /* these are used by bootloader for disabling nodes */ ++ aliases { ++ ethernet0 = &fec; ++ ethernet1 = ð1; ++ i2c0 = &i2c1; ++ i2c1 = &i2c2; ++ i2c2 = &i2c3; ++ led0 = &led0; ++ led1 = &led1; ++ led2 = &led2; ++ sky2 = ð1; ++ ssi0 = &ssi1; ++ spi0 = &ecspi1; ++ usb0 = &usbh1; ++ usb1 = &usbotg; ++ usdhc2 = &usdhc3; ++ }; ++ ++ chosen { ++ bootargs = "console=ttymxc1,115200"; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ led0: user1 { ++ label = "user1"; ++ gpios = <&gpio4 6 0>; /* 102 -> MX6_PANLEDG */ ++ default-state = "on"; ++ linux,default-trigger = "heartbeat"; ++ }; ++ ++ led1: user2 { ++ label = "user2"; ++ gpios = <&gpio4 10 0>; /* 106 -> MX6_PANLEDR */ ++ default-state = "off"; ++ }; ++ ++ led2: user3 { ++ label = "user3"; ++ gpios = <&gpio4 15 1>; /* 111 -> MX6_LOCLED# */ ++ default-state = "off"; ++ }; ++ }; ++ ++ memory { ++ reg = <0x10000000 0x40000000>; ++ }; ++ ++ pps { ++ compatible = "pps-gpio"; ++ gpios = <&gpio1 5 0>; ++ status = "okay"; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_1p0v: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "1P0V"; ++ regulator-min-microvolt = <1000000>; ++ regulator-max-microvolt = <1000000>; ++ regulator-always-on; ++ }; ++ ++ reg_3p3v: regulator@1 { ++ compatible = "regulator-fixed"; ++ reg = <1>; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_h1_vbus: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "usb_h1_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ reg_usb_otg_vbus: regulator@3 { ++ compatible = "regulator-fixed"; ++ reg = <3>; ++ regulator-name = "usb_otg_vbus"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ gpio = <&gpio3 22 0>; ++ enable-active-high; ++ }; ++ }; ++ ++ sound { ++ compatible = "fsl,imx6q-sabrelite-sgtl5000", ++ "fsl,imx-audio-sgtl5000"; ++ model = "imx6q-sabrelite-sgtl5000"; ++ ssi-controller = <&ssi1>; ++ audio-codec = <&codec>; ++ audio-routing = ++ "MIC_IN", "Mic Jack", ++ "Mic Jack", "Mic Bias", ++ "Headphone Jack", "HP_OUT"; ++ mux-int-port = <1>; ++ mux-ext-port = <4>; ++ }; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux>; ++ status = "okay"; ++}; ++ ++&ecspi1 { ++ fsl,spi-num-chipselects = <1>; ++ cs-gpios = <&gpio3 19 0>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_ecspi1>; ++ status = "okay"; ++ ++ flash: m25p80@0 { ++ compatible = "sst,w25q256"; ++ spi-max-frequency = <30000000>; ++ reg = <0>; ++ }; ++}; ++ ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ phy-reset-gpios = <&gpio1 30 0>; ++ status = "okay"; ++}; ++ ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ status = "okay"; ++ ++ eeprom1: eeprom@50 { ++ compatible = "atmel,24c02"; ++ reg = <0x50>; ++ pagesize = <16>; ++ }; ++ ++ eeprom2: eeprom@51 { ++ compatible = "atmel,24c02"; ++ reg = <0x51>; ++ pagesize = <16>; ++ }; ++ ++ eeprom3: eeprom@52 { ++ compatible = "atmel,24c02"; ++ reg = <0x52>; ++ pagesize = <16>; ++ }; ++ ++ eeprom4: eeprom@53 { ++ compatible = "atmel,24c02"; ++ reg = <0x53>; ++ pagesize = <16>; ++ }; ++ ++ gpio: pca9555@23 { ++ compatible = "nxp,pca9555"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ hwmon: gsc@29 { ++ compatible = "gw,gsp"; ++ reg = <0x29>; ++ }; ++ ++ rtc: ds1672@68 { ++ compatible = "dallas,ds1672"; ++ reg = <0x68>; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ 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 = <3950000>; ++ 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; ++ }; ++ }; ++ }; ++ ++ pciswitch: pex8609@3f { ++ compatible = "plx,pex8609"; ++ reg = <0x3f>; ++ }; ++ ++ pciclkgen: si52147@6b { ++ compatible = "sil,si52147"; ++ reg = <0x6b>; ++ }; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3>; ++ status = "okay"; ++ ++ accelerometer: mma8450@1c { ++ compatible = "fsl,mma8450"; ++ reg = <0x1c>; ++ }; ++ ++ codec: sgtl5000@0a { ++ compatible = "fsl,sgtl5000"; ++ reg = <0x0a>; ++ clocks = <&clks 201>; ++ VDDA-supply = <&sw4_reg>; ++ VDDIO-supply = <®_3p3v>; ++ }; ++ ++ hdmiin: adv7611@4c { ++ compatible = "adi,adv7611"; ++ reg = <0x4c>; ++ }; ++ ++ touchscreen: egalax_ts@04 { ++ compatible = "eeti,egalax_ts"; ++ reg = <0x04>; ++ interrupt-parent = <&gpio7>; ++ interrupts = <12 2>; /* gpio7_12 active low */ ++ wakeup-gpios = <&gpio7 12 0>; ++ }; ++ ++ videoout: adv7393@2a { ++ compatible = "adi,adv7393"; ++ reg = <0x2a>; ++ }; ++ ++ videoin: adv7180@20 { ++ compatible = "adi,adv7180"; ++ reg = <0x20>; ++ }; ++}; ++ ++&iomuxc { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_hog>; ++ ++ imx6q-gw5400-a { ++ pinctrl_hog: hoggrp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x80000000 /* OTG_PWR_EN */ ++ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x80000000 /* SPINOR_CS0# */ ++ MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x80000000 /* PCIE IRQ */ ++ MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 /* PCIE RST */ ++ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000130b0 /* AUD4_MCK */ ++ MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x80000000 /* GPS_PPS */ ++ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x80000000 /* TOUCH_IRQ# */ ++ MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x80000000 /* user1 led */ ++ MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x80000000 /* user2 led */ ++ MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x80000000 /* user3 led */ ++ MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x80000000 /* USBHUB_RST# */ ++ MX6QDL_PAD_SD1_DAT3__GPIO1_IO21 0x80000000 /* MIPI_DIO */ ++ >; ++ }; ++ ++ pinctrl_audmux: audmuxgrp { ++ fsl,pins = < ++ MX6QDL_PAD_SD2_DAT0__AUD4_RXD 0x130b0 ++ MX6QDL_PAD_SD2_DAT3__AUD4_TXC 0x130b0 ++ MX6QDL_PAD_SD2_DAT2__AUD4_TXD 0x110b0 ++ MX6QDL_PAD_SD2_DAT1__AUD4_TXFS 0x130b0 ++ >; ++ }; ++ ++ pinctrl_ecspi1: ecspi1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1 ++ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1 ++ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1 ++ >; ++ }; ++ ++ pinctrl_enet: enetgrp { ++ fsl,pins = < ++ 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_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_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1 ++ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1 ++ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_i2c3: i2c3grp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1 ++ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_uart5: uart5grp { ++ fsl,pins = < ++ MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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 ++ >; ++ }; ++ }; ++}; ++ ++&ldb { ++ status = "okay"; ++}; ++ ++&pcie { ++ reset-gpio = <&gpio1 29 0>; ++ status = "okay"; ++ ++ eth1: sky2@8 { /* MAC/PHY on bus 8 */ ++ compatible = "marvell,sky2"; ++ }; ++}; ++ ++&ssi1 { ++ fsl,mode = "i2s-slave"; ++ status = "okay"; ++}; ++ ++&uart1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart1>; ++ status = "okay"; ++}; ++ ++&uart2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart2>; ++ status = "okay"; ++}; ++ ++&uart5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_uart5>; ++ status = "okay"; ++}; ++ ++&usbotg { ++ vbus-supply = <®_usb_otg_vbus>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usbotg>; ++ disable-over-current; ++ status = "okay"; ++}; ++ ++&usbh1 { ++ vbus-supply = <®_usb_h1_vbus>; ++ status = "okay"; ++}; ++ ++&usdhc3 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ cd-gpios = <&gpio7 0 0>; ++ vmmc-supply = <®_3p3v>; ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gw54xx.dts linux-3.14.40/arch/arm/boot/dts/imx6q-gw54xx.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-gw54xx.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-gw54xx.dts 2015-05-01 14:57:57.491427001 -0500 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright 2013 Gateworks Corporation ++ * ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6q.dtsi" ++#include "imx6qdl-gw54xx.dtsi" ++ ++/ { ++ model = "Gateworks Ventana i.MX6 Quad GW54XX"; ++ compatible = "gw,imx6q-gw54xx", "gw,ventana", "fsl,imx6q"; ++}; ++ ++&sata { ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-hummingboard.dts linux-3.14.40/arch/arm/boot/dts/imx6q-hummingboard.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-hummingboard.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-hummingboard.dts 2015-05-01 14:57:57.491427001 -0500 +@@ -0,0 +1,21 @@ ++/* ++ * Copyright (C) 2014 Rabeeh Khoury (rabeeh@solid-run.com) ++ * Based on work by Russell King ++ */ ++/dts-v1/; ++ ++#include "imx6q.dtsi" ++#include "imx6qdl-hummingboard.dtsi" ++ ++/ { ++ model = "SolidRun HummingBoard Dual/Quad"; ++ compatible = "solidrun,hummingboard/q", "fsl,imx6q"; ++}; ++ ++&sata { ++ status = "okay"; ++ fsl,transmit-level-mV = <1104>; ++ fsl,transmit-boost-mdB = <0>; ++ fsl,transmit-atten-16ths = <9>; ++ fsl,no-spread-spectrum; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-nitrogen6x.dts linux-3.14.40/arch/arm/boot/dts/imx6q-nitrogen6x.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-nitrogen6x.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-nitrogen6x.dts 2015-05-01 14:57:57.491427001 -0500 +@@ -0,0 +1,25 @@ ++/* ++ * Copyright 2013 Boundary Devices, Inc. ++ * 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 ++ */ ++ ++/dts-v1/; ++#include "imx6q.dtsi" ++#include "imx6qdl-nitrogen6x.dtsi" ++ ++/ { ++ model = "Freescale i.MX6 Quad Nitrogen6x Board"; ++ compatible = "fsl,imx6q-nitrogen6x", "fsl,imx6q"; ++}; ++ ++&sata { ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-phytec-pbab01.dts linux-3.14.40/arch/arm/boot/dts/imx6q-phytec-pbab01.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-phytec-pbab01.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-phytec-pbab01.dts 2015-05-01 14:57:57.491427001 -0500 +@@ -11,24 +11,17 @@ + + /dts-v1/; + #include "imx6q-phytec-pfla02.dtsi" ++#include "imx6qdl-phytec-pbab01.dtsi" + + / { + model = "Phytec phyFLEX-i.MX6 Quad Carrier-Board"; + compatible = "phytec,imx6q-pbab01", "phytec,imx6q-pfla02", "fsl,imx6q"; +-}; +- +-&fec { +- status = "okay"; +-}; +- +-&uart4 { +- status = "okay"; +-}; + +-&usdhc2 { +- status = "okay"; ++ chosen { ++ stdout-path = &uart4; ++ }; + }; + +-&usdhc3 { +- status = "okay"; ++&sata { ++ status = "okay"; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi linux-3.14.40/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-phytec-pfla02.dtsi 2015-05-01 14:57:57.495427001 -0500 +@@ -10,171 +10,13 @@ + */ + + #include "imx6q.dtsi" ++#include "imx6qdl-phytec-pfla02.dtsi" + + / { +- model = "Phytec phyFLEX-i.MX6 Ouad"; ++ model = "Phytec phyFLEX-i.MX6 Quad"; + compatible = "phytec,imx6q-pfla02", "fsl,imx6q"; + + memory { + reg = <0x10000000 0x80000000>; + }; + }; +- +-&ecspi3 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_ecspi3_1>; +- status = "okay"; +- fsl,spi-num-chipselects = <1>; +- cs-gpios = <&gpio4 24 0>; +- +- flash@0 { +- compatible = "m25p80"; +- spi-max-frequency = <20000000>; +- reg = <0>; +- }; +-}; +- +-&i2c1 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_i2c1_1>; +- status = "okay"; +- +- eeprom@50 { +- compatible = "atmel,24c32"; +- reg = <0x50>; +- }; +- +- pmic@58 { +- compatible = "dialog,da9063"; +- reg = <0x58>; +- interrupt-parent = <&gpio4>; +- interrupts = <17 0x8>; /* active-low GPIO4_17 */ +- +- regulators { +- vddcore_reg: bcore1 { +- regulator-min-microvolt = <730000>; +- regulator-max-microvolt = <1380000>; +- regulator-always-on; +- }; +- +- vddsoc_reg: bcore2 { +- regulator-min-microvolt = <730000>; +- regulator-max-microvolt = <1380000>; +- regulator-always-on; +- }; +- +- vdd_ddr3_reg: bpro { +- regulator-min-microvolt = <1500000>; +- regulator-max-microvolt = <1500000>; +- regulator-always-on; +- }; +- +- vdd_3v3_reg: bperi { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- regulator-always-on; +- }; +- +- vdd_buckmem_reg: bmem { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- regulator-always-on; +- }; +- +- vdd_eth_reg: bio { +- regulator-min-microvolt = <1200000>; +- regulator-max-microvolt = <1200000>; +- regulator-always-on; +- }; +- +- vdd_eth_io_reg: ldo4 { +- regulator-min-microvolt = <2500000>; +- regulator-max-microvolt = <2500000>; +- regulator-always-on; +- }; +- +- vdd_mx6_snvs_reg: ldo5 { +- regulator-min-microvolt = <3000000>; +- regulator-max-microvolt = <3000000>; +- regulator-always-on; +- }; +- +- vdd_3v3_pmic_io_reg: ldo6 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- regulator-always-on; +- }; +- +- vdd_sd0_reg: ldo9 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- vdd_sd1_reg: ldo10 { +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- }; +- +- vdd_mx6_high_reg: ldo11 { +- regulator-min-microvolt = <3000000>; +- regulator-max-microvolt = <3000000>; +- regulator-always-on; +- }; +- }; +- }; +-}; +- +-&iomuxc { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_hog>; +- +- hog { +- pinctrl_hog: hoggrp { +- fsl,pins = < +- MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000 +- MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */ +- MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x80000000 /* PMIC interrupt */ +- >; +- }; +- }; +- +- pfla02 { +- pinctrl_usdhc3_pfla02: usdhc3grp-pfla02 { +- fsl,pins = < +- MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x80000000 +- MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000 +- >; +- }; +- }; +-}; +- +-&fec { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_3>; +- phy-mode = "rgmii"; +- phy-reset-gpios = <&gpio3 23 0>; +- status = "disabled"; +-}; +- +-&uart4 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart4_1>; +- status = "disabled"; +-}; +- +-&usdhc2 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc2_2>; +- cd-gpios = <&gpio1 4 0>; +- wp-gpios = <&gpio1 2 0>; +- status = "disabled"; +-}; +- +-&usdhc3 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc3_2 +- &pinctrl_usdhc3_pfla02>; +- cd-gpios = <&gpio1 27 0>; +- wp-gpios = <&gpio1 29 0>; +- status = "disabled"; +-}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-pinfunc.h linux-3.14.40/arch/arm/boot/dts/imx6q-pinfunc.h +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-pinfunc.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-pinfunc.h 2015-05-01 14:57:57.495427001 -0500 +@@ -673,6 +673,7 @@ + #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__ENET_IRQ 0x230 0x600 0x03c 0x11 0xff000609 + #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 +@@ -1024,6 +1025,7 @@ + #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__OSC32K_32K_OUT 0x350 0x738 0x000 0x2 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 +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-sabreauto.dts linux-3.14.40/arch/arm/boot/dts/imx6q-sabreauto.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-sabreauto.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-sabreauto.dts 2015-05-01 14:57:57.495427001 -0500 +@@ -20,6 +20,22 @@ + compatible = "fsl,imx6q-sabreauto", "fsl,imx6q"; + }; + ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; ++ ++&mxcfb3 { ++ status = "okay"; ++}; ++ ++&mxcfb4 { ++ status = "okay"; ++}; ++ + &sata { + status = "okay"; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-sabrelite.dts linux-3.14.40/arch/arm/boot/dts/imx6q-sabrelite.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-sabrelite.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-sabrelite.dts 2015-05-01 14:57:57.495427001 -0500 +@@ -12,189 +12,13 @@ + + /dts-v1/; + #include "imx6q.dtsi" ++#include "imx6qdl-sabrelite.dtsi" + + / { + model = "Freescale i.MX6 Quad SABRE Lite Board"; + compatible = "fsl,imx6q-sabrelite", "fsl,imx6q"; +- +- memory { +- reg = <0x10000000 0x40000000>; +- }; +- +- regulators { +- compatible = "simple-bus"; +- +- reg_2p5v: 2p5v { +- compatible = "regulator-fixed"; +- regulator-name = "2P5V"; +- regulator-min-microvolt = <2500000>; +- regulator-max-microvolt = <2500000>; +- regulator-always-on; +- }; +- +- reg_3p3v: 3p3v { +- compatible = "regulator-fixed"; +- regulator-name = "3P3V"; +- regulator-min-microvolt = <3300000>; +- 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; +- }; +- }; +- +- sound { +- compatible = "fsl,imx6q-sabrelite-sgtl5000", +- "fsl,imx-audio-sgtl5000"; +- model = "imx6q-sabrelite-sgtl5000"; +- ssi-controller = <&ssi1>; +- audio-codec = <&codec>; +- audio-routing = +- "MIC_IN", "Mic Jack", +- "Mic Jack", "Mic Bias", +- "Headphone Jack", "HP_OUT"; +- mux-int-port = <1>; +- mux-ext-port = <4>; +- }; +-}; +- +-&audmux { +- status = "okay"; +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_audmux_1>; +-}; +- +-&ecspi1 { +- fsl,spi-num-chipselects = <1>; +- cs-gpios = <&gpio3 19 0>; +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_ecspi1_1>; +- status = "okay"; +- +- flash: m25p80@0 { +- compatible = "sst,sst25vf016b"; +- spi-max-frequency = <20000000>; +- reg = <0>; +- }; +-}; +- +-&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 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_hog>; +- +- hog { +- pinctrl_hog: hoggrp { +- fsl,pins = < +- 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 +- >; +- }; +- }; +-}; +- +-&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"; +-}; +- +-&usbotg { +- vbus-supply = <®_usb_otg_vbus>; +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usbotg_1>; +- disable-over-current; +- status = "okay"; +-}; +- +-&usdhc3 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc3_2>; +- cd-gpios = <&gpio7 0 0>; +- wp-gpios = <&gpio7 1 0>; +- vmmc-supply = <®_3p3v>; +- status = "okay"; +-}; +- +-&usdhc4 { +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc4_2>; +- cd-gpios = <&gpio2 6 0>; +- wp-gpios = <&gpio2 7 0>; +- vmmc-supply = <®_3p3v>; +- status = "okay"; +-}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-sabresd.dts linux-3.14.40/arch/arm/boot/dts/imx6q-sabresd.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-sabresd.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-sabresd.dts 2015-05-01 14:57:57.495427001 -0500 +@@ -23,3 +23,19 @@ + &sata { + status = "okay"; + }; ++ ++&mxcfb1 { ++ status = "okay"; ++}; ++ ++&mxcfb2 { ++ status = "okay"; ++}; ++ ++&mxcfb3 { ++ status = "okay"; ++}; ++ ++&mxcfb4 { ++ status = "okay"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts linux-3.14.40/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-sabresd-hdcp.dts 2015-05-01 14:57:57.495427001 -0500 +@@ -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>; ++ fsl,hdcp; ++}; ++ ++&i2c2 { ++ status = "disable"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-sbc6x.dts linux-3.14.40/arch/arm/boot/dts/imx6q-sbc6x.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-sbc6x.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-sbc6x.dts 2015-05-01 14:57:57.495427001 -0500 +@@ -17,28 +17,78 @@ + }; + }; + ++ + &fec { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_enet_1>; ++ pinctrl-0 = <&pinctrl_enet>; + phy-mode = "rgmii"; + status = "okay"; + }; + ++&iomuxc { ++ imx6q-sbc6x { ++ pinctrl_enet: enetgrp { ++ 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_uart1: uart1grp { ++ fsl,pins = < ++ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg: usbotggrp { ++ fsl,pins = < ++ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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 ++ >; ++ }; ++ }; ++}; ++ + &uart1 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart1_1>; ++ pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; + }; + + &usbotg { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usbotg_1>; ++ pinctrl-0 = <&pinctrl_usbotg>; + disable-over-current; + status = "okay"; + }; + + &usdhc3 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc3_2>; ++ pinctrl-0 = <&pinctrl_usdhc3>; + status = "okay"; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6q-udoo.dts linux-3.14.40/arch/arm/boot/dts/imx6q-udoo.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6q-udoo.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6q-udoo.dts 2015-05-01 14:57:57.495427001 -0500 +@@ -16,24 +16,78 @@ + model = "Udoo i.MX6 Quad Board"; + compatible = "udoo,imx6q-udoo", "fsl,imx6q"; + ++ chosen { ++ stdout-path = &uart2; ++ }; ++ + memory { + reg = <0x10000000 0x40000000>; + }; + }; + ++&fec { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_enet>; ++ phy-mode = "rgmii"; ++ status = "okay"; ++}; ++ ++&iomuxc { ++ imx6q-udoo { ++ pinctrl_enet: enetgrp { ++ fsl,pins = < ++ 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_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_ENET_MDIO__ENET_MDIO 0x1b0b0 ++ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0 ++ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8 ++ >; ++ }; ++ ++ pinctrl_uart2: uart2grp { ++ fsl,pins = < ++ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1 ++ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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 ++ >; ++ }; ++ }; ++}; ++ + &sata { + status = "okay"; + }; + + &uart2 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart2_1>; ++ pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; + }; + + &usdhc3 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usdhc3_2>; ++ pinctrl-0 = <&pinctrl_usdhc3>; + non-removable; + status = "okay"; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6sl.dtsi linux-3.14.40/arch/arm/boot/dts/imx6sl.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6sl.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6sl.dtsi 2015-05-01 14:57:57.495427001 -0500 +@@ -7,12 +7,14 @@ + * + */ + ++#include + #include "skeleton.dtsi" + #include "imx6sl-pinfunc.h" + #include + + / { + aliases { ++ ethernet0 = &fec; + gpio0 = &gpio1; + gpio1 = &gpio2; + gpio2 = &gpio3; +@@ -27,25 +29,46 @@ + spi1 = &ecspi2; + spi2 = &ecspi3; + spi3 = &ecspi4; ++ usbphy0 = &usbphy1; ++ usbphy1 = &usbphy2; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + +- cpu@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>; +@@ -57,15 +80,21 @@ + + ckil { + compatible = "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <32768>; + }; + + osc { + compatible = "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <24000000>; + }; + }; + ++ pu_dummy: pudummy_reg { ++ compatible = "fsl,imx6-dummy-pureg"; /* only used in ldo-bypass */ ++ }; ++ + soc { + #address-cells = <1>; + #size-cells = <1>; +@@ -73,19 +102,45 @@ + interrupt-parent = <&intc>; + ranges; + ++ ocram: sram@00900000 { ++ compatible = "mmio-sram"; ++ reg = <0x00900000 0x20000>; ++ clocks = <&clks IMX6SL_CLK_OCRAM>; ++ }; ++ ++ 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>; ++ interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>; + cache-unified; + cache-level = <2>; + arm,tag-latency = <4 2 3>; + arm,data-latency = <4 2 3>; ++ arm,dynamic-clk-gating; ++ arm,standby-mode; + }; + + pmu { + compatible = "arm,cortex-a9-pmu"; +- interrupts = <0 94 0x04>; ++ interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>; + }; + + aips1: aips-bus@02000000 { +@@ -104,7 +159,7 @@ + + spdif: spdif@02004000 { + reg = <0x02004000 0x4000>; +- interrupts = <0 52 0x04>; ++ interrupts = <0 52 IRQ_TYPE_LEVEL_HIGH>; + }; + + ecspi1: ecspi@02008000 { +@@ -112,7 +167,7 @@ + #size-cells = <0>; + compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; + reg = <0x02008000 0x4000>; +- interrupts = <0 31 0x04>; ++ interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_ECSPI1>, + <&clks IMX6SL_CLK_ECSPI1>; + clock-names = "ipg", "per"; +@@ -124,7 +179,7 @@ + #size-cells = <0>; + compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; + reg = <0x0200c000 0x4000>; +- interrupts = <0 32 0x04>; ++ interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_ECSPI2>, + <&clks IMX6SL_CLK_ECSPI2>; + clock-names = "ipg", "per"; +@@ -136,7 +191,7 @@ + #size-cells = <0>; + compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; + reg = <0x02010000 0x4000>; +- interrupts = <0 33 0x04>; ++ interrupts = <0 33 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_ECSPI3>, + <&clks IMX6SL_CLK_ECSPI3>; + clock-names = "ipg", "per"; +@@ -148,7 +203,7 @@ + #size-cells = <0>; + compatible = "fsl,imx6sl-ecspi", "fsl,imx51-ecspi"; + reg = <0x02014000 0x4000>; +- interrupts = <0 34 0x04>; ++ interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_ECSPI4>, + <&clks IMX6SL_CLK_ECSPI4>; + clock-names = "ipg", "per"; +@@ -159,7 +214,7 @@ + compatible = "fsl,imx6sl-uart", + "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02018000 0x4000>; +- interrupts = <0 30 0x04>; ++ interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_UART>, + <&clks IMX6SL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; +@@ -172,7 +227,7 @@ + compatible = "fsl,imx6sl-uart", + "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02020000 0x4000>; +- interrupts = <0 26 0x04>; ++ interrupts = <0 26 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_UART>, + <&clks IMX6SL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; +@@ -185,7 +240,7 @@ + compatible = "fsl,imx6sl-uart", + "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02024000 0x4000>; +- interrupts = <0 27 0x04>; ++ interrupts = <0 27 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_UART>, + <&clks IMX6SL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; +@@ -195,9 +250,11 @@ + }; + + ssi1: ssi@02028000 { +- compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; ++ compatible = "fsl,imx6sl-ssi", ++ "fsl,imx51-ssi", ++ "fsl,imx21-ssi"; + reg = <0x02028000 0x4000>; +- interrupts = <0 46 0x04>; ++ interrupts = <0 46 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_SSI1>; + dmas = <&sdma 37 1 0>, + <&sdma 38 1 0>; +@@ -207,9 +264,11 @@ + }; + + ssi2: ssi@0202c000 { +- compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; ++ compatible = "fsl,imx6sl-ssi", ++ "fsl,imx51-ssi", ++ "fsl,imx21-ssi"; + reg = <0x0202c000 0x4000>; +- interrupts = <0 47 0x04>; ++ interrupts = <0 47 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_SSI2>; + dmas = <&sdma 41 1 0>, + <&sdma 42 1 0>; +@@ -219,9 +278,11 @@ + }; + + ssi3: ssi@02030000 { +- compatible = "fsl,imx6sl-ssi","fsl,imx21-ssi"; ++ compatible = "fsl,imx6sl-ssi", ++ "fsl,imx51-ssi", ++ "fsl,imx21-ssi"; + reg = <0x02030000 0x4000>; +- interrupts = <0 48 0x04>; ++ interrupts = <0 48 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_SSI3>; + dmas = <&sdma 45 1 0>, + <&sdma 46 1 0>; +@@ -234,7 +295,7 @@ + compatible = "fsl,imx6sl-uart", + "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02034000 0x4000>; +- interrupts = <0 28 0x04>; ++ interrupts = <0 28 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_UART>, + <&clks IMX6SL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; +@@ -247,7 +308,7 @@ + compatible = "fsl,imx6sl-uart", + "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02038000 0x4000>; +- interrupts = <0 29 0x04>; ++ interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_UART>, + <&clks IMX6SL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; +@@ -261,7 +322,7 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; + reg = <0x02080000 0x4000>; +- interrupts = <0 83 0x04>; ++ interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_PWM1>, + <&clks IMX6SL_CLK_PWM1>; + clock-names = "ipg", "per"; +@@ -271,7 +332,7 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; + reg = <0x02084000 0x4000>; +- interrupts = <0 84 0x04>; ++ interrupts = <0 84 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_PWM2>, + <&clks IMX6SL_CLK_PWM2>; + clock-names = "ipg", "per"; +@@ -281,7 +342,7 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; + reg = <0x02088000 0x4000>; +- interrupts = <0 85 0x04>; ++ interrupts = <0 85 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_PWM3>, + <&clks IMX6SL_CLK_PWM3>; + clock-names = "ipg", "per"; +@@ -291,7 +352,7 @@ + #pwm-cells = <2>; + compatible = "fsl,imx6sl-pwm", "fsl,imx27-pwm"; + reg = <0x0208c000 0x4000>; +- interrupts = <0 86 0x04>; ++ interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_PWM4>, + <&clks IMX6SL_CLK_PWM4>; + clock-names = "ipg", "per"; +@@ -300,7 +361,7 @@ + gpt: gpt@02098000 { + compatible = "fsl,imx6sl-gpt"; + reg = <0x02098000 0x4000>; +- interrupts = <0 55 0x04>; ++ interrupts = <0 55 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_GPT>, + <&clks IMX6SL_CLK_GPT_SERIAL>; + clock-names = "ipg", "per"; +@@ -309,7 +370,8 @@ + gpio1: gpio@0209c000 { + compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; + reg = <0x0209c000 0x4000>; +- interrupts = <0 66 0x04 0 67 0x04>; ++ interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>, ++ <0 67 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -319,7 +381,8 @@ + gpio2: gpio@020a0000 { + compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; + reg = <0x020a0000 0x4000>; +- interrupts = <0 68 0x04 0 69 0x04>; ++ interrupts = <0 68 IRQ_TYPE_LEVEL_HIGH>, ++ <0 69 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -329,7 +392,8 @@ + gpio3: gpio@020a4000 { + compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; + reg = <0x020a4000 0x4000>; +- interrupts = <0 70 0x04 0 71 0x04>; ++ interrupts = <0 70 IRQ_TYPE_LEVEL_HIGH>, ++ <0 71 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -339,7 +403,8 @@ + gpio4: gpio@020a8000 { + compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; + reg = <0x020a8000 0x4000>; +- interrupts = <0 72 0x04 0 73 0x04>; ++ interrupts = <0 72 IRQ_TYPE_LEVEL_HIGH>, ++ <0 73 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -349,7 +414,8 @@ + gpio5: gpio@020ac000 { + compatible = "fsl,imx6sl-gpio", "fsl,imx35-gpio"; + reg = <0x020ac000 0x4000>; +- interrupts = <0 74 0x04 0 75 0x04>; ++ interrupts = <0 74 IRQ_TYPE_LEVEL_HIGH>, ++ <0 75 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; +@@ -357,21 +423,23 @@ + }; + + kpp: kpp@020b8000 { ++ compatible = "fsl,imx6sl-kpp", "fsl,imx21-kpp"; + reg = <0x020b8000 0x4000>; +- interrupts = <0 82 0x04>; ++ interrupts = <0 82 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SL_CLK_DUMMY>; + }; + + wdog1: wdog@020bc000 { + compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt"; + reg = <0x020bc000 0x4000>; +- interrupts = <0 80 0x04>; ++ interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_DUMMY>; + }; + + wdog2: wdog@020c0000 { + compatible = "fsl,imx6sl-wdt", "fsl,imx21-wdt"; + reg = <0x020c0000 0x4000>; +- interrupts = <0 81 0x04>; ++ interrupts = <0 81 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_DUMMY>; + status = "disabled"; + }; +@@ -379,7 +447,8 @@ + clks: ccm@020c4000 { + compatible = "fsl,imx6sl-ccm"; + reg = <0x020c4000 0x4000>; +- interrupts = <0 87 0x04 0 88 0x04>; ++ interrupts = <0 87 IRQ_TYPE_LEVEL_HIGH>, ++ <0 88 IRQ_TYPE_LEVEL_HIGH>; + #clock-cells = <1>; + }; + +@@ -388,7 +457,9 @@ + "fsl,imx6q-anatop", + "syscon", "simple-bus"; + reg = <0x020c8000 0x1000>; +- interrupts = <0 49 0x04 0 54 0x04 0 127 0x04>; ++ interrupts = <0 49 IRQ_TYPE_LEVEL_HIGH>, ++ <0 54 IRQ_TYPE_LEVEL_HIGH>, ++ <0 127 IRQ_TYPE_LEVEL_HIGH>; + + regulator-1p1@110 { + compatible = "fsl,anatop-regulator"; +@@ -434,7 +505,7 @@ + + reg_arm: regulator-vddcore@140 { + compatible = "fsl,anatop-regulator"; +- regulator-name = "cpu"; ++ regulator-name = "vddarm"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1450000>; + regulator-always-on; +@@ -454,7 +525,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>; +@@ -484,18 +554,34 @@ + }; + }; + ++ 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>; ++ interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; + 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>; ++ interrupts = <0 45 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_USBPHY2>; ++ fsl,anatop = <&anatop>; ++ }; ++ ++ usbphy_nop1: usbphy_nop1 { ++ compatible = "usb-nop-xceiv"; ++ clocks = <&clks IMX6SL_CLK_USBPHY1>; ++ clock-names = "main_clk"; + }; + + snvs@020cc000 { +@@ -507,271 +593,165 @@ + snvs-rtc-lp@34 { + compatible = "fsl,sec-v4.0-mon-rtc-lp"; + reg = <0x34 0x58>; +- interrupts = <0 19 0x04 0 20 0x04>; ++ interrupts = <0 19 IRQ_TYPE_LEVEL_HIGH>, ++ <0 20 IRQ_TYPE_LEVEL_HIGH>; + }; +- }; +- +- 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>; +- }; +- +- gpc: gpc@020dc000 { +- compatible = "fsl,imx6sl-gpc", "fsl,imx6q-gpc"; +- reg = <0x020dc000 0x4000>; +- interrupts = <0 89 0x04>; +- }; +- +- gpr: iomuxc-gpr@020e0000 { +- compatible = "fsl,imx6sl-iomuxc-gpr", +- "fsl,imx6q-iomuxc-gpr", "syscon"; +- reg = <0x020e0000 0x38>; +- }; +- +- iomuxc: iomuxc@020e0000 { +- compatible = "fsl,imx6sl-iomuxc"; +- reg = <0x020e0000 0x4000>; +- +- ecspi1 { +- pinctrl_ecspi1_1: ecspi1grp-1 { ++ csi { ++ pinctrl_csi_0: csigrp-0 { + fsl,pins = < +- MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO 0x100b1 +- MX6SL_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x100b1 +- MX6SL_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x100b1 ++ 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 + >; + }; + }; + +- fec { +- pinctrl_fec_1: fecgrp-1 { ++ i2c1 { ++ pinctrl_i2c1_1: i2c1grp-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 ++ MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x4001b8b1 ++ MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001b8b1 + >; + }; + }; + +- uart1 { +- pinctrl_uart1_1: uart1grp-1 { ++ i2c2 { ++ pinctrl_i2c2_1: i2c2grp-1 { + fsl,pins = < +- MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1 +- MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1 ++ MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x4001b8b1 ++ MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x4001b8b1 + >; + }; + }; + +- usbotg1 { +- pinctrl_usbotg1_1: usbotg1grp-1 { +- fsl,pins = < +- MX6SL_PAD_EPDC_PWRCOM__USB_OTG1_ID 0x17059 +- >; +- }; +- +- pinctrl_usbotg1_2: usbotg1grp-2 { ++ i2c3 { ++ pinctrl_i2c3_1: i2c3grp-1 { + 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 ++ MX6SL_PAD_EPDC_SDCE2__I2C3_SCL 0x4001b8b1 ++ MX6SL_PAD_EPDC_SDCE3__I2C3_SDA 0x4001b8b1 + >; + }; + }; + +- usbotg2 { +- pinctrl_usbotg2_1: usbotg2grp-1 { +- fsl,pins = < +- MX6SL_PAD_ECSPI1_SCLK__USB_OTG2_OC 0x17059 +- >; +- }; +- +- pinctrl_usbotg2_2: usbotg2grp-2 { ++ lcdif { ++ pinctrl_lcdif_dat_0: lcdifdatgrp-0 { + fsl,pins = < +- MX6SL_PAD_ECSPI2_SCLK__USB_OTG2_OC 0x17059 ++ 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_usbotg2_3: usbotg2grp-3 { ++ pinctrl_lcdif_ctrl_0: lcdifctrlgrp-0 { + 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 ++ 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 ++ MX6SL_PAD_LCD_RESET__LCD_RESET 0x1b0b0 + >; + }; + }; + +- usdhc1 { +- pinctrl_usdhc1_1: usdhc1grp-1 { ++ pwm1 { ++ pinctrl_pwm1_0: pwm1grp-0 { + 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 ++ MX6SL_PAD_PWM1__PWM1_OUT 0x110b0 + >; + }; +- +- 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 +- >; +- }; +- +- + }; ++ }; + +- 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 +- >; +- }; ++ epit1: epit@020d0000 { ++ reg = <0x020d0000 0x4000>; ++ interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; ++ }; + +- 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 +- >; +- }; ++ epit2: epit@020d4000 { ++ reg = <0x020d4000 0x4000>; ++ interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; ++ }; + +- }; ++ src: src@020d8000 { ++ compatible = "fsl,imx6sl-src", "fsl,imx51-src"; ++ reg = <0x020d8000 0x4000>; ++ interrupts = <0 91 IRQ_TYPE_LEVEL_HIGH>, ++ <0 96 IRQ_TYPE_LEVEL_HIGH>; ++ #reset-cells = <1>; ++ }; + +- 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 +- >; +- }; ++ gpc: gpc@020dc000 { ++ compatible = "fsl,imx6sl-gpc", "fsl,imx6q-gpc"; ++ reg = <0x020dc000 0x4000>; ++ interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks IMX6SL_CLK_GPU2D_PODF>, <&clks IMX6SL_CLK_GPU2D_OVG>, ++ <&clks IMX6SL_CLK_IPG>; ++ clock-names = "gpu2d_podf", "gpu2d_ovg", "ipg"; ++ pu-supply = <®_pu>; ++ }; + +- 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 +- >; +- }; ++ gpr: iomuxc-gpr@020e0000 { ++ compatible = "fsl,imx6sl-iomuxc-gpr", ++ "fsl,imx6q-iomuxc-gpr", "syscon"; ++ reg = <0x020e0000 0x38>; ++ }; + +- 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 +- >; +- }; +- }; ++ iomuxc: iomuxc@020e0000 { ++ compatible = "fsl,imx6sl-iomuxc"; ++ reg = <0x020e0000 0x4000>; + }; + + csi: csi@020e4000 { ++ compatible = "fsl,imx6sl-csi"; + reg = <0x020e4000 0x4000>; +- interrupts = <0 7 0x04>; ++ interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>; ++ status = "disabled"; + }; + + spdc: spdc@020e8000 { + reg = <0x020e8000 0x4000>; +- interrupts = <0 6 0x04>; ++ interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>; + }; + + sdma: sdma@020ec000 { + compatible = "fsl,imx6sl-sdma", "fsl,imx35-sdma"; + reg = <0x020ec000 0x4000>; +- interrupts = <0 2 0x04>; ++ interrupts = <0 2 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_SDMA>, + <&clks IMX6SL_CLK_SDMA>; + clock-names = "ipg", "ahb"; +@@ -781,23 +761,32 @@ + }; + + pxp: pxp@020f0000 { ++ compatible = "fsl,imx6sl-pxp-dma", "fsl,imx6dl-pxp-dma"; + reg = <0x020f0000 0x4000>; +- interrupts = <0 98 0x04>; ++ interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clks 111>; ++ clock-names = "pxp-axi"; ++ status = "disabled"; + }; + + epdc: epdc@020f4000 { + reg = <0x020f4000 0x4000>; +- interrupts = <0 97 0x04>; ++ interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>; + }; + + lcdif: lcdif@020f8000 { ++ compatible = "fsl,imx6sl-lcdif", "fsl,imx28-lcdif"; + reg = <0x020f8000 0x4000>; +- interrupts = <0 39 0x04>; ++ interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; ++ 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>; ++ interrupts = <0 99 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + +@@ -811,7 +800,7 @@ + usbotg1: usb@02184000 { + compatible = "fsl,imx6sl-usb", "fsl,imx27-usb"; + reg = <0x02184000 0x200>; +- interrupts = <0 43 0x04>; ++ interrupts = <0 43 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_USBOH3>; + fsl,usbphy = <&usbphy1>; + fsl,usbmisc = <&usbmisc 0>; +@@ -821,7 +810,7 @@ + usbotg2: usb@02184200 { + compatible = "fsl,imx6sl-usb", "fsl,imx27-usb"; + reg = <0x02184200 0x200>; +- interrupts = <0 42 0x04>; ++ interrupts = <0 42 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_USBOH3>; + fsl,usbphy = <&usbphy2>; + fsl,usbmisc = <&usbmisc 1>; +@@ -831,9 +820,12 @@ + usbh: usb@02184400 { + compatible = "fsl,imx6sl-usb", "fsl,imx27-usb"; + reg = <0x02184400 0x200>; +- interrupts = <0 40 0x04>; ++ interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_USBOH3>; + fsl,usbmisc = <&usbmisc 2>; ++ phy_type = "hsic"; ++ fsl,usbphy = <&usbphy_nop1>; ++ fsl,anatop = <&anatop>; + status = "disabled"; + }; + +@@ -847,7 +839,7 @@ + fec: ethernet@02188000 { + compatible = "fsl,imx6sl-fec", "fsl,imx25-fec"; + reg = <0x02188000 0x4000>; +- interrupts = <0 114 0x04>; ++ interrupts = <0 114 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_ENET_REF>, + <&clks IMX6SL_CLK_ENET_REF>; + clock-names = "ipg", "ahb"; +@@ -857,7 +849,7 @@ + usdhc1: usdhc@02190000 { + compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; + reg = <0x02190000 0x4000>; +- interrupts = <0 22 0x04>; ++ interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_USDHC1>, + <&clks IMX6SL_CLK_USDHC1>, + <&clks IMX6SL_CLK_USDHC1>; +@@ -869,7 +861,7 @@ + usdhc2: usdhc@02194000 { + compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; + reg = <0x02194000 0x4000>; +- interrupts = <0 23 0x04>; ++ interrupts = <0 23 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_USDHC2>, + <&clks IMX6SL_CLK_USDHC2>, + <&clks IMX6SL_CLK_USDHC2>; +@@ -881,7 +873,7 @@ + usdhc3: usdhc@02198000 { + compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; + reg = <0x02198000 0x4000>; +- interrupts = <0 24 0x04>; ++ interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_USDHC3>, + <&clks IMX6SL_CLK_USDHC3>, + <&clks IMX6SL_CLK_USDHC3>; +@@ -893,7 +885,7 @@ + usdhc4: usdhc@0219c000 { + compatible = "fsl,imx6sl-usdhc", "fsl,imx6q-usdhc"; + reg = <0x0219c000 0x4000>; +- interrupts = <0 25 0x04>; ++ interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_USDHC4>, + <&clks IMX6SL_CLK_USDHC4>, + <&clks IMX6SL_CLK_USDHC4>; +@@ -907,7 +899,7 @@ + #size-cells = <0>; + compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c"; + reg = <0x021a0000 0x4000>; +- interrupts = <0 36 0x04>; ++ interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_I2C1>; + status = "disabled"; + }; +@@ -917,7 +909,7 @@ + #size-cells = <0>; + compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c"; + reg = <0x021a4000 0x4000>; +- interrupts = <0 37 0x04>; ++ interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_I2C2>; + status = "disabled"; + }; +@@ -927,7 +919,7 @@ + #size-cells = <0>; + compatible = "fsl,imx6sl-i2c", "fsl,imx21-i2c"; + reg = <0x021a8000 0x4000>; +- interrupts = <0 38 0x04>; ++ interrupts = <0 38 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6SL_CLK_I2C3>; + status = "disabled"; + }; +@@ -939,17 +931,23 @@ + + rngb: rngb@021b4000 { + reg = <0x021b4000 0x4000>; +- interrupts = <0 5 0x04>; ++ interrupts = <0 5 IRQ_TYPE_LEVEL_HIGH>; + }; + + weim: weim@021b8000 { + reg = <0x021b8000 0x4000>; +- interrupts = <0 14 0x04>; ++ interrupts = <0 14 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ ocotp: ocotp-ctrl@021bc000 { ++ compatible = "syscon"; ++ reg = <0x021bc000 0x4000>; + }; + +- ocotp: ocotp@021bc000 { +- compatible = "fsl,imx6sl-ocotp"; ++ ocotp-fuse@021bc000 { ++ compatible = "fsl,imx6sl-ocotp", "fsl,imx6q-ocotp"; + reg = <0x021bc000 0x4000>; ++ clocks = <&clks IMX6SL_CLK_OCOTP>; + }; + + audmux: audmux@021d8000 { +@@ -957,6 +955,25 @@ + 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>; ++ }; ++ + }; + }; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/imx6sl-evk-csi.dts linux-3.14.40/arch/arm/boot/dts/imx6sl-evk-csi.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6sl-evk-csi.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/imx6sl-evk-csi.dts 2015-05-01 14:57:57.499427001 -0500 +@@ -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.14.40.orig/arch/arm/boot/dts/imx6sl-evk.dts linux-3.14.40/arch/arm/boot/dts/imx6sl-evk.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/imx6sl-evk.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/imx6sl-evk.dts 2015-05-01 14:57:57.499427001 -0500 +@@ -8,6 +8,8 @@ + + /dts-v1/; + ++#include ++#include + #include "imx6sl.dtsi" + + / { +@@ -18,11 +20,26 @@ + reg = <0x80000000 0x40000000>; + }; + ++ leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_led>; ++ ++ user { ++ label = "debug"; ++ gpios = <&gpio3 20 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ }; ++ + regulators { + compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; + +- reg_usb_otg1_vbus: usb_otg1_vbus { ++ reg_usb_otg1_vbus: regulator@0 { + compatible = "regulator-fixed"; ++ reg = <0>; + regulator-name = "usb_otg1_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; +@@ -30,22 +47,63 @@ + enable-active-high; + }; + +- reg_usb_otg2_vbus: usb_otg2_vbus { ++ reg_usb_otg2_vbus: regulator@1 { + compatible = "regulator-fixed"; ++ reg = <1>; + regulator-name = "usb_otg2_vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio4 2 0>; + enable-active-high; + }; ++ ++ reg_aud3v: regulator@2 { ++ compatible = "regulator-fixed"; ++ reg = <2>; ++ regulator-name = "wm8962-supply-3v15"; ++ regulator-min-microvolt = <3150000>; ++ regulator-max-microvolt = <3150000>; ++ regulator-boot-on; ++ }; ++ ++ reg_aud4v: regulator@3 { ++ compatible = "regulator-fixed"; ++ reg = <3>; ++ regulator-name = "wm8962-supply-4v2"; ++ regulator-min-microvolt = <4325000>; ++ regulator-max-microvolt = <4325000>; ++ regulator-boot-on; ++ }; + }; ++ ++ sound { ++ compatible = "fsl,imx6sl-evk-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"; ++ mux-int-port = <2>; ++ mux-ext-port = <3>; ++ }; ++}; ++ ++&audmux { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_audmux3>; ++ status = "okay"; + }; + + &ecspi1 { + fsl,spi-num-chipselects = <1>; + cs-gpios = <&gpio4 11 0>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_ecspi1_1>; ++ pinctrl-0 = <&pinctrl_ecspi1>; + status = "okay"; + + flash: m25p80@0 { +@@ -57,18 +115,326 @@ + }; + }; + ++&csi { ++ 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"; +- pinctrl-0 = <&pinctrl_fec_1>; ++ pinctrl-0 = <&pinctrl_fec>; + phy-mode = "rmii"; + status = "okay"; + }; + ++&i2c1 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c1>; ++ 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>; ++ regulator-always-on; ++ }; ++ ++ 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; ++ }; ++ }; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ ++ reg_lcd_3v3: lcd-3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "lcd-3v3"; ++ gpio = <&gpio4 3 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 = "okay"; ++ }; ++ ++ pxp_v4l2_out { ++ compatible = "fsl,imx6sl-pxp-v4l2"; ++ status = "okay"; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2>; ++ 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>; ++ }; ++}; ++ ++&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; ++ }; ++ }; ++ }; ++ ++ mma8450@1c { ++ compatible = "fsl,mma8450"; ++ reg = <0x1c>; ++ }; ++}; ++ ++&i2c2 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c2_1>; ++ status = "okay"; ++}; ++ ++&i2c3 { ++ clock-frequency = <100000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_i2c3_1>; ++ status = "okay"; ++ ++ 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"; + pinctrl-0 = <&pinctrl_hog>; + +- hog { ++ imx6sl-evk { + pinctrl_hog: hoggrp { + fsl,pins = < + MX6SL_PAD_KEY_ROW7__GPIO4_IO07 0x17059 +@@ -78,21 +444,270 @@ + MX6SL_PAD_REF_CLK_32K__GPIO3_IO22 0x17059 + MX6SL_PAD_KEY_COL4__GPIO4_IO00 0x80000000 + MX6SL_PAD_KEY_COL5__GPIO4_IO02 0x80000000 ++ MX6SL_PAD_AUD_MCLK__AUDIO_CLK_OUT 0x4130b0 ++ >; ++ }; ++ ++ pinctrl_audmux3: audmux3grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_ecspi1: ecspi1grp { ++ fsl,pins = < ++ MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO 0x100b1 ++ MX6SL_PAD_ECSPI1_MOSI__ECSPI1_MOSI 0x100b1 ++ MX6SL_PAD_ECSPI1_SCLK__ECSPI1_SCLK 0x100b1 ++ MX6SL_PAD_ECSPI1_SS0__GPIO4_IO11 0x80000000 ++ >; ++ }; ++ ++ pinctrl_fec: fecgrp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_i2c1: i2c1grp { ++ fsl,pins = < ++ MX6SL_PAD_I2C1_SCL__I2C1_SCL 0x4001b8b1 ++ MX6SL_PAD_I2C1_SDA__I2C1_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ ++ pinctrl_i2c2: i2c2grp { ++ fsl,pins = < ++ MX6SL_PAD_I2C2_SCL__I2C2_SCL 0x4001b8b1 ++ MX6SL_PAD_I2C2_SDA__I2C2_SDA 0x4001b8b1 ++ >; ++ }; ++ ++ pinctrl_led: ledgrp { ++ fsl,pins = < ++ MX6SL_PAD_HSIC_STROBE__GPIO3_IO20 0x17059 ++ >; ++ }; ++ ++ pinctrl_kpp: kppgrp { ++ 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 0x110b0 ++ MX6SL_PAD_KEY_COL1__KEY_COL1 0x110b0 ++ MX6SL_PAD_KEY_COL2__KEY_COL2 0x110b0 ++ >; ++ }; ++ ++ pinctrl_uart1: uart1grp { ++ fsl,pins = < ++ MX6SL_PAD_UART1_RXD__UART1_RX_DATA 0x1b0b1 ++ MX6SL_PAD_UART1_TXD__UART1_TX_DATA 0x1b0b1 ++ >; ++ }; ++ ++ pinctrl_usbotg1: usbotg1grp { ++ fsl,pins = < ++ MX6SL_PAD_EPDC_PWRCOM__USB_OTG1_ID 0x17059 ++ >; ++ }; ++ ++ pinctrl_usdhc1: usdhc1grp { ++ 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 ++ >; ++ }; ++ ++ pinctrl_usdhc1_100mhz: usdhc1grp100mhz { ++ 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_200mhz: usdhc1grp200mhz { ++ 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 ++ >; ++ }; ++ ++ pinctrl_usdhc2: usdhc2grp { ++ 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_100mhz: usdhc2grp100mhz { ++ 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_200mhz: usdhc2grp200mhz { ++ 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 ++ >; ++ }; ++ ++ pinctrl_usdhc3: usdhc3grp { ++ 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_100mhz: usdhc3grp100mhz { ++ 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_200mhz: usdhc3grp200mhz { ++ 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 + >; + }; + }; + }; + ++&kpp { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_kpp>; ++ linux,keymap = < ++ MATRIX_KEY(0x0, 0x0, KEY_UP) /* ROW0, COL0 */ ++ MATRIX_KEY(0x0, 0x1, KEY_DOWN) /* ROW0, COL1 */ ++ MATRIX_KEY(0x0, 0x2, KEY_ENTER) /* ROW0, COL2 */ ++ MATRIX_KEY(0x1, 0x0, KEY_HOME) /* ROW1, COL0 */ ++ MATRIX_KEY(0x1, 0x1, KEY_RIGHT) /* ROW1, COL1 */ ++ MATRIX_KEY(0x1, 0x2, KEY_LEFT) /* ROW1, COL2 */ ++ MATRIX_KEY(0x2, 0x0, KEY_VOLUMEDOWN) /* ROW2, COL0 */ ++ MATRIX_KEY(0x2, 0x1, KEY_VOLUMEUP) /* ROW2, COL1 */ ++ >; ++ status = "okay"; ++}; ++ ++&ssi2 { ++ fsl,mode = "i2s-slave"; ++ 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"; ++ pinctrl-0 = <&pinctrl_pwm1_0>; ++ status = "okay"; ++}; ++ + &uart1 { + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_uart1_1>; ++ pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; + }; + + &usbotg1 { + vbus-supply = <®_usb_otg1_vbus>; + pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_usbotg1_1>; ++ pinctrl-0 = <&pinctrl_usbotg1>; + disable-over-current; + status = "okay"; + }; +@@ -106,9 +721,9 @@ + + &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>; ++ pinctrl-0 = <&pinctrl_usdhc1>; ++ pinctrl-1 = <&pinctrl_usdhc1_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc1_200mhz>; + bus-width = <8>; + cd-gpios = <&gpio4 7 0>; + wp-gpios = <&gpio4 6 0>; +@@ -117,9 +732,9 @@ + + &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>; ++ pinctrl-0 = <&pinctrl_usdhc2>; ++ pinctrl-1 = <&pinctrl_usdhc2_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc2_200mhz>; + cd-gpios = <&gpio5 0 0>; + wp-gpios = <&gpio4 29 0>; + status = "okay"; +@@ -127,9 +742,26 @@ + + &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>; ++ pinctrl-0 = <&pinctrl_usdhc3>; ++ pinctrl-1 = <&pinctrl_usdhc3_100mhz>; ++ pinctrl-2 = <&pinctrl_usdhc3_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; /* use ldo-bypass, u-boot will check it and configure */ ++ 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.14.40.orig/arch/arm/boot/dts/Makefile linux-3.14.40/arch/arm/boot/dts/Makefile +--- linux-3.14.40.orig/arch/arm/boot/dts/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/Makefile 2015-05-01 14:57:57.507427001 -0500 +@@ -154,16 +154,37 @@ + imx53-qsb.dtb \ + imx53-smd.dtb \ + imx6dl-cubox-i.dtb \ ++ imx6dl-dfi-fs700-m60.dtb \ ++ imx6dl-gw51xx.dtb \ ++ imx6dl-gw52xx.dtb \ ++ imx6dl-gw53xx.dtb \ ++ imx6dl-gw54xx.dtb \ + imx6dl-hummingboard.dtb \ ++ imx6dl-nitrogen6x.dtb \ ++ imx6dl-phytec-pbab01.dtb \ + imx6dl-sabreauto.dtb \ ++ imx6dl-sabrelite.dtb \ + imx6dl-sabresd.dtb \ ++ imx6dl-sabresd-hdcp.dtb \ + imx6dl-wandboard.dtb \ + imx6q-arm2.dtb \ ++ imx6q-cm-fx6.dtb \ + imx6q-cubox-i.dtb \ ++ imx6q-hummingboard.dtb \ ++ imx6q-dfi-fs700-m60.dtb \ ++ imx6q-dmo-edmqmx6.dtb \ ++ imx6q-gk802.dtb \ ++ imx6q-gw51xx.dtb \ ++ imx6q-gw52xx.dtb \ ++ imx6q-gw53xx.dtb \ ++ imx6q-gw5400-a.dtb \ ++ imx6q-gw54xx.dtb \ ++ imx6q-nitrogen6x.dtb \ + imx6q-phytec-pbab01.dtb \ + imx6q-sabreauto.dtb \ + imx6q-sabrelite.dtb \ + imx6q-sabresd.dtb \ ++ imx6q-sabresd-hdcp.dtb \ + imx6q-sbc6x.dtb \ + imx6q-udoo.dtb \ + imx6q-wandboard.dtb \ +@@ -312,7 +333,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.14.40.orig/arch/arm/boot/dts/marco.dtsi linux-3.14.40/arch/arm/boot/dts/marco.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/marco.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/marco.dtsi 2015-05-01 14:57:57.507427001 -0500 +@@ -36,7 +36,7 @@ + ranges = <0x40000000 0x40000000 0xa0000000>; + + l2-cache-controller@c0030000 { +- compatible = "sirf,marco-pl310-cache", "arm,pl310-cache"; ++ compatible = "arm,pl310-cache"; + reg = <0xc0030000 0x1000>; + interrupts = <0 59 0>; + arm,tag-latency = <1 1 1>; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/prima2.dtsi linux-3.14.40/arch/arm/boot/dts/prima2.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/prima2.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/prima2.dtsi 2015-05-01 14:57:57.507427001 -0500 +@@ -48,7 +48,7 @@ + ranges = <0x40000000 0x40000000 0x80000000>; + + l2-cache-controller@80040000 { +- compatible = "arm,pl310-cache", "sirf,prima2-pl310-cache"; ++ compatible = "arm,pl310-cache"; + reg = <0x80040000 0x1000>; + interrupts = <59>; + arm,tag-latency = <1 1 1>; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/rtsm_ve-cortex_a15x1.dts linux-3.14.40/arch/arm/boot/dts/rtsm_ve-cortex_a15x1.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/rtsm_ve-cortex_a15x1.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/rtsm_ve-cortex_a15x1.dts 2015-05-01 14:57:57.507427001 -0500 +@@ -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.14.40.orig/arch/arm/boot/dts/rtsm_ve-cortex_a15x2.dts linux-3.14.40/arch/arm/boot/dts/rtsm_ve-cortex_a15x2.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/rtsm_ve-cortex_a15x2.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/rtsm_ve-cortex_a15x2.dts 2015-05-01 14:57:57.511427001 -0500 +@@ -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.14.40.orig/arch/arm/boot/dts/rtsm_ve-cortex_a15x4.dts linux-3.14.40/arch/arm/boot/dts/rtsm_ve-cortex_a15x4.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/rtsm_ve-cortex_a15x4.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/rtsm_ve-cortex_a15x4.dts 2015-05-01 14:57:57.511427001 -0500 +@@ -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.14.40.orig/arch/arm/boot/dts/rtsm_ve-cortex_a9x2.dts linux-3.14.40/arch/arm/boot/dts/rtsm_ve-cortex_a9x2.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/rtsm_ve-cortex_a9x2.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/rtsm_ve-cortex_a9x2.dts 2015-05-01 14:57:57.511427001 -0500 +@@ -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.14.40.orig/arch/arm/boot/dts/rtsm_ve-cortex_a9x4.dts linux-3.14.40/arch/arm/boot/dts/rtsm_ve-cortex_a9x4.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/rtsm_ve-cortex_a9x4.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/rtsm_ve-cortex_a9x4.dts 2015-05-01 14:57:57.511427001 -0500 +@@ -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.14.40.orig/arch/arm/boot/dts/rtsm_ve-motherboard.dtsi linux-3.14.40/arch/arm/boot/dts/rtsm_ve-motherboard.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/rtsm_ve-motherboard.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/rtsm_ve-motherboard.dtsi 2015-05-01 14:57:57.511427001 -0500 +@@ -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.14.40.orig/arch/arm/boot/dts/rtsm_ve-v2p-ca15x1-ca7x1.dts linux-3.14.40/arch/arm/boot/dts/rtsm_ve-v2p-ca15x1-ca7x1.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/rtsm_ve-v2p-ca15x1-ca7x1.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/rtsm_ve-v2p-ca15x1-ca7x1.dts 2015-05-01 14:57:57.511427001 -0500 +@@ -0,0 +1,233 @@ ++/* ++ * 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>; ++ }; ++ ++ 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.14.40.orig/arch/arm/boot/dts/rtsm_ve-v2p-ca15x4-ca7x4.dts linux-3.14.40/arch/arm/boot/dts/rtsm_ve-v2p-ca15x4-ca7x4.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/rtsm_ve-v2p-ca15x4-ca7x4.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/boot/dts/rtsm_ve-v2p-ca15x4-ca7x4.dts 2015-05-01 14:57:57.511427001 -0500 +@@ -0,0 +1,317 @@ ++/* ++ * 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>; ++ }; ++ ++ 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.14.40.orig/arch/arm/boot/dts/vexpress-v2m.dtsi linux-3.14.40/arch/arm/boot/dts/vexpress-v2m.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/vexpress-v2m.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/vexpress-v2m.dtsi 2015-05-01 14:57:57.515427001 -0500 +@@ -227,6 +227,7 @@ + }; + + clcd@1f000 { ++ status = "disabled"; + compatible = "arm,pl111", "arm,primecell"; + reg = <0x1f000 0x1000>; + interrupts = <14>; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi linux-3.14.40/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi 2015-05-01 14:57:57.559427001 -0500 +@@ -228,6 +228,7 @@ + }; + + clcd@1f0000 { ++ status = "disabled"; + compatible = "arm,pl111", "arm,primecell"; + reg = <0x1f0000 0x1000>; + interrupts = <14>; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts linux-3.14.40/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts 2015-05-01 14:57:57.559427001 -0500 +@@ -9,6 +9,8 @@ + + /dts-v1/; + ++/memreserve/ 0xff000000 0x01000000; ++ + / { + model = "V2P-CA15_CA7"; + arm,hbi = <0x249>; +@@ -29,29 +31,60 @@ + 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>; +- cci-control-port = <&cci_control1>; ++ 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>; +- cci-control-port = <&cci_control1>; ++ 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>; + cci-control-port = <&cci_control2>; ++ cluster = <&cluster1>; ++ core = <&core2>; ++ clock-frequency = <800000000>; + }; + + cpu3: cpu@3 { +@@ -59,6 +92,9 @@ + compatible = "arm,cortex-a7"; + reg = <0x101>; + cci-control-port = <&cci_control2>; ++ cluster = <&cluster1>; ++ core = <&core3>; ++ clock-frequency = <800000000>; + }; + + cpu4: cpu@4 { +@@ -66,12 +102,35 @@ + compatible = "arm,cortex-a7"; + reg = <0x102>; + cci-control-port = <&cci_control2>; ++ cluster = <&cluster1>; ++ core = <&core4>; ++ clock-frequency = <800000000>; ++ }; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <0>; ++ cci-control-port = <&cci_control1>; ++ cluster = <&cluster0>; ++ core = <&core0>; ++ clock-frequency = <1000000000>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a15"; ++ reg = <1>; ++ cci-control-port = <&cci_control1>; ++ cluster = <&cluster0>; ++ core = <&core1>; ++ clock-frequency = <1000000000>; + }; + }; + + memory@80000000 { + device_type = "memory"; +- reg = <0 0x80000000 0 0x40000000>; ++ reg = <0 0x80000000 0 0x80000000>; + }; + + wdt@2a490000 { +@@ -86,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"; + }; +@@ -127,6 +188,16 @@ + interface-type = "ace"; + reg = <0x5000 0x1000>; + }; ++ ++ pmu@9000 { ++ compatible = "arm,cci-400-pmu"; ++ reg = <0x9000 0x5000>; ++ interrupts = <0 101 4>, ++ <0 102 4>, ++ <0 103 4>, ++ <0 104 4>, ++ <0 105 4>; ++ }; + }; + + memory-controller@7ffd0000 { +@@ -164,12 +235,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"; +@@ -178,6 +258,19 @@ + clock-output-names = "oscclk6a"; + }; + ++/* PSCI requires support from firmware and is not present in the normal TC2 ++ * distribution, so this node is commented out by default... ++ ++ 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.14.40.orig/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts linux-3.14.40/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dts 2015-05-01 14:57:57.559427001 -0500 +@@ -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 0xbf000000 0 0x01000000>; + }; + + memory-controller@2b0a0000 { +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/vexpress-v2p-ca5s.dts linux-3.14.40/arch/arm/boot/dts/vexpress-v2p-ca5s.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/vexpress-v2p-ca5s.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/vexpress-v2p-ca5s.dts 2015-05-01 14:57:57.559427001 -0500 +@@ -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.14.40.orig/arch/arm/boot/dts/vexpress-v2p-ca9.dts linux-3.14.40/arch/arm/boot/dts/vexpress-v2p-ca9.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/vexpress-v2p-ca9.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/vexpress-v2p-ca9.dts 2015-05-01 14:57:57.559427001 -0500 +@@ -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.14.40.orig/arch/arm/boot/dts/vf610.dtsi linux-3.14.40/arch/arm/boot/dts/vf610.dtsi +--- linux-3.14.40.orig/arch/arm/boot/dts/vf610.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/vf610.dtsi 2015-05-01 14:57:57.563427001 -0500 +@@ -44,11 +44,13 @@ + + sxosc { + compatible = "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <32768>; + }; + + fxosc { + compatible = "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <24000000>; + }; + }; +diff -Nur linux-3.14.40.orig/arch/arm/boot/dts/vf610-twr.dts linux-3.14.40/arch/arm/boot/dts/vf610-twr.dts +--- linux-3.14.40.orig/arch/arm/boot/dts/vf610-twr.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/boot/dts/vf610-twr.dts 2015-05-01 14:57:57.563427001 -0500 +@@ -25,11 +25,13 @@ + clocks { + audio_ext { + compatible = "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <24576000>; + }; + + enet_ext { + compatible = "fixed-clock"; ++ #clock-cells = <0>; + clock-frequency = <50000000>; + }; + }; +diff -Nur linux-3.14.40.orig/arch/arm/common/Makefile linux-3.14.40/arch/arm/common/Makefile +--- linux-3.14.40.orig/arch/arm/common/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/common/Makefile 2015-05-01 14:57:57.579427001 -0500 +@@ -13,6 +13,7 @@ + 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 ++CFLAGS_REMOVE_mcpm_entry.o = -pg + AFLAGS_mcpm_head.o := -march=armv7-a + AFLAGS_vlock.o := -march=armv7-a + obj-$(CONFIG_TI_PRIV_EDMA) += edma.o +diff -Nur linux-3.14.40.orig/arch/arm/configs/imx_v6_v7_defconfig linux-3.14.40/arch/arm/configs/imx_v6_v7_defconfig +--- linux-3.14.40.orig/arch/arm/configs/imx_v6_v7_defconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/configs/imx_v6_v7_defconfig 2015-05-01 14:57:57.587427001 -0500 +@@ -45,6 +45,9 @@ + CONFIG_AEABI=y + CONFIG_HIGHMEM=y + CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" ++CONFIG_CPU_FREQ=y ++CONFIG_ARM_IMX6Q_CPUFREQ=y ++CONFIG_CPU_IDLE=y + CONFIG_VFP=y + CONFIG_NEON=y + CONFIG_BINFMT_MISC=m +@@ -70,6 +73,8 @@ + 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 +@@ -154,7 +159,12 @@ + CONFIG_SPI_IMX=y + CONFIG_GPIO_SYSFS=y + CONFIG_GPIO_MC9S08DZ60=y ++CONFIG_GPIO_PCA953X=y + # CONFIG_HWMON is not set ++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 +@@ -170,32 +180,44 @@ + CONFIG_REGULATOR_PFUZE100=y + CONFIG_MEDIA_SUPPORT=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_V4L_MEM2MEM_DRIVERS=y + CONFIG_VIDEO_CODA=y + CONFIG_SOC_CAMERA_OV2640=y + CONFIG_DRM=y ++CONFIG_DRM_VIVANTE=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_HDMI=y ++CONFIG_FB_MXC_MIPI_DSI=y ++CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL=y + CONFIG_FRAMEBUFFER_CONSOLE=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_PHYCORE_AC97=y + CONFIG_SND_SOC_EUKREA_TLV320=y + CONFIG_SND_SOC_IMX_WM8962=y + CONFIG_SND_SOC_IMX_SGTL5000=y ++CONFIG_SND_SOC_IMX_CS42888=y + CONFIG_SND_SOC_IMX_SPDIF=y + CONFIG_SND_SOC_IMX_MC13783=y + CONFIG_USB=y +@@ -208,12 +230,18 @@ + CONFIG_NOP_USB_XCEIV=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_NEW_LEDS=y + CONFIG_LEDS_CLASS=y + CONFIG_LEDS_GPIO=y +@@ -229,16 +257,10 @@ + 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_FB_HELPER=y +-CONFIG_DRM_IMX_PARALLEL_DISPLAY=y +-CONFIG_DRM_IMX_TVE=y +-CONFIG_DRM_IMX_LDB=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 +diff -Nur linux-3.14.40.orig/arch/arm/configs/imx_v7_cbi_hb_base_defconfig linux-3.14.40/arch/arm/configs/imx_v7_cbi_hb_base_defconfig +--- linux-3.14.40.orig/arch/arm/configs/imx_v7_cbi_hb_base_defconfig 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/configs/imx_v7_cbi_hb_base_defconfig 2015-05-01 14:57:57.587427001 -0500 +@@ -0,0 +1,367 @@ ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_KERNEL_LZO=y ++CONFIG_SYSVIPC=y ++CONFIG_FHANDLE=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=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_CLEANCACHE=y ++CONFIG_FRONTSWAP=y ++CONFIG_ZSWAP=y ++CONFIG_ZSMALLOC=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_SOC_IMX6Q=y ++CONFIG_SOC_IMX6SL=y ++# CONFIG_SWP_EMULATE is not set ++CONFIG_PCI=y ++CONFIG_PCIE_DW=y ++CONFIG_PCI_IMX6=y ++CONFIG_SMP=y ++CONFIG_VMSPLIT_2G=y ++CONFIG_PREEMPT_VOLUNTARY=y ++CONFIG_AEABI=y ++# CONFIG_OABI_COMPAT is not set ++CONFIG_HIGHMEM=y ++CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" ++CONFIG_CPU_FREQ=y ++CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y ++CONFIG_CPU_FREQ_GOV_PERFORMANCE=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_VFPv3=y ++CONFIG_NEON=y ++CONFIG_KERNEL_MODE_NEON=y ++CONFIG_BINFMT_MISC=m ++CONFIG_PM_RUNTIME=y ++CONFIG_PM_DEBUG=y ++CONFIG_PM_TEST_SUSPEND=y ++CONFIG_IOSCHED_BFQ=y ++CONFIG_CGROUP_BFQIO=y ++CONFIG_DEFAULT_BFQ=y ++CONFIG_DEFAULT_IOSCHED="bfq" ++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_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_ETHERNET=y ++# CONFIG_NET_VENDOR_BROADCOM is not set ++# CONFIG_NET_VENDOR_CIRRUS is not set ++# CONFIG_NET_VENDOR_FARADAY ++# CONFIG_NET_VENDOR_INTEL ++# CONFIG_NET_VENDOR_I825XX ++# CONFIG_NET_VENDOR_MARVELL ++# CONFIG_NET_VENDOR_MICROCHIP ++# CONFIG_NET_VENDOR_MICROCHIP=y ++# CONFIG_ENC28J60 is not set ++# CONFIG_NET_VENDOR_NATSEMI=y ++# CONFIG_NET_VENDOR_8390=y ++# CONFIG_AX88796 is not set ++# CONFIG_ETHOC is not set ++# CONFIG_SH_ETH is not set ++# CONFIG_NET_VENDOR_SEEQ=y ++# CONFIG_NET_VENDOR_SMSC=y ++# CONFIG_SMC91X is not set ++# CONFIG_SMC911X is not set ++# CONFIG_SMSC911X is not set ++# CONFIG_NET_VENDOR_STMICRO=y ++# CONFIG_STMMAC_ETH is not set ++# CONFIG_NET_VENDOR_VIA=y ++# CONFIG_VIA_VELOCITY is not set ++# CONFIG_NET_VENDOR_WIZNET=y ++CONFIG_NET_VENDOR_FREESCALE=y ++CONFIG_FEC=y ++CONFIG_PHYLIB=y ++CONFIG_AT803X_PHY=y ++CONFIG_WLAN=y ++CONFIG_BRCMUTIL=m ++CONFIG_BRCMFMAC=m ++CONFIG_BRCMFMAC_SDIO=y ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++CONFIG_DMA_CMA=y ++CONFIG_CMA=y ++CONFIG_CMA_SIZE_MBYTES=256 ++CONFIG_CONNECTOR=y ++# CONFIG_MTD is not set ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=65536 ++# 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_NETDEVICES=y ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_EVBUG is not set ++CONFIG_KEYBOARD_GPIO=y ++CONFIG_KEYBOARD_IMX=y ++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set ++# CONFIG_KEYBOARD_ATKBD is not set ++# CONFIG_MOUSE_PS2 is not set ++CONFIG_INPUT_MISC=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_GPIO_MXC=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_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_ANATOP=y ++CONFIG_REGULATOR_PFUZE100=y ++CONFIG_MEDIA_SUPPORT=y ++CONFIG_MEDIA_CAMERA_SUPPORT=y ++# CONFIG_MEDIA_RADIO_SUPPORT is not set ++CONFIG_VIDEO_V4L2_INT_DEVICE=y ++# CONFIG_MEDIA_USB_SUPPORT isnot set ++# CONFIG_USB_VIDEO_CLASS is not set ++# CONFIG_RADIO_ADAPTERS is not set ++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_SOC_CAMERA_OV2640=y ++CONFIG_DRM=y ++CONFIG_DRM_VIVANTE=y ++CONFIG_FB=y ++# CONFIG_FB_MX3 is not set ++CONFIG_FB_MXC_SYNC_PANEL=y ++CONFIG_FB_MXC_LDB=y ++CONFIG_FB_MXC_HDMI=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_IMX_SGTL5000=y ++CONFIG_SND_SOC_IMX_SPDIF=y ++CONFIG_SND_SOC_IMX_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_NOP_USB_XCEIV=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_MIPI_CSI2=y ++CONFIG_MXC_MLB150=m ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_TRIGGERS=y ++CONFIG_LEDS_TRIGGER_GPIO=y ++CONFIG_RTC_CLASS=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_SRAM=y ++CONFIG_STAGING=y ++CONFIG_COMMON_CLK_DEBUG=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_PWM=y ++CONFIG_PWM_SYSFS=y ++CONFIG_PWM_IMX=y ++CONFIG_IRQCHIP=y ++CONFIG_ARM_GIC=y ++# CONFIG_IPACK_BUS is not set ++CONFIG_ARCH_HAS_RESET_CONTROLLER=y ++CONFIG_RESET_CONTROLLER=y ++CONFIG_RESET_GPIO=y ++CONFIG_EXT4_FS=y ++CONFIG_EXT4_USE_FOR_EXT23=y ++CONFIG_EXT4_FS_XATTR=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_TEST=m ++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_XTS=y ++CONFIG_CRYPTO_MD4=y ++CONFIG_CRYPTO_MD5=y ++CONFIG_CRYPTO_MICHAEL_MIC=y ++CONFIG_CRYPTO_RMD128=y ++CONFIG_CRYPTO_RMD160=y ++CONFIG_CRYPTO_RMD256=y ++CONFIG_CRYPTO_RMD320=y ++CONFIG_CRYPTO_SHA1=y ++CONFIG_CRYPTO_SHA256=y ++CONFIG_CRYPTO_SHA512=y ++CONFIG_CRYPTO_TGR192=y ++CONFIG_CRYPTO_WP512=y ++CONFIG_CRYPTO_BLOWFISH=y ++CONFIG_CRYPTO_CAMELLIA=y ++CONFIG_CRYPTO_DES=y ++CONFIG_CRYPTO_TWOFISH=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_CRYPTO_AES_ARM_BS=y ++CONFIG_CRC_CCITT=m ++CONFIG_CRC_T10DIF=y ++CONFIG_CRC7=m ++CONFIG_LIBCRC32C=m ++# CONFIG_MXC_MMA8451 is not set ++CONFIG_RC_CORE=m ++CONFIG_RC_DECODERS=y ++CONFIG_LIRC=m ++CONFIG_RC_LOOPBACK=m ++CONFIG_RC_MAP=m ++CONFIG_RC_DEVICES=y ++CONFIG_RC_ATI_REMOTE=m ++CONFIG_IR_NEC_DECODER=m ++CONFIG_IR_RC5_DECODER=m ++CONFIG_IR_RC6_DECODER=m ++CONFIG_IR_JVC_DECODER=m ++CONFIG_IR_SONY_DECODER=m ++CONFIG_IR_RC5_SZ_DECODER=m ++CONFIG_IR_SANYO_DECODER=m ++CONFIG_IR_MCE_KBD_DECODER=m ++CONFIG_IR_LIRC_CODEC=m ++CONFIG_IR_IMON=m ++CONFIG_IR_MCEUSB=m ++CONFIG_IR_ITE_CIR=m ++CONFIG_IR_NUVOTON=m ++CONFIG_IR_FINTEK=m ++CONFIG_IR_REDRAT3=m ++CONFIG_IR_ENE=m ++CONFIG_IR_STREAMZAP=m ++CONFIG_IR_WINBOND_CIR=m ++CONFIG_IR_IGUANA=m ++CONFIG_IR_TTUSBIR=m ++CONFIG_IR_GPIO_CIR=m +diff -Nur linux-3.14.40.orig/arch/arm/configs/imx_v7_cbi_hb_defconfig linux-3.14.40/arch/arm/configs/imx_v7_cbi_hb_defconfig +--- linux-3.14.40.orig/arch/arm/configs/imx_v7_cbi_hb_defconfig 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/configs/imx_v7_cbi_hb_defconfig 2015-05-01 14:57:57.591427001 -0500 +@@ -0,0 +1,5138 @@ ++# ++# Automatically generated make config: don't edit ++# ++CONFIG_MMU=y ++CONFIG_HOTPLUG_CPU=y ++# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set ++# CONFIG_DEBUG_HOTPLUG_CPU0 is not set ++CONFIG_LOCALVERSION="" ++CONFIG_CROSS_COMPILE="" ++CONFIG_DEFAULT_HOSTNAME="(none)" ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++CONFIG_HOTPLUG=y ++CONFIG_UEVENT_HELPER_PATH="" ++CONFIG_PREVENT_FIRMWARE_BUILD=y ++ ++CONFIG_BUILD_DOCSRC=y ++ ++# ++# General setup ++# ++CONFIG_KERNEL_LZO=y ++# CONFIG_KERNEL_BZIP2 is not set ++# CONFIG_KERNEL_LZMA is not set ++CONFIG_SWAP=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_BSD_PROCESS_ACCT_V3=y ++# CONFIG_COMPILE_TEST is not set ++CONFIG_TASKSTATS=y ++CONFIG_TASK_DELAY_ACCT=y ++CONFIG_TASK_XACCT=y ++CONFIG_TASK_IO_ACCOUNTING=y ++CONFIG_SYSCTL=y ++# CONFIG_IKCONFIG is not set ++# CONFIG_EMBEDDED is not set ++CONFIG_KALLSYMS=y ++CONFIG_KALLSYMS_ALL=y ++CONFIG_FUTEX=y ++CONFIG_EPOLL=y ++CONFIG_IOSCHED_NOOP=y ++CONFIG_IOSCHED_DEADLINE=y ++CONFIG_IOSCHED_CFQ=y ++CONFIG_CFQ_GROUP_IOSCHED=y ++CONFIG_IOSCHED_BFQ=y ++CONFIG_CGROUP_BFQIO=y ++CONFIG_DEFAULT_BFQ=y ++CONFIG_DEFAULT_IOSCHED="bfq" ++# CONFIG_CHECKPOINT_RESTORE is not set ++CONFIG_NAMESPACES=y ++CONFIG_PID_NS=y ++CONFIG_UTS_NS=y ++CONFIG_IPC_NS=y ++CONFIG_NET_NS=y ++CONFIG_USER_NS=y ++# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set ++CONFIG_SYSVIPC=y ++CONFIG_FHANDLE=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=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_POSIX_MQUEUE=y ++CONFIG_PREEMPT_VOLUNTARY=y ++ ++CONFIG_SLUB=y ++CONFIG_SLUB_CPU_PARTIAL=y ++# CONFIG_SLUB_STATS is not set ++# CONFIG_SLUB_DEBUG_ON is not set ++ ++# CONFIG_AD525X_DPOT is not set ++# CONFIG_ATMEL_PWM is not set ++# CONFIG_IWMC3200TOP is not set ++# CONFIG_BLK_DEV_BSG is not set ++ ++# MX6 specific kernel configuration ++CONFIG_GPIO_PCA953X=y ++CONFIG_ARCH_MXC=y ++CONFIG_MXC_DEBUG_BOARD=y ++CONFIG_SOC_IMX6Q=y ++CONFIG_SOC_IMX6SL=y ++# CONFIG_SWP_EMULATE is not set ++CONFIG_PCI=y ++CONFIG_PCIE_DW=y ++CONFIG_PCI_IMX6=y ++CONFIG_SMP=y ++CONFIG_VMSPLIT_2G=y ++CONFIG_AEABI=y ++# CONFIG_OABI_COMPAT is not set ++CONFIG_HIGHMEM=y ++CONFIG_CMDLINE="noinitrd console=ttymxc0,115200" ++CONFIG_CPU_FREQ=y ++CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y ++CONFIG_CPU_FREQ_GOV_PERFORMANCE=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_VFPv3=y ++CONFIG_NEON=y ++CONFIG_KERNEL_MODE_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_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_ETHERNET=y ++# CONFIG_NET_VENDOR_BROADCOM is not set ++# CONFIG_NET_VENDOR_CIRRUS is not set ++# CONFIG_NET_VENDOR_FARADAY ++# CONFIG_NET_VENDOR_INTEL ++# CONFIG_NET_VENDOR_I825XX ++# CONFIG_NET_VENDOR_MARVELL ++# CONFIG_NET_VENDOR_MICROCHIP ++# CONFIG_NET_VENDOR_MICROCHIP=y ++# CONFIG_ENC28J60 is not set ++# CONFIG_NET_VENDOR_NATSEMI=y ++# CONFIG_NET_VENDOR_8390=y ++# CONFIG_AX88796 is not set ++# CONFIG_ETHOC is not set ++# CONFIG_SH_ETH is not set ++# CONFIG_NET_VENDOR_SEEQ=y ++# CONFIG_NET_VENDOR_SMSC=y ++# CONFIG_SMC91X is not set ++# CONFIG_SMC911X is not set ++# CONFIG_SMSC911X is not set ++# CONFIG_NET_VENDOR_STMICRO=y ++# CONFIG_STMMAC_ETH is not set ++# CONFIG_NET_VENDOR_VIA=y ++# CONFIG_VIA_VELOCITY is not set ++# CONFIG_NET_VENDOR_WIZNET=y ++CONFIG_NET_VENDOR_FREESCALE=y ++CONFIG_FEC=y ++CONFIG_PHYLIB=y ++CONFIG_AT803X_PHY=y ++CONFIG_WLAN=y ++CONFIG_BRCMUTIL=m ++CONFIG_BRCMFMAC=m ++CONFIG_BRCMFMAC_SDIO=y ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++CONFIG_DMA_CMA=y ++CONFIG_CMA=y ++CONFIG_CMA_SIZE_MBYTES=256 ++CONFIG_CONNECTOR=y ++# CONFIG_MTD is not set ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=65536 ++# 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_NETDEVICES=y ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_EVBUG is not set ++CONFIG_KEYBOARD_GPIO=y ++CONFIG_KEYBOARD_IMX=y ++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set ++# CONFIG_KEYBOARD_ATKBD is not set ++# CONFIG_MOUSE_PS2 is not set ++CONFIG_INPUT_MISC=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_GPIO_MXC=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_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_ANATOP=y ++CONFIG_REGULATOR_PFUZE100=y ++CONFIG_MEDIA_SUPPORT=y ++CONFIG_MEDIA_CAMERA_SUPPORT=y ++# CONFIG_MEDIA_RADIO_SUPPORT is not set ++CONFIG_VIDEO_V4L2_INT_DEVICE=y ++CONFIG_MEDIA_USB_SUPPORT=y ++CONFIG_USB_VIDEO_CLASS=m ++# CONFIG_RADIO_ADAPTERS is not set ++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_SOC_CAMERA_OV2640=y ++CONFIG_DRM=y ++CONFIG_DRM_VIVANTE=y ++CONFIG_FB=y ++# CONFIG_FB_MX3 is not set ++CONFIG_FB_MXC_SYNC_PANEL=y ++CONFIG_FB_MXC_LDB=y ++CONFIG_FB_MXC_HDMI=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_IMX_SGTL5000=y ++CONFIG_SND_SOC_IMX_SPDIF=y ++CONFIG_SND_SOC_IMX_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_NOP_USB_XCEIV=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_MIPI_CSI2=y ++CONFIG_MXC_MLB150=m ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++CONFIG_LEDS_GPIO=y ++CONFIG_LEDS_TRIGGERS=y ++CONFIG_LEDS_TRIGGER_GPIO=y ++CONFIG_RTC_CLASS=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_SRAM=y ++CONFIG_STAGING=y ++CONFIG_COMMON_CLK_DEBUG=y ++# CONFIG_IOMMU_SUPPORT is not set ++CONFIG_PWM=y ++CONFIG_PWM_SYSFS=y ++CONFIG_PWM_IMX=y ++CONFIG_IRQCHIP=y ++CONFIG_ARM_GIC=y ++CONFIG_ARCH_HAS_RESET_CONTROLLER=y ++CONFIG_RESET_CONTROLLER=y ++CONFIG_RESET_GPIO=y ++CONFIG_EXT4_FS=y ++CONFIG_EXT4_USE_FOR_EXT23=y ++CONFIG_EXT4_FS_XATTR=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_TEST=m ++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_XTS=y ++CONFIG_CRYPTO_MD4=y ++CONFIG_CRYPTO_MD5=y ++CONFIG_CRYPTO_MICHAEL_MIC=y ++CONFIG_CRYPTO_RMD128=y ++CONFIG_CRYPTO_RMD160=y ++CONFIG_CRYPTO_RMD256=y ++CONFIG_CRYPTO_RMD320=y ++CONFIG_CRYPTO_SHA1=y ++CONFIG_CRYPTO_SHA256=y ++CONFIG_CRYPTO_SHA512=y ++CONFIG_CRYPTO_TGR192=y ++CONFIG_CRYPTO_WP512=y ++CONFIG_CRYPTO_BLOWFISH=y ++CONFIG_CRYPTO_CAMELLIA=y ++CONFIG_CRYPTO_DES=y ++CONFIG_CRYPTO_TWOFISH=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_CRYPTO_AES_ARM_BS=y ++CONFIG_CRC_CCITT=m ++CONFIG_CRC_T10DIF=y ++CONFIG_CRC7=m ++CONFIG_LIBCRC32C=m ++# CONFIG_MXC_MMA8451 is not set ++ ++# ++# Loadable module support ++# ++# CONFIG_MODULE_FORCE_LOAD is not set ++# -- MODULE_FORCE_UNLOAD is controlled by config-debug/nodebug ++ ++# CONFIG_PCI_DEBUG is not set ++CONFIG_PCI_STUB=y ++CONFIG_PCI_IOV=y ++CONFIG_PCI_PRI=y ++CONFIG_PCI_PASID=y ++CONFIG_HT_IRQ=y ++CONFIG_PCI_MSI=y ++# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set ++CONFIG_PCIEPORTBUS=y ++CONFIG_PCIEAER=y ++CONFIG_PCIEASPM=y ++# CONFIG_PCIEASPM_DEBUG is not set ++CONFIG_PCIE_ECRC=y ++CONFIG_PCIEAER_INJECT=m ++CONFIG_HOTPLUG_PCI_PCIE=y ++CONFIG_HOTPLUG_PCI_FAKE=m ++ ++# CONFIG_SGI_IOC4 is not set ++ ++# CONFIG_ISA is not set ++# CONFIG_SCx200 is not set ++ ++# ++# PCMCIA/CardBus support ++# FIXME: Deprecate Cardbus ? ++# ++CONFIG_PCMCIA=y ++CONFIG_PCMCIA_LOAD_CIS=y ++# CONFIG_PCMCIA_DEBUG is not set ++CONFIG_YENTA=m ++CONFIG_CARDBUS=y ++CONFIG_I82092=m ++CONFIG_PD6729=m ++ ++CONFIG_PCCARD=y ++CONFIG_SDIO_UART=m ++# CONFIG_MMC_TEST is not set ++# CONFIG_MMC_DEBUG is not set ++# https://lists.fedoraproject.org/pipermail/kernel/2014-February/004889.html ++# CONFIG_MMC_CLKGATE is not set ++CONFIG_MMC_BLOCK=y ++CONFIG_MMC_BLOCK_MINORS=8 ++CONFIG_MMC_BLOCK_BOUNCE=y ++CONFIG_MMC_SDHCI_PCI=m ++CONFIG_MMC_SDHCI_ACPI=m ++CONFIG_MMC_SDRICOH_CS=m ++CONFIG_MMC_TIFM_SD=m ++CONFIG_MMC_WBSD=m ++CONFIG_MMC_VIA_SDMMC=m ++CONFIG_MMC_CB710=m ++CONFIG_MMC_RICOH_MMC=y ++CONFIG_MMC_USHC=m ++CONFIG_MMC_REALTEK_PCI=m ++CONFIG_MMC_VUB300=m ++# CONFIG_MMC_SDHCI_PXAV2 is not set ++# CONFIG_MMC_SDHCI_PXAV3 is not set ++# CONFIG_MMC_SDHCI_OF_ARASAN is not set ++ ++ ++CONFIG_CB710_CORE=m ++# CONFIG_CB710_DEBUG is not set ++ ++CONFIG_INFINIBAND=m ++CONFIG_INFINIBAND_MTHCA=m ++# CONFIG_INFINIBAND_MTHCA_DEBUG is not set ++CONFIG_INFINIBAND_IPOIB=m ++CONFIG_INFINIBAND_IPOIB_DEBUG=y ++CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y ++CONFIG_INFINIBAND_IPOIB_CM=y ++CONFIG_INFINIBAND_SRP=m ++CONFIG_INFINIBAND_SRPT=m ++CONFIG_INFINIBAND_USER_MAD=m ++CONFIG_INFINIBAND_USER_ACCESS=m ++# CONFIG_INFINIBAND_EXPERIMENTAL_UVERBS_FLOW_STEERING is not set #staging ++CONFIG_INFINIBAND_IPATH=m ++CONFIG_INFINIBAND_ISER=m ++CONFIG_INFINIBAND_ISERT=m ++CONFIG_INFINIBAND_AMSO1100=m ++# CONFIG_INFINIBAND_AMSO1100_DEBUG is not set ++CONFIG_INFINIBAND_CXGB3=m ++CONFIG_INFINIBAND_CXGB4=m ++CONFIG_SCSI_CXGB3_ISCSI=m ++CONFIG_SCSI_CXGB4_ISCSI=m ++# CONFIG_INFINIBAND_CXGB3_DEBUG is not set ++CONFIG_MLX4_INFINIBAND=m ++CONFIG_MLX5_INFINIBAND=m ++CONFIG_INFINIBAND_NES=m ++# CONFIG_INFINIBAND_NES_DEBUG is not set ++CONFIG_INFINIBAND_QIB=m ++CONFIG_INFINIBAND_QIB_DCA=y ++# CONFIG_INFINIBAND_OCRDMA is not set ++# CONFIG_INFINIBAND_USNIC is not set ++ ++# ++# Executable file formats ++# ++CONFIG_BINFMT_ELF=y ++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_SCRIPT=y ++ ++# ++# Device Drivers ++# ++ ++# CONFIG_COMMON_CLK_SI5351 is not set ++ ++# ++# Generic Driver Options ++# ++CONFIG_FW_LOADER=y ++# CONFIG_FIRMWARE_IN_KERNEL is not set ++CONFIG_EXTRA_FIRMWARE="" ++ ++# Give this a try in rawhide for now ++# CONFIG_FW_LOADER_USER_HELPER is not set ++ ++ ++ ++# ++# Memory Technology Devices (MTD) ++# ++# CONFIG_MTD_TESTS is not set ++# CONFIG_MTD_REDBOOT_PARTS is not set ++# CONFIG_MTD_AR7_PARTS is not set ++# CONFIG_MTD_CMDLINE_PARTS is not set ++ ++# ++# User Modules And Translation Layers ++# ++# CONFIG_MTD_CHAR is not set ++# CONFIG_MTD_BLKDEVS is not set ++# CONFIG_MTD_BLOCK is not set ++# CONFIG_MTD_BLOCK_RO is not set ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++# CONFIG_INFTL is not set ++# CONFIG_RFD_FTL is not set ++# CONFIG_SSFDC is not set ++# CONFIG_SM_FTL is not set ++# CONFIG_MTD_OOPS is not set ++# CONFIG_MTD_SWAP is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++# CONFIG_MTD_CFI is not set ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_MAP_BANK_WIDTH_1=y ++CONFIG_MTD_MAP_BANK_WIDTH_2=y ++CONFIG_MTD_MAP_BANK_WIDTH_4=y ++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set ++CONFIG_MTD_CFI_I1=y ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_COMPLEX_MAPPINGS is not set ++# CONFIG_MTD_TS5500 is not set ++# CONFIG_MTD_INTEL_VR_NOR is not set ++# CONFIG_MTD_PLATRAM is not set ++ ++# Self-contained MTD device drivers ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_PHRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLOCK2MTD is not set ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# CONFIG_MTD_DOCG3 is not set ++# CONFIG_MTD_NAND is not set ++# CONFIG_MTD_ONENAND is not set ++# CONFIG_MTD_NAND_VERIFY_WRITE is not set ++# CONFIG_MTD_NAND_ECC_BCH is not set ++# CONFIG_MTD_NAND_MUSEUM_IDS is not set ++# CONFIG_MTD_NAND_DISKONCHIP is not set ++# CONFIG_MTD_LPDDR is not set ++CONFIG_MTD_UBI=m ++CONFIG_MTD_UBI_WL_THRESHOLD=4096 ++CONFIG_MTD_UBI_BEB_LIMIT=20 ++# CONFIG_MTD_UBI_FASTMAP is not set ++# CONFIG_MTD_UBI_GLUEBI is not set ++ ++# ++# Parallel port support ++# ++CONFIG_PARPORT=m ++CONFIG_PARPORT_PC=m ++CONFIG_PARPORT_SERIAL=m ++# CONFIG_PARPORT_PC_FIFO is not set ++# CONFIG_PARPORT_PC_SUPERIO is not set ++CONFIG_PARPORT_PC_PCMCIA=m ++CONFIG_PARPORT_1284=y ++# CONFIG_PARPORT_AX88796 is not set ++ ++CONFIG_ACPI_PCI_SLOT=y ++CONFIG_HOTPLUG_PCI_ACPI=y ++CONFIG_HOTPLUG_PCI_ACPI_IBM=m ++ ++# ++# Block devices ++# ++CONFIG_BLK_DEV=y ++CONFIG_BLK_DEV_NULL_BLK=m ++CONFIG_BLK_DEV_FD=m ++# CONFIG_PARIDE is not set ++CONFIG_ZRAM=m ++# CONFIG_ZRAM_DEBUG is not set ++CONFIG_ENHANCEIO=m ++ ++CONFIG_BLK_CPQ_DA=m ++CONFIG_BLK_CPQ_CISS_DA=m ++CONFIG_CISS_SCSI_TAPE=y ++CONFIG_BLK_DEV_DAC960=m ++# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set ++CONFIG_BLK_DEV_DRBD=m ++CONFIG_BLK_DEV_UMEM=m ++CONFIG_BLK_DEV_LOOP_MIN_COUNT=0 ++# Fedora 18 util-linux is the last release that supports cryptoloop devices ++# CONFIG_BLK_DEV_CRYPTOLOOP is not set ++CONFIG_BLK_DEV_NBD=m ++CONFIG_BLK_DEV_NVME=m ++CONFIG_BLK_DEV_SKD=m # 64-bit only but easier to put here ++CONFIG_BLK_DEV_OSD=m ++CONFIG_BLK_DEV_RAM_COUNT=16 ++CONFIG_BLK_DEV_IO_TRACE=y ++ ++CONFIG_BLK_DEV_BSGLIB=y ++CONFIG_BLK_DEV_INTEGRITY=y ++CONFIG_BLK_DEV_THROTTLING=y ++# CONFIG_BLK_CMDLINE_PARSER is not set ++ ++ ++# ++# ATA/ATAPI/MFM/RLL support ++# ++# CONFIG_IDE is not set ++ ++# CONFIG_BLK_DEV_HD is not set ++# CONFIG_BLK_DEV_RSXX is not set ++ ++CONFIG_SCSI_VIRTIO=m ++CONFIG_VIRTIO_BLK=m ++CONFIG_VIRTIO_PCI=m ++CONFIG_VIRTIO_BALLOON=m ++CONFIG_VIRTIO_MMIO=m ++# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set ++CONFIG_VIRTIO_NET=m ++CONFIG_HW_RANDOM_VIRTIO=m ++CONFIG_VIRTIO_CONSOLE=m ++CONFIG_VHOST_NET=m ++CONFIG_TCM_VHOST=m ++CONFIG_VHOST_SCSI=m ++ ++# ++# SCSI device support ++# ++CONFIG_SCSI=y ++ ++CONFIG_SCSI_ENCLOSURE=m ++CONFIG_SCSI_SRP=m ++CONFIG_SCSI_SRP_ATTRS=m ++CONFIG_SCSI_TGT=m ++CONFIG_SCSI_ISCI=m ++CONFIG_SCSI_CHELSIO_FCOE=m ++ ++CONFIG_SCSI_DH=y ++CONFIG_SCSI_DH_RDAC=m ++CONFIG_SCSI_DH_HP_SW=m ++CONFIG_SCSI_DH_EMC=m ++CONFIG_SCSI_DH_ALUA=m ++ ++# ++# SCSI support type (disk, tape, CD-ROM) ++# ++CONFIG_CHR_DEV_ST=m ++CONFIG_CHR_DEV_OSST=m ++CONFIG_BLK_DEV_SR=y ++CONFIG_BLK_DEV_SR_VENDOR=y ++CONFIG_CHR_DEV_SG=y ++CONFIG_CHR_DEV_SCH=m ++ ++# ++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs ++# ++CONFIG_SCSI_SPI_ATTRS=m ++CONFIG_SCSI_FC_ATTRS=m ++CONFIG_SCSI_FC_TGT_ATTRS=y ++CONFIG_SCSI_ISCSI_ATTRS=m ++CONFIG_SCSI_SAS_ATTRS=m ++CONFIG_SCSI_SRP_TGT_ATTRS=y ++CONFIG_SCSI_SAS_LIBSAS=m ++CONFIG_SCSI_SAS_ATA=y ++CONFIG_SCSI_SAS_HOST_SMP=y ++CONFIG_RAID_ATTRS=m ++ ++CONFIG_ISCSI_TCP=m ++CONFIG_ISCSI_BOOT_SYSFS=m ++ ++# ++# SCSI low-level drivers ++# ++CONFIG_BLK_DEV_3W_XXXX_RAID=m ++CONFIG_SCSI_3W_9XXX=m ++CONFIG_SCSI_ACARD=m ++CONFIG_SCSI_AACRAID=m ++CONFIG_SCSI_AIC7XXX=m ++# http://lists.fedoraproject.org/pipermail/kernel/2013-February/004102.html ++# CONFIG_SCSI_AIC7XXX_OLD is not set ++CONFIG_AIC7XXX_CMDS_PER_DEVICE=4 ++CONFIG_AIC7XXX_RESET_DELAY_MS=15000 ++# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set ++# CONFIG_AIC7XXX_DEBUG_ENABLE is not set ++CONFIG_AIC7XXX_DEBUG_MASK=0 ++# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set ++CONFIG_SCSI_AIC79XX=m ++CONFIG_AIC79XX_CMDS_PER_DEVICE=4 ++CONFIG_AIC79XX_RESET_DELAY_MS=15000 ++# CONFIG_AIC79XX_BUILD_FIRMWARE is not set ++# CONFIG_AIC79XX_DEBUG_ENABLE is not set ++CONFIG_AIC79XX_DEBUG_MASK=0 ++# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set ++CONFIG_SCSI_AIC94XX=m ++# CONFIG_AIC94XX_DEBUG is not set ++# CONFIG_SCSI_ADVANSYS is not set ++CONFIG_SCSI_BFA_FC=m ++CONFIG_MEGARAID_NEWGEN=y ++CONFIG_MEGARAID_MM=m ++CONFIG_MEGARAID_MAILBOX=m ++CONFIG_MEGARAID_LEGACY=m ++CONFIG_MEGARAID_SAS=m ++CONFIG_SCSI_ESAS2R=m ++CONFIG_SCSI_MVSAS=m ++# CONFIG_SCSI_MVSAS_DEBUG is not set ++CONFIG_SCSI_MVSAS_TASKLET=y ++CONFIG_SCSI_MPT2SAS=m ++CONFIG_SCSI_MPT2SAS_MAX_SGE=128 ++CONFIG_SCSI_MPT2SAS_LOGGING=y ++CONFIG_SCSI_MPT3SAS=m ++CONFIG_SCSI_MPT3SAS_MAX_SGE=128 ++CONFIG_SCSI_MPT3SAS_LOGGING=y ++ ++CONFIG_SCSI_UFSHCD=m ++CONFIG_SCSI_UFSHCD_PCI=m ++# CONFIG_SCSI_UFSHCD_PLATFORM is not set ++ ++CONFIG_SCSI_MVUMI=m ++ ++CONFIG_SCSI_OSD_INITIATOR=m ++CONFIG_SCSI_OSD_ULD=m ++CONFIG_SCSI_OSD_DPRINT_SENSE=1 ++# CONFIG_SCSI_OSD_DEBUG is not set ++ ++CONFIG_SCSI_BNX2_ISCSI=m ++CONFIG_SCSI_BNX2X_FCOE=m ++CONFIG_BE2ISCSI=m ++CONFIG_SCSI_PMCRAID=m ++ ++CONFIG_SCSI_HPSA=m ++CONFIG_SCSI_3W_SAS=m ++CONFIG_SCSI_PM8001=m ++CONFIG_VMWARE_PVSCSI=m ++CONFIG_VMWARE_BALLOON=m ++ ++CONFIG_SCSI_ARCMSR=m ++CONFIG_SCSI_BUSLOGIC=m ++CONFIG_SCSI_INITIO=m ++CONFIG_SCSI_FLASHPOINT=y ++CONFIG_SCSI_DMX3191D=m ++# CONFIG_SCSI_EATA is not set ++# CONFIG_SCSI_EATA_PIO is not set ++# CONFIG_SCSI_FUTURE_DOMAIN is not set ++CONFIG_SCSI_GDTH=m ++CONFIG_SCSI_HPTIOP=m ++CONFIG_SCSI_IPS=m ++CONFIG_SCSI_INIA100=m ++# CONFIG_SCSI_PPA is not set ++# CONFIG_SCSI_IMM is not set ++# CONFIG_SCSI_IZIP_EPP16 is not set ++# CONFIG_SCSI_IZIP_SLOW_CTR is not set ++CONFIG_SCSI_STEX=m ++CONFIG_SCSI_SYM53C8XX_2=m ++CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 ++CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 ++CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 ++CONFIG_SCSI_SYM53C8XX_MMIO=y ++CONFIG_SCSI_QLOGIC_1280=m ++CONFIG_SCSI_DC395x=m ++# CONFIG_SCSI_NSP32 is not set ++CONFIG_SCSI_DEBUG=m ++CONFIG_SCSI_DC390T=m ++CONFIG_SCSI_QLA_FC=m ++CONFIG_TCM_QLA2XXX=m ++CONFIG_SCSI_QLA_ISCSI=m ++CONFIG_SCSI_IPR=m ++CONFIG_SCSI_IPR_TRACE=y ++CONFIG_SCSI_IPR_DUMP=y ++# CONFIG_SCSI_DPT_I2O is not set ++CONFIG_SCSI_LPFC=m ++# CONFIG_SCSI_LPFC_DEBUG_FS is not set ++ ++# PCMCIA SCSI adapter support ++# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set ++ ++CONFIG_ATA_BMDMA=y ++CONFIG_ATA_VERBOSE_ERROR=y ++CONFIG_ATA_SFF=y ++CONFIG_ATA_PIIX=y ++# CONFIG_SATA_HIGHBANK is not set ++CONFIG_ATA_ACPI=y ++CONFIG_BLK_DEV_SX8=m ++CONFIG_PDC_ADMA=m ++CONFIG_SATA_AHCI=y ++CONFIG_SATA_INIC162X=m ++CONFIG_SATA_MV=m ++CONFIG_SATA_NV=m ++CONFIG_SATA_PMP=y ++CONFIG_SATA_PROMISE=m ++CONFIG_SATA_QSTOR=m ++CONFIG_SATA_RCAR=m ++CONFIG_SATA_SIL=m ++CONFIG_SATA_SIL24=m ++CONFIG_SATA_SIS=m ++CONFIG_SATA_SVW=m ++CONFIG_SATA_SX4=m ++CONFIG_SATA_ULI=m ++CONFIG_SATA_VIA=m ++CONFIG_SATA_VITESSE=m ++# CONFIG_SATA_ZPODD is not set ++CONFIG_SATA_ACARD_AHCI=m ++ ++# CONFIG_PATA_LEGACY is not set ++CONFIG_PATA_ACPI=m ++CONFIG_PATA_ALI=m ++CONFIG_PATA_AMD=m ++CONFIG_PATA_ARASAN_CF=m ++CONFIG_PATA_ARTOP=m ++CONFIG_PATA_ATIIXP=m ++CONFIG_PATA_CMD640_PCI=m ++CONFIG_PATA_CMD64X=m ++CONFIG_PATA_CS5520=m ++CONFIG_PATA_CS5530=m ++CONFIG_PATA_CS5535=m ++CONFIG_PATA_CS5536=m ++CONFIG_PATA_CYPRESS=m ++CONFIG_PATA_EFAR=m ++CONFIG_ATA_GENERIC=m ++CONFIG_PATA_HPT366=m ++CONFIG_PATA_HPT37X=m ++CONFIG_PATA_HPT3X2N=m ++CONFIG_PATA_HPT3X3=m ++# CONFIG_PATA_HPT3X3_DMA is not set ++CONFIG_PATA_IT821X=m ++CONFIG_PATA_IT8213=m ++CONFIG_PATA_JMICRON=m ++CONFIG_PATA_NINJA32=m ++CONFIG_PATA_MARVELL=m ++CONFIG_PATA_MPIIX=m ++CONFIG_PATA_NETCELL=m ++CONFIG_PATA_NS87410=m ++CONFIG_PATA_NS87415=m ++CONFIG_PATA_OLDPIIX=m ++CONFIG_PATA_OPTI=m ++CONFIG_PATA_OPTIDMA=m ++CONFIG_PATA_PCMCIA=m ++CONFIG_PATA_PDC_OLD=m ++# CONFIG_PATA_RADISYS is not set ++CONFIG_PATA_RDC=m ++# CONFIG_PATA_RZ1000 is not set ++# CONFIG_PATA_SC1200 is not set ++CONFIG_PATA_SERVERWORKS=m ++CONFIG_PATA_PDC2027X=m ++CONFIG_PATA_SCH=m ++CONFIG_PATA_SIL680=m ++CONFIG_PATA_SIS=m ++CONFIG_PATA_TOSHIBA=m ++CONFIG_PATA_TRIFLEX=m ++CONFIG_PATA_VIA=m ++CONFIG_PATA_WINBOND=m ++CONFIG_PATA_ATP867X=m ++ ++ ++# ++# Multi-device support (RAID and LVM) ++# ++CONFIG_MD=y ++CONFIG_BLK_DEV_MD=y ++CONFIG_MD_AUTODETECT=y ++CONFIG_MD_FAULTY=m ++CONFIG_MD_LINEAR=m ++CONFIG_MD_MULTIPATH=m ++CONFIG_MD_RAID0=m ++CONFIG_MD_RAID1=m ++CONFIG_MD_RAID10=m ++CONFIG_MD_RAID456=m ++ ++CONFIG_BCACHE=m ++# CONFIG_BCACHE_DEBUG is not set ++# CONFIG_BCACHE_EDEBUG is not set ++# CONFIG_BCACHE_CLOSURES_DEBUG is not set ++ ++# CONFIG_MULTICORE_RAID456 is not set ++CONFIG_ASYNC_RAID6_TEST=m ++CONFIG_BLK_DEV_DM=y ++CONFIG_DM_CRYPT=m ++CONFIG_DM_DEBUG=y ++CONFIG_DM_DELAY=m ++CONFIG_DM_MIRROR=y ++CONFIG_DM_MULTIPATH=m ++CONFIG_DM_SNAPSHOT=y ++CONFIG_DM_THIN_PROVISIONING=m ++CONFIG_DM_CACHE=m ++CONFIG_DM_CACHE_MQ=m ++CONFIG_DM_CACHE_CLEANER=m ++# CONFIG_DM_DEBUG_BLOCK_STACK_TRACING is not set ++# CONFIG_DM_DEBUG_SPACE_MAPS is not set ++CONFIG_DM_UEVENT=y ++CONFIG_DM_ZERO=y ++CONFIG_DM_LOG_USERSPACE=m ++CONFIG_DM_MULTIPATH_QL=m ++CONFIG_DM_MULTIPATH_ST=m ++CONFIG_DM_RAID=m ++CONFIG_DM_FLAKEY=m ++CONFIG_DM_VERITY=m ++CONFIG_DM_SWITCH=m ++ ++# ++# Fusion MPT device support ++# ++CONFIG_FUSION=y ++CONFIG_FUSION_SPI=m ++CONFIG_FUSION_FC=m ++CONFIG_FUSION_MAX_SGE=40 ++CONFIG_FUSION_CTL=m ++CONFIG_FUSION_LAN=m ++CONFIG_FUSION_SAS=m ++CONFIG_FUSION_LOGGING=y ++ ++# ++# IEEE 1394 (FireWire) support (JUJU alternative stack) ++# ++CONFIG_FIREWIRE=m ++CONFIG_FIREWIRE_OHCI=m ++CONFIG_FIREWIRE_SBP2=m ++CONFIG_FIREWIRE_NET=m ++CONFIG_FIREWIRE_OHCI_DEBUG=y ++CONFIG_FIREWIRE_NOSY=m ++# CONFIG_FIREWIRE_SERIAL is not set ++# CONFIG_FIREWIRE_OHCI_REMOTE_DMA is not set ++ ++# ++# IEEE 1394 (FireWire) support ++# ++ ++# ++# I2O device support ++# ++# CONFIG_I2O is not set ++# CONFIG_I2O_LCT_NOTIFY_ON_CHANGES is not set ++ ++# ++# Virtualization support drivers ++# ++# CONFIG_VIRT_DRIVERS is not set ++ ++# Networking support ++# ++ ++CONFIG_NET_DMA=y ++ ++CONFIG_NETLINK_MMAP=y ++CONFIG_NETLINK_DIAG=m ++ ++CONFIG_TCP_CONG_ADVANCED=y ++CONFIG_TCP_CONG_BIC=m ++CONFIG_TCP_CONG_CUBIC=y ++CONFIG_TCP_CONG_HTCP=m ++CONFIG_TCP_CONG_HSTCP=m ++CONFIG_TCP_CONG_HYBLA=m ++CONFIG_TCP_CONG_ILLINOIS=m ++CONFIG_TCP_CONG_LP=m ++CONFIG_TCP_CONG_SCALABLE=m ++CONFIG_TCP_CONG_VEGAS=m ++CONFIG_TCP_CONG_VENO=m ++CONFIG_TCP_CONG_WESTWOOD=m ++CONFIG_TCP_CONG_YEAH=m ++ ++CONFIG_TCP_MD5SIG=y ++ ++# ++# Networking options ++# ++CONFIG_PACKET_DIAG=m ++CONFIG_UNIX_DIAG=m ++CONFIG_NET_KEY=m ++CONFIG_NET_KEY_MIGRATE=y ++CONFIG_INET_TUNNEL=m ++CONFIG_INET_DIAG=m ++CONFIG_INET_UDP_DIAG=m ++CONFIG_IP_MULTICAST=y ++CONFIG_IP_ADVANCED_ROUTER=y ++CONFIG_IP_FIB_TRIE_STATS=y ++CONFIG_IP_MULTIPLE_TABLES=y ++CONFIG_IP_ROUTE_MULTIPATH=y ++CONFIG_IP_ROUTE_VERBOSE=y ++CONFIG_IP_NF_SECURITY=m ++CONFIG_NET_IPIP=m ++CONFIG_NET_IPGRE_DEMUX=m ++CONFIG_NET_IPGRE=m ++CONFIG_NET_IPGRE_BROADCAST=y ++CONFIG_IP_MROUTE=y ++CONFIG_IP_MROUTE_MULTIPLE_TABLES=y ++CONFIG_IP_PIMSM_V1=y ++CONFIG_IP_PIMSM_V2=y ++CONFIG_ARPD=y ++CONFIG_SYN_COOKIES=y ++CONFIG_NET_IPVTI=m ++CONFIG_INET_AH=m ++CONFIG_INET_ESP=m ++CONFIG_INET_IPCOMP=m ++CONFIG_NETCONSOLE=m ++CONFIG_NETCONSOLE_DYNAMIC=y ++CONFIG_NETPOLL_TRAP=y ++CONFIG_NET_POLL_CONTROLLER=y ++ ++# ++# IP: Virtual Server Configuration ++# ++CONFIG_IP_VS=m ++# CONFIG_IP_VS_DEBUG is not set ++CONFIG_IP_VS_TAB_BITS=12 ++CONFIG_IP_VS_PROTO_TCP=y ++CONFIG_IP_VS_PROTO_UDP=y ++CONFIG_IP_VS_PROTO_ESP=y ++CONFIG_IP_VS_PROTO_AH=y ++CONFIG_IP_VS_PROTO_SCTP=y ++CONFIG_IP_VS_IPV6=y ++CONFIG_IP_VS_RR=m ++CONFIG_IP_VS_WRR=m ++CONFIG_IP_VS_LC=m ++CONFIG_IP_VS_WLC=m ++CONFIG_IP_VS_LBLC=m ++CONFIG_IP_VS_LBLCR=m ++CONFIG_IP_VS_DH=m ++CONFIG_IP_VS_SH=m ++CONFIG_IP_VS_SED=m ++CONFIG_IP_VS_NQ=m ++ ++# ++# IPVS SH scheduler ++# ++CONFIG_IP_VS_SH_TAB_BITS=8 ++ ++CONFIG_IP_VS_FTP=m ++CONFIG_IP_VS_PE_SIP=m ++ ++CONFIG_IPV6_PRIVACY=y ++CONFIG_IPV6_ROUTER_PREF=y ++CONFIG_IPV6_ROUTE_INFO=y ++CONFIG_IPV6_OPTIMISTIC_DAD=y ++CONFIG_INET6_AH=m ++CONFIG_INET6_ESP=m ++CONFIG_INET6_IPCOMP=m ++CONFIG_IPV6_MIP6=y ++CONFIG_IPV6_VTI=m ++CONFIG_IPV6_SIT=m ++CONFIG_IPV6_SIT_6RD=y ++CONFIG_IPV6_TUNNEL=m ++# CONFIG_IPV6_GRE is not set ++CONFIG_IPV6_SUBTREES=y ++CONFIG_IPV6_MULTIPLE_TABLES=y ++CONFIG_IPV6_MROUTE=y ++CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y ++CONFIG_IPV6_PIMSM_V2=y ++ ++CONFIG_RDS=m ++# CONFIG_RDS_DEBUG is not set ++CONFIG_RDS_RDMA=m ++CONFIG_RDS_TCP=m ++ ++CONFIG_NET_9P=m ++CONFIG_NET_9P_VIRTIO=m ++# CONFIG_NET_9P_DEBUG is not set ++CONFIG_NET_9P_RDMA=m ++ ++# CONFIG_DECNET is not set ++CONFIG_BRIDGE=m ++CONFIG_BRIDGE_IGMP_SNOOPING=y ++CONFIG_BRIDGE_VLAN_FILTERING=y ++ ++# PHY timestamping adds overhead ++CONFIG_NETWORK_PHY_TIMESTAMPING=y ++ ++CONFIG_NETFILTER_ADVANCED=y ++CONFIG_NF_CONNTRACK=m ++CONFIG_NETFILTER_NETLINK=m ++CONFIG_NETFILTER_NETLINK_ACCT=m ++CONFIG_NETFILTER_NETLINK_QUEUE=m ++CONFIG_NETFILTER_NETLINK_QUEUE_CT=y ++CONFIG_NETFILTER_NETLINK_LOG=m ++CONFIG_NETFILTER_TPROXY=m ++CONFIG_NETFILTER_XTABLES=y ++CONFIG_NETFILTER_XT_SET=m ++CONFIG_NETFILTER_XT_MARK=m ++CONFIG_NETFILTER_XT_CONNMARK=m ++ ++CONFIG_NETFILTER_XT_TARGET_AUDIT=m ++CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m ++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m ++CONFIG_NETFILTER_XT_TARGET_CONNMARK=m ++CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m ++CONFIG_NETFILTER_XT_TARGET_CT=m ++CONFIG_NETFILTER_XT_TARGET_DSCP=m ++CONFIG_NETFILTER_XT_TARGET_HMARK=m ++CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m ++CONFIG_NETFILTER_XT_TARGET_LED=m ++CONFIG_NETFILTER_XT_TARGET_LOG=m ++CONFIG_NETFILTER_XT_TARGET_MARK=m ++CONFIG_NETFILTER_XT_TARGET_NFLOG=m ++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m ++CONFIG_NETFILTER_XT_TARGET_NOTRACK=m ++CONFIG_NETFILTER_XT_TARGET_RATEEST=m ++CONFIG_NETFILTER_XT_TARGET_SECMARK=m ++CONFIG_NETFILTER_XT_TARGET_TCPMSS=m ++CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m ++CONFIG_NETFILTER_XT_TARGET_TRACE=m ++CONFIG_NETFILTER_XT_TARGET_TEE=m ++CONFIG_NETFILTER_XT_TARGET_TPROXY=m ++ ++CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m ++CONFIG_NETFILTER_XT_MATCH_BPF=m ++CONFIG_NETFILTER_XT_MATCH_CGROUP=m ++CONFIG_NETFILTER_XT_MATCH_CLUSTER=m ++CONFIG_NETFILTER_XT_MATCH_COMMENT=m ++CONFIG_NETFILTER_XT_MATCH_CPU=m ++CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m ++CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m ++CONFIG_NETFILTER_XT_MATCH_CONNMARK=m ++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m ++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y ++CONFIG_NETFILTER_XT_MATCH_DCCP=m ++CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m ++CONFIG_NETFILTER_XT_MATCH_DSCP=m ++CONFIG_NETFILTER_XT_MATCH_ECN=m ++CONFIG_NETFILTER_XT_MATCH_ESP=m ++CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m ++CONFIG_NETFILTER_XT_MATCH_HELPER=m ++CONFIG_NETFILTER_XT_MATCH_HL=m ++CONFIG_NETFILTER_XT_MATCH_IPCOMP=m ++CONFIG_NETFILTER_XT_MATCH_IPRANGE=m ++CONFIG_NETFILTER_XT_MATCH_IPVS=m ++CONFIG_NETFILTER_XT_MATCH_L2TP=m ++CONFIG_NETFILTER_XT_MATCH_LENGTH=m ++CONFIG_NETFILTER_XT_MATCH_LIMIT=m ++CONFIG_NETFILTER_XT_MATCH_MAC=m ++CONFIG_NETFILTER_XT_MATCH_MARK=m ++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m ++CONFIG_NETFILTER_XT_MATCH_NFACCT=m ++CONFIG_NETFILTER_XT_MATCH_OSF=m ++CONFIG_NETFILTER_XT_MATCH_OWNER=m ++CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m ++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m ++CONFIG_NETFILTER_XT_MATCH_POLICY=m ++CONFIG_NETFILTER_XT_MATCH_QUOTA=m ++CONFIG_NETFILTER_XT_MATCH_RATEEST=m ++CONFIG_NETFILTER_XT_MATCH_REALM=m ++CONFIG_NETFILTER_XT_MATCH_RECENT=m ++CONFIG_NETFILTER_XT_MATCH_SCTP=m ++CONFIG_NETFILTER_XT_MATCH_SOCKET=m ++CONFIG_NETFILTER_XT_MATCH_STATE=y ++CONFIG_NETFILTER_XT_MATCH_STATISTIC=m ++CONFIG_NETFILTER_XT_MATCH_STRING=m ++CONFIG_NETFILTER_XT_MATCH_TCPMSS=m ++CONFIG_NETFILTER_XT_MATCH_TIME=m ++CONFIG_NETFILTER_XT_MATCH_U32=m ++ ++# CONFIG_NETFILTER_DEBUG is not set ++CONFIG_BRIDGE_NETFILTER=y ++ ++# ++# IP: Netfilter Configuration ++# ++ ++CONFIG_NF_CONNTRACK_MARK=y ++CONFIG_NF_CONNTRACK_SECMARK=y ++CONFIG_NF_CONNTRACK_EVENTS=y ++CONFIG_NF_CONNTRACK_ZONES=y ++CONFIG_NF_CONNTRACK_PROCFS=y # check if contrack(8) in f17 supports netlink ++# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set ++CONFIG_NF_CONNTRACK_AMANDA=m ++CONFIG_NF_CONNTRACK_FTP=m ++CONFIG_NF_CONNTRACK_H323=m ++CONFIG_NF_CONNTRACK_IRC=m ++CONFIG_NF_CONNTRACK_NETBIOS_NS=m ++CONFIG_NF_CONNTRACK_PPTP=m ++CONFIG_NF_CONNTRACK_SANE=m ++CONFIG_NF_CONNTRACK_SIP=m ++CONFIG_NF_CONNTRACK_TFTP=m ++CONFIG_NF_CONNTRACK_IPV4=y ++CONFIG_NF_CONNTRACK_IPV6=y ++# CONFIG_NF_CONNTRACK_TIMEOUT is not set ++CONFIG_NF_CONNTRACK_TIMESTAMP=y ++CONFIG_NF_CONNTRACK_SNMP=m ++CONFIG_NF_NAT=m ++CONFIG_NF_NAT_SNMP_BASIC=m ++CONFIG_NF_CT_PROTO_DCCP=m ++CONFIG_NF_CT_PROTO_SCTP=m ++CONFIG_NF_CT_NETLINK=m ++# CONFIG_NF_CT_NETLINK_TIMEOUT is not set ++CONFIG_NF_CT_NETLINK_HELPER=m ++CONFIG_NF_CT_PROTO_UDPLITE=m ++ ++CONFIG_IP_NF_MATCH_AH=m ++CONFIG_IP_NF_MATCH_ECN=m ++CONFIG_IP_NF_MATCH_RPFILTER=m ++CONFIG_IP_NF_MATCH_TTL=m ++CONFIG_IP_NF_TARGET_CLUSTERIP=m ++CONFIG_IP_NF_TARGET_REDIRECT=m ++CONFIG_IP_NF_TARGET_NETMAP=m ++CONFIG_IP_NF_TARGET_ECN=m ++CONFIG_IP_NF_TARGET_LOG=m ++CONFIG_IP_NF_TARGET_ULOG=m ++CONFIG_IP_NF_TARGET_REJECT=y ++CONFIG_IP_NF_TARGET_SYNPROXY=m ++CONFIG_IP_NF_TARGET_TTL=m ++CONFIG_NF_NAT_IPV4=m ++CONFIG_IP_NF_TARGET_MASQUERADE=m ++CONFIG_IP_NF_MANGLE=m ++CONFIG_IP_NF_ARPTABLES=m ++CONFIG_IP_NF_ARPFILTER=m ++CONFIG_IP_NF_ARP_MANGLE=m ++CONFIG_IP_NF_QUEUE=m ++CONFIG_IP_NF_RAW=m ++ ++CONFIG_IP_NF_IPTABLES=y ++CONFIG_IP_NF_FILTER=y ++ ++# ++# IPv6: Netfilter Configuration ++# ++CONFIG_IP6_NF_FILTER=m ++CONFIG_IP6_NF_IPTABLES=m ++CONFIG_IP6_NF_MANGLE=m ++CONFIG_IP6_NF_MATCH_AH=m ++CONFIG_IP6_NF_MATCH_EUI64=m ++CONFIG_IP6_NF_MATCH_FRAG=m ++CONFIG_IP6_NF_MATCH_HL=m ++CONFIG_IP6_NF_MATCH_IPV6HEADER=m ++CONFIG_IP6_NF_MATCH_MH=m ++CONFIG_IP6_NF_MATCH_RPFILTER=m ++CONFIG_IP6_NF_MATCH_OPTS=m ++CONFIG_IP6_NF_MATCH_RT=m ++CONFIG_IP6_NF_QUEUE=m ++CONFIG_IP6_NF_RAW=m ++CONFIG_IP6_NF_SECURITY=m ++CONFIG_IP6_NF_TARGET_LOG=m ++CONFIG_IP6_NF_TARGET_REJECT=m ++CONFIG_IP6_NF_TARGET_SYNPROXY=m ++CONFIG_IP6_NF_TARGET_HL=m ++CONFIG_NF_NAT_IPV6=m ++CONFIG_IP6_NF_TARGET_MASQUERADE=m ++# CONFIG_IP6_NF_TARGET_NPT is not set ++ ++# nf_tables support ++CONFIG_NF_TABLES=m ++CONFIG_NF_TABLES_INET=m ++CONFIG_NFT_EXTHDR=m ++CONFIG_NFT_META=m ++CONFIG_NFT_CT=m ++CONFIG_NFT_RBTREE=m ++CONFIG_NFT_HASH=m ++CONFIG_NFT_COUNTER=m ++CONFIG_NFT_LOG=m ++CONFIG_NFT_LIMIT=m ++CONFIG_NFT_NAT=m ++CONFIG_NFT_QUEUE=m ++CONFIG_NFT_REJECT=m ++CONFIG_NFT_COMPAT=m ++ ++CONFIG_NF_TABLES_IPV4=m ++CONFIG_NFT_REJECT_IPV4=m ++CONFIG_NFT_CHAIN_ROUTE_IPV4=m ++CONFIG_NFT_CHAIN_NAT_IPV4=m ++CONFIG_NF_TABLES_ARP=m ++ ++CONFIG_NF_TABLES_IPV6=m ++CONFIG_NFT_CHAIN_ROUTE_IPV6=m ++CONFIG_NFT_CHAIN_NAT_IPV6=m ++ ++CONFIG_NF_TABLES_BRIDGE=m ++# ++# Bridge: Netfilter Configuration ++# ++CONFIG_BRIDGE_NF_EBTABLES=m ++CONFIG_BRIDGE_EBT_802_3=m ++CONFIG_BRIDGE_EBT_AMONG=m ++CONFIG_BRIDGE_EBT_ARP=m ++CONFIG_BRIDGE_EBT_ARPREPLY=m ++CONFIG_BRIDGE_EBT_BROUTE=m ++CONFIG_BRIDGE_EBT_DNAT=m ++CONFIG_BRIDGE_EBT_IP=m ++CONFIG_BRIDGE_EBT_IP6=m ++CONFIG_BRIDGE_EBT_LIMIT=m ++CONFIG_BRIDGE_EBT_LOG=m ++CONFIG_BRIDGE_EBT_MARK=m ++CONFIG_BRIDGE_EBT_MARK_T=m ++CONFIG_BRIDGE_EBT_NFLOG=m ++CONFIG_BRIDGE_EBT_PKTTYPE=m ++CONFIG_BRIDGE_EBT_REDIRECT=m ++CONFIG_BRIDGE_EBT_SNAT=m ++CONFIG_BRIDGE_EBT_STP=m ++CONFIG_BRIDGE_EBT_T_FILTER=m ++CONFIG_BRIDGE_EBT_T_NAT=m ++CONFIG_BRIDGE_EBT_ULOG=m ++CONFIG_BRIDGE_EBT_VLAN=m ++CONFIG_XFRM=y ++CONFIG_XFRM_MIGRATE=y ++CONFIG_XFRM_SUB_POLICY=y ++CONFIG_XFRM_STATISTICS=y ++CONFIG_XFRM_USER=y ++CONFIG_INET6_XFRM_MODE_TRANSPORT=m ++CONFIG_INET6_XFRM_MODE_TUNNEL=m ++CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m ++CONFIG_INET6_XFRM_MODE_BEET=m ++ ++CONFIG_IP_SET=m ++CONFIG_IP_SET_MAX=256 ++CONFIG_IP_SET_BITMAP_IP=m ++CONFIG_IP_SET_BITMAP_IPMAC=m ++CONFIG_IP_SET_BITMAP_PORT=m ++CONFIG_IP_SET_HASH_IP=m ++CONFIG_IP_SET_HASH_IPPORT=m ++CONFIG_IP_SET_HASH_IPPORTIP=m ++CONFIG_IP_SET_HASH_IPPORTNET=m ++CONFIG_IP_SET_HASH_NETPORTNET=m ++CONFIG_IP_SET_HASH_NET=m ++CONFIG_IP_SET_HASH_NETNET=m ++CONFIG_IP_SET_HASH_NETPORT=m ++CONFIG_IP_SET_HASH_NETIFACE=m ++CONFIG_IP_SET_LIST_SET=m ++ ++# ++# SCTP Configuration (EXPERIMENTAL) ++# ++CONFIG_IP_SCTP=m ++CONFIG_NET_SCTPPROBE=m ++# CONFIG_SCTP_DBG_MSG is not set ++# CONFIG_SCTP_DBG_OBJCNT is not set ++CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1=y ++# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5 is not set ++# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set ++CONFIG_SCTP_COOKIE_HMAC_MD5=y ++CONFIG_SCTP_COOKIE_HMAC_SHA1=y ++CONFIG_ATM=m ++CONFIG_VLAN_8021Q_GVRP=y ++CONFIG_VLAN_8021Q_MVRP=y ++CONFIG_LLC=m ++# CONFIG_LLC2 is not set ++CONFIG_IPX=m ++# CONFIG_IPX_INTERN is not set ++CONFIG_ATALK=m ++CONFIG_DEV_APPLETALK=m ++CONFIG_IPDDP=m ++CONFIG_IPDDP_ENCAP=y ++CONFIG_IPDDP_DECAP=y ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_ECONET is not set ++CONFIG_WAN_ROUTER=m ++CONFIG_IP_DCCP=m ++CONFIG_IP_DCCP_CCID2=m ++# CONFIG_IP_DCCP_CCID2_DEBUG is not set ++CONFIG_IP_DCCP_CCID3=y ++# CONFIG_IP_DCCP_CCID3_DEBUG is not set ++# CONFIG_IP_DCCP_DEBUG is not set ++# CONFIG_NET_DCCPPROBE is not set ++ ++# ++# TIPC Configuration (EXPERIMENTAL) ++# ++CONFIG_TIPC=m ++CONFIG_TIPC_PORTS=8192 ++# CONFIG_TIPC_MEDIA_IB is not set ++# CONFIG_TIPC_ADVANCED is not set ++# CONFIG_TIPC_DEBUG is not set ++ ++CONFIG_NETLABEL=y ++ ++# ++# QoS and/or fair queueing ++# ++CONFIG_NET_SCHED=y ++CONFIG_NET_SCH_CBQ=m ++CONFIG_NET_SCH_DSMARK=m ++CONFIG_NET_SCH_DRR=m ++CONFIG_NET_SCH_GRED=m ++CONFIG_NET_SCH_HFSC=m ++CONFIG_NET_SCH_HTB=m ++CONFIG_NET_SCH_INGRESS=m ++CONFIG_NET_SCH_NETEM=m ++CONFIG_NET_SCH_PRIO=m ++CONFIG_NET_SCH_RED=m ++CONFIG_NET_SCH_SFQ=m ++CONFIG_NET_SCH_TBF=m ++CONFIG_NET_SCH_TEQL=m ++CONFIG_NET_SCH_SFB=m ++CONFIG_NET_SCH_MQPRIO=m ++CONFIG_NET_SCH_MULTIQ=m ++CONFIG_NET_SCH_CHOKE=m ++CONFIG_NET_SCH_QFQ=m ++CONFIG_NET_SCH_CODEL=m ++CONFIG_NET_SCH_FQ_CODEL=m ++CONFIG_NET_SCH_FQ=m ++CONFIG_NET_SCH_HHF=m ++CONFIG_NET_SCH_PIE=m ++CONFIG_NET_SCH_PLUG=m ++CONFIG_NET_CLS=y ++CONFIG_NET_CLS_ACT=y ++CONFIG_NET_CLS_BASIC=m ++CONFIG_NET_CLS_CGROUP=y ++CONFIG_NET_CLS_BPF=m ++CONFIG_NET_CLS_FLOW=m ++CONFIG_NET_CLS_FW=m ++CONFIG_NET_CLS_IND=y ++CONFIG_NET_CLS_ROUTE4=m ++CONFIG_NET_CLS_ROUTE=y ++CONFIG_NET_CLS_RSVP=m ++CONFIG_NET_CLS_RSVP6=m ++CONFIG_NET_CLS_TCINDEX=m ++CONFIG_NET_CLS_U32=m ++CONFIG_CLS_U32_MARK=y ++CONFIG_CLS_U32_PERF=y ++CONFIG_NET_EMATCH=y ++CONFIG_NET_EMATCH_CMP=m ++CONFIG_NET_EMATCH_META=m ++CONFIG_NET_EMATCH_NBYTE=m ++CONFIG_NET_EMATCH_STACK=32 ++CONFIG_NET_EMATCH_TEXT=m ++CONFIG_NET_EMATCH_IPSET=m ++CONFIG_NET_EMATCH_U32=m ++ ++CONFIG_NET_ACT_CSUM=m ++CONFIG_NET_ACT_GACT=m ++CONFIG_GACT_PROB=y ++CONFIG_NET_ACT_IPT=m ++CONFIG_NET_ACT_MIRRED=m ++CONFIG_NET_ACT_NAT=m ++CONFIG_NET_ACT_PEDIT=m ++CONFIG_NET_ACT_POLICE=m ++CONFIG_NET_ACT_SIMP=m ++CONFIG_NET_ACT_SKBEDIT=m ++ ++CONFIG_DCB=y ++CONFIG_DNS_RESOLVER=m ++CONFIG_BATMAN_ADV=m ++CONFIG_BATMAN_ADV_BLA=y ++CONFIG_BATMAN_ADV_DAT=y ++CONFIG_BATMAN_ADV_NC=y ++ ++# CONFIG_BATMAN_ADV_DEBUG is not set ++CONFIG_OPENVSWITCH=m ++CONFIG_OPENVSWITCH_GRE=y ++CONFIG_OPENVSWITCH_VXLAN=y ++CONFIG_VSOCKETS=m ++ ++ ++# ++# Network testing ++# ++CONFIG_NET_PKTGEN=m ++# CONFIG_NET_TCPPROBE is not set ++CONFIG_NET_DROP_MONITOR=y ++ ++# disable later --kyle ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++CONFIG_IFB=m ++CONFIG_NET_TEAM=m ++CONFIG_NET_TEAM_MODE_ROUNDROBIN=m ++CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=m ++CONFIG_NET_TEAM_MODE_LOADBALANCE=m ++CONFIG_NET_TEAM_MODE_BROADCAST=m ++CONFIG_NET_TEAM_MODE_RANDOM=m ++CONFIG_DUMMY=m ++CONFIG_BONDING=m ++CONFIG_MACVLAN=m ++CONFIG_MACVTAP=m ++CONFIG_VXLAN=m ++CONFIG_EQUALIZER=m ++CONFIG_TUN=m ++CONFIG_VETH=m ++CONFIG_NLMON=m ++ ++# ++# ATM ++# ++CONFIG_ATM_DRIVERS=y ++# CONFIG_ATM_DUMMY is not set ++CONFIG_ATM_CLIP=m ++CONFIG_ATM_LANE=m ++CONFIG_ATM_BR2684=m ++CONFIG_NET_SCH_ATM=m ++CONFIG_ATM_TCP=m ++# CONFIG_ATM_LANAI is not set ++CONFIG_ATM_ENI=m ++CONFIG_ATM_FIRESTREAM=m ++# CONFIG_ATM_ZATM is not set ++# CONFIG_ATM_IDT77252 is not set ++# CONFIG_ATM_AMBASSADOR is not set ++# CONFIG_ATM_HORIZON is not set ++# CONFIG_ATM_FORE200E is not set ++# CONFIG_ATM_FORE200E_USE_TASKLET is not set ++CONFIG_ATM_FORE200E_TX_RETRY=16 ++CONFIG_ATM_FORE200E_DEBUG=0 ++ ++CONFIG_ATM_HE=m ++CONFIG_PPTP=m ++CONFIG_PPPOATM=m ++CONFIG_PPPOL2TP=m ++CONFIG_ATM_NICSTAR=m ++# CONFIG_ATM_IA is not set ++# CONFIG_ATM_CLIP_NO_ICMP is not set ++# CONFIG_ATM_MPOA is not set ++# CONFIG_ATM_BR2684_IPFILTER is not set ++# CONFIG_ATM_ENI_DEBUG is not set ++# CONFIG_ATM_ENI_TUNE_BURST is not set ++# CONFIG_ATM_ZATM_DEBUG is not set ++# CONFIG_ATM_IDT77252_DEBUG is not set ++# CONFIG_ATM_IDT77252_RCV_ALL is not set ++# CONFIG_ATM_AMBASSADOR_DEBUG is not set ++# CONFIG_ATM_HORIZON_DEBUG is not set ++# CONFIG_ATM_HE_USE_SUNI is not set ++# CONFIG_ATM_NICSTAR_USE_SUNI is not set ++# CONFIG_ATM_NICSTAR_USE_IDT77105 is not set ++# CONFIG_ATM_IA_DEBUG is not set ++CONFIG_ATM_SOLOS=m ++ ++CONFIG_L2TP=m ++CONFIG_L2TP_V3=y ++CONFIG_L2TP_IP=m ++CONFIG_L2TP_ETH=m ++ ++# CONFIG_CAIF is not set ++ ++CONFIG_RFKILL=m ++CONFIG_RFKILL_GPIO=m ++CONFIG_RFKILL_INPUT=y ++ ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++ ++CONFIG_NET_VENDOR_ADAPTEC=y ++CONFIG_ADAPTEC_STARFIRE=m ++ ++CONFIG_NET_VENDOR_ALTEON=y ++CONFIG_ACENIC=m ++# CONFIG_ACENIC_OMIT_TIGON_I is not set ++ ++CONFIG_NET_VENDOR_AMD=y ++CONFIG_PCNET32=m ++CONFIG_AMD8111_ETH=m ++CONFIG_PCMCIA_NMCLAN=m ++ ++CONFIG_NET_VENDOR_ARC=y ++CONFIG_ARC_EMAC=m ++ ++CONFIG_NET_VENDOR_ATHEROS=y ++CONFIG_ALX=m ++CONFIG_ATL2=m ++CONFIG_ATL1=m ++CONFIG_ATL1C=m ++CONFIG_ATL1E=m ++CONFIG_NET_CADENCE=y ++CONFIG_ARM_AT91_ETHER=m ++CONFIG_MACB=m ++ ++CONFIG_NET_VENDOR_BROCADE=y ++CONFIG_BNA=m ++CONFIG_NET_CALXEDA_XGMAC=m ++ ++CONFIG_NET_VENDOR_CHELSIO=y ++CONFIG_CHELSIO_T1=m ++CONFIG_CHELSIO_T1_1G=y ++CONFIG_CHELSIO_T3=m ++CONFIG_CHELSIO_T4=m ++CONFIG_CHELSIO_T4VF=m ++ ++CONFIG_NET_VENDOR_CISCO=y ++CONFIG_ENIC=m ++ ++CONFIG_NET_VENDOR_DEC=y ++# ++# Tulip family network device support ++# ++CONFIG_NET_TULIP=y ++CONFIG_DE2104X=m ++CONFIG_DE2104X_DSL=0 ++CONFIG_TULIP=m ++# CONFIG_TULIP_NAPI is not set ++# CONFIG_TULIP_MWI is not set ++CONFIG_TULIP_MMIO=y ++# CONFIG_NI5010 is not set ++CONFIG_DE4X5=m ++CONFIG_WINBOND_840=m ++CONFIG_DM9102=m ++CONFIG_PCMCIA_XIRCOM=m ++CONFIG_ULI526X=m ++ ++CONFIG_NET_VENDOR_DLINK=y ++CONFIG_DE600=m ++CONFIG_DE620=m ++CONFIG_DL2K=m ++CONFIG_SUNDANCE=m ++# CONFIG_SUNDANCE_MMIO is not set ++ ++CONFIG_NET_VENDOR_EMULEX=y ++CONFIG_BE2NET=m ++ ++CONFIG_NET_VENDOR_EXAR=y ++CONFIG_S2IO=m ++CONFIG_VXGE=m ++# CONFIG_VXGE_DEBUG_TRACE_ALL is not set ++ ++# CONFIG_NET_VENDOR_FARADAY is not set ++# CONFIG_NET_VENDOR_FUJITSU is not set ++# CONFIG_NET_VENDOR_HP is not set ++CONFIG_NET_VENDOR_INTEL=y ++CONFIG_E100=m ++CONFIG_E1000=m ++CONFIG_E1000E=m ++CONFIG_IGB=m ++CONFIG_IGB_HWMON=y ++CONFIG_IGB_DCA=y ++CONFIG_IGB_PTP=y ++CONFIG_IGBVF=m ++CONFIG_IXGB=m ++CONFIG_IXGBEVF=m ++CONFIG_IXGBE=m ++CONFIG_IXGBE_DCA=y ++CONFIG_IXGBE_DCB=y ++CONFIG_IXGBE_HWMON=y ++CONFIG_IXGBE_PTP=y ++CONFIG_I40E=m ++# CONFIG_I40E_VXLAN is not set ++# CONFIG_I40E_DCB is not set ++# CONFIG_I40EVF is not set ++ ++ ++# CONFIG_NET_VENDOR_I825XX is not set ++CONFIG_NET_VENDOR_MARVELL=y ++CONFIG_MVMDIO=m ++CONFIG_SKGE=m ++# CONFIG_SKGE_DEBUG is not set ++CONFIG_SKGE_GENESIS=y ++CONFIG_SKY2=m ++# CONFIG_SKY2_DEBUG is not set ++ ++CONFIG_NET_VENDOR_MICREL=y ++CONFIG_KSZ884X_PCI=m ++# CONFIG_KS8842 is not set ++# CONFIG_KS8851_MLL is not set ++ ++CONFIG_NET_VENDOR_MYRI=y ++CONFIG_MYRI10GE=m ++CONFIG_MYRI10GE_DCA=y ++ ++CONFIG_NATSEMI=m ++CONFIG_NS83820=m ++ ++CONFIG_PCMCIA_AXNET=m ++CONFIG_NE2K_PCI=m ++CONFIG_NE3210=m ++CONFIG_PCMCIA_PCNET=m ++ ++CONFIG_NET_VENDOR_NVIDIA=y ++CONFIG_FORCEDETH=m ++ ++CONFIG_NET_VENDOR_OKI=y ++# CONFIG_PCH_GBE is not set ++# CONFIG_PCH_PTP is not set ++ ++CONFIG_NET_PACKET_ENGINE=y ++CONFIG_HAMACHI=m ++CONFIG_YELLOWFIN=m ++ ++CONFIG_NET_VENDOR_QLOGIC=y ++CONFIG_QLA3XXX=m ++CONFIG_QLCNIC=m ++CONFIG_QLCNIC_SRIOV=y ++CONFIG_QLCNIC_DCB=y ++CONFIG_QLGE=m ++CONFIG_NETXEN_NIC=m ++ ++CONFIG_NET_VENDOR_REALTEK=y ++CONFIG_ATP=m ++CONFIG_8139CP=m ++CONFIG_8139TOO=m ++# CONFIG_8139TOO_PIO is not set ++# CONFIG_8139TOO_TUNE_TWISTER is not set ++CONFIG_8139TOO_8129=y ++# CONFIG_8139_OLD_RX_RESET is not set ++CONFIG_R8169=m ++ ++ ++CONFIG_NET_VENDOR_RDC=y ++CONFIG_R6040=m ++ ++ ++CONFIG_NET_VENDOR_SILAN=y ++CONFIG_SC92031=m ++ ++CONFIG_NET_VENDOR_SIS=y ++CONFIG_SIS900=m ++CONFIG_SIS190=m ++ ++CONFIG_PCMCIA_SMC91C92=m ++CONFIG_EPIC100=m ++CONFIG_SMSC9420=m ++ ++# CONFIG_STMMAC_PLATFORM is not set ++# CONFIG_STMMAC_PCI is not set ++# CONFIG_STMMAC_DA is not set ++# CONFIG_STMMAC_DUAL_MAC is not set ++# CONFIG_STMMAC_TIMER is not set ++# CONFIG_STMMAC_DEBUG_FS is not set ++ ++CONFIG_NET_VENDOR_SUN=y ++CONFIG_HAPPYMEAL=m ++CONFIG_SUNGEM=m ++CONFIG_CASSINI=m ++CONFIG_NIU=m ++ ++CONFIG_NET_VENDOR_TEHUTI=y ++CONFIG_TEHUTI=m ++ ++CONFIG_NET_VENDOR_TI=y ++CONFIG_TLAN=m ++ ++CONFIG_VIA_RHINE=m ++CONFIG_VIA_RHINE_MMIO=y ++ ++CONFIG_WIZNET_W5100=m ++CONFIG_WIZNET_W5300=m ++CONFIG_NET_VENDOR_XIRCOM=y ++CONFIG_PCMCIA_XIRC2PS=m ++ ++CONFIG_AMD_PHY=m ++CONFIG_BROADCOM_PHY=m ++CONFIG_BCM87XX_PHY=m ++CONFIG_CICADA_PHY=m ++CONFIG_DAVICOM_PHY=m ++CONFIG_DP83640_PHY=m ++CONFIG_FIXED_PHY=y ++CONFIG_MDIO_BITBANG=m ++CONFIG_NATIONAL_PHY=m ++CONFIG_ICPLUS_PHY=m ++CONFIG_BCM63XX_PHY=m ++CONFIG_LSI_ET1011C_PHY=m ++CONFIG_LXT_PHY=m ++CONFIG_MARVELL_PHY=m ++CONFIG_QSEMI_PHY=m ++CONFIG_REALTEK_PHY=m ++CONFIG_SMSC_PHY=m ++CONFIG_STE10XP=m ++CONFIG_VITESSE_PHY=m ++CONFIG_MICREL_PHY=m ++ ++CONFIG_MII=m ++CONFIG_NET_CORE=y ++CONFIG_NET_VENDOR_3COM=y ++CONFIG_VORTEX=m ++CONFIG_TYPHOON=m ++CONFIG_DNET=m ++ ++ ++CONFIG_LNE390=m ++CONFIG_ES3210=m ++CONFIG_NET_PCI=y ++CONFIG_B44=m ++CONFIG_B44_PCI=y ++CONFIG_BNX2=m ++CONFIG_BNX2X=m ++CONFIG_BNX2X_SRIOV=y ++CONFIG_CNIC=m ++CONFIG_FEALNX=m ++CONFIG_NET_POCKET=y ++ ++# ++# Ethernet (1000 Mbit) ++# ++CONFIG_TIGON3=m ++CONFIG_JME=m ++ ++# ++# Ethernet (10000 Mbit) ++# ++# CONFIG_IP1000 is not set ++# CONFIG_MLX4_EN is not set ++# CONFIG_SFC is not set ++ ++# CONFIG_FDDI is not set ++# CONFIG_DEFXX is not set ++# CONFIG_SKFP is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++CONFIG_PPP=m ++CONFIG_PPP_MULTILINK=y ++CONFIG_PPP_FILTER=y ++CONFIG_PPP_ASYNC=m ++CONFIG_PPP_SYNC_TTY=m ++CONFIG_PPP_DEFLATE=m ++CONFIG_IPPP_FILTER=y ++CONFIG_PPP_BSDCOMP=y ++CONFIG_PPPOE=m ++CONFIG_PPP_MPPE=m ++CONFIG_SLIP=m ++CONFIG_SLIP_COMPRESSED=y ++CONFIG_SLIP_SMART=y ++# CONFIG_SLIP_MODE_SLIP6 is not set ++ ++# ++# Wireless LAN ++# ++# ++# CONFIG_STRIP is not set ++# CONFIG_PCMCIA_RAYCS is not set ++ ++CONFIG_CFG80211_WEXT=y ++# CONFIG_CFG80211_REG_DEBUG is not set ++# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set ++CONFIG_CFG80211_DEFAULT_PS=y ++CONFIG_NL80211=y ++# CONFIG_NL80211_TESTMODE is not set ++# CONFIG_WIRELESS_EXT_SYSFS is not set ++CONFIG_LIB80211=m ++CONFIG_LIB80211_CRYPT_WEP=m ++CONFIG_LIB80211_CRYPT_CCMP=m ++CONFIG_LIB80211_CRYPT_TKIP=m ++# CONFIG_LIB80211_DEBUG is not set ++ ++CONFIG_MAC80211=m ++CONFIG_MAC80211_RC_MINSTREL=y ++# CONFIG_MAC80211_RC_DEFAULT_PID is not set ++CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y ++CONFIG_MAC80211_RC_DEFAULT="minstrel" ++CONFIG_MAC80211_MESH=y ++CONFIG_MAC80211_LEDS=y ++# CONFIG_MAC80211_DEBUG_MENU is not set ++ ++# CONFIG_WIMAX is not set ++ ++# CONFIG_ADM8211 is not set ++CONFIG_ATH_COMMON=m ++CONFIG_ATH_CARDS=m ++CONFIG_ATH5K=m ++CONFIG_ATH5K_DEBUG=y ++# CONFIG_ATH5K_TRACER is not set ++CONFIG_ATH6KL=m ++CONFIG_ATH6KL_DEBUG=y ++CONFIG_ATH6KL_SDIO=m ++CONFIG_ATH6KL_USB=m ++# CONFIG_ATH6KL_TRACING is not set ++CONFIG_AR5523=m ++CONFIG_ATH9K=m ++CONFIG_ATH9K_PCI=y ++CONFIG_ATH9K_AHB=y ++# CONFIG_ATH9K_DEBUG is not set ++# CONFIG_ATH9K_MAC_DEBUG is not set ++CONFIG_ATH9K_HTC=m ++CONFIG_ATH9K_BTCOEX_SUPPORT=y ++# CONFIG_ATH9K_LEGACY_RATE_CONTROL is not set ++# CONFIG_ATH9K_WOW is not set ++# ++CONFIG_ATH10K=m ++CONFIG_ATH10K_PCI=m ++# CONFIG_ATH10K_DEBUG is not set ++# CONFIG_ATH10K_TRACING is not set ++CONFIG_ATH10K_DEBUGFS=y ++CONFIG_WCN36XX=m ++# CONFIG_WCN36XX_DEBUGFS is not set ++CONFIG_WIL6210=m ++CONFIG_WIL6210_ISR_COR=y ++# CONFIG_WIL6210_TRACING is not set ++CONFIG_CARL9170=m ++CONFIG_CARL9170_LEDS=y ++# CONFIG_CARL9170_HWRNG is not set ++CONFIG_AT76C50X_USB=m ++# CONFIG_AIRO is not set ++# CONFIG_AIRO_CS is not set ++# CONFIG_ATMEL is not set ++CONFIG_B43=m ++CONFIG_B43_PCMCIA=y ++CONFIG_B43_SDIO=y ++CONFIG_B43_BCMA=y ++# CONFIG_B43_BCMA_EXTRA is not set ++CONFIG_B43_BCMA_PIO=y ++# CONFIG_B43_DEBUG is not set ++CONFIG_B43_PHY_LP=y ++CONFIG_B43_PHY_N=y ++CONFIG_B43_PHY_HT=y ++# CONFIG_B43_FORCE_PIO is not set ++CONFIG_B43LEGACY=m ++# CONFIG_B43LEGACY_DEBUG is not set ++CONFIG_B43LEGACY_DMA=y ++CONFIG_B43LEGACY_PIO=y ++CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y ++# CONFIG_B43LEGACY_DMA_MODE is not set ++# CONFIG_B43LEGACY_PIO_MODE is not set ++CONFIG_BRCMSMAC=m ++# CONFIG_BRCMFMAC_SDIO_OOB is not set ++CONFIG_BRCMFMAC_USB=y ++# CONFIG_BRCM_TRACING is not set ++# CONFIG_BRCMISCAN is not set ++# CONFIG_BRCMDBG is not set ++CONFIG_HERMES=m ++CONFIG_HERMES_CACHE_FW_ON_INIT=y ++# CONFIG_HERMES_PRISM is not set ++CONFIG_NORTEL_HERMES=m ++CONFIG_PCI_HERMES=m ++CONFIG_PLX_HERMES=m ++CONFIG_PCMCIA_HERMES=m ++CONFIG_ORINOCO_USB=m ++# CONFIG_TMD_HERMES is not set ++# CONFIG_PCMCIA_SPECTRUM is not set ++CONFIG_CW1200=m ++CONFIG_CW1200_WLAN_SDIO=m ++CONFIG_CW1200_WLAN_SPI=m ++# CONFIG_HOSTAP is not set ++# CONFIG_IPW2100 is not set ++# CONFIG_IPW2200 is not set ++# CONFIG_IPW2100_DEBUG is not set ++# CONFIG_IPW2200_DEBUG is not set ++# CONFIG_LIBIPW_DEBUG is not set ++CONFIG_LIBERTAS=m ++CONFIG_LIBERTAS_USB=m ++CONFIG_LIBERTAS_CS=m ++CONFIG_LIBERTAS_SDIO=m ++# CONFIG_LIBERTAS_DEBUG is not set ++# CONFIG_LIBERTAS_THINFIRM is not set ++CONFIG_LIBERTAS_MESH=y ++CONFIG_IWLWIFI=m ++CONFIG_IWLDVM=m ++CONFIG_IWLMVM=m ++CONFIG_IWLWIFI_DEBUG=y ++CONFIG_IWLWIFI_DEVICE_SVTOOL=y ++# CONFIG_IWLWIFI_EXPERIMENTAL_MFP is not set ++CONFIG_IWLWIFI_UCODE16=y ++# CONFIG_IWLWIFI_P2P is not set ++CONFIG_IWLEGACY=m ++CONFIG_IWLEGACY_DEBUG=y ++# CONFIG_IWLWIFI_LEGACY_DEVICE_TRACING is not set ++CONFIG_IWL4965=y ++CONFIG_IWL3945=m ++# CONFIG_IWM is not set ++# CONFIG_IWLWIFI_DEBUG_EXPERIMENTAL_UCODE is not set ++CONFIG_MAC80211_HWSIM=m ++CONFIG_P54_COMMON=m ++CONFIG_P54_USB=m ++CONFIG_P54_PCI=m ++CONFIG_MWL8K=m ++# CONFIG_PRISM54 is not set ++# CONFIG_PCMCIA_WL3501 is not set ++CONFIG_RT2X00=m ++# CONFIG_RT2X00_DEBUG is not set ++CONFIG_RT2400PCI=m ++CONFIG_RT2500PCI=m ++CONFIG_RT61PCI=m ++CONFIG_RT2500USB=m ++CONFIG_RT2800USB=m ++CONFIG_RT2800USB_RT33XX=y ++CONFIG_RT2800USB_RT35XX=y ++CONFIG_RT2800USB_RT3573=y ++CONFIG_RT2800USB_RT53XX=y ++CONFIG_RT2800USB_RT55XX=y ++CONFIG_RT2800USB_UNKNOWN=y ++CONFIG_RT2800PCI=m ++CONFIG_RT2800PCI_RT3290=y ++CONFIG_RT2800PCI_RT33XX=y ++CONFIG_RT2800PCI_RT35XX=y ++CONFIG_RT2800PCI_RT53XX=y ++CONFIG_RT73USB=m ++CONFIG_RTL8180=m ++CONFIG_RTL8187=m ++# CONFIG_USB_ZD1201 is not set ++# CONFIG_USB_NET_SR9800 is not set ++CONFIG_USB_NET_RNDIS_WLAN=m ++CONFIG_USB_NET_KALMIA=m ++CONFIG_USB_NET_QMI_WWAN=m ++CONFIG_USB_NET_SMSC75XX=m ++# CONFIG_WL_TI is not set ++CONFIG_ZD1211RW=m ++# CONFIG_ZD1211RW_DEBUG is not set ++ ++CONFIG_WL12XX=m ++CONFIG_WL12XX_SPI=m ++CONFIG_WL12XX_SDIO=m ++ ++CONFIG_WL1251=m ++CONFIG_WL1251_SPI=m ++CONFIG_WL1251_SDIO=m ++ ++CONFIG_RTL_CARDS=m ++CONFIG_RTLWIFI=m ++CONFIG_RTL8192CE=m ++CONFIG_RTL8192SE=m ++CONFIG_RTL8192CU=m ++CONFIG_RTL8192DE=m ++CONFIG_RTL8723AE=m ++CONFIG_RTL8188EE=m ++ ++CONFIG_MWIFIEX=m ++CONFIG_MWIFIEX_SDIO=m ++CONFIG_MWIFIEX_PCIE=m ++CONFIG_MWIFIEX_USB=m ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++ ++CONFIG_NET_FC=y ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# PCMCIA network device support ++# ++CONFIG_NET_PCMCIA=y ++CONFIG_PCMCIA_3C589=m ++CONFIG_PCMCIA_3C574=m ++CONFIG_PCMCIA_FMVJ18X=m ++ ++# ++# Amateur Radio support ++# ++CONFIG_HAMRADIO=y ++CONFIG_AX25=m ++CONFIG_AX25_DAMA_SLAVE=y ++ ++# CONFIG_CAN is not set ++ ++CONFIG_NETROM=m ++CONFIG_ROSE=m ++CONFIG_MKISS=m ++CONFIG_6PACK=m ++CONFIG_BPQETHER=m ++CONFIG_BAYCOM_SER_FDX=m ++CONFIG_BAYCOM_SER_HDX=m ++CONFIG_BAYCOM_PAR=m ++CONFIG_BAYCOM_EPP=m ++CONFIG_YAM=m ++ ++CONFIG_NFC=m ++CONFIG_NFC_DIGITAL=m ++CONFIG_NFC_NCI=m ++CONFIG_NFC_HCI=m ++CONFIG_NFC_SHDLC=y ++CONFIG_NFC_LLCP=y ++CONFIG_NFC_SIM=m ++CONFIG_NFC_MRVL=m ++CONFIG_NFC_MRVL_USB=m ++ ++# ++# Near Field Communication (NFC) devices ++# ++CONFIG_NFC_PORT100=m ++CONFIG_NFC_PN544=m ++CONFIG_NFC_PN544_I2C=m ++CONFIG_NFC_PN533=m ++CONFIG_NFC_MICROREAD=m ++CONFIG_NFC_MICROREAD_I2C=m ++ ++# ++# IrDA (infrared) support ++# ++CONFIG_IRDA=m ++# CONFIG_IRDA_DEBUG is not set ++CONFIG_IRLAN=m ++CONFIG_IRNET=m ++CONFIG_IRCOMM=m ++# CONFIG_IRDA_ULTRA is not set ++CONFIG_IRDA_CACHE_LAST_LSAP=y ++CONFIG_IRDA_FAST_RR=y ++CONFIG_IRTTY_SIR=m ++CONFIG_DONGLE=y ++CONFIG_ACTISYS_DONGLE=m ++CONFIG_ACT200L_DONGLE=m ++CONFIG_ESI_DONGLE=m ++CONFIG_GIRBIL_DONGLE=m ++CONFIG_KINGSUN_DONGLE=m ++CONFIG_KSDAZZLE_DONGLE=m ++CONFIG_KS959_DONGLE=m ++CONFIG_LITELINK_DONGLE=m ++CONFIG_MA600_DONGLE=m ++CONFIG_MCP2120_DONGLE=m ++CONFIG_OLD_BELKIN_DONGLE=m ++CONFIG_TEKRAM_DONGLE=m ++CONFIG_TOIM3232_DONGLE=m ++ ++CONFIG_ALI_FIR=m ++CONFIG_MCS_FIR=m ++CONFIG_NSC_FIR=m ++CONFIG_SIGMATEL_FIR=m ++CONFIG_SMC_IRCC_FIR=m ++# CONFIG_TOSHIBA_FIR is not set ++CONFIG_USB_IRDA=m ++CONFIG_VLSI_FIR=m ++CONFIG_VIA_FIR=m ++CONFIG_WINBOND_FIR=m ++ ++# ++# Bluetooth support ++# ++CONFIG_BT=m ++CONFIG_BT_L2CAP=y ++CONFIG_BT_SCO=y ++CONFIG_BT_CMTP=m ++CONFIG_BT_RFCOMM=m ++CONFIG_BT_RFCOMM_TTY=y ++CONFIG_BT_BNEP=m ++CONFIG_BT_BNEP_MC_FILTER=y ++CONFIG_BT_BNEP_PROTO_FILTER=y ++CONFIG_BT_HIDP=m ++ ++# ++# Bluetooth device drivers ++# ++CONFIG_BT_HCIBTUSB=m ++# Disable the BT_HCIUSB driver. ++# It sucks more power than BT_HCIBTUSB which has the same functionality. ++CONFIG_BT_HCIUART=m ++CONFIG_BT_HCIUART_H4=y ++CONFIG_BT_HCIUART_BCSP=y ++CONFIG_BT_HCIUART_ATH3K=y ++CONFIG_BT_HCIUART_3WIRE=y ++CONFIG_BT_HCIDTL1=m ++CONFIG_BT_HCIBT3C=m ++CONFIG_BT_HCIBLUECARD=m ++CONFIG_BT_HCIBTUART=m ++CONFIG_BT_HCIVHCI=m ++CONFIG_BT_HCIBCM203X=m ++CONFIG_BT_HCIBFUSB=m ++CONFIG_BT_HCIBPA10X=m ++CONFIG_BT_HCIBTSDIO=m ++CONFIG_BT_HCIUART_LL=y ++CONFIG_BT_MRVL=m ++CONFIG_BT_MRVL_SDIO=m ++CONFIG_BT_ATH3K=m ++CONFIG_BT_WILINK=m ++ ++# ++# ISDN subsystem ++# ++CONFIG_ISDN=y ++CONFIG_MISDN=m ++CONFIG_MISDN_DSP=m ++CONFIG_MISDN_L1OIP=m ++CONFIG_MISDN_AVMFRITZ=m ++CONFIG_MISDN_SPEEDFAX=m ++CONFIG_MISDN_INFINEON=m ++CONFIG_MISDN_W6692=m ++CONFIG_MISDN_NETJET=m ++ ++# ++# mISDN hardware drivers ++# ++CONFIG_MISDN_HFCPCI=m ++CONFIG_MISDN_HFCMULTI=m ++CONFIG_ISDN_I4L=m ++CONFIG_ISDN_DRV_AVMB1_B1PCI=m ++CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m ++CONFIG_ISDN_DRV_AVMB1_T1PCI=m ++CONFIG_ISDN_DRV_AVMB1_C4=m ++ ++CONFIG_MISDN_HFCUSB=m ++ ++CONFIG_ISDN_PPP=y ++CONFIG_ISDN_PPP_VJ=y ++CONFIG_ISDN_MPP=y ++# CONFIG_ISDN_PPP_BSDCOMP is not set ++CONFIG_ISDN_TTY_FAX=y ++CONFIG_DE_AOC=y ++ ++CONFIG_ISDN_AUDIO=y ++ ++CONFIG_ISDN_DRV_HISAX=m ++CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y ++CONFIG_ISDN_DRV_AVMB1_AVM_CS=m ++ ++CONFIG_ISDN_CAPI_CAPIDRV=m ++CONFIG_ISDN_DIVERSION=m ++ ++CONFIG_HISAX_EURO=y ++CONFIG_HISAX_1TR6=y ++CONFIG_HISAX_NI1=y ++CONFIG_HISAX_MAX_CARDS=8 ++CONFIG_HISAX_16_3=y ++CONFIG_HISAX_TELESPCI=y ++CONFIG_HISAX_S0BOX=y ++CONFIG_HISAX_FRITZPCI=y ++CONFIG_HISAX_AVM_A1_PCMCIA=y ++CONFIG_HISAX_ELSA=y ++CONFIG_HISAX_DIEHLDIVA=y ++CONFIG_HISAX_SEDLBAUER=y ++CONFIG_HISAX_NETJET=y ++CONFIG_HISAX_NETJET_U=y ++CONFIG_HISAX_NICCY=y ++CONFIG_HISAX_BKM_A4T=y ++CONFIG_HISAX_SCT_QUADRO=y ++CONFIG_HISAX_GAZEL=y ++CONFIG_HISAX_HFC_PCI=y ++CONFIG_HISAX_W6692=y ++CONFIG_HISAX_HFC_SX=y ++CONFIG_HISAX_ENTERNOW_PCI=y ++# CONFIG_HISAX_DEBUG is not set ++CONFIG_HISAX_AVM_A1_CS=m ++CONFIG_HISAX_ST5481=m ++# CONFIG_HISAX_HFCUSB is not set ++CONFIG_HISAX_FRITZ_PCIPNP=m ++CONFIG_HISAX_NO_SENDCOMPLETE=y ++CONFIG_HISAX_NO_LLC=y ++CONFIG_HISAX_NO_KEYPAD=y ++CONFIG_HISAX_SEDLBAUER_CS=m ++CONFIG_HISAX_ELSA_CS=m ++CONFIG_HISAX_TELES_CS=m ++CONFIG_HISAX_HFC4S8S=m ++ ++CONFIG_ISDN_DRV_LOOP=m ++CONFIG_HYSDN=m ++CONFIG_HYSDN_CAPI=y ++ ++ ++# ++# CAPI subsystem ++# ++CONFIG_ISDN_CAPI=m ++# CONFIG_CAPI_TRACE is not set ++CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y ++CONFIG_ISDN_CAPI_MIDDLEWARE=y ++CONFIG_ISDN_CAPI_CAPI20=m ++ ++# ++# CAPI hardware drivers ++# ++ ++# ++# Active AVM cards ++# ++CONFIG_CAPI_AVM=y ++ ++# ++# Active Eicon DIVA Server cards ++# ++# CONFIG_CAPI_EICON is not set ++CONFIG_ISDN_DIVAS=m ++CONFIG_ISDN_DIVAS_BRIPCI=y ++CONFIG_ISDN_DIVAS_PRIPCI=y ++CONFIG_ISDN_DIVAS_DIVACAPI=m ++CONFIG_ISDN_DIVAS_USERIDI=m ++CONFIG_ISDN_DIVAS_MAINT=m ++ ++CONFIG_ISDN_DRV_GIGASET=m ++CONFIG_GIGASET_CAPI=y ++CONFIG_GIGASET_BASE=m ++CONFIG_GIGASET_M101=m ++CONFIG_GIGASET_M105=m ++# CONFIG_GIGASET_DEBUG is not set ++ ++# ++# Telephony Support ++# ++# CONFIG_PHONE is not set ++ ++# ++# Input device support ++# ++CONFIG_INPUT=y ++CONFIG_INPUT_FF_MEMLESS=m ++ ++# ++# Userland interfaces ++# ++CONFIG_INPUT_MOUSEDEV=y ++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 ++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 ++CONFIG_INPUT_JOYDEV=m ++# CONFIG_INPUT_MATRIXKMAP is not set ++ ++CONFIG_INPUT_TABLET=y ++CONFIG_TABLET_USB_ACECAD=m ++CONFIG_TABLET_USB_AIPTEK=m ++CONFIG_TABLET_USB_GTCO=m ++CONFIG_TABLET_USB_HANWANG=m ++CONFIG_TABLET_USB_KBTAB=m ++CONFIG_TABLET_USB_WACOM=m ++ ++CONFIG_INPUT_POWERMATE=m ++CONFIG_INPUT_YEALINK=m ++CONFIG_INPUT_CM109=m ++CONFIG_INPUT_POLLDEV=m ++CONFIG_INPUT_SPARSEKMAP=m ++# CONFIG_INPUT_ADXL34X is not set ++# CONFIG_INPUT_BMA150 is not set ++# CONFIG_INPUT_IMS_PCU is not set ++CONFIG_INPUT_CMA3000=m ++CONFIG_INPUT_CMA3000_I2C=m ++CONFIG_INPUT_IDEAPAD_SLIDEBAR=m ++ ++# ++# Input I/O drivers ++# ++CONFIG_GAMEPORT=m ++CONFIG_GAMEPORT_NS558=m ++CONFIG_GAMEPORT_L4=m ++CONFIG_GAMEPORT_EMU10K1=m ++CONFIG_GAMEPORT_FM801=m ++CONFIG_SERIO=y ++CONFIG_SERIO_I8042=y ++CONFIG_SERIO_RAW=m ++CONFIG_SERIO_ALTERA_PS2=m ++# CONFIG_SERIO_PS2MULT is not set ++CONFIG_SERIO_ARC_PS2=m ++# CONFIG_SERIO_APBPS2 is not set ++ ++# CONFIG_SERIO_CT82C710 is not set ++# CONFIG_SERIO_OLPC_APSP is not set ++# CONFIG_SERIO_PARKBD is not set ++# CONFIG_SERIO_PCIPS2 is not set ++# CONFIG_SERIO_LIBPS2 is not set ++ ++# ++# Input Device Drivers ++# ++CONFIG_INPUT_KEYBOARD=y ++# CONFIG_KEYBOARD_SUNKBD is not set ++# CONFIG_KEYBOARD_SH_KEYSC is not set ++# CONFIG_KEYBOARD_XTKBD is not set ++# CONFIG_KEYBOARD_MATRIX is not set ++# CONFIG_KEYBOARD_NEWTON is not set ++# CONFIG_KEYBOARD_STOWAWAY is not set ++# CONFIG_KEYBOARD_LKKBD is not set ++# CONFIG_KEYBOARD_LM8323 is not set ++# CONFIG_KEYBOARD_LM8333 is not set ++# CONFIG_KEYBOARD_MAX7359 is not set ++# CONFIG_KEYBOARD_ADP5589 is not set ++# CONFIG_KEYBOARD_MPR121 is not set ++# CONFIG_KEYBOARD_QT1070 is not set ++# CONFIG_KEYBOARD_MCS is not set ++# CONFIG_KEYBOARD_OPENCORES is not set ++# CONFIG_KEYBOARD_SAMSUNG is not set ++# CONFIG_KEYBOARD_QT2160 is not set ++# CONFIG_KEYBOARD_TCA6416 is not set ++# CONFIG_KEYBOARD_TCA8418 is not set ++# CONFIG_KEYBOARD_OMAP4 is not set ++CONFIG_INPUT_MOUSE=y ++# CONFIG_MOUSE_PS2_TOUCHKIT is not set ++CONFIG_MOUSE_PS2_ELANTECH=y ++CONFIG_MOUSE_PS2_SENTELIC=y ++CONFIG_MOUSE_SERIAL=m ++CONFIG_MOUSE_VSXXXAA=m ++CONFIG_MOUSE_APPLETOUCH=m ++CONFIG_MOUSE_BCM5974=m ++CONFIG_MOUSE_SYNAPTICS_I2C=m ++CONFIG_MOUSE_SYNAPTICS_USB=m ++CONFIG_MOUSE_CYAPA=m ++CONFIG_INPUT_JOYSTICK=y ++CONFIG_JOYSTICK_ANALOG=m ++CONFIG_JOYSTICK_A3D=m ++CONFIG_JOYSTICK_ADI=m ++CONFIG_JOYSTICK_COBRA=m ++CONFIG_JOYSTICK_GF2K=m ++CONFIG_JOYSTICK_GRIP=m ++CONFIG_JOYSTICK_GRIP_MP=m ++CONFIG_JOYSTICK_GUILLEMOT=m ++CONFIG_JOYSTICK_INTERACT=m ++CONFIG_JOYSTICK_SIDEWINDER=m ++CONFIG_JOYSTICK_TMDC=m ++CONFIG_JOYSTICK_IFORCE=m ++CONFIG_JOYSTICK_IFORCE_USB=y ++CONFIG_JOYSTICK_IFORCE_232=y ++CONFIG_JOYSTICK_WARRIOR=m ++CONFIG_JOYSTICK_MAGELLAN=m ++CONFIG_JOYSTICK_SPACEORB=m ++CONFIG_JOYSTICK_SPACEBALL=m ++CONFIG_JOYSTICK_STINGER=m ++CONFIG_JOYSTICK_DB9=m ++CONFIG_JOYSTICK_GAMECON=m ++CONFIG_JOYSTICK_TURBOGRAFX=m ++CONFIG_JOYSTICK_JOYDUMP=m ++CONFIG_JOYSTICK_TWIDJOY=m ++CONFIG_JOYSTICK_WALKERA0701=m ++CONFIG_JOYSTICK_XPAD=m ++CONFIG_JOYSTICK_XPAD_FF=y ++CONFIG_JOYSTICK_XPAD_LEDS=y ++CONFIG_JOYSTICK_ZHENHUA=m ++# CONFIG_JOYSTICK_AS5011 is not set ++ ++CONFIG_INPUT_TOUCHSCREEN=y ++# CONFIG_TOUCHSCREEN_AD7879 is not set ++CONFIG_TOUCHSCREEN_AD7879_I2C=m ++# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set ++# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set ++# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set ++CONFIG_TOUCHSCREEN_DYNAPRO=m ++CONFIG_TOUCHSCREEN_EDT_FT5X06=m ++CONFIG_TOUCHSCREEN_EETI=m ++CONFIG_TOUCHSCREEN_EGALAX=m ++CONFIG_TOUCHSCREEN_ELO=m ++CONFIG_TOUCHSCREEN_FUJITSU=m ++CONFIG_TOUCHSCREEN_GUNZE=m ++# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set ++CONFIG_TOUCHSCREEN_INEXIO=m ++CONFIG_TOUCHSCREEN_ILI210X=m ++CONFIG_TOUCHSCREEN_MMS114=m ++CONFIG_TOUCHSCREEN_MTOUCH=m ++CONFIG_TOUCHSCREEN_MCS5000=m ++CONFIG_TOUCHSCREEN_MK712=m ++CONFIG_TOUCHSCREEN_PENMOUNT=m ++# CONFIG_TOUCHSCREEN_SUR40 is not set ++# CONFIG_TOUCHSCREEN_TPS6507X is not set ++CONFIG_TOUCHSCREEN_TSC_SERIO=m ++CONFIG_TOUCHSCREEN_TSC2007=m ++CONFIG_TOUCHSCREEN_TOUCHIT213=m ++CONFIG_TOUCHSCREEN_TOUCHRIGHT=m ++CONFIG_TOUCHSCREEN_TOUCHWIN=m ++CONFIG_TOUCHSCREEN_PIXCIR=m ++CONFIG_TOUCHSCREEN_UCB1400=m ++CONFIG_TOUCHSCREEN_WACOM_W8001=m ++CONFIG_TOUCHSCREEN_WACOM_I2C=m ++CONFIG_TOUCHSCREEN_USB_E2I=y ++CONFIG_TOUCHSCREEN_USB_COMPOSITE=m ++# CONFIG_TOUCHSCREEN_WM97XX is not set ++CONFIG_TOUCHSCREEN_W90X900=m ++# CONFIG_TOUCHSCREEN_BU21013 is not set ++CONFIG_TOUCHSCREEN_ST1232=m ++CONFIG_TOUCHSCREEN_ATMEL_MXT=m ++# CONFIG_TOUCHSCREEN_MAX11801 is not set ++CONFIG_TOUCHSCREEN_AUO_PIXCIR=m ++CONFIG_TOUCHSCREEN_TI_AM335X_TSC=m ++CONFIG_TOUCHSCREEN_ZFORCE=m ++ ++CONFIG_INPUT_PCSPKR=m ++CONFIG_INPUT_RETU_PWRBUTTON=m ++CONFIG_INPUT_UINPUT=m ++CONFIG_INPUT_WISTRON_BTNS=m ++CONFIG_INPUT_ATLAS_BTNS=m ++ ++CONFIG_INPUT_ATI_REMOTE2=m ++CONFIG_INPUT_KEYSPAN_REMOTE=m ++ ++CONFIG_MAC_EMUMOUSEBTN=y ++ ++CONFIG_INPUT_WM831X_ON=m ++ ++ ++# CONFIG_INPUT_AD714X is not set ++# CONFIG_INPUT_PCF8574 is not set ++CONFIG_INPUT_MMA8450=m ++CONFIG_INPUT_MPU3050=m ++CONFIG_INPUT_KXTJ9=m ++# CONFIG_INPUT_KXTJ9_POLLED_MODE is not set ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_HW_CONSOLE=y ++CONFIG_SERIAL_NONSTANDARD=y ++CONFIG_ROCKETPORT=m ++CONFIG_SYNCLINK=m ++CONFIG_SYNCLINKMP=m ++CONFIG_SYNCLINK_GT=m ++CONFIG_N_HDLC=m ++CONFIG_N_GSM=m ++# CONFIG_TRACE_SINK is not set ++# CONFIG_STALDRV is not set ++# CONFIG_DUMMY_IRQ is not set ++# CONFIG_IBM_ASM is not set ++CONFIG_TIFM_CORE=m ++CONFIG_TIFM_7XX1=m ++CONFIG_TCG_TPM=m ++CONFIG_TCG_TIS=m ++# CONFIG_TCG_TIS_I2C_INFINEON is not set ++# CONFIG_TCG_TIS_I2C_ATMEL is not set ++# CONFIG_TCG_TIS_I2C_NUVOTON is not set ++CONFIG_TCG_NSC=m ++CONFIG_TCG_ATMEL=m ++# CONFIG_TCG_INFINEON is not set ++# CONFIG_TCG_ST33_I2C is not set ++# CONFIG_TCG_XEN is not set ++CONFIG_TELCLOCK=m ++ ++# ++# Serial drivers ++# ++CONFIG_SERIAL_8250=y ++# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_CS=m ++CONFIG_SERIAL_8250_NR_UARTS=32 ++CONFIG_SERIAL_8250_RUNTIME_UARTS=4 ++CONFIG_SERIAL_8250_EXTENDED=y ++CONFIG_SERIAL_8250_MANY_PORTS=y ++CONFIG_SERIAL_8250_SHARE_IRQ=y ++# CONFIG_SERIAL_8250_DETECT_IRQ is not set ++CONFIG_SERIAL_8250_RSA=y ++# CONFIG_SERIAL_8250_DW is not set ++CONFIG_CYCLADES=m ++# CONFIG_CYZ_INTR is not set ++# CONFIG_MOXA_INTELLIO is not set ++# CONFIG_MOXA_SMARTIO is not set ++# CONFIG_ISI is not set ++# CONFIG_RIO is not set ++CONFIG_SERIAL_JSM=m ++# CONFIG_SERIAL_SCCNXP is not set ++# CONFIG_SERIAL_MFD_HSU is not set ++ ++# CONFIG_SERIAL_ALTERA_JTAGUART is not set ++# CONFIG_SERIAL_ALTERA_UART is not set ++ ++# ++# Non-8250 serial port support ++# ++CONFIG_SERIAL_CORE=y ++CONFIG_SERIAL_CORE_CONSOLE=y ++# CONFIG_SERIAL_XILINX_PS_UART is not set ++# CONFIG_SERIAL_TIMBERDALE is not set ++CONFIG_SERIAL_ARC=m ++CONFIG_SERIAL_ARC_NR_PORTS=1 ++# CONFIG_SERIAL_RP2 is not set ++# CONFIG_SERIAL_ST_ASC is not set ++# CONFIG_SERIAL_PCH_UART is not set ++ ++CONFIG_UNIX98_PTYS=y ++CONFIG_DEVPTS_MULTIPLE_INSTANCES=y ++CONFIG_PRINTER=m ++CONFIG_LP_CONSOLE=y ++CONFIG_PPDEV=m ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++# CONFIG_I2C_MUX is not set ++# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set ++# CONFIG_I2C_MUX_PCA954x is not set ++# CONFIG_I2C_MUX_GPIO is not set ++# CONFIG_I2C_MUX_PCA9541 is not set ++# CONFIG_I2C_MUX_PINCTRL is not set ++# ++ ++# ++# I2C Algorithms ++# ++# CONFIG_I2C_DEBUG_ALGO is not set ++CONFIG_I2C_ALGOBIT=m ++ ++# ++# I2C Hardware Bus support ++# ++ ++# CONFIG_I2C_ALI1535 is not set ++# CONFIG_I2C_ALI1563 is not set ++# CONFIG_I2C_ALI15X3 is not set ++# CONFIG_I2C_AMD756 is not set ++# CONFIG_I2C_AMD756_S4882 is not set ++# CONFIG_I2C_AMD8111 is not set ++# CONFIG_I2C_DEBUG_CORE is not set ++# CONFIG_I2C_DEBUG_BUS is not set ++# CONFIG_I2C_I801 is not set ++# CONFIG_I2C_ISCH is not set ++# CONFIG_I2C_NFORCE2_S4985 is not set ++# CONFIG_I2C_INTEL_MID is not set ++# CONFIG_I2C_EG20T is not set ++# CONFIG_I2C_CBUS_GPIO is not set ++CONFIG_I2C_VIPERBOARD=m ++ ++CONFIG_EEPROM_AT24=m ++CONFIG_EEPROM_LEGACY=m ++CONFIG_EEPROM_93CX6=m ++CONFIG_EEPROM_MAX6875=m ++ ++CONFIG_I2C_NFORCE2=m ++# CONFIG_I2C_OCORES is not set ++CONFIG_I2C_PARPORT=m ++CONFIG_I2C_PARPORT_LIGHT=m ++# CONFIG_I2C_ROBOTFUZZ_OSIF is not set ++CONFIG_I2C_PASEMI=m ++CONFIG_I2C_PCA_PLATFORM=m ++# CONFIG_I2C_PIIX4 is not set ++# CONFIG_SCx200_ACB is not set ++# CONFIG_I2C_SIS5595 is not set ++# CONFIG_I2C_SIS630 is not set ++# CONFIG_I2C_SIS96X is not set ++CONFIG_I2C_SIMTEC=m ++CONFIG_I2C_STUB=m ++CONFIG_I2C_TINY_USB=m ++# CONFIG_I2C_TAOS_EVM is not set ++# CONFIG_I2C_VIA is not set ++# CONFIG_I2C_VIAPRO is not set ++# CONFIG_I2C_DESIGNWARE is not set ++# CONFIG_I2C_XILINX is not set ++ ++CONFIG_I2C_DIOLAN_U2C=m ++ ++# ++# I2C Hardware Sensors Chip support ++# ++CONFIG_SENSORS_ATK0110=m ++CONFIG_SENSORS_ABITUGURU=m ++CONFIG_SENSORS_ABITUGURU3=m ++CONFIG_SENSORS_AD7414=m ++CONFIG_SENSORS_AD7418=m ++CONFIG_SENSORS_ADM1021=m ++CONFIG_SENSORS_ADM1025=m ++CONFIG_SENSORS_ADM1026=m ++CONFIG_SENSORS_ADM1029=m ++CONFIG_SENSORS_ADM1031=m ++CONFIG_SENSORS_ADM9240=m ++CONFIG_SENSORS_ADT7310=m ++CONFIG_SENSORS_ADT7410=m ++CONFIG_SENSORS_ADS7828=m ++CONFIG_SENSORS_ADT7462=m ++CONFIG_SENSORS_ADT7470=m ++CONFIG_SENSORS_ADT7475=m ++CONFIG_SENSORS_APPLESMC=m ++CONFIG_SENSORS_ASB100=m ++CONFIG_SENSORS_ATXP1=m ++CONFIG_SENSORS_CORETEMP=m ++CONFIG_SENSORS_DME1737=m ++CONFIG_SENSORS_DS1621=m ++# CONFIG_DS1682 is not set ++CONFIG_SENSORS_F71805F=m ++CONFIG_SENSORS_F71882FG=m ++CONFIG_SENSORS_F75375S=m ++CONFIG_SENSORS_FSCHMD=m ++CONFIG_SENSORS_G760A=m ++CONFIG_SENSORS_G762=m ++CONFIG_SENSORS_GL518SM=m ++CONFIG_SENSORS_GL520SM=m ++CONFIG_SENSORS_HDAPS=m ++# CONFIG_SENSORS_HIH6130 is not set ++# CONFIG_SENSORS_HTU21 is not set ++# CONFIG_SENSORS_I5K_AMB is not set ++# FIXME: IBMAEM x86 only? ++CONFIG_SENSORS_IBMAEM=m ++CONFIG_SENSORS_IBMPEX=m ++# CONFIG_SENSORS_IIO_HWMON is not set ++CONFIG_SENSORS_IT87=m ++CONFIG_SENSORS_K8TEMP=m ++CONFIG_SENSORS_K10TEMP=m ++CONFIG_SENSORS_LIS3LV02D=m ++CONFIG_SENSORS_LIS3_SPI=m ++CONFIG_SENSORS_LIS3_I2C=m ++CONFIG_SENSORS_LM63=m ++CONFIG_SENSORS_LM75=m ++CONFIG_SENSORS_LM77=m ++CONFIG_SENSORS_LM78=m ++CONFIG_SENSORS_LM80=m ++CONFIG_SENSORS_LM83=m ++CONFIG_SENSORS_LM85=m ++CONFIG_SENSORS_LM87=m ++CONFIG_SENSORS_LM90=m ++CONFIG_SENSORS_LM92=m ++CONFIG_SENSORS_LM93=m ++CONFIG_SENSORS_LM95234=m ++CONFIG_SENSORS_LTC4245=m ++CONFIG_SENSORS_MAX1619=m ++CONFIG_SENSORS_MAX6650=m ++CONFIG_SENSORS_MAX6697=m ++CONFIG_SENSORS_MCP3021=m ++CONFIG_SENSORS_NCT6775=m ++CONFIG_SENSORS_NTC_THERMISTOR=m ++CONFIG_SENSORS_PC87360=m ++CONFIG_SENSORS_PC87427=m ++CONFIG_SENSORS_PCF8591=m ++CONFIG_SENSORS_SHT15=m ++CONFIG_SENSORS_SIS5595=m ++CONFIG_CHARGER_SMB347=m ++CONFIG_SENSORS_SMSC47M1=m ++CONFIG_SENSORS_SMSC47M192=m ++CONFIG_SENSORS_SMSC47B397=m ++CONFIG_SENSORS_THMC50=m ++CONFIG_SENSORS_TMP401=m ++CONFIG_APDS9802ALS=m ++CONFIG_ISL29020=m ++CONFIG_ISL29003=m ++CONFIG_SENSORS_BH1770=m ++CONFIG_SENSORS_APDS990X=m ++CONFIG_SENSORS_TSL2550=m ++CONFIG_SENSORS_VIA686A=m ++CONFIG_SENSORS_VIA_CPUTEMP=m ++CONFIG_SENSORS_VT1211=m ++CONFIG_SENSORS_VT8231=m ++CONFIG_SENSORS_W83627HF=m ++CONFIG_SENSORS_W83781D=m ++CONFIG_SENSORS_W83L785TS=m ++CONFIG_SENSORS_W83L786NG=m ++CONFIG_SENSORS_W83627EHF=m ++CONFIG_SENSORS_W83791D=m ++CONFIG_SENSORS_W83792D=m ++CONFIG_SENSORS_W83793=m ++CONFIG_SENSORS_LTC4215=m ++CONFIG_SENSORS_LM95241=m ++CONFIG_SENSORS_LM95245=m ++CONFIG_SENSORS_TMP421=m ++CONFIG_SENSORS_WM8350=m ++CONFIG_SENSORS_WM831X=m ++CONFIG_SENSORS_LM73=m ++CONFIG_SENSORS_AMC6821=m ++CONFIG_SENSORS_INA2XX=m ++CONFIG_SENSORS_INA209=m ++CONFIG_SENSORS_ADT7411=m ++CONFIG_SENSORS_ASC7621=m ++CONFIG_SENSORS_EMC1403=m ++CONFIG_SENSORS_TMP102=m ++CONFIG_SENSORS_LTC4261=m ++# CONFIG_SENSORS_BH1780 is not set ++# CONFIG_SENSORS_JC42 is not set ++# CONFIG_SENSORS_SMM665 is not set ++# CONFIG_SENSORS_EMC2103 is not set ++# CONFIG_SENSORS_GPIO_FAN is not set ++CONFIG_SENSORS_W83795=m ++# CONFIG_SENSORS_W83795_FANCTRL is not set ++CONFIG_SENSORS_DS620=m ++CONFIG_SENSORS_SHT21=m ++CONFIG_SENSORS_LINEAGE=m ++CONFIG_SENSORS_LTC4151=m ++CONFIG_SENSORS_MAX6639=m ++CONFIG_SENSORS_SCH5627=m ++CONFIG_SENSORS_SCH5636=m ++CONFIG_SENSORS_ADS1015=m ++CONFIG_SENSORS_MAX16065=m ++CONFIG_SENSORS_MAX6642=m ++CONFIG_SENSORS_ADM1275=m ++CONFIG_SENSORS_UCD9000=m ++CONFIG_SENSORS_UCD9200=m ++CONFIG_SENSORS_ZL6100=m ++CONFIG_SENSORS_EMC6W201=m ++ ++CONFIG_PMBUS=m ++CONFIG_SENSORS_PMBUS=m ++CONFIG_SENSORS_MAX16064=m ++CONFIG_SENSORS_LM25066=m ++CONFIG_SENSORS_LTC2978=m ++CONFIG_SENSORS_MAX34440=m ++CONFIG_SENSORS_MAX8688=m ++CONFIG_SENSORS_MAX1668=m ++CONFIG_SENSORS_MAX197=m ++ ++# Industrial I/O subsystem configuration ++CONFIG_IIO=m ++CONFIG_IIO_BUFFER=y ++CONFIG_IIO_BUFFER_CB=y ++# CONFIG_IIO_KFIFO_BUF is not set ++CONFIG_IIO_TRIGGERED_BUFFER=m ++CONFIG_IIO_TRIGGER=y ++CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 ++CONFIG_IIO_INTERRUPT_TRIGGER=m ++CONFIG_HID_SENSOR_IIO_COMMON=m ++CONFIG_HID_SENSOR_IIO_TRIGGER=m ++CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS=y ++# CONFIG_IIO_SYSFS_TRIGGER is not set ++# CONFIG_AD5446 is not set ++# CONFIG_AD5380 is not set ++# CONFIG_AD5064 is not set ++# CONFIG_BMA180 is not set ++# CONFIG_MAX1363 is not set ++# CONFIG_MAX517 is not set ++# CONFIG_MCP4725 is not set ++# CONFIG_ITG3200 is not set ++# CONFIG_APDS9300 is not set ++# CONFIG_CM32181 is not set ++# CONFIG_CM36651 is not set ++# CONFIG_GP2AP020A00F is not set ++# CONFIG_TSL2583 is not set ++# CONFIG_TSL2x7x is not set ++# CONFIG_TCS3472 is not set ++# CONFIG_TSL4531 is not set ++# CONFIG_NAU7802 is not set ++# CONFIG_TI_ADC081C is not set ++# CONFIG_EXYNOS_ADC is not set ++# CONFIG_VIPERBOARD_ADC is not set ++# CONFIG_INV_MPU6050_IIO is not set ++CONFIG_IIO_ST_GYRO_3AXIS=m ++CONFIG_IIO_ST_MAGN_3AXIS=m ++CONFIG_IIO_ST_ACCEL_3AXIS=m ++CONFIG_HID_SENSOR_INCLINOMETER_3D=m ++# CONFIG_ADJD_S311 is not set ++# CONFIG_SENSORS_TSL2563 is not set ++# CONFIG_VCNL4000 is not set ++# CONFIG_AK8975 is not set ++# CONFIG_MAG3110 is not set ++# CONFIG_TMP006 is not set ++# CONFIG_IIO_ST_PRESS is not set ++# CONFIG_KXSD9 is not set ++# CONFIG_AD7266 is not set ++# CONFIG_AD7298 is not set ++# CONFIG_AD7476 is not set ++# CONFIG_AD7791 is not set ++# CONFIG_AD7793 is not set ++# CONFIG_AD7887 is not set ++# CONFIG_AD7923 is not set ++# CONFIG_MCP320X is not set ++# CONFIG_MCP3422 is not set ++# CONFIG_AD8366 is not set ++# CONFIG_AD5360 is not set ++# CONFIG_AD5421 is not set ++# CONFIG_AD5449 is not set ++# CONFIG_AD5504 is not set ++# CONFIG_AD5624R_SPI is not set ++# CONFIG_AD5686 is not set ++# CONFIG_AD5755 is not set ++# CONFIG_AD5764 is not set ++# CONFIG_AD5791 is not set ++# CONFIG_AD7303 is not set ++# CONFIG_AD9523 is not set ++# CONFIG_ADF4350 is not set ++# CONFIG_ADIS16080 is not set ++# CONFIG_ADIS16130 is not set ++# CONFIG_ADIS16136 is not set ++# CONFIG_ADIS16260 is not set ++# CONFIG_ADXRS450 is not set ++# CONFIG_ADIS16400 is not set ++# CONFIG_ADIS16480 is not set ++# CONFIG_DHT11 is not set ++# CONFIG_MPL3115 is not set ++ ++# staging IIO drivers ++# CONFIG_AD7291 is not set ++# CONFIG_AD7606 is not set ++# CONFIG_AD799X is not set ++# CONFIG_ADT7316 is not set ++# CONFIG_AD7150 is not set ++# CONFIG_AD7152 is not set ++# CONFIG_AD7746 is not set ++# CONFIG_AD5933 is not set ++# CONFIG_ADE7854 is not set ++# CONFIG_SENSORS_ISL29018 is not set ++# CONFIG_SENSORS_ISL29028 is not set ++# CONFIG_SENSORS_HMC5843 is not set ++# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set ++# CONFIG_IIO_SIMPLE_DUMMY is not set ++# CONFIG_ADIS16201 is not set ++# CONFIG_ADIS16203 is not set ++# CONFIG_ADIS16204 is not set ++# CONFIG_ADIS16209 is not set ++# CONFIG_ADIS16220 is not set ++# CONFIG_ADIS16240 is not set ++# CONFIG_LIS3L02DQ is not set ++# CONFIG_SCA3000 is not set ++# CONFIG_AD7780 is not set ++# CONFIG_AD7816 is not set ++# CONFIG_AD7192 is not set ++# CONFIG_AD7280 is not set ++# CONFIG_AD5930 is not set ++# CONFIG_AD9832 is not set ++# CONFIG_AD9834 is not set ++# CONFIG_AD9850 is not set ++# CONFIG_AD9852 is not set ++# CONFIG_AD9910 is not set ++# CONFIG_AD9951 is not set ++# CONFIG_ADIS16060 is not set ++# CONFIG_ADE7753 is not set ++# CONFIG_ADE7754 is not set ++# CONFIG_ADE7758 is not set ++# CONFIG_ADE7759 is not set ++# CONFIG_AD2S90 is not set ++# CONFIG_AD2S1200 is not set ++# CONFIG_AD2S1210 is not set ++ ++ ++ ++# CONFIG_HMC6352 is not set ++# CONFIG_BMP085 is not set ++# CONFIG_BMP085_I2C is not set ++# CONFIG_PCH_PHUB is not set ++# CONFIG_USB_SWITCH_FSA9480 is not set ++ ++CONFIG_W1=m ++CONFIG_W1_CON=y ++# CONFIG_W1_MASTER_MATROX is not set ++CONFIG_W1_MASTER_DS2490=m ++CONFIG_W1_MASTER_DS2482=m ++CONFIG_W1_MASTER_DS1WM=m ++CONFIG_W1_MASTER_GPIO=m ++# CONFIG_HDQ_MASTER_OMAP is not set ++CONFIG_W1_SLAVE_THERM=m ++CONFIG_W1_SLAVE_SMEM=m ++CONFIG_W1_SLAVE_DS2408=m ++# CONFIG_W1_SLAVE_DS2408_READBACK is not set ++CONFIG_W1_SLAVE_DS2413=m ++CONFIG_W1_SLAVE_DS2423=m ++CONFIG_W1_SLAVE_DS2431=m ++CONFIG_W1_SLAVE_DS2433=m ++CONFIG_W1_SLAVE_DS2433_CRC=y ++CONFIG_W1_SLAVE_DS2760=m ++CONFIG_W1_SLAVE_DS2780=m ++CONFIG_W1_SLAVE_DS2781=m ++CONFIG_W1_SLAVE_DS28E04=m ++CONFIG_W1_SLAVE_BQ27000=m ++ ++# ++# Mice ++# ++ ++# ++# IPMI ++# ++CONFIG_IPMI_HANDLER=m ++# CONFIG_IPMI_PANIC_EVENT is not set ++CONFIG_IPMI_DEVICE_INTERFACE=m ++CONFIG_IPMI_WATCHDOG=m ++CONFIG_IPMI_SI=m ++CONFIG_IPMI_POWEROFF=m ++ ++# ++# Watchdog Cards ++# ++CONFIG_WATCHDOG_CORE=y ++# CONFIG_WATCHDOG_NOWAYOUT is not set ++CONFIG_SOFT_WATCHDOG=m ++CONFIG_WDTPCI=m ++# CONFIG_ACQUIRE_WDT is not set ++# CONFIG_ADVANTECH_WDT is not set ++# CONFIG_EUROTECH_WDT is not set ++CONFIG_IB700_WDT=m ++# CONFIG_SCx200_WDT is not set ++# CONFIG_60XX_WDT is not set ++CONFIG_W83877F_WDT=m ++CONFIG_W83627HF_WDT=m ++CONFIG_MACHZ_WDT=m ++# CONFIG_SC520_WDT is not set ++CONFIG_ALIM7101_WDT=m ++CONFIG_ALIM1535_WDT=m ++CONFIG_IT87_WDT=m ++CONFIG_ITCO_WDT=m ++CONFIG_ITCO_VENDOR_SUPPORT=y ++# CONFIG_SC1200_WDT is not set ++# CONFIG_PC87413_WDT is not set ++# CONFIG_WAFER_WDT is not set ++# CONFIG_CPU5_WDT is not set ++CONFIG_I6300ESB_WDT=m ++CONFIG_IT8712F_WDT=m ++# CONFIG_SBC8360_WDT is not set ++# CONFIG_SBC7240_WDT is not set ++CONFIG_SMSC_SCH311X_WDT=m ++CONFIG_W83977F_WDT=m ++CONFIG_PCIPCWATCHDOG=m ++CONFIG_USBPCWATCHDOG=m ++# CONFIG_SBC_EPX_C3_WATCHDOG is not set ++CONFIG_WM8350_WATCHDOG=m ++CONFIG_WM831X_WATCHDOG=m ++# CONFIG_MAX63XX_WATCHDOG is not set ++# CONFIG_DW_WATCHDOG is not set ++CONFIG_W83697UG_WDT=m ++# CONFIG_MEN_A21_WDT is not set ++# CONFIG_GPIO_WATCHDOG is not set ++ ++CONFIG_HW_RANDOM=y ++CONFIG_HW_RANDOM_TIMERIOMEM=m ++CONFIG_HW_RANDOM_TPM=m ++# CONFIG_HW_RANDOM_ATMEL is not set ++# CONFIG_HW_RANDOM_EXYNOS is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++# CONFIG_RTC_DEBUG is not set ++# CONFIG_GEN_RTC is not set ++CONFIG_RTC_HCTOSYS=y ++# CONFIG_RTC_SYSTOHC is not set ++CONFIG_RTC_HCTOSYS_DEVICE="rtc0" ++CONFIG_RTC_INTF_SYSFS=y ++CONFIG_RTC_INTF_PROC=y ++CONFIG_RTC_INTF_DEV=y ++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set ++CONFIG_RTC_DRV_CMOS=y ++CONFIG_RTC_DRV_DS1307=m ++CONFIG_RTC_DRV_DS1511=m ++CONFIG_RTC_DRV_DS1553=m ++CONFIG_RTC_DRV_DS1672=m ++CONFIG_RTC_DRV_DS1742=m ++CONFIG_RTC_DRV_DS1374=m ++# CONFIG_RTC_DRV_EP93XX is not set ++CONFIG_RTC_DRV_FM3130=m ++CONFIG_RTC_DRV_ISL1208=m ++CONFIG_RTC_DRV_M41T80=m ++CONFIG_RTC_DRV_M41T80_WDT=y ++CONFIG_RTC_DRV_M48T59=m ++CONFIG_RTC_DRV_MAX6900=m ++# CONFIG_RTC_DRV_M48T86 is not set ++CONFIG_RTC_DRV_PCF2127=m ++CONFIG_RTC_DRV_PCF8563=m ++CONFIG_RTC_DRV_PCF8583=m ++CONFIG_RTC_DRV_RS5C372=m ++# CONFIG_RTC_DRV_SA1100 is not set ++# CONFIG_RTC_DRV_TEST is not set ++CONFIG_RTC_DRV_X1205=m ++CONFIG_RTC_DRV_V3020=m ++CONFIG_RTC_DRV_DS2404=m ++CONFIG_RTC_DRV_STK17TA8=m ++# CONFIG_RTC_DRV_S35390A is not set ++CONFIG_RTC_DRV_RX8581=m ++CONFIG_RTC_DRV_RX8025=m ++CONFIG_RTC_DRV_DS1286=m ++CONFIG_RTC_DRV_M48T35=m ++CONFIG_RTC_DRV_BQ4802=m ++CONFIG_RTC_DRV_WM8350=m ++# CONFIG_RTC_DRV_AB3100 is not set ++CONFIG_RTC_DRV_WM831X=m ++CONFIG_RTC_DRV_BQ32K=m ++CONFIG_RTC_DRV_MSM6242=m ++CONFIG_RTC_DRV_RP5C01=m ++CONFIG_RTC_DRV_EM3027=m ++CONFIG_RTC_DRV_RV3029C2=m ++CONFIG_RTC_DRV_PCF50633=m ++CONFIG_RTC_DRV_DS3232=m ++CONFIG_RTC_DRV_ISL12022=m ++# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set ++# CONFIG_RTC_DRV_MOXART is not set ++# CONFIG_RTC_DRV_ISL12057 is not set ++ ++CONFIG_R3964=m ++# CONFIG_APPLICOM is not set ++# CONFIG_SONYPI is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++CONFIG_AGP=y ++CONFIG_AGP_ALI=y ++CONFIG_AGP_ATI=y ++CONFIG_AGP_AMD=y ++CONFIG_AGP_AMD64=y ++CONFIG_AGP_INTEL=y ++CONFIG_AGP_NVIDIA=y ++CONFIG_AGP_SIS=y ++CONFIG_AGP_SWORKS=y ++CONFIG_AGP_VIA=y ++CONFIG_AGP_EFFICEON=y ++ ++CONFIG_VGA_ARB=y ++CONFIG_VGA_ARB_MAX_GPUS=16 ++ ++# CONFIG_STUB_POULSBO is not set ++ ++# ++# PCMCIA character devices ++# ++# CONFIG_SYNCLINK_CS is not set ++ ++CONFIG_CARDMAN_4000=m ++CONFIG_CARDMAN_4040=m ++ ++CONFIG_MWAVE=m ++CONFIG_RAW_DRIVER=y ++CONFIG_MAX_RAW_DEVS=8192 ++CONFIG_HANGCHECK_TIMER=m ++ ++CONFIG_MEDIA_PCI_SUPPORT=y ++# ++# Multimedia devices ++# ++CONFIG_MEDIA_ANALOG_TV_SUPPORT=y ++CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y ++CONFIG_MEDIA_RC_SUPPORT=y ++CONFIG_MEDIA_CONTROLLER=y ++CONFIG_VIDEO_DEV=m ++# CONFIG_VIDEO_ADV_DEBUG is not set ++CONFIG_VIDEO_HELPER_CHIPS_AUTO=y ++CONFIG_VIDEO_V4L2=y ++CONFIG_VIDEO_V4L2_SUBDEV_API=y ++# CONFIG_VIDEO_VIVI is not set ++# CONFIG_USB_SI4713 is not set ++# CONFIG_PLATFORM_SI4713 is not set ++# CONFIG_I2C_SI4713 is not set ++# CONFIG_USB_RAREMONO is not set ++ ++# ++# Video For Linux ++# ++ ++# ++# Video Adapters ++# ++CONFIG_V4L_USB_DRIVERS=y ++CONFIG_VIDEO_CAPTURE_DRIVERS=y ++CONFIG_V4L_PCI_DRIVERS=y ++CONFIG_VIDEO_AU0828=m ++CONFIG_VIDEO_AU0828_V4L2=y ++CONFIG_VIDEO_BT848=m ++CONFIG_VIDEO_BT848_DVB=y ++CONFIG_VIDEO_BWQCAM=m ++CONFIG_VIDEO_SR030PC30=m ++CONFIG_VIDEO_NOON010PC30=m ++CONFIG_VIDEO_CAFE_CCIC=m ++# CONFIG_VIDEO_CPIA is not set ++CONFIG_VIDEO_CPIA2=m ++CONFIG_VIDEO_CQCAM=m ++CONFIG_VIDEO_CX23885=m ++CONFIG_MEDIA_ALTERA_CI=m ++CONFIG_VIDEO_CX18=m ++CONFIG_VIDEO_CX18_ALSA=m ++CONFIG_VIDEO_CX88=m ++CONFIG_VIDEO_CX88_DVB=m ++CONFIG_VIDEO_CX88_ALSA=m ++CONFIG_VIDEO_CX88_BLACKBIRD=m ++CONFIG_VIDEO_CX88_ENABLE_VP3054=y ++CONFIG_VIDEO_CX88_VP3054=m ++CONFIG_VIDEO_EM28XX=m ++CONFIG_VIDEO_EM28XX_V4L2=m ++CONFIG_VIDEO_EM28XX_ALSA=m ++CONFIG_VIDEO_EM28XX_DVB=m ++CONFIG_VIDEO_EM28XX_RC=y ++CONFIG_VIDEO_CX231XX=m ++CONFIG_VIDEO_CX231XX_ALSA=m ++CONFIG_VIDEO_CX231XX_DVB=m ++CONFIG_VIDEO_CX231XX_RC=y ++CONFIG_VIDEO_HEXIUM_ORION=m ++CONFIG_VIDEO_HEXIUM_GEMINI=m ++CONFIG_VIDEO_IVTV=m ++# CONFIG_VIDEO_IVTV_ALSA is not set ++CONFIG_VIDEO_MEYE=m ++CONFIG_VIDEO_MXB=m ++CONFIG_VIDEO_PVRUSB2_DVB=y ++# CONFIG_VIDEO_PMS is not set ++CONFIG_VIDEO_HDPVR=m ++CONFIG_VIDEO_SAA6588=m ++CONFIG_VIDEO_SAA7134=m ++CONFIG_VIDEO_SAA7134_ALSA=m ++CONFIG_VIDEO_SAA7134_DVB=m ++CONFIG_VIDEO_SAA7134_RC=y ++CONFIG_VIDEO_USBVISION=m ++CONFIG_VIDEO_STK1160_COMMON=m ++CONFIG_VIDEO_STK1160=m ++CONFIG_VIDEO_STK1160_AC97=y ++CONFIG_VIDEO_W9966=m ++CONFIG_VIDEO_ZORAN=m ++CONFIG_VIDEO_ZORAN_AVS6EYES=m ++CONFIG_VIDEO_ZORAN_BUZ=m ++CONFIG_VIDEO_ZORAN_DC10=m ++CONFIG_VIDEO_ZORAN_DC30=m ++CONFIG_VIDEO_ZORAN_LML33=m ++CONFIG_VIDEO_ZORAN_LML33R10=m ++CONFIG_VIDEO_ZORAN_ZR36060=m ++# CONFIG_V4L_ISA_PARPORT_DRIVERS is not set ++CONFIG_VIDEO_FB_IVTV=m ++CONFIG_VIDEO_SAA7164=m ++CONFIG_VIDEO_TM6000=m ++CONFIG_VIDEO_TM6000_ALSA=m ++CONFIG_VIDEO_TM6000_DVB=m ++CONFIG_VIDEO_TLG2300=m ++CONFIG_VIDEO_USBTV=m ++ ++CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y ++ ++# ++# Radio Adapters ++# ++CONFIG_RADIO_MAXIRADIO=m ++CONFIG_RADIO_SHARK=m ++CONFIG_RADIO_SHARK2=m ++CONFIG_RADIO_WL1273=m ++ ++CONFIG_MEDIA_ATTACH=y ++ ++# ++# V4L/DVB tuners ++# Selected automatically by not setting CONFIG_MEDIA_TUNER_CUSTOMISE ++# ++# CONFIG_MEDIA_TUNER_CUSTOMISE is not set ++ ++# ++# Digital Video Broadcasting Devices ++# ++CONFIG_DVB_CAPTURE_DRIVERS=y ++CONFIG_DVB_CORE=m ++CONFIG_DVB_NET=y ++CONFIG_DVB_MAX_ADAPTERS=8 ++CONFIG_DVB_DYNAMIC_MINORS=y ++ ++# ++# DVB frontends ++# Selected automatically by not setting CONFIG_DVB_FE_CUSTOMISE ++# ++# CONFIG_DVB_FE_CUSTOMISE is not set ++ ++# ++# Supported DVB bridge Modules ++# ++CONFIG_DVB_BT8XX=m ++CONFIG_DVB_BUDGET_CORE=m ++CONFIG_DVB_PLUTO2=m ++CONFIG_SMS_SIANO_MDTV=m ++CONFIG_SMS_SIANO_RC=y ++# CONFIG_SMS_SIANO_DEBUGFS is not set ++CONFIG_MEDIA_SUBDRV_AUTOSELECT=y ++CONFIG_SMS_USB_DRV=m ++CONFIG_SMS_SDIO_DRV=m ++CONFIG_DVB_TTUSB_DEC=m ++CONFIG_DVB_USB_DTV5100=m ++CONFIG_DVB_USB_AF9015=m ++CONFIG_DVB_USB_ANYSEE=m ++CONFIG_DVB_USB_DW2102=m ++CONFIG_DVB_USB_FRIIO=m ++CONFIG_DVB_USB_EC168=m ++CONFIG_DVB_USB_PCTV452E=m ++CONFIG_DVB_USB_IT913X=m ++CONFIG_DVB_USB_MXL111SF=m ++CONFIG_DVB_DM1105=m ++CONFIG_DVB_FIREDTV=m ++CONFIG_DVB_NGENE=m ++CONFIG_DVB_DDBRIDGE=m ++CONFIG_DVB_USB_TECHNISAT_USB2=m ++CONFIG_DVB_USB_V2=m ++ ++CONFIG_DVB_AV7110=m ++CONFIG_DVB_AV7110_OSD=y ++CONFIG_DVB_BUDGET=m ++CONFIG_DVB_BUDGET_CI=m ++CONFIG_DVB_BUDGET_AV=m ++CONFIG_DVB_BUDGET_PATCH=m ++ ++CONFIG_DVB_TTUSB_BUDGET=m ++ ++CONFIG_DVB_USB_CINERGY_T2=m ++CONFIG_DVB_B2C2_FLEXCOP=m ++# CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG is not set ++ ++CONFIG_DVB_B2C2_FLEXCOP_PCI=m ++# CONFIG_DVB_B2C2_FLEXCOP_PCI_DEBUG is not set ++CONFIG_DVB_B2C2_FLEXCOP_USB=m ++# CONFIG_DVB_B2C2_FLEXCOP_DEBUG is not set ++CONFIG_DVB_USB=m ++# CONFIG_DVB_USB_DEBUG is not set ++CONFIG_DVB_USB_A800=m ++CONFIG_DVB_USB_AF9005=m ++CONFIG_DVB_USB_AF9005_REMOTE=m ++CONFIG_DVB_USB_AU6610=m ++CONFIG_DVB_USB_CXUSB=m ++CONFIG_DVB_USB_DIBUSB_MB=m ++# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set ++CONFIG_DVB_USB_DIBUSB_MC=m ++CONFIG_DVB_USB_DIB0700=m ++CONFIG_DVB_USB_DIGITV=m ++CONFIG_DVB_USB_DTT200U=m ++CONFIG_DVB_USB_GL861=m ++CONFIG_DVB_USB_GP8PSK=m ++CONFIG_DVB_USB_M920X=m ++CONFIG_DVB_USB_NOVA_T_USB2=m ++CONFIG_DVB_USB_CE6230=m ++CONFIG_DVB_USB_OPERA1=m ++CONFIG_DVB_USB_TTUSB2=m ++CONFIG_DVB_USB_UMT_010=m ++CONFIG_DVB_USB_VP702X=m ++CONFIG_DVB_USB_VP7045=m ++CONFIG_DVB_USB_AZ6027=m ++CONFIG_DVB_USB_AZ6007=m ++CONFIG_DVB_USB_LME2510=m ++CONFIG_DVB_USB_RTL28XXU=m ++CONFIG_DVB_USB_AF9035=m ++ ++CONFIG_DVB_PT1=m ++ ++CONFIG_MANTIS_CORE=m ++CONFIG_DVB_MANTIS=m ++CONFIG_DVB_HOPPER=m ++ ++CONFIG_VIDEO_SAA7146=m ++CONFIG_VIDEO_SAA7146_VV=m ++CONFIG_VIDEO_TVP5150=m ++CONFIG_VIDEO_TUNER=m ++CONFIG_VIDEO_BTCX=m ++CONFIG_VIDEO_PVRUSB2=m ++CONFIG_VIDEO_PVRUSB2_SYSFS=y ++# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set ++ ++CONFIG_RC_CORE=m ++CONFIG_RC_DECODERS=y ++CONFIG_LIRC=m ++CONFIG_RC_LOOPBACK=m ++CONFIG_RC_MAP=m ++CONFIG_RC_DEVICES=y ++CONFIG_RC_ATI_REMOTE=m ++CONFIG_IR_NEC_DECODER=m ++CONFIG_IR_RC5_DECODER=m ++CONFIG_IR_RC6_DECODER=m ++CONFIG_IR_JVC_DECODER=m ++CONFIG_IR_SONY_DECODER=m ++CONFIG_IR_RC5_SZ_DECODER=m ++CONFIG_IR_SANYO_DECODER=m ++CONFIG_IR_MCE_KBD_DECODER=m ++CONFIG_IR_LIRC_CODEC=m ++CONFIG_IR_IMON=m ++CONFIG_IR_MCEUSB=m ++CONFIG_IR_ITE_CIR=m ++CONFIG_IR_NUVOTON=m ++CONFIG_IR_FINTEK=m ++CONFIG_IR_REDRAT3=m ++CONFIG_IR_ENE=m ++CONFIG_IR_STREAMZAP=m ++CONFIG_IR_WINBOND_CIR=m ++CONFIG_IR_IGUANA=m ++CONFIG_IR_TTUSBIR=m ++CONFIG_IR_GPIO_CIR=m ++ ++CONFIG_V4L_MEM2MEM_DRIVERS=y ++# CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set ++# CONFIG_VIDEO_SH_VEU is not set ++# CONFIG_VIDEO_RENESAS_VSP1 is not set ++# CONFIG_V4L_TEST_DRIVERS is not set ++ ++# CONFIG_VIDEO_MEM2MEM_TESTDEV is not set ++ ++# ++# Broadcom Crystal HD video decoder driver ++# ++CONFIG_CRYSTALHD=m ++ ++# ++# Graphics support ++# ++ ++CONFIG_DISPLAY_SUPPORT=m ++CONFIG_VIDEO_OUTPUT_CONTROL=m ++ ++# ++# Console display driver support ++# ++CONFIG_VGA_CONSOLE=y ++CONFIG_VGACON_SOFT_SCROLLBACK=y ++CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64 ++CONFIG_DUMMY_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y ++ ++# ++# Logo configuration ++# ++# CONFIG_LOGO_LINUX_MONO is not set ++# CONFIG_LOGO_LINUX_VGA16 is not set ++CONFIG_LOGO_LINUX_CLUT224=y ++ ++# ++# Sound ++# ++ ++# ++# Advanced Linux Sound Architecture ++# ++CONFIG_SOUND_OSS_CORE_PRECLAIM=y ++# CONFIG_SND_DEBUG_VERBOSE is not set ++CONFIG_SND_VERBOSE_PROCFS=y ++CONFIG_SND_SEQUENCER=y ++CONFIG_SND_HRTIMER=y ++CONFIG_SND_SEQ_HRTIMER_DEFAULT=y ++CONFIG_SND_SEQ_DUMMY=m ++CONFIG_SND_SEQUENCER_OSS=y ++CONFIG_SND_SEQ_RTCTIMER_DEFAULT=y ++CONFIG_SND_OSSEMUL=y ++CONFIG_SND_MIXER_OSS=y ++CONFIG_SND_PCM_OSS=y ++CONFIG_SND_PCM_OSS_PLUGINS=y ++CONFIG_SND_RTCTIMER=y ++CONFIG_SND_DYNAMIC_MINORS=y ++CONFIG_SND_MAX_CARDS=32 ++# CONFIG_SND_SUPPORT_OLD_API is not set ++ ++# ++# Generic devices ++# ++CONFIG_SND_DUMMY=m ++CONFIG_SND_ALOOP=m ++CONFIG_SND_VIRMIDI=m ++CONFIG_SND_MTPAV=m ++CONFIG_SND_MTS64=m ++CONFIG_SND_SERIAL_U16550=m ++CONFIG_SND_MPU401=m ++CONFIG_SND_PORTMAN2X4=m ++CONFIG_SND_AC97_POWER_SAVE=y ++CONFIG_SND_AC97_POWER_SAVE_DEFAULT=0 ++ ++CONFIG_SND_DRIVERS=y ++ ++# ++# ISA devices ++# ++CONFIG_SND_AD1889=m ++ ++# ++# PCI devices ++# ++CONFIG_SND_PCI=y ++CONFIG_SND_ALI5451=m ++CONFIG_SND_ALS300=m ++CONFIG_SND_ALS4000=m ++CONFIG_SND_ATIIXP=m ++CONFIG_SND_ATIIXP_MODEM=m ++CONFIG_SND_AU8810=m ++CONFIG_SND_AU8820=m ++CONFIG_SND_AU8830=m ++# CONFIG_SND_AW2 is not set ++CONFIG_SND_AZT3328=m ++CONFIG_SND_BT87X=m ++# CONFIG_SND_BT87X_OVERCLOCK is not set ++CONFIG_SND_CA0106=m ++CONFIG_SND_CMIPCI=m ++CONFIG_SND_CS46XX=m ++CONFIG_SND_CS46XX_NEW_DSP=y ++CONFIG_SND_CS4281=m ++CONFIG_SND_CS5530=m ++CONFIG_SND_CS5535AUDIO=m ++CONFIG_SND_EMU10K1=m ++CONFIG_SND_EMU10K1X=m ++CONFIG_SND_ENS1370=m ++CONFIG_SND_ENS1371=m ++CONFIG_SND_ES1938=m ++CONFIG_SND_ES1968=m ++CONFIG_SND_ES1968_INPUT=y ++CONFIG_SND_ES1968_RADIO=y ++CONFIG_SND_FM801=m ++CONFIG_SND_FM801_TEA575X_BOOL=y ++CONFIG_SND_CTXFI=m ++CONFIG_SND_LX6464ES=m ++CONFIG_SND_HDA_INTEL=y ++CONFIG_SND_HDA_INPUT_BEEP=y ++CONFIG_SND_HDA_INPUT_BEEP_MODE=0 ++CONFIG_SND_HDA_INPUT_JACK=y ++CONFIG_SND_HDA_PATCH_LOADER=y ++CONFIG_SND_HDA_HWDEP=y ++CONFIG_SND_HDA_CODEC_REALTEK=y ++CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS=y ++CONFIG_SND_HDA_CODEC_CA0110=y ++CONFIG_SND_HDA_CODEC_ANALOG=y ++CONFIG_SND_HDA_CODEC_SIGMATEL=y ++CONFIG_SND_HDA_CODEC_VIA=y ++CONFIG_SND_HDA_CODEC_CIRRUS=y ++CONFIG_SND_HDA_CODEC_CONEXANT=y ++CONFIG_SND_HDA_CODEC_CMEDIA=y ++CONFIG_SND_HDA_CODEC_SI3054=y ++CONFIG_SND_HDA_CODEC_HDMI=y ++CONFIG_SND_HDA_I915=y ++CONFIG_SND_HDA_CODEC_CA0132=y ++CONFIG_SND_HDA_CODEC_CA0132_DSP=y ++CONFIG_SND_HDA_GENERIC=y ++CONFIG_SND_HDA_POWER_SAVE=y ++CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 ++CONFIG_SND_HDA_RECONFIG=y ++CONFIG_SND_HDA_PREALLOC_SIZE=4096 ++CONFIG_SND_HDSPM=m ++CONFIG_SND_ICE1712=m ++CONFIG_SND_ICE1724=m ++CONFIG_SND_INTEL8X0=y ++CONFIG_SND_INTEL8X0M=m ++CONFIG_SND_KORG1212=m ++CONFIG_SND_MAESTRO3=m ++CONFIG_SND_MAESTRO3_INPUT=y ++CONFIG_SND_MIXART=m ++CONFIG_SND_NM256=m ++CONFIG_SND_OXYGEN=m ++CONFIG_SND_RME32=m ++CONFIG_SND_PCSP=m ++CONFIG_SND_PCXHR=m ++CONFIG_SND_RIPTIDE=m ++CONFIG_SND_RME96=m ++CONFIG_SND_RME9652=m ++CONFIG_SND_SIS7019=m ++CONFIG_SND_SONICVIBES=m ++CONFIG_SND_HDSP=m ++CONFIG_SND_TRIDENT=m ++CONFIG_SND_VIA82XX=m ++CONFIG_SND_VIA82XX_MODEM=m ++CONFIG_SND_VIRTUOSO=m ++CONFIG_SND_VX222=m ++CONFIG_SND_YMFPCI=m ++CONFIG_SND_ASIHPI=m ++CONFIG_SND_LOLA=m ++ ++# ++# ALSA USB devices ++# ++CONFIG_SND_USB=y ++CONFIG_SND_USB_CAIAQ=m ++CONFIG_SND_USB_CAIAQ_INPUT=y ++CONFIG_SND_USB_USX2Y=m ++CONFIG_SND_USB_US122L=m ++CONFIG_SND_USB_UA101=m ++CONFIG_SND_USB_6FIRE=m ++CONFIG_SND_USB_HIFACE=m ++ ++# ++# PCMCIA devices ++# ++# CONFIG_SND_PCMCIA is not set ++ ++CONFIG_SND_FIREWIRE=y ++CONFIG_SND_FIREWIRE_SPEAKERS=m ++CONFIG_SND_ISIGHT=m ++CONFIG_SND_SCS1X=m ++CONFIG_SND_DICE=m ++ ++# ++# Open Sound System ++# ++# CONFIG_SOUND_PRIME is not set ++ ++# ++# USB support ++# ++CONFIG_USB_SUPPORT=y ++# CONFIG_USB_DEBUG is not set ++ ++# DEPRECATED: See bug 362221. Fix udev. ++# CONFIG_USB_DEVICE_CLASS is not set ++ ++ ++# ++# Miscellaneous USB options ++# ++ ++# Deprecated. ++# CONFIG_USB_DEVICEFS is not set ++ ++CONFIG_USB_DEFAULT_PERSIST=y ++# CONFIG_USB_DYNAMIC_MINORS is not set ++CONFIG_USB_SUSPEND=y ++ ++# ++# USB Host Controller Drivers ++# ++CONFIG_USB_EHCI_ROOT_HUB_TT=y ++CONFIG_USB_EHCI_TT_NEWSCHED=y ++# CONFIG_USB_EHCI_MV is not set ++# CONFIG_USB_EHCI_HCD_PLATFORM is not set ++# CONFIG_USB_ISP116X_HCD is not set ++# CONFIG_USB_ISP1760_HCD is not set ++CONFIG_USB_ISP1362_HCD=m ++CONFIG_USB_FUSBH200_HCD=m ++# CONFIG_USB_FOTG210_HCD is not set ++# CONFIG_USB_GR_UDC is not set ++CONFIG_USB_OHCI_HCD=y ++CONFIG_USB_OHCI_HCD_PCI=y ++# CONFIG_USB_OHCI_HCD_SSB is not set ++# CONFIG_USB_HCD_TEST_MODE is not set ++# CONFIG_USB_OHCI_HCD_PLATFORM is not set ++CONFIG_USB_UHCI_HCD=y ++CONFIG_USB_SL811_HCD=m ++CONFIG_USB_SL811_HCD_ISO=y ++# CONFIG_USB_SL811_CS is not set ++# CONFIG_USB_R8A66597_HCD is not set ++CONFIG_USB_XHCI_HCD=y ++# CONFIG_USB_XHCI_HCD_DEBUGGING is not set ++ ++# ++# USB Device Class drivers ++# ++ ++# ++# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem ++# ++CONFIG_USB_ACM=m ++CONFIG_USB_PRINTER=m ++CONFIG_USB_WDM=m ++CONFIG_USB_TMC=m ++# CONFIG_BLK_DEV_UB is not set ++# CONFIG_USB_STORAGE_DEBUG is not set ++CONFIG_USB_STORAGE_CYPRESS_ATACB=m ++CONFIG_USB_STORAGE_DATAFAB=m ++CONFIG_USB_STORAGE_FREECOM=m ++CONFIG_USB_STORAGE_ISD200=m ++CONFIG_USB_STORAGE_SDDR09=m ++CONFIG_USB_STORAGE_SDDR55=m ++CONFIG_USB_STORAGE_JUMPSHOT=m ++CONFIG_USB_STORAGE_USBAT=y ++CONFIG_USB_STORAGE_ONETOUCH=m ++CONFIG_USB_STORAGE_ALAUDA=m ++CONFIG_USB_STORAGE_KARMA=m ++CONFIG_USB_STORAGE_REALTEK=m ++CONFIG_REALTEK_AUTOPM=y ++CONFIG_USB_STORAGE_ENE_UB6250=m ++# CONFIG_USB_LIBUSUAL is not set ++# CONFIG_USB_UAS is not set ++ ++ ++# ++# USB Human Interface Devices (HID) ++# ++CONFIG_USB_HID=y ++ ++CONFIG_HID_SUPPORT=y ++ ++CONFIG_HID=y ++CONFIG_I2C_HID=m ++CONFIG_HID_BATTERY_STRENGTH=y ++# debugging default is y upstream now ++CONFIG_HIDRAW=y ++CONFIG_UHID=m ++CONFIG_HID_PID=y ++CONFIG_LOGITECH_FF=y ++CONFIG_HID_LOGITECH_DJ=m ++CONFIG_LOGIWII_FF=y ++CONFIG_LOGIRUMBLEPAD2_FF=y ++CONFIG_PANTHERLORD_FF=y ++CONFIG_THRUSTMASTER_FF=y ++CONFIG_HID_WACOM=m ++CONFIG_HID_WACOM_POWER_SUPPLY=y ++CONFIG_ZEROPLUS_FF=y ++CONFIG_USB_HIDDEV=y ++CONFIG_USB_IDMOUSE=m ++CONFIG_DRAGONRISE_FF=y ++CONFIG_GREENASIA_FF=y ++CONFIG_SMARTJOYPLUS_FF=y ++CONFIG_LOGIG940_FF=y ++CONFIG_LOGIWHEELS_FF=y ++CONFIG_HID_MAGICMOUSE=y ++CONFIG_HID_MULTITOUCH=m ++CONFIG_HID_NTRIG=y ++CONFIG_HID_QUANTA=y ++CONFIG_HID_PRIMAX=m ++CONFIG_HID_PS3REMOTE=m ++CONFIG_HID_PRODIKEYS=m ++CONFIG_HID_DRAGONRISE=m ++CONFIG_HID_GYRATION=m ++CONFIG_HID_ICADE=m ++CONFIG_HID_TWINHAN=m ++CONFIG_HID_ORTEK=m ++CONFIG_HID_PANTHERLORD=m ++CONFIG_HID_PETALYNX=m ++CONFIG_HID_PICOLCD=m ++CONFIG_HID_RMI=m ++CONFIG_HID_ROCCAT=m ++CONFIG_HID_ROCCAT_KONE=m ++CONFIG_HID_SAMSUNG=m ++CONFIG_HID_SONY=m ++CONFIG_SONY_FF=y ++CONFIG_HID_SUNPLUS=m ++CONFIG_HID_STEELSERIES=m ++CONFIG_HID_GREENASIA=m ++CONFIG_HID_SMARTJOYPLUS=m ++CONFIG_HID_TOPSEED=m ++CONFIG_HID_THINGM=m ++CONFIG_HID_THRUSTMASTER=m ++CONFIG_HID_XINMO=m ++CONFIG_HID_ZEROPLUS=m ++CONFIG_HID_ZYDACRON=m ++CONFIG_HID_SENSOR_HUB=m ++CONFIG_HID_SENSOR_GYRO_3D=m ++CONFIG_HID_SENSOR_MAGNETOMETER_3D=m ++CONFIG_HID_SENSOR_ALS=m ++CONFIG_HID_SENSOR_ACCEL_3D=m ++CONFIG_HID_EMS_FF=m ++CONFIG_HID_ELECOM=m ++CONFIG_HID_ELO=m ++CONFIG_HID_UCLOGIC=m ++CONFIG_HID_WALTOP=m ++CONFIG_HID_ROCCAT_PYRA=m ++CONFIG_HID_ROCCAT_KONEPLUS=m ++CONFIG_HID_ACRUX=m ++CONFIG_HID_ACRUX_FF=y ++CONFIG_HID_KEYTOUCH=m ++CONFIG_HID_LCPOWER=m ++CONFIG_HID_LENOVO_TPKBD=m ++CONFIG_HID_ROCCAT_ARVO=m ++CONFIG_HID_ROCCAT_ISKU=m ++CONFIG_HID_ROCCAT_KOVAPLUS=m ++CONFIG_HID_HOLTEK=m ++CONFIG_HOLTEK_FF=y ++CONFIG_HID_HUION=m ++CONFIG_HID_SPEEDLINK=m ++CONFIG_HID_WIIMOTE=m ++CONFIG_HID_WIIMOTE_EXT=y ++CONFIG_HID_KYE=m ++CONFIG_HID_SAITEK=m ++CONFIG_HID_TIVO=m ++CONFIG_HID_GENERIC=y ++CONFIG_HID_AUREAL=m ++CONFIG_HID_APPLEIR=m ++ ++ ++# ++# USB Imaging devices ++# ++CONFIG_USB_MDC800=m ++CONFIG_USB_MICROTEK=m ++ ++# ++# USB Multimedia devices ++# ++ ++CONFIG_USB_DSBR=m ++# CONFIG_USB_ET61X251 is not set ++CONFIG_USB_M5602=m ++CONFIG_USB_STV06XX=m ++CONFIG_USB_GSPCA=m ++CONFIG_USB_GSPCA_MR97310A=m ++CONFIG_USB_GSPCA_BENQ=m ++CONFIG_USB_GSPCA_CONEX=m ++CONFIG_USB_GSPCA_CPIA1=m ++CONFIG_USB_GSPCA_ETOMS=m ++CONFIG_USB_GSPCA_FINEPIX=m ++CONFIG_USB_GSPCA_MARS=m ++CONFIG_USB_GSPCA_OV519=m ++CONFIG_USB_GSPCA_OV534=m ++CONFIG_USB_GSPCA_OV534_9=m ++CONFIG_USB_GSPCA_PAC207=m ++CONFIG_USB_GSPCA_PAC7311=m ++CONFIG_USB_GSPCA_SN9C2028=m ++CONFIG_USB_GSPCA_SN9C20X=m ++CONFIG_USB_GSPCA_SONIXB=m ++CONFIG_USB_GSPCA_SONIXJ=m ++CONFIG_USB_GSPCA_SPCA500=m ++CONFIG_USB_GSPCA_SPCA501=m ++CONFIG_USB_GSPCA_SPCA505=m ++CONFIG_USB_GSPCA_SPCA506=m ++CONFIG_USB_GSPCA_SPCA508=m ++CONFIG_USB_GSPCA_SPCA561=m ++CONFIG_USB_GSPCA_STK014=m ++CONFIG_USB_GSPCA_STK1135=m ++CONFIG_USB_GSPCA_SUNPLUS=m ++CONFIG_USB_GSPCA_T613=m ++CONFIG_USB_GSPCA_TOPRO=m ++CONFIG_USB_GSPCA_TV8532=m ++CONFIG_USB_GSPCA_VC032X=m ++CONFIG_USB_GSPCA_ZC3XX=m ++CONFIG_USB_GSPCA_SQ905=m ++CONFIG_USB_GSPCA_SQ905C=m ++CONFIG_USB_GSPCA_PAC7302=m ++CONFIG_USB_GSPCA_STV0680=m ++CONFIG_USB_GL860=m ++CONFIG_USB_GSPCA_JEILINJ=m ++CONFIG_USB_GSPCA_JL2005BCD=m ++CONFIG_USB_GSPCA_KONICA=m ++CONFIG_USB_GSPCA_XIRLINK_CIT=m ++CONFIG_USB_GSPCA_SPCA1528=m ++CONFIG_USB_GSPCA_SQ930X=m ++CONFIG_USB_GSPCA_NW80X=m ++CONFIG_USB_GSPCA_VICAM=m ++CONFIG_USB_GSPCA_KINECT=m ++CONFIG_USB_GSPCA_SE401=m ++ ++CONFIG_USB_S2255=m ++# CONFIG_VIDEO_SH_MOBILE_CEU is not set ++# CONFIG_VIDEO_SH_MOBILE_CSI2 is not set ++# CONFIG_USB_SN9C102 is not set ++CONFIG_USB_ZR364XX=m ++ ++# ++# USB Network adaptors ++# ++CONFIG_USB_CATC=m ++CONFIG_USB_HSO=m ++CONFIG_USB_KAWETH=m ++CONFIG_USB_PEGASUS=m ++CONFIG_USB_RTL8150=m ++CONFIG_USB_RTL8152=m ++CONFIG_USB_USBNET=m ++CONFIG_USB_SPEEDTOUCH=m ++CONFIG_USB_NET_AX8817X=m ++CONFIG_USB_NET_AX88179_178A=m ++CONFIG_USB_NET_DM9601=m ++CONFIG_USB_NET_SR9700=m ++CONFIG_USB_NET_SMSC95XX=m ++CONFIG_USB_NET_GL620A=m ++CONFIG_USB_NET_NET1080=m ++CONFIG_USB_NET_PLUSB=m ++CONFIG_USB_NET_MCS7830=m ++CONFIG_USB_NET_RNDIS_HOST=m ++CONFIG_USB_NET_CDC_SUBSET=m ++CONFIG_USB_NET_CDC_EEM=m ++CONFIG_USB_NET_CDC_NCM=m ++CONFIG_USB_NET_HUAWEI_CDC_NCM=m ++CONFIG_USB_NET_CDC_MBIM=m ++CONFIG_USB_NET_ZAURUS=m ++CONFIG_USB_NET_CX82310_ETH=m ++CONFIG_USB_NET_INT51X1=m ++CONFIG_USB_CDC_PHONET=m ++CONFIG_USB_IPHETH=m ++CONFIG_USB_SIERRA_NET=m ++CONFIG_USB_VL600=m ++ ++# ++# USB Host-to-Host Cables ++# ++CONFIG_USB_AN2720=y ++CONFIG_USB_BELKIN=y ++ ++# ++# Intelligent USB Devices/Gadgets ++# ++CONFIG_USB_ARMLINUX=y ++CONFIG_USB_EPSON2888=y ++CONFIG_USB_KC2190=y ++ ++# CONFIG_USB_MUSB_HDRC is not set ++ ++# ++# USB port drivers ++# ++CONFIG_USB_USS720=m ++ ++# ++# USB Serial Converter support ++# ++CONFIG_USB_SERIAL=y ++CONFIG_USB_SERIAL_GENERIC=y ++CONFIG_USB_SERIAL_SIMPLE=m ++CONFIG_USB_SERIAL_AIRCABLE=m ++CONFIG_USB_SERIAL_ARK3116=m ++CONFIG_USB_SERIAL_BELKIN=m ++CONFIG_USB_SERIAL_CH341=m ++CONFIG_USB_SERIAL_CYPRESS_M8=m ++CONFIG_USB_SERIAL_CYBERJACK=m ++CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m ++CONFIG_USB_SERIAL_CP210X=m ++CONFIG_USB_SERIAL_QUALCOMM=m ++CONFIG_USB_SERIAL_SYMBOL=m ++CONFIG_USB_SERIAL_EDGEPORT=m ++CONFIG_USB_SERIAL_EDGEPORT_TI=m ++CONFIG_USB_SERIAL_EMPEG=m ++# CONFIG_USB_SERIAL_F81232 is not set ++CONFIG_USB_SERIAL_FTDI_SIO=m ++CONFIG_USB_SERIAL_FUNSOFT=m ++CONFIG_USB_SERIAL_GARMIN=m ++CONFIG_USB_SERIAL_HP4X=m ++CONFIG_USB_SERIAL_IPAQ=m ++CONFIG_USB_SERIAL_IPW=m ++CONFIG_USB_SERIAL_IR=m ++CONFIG_USB_SERIAL_IUU=m ++CONFIG_USB_SERIAL_KEYSPAN_PDA=m ++CONFIG_USB_SERIAL_KEYSPAN=m ++CONFIG_USB_SERIAL_KEYSPAN_MPR=y ++CONFIG_USB_SERIAL_KEYSPAN_USA28=y ++CONFIG_USB_SERIAL_KEYSPAN_USA28X=y ++CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y ++CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y ++CONFIG_USB_SERIAL_KEYSPAN_USA19=y ++CONFIG_USB_SERIAL_KEYSPAN_USA18X=y ++CONFIG_USB_SERIAL_KEYSPAN_USA19W=y ++CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y ++CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y ++CONFIG_USB_SERIAL_KEYSPAN_USA49W=y ++CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y ++CONFIG_USB_SERIAL_KLSI=m ++CONFIG_USB_SERIAL_KOBIL_SCT=m ++CONFIG_USB_SERIAL_MCT_U232=m ++# CONFIG_USB_SERIAL_METRO is not set ++CONFIG_USB_SERIAL_MOS7720=m ++CONFIG_USB_SERIAL_MOS7715_PARPORT=y ++# CONFIG_USB_SERIAL_ZIO is not set ++# CONFIG_USB_SERIAL_WISHBONE is not set ++# CONFIG_USB_SERIAL_ZTE is not set ++CONFIG_USB_SERIAL_MOS7840=m ++CONFIG_USB_SERIAL_MOTOROLA=m ++# CONFIG_USB_SERIAL_MXUPORT is not set ++CONFIG_USB_SERIAL_NAVMAN=m ++CONFIG_USB_SERIAL_OPTION=m ++CONFIG_USB_SERIAL_OTI6858=m ++CONFIG_USB_SERIAL_OPTICON=m ++CONFIG_USB_SERIAL_OMNINET=m ++CONFIG_USB_SERIAL_PL2303=m ++# CONFIG_USB_SERIAL_QUATECH2 is not set ++CONFIG_USB_SERIAL_SAFE=m ++CONFIG_USB_SERIAL_SAFE_PADDED=y ++CONFIG_USB_SERIAL_SIERRAWIRELESS=m ++CONFIG_USB_SERIAL_SIEMENS_MPI=m ++CONFIG_USB_SERIAL_SPCP8X5=m ++CONFIG_USB_SERIAL_TI=m ++CONFIG_USB_SERIAL_VISOR=m ++CONFIG_USB_SERIAL_WHITEHEAT=m ++CONFIG_USB_SERIAL_XIRCOM=m ++CONFIG_USB_SERIAL_QCAUX=m ++CONFIG_USB_SERIAL_VIVOPAY_SERIAL=m ++CONFIG_USB_SERIAL_XSENS_MT=m ++CONFIG_USB_SERIAL_DEBUG=m ++CONFIG_USB_SERIAL_SSU100=m ++CONFIG_USB_SERIAL_QT2=m ++CONFIG_USB_SERIAL_FLASHLOADER=m ++CONFIG_USB_SERIAL_SUUNTO=m ++CONFIG_USB_SERIAL_CONSOLE=y ++ ++CONFIG_USB_EZUSB=y ++CONFIG_USB_EMI62=m ++CONFIG_USB_LED=m ++# CONFIG_USB_CYPRESS_CY7C63 is not set ++ ++# ++# USB Miscellaneous drivers ++# ++ ++CONFIG_USB_ADUTUX=m ++CONFIG_USB_SEVSEG=m ++CONFIG_USB_ALI_M5632=y ++CONFIG_USB_APPLEDISPLAY=m ++ ++# Physical Layer USB driver ++# CONFIG_USB_OTG_FSM is not set ++ ++# CONFIG_GENERIC_PHY is not set ++# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set ++# CONFIG_PHY_EXYNOS_DP_VIDEO is not set ++# CONFIG_OMAP_USB2 is not set ++# CONFIG_OMAP_USB3 is not set ++# CONFIG_OMAP_CONTROL_USB is not set ++# CONFIG_AM335X_PHY_USB is not set ++# CONFIG_SAMSUNG_USBPHY is not set ++# CONFIG_SAMSUNG_USB2PHY is not set ++# CONFIG_SAMSUNG_USB3PHY is not set ++# CONFIG_BCM_KONA_USB2_PHY is not set ++CONFIG_USB_RCAR_PHY=m ++CONFIG_USB_ATM=m ++CONFIG_USB_CXACRU=m ++# CONFIG_USB_C67X00_HCD is not set ++# CONFIG_USB_CYTHERM is not set ++CONFIG_USB_EMI26=m ++CONFIG_USB_FTDI_ELAN=m ++CONFIG_USB_FILE_STORAGE=m ++# CONFIG_USB_FILE_STORAGE_TEST is not set ++# CONFIG_USB_DWC3 is not set ++# CONFIG_USB_GADGETFS is not set ++# CONFIG_USB_OXU210HP_HCD is not set ++CONFIG_USB_IOWARRIOR=m ++CONFIG_USB_ISIGHTFW=m ++CONFIG_USB_YUREX=m ++CONFIG_USB_EZUSB_FX2=m ++CONFIG_USB_HSIC_USB3503=m ++CONFIG_USB_LCD=m ++CONFIG_USB_LD=m ++CONFIG_USB_LEGOTOWER=m ++CONFIG_USB_MON=y ++CONFIG_USB_PWC=m ++CONFIG_USB_PWC_INPUT_EVDEV=y ++# CONFIG_USB_PWC_DEBUG is not set ++# CONFIG_USB_RIO500 is not set ++CONFIG_USB_SISUSBVGA=m ++CONFIG_USB_SISUSBVGA_CON=y ++CONFIG_RADIO_SI470X=y ++CONFIG_USB_KEENE=m ++CONFIG_USB_MA901=m ++CONFIG_USB_SI470X=m ++CONFIG_I2C_SI470X=m ++CONFIG_RADIO_SI4713=m ++# CONFIG_RADIO_TEF6862 is not set ++CONFIG_USB_MR800=m ++CONFIG_USB_STKWEBCAM=m ++# CONFIG_USB_TEST is not set ++# CONFIG_USB_EHSET_TEST_FIXTURE is not set ++CONFIG_USB_TRANCEVIBRATOR=m ++CONFIG_USB_U132_HCD=m ++CONFIG_USB_UEAGLEATM=m ++CONFIG_USB_XUSBATM=m ++ ++# CONFIG_USB_DWC2 is not set ++ ++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y ++ ++# CONFIG_USB_ISP1301 is not set ++ ++# CONFIG_USB_OTG is not set ++ ++# ++# Sonics Silicon Backplane ++# ++CONFIG_SSB=m ++CONFIG_SSB_PCIHOST=y ++CONFIG_SSB_SDIOHOST=y ++CONFIG_SSB_PCMCIAHOST=y ++# CONFIG_SSB_SILENT is not set ++# CONFIG_SSB_DEBUG is not set ++CONFIG_SSB_DRIVER_PCICORE=y ++CONFIG_SSB_DRIVER_GPIO=y ++ ++# Multifunction USB devices ++# CONFIG_MFD_PCF50633 is not set ++CONFIG_PCF50633_ADC=m ++CONFIG_PCF50633_GPIO=m ++# CONFIG_AB3100_CORE is not set ++CONFIG_INPUT_PCF50633_PMU=m ++CONFIG_INPUT_GPIO_ROTARY_ENCODER=m ++ ++CONFIG_MFD_SUPPORT=y ++CONFIG_MFD_VX855=m ++CONFIG_MFD_SM501=m ++CONFIG_MFD_SM501_GPIO=y ++CONFIG_MFD_RTSX_PCI=m ++# CONFIG_MFD_TI_AM335X_TSCADC is not set ++CONFIG_MFD_VIPERBOARD=m ++# CONFIG_MFD_RETU is not set ++# CONFIG_MFD_TC6393XB is not set ++# CONFIG_MFD_WM8400 is not set ++# CONFIG_MFD_WM8350_I2C is not set ++# CONFIG_MFD_WM8350 is not set ++# CONFIG_MFD_WM831X is not set ++# CONFIG_AB3100_OTP is not set ++# CONFIG_MFD_TIMBERDALE is not set ++# CONFIG_MFD_WM8994 is not set ++# CONFIG_MFD_88PM860X is not set ++# CONFIG_LPC_SCH is not set ++# CONFIG_LPC_ICH is not set ++# CONFIG_HTC_I2CPLD is not set ++# CONFIG_MFD_MAX8925 is not set ++# CONFIG_MFD_ASIC3 is not set ++# CONFIG_MFD_AS3722 is not set ++# CONFIG_HTC_EGPIO is not set ++# CONFIG_TPS6507X is not set ++# CONFIG_ABX500_CORE is not set ++# CONFIG_MFD_RDC321X is not set ++# CONFIG_MFD_JANZ_CMODIO is not set ++# CONFIG_MFD_KEMPLD is not set ++# CONFIG_MFD_WM831X_I2C is not set ++# CONFIG_MFD_CS5535 is not set ++# CONFIG_MFD_STMPE is not set ++# CONFIG_MFD_MAX8998 is not set ++# CONFIG_MFD_TPS6586X is not set ++# CONFIG_MFD_TC3589X is not set ++# CONFIG_MFD_WL1273_CORE is not set ++# CONFIG_MFD_TPS65217 is not set ++# CONFIG_MFD_LM3533 is not set ++# CONFIG_MFD_ARIZONA is not set ++# CONFIG_MFD_ARIZONA_I2C is not set ++# CONFIG_MFD_CROS_EC is not set ++# CONFIG_MFD_TPS65912 is not set ++# CONFIG_MFD_SYSCON is not set ++# CONFIG_MFD_DA9063 is not set ++# CONFIG_MFD_LP3943 is not set ++ ++# ++# File systems ++# ++CONFIG_MISC_FILESYSTEMS=y ++ ++# ext4 is used for ext2 and ext3 filesystems ++CONFIG_JBD2=y ++CONFIG_FS_MBCACHE=y ++CONFIG_REISERFS_FS=m ++# CONFIG_REISERFS_CHECK is not set ++CONFIG_REISERFS_PROC_INFO=y ++CONFIG_REISERFS_FS_XATTR=y ++CONFIG_REISERFS_FS_POSIX_ACL=y ++CONFIG_REISERFS_FS_SECURITY=y ++CONFIG_JFS_FS=m ++# CONFIG_JFS_DEBUG is not set ++# CONFIG_JFS_STATISTICS is not set ++CONFIG_JFS_POSIX_ACL=y ++CONFIG_JFS_SECURITY=y ++CONFIG_XFS_FS=m ++# CONFIG_XFS_DEBUG is not set ++# CONFIG_XFS_RT is not set ++CONFIG_XFS_QUOTA=y ++CONFIG_XFS_POSIX_ACL=y ++CONFIG_MINIX_FS=m ++CONFIG_ROMFS_FS=m ++# CONFIG_QFMT_V1 is not set ++CONFIG_QFMT_V2=y ++CONFIG_QUOTACTL=y ++CONFIG_DNOTIFY=y ++# Autofsv3 is obsolete. ++# systemd is dependant upon AUTOFS, so build it in. ++# CONFIG_EXOFS_FS is not set ++# CONFIG_EXOFS_DEBUG is not set ++CONFIG_NILFS2_FS=m ++# CONFIG_LOGFS is not set ++CONFIG_CEPH_FS=m ++CONFIG_CEPH_FSCACHE=y ++CONFIG_BLK_DEV_RBD=m ++CONFIG_CEPH_LIB=m ++CONFIG_CEPH_FS_POSIX_ACL=y ++# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set ++ ++CONFIG_FSCACHE=m ++CONFIG_FSCACHE_STATS=y ++# CONFIG_FSCACHE_HISTOGRAM is not set ++# CONFIG_FSCACHE_DEBUG is not set ++CONFIG_FSCACHE_OBJECT_LIST=y ++ ++CONFIG_CACHEFILES=m ++# CONFIG_CACHEFILES_DEBUG is not set ++# CONFIG_CACHEFILES_HISTOGRAM is not set ++ ++# ++# CD-ROM/DVD Filesystems ++# ++ ++# ++# DOS/FAT/NT Filesystems ++# ++CONFIG_FAT_FS=m ++CONFIG_FAT_DEFAULT_CODEPAGE=437 ++CONFIG_FAT_DEFAULT_IOCHARSET="ascii" ++# CONFIG_NTFS_FS is not set ++ ++# ++# Pseudo filesystems ++# ++CONFIG_PROC_FS=y ++CONFIG_PROC_KCORE=y ++CONFIG_PROC_VMCORE=y ++CONFIG_TMPFS_POSIX_ACL=y ++CONFIG_TMPFS_XATTR=y ++CONFIG_HUGETLBFS=y ++CONFIG_HUGETLB_PAGE=y ++# CONFIG_DEBUG_FS is not set ++ ++# ++# Miscellaneous filesystems ++# ++# CONFIG_ADFS_FS is not set ++CONFIG_AFFS_FS=m ++CONFIG_ECRYPT_FS=m ++# CONFIG_ECRYPT_FS_MESSAGING is not set ++CONFIG_HFS_FS=m ++CONFIG_HFSPLUS_FS=m ++# CONFIG_HFSPLUS_FS_POSIX_ACL is not set ++CONFIG_BEFS_FS=m ++# CONFIG_BEFS_DEBUG is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EFS_FS is not set ++ ++CONFIG_CRAMFS=m ++CONFIG_SQUASHFS=m ++CONFIG_SQUASHFS_XATTR=y ++CONFIG_SQUASHFS_LZO=y ++CONFIG_SQUASHFS_XZ=y ++CONFIG_SQUASHFS_ZLIB=y ++# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set ++# CONFIG_SQUASHFS_EMBEDDED is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_HPFS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX6FS_FS is not set ++CONFIG_SYSV_FS=m ++CONFIG_UFS_FS=m ++# CONFIG_UFS_FS_WRITE is not set ++# CONFIG_UFS_DEBUG is not set ++CONFIG_9P_FS=m ++CONFIG_9P_FSCACHE=y ++CONFIG_9P_FS_POSIX_ACL=y ++CONFIG_9P_FS_SECURITY=y ++# CONFIG_OMFS_FS is not set ++CONFIG_CUSE=m ++# CONFIG_F2FS_FS is not set ++ ++# ++# Network File Systems ++# ++CONFIG_NETWORK_FILESYSTEMS=y ++# CONFIG_NFS_V2 is not set ++CONFIG_NFS_V3=y ++CONFIG_NFS_SWAP=y ++CONFIG_NFS_V4_1=y ++CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" ++# CONFIG_NFS_V4_1_MIGRATION is not set ++CONFIG_NFS_V4_2=y ++CONFIG_NFSD=m ++CONFIG_NFSD_V3=y ++CONFIG_NFSD_V3_ACL=y ++CONFIG_NFSD_V4=y ++CONFIG_NFSD_V4_SECURITY_LABEL=y ++CONFIG_NFS_FSCACHE=y ++# CONFIG_NFS_USE_LEGACY_DNS is not set ++CONFIG_PNFS_OBJLAYOUT=m ++CONFIG_PNFS_BLOCK=m ++CONFIG_LOCKD=m ++CONFIG_LOCKD_V4=y ++CONFIG_EXPORTFS=y ++CONFIG_SUNRPC=m ++CONFIG_SUNRPC_GSS=m ++CONFIG_SUNRPC_XPRT_RDMA=m ++CONFIG_SUNRPC_DEBUG=y ++CONFIG_RPCSEC_GSS_KRB5=m ++CONFIG_CIFS=m ++CONFIG_CIFS_STATS=y ++# CONFIG_CIFS_STATS2 is not set ++CONFIG_CIFS_SMB2=y ++CONFIG_CIFS_UPCALL=y ++CONFIG_CIFS_XATTR=y ++CONFIG_CIFS_POSIX=y ++CONFIG_CIFS_FSCACHE=y ++CONFIG_CIFS_ACL=y ++CONFIG_CIFS_WEAK_PW_HASH=y ++CONFIG_CIFS_DEBUG=y ++# CONFIG_CIFS_DEBUG2 is not set ++CONFIG_CIFS_DFS_UPCALL=y ++CONFIG_CIFS_NFSD_EXPORT=y ++CONFIG_NCP_FS=m ++CONFIG_NCPFS_PACKET_SIGNING=y ++CONFIG_NCPFS_IOCTL_LOCKING=y ++CONFIG_NCPFS_STRONG=y ++CONFIG_NCPFS_NFS_NS=y ++CONFIG_NCPFS_OS2_NS=y ++CONFIG_NCPFS_SMALLDOS=y ++CONFIG_NCPFS_NLS=y ++CONFIG_NCPFS_EXTRAS=y ++CONFIG_CODA_FS=m ++# CONFIG_AFS_FS is not set ++# CONFIG_AF_RXRPC is not set ++ ++CONFIG_OCFS2_FS=m ++# CONFIG_OCFS2_DEBUG_FS is not set ++# CONFIG_OCFS2_DEBUG_MASKLOG is not set ++CONFIG_OCFS2_FS_O2CB=m ++CONFIG_OCFS2_FS_USERSPACE_CLUSTER=m ++# CONFIG_OCFS2_FS_STATS is not set ++ ++CONFIG_BTRFS_FS=m ++CONFIG_BTRFS_FS_POSIX_ACL=y ++# Maybe see if we want this on for debug kernels? ++# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set ++# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set ++# CONFIG_BTRFS_DEBUG is not set ++# CONFIG_BTRFS_ASSERT is not set ++ ++CONFIG_CONFIGFS_FS=y ++ ++CONFIG_DLM=m ++CONFIG_DLM_DEBUG=y ++CONFIG_GFS2_FS=m ++CONFIG_GFS2_FS_LOCKING_DLM=y ++ ++ ++CONFIG_UBIFS_FS_XATTR=y ++# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set ++# CONFIG_UBIFS_FS_DEBUG is not set ++ ++# ++# Partition Types ++# ++CONFIG_PARTITION_ADVANCED=y ++# CONFIG_ACORN_PARTITION is not set ++CONFIG_AIX_PARTITION=y ++CONFIG_AMIGA_PARTITION=y ++# CONFIG_ATARI_PARTITION is not set ++CONFIG_BSD_DISKLABEL=y ++CONFIG_EFI_PARTITION=y ++CONFIG_KARMA_PARTITION=y ++CONFIG_LDM_PARTITION=y ++# CONFIG_LDM_DEBUG is not set ++CONFIG_MAC_PARTITION=y ++CONFIG_MSDOS_PARTITION=y ++CONFIG_MINIX_SUBPARTITION=y ++CONFIG_OSF_PARTITION=y ++CONFIG_SGI_PARTITION=y ++CONFIG_SOLARIS_X86_PARTITION=y ++CONFIG_SUN_PARTITION=y ++# CONFIG_SYSV68_PARTITION is not set ++CONFIG_UNIXWARE_DISKLABEL=y ++# CONFIG_ULTRIX_PARTITION is not set ++# CONFIG_CMDLINE_PARTITION is not set ++ ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_CODEPAGE_737=m ++CONFIG_NLS_CODEPAGE_775=m ++CONFIG_NLS_CODEPAGE_850=m ++CONFIG_NLS_CODEPAGE_852=m ++CONFIG_NLS_CODEPAGE_855=m ++CONFIG_NLS_CODEPAGE_857=m ++CONFIG_NLS_CODEPAGE_860=m ++CONFIG_NLS_CODEPAGE_861=m ++CONFIG_NLS_CODEPAGE_862=m ++CONFIG_NLS_CODEPAGE_863=m ++CONFIG_NLS_CODEPAGE_864=m ++CONFIG_NLS_CODEPAGE_865=m ++CONFIG_NLS_CODEPAGE_866=m ++CONFIG_NLS_CODEPAGE_869=m ++CONFIG_NLS_CODEPAGE_936=m ++CONFIG_NLS_CODEPAGE_950=m ++CONFIG_NLS_CODEPAGE_932=m ++CONFIG_NLS_CODEPAGE_949=m ++CONFIG_NLS_CODEPAGE_874=m ++CONFIG_NLS_ISO8859_8=m ++CONFIG_NLS_CODEPAGE_1250=m ++CONFIG_NLS_CODEPAGE_1251=m ++CONFIG_NLS_ISO8859_2=m ++CONFIG_NLS_ISO8859_3=m ++CONFIG_NLS_ISO8859_4=m ++CONFIG_NLS_ISO8859_5=m ++CONFIG_NLS_ISO8859_6=m ++CONFIG_NLS_ISO8859_7=m ++CONFIG_NLS_ISO8859_9=m ++CONFIG_NLS_ISO8859_13=m ++CONFIG_NLS_ISO8859_14=m ++CONFIG_NLS_KOI8_R=m ++CONFIG_NLS_KOI8_U=m ++CONFIG_NLS_MAC_ROMAN=m ++CONFIG_NLS_MAC_CELTIC=m ++CONFIG_NLS_MAC_CENTEURO=m ++CONFIG_NLS_MAC_CROATIAN=m ++CONFIG_NLS_MAC_CYRILLIC=m ++CONFIG_NLS_MAC_GAELIC=m ++CONFIG_NLS_MAC_GREEK=m ++CONFIG_NLS_MAC_ICELAND=m ++CONFIG_NLS_MAC_INUIT=m ++CONFIG_NLS_MAC_ROMANIAN=m ++CONFIG_NLS_MAC_TURKISH=m ++ ++# ++# Profiling support ++# ++CONFIG_PROFILING=y ++CONFIG_OPROFILE=m ++CONFIG_OPROFILE_EVENT_MULTIPLEX=y ++ ++# ++# Kernel hacking ++# ++CONFIG_DEBUG_KERNEL=y ++CONFIG_FRAME_WARN=1024 ++CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x0 ++# CONFIG_DEBUG_INFO is not set ++CONFIG_FRAME_POINTER=y ++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set ++# CONFIG_DEBUG_DRIVER is not set ++CONFIG_HEADERS_CHECK=y ++# CONFIG_LKDTM is not set ++# CONFIG_NOTIFIER_ERROR_INJECTION is not set ++# CONFIG_READABLE_ASM is not set ++ ++# CONFIG_RT_MUTEX_TESTER is not set ++# CONFIG_DEBUG_LOCKDEP is not set ++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set ++ ++# DEBUG options that don't get enabled/disabled with 'make debug/release' ++ ++# This generates a huge amount of dmesg spew ++# CONFIG_DEBUG_KOBJECT is not set ++# ++# This breaks booting until the module patches are in-tree ++# CONFIG_DEBUG_KOBJECT_RELEASE is not set ++# ++# ++# These debug options are deliberatly left on (even in 'make release' kernels). ++# They aren't that much of a performance impact, and the value ++# from getting useful bug-reports makes it worth leaving them on. ++# CONFIG_DEBUG_HIGHMEM is not set ++# CONFIG_DEBUG_SHIRQ is not set ++CONFIG_BOOT_PRINTK_DELAY=y ++CONFIG_DEBUG_DEVRES=y ++CONFIG_DEBUG_RODATA_TEST=y ++CONFIG_DEBUG_NX_TEST=m ++CONFIG_DEBUG_SET_MODULE_RONX=y ++CONFIG_DEBUG_BOOT_PARAMS=y ++# CONFIG_DEBUG_VM is not set ++# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set ++CONFIG_LOCKUP_DETECTOR=y ++# CONFIG_DEBUG_INFO_REDUCED is not set ++# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set ++# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set ++# CONFIG_PANIC_ON_OOPS is not set ++CONFIG_PANIC_TIMEOUT=0 ++CONFIG_ATOMIC64_SELFTEST=y ++CONFIG_MEMORY_FAILURE=y ++CONFIG_HWPOISON_INJECT=m ++CONFIG_CROSS_MEMORY_ATTACH=y ++# CONFIG_DEBUG_SECTION_MISMATCH is not set ++# CONFIG_BACKTRACE_SELF_TEST is not set ++CONFIG_RESOURCE_COUNTERS=y ++# CONFIG_DEBUG_VIRTUAL is not set ++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set ++CONFIG_EARLY_PRINTK_DBGP=y ++# CONFIG_PAGE_POISONING is not set ++# CONFIG_CRASH_DUMP is not set ++# CONFIG_CRASH is not set ++# CONFIG_GCOV_KERNEL is not set ++# CONFIG_RAMOOPS is not set ++ ++ ++# ++# Security options ++# ++CONFIG_SECURITY=y ++# CONFIG_SECURITY_DMESG_RESTRICT is not set ++CONFIG_SECURITY_NETWORK=y ++CONFIG_SECURITY_NETWORK_XFRM=y ++# CONFIG_SECURITY_PATH is not set ++CONFIG_SECURITY_SELINUX=y ++CONFIG_SECURITY_SELINUX_BOOTPARAM=y ++CONFIG_SECURITY_SELINUX_DISABLE=y ++CONFIG_SECURITY_SELINUX_DEVELOP=y ++CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1 ++CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 ++CONFIG_SECURITY_SELINUX_AVC_STATS=y ++# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set ++# CONFIG_SECURITY_SMACK is not set ++# CONFIG_SECURITY_TOMOYO is not set ++# CONFIG_SECURITY_APPARMOR is not set ++# CONFIG_SECURITY_YAMA is not set ++CONFIG_AUDIT=y ++CONFIG_AUDITSYSCALL=y ++# http://lists.fedoraproject.org/pipermail/kernel/2013-February/004125.html ++CONFIG_AUDIT_LOGINUID_IMMUTABLE=y ++ ++CONFIG_SECCOMP=y ++ ++# CONFIG_SSBI is not set ++ ++# ++# Cryptographic options ++# ++CONFIG_CRYPTO=y ++CONFIG_CRYPTO_FIPS=y ++CONFIG_CRYPTO_USER_API_HASH=y ++CONFIG_CRYPTO_USER_API_SKCIPHER=y ++CONFIG_CRYPTO_MANAGER=y ++# Note, CONFIG_CRYPTO_MANAGER_DISABLE_TESTS needs to be unset, or FIPS will be disabled. ++# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set ++CONFIG_CRYPTO_HW=y ++CONFIG_CRYPTO_BLKCIPHER=y ++# CONFIG_CRYPTO_CRYPTD is not set ++CONFIG_CRYPTO_AES=y ++CONFIG_CRYPTO_ARC4=m ++CONFIG_CRYPTO_ANUBIS=m ++CONFIG_CRYPTO_AUTHENC=m ++CONFIG_CRYPTO_CAST5=m ++CONFIG_CRYPTO_CAST6=m ++CONFIG_CRYPTO_CRC32C=y ++CONFIG_CRYPTO_CRC32=m ++CONFIG_CRYPTO_CTR=y ++CONFIG_CRYPTO_DEFLATE=m ++CONFIG_CRYPTO_FCRYPT=m ++CONFIG_CRYPTO_GF128MUL=m ++CONFIG_CRYPTO_CMAC=m ++CONFIG_CRYPTO_HMAC=y ++CONFIG_CRYPTO_KHAZAD=m ++CONFIG_CRYPTO_LZO=m ++CONFIG_CRYPTO_LZ4=m ++CONFIG_CRYPTO_LZ4HC=m ++CONFIG_CRYPTO_NULL=m ++CONFIG_CRYPTO_PCBC=m ++CONFIG_CRYPTO_SALSA20=m ++CONFIG_CRYPTO_SALSA20_586=m ++CONFIG_CRYPTO_SEED=m ++CONFIG_CRYPTO_SEQIV=m ++CONFIG_CRYPTO_SERPENT=m ++CONFIG_CRYPTO_TEA=m ++CONFIG_CRYPTO_XCBC=m ++CONFIG_CRYPTO_VMAC=m ++CONFIG_CRYPTO_CRC32C_INTEL=m ++CONFIG_CRYPTO_GHASH=m ++CONFIG_CRYPTO_DEV_HIFN_795X=m ++CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y ++CONFIG_CRYPTO_PCRYPT=m ++ ++ ++ ++# Random number generation ++ ++# ++# Library routines ++# ++CONFIG_CRC16=y ++CONFIG_CRC32=m ++# CONFIG_CRC32_SELFTEST is not set ++CONFIG_CRC_ITU_T=m ++CONFIG_CRC8=m ++# CONFIG_RANDOM32_SELFTEST is not set ++CONFIG_CORDIC=m ++# CONFIG_DDR is not set ++ ++CONFIG_CRYPTO_ZLIB=m ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=m ++ ++CONFIG_INITRAMFS_SOURCE="" ++CONFIG_KEYS=y ++CONFIG_PERSISTENT_KEYRINGS=y ++CONFIG_BIG_KEYS=y ++CONFIG_TRUSTED_KEYS=m ++CONFIG_ENCRYPTED_KEYS=m ++CONFIG_KEYS_DEBUG_PROC_KEYS=y ++CONFIG_CDROM_PKTCDVD=m ++CONFIG_CDROM_PKTCDVD_BUFFERS=8 ++# CONFIG_CDROM_PKTCDVD_WCACHE is not set ++ ++CONFIG_ATA_OVER_ETH=m ++CONFIG_BACKLIGHT_LCD_SUPPORT=y ++CONFIG_BACKLIGHT_CLASS_DEVICE=m ++# CONFIG_BACKLIGHT_GENERIC is not set ++CONFIG_BACKLIGHT_PROGEAR=m ++ ++CONFIG_LCD_CLASS_DEVICE=m ++CONFIG_LCD_PLATFORM=m ++ ++CONFIG_FAIR_GROUP_SCHED=y ++CONFIG_CFS_BANDWIDTH=y ++CONFIG_SCHED_OMIT_FRAME_POINTER=y ++CONFIG_RT_GROUP_SCHED=y ++CONFIG_SCHED_AUTOGROUP=y ++ ++CONFIG_CPUSETS=y ++CONFIG_PROC_PID_CPUSET=y ++ ++# CONFIG_CGROUP_DEBUG is not set ++CONFIG_CGROUP_CPUACCT=y ++CONFIG_CGROUP_DEVICE=y ++CONFIG_CGROUP_FREEZER=y ++CONFIG_CGROUP_SCHED=y ++CONFIG_MEMCG=y ++CONFIG_MEMCG_SWAP=y ++CONFIG_MEMCG_SWAP_ENABLED=y ++CONFIG_MEMCG_KMEM=y ++# CONFIG_CGROUP_HUGETLB is not set ++CONFIG_CGROUP_PERF=y ++CONFIG_CGROUP_NET_PRIO=m ++# CONFIG_CGROUP_NET_CLASSID is not set ++CONFIG_BLK_CGROUP=y ++ ++# CONFIG_SYSFS_DEPRECATED is not set ++# CONFIG_SYSFS_DEPRECATED_V2 is not set ++ ++CONFIG_PRINTK_TIME=y ++ ++CONFIG_ENABLE_MUST_CHECK=y ++# CONFIG_ENABLE_WARN_DEPRECATED is not set ++ ++CONFIG_KEXEC=y ++ ++CONFIG_HWMON=y ++# CONFIG_HWMON_DEBUG_CHIP is not set ++CONFIG_THERMAL_HWMON=y ++# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set ++# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set ++CONFIG_THERMAL_GOV_FAIR_SHARE=y ++# CONFIG_THERMAL_GOV_USER_SPACE is not set ++CONFIG_THERMAL_GOV_STEP_WISE=y ++# CONFIG_THERMAL_EMULATION is not set ++ ++CONFIG_INOTIFY=y ++CONFIG_INOTIFY_USER=y ++ ++# ++# Bus devices ++# ++# CONFIG_OMAP_OCP2SCP is not set ++CONFIG_PROC_EVENTS=y ++ ++CONFIG_IBMASR=m ++ ++CONFIG_PM=y ++CONFIG_PM_STD_PARTITION="" ++# CONFIG_DPM_WATCHDOG is not set # revisit this in debug ++CONFIG_PM_TRACE=y ++CONFIG_PM_TRACE_RTC=y ++# CONFIG_PM_OPP is not set ++# CONFIG_PM_AUTOSLEEP is not set ++# CONFIG_PM_WAKELOCKS is not set ++CONFIG_HIBERNATION=y ++# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set ++CONFIG_SUSPEND=y ++ ++CONFIG_CPU_FREQ_TABLE=y ++CONFIG_CPU_FREQ_STAT=m ++CONFIG_CPU_FREQ_STAT_DETAILS=y ++ ++ ++CONFIG_NET_VENDOR_SMC=y ++# CONFIG_IBMTR is not set ++# CONFIG_SKISA is not set ++# CONFIG_PROTEON is not set ++# CONFIG_SMCTR is not set ++ ++# CONFIG_MOUSE_ATIXL is not set ++ ++# CONFIG_MEDIA_PARPORT_SUPPORT is not set ++ ++CONFIG_RADIO_TEA5764=m ++CONFIG_RADIO_SAA7706H=m ++CONFIG_RADIO_CADET=m ++CONFIG_RADIO_RTRACK=m ++CONFIG_RADIO_RTRACK2=m ++CONFIG_RADIO_AZTECH=m ++CONFIG_RADIO_GEMTEK=m ++CONFIG_RADIO_SF16FMI=m ++CONFIG_RADIO_SF16FMR2=m ++CONFIG_RADIO_TERRATEC=m ++CONFIG_RADIO_TRUST=m ++CONFIG_RADIO_TYPHOON=m ++CONFIG_RADIO_ZOLTRIX=m ++ ++CONFIG_SND_DARLA20=m ++CONFIG_SND_GINA20=m ++CONFIG_SND_LAYLA20=m ++CONFIG_SND_DARLA24=m ++CONFIG_SND_GINA24=m ++CONFIG_SND_LAYLA24=m ++CONFIG_SND_MONA=m ++CONFIG_SND_MIA=m ++CONFIG_SND_ECHO3G=m ++CONFIG_SND_INDIGO=m ++CONFIG_SND_INDIGOIO=m ++CONFIG_SND_INDIGODJ=m ++CONFIG_SND_INDIGOIOX=m ++CONFIG_SND_INDIGODJX=m ++ ++CONFIG_BALLOON_COMPACTION=y ++CONFIG_COMPACTION=y ++CONFIG_MIGRATION=y ++CONFIG_BOUNCE=y ++# CONFIG_LEDS_AMS_DELTA is not set ++# CONFIG_LEDS_LOCOMO is not set ++# CONFIG_LEDS_NET48XX is not set ++# CONFIG_LEDS_NET5501 is not set ++# CONFIG_LEDS_PCA9532 is not set ++# CONFIG_LEDS_PCA955X is not set ++# CONFIG_LEDS_BD2802 is not set ++# CONFIG_LEDS_S3C24XX is not set ++# CONFIG_LEDS_PCA9633 is not set ++CONFIG_LEDS_DELL_NETBOOKS=m ++# CONFIG_LEDS_TCA6507 is not set ++# CONFIG_LEDS_LM355x is not set ++# CONFIG_LEDS_OT200 is not set ++# CONFIG_LEDS_PWM is not set ++# CONFIG_LEDS_LP8501 is not set ++# CONFIG_LEDS_PCA963X is not set ++# CONFIG_LEDS_PCA9685 is not set ++CONFIG_LEDS_TRIGGER_TIMER=m ++CONFIG_LEDS_TRIGGER_ONESHOT=m ++CONFIG_LEDS_TRIGGER_IDE_DISK=y ++CONFIG_LEDS_TRIGGER_HEARTBEAT=m ++CONFIG_LEDS_TRIGGER_BACKLIGHT=m ++# CONFIG_LEDS_TRIGGER_CPU is not set ++CONFIG_LEDS_TRIGGER_DEFAULT_ON=m ++CONFIG_LEDS_TRIGGER_TRANSIENT=m ++CONFIG_LEDS_TRIGGER_CAMERA=m ++CONFIG_LEDS_ALIX2=m ++CONFIG_LEDS_CLEVO_MAIL=m ++CONFIG_LEDS_INTEL_SS4200=m ++CONFIG_LEDS_LM3530=m ++# CONFIG_LEDS_LM3642 is not set ++CONFIG_LEDS_LM3556=m ++CONFIG_LEDS_BLINKM=m ++CONFIG_LEDS_LP3944=m ++CONFIG_LEDS_LP5521=m ++CONFIG_LEDS_LP5523=m ++CONFIG_LEDS_LP5562=m ++CONFIG_LEDS_LT3593=m ++CONFIG_LEDS_REGULATOR=m ++CONFIG_LEDS_WM8350=m ++CONFIG_LEDS_WM831X_STATUS=m ++ ++CONFIG_DMA_ENGINE=y ++CONFIG_DW_DMAC_CORE=m ++CONFIG_DW_DMAC=m ++CONFIG_DW_DMAC_PCI=m ++# CONFIG_DW_DMAC_BIG_ENDIAN_IO is not set ++# CONFIG_TIMB_DMA is not set ++# CONFIG_DMATEST is not set ++CONFIG_ASYNC_TX_DMA=y ++ ++CONFIG_UNUSED_SYMBOLS=y ++ ++CONFIG_UPROBE_EVENT=y ++ ++CONFIG_DYNAMIC_FTRACE=y ++# CONFIG_IRQSOFF_TRACER is not set ++CONFIG_SCHED_TRACER=y ++CONFIG_CONTEXT_SWITCH_TRACER=y ++CONFIG_TRACER_SNAPSHOT=y ++# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set ++CONFIG_FTRACE_SYSCALLS=y ++CONFIG_FTRACE_MCOUNT_RECORD=y ++# CONFIG_FTRACE_STARTUP_TEST is not set ++# CONFIG_TRACE_BRANCH_PROFILING is not set ++CONFIG_FUNCTION_PROFILER=y ++CONFIG_RING_BUFFER_BENCHMARK=m ++# CONFIG_RING_BUFFER_STARTUP_TEST is not set ++# CONFIG_RBTREE_TEST is not set ++# CONFIG_INTERVAL_TREE_TEST is not set ++CONFIG_FUNCTION_TRACER=y ++CONFIG_STACK_TRACER=y ++# CONFIG_FUNCTION_GRAPH_TRACER is not set ++ ++CONFIG_KPROBES=y ++CONFIG_KPROBE_EVENT=y ++# CONFIG_KPROBES_SANITY_TEST is not set ++# CONFIG_JUMP_LABEL is not set ++CONFIG_OPTPROBES=y ++ ++CONFIG_HZ_1000=y ++ ++CONFIG_TIMER_STATS=y ++CONFIG_PERF_COUNTERS=y ++ ++# Auxillary displays ++CONFIG_KS0108=m ++CONFIG_KS0108_PORT=0x378 ++CONFIG_KS0108_DELAY=2 ++CONFIG_CFAG12864B=y ++CONFIG_CFAG12864B_RATE=20 ++ ++# CONFIG_PHANTOM is not set ++ ++# CONFIG_POWER_SUPPLY_DEBUG is not set ++ ++# CONFIG_TEST_POWER is not set ++CONFIG_APM_POWER=m ++# CONFIG_GENERIC_ADC_BATTERY is not set ++# CONFIG_WM831X_POWER is not set ++ ++# CONFIG_BATTERY_DS2760 is not set ++# CONFIG_BATTERY_DS2781 is not set ++# CONFIG_BATTERY_DS2782 is not set ++# CONFIG_BATTERY_SBS is not set ++# CONFIG_BATTERY_BQ20Z75 is not set ++# CONFIG_BATTERY_DS2780 is not set ++# CONFIG_BATTERY_BQ27x00 is not set ++# CONFIG_BATTERY_MAX17040 is not set ++# CONFIG_BATTERY_MAX17042 is not set ++# CONFIG_BATTERY_GOLDFISH is not set ++ ++# CONFIG_CHARGER_ISP1704 is not set ++# CONFIG_CHARGER_MAX8903 is not set ++# CONFIG_CHARGER_LP8727 is not set ++# CONFIG_CHARGER_GPIO is not set ++# CONFIG_CHARGER_PCF50633 is not set ++# CONFIG_CHARGER_BQ2415X is not set ++# CONFIG_CHARGER_BQ24190 is not set ++# CONFIG_CHARGER_BQ24735 is not set ++CONFIG_POWER_RESET=y ++ ++# CONFIG_PDA_POWER is not set ++ ++CONFIG_AUXDISPLAY=y ++ ++CONFIG_UIO=m ++CONFIG_UIO_CIF=m ++# CONFIG_UIO_PDRV is not set ++# CONFIG_UIO_PDRV_GENIRQ is not set ++# CONFIG_UIO_DMEM_GENIRQ is not set ++CONFIG_UIO_AEC=m ++CONFIG_UIO_SERCOS3=m ++CONFIG_UIO_PCI_GENERIC=m ++# CONFIG_UIO_NETX is not set ++# CONFIG_UIO_MF624 is not set ++ ++CONFIG_VFIO=m ++CONFIG_VFIO_IOMMU_TYPE1=m ++CONFIG_VFIO_PCI=m ++ ++ ++# LIRC ++CONFIG_LIRC_STAGING=y ++CONFIG_LIRC_BT829=m ++CONFIG_LIRC_IGORPLUGUSB=m ++CONFIG_LIRC_IMON=m ++CONFIG_LIRC_ZILOG=m ++CONFIG_LIRC_PARALLEL=m ++CONFIG_LIRC_SERIAL=m ++CONFIG_LIRC_SERIAL_TRANSMITTER=y ++CONFIG_LIRC_SASEM=m ++CONFIG_LIRC_SIR=m ++CONFIG_LIRC_TTUSBIR=m ++ ++# CONFIG_SAMPLES is not set ++ ++ ++CONFIG_NOZOMI=m ++# CONFIG_TPS65010 is not set ++ ++CONFIG_INPUT_APANEL=m ++CONFIG_INPUT_GP2A=m ++# CONFIG_INPUT_GPIO_TILT_POLLED is not set ++# CONFIG_INPUT_GPIO_BEEPER is not set ++ ++# CONFIG_INTEL_MENLOW is not set ++CONFIG_ENCLOSURE_SERVICES=m ++CONFIG_IPWIRELESS=m ++ ++# CONFIG_BLK_DEV_XIP is not set ++CONFIG_MEMSTICK=m ++# CONFIG_MEMSTICK_DEBUG is not set ++# CONFIG_MEMSTICK_UNSAFE_RESUME is not set ++CONFIG_MSPRO_BLOCK=m ++# CONFIG_MS_BLOCK is not set ++CONFIG_MEMSTICK_TIFM_MS=m ++CONFIG_MEMSTICK_JMICRON_38X=m ++CONFIG_MEMSTICK_R592=m ++CONFIG_MEMSTICK_REALTEK_PCI=m ++ ++CONFIG_ACCESSIBILITY=y ++CONFIG_A11Y_BRAILLE_CONSOLE=y ++ ++# CONFIG_HTC_PASIC3 is not set ++ ++# MT9V022_PCA9536_SWITCH is not set ++ ++CONFIG_OPTIMIZE_INLINING=y ++ ++# FIXME: This should be x86/ia64 only ++# CONFIG_HP_ILO is not set ++ ++CONFIG_GPIOLIB=y ++# CONFIG_PINCTRL is not set ++# CONFIG_DEBUG_PINCTRL is not set ++# CONFIG_PINMUX is not set ++# CONFIG_PINCONF is not set ++ ++CONFIG_NET_DSA=m ++CONFIG_NET_DSA_MV88E6060=m ++CONFIG_NET_DSA_MV88E6131=m ++CONFIG_NET_DSA_MV88E6123_61_65=m ++ ++# Used by Maemo, we don't care. ++# CONFIG_PHONET is not set ++ ++# CONFIG_ICS932S401 is not set ++# CONFIG_ATMEL_SSC is not set ++ ++# CONFIG_C2PORT is not set ++ ++# CONFIG_REGULATOR_DEBUG is not set ++ ++CONFIG_WM8350_POWER=m ++ ++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set ++ ++CONFIG_USB_WUSB=m ++CONFIG_USB_WUSB_CBAF=m ++# CONFIG_USB_WUSB_CBAF_DEBUG is not set ++CONFIG_USB_WHCI_HCD=m ++CONFIG_USB_HWA_HCD=m ++# CONFIG_USB_HCD_BCMA is not set ++# CONFIG_USB_HCD_SSB is not set ++ ++CONFIG_UWB=m ++CONFIG_UWB_HWA=m ++CONFIG_UWB_WHCI=m ++CONFIG_UWB_I1480U=m ++ ++# CONFIG_ANDROID is not set ++CONFIG_STAGING_MEDIA=y ++# CONFIG_DVB_AS102 is not set ++# CONFIG_ET131X is not set ++# CONFIG_SLICOSS is not set ++# CONFIG_WLAGS49_H2 is not set ++# CONFIG_WLAGS49_H25 is not set ++# CONFIG_VIDEO_DT3155 is not set ++# CONFIG_TI_ST is not set ++# CONFIG_FB_XGI is not set ++# CONFIG_VIDEO_GO7007 is not set ++# CONFIG_I2C_BCM2048 is not set ++# CONFIG_VIDEO_TCM825X is not set ++# CONFIG_VIDEO_OMAP4 is not set ++# CONFIG_USB_MSI3101 is not set ++# CONFIG_DT3155 is not set ++# CONFIG_W35UND is not set ++# CONFIG_PRISM2_USB is not set ++# CONFIG_ECHO is not set ++CONFIG_USB_ATMEL=m ++# CONFIG_COMEDI is not set ++# CONFIG_ASUS_OLED is not set ++# CONFIG_PANEL is not set ++# CONFIG_TRANZPORT is not set ++# CONFIG_POHMELFS is not set ++# CONFIG_IDE_PHISON is not set ++# CONFIG_LINE6_USB is not set ++# CONFIG_VME_BUS is not set ++# CONFIG_RAR_REGISTER is not set ++# CONFIG_VT6656 is not set ++# CONFIG_USB_SERIAL_QUATECH_USB2 is not set ++# Larry Finger maintains these (rhbz 913753) ++CONFIG_RTLLIB=m ++CONFIG_RTLLIB_CRYPTO_CCMP=m ++CONFIG_RTLLIB_CRYPTO_TKIP=m ++CONFIG_RTLLIB_CRYPTO_WEP=m ++CONFIG_RTL8192E=m ++# CONFIG_INPUT_GPIO is not set ++# CONFIG_VIDEO_CX25821 is not set ++# CONFIG_R8187SE is not set ++# CONFIG_R8188EU is not set ++# CONFIG_R8821AE is not set ++# CONFIG_RTL8192U is not set ++# CONFIG_FB_SM7XX is not set ++# CONFIG_SPECTRA is not set ++# CONFIG_EASYCAP is not set ++# CONFIG_SOLO6X10 is not set ++# CONFIG_ACPI_QUICKSTART is not set ++# CONFIG_LTE_GDM724X is not set ++CONFIG_R8712U=m # Larry Finger maintains this (rhbz 699618) ++# CONFIG_R8712_AP is not set ++# CONFIG_ATH6K_LEGACY is not set ++# CONFIG_USB_ENESTORAGE is not set ++# CONFIG_BCM_WIMAX is not set ++# CONFIG_USB_BTMTK is not set ++# CONFIG_FT1000 is not set ++# CONFIG_SPEAKUP is not set ++# CONFIG_DX_SEP is not set ++# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set ++# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set ++# CONFIG_RTS_PSTOR is not set ++CONFIG_ALTERA_STAPL=m ++# CONFIG_DVB_CXD2099 is not set ++# CONFIG_USBIP_CORE is not set ++# CONFIG_INTEL_MEI is not set ++# CONFIG_ZCACHE is not set ++# CONFIG_RTS5139 is not set ++# CONFIG_NVEC_LEDS is not set ++# CONFIG_VT6655 is not set ++# CONFIG_RAMSTER is not set ++# CONFIG_USB_WPAN_HCD is not set ++# CONFIG_WIMAX_GDM72XX is not set ++# CONFIG_IPACK_BUS is not set ++# CONFIG_CSR_WIFI is not set ++# CONFIG_ZCACHE2 is not set ++# CONFIG_NET_VENDOR_SILICOM is not set ++# CONFIG_SBYPASS is not set ++# CONFIG_BPCTL is not set ++# CONFIG_CED1401 is not set ++# CONFIG_DGRP is not set ++# CONFIG_SB105X is not set ++# CONFIG_LUSTRE_FS is not set ++# CONFIG_XILLYBUS is not set ++# CONFIG_DGAP is not set ++# CONFIG_DGNC is not set ++# CONFIG_RTS5208 is not set ++# END OF STAGING ++ ++# ++# Remoteproc drivers (EXPERIMENTAL) ++# ++# CONFIG_STE_MODEM_RPROC is not set ++ ++CONFIG_LIBFC=m ++CONFIG_LIBFCOE=m ++CONFIG_FCOE=m ++CONFIG_FCOE_FNIC=m ++ ++ ++# CONFIG_IMA is not set ++CONFIG_IMA_MEASURE_PCR_IDX=10 ++CONFIG_IMA_AUDIT=y ++CONFIG_IMA_LSM_RULES=y ++ ++# CONFIG_EVM is not set ++# CONFIG_PWM_PCA9685 is not set ++ ++CONFIG_LSM_MMAP_MIN_ADDR=65536 ++ ++CONFIG_STRIP_ASM_SYMS=y ++ ++# CONFIG_RCU_FANOUT_EXACT is not set ++# FIXME: Revisit FAST_NO_HZ after it's fixed ++# CONFIG_RCU_FAST_NO_HZ is not set ++# CONFIG_RCU_NOCB_CPU is not set ++CONFIG_RCU_CPU_STALL_TIMEOUT=60 ++# CONFIG_RCU_TORTURE_TEST is not set ++# CONFIG_RCU_TRACE is not set ++# CONFIG_RCU_CPU_STALL_INFO is not set ++# CONFIG_RCU_USER_QS is not set ++ ++CONFIG_KSM=y ++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 ++ ++CONFIG_FSNOTIFY=y ++CONFIG_FANOTIFY=y ++CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y ++ ++CONFIG_IEEE802154=m ++CONFIG_IEEE802154_6LOWPAN=m ++CONFIG_IEEE802154_DRIVERS=m ++CONFIG_IEEE802154_FAKEHARD=m ++CONFIG_IEEE802154_FAKELB=m ++ ++CONFIG_MAC802154=m ++CONFIG_NET_MPLS_GSO=m ++ ++# CONFIG_HSR is not set ++ ++# CONFIG_EXTCON is not set ++# CONFIG_EXTCON_ADC_JACK is not set ++# CONFIG_MEMORY is not set ++ ++CONFIG_PPS=m ++# CONFIG_PPS_CLIENT_KTIMER is not set ++CONFIG_PPS_CLIENT_LDISC=m ++# CONFIG_PPS_DEBUG is not set ++CONFIG_PPS_CLIENT_PARPORT=m ++CONFIG_PPS_GENERATOR_PARPORT=m ++CONFIG_PPS_CLIENT_GPIO=m ++CONFIG_NTP_PPS=y ++ ++CONFIG_PTP_1588_CLOCK=m ++CONFIG_PTP_1588_CLOCK_PCH=m ++ ++CONFIG_CLEANCACHE=y ++CONFIG_FRONTSWAP=y ++CONFIG_ZSWAP=y ++CONFIG_ZSMALLOC=y ++# CONFIG_PGTABLE_MAPPING is not set ++ ++# CONFIG_MDIO_GPIO is not set ++# CONFIG_KEYBOARD_GPIO_POLLED is not set ++# CONFIG_MOUSE_GPIO is not set ++# CONFIG_I2C_DESIGNWARE_PLATFORM is not set ++# CONFIG_I2C_DESIGNWARE_PCI is not set ++# CONFIG_I2C_GPIO is not set ++# CONFIG_DEBUG_GPIO is not set ++# CONFIG_GPIO_GENERIC_PLATFORM is not set ++# CONFIG_GPIO_CS5535 is not set ++# CONFIG_GPIO_IT8761E is not set ++# CONFIG SB105x is not set ++# CONFIG_GPIO_TS5500 is not set ++CONFIG_GPIO_VIPERBOARD=m ++# CONFIG_UCB1400_CORE is not set ++# CONFIG_TPS6105X is not set ++# CONFIG_RADIO_MIROPCM20 is not set ++# CONFIG_USB_GPIO_VBUS is not set ++# CONFIG_GPIO_SCH is not set ++# CONFIG_GPIO_LANGWELL is not set ++# CONFIG_GPIO_RDC321X is not set ++# CONFIG_GPIO_VX855 is not set ++# CONFIG_GPIO_PCH is not set ++# CONFIG_GPIO_ML_IOH is not set ++# CONFIG_GPIO_AMD8111 is not set ++# CONFIG_GPIO_BT8XX is not set ++# CONFIG_GPIO_GRGPIO is not set ++# CONFIG_GPIO_PL061 is not set ++# CONFIG_GPIO_BCM_KONA is not set ++# CONFIG_GPIO_SCH311X is not set ++CONFIG_GPIO_MAX730X=m ++CONFIG_GPIO_MAX7300=m ++CONFIG_GPIO_MAX732X=m ++CONFIG_GPIO_PCF857X=m ++CONFIG_GPIO_SX150X=y ++CONFIG_GPIO_ADP5588=m ++CONFIG_GPIO_ADNP=m ++CONFIG_GPIO_MAX7301=m ++CONFIG_GPIO_MCP23S08=m ++CONFIG_GPIO_MC33880=m ++CONFIG_GPIO_74X164=m ++ ++# FIXME: Why? ++CONFIG_EVENT_POWER_TRACING_DEPRECATED=y ++ ++CONFIG_TEST_KSTRTOX=y ++CONFIG_XZ_DEC=y ++CONFIG_XZ_DEC_X86=y ++CONFIG_XZ_DEC_POWERPC=y ++# CONFIG_XZ_DEC_IA64 is not set ++CONFIG_XZ_DEC_ARM=y ++# CONFIG_XZ_DEC_ARMTHUMB is not set ++# CONFIG_XZ_DEC_SPARC is not set ++# CONFIG_XZ_DEC_TEST is not set ++ ++# CONFIG_POWER_AVS is not set ++ ++CONFIG_TARGET_CORE=m ++CONFIG_ISCSI_TARGET=m ++CONFIG_LOOPBACK_TARGET=m ++CONFIG_SBP_TARGET=m ++CONFIG_TCM_IBLOCK=m ++CONFIG_TCM_FILEIO=m ++CONFIG_TCM_PSCSI=m ++CONFIG_TCM_FC=m ++ ++CONFIG_HWSPINLOCK=m ++ ++CONFIG_PSTORE=y ++CONFIG_PSTORE_RAM=m ++# CONFIG_PSTORE_CONSOLE is not set ++# CONFIG_PSTORE_FTRACE is not set ++ ++# CONFIG_TEST_MODULE is not set ++# CONFIG_TEST_USER_COPY is not set ++ ++# CONFIG_AVERAGE is not set ++# CONFIG_VMXNET3 is not set ++ ++# CONFIG_SIGMA is not set ++ ++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 ++ ++CONFIG_BCMA=m ++CONFIG_BCMA_BLOCKIO=y ++CONFIG_BCMA_HOST_PCI_POSSIBLE=y ++CONFIG_BCMA_HOST_PCI=y ++# CONFIG_BCMA_HOST_SOC is not set ++CONFIG_BCMA_DRIVER_GMAC_CMN=y ++CONFIG_BCMA_DRIVER_GPIO=y ++# CONFIG_BCMA_DEBUG is not set ++ ++# CONFIG_GOOGLE_FIRMWARE is not set ++# CONFIG_INTEL_MID_PTI is not set ++ ++# CONFIG_MAILBOX is not set ++ ++CONFIG_FMC=m ++CONFIG_FMC_FAKEDEV=m ++CONFIG_FMC_TRIVIAL=m ++CONFIG_FMC_WRITE_EEPROM=m ++CONFIG_FMC_CHARDEV=m ++ ++# CONFIG_GENWQE is not set ++ ++# CONFIG_POWERCAP is not set ++ ++# CONFIG_HSI is not set ++ ++ ++# CONFIG_ARM_ARCH_TIMER_EVTSTREAM is not set ++ ++# CONFIG_PM_DEVFREQ is not set ++# CONFIG_MODULE_SIG is not set ++# CONFIG_SYSTEM_TRUSTED_KEYRING is not set ++# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set ++# CONFIG_MODULE_VERIFY_ELF is not set ++# CONFIG_CRYPTO_KEY_TYPE is not set ++# CONFIG_PGP_LIBRARY is not set ++# CONFIG_PGP_PRELOAD is not set ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_PROC_DEVICETREE=y ++ +diff -Nur linux-3.14.40.orig/arch/arm/configs/imx_v7_defconfig linux-3.14.40/arch/arm/configs/imx_v7_defconfig +--- linux-3.14.40.orig/arch/arm/configs/imx_v7_defconfig 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/configs/imx_v7_defconfig 2015-05-01 14:57:57.591427001 -0500 +@@ -0,0 +1,343 @@ ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_KERNEL_LZO=y ++CONFIG_SYSVIPC=y ++CONFIG_NO_HZ=y ++CONFIG_HIGH_RES_TIMERS=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=y ++CONFIG_AEABI=y ++# CONFIG_OABI_COMPAT is not set ++CONFIG_HIGHMEM=y ++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_WIRELESS is not set ++CONFIG_DEVTMPFS=y ++CONFIG_DEVTMPFS_MOUNT=y ++# CONFIG_STANDALONE is not set ++CONFIG_CMA=y ++CONFIG_CMA_SIZE_MBYTES=320 ++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_WLAN is not set ++# 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_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_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_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_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_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_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_NOP_USB_XCEIV=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_LEDS_GPIO=y ++CONFIG_LEDS_TRIGGERS=y ++CONFIG_LEDS_TRIGGER_GPIO=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_TEST=m ++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_XTS=y ++CONFIG_CRYPTO_MD4=y ++CONFIG_CRYPTO_MD5=y ++CONFIG_CRYPTO_MICHAEL_MIC=y ++CONFIG_CRYPTO_RMD128=y ++CONFIG_CRYPTO_RMD160=y ++CONFIG_CRYPTO_RMD256=y ++CONFIG_CRYPTO_RMD320=y ++CONFIG_CRYPTO_SHA1=y ++CONFIG_CRYPTO_SHA256=y ++CONFIG_CRYPTO_SHA512=y ++CONFIG_CRYPTO_TGR192=y ++CONFIG_CRYPTO_WP512=y ++CONFIG_CRYPTO_BLOWFISH=y ++CONFIG_CRYPTO_CAMELLIA=y ++CONFIG_CRYPTO_DES=y ++CONFIG_CRYPTO_TWOFISH=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.14.40.orig/arch/arm/configs/imx_v7_mfg_defconfig linux-3.14.40/arch/arm/configs/imx_v7_mfg_defconfig +--- linux-3.14.40.orig/arch/arm/configs/imx_v7_mfg_defconfig 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/configs/imx_v7_mfg_defconfig 2015-05-01 14:57:57.591427001 -0500 +@@ -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=320 ++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.14.40.orig/arch/arm/include/asm/arch_timer.h linux-3.14.40/arch/arm/include/asm/arch_timer.h +--- linux-3.14.40.orig/arch/arm/include/asm/arch_timer.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/include/asm/arch_timer.h 2015-05-01 14:57:57.599427001 -0500 +@@ -107,7 +107,6 @@ + /* Also disable virtual event stream */ + cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN + | ARCH_TIMER_USR_VT_ACCESS_EN +- | ARCH_TIMER_VIRT_EVT_EN + | ARCH_TIMER_USR_VCT_ACCESS_EN + | ARCH_TIMER_USR_PCT_ACCESS_EN); + arch_timer_set_cntkctl(cntkctl); +diff -Nur linux-3.14.40.orig/arch/arm/include/asm/atomic.h linux-3.14.40/arch/arm/include/asm/atomic.h +--- linux-3.14.40.orig/arch/arm/include/asm/atomic.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/include/asm/atomic.h 2015-05-01 14:57:57.611427001 -0500 +@@ -60,6 +60,7 @@ + int result; + + smp_mb(); ++ prefetchw(&v->counter); + + __asm__ __volatile__("@ atomic_add_return\n" + "1: ldrex %0, [%3]\n" +@@ -99,6 +100,7 @@ + int result; + + smp_mb(); ++ prefetchw(&v->counter); + + __asm__ __volatile__("@ atomic_sub_return\n" + "1: ldrex %0, [%3]\n" +@@ -121,6 +123,7 @@ + unsigned long res; + + smp_mb(); ++ prefetchw(&ptr->counter); + + do { + __asm__ __volatile__("@ atomic_cmpxchg\n" +@@ -138,6 +141,33 @@ + return oldval; + } + ++static inline int __atomic_add_unless(atomic_t *v, int a, int u) ++{ ++ int oldval, newval; ++ unsigned long tmp; ++ ++ smp_mb(); ++ prefetchw(&v->counter); ++ ++ __asm__ __volatile__ ("@ atomic_add_unless\n" ++"1: ldrex %0, [%4]\n" ++" teq %0, %5\n" ++" beq 2f\n" ++" add %1, %0, %6\n" ++" strex %2, %1, [%4]\n" ++" teq %2, #0\n" ++" bne 1b\n" ++"2:" ++ : "=&r" (oldval), "=&r" (newval), "=&r" (tmp), "+Qo" (v->counter) ++ : "r" (&v->counter), "r" (u), "r" (a) ++ : "cc"); ++ ++ if (oldval != u) ++ smp_mb(); ++ ++ return oldval; ++} ++ + #else /* ARM_ARCH_6 */ + + #ifdef CONFIG_SMP +@@ -186,10 +216,6 @@ + return ret; + } + +-#endif /* __LINUX_ARM_ARCH__ */ +- +-#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) +- + static inline int __atomic_add_unless(atomic_t *v, int a, int u) + { + int c, old; +@@ -200,6 +226,10 @@ + return c; + } + ++#endif /* __LINUX_ARM_ARCH__ */ ++ ++#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) ++ + #define atomic_inc(v) atomic_add(1, v) + #define atomic_dec(v) atomic_sub(1, v) + +@@ -299,6 +329,7 @@ + unsigned long tmp; + + smp_mb(); ++ prefetchw(&v->counter); + + __asm__ __volatile__("@ atomic64_add_return\n" + "1: ldrexd %0, %H0, [%3]\n" +@@ -340,6 +371,7 @@ + unsigned long tmp; + + smp_mb(); ++ prefetchw(&v->counter); + + __asm__ __volatile__("@ atomic64_sub_return\n" + "1: ldrexd %0, %H0, [%3]\n" +@@ -364,6 +396,7 @@ + unsigned long res; + + smp_mb(); ++ prefetchw(&ptr->counter); + + do { + __asm__ __volatile__("@ atomic64_cmpxchg\n" +@@ -388,6 +421,7 @@ + unsigned long tmp; + + smp_mb(); ++ prefetchw(&ptr->counter); + + __asm__ __volatile__("@ atomic64_xchg\n" + "1: ldrexd %0, %H0, [%3]\n" +@@ -409,6 +443,7 @@ + unsigned long tmp; + + smp_mb(); ++ prefetchw(&v->counter); + + __asm__ __volatile__("@ atomic64_dec_if_positive\n" + "1: ldrexd %0, %H0, [%3]\n" +@@ -436,6 +471,7 @@ + int ret = 1; + + smp_mb(); ++ prefetchw(&v->counter); + + __asm__ __volatile__("@ atomic64_add_unless\n" + "1: ldrexd %0, %H0, [%4]\n" +diff -Nur linux-3.14.40.orig/arch/arm/include/asm/cmpxchg.h linux-3.14.40/arch/arm/include/asm/cmpxchg.h +--- linux-3.14.40.orig/arch/arm/include/asm/cmpxchg.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/include/asm/cmpxchg.h 2015-05-01 14:57:57.611427001 -0500 +@@ -2,6 +2,7 @@ + #define __ASM_ARM_CMPXCHG_H + + #include ++#include + #include + + #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110) +@@ -35,6 +36,7 @@ + #endif + + smp_mb(); ++ prefetchw((const void *)ptr); + + switch (size) { + #if __LINUX_ARM_ARCH__ >= 6 +@@ -138,6 +140,8 @@ + { + unsigned long oldval, res; + ++ prefetchw((const void *)ptr); ++ + switch (size) { + #ifndef CONFIG_CPU_V6 /* min ARCH >= ARMv6K */ + case 1: +@@ -230,6 +234,8 @@ + unsigned long long oldval; + unsigned long res; + ++ prefetchw(ptr); ++ + __asm__ __volatile__( + "1: ldrexd %1, %H1, [%3]\n" + " teq %1, %4\n" +diff -Nur linux-3.14.40.orig/arch/arm/include/asm/ftrace.h linux-3.14.40/arch/arm/include/asm/ftrace.h +--- linux-3.14.40.orig/arch/arm/include/asm/ftrace.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/include/asm/ftrace.h 2015-05-01 14:57:57.639427001 -0500 +@@ -52,15 +52,7 @@ + + #endif + +-#define HAVE_ARCH_CALLER_ADDR +- +-#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) +-#define CALLER_ADDR1 ((unsigned long)return_address(1)) +-#define CALLER_ADDR2 ((unsigned long)return_address(2)) +-#define CALLER_ADDR3 ((unsigned long)return_address(3)) +-#define CALLER_ADDR4 ((unsigned long)return_address(4)) +-#define CALLER_ADDR5 ((unsigned long)return_address(5)) +-#define CALLER_ADDR6 ((unsigned long)return_address(6)) ++#define ftrace_return_address(n) return_address(n) + + #endif /* ifndef __ASSEMBLY__ */ + +diff -Nur linux-3.14.40.orig/arch/arm/include/asm/futex.h linux-3.14.40/arch/arm/include/asm/futex.h +--- linux-3.14.40.orig/arch/arm/include/asm/futex.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/include/asm/futex.h 2015-05-01 14:57:57.643427001 -0500 +@@ -23,6 +23,7 @@ + + #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ + smp_mb(); \ ++ prefetchw(uaddr); \ + __asm__ __volatile__( \ + "1: ldrex %1, [%3]\n" \ + " " insn "\n" \ +@@ -46,6 +47,8 @@ + return -EFAULT; + + smp_mb(); ++ /* Prefetching cannot fault */ ++ prefetchw(uaddr); + __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" + "1: ldrex %1, [%4]\n" + " teq %1, %2\n" +diff -Nur linux-3.14.40.orig/arch/arm/include/asm/glue-cache.h linux-3.14.40/arch/arm/include/asm/glue-cache.h +--- linux-3.14.40.orig/arch/arm/include/asm/glue-cache.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/include/asm/glue-cache.h 2015-05-01 14:57:57.659427001 -0500 +@@ -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(CONFIG_CPU_V7M) +diff -Nur linux-3.14.40.orig/arch/arm/include/asm/hardware/cache-l2x0.h linux-3.14.40/arch/arm/include/asm/hardware/cache-l2x0.h +--- linux-3.14.40.orig/arch/arm/include/asm/hardware/cache-l2x0.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/include/asm/hardware/cache-l2x0.h 2015-05-01 14:57:57.659427001 -0500 +@@ -26,8 +26,8 @@ + #define L2X0_CACHE_TYPE 0x004 + #define L2X0_CTRL 0x100 + #define L2X0_AUX_CTRL 0x104 +-#define L2X0_TAG_LATENCY_CTRL 0x108 +-#define L2X0_DATA_LATENCY_CTRL 0x10C ++#define L310_TAG_LATENCY_CTRL 0x108 ++#define L310_DATA_LATENCY_CTRL 0x10C + #define L2X0_EVENT_CNT_CTRL 0x200 + #define L2X0_EVENT_CNT1_CFG 0x204 + #define L2X0_EVENT_CNT0_CFG 0x208 +@@ -54,53 +54,93 @@ + #define L2X0_LOCKDOWN_WAY_D_BASE 0x900 + #define L2X0_LOCKDOWN_WAY_I_BASE 0x904 + #define L2X0_LOCKDOWN_STRIDE 0x08 +-#define L2X0_ADDR_FILTER_START 0xC00 +-#define L2X0_ADDR_FILTER_END 0xC04 ++#define L310_ADDR_FILTER_START 0xC00 ++#define L310_ADDR_FILTER_END 0xC04 + #define L2X0_TEST_OPERATION 0xF00 + #define L2X0_LINE_DATA 0xF10 + #define L2X0_LINE_TAG 0xF30 + #define L2X0_DEBUG_CTRL 0xF40 +-#define L2X0_PREFETCH_CTRL 0xF60 +-#define L2X0_POWER_CTRL 0xF80 +-#define L2X0_DYNAMIC_CLK_GATING_EN (1 << 1) +-#define L2X0_STNDBY_MODE_EN (1 << 0) ++#define L310_PREFETCH_CTRL 0xF60 ++#define L310_POWER_CTRL 0xF80 ++#define L310_DYNAMIC_CLK_GATING_EN (1 << 1) ++#define L310_STNDBY_MODE_EN (1 << 0) + + /* Registers shifts and masks */ + #define L2X0_CACHE_ID_PART_MASK (0xf << 6) + #define L2X0_CACHE_ID_PART_L210 (1 << 6) ++#define L2X0_CACHE_ID_PART_L220 (2 << 6) + #define L2X0_CACHE_ID_PART_L310 (3 << 6) + #define L2X0_CACHE_ID_RTL_MASK 0x3f +-#define L2X0_CACHE_ID_RTL_R0P0 0x0 +-#define L2X0_CACHE_ID_RTL_R1P0 0x2 +-#define L2X0_CACHE_ID_RTL_R2P0 0x4 +-#define L2X0_CACHE_ID_RTL_R3P0 0x5 +-#define L2X0_CACHE_ID_RTL_R3P1 0x6 +-#define L2X0_CACHE_ID_RTL_R3P2 0x8 +- +-#define L2X0_AUX_CTRL_MASK 0xc0000fff ++#define L210_CACHE_ID_RTL_R0P2_02 0x00 ++#define L210_CACHE_ID_RTL_R0P1 0x01 ++#define L210_CACHE_ID_RTL_R0P2_01 0x02 ++#define L210_CACHE_ID_RTL_R0P3 0x03 ++#define L210_CACHE_ID_RTL_R0P4 0x0b ++#define L210_CACHE_ID_RTL_R0P5 0x0f ++#define L220_CACHE_ID_RTL_R1P7_01REL0 0x06 ++#define L310_CACHE_ID_RTL_R0P0 0x00 ++#define L310_CACHE_ID_RTL_R1P0 0x02 ++#define L310_CACHE_ID_RTL_R2P0 0x04 ++#define L310_CACHE_ID_RTL_R3P0 0x05 ++#define L310_CACHE_ID_RTL_R3P1 0x06 ++#define L310_CACHE_ID_RTL_R3P1_50REL0 0x07 ++#define L310_CACHE_ID_RTL_R3P2 0x08 ++#define L310_CACHE_ID_RTL_R3P3 0x09 ++ ++/* L2C auxiliary control register - bits common to L2C-210/220/310 */ ++#define L2C_AUX_CTRL_WAY_SIZE_SHIFT 17 ++#define L2C_AUX_CTRL_WAY_SIZE_MASK (7 << 17) ++#define L2C_AUX_CTRL_WAY_SIZE(n) ((n) << 17) ++#define L2C_AUX_CTRL_EVTMON_ENABLE BIT(20) ++#define L2C_AUX_CTRL_PARITY_ENABLE BIT(21) ++#define L2C_AUX_CTRL_SHARED_OVERRIDE BIT(22) ++/* L2C-210/220 common bits */ + #define L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT 0 +-#define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK 0x7 ++#define L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK (7 << 0) + #define L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT 3 +-#define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK (0x7 << 3) ++#define L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK (7 << 3) + #define L2X0_AUX_CTRL_TAG_LATENCY_SHIFT 6 +-#define L2X0_AUX_CTRL_TAG_LATENCY_MASK (0x7 << 6) ++#define L2X0_AUX_CTRL_TAG_LATENCY_MASK (7 << 6) + #define L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT 9 +-#define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK (0x7 << 9) +-#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16 +-#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17 +-#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17) +-#define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT 22 +-#define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT 26 +-#define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT 27 +-#define L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT 28 +-#define L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT 29 +-#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30 +- +-#define L2X0_LATENCY_CTRL_SETUP_SHIFT 0 +-#define L2X0_LATENCY_CTRL_RD_SHIFT 4 +-#define L2X0_LATENCY_CTRL_WR_SHIFT 8 +- +-#define L2X0_ADDR_FILTER_EN 1 ++#define L2X0_AUX_CTRL_DIRTY_LATENCY_MASK (7 << 9) ++#define L2X0_AUX_CTRL_ASSOC_SHIFT 13 ++#define L2X0_AUX_CTRL_ASSOC_MASK (15 << 13) ++/* L2C-210 specific bits */ ++#define L210_AUX_CTRL_WRAP_DISABLE BIT(12) ++#define L210_AUX_CTRL_WA_OVERRIDE BIT(23) ++#define L210_AUX_CTRL_EXCLUSIVE_ABORT BIT(24) ++/* L2C-220 specific bits */ ++#define L220_AUX_CTRL_EXCLUSIVE_CACHE BIT(12) ++#define L220_AUX_CTRL_FWA_SHIFT 23 ++#define L220_AUX_CTRL_FWA_MASK (3 << 23) ++#define L220_AUX_CTRL_NS_LOCKDOWN BIT(26) ++#define L220_AUX_CTRL_NS_INT_CTRL BIT(27) ++/* L2C-310 specific bits */ ++#define L310_AUX_CTRL_FULL_LINE_ZERO BIT(0) /* R2P0+ */ ++#define L310_AUX_CTRL_HIGHPRIO_SO_DEV BIT(10) /* R2P0+ */ ++#define L310_AUX_CTRL_STORE_LIMITATION BIT(11) /* R2P0+ */ ++#define L310_AUX_CTRL_EXCLUSIVE_CACHE BIT(12) ++#define L310_AUX_CTRL_ASSOCIATIVITY_16 BIT(16) ++#define L310_AUX_CTRL_CACHE_REPLACE_RR BIT(25) /* R2P0+ */ ++#define L310_AUX_CTRL_NS_LOCKDOWN BIT(26) ++#define L310_AUX_CTRL_NS_INT_CTRL BIT(27) ++#define L310_AUX_CTRL_DATA_PREFETCH BIT(28) ++#define L310_AUX_CTRL_INSTR_PREFETCH BIT(29) ++#define L310_AUX_CTRL_EARLY_BRESP BIT(30) /* R2P0+ */ ++ ++#define L310_LATENCY_CTRL_SETUP(n) ((n) << 0) ++#define L310_LATENCY_CTRL_RD(n) ((n) << 4) ++#define L310_LATENCY_CTRL_WR(n) ((n) << 8) ++ ++#define L310_ADDR_FILTER_EN 1 ++ ++#define L310_PREFETCH_CTRL_OFFSET_MASK 0x1f ++#define L310_PREFETCH_CTRL_DBL_LINEFILL_INCR BIT(23) ++#define L310_PREFETCH_CTRL_PREFETCH_DROP BIT(24) ++#define L310_PREFETCH_CTRL_DBL_LINEFILL_WRAP BIT(27) ++#define L310_PREFETCH_CTRL_DATA_PREFETCH BIT(28) ++#define L310_PREFETCH_CTRL_INSTR_PREFETCH BIT(29) ++#define L310_PREFETCH_CTRL_DBL_LINEFILL BIT(30) + + #define L2X0_CTRL_EN 1 + +diff -Nur linux-3.14.40.orig/arch/arm/include/asm/outercache.h linux-3.14.40/arch/arm/include/asm/outercache.h +--- linux-3.14.40.orig/arch/arm/include/asm/outercache.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/include/asm/outercache.h 2015-05-01 14:57:57.663427001 -0500 +@@ -21,6 +21,7 @@ + #ifndef __ASM_OUTERCACHE_H + #define __ASM_OUTERCACHE_H + ++#include + #include + + struct outer_cache_fns { +@@ -28,53 +29,84 @@ + void (*clean_range)(unsigned long, unsigned long); + void (*flush_range)(unsigned long, unsigned long); + void (*flush_all)(void); +- void (*inv_all)(void); + void (*disable)(void); + #ifdef CONFIG_OUTER_CACHE_SYNC + void (*sync)(void); + #endif +- void (*set_debug)(unsigned long); + void (*resume)(void); ++ ++ /* This is an ARM L2C thing */ ++ void (*write_sec)(unsigned long, unsigned); + }; + + extern struct outer_cache_fns outer_cache; + + #ifdef CONFIG_OUTER_CACHE +- ++/** ++ * outer_inv_range - invalidate range of outer cache lines ++ * @start: starting physical address, inclusive ++ * @end: end physical address, exclusive ++ */ + static inline void outer_inv_range(phys_addr_t start, phys_addr_t end) + { + if (outer_cache.inv_range) + outer_cache.inv_range(start, end); + } ++ ++/** ++ * outer_clean_range - clean dirty outer cache lines ++ * @start: starting physical address, inclusive ++ * @end: end physical address, exclusive ++ */ + static inline void outer_clean_range(phys_addr_t start, phys_addr_t end) + { + if (outer_cache.clean_range) + outer_cache.clean_range(start, end); + } ++ ++/** ++ * outer_flush_range - clean and invalidate outer cache lines ++ * @start: starting physical address, inclusive ++ * @end: end physical address, exclusive ++ */ + static inline void outer_flush_range(phys_addr_t start, phys_addr_t end) + { + if (outer_cache.flush_range) + outer_cache.flush_range(start, end); + } + ++/** ++ * outer_flush_all - clean and invalidate all cache lines in the outer cache ++ * ++ * Note: depending on implementation, this may not be atomic - it must ++ * only be called with interrupts disabled and no other active outer ++ * cache masters. ++ * ++ * It is intended that this function is only used by implementations ++ * needing to override the outer_cache.disable() method due to security. ++ * (Some implementations perform this as a clean followed by an invalidate.) ++ */ + static inline void outer_flush_all(void) + { + if (outer_cache.flush_all) + outer_cache.flush_all(); + } + +-static inline void outer_inv_all(void) +-{ +- if (outer_cache.inv_all) +- outer_cache.inv_all(); +-} +- +-static inline void outer_disable(void) +-{ +- if (outer_cache.disable) +- outer_cache.disable(); +-} +- ++/** ++ * outer_disable - clean, invalidate and disable the outer cache ++ * ++ * Disable the outer cache, ensuring that any data contained in the outer ++ * cache is pushed out to lower levels of system memory. The note and ++ * conditions above concerning outer_flush_all() applies here. ++ */ ++extern void outer_disable(void); ++ ++/** ++ * outer_resume - restore the cache configuration and re-enable outer cache ++ * ++ * Restore any configuration that the cache had when previously enabled, ++ * and re-enable the outer cache. ++ */ + static inline void outer_resume(void) + { + if (outer_cache.resume) +@@ -90,13 +122,18 @@ + static inline void outer_flush_range(phys_addr_t start, phys_addr_t end) + { } + static inline void outer_flush_all(void) { } +-static inline void outer_inv_all(void) { } + static inline void outer_disable(void) { } + static inline void outer_resume(void) { } + + #endif + + #ifdef CONFIG_OUTER_CACHE_SYNC ++/** ++ * outer_sync - perform a sync point for outer cache ++ * ++ * Ensure that all outer cache operations are complete and any store ++ * buffers are drained. ++ */ + static inline void outer_sync(void) + { + if (outer_cache.sync) +diff -Nur linux-3.14.40.orig/arch/arm/include/asm/pmu.h linux-3.14.40/arch/arm/include/asm/pmu.h +--- linux-3.14.40.orig/arch/arm/include/asm/pmu.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/include/asm/pmu.h 2015-05-01 14:57:57.663427001 -0500 +@@ -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.14.40.orig/arch/arm/include/asm/psci.h linux-3.14.40/arch/arm/include/asm/psci.h +--- linux-3.14.40.orig/arch/arm/include/asm/psci.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/include/asm/psci.h 2015-05-01 14:57:57.663427001 -0500 +@@ -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; +@@ -42,4 +46,12 @@ + static inline bool psci_smp_available(void) { return false; } + #endif + ++#ifdef CONFIG_ARM_PSCI ++extern int psci_probe(void); ++#else ++static inline int psci_probe(void) ++{ ++ return -ENODEV; ++} ++#endif + #endif /* __ASM_ARM_PSCI_H */ +diff -Nur linux-3.14.40.orig/arch/arm/include/asm/topology.h linux-3.14.40/arch/arm/include/asm/topology.h +--- linux-3.14.40.orig/arch/arm/include/asm/topology.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/include/asm/topology.h 2015-05-01 14:57:57.663427001 -0500 +@@ -26,11 +26,14 @@ + 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); + + #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.14.40.orig/arch/arm/Kconfig linux-3.14.40/arch/arm/Kconfig +--- linux-3.14.40.orig/arch/arm/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/Kconfig 2015-05-01 14:57:57.691427001 -0500 +@@ -1216,19 +1216,6 @@ + register of the Cortex-A9 which reduces the linefill issuing + capabilities of the processor. + +-config PL310_ERRATA_588369 +- bool "PL310 errata: Clean & Invalidate maintenance operations do not invalidate clean lines" +- depends on CACHE_L2X0 +- help +- The PL310 L2 cache controller implements three types of Clean & +- Invalidate maintenance operations: by Physical Address +- (offset 0x7F0), by Index/Way (0x7F8) and by Way (0x7FC). +- They are architecturally defined to behave as the execution of a +- clean operation followed immediately by an invalidate operation, +- both performing to the same memory location. This functionality +- is not correctly implemented in PL310 as clean lines are not +- invalidated as a result of these operations. +- + config ARM_ERRATA_643719 + bool "ARM errata: LoUIS bit field in CLIDR register is incorrect" + depends on CPU_V7 && SMP +@@ -1251,17 +1238,6 @@ + tables. The workaround changes the TLB flushing routines to invalidate + entries regardless of the ASID. + +-config PL310_ERRATA_727915 +- bool "PL310 errata: Background Clean & Invalidate by Way operation can cause data corruption" +- depends on CACHE_L2X0 +- help +- PL310 implements the Clean & Invalidate by Way L2 cache maintenance +- operation (offset 0x7FC). This operation runs in background so that +- PL310 can handle normal accesses while it is in progress. Under very +- rare circumstances, due to this erratum, write data can be lost when +- PL310 treats a cacheable write transaction during a Clean & +- Invalidate by Way operation. +- + config ARM_ERRATA_743622 + bool "ARM errata: Faulty hazard checking in the Store Buffer may lead to data corruption" + depends on CPU_V7 +@@ -1287,21 +1263,6 @@ + operation is received by a CPU before the ICIALLUIS has completed, + potentially leading to corrupted entries in the cache or TLB. + +-config PL310_ERRATA_753970 +- bool "PL310 errata: cache sync operation may be faulty" +- depends on CACHE_PL310 +- help +- This option enables the workaround for the 753970 PL310 (r3p0) erratum. +- +- Under some condition the effect of cache sync operation on +- the store buffer still remains when the operation completes. +- This means that the store buffer is always asked to drain and +- this prevents it from merging any further writes. The workaround +- is to replace the normal offset of cache sync operation (0x730) +- by another offset targeting an unmapped PL310 register 0x740. +- This has the same effect as the cache sync operation: store buffer +- drain and waiting for all buffers empty. +- + config ARM_ERRATA_754322 + bool "ARM errata: possible faulty MMU translations following an ASID switch" + depends on CPU_V7 +@@ -1350,18 +1311,6 @@ + relevant cache maintenance functions and sets a specific bit + in the diagnostic control register of the SCU. + +-config PL310_ERRATA_769419 +- bool "PL310 errata: no automatic Store Buffer drain" +- depends on CACHE_L2X0 +- help +- On revisions of the PL310 prior to r3p2, the Store Buffer does +- not automatically drain. This can cause normal, non-cacheable +- writes to be retained when the memory system is idle, leading +- to suboptimal I/O performance for drivers using coherent DMA. +- This option adds a write barrier to the cpu_idle loop so that, +- on systems with an outer cache, the store buffer is drained +- explicitly. +- + config ARM_ERRATA_775420 + bool "ARM errata: A data cache maintenance operation which aborts, might lead to deadlock" + depends on CPU_V7 +@@ -1391,6 +1340,29 @@ + loop buffer may deliver incorrect instructions. This + workaround disables the loop buffer to avoid the erratum. + ++config ARM_ERRATA_794072 ++ bool "ARM errata: A short loop including a DMB instruction might cause a denial of service" ++ depends on CPU_V7 && SMP ++ help ++ This option enables the workaround for the 794072 Cortex-A9 ++ (all revisions). A processor which continuously executes a short ++ loop containing a DMB instruction might prevent a CP15 operation ++ broadcast by another processor making further progress, causing ++ a denial of service. This erratum can be worked around by setting ++ bit[4] of the undocumented Diagnostic Control Register to 1. ++ ++config ARM_ERRATA_761320 ++ bool "Full cache line writes to the same memory region from at least two processors might deadlock processor" ++ depends on CPU_V7 && SMP ++ help ++ This option enables the workaround for the 761320 Cortex-A9 (r0..r3). ++ Under very rare circumstances, full cache line writes ++ from (at least) 2 processors on cache lines in hazard with ++ other requests may cause arbitration issues in the SCU, ++ leading to processor deadlock. This erratum can be ++ worked around by setting bit[21] of the undocumented ++ Diagnostic Control Register to 1. ++ + endmenu + + source "arch/arm/common/Kconfig" +@@ -1835,6 +1807,7 @@ + range 11 64 if ARCH_SHMOBILE_LEGACY + default "12" if SOC_AM33XX + default "9" if SA1111 || ARCH_EFM32 ++ default "14" if ARCH_MXC + default "11" + help + The kernel memory allocator divides physically contiguous memory +diff -Nur linux-3.14.40.orig/arch/arm/kernel/perf_event.c linux-3.14.40/arch/arm/kernel/perf_event.c +--- linux-3.14.40.orig/arch/arm/kernel/perf_event.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/kernel/perf_event.c 2015-05-01 14:57:57.719427001 -0500 +@@ -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; +@@ -159,6 +163,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(). +@@ -175,6 +181,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. +@@ -202,6 +210,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); +@@ -218,6 +229,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. */ +@@ -419,6 +434,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.14.40.orig/arch/arm/kernel/perf_event_cpu.c linux-3.14.40/arch/arm/kernel/perf_event_cpu.c +--- linux-3.14.40.orig/arch/arm/kernel/perf_event_cpu.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/kernel/perf_event_cpu.c 2015-05-01 14:57:57.723427001 -0500 +@@ -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; +@@ -127,7 +135,7 @@ + return err; + } + +- cpumask_set_cpu(i, &cpu_pmu->active_irqs); ++ cpumask_set_cpu(cpu, &cpu_pmu->active_irqs); + } + + return 0; +@@ -136,7 +144,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); +@@ -149,7 +157,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); + } + + /* +@@ -161,21 +169,46 @@ + static int 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 cpu_pmu_hotplug_notifier = { + .notifier_call = cpu_pmu_notify, + }; + ++static struct notifier_block cpu_pmu_pm_notifier = { ++ .notifier_call = cpu_pmu_pm_notify, ++}; ++ + /* + * PMU platform driver and devicetree bindings. + */ +@@ -247,6 +280,9 @@ + } + } + ++ /* assume PMU support all the CPUs in this case */ ++ cpumask_setall(&pmu->valid_cpus); ++ + put_cpu(); + return ret; + } +@@ -254,15 +290,10 @@ + static int cpu_pmu_device_probe(struct platform_device *pdev) + { + const struct of_device_id *of_id; +- const 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) { +@@ -271,8 +302,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); + } +@@ -282,10 +333,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; +@@ -314,9 +367,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.14.40.orig/arch/arm/kernel/perf_event_v7.c linux-3.14.40/arch/arm/kernel/perf_event_v7.c +--- linux-3.14.40.orig/arch/arm/kernel/perf_event_v7.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/kernel/perf_event_v7.c 2015-05-01 14:57:57.727427001 -0500 +@@ -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.14.40.orig/arch/arm/kernel/process.c linux-3.14.40/arch/arm/kernel/process.c +--- linux-3.14.40.orig/arch/arm/kernel/process.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/kernel/process.c 2015-05-01 14:57:57.727427001 -0500 +@@ -172,8 +172,10 @@ + */ + void arch_cpu_idle(void) + { ++ idle_notifier_call_chain(IDLE_START); + if (cpuidle_idle_call()) + default_idle(); ++ idle_notifier_call_chain(IDLE_END); + } + + /* +diff -Nur linux-3.14.40.orig/arch/arm/kernel/psci.c linux-3.14.40/arch/arm/kernel/psci.c +--- linux-3.14.40.orig/arch/arm/kernel/psci.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/kernel/psci.c 2015-05-01 14:57:57.747427001 -0500 +@@ -42,6 +42,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 +55,8 @@ + return -EINVAL; + case PSCI_RET_EPERM: + return -EPERM; ++ case PSCI_RET_EALREADYON: ++ return -EAGAIN; + }; + + return -EINVAL; +@@ -153,7 +156,7 @@ + return psci_to_linux_errno(err); + } + +-static const struct of_device_id psci_of_match[] __initconst = { ++static const struct of_device_id psci_of_match[] = { + { .compatible = "arm,psci", }, + {}, + }; +@@ -208,3 +211,16 @@ + of_node_put(np); + return; + } ++ ++int psci_probe(void) ++{ ++ struct device_node *np; ++ int ret = -ENODEV; ++ ++ np = of_find_matching_node(NULL, psci_of_match); ++ if (np) ++ ret = 0; ++ ++ of_node_put(np); ++ return ret; ++} +diff -Nur linux-3.14.40.orig/arch/arm/kernel/setup.c linux-3.14.40/arch/arm/kernel/setup.c +--- linux-3.14.40.orig/arch/arm/kernel/setup.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/kernel/setup.c 2015-05-01 14:57:57.747427001 -0500 +@@ -273,6 +273,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; +diff -Nur linux-3.14.40.orig/arch/arm/kernel/topology.c linux-3.14.40/arch/arm/kernel/topology.c +--- linux-3.14.40.orig/arch/arm/kernel/topology.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/kernel/topology.c 2015-05-01 14:57:57.755427001 -0500 +@@ -267,6 +267,33 @@ + } + + /* ++ * 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.14.40.orig/arch/arm/lib/bitops.h linux-3.14.40/arch/arm/lib/bitops.h +--- linux-3.14.40.orig/arch/arm/lib/bitops.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/lib/bitops.h 2015-05-01 14:57:57.763427001 -0500 +@@ -37,6 +37,11 @@ + add r1, r1, r0, lsl #2 @ Get word offset + mov r3, r2, lsl r3 @ create mask + smp_dmb ++#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP) ++ .arch_extension mp ++ ALT_SMP(W(pldw) [r1]) ++ ALT_UP(W(nop)) ++#endif + 1: ldrex r2, [r1] + ands r0, r2, r3 @ save old value of bit + \instr r2, r2, r3 @ toggle bit +diff -Nur linux-3.14.40.orig/arch/arm/mach-berlin/berlin.c linux-3.14.40/arch/arm/mach-berlin/berlin.c +--- linux-3.14.40.orig/arch/arm/mach-berlin/berlin.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-berlin/berlin.c 2015-05-01 14:57:57.771427001 -0500 +@@ -24,7 +24,7 @@ + * with DT probing for L2CCs, berlin_init_machine can be removed. + * Note: 88DE3005 (Armada 1500-mini) uses pl310 l2cc + */ +- l2x0_of_init(0x70c00000, 0xfeffffff); ++ l2x0_of_init(0x30c00000, 0xfeffffff); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + } + +diff -Nur linux-3.14.40.orig/arch/arm/mach-cns3xxx/core.c linux-3.14.40/arch/arm/mach-cns3xxx/core.c +--- linux-3.14.40.orig/arch/arm/mach-cns3xxx/core.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-cns3xxx/core.c 2015-05-01 14:57:57.771427001 -0500 +@@ -240,9 +240,9 @@ + * + * 1 cycle of latency for setup, read and write accesses + */ +- val = readl(base + L2X0_TAG_LATENCY_CTRL); ++ val = readl(base + L310_TAG_LATENCY_CTRL); + val &= 0xfffff888; +- writel(val, base + L2X0_TAG_LATENCY_CTRL); ++ writel(val, base + L310_TAG_LATENCY_CTRL); + + /* + * Data RAM Control register +@@ -253,12 +253,12 @@ + * + * 1 cycle of latency for setup, read and write accesses + */ +- val = readl(base + L2X0_DATA_LATENCY_CTRL); ++ val = readl(base + L310_DATA_LATENCY_CTRL); + val &= 0xfffff888; +- writel(val, base + L2X0_DATA_LATENCY_CTRL); ++ writel(val, base + L310_DATA_LATENCY_CTRL); + + /* 32 KiB, 8-way, parity disable */ +- l2x0_init(base, 0x00540000, 0xfe000fff); ++ l2x0_init(base, 0x00500000, 0xfe0f0fff); + } + + #endif /* CONFIG_CACHE_L2X0 */ +diff -Nur linux-3.14.40.orig/arch/arm/mach-exynos/common.c linux-3.14.40/arch/arm/mach-exynos/common.c +--- linux-3.14.40.orig/arch/arm/mach-exynos/common.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-exynos/common.c 2015-05-01 14:57:57.771427001 -0500 +@@ -45,9 +45,6 @@ + #include "common.h" + #include "regs-pmu.h" + +-#define L2_AUX_VAL 0x7C470001 +-#define L2_AUX_MASK 0xC200ffff +- + static const char name_exynos4210[] = "EXYNOS4210"; + static const char name_exynos4212[] = "EXYNOS4212"; + static const char name_exynos4412[] = "EXYNOS4412"; +@@ -400,7 +397,7 @@ + { + int ret; + +- ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK); ++ ret = l2x0_of_init(0x3c400001, 0xc20fffff); + if (ret) + return ret; + +diff -Nur linux-3.14.40.orig/arch/arm/mach-highbank/highbank.c linux-3.14.40/arch/arm/mach-highbank/highbank.c +--- linux-3.14.40.orig/arch/arm/mach-highbank/highbank.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-highbank/highbank.c 2015-05-01 14:57:57.787427001 -0500 +@@ -20,7 +20,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + #include +@@ -51,11 +51,13 @@ + } + + +-static void highbank_l2x0_disable(void) ++static void highbank_l2c310_write_sec(unsigned long val, unsigned reg) + { +- outer_flush_all(); +- /* Disable PL310 L2 Cache controller */ +- highbank_smc1(0x102, 0x0); ++ if (reg == L2X0_CTRL) ++ highbank_smc1(0x102, val); ++ else ++ WARN_ONCE(1, "Highbank L2C310: ignoring write to reg 0x%x\n", ++ reg); + } + + static void __init highbank_init_irq(void) +@@ -66,11 +68,9 @@ + highbank_scu_map_io(); + + /* Enable PL310 L2 Cache controller */ +- if (IS_ENABLED(CONFIG_CACHE_L2X0) && +- of_find_compatible_node(NULL, NULL, "arm,pl310-cache")) { +- highbank_smc1(0x102, 0x1); +- l2x0_of_init(0, ~0UL); +- outer_cache.disable = highbank_l2x0_disable; ++ if (IS_ENABLED(CONFIG_CACHE_L2X0)) { ++ outer_cache.write_sec = highbank_l2c310_write_sec; ++ l2x0_of_init(0, ~0); + } + } + +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/anatop.c linux-3.14.40/arch/arm/mach-imx/anatop.c +--- linux-3.14.40.orig/arch/arm/mach-imx/anatop.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/anatop.c 2015-05-01 14:57:57.795427001 -0500 +@@ -9,6 +9,7 @@ + * http://www.gnu.org/copyleft/gpl.html + */ + ++#include + #include + #include + #include +@@ -35,6 +36,10 @@ + #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) +@@ -78,6 +83,28 @@ + BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B); + } + ++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; +@@ -104,6 +131,15 @@ + 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; + } +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/busfreq_ddr3.c linux-3.14.40/arch/arm/mach-imx/busfreq_ddr3.c +--- linux-3.14.40.orig/arch/arm/mach-imx/busfreq_ddr3.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mach-imx/busfreq_ddr3.c 2015-05-01 14:57:57.795427001 -0500 +@@ -0,0 +1,471 @@ ++/* ++ * 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; ++ ++ pr_debug("Bus 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(); ++ ++ pr_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; ++ ++ node = of_find_compatible_node(NULL, NULL, "fsl,imx6q-mmdc-combine"); ++ if (!node) { ++ pr_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) { ++ pr_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) { ++ pr_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) { ++ pr_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) { ++ pr_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_iomux_settings = gen_pool_alloc(iram_pool, ++ (iomux_settings_size * 8) + 8); ++ 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_ddr_settings = gen_pool_alloc(iram_pool, ++ (ddr_settings_size * 8) + 8 + 32); ++ 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 = 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_RWX_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.14.40.orig/arch/arm/mach-imx/busfreq-imx6.c linux-3.14.40/arch/arm/mach-imx/busfreq-imx6.c +--- linux-3.14.40.orig/arch/arm/mach-imx/busfreq-imx6.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mach-imx/busfreq-imx6.c 2015-05-01 14:57:57.799427001 -0500 +@@ -0,0 +1,952 @@ ++/* ++ * 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; ++ ++#ifdef CONFIG_ARM_IMX6_CPUFREQ ++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; ++} ++#endif ++ ++void request_bus_freq(enum bus_freq_mode mode) ++{ ++#ifdef CONFIG_ARM_IMX6_CPUFREQ ++ 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); ++#endif ++ return; ++} ++EXPORT_SYMBOL(request_bus_freq); ++ ++void release_bus_freq(enum bus_freq_mode mode) ++{ ++#ifdef CONFIG_ARM_IMX6_CPUFREQ ++ 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); ++#endif ++ return; ++} ++EXPORT_SYMBOL(release_bus_freq); ++ ++#ifdef CONFIG_ARM_IMX6_CPUFREQ ++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); ++#endif ++ ++/*! ++ * 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) ++{ ++#ifdef CONFIG_ARM_IMX6_CPUFREQ ++ 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; ++ } ++#endif ++ ++ 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; ++ ++#ifdef CONFIG_ARM_IMX6_CPUFREQ ++ 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; ++ } ++#endif ++ 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) ++{ ++#ifdef CONFIG_ARM_IMX6_CPUFREQ ++ sysfs_remove_file(&busfreq_dev->kobj, &dev_attr_enable.attr); ++ ++ bus_freq_scaling_initialized = 0; ++#endif ++ /* Unregister the device structure */ ++ platform_driver_unregister(&busfreq_driver); ++} ++ ++module_init(busfreq_init); ++module_exit(busfreq_cleanup); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("BusFreq driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/busfreq_lpddr2.c linux-3.14.40/arch/arm/mach-imx/busfreq_lpddr2.c +--- linux-3.14.40.orig/arch/arm/mach-imx/busfreq_lpddr2.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mach-imx/busfreq_lpddr2.c 2015-05-01 14:57:57.799427001 -0500 +@@ -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_RWX_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.14.40.orig/arch/arm/mach-imx/clk.h linux-3.14.40/arch/arm/mach-imx/clk.h +--- linux-3.14.40.orig/arch/arm/mach-imx/clk.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/clk.h 2015-05-01 14:57:57.799427001 -0500 +@@ -23,7 +23,8 @@ + }; + + 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, +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/clk-imx6q.c linux-3.14.40/arch/arm/mach-imx/clk-imx6q.c +--- linux-3.14.40.orig/arch/arm/mach-imx/clk-imx6q.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/clk-imx6q.c 2015-05-01 14:57:57.807427001 -0500 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011-2013 Freescale Semiconductor, Inc. ++ * Copyright 2011-2014 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -24,6 +24,8 @@ + #include "common.h" + #include "hardware.h" + ++#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", }; + static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", }; +@@ -39,6 +41,8 @@ + 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", }; +@@ -72,6 +76,10 @@ + "pll4_audio", "pll5_video", "pll8_mlb", "enet_ref", + "pcie_ref", "sata_ref", + }; ++static const char *pll_av_sels[] = { "osc", "lvds1_in", "lvds2_in", "dummy", }; ++static void __iomem *anatop_base; ++static void __iomem *ccm_base; ++ + + enum mx6q_clks { + dummy, ckil, ckih, osc, pll2_pfd0_352m, pll2_pfd1_594m, pll2_pfd2_396m, +@@ -88,11 +96,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, +@@ -107,7 +115,10 @@ + 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, eim_slow, + spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, pll4_audio_div, +- lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, clk_max ++ lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, gpt_3m, video_27m, ++ ldb_di0_div_7, ldb_di1_div_7, ldb_di0_div_sel, ldb_di1_div_sel, ++ caam_mem, caam_aclk, caam_ipg, epit1, epit2, tzasc2, lvds1_in, lvds1_out, ++ pll4_sel, lvds2_in, lvds2_out, anaclk1, anaclk2, clk_max + }; + + static struct clk *clk[clk_max]; +@@ -140,20 +151,131 @@ + { /* sentinel */ } + }; + ++static void init_ldb_clks(enum mx6q_clks new_parent) ++{ ++ u32 reg; ++ ++ /* ++ * Need to follow a strict procedure when changing the LDB ++ * clock, else we can introduce a glitch. Things to keep in ++ * mind: ++ * 1. The current and new parent clocks must be disabled. ++ * 2. The default clock for ldb_dio_clk is mmdc_ch1 which has ++ * no CG bit. ++ * 3. In the RTL implementation of the LDB_DI_CLK_SEL mux ++ * the top four options are in one mux and the PLL3 option along ++ * with another option is in the second mux. There is third mux ++ * used to decide between the first and second mux. ++ * The code below switches the parent to the bottom mux first ++ * and then manipulates the top mux. This ensures that no glitch ++ * will enter the divider. ++ * ++ * Need to disable MMDC_CH1 clock manually as there is no CG bit ++ * for this clock. The only way to disable this clock is to move ++ * it topll3_sw_clk and then to disable pll3_sw_clk ++ * Make sure periph2_clk2_sel is set to pll3_sw_clk ++ */ ++ reg = readl_relaxed(ccm_base + 0x18); ++ reg &= ~(1 << 20); ++ writel_relaxed(reg, ccm_base + 0x18); ++ ++ /* ++ * Set MMDC_CH1 mask bit. ++ */ ++ reg = readl_relaxed(ccm_base + 0x4); ++ reg |= 1 << 16; ++ writel_relaxed(reg, ccm_base + 0x4); ++ ++ /* ++ * Set the periph2_clk_sel to the top mux so that ++ * mmdc_ch1 is from pll3_sw_clk. ++ */ ++ reg = readl_relaxed(ccm_base + 0x14); ++ reg |= 1 << 26; ++ writel_relaxed(reg, ccm_base + 0x14); ++ ++ /* ++ * Wait for the clock switch. ++ */ ++ while (readl_relaxed(ccm_base + 0x48)) ++ ; ++ ++ /* ++ * Disable pll3_sw_clk by selecting the bypass clock source. ++ */ ++ reg = readl_relaxed(ccm_base + 0xc); ++ reg |= 1 << 0; ++ writel_relaxed(reg, ccm_base + 0xc); ++ ++ /* ++ * Set the ldb_di0_clk and ldb_di1_clk to 111b. ++ */ ++ reg = readl_relaxed(ccm_base + 0x2c); ++ reg |= ((7 << 9) | (7 << 12)); ++ writel_relaxed(reg, ccm_base + 0x2c); ++ ++ /* ++ * Set the ldb_di0_clk and ldb_di1_clk to 100b. ++ */ ++ reg = readl_relaxed(ccm_base + 0x2c); ++ reg &= ~((7 << 9) | (7 << 12)); ++ reg |= ((4 << 9) | (4 << 12)); ++ writel_relaxed(reg, ccm_base + 0x2c); ++ ++ /* ++ * Perform the LDB parent clock switch. ++ */ ++ clk_set_parent(clk[ldb_di0_sel], clk[new_parent]); ++ clk_set_parent(clk[ldb_di1_sel], clk[new_parent]); ++ ++ /* ++ * Unbypass pll3_sw_clk. ++ */ ++ reg = readl_relaxed(ccm_base + 0xc); ++ reg &= ~(1 << 0); ++ writel_relaxed(reg, ccm_base + 0xc); ++ ++ /* ++ * Set the periph2_clk_sel back to the bottom mux so that ++ * mmdc_ch1 is from its original parent. ++ */ ++ reg = readl_relaxed(ccm_base + 0x14); ++ reg &= ~(1 << 26); ++ writel_relaxed(reg, ccm_base + 0x14); ++ ++ /* ++ * Wait for the clock switch. ++ */ ++ while (readl_relaxed(ccm_base + 0x48)) ++ ; ++ ++ /* ++ * Clear MMDC_CH1 mask bit. ++ */ ++ reg = readl_relaxed(ccm_base + 0x4); ++ reg &= ~(1 << 16); ++ writel_relaxed(reg, ccm_base + 0x4); ++ ++} ++ + static void __init imx6q_clocks_init(struct device_node *ccm_node) + { + struct device_node *np; + void __iomem *base; + int i, irq; + int ret; ++ u32 reg; + + clk[dummy] = imx_clk_fixed("dummy", 0); + clk[ckil] = imx_obtain_fixed_clock("ckil", 0); + clk[ckih] = imx_obtain_fixed_clock("ckih1", 0); + clk[osc] = imx_obtain_fixed_clock("osc", 0); ++ /* Clock source from external clock via ANACLK1/2 PADs */ ++ clk[anaclk1] = imx_obtain_fixed_clock("anaclk1", 0); ++ clk[anaclk2] = imx_obtain_fixed_clock("anaclk2", 0); + + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); +- base = of_iomap(np, 0); ++ anatop_base = base = of_iomap(np, 0); + WARN_ON(!base); + + /* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */ +@@ -165,13 +287,18 @@ + } + + /* 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[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", "pll4_sel", 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)); ++ clk[lvds2_sel] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); ++ clk[pll4_sel] = imx_clk_mux("pll4_sel", base + 0x70, 14, 2, pll_av_sels, ARRAY_SIZE(pll_av_sels)); + + /* + * Bit 20 is the reserved and read-only bit, we do this only for: +@@ -191,6 +318,11 @@ + + 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/2 in/out is used to select the clk direction */ ++ clk[lvds1_in] = imx_clk_gate("lvds1_in", "anaclk1", base + 0x160, 12); ++ clk[lvds2_in] = imx_clk_gate("lvds2_in", "anaclk2", base + 0x160, 13); ++ clk[lvds1_out] = imx_clk_gate("lvds1_out", "lvds1_sel", base + 0x160, 10); ++ clk[lvds2_out] = imx_clk_gate("lvds2_out", "lvds2_sel", base + 0x160, 11); + + 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); +@@ -199,18 +331,6 @@ + base + 0xe0, 0, 2, 0, clk_enet_ref_table, + &imx_ccm_lock); + +- clk[lvds1_sel] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); +- clk[lvds2_sel] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels)); +- +- /* +- * lvds1_gate and lvds2_gate are pseudo-gates. Both can be +- * independently configured as clock inputs or outputs. We treat +- * the "output_enable" bit as a gate, even though it's really just +- * enabling clock output. +- */ +- clk[lvds1_gate] = imx_clk_gate("lvds1_gate", "dummy", base + 0x160, 10); +- clk[lvds2_gate] = imx_clk_gate("lvds2_gate", "dummy", base + 0x160, 11); +- + /* name parent_name reg idx */ + clk[pll2_pfd0_352m] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0); + clk[pll2_pfd1_594m] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1); +@@ -226,6 +346,8 @@ + 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); +@@ -233,7 +355,7 @@ + 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 = ccm_node; +- base = of_iomap(np, 0); ++ ccm_base = base = of_iomap(np, 0); + WARN_ON(!base); + + imx6q_pm_set_ccm_base(base); +@@ -258,14 +380,16 @@ + 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_fixup_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels), imx_cscmr1_fixup); +@@ -307,9 +431,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); +@@ -344,6 +468,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); +@@ -354,6 +481,8 @@ + 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); +@@ -373,15 +502,16 @@ + 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); + if (cpu_is_imx6dl()) + /* +@@ -413,6 +543,9 @@ + 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); +@@ -431,25 +564,79 @@ + 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); ++ ++ /* Make sure PFDs are disabled at boot. */ ++ reg = readl_relaxed(anatop_base + 0x100); ++ /* Cannot disable pll2_pfd2_396M, as it is the MMDC clock in iMX6DL */ ++ if (cpu_is_imx6dl()) ++ reg |= 0x80008080; ++ else ++ reg |= 0x80808080; ++ writel_relaxed(reg, anatop_base + 0x100); ++ ++ /* Disable PLL3 PFDs. */ ++ reg = readl_relaxed(anatop_base + 0xF0); ++ reg |= 0x80808080; ++ writel_relaxed(reg, anatop_base + 0xF0); ++ ++ /* Make sure PLLs is disabled */ ++ reg = readl_relaxed(anatop_base + 0xA0); ++ reg &= ~(1 << 13); ++ writel_relaxed(reg, anatop_base + 0xA0); ++ + 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"); +- clk_register_clkdev(clk[pll4_post_div], "pll4_post_div", NULL); +- clk_register_clkdev(clk[pll4_audio], "pll4_audio", NULL); ++ clk_register_clkdev(clk[pll4_audio_div], "pll4_audio_div", NULL); ++ clk_register_clkdev(clk[pll4_sel], "pll4_sel", NULL); ++ clk_register_clkdev(clk[lvds2_in], "lvds2_in", NULL); ++ clk_register_clkdev(clk[esai], "esai", NULL); + +- 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]); + } + ++ 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]); ++ + /* + * The gpmi needs 100MHz frequency in the EDO/Sync mode, + * We can not get the 100MHz from the pll2_pfd0_352m. +@@ -457,6 +644,19 @@ + */ + 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]]); + +@@ -465,6 +665,25 @@ + clk_prepare_enable(clk[usbphy2_gate]); + } + ++ /* ipu clock initialization */ ++ init_ldb_clks(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]); ++ } 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. +@@ -482,6 +701,18 @@ + if (IS_ENABLED(CONFIG_PCI_IMX6)) + clk_set_parent(clk[lvds1_sel], clk[sata_ref]); + ++ /* 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[esai_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); + +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/clk-imx6sl.c linux-3.14.40/arch/arm/mach-imx/clk-imx6sl.c +--- linux-3.14.40.orig/arch/arm/mach-imx/clk-imx6sl.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/clk-imx6sl.c 2015-05-01 14:57:57.819427001 -0500 +@@ -7,9 +7,29 @@ + * + */ + ++#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 +@@ -18,6 +38,7 @@ + #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", }; +@@ -25,8 +46,8 @@ + 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_podf", }; +-static const char const *periph2_sels[] = { "pre_periph2_sel", "periph2_clk2_podf", }; ++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_lcdif_sels[] = { "mmdc", "pll2_pfd2", "pll3_120m", "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", }; +@@ -38,7 +59,7 @@ + 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", "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, }, +@@ -65,6 +86,80 @@ + + static struct clk *clks[IMX6SL_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) + { +@@ -72,6 +167,8 @@ + void __iomem *base; + int irq; + int i; ++ int ret; ++ u32 reg; + + clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); + clks[IMX6SL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0); +@@ -82,13 +179,18 @@ + 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); +- clks[IMX6SL_CLK_PLL2_BUS] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_bus", "osc", base + 0x30, 0x1); +- clks[IMX6SL_CLK_PLL3_USB_OTG] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc", base + 0x10, 0x3); +- clks[IMX6SL_CLK_PLL4_AUDIO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4_audio", "osc", base + 0x70, 0x7f); +- clks[IMX6SL_CLK_PLL5_VIDEO] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "osc", base + 0xa0, 0x7f); +- clks[IMX6SL_CLK_PLL6_ENET] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6_enet", "osc", base + 0xe0, 0x3); +- clks[IMX6SL_CLK_PLL7_USB_HOST] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7_usb_host", "osc", base + 0x20, 0x3); ++ 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); ++ ++ /* 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); + + /* + * usbphy1 and usbphy2 are implemented as dummy gates using reserve +@@ -118,11 +220,36 @@ + 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); ++ /* 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); +@@ -158,7 +285,7 @@ + clks[IMX6SL_CLK_EPDC_PIX_SEL] = imx_clk_mux("epdc_pix_sel", base + 0x38, 15, 3, epdc_pix_sels, ARRAY_SIZE(epdc_pix_sels)); + 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("extern_audio_sel", base + 0x20, 19, 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)); + +@@ -168,8 +295,8 @@ + + /* 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_PODF] = imx_clk_divider("periph_clk2_podf", "periph_clk2_sel", base + 0x14, 27, 3); +- clks[IMX6SL_CLK_PERIPH2_CLK2_PODF] = imx_clk_divider("periph2_clk2_podf", "periph2_clk2_sel", base + 0x14, 0, 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); +@@ -251,6 +378,25 @@ + 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); +@@ -258,17 +404,58 @@ + clk_register_clkdev(clks[IMX6SL_CLK_GPT], "ipg", "imx-gpt.0"); + clk_register_clkdev(clks[IMX6SL_CLK_GPT_SERIAL], "per", "imx-gpt.0"); + ++ /* ++ * 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]); ++ + /* Audio-related clocks configuration */ + 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 initial power mode */ + imx6q_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); +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/clk-pfd.c linux-3.14.40/arch/arm/mach-imx/clk-pfd.c +--- linux-3.14.40.orig/arch/arm/mach-imx/clk-pfd.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/clk-pfd.c 2015-05-01 14:57:57.819427001 -0500 +@@ -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; +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/clk-pllv3.c linux-3.14.40/arch/arm/mach-imx/clk-pllv3.c +--- linux-3.14.40.orig/arch/arm/mach-imx/clk-pllv3.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/clk-pllv3.c 2015-05-01 14:57:57.819427001 -0500 +@@ -26,12 +26,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 +@@ -41,7 +44,9 @@ + 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) +@@ -61,54 +66,53 @@ + break; + if (time_after(jiffies, timeout)) + break; +- usleep_range(50, 500); ++ udelay(100); + } while (1); + + return readl_relaxed(pll->base) & BM_PLL_LOCK ? 0 : -ETIMEDOUT; + } + +-static int clk_pllv3_prepare(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; +- int ret; +- +- val = readl_relaxed(pll->base); +- if (pll->powerup_set) +- val |= BM_PLL_POWER; +- else +- val &= ~BM_PLL_POWER; +- writel_relaxed(val, pll->base); +- +- ret = clk_pllv3_wait_lock(pll); +- if (ret) +- return ret; ++ u32 val, ret = 0; + +- val = readl_relaxed(pll->base); +- val &= ~BM_PLL_BYPASS; +- writel_relaxed(val, pll->base); +- +- return 0; +-} ++ 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_lock(pll); ++ } 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); ++ } + +-static void clk_pllv3_unprepare(struct clk_hw *hw) +-{ +- struct clk_pllv3 *pll = to_clk_pllv3(hw); +- u32 val; ++ if (!ret) { ++ val = readl_relaxed(pll->base); ++ val &= ~BM_PLL_BYPASS; ++ writel_relaxed(val, pll->base); ++ } + +- 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; +@@ -123,8 +127,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, +@@ -132,8 +140,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, +@@ -141,6 +156,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; + } +@@ -151,6 +170,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) +@@ -167,8 +202,6 @@ + } + + 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, +@@ -181,6 +214,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; + } +@@ -193,6 +230,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) +@@ -210,9 +250,26 @@ + 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; +@@ -223,8 +280,6 @@ + } + + 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, +@@ -239,6 +294,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); + } +@@ -253,6 +312,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) +@@ -273,13 +335,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; +@@ -287,18 +372,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 clk_pllv3_wait_lock(pll); ++ ret = clk_pllv3_wait_lock(pll); ++ 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, +@@ -313,8 +410,6 @@ + } + + 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, +@@ -322,7 +417,7 @@ + + 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; +@@ -352,6 +447,7 @@ + } + pll->base = base; + pll->div_mask = div_mask; ++ pll->always_on = always_on; + + init.name = name; + init.ops = ops; +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/common.h linux-3.14.40/arch/arm/mach-imx/common.h +--- linux-3.14.40.orig/arch/arm/mach-imx/common.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/common.h 2015-05-01 14:57:57.823427001 -0500 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved. + */ + + /* +@@ -116,7 +116,6 @@ + void imx_set_cpu_jump(int cpu, void *jump_addr); + u32 imx_get_cpu_arg(int cpu); + void imx_set_cpu_arg(int cpu, u32 arg); +-void v7_cpu_resume(void); + #ifdef CONFIG_SMP + void v7_secondary_startup(void); + void imx_scu_map_io(void); +@@ -129,7 +128,7 @@ + #endif + void imx_src_init(void); + void imx_gpc_init(void); +-void imx_gpc_pre_suspend(void); ++void imx_gpc_pre_suspend(bool arm_power_off); + void imx_gpc_post_resume(void); + void imx_gpc_mask_all(void); + void imx_gpc_restore_all(void); +@@ -138,14 +137,28 @@ + void imx_anatop_init(void); + void imx_anatop_pre_suspend(void); + void imx_anatop_post_resume(void); ++void imx_anatop_pu_enable(bool enable); + int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode); +-void imx6q_set_chicken_bit(void); ++void imx6q_set_cache_lpm_in_wait(bool enable); ++void imx6sl_set_wait_clk(bool enter); ++void imx6_enet_mac_init(const char *compatible); + + void imx_cpu_die(unsigned int cpu); + int imx_cpu_kill(unsigned int cpu); + ++#ifdef CONFIG_SUSPEND ++void v7_cpu_resume(void); ++void imx6_suspend(void __iomem *ocram_vbase); ++#else ++static inline void v7_cpu_resume(void) {} ++static inline void imx6_suspend(void __iomem *ocram_vbase) {} ++#endif ++ + void imx6q_pm_init(void); ++void imx6dl_pm_init(void); ++void imx6sl_pm_init(void); + void imx6q_pm_set_ccm_base(void __iomem *base); ++ + #ifdef CONFIG_PM + void imx5_pm_init(void); + #else +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/cpuidle.h linux-3.14.40/arch/arm/mach-imx/cpuidle.h +--- linux-3.14.40.orig/arch/arm/mach-imx/cpuidle.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/cpuidle.h 2015-05-01 14:57:57.827427001 -0500 +@@ -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.14.40.orig/arch/arm/mach-imx/cpuidle-imx6q.c linux-3.14.40/arch/arm/mach-imx/cpuidle-imx6q.c +--- linux-3.14.40.orig/arch/arm/mach-imx/cpuidle-imx6q.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/cpuidle-imx6q.c 2015-05-01 14:57:57.827427001 -0500 +@@ -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 +@@ -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 */ ++ imx6q_set_cache_lpm_in_wait(true); + + return cpuidle_register(&imx6q_cpuidle_driver, NULL); + } +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/cpuidle-imx6sl.c linux-3.14.40/arch/arm/mach-imx/cpuidle-imx6sl.c +--- linux-3.14.40.orig/arch/arm/mach-imx/cpuidle-imx6sl.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mach-imx/cpuidle-imx6sl.c 2015-05-01 14:57:57.831427001 -0500 +@@ -0,0 +1,149 @@ ++/* ++ * 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) ++{ ++ imx6q_set_lpm(WAIT_UNCLOCKED); ++#ifdef CONFIG_ARM_IMX6_CPUFREQ ++ 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 ++#endif ++ { ++ imx6sl_set_wait_clk(true); ++ cpu_do_idle(); ++ imx6sl_set_wait_clk(false); ++ } ++ imx6q_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_RWX_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.14.40.orig/arch/arm/mach-imx/ddr3_freq_imx6.S linux-3.14.40/arch/arm/mach-imx/ddr3_freq_imx6.S +--- linux-3.14.40.orig/arch/arm/mach-imx/ddr3_freq_imx6.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mach-imx/ddr3_freq_imx6.S 2015-05-01 14:57:57.831427001 -0500 +@@ -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.14.40.orig/arch/arm/mach-imx/gpc.c linux-3.14.40/arch/arm/mach-imx/gpc.c +--- linux-3.14.40.orig/arch/arm/mach-imx/gpc.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/gpc.c 2015-05-01 14:57:57.831427001 -0500 +@@ -10,30 +10,69 @@ + * 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_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 *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) ++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); ++ 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); +@@ -120,10 +159,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(vpu_clk); ++ clk_prepare_enable(gpu3d_clk); ++ clk_prepare_enable(gpu3d_shader_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(openvg_axi_clk); ++ clk_disable_unprepare(gpu2d_axi_clk); ++ clk_disable_unprepare(gpu2d_clk); ++ clk_disable_unprepare(gpu3d_shader_clk); ++ clk_disable_unprepare(gpu3d_clk); ++ clk_disable_unprepare(vpu_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 +285,190 @@ + 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"); ++ if (IS_ERR(gpu2d_clk) || IS_ERR(openvg_axi_clk) ++ || IS_ERR(ipg_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.14.40.orig/arch/arm/mach-imx/hardware.h linux-3.14.40/arch/arm/mach-imx/hardware.h +--- linux-3.14.40.orig/arch/arm/mach-imx/hardware.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/hardware.h 2015-05-01 14:57:57.831427001 -0500 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. ++ * Copyright 2004-2007, 2014 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,7 +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) \ +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/headsmp.S linux-3.14.40/arch/arm/mach-imx/headsmp.S +--- linux-3.14.40.orig/arch/arm/mach-imx/headsmp.S 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/headsmp.S 2015-05-01 14:57:57.831427001 -0500 +@@ -12,8 +12,6 @@ + + #include + #include +-#include +-#include + + .section ".text.head", "ax" + +@@ -35,37 +33,3 @@ + b secondary_startup + ENDPROC(v7_secondary_startup) + #endif +- +-#ifdef CONFIG_ARM_CPU_SUSPEND +-/* +- * The following code must assume it is running from physical address +- * where absolute virtual addresses to the data section have to be +- * turned into relative ones. +- */ +- +-#ifdef CONFIG_CACHE_L2X0 +- .macro pl310_resume +- adr r0, l2x0_saved_regs_offset +- ldr r2, [r0] +- add r2, r2, r0 +- ldr r0, [r2, #L2X0_R_PHY_BASE] @ get physical base of l2x0 +- ldr r1, [r2, #L2X0_R_AUX_CTRL] @ get aux_ctrl value +- str r1, [r0, #L2X0_AUX_CTRL] @ restore aux_ctrl +- mov r1, #0x1 +- str r1, [r0, #L2X0_CTRL] @ re-enable L2 +- .endm +- +-l2x0_saved_regs_offset: +- .word l2x0_saved_regs - . +- +-#else +- .macro pl310_resume +- .endm +-#endif +- +-ENTRY(v7_cpu_resume) +- bl v7_invalidate_l1 +- pl310_resume +- b cpu_resume +-ENDPROC(v7_cpu_resume) +-#endif +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/imx6sl_wfi.S linux-3.14.40/arch/arm/mach-imx/imx6sl_wfi.S +--- linux-3.14.40.orig/arch/arm/mach-imx/imx6sl_wfi.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mach-imx/imx6sl_wfi.S 2015-05-01 14:57:57.831427001 -0500 +@@ -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.14.40.orig/arch/arm/mach-imx/Kconfig linux-3.14.40/arch/arm/mach-imx/Kconfig +--- linux-3.14.40.orig/arch/arm/mach-imx/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/Kconfig 2015-05-01 14:57:57.831427001 -0500 +@@ -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_CPU_SUSPEND if PM + select ARM_PATCH_PHYS_VIRT +@@ -13,6 +14,7 @@ + select PINCTRL + select SOC_BUS + select SPARSE_IRQ ++ select SRAM + select USE_OF + help + Support for Freescale MXC/iMX-based family of processors +@@ -63,7 +65,6 @@ + + config HAVE_IMX_SRC + def_bool y if SMP +- select ARCH_HAS_RESET_CONTROLLER + + config IMX_HAVE_IOMUX_V1 + bool +@@ -791,6 +792,8 @@ + select ARM_ERRATA_754322 + select ARM_ERRATA_764369 if SMP + select ARM_ERRATA_775420 ++ select ARM_ERRATA_794072 if SMP ++ select ARM_ERRATA_761320 if SMP + select ARM_GIC + select CPU_V7 + select HAVE_ARM_SCU if SMP +@@ -803,11 +806,13 @@ + select MFD_SYSCON + select MIGHT_HAVE_PCI + select PCI_DOMAINS if PCI ++ select ARCH_SUPPORTS_MSI + 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. +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/lpddr2_freq_imx6.S linux-3.14.40/arch/arm/mach-imx/lpddr2_freq_imx6.S +--- linux-3.14.40.orig/arch/arm/mach-imx/lpddr2_freq_imx6.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mach-imx/lpddr2_freq_imx6.S 2015-05-01 14:57:57.831427001 -0500 +@@ -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.14.40.orig/arch/arm/mach-imx/mach-imx6q.c linux-3.14.40/arch/arm/mach-imx/mach-imx6q.c +--- linux-3.14.40.orig/arch/arm/mach-imx/mach-imx6q.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/mach-imx6q.c 2015-05-01 14:57:57.831427001 -0500 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2011-2013 Freescale Semiconductor, Inc. ++ * Copyright 2011-2014 Freescale Semiconductor, Inc. + * Copyright 2011 Linaro Ltd. + * + * The code contained herein is licensed under the GNU General Public +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -22,15 +23,19 @@ + #include + #include + #include ++#include + #include + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -194,6 +199,87 @@ + + } + ++static void __init imx6q_csi_mux_init(void) ++{ ++ /* ++ * 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__); ++ } ++} ++ ++#define OCOTP_MACn(n) (0x00000620 + (n) * 0x10) ++void __init imx6_enet_mac_init(const char *compatible) ++{ ++ struct device_node *enet_np; ++ struct property *newmac; ++ u32 macaddr_low, macaddr_high; ++ u8 *macaddr; ++ int ret; ++ ++ enet_np = of_find_compatible_node(NULL, NULL, compatible); ++ if (!enet_np) ++ return; ++ ++ if (of_get_mac_address(enet_np)) ++ goto put_enet_node; ++ ++ ret = fsl_otp_readl(OCOTP_MACn(0), &macaddr_high); ++ ret = fsl_otp_readl(OCOTP_MACn(1), &macaddr_low); ++ ++ newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL); ++ if (!newmac) ++ goto put_enet_node; ++ ++ newmac->value = newmac + 1; ++ newmac->length = 6; ++ newmac->name = kstrdup("local-mac-address", GFP_KERNEL); ++ if (!newmac->name) { ++ kfree(newmac); ++ goto put_enet_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_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(); ++} ++ + static void __init imx6q_init_machine(void) + { + struct device *parent; +@@ -207,45 +293,56 @@ + if (parent == NULL) + pr_warn("failed to initialize soc device\n"); + +- imx6q_enet_phy_init(); +- + of_platform_populate(NULL, of_default_bus_match_table, NULL, parent); + ++ imx6q_enet_init(); + imx_anatop_init(); +- imx6q_pm_init(); +- imx6q_1588_init(); ++ cpu_is_imx6q() ? imx6q_pm_init() : imx6dl_pm_init(); ++ imx6q_csi_mux_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; + u32 val; ++ int ret; + +- np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp"); +- if (!np) { +- pr_warn("failed to find ocotp node\n"); +- return; ++ ret = fsl_otp_readl(OCOTP_CFG3, &val); ++ if (ret) { ++ pr_warn("failed to read ocotp\n"); ++ return; + } + +- base = of_iomap(np, 0); +- if (!base) { +- pr_warn("failed to map ocotp\n"); +- 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 (dev_pm_opp_disable(cpu_dev, 1200000000)) +- pr_warn("failed to disable 1.2 GHz OPP\n"); +- +-put_node: +- of_node_put(np); ++ if (cpu_is_imx6q()) { ++ if ((val & 0x3) < OCOTP_CFG3_SPEED_1P2GHZ) ++ if (dev_pm_opp_disable(cpu_dev, 1200000000)) ++ pr_warn("failed to disable 1.2 GHz OPP\n"); ++ } ++ if ((val & 0x3) < OCOTP_CFG3_SPEED_1GHZ) ++ if (dev_pm_opp_disable(cpu_dev, 996000000)) ++ pr_warn("failed to disable 1 GHz OPP\n"); ++ if (cpu_is_imx6q()) { ++ if ((val & 0x3) < OCOTP_CFG3_SPEED_850MHZ || ++ (val & 0x3) == OCOTP_CFG3_SPEED_1GHZ) ++ if (dev_pm_opp_disable(cpu_dev, 852000000)) ++ pr_warn("failed to disable 850 MHz OPP\n"); ++ } + } + + static void __init imx6q_opp_init(void) +@@ -268,29 +365,70 @@ + goto put_node; + } + +- imx6q_opp_check_1p2ghz(cpu_dev); ++ imx6q_opp_check_speed_grading(cpu_dev); + + put_node: + of_node_put(np); + } + ++#define ESAI_AUDIO_MCLK 24576000 ++ ++static void __init imx6q_audio_lvds2_init(void) ++{ ++ struct clk *pll4_sel, *lvds2_in, *pll4_audio_div, *esai; ++ ++ pll4_audio_div = clk_get_sys(NULL, "pll4_audio_div"); ++ pll4_sel = clk_get_sys(NULL, "pll4_sel"); ++ lvds2_in = clk_get_sys(NULL, "lvds2_in"); ++ esai = clk_get_sys(NULL, "esai"); ++ if (IS_ERR(pll4_audio_div) || IS_ERR(pll4_sel) || ++ IS_ERR(lvds2_in) || IS_ERR(esai)) ++ return; ++ ++ if (clk_get_rate(lvds2_in) != ESAI_AUDIO_MCLK) ++ return; ++ ++ clk_set_parent(pll4_sel, lvds2_in); ++ clk_set_rate(pll4_audio_div, 786432000); ++ clk_set_rate(esai, ESAI_AUDIO_MCLK); ++} ++ + 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 (imx_get_soc_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(); + platform_device_register(&imx6q_cpufreq_pdev); + } ++ ++ if (of_machine_is_compatible("fsl,imx6q-sabreauto") ++ || of_machine_is_compatible("fsl,imx6dl-sabreauto")) { ++ imx6q_audio_lvds2_init(); ++ } + } + + static void __init imx6q_map_io(void) +@@ -315,6 +453,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, +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/mach-imx6sl.c linux-3.14.40/arch/arm/mach-imx/mach-imx6sl.c +--- linux-3.14.40.orig/arch/arm/mach-imx/mach-imx6sl.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/mach-imx6sl.c 2015-05-01 14:57:57.835427001 -0500 +@@ -17,8 +17,9 @@ + #include + + #include "common.h" ++#include "cpuidle.h" + +-static void __init imx6sl_fec_init(void) ++static void __init imx6sl_fec_clk_init(void) + { + struct regmap *gpr; + +@@ -34,8 +35,17 @@ + } + } + ++static inline void imx6sl_fec_init(void) ++{ ++ imx6sl_fec_clk_init(); ++ imx6_enet_mac_init("fsl,imx6sl-fec"); ++} ++ + static void __init imx6sl_init_late(void) + { ++ /* Init CPUIDLE */ ++ imx6sl_cpuidle_init(); ++ + /* imx6sl reuses imx6q cpufreq driver */ + if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) + platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0); +@@ -55,8 +65,7 @@ + + imx6sl_fec_init(); + imx_anatop_init(); +- /* Reuse imx6q pm code */ +- imx6q_pm_init(); ++ imx6sl_pm_init(); + } + + static void __init imx6sl_init_irq(void) +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/mach-vf610.c linux-3.14.40/arch/arm/mach-imx/mach-vf610.c +--- linux-3.14.40.orig/arch/arm/mach-imx/mach-vf610.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/mach-vf610.c 2015-05-01 14:57:57.835427001 -0500 +@@ -22,7 +22,7 @@ + + static void __init vf610_init_irq(void) + { +- l2x0_of_init(0, ~0UL); ++ l2x0_of_init(0, ~0); + irqchip_init(); + } + +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/Makefile linux-3.14.40/arch/arm/mach-imx/Makefile +--- linux-3.14.40.orig/arch/arm/mach-imx/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/Makefile 2015-05-01 14:57:57.843427001 -0500 +@@ -30,6 +30,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 +@@ -101,9 +102,18 @@ + obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o + obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o + +-obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o +-# i.MX6SL reuses i.MX6Q code +-obj-$(CONFIG_SOC_IMX6SL) += pm-imx6q.o headsmp.o ++AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a ++obj-$(CONFIG_PM) += suspend-imx6.o pm-imx6.o headsmp.o ++ ++obj-y += busfreq-imx6.o ++ifeq ($(CONFIG_ARM_IMX6_CPUFREQ),y) ++obj-$(CONFIG_SOC_IMX6Q) += ddr3_freq_imx6.o busfreq_ddr3.o ++obj-$(CONFIG_SOC_IMX6SL) += lpddr2_freq_imx6.o busfreq_lpddr2.o ++endif ++ifeq ($(CONFIG_CPU_IDLE), y) ++obj-$(CONFIG_SOC_IMX6SL) += imx6sl_wfi.o ++endif ++ + + # i.MX5 based machines + obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/mx6.h linux-3.14.40/arch/arm/mach-imx/mx6.h +--- linux-3.14.40.orig/arch/arm/mach-imx/mx6.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mach-imx/mx6.h 2015-05-01 14:57:57.843427001 -0500 +@@ -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.14.40.orig/arch/arm/mach-imx/mxc.h linux-3.14.40/arch/arm/mach-imx/mxc.h +--- linux-3.14.40.orig/arch/arm/mach-imx/mxc.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/mxc.h 2015-05-01 14:57:57.843427001 -0500 +@@ -42,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 +@@ -177,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.14.40.orig/arch/arm/mach-imx/pm-imx6.c linux-3.14.40/arch/arm/mach-imx/pm-imx6.c +--- linux-3.14.40.orig/arch/arm/mach-imx/pm-imx6.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mach-imx/pm-imx6.c 2015-05-01 14:57:57.843427001 -0500 +@@ -0,0 +1,580 @@ ++/* ++ * Copyright 2011-2014 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 ++#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 MX6Q_SUSPEND_OCRAM_SIZE 0x1000 ++#define MX6_MAX_MMDC_IO_NUM 33 ++ ++static void __iomem *ccm_base; ++static void __iomem *suspend_ocram_base; ++static void (*imx6_suspend_in_ocram_fn)(void __iomem *ocram_vbase); ++ ++/* ++ * suspend ocram space layout: ++ * ======================== high address ====================== ++ * . ++ * . ++ * . ++ * ^ ++ * ^ ++ * ^ ++ * imx6_suspend code ++ * PM_INFO structure(imx6_cpu_pm_info) ++ * ======================== low address ======================= ++ */ ++ ++struct imx6_pm_base { ++ phys_addr_t pbase; ++ void __iomem *vbase; ++}; ++ ++struct imx6_pm_socdata { ++ u32 cpu_type; ++ const char *mmdc_compat; ++ const char *src_compat; ++ const char *iomuxc_compat; ++ const char *gpc_compat; ++ const u32 mmdc_io_num; ++ const u32 *mmdc_io_offset; ++}; ++ ++static const u32 imx6q_mmdc_io_offset[] __initconst = { ++ 0x5ac, 0x5b4, 0x528, 0x520, /* DQM0 ~ DQM3 */ ++ 0x514, 0x510, 0x5bc, 0x5c4, /* DQM4 ~ DQM7 */ ++ 0x56c, 0x578, 0x588, 0x594, /* CAS, RAS, SDCLK_0, SDCLK_1 */ ++ 0x5a8, 0x5b0, 0x524, 0x51c, /* SDQS0 ~ SDQS3 */ ++ 0x518, 0x50c, 0x5b8, 0x5c0, /* SDQS4 ~ SDQS7 */ ++ 0x784, 0x788, 0x794, 0x79c, /* GPR_B0DS ~ GPR_B3DS */ ++ 0x7a0, 0x7a4, 0x7a8, 0x748, /* GPR_B4DS ~ GPR_B7DS */ ++ 0x59c, 0x5a0, 0x750, 0x774, /* SODT0, SODT1, MODE_CTL, MODE */ ++ 0x74c, /* GPR_ADDS */ ++}; ++ ++static const struct imx6_pm_socdata imx6q_pm_data __initconst = { ++ .cpu_type = MXC_CPU_IMX6Q, ++ .mmdc_compat = "fsl,imx6q-mmdc", ++ .src_compat = "fsl,imx6q-src", ++ .iomuxc_compat = "fsl,imx6q-iomuxc", ++ .gpc_compat = "fsl,imx6q-gpc", ++ .mmdc_io_num = ARRAY_SIZE(imx6q_mmdc_io_offset), ++ .mmdc_io_offset = imx6q_mmdc_io_offset, ++}; ++ ++/* ++ * This structure is for passing necessary data for low level ocram ++ * suspend code(arch/arm/mach-imx/suspend-imx6.S), if this struct ++ * definition is changed, the offset definition in ++ * arch/arm/mach-imx/suspend-imx6.S must be also changed accordingly, ++ * otherwise, the suspend to ocram function will be broken! ++ */ ++struct imx6_cpu_pm_info { ++ phys_addr_t pbase; /* The physical address of pm_info. */ ++ phys_addr_t resume_addr; /* The physical resume address for asm code */ ++ u32 cpu_type; ++ u32 pm_info_size; /* Size of pm_info. */ ++ struct imx6_pm_base mmdc_base; ++ struct imx6_pm_base src_base; ++ struct imx6_pm_base iomuxc_base; ++ struct imx6_pm_base ccm_base; ++ struct imx6_pm_base gpc_base; ++ struct imx6_pm_base l2_base; ++ u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */ ++ u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */ ++} __aligned(8); ++ ++void imx6q_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 imx6q_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 imx6q_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 imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) ++{ ++ struct irq_desc *iomuxc_irq_desc; ++ u32 val = readl_relaxed(ccm_base + CLPCR); ++ ++ 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; ++ 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: ++ return -EINVAL; ++ } ++ ++ /* ++ * ERR007265: CCM: When improper low-power sequence is used, ++ * the SoC enters low power mode before the ARM core executes WFI. ++ * ++ * Software workaround: ++ * 1) Software should trigger IRQ #32 (IOMUX) to be always pending ++ * by setting IOMUX_GPR1_GINT. ++ * 2) Software should then unmask IRQ #32 in GPC before setting CCM ++ * Low-Power mode. ++ * 3) Software should mask IRQ #32 right after CCM Low-Power mode ++ * is set (set bits 0-1 of CCM_CLPCR). ++ */ ++ iomuxc_irq_desc = irq_to_desc(32); ++ imx_gpc_irq_unmask(&iomuxc_irq_desc->irq_data); ++ writel_relaxed(val, ccm_base + CLPCR); ++ imx_gpc_irq_mask(&iomuxc_irq_desc->irq_data); ++ ++ return 0; ++} ++ ++static int imx6q_suspend_finish(unsigned long val) ++{ ++ if (!imx6_suspend_in_ocram_fn) { ++ cpu_do_idle(); ++ } else { ++ /* ++ * call low level suspend function in ocram, ++ * as we need to float DDR IO. ++ */ ++ local_flush_tlb_all(); ++ imx6_suspend_in_ocram_fn(suspend_ocram_base); ++ } ++ ++ return 0; ++} ++ ++static int imx6q_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: ++ imx6q_set_lpm(STOP_POWER_ON); ++ imx6q_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(); ++ imx6q_set_lpm(WAIT_CLOCKED); ++ break; ++ case PM_SUSPEND_MEM: ++ imx6q_set_cache_lpm_in_wait(false); ++ imx6q_set_lpm(STOP_POWER_OFF); ++ imx6q_enable_wb(true); ++ /* ++ * For suspend into ocram, asm code already take care of ++ * RBC setting, so we do NOT need to do that here. ++ */ ++ if (!imx6_suspend_in_ocram_fn) ++ imx6q_enable_rbc(true); ++ imx_gpc_pre_suspend(true); ++ imx_anatop_pre_suspend(); ++ imx_set_cpu_jump(0, v7_cpu_resume); ++ /* Zzz ... */ ++ cpu_suspend(0, imx6q_suspend_finish); ++ if (cpu_is_imx6q() || cpu_is_imx6dl()) ++ imx_smp_prepare(); ++ imx_anatop_post_resume(); ++ imx_gpc_post_resume(); ++ imx6q_enable_wb(false); ++ imx6q_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 int imx6q_pm_valid(suspend_state_t state) ++{ ++ return (state == PM_SUSPEND_STANDBY || state == PM_SUSPEND_MEM); ++} ++ ++static const struct platform_suspend_ops imx6q_pm_ops = { ++ .enter = imx6q_pm_enter, ++ .valid = imx6q_pm_valid, ++}; ++ ++void __init imx6q_pm_set_ccm_base(void __iomem *base) ++{ ++ ccm_base = base; ++} ++ ++static int __init imx6_pm_get_base(struct imx6_pm_base *base, ++ const char *compat) ++{ ++ struct device_node *node; ++ struct resource res; ++ int ret = 0; ++ ++ node = of_find_compatible_node(NULL, NULL, compat); ++ if (!node) { ++ ret = -ENODEV; ++ goto out; ++ } ++ ++ ret = of_address_to_resource(node, 0, &res); ++ if (ret) ++ goto put_node; ++ ++ base->pbase = res.start; ++ base->vbase = ioremap(res.start, resource_size(&res)); ++ if (!base->vbase) ++ ret = -ENOMEM; ++ ++put_node: ++ of_node_put(node); ++out: ++ return ret; ++} ++ ++static int __init imx6q_ocram_suspend_init(const struct imx6_pm_socdata ++ *socdata) ++{ ++ phys_addr_t ocram_pbase; ++ struct device_node *node; ++ struct platform_device *pdev; ++ struct imx6_cpu_pm_info *pm_info; ++ struct gen_pool *ocram_pool; ++ unsigned long ocram_base; ++ int i, ret = 0; ++ const u32 *mmdc_offset_array; ++ ++ if (!socdata) { ++ pr_warn("%s: invalid argument!\n", __func__); ++ return -EINVAL; ++ } ++ ++ node = of_find_compatible_node(NULL, NULL, "mmio-sram"); ++ if (!node) { ++ pr_warn("%s: failed to find ocram node!\n", __func__); ++ return -ENODEV; ++ } ++ ++ pdev = of_find_device_by_node(node); ++ if (!pdev) { ++ pr_warn("%s: failed to find ocram device!\n", __func__); ++ ret = -ENODEV; ++ goto put_node; ++ } ++ ++ ocram_pool = dev_get_gen_pool(&pdev->dev); ++ if (!ocram_pool) { ++ pr_warn("%s: ocram pool unavailable!\n", __func__); ++ ret = -ENODEV; ++ goto put_node; ++ } ++ ++ ocram_base = gen_pool_alloc(ocram_pool, MX6Q_SUSPEND_OCRAM_SIZE); ++ if (!ocram_base) { ++ pr_warn("%s: unable to alloc ocram!\n", __func__); ++ ret = -ENOMEM; ++ goto put_node; ++ } ++ ++ ocram_pbase = gen_pool_virt_to_phys(ocram_pool, ocram_base); ++ ++ suspend_ocram_base = __arm_ioremap_exec(ocram_pbase, ++ MX6Q_SUSPEND_OCRAM_SIZE, false); ++ ++ pm_info = suspend_ocram_base; ++ pm_info->pbase = ocram_pbase; ++ pm_info->resume_addr = virt_to_phys(v7_cpu_resume); ++ pm_info->pm_info_size = sizeof(*pm_info); ++ ++ /* ++ * ccm physical address is not used by asm code currently, ++ * so get ccm virtual address directly, as we already have ++ * it from ccm driver. ++ */ ++ pm_info->ccm_base.vbase = ccm_base; ++ ++ ret = imx6_pm_get_base(&pm_info->mmdc_base, socdata->mmdc_compat); ++ if (ret) { ++ pr_warn("%s: failed to get mmdc base %d!\n", __func__, ret); ++ goto put_node; ++ } ++ ++ ret = imx6_pm_get_base(&pm_info->src_base, socdata->src_compat); ++ if (ret) { ++ pr_warn("%s: failed to get src base %d!\n", __func__, ret); ++ goto src_map_failed; ++ } ++ ++ ret = imx6_pm_get_base(&pm_info->iomuxc_base, socdata->iomuxc_compat); ++ if (ret) { ++ pr_warn("%s: failed to get iomuxc base %d!\n", __func__, ret); ++ goto iomuxc_map_failed; ++ } ++ ++ ret = imx6_pm_get_base(&pm_info->gpc_base, socdata->gpc_compat); ++ if (ret) { ++ pr_warn("%s: failed to get gpc base %d!\n", __func__, ret); ++ goto gpc_map_failed; ++ } ++ ++ ret = imx6_pm_get_base(&pm_info->l2_base, "arm,pl310-cache"); ++ if (ret) { ++ pr_warn("%s: failed to get pl310-cache base %d!\n", ++ __func__, ret); ++ goto pl310_cache_map_failed; ++ } ++ ++ pm_info->cpu_type = socdata->cpu_type; ++ pm_info->mmdc_io_num = socdata->mmdc_io_num; ++ mmdc_offset_array = socdata->mmdc_io_offset; ++ ++ for (i = 0; i < pm_info->mmdc_io_num; i++) { ++ pm_info->mmdc_io_val[i][0] = ++ mmdc_offset_array[i]; ++ pm_info->mmdc_io_val[i][1] = ++ readl_relaxed(pm_info->iomuxc_base.vbase + ++ mmdc_offset_array[i]); ++ } ++ ++ imx6_suspend_in_ocram_fn = fncpy( ++ suspend_ocram_base + sizeof(*pm_info), ++ &imx6_suspend, ++ MX6Q_SUSPEND_OCRAM_SIZE - sizeof(*pm_info)); ++ ++ goto put_node; ++ ++pl310_cache_map_failed: ++ iounmap(&pm_info->gpc_base.vbase); ++gpc_map_failed: ++ iounmap(&pm_info->iomuxc_base.vbase); ++iomuxc_map_failed: ++ iounmap(&pm_info->src_base.vbase); ++src_map_failed: ++ iounmap(&pm_info->mmdc_base.vbase); ++put_node: ++ of_node_put(node); ++ ++ return ret; ++} ++ ++static void __init imx6_pm_common_init(const struct imx6_pm_socdata ++ *socdata) ++{ ++ struct regmap *gpr; ++ int ret; ++ ++ WARN_ON(!ccm_base); ++ ++ ret = imx6q_ocram_suspend_init(socdata); ++ if (ret) ++ pr_warn("%s: failed to initialize ocram suspend %d!\n", ++ __func__, ret); ++ ++ /* ++ * This is for SW workaround step #1 of ERR007265, see comments ++ * in imx6q_set_lpm for details of this errata. ++ * Force IOMUXC irq pending, so that the interrupt to GPC can be ++ * used to deassert dsm_request signal when the signal gets ++ * asserted unexpectedly. ++ */ ++ 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_MASK); ++ ++ ++ suspend_set_ops(&imx6q_pm_ops); ++} ++ ++void __init imx6q_pm_init(void) ++{ ++ imx6_pm_common_init(&imx6q_pm_data); ++} ++ ++void __init imx6dl_pm_init(void) ++{ ++ imx6_pm_common_init(NULL); ++} ++ ++void __init imx6sl_pm_init(void) ++{ ++ imx6_pm_common_init(NULL); ++} +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/pm-imx6q.c linux-3.14.40/arch/arm/mach-imx/pm-imx6q.c +--- linux-3.14.40.orig/arch/arm/mach-imx/pm-imx6q.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/pm-imx6q.c 1969-12-31 18:00:00.000000000 -0600 +@@ -1,241 +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 +-#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_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; +- +- /* +- * 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 imx6q_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 imx6q_set_lpm(enum mxc_cpu_pwr_mode mode) +-{ +- struct irq_desc *iomuxc_irq_desc; +- u32 val = readl_relaxed(ccm_base + CLPCR); +- +- 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; +- 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; +- 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: +- return -EINVAL; +- } +- +- /* +- * ERR007265: CCM: When improper low-power sequence is used, +- * the SoC enters low power mode before the ARM core executes WFI. +- * +- * Software workaround: +- * 1) Software should trigger IRQ #32 (IOMUX) to be always pending +- * by setting IOMUX_GPR1_GINT. +- * 2) Software should then unmask IRQ #32 in GPC before setting CCM +- * Low-Power mode. +- * 3) Software should mask IRQ #32 right after CCM Low-Power mode +- * is set (set bits 0-1 of CCM_CLPCR). +- */ +- iomuxc_irq_desc = irq_to_desc(32); +- imx_gpc_irq_unmask(&iomuxc_irq_desc->irq_data); +- writel_relaxed(val, ccm_base + CLPCR); +- imx_gpc_irq_mask(&iomuxc_irq_desc->irq_data); +- +- return 0; +-} +- +-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); +- imx6q_enable_wb(true); +- imx6q_enable_rbc(true); +- imx_gpc_pre_suspend(); +- imx_anatop_pre_suspend(); +- imx_set_cpu_jump(0, v7_cpu_resume); +- /* Zzz ... */ +- cpu_suspend(0, imx6q_suspend_finish); +- if (cpu_is_imx6q() || cpu_is_imx6dl()) +- imx_smp_prepare(); +- imx_anatop_post_resume(); +- imx_gpc_post_resume(); +- imx6q_enable_rbc(false); +- imx6q_enable_wb(false); +- 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_set_ccm_base(void __iomem *base) +-{ +- ccm_base = base; +-} +- +-void __init imx6q_pm_init(void) +-{ +- struct regmap *gpr; +- +- WARN_ON(!ccm_base); +- +- /* +- * This is for SW workaround step #1 of ERR007265, see comments +- * in imx6q_set_lpm for details of this errata. +- * Force IOMUXC irq pending, so that the interrupt to GPC can be +- * used to deassert dsm_request signal when the signal gets +- * asserted unexpectedly. +- */ +- gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); +- if (!IS_ERR(gpr)) +- regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT, +- IMX6Q_GPR1_GINT); +- +- +- suspend_set_ops(&imx6q_pm_ops); +-} +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/suspend-imx6.S linux-3.14.40/arch/arm/mach-imx/suspend-imx6.S +--- linux-3.14.40.orig/arch/arm/mach-imx/suspend-imx6.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mach-imx/suspend-imx6.S 2015-05-01 14:57:57.847427001 -0500 +@@ -0,0 +1,306 @@ ++/* ++ * Copyright 2014 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 "hardware.h" ++ ++/* ++ * ==================== low level suspend ==================== ++ * ++ * Better to follow below rules to use ARM registers: ++ * r0: pm_info structure address; ++ * r1 ~ r4: for saving pm_info members; ++ * r5 ~ r10: free registers; ++ * r11: io base address. ++ * ++ * suspend ocram space layout: ++ * ======================== high address ====================== ++ * . ++ * . ++ * . ++ * ^ ++ * ^ ++ * ^ ++ * imx6_suspend code ++ * PM_INFO structure(imx6_cpu_pm_info) ++ * ======================== low address ======================= ++ */ ++ ++/* ++ * Below offsets are based on struct imx6_cpu_pm_info ++ * which defined in arch/arm/mach-imx/pm-imx6q.c, this ++ * structure contains necessary pm info for low level ++ * suspend related code. ++ */ ++#define PM_INFO_PBASE_OFFSET 0x0 ++#define PM_INFO_RESUME_ADDR_OFFSET 0x4 ++#define PM_INFO_CPU_TYPE_OFFSET 0x8 ++#define PM_INFO_PM_INFO_SIZE_OFFSET 0xC ++#define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10 ++#define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14 ++#define PM_INFO_MX6Q_SRC_P_OFFSET 0x18 ++#define PM_INFO_MX6Q_SRC_V_OFFSET 0x1C ++#define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x20 ++#define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x24 ++#define PM_INFO_MX6Q_CCM_P_OFFSET 0x28 ++#define PM_INFO_MX6Q_CCM_V_OFFSET 0x2C ++#define PM_INFO_MX6Q_GPC_P_OFFSET 0x30 ++#define PM_INFO_MX6Q_GPC_V_OFFSET 0x34 ++#define PM_INFO_MX6Q_L2_P_OFFSET 0x38 ++#define PM_INFO_MX6Q_L2_V_OFFSET 0x3C ++#define PM_INFO_MMDC_IO_NUM_OFFSET 0x40 ++#define PM_INFO_MMDC_IO_VAL_OFFSET 0x44 ++ ++#define MX6Q_SRC_GPR1 0x20 ++#define MX6Q_SRC_GPR2 0x24 ++#define MX6Q_MMDC_MAPSR 0x404 ++#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 ++ ++ .align 3 ++ ++ .macro sync_l2_cache ++ ++ /* sync L2 cache to drain L2's buffers to DRAM. */ ++#ifdef CONFIG_CACHE_L2X0 ++ ldr r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET] ++ mov r6, #0x0 ++ str r6, [r11, #L2X0_CACHE_SYNC] ++1: ++ ldr r6, [r11, #L2X0_CACHE_SYNC] ++ ands r6, r6, #0x1 ++ bne 1b ++#endif ++ ++ .endm ++ ++ .macro resume_mmdc ++ ++ /* restore MMDC IO */ ++ cmp r5, #0x0 ++ ldreq r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] ++ ldrne r11, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET] ++ ++ ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] ++ ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET ++ add r7, r7, r0 ++1: ++ ldr r8, [r7], #0x4 ++ ldr r9, [r7], #0x4 ++ str r9, [r11, r8] ++ subs r6, r6, #0x1 ++ bne 1b ++ ++ cmp r5, #0x0 ++ ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] ++ ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET] ++ ++ /* let DDR out of self-refresh */ ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #(1 << 21) ++ str r7, [r11, #MX6Q_MMDC_MAPSR] ++2: ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ ands r7, r7, #(1 << 25) ++ bne 2b ++ ++ /* enable DDR auto power saving */ ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ bic r7, r7, #0x1 ++ str r7, [r11, #MX6Q_MMDC_MAPSR] ++ ++ .endm ++ ++ENTRY(imx6_suspend) ++ ldr r1, [r0, #PM_INFO_PBASE_OFFSET] ++ ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET] ++ ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET] ++ ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET] ++ ++ /* ++ * counting the resume address in iram ++ * to set it in SRC register. ++ */ ++ ldr r6, =imx6_suspend ++ ldr r7, =resume ++ sub r7, r7, r6 ++ add r8, r1, r4 ++ add r9, r8, r7 ++ ++ /* ++ * make sure TLB contain the addr we want, ++ * as we will access them after MMDC IO floated. ++ */ ++ ++ ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] ++ ldr r6, [r11, #0x0] ++ ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] ++ ldr r6, [r11, #0x0] ++ ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] ++ ldr r6, [r11, #0x0] ++ ++ /* use r11 to store the IO address */ ++ ldr r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET] ++ /* store physical resume addr and pm_info address. */ ++ str r9, [r11, #MX6Q_SRC_GPR1] ++ str r1, [r11, #MX6Q_SRC_GPR2] ++ ++ /* need to sync L2 cache before DSM. */ ++ sync_l2_cache ++ ++ ldr r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET] ++ /* ++ * put DDR explicitly into self-refresh and ++ * disable automatic power savings. ++ */ ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ orr r7, r7, #0x1 ++ str r7, [r11, #MX6Q_MMDC_MAPSR] ++ ++ /* make the DDR explicitly enter self-refresh. */ ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ orr r7, r7, #(1 << 21) ++ str r7, [r11, #MX6Q_MMDC_MAPSR] ++ ++poll_dvfs_set: ++ ldr r7, [r11, #MX6Q_MMDC_MAPSR] ++ ands r7, r7, #(1 << 25) ++ beq poll_dvfs_set ++ ++ ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET] ++ ldr r6, =0x0 ++ ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET] ++ ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET ++ add r8, r8, r0 ++set_mmdc_io_lpm: ++ ldr r9, [r8], #0x8 ++ str r6, [r11, r9] ++ subs r7, r7, #0x1 ++ bne set_mmdc_io_lpm ++ ++ /* ++ * mask all GPC interrupts before ++ * enabling the RBC counters to ++ * avoid the counter starting too ++ * early if an interupt is already ++ * pending. ++ */ ++ ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] ++ ldr r6, [r11, #MX6Q_GPC_IMR1] ++ ldr r7, [r11, #MX6Q_GPC_IMR2] ++ ldr r8, [r11, #MX6Q_GPC_IMR3] ++ ldr r9, [r11, #MX6Q_GPC_IMR4] ++ ++ ldr r10, =0xffffffff ++ str r10, [r11, #MX6Q_GPC_IMR1] ++ str r10, [r11, #MX6Q_GPC_IMR2] ++ str r10, [r11, #MX6Q_GPC_IMR3] ++ str r10, [r11, #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 r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET] ++ ldr r10, [r11, #MX6Q_CCM_CCR] ++ bic r10, r10, #(0x3f << 21) ++ orr r10, r10, #(0x20 << 21) ++ str r10, [r11, #MX6Q_CCM_CCR] ++ ++ /* enable the counter. */ ++ ldr r10, [r11, #MX6Q_CCM_CCR] ++ orr r10, r10, #(0x1 << 27) ++ str r10, [r11, #MX6Q_CCM_CCR] ++ ++ /* unmask all the GPC interrupts. */ ++ ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET] ++ str r6, [r11, #MX6Q_GPC_IMR1] ++ str r7, [r11, #MX6Q_GPC_IMR2] ++ str r8, [r11, #MX6Q_GPC_IMR3] ++ str r9, [r11, #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 r6, =2000 ++rbc_loop: ++ subs r6, r6, #0x1 ++ bne rbc_loop ++ ++ /* 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 MMDC IO first ++ */ ++ mov r5, #0x0 ++ resume_mmdc ++ ++ /* return to suspend finish */ ++ mov pc, lr ++ ++resume: ++ /* invalidate L1 I-cache first */ ++ mov r6, #0x0 ++ mcr p15, 0, r6, c7, c5, 0 ++ mcr p15, 0, r6, c7, c5, 6 ++ /* enable the Icache and branch prediction */ ++ mov r6, #0x1800 ++ mcr p15, 0, r6, c1, c0, 0 ++ isb ++ ++ /* get physical resume address from pm_info. */ ++ ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET] ++ /* clear core0's entry and parameter */ ++ ldr r11, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET] ++ mov r7, #0x0 ++ str r7, [r11, #MX6Q_SRC_GPR1] ++ str r7, [r11, #MX6Q_SRC_GPR2] ++ ++ mov r5, #0x1 ++ resume_mmdc ++ ++ mov pc, lr ++ENDPROC(imx6_suspend) ++ ++/* ++ * The following code must assume it is running from physical address ++ * where absolute virtual addresses to the data section have to be ++ * turned into relative ones. ++ */ ++ ++ENTRY(v7_cpu_resume) ++ bl v7_invalidate_l1 ++#ifdef CONFIG_CACHE_L2X0 ++ bl l2c310_early_resume ++#endif ++ b cpu_resume ++ENDPROC(v7_cpu_resume) +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/system.c linux-3.14.40/arch/arm/mach-imx/system.c +--- linux-3.14.40.orig/arch/arm/mach-imx/system.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/system.c 2015-05-01 14:57:57.847427001 -0500 +@@ -34,6 +34,7 @@ + + 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(). +@@ -47,6 +48,15 @@ + + 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); + +@@ -90,12 +100,29 @@ + + void __init mxc_arch_reset_init_dt(void) + { +- struct device_node *np; ++ 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__); +@@ -124,7 +151,7 @@ + } + + /* Configure the L2 PREFETCH and POWER registers */ +- val = readl_relaxed(l2x0_base + L2X0_PREFETCH_CTRL); ++ val = readl_relaxed(l2x0_base + L310_PREFETCH_CTRL); + val |= 0x70800000; + /* + * The L2 cache controller(PL310) version on the i.MX6D/Q is r3p1-50rel0 +@@ -137,14 +164,12 @@ + */ + if (cpu_is_imx6q()) + val &= ~(1 << 30 | 1 << 23); +- 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); ++ writel_relaxed(val, l2x0_base + L310_PREFETCH_CTRL); + + iounmap(l2x0_base); + of_node_put(np); + + out: +- l2x0_of_init(0, ~0UL); ++ l2x0_of_init(0, ~0); + } + #endif +diff -Nur linux-3.14.40.orig/arch/arm/mach-imx/time.c linux-3.14.40/arch/arm/mach-imx/time.c +--- linux-3.14.40.orig/arch/arm/mach-imx/time.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-imx/time.c 2015-05-01 14:57:57.847427001 -0500 +@@ -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.14.40.orig/arch/arm/mach-nomadik/cpu-8815.c linux-3.14.40/arch/arm/mach-nomadik/cpu-8815.c +--- linux-3.14.40.orig/arch/arm/mach-nomadik/cpu-8815.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-nomadik/cpu-8815.c 2015-05-01 14:57:57.855427001 -0500 +@@ -147,7 +147,7 @@ + { + #ifdef CONFIG_CACHE_L2X0 + /* At full speed latency must be >=2, so 0x249 in low bits */ +- l2x0_of_init(0x00730249, 0xfe000fff); ++ l2x0_of_init(0x00700249, 0xfe0fefff); + #endif + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + } +diff -Nur linux-3.14.40.orig/arch/arm/mach-omap2/common.h linux-3.14.40/arch/arm/mach-omap2/common.h +--- linux-3.14.40.orig/arch/arm/mach-omap2/common.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-omap2/common.h 2015-05-01 14:57:57.871427001 -0500 +@@ -91,6 +91,7 @@ + extern void omap3_secure_sync32k_timer_init(void); + extern void omap3_gptimer_timer_init(void); + extern void omap4_local_timer_init(void); ++int omap_l2_cache_init(void); + extern void omap5_realtime_timer_init(void); + + void omap2420_init_early(void); +diff -Nur linux-3.14.40.orig/arch/arm/mach-omap2/io.c linux-3.14.40/arch/arm/mach-omap2/io.c +--- linux-3.14.40.orig/arch/arm/mach-omap2/io.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-omap2/io.c 2015-05-01 14:57:57.879427001 -0500 +@@ -608,6 +608,7 @@ + am43xx_clockdomains_init(); + am43xx_hwmod_init(); + omap_hwmod_init_postsetup(); ++ omap_l2_cache_init(); + omap_clk_soc_init = am43xx_dt_clk_init; + } + +@@ -639,6 +640,7 @@ + omap44xx_clockdomains_init(); + omap44xx_hwmod_init(); + omap_hwmod_init_postsetup(); ++ omap_l2_cache_init(); + omap_clk_soc_init = omap4xxx_dt_clk_init; + } + +diff -Nur linux-3.14.40.orig/arch/arm/mach-omap2/Kconfig linux-3.14.40/arch/arm/mach-omap2/Kconfig +--- linux-3.14.40.orig/arch/arm/mach-omap2/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-omap2/Kconfig 2015-05-01 14:57:57.895427001 -0500 +@@ -78,6 +78,7 @@ + select MULTI_IRQ_HANDLER + select ARM_GIC + select MACH_OMAP_GENERIC ++ select MIGHT_HAVE_CACHE_L2X0 + + config SOC_DRA7XX + bool "TI DRA7XX" +diff -Nur linux-3.14.40.orig/arch/arm/mach-omap2/omap4-common.c linux-3.14.40/arch/arm/mach-omap2/omap4-common.c +--- linux-3.14.40.orig/arch/arm/mach-omap2/omap4-common.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-omap2/omap4-common.c 2015-05-01 14:57:57.907427001 -0500 +@@ -166,75 +166,57 @@ + return l2cache_base; + } + +-static void omap4_l2x0_disable(void) ++static void omap4_l2c310_write_sec(unsigned long val, unsigned reg) + { +- outer_flush_all(); +- /* Disable PL310 L2 Cache controller */ +- omap_smc1(0x102, 0x0); +-} ++ unsigned smc_op; + +-static void omap4_l2x0_set_debug(unsigned long val) +-{ +- /* Program PL310 L2 Cache controller debug register */ +- omap_smc1(0x100, val); ++ switch (reg) { ++ case L2X0_CTRL: ++ smc_op = OMAP4_MON_L2X0_CTRL_INDEX; ++ break; ++ ++ case L2X0_AUX_CTRL: ++ smc_op = OMAP4_MON_L2X0_AUXCTRL_INDEX; ++ break; ++ ++ case L2X0_DEBUG_CTRL: ++ smc_op = OMAP4_MON_L2X0_DBG_CTRL_INDEX; ++ break; ++ ++ case L310_PREFETCH_CTRL: ++ smc_op = OMAP4_MON_L2X0_PREFETCH_INDEX; ++ break; ++ ++ default: ++ WARN_ONCE(1, "OMAP L2C310: ignoring write to reg 0x%x\n", reg); ++ return; ++ } ++ ++ omap_smc1(smc_op, val); + } + +-static int __init omap_l2_cache_init(void) ++int __init omap_l2_cache_init(void) + { +- u32 aux_ctrl = 0; +- +- /* +- * To avoid code running on other OMAPs in +- * multi-omap builds +- */ +- if (!cpu_is_omap44xx()) +- return -ENODEV; ++ u32 aux_ctrl; + + /* Static mapping, never released */ + l2cache_base = ioremap(OMAP44XX_L2CACHE_BASE, SZ_4K); + if (WARN_ON(!l2cache_base)) + return -ENOMEM; + +- /* +- * 16-way associativity, parity disabled +- * Way size - 32KB (es1.0) +- * Way size - 64KB (es2.0 +) +- */ +- aux_ctrl = ((1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT) | +- (0x1 << 25) | +- (0x1 << L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT) | +- (0x1 << L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT)); +- +- if (omap_rev() == OMAP4430_REV_ES1_0) { +- aux_ctrl |= 0x2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT; +- } else { +- aux_ctrl |= ((0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | +- (1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | +- (1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | +- (1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) | +- (1 << L2X0_AUX_CTRL_EARLY_BRESP_SHIFT)); +- } +- if (omap_rev() != OMAP4430_REV_ES1_0) +- omap_smc1(0x109, aux_ctrl); +- +- /* Enable PL310 L2 Cache controller */ +- omap_smc1(0x102, 0x1); ++ /* 16-way associativity, parity disabled, way size - 64KB (es2.0 +) */ ++ aux_ctrl = L2C_AUX_CTRL_SHARED_OVERRIDE | ++ L310_AUX_CTRL_DATA_PREFETCH | ++ L310_AUX_CTRL_INSTR_PREFETCH; + ++ outer_cache.write_sec = omap4_l2c310_write_sec; + if (of_have_populated_dt()) +- l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK); ++ l2x0_of_init(aux_ctrl, 0xcf9fffff); + else +- l2x0_init(l2cache_base, aux_ctrl, L2X0_AUX_CTRL_MASK); +- +- /* +- * Override default outer_cache.disable with a OMAP4 +- * specific one +- */ +- outer_cache.disable = omap4_l2x0_disable; +- outer_cache.set_debug = omap4_l2x0_set_debug; ++ l2x0_init(l2cache_base, aux_ctrl, 0xcf9fffff); + + return 0; + } +-omap_early_initcall(omap_l2_cache_init); + #endif + + void __iomem *omap4_get_sar_ram_base(void) +diff -Nur linux-3.14.40.orig/arch/arm/mach-omap2/omap-mpuss-lowpower.c linux-3.14.40/arch/arm/mach-omap2/omap-mpuss-lowpower.c +--- linux-3.14.40.orig/arch/arm/mach-omap2/omap-mpuss-lowpower.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-omap2/omap-mpuss-lowpower.c 2015-05-01 14:57:57.915427001 -0500 +@@ -187,19 +187,15 @@ + * in every restore MPUSS OFF path. + */ + #ifdef CONFIG_CACHE_L2X0 +-static void save_l2x0_context(void) ++static void __init save_l2x0_context(void) + { +- u32 val; +- void __iomem *l2x0_base = omap4_get_l2cache_base(); +- if (l2x0_base) { +- val = __raw_readl(l2x0_base + L2X0_AUX_CTRL); +- __raw_writel(val, sar_base + L2X0_AUXCTRL_OFFSET); +- val = __raw_readl(l2x0_base + L2X0_PREFETCH_CTRL); +- __raw_writel(val, sar_base + L2X0_PREFETCH_CTRL_OFFSET); +- } ++ __raw_writel(l2x0_saved_regs.aux_ctrl, ++ sar_base + L2X0_AUXCTRL_OFFSET); ++ __raw_writel(l2x0_saved_regs.prefetch_ctrl, ++ sar_base + L2X0_PREFETCH_CTRL_OFFSET); + } + #else +-static void save_l2x0_context(void) ++static void __init save_l2x0_context(void) + {} + #endif + +diff -Nur linux-3.14.40.orig/arch/arm/mach-prima2/l2x0.c linux-3.14.40/arch/arm/mach-prima2/l2x0.c +--- linux-3.14.40.orig/arch/arm/mach-prima2/l2x0.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-prima2/l2x0.c 2015-05-01 14:57:57.931427001 -0500 +@@ -8,43 +8,10 @@ + + #include + #include +-#include + #include + +-struct l2x0_aux +-{ +- u32 val; +- u32 mask; +-}; +- +-static struct l2x0_aux prima2_l2x0_aux __initconst = { +- .val = 2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT, +- .mask = 0, +-}; +- +-static struct l2x0_aux marco_l2x0_aux __initconst = { +- .val = (2 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT) | +- (1 << L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT), +- .mask = L2X0_AUX_CTRL_MASK, +-}; +- +-static struct of_device_id sirf_l2x0_ids[] __initconst = { +- { .compatible = "sirf,prima2-pl310-cache", .data = &prima2_l2x0_aux, }, +- { .compatible = "sirf,marco-pl310-cache", .data = &marco_l2x0_aux, }, +- {}, +-}; +- + static int __init sirfsoc_l2x0_init(void) + { +- struct device_node *np; +- const struct l2x0_aux *aux; +- +- np = of_find_matching_node(NULL, sirf_l2x0_ids); +- if (np) { +- aux = of_match_node(sirf_l2x0_ids, np)->data; +- return l2x0_of_init(aux->val, aux->mask); +- } +- +- return 0; ++ return l2x0_of_init(0, ~0); + } + early_initcall(sirfsoc_l2x0_init); +diff -Nur linux-3.14.40.orig/arch/arm/mach-prima2/pm.c linux-3.14.40/arch/arm/mach-prima2/pm.c +--- linux-3.14.40.orig/arch/arm/mach-prima2/pm.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-prima2/pm.c 2015-05-01 14:57:57.935427001 -0500 +@@ -71,7 +71,6 @@ + case PM_SUSPEND_MEM: + sirfsoc_pre_suspend_power_off(); + +- outer_flush_all(); + outer_disable(); + /* go zzz */ + cpu_suspend(0, sirfsoc_finish_suspend); +diff -Nur linux-3.14.40.orig/arch/arm/mach-realview/realview_eb.c linux-3.14.40/arch/arm/mach-realview/realview_eb.c +--- linux-3.14.40.orig/arch/arm/mach-realview/realview_eb.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-realview/realview_eb.c 2015-05-01 14:57:57.955427001 -0500 +@@ -442,8 +442,13 @@ + realview_eb11mp_fixup(); + + #ifdef CONFIG_CACHE_L2X0 +- /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled +- * Bits: .... ...0 0111 1001 0000 .... .... .... */ ++ /* ++ * The PL220 needs to be manually configured as the hardware ++ * doesn't report the correct sizes. ++ * 1MB (128KB/way), 8-way associativity, event monitor and ++ * parity enabled, ignore share bit, no force write allocate ++ * Bits: .... ...0 0111 1001 0000 .... .... .... ++ */ + l2x0_init(__io_address(REALVIEW_EB11MP_L220_BASE), 0x00790000, 0xfe000fff); + #endif + platform_device_register(&pmu_device); +diff -Nur linux-3.14.40.orig/arch/arm/mach-realview/realview_pb1176.c linux-3.14.40/arch/arm/mach-realview/realview_pb1176.c +--- linux-3.14.40.orig/arch/arm/mach-realview/realview_pb1176.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-realview/realview_pb1176.c 2015-05-01 14:57:57.963427001 -0500 +@@ -355,7 +355,13 @@ + int i; + + #ifdef CONFIG_CACHE_L2X0 +- /* 128Kb (16Kb/way) 8-way associativity. evmon/parity/share enabled. */ ++ /* ++ * The PL220 needs to be manually configured as the hardware ++ * doesn't report the correct sizes. ++ * 128kB (16kB/way), 8-way associativity, event monitor and ++ * parity enabled, ignore share bit, no force write allocate ++ * Bits: .... ...0 0111 0011 0000 .... .... .... ++ */ + l2x0_init(__io_address(REALVIEW_PB1176_L220_BASE), 0x00730000, 0xfe000fff); + #endif + +diff -Nur linux-3.14.40.orig/arch/arm/mach-realview/realview_pb11mp.c linux-3.14.40/arch/arm/mach-realview/realview_pb11mp.c +--- linux-3.14.40.orig/arch/arm/mach-realview/realview_pb11mp.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-realview/realview_pb11mp.c 2015-05-01 14:57:57.963427001 -0500 +@@ -337,8 +337,13 @@ + int i; + + #ifdef CONFIG_CACHE_L2X0 +- /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled +- * Bits: .... ...0 0111 1001 0000 .... .... .... */ ++ /* ++ * The PL220 needs to be manually configured as the hardware ++ * doesn't report the correct sizes. ++ * 1MB (128KB/way), 8-way associativity, event monitor and ++ * parity enabled, ignore share bit, no force write allocate ++ * Bits: .... ...0 0111 1001 0000 .... .... .... ++ */ + l2x0_init(__io_address(REALVIEW_TC11MP_L220_BASE), 0x00790000, 0xfe000fff); + #endif + +diff -Nur linux-3.14.40.orig/arch/arm/mach-realview/realview_pbx.c linux-3.14.40/arch/arm/mach-realview/realview_pbx.c +--- linux-3.14.40.orig/arch/arm/mach-realview/realview_pbx.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-realview/realview_pbx.c 2015-05-01 14:57:57.963427001 -0500 +@@ -370,8 +370,8 @@ + __io_address(REALVIEW_PBX_TILE_L220_BASE); + + /* set RAM latencies to 1 cycle for eASIC */ +- writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL); +- writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL); ++ writel(0, l2x0_base + L310_TAG_LATENCY_CTRL); ++ writel(0, l2x0_base + L310_DATA_LATENCY_CTRL); + + /* 16KB way size, 8-way associativity, parity disabled + * Bits: .. 0 0 0 0 1 00 1 0 1 001 0 000 0 .... .... .... */ +diff -Nur linux-3.14.40.orig/arch/arm/mach-rockchip/rockchip.c linux-3.14.40/arch/arm/mach-rockchip/rockchip.c +--- linux-3.14.40.orig/arch/arm/mach-rockchip/rockchip.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-rockchip/rockchip.c 2015-05-01 14:57:57.963427001 -0500 +@@ -25,7 +25,7 @@ + + static void __init rockchip_dt_init(void) + { +- l2x0_of_init(0, ~0UL); ++ l2x0_of_init(0, ~0); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + } + +diff -Nur linux-3.14.40.orig/arch/arm/mach-shmobile/board-armadillo800eva.c linux-3.14.40/arch/arm/mach-shmobile/board-armadillo800eva.c +--- linux-3.14.40.orig/arch/arm/mach-shmobile/board-armadillo800eva.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-shmobile/board-armadillo800eva.c 2015-05-01 14:57:57.975427001 -0500 +@@ -1270,8 +1270,8 @@ + + + #ifdef CONFIG_CACHE_L2X0 +- /* Early BRESP enable, Shared attribute override enable, 32K*8way */ +- l2x0_init(IOMEM(0xf0002000), 0x40440000, 0x82000fff); ++ /* Shared attribute override enable, 32K*8way */ ++ l2x0_init(IOMEM(0xf0002000), 0x00400000, 0xc20f0fff); + #endif + + i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices)); +diff -Nur linux-3.14.40.orig/arch/arm/mach-shmobile/board-armadillo800eva-reference.c linux-3.14.40/arch/arm/mach-shmobile/board-armadillo800eva-reference.c +--- linux-3.14.40.orig/arch/arm/mach-shmobile/board-armadillo800eva-reference.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-shmobile/board-armadillo800eva-reference.c 2015-05-01 14:57:57.983427001 -0500 +@@ -164,8 +164,8 @@ + r8a7740_meram_workaround(); + + #ifdef CONFIG_CACHE_L2X0 +- /* Early BRESP enable, Shared attribute override enable, 32K*8way */ +- l2x0_init(IOMEM(0xf0002000), 0x40440000, 0x82000fff); ++ /* Shared attribute override enable, 32K*8way */ ++ l2x0_init(IOMEM(0xf0002000), 0x00400000, 0xc20f0fff); + #endif + + r8a7740_add_standard_devices_dt(); +diff -Nur linux-3.14.40.orig/arch/arm/mach-shmobile/board-kzm9g.c linux-3.14.40/arch/arm/mach-shmobile/board-kzm9g.c +--- linux-3.14.40.orig/arch/arm/mach-shmobile/board-kzm9g.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-shmobile/board-kzm9g.c 2015-05-01 14:57:57.983427001 -0500 +@@ -878,8 +878,8 @@ + gpio_request_one(223, GPIOF_IN, NULL); /* IRQ8 */ + + #ifdef CONFIG_CACHE_L2X0 +- /* Early BRESP enable, Shared attribute override enable, 64K*8way */ +- l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff); ++ /* Shared attribute override enable, 64K*8way */ ++ l2x0_init(IOMEM(0xf0100000), 0x00400000, 0xc20f0fff); + #endif + + i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices)); +diff -Nur linux-3.14.40.orig/arch/arm/mach-shmobile/board-kzm9g-reference.c linux-3.14.40/arch/arm/mach-shmobile/board-kzm9g-reference.c +--- linux-3.14.40.orig/arch/arm/mach-shmobile/board-kzm9g-reference.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-shmobile/board-kzm9g-reference.c 2015-05-01 14:57:57.995427001 -0500 +@@ -36,8 +36,8 @@ + sh73a0_add_standard_devices_dt(); + + #ifdef CONFIG_CACHE_L2X0 +- /* Early BRESP enable, Shared attribute override enable, 64K*8way */ +- l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff); ++ /* Shared attribute override enable, 64K*8way */ ++ l2x0_init(IOMEM(0xf0100000), 0x00400000, 0xc20f0fff); + #endif + } + +diff -Nur linux-3.14.40.orig/arch/arm/mach-shmobile/setup-r8a7778.c linux-3.14.40/arch/arm/mach-shmobile/setup-r8a7778.c +--- linux-3.14.40.orig/arch/arm/mach-shmobile/setup-r8a7778.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-shmobile/setup-r8a7778.c 2015-05-01 14:57:57.999427001 -0500 +@@ -298,10 +298,10 @@ + void __iomem *base = ioremap_nocache(0xf0100000, 0x1000); + if (base) { + /* +- * Early BRESP enable, Shared attribute override enable, 64K*16way ++ * Shared attribute override enable, 64K*16way + * don't call iounmap(base) + */ +- l2x0_init(base, 0x40470000, 0x82000fff); ++ l2x0_init(base, 0x00400000, 0xc20f0fff); + } + #endif + +diff -Nur linux-3.14.40.orig/arch/arm/mach-shmobile/setup-r8a7779.c linux-3.14.40/arch/arm/mach-shmobile/setup-r8a7779.c +--- linux-3.14.40.orig/arch/arm/mach-shmobile/setup-r8a7779.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-shmobile/setup-r8a7779.c 2015-05-01 14:57:57.999427001 -0500 +@@ -700,8 +700,8 @@ + void __init r8a7779_add_standard_devices(void) + { + #ifdef CONFIG_CACHE_L2X0 +- /* Early BRESP enable, Shared attribute override enable, 64K*16way */ +- l2x0_init(IOMEM(0xf0100000), 0x40470000, 0x82000fff); ++ /* Shared attribute override enable, 64K*16way */ ++ l2x0_init(IOMEM(0xf0100000), 0x00400000, 0xc20f0fff); + #endif + r8a7779_pm_init(); + +diff -Nur linux-3.14.40.orig/arch/arm/mach-socfpga/socfpga.c linux-3.14.40/arch/arm/mach-socfpga/socfpga.c +--- linux-3.14.40.orig/arch/arm/mach-socfpga/socfpga.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-socfpga/socfpga.c 2015-05-01 14:57:57.999427001 -0500 +@@ -104,7 +104,7 @@ + + static void __init socfpga_cyclone5_init(void) + { +- l2x0_of_init(0, ~0UL); ++ l2x0_of_init(0, ~0); + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + socfpga_init_clocks(); + } +diff -Nur linux-3.14.40.orig/arch/arm/mach-spear/platsmp.c linux-3.14.40/arch/arm/mach-spear/platsmp.c +--- linux-3.14.40.orig/arch/arm/mach-spear/platsmp.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-spear/platsmp.c 2015-05-01 14:57:58.031427001 -0500 +@@ -20,6 +20,18 @@ + #include + #include "generic.h" + ++/* ++ * Write 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(int val) ++{ ++ pen_release = val; ++ smp_wmb(); ++ sync_cache_w(&pen_release); ++} ++ + static DEFINE_SPINLOCK(boot_lock); + + static void __iomem *scu_base = IOMEM(VA_SCU_BASE); +@@ -30,8 +42,7 @@ + * let the primary processor know we're out of the + * pen, then head off into the C entry point + */ +- pen_release = -1; +- smp_wmb(); ++ write_pen_release(-1); + + /* + * Synchronise with the boot thread. +@@ -58,9 +69,7 @@ + * Note that "pen_release" is the hardware CPU ID, whereas + * "cpu" is Linux's internal ID. + */ +- pen_release = cpu; +- flush_cache_all(); +- outer_flush_all(); ++ write_pen_release(cpu); + + timeout = jiffies + (1 * HZ); + while (time_before(jiffies, timeout)) { +diff -Nur linux-3.14.40.orig/arch/arm/mach-spear/spear13xx.c linux-3.14.40/arch/arm/mach-spear/spear13xx.c +--- linux-3.14.40.orig/arch/arm/mach-spear/spear13xx.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-spear/spear13xx.c 2015-05-01 14:57:58.035427001 -0500 +@@ -38,15 +38,15 @@ + if (!IS_ENABLED(CONFIG_CACHE_L2X0)) + return; + +- writel_relaxed(0x06, VA_L2CC_BASE + L2X0_PREFETCH_CTRL); ++ writel_relaxed(0x06, VA_L2CC_BASE + L310_PREFETCH_CTRL); + + /* + * Program following latencies in order to make + * SPEAr1340 work at 600 MHz + */ +- writel_relaxed(0x221, VA_L2CC_BASE + L2X0_TAG_LATENCY_CTRL); +- writel_relaxed(0x441, VA_L2CC_BASE + L2X0_DATA_LATENCY_CTRL); +- l2x0_init(VA_L2CC_BASE, 0x70A60001, 0xfe00ffff); ++ writel_relaxed(0x221, VA_L2CC_BASE + L310_TAG_LATENCY_CTRL); ++ writel_relaxed(0x441, VA_L2CC_BASE + L310_DATA_LATENCY_CTRL); ++ l2x0_init(VA_L2CC_BASE, 0x30a00001, 0xfe0fffff); + } + + /* +diff -Nur linux-3.14.40.orig/arch/arm/mach-sti/board-dt.c linux-3.14.40/arch/arm/mach-sti/board-dt.c +--- linux-3.14.40.orig/arch/arm/mach-sti/board-dt.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-sti/board-dt.c 2015-05-01 14:57:58.035427001 -0500 +@@ -16,15 +16,9 @@ + + void __init stih41x_l2x0_init(void) + { +- u32 way_size = 0x4; +- u32 aux_ctrl; +- /* may be this can be encoded in macros like BIT*() */ +- aux_ctrl = (0x1 << L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT) | +- (0x1 << L2X0_AUX_CTRL_DATA_PREFETCH_SHIFT) | +- (0x1 << L2X0_AUX_CTRL_INSTR_PREFETCH_SHIFT) | +- (way_size << L2X0_AUX_CTRL_WAY_SIZE_SHIFT); +- +- l2x0_of_init(aux_ctrl, L2X0_AUX_CTRL_MASK); ++ l2x0_of_init(L2C_AUX_CTRL_SHARED_OVERRIDE | ++ L310_AUX_CTRL_DATA_PREFETCH | ++ L310_AUX_CTRL_INSTR_PREFETCH, 0xc00f0fff); + } + + static void __init stih41x_machine_init(void) +diff -Nur linux-3.14.40.orig/arch/arm/mach-tegra/pm.h linux-3.14.40/arch/arm/mach-tegra/pm.h +--- linux-3.14.40.orig/arch/arm/mach-tegra/pm.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-tegra/pm.h 2015-05-01 14:57:58.035427001 -0500 +@@ -35,8 +35,6 @@ + void tegra30_lp1_iram_hook(void); + void tegra30_sleep_core_init(void); + +-extern unsigned long l2x0_saved_regs_addr; +- + void tegra_clear_cpu_in_lp2(void); + bool tegra_set_cpu_in_lp2(void); + +diff -Nur linux-3.14.40.orig/arch/arm/mach-tegra/reset-handler.S linux-3.14.40/arch/arm/mach-tegra/reset-handler.S +--- linux-3.14.40.orig/arch/arm/mach-tegra/reset-handler.S 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-tegra/reset-handler.S 2015-05-01 14:57:58.035427001 -0500 +@@ -19,7 +19,6 @@ + + #include + #include +-#include + + #include "flowctrl.h" + #include "fuse.h" +@@ -79,8 +78,10 @@ + str r1, [r0] + #endif + ++#ifdef CONFIG_CACHE_L2X0 + /* L2 cache resume & re-enable */ +- l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr ++ bl l2c310_early_resume ++#endif + end_ca9_scu_l2_resume: + mov32 r9, 0xc0f + cmp r8, r9 +@@ -90,12 +91,6 @@ + ENDPROC(tegra_resume) + #endif + +-#ifdef CONFIG_CACHE_L2X0 +- .globl l2x0_saved_regs_addr +-l2x0_saved_regs_addr: +- .long 0 +-#endif +- + .align L1_CACHE_SHIFT + ENTRY(__tegra_cpu_reset_handler_start) + +diff -Nur linux-3.14.40.orig/arch/arm/mach-tegra/sleep.h linux-3.14.40/arch/arm/mach-tegra/sleep.h +--- linux-3.14.40.orig/arch/arm/mach-tegra/sleep.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-tegra/sleep.h 2015-05-01 14:57:58.035427001 -0500 +@@ -120,37 +120,6 @@ + mov \tmp1, \tmp1, lsr #8 + .endm + +-/* Macro to resume & re-enable L2 cache */ +-#ifndef L2X0_CTRL_EN +-#define L2X0_CTRL_EN 1 +-#endif +- +-#ifdef CONFIG_CACHE_L2X0 +-.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs +- W(adr) \tmp1, \phys_l2x0_saved_regs +- ldr \tmp1, [\tmp1] +- ldr \tmp2, [\tmp1, #L2X0_R_PHY_BASE] +- ldr \tmp3, [\tmp2, #L2X0_CTRL] +- tst \tmp3, #L2X0_CTRL_EN +- bne exit_l2_resume +- ldr \tmp3, [\tmp1, #L2X0_R_TAG_LATENCY] +- str \tmp3, [\tmp2, #L2X0_TAG_LATENCY_CTRL] +- ldr \tmp3, [\tmp1, #L2X0_R_DATA_LATENCY] +- str \tmp3, [\tmp2, #L2X0_DATA_LATENCY_CTRL] +- ldr \tmp3, [\tmp1, #L2X0_R_PREFETCH_CTRL] +- str \tmp3, [\tmp2, #L2X0_PREFETCH_CTRL] +- ldr \tmp3, [\tmp1, #L2X0_R_PWR_CTRL] +- str \tmp3, [\tmp2, #L2X0_POWER_CTRL] +- ldr \tmp3, [\tmp1, #L2X0_R_AUX_CTRL] +- str \tmp3, [\tmp2, #L2X0_AUX_CTRL] +- mov \tmp3, #L2X0_CTRL_EN +- str \tmp3, [\tmp2, #L2X0_CTRL] +-exit_l2_resume: +-.endm +-#else /* CONFIG_CACHE_L2X0 */ +-.macro l2_cache_resume, tmp1, tmp2, tmp3, phys_l2x0_saved_regs +-.endm +-#endif /* CONFIG_CACHE_L2X0 */ + #else + void tegra_pen_lock(void); + void tegra_pen_unlock(void); +diff -Nur linux-3.14.40.orig/arch/arm/mach-tegra/tegra.c linux-3.14.40/arch/arm/mach-tegra/tegra.c +--- linux-3.14.40.orig/arch/arm/mach-tegra/tegra.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-tegra/tegra.c 2015-05-01 14:57:58.035427001 -0500 +@@ -73,27 +73,7 @@ + static void __init tegra_init_cache(void) + { + #ifdef CONFIG_CACHE_L2X0 +- static const struct of_device_id pl310_ids[] __initconst = { +- { .compatible = "arm,pl310-cache", }, +- {} +- }; +- +- struct device_node *np; +- int ret; +- void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000; +- u32 aux_ctrl, cache_type; +- +- np = of_find_matching_node(NULL, pl310_ids); +- if (!np) +- return; +- +- cache_type = readl(p + L2X0_CACHE_TYPE); +- aux_ctrl = (cache_type & 0x700) << (17-8); +- aux_ctrl |= 0x7C400001; +- +- ret = l2x0_of_init(aux_ctrl, 0x8200c3fe); +- if (!ret) +- l2x0_saved_regs_addr = virt_to_phys(&l2x0_saved_regs); ++ l2x0_of_init(0x3c400001, 0xc20fc3fe); + #endif + } + +diff -Nur linux-3.14.40.orig/arch/arm/mach-ux500/board-mop500-audio.c linux-3.14.40/arch/arm/mach-ux500/board-mop500-audio.c +--- linux-3.14.40.orig/arch/arm/mach-ux500/board-mop500-audio.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-ux500/board-mop500-audio.c 2015-05-01 14:57:58.035427001 -0500 +@@ -9,7 +9,6 @@ + #include + #include + +-#include "irqs.h" + #include + + #include "ste-dma40-db8500.h" +diff -Nur linux-3.14.40.orig/arch/arm/mach-ux500/cache-l2x0.c linux-3.14.40/arch/arm/mach-ux500/cache-l2x0.c +--- linux-3.14.40.orig/arch/arm/mach-ux500/cache-l2x0.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-ux500/cache-l2x0.c 2015-05-01 14:57:58.035427001 -0500 +@@ -35,10 +35,16 @@ + return 0; + } + +-static int __init ux500_l2x0_init(void) ++static void ux500_l2c310_write_sec(unsigned long val, unsigned reg) + { +- u32 aux_val = 0x3e000000; ++ /* ++ * We can't write to secure registers as we are in non-secure ++ * mode, until we have some SMI service available. ++ */ ++} + ++static int __init ux500_l2x0_init(void) ++{ + if (cpu_is_u8500_family() || cpu_is_ux540_family()) + l2x0_base = __io_address(U8500_L2CC_BASE); + else +@@ -48,28 +54,12 @@ + /* Unlock before init */ + ux500_l2x0_unlock(); + +- /* DBx540's L2 has 128KB way size */ +- if (cpu_is_ux540_family()) +- /* 128KB way size */ +- aux_val |= (0x4 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT); +- else +- /* 64KB way size */ +- aux_val |= (0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT); ++ outer_cache.write_sec = ux500_l2c310_write_sec; + +- /* 64KB way size, 8 way associativity, force WA */ + if (of_have_populated_dt()) +- l2x0_of_init(aux_val, 0xc0000fff); ++ l2x0_of_init(0, ~0); + else +- l2x0_init(l2x0_base, aux_val, 0xc0000fff); +- +- /* +- * We can't disable l2 as we are in non secure mode, currently +- * this seems be called only during kexec path. So let's +- * override outer.disable with nasty assignment until we have +- * some SMI service available. +- */ +- outer_cache.disable = NULL; +- outer_cache.set_debug = NULL; ++ l2x0_init(l2x0_base, 0, ~0); + + return 0; + } +diff -Nur linux-3.14.40.orig/arch/arm/mach-ux500/cpu-db8500.c linux-3.14.40/arch/arm/mach-ux500/cpu-db8500.c +--- linux-3.14.40.orig/arch/arm/mach-ux500/cpu-db8500.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-ux500/cpu-db8500.c 2015-05-01 14:57:58.035427001 -0500 +@@ -27,7 +27,6 @@ + #include + + #include "setup.h" +-#include "irqs.h" + + #include "board-mop500-regulators.h" + #include "board-mop500.h" +@@ -35,14 +34,11 @@ + #include "id.h" + + struct ab8500_platform_data ab8500_platdata = { +- .irq_base = MOP500_AB8500_IRQ_BASE, + .regulator = &ab8500_regulator_plat_data, + }; + + struct prcmu_pdata db8500_prcmu_pdata = { + .ab_platdata = &ab8500_platdata, +- .ab_irq = IRQ_DB8500_AB8500, +- .irq_base = IRQ_PRCMU_BASE, + .version_offset = DB8500_PRCMU_FW_VERSION_OFFSET, + .legacy_offset = DB8500_PRCMU_LEGACY_OFFSET, + }; +diff -Nur linux-3.14.40.orig/arch/arm/mach-ux500/irqs-board-mop500.h linux-3.14.40/arch/arm/mach-ux500/irqs-board-mop500.h +--- linux-3.14.40.orig/arch/arm/mach-ux500/irqs-board-mop500.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-ux500/irqs-board-mop500.h 1969-12-31 18:00:00.000000000 -0600 +@@ -1,55 +0,0 @@ +-/* +- * Copyright (C) ST-Ericsson SA 2010 +- * +- * Author: Rabin Vincent +- * License terms: GNU General Public License (GPL) version 2 +- */ +- +-#ifndef __MACH_IRQS_BOARD_MOP500_H +-#define __MACH_IRQS_BOARD_MOP500_H +- +-/* Number of AB8500 irqs is taken from header file */ +-#include +- +-#define MOP500_AB8500_IRQ_BASE IRQ_BOARD_START +-#define MOP500_AB8500_IRQ_END (MOP500_AB8500_IRQ_BASE \ +- + AB8500_MAX_NR_IRQS) +- +-/* TC35892 */ +-#define TC35892_NR_INTERNAL_IRQS 8 +-#define TC35892_INT_GPIO(x) (TC35892_NR_INTERNAL_IRQS + (x)) +-#define TC35892_NR_GPIOS 24 +-#define TC35892_NR_IRQS TC35892_INT_GPIO(TC35892_NR_GPIOS) +- +-#define MOP500_EGPIO_NR_IRQS TC35892_NR_IRQS +- +-#define MOP500_EGPIO_IRQ_BASE MOP500_AB8500_IRQ_END +-#define MOP500_EGPIO_IRQ_END (MOP500_EGPIO_IRQ_BASE \ +- + MOP500_EGPIO_NR_IRQS) +-/* STMPE1601 irqs */ +-#define STMPE_NR_INTERNAL_IRQS 9 +-#define STMPE_INT_GPIO(x) (STMPE_NR_INTERNAL_IRQS + (x)) +-#define STMPE_NR_GPIOS 24 +-#define STMPE_NR_IRQS STMPE_INT_GPIO(STMPE_NR_GPIOS) +- +-#define MOP500_STMPE1601_IRQBASE MOP500_EGPIO_IRQ_END +-#define MOP500_STMPE1601_IRQ(x) (MOP500_STMPE1601_IRQBASE + (x)) +- +-#define MOP500_STMPE1601_IRQ_END \ +- MOP500_STMPE1601_IRQ(STMPE_NR_INTERNAL_IRQS) +- +-#define MOP500_NR_IRQS MOP500_STMPE1601_IRQ_END +- +-#define MOP500_IRQ_END MOP500_NR_IRQS +- +-/* +- * We may have several boards, but only one will run at a +- * time, so the one with most IRQs will bump this ahead, +- * but the IRQ_BOARD_START remains the same for either board. +- */ +-#if MOP500_IRQ_END > IRQ_BOARD_END +-#undef IRQ_BOARD_END +-#define IRQ_BOARD_END MOP500_IRQ_END +-#endif +- +-#endif +diff -Nur linux-3.14.40.orig/arch/arm/mach-ux500/irqs-db8500.h linux-3.14.40/arch/arm/mach-ux500/irqs-db8500.h +--- linux-3.14.40.orig/arch/arm/mach-ux500/irqs-db8500.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-ux500/irqs-db8500.h 1969-12-31 18:00:00.000000000 -0600 +@@ -1,125 +0,0 @@ +-/* +- * Copyright (C) ST-Ericsson SA 2010 +- * +- * Author: Rabin Vincent +- * License terms: GNU General Public License (GPL) version 2 +- */ +- +-#ifndef __MACH_IRQS_DB8500_H +-#define __MACH_IRQS_DB8500_H +- +-#define IRQ_DB8500_MTU0 (IRQ_SHPI_START + 4) +-#define IRQ_DB8500_SPI2 (IRQ_SHPI_START + 6) +-#define IRQ_DB8500_PMU (IRQ_SHPI_START + 7) +-#define IRQ_DB8500_SPI0 (IRQ_SHPI_START + 8) +-#define IRQ_DB8500_RTT (IRQ_SHPI_START + 9) +-#define IRQ_DB8500_PKA (IRQ_SHPI_START + 10) +-#define IRQ_DB8500_UART0 (IRQ_SHPI_START + 11) +-#define IRQ_DB8500_I2C3 (IRQ_SHPI_START + 12) +-#define IRQ_DB8500_L2CC (IRQ_SHPI_START + 13) +-#define IRQ_DB8500_SSP0 (IRQ_SHPI_START + 14) +-#define IRQ_DB8500_CRYP1 (IRQ_SHPI_START + 15) +-#define IRQ_DB8500_MSP1_RX (IRQ_SHPI_START + 16) +-#define IRQ_DB8500_MTU1 (IRQ_SHPI_START + 17) +-#define IRQ_DB8500_RTC (IRQ_SHPI_START + 18) +-#define IRQ_DB8500_UART1 (IRQ_SHPI_START + 19) +-#define IRQ_DB8500_USB_WAKEUP (IRQ_SHPI_START + 20) +-#define IRQ_DB8500_I2C0 (IRQ_SHPI_START + 21) +-#define IRQ_DB8500_I2C1 (IRQ_SHPI_START + 22) +-#define IRQ_DB8500_USBOTG (IRQ_SHPI_START + 23) +-#define IRQ_DB8500_DMA_SECURE (IRQ_SHPI_START + 24) +-#define IRQ_DB8500_DMA (IRQ_SHPI_START + 25) +-#define IRQ_DB8500_UART2 (IRQ_SHPI_START + 26) +-#define IRQ_DB8500_ICN_PMU1 (IRQ_SHPI_START + 27) +-#define IRQ_DB8500_ICN_PMU2 (IRQ_SHPI_START + 28) +-#define IRQ_DB8500_HSIR_EXCEP (IRQ_SHPI_START + 29) +-#define IRQ_DB8500_MSP0 (IRQ_SHPI_START + 31) +-#define IRQ_DB8500_HSIR_CH0_OVRRUN (IRQ_SHPI_START + 32) +-#define IRQ_DB8500_HSIR_CH1_OVRRUN (IRQ_SHPI_START + 33) +-#define IRQ_DB8500_HSIR_CH2_OVRRUN (IRQ_SHPI_START + 34) +-#define IRQ_DB8500_HSIR_CH3_OVRRUN (IRQ_SHPI_START + 35) +-#define IRQ_DB8500_HSIR_CH4_OVRRUN (IRQ_SHPI_START + 36) +-#define IRQ_DB8500_HSIR_CH5_OVRRUN (IRQ_SHPI_START + 37) +-#define IRQ_DB8500_HSIR_CH6_OVRRUN (IRQ_SHPI_START + 38) +-#define IRQ_DB8500_HSIR_CH7_OVRRUN (IRQ_SHPI_START + 39) +-#define IRQ_DB8500_AB8500 (IRQ_SHPI_START + 40) +-#define IRQ_DB8500_SDMMC2 (IRQ_SHPI_START + 41) +-#define IRQ_DB8500_SIA (IRQ_SHPI_START + 42) +-#define IRQ_DB8500_SIA2 (IRQ_SHPI_START + 43) +-#define IRQ_DB8500_SVA (IRQ_SHPI_START + 44) +-#define IRQ_DB8500_SVA2 (IRQ_SHPI_START + 45) +-#define IRQ_DB8500_PRCMU0 (IRQ_SHPI_START + 46) +-#define IRQ_DB8500_PRCMU1 (IRQ_SHPI_START + 47) +-#define IRQ_DB8500_DISP (IRQ_SHPI_START + 48) +-#define IRQ_DB8500_SPI3 (IRQ_SHPI_START + 49) +-#define IRQ_DB8500_SDMMC1 (IRQ_SHPI_START + 50) +-#define IRQ_DB8500_I2C4 (IRQ_SHPI_START + 51) +-#define IRQ_DB8500_SSP1 (IRQ_SHPI_START + 52) +-#define IRQ_DB8500_SKE (IRQ_SHPI_START + 53) +-#define IRQ_DB8500_KB (IRQ_SHPI_START + 54) +-#define IRQ_DB8500_I2C2 (IRQ_SHPI_START + 55) +-#define IRQ_DB8500_B2R2 (IRQ_SHPI_START + 56) +-#define IRQ_DB8500_CRYP0 (IRQ_SHPI_START + 57) +-#define IRQ_DB8500_SDMMC3 (IRQ_SHPI_START + 59) +-#define IRQ_DB8500_SDMMC0 (IRQ_SHPI_START + 60) +-#define IRQ_DB8500_HSEM (IRQ_SHPI_START + 61) +-#define IRQ_DB8500_MSP1 (IRQ_SHPI_START + 62) +-#define IRQ_DB8500_SBAG (IRQ_SHPI_START + 63) +-#define IRQ_DB8500_SPI1 (IRQ_SHPI_START + 96) +-#define IRQ_DB8500_SRPTIMER (IRQ_SHPI_START + 97) +-#define IRQ_DB8500_MSP2 (IRQ_SHPI_START + 98) +-#define IRQ_DB8500_SDMMC4 (IRQ_SHPI_START + 99) +-#define IRQ_DB8500_SDMMC5 (IRQ_SHPI_START + 100) +-#define IRQ_DB8500_HSIRD0 (IRQ_SHPI_START + 104) +-#define IRQ_DB8500_HSIRD1 (IRQ_SHPI_START + 105) +-#define IRQ_DB8500_HSITD0 (IRQ_SHPI_START + 106) +-#define IRQ_DB8500_HSITD1 (IRQ_SHPI_START + 107) +-#define IRQ_DB8500_CTI0 (IRQ_SHPI_START + 108) +-#define IRQ_DB8500_CTI1 (IRQ_SHPI_START + 109) +-#define IRQ_DB8500_ICN_ERR (IRQ_SHPI_START + 110) +-#define IRQ_DB8500_MALI_PPMMU (IRQ_SHPI_START + 112) +-#define IRQ_DB8500_MALI_PP (IRQ_SHPI_START + 113) +-#define IRQ_DB8500_MALI_GPMMU (IRQ_SHPI_START + 114) +-#define IRQ_DB8500_MALI_GP (IRQ_SHPI_START + 115) +-#define IRQ_DB8500_MALI (IRQ_SHPI_START + 116) +-#define IRQ_DB8500_PRCMU_SEM (IRQ_SHPI_START + 118) +-#define IRQ_DB8500_GPIO0 (IRQ_SHPI_START + 119) +-#define IRQ_DB8500_GPIO1 (IRQ_SHPI_START + 120) +-#define IRQ_DB8500_GPIO2 (IRQ_SHPI_START + 121) +-#define IRQ_DB8500_GPIO3 (IRQ_SHPI_START + 122) +-#define IRQ_DB8500_GPIO4 (IRQ_SHPI_START + 123) +-#define IRQ_DB8500_GPIO5 (IRQ_SHPI_START + 124) +-#define IRQ_DB8500_GPIO6 (IRQ_SHPI_START + 125) +-#define IRQ_DB8500_GPIO7 (IRQ_SHPI_START + 126) +-#define IRQ_DB8500_GPIO8 (IRQ_SHPI_START + 127) +- +-#define IRQ_CA_WAKE_REQ_ED (IRQ_SHPI_START + 71) +-#define IRQ_AC_READ_NOTIFICATION_0_ED (IRQ_SHPI_START + 66) +-#define IRQ_AC_READ_NOTIFICATION_1_ED (IRQ_SHPI_START + 64) +-#define IRQ_CA_MSG_PEND_NOTIFICATION_0_ED (IRQ_SHPI_START + 67) +-#define IRQ_CA_MSG_PEND_NOTIFICATION_1_ED (IRQ_SHPI_START + 65) +- +-#define IRQ_CA_WAKE_REQ_V1 (IRQ_SHPI_START + 83) +-#define IRQ_AC_READ_NOTIFICATION_0_V1 (IRQ_SHPI_START + 78) +-#define IRQ_AC_READ_NOTIFICATION_1_V1 (IRQ_SHPI_START + 76) +-#define IRQ_CA_MSG_PEND_NOTIFICATION_0_V1 (IRQ_SHPI_START + 79) +-#define IRQ_CA_MSG_PEND_NOTIFICATION_1_V1 (IRQ_SHPI_START + 77) +- +-#ifdef CONFIG_UX500_SOC_DB8500 +- +-/* Virtual interrupts corresponding to the PRCMU wakeups. */ +-#define IRQ_PRCMU_BASE IRQ_SOC_START +-#define IRQ_PRCMU_END (IRQ_PRCMU_BASE + 23) +- +-/* +- * We may have several SoCs, but only one will run at a +- * time, so the one with most IRQs will bump this ahead, +- * but the IRQ_SOC_START remains the same for either SoC. +- */ +-#if IRQ_SOC_END < IRQ_PRCMU_END +-#undef IRQ_SOC_END +-#define IRQ_SOC_END IRQ_PRCMU_END +-#endif +- +-#endif /* CONFIG_UX500_SOC_DB8500 */ +-#endif +diff -Nur linux-3.14.40.orig/arch/arm/mach-ux500/irqs.h linux-3.14.40/arch/arm/mach-ux500/irqs.h +--- linux-3.14.40.orig/arch/arm/mach-ux500/irqs.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-ux500/irqs.h 1969-12-31 18:00:00.000000000 -0600 +@@ -1,49 +0,0 @@ +-/* +- * Copyright (C) 2008 STMicroelectronics +- * Copyright (C) 2009 ST-Ericsson. +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- */ +-#ifndef ASM_ARCH_IRQS_H +-#define ASM_ARCH_IRQS_H +- +-#define IRQ_LOCALTIMER 29 +-#define IRQ_LOCALWDOG 30 +- +-/* Shared Peripheral Interrupt (SHPI) */ +-#define IRQ_SHPI_START 32 +- +-/* +- * MTU0 preserved for now until plat-nomadik is taught not to use it. Don't +- * add any other IRQs here, use the irqs-dbx500.h files. +- */ +-#define IRQ_MTU0 (IRQ_SHPI_START + 4) +- +-#define DBX500_NR_INTERNAL_IRQS 166 +- +-/* After chip-specific IRQ numbers we have the GPIO ones */ +-#define NOMADIK_NR_GPIO 288 +-#define NOMADIK_GPIO_TO_IRQ(gpio) ((gpio) + DBX500_NR_INTERNAL_IRQS) +-#define NOMADIK_IRQ_TO_GPIO(irq) ((irq) - DBX500_NR_INTERNAL_IRQS) +-#define IRQ_GPIO_END NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO) +- +-#define IRQ_SOC_START IRQ_GPIO_END +-/* This will be overridden by SoC-specific irq headers */ +-#define IRQ_SOC_END IRQ_SOC_START +- +-#include "irqs-db8500.h" +- +-#define IRQ_BOARD_START IRQ_SOC_END +-/* This will be overridden by board-specific irq headers */ +-#define IRQ_BOARD_END IRQ_BOARD_START +- +-#ifdef CONFIG_MACH_MOP500 +-#include "irqs-board-mop500.h" +-#endif +- +-#define UX500_NR_IRQS IRQ_BOARD_END +- +-#endif /* ASM_ARCH_IRQS_H */ +diff -Nur linux-3.14.40.orig/arch/arm/mach-vexpress/ct-ca9x4.c linux-3.14.40/arch/arm/mach-vexpress/ct-ca9x4.c +--- linux-3.14.40.orig/arch/arm/mach-vexpress/ct-ca9x4.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-vexpress/ct-ca9x4.c 2015-05-01 14:57:58.039427001 -0500 +@@ -45,6 +45,23 @@ + iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc)); + } + ++static void __init ca9x4_l2_init(void) ++{ ++#ifdef CONFIG_CACHE_L2X0 ++ void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K); ++ ++ if (l2x0_base) { ++ /* set RAM latencies to 1 cycle for this core tile. */ ++ writel(0, l2x0_base + L310_TAG_LATENCY_CTRL); ++ writel(0, l2x0_base + L310_DATA_LATENCY_CTRL); ++ ++ l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff); ++ } else { ++ pr_err("L2C: unable to map L2 cache controller\n"); ++ } ++#endif ++} ++ + #ifdef CONFIG_HAVE_ARM_TWD + static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, A9_MPCORE_TWD, IRQ_LOCALTIMER); + +@@ -63,6 +80,7 @@ + gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K), + ioremap(A9_MPCORE_GIC_CPU, SZ_256)); + ca9x4_twd_init(); ++ ca9x4_l2_init(); + } + + static int ct_ca9x4_clcd_setup(struct clcd_fb *fb) +@@ -141,16 +159,6 @@ + { + int i; + +-#ifdef CONFIG_CACHE_L2X0 +- void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K); +- +- /* set RAM latencies to 1 cycle for this core tile. */ +- writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL); +- writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL); +- +- l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff); +-#endif +- + for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++) + amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource); + +diff -Nur linux-3.14.40.orig/arch/arm/mach-vexpress/dcscb.c linux-3.14.40/arch/arm/mach-vexpress/dcscb.c +--- linux-3.14.40.orig/arch/arm/mach-vexpress/dcscb.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-vexpress/dcscb.c 2015-05-01 14:57:58.039427001 -0500 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + + #define RST_HOLD0 0x0 +@@ -193,6 +194,12 @@ + 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; + +diff -Nur linux-3.14.40.orig/arch/arm/mach-vexpress/Kconfig linux-3.14.40/arch/arm/mach-vexpress/Kconfig +--- linux-3.14.40.orig/arch/arm/mach-vexpress/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-vexpress/Kconfig 2015-05-01 14:57:58.039427001 -0500 +@@ -55,6 +55,7 @@ + + 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" +diff -Nur linux-3.14.40.orig/arch/arm/mach-vexpress/Makefile linux-3.14.40/arch/arm/mach-vexpress/Makefile +--- linux-3.14.40.orig/arch/arm/mach-vexpress/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-vexpress/Makefile 2015-05-01 14:57:58.039427001 -0500 +@@ -8,8 +8,15 @@ + obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o + obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o + CFLAGS_dcscb.o += -march=armv7-a ++CFLAGS_REMOVE_dcscb.o = -pg + obj-$(CONFIG_ARCH_VEXPRESS_SPC) += spc.o ++CFLAGS_REMOVE_spc.o = -pg + obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o + CFLAGS_tc2_pm.o += -march=armv7-a ++CFLAGS_REMOVE_tc2_pm.o = -pg ++ifeq ($(CONFIG_ARCH_VEXPRESS_TC2_PM),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.14.40.orig/arch/arm/mach-vexpress/spc.c linux-3.14.40/arch/arm/mach-vexpress/spc.c +--- linux-3.14.40.orig/arch/arm/mach-vexpress/spc.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-vexpress/spc.c 2015-05-01 14:57:58.039427001 -0500 +@@ -392,7 +392,7 @@ + * +--------------------------+ + * | 31 20 | 19 0 | + * +--------------------------+ +- * | u_volt | freq(kHz) | ++ * | m_volt | freq(kHz) | + * +--------------------------+ + */ + #define MULT_FACTOR 20 +@@ -414,7 +414,7 @@ + ret = ve_spc_read_sys_cfg(SYSCFG_SCC, off, &data); + if (!ret) { + opps->freq = (data & FREQ_MASK) * MULT_FACTOR; +- opps->u_volt = data >> VOLT_SHIFT; ++ opps->u_volt = (data >> VOLT_SHIFT) * 1000; + } else { + break; + } +diff -Nur linux-3.14.40.orig/arch/arm/mach-vexpress/tc2_pm.c linux-3.14.40/arch/arm/mach-vexpress/tc2_pm.c +--- linux-3.14.40.orig/arch/arm/mach-vexpress/tc2_pm.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-vexpress/tc2_pm.c 2015-05-01 14:57:58.039427001 -0500 +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #include + +@@ -329,6 +330,12 @@ + u32 a15_cluster_id, a7_cluster_id, sys_info; + struct device_node *np; + ++ ret = psci_probe(); ++ if (!ret) { ++ pr_debug("psci found. Aborting native init\n"); ++ return -ENODEV; ++ } ++ + /* + * The power management-related features are hidden behind + * SCC registers. We need to extract runtime information like +diff -Nur linux-3.14.40.orig/arch/arm/mach-vexpress/tc2_pm_psci.c linux-3.14.40/arch/arm/mach-vexpress/tc2_pm_psci.c +--- linux-3.14.40.orig/arch/arm/mach-vexpress/tc2_pm_psci.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mach-vexpress/tc2_pm_psci.c 2015-05-01 14:57:58.039427001 -0500 +@@ -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 ++ ++#define TC2_CLUSTERS 2 ++#define TC2_MAX_CPUS_PER_CLUSTER 3 ++ ++static atomic_t tc2_pm_use_count[TC2_MAX_CPUS_PER_CLUSTER][TC2_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_CLUSTERS || cpu >= TC2_MAX_CPUS_PER_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 (!of_machine_is_compatible("arm,vexpress,v2p-ca15_a7")) ++ 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 using PSCI initialized\n"); ++ return ret; ++} ++ ++early_initcall(tc2_pm_psci_init); +diff -Nur linux-3.14.40.orig/arch/arm/mach-vexpress/v2m.c linux-3.14.40/arch/arm/mach-vexpress/v2m.c +--- linux-3.14.40.orig/arch/arm/mach-vexpress/v2m.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-vexpress/v2m.c 2015-05-01 14:57:58.039427001 -0500 +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -369,6 +370,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), +@@ -421,6 +447,8 @@ + } + + versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), 24000000); ++ ++ v2m_dt_hdlcd_init(); + } + + static const struct of_device_id v2m_dt_bus_match[] __initconst = { +diff -Nur linux-3.14.40.orig/arch/arm/mach-zynq/common.c linux-3.14.40/arch/arm/mach-zynq/common.c +--- linux-3.14.40.orig/arch/arm/mach-zynq/common.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mach-zynq/common.c 2015-05-01 14:57:58.039427001 -0500 +@@ -67,7 +67,7 @@ + /* + * 64KB way size, 8-way associativity, parity disabled + */ +- l2x0_of_init(0x02060000, 0xF0F0FFFF); ++ l2x0_of_init(0x02000000, 0xf0ffffff); + + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + +diff -Nur linux-3.14.40.orig/arch/arm/mm/cache-feroceon-l2.c linux-3.14.40/arch/arm/mm/cache-feroceon-l2.c +--- linux-3.14.40.orig/arch/arm/mm/cache-feroceon-l2.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mm/cache-feroceon-l2.c 2015-05-01 14:57:58.043427001 -0500 +@@ -343,7 +343,6 @@ + outer_cache.inv_range = feroceon_l2_inv_range; + outer_cache.clean_range = feroceon_l2_clean_range; + outer_cache.flush_range = feroceon_l2_flush_range; +- outer_cache.inv_all = l2_inv_all; + + enable_l2(); + +diff -Nur linux-3.14.40.orig/arch/arm/mm/cache-l2x0.c linux-3.14.40/arch/arm/mm/cache-l2x0.c +--- linux-3.14.40.orig/arch/arm/mm/cache-l2x0.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mm/cache-l2x0.c 2015-05-01 14:57:58.043427001 -0500 +@@ -16,18 +16,33 @@ + * 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 "cache-tauros3.h" + #include "cache-aurora-l2.h" + ++struct l2c_init_data { ++ const char *type; ++ unsigned way_size_0; ++ unsigned num_lock; ++ void (*of_parse)(const struct device_node *, u32 *, u32 *); ++ void (*enable)(void __iomem *, u32, unsigned); ++ void (*fixup)(void __iomem *, u32, struct outer_cache_fns *); ++ void (*save)(void __iomem *); ++ struct outer_cache_fns outer_cache; ++}; ++ + #define CACHE_LINE_SIZE 32 + + static void __iomem *l2x0_base; +@@ -36,96 +51,116 @@ + static u32 l2x0_size; + static unsigned long sync_reg_offset = L2X0_CACHE_SYNC; + +-/* Aurora don't have the cache ID register available, so we have to +- * pass it though the device tree */ +-static u32 cache_id_part_number_from_dt; +- + struct l2x0_regs l2x0_saved_regs; + +-struct l2x0_of_data { +- void (*setup)(const struct device_node *, u32 *, u32 *); +- void (*save)(void); +- struct outer_cache_fns outer_cache; +-}; +- +-static bool of_init = false; +- +-static inline void cache_wait_way(void __iomem *reg, unsigned long mask) ++/* ++ * Common code for all cache controllers. ++ */ ++static inline void l2c_wait_mask(void __iomem *reg, unsigned long mask) + { + /* wait for cache operation by line or way to complete */ + while (readl_relaxed(reg) & mask) + cpu_relax(); + } + +-#ifdef CONFIG_CACHE_PL310 +-static inline void cache_wait(void __iomem *reg, unsigned long mask) ++/* ++ * By default, we write directly to secure registers. Platforms must ++ * override this if they are running non-secure. ++ */ ++static void l2c_write_sec(unsigned long val, void __iomem *base, unsigned reg) + { +- /* cache operations by line are atomic on PL310 */ ++ if (val == readl_relaxed(base + reg)) ++ return; ++ if (outer_cache.write_sec) ++ outer_cache.write_sec(val, reg); ++ else ++ writel_relaxed(val, base + reg); + } +-#else +-#define cache_wait cache_wait_way +-#endif + +-static inline void cache_sync(void) ++/* ++ * This should only be called when we have a requirement that the ++ * register be written due to a work-around, as platforms running ++ * in non-secure mode may not be able to access this register. ++ */ ++static inline void l2c_set_debug(void __iomem *base, unsigned long val) + { +- void __iomem *base = l2x0_base; +- +- writel_relaxed(0, base + sync_reg_offset); +- cache_wait(base + L2X0_CACHE_SYNC, 1); ++ l2c_write_sec(val, base, L2X0_DEBUG_CTRL); + } + +-static inline void l2x0_clean_line(unsigned long addr) ++static void __l2c_op_way(void __iomem *reg) + { +- void __iomem *base = l2x0_base; +- cache_wait(base + L2X0_CLEAN_LINE_PA, 1); +- writel_relaxed(addr, base + L2X0_CLEAN_LINE_PA); ++ writel_relaxed(l2x0_way_mask, reg); ++ l2c_wait_mask(reg, l2x0_way_mask); + } + +-static inline void l2x0_inv_line(unsigned long addr) ++static inline void l2c_unlock(void __iomem *base, unsigned num) + { +- void __iomem *base = l2x0_base; +- cache_wait(base + L2X0_INV_LINE_PA, 1); +- writel_relaxed(addr, base + L2X0_INV_LINE_PA); ++ unsigned i; ++ ++ for (i = 0; i < num; i++) { ++ writel_relaxed(0, base + L2X0_LOCKDOWN_WAY_D_BASE + ++ i * L2X0_LOCKDOWN_STRIDE); ++ writel_relaxed(0, base + L2X0_LOCKDOWN_WAY_I_BASE + ++ i * L2X0_LOCKDOWN_STRIDE); ++ } + } + +-#if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) +-static inline void debug_writel(unsigned long val) ++/* ++ * Enable the L2 cache controller. This function must only be ++ * called when the cache controller is known to be disabled. ++ */ ++static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock) + { +- if (outer_cache.set_debug) +- outer_cache.set_debug(val); ++ unsigned long flags; ++ ++ l2c_write_sec(aux, base, L2X0_AUX_CTRL); ++ ++ l2c_unlock(base, num_lock); ++ ++ local_irq_save(flags); ++ __l2c_op_way(base + L2X0_INV_WAY); ++ writel_relaxed(0, base + sync_reg_offset); ++ l2c_wait_mask(base + sync_reg_offset, 1); ++ local_irq_restore(flags); ++ ++ l2c_write_sec(L2X0_CTRL_EN, base, L2X0_CTRL); + } + +-static void pl310_set_debug(unsigned long val) ++static void l2c_disable(void) + { +- writel_relaxed(val, l2x0_base + L2X0_DEBUG_CTRL); ++ void __iomem *base = l2x0_base; ++ ++ outer_cache.flush_all(); ++ l2c_write_sec(0, base, L2X0_CTRL); ++ dsb(st); + } +-#else +-/* Optimised out for non-errata case */ +-static inline void debug_writel(unsigned long val) ++ ++#ifdef CONFIG_CACHE_PL310 ++static inline void cache_wait(void __iomem *reg, unsigned long mask) + { ++ /* cache operations by line are atomic on PL310 */ + } +- +-#define pl310_set_debug NULL ++#else ++#define cache_wait l2c_wait_mask + #endif + +-#ifdef CONFIG_PL310_ERRATA_588369 +-static inline void l2x0_flush_line(unsigned long addr) ++static inline void cache_sync(void) + { + void __iomem *base = l2x0_base; + +- /* Clean by PA followed by Invalidate by PA */ +- cache_wait(base + L2X0_CLEAN_LINE_PA, 1); +- writel_relaxed(addr, base + L2X0_CLEAN_LINE_PA); +- cache_wait(base + L2X0_INV_LINE_PA, 1); +- writel_relaxed(addr, base + L2X0_INV_LINE_PA); ++ writel_relaxed(0, base + sync_reg_offset); ++ cache_wait(base + L2X0_CACHE_SYNC, 1); + } +-#else + +-static inline void l2x0_flush_line(unsigned long addr) ++#if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915) ++static inline void debug_writel(unsigned long val) ++{ ++ l2c_set_debug(l2x0_base, val); ++} ++#else ++/* Optimised out for non-errata case */ ++static inline void debug_writel(unsigned long val) + { +- void __iomem *base = l2x0_base; +- cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); +- writel_relaxed(addr, base + L2X0_CLEAN_INV_LINE_PA); + } + #endif + +@@ -141,8 +176,7 @@ + static void __l2x0_flush_all(void) + { + debug_writel(0x03); +- writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY); +- cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask); ++ __l2c_op_way(l2x0_base + L2X0_CLEAN_INV_WAY); + cache_sync(); + debug_writel(0x00); + } +@@ -157,274 +191,882 @@ + raw_spin_unlock_irqrestore(&l2x0_lock, flags); + } + +-static void l2x0_clean_all(void) ++static void l2x0_disable(void) + { + unsigned long flags; + +- /* clean all ways */ + raw_spin_lock_irqsave(&l2x0_lock, flags); +- writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY); +- cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask); +- cache_sync(); ++ __l2x0_flush_all(); ++ l2c_write_sec(0, l2x0_base, L2X0_CTRL); ++ dsb(st); + raw_spin_unlock_irqrestore(&l2x0_lock, flags); + } + +-static void l2x0_inv_all(void) ++static void l2c_save(void __iomem *base) + { +- unsigned long flags; ++ l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); ++} + +- /* invalidate all ways */ +- raw_spin_lock_irqsave(&l2x0_lock, flags); +- /* Invalidating when L2 is enabled is a nono */ +- BUG_ON(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN); +- writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_INV_WAY); +- cache_wait_way(l2x0_base + L2X0_INV_WAY, l2x0_way_mask); +- cache_sync(); +- raw_spin_unlock_irqrestore(&l2x0_lock, flags); ++/* ++ * L2C-210 specific code. ++ * ++ * The L2C-2x0 PA, set/way and sync operations are atomic, but we must ++ * ensure that no background operation is running. The way operations ++ * are all background tasks. ++ * ++ * While a background operation is in progress, any new operation is ++ * ignored (unspecified whether this causes an error.) Thankfully, not ++ * used on SMP. ++ * ++ * Never has a different sync register other than L2X0_CACHE_SYNC, but ++ * we use sync_reg_offset here so we can share some of this with L2C-310. ++ */ ++static void __l2c210_cache_sync(void __iomem *base) ++{ ++ writel_relaxed(0, base + sync_reg_offset); + } + +-static void l2x0_inv_range(unsigned long start, unsigned long end) ++static void __l2c210_op_pa_range(void __iomem *reg, unsigned long start, ++ unsigned long end) ++{ ++ while (start < end) { ++ writel_relaxed(start, reg); ++ start += CACHE_LINE_SIZE; ++ } ++} ++ ++static void l2c210_inv_range(unsigned long start, unsigned long end) + { + void __iomem *base = l2x0_base; +- unsigned long flags; + +- raw_spin_lock_irqsave(&l2x0_lock, flags); + if (start & (CACHE_LINE_SIZE - 1)) { + start &= ~(CACHE_LINE_SIZE - 1); +- debug_writel(0x03); +- l2x0_flush_line(start); +- debug_writel(0x00); ++ writel_relaxed(start, base + L2X0_CLEAN_INV_LINE_PA); + start += CACHE_LINE_SIZE; + } + + if (end & (CACHE_LINE_SIZE - 1)) { + end &= ~(CACHE_LINE_SIZE - 1); +- debug_writel(0x03); +- l2x0_flush_line(end); +- debug_writel(0x00); ++ writel_relaxed(end, base + L2X0_CLEAN_INV_LINE_PA); + } + ++ __l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end); ++ __l2c210_cache_sync(base); ++} ++ ++static void l2c210_clean_range(unsigned long start, unsigned long end) ++{ ++ void __iomem *base = l2x0_base; ++ ++ start &= ~(CACHE_LINE_SIZE - 1); ++ __l2c210_op_pa_range(base + L2X0_CLEAN_LINE_PA, start, end); ++ __l2c210_cache_sync(base); ++} ++ ++static void l2c210_flush_range(unsigned long start, unsigned long end) ++{ ++ void __iomem *base = l2x0_base; ++ ++ start &= ~(CACHE_LINE_SIZE - 1); ++ __l2c210_op_pa_range(base + L2X0_CLEAN_INV_LINE_PA, start, end); ++ __l2c210_cache_sync(base); ++} ++ ++static void l2c210_flush_all(void) ++{ ++ void __iomem *base = l2x0_base; ++ ++ BUG_ON(!irqs_disabled()); ++ ++ __l2c_op_way(base + L2X0_CLEAN_INV_WAY); ++ __l2c210_cache_sync(base); ++} ++ ++static void l2c210_sync(void) ++{ ++ __l2c210_cache_sync(l2x0_base); ++} ++ ++static void l2c210_resume(void) ++{ ++ void __iomem *base = l2x0_base; ++ ++ if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) ++ l2c_enable(base, l2x0_saved_regs.aux_ctrl, 1); ++} ++ ++static const struct l2c_init_data l2c210_data __initconst = { ++ .type = "L2C-210", ++ .way_size_0 = SZ_8K, ++ .num_lock = 1, ++ .enable = l2c_enable, ++ .save = l2c_save, ++ .outer_cache = { ++ .inv_range = l2c210_inv_range, ++ .clean_range = l2c210_clean_range, ++ .flush_range = l2c210_flush_range, ++ .flush_all = l2c210_flush_all, ++ .disable = l2c_disable, ++ .sync = l2c210_sync, ++ .resume = l2c210_resume, ++ }, ++}; ++ ++/* ++ * L2C-220 specific code. ++ * ++ * All operations are background operations: they have to be waited for. ++ * Conflicting requests generate a slave error (which will cause an ++ * imprecise abort.) Never uses sync_reg_offset, so we hard-code the ++ * sync register here. ++ * ++ * However, we can re-use the l2c210_resume call. ++ */ ++static inline void __l2c220_cache_sync(void __iomem *base) ++{ ++ writel_relaxed(0, base + L2X0_CACHE_SYNC); ++ l2c_wait_mask(base + L2X0_CACHE_SYNC, 1); ++} ++ ++static void l2c220_op_way(void __iomem *base, unsigned reg) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&l2x0_lock, flags); ++ __l2c_op_way(base + reg); ++ __l2c220_cache_sync(base); ++ raw_spin_unlock_irqrestore(&l2x0_lock, flags); ++} ++ ++static unsigned long l2c220_op_pa_range(void __iomem *reg, unsigned long start, ++ unsigned long end, unsigned long flags) ++{ ++ raw_spinlock_t *lock = &l2x0_lock; ++ + while (start < end) { + unsigned long blk_end = start + min(end - start, 4096UL); + + while (start < blk_end) { +- l2x0_inv_line(start); ++ l2c_wait_mask(reg, 1); ++ writel_relaxed(start, reg); + start += CACHE_LINE_SIZE; + } + + if (blk_end < end) { +- raw_spin_unlock_irqrestore(&l2x0_lock, flags); +- raw_spin_lock_irqsave(&l2x0_lock, flags); ++ raw_spin_unlock_irqrestore(lock, flags); ++ raw_spin_lock_irqsave(lock, flags); + } + } +- cache_wait(base + L2X0_INV_LINE_PA, 1); +- cache_sync(); +- raw_spin_unlock_irqrestore(&l2x0_lock, flags); ++ ++ return flags; + } + +-static void l2x0_clean_range(unsigned long start, unsigned long end) ++static void l2c220_inv_range(unsigned long start, unsigned long end) + { + void __iomem *base = l2x0_base; + unsigned long flags; + +- if ((end - start) >= l2x0_size) { +- l2x0_clean_all(); +- return; +- } +- + raw_spin_lock_irqsave(&l2x0_lock, flags); +- start &= ~(CACHE_LINE_SIZE - 1); +- while (start < end) { +- unsigned long blk_end = start + min(end - start, 4096UL); +- +- while (start < blk_end) { +- l2x0_clean_line(start); ++ if ((start | end) & (CACHE_LINE_SIZE - 1)) { ++ if (start & (CACHE_LINE_SIZE - 1)) { ++ start &= ~(CACHE_LINE_SIZE - 1); ++ writel_relaxed(start, base + L2X0_CLEAN_INV_LINE_PA); + start += CACHE_LINE_SIZE; + } + +- if (blk_end < end) { +- raw_spin_unlock_irqrestore(&l2x0_lock, flags); +- raw_spin_lock_irqsave(&l2x0_lock, flags); ++ if (end & (CACHE_LINE_SIZE - 1)) { ++ end &= ~(CACHE_LINE_SIZE - 1); ++ l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1); ++ writel_relaxed(end, base + L2X0_CLEAN_INV_LINE_PA); + } + } +- cache_wait(base + L2X0_CLEAN_LINE_PA, 1); +- cache_sync(); ++ ++ flags = l2c220_op_pa_range(base + L2X0_INV_LINE_PA, ++ start, end, flags); ++ l2c_wait_mask(base + L2X0_INV_LINE_PA, 1); ++ __l2c220_cache_sync(base); + raw_spin_unlock_irqrestore(&l2x0_lock, flags); + } + +-static void l2x0_flush_range(unsigned long start, unsigned long end) ++static void l2c220_clean_range(unsigned long start, unsigned long end) + { + void __iomem *base = l2x0_base; + unsigned long flags; + ++ start &= ~(CACHE_LINE_SIZE - 1); + if ((end - start) >= l2x0_size) { +- l2x0_flush_all(); ++ l2c220_op_way(base, L2X0_CLEAN_WAY); + return; + } + + raw_spin_lock_irqsave(&l2x0_lock, flags); ++ flags = l2c220_op_pa_range(base + L2X0_CLEAN_LINE_PA, ++ start, end, flags); ++ l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1); ++ __l2c220_cache_sync(base); ++ raw_spin_unlock_irqrestore(&l2x0_lock, flags); ++} ++ ++static void l2c220_flush_range(unsigned long start, unsigned long end) ++{ ++ void __iomem *base = l2x0_base; ++ unsigned long flags; ++ + start &= ~(CACHE_LINE_SIZE - 1); ++ if ((end - start) >= l2x0_size) { ++ l2c220_op_way(base, L2X0_CLEAN_INV_WAY); ++ return; ++ } ++ ++ raw_spin_lock_irqsave(&l2x0_lock, flags); ++ flags = l2c220_op_pa_range(base + L2X0_CLEAN_INV_LINE_PA, ++ start, end, flags); ++ l2c_wait_mask(base + L2X0_CLEAN_INV_LINE_PA, 1); ++ __l2c220_cache_sync(base); ++ raw_spin_unlock_irqrestore(&l2x0_lock, flags); ++} ++ ++static void l2c220_flush_all(void) ++{ ++ l2c220_op_way(l2x0_base, L2X0_CLEAN_INV_WAY); ++} ++ ++static void l2c220_sync(void) ++{ ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&l2x0_lock, flags); ++ __l2c220_cache_sync(l2x0_base); ++ raw_spin_unlock_irqrestore(&l2x0_lock, flags); ++} ++ ++static void l2c220_enable(void __iomem *base, u32 aux, unsigned num_lock) ++{ ++ /* ++ * Always enable non-secure access to the lockdown registers - ++ * we write to them as part of the L2C enable sequence so they ++ * need to be accessible. ++ */ ++ aux |= L220_AUX_CTRL_NS_LOCKDOWN; ++ ++ l2c_enable(base, aux, num_lock); ++} ++ ++static const struct l2c_init_data l2c220_data = { ++ .type = "L2C-220", ++ .way_size_0 = SZ_8K, ++ .num_lock = 1, ++ .enable = l2c220_enable, ++ .save = l2c_save, ++ .outer_cache = { ++ .inv_range = l2c220_inv_range, ++ .clean_range = l2c220_clean_range, ++ .flush_range = l2c220_flush_range, ++ .flush_all = l2c220_flush_all, ++ .disable = l2c_disable, ++ .sync = l2c220_sync, ++ .resume = l2c210_resume, ++ }, ++}; ++ ++/* ++ * L2C-310 specific code. ++ * ++ * Very similar to L2C-210, the PA, set/way and sync operations are atomic, ++ * and the way operations are all background tasks. However, issuing an ++ * operation while a background operation is in progress results in a ++ * SLVERR response. We can reuse: ++ * ++ * __l2c210_cache_sync (using sync_reg_offset) ++ * l2c210_sync ++ * l2c210_inv_range (if 588369 is not applicable) ++ * l2c210_clean_range ++ * l2c210_flush_range (if 588369 is not applicable) ++ * l2c210_flush_all (if 727915 is not applicable) ++ * ++ * Errata: ++ * 588369: PL310 R0P0->R1P0, fixed R2P0. ++ * Affects: all clean+invalidate operations ++ * clean and invalidate skips the invalidate step, so we need to issue ++ * separate operations. We also require the above debug workaround ++ * enclosing this code fragment on affected parts. On unaffected parts, ++ * we must not use this workaround without the debug register writes ++ * to avoid exposing a problem similar to 727915. ++ * ++ * 727915: PL310 R2P0->R3P0, fixed R3P1. ++ * Affects: clean+invalidate by way ++ * clean and invalidate by way runs in the background, and a store can ++ * hit the line between the clean operation and invalidate operation, ++ * resulting in the store being lost. ++ * ++ * 752271: PL310 R3P0->R3P1-50REL0, fixed R3P2. ++ * Affects: 8x64-bit (double fill) line fetches ++ * double fill line fetches can fail to cause dirty data to be evicted ++ * from the cache before the new data overwrites the second line. ++ * ++ * 753970: PL310 R3P0, fixed R3P1. ++ * Affects: sync ++ * prevents merging writes after the sync operation, until another L2C ++ * operation is performed (or a number of other conditions.) ++ * ++ * 769419: PL310 R0P0->R3P1, fixed R3P2. ++ * Affects: store buffer ++ * store buffer is not automatically drained. ++ */ ++static void l2c310_inv_range_erratum(unsigned long start, unsigned long end) ++{ ++ void __iomem *base = l2x0_base; ++ ++ if ((start | end) & (CACHE_LINE_SIZE - 1)) { ++ unsigned long flags; ++ ++ /* Erratum 588369 for both clean+invalidate operations */ ++ raw_spin_lock_irqsave(&l2x0_lock, flags); ++ l2c_set_debug(base, 0x03); ++ ++ if (start & (CACHE_LINE_SIZE - 1)) { ++ start &= ~(CACHE_LINE_SIZE - 1); ++ writel_relaxed(start, base + L2X0_CLEAN_LINE_PA); ++ writel_relaxed(start, base + L2X0_INV_LINE_PA); ++ start += CACHE_LINE_SIZE; ++ } ++ ++ if (end & (CACHE_LINE_SIZE - 1)) { ++ end &= ~(CACHE_LINE_SIZE - 1); ++ writel_relaxed(end, base + L2X0_CLEAN_LINE_PA); ++ writel_relaxed(end, base + L2X0_INV_LINE_PA); ++ } ++ ++ l2c_set_debug(base, 0x00); ++ raw_spin_unlock_irqrestore(&l2x0_lock, flags); ++ } ++ ++ __l2c210_op_pa_range(base + L2X0_INV_LINE_PA, start, end); ++ __l2c210_cache_sync(base); ++} ++ ++static void l2c310_flush_range_erratum(unsigned long start, unsigned long end) ++{ ++ raw_spinlock_t *lock = &l2x0_lock; ++ unsigned long flags; ++ void __iomem *base = l2x0_base; ++ ++ raw_spin_lock_irqsave(lock, flags); + while (start < end) { + unsigned long blk_end = start + min(end - start, 4096UL); + +- debug_writel(0x03); ++ l2c_set_debug(base, 0x03); + while (start < blk_end) { +- l2x0_flush_line(start); ++ writel_relaxed(start, base + L2X0_CLEAN_LINE_PA); ++ writel_relaxed(start, base + L2X0_INV_LINE_PA); + start += CACHE_LINE_SIZE; + } +- debug_writel(0x00); ++ l2c_set_debug(base, 0x00); + + if (blk_end < end) { +- raw_spin_unlock_irqrestore(&l2x0_lock, flags); +- raw_spin_lock_irqsave(&l2x0_lock, flags); ++ raw_spin_unlock_irqrestore(lock, flags); ++ raw_spin_lock_irqsave(lock, flags); + } + } +- cache_wait(base + L2X0_CLEAN_INV_LINE_PA, 1); +- cache_sync(); +- raw_spin_unlock_irqrestore(&l2x0_lock, flags); ++ raw_spin_unlock_irqrestore(lock, flags); ++ __l2c210_cache_sync(base); + } + +-static void l2x0_disable(void) ++static void l2c310_flush_all_erratum(void) + { ++ void __iomem *base = l2x0_base; + unsigned long flags; + + raw_spin_lock_irqsave(&l2x0_lock, flags); +- __l2x0_flush_all(); +- writel_relaxed(0, l2x0_base + L2X0_CTRL); +- dsb(st); ++ l2c_set_debug(base, 0x03); ++ __l2c_op_way(base + L2X0_CLEAN_INV_WAY); ++ l2c_set_debug(base, 0x00); ++ __l2c210_cache_sync(base); + raw_spin_unlock_irqrestore(&l2x0_lock, flags); + } + +-static void l2x0_unlock(u32 cache_id) ++static void __init l2c310_save(void __iomem *base) + { +- int lockregs; +- int i; ++ unsigned revision; + +- switch (cache_id & L2X0_CACHE_ID_PART_MASK) { +- case L2X0_CACHE_ID_PART_L310: +- lockregs = 8; +- break; +- case AURORA_CACHE_ID: +- lockregs = 4; ++ l2c_save(base); ++ ++ l2x0_saved_regs.tag_latency = readl_relaxed(base + ++ L310_TAG_LATENCY_CTRL); ++ l2x0_saved_regs.data_latency = readl_relaxed(base + ++ L310_DATA_LATENCY_CTRL); ++ l2x0_saved_regs.filter_end = readl_relaxed(base + ++ L310_ADDR_FILTER_END); ++ l2x0_saved_regs.filter_start = readl_relaxed(base + ++ L310_ADDR_FILTER_START); ++ ++ revision = readl_relaxed(base + L2X0_CACHE_ID) & ++ L2X0_CACHE_ID_RTL_MASK; ++ ++ /* From r2p0, there is Prefetch offset/control register */ ++ if (revision >= L310_CACHE_ID_RTL_R2P0) ++ l2x0_saved_regs.prefetch_ctrl = readl_relaxed(base + ++ L310_PREFETCH_CTRL); ++ ++ /* From r3p0, there is Power control register */ ++ if (revision >= L310_CACHE_ID_RTL_R3P0) ++ l2x0_saved_regs.pwr_ctrl = readl_relaxed(base + ++ L310_POWER_CTRL); ++} ++ ++static void l2c310_resume(void) ++{ ++ void __iomem *base = l2x0_base; ++ ++ if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) { ++ unsigned revision; ++ ++ /* restore pl310 setup */ ++ writel_relaxed(l2x0_saved_regs.tag_latency, ++ base + L310_TAG_LATENCY_CTRL); ++ writel_relaxed(l2x0_saved_regs.data_latency, ++ base + L310_DATA_LATENCY_CTRL); ++ writel_relaxed(l2x0_saved_regs.filter_end, ++ base + L310_ADDR_FILTER_END); ++ writel_relaxed(l2x0_saved_regs.filter_start, ++ base + L310_ADDR_FILTER_START); ++ ++ revision = readl_relaxed(base + L2X0_CACHE_ID) & ++ L2X0_CACHE_ID_RTL_MASK; ++ ++ if (revision >= L310_CACHE_ID_RTL_R2P0) ++ l2c_write_sec(l2x0_saved_regs.prefetch_ctrl, base, ++ L310_PREFETCH_CTRL); ++ if (revision >= L310_CACHE_ID_RTL_R3P0) ++ l2c_write_sec(l2x0_saved_regs.pwr_ctrl, base, ++ L310_POWER_CTRL); ++ ++ l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8); ++ ++ /* Re-enable full-line-of-zeros for Cortex-A9 */ ++ if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO) ++ set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); ++ } ++} ++ ++static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, void *data) ++{ ++ switch (act & ~CPU_TASKS_FROZEN) { ++ case CPU_STARTING: ++ set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); + break; +- default: +- /* L210 and unknown types */ +- lockregs = 1; ++ case CPU_DYING: ++ set_auxcr(get_auxcr() & ~(BIT(3) | BIT(2) | BIT(1))); + break; + } ++ return NOTIFY_OK; ++} + +- for (i = 0; i < lockregs; i++) { +- writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE + +- i * L2X0_LOCKDOWN_STRIDE); +- writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE + +- i * L2X0_LOCKDOWN_STRIDE); ++static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock) ++{ ++ unsigned rev = readl_relaxed(base + L2X0_CACHE_ID) & L2X0_CACHE_ID_PART_MASK; ++ bool cortex_a9 = read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9; ++ ++ if (rev >= L310_CACHE_ID_RTL_R2P0) { ++ if (cortex_a9) { ++ aux |= L310_AUX_CTRL_EARLY_BRESP; ++ pr_info("L2C-310 enabling early BRESP for Cortex-A9\n"); ++ } else if (aux & L310_AUX_CTRL_EARLY_BRESP) { ++ pr_warn("L2C-310 early BRESP only supported with Cortex-A9\n"); ++ aux &= ~L310_AUX_CTRL_EARLY_BRESP; ++ } ++ } ++ ++ if (cortex_a9) { ++ u32 aux_cur = readl_relaxed(base + L2X0_AUX_CTRL); ++ u32 acr = get_auxcr(); ++ ++ pr_debug("Cortex-A9 ACR=0x%08x\n", acr); ++ ++ if (acr & BIT(3) && !(aux_cur & L310_AUX_CTRL_FULL_LINE_ZERO)) ++ pr_err("L2C-310: full line of zeros enabled in Cortex-A9 but not L2C-310 - invalid\n"); ++ ++ if (aux & L310_AUX_CTRL_FULL_LINE_ZERO && !(acr & BIT(3))) ++ pr_err("L2C-310: enabling full line of zeros but not enabled in Cortex-A9\n"); ++ ++ if (!(aux & L310_AUX_CTRL_FULL_LINE_ZERO) && !outer_cache.write_sec) { ++ aux |= L310_AUX_CTRL_FULL_LINE_ZERO; ++ pr_info("L2C-310 full line of zeros enabled for Cortex-A9\n"); ++ } ++ } else if (aux & (L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP)) { ++ pr_err("L2C-310: disabling Cortex-A9 specific feature bits\n"); ++ aux &= ~(L310_AUX_CTRL_FULL_LINE_ZERO | L310_AUX_CTRL_EARLY_BRESP); ++ } ++ ++ if (aux & (L310_AUX_CTRL_DATA_PREFETCH | L310_AUX_CTRL_INSTR_PREFETCH)) { ++ u32 prefetch = readl_relaxed(base + L310_PREFETCH_CTRL); ++ ++ pr_info("L2C-310 %s%s prefetch enabled, offset %u lines\n", ++ aux & L310_AUX_CTRL_INSTR_PREFETCH ? "I" : "", ++ aux & L310_AUX_CTRL_DATA_PREFETCH ? "D" : "", ++ 1 + (prefetch & L310_PREFETCH_CTRL_OFFSET_MASK)); ++ } ++ ++ /* r3p0 or later has power control register */ ++ if (rev >= L310_CACHE_ID_RTL_R3P0) { ++ u32 power_ctrl; ++ ++ l2c_write_sec(L310_DYNAMIC_CLK_GATING_EN | L310_STNDBY_MODE_EN, ++ base, L310_POWER_CTRL); ++ power_ctrl = readl_relaxed(base + L310_POWER_CTRL); ++ pr_info("L2C-310 dynamic clock gating %sabled, standby mode %sabled\n", ++ power_ctrl & L310_DYNAMIC_CLK_GATING_EN ? "en" : "dis", ++ power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis"); ++ } ++ ++ /* ++ * Always enable non-secure access to the lockdown registers - ++ * we write to them as part of the L2C enable sequence so they ++ * need to be accessible. ++ */ ++ aux |= L310_AUX_CTRL_NS_LOCKDOWN; ++ ++ l2c_enable(base, aux, num_lock); ++ ++ if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) { ++ set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1)); ++ cpu_notifier(l2c310_cpu_enable_flz, 0); + } + } + +-void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) ++static void __init l2c310_fixup(void __iomem *base, u32 cache_id, ++ struct outer_cache_fns *fns) + { +- u32 aux; +- u32 cache_id; +- u32 way_size = 0; +- int ways; +- int way_size_shift = L2X0_WAY_SIZE_SHIFT; +- const char *type; ++ unsigned revision = cache_id & L2X0_CACHE_ID_RTL_MASK; ++ const char *errata[8]; ++ unsigned n = 0; + +- l2x0_base = base; +- if (cache_id_part_number_from_dt) +- cache_id = cache_id_part_number_from_dt; +- else +- cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); +- aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); ++ if (IS_ENABLED(CONFIG_PL310_ERRATA_588369) && ++ revision < L310_CACHE_ID_RTL_R2P0 && ++ /* For bcm compatibility */ ++ fns->inv_range == l2c210_inv_range) { ++ fns->inv_range = l2c310_inv_range_erratum; ++ fns->flush_range = l2c310_flush_range_erratum; ++ errata[n++] = "588369"; ++ } ++ ++ if (IS_ENABLED(CONFIG_PL310_ERRATA_727915) && ++ revision >= L310_CACHE_ID_RTL_R2P0 && ++ revision < L310_CACHE_ID_RTL_R3P1) { ++ fns->flush_all = l2c310_flush_all_erratum; ++ errata[n++] = "727915"; ++ } ++ ++ if (revision >= L310_CACHE_ID_RTL_R3P0 && ++ revision < L310_CACHE_ID_RTL_R3P2) { ++ u32 val = readl_relaxed(base + L310_PREFETCH_CTRL); ++ /* I don't think bit23 is required here... but iMX6 does so */ ++ if (val & (BIT(30) | BIT(23))) { ++ val &= ~(BIT(30) | BIT(23)); ++ l2c_write_sec(val, base, L310_PREFETCH_CTRL); ++ errata[n++] = "752271"; ++ } ++ } ++ ++ if (IS_ENABLED(CONFIG_PL310_ERRATA_753970) && ++ revision == L310_CACHE_ID_RTL_R3P0) { ++ sync_reg_offset = L2X0_DUMMY_REG; ++ errata[n++] = "753970"; ++ } ++ ++ if (IS_ENABLED(CONFIG_PL310_ERRATA_769419)) ++ errata[n++] = "769419"; ++ ++ if (n) { ++ unsigned i; ++ ++ pr_info("L2C-310 errat%s", n > 1 ? "a" : "um"); ++ for (i = 0; i < n; i++) ++ pr_cont(" %s", errata[i]); ++ pr_cont(" enabled\n"); ++ } ++} ++ ++static void l2c310_disable(void) ++{ ++ /* ++ * If full-line-of-zeros is enabled, we must first disable it in the ++ * Cortex-A9 auxiliary control register before disabling the L2 cache. ++ */ ++ if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_FULL_LINE_ZERO) ++ set_auxcr(get_auxcr() & ~(BIT(3) | BIT(2) | BIT(1))); + ++ l2c_disable(); ++} ++ ++static const struct l2c_init_data l2c310_init_fns __initconst = { ++ .type = "L2C-310", ++ .way_size_0 = SZ_8K, ++ .num_lock = 8, ++ .enable = l2c310_enable, ++ .fixup = l2c310_fixup, ++ .save = l2c310_save, ++ .outer_cache = { ++ .inv_range = l2c210_inv_range, ++ .clean_range = l2c210_clean_range, ++ .flush_range = l2c210_flush_range, ++ .flush_all = l2c210_flush_all, ++ .disable = l2c310_disable, ++ .sync = l2c210_sync, ++ .resume = l2c310_resume, ++ }, ++}; ++ ++static void __init __l2c_init(const struct l2c_init_data *data, ++ u32 aux_val, u32 aux_mask, u32 cache_id) ++{ ++ struct outer_cache_fns fns; ++ unsigned way_size_bits, ways; ++ u32 aux, old_aux; ++ ++ /* ++ * Sanity check the aux values. aux_mask is the bits we preserve ++ * from reading the hardware register, and aux_val is the bits we ++ * set. ++ */ ++ if (aux_val & aux_mask) ++ pr_alert("L2C: platform provided aux values permit register corruption.\n"); ++ ++ old_aux = aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); + aux &= aux_mask; + aux |= aux_val; + ++ if (old_aux != aux) ++ pr_warn("L2C: DT/platform modifies aux control register: 0x%08x -> 0x%08x\n", ++ old_aux, aux); ++ + /* Determine the number of ways */ + switch (cache_id & L2X0_CACHE_ID_PART_MASK) { + case L2X0_CACHE_ID_PART_L310: ++ if ((aux_val | ~aux_mask) & (L2C_AUX_CTRL_WAY_SIZE_MASK | L310_AUX_CTRL_ASSOCIATIVITY_16)) ++ pr_warn("L2C: DT/platform tries to modify or specify cache size\n"); + if (aux & (1 << 16)) + ways = 16; + else + ways = 8; +- type = "L310"; +-#ifdef CONFIG_PL310_ERRATA_753970 +- /* Unmapped register. */ +- sync_reg_offset = L2X0_DUMMY_REG; +-#endif +- if ((cache_id & L2X0_CACHE_ID_RTL_MASK) <= L2X0_CACHE_ID_RTL_R3P0) +- outer_cache.set_debug = pl310_set_debug; + break; ++ + case L2X0_CACHE_ID_PART_L210: ++ case L2X0_CACHE_ID_PART_L220: + ways = (aux >> 13) & 0xf; +- type = "L210"; + break; + + case AURORA_CACHE_ID: +- sync_reg_offset = AURORA_SYNC_REG; + ways = (aux >> 13) & 0xf; + ways = 2 << ((ways + 1) >> 2); +- way_size_shift = AURORA_WAY_SIZE_SHIFT; +- type = "Aurora"; + break; ++ + default: + /* Assume unknown chips have 8 ways */ + ways = 8; +- type = "L2x0 series"; + break; + } + + l2x0_way_mask = (1 << ways) - 1; + + /* +- * L2 cache Size = Way size * Number of ways ++ * way_size_0 is the size that a way_size value of zero would be ++ * given the calculation: way_size = way_size_0 << way_size_bits. ++ * So, if way_size_bits=0 is reserved, but way_size_bits=1 is 16k, ++ * then way_size_0 would be 8k. ++ * ++ * L2 cache size = number of ways * way size. ++ */ ++ way_size_bits = (aux & L2C_AUX_CTRL_WAY_SIZE_MASK) >> ++ L2C_AUX_CTRL_WAY_SIZE_SHIFT; ++ l2x0_size = ways * (data->way_size_0 << way_size_bits); ++ ++ fns = data->outer_cache; ++ fns.write_sec = outer_cache.write_sec; ++ if (data->fixup) ++ data->fixup(l2x0_base, cache_id, &fns); ++ ++ /* ++ * Check if l2x0 controller is already enabled. If we are booting ++ * in non-secure mode accessing the below registers will fault. + */ +- way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17; +- way_size = 1 << (way_size + way_size_shift); ++ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) ++ data->enable(l2x0_base, aux, data->num_lock); + +- l2x0_size = ways * way_size * SZ_1K; ++ outer_cache = fns; + + /* +- * Check if l2x0 controller is already enabled. +- * If you are booting from non-secure mode +- * accessing the below registers will fault. ++ * It is strange to save the register state before initialisation, ++ * but hey, this is what the DT implementations decided to do. + */ +- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { +- /* Make sure that I&D is not locked down when starting */ +- l2x0_unlock(cache_id); ++ if (data->save) ++ data->save(l2x0_base); ++ ++ /* Re-read it in case some bits are reserved. */ ++ aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); ++ ++ pr_info("%s cache controller enabled, %d ways, %d kB\n", ++ data->type, ways, l2x0_size >> 10); ++ pr_info("%s: CACHE_ID 0x%08x, AUX_CTRL 0x%08x\n", ++ data->type, cache_id, aux); ++} + +- /* l2x0 controller is disabled */ +- writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL); ++void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask) ++{ ++ const struct l2c_init_data *data; ++ u32 cache_id; + +- l2x0_inv_all(); ++ l2x0_base = base; + +- /* enable L2X0 */ +- writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL); ++ cache_id = readl_relaxed(base + L2X0_CACHE_ID); ++ ++ switch (cache_id & L2X0_CACHE_ID_PART_MASK) { ++ default: ++ case L2X0_CACHE_ID_PART_L210: ++ data = &l2c210_data; ++ break; ++ ++ case L2X0_CACHE_ID_PART_L220: ++ data = &l2c220_data; ++ break; ++ ++ case L2X0_CACHE_ID_PART_L310: ++ data = &l2c310_init_fns; ++ break; + } + +- /* Re-read it in case some bits are reserved. */ +- aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); ++ __l2c_init(data, aux_val, aux_mask, cache_id); ++} ++ ++#ifdef CONFIG_OF ++static int l2_wt_override; ++ ++/* Aurora don't have the cache ID register available, so we have to ++ * pass it though the device tree */ ++static u32 cache_id_part_number_from_dt; ++ ++static void __init l2x0_of_parse(const struct device_node *np, ++ u32 *aux_val, u32 *aux_mask) ++{ ++ u32 data[2] = { 0, 0 }; ++ u32 tag = 0; ++ u32 dirty = 0; ++ u32 val = 0, mask = 0; ++ ++ of_property_read_u32(np, "arm,tag-latency", &tag); ++ if (tag) { ++ mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK; ++ val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT; ++ } ++ ++ of_property_read_u32_array(np, "arm,data-latency", ++ data, ARRAY_SIZE(data)); ++ if (data[0] && data[1]) { ++ mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK | ++ L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK; ++ val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) | ++ ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT); ++ } ++ ++ of_property_read_u32(np, "arm,dirty-latency", &dirty); ++ if (dirty) { ++ mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK; ++ val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT; ++ } + +- /* Save the value for resuming. */ +- l2x0_saved_regs.aux_ctrl = aux; ++ *aux_val &= ~mask; ++ *aux_val |= val; ++ *aux_mask &= ~mask; ++} ++ ++static const struct l2c_init_data of_l2c210_data __initconst = { ++ .type = "L2C-210", ++ .way_size_0 = SZ_8K, ++ .num_lock = 1, ++ .of_parse = l2x0_of_parse, ++ .enable = l2c_enable, ++ .save = l2c_save, ++ .outer_cache = { ++ .inv_range = l2c210_inv_range, ++ .clean_range = l2c210_clean_range, ++ .flush_range = l2c210_flush_range, ++ .flush_all = l2c210_flush_all, ++ .disable = l2c_disable, ++ .sync = l2c210_sync, ++ .resume = l2c210_resume, ++ }, ++}; ++ ++static const struct l2c_init_data of_l2c220_data __initconst = { ++ .type = "L2C-220", ++ .way_size_0 = SZ_8K, ++ .num_lock = 1, ++ .of_parse = l2x0_of_parse, ++ .enable = l2c220_enable, ++ .save = l2c_save, ++ .outer_cache = { ++ .inv_range = l2c220_inv_range, ++ .clean_range = l2c220_clean_range, ++ .flush_range = l2c220_flush_range, ++ .flush_all = l2c220_flush_all, ++ .disable = l2c_disable, ++ .sync = l2c220_sync, ++ .resume = l2c210_resume, ++ }, ++}; ++ ++static void __init l2c310_of_parse(const struct device_node *np, ++ u32 *aux_val, u32 *aux_mask) ++{ ++ u32 data[3] = { 0, 0, 0 }; ++ u32 tag[3] = { 0, 0, 0 }; ++ u32 filter[2] = { 0, 0 }; ++ ++ of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); ++ if (tag[0] && tag[1] && tag[2]) ++ writel_relaxed( ++ L310_LATENCY_CTRL_RD(tag[0] - 1) | ++ L310_LATENCY_CTRL_WR(tag[1] - 1) | ++ L310_LATENCY_CTRL_SETUP(tag[2] - 1), ++ l2x0_base + L310_TAG_LATENCY_CTRL); ++ ++ of_property_read_u32_array(np, "arm,data-latency", ++ data, ARRAY_SIZE(data)); ++ if (data[0] && data[1] && data[2]) ++ writel_relaxed( ++ L310_LATENCY_CTRL_RD(data[0] - 1) | ++ L310_LATENCY_CTRL_WR(data[1] - 1) | ++ L310_LATENCY_CTRL_SETUP(data[2] - 1), ++ l2x0_base + L310_DATA_LATENCY_CTRL); + +- if (!of_init) { +- outer_cache.inv_range = l2x0_inv_range; +- outer_cache.clean_range = l2x0_clean_range; +- outer_cache.flush_range = l2x0_flush_range; +- outer_cache.sync = l2x0_cache_sync; +- outer_cache.flush_all = l2x0_flush_all; +- outer_cache.inv_all = l2x0_inv_all; +- outer_cache.disable = l2x0_disable; +- } +- +- pr_info("%s cache controller enabled\n", type); +- pr_info("l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d kB\n", +- ways, cache_id, aux, l2x0_size >> 10); ++ of_property_read_u32_array(np, "arm,filter-ranges", ++ filter, ARRAY_SIZE(filter)); ++ if (filter[1]) { ++ writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M), ++ l2x0_base + L310_ADDR_FILTER_END); ++ writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L310_ADDR_FILTER_EN, ++ l2x0_base + L310_ADDR_FILTER_START); ++ } + } + +-#ifdef CONFIG_OF +-static int l2_wt_override; ++static const struct l2c_init_data of_l2c310_data __initconst = { ++ .type = "L2C-310", ++ .way_size_0 = SZ_8K, ++ .num_lock = 8, ++ .of_parse = l2c310_of_parse, ++ .enable = l2c310_enable, ++ .fixup = l2c310_fixup, ++ .save = l2c310_save, ++ .outer_cache = { ++ .inv_range = l2c210_inv_range, ++ .clean_range = l2c210_clean_range, ++ .flush_range = l2c210_flush_range, ++ .flush_all = l2c210_flush_all, ++ .disable = l2c310_disable, ++ .sync = l2c210_sync, ++ .resume = l2c310_resume, ++ }, ++}; + + /* + * Note that the end addresses passed to Linux primitives are +@@ -524,6 +1166,100 @@ + } + } + ++static void aurora_save(void __iomem *base) ++{ ++ l2x0_saved_regs.ctrl = readl_relaxed(base + L2X0_CTRL); ++ l2x0_saved_regs.aux_ctrl = readl_relaxed(base + L2X0_AUX_CTRL); ++} ++ ++static void aurora_resume(void) ++{ ++ void __iomem *base = l2x0_base; ++ ++ if (!(readl(base + L2X0_CTRL) & L2X0_CTRL_EN)) { ++ writel_relaxed(l2x0_saved_regs.aux_ctrl, base + L2X0_AUX_CTRL); ++ writel_relaxed(l2x0_saved_regs.ctrl, base + L2X0_CTRL); ++ } ++} ++ ++/* ++ * For Aurora cache in no outer mode, enable via the CP15 coprocessor ++ * broadcasting of cache commands to L2. ++ */ ++static void __init aurora_enable_no_outer(void __iomem *base, u32 aux, ++ unsigned num_lock) ++{ ++ u32 u; ++ ++ asm volatile("mrc p15, 1, %0, c15, c2, 0" : "=r" (u)); ++ u |= AURORA_CTRL_FW; /* Set the FW bit */ ++ asm volatile("mcr p15, 1, %0, c15, c2, 0" : : "r" (u)); ++ ++ isb(); ++ ++ l2c_enable(base, aux, num_lock); ++} ++ ++static void __init aurora_fixup(void __iomem *base, u32 cache_id, ++ struct outer_cache_fns *fns) ++{ ++ sync_reg_offset = AURORA_SYNC_REG; ++} ++ ++static void __init aurora_of_parse(const struct device_node *np, ++ u32 *aux_val, u32 *aux_mask) ++{ ++ u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU; ++ u32 mask = AURORA_ACR_REPLACEMENT_MASK; ++ ++ of_property_read_u32(np, "cache-id-part", ++ &cache_id_part_number_from_dt); ++ ++ /* Determine and save the write policy */ ++ l2_wt_override = of_property_read_bool(np, "wt-override"); ++ ++ if (l2_wt_override) { ++ val |= AURORA_ACR_FORCE_WRITE_THRO_POLICY; ++ mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK; ++ } ++ ++ *aux_val &= ~mask; ++ *aux_val |= val; ++ *aux_mask &= ~mask; ++} ++ ++static const struct l2c_init_data of_aurora_with_outer_data __initconst = { ++ .type = "Aurora", ++ .way_size_0 = SZ_4K, ++ .num_lock = 4, ++ .of_parse = aurora_of_parse, ++ .enable = l2c_enable, ++ .fixup = aurora_fixup, ++ .save = aurora_save, ++ .outer_cache = { ++ .inv_range = aurora_inv_range, ++ .clean_range = aurora_clean_range, ++ .flush_range = aurora_flush_range, ++ .flush_all = l2x0_flush_all, ++ .disable = l2x0_disable, ++ .sync = l2x0_cache_sync, ++ .resume = aurora_resume, ++ }, ++}; ++ ++static const struct l2c_init_data of_aurora_no_outer_data __initconst = { ++ .type = "Aurora", ++ .way_size_0 = SZ_4K, ++ .num_lock = 4, ++ .of_parse = aurora_of_parse, ++ .enable = aurora_enable_no_outer, ++ .fixup = aurora_fixup, ++ .save = aurora_save, ++ .outer_cache = { ++ .resume = aurora_resume, ++ }, ++}; ++ + /* + * For certain Broadcom SoCs, depending on the address range, different offsets + * need to be added to the address before passing it to L2 for +@@ -588,16 +1324,16 @@ + + /* normal case, no cross section between start and end */ + if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) { +- l2x0_inv_range(new_start, new_end); ++ l2c210_inv_range(new_start, new_end); + return; + } + + /* They cross sections, so it can only be a cross from section + * 2 to section 3 + */ +- l2x0_inv_range(new_start, ++ l2c210_inv_range(new_start, + bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1)); +- l2x0_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), ++ l2c210_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), + new_end); + } + +@@ -610,26 +1346,21 @@ + if (unlikely(end <= start)) + return; + +- if ((end - start) >= l2x0_size) { +- l2x0_clean_all(); +- return; +- } +- + new_start = bcm_l2_phys_addr(start); + new_end = bcm_l2_phys_addr(end); + + /* normal case, no cross section between start and end */ + if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) { +- l2x0_clean_range(new_start, new_end); ++ l2c210_clean_range(new_start, new_end); + return; + } + + /* They cross sections, so it can only be a cross from section + * 2 to section 3 + */ +- l2x0_clean_range(new_start, ++ l2c210_clean_range(new_start, + bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1)); +- l2x0_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), ++ l2c210_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), + new_end); + } + +@@ -643,7 +1374,7 @@ + return; + + if ((end - start) >= l2x0_size) { +- l2x0_flush_all(); ++ outer_cache.flush_all(); + return; + } + +@@ -652,283 +1383,67 @@ + + /* normal case, no cross section between start and end */ + if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) { +- l2x0_flush_range(new_start, new_end); ++ l2c210_flush_range(new_start, new_end); + return; + } + + /* They cross sections, so it can only be a cross from section + * 2 to section 3 + */ +- l2x0_flush_range(new_start, ++ l2c210_flush_range(new_start, + bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1)); +- l2x0_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), ++ l2c210_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR), + new_end); + } + +-static void __init l2x0_of_setup(const struct device_node *np, +- u32 *aux_val, u32 *aux_mask) +-{ +- u32 data[2] = { 0, 0 }; +- u32 tag = 0; +- u32 dirty = 0; +- u32 val = 0, mask = 0; +- +- of_property_read_u32(np, "arm,tag-latency", &tag); +- if (tag) { +- mask |= L2X0_AUX_CTRL_TAG_LATENCY_MASK; +- val |= (tag - 1) << L2X0_AUX_CTRL_TAG_LATENCY_SHIFT; +- } +- +- of_property_read_u32_array(np, "arm,data-latency", +- data, ARRAY_SIZE(data)); +- if (data[0] && data[1]) { +- mask |= L2X0_AUX_CTRL_DATA_RD_LATENCY_MASK | +- L2X0_AUX_CTRL_DATA_WR_LATENCY_MASK; +- val |= ((data[0] - 1) << L2X0_AUX_CTRL_DATA_RD_LATENCY_SHIFT) | +- ((data[1] - 1) << L2X0_AUX_CTRL_DATA_WR_LATENCY_SHIFT); +- } +- +- of_property_read_u32(np, "arm,dirty-latency", &dirty); +- if (dirty) { +- mask |= L2X0_AUX_CTRL_DIRTY_LATENCY_MASK; +- val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT; +- } +- +- *aux_val &= ~mask; +- *aux_val |= val; +- *aux_mask &= ~mask; +-} +- +-static void __init pl310_of_setup(const struct device_node *np, +- u32 *aux_val, u32 *aux_mask) +-{ +- u32 data[3] = { 0, 0, 0 }; +- u32 tag[3] = { 0, 0, 0 }; +- u32 filter[2] = { 0, 0 }; +- +- of_property_read_u32_array(np, "arm,tag-latency", tag, ARRAY_SIZE(tag)); +- if (tag[0] && tag[1] && tag[2]) +- writel_relaxed( +- ((tag[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) | +- ((tag[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) | +- ((tag[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT), +- l2x0_base + L2X0_TAG_LATENCY_CTRL); +- +- of_property_read_u32_array(np, "arm,data-latency", +- data, ARRAY_SIZE(data)); +- if (data[0] && data[1] && data[2]) +- writel_relaxed( +- ((data[0] - 1) << L2X0_LATENCY_CTRL_RD_SHIFT) | +- ((data[1] - 1) << L2X0_LATENCY_CTRL_WR_SHIFT) | +- ((data[2] - 1) << L2X0_LATENCY_CTRL_SETUP_SHIFT), +- l2x0_base + L2X0_DATA_LATENCY_CTRL); +- +- of_property_read_u32_array(np, "arm,filter-ranges", +- filter, ARRAY_SIZE(filter)); +- if (filter[1]) { +- writel_relaxed(ALIGN(filter[0] + filter[1], SZ_1M), +- l2x0_base + L2X0_ADDR_FILTER_END); +- writel_relaxed((filter[0] & ~(SZ_1M - 1)) | L2X0_ADDR_FILTER_EN, +- l2x0_base + L2X0_ADDR_FILTER_START); +- } +-} +- +-static void __init pl310_save(void) +-{ +- u32 l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) & +- L2X0_CACHE_ID_RTL_MASK; +- +- l2x0_saved_regs.tag_latency = readl_relaxed(l2x0_base + +- L2X0_TAG_LATENCY_CTRL); +- l2x0_saved_regs.data_latency = readl_relaxed(l2x0_base + +- L2X0_DATA_LATENCY_CTRL); +- l2x0_saved_regs.filter_end = readl_relaxed(l2x0_base + +- L2X0_ADDR_FILTER_END); +- l2x0_saved_regs.filter_start = readl_relaxed(l2x0_base + +- L2X0_ADDR_FILTER_START); +- +- if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) { +- /* +- * From r2p0, there is Prefetch offset/control register +- */ +- l2x0_saved_regs.prefetch_ctrl = readl_relaxed(l2x0_base + +- L2X0_PREFETCH_CTRL); +- /* +- * From r3p0, there is Power control register +- */ +- if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0) +- l2x0_saved_regs.pwr_ctrl = readl_relaxed(l2x0_base + +- L2X0_POWER_CTRL); +- } +-} ++/* Broadcom L2C-310 start from ARMs R3P2 or later, and require no fixups */ ++static const struct l2c_init_data of_bcm_l2x0_data __initconst = { ++ .type = "BCM-L2C-310", ++ .way_size_0 = SZ_8K, ++ .num_lock = 8, ++ .of_parse = l2c310_of_parse, ++ .enable = l2c310_enable, ++ .save = l2c310_save, ++ .outer_cache = { ++ .inv_range = bcm_inv_range, ++ .clean_range = bcm_clean_range, ++ .flush_range = bcm_flush_range, ++ .flush_all = l2c210_flush_all, ++ .disable = l2c310_disable, ++ .sync = l2c210_sync, ++ .resume = l2c310_resume, ++ }, ++}; + +-static void aurora_save(void) ++static void __init tauros3_save(void __iomem *base) + { +- l2x0_saved_regs.ctrl = readl_relaxed(l2x0_base + L2X0_CTRL); +- l2x0_saved_regs.aux_ctrl = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); +-} ++ l2c_save(base); + +-static void __init tauros3_save(void) +-{ + l2x0_saved_regs.aux2_ctrl = +- readl_relaxed(l2x0_base + TAUROS3_AUX2_CTRL); ++ readl_relaxed(base + TAUROS3_AUX2_CTRL); + l2x0_saved_regs.prefetch_ctrl = +- readl_relaxed(l2x0_base + L2X0_PREFETCH_CTRL); +-} +- +-static void l2x0_resume(void) +-{ +- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { +- /* restore aux ctrl and enable l2 */ +- l2x0_unlock(readl_relaxed(l2x0_base + L2X0_CACHE_ID)); +- +- writel_relaxed(l2x0_saved_regs.aux_ctrl, l2x0_base + +- L2X0_AUX_CTRL); +- +- l2x0_inv_all(); +- +- writel_relaxed(L2X0_CTRL_EN, l2x0_base + L2X0_CTRL); +- } +-} +- +-static void pl310_resume(void) +-{ +- u32 l2x0_revision; +- +- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { +- /* restore pl310 setup */ +- writel_relaxed(l2x0_saved_regs.tag_latency, +- l2x0_base + L2X0_TAG_LATENCY_CTRL); +- writel_relaxed(l2x0_saved_regs.data_latency, +- l2x0_base + L2X0_DATA_LATENCY_CTRL); +- writel_relaxed(l2x0_saved_regs.filter_end, +- l2x0_base + L2X0_ADDR_FILTER_END); +- writel_relaxed(l2x0_saved_regs.filter_start, +- l2x0_base + L2X0_ADDR_FILTER_START); +- +- l2x0_revision = readl_relaxed(l2x0_base + L2X0_CACHE_ID) & +- L2X0_CACHE_ID_RTL_MASK; +- +- if (l2x0_revision >= L2X0_CACHE_ID_RTL_R2P0) { +- writel_relaxed(l2x0_saved_regs.prefetch_ctrl, +- l2x0_base + L2X0_PREFETCH_CTRL); +- if (l2x0_revision >= L2X0_CACHE_ID_RTL_R3P0) +- writel_relaxed(l2x0_saved_regs.pwr_ctrl, +- l2x0_base + L2X0_POWER_CTRL); +- } +- } +- +- l2x0_resume(); +-} +- +-static void aurora_resume(void) +-{ +- if (!(readl(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { +- writel_relaxed(l2x0_saved_regs.aux_ctrl, +- l2x0_base + L2X0_AUX_CTRL); +- writel_relaxed(l2x0_saved_regs.ctrl, l2x0_base + L2X0_CTRL); +- } ++ readl_relaxed(base + L310_PREFETCH_CTRL); + } + + static void tauros3_resume(void) + { +- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { ++ void __iomem *base = l2x0_base; ++ ++ if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)) { + writel_relaxed(l2x0_saved_regs.aux2_ctrl, +- l2x0_base + TAUROS3_AUX2_CTRL); ++ base + TAUROS3_AUX2_CTRL); + writel_relaxed(l2x0_saved_regs.prefetch_ctrl, +- l2x0_base + L2X0_PREFETCH_CTRL); +- } +- +- l2x0_resume(); +-} +- +-static void __init aurora_broadcast_l2_commands(void) +-{ +- __u32 u; +- /* Enable Broadcasting of cache commands to L2*/ +- __asm__ __volatile__("mrc p15, 1, %0, c15, c2, 0" : "=r"(u)); +- u |= AURORA_CTRL_FW; /* Set the FW bit */ +- __asm__ __volatile__("mcr p15, 1, %0, c15, c2, 0\n" : : "r"(u)); +- isb(); +-} +- +-static void __init aurora_of_setup(const struct device_node *np, +- u32 *aux_val, u32 *aux_mask) +-{ +- u32 val = AURORA_ACR_REPLACEMENT_TYPE_SEMIPLRU; +- u32 mask = AURORA_ACR_REPLACEMENT_MASK; ++ base + L310_PREFETCH_CTRL); + +- of_property_read_u32(np, "cache-id-part", +- &cache_id_part_number_from_dt); +- +- /* Determine and save the write policy */ +- l2_wt_override = of_property_read_bool(np, "wt-override"); +- +- if (l2_wt_override) { +- val |= AURORA_ACR_FORCE_WRITE_THRO_POLICY; +- mask |= AURORA_ACR_FORCE_WRITE_POLICY_MASK; ++ l2c_enable(base, l2x0_saved_regs.aux_ctrl, 8); + } +- +- *aux_val &= ~mask; +- *aux_val |= val; +- *aux_mask &= ~mask; + } + +-static const struct l2x0_of_data pl310_data = { +- .setup = pl310_of_setup, +- .save = pl310_save, +- .outer_cache = { +- .resume = pl310_resume, +- .inv_range = l2x0_inv_range, +- .clean_range = l2x0_clean_range, +- .flush_range = l2x0_flush_range, +- .sync = l2x0_cache_sync, +- .flush_all = l2x0_flush_all, +- .inv_all = l2x0_inv_all, +- .disable = l2x0_disable, +- }, +-}; +- +-static const struct l2x0_of_data l2x0_data = { +- .setup = l2x0_of_setup, +- .save = NULL, +- .outer_cache = { +- .resume = l2x0_resume, +- .inv_range = l2x0_inv_range, +- .clean_range = l2x0_clean_range, +- .flush_range = l2x0_flush_range, +- .sync = l2x0_cache_sync, +- .flush_all = l2x0_flush_all, +- .inv_all = l2x0_inv_all, +- .disable = l2x0_disable, +- }, +-}; +- +-static const struct l2x0_of_data aurora_with_outer_data = { +- .setup = aurora_of_setup, +- .save = aurora_save, +- .outer_cache = { +- .resume = aurora_resume, +- .inv_range = aurora_inv_range, +- .clean_range = aurora_clean_range, +- .flush_range = aurora_flush_range, +- .sync = l2x0_cache_sync, +- .flush_all = l2x0_flush_all, +- .inv_all = l2x0_inv_all, +- .disable = l2x0_disable, +- }, +-}; +- +-static const struct l2x0_of_data aurora_no_outer_data = { +- .setup = aurora_of_setup, +- .save = aurora_save, +- .outer_cache = { +- .resume = aurora_resume, +- }, +-}; +- +-static const struct l2x0_of_data tauros3_data = { +- .setup = NULL, ++static const struct l2c_init_data of_tauros3_data __initconst = { ++ .type = "Tauros3", ++ .way_size_0 = SZ_8K, ++ .num_lock = 8, ++ .enable = l2c_enable, + .save = tauros3_save, + /* Tauros3 broadcasts L1 cache operations to L2 */ + .outer_cache = { +@@ -936,43 +1451,26 @@ + }, + }; + +-static const struct l2x0_of_data bcm_l2x0_data = { +- .setup = pl310_of_setup, +- .save = pl310_save, +- .outer_cache = { +- .resume = pl310_resume, +- .inv_range = bcm_inv_range, +- .clean_range = bcm_clean_range, +- .flush_range = bcm_flush_range, +- .sync = l2x0_cache_sync, +- .flush_all = l2x0_flush_all, +- .inv_all = l2x0_inv_all, +- .disable = l2x0_disable, +- }, +-}; +- ++#define L2C_ID(name, fns) { .compatible = name, .data = (void *)&fns } + static const struct of_device_id l2x0_ids[] __initconst = { +- { .compatible = "arm,l210-cache", .data = (void *)&l2x0_data }, +- { .compatible = "arm,l220-cache", .data = (void *)&l2x0_data }, +- { .compatible = "arm,pl310-cache", .data = (void *)&pl310_data }, +- { .compatible = "bcm,bcm11351-a2-pl310-cache", /* deprecated name */ +- .data = (void *)&bcm_l2x0_data}, +- { .compatible = "brcm,bcm11351-a2-pl310-cache", +- .data = (void *)&bcm_l2x0_data}, +- { .compatible = "marvell,aurora-outer-cache", +- .data = (void *)&aurora_with_outer_data}, +- { .compatible = "marvell,aurora-system-cache", +- .data = (void *)&aurora_no_outer_data}, +- { .compatible = "marvell,tauros3-cache", +- .data = (void *)&tauros3_data }, ++ L2C_ID("arm,l210-cache", of_l2c210_data), ++ L2C_ID("arm,l220-cache", of_l2c220_data), ++ L2C_ID("arm,pl310-cache", of_l2c310_data), ++ L2C_ID("brcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data), ++ L2C_ID("marvell,aurora-outer-cache", of_aurora_with_outer_data), ++ L2C_ID("marvell,aurora-system-cache", of_aurora_no_outer_data), ++ L2C_ID("marvell,tauros3-cache", of_tauros3_data), ++ /* Deprecated IDs */ ++ L2C_ID("bcm,bcm11351-a2-pl310-cache", of_bcm_l2x0_data), + {} + }; + + int __init l2x0_of_init(u32 aux_val, u32 aux_mask) + { ++ const struct l2c_init_data *data; + struct device_node *np; +- const struct l2x0_of_data *data; + struct resource res; ++ u32 cache_id, old_aux; + + np = of_find_matching_node(NULL, l2x0_ids); + if (!np) +@@ -989,23 +1487,29 @@ + + data = of_match_node(l2x0_ids, np)->data; + +- /* L2 configuration can only be changed if the cache is disabled */ +- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) { +- if (data->setup) +- data->setup(np, &aux_val, &aux_mask); +- +- /* For aurora cache in no outer mode select the +- * correct mode using the coprocessor*/ +- if (data == &aurora_no_outer_data) +- aurora_broadcast_l2_commands(); ++ old_aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL); ++ if (old_aux != ((old_aux & aux_mask) | aux_val)) { ++ pr_warn("L2C: platform modifies aux control register: 0x%08x -> 0x%08x\n", ++ old_aux, (old_aux & aux_mask) | aux_val); ++ } else if (aux_mask != ~0U && aux_val != 0) { ++ pr_alert("L2C: platform provided aux values match the hardware, so have no effect. Please remove them.\n"); + } + +- if (data->save) +- data->save(); ++ /* All L2 caches are unified, so this property should be specified */ ++ if (!of_property_read_bool(np, "cache-unified")) ++ pr_err("L2C: device tree omits to specify unified cache\n"); ++ ++ /* L2 configuration can only be changed if the cache is disabled */ ++ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) ++ if (data->of_parse) ++ data->of_parse(np, &aux_val, &aux_mask); ++ ++ if (cache_id_part_number_from_dt) ++ cache_id = cache_id_part_number_from_dt; ++ else ++ cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID); + +- of_init = true; +- memcpy(&outer_cache, &data->outer_cache, sizeof(outer_cache)); +- l2x0_init(l2x0_base, aux_val, aux_mask); ++ __l2c_init(data, aux_val, aux_mask, cache_id); + + return 0; + } +diff -Nur linux-3.14.40.orig/arch/arm/mm/dma-mapping.c linux-3.14.40/arch/arm/mm/dma-mapping.c +--- linux-3.14.40.orig/arch/arm/mm/dma-mapping.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mm/dma-mapping.c 2015-05-01 14:57:58.051427001 -0500 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include + #include +diff -Nur linux-3.14.40.orig/arch/arm/mm/fault.c linux-3.14.40/arch/arm/mm/fault.c +--- linux-3.14.40.orig/arch/arm/mm/fault.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mm/fault.c 2015-05-01 14:57:58.087427001 -0500 +@@ -449,8 +449,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); +@@ -473,8 +481,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.14.40.orig/arch/arm/mm/init.c linux-3.14.40/arch/arm/mm/init.c +--- linux-3.14.40.orig/arch/arm/mm/init.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mm/init.c 2015-05-01 14:57:58.091427001 -0500 +@@ -327,7 +327,7 @@ + * reserve memory for DMA contigouos allocations, + * must come from DMA area inside low memory + */ +- dma_contiguous_reserve(min(arm_dma_limit, arm_lowmem_limit)); ++ dma_contiguous_reserve(arm_dma_limit); + + arm_memblock_steal_permitted = false; + memblock_dump_all(); +diff -Nur linux-3.14.40.orig/arch/arm/mm/Kconfig linux-3.14.40/arch/arm/mm/Kconfig +--- linux-3.14.40.orig/arch/arm/mm/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mm/Kconfig 2015-05-01 14:57:58.095427001 -0500 +@@ -898,6 +898,57 @@ + This option enables optimisations for the PL310 cache + controller. + ++config PL310_ERRATA_588369 ++ bool "PL310 errata: Clean & Invalidate maintenance operations do not invalidate clean lines" ++ depends on CACHE_L2X0 ++ help ++ The PL310 L2 cache controller implements three types of Clean & ++ Invalidate maintenance operations: by Physical Address ++ (offset 0x7F0), by Index/Way (0x7F8) and by Way (0x7FC). ++ They are architecturally defined to behave as the execution of a ++ clean operation followed immediately by an invalidate operation, ++ both performing to the same memory location. This functionality ++ is not correctly implemented in PL310 as clean lines are not ++ invalidated as a result of these operations. ++ ++config PL310_ERRATA_727915 ++ bool "PL310 errata: Background Clean & Invalidate by Way operation can cause data corruption" ++ depends on CACHE_L2X0 ++ help ++ PL310 implements the Clean & Invalidate by Way L2 cache maintenance ++ operation (offset 0x7FC). This operation runs in background so that ++ PL310 can handle normal accesses while it is in progress. Under very ++ rare circumstances, due to this erratum, write data can be lost when ++ PL310 treats a cacheable write transaction during a Clean & ++ Invalidate by Way operation. ++ ++config PL310_ERRATA_753970 ++ bool "PL310 errata: cache sync operation may be faulty" ++ depends on CACHE_PL310 ++ help ++ This option enables the workaround for the 753970 PL310 (r3p0) erratum. ++ ++ Under some condition the effect of cache sync operation on ++ the store buffer still remains when the operation completes. ++ This means that the store buffer is always asked to drain and ++ this prevents it from merging any further writes. The workaround ++ is to replace the normal offset of cache sync operation (0x730) ++ by another offset targeting an unmapped PL310 register 0x740. ++ This has the same effect as the cache sync operation: store buffer ++ drain and waiting for all buffers empty. ++ ++config PL310_ERRATA_769419 ++ bool "PL310 errata: no automatic Store Buffer drain" ++ depends on CACHE_L2X0 ++ help ++ On revisions of the PL310 prior to r3p2, the Store Buffer does ++ not automatically drain. This can cause normal, non-cacheable ++ writes to be retained when the memory system is idle, leading ++ to suboptimal I/O performance for drivers using coherent DMA. ++ This option adds a write barrier to the cpu_idle loop so that, ++ on systems with an outer cache, the store buffer is drained ++ explicitly. ++ + config CACHE_TAUROS2 + bool "Enable the Tauros2 L2 cache controller" + depends on (ARCH_DOVE || ARCH_MMP || CPU_PJ4) +diff -Nur linux-3.14.40.orig/arch/arm/mm/l2c-common.c linux-3.14.40/arch/arm/mm/l2c-common.c +--- linux-3.14.40.orig/arch/arm/mm/l2c-common.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mm/l2c-common.c 2015-05-01 14:57:58.095427001 -0500 +@@ -0,0 +1,20 @@ ++/* ++ * Copyright (C) 2010 ARM Ltd. ++ * Written by Catalin Marinas ++ * ++ * This program is free software; you can 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 ++ ++void outer_disable(void) ++{ ++ WARN_ON(!irqs_disabled()); ++ WARN_ON(num_online_cpus() > 1); ++ ++ if (outer_cache.disable) ++ outer_cache.disable(); ++} +diff -Nur linux-3.14.40.orig/arch/arm/mm/l2c-l2x0-resume.S linux-3.14.40/arch/arm/mm/l2c-l2x0-resume.S +--- linux-3.14.40.orig/arch/arm/mm/l2c-l2x0-resume.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm/mm/l2c-l2x0-resume.S 2015-05-01 14:57:58.095427001 -0500 +@@ -0,0 +1,58 @@ ++/* ++ * L2C-310 early resume code. This can be used by platforms to restore ++ * the settings of their L2 cache controller before restoring the ++ * processor state. ++ * ++ * This code can only be used to if you are running in the secure world. ++ */ ++#include ++#include ++ ++ .text ++ ++ENTRY(l2c310_early_resume) ++ adr r0, 1f ++ ldr r2, [r0] ++ add r0, r2, r0 ++ ++ ldmia r0, {r1, r2, r3, r4, r5, r6, r7, r8} ++ @ r1 = phys address of L2C-310 controller ++ @ r2 = aux_ctrl ++ @ r3 = tag_latency ++ @ r4 = data_latency ++ @ r5 = filter_start ++ @ r6 = filter_end ++ @ r7 = prefetch_ctrl ++ @ r8 = pwr_ctrl ++ ++ @ Check that the address has been initialised ++ teq r1, #0 ++ moveq pc, lr ++ ++ @ The prefetch and power control registers are revision dependent ++ @ and can be written whether or not the L2 cache is enabled ++ ldr r0, [r1, #L2X0_CACHE_ID] ++ and r0, r0, #L2X0_CACHE_ID_RTL_MASK ++ cmp r0, #L310_CACHE_ID_RTL_R2P0 ++ strcs r7, [r1, #L310_PREFETCH_CTRL] ++ cmp r0, #L310_CACHE_ID_RTL_R3P0 ++ strcs r8, [r1, #L310_POWER_CTRL] ++ ++ @ Don't setup the L2 cache if it is already enabled ++ ldr r0, [r1, #L2X0_CTRL] ++ tst r0, #L2X0_CTRL_EN ++ movne pc, lr ++ ++ str r3, [r1, #L310_TAG_LATENCY_CTRL] ++ str r4, [r1, #L310_DATA_LATENCY_CTRL] ++ str r6, [r1, #L310_ADDR_FILTER_END] ++ str r5, [r1, #L310_ADDR_FILTER_START] ++ ++ str r2, [r1, #L2X0_AUX_CTRL] ++ mov r9, #L2X0_CTRL_EN ++ str r9, [r1, #L2X0_CTRL] ++ mov pc, lr ++ENDPROC(l2c310_early_resume) ++ ++ .align ++1: .long l2x0_saved_regs - . +diff -Nur linux-3.14.40.orig/arch/arm/mm/Makefile linux-3.14.40/arch/arm/mm/Makefile +--- linux-3.14.40.orig/arch/arm/mm/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mm/Makefile 2015-05-01 14:57:58.111427001 -0500 +@@ -95,7 +95,8 @@ + AFLAGS_proc-v6.o :=-Wa,-march=armv6 + AFLAGS_proc-v7.o :=-Wa,-march=armv7-a + ++obj-$(CONFIG_OUTER_CACHE) += l2c-common.o + obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o +-obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o ++obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o l2c-l2x0-resume.o + obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o + obj-$(CONFIG_CACHE_TAUROS2) += cache-tauros2.o +diff -Nur linux-3.14.40.orig/arch/arm/mm/proc-v7.S linux-3.14.40/arch/arm/mm/proc-v7.S +--- linux-3.14.40.orig/arch/arm/mm/proc-v7.S 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm/mm/proc-v7.S 2015-05-01 14:57:58.119427001 -0500 +@@ -334,6 +334,17 @@ + mcrlt p15, 0, r10, c15, c0, 1 @ write diagnostic register + 1: + #endif ++#ifdef CONFIG_ARM_ERRATA_794072 ++ mrc p15, 0, r10, c15, c0, 1 @ read diagnostic register ++ orr r10, r10, #1 << 4 @ set bit #4 ++ mcr p15, 0, r10, c15, c0, 1 @ write diagnostic register ++#endif ++#ifdef CONFIG_ARM_ERRATA_761320 ++ cmp r6, #0x40 @ present prior to r4p0 ++ mrclt p15, 0, r10, c15, c0, 1 @ read diagnostic register ++ orrlt r10, r10, #1 << 21 @ set bit #21 ++ mcrlt p15, 0, r10, c15, c0, 1 @ write diagnostic register ++#endif + + /* Cortex-A15 Errata */ + 3: ldr r10, =0x00000c0f @ Cortex-A15 primary part number +diff -Nur linux-3.14.40.orig/arch/arm64/boot/dts/apm-mustang.dts linux-3.14.40/arch/arm64/boot/dts/apm-mustang.dts +--- linux-3.14.40.orig/arch/arm64/boot/dts/apm-mustang.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/boot/dts/apm-mustang.dts 2015-05-01 14:57:58.127427001 -0500 +@@ -24,3 +24,7 @@ + reg = < 0x1 0x00000000 0x0 0x80000000 >; /* Updated by bootloader */ + }; + }; ++ ++&serial0 { ++ status = "ok"; ++}; +diff -Nur linux-3.14.40.orig/arch/arm64/boot/dts/apm-storm.dtsi linux-3.14.40/arch/arm64/boot/dts/apm-storm.dtsi +--- linux-3.14.40.orig/arch/arm64/boot/dts/apm-storm.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/boot/dts/apm-storm.dtsi 2015-05-01 14:57:58.127427001 -0500 +@@ -176,16 +176,226 @@ + reg-names = "csr-reg"; + clock-output-names = "eth8clk"; + }; ++ ++ sataphy1clk: sataphy1clk@1f21c000 { ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f21c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ clock-output-names = "sataphy1clk"; ++ status = "disabled"; ++ csr-offset = <0x4>; ++ csr-mask = <0x00>; ++ enable-offset = <0x0>; ++ enable-mask = <0x06>; ++ }; ++ ++ sataphy2clk: sataphy1clk@1f22c000 { ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f22c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ clock-output-names = "sataphy2clk"; ++ status = "ok"; ++ csr-offset = <0x4>; ++ csr-mask = <0x3a>; ++ enable-offset = <0x0>; ++ enable-mask = <0x06>; ++ }; ++ ++ sataphy3clk: sataphy1clk@1f23c000 { ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f23c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ clock-output-names = "sataphy3clk"; ++ status = "ok"; ++ csr-offset = <0x4>; ++ csr-mask = <0x3a>; ++ enable-offset = <0x0>; ++ enable-mask = <0x06>; ++ }; ++ ++ sata01clk: sata01clk@1f21c000 { ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f21c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ clock-output-names = "sata01clk"; ++ csr-offset = <0x4>; ++ csr-mask = <0x05>; ++ enable-offset = <0x0>; ++ enable-mask = <0x39>; ++ }; ++ ++ sata23clk: sata23clk@1f22c000 { ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f22c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ clock-output-names = "sata23clk"; ++ csr-offset = <0x4>; ++ csr-mask = <0x05>; ++ enable-offset = <0x0>; ++ enable-mask = <0x39>; ++ }; ++ ++ sata45clk: sata45clk@1f23c000 { ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x1f23c000 0x0 0x1000>; ++ reg-names = "csr-reg"; ++ clock-output-names = "sata45clk"; ++ csr-offset = <0x4>; ++ csr-mask = <0x05>; ++ enable-offset = <0x0>; ++ enable-mask = <0x39>; ++ }; ++ ++ rtcclk: rtcclk@17000000 { ++ compatible = "apm,xgene-device-clock"; ++ #clock-cells = <1>; ++ clocks = <&socplldiv2 0>; ++ reg = <0x0 0x17000000 0x0 0x2000>; ++ reg-names = "csr-reg"; ++ csr-offset = <0xc>; ++ csr-mask = <0x2>; ++ enable-offset = <0x10>; ++ enable-mask = <0x2>; ++ clock-output-names = "rtcclk"; ++ }; + }; + + serial0: serial@1c020000 { ++ status = "disabled"; + device_type = "serial"; +- compatible = "ns16550"; ++ compatible = "ns16550a"; + reg = <0 0x1c020000 0x0 0x1000>; + reg-shift = <2>; + clock-frequency = <10000000>; /* Updated by bootloader */ + interrupt-parent = <&gic>; + interrupts = <0x0 0x4c 0x4>; + }; ++ ++ serial1: serial@1c021000 { ++ status = "disabled"; ++ device_type = "serial"; ++ compatible = "ns16550a"; ++ reg = <0 0x1c021000 0x0 0x1000>; ++ reg-shift = <2>; ++ clock-frequency = <10000000>; /* Updated by bootloader */ ++ interrupt-parent = <&gic>; ++ interrupts = <0x0 0x4d 0x4>; ++ }; ++ ++ serial2: serial@1c022000 { ++ status = "disabled"; ++ device_type = "serial"; ++ compatible = "ns16550a"; ++ reg = <0 0x1c022000 0x0 0x1000>; ++ reg-shift = <2>; ++ clock-frequency = <10000000>; /* Updated by bootloader */ ++ interrupt-parent = <&gic>; ++ interrupts = <0x0 0x4e 0x4>; ++ }; ++ ++ serial3: serial@1c023000 { ++ status = "disabled"; ++ device_type = "serial"; ++ compatible = "ns16550a"; ++ reg = <0 0x1c023000 0x0 0x1000>; ++ reg-shift = <2>; ++ clock-frequency = <10000000>; /* Updated by bootloader */ ++ interrupt-parent = <&gic>; ++ interrupts = <0x0 0x4f 0x4>; ++ }; ++ ++ phy1: phy@1f21a000 { ++ compatible = "apm,xgene-phy"; ++ reg = <0x0 0x1f21a000 0x0 0x100>; ++ #phy-cells = <1>; ++ clocks = <&sataphy1clk 0>; ++ status = "disabled"; ++ apm,tx-boost-gain = <30 30 30 30 30 30>; ++ apm,tx-eye-tuning = <2 10 10 2 10 10>; ++ }; ++ ++ phy2: phy@1f22a000 { ++ compatible = "apm,xgene-phy"; ++ reg = <0x0 0x1f22a000 0x0 0x100>; ++ #phy-cells = <1>; ++ clocks = <&sataphy2clk 0>; ++ status = "ok"; ++ apm,tx-boost-gain = <30 30 30 30 30 30>; ++ apm,tx-eye-tuning = <1 10 10 2 10 10>; ++ }; ++ ++ phy3: phy@1f23a000 { ++ compatible = "apm,xgene-phy"; ++ reg = <0x0 0x1f23a000 0x0 0x100>; ++ #phy-cells = <1>; ++ clocks = <&sataphy3clk 0>; ++ status = "ok"; ++ apm,tx-boost-gain = <31 31 31 31 31 31>; ++ apm,tx-eye-tuning = <2 10 10 2 10 10>; ++ }; ++ ++ sata1: sata@1a000000 { ++ compatible = "apm,xgene-ahci"; ++ reg = <0x0 0x1a000000 0x0 0x1000>, ++ <0x0 0x1f210000 0x0 0x1000>, ++ <0x0 0x1f21d000 0x0 0x1000>, ++ <0x0 0x1f21e000 0x0 0x1000>, ++ <0x0 0x1f217000 0x0 0x1000>; ++ interrupts = <0x0 0x86 0x4>; ++ dma-coherent; ++ status = "disabled"; ++ clocks = <&sata01clk 0>; ++ phys = <&phy1 0>; ++ phy-names = "sata-phy"; ++ }; ++ ++ sata2: sata@1a400000 { ++ compatible = "apm,xgene-ahci"; ++ reg = <0x0 0x1a400000 0x0 0x1000>, ++ <0x0 0x1f220000 0x0 0x1000>, ++ <0x0 0x1f22d000 0x0 0x1000>, ++ <0x0 0x1f22e000 0x0 0x1000>, ++ <0x0 0x1f227000 0x0 0x1000>; ++ interrupts = <0x0 0x87 0x4>; ++ dma-coherent; ++ status = "ok"; ++ clocks = <&sata23clk 0>; ++ phys = <&phy2 0>; ++ phy-names = "sata-phy"; ++ }; ++ ++ sata3: sata@1a800000 { ++ compatible = "apm,xgene-ahci"; ++ reg = <0x0 0x1a800000 0x0 0x1000>, ++ <0x0 0x1f230000 0x0 0x1000>, ++ <0x0 0x1f23d000 0x0 0x1000>, ++ <0x0 0x1f23e000 0x0 0x1000>; ++ interrupts = <0x0 0x88 0x4>; ++ dma-coherent; ++ status = "ok"; ++ clocks = <&sata45clk 0>; ++ phys = <&phy3 0>; ++ phy-names = "sata-phy"; ++ }; ++ ++ rtc: rtc@10510000 { ++ compatible = "apm,xgene-rtc"; ++ reg = <0x0 0x10510000 0x0 0x400>; ++ interrupts = <0x0 0x46 0x4>; ++ #clock-cells = <1>; ++ clocks = <&rtcclk 0>; ++ }; + }; + }; +diff -Nur linux-3.14.40.orig/arch/arm64/boot/dts/clcd-panels.dtsi linux-3.14.40/arch/arm64/boot/dts/clcd-panels.dtsi +--- linux-3.14.40.orig/arch/arm64/boot/dts/clcd-panels.dtsi 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/boot/dts/clcd-panels.dtsi 2015-05-01 14:57:58.127427001 -0500 +@@ -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.14.40.orig/arch/arm64/boot/dts/fvp-base-gicv2-psci.dts linux-3.14.40/arch/arm64/boot/dts/fvp-base-gicv2-psci.dts +--- linux-3.14.40.orig/arch/arm64/boot/dts/fvp-base-gicv2-psci.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/boot/dts/fvp-base-gicv2-psci.dts 2015-05-01 14:57:58.127427001 -0500 +@@ -0,0 +1,266 @@ ++/* ++ * 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" ++ }; ++}; ++ ++/include/ "clcd-panels.dtsi" +diff -Nur linux-3.14.40.orig/arch/arm64/boot/dts/juno.dts linux-3.14.40/arch/arm64/boot/dts/juno.dts +--- linux-3.14.40.orig/arch/arm64/boot/dts/juno.dts 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/boot/dts/juno.dts 2015-05-01 14:57:58.127427001 -0500 +@@ -0,0 +1,498 @@ ++/* ++ * ARM Ltd. Juno Plaform ++ * ++ * Fast Models FVP v2 support ++ */ ++ ++/dts-v1/; ++ ++#include ++ ++/ { ++ model = "Juno"; ++ compatible = "arm,juno", "arm,vexpress"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ aliases { ++ serial0 = &soc_uart0; ++ }; ++ ++ cpus { ++ #address-cells = <2>; ++ #size-cells = <0>; ++ ++ cpu@100 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53","arm,armv8"; ++ reg = <0x0 0x100>; ++ enable-method = "psci"; ++ }; ++ ++ cpu@101 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53","arm,armv8"; ++ reg = <0x0 0x101>; ++ enable-method = "psci"; ++ }; ++ ++ cpu@102 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53","arm,armv8"; ++ reg = <0x0 0x102>; ++ enable-method = "psci"; ++ }; ++ ++ cpu@103 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53","arm,armv8"; ++ reg = <0x0 0x103>; ++ enable-method = "psci"; ++ }; ++ ++ cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57","arm,armv8"; ++ reg = <0x0 0x0>; ++ enable-method = "psci"; ++ }; ++ ++ cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57","arm,armv8"; ++ reg = <0x0 0x1>; ++ enable-method = "psci"; ++ }; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0x00000000 0x80000000 0x0 0x80000000>, ++ <0x00000008 0x80000000 0x1 0x80000000>; ++ }; ++ ++ /* memory@14000000 { ++ device_type = "memory"; ++ reg = <0x00000000 0x14000000 0x0 0x02000000>; ++ }; */ ++ ++ gic: interrupt-controller@2c001000 { ++ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; ++ #interrupt-cells = <3>; ++ #address-cells = <0>; ++ interrupt-controller; ++ reg = <0x0 0x2c010000 0 0x1000>, ++ <0x0 0x2c02f000 0 0x1000>, ++ <0x0 0x2c04f000 0 0x2000>, ++ <0x0 0x2c06f000 0 0x2000>; ++ interrupts = ; ++ }; ++ ++ msi0: msi@2c1c0000 { ++ compatible = "arm,gic-msi"; ++ reg = <0x0 0x2c1c0000 0 0x10000 ++ 0x0 0x2c1d0000 0 0x10000 ++ 0x0 0x2c1e0000 0 0x10000 ++ 0x0 0x2c1f0000 0 0x10000>; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = , ++ , ++ , ++ ; ++ }; ++ ++ pmu { ++ compatible = "arm,armv8-pmuv3"; ++ interrupts = , ++ , ++ , ++ ; ++ }; ++ ++ psci { ++ compatible = "arm,psci"; ++ method = "smc"; ++ cpu_suspend = <0xC4000001>; ++ cpu_off = <0x84000002>; ++ cpu_on = <0xC4000003>; ++ migrate = <0xC4000005>; ++ }; ++ ++ pci0: pci@30000000 { ++ compatible = "arm,pcie-xr3"; ++ device_type = "pci"; ++ reg = <0 0x7ff30000 0 0x1000 ++ 0 0x7ff20000 0 0x10000 ++ 0 0x40000000 0 0x10000000>; ++ bus-range = <0 255>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ ranges = <0x01000000 0x0 0x00000000 0x00 0x5ff00000 0x0 0x00100000 ++ 0x02000000 0x0 0x00000000 0x40 0x00000000 0x0 0x80000000 ++ 0x42000000 0x0 0x80000000 0x40 0x80000000 0x0 0x80000000>; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &gic 0 136 4 ++ 0 0 0 2 &gic 0 137 4 ++ 0 0 0 3 &gic 0 138 4 ++ 0 0 0 4 &gic 0 139 4>; ++ }; ++ ++ scpi: scpi@2b1f0000 { ++ compatible = "arm,scpi-mhu"; ++ reg = <0x0 0x2b1f0000 0x0 0x10000>, /* MHU registers */ ++ <0x0 0x2e000000 0x0 0x10000>; /* Payload area */ ++ interrupts = <0 36 4>, /* low priority interrupt */ ++ <0 35 4>, /* high priority interrupt */ ++ <0 37 4>; /* secure channel interrupt */ ++ #clock-cells = <1>; ++ clock-output-names = "a57", "a53", "gpu", "hdlcd0", "hdlcd1"; ++ }; ++ ++ hdlcd0_osc: scpi_osc@3 { ++ compatible = "arm,scpi-osc"; ++ #clock-cells = <0>; ++ clocks = <&scpi 3>; ++ frequency-range = <23000000 210000000>; ++ clock-output-names = "pxlclk0"; ++ }; ++ ++ hdlcd1_osc: scpi_osc@4 { ++ compatible = "arm,scpi-osc"; ++ #clock-cells = <0>; ++ clocks = <&scpi 4>; ++ frequency-range = <23000000 210000000>; ++ clock-output-names = "pxlclk1"; ++ }; ++ ++ soc_uartclk: refclk72738khz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <7273800>; ++ clock-output-names = "juno:uartclk"; ++ }; ++ ++ soc_refclk24mhz: clk24mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24000000>; ++ clock-output-names = "juno:clk24mhz"; ++ }; ++ ++ mb_eth25mhz: clk25mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <25000000>; ++ clock-output-names = "ethclk25mhz"; ++ }; ++ ++ soc_usb48mhz: clk48mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <48000000>; ++ clock-output-names = "clk48mhz"; ++ }; ++ ++ soc_smc50mhz: clk50mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <50000000>; ++ clock-output-names = "smc_clk"; ++ }; ++ ++ soc_refclk100mhz: refclk100mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <100000000>; ++ clock-output-names = "apb_pclk"; ++ }; ++ ++ soc_faxiclk: refclk533mhz { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <533000000>; ++ clock-output-names = "faxi_clk"; ++ }; ++ ++ soc_fixed_3v3: fixedregulator@0 { ++ compatible = "regulator-fixed"; ++ regulator-name = "3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ memory-controller@7ffd0000 { ++ compatible = "arm,pl354", "arm,primecell"; ++ reg = <0 0x7ffd0000 0 0x1000>; ++ interrupts = <0 86 4>, ++ <0 87 4>; ++ clocks = <&soc_smc50mhz>; ++ clock-names = "apb_pclk"; ++ chip5-memwidth = <16>; ++ }; ++ ++ dma0: dma@0x7ff00000 { ++ compatible = "arm,pl330", "arm,primecell"; ++ reg = <0x0 0x7ff00000 0 0x1000>; ++ interrupts = <0 95 4>, ++ <0 88 4>, ++ <0 89 4>, ++ <0 90 4>, ++ <0 91 4>, ++ <0 108 4>, ++ <0 109 4>, ++ <0 110 4>, ++ <0 111 4>; ++ #dma-cells = <1>; ++ #dma-channels = <8>; ++ #dma-requests = <32>; ++ clocks = <&soc_faxiclk>; ++ clock-names = "apb_pclk"; ++ }; ++ ++ soc_uart0: uart@7ff80000 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x0 0x7ff80000 0x0 0x1000>; ++ interrupts = <0 83 4>; ++ clocks = <&soc_uartclk>, <&soc_refclk100mhz>; ++ clock-names = "uartclk", "apb_pclk"; ++ dmas = <&dma0 1 ++ &dma0 2>; ++ dma-names = "rx", "tx"; ++ }; ++ ++ /* this UART is reserved for secure software. ++ soc_uart1: uart@7ff70000 { ++ compatible = "arm,pl011", "arm,primecell"; ++ reg = <0x0 0x7ff70000 0x0 0x1000>; ++ interrupts = <0 84 4>; ++ clocks = <&soc_uartclk>, <&soc_refclk100mhz>; ++ clock-names = "uartclk", "apb_pclk"; ++ }; */ ++ ++ ulpi_phy: phy@0 { ++ compatible = "phy-ulpi-generic"; ++ reg = <0x0 0x94 0x0 0x4>; ++ phy-id = <0>; ++ }; ++ ++ ehci@7ffc0000 { ++ compatible = "snps,ehci-h20ahb"; ++ /* compatible = "arm,h20ahb-ehci"; */ ++ reg = <0x0 0x7ffc0000 0x0 0x10000>; ++ interrupts = <0 117 4>; ++ clocks = <&soc_usb48mhz>; ++ clock-names = "otg"; ++ phys = <&ulpi_phy>; ++ }; ++ ++ ohci@0x7ffb0000 { ++ compatible = "generic-ohci"; ++ reg = <0x0 0x7ffb0000 0x0 0x10000>; ++ interrupts = <0 116 4>; ++ clocks = <&soc_usb48mhz>; ++ clock-names = "otg"; ++ }; ++ ++ i2c@0x7ffa0000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,designware-i2c"; ++ reg = <0x0 0x7ffa0000 0x0 0x1000>; ++ interrupts = <0 104 4>; ++ clock-frequency = <400000>; ++ i2c-sda-hold-time-ns = <500>; ++ clocks = <&soc_smc50mhz>; ++ ++ dvi0: dvi-transmitter@70 { ++ compatible = "nxp,tda998x"; ++ reg = <0x70>; ++ }; ++ ++ dvi1: dvi-transmitter@71 { ++ compatible = "nxp,tda998x"; ++ reg = <0x71>; ++ }; ++ }; ++ ++ /* mmci@1c050000 { ++ compatible = "arm,pl180", "arm,primecell"; ++ reg = <0x0 0x1c050000 0x0 0x1000>; ++ interrupts = <0 73 4>, ++ <0 74 4>; ++ max-frequency = <12000000>; ++ vmmc-supply = <&soc_fixed_3v3>; ++ clocks = <&soc_refclk24mhz>, <&soc_refclk100mhz>; ++ clock-names = "mclk", "apb_pclk"; ++ }; */ ++ ++ hdlcd@7ff60000 { ++ compatible = "arm,hdlcd"; ++ reg = <0 0x7ff60000 0 0x1000>; ++ interrupts = <0 85 4>; ++ clocks = <&hdlcd0_osc>; ++ clock-names = "pxlclk"; ++ i2c-slave = <&dvi0>; ++ ++ /* display-timings { ++ native-mode = <&timing0>; ++ timing0: timing@0 { ++ /* 1024 x 768 framebufer, standard VGA timings * / ++ clock-frequency = <65000>; ++ hactive = <1024>; ++ vactive = <768>; ++ hfront-porch = <24>; ++ hback-porch = <160>; ++ hsync-len = <136>; ++ vfront-porch = <3>; ++ vback-porch = <29>; ++ vsync-len = <6>; ++ }; ++ }; */ ++ }; ++ ++ hdlcd@7ff50000 { ++ compatible = "arm,hdlcd"; ++ reg = <0 0x7ff50000 0 0x1000>; ++ interrupts = <0 93 4>; ++ clocks = <&hdlcd1_osc>; ++ clock-names = "pxlclk"; ++ i2c-slave = <&dvi1>; ++ ++ display-timings { ++ native-mode = <&timing1>; ++ timing1: timing@1 { ++ /* 1024 x 768 framebufer, standard VGA timings */ ++ clock-frequency = <65000>; ++ hactive = <1024>; ++ vactive = <768>; ++ hfront-porch = <24>; ++ hback-porch = <160>; ++ hsync-len = <136>; ++ vfront-porch = <3>; ++ vback-porch = <29>; ++ vsync-len = <6>; ++ }; ++ }; ++ }; ++ ++ 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 15>; ++ interrupt-map = <0 0 0 &gic 0 68 4>, ++ <0 0 1 &gic 0 69 4>, ++ <0 0 2 &gic 0 70 4>, ++ <0 0 3 &gic 0 160 4>, ++ <0 0 4 &gic 0 161 4>, ++ <0 0 5 &gic 0 162 4>, ++ <0 0 6 &gic 0 163 4>, ++ <0 0 7 &gic 0 164 4>, ++ <0 0 8 &gic 0 165 4>, ++ <0 0 9 &gic 0 166 4>, ++ <0 0 10 &gic 0 167 4>, ++ <0 0 11 &gic 0 168 4>, ++ <0 0 12 &gic 0 169 4>; ++ ++ motherboard { ++ model = "V2M-Juno"; ++ arm,hbi = <0x252>; ++ arm,vexpress,site = <0>; ++ arm,v2m-memory-map = "rs1"; ++ compatible = "arm,vexpress,v2p-p1", "simple-bus"; ++ #address-cells = <2>; /* SMB chipselect number and offset */ ++ #size-cells = <1>; ++ #interrupt-cells = <1>; ++ ranges; ++ ++ usb@5,00000000 { ++ compatible = "nxp,usb-isp1763"; ++ reg = <5 0x00000000 0x20000>; ++ bus-width = <16>; ++ interrupts = <4>; ++ }; ++ ++ ethernet@2,00000000 { ++ compatible = "smsc,lan9118", "smsc,lan9115"; ++ reg = <2 0x00000000 0x10000>; ++ interrupts = <3>; ++ phy-mode = "mii"; ++ reg-io-width = <4>; ++ smsc,irq-active-high; ++ smsc,irq-push-pull; ++ clocks = <&mb_eth25mhz>; ++ vdd33a-supply = <&soc_fixed_3v3>; /* change this */ ++ vddvario-supply = <&soc_fixed_3v3>; /* and this */ ++ }; ++ ++ iofpga@3,00000000 { ++ compatible = "arm,amba-bus", "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 3 0 0x200000>; ++ ++ kmi@060000 { ++ compatible = "arm,pl050", "arm,primecell"; ++ reg = <0x060000 0x1000>; ++ interrupts = <8>; ++ clocks = <&soc_refclk24mhz>, <&soc_smc50mhz>; ++ clock-names = "KMIREFCLK", "apb_pclk"; ++ }; ++ ++ kmi@070000 { ++ compatible = "arm,pl050", "arm,primecell"; ++ reg = <0x070000 0x1000>; ++ interrupts = <8>; ++ clocks = <&soc_refclk24mhz>, <&soc_smc50mhz>; ++ clock-names = "KMIREFCLK", "apb_pclk"; ++ }; ++ ++ wdt@0f0000 { ++ compatible = "arm,sp805", "arm,primecell"; ++ reg = <0x0f0000 0x10000>; ++ interrupts = <7>; ++ clocks = <&soc_refclk24mhz>, <&soc_smc50mhz>; ++ clock-names = "wdogclk", "apb_pclk"; ++ }; ++ ++ v2m_timer01: timer@110000 { ++ compatible = "arm,sp804", "arm,primecell"; ++ reg = <0x110000 0x10000>; ++ interrupts = <9>; ++ clocks = <&soc_refclk24mhz>, <&soc_smc50mhz>; ++ clock-names = "timclken1", "apb_pclk"; ++ }; ++ ++ v2m_timer23: timer@120000 { ++ compatible = "arm,sp804", "arm,primecell"; ++ reg = <0x120000 0x10000>; ++ interrupts = <9>; ++ clocks = <&soc_refclk24mhz>, <&soc_smc50mhz>; ++ clock-names = "timclken1", "apb_pclk"; ++ }; ++ ++ rtc@170000 { ++ compatible = "arm,pl031", "arm,primecell"; ++ reg = <0x170000 0x10000>; ++ interrupts = <0>; ++ clocks = <&soc_smc50mhz>; ++ clock-names = "apb_pclk"; ++ }; ++ }; ++ }; ++ }; ++}; +diff -Nur linux-3.14.40.orig/arch/arm64/boot/dts/Makefile linux-3.14.40/arch/arm64/boot/dts/Makefile +--- linux-3.14.40.orig/arch/arm64/boot/dts/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/boot/dts/Makefile 2015-05-01 14:57:58.127427001 -0500 +@@ -1,5 +1,7 @@ +-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 + dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb ++dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb + + targets += dtbs + targets += $(dtb-y) +diff -Nur linux-3.14.40.orig/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts linux-3.14.40/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts +--- linux-3.14.40.orig/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts 2015-05-01 14:57:58.131427001 -0500 +@@ -157,3 +157,5 @@ + /include/ "rtsm_ve-motherboard.dtsi" + }; + }; ++ ++/include/ "clcd-panels.dtsi" +diff -Nur linux-3.14.40.orig/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi linux-3.14.40/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi +--- linux-3.14.40.orig/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi 2015-05-01 14:57:58.131427001 -0500 +@@ -182,6 +182,9 @@ + interrupts = <14>; + clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>; + clock-names = "clcdclk", "apb_pclk"; ++ mode = "XVGA"; ++ use_dma = <0>; ++ framebuffer = <0x18000000 0x00180000>; + }; + + virtio_block@0130000 { +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/aes-ce-ccm-core.S linux-3.14.40/arch/arm64/crypto/aes-ce-ccm-core.S +--- linux-3.14.40.orig/arch/arm64/crypto/aes-ce-ccm-core.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/aes-ce-ccm-core.S 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,222 @@ ++/* ++ * aesce-ccm-core.S - AES-CCM transform for ARMv8 with Crypto Extensions ++ * ++ * Copyright (C) 2013 - 2014 Linaro 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. ++ */ ++ ++#include ++ ++ .text ++ .arch armv8-a+crypto ++ ++ /* ++ * void ce_aes_ccm_auth_data(u8 mac[], u8 const in[], u32 abytes, ++ * u32 *macp, u8 const rk[], u32 rounds); ++ */ ++ENTRY(ce_aes_ccm_auth_data) ++ ldr w8, [x3] /* leftover from prev round? */ ++ ld1 {v0.2d}, [x0] /* load mac */ ++ cbz w8, 1f ++ sub w8, w8, #16 ++ eor v1.16b, v1.16b, v1.16b ++0: ldrb w7, [x1], #1 /* get 1 byte of input */ ++ subs w2, w2, #1 ++ add w8, w8, #1 ++ ins v1.b[0], w7 ++ ext v1.16b, v1.16b, v1.16b, #1 /* rotate in the input bytes */ ++ beq 8f /* out of input? */ ++ cbnz w8, 0b ++ eor v0.16b, v0.16b, v1.16b ++1: ld1 {v3.2d}, [x4] /* load first round key */ ++ prfm pldl1strm, [x1] ++ cmp w5, #12 /* which key size? */ ++ add x6, x4, #16 ++ sub w7, w5, #2 /* modified # of rounds */ ++ bmi 2f ++ bne 5f ++ mov v5.16b, v3.16b ++ b 4f ++2: mov v4.16b, v3.16b ++ ld1 {v5.2d}, [x6], #16 /* load 2nd round key */ ++3: aese v0.16b, v4.16b ++ aesmc v0.16b, v0.16b ++4: ld1 {v3.2d}, [x6], #16 /* load next round key */ ++ aese v0.16b, v5.16b ++ aesmc v0.16b, v0.16b ++5: ld1 {v4.2d}, [x6], #16 /* load next round key */ ++ subs w7, w7, #3 ++ aese v0.16b, v3.16b ++ aesmc v0.16b, v0.16b ++ ld1 {v5.2d}, [x6], #16 /* load next round key */ ++ bpl 3b ++ aese v0.16b, v4.16b ++ subs w2, w2, #16 /* last data? */ ++ eor v0.16b, v0.16b, v5.16b /* final round */ ++ bmi 6f ++ ld1 {v1.16b}, [x1], #16 /* load next input block */ ++ eor v0.16b, v0.16b, v1.16b /* xor with mac */ ++ bne 1b ++6: st1 {v0.2d}, [x0] /* store mac */ ++ beq 10f ++ adds w2, w2, #16 ++ beq 10f ++ mov w8, w2 ++7: ldrb w7, [x1], #1 ++ umov w6, v0.b[0] ++ eor w6, w6, w7 ++ strb w6, [x0], #1 ++ subs w2, w2, #1 ++ beq 10f ++ ext v0.16b, v0.16b, v0.16b, #1 /* rotate out the mac bytes */ ++ b 7b ++8: mov w7, w8 ++ add w8, w8, #16 ++9: ext v1.16b, v1.16b, v1.16b, #1 ++ adds w7, w7, #1 ++ bne 9b ++ eor v0.16b, v0.16b, v1.16b ++ st1 {v0.2d}, [x0] ++10: str w8, [x3] ++ ret ++ENDPROC(ce_aes_ccm_auth_data) ++ ++ /* ++ * void ce_aes_ccm_final(u8 mac[], u8 const ctr[], u8 const rk[], ++ * u32 rounds); ++ */ ++ENTRY(ce_aes_ccm_final) ++ ld1 {v3.2d}, [x2], #16 /* load first round key */ ++ ld1 {v0.2d}, [x0] /* load mac */ ++ cmp w3, #12 /* which key size? */ ++ sub w3, w3, #2 /* modified # of rounds */ ++ ld1 {v1.2d}, [x1] /* load 1st ctriv */ ++ bmi 0f ++ bne 3f ++ mov v5.16b, v3.16b ++ b 2f ++0: mov v4.16b, v3.16b ++1: ld1 {v5.2d}, [x2], #16 /* load next round key */ ++ aese v0.16b, v4.16b ++ aese v1.16b, v4.16b ++ aesmc v0.16b, v0.16b ++ aesmc v1.16b, v1.16b ++2: ld1 {v3.2d}, [x2], #16 /* load next round key */ ++ aese v0.16b, v5.16b ++ aese v1.16b, v5.16b ++ aesmc v0.16b, v0.16b ++ aesmc v1.16b, v1.16b ++3: ld1 {v4.2d}, [x2], #16 /* load next round key */ ++ subs w3, w3, #3 ++ aese v0.16b, v3.16b ++ aese v1.16b, v3.16b ++ aesmc v0.16b, v0.16b ++ aesmc v1.16b, v1.16b ++ bpl 1b ++ aese v0.16b, v4.16b ++ aese v1.16b, v4.16b ++ /* final round key cancels out */ ++ eor v0.16b, v0.16b, v1.16b /* en-/decrypt the mac */ ++ st1 {v0.2d}, [x0] /* store result */ ++ ret ++ENDPROC(ce_aes_ccm_final) ++ ++ .macro aes_ccm_do_crypt,enc ++ ldr x8, [x6, #8] /* load lower ctr */ ++ ld1 {v0.2d}, [x5] /* load mac */ ++ rev x8, x8 /* keep swabbed ctr in reg */ ++0: /* outer loop */ ++ ld1 {v1.1d}, [x6] /* load upper ctr */ ++ prfm pldl1strm, [x1] ++ add x8, x8, #1 ++ rev x9, x8 ++ cmp w4, #12 /* which key size? */ ++ sub w7, w4, #2 /* get modified # of rounds */ ++ ins v1.d[1], x9 /* no carry in lower ctr */ ++ ld1 {v3.2d}, [x3] /* load first round key */ ++ add x10, x3, #16 ++ bmi 1f ++ bne 4f ++ mov v5.16b, v3.16b ++ b 3f ++1: mov v4.16b, v3.16b ++ ld1 {v5.2d}, [x10], #16 /* load 2nd round key */ ++2: /* inner loop: 3 rounds, 2x interleaved */ ++ aese v0.16b, v4.16b ++ aese v1.16b, v4.16b ++ aesmc v0.16b, v0.16b ++ aesmc v1.16b, v1.16b ++3: ld1 {v3.2d}, [x10], #16 /* load next round key */ ++ aese v0.16b, v5.16b ++ aese v1.16b, v5.16b ++ aesmc v0.16b, v0.16b ++ aesmc v1.16b, v1.16b ++4: ld1 {v4.2d}, [x10], #16 /* load next round key */ ++ subs w7, w7, #3 ++ aese v0.16b, v3.16b ++ aese v1.16b, v3.16b ++ aesmc v0.16b, v0.16b ++ aesmc v1.16b, v1.16b ++ ld1 {v5.2d}, [x10], #16 /* load next round key */ ++ bpl 2b ++ aese v0.16b, v4.16b ++ aese v1.16b, v4.16b ++ subs w2, w2, #16 ++ bmi 6f /* partial block? */ ++ ld1 {v2.16b}, [x1], #16 /* load next input block */ ++ .if \enc == 1 ++ eor v2.16b, v2.16b, v5.16b /* final round enc+mac */ ++ eor v1.16b, v1.16b, v2.16b /* xor with crypted ctr */ ++ .else ++ eor v2.16b, v2.16b, v1.16b /* xor with crypted ctr */ ++ eor v1.16b, v2.16b, v5.16b /* final round enc */ ++ .endif ++ eor v0.16b, v0.16b, v2.16b /* xor mac with pt ^ rk[last] */ ++ st1 {v1.16b}, [x0], #16 /* write output block */ ++ bne 0b ++ rev x8, x8 ++ st1 {v0.2d}, [x5] /* store mac */ ++ str x8, [x6, #8] /* store lsb end of ctr (BE) */ ++5: ret ++ ++6: eor v0.16b, v0.16b, v5.16b /* final round mac */ ++ eor v1.16b, v1.16b, v5.16b /* final round enc */ ++ st1 {v0.2d}, [x5] /* store mac */ ++ add w2, w2, #16 /* process partial tail block */ ++7: ldrb w9, [x1], #1 /* get 1 byte of input */ ++ umov w6, v1.b[0] /* get top crypted ctr byte */ ++ umov w7, v0.b[0] /* get top mac byte */ ++ .if \enc == 1 ++ eor w7, w7, w9 ++ eor w9, w9, w6 ++ .else ++ eor w9, w9, w6 ++ eor w7, w7, w9 ++ .endif ++ strb w9, [x0], #1 /* store out byte */ ++ strb w7, [x5], #1 /* store mac byte */ ++ subs w2, w2, #1 ++ beq 5b ++ ext v0.16b, v0.16b, v0.16b, #1 /* shift out mac byte */ ++ ext v1.16b, v1.16b, v1.16b, #1 /* shift out ctr byte */ ++ b 7b ++ .endm ++ ++ /* ++ * void ce_aes_ccm_encrypt(u8 out[], u8 const in[], u32 cbytes, ++ * u8 const rk[], u32 rounds, u8 mac[], ++ * u8 ctr[]); ++ * void ce_aes_ccm_decrypt(u8 out[], u8 const in[], u32 cbytes, ++ * u8 const rk[], u32 rounds, u8 mac[], ++ * u8 ctr[]); ++ */ ++ENTRY(ce_aes_ccm_encrypt) ++ aes_ccm_do_crypt 1 ++ENDPROC(ce_aes_ccm_encrypt) ++ ++ENTRY(ce_aes_ccm_decrypt) ++ aes_ccm_do_crypt 0 ++ENDPROC(ce_aes_ccm_decrypt) +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/aes-ce-ccm-glue.c linux-3.14.40/arch/arm64/crypto/aes-ce-ccm-glue.c +--- linux-3.14.40.orig/arch/arm64/crypto/aes-ce-ccm-glue.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/aes-ce-ccm-glue.c 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,297 @@ ++/* ++ * aes-ccm-glue.c - AES-CCM transform for ARMv8 with Crypto Extensions ++ * ++ * Copyright (C) 2013 - 2014 Linaro 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int num_rounds(struct crypto_aes_ctx *ctx) ++{ ++ /* ++ * # of rounds specified by AES: ++ * 128 bit key 10 rounds ++ * 192 bit key 12 rounds ++ * 256 bit key 14 rounds ++ * => n byte key => 6 + (n/4) rounds ++ */ ++ return 6 + ctx->key_length / 4; ++} ++ ++asmlinkage void ce_aes_ccm_auth_data(u8 mac[], u8 const in[], u32 abytes, ++ u32 *macp, u32 const rk[], u32 rounds); ++ ++asmlinkage void ce_aes_ccm_encrypt(u8 out[], u8 const in[], u32 cbytes, ++ u32 const rk[], u32 rounds, u8 mac[], ++ u8 ctr[]); ++ ++asmlinkage void ce_aes_ccm_decrypt(u8 out[], u8 const in[], u32 cbytes, ++ u32 const rk[], u32 rounds, u8 mac[], ++ u8 ctr[]); ++ ++asmlinkage void ce_aes_ccm_final(u8 mac[], u8 const ctr[], u32 const rk[], ++ u32 rounds); ++ ++static int ccm_setkey(struct crypto_aead *tfm, const u8 *in_key, ++ unsigned int key_len) ++{ ++ struct crypto_aes_ctx *ctx = crypto_aead_ctx(tfm); ++ int ret; ++ ++ ret = crypto_aes_expand_key(ctx, in_key, key_len); ++ if (!ret) ++ return 0; ++ ++ tfm->base.crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; ++ return -EINVAL; ++} ++ ++static int ccm_setauthsize(struct crypto_aead *tfm, unsigned int authsize) ++{ ++ if ((authsize & 1) || authsize < 4) ++ return -EINVAL; ++ return 0; ++} ++ ++static int ccm_init_mac(struct aead_request *req, u8 maciv[], u32 msglen) ++{ ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ __be32 *n = (__be32 *)&maciv[AES_BLOCK_SIZE - 8]; ++ u32 l = req->iv[0] + 1; ++ ++ /* verify that CCM dimension 'L' is set correctly in the IV */ ++ if (l < 2 || l > 8) ++ return -EINVAL; ++ ++ /* verify that msglen can in fact be represented in L bytes */ ++ if (l < 4 && msglen >> (8 * l)) ++ return -EOVERFLOW; ++ ++ /* ++ * Even if the CCM spec allows L values of up to 8, the Linux cryptoapi ++ * uses a u32 type to represent msglen so the top 4 bytes are always 0. ++ */ ++ n[0] = 0; ++ n[1] = cpu_to_be32(msglen); ++ ++ memcpy(maciv, req->iv, AES_BLOCK_SIZE - l); ++ ++ /* ++ * Meaning of byte 0 according to CCM spec (RFC 3610/NIST 800-38C) ++ * - bits 0..2 : max # of bytes required to represent msglen, minus 1 ++ * (already set by caller) ++ * - bits 3..5 : size of auth tag (1 => 4 bytes, 2 => 6 bytes, etc) ++ * - bit 6 : indicates presence of authenticate-only data ++ */ ++ maciv[0] |= (crypto_aead_authsize(aead) - 2) << 2; ++ if (req->assoclen) ++ maciv[0] |= 0x40; ++ ++ memset(&req->iv[AES_BLOCK_SIZE - l], 0, l); ++ return 0; ++} ++ ++static void ccm_calculate_auth_mac(struct aead_request *req, u8 mac[]) ++{ ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct crypto_aes_ctx *ctx = crypto_aead_ctx(aead); ++ struct __packed { __be16 l; __be32 h; u16 len; } ltag; ++ struct scatter_walk walk; ++ u32 len = req->assoclen; ++ u32 macp = 0; ++ ++ /* prepend the AAD with a length tag */ ++ if (len < 0xff00) { ++ ltag.l = cpu_to_be16(len); ++ ltag.len = 2; ++ } else { ++ ltag.l = cpu_to_be16(0xfffe); ++ put_unaligned_be32(len, <ag.h); ++ ltag.len = 6; ++ } ++ ++ ce_aes_ccm_auth_data(mac, (u8 *)<ag, ltag.len, &macp, ctx->key_enc, ++ num_rounds(ctx)); ++ scatterwalk_start(&walk, req->assoc); ++ ++ do { ++ u32 n = scatterwalk_clamp(&walk, len); ++ u8 *p; ++ ++ if (!n) { ++ scatterwalk_start(&walk, sg_next(walk.sg)); ++ n = scatterwalk_clamp(&walk, len); ++ } ++ p = scatterwalk_map(&walk); ++ ce_aes_ccm_auth_data(mac, p, n, &macp, ctx->key_enc, ++ num_rounds(ctx)); ++ len -= n; ++ ++ scatterwalk_unmap(p); ++ scatterwalk_advance(&walk, n); ++ scatterwalk_done(&walk, 0, len); ++ } while (len); ++} ++ ++static int ccm_encrypt(struct aead_request *req) ++{ ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct crypto_aes_ctx *ctx = crypto_aead_ctx(aead); ++ struct blkcipher_desc desc = { .info = req->iv }; ++ struct blkcipher_walk walk; ++ u8 __aligned(8) mac[AES_BLOCK_SIZE]; ++ u8 buf[AES_BLOCK_SIZE]; ++ u32 len = req->cryptlen; ++ int err; ++ ++ err = ccm_init_mac(req, mac, len); ++ if (err) ++ return err; ++ ++ kernel_neon_begin_partial(6); ++ ++ if (req->assoclen) ++ ccm_calculate_auth_mac(req, mac); ++ ++ /* preserve the original iv for the final round */ ++ memcpy(buf, req->iv, AES_BLOCK_SIZE); ++ ++ blkcipher_walk_init(&walk, req->dst, req->src, len); ++ err = blkcipher_aead_walk_virt_block(&desc, &walk, aead, ++ AES_BLOCK_SIZE); ++ ++ while (walk.nbytes) { ++ u32 tail = walk.nbytes % AES_BLOCK_SIZE; ++ ++ if (walk.nbytes == len) ++ tail = 0; ++ ++ ce_aes_ccm_encrypt(walk.dst.virt.addr, walk.src.virt.addr, ++ walk.nbytes - tail, ctx->key_enc, ++ num_rounds(ctx), mac, walk.iv); ++ ++ len -= walk.nbytes - tail; ++ err = blkcipher_walk_done(&desc, &walk, tail); ++ } ++ if (!err) ++ ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx)); ++ ++ kernel_neon_end(); ++ ++ if (err) ++ return err; ++ ++ /* copy authtag to end of dst */ ++ scatterwalk_map_and_copy(mac, req->dst, req->cryptlen, ++ crypto_aead_authsize(aead), 1); ++ ++ return 0; ++} ++ ++static int ccm_decrypt(struct aead_request *req) ++{ ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct crypto_aes_ctx *ctx = crypto_aead_ctx(aead); ++ unsigned int authsize = crypto_aead_authsize(aead); ++ struct blkcipher_desc desc = { .info = req->iv }; ++ struct blkcipher_walk walk; ++ u8 __aligned(8) mac[AES_BLOCK_SIZE]; ++ u8 buf[AES_BLOCK_SIZE]; ++ u32 len = req->cryptlen - authsize; ++ int err; ++ ++ err = ccm_init_mac(req, mac, len); ++ if (err) ++ return err; ++ ++ kernel_neon_begin_partial(6); ++ ++ if (req->assoclen) ++ ccm_calculate_auth_mac(req, mac); ++ ++ /* preserve the original iv for the final round */ ++ memcpy(buf, req->iv, AES_BLOCK_SIZE); ++ ++ blkcipher_walk_init(&walk, req->dst, req->src, len); ++ err = blkcipher_aead_walk_virt_block(&desc, &walk, aead, ++ AES_BLOCK_SIZE); ++ ++ while (walk.nbytes) { ++ u32 tail = walk.nbytes % AES_BLOCK_SIZE; ++ ++ if (walk.nbytes == len) ++ tail = 0; ++ ++ ce_aes_ccm_decrypt(walk.dst.virt.addr, walk.src.virt.addr, ++ walk.nbytes - tail, ctx->key_enc, ++ num_rounds(ctx), mac, walk.iv); ++ ++ len -= walk.nbytes - tail; ++ err = blkcipher_walk_done(&desc, &walk, tail); ++ } ++ if (!err) ++ ce_aes_ccm_final(mac, buf, ctx->key_enc, num_rounds(ctx)); ++ ++ kernel_neon_end(); ++ ++ if (err) ++ return err; ++ ++ /* compare calculated auth tag with the stored one */ ++ scatterwalk_map_and_copy(buf, req->src, req->cryptlen - authsize, ++ authsize, 0); ++ ++ if (memcmp(mac, buf, authsize)) ++ return -EBADMSG; ++ return 0; ++} ++ ++static struct crypto_alg ccm_aes_alg = { ++ .cra_name = "ccm(aes)", ++ .cra_driver_name = "ccm-aes-ce", ++ .cra_priority = 300, ++ .cra_flags = CRYPTO_ALG_TYPE_AEAD, ++ .cra_blocksize = 1, ++ .cra_ctxsize = sizeof(struct crypto_aes_ctx), ++ .cra_alignmask = 7, ++ .cra_type = &crypto_aead_type, ++ .cra_module = THIS_MODULE, ++ .cra_aead = { ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = AES_BLOCK_SIZE, ++ .setkey = ccm_setkey, ++ .setauthsize = ccm_setauthsize, ++ .encrypt = ccm_encrypt, ++ .decrypt = ccm_decrypt, ++ } ++}; ++ ++static int __init aes_mod_init(void) ++{ ++ if (!(elf_hwcap & HWCAP_AES)) ++ return -ENODEV; ++ return crypto_register_alg(&ccm_aes_alg); ++} ++ ++static void __exit aes_mod_exit(void) ++{ ++ crypto_unregister_alg(&ccm_aes_alg); ++} ++ ++module_init(aes_mod_init); ++module_exit(aes_mod_exit); ++ ++MODULE_DESCRIPTION("Synchronous AES in CCM mode using ARMv8 Crypto Extensions"); ++MODULE_AUTHOR("Ard Biesheuvel "); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("ccm(aes)"); +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/aes-ce-cipher.c linux-3.14.40/arch/arm64/crypto/aes-ce-cipher.c +--- linux-3.14.40.orig/arch/arm64/crypto/aes-ce-cipher.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/aes-ce-cipher.c 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,155 @@ ++/* ++ * aes-ce-cipher.c - core AES cipher using ARMv8 Crypto Extensions ++ * ++ * Copyright (C) 2013 - 2014 Linaro 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_DESCRIPTION("Synchronous AES cipher using ARMv8 Crypto Extensions"); ++MODULE_AUTHOR("Ard Biesheuvel "); ++MODULE_LICENSE("GPL v2"); ++ ++struct aes_block { ++ u8 b[AES_BLOCK_SIZE]; ++}; ++ ++static int num_rounds(struct crypto_aes_ctx *ctx) ++{ ++ /* ++ * # of rounds specified by AES: ++ * 128 bit key 10 rounds ++ * 192 bit key 12 rounds ++ * 256 bit key 14 rounds ++ * => n byte key => 6 + (n/4) rounds ++ */ ++ return 6 + ctx->key_length / 4; ++} ++ ++static void aes_cipher_encrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) ++{ ++ struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct aes_block *out = (struct aes_block *)dst; ++ struct aes_block const *in = (struct aes_block *)src; ++ void *dummy0; ++ int dummy1; ++ ++ kernel_neon_begin_partial(4); ++ ++ __asm__(" ld1 {v0.16b}, %[in] ;" ++ " ld1 {v1.2d}, [%[key]], #16 ;" ++ " cmp %w[rounds], #10 ;" ++ " bmi 0f ;" ++ " bne 3f ;" ++ " mov v3.16b, v1.16b ;" ++ " b 2f ;" ++ "0: mov v2.16b, v1.16b ;" ++ " ld1 {v3.2d}, [%[key]], #16 ;" ++ "1: aese v0.16b, v2.16b ;" ++ " aesmc v0.16b, v0.16b ;" ++ "2: ld1 {v1.2d}, [%[key]], #16 ;" ++ " aese v0.16b, v3.16b ;" ++ " aesmc v0.16b, v0.16b ;" ++ "3: ld1 {v2.2d}, [%[key]], #16 ;" ++ " subs %w[rounds], %w[rounds], #3 ;" ++ " aese v0.16b, v1.16b ;" ++ " aesmc v0.16b, v0.16b ;" ++ " ld1 {v3.2d}, [%[key]], #16 ;" ++ " bpl 1b ;" ++ " aese v0.16b, v2.16b ;" ++ " eor v0.16b, v0.16b, v3.16b ;" ++ " st1 {v0.16b}, %[out] ;" ++ ++ : [out] "=Q"(*out), ++ [key] "=r"(dummy0), ++ [rounds] "=r"(dummy1) ++ : [in] "Q"(*in), ++ "1"(ctx->key_enc), ++ "2"(num_rounds(ctx) - 2) ++ : "cc"); ++ ++ kernel_neon_end(); ++} ++ ++static void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) ++{ ++ struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); ++ struct aes_block *out = (struct aes_block *)dst; ++ struct aes_block const *in = (struct aes_block *)src; ++ void *dummy0; ++ int dummy1; ++ ++ kernel_neon_begin_partial(4); ++ ++ __asm__(" ld1 {v0.16b}, %[in] ;" ++ " ld1 {v1.2d}, [%[key]], #16 ;" ++ " cmp %w[rounds], #10 ;" ++ " bmi 0f ;" ++ " bne 3f ;" ++ " mov v3.16b, v1.16b ;" ++ " b 2f ;" ++ "0: mov v2.16b, v1.16b ;" ++ " ld1 {v3.2d}, [%[key]], #16 ;" ++ "1: aesd v0.16b, v2.16b ;" ++ " aesimc v0.16b, v0.16b ;" ++ "2: ld1 {v1.2d}, [%[key]], #16 ;" ++ " aesd v0.16b, v3.16b ;" ++ " aesimc v0.16b, v0.16b ;" ++ "3: ld1 {v2.2d}, [%[key]], #16 ;" ++ " subs %w[rounds], %w[rounds], #3 ;" ++ " aesd v0.16b, v1.16b ;" ++ " aesimc v0.16b, v0.16b ;" ++ " ld1 {v3.2d}, [%[key]], #16 ;" ++ " bpl 1b ;" ++ " aesd v0.16b, v2.16b ;" ++ " eor v0.16b, v0.16b, v3.16b ;" ++ " st1 {v0.16b}, %[out] ;" ++ ++ : [out] "=Q"(*out), ++ [key] "=r"(dummy0), ++ [rounds] "=r"(dummy1) ++ : [in] "Q"(*in), ++ "1"(ctx->key_dec), ++ "2"(num_rounds(ctx) - 2) ++ : "cc"); ++ ++ kernel_neon_end(); ++} ++ ++static struct crypto_alg aes_alg = { ++ .cra_name = "aes", ++ .cra_driver_name = "aes-ce", ++ .cra_priority = 300, ++ .cra_flags = CRYPTO_ALG_TYPE_CIPHER, ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct crypto_aes_ctx), ++ .cra_module = THIS_MODULE, ++ .cra_cipher = { ++ .cia_min_keysize = AES_MIN_KEY_SIZE, ++ .cia_max_keysize = AES_MAX_KEY_SIZE, ++ .cia_setkey = crypto_aes_set_key, ++ .cia_encrypt = aes_cipher_encrypt, ++ .cia_decrypt = aes_cipher_decrypt ++ } ++}; ++ ++static int __init aes_mod_init(void) ++{ ++ return crypto_register_alg(&aes_alg); ++} ++ ++static void __exit aes_mod_exit(void) ++{ ++ crypto_unregister_alg(&aes_alg); ++} ++ ++module_cpu_feature_match(AES, aes_mod_init); ++module_exit(aes_mod_exit); +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/aes-ce.S linux-3.14.40/arch/arm64/crypto/aes-ce.S +--- linux-3.14.40.orig/arch/arm64/crypto/aes-ce.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/aes-ce.S 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,133 @@ ++/* ++ * linux/arch/arm64/crypto/aes-ce.S - AES cipher for ARMv8 with ++ * Crypto Extensions ++ * ++ * Copyright (C) 2013 Linaro 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. ++ */ ++ ++#include ++ ++#define AES_ENTRY(func) ENTRY(ce_ ## func) ++#define AES_ENDPROC(func) ENDPROC(ce_ ## func) ++ ++ .arch armv8-a+crypto ++ ++ /* preload all round keys */ ++ .macro load_round_keys, rounds, rk ++ cmp \rounds, #12 ++ blo 2222f /* 128 bits */ ++ beq 1111f /* 192 bits */ ++ ld1 {v17.16b-v18.16b}, [\rk], #32 ++1111: ld1 {v19.16b-v20.16b}, [\rk], #32 ++2222: ld1 {v21.16b-v24.16b}, [\rk], #64 ++ ld1 {v25.16b-v28.16b}, [\rk], #64 ++ ld1 {v29.16b-v31.16b}, [\rk] ++ .endm ++ ++ /* prepare for encryption with key in rk[] */ ++ .macro enc_prepare, rounds, rk, ignore ++ load_round_keys \rounds, \rk ++ .endm ++ ++ /* prepare for encryption (again) but with new key in rk[] */ ++ .macro enc_switch_key, rounds, rk, ignore ++ load_round_keys \rounds, \rk ++ .endm ++ ++ /* prepare for decryption with key in rk[] */ ++ .macro dec_prepare, rounds, rk, ignore ++ load_round_keys \rounds, \rk ++ .endm ++ ++ .macro do_enc_Nx, de, mc, k, i0, i1, i2, i3 ++ aes\de \i0\().16b, \k\().16b ++ .ifnb \i1 ++ aes\de \i1\().16b, \k\().16b ++ .ifnb \i3 ++ aes\de \i2\().16b, \k\().16b ++ aes\de \i3\().16b, \k\().16b ++ .endif ++ .endif ++ aes\mc \i0\().16b, \i0\().16b ++ .ifnb \i1 ++ aes\mc \i1\().16b, \i1\().16b ++ .ifnb \i3 ++ aes\mc \i2\().16b, \i2\().16b ++ aes\mc \i3\().16b, \i3\().16b ++ .endif ++ .endif ++ .endm ++ ++ /* up to 4 interleaved encryption rounds with the same round key */ ++ .macro round_Nx, enc, k, i0, i1, i2, i3 ++ .ifc \enc, e ++ do_enc_Nx e, mc, \k, \i0, \i1, \i2, \i3 ++ .else ++ do_enc_Nx d, imc, \k, \i0, \i1, \i2, \i3 ++ .endif ++ .endm ++ ++ /* up to 4 interleaved final rounds */ ++ .macro fin_round_Nx, de, k, k2, i0, i1, i2, i3 ++ aes\de \i0\().16b, \k\().16b ++ .ifnb \i1 ++ aes\de \i1\().16b, \k\().16b ++ .ifnb \i3 ++ aes\de \i2\().16b, \k\().16b ++ aes\de \i3\().16b, \k\().16b ++ .endif ++ .endif ++ eor \i0\().16b, \i0\().16b, \k2\().16b ++ .ifnb \i1 ++ eor \i1\().16b, \i1\().16b, \k2\().16b ++ .ifnb \i3 ++ eor \i2\().16b, \i2\().16b, \k2\().16b ++ eor \i3\().16b, \i3\().16b, \k2\().16b ++ .endif ++ .endif ++ .endm ++ ++ /* up to 4 interleaved blocks */ ++ .macro do_block_Nx, enc, rounds, i0, i1, i2, i3 ++ cmp \rounds, #12 ++ blo 2222f /* 128 bits */ ++ beq 1111f /* 192 bits */ ++ round_Nx \enc, v17, \i0, \i1, \i2, \i3 ++ round_Nx \enc, v18, \i0, \i1, \i2, \i3 ++1111: round_Nx \enc, v19, \i0, \i1, \i2, \i3 ++ round_Nx \enc, v20, \i0, \i1, \i2, \i3 ++2222: .irp key, v21, v22, v23, v24, v25, v26, v27, v28, v29 ++ round_Nx \enc, \key, \i0, \i1, \i2, \i3 ++ .endr ++ fin_round_Nx \enc, v30, v31, \i0, \i1, \i2, \i3 ++ .endm ++ ++ .macro encrypt_block, in, rounds, t0, t1, t2 ++ do_block_Nx e, \rounds, \in ++ .endm ++ ++ .macro encrypt_block2x, i0, i1, rounds, t0, t1, t2 ++ do_block_Nx e, \rounds, \i0, \i1 ++ .endm ++ ++ .macro encrypt_block4x, i0, i1, i2, i3, rounds, t0, t1, t2 ++ do_block_Nx e, \rounds, \i0, \i1, \i2, \i3 ++ .endm ++ ++ .macro decrypt_block, in, rounds, t0, t1, t2 ++ do_block_Nx d, \rounds, \in ++ .endm ++ ++ .macro decrypt_block2x, i0, i1, rounds, t0, t1, t2 ++ do_block_Nx d, \rounds, \i0, \i1 ++ .endm ++ ++ .macro decrypt_block4x, i0, i1, i2, i3, rounds, t0, t1, t2 ++ do_block_Nx d, \rounds, \i0, \i1, \i2, \i3 ++ .endm ++ ++#include "aes-modes.S" +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/aes-glue.c linux-3.14.40/arch/arm64/crypto/aes-glue.c +--- linux-3.14.40.orig/arch/arm64/crypto/aes-glue.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/aes-glue.c 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,446 @@ ++/* ++ * linux/arch/arm64/crypto/aes-glue.c - wrapper code for ARMv8 AES ++ * ++ * Copyright (C) 2013 Linaro 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef USE_V8_CRYPTO_EXTENSIONS ++#define MODE "ce" ++#define PRIO 300 ++#define aes_ecb_encrypt ce_aes_ecb_encrypt ++#define aes_ecb_decrypt ce_aes_ecb_decrypt ++#define aes_cbc_encrypt ce_aes_cbc_encrypt ++#define aes_cbc_decrypt ce_aes_cbc_decrypt ++#define aes_ctr_encrypt ce_aes_ctr_encrypt ++#define aes_xts_encrypt ce_aes_xts_encrypt ++#define aes_xts_decrypt ce_aes_xts_decrypt ++MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions"); ++#else ++#define MODE "neon" ++#define PRIO 200 ++#define aes_ecb_encrypt neon_aes_ecb_encrypt ++#define aes_ecb_decrypt neon_aes_ecb_decrypt ++#define aes_cbc_encrypt neon_aes_cbc_encrypt ++#define aes_cbc_decrypt neon_aes_cbc_decrypt ++#define aes_ctr_encrypt neon_aes_ctr_encrypt ++#define aes_xts_encrypt neon_aes_xts_encrypt ++#define aes_xts_decrypt neon_aes_xts_decrypt ++MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 NEON"); ++MODULE_ALIAS("ecb(aes)"); ++MODULE_ALIAS("cbc(aes)"); ++MODULE_ALIAS("ctr(aes)"); ++MODULE_ALIAS("xts(aes)"); ++#endif ++ ++MODULE_AUTHOR("Ard Biesheuvel "); ++MODULE_LICENSE("GPL v2"); ++ ++/* defined in aes-modes.S */ ++asmlinkage void aes_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[], ++ int rounds, int blocks, int first); ++asmlinkage void aes_ecb_decrypt(u8 out[], u8 const in[], u8 const rk[], ++ int rounds, int blocks, int first); ++ ++asmlinkage void aes_cbc_encrypt(u8 out[], u8 const in[], u8 const rk[], ++ int rounds, int blocks, u8 iv[], int first); ++asmlinkage void aes_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[], ++ int rounds, int blocks, u8 iv[], int first); ++ ++asmlinkage void aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], ++ int rounds, int blocks, u8 ctr[], int first); ++ ++asmlinkage void aes_xts_encrypt(u8 out[], u8 const in[], u8 const rk1[], ++ int rounds, int blocks, u8 const rk2[], u8 iv[], ++ int first); ++asmlinkage void aes_xts_decrypt(u8 out[], u8 const in[], u8 const rk1[], ++ int rounds, int blocks, u8 const rk2[], u8 iv[], ++ int first); ++ ++struct crypto_aes_xts_ctx { ++ struct crypto_aes_ctx key1; ++ struct crypto_aes_ctx __aligned(8) key2; ++}; ++ ++static int xts_set_key(struct crypto_tfm *tfm, const u8 *in_key, ++ unsigned int key_len) ++{ ++ struct crypto_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm); ++ int ret; ++ ++ ret = crypto_aes_expand_key(&ctx->key1, in_key, key_len / 2); ++ if (!ret) ++ ret = crypto_aes_expand_key(&ctx->key2, &in_key[key_len / 2], ++ key_len / 2); ++ if (!ret) ++ return 0; ++ ++ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; ++ return -EINVAL; ++} ++ ++static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, ++ struct scatterlist *src, unsigned int nbytes) ++{ ++ struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); ++ int err, first, rounds = 6 + ctx->key_length / 4; ++ struct blkcipher_walk walk; ++ unsigned int blocks; ++ ++ desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; ++ blkcipher_walk_init(&walk, dst, src, nbytes); ++ err = blkcipher_walk_virt(desc, &walk); ++ ++ kernel_neon_begin(); ++ for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { ++ aes_ecb_encrypt(walk.dst.virt.addr, walk.src.virt.addr, ++ (u8 *)ctx->key_enc, rounds, blocks, first); ++ err = blkcipher_walk_done(desc, &walk, 0); ++ } ++ kernel_neon_end(); ++ return err; ++} ++ ++static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, ++ struct scatterlist *src, unsigned int nbytes) ++{ ++ struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); ++ int err, first, rounds = 6 + ctx->key_length / 4; ++ struct blkcipher_walk walk; ++ unsigned int blocks; ++ ++ desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; ++ blkcipher_walk_init(&walk, dst, src, nbytes); ++ err = blkcipher_walk_virt(desc, &walk); ++ ++ kernel_neon_begin(); ++ for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { ++ aes_ecb_decrypt(walk.dst.virt.addr, walk.src.virt.addr, ++ (u8 *)ctx->key_dec, rounds, blocks, first); ++ err = blkcipher_walk_done(desc, &walk, 0); ++ } ++ kernel_neon_end(); ++ return err; ++} ++ ++static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, ++ struct scatterlist *src, unsigned int nbytes) ++{ ++ struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); ++ int err, first, rounds = 6 + ctx->key_length / 4; ++ struct blkcipher_walk walk; ++ unsigned int blocks; ++ ++ desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; ++ blkcipher_walk_init(&walk, dst, src, nbytes); ++ err = blkcipher_walk_virt(desc, &walk); ++ ++ kernel_neon_begin(); ++ for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { ++ aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr, ++ (u8 *)ctx->key_enc, rounds, blocks, walk.iv, ++ first); ++ err = blkcipher_walk_done(desc, &walk, 0); ++ } ++ kernel_neon_end(); ++ return err; ++} ++ ++static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, ++ struct scatterlist *src, unsigned int nbytes) ++{ ++ struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); ++ int err, first, rounds = 6 + ctx->key_length / 4; ++ struct blkcipher_walk walk; ++ unsigned int blocks; ++ ++ desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; ++ blkcipher_walk_init(&walk, dst, src, nbytes); ++ err = blkcipher_walk_virt(desc, &walk); ++ ++ kernel_neon_begin(); ++ for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { ++ aes_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr, ++ (u8 *)ctx->key_dec, rounds, blocks, walk.iv, ++ first); ++ err = blkcipher_walk_done(desc, &walk, 0); ++ } ++ kernel_neon_end(); ++ return err; ++} ++ ++static int ctr_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, ++ struct scatterlist *src, unsigned int nbytes) ++{ ++ struct crypto_aes_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); ++ int err, first, rounds = 6 + ctx->key_length / 4; ++ struct blkcipher_walk walk; ++ int blocks; ++ ++ desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; ++ blkcipher_walk_init(&walk, dst, src, nbytes); ++ err = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE); ++ ++ first = 1; ++ kernel_neon_begin(); ++ while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { ++ aes_ctr_encrypt(walk.dst.virt.addr, walk.src.virt.addr, ++ (u8 *)ctx->key_enc, rounds, blocks, walk.iv, ++ first); ++ first = 0; ++ nbytes -= blocks * AES_BLOCK_SIZE; ++ if (nbytes && nbytes == walk.nbytes % AES_BLOCK_SIZE) ++ break; ++ err = blkcipher_walk_done(desc, &walk, ++ walk.nbytes % AES_BLOCK_SIZE); ++ } ++ if (nbytes) { ++ u8 *tdst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE; ++ u8 *tsrc = walk.src.virt.addr + blocks * AES_BLOCK_SIZE; ++ u8 __aligned(8) tail[AES_BLOCK_SIZE]; ++ ++ /* ++ * Minimum alignment is 8 bytes, so if nbytes is <= 8, we need ++ * to tell aes_ctr_encrypt() to only read half a block. ++ */ ++ blocks = (nbytes <= 8) ? -1 : 1; ++ ++ aes_ctr_encrypt(tail, tsrc, (u8 *)ctx->key_enc, rounds, ++ blocks, walk.iv, first); ++ memcpy(tdst, tail, nbytes); ++ err = blkcipher_walk_done(desc, &walk, 0); ++ } ++ kernel_neon_end(); ++ ++ return err; ++} ++ ++static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, ++ struct scatterlist *src, unsigned int nbytes) ++{ ++ struct crypto_aes_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); ++ int err, first, rounds = 6 + ctx->key1.key_length / 4; ++ struct blkcipher_walk walk; ++ unsigned int blocks; ++ ++ desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; ++ blkcipher_walk_init(&walk, dst, src, nbytes); ++ err = blkcipher_walk_virt(desc, &walk); ++ ++ kernel_neon_begin(); ++ for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { ++ aes_xts_encrypt(walk.dst.virt.addr, walk.src.virt.addr, ++ (u8 *)ctx->key1.key_enc, rounds, blocks, ++ (u8 *)ctx->key2.key_enc, walk.iv, first); ++ err = blkcipher_walk_done(desc, &walk, 0); ++ } ++ kernel_neon_end(); ++ ++ return err; ++} ++ ++static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, ++ struct scatterlist *src, unsigned int nbytes) ++{ ++ struct crypto_aes_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); ++ int err, first, rounds = 6 + ctx->key1.key_length / 4; ++ struct blkcipher_walk walk; ++ unsigned int blocks; ++ ++ desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; ++ blkcipher_walk_init(&walk, dst, src, nbytes); ++ err = blkcipher_walk_virt(desc, &walk); ++ ++ kernel_neon_begin(); ++ for (first = 1; (blocks = (walk.nbytes / AES_BLOCK_SIZE)); first = 0) { ++ aes_xts_decrypt(walk.dst.virt.addr, walk.src.virt.addr, ++ (u8 *)ctx->key1.key_dec, rounds, blocks, ++ (u8 *)ctx->key2.key_enc, walk.iv, first); ++ err = blkcipher_walk_done(desc, &walk, 0); ++ } ++ kernel_neon_end(); ++ ++ return err; ++} ++ ++static struct crypto_alg aes_algs[] = { { ++ .cra_name = "__ecb-aes-" MODE, ++ .cra_driver_name = "__driver-ecb-aes-" MODE, ++ .cra_priority = 0, ++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct crypto_aes_ctx), ++ .cra_alignmask = 7, ++ .cra_type = &crypto_blkcipher_type, ++ .cra_module = THIS_MODULE, ++ .cra_blkcipher = { ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ .setkey = crypto_aes_set_key, ++ .encrypt = ecb_encrypt, ++ .decrypt = ecb_decrypt, ++ }, ++}, { ++ .cra_name = "__cbc-aes-" MODE, ++ .cra_driver_name = "__driver-cbc-aes-" MODE, ++ .cra_priority = 0, ++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct crypto_aes_ctx), ++ .cra_alignmask = 7, ++ .cra_type = &crypto_blkcipher_type, ++ .cra_module = THIS_MODULE, ++ .cra_blkcipher = { ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ .setkey = crypto_aes_set_key, ++ .encrypt = cbc_encrypt, ++ .decrypt = cbc_decrypt, ++ }, ++}, { ++ .cra_name = "__ctr-aes-" MODE, ++ .cra_driver_name = "__driver-ctr-aes-" MODE, ++ .cra_priority = 0, ++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, ++ .cra_blocksize = 1, ++ .cra_ctxsize = sizeof(struct crypto_aes_ctx), ++ .cra_alignmask = 7, ++ .cra_type = &crypto_blkcipher_type, ++ .cra_module = THIS_MODULE, ++ .cra_blkcipher = { ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ .setkey = crypto_aes_set_key, ++ .encrypt = ctr_encrypt, ++ .decrypt = ctr_encrypt, ++ }, ++}, { ++ .cra_name = "__xts-aes-" MODE, ++ .cra_driver_name = "__driver-xts-aes-" MODE, ++ .cra_priority = 0, ++ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct crypto_aes_xts_ctx), ++ .cra_alignmask = 7, ++ .cra_type = &crypto_blkcipher_type, ++ .cra_module = THIS_MODULE, ++ .cra_blkcipher = { ++ .min_keysize = 2 * AES_MIN_KEY_SIZE, ++ .max_keysize = 2 * AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ .setkey = xts_set_key, ++ .encrypt = xts_encrypt, ++ .decrypt = xts_decrypt, ++ }, ++}, { ++ .cra_name = "ecb(aes)", ++ .cra_driver_name = "ecb-aes-" MODE, ++ .cra_priority = PRIO, ++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct async_helper_ctx), ++ .cra_alignmask = 7, ++ .cra_type = &crypto_ablkcipher_type, ++ .cra_module = THIS_MODULE, ++ .cra_init = ablk_init, ++ .cra_exit = ablk_exit, ++ .cra_ablkcipher = { ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ .setkey = ablk_set_key, ++ .encrypt = ablk_encrypt, ++ .decrypt = ablk_decrypt, ++ } ++}, { ++ .cra_name = "cbc(aes)", ++ .cra_driver_name = "cbc-aes-" MODE, ++ .cra_priority = PRIO, ++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct async_helper_ctx), ++ .cra_alignmask = 7, ++ .cra_type = &crypto_ablkcipher_type, ++ .cra_module = THIS_MODULE, ++ .cra_init = ablk_init, ++ .cra_exit = ablk_exit, ++ .cra_ablkcipher = { ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ .setkey = ablk_set_key, ++ .encrypt = ablk_encrypt, ++ .decrypt = ablk_decrypt, ++ } ++}, { ++ .cra_name = "ctr(aes)", ++ .cra_driver_name = "ctr-aes-" MODE, ++ .cra_priority = PRIO, ++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, ++ .cra_blocksize = 1, ++ .cra_ctxsize = sizeof(struct async_helper_ctx), ++ .cra_alignmask = 7, ++ .cra_type = &crypto_ablkcipher_type, ++ .cra_module = THIS_MODULE, ++ .cra_init = ablk_init, ++ .cra_exit = ablk_exit, ++ .cra_ablkcipher = { ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ .setkey = ablk_set_key, ++ .encrypt = ablk_encrypt, ++ .decrypt = ablk_decrypt, ++ } ++}, { ++ .cra_name = "xts(aes)", ++ .cra_driver_name = "xts-aes-" MODE, ++ .cra_priority = PRIO, ++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC, ++ .cra_blocksize = AES_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct async_helper_ctx), ++ .cra_alignmask = 7, ++ .cra_type = &crypto_ablkcipher_type, ++ .cra_module = THIS_MODULE, ++ .cra_init = ablk_init, ++ .cra_exit = ablk_exit, ++ .cra_ablkcipher = { ++ .min_keysize = 2 * AES_MIN_KEY_SIZE, ++ .max_keysize = 2 * AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ .setkey = ablk_set_key, ++ .encrypt = ablk_encrypt, ++ .decrypt = ablk_decrypt, ++ } ++} }; ++ ++static int __init aes_init(void) ++{ ++ return crypto_register_algs(aes_algs, ARRAY_SIZE(aes_algs)); ++} ++ ++static void __exit aes_exit(void) ++{ ++ crypto_unregister_algs(aes_algs, ARRAY_SIZE(aes_algs)); ++} ++ ++#ifdef USE_V8_CRYPTO_EXTENSIONS ++module_cpu_feature_match(AES, aes_init); ++#else ++module_init(aes_init); ++#endif ++module_exit(aes_exit); +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/aes-modes.S linux-3.14.40/arch/arm64/crypto/aes-modes.S +--- linux-3.14.40.orig/arch/arm64/crypto/aes-modes.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/aes-modes.S 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,532 @@ ++/* ++ * linux/arch/arm64/crypto/aes-modes.S - chaining mode wrappers for AES ++ * ++ * Copyright (C) 2013 Linaro 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. ++ */ ++ ++/* included by aes-ce.S and aes-neon.S */ ++ ++ .text ++ .align 4 ++ ++/* ++ * There are several ways to instantiate this code: ++ * - no interleave, all inline ++ * - 2-way interleave, 2x calls out of line (-DINTERLEAVE=2) ++ * - 2-way interleave, all inline (-DINTERLEAVE=2 -DINTERLEAVE_INLINE) ++ * - 4-way interleave, 4x calls out of line (-DINTERLEAVE=4) ++ * - 4-way interleave, all inline (-DINTERLEAVE=4 -DINTERLEAVE_INLINE) ++ * ++ * Macros imported by this code: ++ * - enc_prepare - setup NEON registers for encryption ++ * - dec_prepare - setup NEON registers for decryption ++ * - enc_switch_key - change to new key after having prepared for encryption ++ * - encrypt_block - encrypt a single block ++ * - decrypt block - decrypt a single block ++ * - encrypt_block2x - encrypt 2 blocks in parallel (if INTERLEAVE == 2) ++ * - decrypt_block2x - decrypt 2 blocks in parallel (if INTERLEAVE == 2) ++ * - encrypt_block4x - encrypt 4 blocks in parallel (if INTERLEAVE == 4) ++ * - decrypt_block4x - decrypt 4 blocks in parallel (if INTERLEAVE == 4) ++ */ ++ ++#if defined(INTERLEAVE) && !defined(INTERLEAVE_INLINE) ++#define FRAME_PUSH stp x29, x30, [sp,#-16]! ; mov x29, sp ++#define FRAME_POP ldp x29, x30, [sp],#16 ++ ++#if INTERLEAVE == 2 ++ ++aes_encrypt_block2x: ++ encrypt_block2x v0, v1, w3, x2, x6, w7 ++ ret ++ENDPROC(aes_encrypt_block2x) ++ ++aes_decrypt_block2x: ++ decrypt_block2x v0, v1, w3, x2, x6, w7 ++ ret ++ENDPROC(aes_decrypt_block2x) ++ ++#elif INTERLEAVE == 4 ++ ++aes_encrypt_block4x: ++ encrypt_block4x v0, v1, v2, v3, w3, x2, x6, w7 ++ ret ++ENDPROC(aes_encrypt_block4x) ++ ++aes_decrypt_block4x: ++ decrypt_block4x v0, v1, v2, v3, w3, x2, x6, w7 ++ ret ++ENDPROC(aes_decrypt_block4x) ++ ++#else ++#error INTERLEAVE should equal 2 or 4 ++#endif ++ ++ .macro do_encrypt_block2x ++ bl aes_encrypt_block2x ++ .endm ++ ++ .macro do_decrypt_block2x ++ bl aes_decrypt_block2x ++ .endm ++ ++ .macro do_encrypt_block4x ++ bl aes_encrypt_block4x ++ .endm ++ ++ .macro do_decrypt_block4x ++ bl aes_decrypt_block4x ++ .endm ++ ++#else ++#define FRAME_PUSH ++#define FRAME_POP ++ ++ .macro do_encrypt_block2x ++ encrypt_block2x v0, v1, w3, x2, x6, w7 ++ .endm ++ ++ .macro do_decrypt_block2x ++ decrypt_block2x v0, v1, w3, x2, x6, w7 ++ .endm ++ ++ .macro do_encrypt_block4x ++ encrypt_block4x v0, v1, v2, v3, w3, x2, x6, w7 ++ .endm ++ ++ .macro do_decrypt_block4x ++ decrypt_block4x v0, v1, v2, v3, w3, x2, x6, w7 ++ .endm ++ ++#endif ++ ++ /* ++ * aes_ecb_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, ++ * int blocks, int first) ++ * aes_ecb_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, ++ * int blocks, int first) ++ */ ++ ++AES_ENTRY(aes_ecb_encrypt) ++ FRAME_PUSH ++ cbz w5, .LecbencloopNx ++ ++ enc_prepare w3, x2, x5 ++ ++.LecbencloopNx: ++#if INTERLEAVE >= 2 ++ subs w4, w4, #INTERLEAVE ++ bmi .Lecbenc1x ++#if INTERLEAVE == 2 ++ ld1 {v0.16b-v1.16b}, [x1], #32 /* get 2 pt blocks */ ++ do_encrypt_block2x ++ st1 {v0.16b-v1.16b}, [x0], #32 ++#else ++ ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 pt blocks */ ++ do_encrypt_block4x ++ st1 {v0.16b-v3.16b}, [x0], #64 ++#endif ++ b .LecbencloopNx ++.Lecbenc1x: ++ adds w4, w4, #INTERLEAVE ++ beq .Lecbencout ++#endif ++.Lecbencloop: ++ ld1 {v0.16b}, [x1], #16 /* get next pt block */ ++ encrypt_block v0, w3, x2, x5, w6 ++ st1 {v0.16b}, [x0], #16 ++ subs w4, w4, #1 ++ bne .Lecbencloop ++.Lecbencout: ++ FRAME_POP ++ ret ++AES_ENDPROC(aes_ecb_encrypt) ++ ++ ++AES_ENTRY(aes_ecb_decrypt) ++ FRAME_PUSH ++ cbz w5, .LecbdecloopNx ++ ++ dec_prepare w3, x2, x5 ++ ++.LecbdecloopNx: ++#if INTERLEAVE >= 2 ++ subs w4, w4, #INTERLEAVE ++ bmi .Lecbdec1x ++#if INTERLEAVE == 2 ++ ld1 {v0.16b-v1.16b}, [x1], #32 /* get 2 ct blocks */ ++ do_decrypt_block2x ++ st1 {v0.16b-v1.16b}, [x0], #32 ++#else ++ ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 ct blocks */ ++ do_decrypt_block4x ++ st1 {v0.16b-v3.16b}, [x0], #64 ++#endif ++ b .LecbdecloopNx ++.Lecbdec1x: ++ adds w4, w4, #INTERLEAVE ++ beq .Lecbdecout ++#endif ++.Lecbdecloop: ++ ld1 {v0.16b}, [x1], #16 /* get next ct block */ ++ decrypt_block v0, w3, x2, x5, w6 ++ st1 {v0.16b}, [x0], #16 ++ subs w4, w4, #1 ++ bne .Lecbdecloop ++.Lecbdecout: ++ FRAME_POP ++ ret ++AES_ENDPROC(aes_ecb_decrypt) ++ ++ ++ /* ++ * aes_cbc_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, ++ * int blocks, u8 iv[], int first) ++ * aes_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, ++ * int blocks, u8 iv[], int first) ++ */ ++ ++AES_ENTRY(aes_cbc_encrypt) ++ cbz w6, .Lcbcencloop ++ ++ ld1 {v0.16b}, [x5] /* get iv */ ++ enc_prepare w3, x2, x5 ++ ++.Lcbcencloop: ++ ld1 {v1.16b}, [x1], #16 /* get next pt block */ ++ eor v0.16b, v0.16b, v1.16b /* ..and xor with iv */ ++ encrypt_block v0, w3, x2, x5, w6 ++ st1 {v0.16b}, [x0], #16 ++ subs w4, w4, #1 ++ bne .Lcbcencloop ++ ret ++AES_ENDPROC(aes_cbc_encrypt) ++ ++ ++AES_ENTRY(aes_cbc_decrypt) ++ FRAME_PUSH ++ cbz w6, .LcbcdecloopNx ++ ++ ld1 {v7.16b}, [x5] /* get iv */ ++ dec_prepare w3, x2, x5 ++ ++.LcbcdecloopNx: ++#if INTERLEAVE >= 2 ++ subs w4, w4, #INTERLEAVE ++ bmi .Lcbcdec1x ++#if INTERLEAVE == 2 ++ ld1 {v0.16b-v1.16b}, [x1], #32 /* get 2 ct blocks */ ++ mov v2.16b, v0.16b ++ mov v3.16b, v1.16b ++ do_decrypt_block2x ++ eor v0.16b, v0.16b, v7.16b ++ eor v1.16b, v1.16b, v2.16b ++ mov v7.16b, v3.16b ++ st1 {v0.16b-v1.16b}, [x0], #32 ++#else ++ ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 ct blocks */ ++ mov v4.16b, v0.16b ++ mov v5.16b, v1.16b ++ mov v6.16b, v2.16b ++ do_decrypt_block4x ++ sub x1, x1, #16 ++ eor v0.16b, v0.16b, v7.16b ++ eor v1.16b, v1.16b, v4.16b ++ ld1 {v7.16b}, [x1], #16 /* reload 1 ct block */ ++ eor v2.16b, v2.16b, v5.16b ++ eor v3.16b, v3.16b, v6.16b ++ st1 {v0.16b-v3.16b}, [x0], #64 ++#endif ++ b .LcbcdecloopNx ++.Lcbcdec1x: ++ adds w4, w4, #INTERLEAVE ++ beq .Lcbcdecout ++#endif ++.Lcbcdecloop: ++ ld1 {v1.16b}, [x1], #16 /* get next ct block */ ++ mov v0.16b, v1.16b /* ...and copy to v0 */ ++ decrypt_block v0, w3, x2, x5, w6 ++ eor v0.16b, v0.16b, v7.16b /* xor with iv => pt */ ++ mov v7.16b, v1.16b /* ct is next iv */ ++ st1 {v0.16b}, [x0], #16 ++ subs w4, w4, #1 ++ bne .Lcbcdecloop ++.Lcbcdecout: ++ FRAME_POP ++ ret ++AES_ENDPROC(aes_cbc_decrypt) ++ ++ ++ /* ++ * aes_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, ++ * int blocks, u8 ctr[], int first) ++ */ ++ ++AES_ENTRY(aes_ctr_encrypt) ++ FRAME_PUSH ++ cbnz w6, .Lctrfirst /* 1st time around? */ ++ umov x5, v4.d[1] /* keep swabbed ctr in reg */ ++ rev x5, x5 ++#if INTERLEAVE >= 2 ++ cmn w5, w4 /* 32 bit overflow? */ ++ bcs .Lctrinc ++ add x5, x5, #1 /* increment BE ctr */ ++ b .LctrincNx ++#else ++ b .Lctrinc ++#endif ++.Lctrfirst: ++ enc_prepare w3, x2, x6 ++ ld1 {v4.16b}, [x5] ++ umov x5, v4.d[1] /* keep swabbed ctr in reg */ ++ rev x5, x5 ++#if INTERLEAVE >= 2 ++ cmn w5, w4 /* 32 bit overflow? */ ++ bcs .Lctrloop ++.LctrloopNx: ++ subs w4, w4, #INTERLEAVE ++ bmi .Lctr1x ++#if INTERLEAVE == 2 ++ mov v0.8b, v4.8b ++ mov v1.8b, v4.8b ++ rev x7, x5 ++ add x5, x5, #1 ++ ins v0.d[1], x7 ++ rev x7, x5 ++ add x5, x5, #1 ++ ins v1.d[1], x7 ++ ld1 {v2.16b-v3.16b}, [x1], #32 /* get 2 input blocks */ ++ do_encrypt_block2x ++ eor v0.16b, v0.16b, v2.16b ++ eor v1.16b, v1.16b, v3.16b ++ st1 {v0.16b-v1.16b}, [x0], #32 ++#else ++ ldr q8, =0x30000000200000001 /* addends 1,2,3[,0] */ ++ dup v7.4s, w5 ++ mov v0.16b, v4.16b ++ add v7.4s, v7.4s, v8.4s ++ mov v1.16b, v4.16b ++ rev32 v8.16b, v7.16b ++ mov v2.16b, v4.16b ++ mov v3.16b, v4.16b ++ mov v1.s[3], v8.s[0] ++ mov v2.s[3], v8.s[1] ++ mov v3.s[3], v8.s[2] ++ ld1 {v5.16b-v7.16b}, [x1], #48 /* get 3 input blocks */ ++ do_encrypt_block4x ++ eor v0.16b, v5.16b, v0.16b ++ ld1 {v5.16b}, [x1], #16 /* get 1 input block */ ++ eor v1.16b, v6.16b, v1.16b ++ eor v2.16b, v7.16b, v2.16b ++ eor v3.16b, v5.16b, v3.16b ++ st1 {v0.16b-v3.16b}, [x0], #64 ++ add x5, x5, #INTERLEAVE ++#endif ++ cbz w4, .LctroutNx ++.LctrincNx: ++ rev x7, x5 ++ ins v4.d[1], x7 ++ b .LctrloopNx ++.LctroutNx: ++ sub x5, x5, #1 ++ rev x7, x5 ++ ins v4.d[1], x7 ++ b .Lctrout ++.Lctr1x: ++ adds w4, w4, #INTERLEAVE ++ beq .Lctrout ++#endif ++.Lctrloop: ++ mov v0.16b, v4.16b ++ encrypt_block v0, w3, x2, x6, w7 ++ subs w4, w4, #1 ++ bmi .Lctrhalfblock /* blocks < 0 means 1/2 block */ ++ ld1 {v3.16b}, [x1], #16 ++ eor v3.16b, v0.16b, v3.16b ++ st1 {v3.16b}, [x0], #16 ++ beq .Lctrout ++.Lctrinc: ++ adds x5, x5, #1 /* increment BE ctr */ ++ rev x7, x5 ++ ins v4.d[1], x7 ++ bcc .Lctrloop /* no overflow? */ ++ umov x7, v4.d[0] /* load upper word of ctr */ ++ rev x7, x7 /* ... to handle the carry */ ++ add x7, x7, #1 ++ rev x7, x7 ++ ins v4.d[0], x7 ++ b .Lctrloop ++.Lctrhalfblock: ++ ld1 {v3.8b}, [x1] ++ eor v3.8b, v0.8b, v3.8b ++ st1 {v3.8b}, [x0] ++.Lctrout: ++ FRAME_POP ++ ret ++AES_ENDPROC(aes_ctr_encrypt) ++ .ltorg ++ ++ ++ /* ++ * aes_xts_decrypt(u8 out[], u8 const in[], u8 const rk1[], int rounds, ++ * int blocks, u8 const rk2[], u8 iv[], int first) ++ * aes_xts_decrypt(u8 out[], u8 const in[], u8 const rk1[], int rounds, ++ * int blocks, u8 const rk2[], u8 iv[], int first) ++ */ ++ ++ .macro next_tweak, out, in, const, tmp ++ sshr \tmp\().2d, \in\().2d, #63 ++ and \tmp\().16b, \tmp\().16b, \const\().16b ++ add \out\().2d, \in\().2d, \in\().2d ++ ext \tmp\().16b, \tmp\().16b, \tmp\().16b, #8 ++ eor \out\().16b, \out\().16b, \tmp\().16b ++ .endm ++ ++.Lxts_mul_x: ++ .word 1, 0, 0x87, 0 ++ ++AES_ENTRY(aes_xts_encrypt) ++ FRAME_PUSH ++ cbz w7, .LxtsencloopNx ++ ++ ld1 {v4.16b}, [x6] ++ enc_prepare w3, x5, x6 ++ encrypt_block v4, w3, x5, x6, w7 /* first tweak */ ++ enc_switch_key w3, x2, x6 ++ ldr q7, .Lxts_mul_x ++ b .LxtsencNx ++ ++.LxtsencloopNx: ++ ldr q7, .Lxts_mul_x ++ next_tweak v4, v4, v7, v8 ++.LxtsencNx: ++#if INTERLEAVE >= 2 ++ subs w4, w4, #INTERLEAVE ++ bmi .Lxtsenc1x ++#if INTERLEAVE == 2 ++ ld1 {v0.16b-v1.16b}, [x1], #32 /* get 2 pt blocks */ ++ next_tweak v5, v4, v7, v8 ++ eor v0.16b, v0.16b, v4.16b ++ eor v1.16b, v1.16b, v5.16b ++ do_encrypt_block2x ++ eor v0.16b, v0.16b, v4.16b ++ eor v1.16b, v1.16b, v5.16b ++ st1 {v0.16b-v1.16b}, [x0], #32 ++ cbz w4, .LxtsencoutNx ++ next_tweak v4, v5, v7, v8 ++ b .LxtsencNx ++.LxtsencoutNx: ++ mov v4.16b, v5.16b ++ b .Lxtsencout ++#else ++ ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 pt blocks */ ++ next_tweak v5, v4, v7, v8 ++ eor v0.16b, v0.16b, v4.16b ++ next_tweak v6, v5, v7, v8 ++ eor v1.16b, v1.16b, v5.16b ++ eor v2.16b, v2.16b, v6.16b ++ next_tweak v7, v6, v7, v8 ++ eor v3.16b, v3.16b, v7.16b ++ do_encrypt_block4x ++ eor v3.16b, v3.16b, v7.16b ++ eor v0.16b, v0.16b, v4.16b ++ eor v1.16b, v1.16b, v5.16b ++ eor v2.16b, v2.16b, v6.16b ++ st1 {v0.16b-v3.16b}, [x0], #64 ++ mov v4.16b, v7.16b ++ cbz w4, .Lxtsencout ++ b .LxtsencloopNx ++#endif ++.Lxtsenc1x: ++ adds w4, w4, #INTERLEAVE ++ beq .Lxtsencout ++#endif ++.Lxtsencloop: ++ ld1 {v1.16b}, [x1], #16 ++ eor v0.16b, v1.16b, v4.16b ++ encrypt_block v0, w3, x2, x6, w7 ++ eor v0.16b, v0.16b, v4.16b ++ st1 {v0.16b}, [x0], #16 ++ subs w4, w4, #1 ++ beq .Lxtsencout ++ next_tweak v4, v4, v7, v8 ++ b .Lxtsencloop ++.Lxtsencout: ++ FRAME_POP ++ ret ++AES_ENDPROC(aes_xts_encrypt) ++ ++ ++AES_ENTRY(aes_xts_decrypt) ++ FRAME_PUSH ++ cbz w7, .LxtsdecloopNx ++ ++ ld1 {v4.16b}, [x6] ++ enc_prepare w3, x5, x6 ++ encrypt_block v4, w3, x5, x6, w7 /* first tweak */ ++ dec_prepare w3, x2, x6 ++ ldr q7, .Lxts_mul_x ++ b .LxtsdecNx ++ ++.LxtsdecloopNx: ++ ldr q7, .Lxts_mul_x ++ next_tweak v4, v4, v7, v8 ++.LxtsdecNx: ++#if INTERLEAVE >= 2 ++ subs w4, w4, #INTERLEAVE ++ bmi .Lxtsdec1x ++#if INTERLEAVE == 2 ++ ld1 {v0.16b-v1.16b}, [x1], #32 /* get 2 ct blocks */ ++ next_tweak v5, v4, v7, v8 ++ eor v0.16b, v0.16b, v4.16b ++ eor v1.16b, v1.16b, v5.16b ++ do_decrypt_block2x ++ eor v0.16b, v0.16b, v4.16b ++ eor v1.16b, v1.16b, v5.16b ++ st1 {v0.16b-v1.16b}, [x0], #32 ++ cbz w4, .LxtsdecoutNx ++ next_tweak v4, v5, v7, v8 ++ b .LxtsdecNx ++.LxtsdecoutNx: ++ mov v4.16b, v5.16b ++ b .Lxtsdecout ++#else ++ ld1 {v0.16b-v3.16b}, [x1], #64 /* get 4 ct blocks */ ++ next_tweak v5, v4, v7, v8 ++ eor v0.16b, v0.16b, v4.16b ++ next_tweak v6, v5, v7, v8 ++ eor v1.16b, v1.16b, v5.16b ++ eor v2.16b, v2.16b, v6.16b ++ next_tweak v7, v6, v7, v8 ++ eor v3.16b, v3.16b, v7.16b ++ do_decrypt_block4x ++ eor v3.16b, v3.16b, v7.16b ++ eor v0.16b, v0.16b, v4.16b ++ eor v1.16b, v1.16b, v5.16b ++ eor v2.16b, v2.16b, v6.16b ++ st1 {v0.16b-v3.16b}, [x0], #64 ++ mov v4.16b, v7.16b ++ cbz w4, .Lxtsdecout ++ b .LxtsdecloopNx ++#endif ++.Lxtsdec1x: ++ adds w4, w4, #INTERLEAVE ++ beq .Lxtsdecout ++#endif ++.Lxtsdecloop: ++ ld1 {v1.16b}, [x1], #16 ++ eor v0.16b, v1.16b, v4.16b ++ decrypt_block v0, w3, x2, x6, w7 ++ eor v0.16b, v0.16b, v4.16b ++ st1 {v0.16b}, [x0], #16 ++ subs w4, w4, #1 ++ beq .Lxtsdecout ++ next_tweak v4, v4, v7, v8 ++ b .Lxtsdecloop ++.Lxtsdecout: ++ FRAME_POP ++ ret ++AES_ENDPROC(aes_xts_decrypt) +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/aes-neon.S linux-3.14.40/arch/arm64/crypto/aes-neon.S +--- linux-3.14.40.orig/arch/arm64/crypto/aes-neon.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/aes-neon.S 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,382 @@ ++/* ++ * linux/arch/arm64/crypto/aes-neon.S - AES cipher for ARMv8 NEON ++ * ++ * Copyright (C) 2013 Linaro 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. ++ */ ++ ++#include ++ ++#define AES_ENTRY(func) ENTRY(neon_ ## func) ++#define AES_ENDPROC(func) ENDPROC(neon_ ## func) ++ ++ /* multiply by polynomial 'x' in GF(2^8) */ ++ .macro mul_by_x, out, in, temp, const ++ sshr \temp, \in, #7 ++ add \out, \in, \in ++ and \temp, \temp, \const ++ eor \out, \out, \temp ++ .endm ++ ++ /* preload the entire Sbox */ ++ .macro prepare, sbox, shiftrows, temp ++ adr \temp, \sbox ++ movi v12.16b, #0x40 ++ ldr q13, \shiftrows ++ movi v14.16b, #0x1b ++ ld1 {v16.16b-v19.16b}, [\temp], #64 ++ ld1 {v20.16b-v23.16b}, [\temp], #64 ++ ld1 {v24.16b-v27.16b}, [\temp], #64 ++ ld1 {v28.16b-v31.16b}, [\temp] ++ .endm ++ ++ /* do preload for encryption */ ++ .macro enc_prepare, ignore0, ignore1, temp ++ prepare .LForward_Sbox, .LForward_ShiftRows, \temp ++ .endm ++ ++ .macro enc_switch_key, ignore0, ignore1, temp ++ /* do nothing */ ++ .endm ++ ++ /* do preload for decryption */ ++ .macro dec_prepare, ignore0, ignore1, temp ++ prepare .LReverse_Sbox, .LReverse_ShiftRows, \temp ++ .endm ++ ++ /* apply SubBytes transformation using the the preloaded Sbox */ ++ .macro sub_bytes, in ++ sub v9.16b, \in\().16b, v12.16b ++ tbl \in\().16b, {v16.16b-v19.16b}, \in\().16b ++ sub v10.16b, v9.16b, v12.16b ++ tbx \in\().16b, {v20.16b-v23.16b}, v9.16b ++ sub v11.16b, v10.16b, v12.16b ++ tbx \in\().16b, {v24.16b-v27.16b}, v10.16b ++ tbx \in\().16b, {v28.16b-v31.16b}, v11.16b ++ .endm ++ ++ /* apply MixColumns transformation */ ++ .macro mix_columns, in ++ mul_by_x v10.16b, \in\().16b, v9.16b, v14.16b ++ rev32 v8.8h, \in\().8h ++ eor \in\().16b, v10.16b, \in\().16b ++ shl v9.4s, v8.4s, #24 ++ shl v11.4s, \in\().4s, #24 ++ sri v9.4s, v8.4s, #8 ++ sri v11.4s, \in\().4s, #8 ++ eor v9.16b, v9.16b, v8.16b ++ eor v10.16b, v10.16b, v9.16b ++ eor \in\().16b, v10.16b, v11.16b ++ .endm ++ ++ /* Inverse MixColumns: pre-multiply by { 5, 0, 4, 0 } */ ++ .macro inv_mix_columns, in ++ mul_by_x v11.16b, \in\().16b, v10.16b, v14.16b ++ mul_by_x v11.16b, v11.16b, v10.16b, v14.16b ++ eor \in\().16b, \in\().16b, v11.16b ++ rev32 v11.8h, v11.8h ++ eor \in\().16b, \in\().16b, v11.16b ++ mix_columns \in ++ .endm ++ ++ .macro do_block, enc, in, rounds, rk, rkp, i ++ ld1 {v15.16b}, [\rk] ++ add \rkp, \rk, #16 ++ mov \i, \rounds ++1111: eor \in\().16b, \in\().16b, v15.16b /* ^round key */ ++ tbl \in\().16b, {\in\().16b}, v13.16b /* ShiftRows */ ++ sub_bytes \in ++ ld1 {v15.16b}, [\rkp], #16 ++ subs \i, \i, #1 ++ beq 2222f ++ .if \enc == 1 ++ mix_columns \in ++ .else ++ inv_mix_columns \in ++ .endif ++ b 1111b ++2222: eor \in\().16b, \in\().16b, v15.16b /* ^round key */ ++ .endm ++ ++ .macro encrypt_block, in, rounds, rk, rkp, i ++ do_block 1, \in, \rounds, \rk, \rkp, \i ++ .endm ++ ++ .macro decrypt_block, in, rounds, rk, rkp, i ++ do_block 0, \in, \rounds, \rk, \rkp, \i ++ .endm ++ ++ /* ++ * Interleaved versions: functionally equivalent to the ++ * ones above, but applied to 2 or 4 AES states in parallel. ++ */ ++ ++ .macro sub_bytes_2x, in0, in1 ++ sub v8.16b, \in0\().16b, v12.16b ++ sub v9.16b, \in1\().16b, v12.16b ++ tbl \in0\().16b, {v16.16b-v19.16b}, \in0\().16b ++ tbl \in1\().16b, {v16.16b-v19.16b}, \in1\().16b ++ sub v10.16b, v8.16b, v12.16b ++ sub v11.16b, v9.16b, v12.16b ++ tbx \in0\().16b, {v20.16b-v23.16b}, v8.16b ++ tbx \in1\().16b, {v20.16b-v23.16b}, v9.16b ++ sub v8.16b, v10.16b, v12.16b ++ sub v9.16b, v11.16b, v12.16b ++ tbx \in0\().16b, {v24.16b-v27.16b}, v10.16b ++ tbx \in1\().16b, {v24.16b-v27.16b}, v11.16b ++ tbx \in0\().16b, {v28.16b-v31.16b}, v8.16b ++ tbx \in1\().16b, {v28.16b-v31.16b}, v9.16b ++ .endm ++ ++ .macro sub_bytes_4x, in0, in1, in2, in3 ++ sub v8.16b, \in0\().16b, v12.16b ++ tbl \in0\().16b, {v16.16b-v19.16b}, \in0\().16b ++ sub v9.16b, \in1\().16b, v12.16b ++ tbl \in1\().16b, {v16.16b-v19.16b}, \in1\().16b ++ sub v10.16b, \in2\().16b, v12.16b ++ tbl \in2\().16b, {v16.16b-v19.16b}, \in2\().16b ++ sub v11.16b, \in3\().16b, v12.16b ++ tbl \in3\().16b, {v16.16b-v19.16b}, \in3\().16b ++ tbx \in0\().16b, {v20.16b-v23.16b}, v8.16b ++ tbx \in1\().16b, {v20.16b-v23.16b}, v9.16b ++ sub v8.16b, v8.16b, v12.16b ++ tbx \in2\().16b, {v20.16b-v23.16b}, v10.16b ++ sub v9.16b, v9.16b, v12.16b ++ tbx \in3\().16b, {v20.16b-v23.16b}, v11.16b ++ sub v10.16b, v10.16b, v12.16b ++ tbx \in0\().16b, {v24.16b-v27.16b}, v8.16b ++ sub v11.16b, v11.16b, v12.16b ++ tbx \in1\().16b, {v24.16b-v27.16b}, v9.16b ++ sub v8.16b, v8.16b, v12.16b ++ tbx \in2\().16b, {v24.16b-v27.16b}, v10.16b ++ sub v9.16b, v9.16b, v12.16b ++ tbx \in3\().16b, {v24.16b-v27.16b}, v11.16b ++ sub v10.16b, v10.16b, v12.16b ++ tbx \in0\().16b, {v28.16b-v31.16b}, v8.16b ++ sub v11.16b, v11.16b, v12.16b ++ tbx \in1\().16b, {v28.16b-v31.16b}, v9.16b ++ tbx \in2\().16b, {v28.16b-v31.16b}, v10.16b ++ tbx \in3\().16b, {v28.16b-v31.16b}, v11.16b ++ .endm ++ ++ .macro mul_by_x_2x, out0, out1, in0, in1, tmp0, tmp1, const ++ sshr \tmp0\().16b, \in0\().16b, #7 ++ add \out0\().16b, \in0\().16b, \in0\().16b ++ sshr \tmp1\().16b, \in1\().16b, #7 ++ and \tmp0\().16b, \tmp0\().16b, \const\().16b ++ add \out1\().16b, \in1\().16b, \in1\().16b ++ and \tmp1\().16b, \tmp1\().16b, \const\().16b ++ eor \out0\().16b, \out0\().16b, \tmp0\().16b ++ eor \out1\().16b, \out1\().16b, \tmp1\().16b ++ .endm ++ ++ .macro mix_columns_2x, in0, in1 ++ mul_by_x_2x v8, v9, \in0, \in1, v10, v11, v14 ++ rev32 v10.8h, \in0\().8h ++ rev32 v11.8h, \in1\().8h ++ eor \in0\().16b, v8.16b, \in0\().16b ++ eor \in1\().16b, v9.16b, \in1\().16b ++ shl v12.4s, v10.4s, #24 ++ shl v13.4s, v11.4s, #24 ++ eor v8.16b, v8.16b, v10.16b ++ sri v12.4s, v10.4s, #8 ++ shl v10.4s, \in0\().4s, #24 ++ eor v9.16b, v9.16b, v11.16b ++ sri v13.4s, v11.4s, #8 ++ shl v11.4s, \in1\().4s, #24 ++ sri v10.4s, \in0\().4s, #8 ++ eor \in0\().16b, v8.16b, v12.16b ++ sri v11.4s, \in1\().4s, #8 ++ eor \in1\().16b, v9.16b, v13.16b ++ eor \in0\().16b, v10.16b, \in0\().16b ++ eor \in1\().16b, v11.16b, \in1\().16b ++ .endm ++ ++ .macro inv_mix_cols_2x, in0, in1 ++ mul_by_x_2x v8, v9, \in0, \in1, v10, v11, v14 ++ mul_by_x_2x v8, v9, v8, v9, v10, v11, v14 ++ eor \in0\().16b, \in0\().16b, v8.16b ++ eor \in1\().16b, \in1\().16b, v9.16b ++ rev32 v8.8h, v8.8h ++ rev32 v9.8h, v9.8h ++ eor \in0\().16b, \in0\().16b, v8.16b ++ eor \in1\().16b, \in1\().16b, v9.16b ++ mix_columns_2x \in0, \in1 ++ .endm ++ ++ .macro inv_mix_cols_4x, in0, in1, in2, in3 ++ mul_by_x_2x v8, v9, \in0, \in1, v10, v11, v14 ++ mul_by_x_2x v10, v11, \in2, \in3, v12, v13, v14 ++ mul_by_x_2x v8, v9, v8, v9, v12, v13, v14 ++ mul_by_x_2x v10, v11, v10, v11, v12, v13, v14 ++ eor \in0\().16b, \in0\().16b, v8.16b ++ eor \in1\().16b, \in1\().16b, v9.16b ++ eor \in2\().16b, \in2\().16b, v10.16b ++ eor \in3\().16b, \in3\().16b, v11.16b ++ rev32 v8.8h, v8.8h ++ rev32 v9.8h, v9.8h ++ rev32 v10.8h, v10.8h ++ rev32 v11.8h, v11.8h ++ eor \in0\().16b, \in0\().16b, v8.16b ++ eor \in1\().16b, \in1\().16b, v9.16b ++ eor \in2\().16b, \in2\().16b, v10.16b ++ eor \in3\().16b, \in3\().16b, v11.16b ++ mix_columns_2x \in0, \in1 ++ mix_columns_2x \in2, \in3 ++ .endm ++ ++ .macro do_block_2x, enc, in0, in1 rounds, rk, rkp, i ++ ld1 {v15.16b}, [\rk] ++ add \rkp, \rk, #16 ++ mov \i, \rounds ++1111: eor \in0\().16b, \in0\().16b, v15.16b /* ^round key */ ++ eor \in1\().16b, \in1\().16b, v15.16b /* ^round key */ ++ sub_bytes_2x \in0, \in1 ++ tbl \in0\().16b, {\in0\().16b}, v13.16b /* ShiftRows */ ++ tbl \in1\().16b, {\in1\().16b}, v13.16b /* ShiftRows */ ++ ld1 {v15.16b}, [\rkp], #16 ++ subs \i, \i, #1 ++ beq 2222f ++ .if \enc == 1 ++ mix_columns_2x \in0, \in1 ++ ldr q13, .LForward_ShiftRows ++ .else ++ inv_mix_cols_2x \in0, \in1 ++ ldr q13, .LReverse_ShiftRows ++ .endif ++ movi v12.16b, #0x40 ++ b 1111b ++2222: eor \in0\().16b, \in0\().16b, v15.16b /* ^round key */ ++ eor \in1\().16b, \in1\().16b, v15.16b /* ^round key */ ++ .endm ++ ++ .macro do_block_4x, enc, in0, in1, in2, in3, rounds, rk, rkp, i ++ ld1 {v15.16b}, [\rk] ++ add \rkp, \rk, #16 ++ mov \i, \rounds ++1111: eor \in0\().16b, \in0\().16b, v15.16b /* ^round key */ ++ eor \in1\().16b, \in1\().16b, v15.16b /* ^round key */ ++ eor \in2\().16b, \in2\().16b, v15.16b /* ^round key */ ++ eor \in3\().16b, \in3\().16b, v15.16b /* ^round key */ ++ sub_bytes_4x \in0, \in1, \in2, \in3 ++ tbl \in0\().16b, {\in0\().16b}, v13.16b /* ShiftRows */ ++ tbl \in1\().16b, {\in1\().16b}, v13.16b /* ShiftRows */ ++ tbl \in2\().16b, {\in2\().16b}, v13.16b /* ShiftRows */ ++ tbl \in3\().16b, {\in3\().16b}, v13.16b /* ShiftRows */ ++ ld1 {v15.16b}, [\rkp], #16 ++ subs \i, \i, #1 ++ beq 2222f ++ .if \enc == 1 ++ mix_columns_2x \in0, \in1 ++ mix_columns_2x \in2, \in3 ++ ldr q13, .LForward_ShiftRows ++ .else ++ inv_mix_cols_4x \in0, \in1, \in2, \in3 ++ ldr q13, .LReverse_ShiftRows ++ .endif ++ movi v12.16b, #0x40 ++ b 1111b ++2222: eor \in0\().16b, \in0\().16b, v15.16b /* ^round key */ ++ eor \in1\().16b, \in1\().16b, v15.16b /* ^round key */ ++ eor \in2\().16b, \in2\().16b, v15.16b /* ^round key */ ++ eor \in3\().16b, \in3\().16b, v15.16b /* ^round key */ ++ .endm ++ ++ .macro encrypt_block2x, in0, in1, rounds, rk, rkp, i ++ do_block_2x 1, \in0, \in1, \rounds, \rk, \rkp, \i ++ .endm ++ ++ .macro decrypt_block2x, in0, in1, rounds, rk, rkp, i ++ do_block_2x 0, \in0, \in1, \rounds, \rk, \rkp, \i ++ .endm ++ ++ .macro encrypt_block4x, in0, in1, in2, in3, rounds, rk, rkp, i ++ do_block_4x 1, \in0, \in1, \in2, \in3, \rounds, \rk, \rkp, \i ++ .endm ++ ++ .macro decrypt_block4x, in0, in1, in2, in3, rounds, rk, rkp, i ++ do_block_4x 0, \in0, \in1, \in2, \in3, \rounds, \rk, \rkp, \i ++ .endm ++ ++#include "aes-modes.S" ++ ++ .text ++ .align 4 ++.LForward_ShiftRows: ++ .byte 0x0, 0x5, 0xa, 0xf, 0x4, 0x9, 0xe, 0x3 ++ .byte 0x8, 0xd, 0x2, 0x7, 0xc, 0x1, 0x6, 0xb ++ ++.LReverse_ShiftRows: ++ .byte 0x0, 0xd, 0xa, 0x7, 0x4, 0x1, 0xe, 0xb ++ .byte 0x8, 0x5, 0x2, 0xf, 0xc, 0x9, 0x6, 0x3 ++ ++.LForward_Sbox: ++ .byte 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5 ++ .byte 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 ++ .byte 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0 ++ .byte 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 ++ .byte 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc ++ .byte 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 ++ .byte 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a ++ .byte 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 ++ .byte 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0 ++ .byte 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 ++ .byte 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b ++ .byte 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf ++ .byte 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85 ++ .byte 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 ++ .byte 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5 ++ .byte 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 ++ .byte 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17 ++ .byte 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 ++ .byte 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88 ++ .byte 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb ++ .byte 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c ++ .byte 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 ++ .byte 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9 ++ .byte 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 ++ .byte 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6 ++ .byte 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a ++ .byte 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e ++ .byte 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e ++ .byte 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94 ++ .byte 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf ++ .byte 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68 ++ .byte 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ++ ++.LReverse_Sbox: ++ .byte 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38 ++ .byte 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb ++ .byte 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87 ++ .byte 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb ++ .byte 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d ++ .byte 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e ++ .byte 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2 ++ .byte 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 ++ .byte 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16 ++ .byte 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 ++ .byte 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda ++ .byte 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 ++ .byte 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a ++ .byte 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 ++ .byte 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02 ++ .byte 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b ++ .byte 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea ++ .byte 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 ++ .byte 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85 ++ .byte 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e ++ .byte 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89 ++ .byte 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b ++ .byte 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20 ++ .byte 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 ++ .byte 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31 ++ .byte 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f ++ .byte 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d ++ .byte 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef ++ .byte 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0 ++ .byte 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 ++ .byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26 ++ .byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/ghash-ce-core.S linux-3.14.40/arch/arm64/crypto/ghash-ce-core.S +--- linux-3.14.40.orig/arch/arm64/crypto/ghash-ce-core.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/ghash-ce-core.S 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,79 @@ ++/* ++ * Accelerated GHASH implementation with ARMv8 PMULL instructions. ++ * ++ * Copyright (C) 2014 Linaro 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. ++ */ ++ ++#include ++#include ++ ++ SHASH .req v0 ++ SHASH2 .req v1 ++ T1 .req v2 ++ T2 .req v3 ++ MASK .req v4 ++ XL .req v5 ++ XM .req v6 ++ XH .req v7 ++ IN1 .req v7 ++ ++ .text ++ .arch armv8-a+crypto ++ ++ /* ++ * void pmull_ghash_update(int blocks, u64 dg[], const char *src, ++ * struct ghash_key const *k, const char *head) ++ */ ++ENTRY(pmull_ghash_update) ++ ld1 {SHASH.16b}, [x3] ++ ld1 {XL.16b}, [x1] ++ movi MASK.16b, #0xe1 ++ ext SHASH2.16b, SHASH.16b, SHASH.16b, #8 ++ shl MASK.2d, MASK.2d, #57 ++ eor SHASH2.16b, SHASH2.16b, SHASH.16b ++ ++ /* do the head block first, if supplied */ ++ cbz x4, 0f ++ ld1 {T1.2d}, [x4] ++ b 1f ++ ++0: ld1 {T1.2d}, [x2], #16 ++ sub w0, w0, #1 ++ ++1: /* multiply XL by SHASH in GF(2^128) */ ++CPU_LE( rev64 T1.16b, T1.16b ) ++ ++ ext T2.16b, XL.16b, XL.16b, #8 ++ ext IN1.16b, T1.16b, T1.16b, #8 ++ eor T1.16b, T1.16b, T2.16b ++ eor XL.16b, XL.16b, IN1.16b ++ ++ pmull2 XH.1q, SHASH.2d, XL.2d // a1 * b1 ++ eor T1.16b, T1.16b, XL.16b ++ pmull XL.1q, SHASH.1d, XL.1d // a0 * b0 ++ pmull XM.1q, SHASH2.1d, T1.1d // (a1 + a0)(b1 + b0) ++ ++ ext T1.16b, XL.16b, XH.16b, #8 ++ eor T2.16b, XL.16b, XH.16b ++ eor XM.16b, XM.16b, T1.16b ++ eor XM.16b, XM.16b, T2.16b ++ pmull T2.1q, XL.1d, MASK.1d ++ ++ mov XH.d[0], XM.d[1] ++ mov XM.d[1], XL.d[0] ++ ++ eor XL.16b, XM.16b, T2.16b ++ ext T2.16b, XL.16b, XL.16b, #8 ++ pmull XL.1q, XL.1d, MASK.1d ++ eor T2.16b, T2.16b, XH.16b ++ eor XL.16b, XL.16b, T2.16b ++ ++ cbnz w0, 0b ++ ++ st1 {XL.16b}, [x1] ++ ret ++ENDPROC(pmull_ghash_update) +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/ghash-ce-glue.c linux-3.14.40/arch/arm64/crypto/ghash-ce-glue.c +--- linux-3.14.40.orig/arch/arm64/crypto/ghash-ce-glue.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/ghash-ce-glue.c 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,156 @@ ++/* ++ * Accelerated GHASH implementation with ARMv8 PMULL instructions. ++ * ++ * Copyright (C) 2014 Linaro 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_DESCRIPTION("GHASH secure hash using ARMv8 Crypto Extensions"); ++MODULE_AUTHOR("Ard Biesheuvel "); ++MODULE_LICENSE("GPL v2"); ++ ++#define GHASH_BLOCK_SIZE 16 ++#define GHASH_DIGEST_SIZE 16 ++ ++struct ghash_key { ++ u64 a; ++ u64 b; ++}; ++ ++struct ghash_desc_ctx { ++ u64 digest[GHASH_DIGEST_SIZE/sizeof(u64)]; ++ u8 buf[GHASH_BLOCK_SIZE]; ++ u32 count; ++}; ++ ++asmlinkage void pmull_ghash_update(int blocks, u64 dg[], const char *src, ++ struct ghash_key const *k, const char *head); ++ ++static int ghash_init(struct shash_desc *desc) ++{ ++ struct ghash_desc_ctx *ctx = shash_desc_ctx(desc); ++ ++ *ctx = (struct ghash_desc_ctx){}; ++ return 0; ++} ++ ++static int ghash_update(struct shash_desc *desc, const u8 *src, ++ unsigned int len) ++{ ++ struct ghash_desc_ctx *ctx = shash_desc_ctx(desc); ++ unsigned int partial = ctx->count % GHASH_BLOCK_SIZE; ++ ++ ctx->count += len; ++ ++ if ((partial + len) >= GHASH_BLOCK_SIZE) { ++ struct ghash_key *key = crypto_shash_ctx(desc->tfm); ++ int blocks; ++ ++ if (partial) { ++ int p = GHASH_BLOCK_SIZE - partial; ++ ++ memcpy(ctx->buf + partial, src, p); ++ src += p; ++ len -= p; ++ } ++ ++ blocks = len / GHASH_BLOCK_SIZE; ++ len %= GHASH_BLOCK_SIZE; ++ ++ kernel_neon_begin_partial(8); ++ pmull_ghash_update(blocks, ctx->digest, src, key, ++ partial ? ctx->buf : NULL); ++ kernel_neon_end(); ++ src += blocks * GHASH_BLOCK_SIZE; ++ partial = 0; ++ } ++ if (len) ++ memcpy(ctx->buf + partial, src, len); ++ return 0; ++} ++ ++static int ghash_final(struct shash_desc *desc, u8 *dst) ++{ ++ struct ghash_desc_ctx *ctx = shash_desc_ctx(desc); ++ unsigned int partial = ctx->count % GHASH_BLOCK_SIZE; ++ ++ if (partial) { ++ struct ghash_key *key = crypto_shash_ctx(desc->tfm); ++ ++ memset(ctx->buf + partial, 0, GHASH_BLOCK_SIZE - partial); ++ ++ kernel_neon_begin_partial(8); ++ pmull_ghash_update(1, ctx->digest, ctx->buf, key, NULL); ++ kernel_neon_end(); ++ } ++ put_unaligned_be64(ctx->digest[1], dst); ++ put_unaligned_be64(ctx->digest[0], dst + 8); ++ ++ *ctx = (struct ghash_desc_ctx){}; ++ return 0; ++} ++ ++static int ghash_setkey(struct crypto_shash *tfm, ++ const u8 *inkey, unsigned int keylen) ++{ ++ struct ghash_key *key = crypto_shash_ctx(tfm); ++ u64 a, b; ++ ++ if (keylen != GHASH_BLOCK_SIZE) { ++ crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); ++ return -EINVAL; ++ } ++ ++ /* perform multiplication by 'x' in GF(2^128) */ ++ b = get_unaligned_be64(inkey); ++ a = get_unaligned_be64(inkey + 8); ++ ++ key->a = (a << 1) | (b >> 63); ++ key->b = (b << 1) | (a >> 63); ++ ++ if (b >> 63) ++ key->b ^= 0xc200000000000000UL; ++ ++ return 0; ++} ++ ++static struct shash_alg ghash_alg = { ++ .digestsize = GHASH_DIGEST_SIZE, ++ .init = ghash_init, ++ .update = ghash_update, ++ .final = ghash_final, ++ .setkey = ghash_setkey, ++ .descsize = sizeof(struct ghash_desc_ctx), ++ .base = { ++ .cra_name = "ghash", ++ .cra_driver_name = "ghash-ce", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_TYPE_SHASH, ++ .cra_blocksize = GHASH_BLOCK_SIZE, ++ .cra_ctxsize = sizeof(struct ghash_key), ++ .cra_module = THIS_MODULE, ++ }, ++}; ++ ++static int __init ghash_ce_mod_init(void) ++{ ++ return crypto_register_shash(&ghash_alg); ++} ++ ++static void __exit ghash_ce_mod_exit(void) ++{ ++ crypto_unregister_shash(&ghash_alg); ++} ++ ++module_cpu_feature_match(PMULL, ghash_ce_mod_init); ++module_exit(ghash_ce_mod_exit); +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/Kconfig linux-3.14.40/arch/arm64/crypto/Kconfig +--- linux-3.14.40.orig/arch/arm64/crypto/Kconfig 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/Kconfig 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,53 @@ ++ ++menuconfig ARM64_CRYPTO ++ bool "ARM64 Accelerated Cryptographic Algorithms" ++ depends on ARM64 ++ help ++ Say Y here to choose from a selection of cryptographic algorithms ++ implemented using ARM64 specific CPU features or instructions. ++ ++if ARM64_CRYPTO ++ ++config CRYPTO_SHA1_ARM64_CE ++ tristate "SHA-1 digest algorithm (ARMv8 Crypto Extensions)" ++ depends on ARM64 && KERNEL_MODE_NEON ++ select CRYPTO_HASH ++ ++config CRYPTO_SHA2_ARM64_CE ++ tristate "SHA-224/SHA-256 digest algorithm (ARMv8 Crypto Extensions)" ++ depends on ARM64 && KERNEL_MODE_NEON ++ select CRYPTO_HASH ++ ++config CRYPTO_GHASH_ARM64_CE ++ tristate "GHASH (for GCM chaining mode) using ARMv8 Crypto Extensions" ++ depends on ARM64 && KERNEL_MODE_NEON ++ select CRYPTO_HASH ++ ++config CRYPTO_AES_ARM64_CE ++ tristate "AES core cipher using ARMv8 Crypto Extensions" ++ depends on ARM64 && KERNEL_MODE_NEON ++ select CRYPTO_ALGAPI ++ select CRYPTO_AES ++ ++config CRYPTO_AES_ARM64_CE_CCM ++ tristate "AES in CCM mode using ARMv8 Crypto Extensions" ++ depends on ARM64 && KERNEL_MODE_NEON ++ select CRYPTO_ALGAPI ++ select CRYPTO_AES ++ select CRYPTO_AEAD ++ ++config CRYPTO_AES_ARM64_CE_BLK ++ tristate "AES in ECB/CBC/CTR/XTS modes using ARMv8 Crypto Extensions" ++ depends on ARM64 && KERNEL_MODE_NEON ++ select CRYPTO_BLKCIPHER ++ select CRYPTO_AES ++ select CRYPTO_ABLK_HELPER ++ ++config CRYPTO_AES_ARM64_NEON_BLK ++ tristate "AES in ECB/CBC/CTR/XTS modes using NEON instructions" ++ depends on ARM64 && KERNEL_MODE_NEON ++ select CRYPTO_BLKCIPHER ++ select CRYPTO_AES ++ select CRYPTO_ABLK_HELPER ++ ++endif +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/Makefile linux-3.14.40/arch/arm64/crypto/Makefile +--- linux-3.14.40.orig/arch/arm64/crypto/Makefile 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/Makefile 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,38 @@ ++# ++# linux/arch/arm64/crypto/Makefile ++# ++# Copyright (C) 2014 Linaro 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. ++# ++ ++obj-$(CONFIG_CRYPTO_SHA1_ARM64_CE) += sha1-ce.o ++sha1-ce-y := sha1-ce-glue.o sha1-ce-core.o ++ ++obj-$(CONFIG_CRYPTO_SHA2_ARM64_CE) += sha2-ce.o ++sha2-ce-y := sha2-ce-glue.o sha2-ce-core.o ++ ++obj-$(CONFIG_CRYPTO_GHASH_ARM64_CE) += ghash-ce.o ++ghash-ce-y := ghash-ce-glue.o ghash-ce-core.o ++ ++obj-$(CONFIG_CRYPTO_AES_ARM64_CE) += aes-ce-cipher.o ++CFLAGS_aes-ce-cipher.o += -march=armv8-a+crypto ++ ++obj-$(CONFIG_CRYPTO_AES_ARM64_CE_CCM) += aes-ce-ccm.o ++aes-ce-ccm-y := aes-ce-ccm-glue.o aes-ce-ccm-core.o ++ ++obj-$(CONFIG_CRYPTO_AES_ARM64_CE_BLK) += aes-ce-blk.o ++aes-ce-blk-y := aes-glue-ce.o aes-ce.o ++ ++obj-$(CONFIG_CRYPTO_AES_ARM64_NEON_BLK) += aes-neon-blk.o ++aes-neon-blk-y := aes-glue-neon.o aes-neon.o ++ ++AFLAGS_aes-ce.o := -DINTERLEAVE=2 -DINTERLEAVE_INLINE ++AFLAGS_aes-neon.o := -DINTERLEAVE=4 ++ ++CFLAGS_aes-glue-ce.o := -DUSE_V8_CRYPTO_EXTENSIONS ++ ++$(obj)/aes-glue-%.o: $(src)/aes-glue.c FORCE ++ $(call if_changed_dep,cc_o_c) +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/sha1-ce-core.S linux-3.14.40/arch/arm64/crypto/sha1-ce-core.S +--- linux-3.14.40.orig/arch/arm64/crypto/sha1-ce-core.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/sha1-ce-core.S 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,153 @@ ++/* ++ * sha1-ce-core.S - SHA-1 secure hash using ARMv8 Crypto Extensions ++ * ++ * Copyright (C) 2014 Linaro 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. ++ */ ++ ++#include ++#include ++ ++ .text ++ .arch armv8-a+crypto ++ ++ k0 .req v0 ++ k1 .req v1 ++ k2 .req v2 ++ k3 .req v3 ++ ++ t0 .req v4 ++ t1 .req v5 ++ ++ dga .req q6 ++ dgav .req v6 ++ dgb .req s7 ++ dgbv .req v7 ++ ++ dg0q .req q12 ++ dg0s .req s12 ++ dg0v .req v12 ++ dg1s .req s13 ++ dg1v .req v13 ++ dg2s .req s14 ++ ++ .macro add_only, op, ev, rc, s0, dg1 ++ .ifc \ev, ev ++ add t1.4s, v\s0\().4s, \rc\().4s ++ sha1h dg2s, dg0s ++ .ifnb \dg1 ++ sha1\op dg0q, \dg1, t0.4s ++ .else ++ sha1\op dg0q, dg1s, t0.4s ++ .endif ++ .else ++ .ifnb \s0 ++ add t0.4s, v\s0\().4s, \rc\().4s ++ .endif ++ sha1h dg1s, dg0s ++ sha1\op dg0q, dg2s, t1.4s ++ .endif ++ .endm ++ ++ .macro add_update, op, ev, rc, s0, s1, s2, s3, dg1 ++ sha1su0 v\s0\().4s, v\s1\().4s, v\s2\().4s ++ add_only \op, \ev, \rc, \s1, \dg1 ++ sha1su1 v\s0\().4s, v\s3\().4s ++ .endm ++ ++ /* ++ * The SHA1 round constants ++ */ ++ .align 4 ++.Lsha1_rcon: ++ .word 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 ++ ++ /* ++ * void sha1_ce_transform(int blocks, u8 const *src, u32 *state, ++ * u8 *head, long bytes) ++ */ ++ENTRY(sha1_ce_transform) ++ /* load round constants */ ++ adr x6, .Lsha1_rcon ++ ld1r {k0.4s}, [x6], #4 ++ ld1r {k1.4s}, [x6], #4 ++ ld1r {k2.4s}, [x6], #4 ++ ld1r {k3.4s}, [x6] ++ ++ /* load state */ ++ ldr dga, [x2] ++ ldr dgb, [x2, #16] ++ ++ /* load partial state (if supplied) */ ++ cbz x3, 0f ++ ld1 {v8.4s-v11.4s}, [x3] ++ b 1f ++ ++ /* load input */ ++0: ld1 {v8.4s-v11.4s}, [x1], #64 ++ sub w0, w0, #1 ++ ++1: ++CPU_LE( rev32 v8.16b, v8.16b ) ++CPU_LE( rev32 v9.16b, v9.16b ) ++CPU_LE( rev32 v10.16b, v10.16b ) ++CPU_LE( rev32 v11.16b, v11.16b ) ++ ++2: add t0.4s, v8.4s, k0.4s ++ mov dg0v.16b, dgav.16b ++ ++ add_update c, ev, k0, 8, 9, 10, 11, dgb ++ add_update c, od, k0, 9, 10, 11, 8 ++ add_update c, ev, k0, 10, 11, 8, 9 ++ add_update c, od, k0, 11, 8, 9, 10 ++ add_update c, ev, k1, 8, 9, 10, 11 ++ ++ add_update p, od, k1, 9, 10, 11, 8 ++ add_update p, ev, k1, 10, 11, 8, 9 ++ add_update p, od, k1, 11, 8, 9, 10 ++ add_update p, ev, k1, 8, 9, 10, 11 ++ add_update p, od, k2, 9, 10, 11, 8 ++ ++ add_update m, ev, k2, 10, 11, 8, 9 ++ add_update m, od, k2, 11, 8, 9, 10 ++ add_update m, ev, k2, 8, 9, 10, 11 ++ add_update m, od, k2, 9, 10, 11, 8 ++ add_update m, ev, k3, 10, 11, 8, 9 ++ ++ add_update p, od, k3, 11, 8, 9, 10 ++ add_only p, ev, k3, 9 ++ add_only p, od, k3, 10 ++ add_only p, ev, k3, 11 ++ add_only p, od ++ ++ /* update state */ ++ add dgbv.2s, dgbv.2s, dg1v.2s ++ add dgav.4s, dgav.4s, dg0v.4s ++ ++ cbnz w0, 0b ++ ++ /* ++ * Final block: add padding and total bit count. ++ * Skip if we have no total byte count in x4. In that case, the input ++ * size was not a round multiple of the block size, and the padding is ++ * handled by the C code. ++ */ ++ cbz x4, 3f ++ movi v9.2d, #0 ++ mov x8, #0x80000000 ++ movi v10.2d, #0 ++ ror x7, x4, #29 // ror(lsl(x4, 3), 32) ++ fmov d8, x8 ++ mov x4, #0 ++ mov v11.d[0], xzr ++ mov v11.d[1], x7 ++ b 2b ++ ++ /* store new state */ ++3: str dga, [x2] ++ str dgb, [x2, #16] ++ ret ++ENDPROC(sha1_ce_transform) +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/sha1-ce-glue.c linux-3.14.40/arch/arm64/crypto/sha1-ce-glue.c +--- linux-3.14.40.orig/arch/arm64/crypto/sha1-ce-glue.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/sha1-ce-glue.c 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,174 @@ ++/* ++ * sha1-ce-glue.c - SHA-1 secure hash using ARMv8 Crypto Extensions ++ * ++ * Copyright (C) 2014 Linaro 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_DESCRIPTION("SHA1 secure hash using ARMv8 Crypto Extensions"); ++MODULE_AUTHOR("Ard Biesheuvel "); ++MODULE_LICENSE("GPL v2"); ++ ++asmlinkage void sha1_ce_transform(int blocks, u8 const *src, u32 *state, ++ u8 *head, long bytes); ++ ++static int sha1_init(struct shash_desc *desc) ++{ ++ struct sha1_state *sctx = shash_desc_ctx(desc); ++ ++ *sctx = (struct sha1_state){ ++ .state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, ++ }; ++ return 0; ++} ++ ++static int sha1_update(struct shash_desc *desc, const u8 *data, ++ unsigned int len) ++{ ++ struct sha1_state *sctx = shash_desc_ctx(desc); ++ unsigned int partial = sctx->count % SHA1_BLOCK_SIZE; ++ ++ sctx->count += len; ++ ++ if ((partial + len) >= SHA1_BLOCK_SIZE) { ++ int blocks; ++ ++ if (partial) { ++ int p = SHA1_BLOCK_SIZE - partial; ++ ++ memcpy(sctx->buffer + partial, data, p); ++ data += p; ++ len -= p; ++ } ++ ++ blocks = len / SHA1_BLOCK_SIZE; ++ len %= SHA1_BLOCK_SIZE; ++ ++ kernel_neon_begin_partial(16); ++ sha1_ce_transform(blocks, data, sctx->state, ++ partial ? sctx->buffer : NULL, 0); ++ kernel_neon_end(); ++ ++ data += blocks * SHA1_BLOCK_SIZE; ++ partial = 0; ++ } ++ if (len) ++ memcpy(sctx->buffer + partial, data, len); ++ return 0; ++} ++ ++static int sha1_final(struct shash_desc *desc, u8 *out) ++{ ++ static const u8 padding[SHA1_BLOCK_SIZE] = { 0x80, }; ++ ++ struct sha1_state *sctx = shash_desc_ctx(desc); ++ __be64 bits = cpu_to_be64(sctx->count << 3); ++ __be32 *dst = (__be32 *)out; ++ int i; ++ ++ u32 padlen = SHA1_BLOCK_SIZE ++ - ((sctx->count + sizeof(bits)) % SHA1_BLOCK_SIZE); ++ ++ sha1_update(desc, padding, padlen); ++ sha1_update(desc, (const u8 *)&bits, sizeof(bits)); ++ ++ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++) ++ put_unaligned_be32(sctx->state[i], dst++); ++ ++ *sctx = (struct sha1_state){}; ++ return 0; ++} ++ ++static int sha1_finup(struct shash_desc *desc, const u8 *data, ++ unsigned int len, u8 *out) ++{ ++ struct sha1_state *sctx = shash_desc_ctx(desc); ++ __be32 *dst = (__be32 *)out; ++ int blocks; ++ int i; ++ ++ if (sctx->count || !len || (len % SHA1_BLOCK_SIZE)) { ++ sha1_update(desc, data, len); ++ return sha1_final(desc, out); ++ } ++ ++ /* ++ * Use a fast path if the input is a multiple of 64 bytes. In ++ * this case, there is no need to copy data around, and we can ++ * perform the entire digest calculation in a single invocation ++ * of sha1_ce_transform() ++ */ ++ blocks = len / SHA1_BLOCK_SIZE; ++ ++ kernel_neon_begin_partial(16); ++ sha1_ce_transform(blocks, data, sctx->state, NULL, len); ++ kernel_neon_end(); ++ ++ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++) ++ put_unaligned_be32(sctx->state[i], dst++); ++ ++ *sctx = (struct sha1_state){}; ++ return 0; ++} ++ ++static int sha1_export(struct shash_desc *desc, void *out) ++{ ++ struct sha1_state *sctx = shash_desc_ctx(desc); ++ struct sha1_state *dst = out; ++ ++ *dst = *sctx; ++ return 0; ++} ++ ++static int sha1_import(struct shash_desc *desc, const void *in) ++{ ++ struct sha1_state *sctx = shash_desc_ctx(desc); ++ struct sha1_state const *src = in; ++ ++ *sctx = *src; ++ return 0; ++} ++ ++static struct shash_alg alg = { ++ .init = sha1_init, ++ .update = sha1_update, ++ .final = sha1_final, ++ .finup = sha1_finup, ++ .export = sha1_export, ++ .import = sha1_import, ++ .descsize = sizeof(struct sha1_state), ++ .digestsize = SHA1_DIGEST_SIZE, ++ .statesize = sizeof(struct sha1_state), ++ .base = { ++ .cra_name = "sha1", ++ .cra_driver_name = "sha1-ce", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_TYPE_SHASH, ++ .cra_blocksize = SHA1_BLOCK_SIZE, ++ .cra_module = THIS_MODULE, ++ } ++}; ++ ++static int __init sha1_ce_mod_init(void) ++{ ++ return crypto_register_shash(&alg); ++} ++ ++static void __exit sha1_ce_mod_fini(void) ++{ ++ crypto_unregister_shash(&alg); ++} ++ ++module_cpu_feature_match(SHA1, sha1_ce_mod_init); ++module_exit(sha1_ce_mod_fini); +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/sha2-ce-core.S linux-3.14.40/arch/arm64/crypto/sha2-ce-core.S +--- linux-3.14.40.orig/arch/arm64/crypto/sha2-ce-core.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/sha2-ce-core.S 2015-05-01 14:57:58.131427001 -0500 +@@ -0,0 +1,156 @@ ++/* ++ * sha2-ce-core.S - core SHA-224/SHA-256 transform using v8 Crypto Extensions ++ * ++ * Copyright (C) 2014 Linaro 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. ++ */ ++ ++#include ++#include ++ ++ .text ++ .arch armv8-a+crypto ++ ++ dga .req q20 ++ dgav .req v20 ++ dgb .req q21 ++ dgbv .req v21 ++ ++ t0 .req v22 ++ t1 .req v23 ++ ++ dg0q .req q24 ++ dg0v .req v24 ++ dg1q .req q25 ++ dg1v .req v25 ++ dg2q .req q26 ++ dg2v .req v26 ++ ++ .macro add_only, ev, rc, s0 ++ mov dg2v.16b, dg0v.16b ++ .ifeq \ev ++ add t1.4s, v\s0\().4s, \rc\().4s ++ sha256h dg0q, dg1q, t0.4s ++ sha256h2 dg1q, dg2q, t0.4s ++ .else ++ .ifnb \s0 ++ add t0.4s, v\s0\().4s, \rc\().4s ++ .endif ++ sha256h dg0q, dg1q, t1.4s ++ sha256h2 dg1q, dg2q, t1.4s ++ .endif ++ .endm ++ ++ .macro add_update, ev, rc, s0, s1, s2, s3 ++ sha256su0 v\s0\().4s, v\s1\().4s ++ add_only \ev, \rc, \s1 ++ sha256su1 v\s0\().4s, v\s2\().4s, v\s3\().4s ++ .endm ++ ++ /* ++ * The SHA-256 round constants ++ */ ++ .align 4 ++.Lsha2_rcon: ++ .word 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5 ++ .word 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5 ++ .word 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3 ++ .word 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174 ++ .word 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc ++ .word 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da ++ .word 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7 ++ .word 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967 ++ .word 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13 ++ .word 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85 ++ .word 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3 ++ .word 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070 ++ .word 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5 ++ .word 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3 ++ .word 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208 ++ .word 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ++ ++ /* ++ * void sha2_ce_transform(int blocks, u8 const *src, u32 *state, ++ * u8 *head, long bytes) ++ */ ++ENTRY(sha2_ce_transform) ++ /* load round constants */ ++ adr x8, .Lsha2_rcon ++ ld1 { v0.4s- v3.4s}, [x8], #64 ++ ld1 { v4.4s- v7.4s}, [x8], #64 ++ ld1 { v8.4s-v11.4s}, [x8], #64 ++ ld1 {v12.4s-v15.4s}, [x8] ++ ++ /* load state */ ++ ldp dga, dgb, [x2] ++ ++ /* load partial input (if supplied) */ ++ cbz x3, 0f ++ ld1 {v16.4s-v19.4s}, [x3] ++ b 1f ++ ++ /* load input */ ++0: ld1 {v16.4s-v19.4s}, [x1], #64 ++ sub w0, w0, #1 ++ ++1: ++CPU_LE( rev32 v16.16b, v16.16b ) ++CPU_LE( rev32 v17.16b, v17.16b ) ++CPU_LE( rev32 v18.16b, v18.16b ) ++CPU_LE( rev32 v19.16b, v19.16b ) ++ ++2: add t0.4s, v16.4s, v0.4s ++ mov dg0v.16b, dgav.16b ++ mov dg1v.16b, dgbv.16b ++ ++ add_update 0, v1, 16, 17, 18, 19 ++ add_update 1, v2, 17, 18, 19, 16 ++ add_update 0, v3, 18, 19, 16, 17 ++ add_update 1, v4, 19, 16, 17, 18 ++ ++ add_update 0, v5, 16, 17, 18, 19 ++ add_update 1, v6, 17, 18, 19, 16 ++ add_update 0, v7, 18, 19, 16, 17 ++ add_update 1, v8, 19, 16, 17, 18 ++ ++ add_update 0, v9, 16, 17, 18, 19 ++ add_update 1, v10, 17, 18, 19, 16 ++ add_update 0, v11, 18, 19, 16, 17 ++ add_update 1, v12, 19, 16, 17, 18 ++ ++ add_only 0, v13, 17 ++ add_only 1, v14, 18 ++ add_only 0, v15, 19 ++ add_only 1 ++ ++ /* update state */ ++ add dgav.4s, dgav.4s, dg0v.4s ++ add dgbv.4s, dgbv.4s, dg1v.4s ++ ++ /* handled all input blocks? */ ++ cbnz w0, 0b ++ ++ /* ++ * Final block: add padding and total bit count. ++ * Skip if we have no total byte count in x4. In that case, the input ++ * size was not a round multiple of the block size, and the padding is ++ * handled by the C code. ++ */ ++ cbz x4, 3f ++ movi v17.2d, #0 ++ mov x8, #0x80000000 ++ movi v18.2d, #0 ++ ror x7, x4, #29 // ror(lsl(x4, 3), 32) ++ fmov d16, x8 ++ mov x4, #0 ++ mov v19.d[0], xzr ++ mov v19.d[1], x7 ++ b 2b ++ ++ /* store new state */ ++3: stp dga, dgb, [x2] ++ ret ++ENDPROC(sha2_ce_transform) +diff -Nur linux-3.14.40.orig/arch/arm64/crypto/sha2-ce-glue.c linux-3.14.40/arch/arm64/crypto/sha2-ce-glue.c +--- linux-3.14.40.orig/arch/arm64/crypto/sha2-ce-glue.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/crypto/sha2-ce-glue.c 2015-05-01 14:57:58.135427001 -0500 +@@ -0,0 +1,255 @@ ++/* ++ * sha2-ce-glue.c - SHA-224/SHA-256 using ARMv8 Crypto Extensions ++ * ++ * Copyright (C) 2014 Linaro 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_DESCRIPTION("SHA-224/SHA-256 secure hash using ARMv8 Crypto Extensions"); ++MODULE_AUTHOR("Ard Biesheuvel "); ++MODULE_LICENSE("GPL v2"); ++ ++asmlinkage int sha2_ce_transform(int blocks, u8 const *src, u32 *state, ++ u8 *head, long bytes); ++ ++static int sha224_init(struct shash_desc *desc) ++{ ++ struct sha256_state *sctx = shash_desc_ctx(desc); ++ ++ *sctx = (struct sha256_state){ ++ .state = { ++ SHA224_H0, SHA224_H1, SHA224_H2, SHA224_H3, ++ SHA224_H4, SHA224_H5, SHA224_H6, SHA224_H7, ++ } ++ }; ++ return 0; ++} ++ ++static int sha256_init(struct shash_desc *desc) ++{ ++ struct sha256_state *sctx = shash_desc_ctx(desc); ++ ++ *sctx = (struct sha256_state){ ++ .state = { ++ SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, ++ SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7, ++ } ++ }; ++ return 0; ++} ++ ++static int sha2_update(struct shash_desc *desc, const u8 *data, ++ unsigned int len) ++{ ++ struct sha256_state *sctx = shash_desc_ctx(desc); ++ unsigned int partial = sctx->count % SHA256_BLOCK_SIZE; ++ ++ sctx->count += len; ++ ++ if ((partial + len) >= SHA256_BLOCK_SIZE) { ++ int blocks; ++ ++ if (partial) { ++ int p = SHA256_BLOCK_SIZE - partial; ++ ++ memcpy(sctx->buf + partial, data, p); ++ data += p; ++ len -= p; ++ } ++ ++ blocks = len / SHA256_BLOCK_SIZE; ++ len %= SHA256_BLOCK_SIZE; ++ ++ kernel_neon_begin_partial(28); ++ sha2_ce_transform(blocks, data, sctx->state, ++ partial ? sctx->buf : NULL, 0); ++ kernel_neon_end(); ++ ++ data += blocks * SHA256_BLOCK_SIZE; ++ partial = 0; ++ } ++ if (len) ++ memcpy(sctx->buf + partial, data, len); ++ return 0; ++} ++ ++static void sha2_final(struct shash_desc *desc) ++{ ++ static const u8 padding[SHA256_BLOCK_SIZE] = { 0x80, }; ++ ++ struct sha256_state *sctx = shash_desc_ctx(desc); ++ __be64 bits = cpu_to_be64(sctx->count << 3); ++ u32 padlen = SHA256_BLOCK_SIZE ++ - ((sctx->count + sizeof(bits)) % SHA256_BLOCK_SIZE); ++ ++ sha2_update(desc, padding, padlen); ++ sha2_update(desc, (const u8 *)&bits, sizeof(bits)); ++} ++ ++static int sha224_final(struct shash_desc *desc, u8 *out) ++{ ++ struct sha256_state *sctx = shash_desc_ctx(desc); ++ __be32 *dst = (__be32 *)out; ++ int i; ++ ++ sha2_final(desc); ++ ++ for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(__be32); i++) ++ put_unaligned_be32(sctx->state[i], dst++); ++ ++ *sctx = (struct sha256_state){}; ++ return 0; ++} ++ ++static int sha256_final(struct shash_desc *desc, u8 *out) ++{ ++ struct sha256_state *sctx = shash_desc_ctx(desc); ++ __be32 *dst = (__be32 *)out; ++ int i; ++ ++ sha2_final(desc); ++ ++ for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(__be32); i++) ++ put_unaligned_be32(sctx->state[i], dst++); ++ ++ *sctx = (struct sha256_state){}; ++ return 0; ++} ++ ++static void sha2_finup(struct shash_desc *desc, const u8 *data, ++ unsigned int len) ++{ ++ struct sha256_state *sctx = shash_desc_ctx(desc); ++ int blocks; ++ ++ if (sctx->count || !len || (len % SHA256_BLOCK_SIZE)) { ++ sha2_update(desc, data, len); ++ sha2_final(desc); ++ return; ++ } ++ ++ /* ++ * Use a fast path if the input is a multiple of 64 bytes. In ++ * this case, there is no need to copy data around, and we can ++ * perform the entire digest calculation in a single invocation ++ * of sha2_ce_transform() ++ */ ++ blocks = len / SHA256_BLOCK_SIZE; ++ ++ kernel_neon_begin_partial(28); ++ sha2_ce_transform(blocks, data, sctx->state, NULL, len); ++ kernel_neon_end(); ++ data += blocks * SHA256_BLOCK_SIZE; ++} ++ ++static int sha224_finup(struct shash_desc *desc, const u8 *data, ++ unsigned int len, u8 *out) ++{ ++ struct sha256_state *sctx = shash_desc_ctx(desc); ++ __be32 *dst = (__be32 *)out; ++ int i; ++ ++ sha2_finup(desc, data, len); ++ ++ for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(__be32); i++) ++ put_unaligned_be32(sctx->state[i], dst++); ++ ++ *sctx = (struct sha256_state){}; ++ return 0; ++} ++ ++static int sha256_finup(struct shash_desc *desc, const u8 *data, ++ unsigned int len, u8 *out) ++{ ++ struct sha256_state *sctx = shash_desc_ctx(desc); ++ __be32 *dst = (__be32 *)out; ++ int i; ++ ++ sha2_finup(desc, data, len); ++ ++ for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(__be32); i++) ++ put_unaligned_be32(sctx->state[i], dst++); ++ ++ *sctx = (struct sha256_state){}; ++ return 0; ++} ++ ++static int sha2_export(struct shash_desc *desc, void *out) ++{ ++ struct sha256_state *sctx = shash_desc_ctx(desc); ++ struct sha256_state *dst = out; ++ ++ *dst = *sctx; ++ return 0; ++} ++ ++static int sha2_import(struct shash_desc *desc, const void *in) ++{ ++ struct sha256_state *sctx = shash_desc_ctx(desc); ++ struct sha256_state const *src = in; ++ ++ *sctx = *src; ++ return 0; ++} ++ ++static struct shash_alg algs[] = { { ++ .init = sha224_init, ++ .update = sha2_update, ++ .final = sha224_final, ++ .finup = sha224_finup, ++ .export = sha2_export, ++ .import = sha2_import, ++ .descsize = sizeof(struct sha256_state), ++ .digestsize = SHA224_DIGEST_SIZE, ++ .statesize = sizeof(struct sha256_state), ++ .base = { ++ .cra_name = "sha224", ++ .cra_driver_name = "sha224-ce", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_TYPE_SHASH, ++ .cra_blocksize = SHA256_BLOCK_SIZE, ++ .cra_module = THIS_MODULE, ++ } ++}, { ++ .init = sha256_init, ++ .update = sha2_update, ++ .final = sha256_final, ++ .finup = sha256_finup, ++ .export = sha2_export, ++ .import = sha2_import, ++ .descsize = sizeof(struct sha256_state), ++ .digestsize = SHA256_DIGEST_SIZE, ++ .statesize = sizeof(struct sha256_state), ++ .base = { ++ .cra_name = "sha256", ++ .cra_driver_name = "sha256-ce", ++ .cra_priority = 200, ++ .cra_flags = CRYPTO_ALG_TYPE_SHASH, ++ .cra_blocksize = SHA256_BLOCK_SIZE, ++ .cra_module = THIS_MODULE, ++ } ++} }; ++ ++static int __init sha2_ce_mod_init(void) ++{ ++ return crypto_register_shashes(algs, ARRAY_SIZE(algs)); ++} ++ ++static void __exit sha2_ce_mod_fini(void) ++{ ++ crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); ++} ++ ++module_cpu_feature_match(SHA2, sha2_ce_mod_init); ++module_exit(sha2_ce_mod_fini); +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/bL_switcher.h linux-3.14.40/arch/arm64/include/asm/bL_switcher.h +--- linux-3.14.40.orig/arch/arm64/include/asm/bL_switcher.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/include/asm/bL_switcher.h 2015-05-01 14:57:58.135427001 -0500 +@@ -0,0 +1,54 @@ ++/* ++ * Based on the stubs for the ARM implementation which is: ++ * ++ * Created by: Nicolas Pitre, April 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. ++ */ ++ ++#ifndef ASM_BL_SWITCHER_H ++#define ASM_BL_SWITCHER_H ++ ++#include ++#include ++ ++typedef void (*bL_switch_completion_handler)(void *cookie); ++ ++static inline int bL_switch_request(unsigned int cpu, ++ unsigned int new_cluster_id) ++{ ++ return -ENOTSUPP; ++} ++ ++/* ++ * 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 ++ ++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 +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/cacheflush.h linux-3.14.40/arch/arm64/include/asm/cacheflush.h +--- linux-3.14.40.orig/arch/arm64/include/asm/cacheflush.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/cacheflush.h 2015-05-01 14:57:58.159427001 -0500 +@@ -85,6 +85,13 @@ + } + + /* ++ * Cache maintenance functions used by the DMA API. No to be used directly. ++ */ ++extern void __dma_map_area(const void *, size_t, int); ++extern void __dma_unmap_area(const void *, size_t, int); ++extern void __dma_flush_range(const void *, const void *); ++ ++/* + * Copy user data from/to a page which is mapped into a different + * processes address space. Really, we want to allow our "user + * space" model to handle this. +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/compat.h linux-3.14.40/arch/arm64/include/asm/compat.h +--- linux-3.14.40.orig/arch/arm64/include/asm/compat.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/compat.h 2015-05-01 14:57:58.167427001 -0500 +@@ -228,7 +228,7 @@ + return (u32)(unsigned long)uptr; + } + +-#define compat_user_stack_pointer() (current_pt_regs()->compat_sp) ++#define compat_user_stack_pointer() (user_stack_pointer(current_pt_regs())) + + static inline void __user *arch_compat_alloc_user_space(long len) + { +@@ -305,11 +305,6 @@ + + #else /* !CONFIG_COMPAT */ + +-static inline int is_compat_task(void) +-{ +- return 0; +-} +- + static inline int is_compat_thread(struct thread_info *thread) + { + return 0; +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/cpufeature.h linux-3.14.40/arch/arm64/include/asm/cpufeature.h +--- linux-3.14.40.orig/arch/arm64/include/asm/cpufeature.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/include/asm/cpufeature.h 2015-05-01 14:57:58.167427001 -0500 +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2014 Linaro 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. ++ */ ++ ++#ifndef __ASM_CPUFEATURE_H ++#define __ASM_CPUFEATURE_H ++ ++#include ++ ++/* ++ * In the arm64 world (as in the ARM world), elf_hwcap is used both internally ++ * in the kernel and for user space to keep track of which optional features ++ * are supported by the current system. So let's map feature 'x' to HWCAP_x. ++ * Note that HWCAP_x constants are bit fields so we need to take the log. ++ */ ++ ++#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap)) ++#define cpu_feature(x) ilog2(HWCAP_ ## x) ++ ++static inline bool cpu_have_feature(unsigned int num) ++{ ++ return elf_hwcap & (1UL << num); ++} ++ ++#endif +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/debug-monitors.h linux-3.14.40/arch/arm64/include/asm/debug-monitors.h +--- linux-3.14.40.orig/arch/arm64/include/asm/debug-monitors.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/debug-monitors.h 2015-05-01 14:57:58.175427001 -0500 +@@ -26,6 +26,53 @@ + #define DBG_ESR_EVT_HWWP 0x2 + #define DBG_ESR_EVT_BRK 0x6 + ++/* ++ * Break point instruction encoding ++ */ ++#define BREAK_INSTR_SIZE 4 ++ ++/* ++ * ESR values expected for dynamic and compile time BRK instruction ++ */ ++#define DBG_ESR_VAL_BRK(x) (0xf2000000 | ((x) & 0xfffff)) ++ ++/* ++ * #imm16 values used for BRK instruction generation ++ * Allowed values for kgbd are 0x400 - 0x7ff ++ * 0x400: for dynamic BRK instruction ++ * 0x401: for compile time BRK instruction ++ */ ++#define KGDB_DYN_DGB_BRK_IMM 0x400 ++#define KDBG_COMPILED_DBG_BRK_IMM 0x401 ++ ++/* ++ * BRK instruction encoding ++ * The #imm16 value should be placed at bits[20:5] within BRK ins ++ */ ++#define AARCH64_BREAK_MON 0xd4200000 ++ ++/* ++ * Extract byte from BRK instruction ++ */ ++#define KGDB_DYN_DGB_BRK_INS_BYTE(x) \ ++ ((((AARCH64_BREAK_MON) & 0xffe0001f) >> (x * 8)) & 0xff) ++ ++/* ++ * Extract byte from BRK #imm16 ++ */ ++#define KGBD_DYN_DGB_BRK_IMM_BYTE(x) \ ++ (((((KGDB_DYN_DGB_BRK_IMM) & 0xffff) << 5) >> (x * 8)) & 0xff) ++ ++#define KGDB_DYN_DGB_BRK_BYTE(x) \ ++ (KGDB_DYN_DGB_BRK_INS_BYTE(x) | KGBD_DYN_DGB_BRK_IMM_BYTE(x)) ++ ++#define KGDB_DYN_BRK_INS_BYTE0 KGDB_DYN_DGB_BRK_BYTE(0) ++#define KGDB_DYN_BRK_INS_BYTE1 KGDB_DYN_DGB_BRK_BYTE(1) ++#define KGDB_DYN_BRK_INS_BYTE2 KGDB_DYN_DGB_BRK_BYTE(2) ++#define KGDB_DYN_BRK_INS_BYTE3 KGDB_DYN_DGB_BRK_BYTE(3) ++ ++#define CACHE_FLUSH_IS_SAFE 1 ++ + enum debug_el { + DBG_ACTIVE_EL0 = 0, + DBG_ACTIVE_EL1, +@@ -43,23 +90,6 @@ + #ifndef __ASSEMBLY__ + struct task_struct; + +-#define local_dbg_save(flags) \ +- do { \ +- typecheck(unsigned long, flags); \ +- asm volatile( \ +- "mrs %0, daif // local_dbg_save\n" \ +- "msr daifset, #8" \ +- : "=r" (flags) : : "memory"); \ +- } while (0) +- +-#define local_dbg_restore(flags) \ +- do { \ +- typecheck(unsigned long, flags); \ +- asm volatile( \ +- "msr daif, %0 // local_dbg_restore\n" \ +- : : "r" (flags) : "memory"); \ +- } while (0) +- + #define DBG_ARCH_ID_RESERVED 0 /* In case of ptrace ABI updates. */ + + #define DBG_HOOK_HANDLED 0 +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/dma-mapping.h linux-3.14.40/arch/arm64/include/asm/dma-mapping.h +--- linux-3.14.40.orig/arch/arm64/include/asm/dma-mapping.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/dma-mapping.h 2015-05-01 14:57:58.175427001 -0500 +@@ -28,6 +28,8 @@ + + #define DMA_ERROR_CODE (~(dma_addr_t)0) + extern struct dma_map_ops *dma_ops; ++extern struct dma_map_ops coherent_swiotlb_dma_ops; ++extern struct dma_map_ops noncoherent_swiotlb_dma_ops; + + static inline struct dma_map_ops *__generic_dma_ops(struct device *dev) + { +@@ -45,6 +47,11 @@ + return __generic_dma_ops(dev); + } + ++static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops) ++{ ++ dev->archdata.dma_ops = ops; ++} ++ + #include + + static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/ftrace.h linux-3.14.40/arch/arm64/include/asm/ftrace.h +--- linux-3.14.40.orig/arch/arm64/include/asm/ftrace.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/include/asm/ftrace.h 2015-05-01 14:57:58.175427001 -0500 +@@ -0,0 +1,59 @@ ++/* ++ * arch/arm64/include/asm/ftrace.h ++ * ++ * Copyright (C) 2013 Linaro Limited ++ * Author: AKASHI Takahiro ++ * ++ * This program is free software; you can 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_FTRACE_H ++#define __ASM_FTRACE_H ++ ++#include ++ ++#define MCOUNT_ADDR ((unsigned long)_mcount) ++#define MCOUNT_INSN_SIZE AARCH64_INSN_SIZE ++ ++#ifndef __ASSEMBLY__ ++#include ++ ++extern void _mcount(unsigned long); ++extern void *return_address(unsigned int); ++ ++struct dyn_arch_ftrace { ++ /* No extra data needed for arm64 */ ++}; ++ ++extern unsigned long ftrace_graph_call; ++ ++static inline unsigned long ftrace_call_adjust(unsigned long addr) ++{ ++ /* ++ * addr is the address of the mcount call instruction. ++ * recordmcount does the necessary offset calculation. ++ */ ++ return addr; ++} ++ ++#define ftrace_return_address(n) return_address(n) ++ ++/* ++ * Because AArch32 mode does not share the same syscall table with AArch64, ++ * tracing compat syscalls may result in reporting bogus syscalls or even ++ * hang-up, so just do not trace them. ++ * See kernel/trace/trace_syscalls.c ++ * ++ * x86 code says: ++ * If the user realy wants these, then they should use the ++ * raw syscall tracepoints with filtering. ++ */ ++#define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS ++static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs) ++{ ++ return is_compat_task(); ++} ++#endif /* ifndef __ASSEMBLY__ */ ++ ++#endif /* __ASM_FTRACE_H */ +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/hwcap.h linux-3.14.40/arch/arm64/include/asm/hwcap.h +--- linux-3.14.40.orig/arch/arm64/include/asm/hwcap.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/hwcap.h 2015-05-01 14:57:58.175427001 -0500 +@@ -33,6 +33,12 @@ + #define COMPAT_HWCAP_LPAE (1 << 20) + #define COMPAT_HWCAP_EVTSTRM (1 << 21) + ++#define COMPAT_HWCAP2_AES (1 << 0) ++#define COMPAT_HWCAP2_PMULL (1 << 1) ++#define COMPAT_HWCAP2_SHA1 (1 << 2) ++#define COMPAT_HWCAP2_SHA2 (1 << 3) ++#define COMPAT_HWCAP2_CRC32 (1 << 4) ++ + #ifndef __ASSEMBLY__ + /* + * This yields a mask that user programs can use to figure out what +@@ -42,7 +48,8 @@ + + #ifdef CONFIG_COMPAT + #define COMPAT_ELF_HWCAP (compat_elf_hwcap) +-extern unsigned int compat_elf_hwcap; ++#define COMPAT_ELF_HWCAP2 (compat_elf_hwcap2) ++extern unsigned int compat_elf_hwcap, compat_elf_hwcap2; + #endif + + extern unsigned long elf_hwcap; +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/insn.h linux-3.14.40/arch/arm64/include/asm/insn.h +--- linux-3.14.40.orig/arch/arm64/include/asm/insn.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/insn.h 2015-05-01 14:57:58.175427001 -0500 +@@ -16,11 +16,14 @@ + */ + #ifndef __ASM_INSN_H + #define __ASM_INSN_H ++ + #include + + /* A64 instructions are always 32 bits. */ + #define AARCH64_INSN_SIZE 4 + ++#ifndef __ASSEMBLY__ ++ + /* + * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a + * Section C3.1 "A64 instruction index by encoding": +@@ -105,4 +108,6 @@ + int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt); + int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt); + ++#endif /* __ASSEMBLY__ */ ++ + #endif /* __ASM_INSN_H */ +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/irqflags.h linux-3.14.40/arch/arm64/include/asm/irqflags.h +--- linux-3.14.40.orig/arch/arm64/include/asm/irqflags.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/irqflags.h 2015-05-01 14:57:58.175427001 -0500 +@@ -90,5 +90,28 @@ + return flags & PSR_I_BIT; + } + ++/* ++ * save and restore debug state ++ */ ++#define local_dbg_save(flags) \ ++ do { \ ++ typecheck(unsigned long, flags); \ ++ asm volatile( \ ++ "mrs %0, daif // local_dbg_save\n" \ ++ "msr daifset, #8" \ ++ : "=r" (flags) : : "memory"); \ ++ } while (0) ++ ++#define local_dbg_restore(flags) \ ++ do { \ ++ typecheck(unsigned long, flags); \ ++ asm volatile( \ ++ "msr daif, %0 // local_dbg_restore\n" \ ++ : : "r" (flags) : "memory"); \ ++ } while (0) ++ ++#define local_dbg_enable() asm("msr daifclr, #8" : : : "memory") ++#define local_dbg_disable() asm("msr daifset, #8" : : : "memory") ++ + #endif + #endif +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/Kbuild linux-3.14.40/arch/arm64/include/asm/Kbuild +--- linux-3.14.40.orig/arch/arm64/include/asm/Kbuild 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/Kbuild 2015-05-01 14:57:58.175427001 -0500 +@@ -35,6 +35,7 @@ + generic-y += sembuf.h + generic-y += serial.h + generic-y += shmbuf.h ++generic-y += simd.h + generic-y += sizes.h + generic-y += socket.h + generic-y += sockios.h +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/kgdb.h linux-3.14.40/arch/arm64/include/asm/kgdb.h +--- linux-3.14.40.orig/arch/arm64/include/asm/kgdb.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/include/asm/kgdb.h 2015-05-01 14:57:58.175427001 -0500 +@@ -0,0 +1,84 @@ ++/* ++ * AArch64 KGDB support ++ * ++ * Based on arch/arm/include/kgdb.h ++ * ++ * Copyright (C) 2013 Cavium Inc. ++ * Author: Vijaya Kumar K ++ * ++ * This program is free software; you can 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 __ARM_KGDB_H ++#define __ARM_KGDB_H ++ ++#include ++#include ++ ++#ifndef __ASSEMBLY__ ++ ++static inline void arch_kgdb_breakpoint(void) ++{ ++ asm ("brk %0" : : "I" (KDBG_COMPILED_DBG_BRK_IMM)); ++} ++ ++extern void kgdb_handle_bus_error(void); ++extern int kgdb_fault_expected; ++ ++#endif /* !__ASSEMBLY__ */ ++ ++/* ++ * gdb is expecting the following registers layout. ++ * ++ * General purpose regs: ++ * r0-r30: 64 bit ++ * sp,pc : 64 bit ++ * pstate : 64 bit ++ * Total: 34 ++ * FPU regs: ++ * f0-f31: 128 bit ++ * Total: 32 ++ * Extra regs ++ * fpsr & fpcr: 32 bit ++ * Total: 2 ++ * ++ */ ++ ++#define _GP_REGS 34 ++#define _FP_REGS 32 ++#define _EXTRA_REGS 2 ++/* ++ * general purpose registers size in bytes. ++ * pstate is only 4 bytes. subtract 4 bytes ++ */ ++#define GP_REG_BYTES (_GP_REGS * 8) ++#define DBG_MAX_REG_NUM (_GP_REGS + _FP_REGS + _EXTRA_REGS) ++ ++/* ++ * Size of I/O buffer for gdb packet. ++ * considering to hold all register contents, size is set ++ */ ++ ++#define BUFMAX 2048 ++ ++/* ++ * Number of bytes required for gdb_regs buffer. ++ * _GP_REGS: 8 bytes, _FP_REGS: 16 bytes and _EXTRA_REGS: 4 bytes each ++ * GDB fails to connect for size beyond this with error ++ * "'g' packet reply is too long" ++ */ ++ ++#define NUMREGBYTES ((_GP_REGS * 8) + (_FP_REGS * 16) + \ ++ (_EXTRA_REGS * 4)) ++ ++#endif /* __ASM_KGDB_H */ +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/page.h linux-3.14.40/arch/arm64/include/asm/page.h +--- linux-3.14.40.orig/arch/arm64/include/asm/page.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/page.h 2015-05-01 14:57:58.175427001 -0500 +@@ -31,6 +31,15 @@ + /* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */ + #define __HAVE_ARCH_GATE_AREA 1 + ++/* ++ * The idmap and swapper page tables need some space reserved in the kernel ++ * image. The idmap only requires a pgd and a next level table to (section) map ++ * the kernel, while the swapper also maps the FDT and requires an additional ++ * table to map an early UART. See __create_page_tables for more information. ++ */ ++#define SWAPPER_DIR_SIZE (3 * PAGE_SIZE) ++#define IDMAP_DIR_SIZE (2 * PAGE_SIZE) ++ + #ifndef __ASSEMBLY__ + + #ifdef CONFIG_ARM64_64K_PAGES +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/pgtable.h linux-3.14.40/arch/arm64/include/asm/pgtable.h +--- linux-3.14.40.orig/arch/arm64/include/asm/pgtable.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/pgtable.h 2015-05-01 14:57:58.175427001 -0500 +@@ -227,36 +227,36 @@ + + #define __HAVE_ARCH_PTE_SPECIAL + +-/* +- * Software PMD bits for THP +- */ ++static inline pte_t pmd_pte(pmd_t pmd) ++{ ++ return __pte(pmd_val(pmd)); ++} + +-#define PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55) +-#define PMD_SECT_SPLITTING (_AT(pmdval_t, 1) << 57) ++static inline pmd_t pte_pmd(pte_t pte) ++{ ++ return __pmd(pte_val(pte)); ++} + + /* + * THP definitions. + */ +-#define pmd_young(pmd) (pmd_val(pmd) & PMD_SECT_AF) +- +-#define __HAVE_ARCH_PMD_WRITE +-#define pmd_write(pmd) (!(pmd_val(pmd) & PMD_SECT_RDONLY)) + + #ifdef CONFIG_TRANSPARENT_HUGEPAGE + #define pmd_trans_huge(pmd) (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT)) +-#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING) ++#define pmd_trans_splitting(pmd) pte_special(pmd_pte(pmd)) + #endif + +-#define PMD_BIT_FUNC(fn,op) \ +-static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; } ++#define pmd_young(pmd) pte_young(pmd_pte(pmd)) ++#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd))) ++#define pmd_mksplitting(pmd) pte_pmd(pte_mkspecial(pmd_pte(pmd))) ++#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd))) ++#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) ++#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) ++#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) ++#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) &= ~PMD_TYPE_MASK)) + +-PMD_BIT_FUNC(wrprotect, |= PMD_SECT_RDONLY); +-PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF); +-PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING); +-PMD_BIT_FUNC(mkwrite, &= ~PMD_SECT_RDONLY); +-PMD_BIT_FUNC(mkdirty, |= PMD_SECT_DIRTY); +-PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF); +-PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK); ++#define __HAVE_ARCH_PMD_WRITE ++#define pmd_write(pmd) pte_write(pmd_pte(pmd)) + + #define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT)) + +@@ -266,16 +266,7 @@ + + #define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK)) + +-static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) +-{ +- const pmdval_t mask = PMD_SECT_USER | PMD_SECT_PXN | PMD_SECT_UXN | +- PMD_SECT_RDONLY | PMD_SECT_PROT_NONE | +- PMD_SECT_VALID; +- pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask); +- return pmd; +-} +- +-#define set_pmd_at(mm, addr, pmdp, pmd) set_pmd(pmdp, pmd) ++#define set_pmd_at(mm, addr, pmdp, pmd) set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd)) + + static inline int has_transparent_hugepage(void) + { +@@ -383,12 +374,14 @@ + return pte; + } + ++static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) ++{ ++ return pte_pmd(pte_modify(pmd_pte(pmd), newprot)); ++} ++ + extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; + +-#define SWAPPER_DIR_SIZE (3 * PAGE_SIZE) +-#define IDMAP_DIR_SIZE (2 * PAGE_SIZE) +- + /* + * Encode and decode a swap entry: + * bits 0-1: present (must be zero) +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/ptrace.h linux-3.14.40/arch/arm64/include/asm/ptrace.h +--- linux-3.14.40.orig/arch/arm64/include/asm/ptrace.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/ptrace.h 2015-05-01 14:57:58.179427001 -0500 +@@ -68,6 +68,7 @@ + + /* Architecturally defined mapping between AArch32 and AArch64 registers */ + #define compat_usr(x) regs[(x)] ++#define compat_fp regs[11] + #define compat_sp regs[13] + #define compat_lr regs[14] + #define compat_sp_hyp regs[15] +@@ -132,7 +133,12 @@ + (!((regs)->pstate & PSR_F_BIT)) + + #define user_stack_pointer(regs) \ +- ((regs)->sp) ++ (!compat_user_mode(regs)) ? ((regs)->sp) : ((regs)->compat_sp) ++ ++static inline unsigned long regs_return_value(struct pt_regs *regs) ++{ ++ return regs->regs[0]; ++} + + /* + * Are the current registers suitable for user mode? (used to maintain +@@ -164,7 +170,7 @@ + return 0; + } + +-#define instruction_pointer(regs) (regs)->pc ++#define instruction_pointer(regs) ((unsigned long)(regs)->pc) + + #ifdef CONFIG_SMP + extern unsigned long profile_pc(struct pt_regs *regs); +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/syscall.h linux-3.14.40/arch/arm64/include/asm/syscall.h +--- linux-3.14.40.orig/arch/arm64/include/asm/syscall.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/syscall.h 2015-05-01 14:57:58.195427001 -0500 +@@ -18,6 +18,7 @@ + + #include + ++extern const void *sys_call_table[]; + + static inline int syscall_get_nr(struct task_struct *task, + struct pt_regs *regs) +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/thread_info.h linux-3.14.40/arch/arm64/include/asm/thread_info.h +--- linux-3.14.40.orig/arch/arm64/include/asm/thread_info.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/thread_info.h 2015-05-01 14:57:58.195427001 -0500 +@@ -91,6 +91,9 @@ + /* + * thread information flags: + * TIF_SYSCALL_TRACE - syscall trace active ++ * TIF_SYSCALL_TRACEPOINT - syscall tracepoint for ftrace ++ * TIF_SYSCALL_AUDIT - syscall auditing ++ * TIF_SECOMP - syscall secure computing + * TIF_SIGPENDING - signal pending + * TIF_NEED_RESCHED - rescheduling necessary + * TIF_NOTIFY_RESUME - callback before returning to user +@@ -101,6 +104,9 @@ + #define TIF_NEED_RESCHED 1 + #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ + #define TIF_SYSCALL_TRACE 8 ++#define TIF_SYSCALL_AUDIT 9 ++#define TIF_SYSCALL_TRACEPOINT 10 ++#define TIF_SECCOMP 11 + #define TIF_POLLING_NRFLAG 16 + #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ + #define TIF_FREEZE 19 +@@ -112,10 +118,17 @@ + #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) + #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) + #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) ++#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) ++#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) ++#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) ++#define _TIF_SECCOMP (1 << TIF_SECCOMP) + #define _TIF_32BIT (1 << TIF_32BIT) + + #define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ + _TIF_NOTIFY_RESUME) + ++#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ ++ _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP) ++ + #endif /* __KERNEL__ */ + #endif /* __ASM_THREAD_INFO_H */ +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/topology.h linux-3.14.40/arch/arm64/include/asm/topology.h +--- linux-3.14.40.orig/arch/arm64/include/asm/topology.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/include/asm/topology.h 2015-05-01 14:57:58.195427001 -0500 +@@ -0,0 +1,70 @@ ++#ifndef __ASM_TOPOLOGY_H ++#define __ASM_TOPOLOGY_H ++ ++#ifdef CONFIG_SMP ++ ++#include ++ ++struct cpu_topology { ++ int thread_id; ++ int core_id; ++ int cluster_id; ++ cpumask_t thread_sibling; ++ cpumask_t core_sibling; ++}; ++ ++extern struct cpu_topology cpu_topology[NR_CPUS]; ++ ++#define topology_physical_package_id(cpu) (cpu_topology[cpu].cluster_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].cluster_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); ++ ++#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) { } ++ ++#endif ++ ++#include ++ ++#endif /* _ASM_ARM_TOPOLOGY_H */ +diff -Nur linux-3.14.40.orig/arch/arm64/include/asm/unistd.h linux-3.14.40/arch/arm64/include/asm/unistd.h +--- linux-3.14.40.orig/arch/arm64/include/asm/unistd.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/asm/unistd.h 2015-05-01 14:57:58.195427001 -0500 +@@ -28,3 +28,5 @@ + #endif + #define __ARCH_WANT_SYS_CLONE + #include ++ ++#define NR_syscalls (__NR_syscalls) +diff -Nur linux-3.14.40.orig/arch/arm64/include/uapi/asm/Kbuild linux-3.14.40/arch/arm64/include/uapi/asm/Kbuild +--- linux-3.14.40.orig/arch/arm64/include/uapi/asm/Kbuild 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/include/uapi/asm/Kbuild 2015-05-01 14:57:58.195427001 -0500 +@@ -9,6 +9,7 @@ + header-y += fcntl.h + header-y += hwcap.h + header-y += kvm_para.h ++header-y += perf_regs.h + header-y += param.h + header-y += ptrace.h + header-y += setup.h +diff -Nur linux-3.14.40.orig/arch/arm64/include/uapi/asm/perf_regs.h linux-3.14.40/arch/arm64/include/uapi/asm/perf_regs.h +--- linux-3.14.40.orig/arch/arm64/include/uapi/asm/perf_regs.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/include/uapi/asm/perf_regs.h 2015-05-01 14:57:58.195427001 -0500 +@@ -0,0 +1,40 @@ ++#ifndef _ASM_ARM64_PERF_REGS_H ++#define _ASM_ARM64_PERF_REGS_H ++ ++enum perf_event_arm_regs { ++ PERF_REG_ARM64_X0, ++ PERF_REG_ARM64_X1, ++ PERF_REG_ARM64_X2, ++ PERF_REG_ARM64_X3, ++ PERF_REG_ARM64_X4, ++ PERF_REG_ARM64_X5, ++ PERF_REG_ARM64_X6, ++ PERF_REG_ARM64_X7, ++ PERF_REG_ARM64_X8, ++ PERF_REG_ARM64_X9, ++ PERF_REG_ARM64_X10, ++ PERF_REG_ARM64_X11, ++ PERF_REG_ARM64_X12, ++ PERF_REG_ARM64_X13, ++ PERF_REG_ARM64_X14, ++ PERF_REG_ARM64_X15, ++ PERF_REG_ARM64_X16, ++ PERF_REG_ARM64_X17, ++ PERF_REG_ARM64_X18, ++ PERF_REG_ARM64_X19, ++ PERF_REG_ARM64_X20, ++ PERF_REG_ARM64_X21, ++ PERF_REG_ARM64_X22, ++ PERF_REG_ARM64_X23, ++ PERF_REG_ARM64_X24, ++ PERF_REG_ARM64_X25, ++ PERF_REG_ARM64_X26, ++ PERF_REG_ARM64_X27, ++ PERF_REG_ARM64_X28, ++ PERF_REG_ARM64_X29, ++ PERF_REG_ARM64_LR, ++ PERF_REG_ARM64_SP, ++ PERF_REG_ARM64_PC, ++ PERF_REG_ARM64_MAX, ++}; ++#endif /* _ASM_ARM64_PERF_REGS_H */ +diff -Nur linux-3.14.40.orig/arch/arm64/Kconfig linux-3.14.40/arch/arm64/Kconfig +--- linux-3.14.40.orig/arch/arm64/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/Kconfig 2015-05-01 14:57:58.199427001 -0500 +@@ -4,6 +4,7 @@ + select ARCH_USE_CMPXCHG_LOCKREF + select ARCH_SUPPORTS_ATOMIC_RMW + select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST ++ select ARCH_HAS_OPP + select ARCH_WANT_OPTIONAL_GPIOLIB + select ARCH_WANT_COMPAT_IPC_PARSE_VERSION + select ARCH_WANT_FRAME_POINTERS +@@ -17,6 +18,7 @@ + select DCACHE_WORD_ACCESS + select GENERIC_CLOCKEVENTS + select GENERIC_CLOCKEVENTS_BROADCAST if SMP ++ select GENERIC_CPU_AUTOPROBE + select GENERIC_IOMAP + select GENERIC_IRQ_PROBE + select GENERIC_IRQ_SHOW +@@ -27,18 +29,27 @@ + select GENERIC_TIME_VSYSCALL + select HARDIRQS_SW_RESEND + select HAVE_ARCH_JUMP_LABEL ++ select HAVE_ARCH_KGDB + select HAVE_ARCH_TRACEHOOK ++ select HAVE_C_RECORDMCOUNT + select HAVE_DEBUG_BUGVERBOSE + select HAVE_DEBUG_KMEMLEAK + select HAVE_DMA_API_DEBUG + select HAVE_DMA_ATTRS + select HAVE_DMA_CONTIGUOUS + select HAVE_EFFICIENT_UNALIGNED_ACCESS ++ select HAVE_DYNAMIC_FTRACE ++ select HAVE_FTRACE_MCOUNT_RECORD ++ select HAVE_FUNCTION_TRACER ++ select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_GENERIC_DMA_COHERENT + select HAVE_HW_BREAKPOINT if PERF_EVENTS + select HAVE_MEMBLOCK + select HAVE_PATA_PLATFORM + select HAVE_PERF_EVENTS ++ select HAVE_PERF_REGS ++ select HAVE_PERF_USER_STACK_DUMP ++ select HAVE_SYSCALL_TRACEPOINTS + select IRQ_DOMAIN + select MODULES_USE_ELF_RELA + select NO_BOOTMEM +@@ -86,7 +97,7 @@ + config GENERIC_CALIBRATE_DELAY + def_bool y + +-config ZONE_DMA32 ++config ZONE_DMA + def_bool y + + config ARCH_DMA_ADDR_T_64BIT +@@ -165,6 +176,134 @@ + + If you don't know what to do here, say N. + ++config SCHED_MC ++ bool "Multi-core scheduler support" ++ depends on SMP ++ 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 SMP ++ 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 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 +@@ -317,5 +456,8 @@ + source "security/Kconfig" + + source "crypto/Kconfig" ++if CRYPTO ++source "arch/arm64/crypto/Kconfig" ++endif + + source "lib/Kconfig" +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/arm64ksyms.c linux-3.14.40/arch/arm64/kernel/arm64ksyms.c +--- linux-3.14.40.orig/arch/arm64/kernel/arm64ksyms.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/arm64ksyms.c 2015-05-01 14:57:58.211427001 -0500 +@@ -56,3 +56,7 @@ + EXPORT_SYMBOL(test_and_clear_bit); + EXPORT_SYMBOL(change_bit); + EXPORT_SYMBOL(test_and_change_bit); ++ ++#ifdef CONFIG_FUNCTION_TRACER ++EXPORT_SYMBOL(_mcount); ++#endif +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/debug-monitors.c linux-3.14.40/arch/arm64/kernel/debug-monitors.c +--- linux-3.14.40.orig/arch/arm64/kernel/debug-monitors.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/debug-monitors.c 2015-05-01 14:57:58.215427001 -0500 +@@ -138,6 +138,7 @@ + { + asm volatile("msr oslar_el1, %0" : : "r" (0)); + isb(); ++ local_dbg_enable(); + } + + static int os_lock_notify(struct notifier_block *self, +@@ -314,9 +315,6 @@ + if (call_break_hook(regs, esr) == DBG_HOOK_HANDLED) + return 0; + +- pr_warn("unexpected brk exception at %lx, esr=0x%x\n", +- (long)instruction_pointer(regs), esr); +- + if (!user_mode(regs)) + return -EFAULT; + +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/entry-ftrace.S linux-3.14.40/arch/arm64/kernel/entry-ftrace.S +--- linux-3.14.40.orig/arch/arm64/kernel/entry-ftrace.S 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/kernel/entry-ftrace.S 2015-05-01 14:57:58.215427001 -0500 +@@ -0,0 +1,218 @@ ++/* ++ * arch/arm64/kernel/entry-ftrace.S ++ * ++ * Copyright (C) 2013 Linaro Limited ++ * Author: AKASHI Takahiro ++ * ++ * This program is free software; you can 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 ++ ++/* ++ * Gcc with -pg will put the following code in the beginning of each function: ++ * mov x0, x30 ++ * bl _mcount ++ * [function's body ...] ++ * "bl _mcount" may be replaced to "bl ftrace_caller" or NOP if dynamic ++ * ftrace is enabled. ++ * ++ * Please note that x0 as an argument will not be used here because we can ++ * get lr(x30) of instrumented function at any time by winding up call stack ++ * as long as the kernel is compiled without -fomit-frame-pointer. ++ * (or CONFIG_FRAME_POINTER, this is forced on arm64) ++ * ++ * stack layout after mcount_enter in _mcount(): ++ * ++ * current sp/fp => 0:+-----+ ++ * in _mcount() | x29 | -> instrumented function's fp ++ * +-----+ ++ * | x30 | -> _mcount()'s lr (= instrumented function's pc) ++ * old sp => +16:+-----+ ++ * when instrumented | | ++ * function calls | ... | ++ * _mcount() | | ++ * | | ++ * instrumented => +xx:+-----+ ++ * function's fp | x29 | -> parent's fp ++ * +-----+ ++ * | x30 | -> instrumented function's lr (= parent's pc) ++ * +-----+ ++ * | ... | ++ */ ++ ++ .macro mcount_enter ++ stp x29, x30, [sp, #-16]! ++ mov x29, sp ++ .endm ++ ++ .macro mcount_exit ++ ldp x29, x30, [sp], #16 ++ ret ++ .endm ++ ++ .macro mcount_adjust_addr rd, rn ++ sub \rd, \rn, #AARCH64_INSN_SIZE ++ .endm ++ ++ /* for instrumented function's parent */ ++ .macro mcount_get_parent_fp reg ++ ldr \reg, [x29] ++ ldr \reg, [\reg] ++ .endm ++ ++ /* for instrumented function */ ++ .macro mcount_get_pc0 reg ++ mcount_adjust_addr \reg, x30 ++ .endm ++ ++ .macro mcount_get_pc reg ++ ldr \reg, [x29, #8] ++ mcount_adjust_addr \reg, \reg ++ .endm ++ ++ .macro mcount_get_lr reg ++ ldr \reg, [x29] ++ ldr \reg, [\reg, #8] ++ mcount_adjust_addr \reg, \reg ++ .endm ++ ++ .macro mcount_get_lr_addr reg ++ ldr \reg, [x29] ++ add \reg, \reg, #8 ++ .endm ++ ++#ifndef CONFIG_DYNAMIC_FTRACE ++/* ++ * void _mcount(unsigned long return_address) ++ * @return_address: return address to instrumented function ++ * ++ * This function makes calls, if enabled, to: ++ * - tracer function to probe instrumented function's entry, ++ * - ftrace_graph_caller to set up an exit hook ++ */ ++ENTRY(_mcount) ++#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST ++ ldr x0, =ftrace_trace_stop ++ ldr x0, [x0] // if ftrace_trace_stop ++ ret // return; ++#endif ++ mcount_enter ++ ++ ldr x0, =ftrace_trace_function ++ ldr x2, [x0] ++ adr x0, ftrace_stub ++ cmp x0, x2 // if (ftrace_trace_function ++ b.eq skip_ftrace_call // != ftrace_stub) { ++ ++ mcount_get_pc x0 // function's pc ++ mcount_get_lr x1 // function's lr (= parent's pc) ++ blr x2 // (*ftrace_trace_function)(pc, lr); ++ ++#ifndef CONFIG_FUNCTION_GRAPH_TRACER ++skip_ftrace_call: // return; ++ mcount_exit // } ++#else ++ mcount_exit // return; ++ // } ++skip_ftrace_call: ++ ldr x1, =ftrace_graph_return ++ ldr x2, [x1] // if ((ftrace_graph_return ++ cmp x0, x2 // != ftrace_stub) ++ b.ne ftrace_graph_caller ++ ++ ldr x1, =ftrace_graph_entry // || (ftrace_graph_entry ++ ldr x2, [x1] // != ftrace_graph_entry_stub)) ++ ldr x0, =ftrace_graph_entry_stub ++ cmp x0, x2 ++ b.ne ftrace_graph_caller // ftrace_graph_caller(); ++ ++ mcount_exit ++#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ ++ENDPROC(_mcount) ++ ++#else /* CONFIG_DYNAMIC_FTRACE */ ++/* ++ * _mcount() is used to build the kernel with -pg option, but all the branch ++ * instructions to _mcount() are replaced to NOP initially at kernel start up, ++ * and later on, NOP to branch to ftrace_caller() when enabled or branch to ++ * NOP when disabled per-function base. ++ */ ++ENTRY(_mcount) ++ ret ++ENDPROC(_mcount) ++ ++/* ++ * void ftrace_caller(unsigned long return_address) ++ * @return_address: return address to instrumented function ++ * ++ * This function is a counterpart of _mcount() in 'static' ftrace, and ++ * makes calls to: ++ * - tracer function to probe instrumented function's entry, ++ * - ftrace_graph_caller to set up an exit hook ++ */ ++ENTRY(ftrace_caller) ++ mcount_enter ++ ++ mcount_get_pc0 x0 // function's pc ++ mcount_get_lr x1 // function's lr ++ ++ .global ftrace_call ++ftrace_call: // tracer(pc, lr); ++ nop // This will be replaced with "bl xxx" ++ // where xxx can be any kind of tracer. ++ ++#ifdef CONFIG_FUNCTION_GRAPH_TRACER ++ .global ftrace_graph_call ++ftrace_graph_call: // ftrace_graph_caller(); ++ nop // If enabled, this will be replaced ++ // "b ftrace_graph_caller" ++#endif ++ ++ mcount_exit ++ENDPROC(ftrace_caller) ++#endif /* CONFIG_DYNAMIC_FTRACE */ ++ ++ENTRY(ftrace_stub) ++ ret ++ENDPROC(ftrace_stub) ++ ++#ifdef CONFIG_FUNCTION_GRAPH_TRACER ++/* ++ * void ftrace_graph_caller(void) ++ * ++ * Called from _mcount() or ftrace_caller() when function_graph tracer is ++ * selected. ++ * This function w/ prepare_ftrace_return() fakes link register's value on ++ * the call stack in order to intercept instrumented function's return path ++ * and run return_to_handler() later on its exit. ++ */ ++ENTRY(ftrace_graph_caller) ++ mcount_get_lr_addr x0 // pointer to function's saved lr ++ mcount_get_pc x1 // function's pc ++ mcount_get_parent_fp x2 // parent's fp ++ bl prepare_ftrace_return // prepare_ftrace_return(&lr, pc, fp) ++ ++ mcount_exit ++ENDPROC(ftrace_graph_caller) ++ ++/* ++ * void return_to_handler(void) ++ * ++ * Run ftrace_return_to_handler() before going back to parent. ++ * @fp is checked against the value passed by ftrace_graph_caller() ++ * only when CONFIG_FUNCTION_GRAPH_FP_TEST is enabled. ++ */ ++ENTRY(return_to_handler) ++ str x0, [sp, #-16]! ++ mov x0, x29 // parent's fp ++ bl ftrace_return_to_handler// addr = ftrace_return_to_hander(fp); ++ mov x30, x0 // restore the original return address ++ ldr x0, [sp], #16 ++ ret ++END(return_to_handler) ++#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/entry.S linux-3.14.40/arch/arm64/kernel/entry.S +--- linux-3.14.40.orig/arch/arm64/kernel/entry.S 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/entry.S 2015-05-01 14:57:58.219427001 -0500 +@@ -630,8 +630,9 @@ + enable_irq + + get_thread_info tsk +- ldr x16, [tsk, #TI_FLAGS] // check for syscall tracing +- tbnz x16, #TIF_SYSCALL_TRACE, __sys_trace // are we tracing syscalls? ++ ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks ++ tst x16, #_TIF_SYSCALL_WORK ++ b.ne __sys_trace + adr lr, ret_fast_syscall // return address + cmp scno, sc_nr // check upper syscall limit + b.hs ni_sys +@@ -647,9 +648,8 @@ + * switches, and waiting for our parent to respond. + */ + __sys_trace: +- mov x1, sp +- mov w0, #0 // trace entry +- bl syscall_trace ++ mov x0, sp ++ bl syscall_trace_enter + adr lr, __sys_trace_return // return address + uxtw scno, w0 // syscall number (possibly new) + mov x1, sp // pointer to regs +@@ -664,9 +664,8 @@ + + __sys_trace_return: + str x0, [sp] // save returned x0 +- mov x1, sp +- mov w0, #1 // trace exit +- bl syscall_trace ++ mov x0, sp ++ bl syscall_trace_exit + b ret_to_user + + /* +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/ftrace.c linux-3.14.40/arch/arm64/kernel/ftrace.c +--- linux-3.14.40.orig/arch/arm64/kernel/ftrace.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/kernel/ftrace.c 2015-05-01 14:57:58.219427001 -0500 +@@ -0,0 +1,177 @@ ++/* ++ * arch/arm64/kernel/ftrace.c ++ * ++ * Copyright (C) 2013 Linaro Limited ++ * Author: AKASHI Takahiro ++ * ++ * This program is free software; you can 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 ++ ++#ifdef CONFIG_DYNAMIC_FTRACE ++/* ++ * Replace a single instruction, which may be a branch or NOP. ++ * If @validate == true, a replaced instruction is checked against 'old'. ++ */ ++static int ftrace_modify_code(unsigned long pc, u32 old, u32 new, ++ bool validate) ++{ ++ u32 replaced; ++ ++ /* ++ * Note: ++ * Due to modules and __init, code can disappear and change, ++ * we need to protect against faulting as well as code changing. ++ * We do this by aarch64_insn_*() which use the probe_kernel_*(). ++ * ++ * No lock is held here because all the modifications are run ++ * through stop_machine(). ++ */ ++ if (validate) { ++ if (aarch64_insn_read((void *)pc, &replaced)) ++ return -EFAULT; ++ ++ if (replaced != old) ++ return -EINVAL; ++ } ++ if (aarch64_insn_patch_text_nosync((void *)pc, new)) ++ return -EPERM; ++ ++ return 0; ++} ++ ++/* ++ * Replace tracer function in ftrace_caller() ++ */ ++int ftrace_update_ftrace_func(ftrace_func_t func) ++{ ++ unsigned long pc; ++ u32 new; ++ ++ pc = (unsigned long)&ftrace_call; ++ new = aarch64_insn_gen_branch_imm(pc, (unsigned long)func, true); ++ ++ return ftrace_modify_code(pc, 0, new, false); ++} ++ ++/* ++ * Turn on the call to ftrace_caller() in instrumented function ++ */ ++int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) ++{ ++ unsigned long pc = rec->ip; ++ u32 old, new; ++ ++ old = aarch64_insn_gen_nop(); ++ new = aarch64_insn_gen_branch_imm(pc, addr, true); ++ ++ return ftrace_modify_code(pc, old, new, true); ++} ++ ++/* ++ * Turn off the call to ftrace_caller() in instrumented function ++ */ ++int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, ++ unsigned long addr) ++{ ++ unsigned long pc = rec->ip; ++ u32 old, new; ++ ++ old = aarch64_insn_gen_branch_imm(pc, addr, true); ++ new = aarch64_insn_gen_nop(); ++ ++ return ftrace_modify_code(pc, old, new, true); ++} ++ ++int __init ftrace_dyn_arch_init(void *data) ++{ ++ *(unsigned long *)data = 0; ++ return 0; ++} ++#endif /* CONFIG_DYNAMIC_FTRACE */ ++ ++#ifdef CONFIG_FUNCTION_GRAPH_TRACER ++/* ++ * function_graph tracer expects ftrace_return_to_handler() to be called ++ * on the way back to parent. For this purpose, this function is called ++ * in _mcount() or ftrace_caller() to replace return address (*parent) on ++ * the call stack to return_to_handler. ++ * ++ * Note that @frame_pointer is used only for sanity check later. ++ */ ++void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, ++ unsigned long frame_pointer) ++{ ++ unsigned long return_hooker = (unsigned long)&return_to_handler; ++ unsigned long old; ++ struct ftrace_graph_ent trace; ++ int err; ++ ++ if (unlikely(atomic_read(¤t->tracing_graph_pause))) ++ return; ++ ++ /* ++ * Note: ++ * No protection against faulting at *parent, which may be seen ++ * on other archs. It's unlikely on AArch64. ++ */ ++ old = *parent; ++ *parent = return_hooker; ++ ++ trace.func = self_addr; ++ trace.depth = current->curr_ret_stack + 1; ++ ++ /* Only trace if the calling function expects to */ ++ if (!ftrace_graph_entry(&trace)) { ++ *parent = old; ++ return; ++ } ++ ++ err = ftrace_push_return_trace(old, self_addr, &trace.depth, ++ frame_pointer); ++ if (err == -EBUSY) { ++ *parent = old; ++ return; ++ } ++} ++ ++#ifdef CONFIG_DYNAMIC_FTRACE ++/* ++ * Turn on/off the call to ftrace_graph_caller() in ftrace_caller() ++ * depending on @enable. ++ */ ++static int ftrace_modify_graph_caller(bool enable) ++{ ++ unsigned long pc = (unsigned long)&ftrace_graph_call; ++ u32 branch, nop; ++ ++ branch = aarch64_insn_gen_branch_imm(pc, ++ (unsigned long)ftrace_graph_caller, false); ++ nop = aarch64_insn_gen_nop(); ++ ++ if (enable) ++ return ftrace_modify_code(pc, nop, branch, true); ++ else ++ return ftrace_modify_code(pc, branch, nop, true); ++} ++ ++int ftrace_enable_ftrace_graph_caller(void) ++{ ++ return ftrace_modify_graph_caller(true); ++} ++ ++int ftrace_disable_ftrace_graph_caller(void) ++{ ++ return ftrace_modify_graph_caller(false); ++} ++#endif /* CONFIG_DYNAMIC_FTRACE */ ++#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/head.S linux-3.14.40/arch/arm64/kernel/head.S +--- linux-3.14.40.orig/arch/arm64/kernel/head.S 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/head.S 2015-05-01 14:57:58.219427001 -0500 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -34,29 +35,17 @@ + #include + #include + +-/* +- * swapper_pg_dir is the virtual address of the initial page table. We place +- * the page tables 3 * PAGE_SIZE below KERNEL_RAM_VADDR. The idmap_pg_dir has +- * 2 pages and is placed below swapper_pg_dir. +- */ + #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) + + #if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000 + #error KERNEL_RAM_VADDR must start at 0xXXX80000 + #endif + +-#define SWAPPER_DIR_SIZE (3 * PAGE_SIZE) +-#define IDMAP_DIR_SIZE (2 * PAGE_SIZE) +- +- .globl swapper_pg_dir +- .equ swapper_pg_dir, KERNEL_RAM_VADDR - SWAPPER_DIR_SIZE +- +- .globl idmap_pg_dir +- .equ idmap_pg_dir, swapper_pg_dir - IDMAP_DIR_SIZE +- +- .macro pgtbl, ttb0, ttb1, phys +- add \ttb1, \phys, #TEXT_OFFSET - SWAPPER_DIR_SIZE +- sub \ttb0, \ttb1, #IDMAP_DIR_SIZE ++ .macro pgtbl, ttb0, ttb1, virt_to_phys ++ ldr \ttb1, =swapper_pg_dir ++ ldr \ttb0, =idmap_pg_dir ++ add \ttb1, \ttb1, \virt_to_phys ++ add \ttb0, \ttb0, \virt_to_phys + .endm + + #ifdef CONFIG_ARM64_64K_PAGES +@@ -229,7 +218,11 @@ + cmp w20, #BOOT_CPU_MODE_EL2 + b.ne 1f + add x1, x1, #4 +-1: str w20, [x1] // This CPU has booted in EL1 ++1: dc cvac, x1 // Clean potentially dirty cache line ++ dsb sy ++ str w20, [x1] // This CPU has booted in EL1 ++ dc civac, x1 // Clean&invalidate potentially stale cache line ++ dsb sy + ret + ENDPROC(set_cpu_boot_mode_flag) + +@@ -240,8 +233,9 @@ + * This is not in .bss, because we set it sufficiently early that the boot-time + * zeroing of .bss would clobber it. + */ +- .pushsection .data ++ .pushsection .data..cacheline_aligned + ENTRY(__boot_cpu_mode) ++ .align L1_CACHE_SHIFT + .long BOOT_CPU_MODE_EL2 + .long 0 + .popsection +@@ -298,7 +292,7 @@ + mov x23, x0 // x23=current cpu_table + cbz x23, __error_p // invalid processor (x23=0)? + +- pgtbl x25, x26, x24 // x25=TTBR0, x26=TTBR1 ++ pgtbl x25, x26, x28 // x25=TTBR0, x26=TTBR1 + ldr x12, [x23, #CPU_INFO_SETUP] + add x12, x12, x28 // __virt_to_phys + blr x12 // initialise processor +@@ -340,8 +334,13 @@ + * x27 = *virtual* address to jump to upon completion + * + * other registers depend on the function called upon completion ++ * ++ * We align the entire function to the smallest power of two larger than it to ++ * ensure it fits within a single block map entry. Otherwise were PHYS_OFFSET ++ * close to the end of a 512MB or 1GB block we might require an additional ++ * table to map the entire function. + */ +- .align 6 ++ .align 4 + __turn_mmu_on: + msr sctlr_el1, x0 + isb +@@ -384,26 +383,18 @@ + * Preserves: tbl, flags + * Corrupts: phys, start, end, pstate + */ +- .macro create_block_map, tbl, flags, phys, start, end, idmap=0 ++ .macro create_block_map, tbl, flags, phys, start, end + lsr \phys, \phys, #BLOCK_SHIFT +- .if \idmap +- and \start, \phys, #PTRS_PER_PTE - 1 // table index +- .else + lsr \start, \start, #BLOCK_SHIFT + and \start, \start, #PTRS_PER_PTE - 1 // table index +- .endif + orr \phys, \flags, \phys, lsl #BLOCK_SHIFT // table entry +- .ifnc \start,\end + lsr \end, \end, #BLOCK_SHIFT + and \end, \end, #PTRS_PER_PTE - 1 // table end index +- .endif + 9999: str \phys, [\tbl, \start, lsl #3] // store the entry +- .ifnc \start,\end + add \start, \start, #1 // next entry + add \phys, \phys, #BLOCK_SIZE // next block + cmp \start, \end + b.ls 9999b +- .endif + .endm + + /* +@@ -415,7 +406,16 @@ + * - UART mapping if CONFIG_EARLY_PRINTK is enabled (TTBR1) + */ + __create_page_tables: +- pgtbl x25, x26, x24 // idmap_pg_dir and swapper_pg_dir addresses ++ pgtbl x25, x26, x28 // idmap_pg_dir and swapper_pg_dir addresses ++ mov x27, lr ++ ++ /* ++ * Invalidate the idmap and swapper page tables to avoid potential ++ * dirty cache lines being evicted. ++ */ ++ mov x0, x25 ++ add x1, x26, #SWAPPER_DIR_SIZE ++ bl __inval_cache_range + + /* + * Clear the idmap and swapper page tables. +@@ -435,9 +435,13 @@ + * Create the identity mapping. + */ + add x0, x25, #PAGE_SIZE // section table address +- adr x3, __turn_mmu_on // virtual/physical address ++ ldr x3, =KERNEL_START ++ add x3, x3, x28 // __pa(KERNEL_START) + create_pgd_entry x25, x0, x3, x5, x6 +- create_block_map x0, x7, x3, x5, x5, idmap=1 ++ ldr x6, =KERNEL_END ++ mov x5, x3 // __pa(KERNEL_START) ++ add x6, x6, x28 // __pa(KERNEL_END) ++ create_block_map x0, x7, x3, x5, x6 + + /* + * Map the kernel image (starting with PHYS_OFFSET). +@@ -445,7 +449,7 @@ + add x0, x26, #PAGE_SIZE // section table address + mov x5, #PAGE_OFFSET + create_pgd_entry x26, x0, x5, x3, x6 +- ldr x6, =KERNEL_END - 1 ++ ldr x6, =KERNEL_END + mov x3, x24 // phys offset + create_block_map x0, x7, x3, x5, x6 + +@@ -474,6 +478,17 @@ + add x0, x26, #2 * PAGE_SIZE // section table address + create_pgd_entry x26, x0, x5, x6, x7 + #endif ++ ++ /* ++ * Since the page tables have been populated with non-cacheable ++ * accesses (MMU disabled), invalidate the idmap and swapper page ++ * tables again to remove any speculatively loaded cache lines. ++ */ ++ mov x0, x25 ++ add x1, x26, #SWAPPER_DIR_SIZE ++ bl __inval_cache_range ++ ++ mov lr, x27 + ret + ENDPROC(__create_page_tables) + .ltorg +@@ -483,7 +498,7 @@ + __switch_data: + .quad __mmap_switched + .quad __bss_start // x6 +- .quad _end // x7 ++ .quad __bss_stop // x7 + .quad processor_id // x4 + .quad __fdt_pointer // x5 + .quad memstart_addr // x6 +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/hw_breakpoint.c linux-3.14.40/arch/arm64/kernel/hw_breakpoint.c +--- linux-3.14.40.orig/arch/arm64/kernel/hw_breakpoint.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/hw_breakpoint.c 2015-05-01 14:57:58.219427001 -0500 +@@ -20,6 +20,7 @@ + + #define pr_fmt(fmt) "hw-breakpoint: " fmt + ++#include + #include + #include + #include +@@ -27,7 +28,6 @@ + #include + #include + +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/kgdb.c linux-3.14.40/arch/arm64/kernel/kgdb.c +--- linux-3.14.40.orig/arch/arm64/kernel/kgdb.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/kernel/kgdb.c 2015-05-01 14:57:58.219427001 -0500 +@@ -0,0 +1,336 @@ ++/* ++ * AArch64 KGDB support ++ * ++ * Based on arch/arm/kernel/kgdb.c ++ * ++ * Copyright (C) 2013 Cavium Inc. ++ * Author: Vijaya Kumar K ++ * ++ * This program is free software; you can 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 ++ ++struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { ++ { "x0", 8, offsetof(struct pt_regs, regs[0])}, ++ { "x1", 8, offsetof(struct pt_regs, regs[1])}, ++ { "x2", 8, offsetof(struct pt_regs, regs[2])}, ++ { "x3", 8, offsetof(struct pt_regs, regs[3])}, ++ { "x4", 8, offsetof(struct pt_regs, regs[4])}, ++ { "x5", 8, offsetof(struct pt_regs, regs[5])}, ++ { "x6", 8, offsetof(struct pt_regs, regs[6])}, ++ { "x7", 8, offsetof(struct pt_regs, regs[7])}, ++ { "x8", 8, offsetof(struct pt_regs, regs[8])}, ++ { "x9", 8, offsetof(struct pt_regs, regs[9])}, ++ { "x10", 8, offsetof(struct pt_regs, regs[10])}, ++ { "x11", 8, offsetof(struct pt_regs, regs[11])}, ++ { "x12", 8, offsetof(struct pt_regs, regs[12])}, ++ { "x13", 8, offsetof(struct pt_regs, regs[13])}, ++ { "x14", 8, offsetof(struct pt_regs, regs[14])}, ++ { "x15", 8, offsetof(struct pt_regs, regs[15])}, ++ { "x16", 8, offsetof(struct pt_regs, regs[16])}, ++ { "x17", 8, offsetof(struct pt_regs, regs[17])}, ++ { "x18", 8, offsetof(struct pt_regs, regs[18])}, ++ { "x19", 8, offsetof(struct pt_regs, regs[19])}, ++ { "x20", 8, offsetof(struct pt_regs, regs[20])}, ++ { "x21", 8, offsetof(struct pt_regs, regs[21])}, ++ { "x22", 8, offsetof(struct pt_regs, regs[22])}, ++ { "x23", 8, offsetof(struct pt_regs, regs[23])}, ++ { "x24", 8, offsetof(struct pt_regs, regs[24])}, ++ { "x25", 8, offsetof(struct pt_regs, regs[25])}, ++ { "x26", 8, offsetof(struct pt_regs, regs[26])}, ++ { "x27", 8, offsetof(struct pt_regs, regs[27])}, ++ { "x28", 8, offsetof(struct pt_regs, regs[28])}, ++ { "x29", 8, offsetof(struct pt_regs, regs[29])}, ++ { "x30", 8, offsetof(struct pt_regs, regs[30])}, ++ { "sp", 8, offsetof(struct pt_regs, sp)}, ++ { "pc", 8, offsetof(struct pt_regs, pc)}, ++ { "pstate", 8, offsetof(struct pt_regs, pstate)}, ++ { "v0", 16, -1 }, ++ { "v1", 16, -1 }, ++ { "v2", 16, -1 }, ++ { "v3", 16, -1 }, ++ { "v4", 16, -1 }, ++ { "v5", 16, -1 }, ++ { "v6", 16, -1 }, ++ { "v7", 16, -1 }, ++ { "v8", 16, -1 }, ++ { "v9", 16, -1 }, ++ { "v10", 16, -1 }, ++ { "v11", 16, -1 }, ++ { "v12", 16, -1 }, ++ { "v13", 16, -1 }, ++ { "v14", 16, -1 }, ++ { "v15", 16, -1 }, ++ { "v16", 16, -1 }, ++ { "v17", 16, -1 }, ++ { "v18", 16, -1 }, ++ { "v19", 16, -1 }, ++ { "v20", 16, -1 }, ++ { "v21", 16, -1 }, ++ { "v22", 16, -1 }, ++ { "v23", 16, -1 }, ++ { "v24", 16, -1 }, ++ { "v25", 16, -1 }, ++ { "v26", 16, -1 }, ++ { "v27", 16, -1 }, ++ { "v28", 16, -1 }, ++ { "v29", 16, -1 }, ++ { "v30", 16, -1 }, ++ { "v31", 16, -1 }, ++ { "fpsr", 4, -1 }, ++ { "fpcr", 4, -1 }, ++}; ++ ++char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) ++{ ++ if (regno >= DBG_MAX_REG_NUM || regno < 0) ++ return NULL; ++ ++ if (dbg_reg_def[regno].offset != -1) ++ memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, ++ dbg_reg_def[regno].size); ++ else ++ memset(mem, 0, dbg_reg_def[regno].size); ++ return dbg_reg_def[regno].name; ++} ++ ++int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) ++{ ++ if (regno >= DBG_MAX_REG_NUM || regno < 0) ++ return -EINVAL; ++ ++ if (dbg_reg_def[regno].offset != -1) ++ memcpy((void *)regs + dbg_reg_def[regno].offset, mem, ++ dbg_reg_def[regno].size); ++ return 0; ++} ++ ++void ++sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) ++{ ++ struct pt_regs *thread_regs; ++ ++ /* Initialize to zero */ ++ memset((char *)gdb_regs, 0, NUMREGBYTES); ++ thread_regs = task_pt_regs(task); ++ memcpy((void *)gdb_regs, (void *)thread_regs->regs, GP_REG_BYTES); ++} ++ ++void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) ++{ ++ regs->pc = pc; ++} ++ ++static int compiled_break; ++ ++static void kgdb_arch_update_addr(struct pt_regs *regs, ++ char *remcom_in_buffer) ++{ ++ unsigned long addr; ++ char *ptr; ++ ++ ptr = &remcom_in_buffer[1]; ++ if (kgdb_hex2long(&ptr, &addr)) ++ kgdb_arch_set_pc(regs, addr); ++ else if (compiled_break == 1) ++ kgdb_arch_set_pc(regs, regs->pc + 4); ++ ++ compiled_break = 0; ++} ++ ++int kgdb_arch_handle_exception(int exception_vector, int signo, ++ int err_code, char *remcom_in_buffer, ++ char *remcom_out_buffer, ++ struct pt_regs *linux_regs) ++{ ++ int err; ++ ++ switch (remcom_in_buffer[0]) { ++ case 'D': ++ case 'k': ++ /* ++ * Packet D (Detach), k (kill). No special handling ++ * is required here. Handle same as c packet. ++ */ ++ case 'c': ++ /* ++ * Packet c (Continue) to continue executing. ++ * Set pc to required address. ++ * Try to read optional parameter and set pc. ++ * If this was a compiled breakpoint, we need to move ++ * to the next instruction else we will just breakpoint ++ * over and over again. ++ */ ++ kgdb_arch_update_addr(linux_regs, remcom_in_buffer); ++ atomic_set(&kgdb_cpu_doing_single_step, -1); ++ kgdb_single_step = 0; ++ ++ /* ++ * Received continue command, disable single step ++ */ ++ if (kernel_active_single_step()) ++ kernel_disable_single_step(); ++ ++ err = 0; ++ break; ++ case 's': ++ /* ++ * Update step address value with address passed ++ * with step packet. ++ * On debug exception return PC is copied to ELR ++ * So just update PC. ++ * If no step address is passed, resume from the address ++ * pointed by PC. Do not update PC ++ */ ++ kgdb_arch_update_addr(linux_regs, remcom_in_buffer); ++ atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id()); ++ kgdb_single_step = 1; ++ ++ /* ++ * Enable single step handling ++ */ ++ if (!kernel_active_single_step()) ++ kernel_enable_single_step(linux_regs); ++ err = 0; ++ break; ++ default: ++ err = -1; ++ } ++ return err; ++} ++ ++static int kgdb_brk_fn(struct pt_regs *regs, unsigned int esr) ++{ ++ kgdb_handle_exception(1, SIGTRAP, 0, regs); ++ return 0; ++} ++ ++static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int esr) ++{ ++ compiled_break = 1; ++ kgdb_handle_exception(1, SIGTRAP, 0, regs); ++ ++ return 0; ++} ++ ++static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr) ++{ ++ kgdb_handle_exception(1, SIGTRAP, 0, regs); ++ return 0; ++} ++ ++static struct break_hook kgdb_brkpt_hook = { ++ .esr_mask = 0xffffffff, ++ .esr_val = DBG_ESR_VAL_BRK(KGDB_DYN_DGB_BRK_IMM), ++ .fn = kgdb_brk_fn ++}; ++ ++static struct break_hook kgdb_compiled_brkpt_hook = { ++ .esr_mask = 0xffffffff, ++ .esr_val = DBG_ESR_VAL_BRK(KDBG_COMPILED_DBG_BRK_IMM), ++ .fn = kgdb_compiled_brk_fn ++}; ++ ++static struct step_hook kgdb_step_hook = { ++ .fn = kgdb_step_brk_fn ++}; ++ ++static void kgdb_call_nmi_hook(void *ignored) ++{ ++ kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs()); ++} ++ ++void kgdb_roundup_cpus(unsigned long flags) ++{ ++ local_irq_enable(); ++ smp_call_function(kgdb_call_nmi_hook, NULL, 0); ++ local_irq_disable(); ++} ++ ++static int __kgdb_notify(struct die_args *args, unsigned long cmd) ++{ ++ struct pt_regs *regs = args->regs; ++ ++ if (kgdb_handle_exception(1, args->signr, cmd, regs)) ++ return NOTIFY_DONE; ++ return NOTIFY_STOP; ++} ++ ++static int ++kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) ++{ ++ unsigned long flags; ++ int ret; ++ ++ local_irq_save(flags); ++ ret = __kgdb_notify(ptr, cmd); ++ local_irq_restore(flags); ++ ++ return ret; ++} ++ ++static struct notifier_block kgdb_notifier = { ++ .notifier_call = kgdb_notify, ++ /* ++ * Want to be lowest priority ++ */ ++ .priority = -INT_MAX, ++}; ++ ++/* ++ * kgdb_arch_init - Perform any architecture specific initalization. ++ * This function will handle the initalization of any architecture ++ * specific callbacks. ++ */ ++int kgdb_arch_init(void) ++{ ++ int ret = register_die_notifier(&kgdb_notifier); ++ ++ if (ret != 0) ++ return ret; ++ ++ register_break_hook(&kgdb_brkpt_hook); ++ register_break_hook(&kgdb_compiled_brkpt_hook); ++ register_step_hook(&kgdb_step_hook); ++ return 0; ++} ++ ++/* ++ * kgdb_arch_exit - Perform any architecture specific uninitalization. ++ * This function will handle the uninitalization of any architecture ++ * specific callbacks, for dynamic registration and unregistration. ++ */ ++void kgdb_arch_exit(void) ++{ ++ unregister_break_hook(&kgdb_brkpt_hook); ++ unregister_break_hook(&kgdb_compiled_brkpt_hook); ++ unregister_step_hook(&kgdb_step_hook); ++ unregister_die_notifier(&kgdb_notifier); ++} ++ ++/* ++ * ARM instructions are always in LE. ++ * Break instruction is encoded in LE format ++ */ ++struct kgdb_arch arch_kgdb_ops = { ++ .gdb_bpt_instr = { ++ KGDB_DYN_BRK_INS_BYTE0, ++ KGDB_DYN_BRK_INS_BYTE1, ++ KGDB_DYN_BRK_INS_BYTE2, ++ KGDB_DYN_BRK_INS_BYTE3, ++ } ++}; +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/Makefile linux-3.14.40/arch/arm64/kernel/Makefile +--- linux-3.14.40.orig/arch/arm64/kernel/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/Makefile 2015-05-01 14:57:58.219427001 -0500 +@@ -5,21 +5,29 @@ + CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) + AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) + ++CFLAGS_REMOVE_ftrace.o = -pg ++CFLAGS_REMOVE_insn.o = -pg ++CFLAGS_REMOVE_return_address.o = -pg ++ + # Object file lists. + 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 cpu_ops.o insn.o ++ hyp-stub.o psci.o cpu_ops.o insn.o return_address.o + + arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ + sys_compat.o ++arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o + arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o ++arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o + arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o ++arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o + arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o +-arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o ++arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o + arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o + arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o ++arm64-obj-$(CONFIG_KGDB) += kgdb.o + + obj-y += $(arm64-obj-y) vdso/ + obj-m += $(arm64-obj-m) +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/perf_event.c linux-3.14.40/arch/arm64/kernel/perf_event.c +--- linux-3.14.40.orig/arch/arm64/kernel/perf_event.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/perf_event.c 2015-05-01 14:57:58.219427001 -0500 +@@ -1348,8 +1348,8 @@ + * Callchain handling code. + */ + struct frame_tail { +- struct frame_tail __user *fp; +- unsigned long lr; ++ struct frame_tail __user *fp; ++ unsigned long lr; + } __attribute__((packed)); + + /* +@@ -1386,22 +1386,84 @@ + return buftail.fp; + } + ++#ifdef CONFIG_COMPAT ++/* ++ * The registers we're interested in are at the end of the variable ++ * length saved register structure. The fp points at the end of this ++ * structure so the address of this struct is: ++ * (struct compat_frame_tail *)(xxx->fp)-1 ++ * ++ * This code has been adapted from the ARM OProfile support. ++ */ ++struct compat_frame_tail { ++ compat_uptr_t fp; /* a (struct compat_frame_tail *) in compat mode */ ++ u32 sp; ++ u32 lr; ++} __attribute__((packed)); ++ ++static struct compat_frame_tail __user * ++compat_user_backtrace(struct compat_frame_tail __user *tail, ++ struct perf_callchain_entry *entry) ++{ ++ struct compat_frame_tail buftail; ++ unsigned long err; ++ ++ /* Also check accessibility of one struct frame_tail beyond */ ++ if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) ++ return NULL; ++ ++ pagefault_disable(); ++ err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail)); ++ pagefault_enable(); ++ ++ if (err) ++ return NULL; ++ ++ perf_callchain_store(entry, buftail.lr); ++ ++ /* ++ * Frame pointers should strictly progress back up the stack ++ * (towards higher addresses). ++ */ ++ if (tail + 1 >= (struct compat_frame_tail __user *) ++ compat_ptr(buftail.fp)) ++ return NULL; ++ ++ return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1; ++} ++#endif /* CONFIG_COMPAT */ ++ + void perf_callchain_user(struct perf_callchain_entry *entry, + struct pt_regs *regs) + { +- struct frame_tail __user *tail; +- + if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + /* We don't support guest os callchain now */ + return; + } + + perf_callchain_store(entry, regs->pc); +- tail = (struct frame_tail __user *)regs->regs[29]; + +- while (entry->nr < PERF_MAX_STACK_DEPTH && +- tail && !((unsigned long)tail & 0xf)) +- tail = user_backtrace(tail, entry); ++ if (!compat_user_mode(regs)) { ++ /* AARCH64 mode */ ++ struct frame_tail __user *tail; ++ ++ tail = (struct frame_tail __user *)regs->regs[29]; ++ ++ while (entry->nr < PERF_MAX_STACK_DEPTH && ++ tail && !((unsigned long)tail & 0xf)) ++ tail = user_backtrace(tail, entry); ++ } else { ++#ifdef CONFIG_COMPAT ++ /* AARCH32 compat mode */ ++ struct compat_frame_tail __user *tail; ++ ++ tail = (struct compat_frame_tail __user *)regs->compat_fp - 1; ++ ++ while ((entry->nr < PERF_MAX_STACK_DEPTH) && ++ tail && !((unsigned long)tail & 0x3)) ++ tail = compat_user_backtrace(tail, entry); ++#endif ++ } + } + + /* +@@ -1429,6 +1491,7 @@ + frame.fp = regs->regs[29]; + frame.sp = regs->sp; + frame.pc = regs->pc; ++ + walk_stackframe(&frame, callchain_trace, entry); + } + +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/perf_regs.c linux-3.14.40/arch/arm64/kernel/perf_regs.c +--- linux-3.14.40.orig/arch/arm64/kernel/perf_regs.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/kernel/perf_regs.c 2015-05-01 14:57:58.219427001 -0500 +@@ -0,0 +1,46 @@ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++u64 perf_reg_value(struct pt_regs *regs, int idx) ++{ ++ if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX)) ++ return 0; ++ ++ /* ++ * Compat (i.e. 32 bit) mode: ++ * - PC has been set in the pt_regs struct in kernel_entry, ++ * - Handle SP and LR here. ++ */ ++ if (compat_user_mode(regs)) { ++ if ((u32)idx == PERF_REG_ARM64_SP) ++ return regs->compat_sp; ++ if ((u32)idx == PERF_REG_ARM64_LR) ++ return regs->compat_lr; ++ } ++ ++ return regs->regs[idx]; ++} ++ ++#define REG_RESERVED (~((1ULL << PERF_REG_ARM64_MAX) - 1)) ++ ++int perf_reg_validate(u64 mask) ++{ ++ if (!mask || mask & REG_RESERVED) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++u64 perf_reg_abi(struct task_struct *task) ++{ ++ if (is_compat_thread(task_thread_info(task))) ++ return PERF_SAMPLE_REGS_ABI_32; ++ else ++ return PERF_SAMPLE_REGS_ABI_64; ++} +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/process.c linux-3.14.40/arch/arm64/kernel/process.c +--- linux-3.14.40.orig/arch/arm64/kernel/process.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/process.c 2015-05-01 14:57:58.223427001 -0500 +@@ -20,6 +20,7 @@ + + #include + ++#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/ptrace.c linux-3.14.40/arch/arm64/kernel/ptrace.c +--- linux-3.14.40.orig/arch/arm64/kernel/ptrace.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/ptrace.c 2015-05-01 14:57:58.223427001 -0500 +@@ -19,6 +19,7 @@ + * along with this program. If not, see . + */ + ++#include + #include + #include + #include +@@ -41,6 +42,9 @@ + #include + #include + ++#define CREATE_TRACE_POINTS ++#include ++ + /* + * TODO: does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. +@@ -1073,35 +1077,49 @@ + return ptrace_request(child, request, addr, data); + } + +-asmlinkage int syscall_trace(int dir, struct pt_regs *regs) ++enum ptrace_syscall_dir { ++ PTRACE_SYSCALL_ENTER = 0, ++ PTRACE_SYSCALL_EXIT, ++}; ++ ++static void tracehook_report_syscall(struct pt_regs *regs, ++ enum ptrace_syscall_dir dir) + { ++ int regno; + unsigned long saved_reg; + +- if (!test_thread_flag(TIF_SYSCALL_TRACE)) +- return regs->syscallno; +- +- if (is_compat_task()) { +- /* AArch32 uses ip (r12) for scratch */ +- saved_reg = regs->regs[12]; +- regs->regs[12] = dir; +- } else { +- /* +- * Save X7. X7 is used to denote syscall entry/exit: +- * X7 = 0 -> entry, = 1 -> exit +- */ +- saved_reg = regs->regs[7]; +- regs->regs[7] = dir; +- } ++ /* ++ * A scratch register (ip(r12) on AArch32, x7 on AArch64) is ++ * used to denote syscall entry/exit: ++ */ ++ regno = (is_compat_task() ? 12 : 7); ++ saved_reg = regs->regs[regno]; ++ regs->regs[regno] = dir; + +- if (dir) ++ if (dir == PTRACE_SYSCALL_EXIT) + tracehook_report_syscall_exit(regs, 0); + else if (tracehook_report_syscall_entry(regs)) + regs->syscallno = ~0UL; + +- if (is_compat_task()) +- regs->regs[12] = saved_reg; +- else +- regs->regs[7] = saved_reg; ++ regs->regs[regno] = saved_reg; ++} ++ ++asmlinkage int syscall_trace_enter(struct pt_regs *regs) ++{ ++ if (test_thread_flag(TIF_SYSCALL_TRACE)) ++ tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER); ++ ++ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) ++ trace_sys_enter(regs, regs->syscallno); + + return regs->syscallno; + } ++ ++asmlinkage void syscall_trace_exit(struct pt_regs *regs) ++{ ++ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) ++ trace_sys_exit(regs, regs_return_value(regs)); ++ ++ if (test_thread_flag(TIF_SYSCALL_TRACE)) ++ tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT); ++} +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/return_address.c linux-3.14.40/arch/arm64/kernel/return_address.c +--- linux-3.14.40.orig/arch/arm64/kernel/return_address.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/kernel/return_address.c 2015-05-01 14:57:58.223427001 -0500 +@@ -0,0 +1,55 @@ ++/* ++ * arch/arm64/kernel/return_address.c ++ * ++ * Copyright (C) 2013 Linaro Limited ++ * Author: AKASHI Takahiro ++ * ++ * This program is free software; you can 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 ++ ++struct return_address_data { ++ unsigned int level; ++ void *addr; ++}; ++ ++static int save_return_addr(struct stackframe *frame, void *d) ++{ ++ struct return_address_data *data = d; ++ ++ if (!data->level) { ++ data->addr = (void *)frame->pc; ++ return 1; ++ } else { ++ --data->level; ++ return 0; ++ } ++} ++ ++void *return_address(unsigned int level) ++{ ++ struct return_address_data data; ++ struct stackframe frame; ++ register unsigned long current_sp asm ("sp"); ++ ++ data.level = level + 2; ++ data.addr = NULL; ++ ++ frame.fp = (unsigned long)__builtin_frame_address(0); ++ frame.sp = current_sp; ++ frame.pc = (unsigned long)return_address; /* dummy */ ++ ++ walk_stackframe(&frame, save_return_addr, &data); ++ ++ if (!data.level) ++ return data.addr; ++ else ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(return_address); +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/setup.c linux-3.14.40/arch/arm64/kernel/setup.c +--- linux-3.14.40.orig/arch/arm64/kernel/setup.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/setup.c 2015-05-01 14:57:58.223427001 -0500 +@@ -71,6 +71,7 @@ + COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV|\ + COMPAT_HWCAP_LPAE) + unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT; ++unsigned int compat_elf_hwcap2 __read_mostly; + #endif + + static const char *cpu_name; +@@ -258,6 +259,38 @@ + block = (features >> 16) & 0xf; + if (block && !(block & 0x8)) + elf_hwcap |= HWCAP_CRC32; ++ ++#ifdef CONFIG_COMPAT ++ /* ++ * ID_ISAR5_EL1 carries similar information as above, but pertaining to ++ * the Aarch32 32-bit execution state. ++ */ ++ features = read_cpuid(ID_ISAR5_EL1); ++ block = (features >> 4) & 0xf; ++ if (!(block & 0x8)) { ++ switch (block) { ++ default: ++ case 2: ++ compat_elf_hwcap2 |= COMPAT_HWCAP2_PMULL; ++ case 1: ++ compat_elf_hwcap2 |= COMPAT_HWCAP2_AES; ++ case 0: ++ break; ++ } ++ } ++ ++ block = (features >> 8) & 0xf; ++ if (block && !(block & 0x8)) ++ compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA1; ++ ++ block = (features >> 12) & 0xf; ++ if (block && !(block & 0x8)) ++ compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA2; ++ ++ block = (features >> 16) & 0xf; ++ if (block && !(block & 0x8)) ++ compat_elf_hwcap2 |= COMPAT_HWCAP2_CRC32; ++#endif + } + + static void __init setup_machine_fdt(phys_addr_t dt_phys) +@@ -374,7 +407,7 @@ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + return 0; + } +-arch_initcall(arm64_device_init); ++arch_initcall_sync(arm64_device_init); + + static int __init topology_init(void) + { +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/signal.c linux-3.14.40/arch/arm64/kernel/signal.c +--- linux-3.14.40.orig/arch/arm64/kernel/signal.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/signal.c 2015-05-01 14:57:58.223427001 -0500 +@@ -17,6 +17,7 @@ + * along with this program. If not, see . + */ + ++#include + #include + #include + #include +@@ -25,7 +26,6 @@ + #include + #include + +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/smp.c linux-3.14.40/arch/arm64/kernel/smp.c +--- linux-3.14.40.orig/arch/arm64/kernel/smp.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/smp.c 2015-05-01 14:57:58.223427001 -0500 +@@ -114,6 +114,11 @@ + return ret; + } + ++static void 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. +@@ -157,6 +162,8 @@ + */ + notify_cpu_starting(cpu); + ++ smp_store_cpu_info(cpu); ++ + /* + * OK, now it's safe to let the boot CPU continue. Wait for + * the CPU migration code to notice that the CPU is online +@@ -395,6 +402,10 @@ + 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? + */ +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/stacktrace.c linux-3.14.40/arch/arm64/kernel/stacktrace.c +--- linux-3.14.40.orig/arch/arm64/kernel/stacktrace.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/stacktrace.c 2015-05-01 14:57:58.223427001 -0500 +@@ -35,7 +35,7 @@ + * ldp x29, x30, [sp] + * add sp, sp, #0x10 + */ +-int unwind_frame(struct stackframe *frame) ++int notrace unwind_frame(struct stackframe *frame) + { + unsigned long high, low; + unsigned long fp = frame->fp; +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/topology.c linux-3.14.40/arch/arm64/kernel/topology.c +--- linux-3.14.40.orig/arch/arm64/kernel/topology.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/arch/arm64/kernel/topology.c 2015-05-01 14:57:58.223427001 -0500 +@@ -0,0 +1,558 @@ ++/* ++ * arch/arm64/kernel/topology.c ++ * ++ * Copyright (C) 2011,2013,2014 Linaro Limited. ++ * ++ * Based on the arm32 version written by Vincent Guittot in turn 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 ++ ++/* ++ * 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; ++} ++ ++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) ++ return -1; ++ ++ for_each_possible_cpu(cpu) { ++ if (of_get_cpu_node(cpu, NULL) == cpu_node) { ++ of_node_put(cpu_node); ++ return cpu; ++ } ++ } ++ ++ pr_crit("Unable to find CPU node for %s\n", cpu_node->full_name); ++ ++ of_node_put(cpu_node); ++ return -1; ++} ++ ++static int __init parse_core(struct device_node *core, int cluster_id, ++ int core_id) ++{ ++ char name[10]; ++ bool leaf = true; ++ int i = 0; ++ int cpu; ++ struct device_node *t; ++ ++ 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 >= 0) { ++ cpu_topology[cpu].cluster_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); ++ of_node_put(t); ++ return -EINVAL; ++ } ++ of_node_put(t); ++ } ++ 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 -EINVAL; ++ } ++ ++ cpu_topology[cpu].cluster_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); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int __init parse_cluster(struct device_node *cluster, int depth) ++{ ++ char name[10]; ++ bool leaf = true; ++ bool has_cores = false; ++ struct device_node *c; ++ static int cluster_id __initdata; ++ int core_id = 0; ++ int i, ret; ++ ++ /* ++ * 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) { ++ leaf = false; ++ ret = parse_cluster(c, depth + 1); ++ of_node_put(c); ++ if (ret != 0) ++ return ret; ++ } ++ 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 (depth == 0) { ++ pr_err("%s: cpu-map children should be clusters\n", ++ c->full_name); ++ of_node_put(c); ++ return -EINVAL; ++ } ++ ++ if (leaf) { ++ ret = parse_core(c, cluster_id, core_id++); ++ } else { ++ pr_err("%s: Non-leaf cluster with core %s\n", ++ cluster->full_name, name); ++ ret = -EINVAL; ++ } ++ ++ of_node_put(c); ++ if (ret != 0) ++ return ret; ++ } ++ i++; ++ } while (c); ++ ++ if (leaf && !has_cores) ++ pr_warn("%s: empty cluster\n", cluster->full_name); ++ ++ if (leaf) ++ cluster_id++; ++ ++ return 0; ++} ++ ++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; ++ ++/* ++ * 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 int __init parse_dt_topology(void) ++{ ++ struct device_node *cn, *map; ++ int ret = 0; ++ int cpu; ++ ++ cn = of_find_node_by_path("/cpus"); ++ if (!cn) { ++ pr_err("No CPU information found in DT\n"); ++ return 0; ++ } ++ ++ /* ++ * When topology is provided cpu-map is essentially a root ++ * cluster with restricted subnodes. ++ */ ++ map = of_get_child_by_name(cn, "cpu-map"); ++ if (!map) ++ goto out; ++ ++ ret = parse_cluster(map, 0); ++ if (ret != 0) ++ goto out_map; ++ ++ /* ++ * Check that all cores are in the topology; the SMP code will ++ * only mark cores described in the DT as possible. ++ */ ++ for_each_possible_cpu(cpu) { ++ if (cpu_topology[cpu].cluster_id == -1) { ++ pr_err("CPU%d: No topology information specified\n", ++ cpu); ++ ret = -EINVAL; ++ } ++ } ++ ++out_map: ++ of_node_put(map); ++out: ++ of_node_put(cn); ++ return ret; ++} ++ ++static void __init parse_dt_cpu_power(void) ++{ ++ const struct cpu_efficiency *cpu_eff; ++ struct device_node *cn; ++ unsigned long min_capacity = ULONG_MAX; ++ unsigned long max_capacity = 0; ++ unsigned long capacity = 0; ++ int cpu; ++ ++ __cpu_capacity = kcalloc(nr_cpu_ids, sizeof(*__cpu_capacity), ++ GFP_NOWAIT); ++ ++ 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; ++ } ++ ++ 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)); ++} ++ ++/* ++ * cpu topology table ++ */ ++struct cpu_topology 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 cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; ++ int cpu; ++ ++ if (cpuid_topo->cluster_id == -1) { ++ /* ++ * DT does not contain topology information for this cpu. ++ */ ++ pr_debug("CPU%u: No topology information configured\n", cpuid); ++ return; ++ } ++ ++ /* update core and thread sibling masks */ ++ for_each_possible_cpu(cpu) { ++ cpu_topo = &cpu_topology[cpu]; ++ ++ if (cpuid_topo->cluster_id != cpu_topo->cluster_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); ++ } ++} ++ ++void store_cpu_topology(unsigned int cpuid) ++{ ++ 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 */ ++ ++static void __init reset_cpu_topology(void) ++{ ++ unsigned int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ struct cpu_topology *cpu_topo = &cpu_topology[cpu]; ++ ++ cpu_topo->thread_id = -1; ++ cpu_topo->core_id = 0; ++ cpu_topo->cluster_id = -1; ++ ++ cpumask_clear(&cpu_topo->core_sibling); ++ cpumask_set_cpu(cpu, &cpu_topo->core_sibling); ++ cpumask_clear(&cpu_topo->thread_sibling); ++ cpumask_set_cpu(cpu, &cpu_topo->thread_sibling); ++ } ++} ++ ++static void __init reset_cpu_power(void) ++{ ++ unsigned int cpu; ++ ++ for_each_possible_cpu(cpu) ++ set_power_scale(cpu, SCHED_POWER_SCALE); ++} ++ ++void __init init_cpu_topology(void) ++{ ++ reset_cpu_topology(); ++ ++ /* ++ * Discard anything that was parsed if we hit an error so we ++ * don't use partial information. ++ */ ++ if (parse_dt_topology()) ++ reset_cpu_topology(); ++ ++ reset_cpu_power(); ++ parse_dt_cpu_power(); ++} +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/vdso/Makefile linux-3.14.40/arch/arm64/kernel/vdso/Makefile +--- linux-3.14.40.orig/arch/arm64/kernel/vdso/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/vdso/Makefile 2015-05-01 14:57:58.223427001 -0500 +@@ -47,9 +47,9 @@ + $(call if_changed_dep,vdsoas) + + # Actual build commands +-quiet_cmd_vdsold = VDSOL $@ ++quiet_cmd_vdsold = VDSOL $@ + cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $^ -o $@ +-quiet_cmd_vdsoas = VDSOA $@ ++quiet_cmd_vdsoas = VDSOA $@ + cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $< + + # Install commands for the unstripped file +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/vdso.c linux-3.14.40/arch/arm64/kernel/vdso.c +--- linux-3.14.40.orig/arch/arm64/kernel/vdso.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/vdso.c 2015-05-01 14:57:58.223427001 -0500 +@@ -156,11 +156,12 @@ + int uses_interp) + { + struct mm_struct *mm = current->mm; +- unsigned long vdso_base, vdso_mapping_len; ++ unsigned long vdso_base, vdso_text_len, vdso_mapping_len; + int ret; + ++ vdso_text_len = vdso_pages << PAGE_SHIFT; + /* Be sure to map the data page */ +- vdso_mapping_len = (vdso_pages + 1) << PAGE_SHIFT; ++ vdso_mapping_len = vdso_text_len + PAGE_SIZE; + + down_write(&mm->mmap_sem); + vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0); +@@ -170,35 +171,52 @@ + } + mm->context.vdso = (void *)vdso_base; + +- ret = install_special_mapping(mm, vdso_base, vdso_mapping_len, ++ ret = install_special_mapping(mm, vdso_base, vdso_text_len, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, + vdso_pagelist); +- if (ret) { +- mm->context.vdso = NULL; ++ if (ret) ++ goto up_fail; ++ ++ vdso_base += vdso_text_len; ++ ret = install_special_mapping(mm, vdso_base, PAGE_SIZE, ++ VM_READ|VM_MAYREAD, ++ vdso_pagelist + vdso_pages); ++ if (ret) + goto up_fail; +- } + +-up_fail: + up_write(&mm->mmap_sem); ++ return 0; + ++up_fail: ++ mm->context.vdso = NULL; ++ up_write(&mm->mmap_sem); + return ret; + } + + const char *arch_vma_name(struct vm_area_struct *vma) + { ++ unsigned long vdso_text; ++ ++ if (!vma->vm_mm) ++ return NULL; ++ ++ vdso_text = (unsigned long)vma->vm_mm->context.vdso; ++ + /* + * We can re-use the vdso pointer in mm_context_t for identifying + * the vectors page for compat applications. The vDSO will always + * sit above TASK_UNMAPPED_BASE and so we don't need to worry about + * it conflicting with the vectors base. + */ +- if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) { ++ if (vma->vm_start == vdso_text) { + #ifdef CONFIG_COMPAT + if (vma->vm_start == AARCH32_VECTORS_BASE) + return "[vectors]"; + #endif + return "[vdso]"; ++ } else if (vma->vm_start == (vdso_text + (vdso_pages << PAGE_SHIFT))) { ++ return "[vvar]"; + } + + return NULL; +diff -Nur linux-3.14.40.orig/arch/arm64/kernel/vmlinux.lds.S linux-3.14.40/arch/arm64/kernel/vmlinux.lds.S +--- linux-3.14.40.orig/arch/arm64/kernel/vmlinux.lds.S 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/kernel/vmlinux.lds.S 2015-05-01 14:57:58.227427001 -0500 +@@ -104,6 +104,13 @@ + _edata = .; + + BSS_SECTION(0, 0, 0) ++ ++ . = ALIGN(PAGE_SIZE); ++ idmap_pg_dir = .; ++ . += IDMAP_DIR_SIZE; ++ swapper_pg_dir = .; ++ . += SWAPPER_DIR_SIZE; ++ + _end = .; + + STABS_DEBUG +diff -Nur linux-3.14.40.orig/arch/arm64/Makefile linux-3.14.40/arch/arm64/Makefile +--- linux-3.14.40.orig/arch/arm64/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/Makefile 2015-05-01 14:57:58.231427001 -0500 +@@ -45,6 +45,7 @@ + core-y += arch/arm64/kernel/ arch/arm64/mm/ + core-$(CONFIG_KVM) += arch/arm64/kvm/ + core-$(CONFIG_XEN) += arch/arm64/xen/ ++core-$(CONFIG_CRYPTO) += arch/arm64/crypto/ + libs-y := arch/arm64/lib/ $(libs-y) + libs-y += $(LIBGCC) + +diff -Nur linux-3.14.40.orig/arch/arm64/mm/cache.S linux-3.14.40/arch/arm64/mm/cache.S +--- linux-3.14.40.orig/arch/arm64/mm/cache.S 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/mm/cache.S 2015-05-01 14:57:58.231427001 -0500 +@@ -30,7 +30,7 @@ + * + * Corrupted registers: x0-x7, x9-x11 + */ +-ENTRY(__flush_dcache_all) ++__flush_dcache_all: + dsb sy // ensure ordering with previous memory accesses + mrs x0, clidr_el1 // read clidr + and x3, x0, #0x7000000 // extract loc from clidr +@@ -166,3 +166,97 @@ + dsb sy + ret + ENDPROC(__flush_dcache_area) ++ ++/* ++ * __inval_cache_range(start, end) ++ * - start - start address of region ++ * - end - end address of region ++ */ ++ENTRY(__inval_cache_range) ++ /* FALLTHROUGH */ ++ ++/* ++ * __dma_inv_range(start, end) ++ * - start - virtual start address of region ++ * - end - virtual end address of region ++ */ ++__dma_inv_range: ++ dcache_line_size x2, x3 ++ sub x3, x2, #1 ++ tst x1, x3 // end cache line aligned? ++ bic x1, x1, x3 ++ b.eq 1f ++ dc civac, x1 // clean & invalidate D / U line ++1: tst x0, x3 // start cache line aligned? ++ bic x0, x0, x3 ++ b.eq 2f ++ dc civac, x0 // clean & invalidate D / U line ++ b 3f ++2: dc ivac, x0 // invalidate D / U line ++3: add x0, x0, x2 ++ cmp x0, x1 ++ b.lo 2b ++ dsb sy ++ ret ++ENDPROC(__inval_cache_range) ++ENDPROC(__dma_inv_range) ++ ++/* ++ * __dma_clean_range(start, end) ++ * - start - virtual start address of region ++ * - end - virtual end address of region ++ */ ++__dma_clean_range: ++ dcache_line_size x2, x3 ++ sub x3, x2, #1 ++ bic x0, x0, x3 ++1: dc cvac, x0 // clean D / U line ++ add x0, x0, x2 ++ cmp x0, x1 ++ b.lo 1b ++ dsb sy ++ ret ++ENDPROC(__dma_clean_range) ++ ++/* ++ * __dma_flush_range(start, end) ++ * - start - virtual start address of region ++ * - end - virtual end address of region ++ */ ++ENTRY(__dma_flush_range) ++ dcache_line_size x2, x3 ++ sub x3, x2, #1 ++ bic x0, x0, x3 ++1: dc civac, x0 // clean & invalidate D / U line ++ add x0, x0, x2 ++ cmp x0, x1 ++ b.lo 1b ++ dsb sy ++ ret ++ENDPROC(__dma_flush_range) ++ ++/* ++ * __dma_map_area(start, size, dir) ++ * - start - kernel virtual start address ++ * - size - size of region ++ * - dir - DMA direction ++ */ ++ENTRY(__dma_map_area) ++ add x1, x1, x0 ++ cmp w2, #DMA_FROM_DEVICE ++ b.eq __dma_inv_range ++ b __dma_clean_range ++ENDPROC(__dma_map_area) ++ ++/* ++ * __dma_unmap_area(start, size, dir) ++ * - start - kernel virtual start address ++ * - size - size of region ++ * - dir - DMA direction ++ */ ++ENTRY(__dma_unmap_area) ++ add x1, x1, x0 ++ cmp w2, #DMA_TO_DEVICE ++ b.ne __dma_inv_range ++ ret ++ENDPROC(__dma_unmap_area) +diff -Nur linux-3.14.40.orig/arch/arm64/mm/copypage.c linux-3.14.40/arch/arm64/mm/copypage.c +--- linux-3.14.40.orig/arch/arm64/mm/copypage.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/mm/copypage.c 2015-05-01 14:57:58.231427001 -0500 +@@ -27,8 +27,10 @@ + copy_page(kto, kfrom); + __flush_dcache_area(kto, PAGE_SIZE); + } ++EXPORT_SYMBOL_GPL(__cpu_copy_user_page); + + void __cpu_clear_user_page(void *kaddr, unsigned long vaddr) + { + clear_page(kaddr); + } ++EXPORT_SYMBOL_GPL(__cpu_clear_user_page); +diff -Nur linux-3.14.40.orig/arch/arm64/mm/dma-mapping.c linux-3.14.40/arch/arm64/mm/dma-mapping.c +--- linux-3.14.40.orig/arch/arm64/mm/dma-mapping.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/mm/dma-mapping.c 2015-05-01 14:57:58.239427001 -0500 +@@ -22,26 +22,39 @@ + #include + #include + #include ++#include ++#include + #include + #include ++#include + + #include + + struct dma_map_ops *dma_ops; + EXPORT_SYMBOL(dma_ops); + +-static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size, +- dma_addr_t *dma_handle, gfp_t flags, +- struct dma_attrs *attrs) ++static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot, ++ bool coherent) ++{ ++ if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs)) ++ return pgprot_writecombine(prot); ++ else if (!coherent) ++ return pgprot_dmacoherent(prot); ++ return prot; ++} ++ ++static void *__dma_alloc_coherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t flags, ++ struct dma_attrs *attrs) + { + if (dev == NULL) { + WARN_ONCE(1, "Use an actual device structure for DMA allocation\n"); + return NULL; + } + +- if (IS_ENABLED(CONFIG_ZONE_DMA32) && ++ if (IS_ENABLED(CONFIG_ZONE_DMA) && + dev->coherent_dma_mask <= DMA_BIT_MASK(32)) +- flags |= GFP_DMA32; ++ flags |= GFP_DMA; + if (IS_ENABLED(CONFIG_DMA_CMA)) { + struct page *page; + void *addr; +@@ -62,9 +75,9 @@ + } + } + +-static void arm64_swiotlb_free_coherent(struct device *dev, size_t size, +- void *vaddr, dma_addr_t dma_handle, +- struct dma_attrs *attrs) ++static void __dma_free_coherent(struct device *dev, size_t size, ++ void *vaddr, dma_addr_t dma_handle, ++ struct dma_attrs *attrs) + { + if (dev == NULL) { + WARN_ONCE(1, "Use an actual device structure for DMA allocation\n"); +@@ -82,9 +95,212 @@ + } + } + +-static struct dma_map_ops arm64_swiotlb_dma_ops = { +- .alloc = arm64_swiotlb_alloc_coherent, +- .free = arm64_swiotlb_free_coherent, ++static void *__dma_alloc_noncoherent(struct device *dev, size_t size, ++ dma_addr_t *dma_handle, gfp_t flags, ++ struct dma_attrs *attrs) ++{ ++ struct page *page, **map; ++ void *ptr, *coherent_ptr; ++ int order, i; ++ ++ size = PAGE_ALIGN(size); ++ order = get_order(size); ++ ++ ptr = __dma_alloc_coherent(dev, size, dma_handle, flags, attrs); ++ if (!ptr) ++ goto no_mem; ++ map = kmalloc(sizeof(struct page *) << order, flags & ~GFP_DMA); ++ if (!map) ++ goto no_map; ++ ++ /* remove any dirty cache lines on the kernel alias */ ++ __dma_flush_range(ptr, ptr + size); ++ ++ /* create a coherent mapping */ ++ page = virt_to_page(ptr); ++ for (i = 0; i < (size >> PAGE_SHIFT); i++) ++ map[i] = page + i; ++ coherent_ptr = vmap(map, size >> PAGE_SHIFT, VM_MAP, ++ __get_dma_pgprot(attrs, pgprot_default, false)); ++ kfree(map); ++ if (!coherent_ptr) ++ goto no_map; ++ ++ return coherent_ptr; ++ ++no_map: ++ __dma_free_coherent(dev, size, ptr, *dma_handle, attrs); ++no_mem: ++ *dma_handle = ~0; ++ return NULL; ++} ++ ++static void __dma_free_noncoherent(struct device *dev, size_t size, ++ void *vaddr, dma_addr_t dma_handle, ++ struct dma_attrs *attrs) ++{ ++ void *swiotlb_addr = phys_to_virt(dma_to_phys(dev, dma_handle)); ++ ++ vunmap(vaddr); ++ __dma_free_coherent(dev, size, swiotlb_addr, dma_handle, attrs); ++} ++ ++static dma_addr_t __swiotlb_map_page(struct device *dev, struct page *page, ++ unsigned long offset, size_t size, ++ enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ dma_addr_t dev_addr; ++ ++ dev_addr = swiotlb_map_page(dev, page, offset, size, dir, attrs); ++ __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); ++ ++ return dev_addr; ++} ++ ++ ++static void __swiotlb_unmap_page(struct device *dev, dma_addr_t dev_addr, ++ size_t size, enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); ++ swiotlb_unmap_page(dev, dev_addr, size, dir, attrs); ++} ++ ++static int __swiotlb_map_sg_attrs(struct device *dev, struct scatterlist *sgl, ++ int nelems, enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct scatterlist *sg; ++ int i, ret; ++ ++ ret = swiotlb_map_sg_attrs(dev, sgl, nelems, dir, attrs); ++ for_each_sg(sgl, sg, ret, i) ++ __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), ++ sg->length, dir); ++ ++ return ret; ++} ++ ++static void __swiotlb_unmap_sg_attrs(struct device *dev, ++ struct scatterlist *sgl, int nelems, ++ enum dma_data_direction dir, ++ struct dma_attrs *attrs) ++{ ++ struct scatterlist *sg; ++ int i; ++ ++ for_each_sg(sgl, sg, nelems, i) ++ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), ++ sg->length, dir); ++ swiotlb_unmap_sg_attrs(dev, sgl, nelems, dir, attrs); ++} ++ ++static void __swiotlb_sync_single_for_cpu(struct device *dev, ++ dma_addr_t dev_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); ++ swiotlb_sync_single_for_cpu(dev, dev_addr, size, dir); ++} ++ ++static void __swiotlb_sync_single_for_device(struct device *dev, ++ dma_addr_t dev_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ swiotlb_sync_single_for_device(dev, dev_addr, size, dir); ++ __dma_map_area(phys_to_virt(dma_to_phys(dev, dev_addr)), size, dir); ++} ++ ++static void __swiotlb_sync_sg_for_cpu(struct device *dev, ++ struct scatterlist *sgl, int nelems, ++ enum dma_data_direction dir) ++{ ++ struct scatterlist *sg; ++ int i; ++ ++ for_each_sg(sgl, sg, nelems, i) ++ __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), ++ sg->length, dir); ++ swiotlb_sync_sg_for_cpu(dev, sgl, nelems, dir); ++} ++ ++static void __swiotlb_sync_sg_for_device(struct device *dev, ++ struct scatterlist *sgl, int nelems, ++ enum dma_data_direction dir) ++{ ++ struct scatterlist *sg; ++ int i; ++ ++ swiotlb_sync_sg_for_device(dev, sgl, nelems, dir); ++ for_each_sg(sgl, sg, nelems, i) ++ __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), ++ sg->length, dir); ++} ++ ++/* vma->vm_page_prot must be set appropriately before calling this function */ ++static int __dma_common_mmap(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size) ++{ ++ int ret = -ENXIO; ++ unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >> ++ PAGE_SHIFT; ++ unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; ++ unsigned long pfn = dma_to_phys(dev, dma_addr) >> PAGE_SHIFT; ++ unsigned long off = vma->vm_pgoff; ++ ++ if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) ++ return ret; ++ ++ if (off < nr_pages && nr_vma_pages <= (nr_pages - off)) { ++ ret = remap_pfn_range(vma, vma->vm_start, ++ pfn + off, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot); ++ } ++ ++ return ret; ++} ++ ++static int __swiotlb_mmap_noncoherent(struct device *dev, ++ struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size, ++ struct dma_attrs *attrs) ++{ ++ vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, false); ++ return __dma_common_mmap(dev, vma, cpu_addr, dma_addr, size); ++} ++ ++static int __swiotlb_mmap_coherent(struct device *dev, ++ struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size, ++ struct dma_attrs *attrs) ++{ ++ /* Just use whatever page_prot attributes were specified */ ++ return __dma_common_mmap(dev, vma, cpu_addr, dma_addr, size); ++} ++ ++struct dma_map_ops noncoherent_swiotlb_dma_ops = { ++ .alloc = __dma_alloc_noncoherent, ++ .free = __dma_free_noncoherent, ++ .mmap = __swiotlb_mmap_noncoherent, ++ .map_page = __swiotlb_map_page, ++ .unmap_page = __swiotlb_unmap_page, ++ .map_sg = __swiotlb_map_sg_attrs, ++ .unmap_sg = __swiotlb_unmap_sg_attrs, ++ .sync_single_for_cpu = __swiotlb_sync_single_for_cpu, ++ .sync_single_for_device = __swiotlb_sync_single_for_device, ++ .sync_sg_for_cpu = __swiotlb_sync_sg_for_cpu, ++ .sync_sg_for_device = __swiotlb_sync_sg_for_device, ++ .dma_supported = swiotlb_dma_supported, ++ .mapping_error = swiotlb_dma_mapping_error, ++}; ++EXPORT_SYMBOL(noncoherent_swiotlb_dma_ops); ++ ++struct dma_map_ops coherent_swiotlb_dma_ops = { ++ .alloc = __dma_alloc_coherent, ++ .free = __dma_free_coherent, ++ .mmap = __swiotlb_mmap_coherent, + .map_page = swiotlb_map_page, + .unmap_page = swiotlb_unmap_page, + .map_sg = swiotlb_map_sg_attrs, +@@ -96,12 +312,47 @@ + .dma_supported = swiotlb_dma_supported, + .mapping_error = swiotlb_dma_mapping_error, + }; ++EXPORT_SYMBOL(coherent_swiotlb_dma_ops); + +-void __init arm64_swiotlb_init(void) ++static int dma_bus_notifier(struct notifier_block *nb, ++ unsigned long event, void *_dev) + { +- dma_ops = &arm64_swiotlb_dma_ops; +- swiotlb_init(1); ++ struct device *dev = _dev; ++ ++ if (event != BUS_NOTIFY_ADD_DEVICE) ++ return NOTIFY_DONE; ++ ++ if (of_property_read_bool(dev->of_node, "dma-coherent")) ++ set_dma_ops(dev, &coherent_swiotlb_dma_ops); ++ ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block platform_bus_nb = { ++ .notifier_call = dma_bus_notifier, ++}; ++ ++static struct notifier_block amba_bus_nb = { ++ .notifier_call = dma_bus_notifier, ++}; ++ ++extern int swiotlb_late_init_with_default_size(size_t default_size); ++ ++static int __init swiotlb_late_init(void) ++{ ++ size_t swiotlb_size = min(SZ_64M, MAX_ORDER_NR_PAGES << PAGE_SHIFT); ++ ++ /* ++ * These must be registered before of_platform_populate(). ++ */ ++ bus_register_notifier(&platform_bus_type, &platform_bus_nb); ++ bus_register_notifier(&amba_bustype, &amba_bus_nb); ++ ++ dma_ops = &noncoherent_swiotlb_dma_ops; ++ ++ return swiotlb_late_init_with_default_size(swiotlb_size); + } ++arch_initcall(swiotlb_late_init); + + #define PREALLOC_DMA_DEBUG_ENTRIES 4096 + +diff -Nur linux-3.14.40.orig/arch/arm64/mm/init.c linux-3.14.40/arch/arm64/mm/init.c +--- linux-3.14.40.orig/arch/arm64/mm/init.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/mm/init.c 2015-05-01 14:57:58.243427001 -0500 +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -59,22 +60,22 @@ + early_param("initrd", early_initrd); + #endif + +-#define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT) +- + static void __init zone_sizes_init(unsigned long min, unsigned long max) + { + struct memblock_region *reg; + unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; +- unsigned long max_dma32 = min; ++ unsigned long max_dma = min; + + memset(zone_size, 0, sizeof(zone_size)); + +-#ifdef CONFIG_ZONE_DMA32 + /* 4GB maximum for 32-bit only capable devices */ +- max_dma32 = max(min, min(max, MAX_DMA32_PFN)); +- zone_size[ZONE_DMA32] = max_dma32 - min; +-#endif +- zone_size[ZONE_NORMAL] = max - max_dma32; ++ if (IS_ENABLED(CONFIG_ZONE_DMA)) { ++ unsigned long max_dma_phys = ++ (unsigned long)dma_to_phys(NULL, DMA_BIT_MASK(32) + 1); ++ max_dma = max(min, min(max, max_dma_phys >> PAGE_SHIFT)); ++ zone_size[ZONE_DMA] = max_dma - min; ++ } ++ zone_size[ZONE_NORMAL] = max - max_dma; + + memcpy(zhole_size, zone_size, sizeof(zhole_size)); + +@@ -84,15 +85,15 @@ + + if (start >= max) + continue; +-#ifdef CONFIG_ZONE_DMA32 +- if (start < max_dma32) { +- unsigned long dma_end = min(end, max_dma32); +- zhole_size[ZONE_DMA32] -= dma_end - start; ++ ++ if (IS_ENABLED(CONFIG_ZONE_DMA) && start < max_dma) { ++ unsigned long dma_end = min(end, max_dma); ++ zhole_size[ZONE_DMA] -= dma_end - start; + } +-#endif +- if (end > max_dma32) { ++ ++ if (end > max_dma) { + unsigned long normal_end = min(end, max); +- unsigned long normal_start = max(start, max_dma32); ++ unsigned long normal_start = max(start, max_dma); + zhole_size[ZONE_NORMAL] -= normal_end - normal_start; + } + } +@@ -127,20 +128,16 @@ + { + u64 *reserve_map, base, size; + +- /* Register the kernel text, kernel data and initrd with memblock */ ++ /* ++ * Register the kernel text, kernel data, initrd, and initial ++ * pagetables with memblock. ++ */ + memblock_reserve(__pa(_text), _end - _text); + #ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start); + #endif + +- /* +- * Reserve the page tables. These are already in use, +- * and can only be in node 0. +- */ +- memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE); +- memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE); +- + /* Reserve the dtb region */ + memblock_reserve(virt_to_phys(initial_boot_params), + be32_to_cpu(initial_boot_params->totalsize)); +@@ -261,8 +258,6 @@ + */ + void __init mem_init(void) + { +- arm64_swiotlb_init(); +- + max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map; + + #ifndef CONFIG_SPARSEMEM_VMEMMAP +diff -Nur linux-3.14.40.orig/arch/arm64/mm/proc.S linux-3.14.40/arch/arm64/mm/proc.S +--- linux-3.14.40.orig/arch/arm64/mm/proc.S 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/arm64/mm/proc.S 2015-05-01 14:57:58.243427001 -0500 +@@ -173,12 +173,6 @@ + * value of the SCTLR_EL1 register. + */ + ENTRY(__cpu_setup) +- /* +- * Preserve the link register across the function call. +- */ +- mov x28, lr +- bl __flush_dcache_all +- mov lr, x28 + ic iallu // I+BTB cache invalidate + tlbi vmalle1is // invalidate I + D TLBs + dsb sy +diff -Nur linux-3.14.40.orig/arch/avr32/kernel/cpu.c linux-3.14.40/arch/avr32/kernel/cpu.c +--- linux-3.14.40.orig/arch/avr32/kernel/cpu.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/avr32/kernel/cpu.c 2015-05-01 14:57:58.275427001 -0500 +@@ -39,10 +39,12 @@ + size_t count) + { + unsigned long val; +- char *endp; ++ int ret; + +- val = simple_strtoul(buf, &endp, 0); +- if (endp == buf || val > 0x3f) ++ ret = kstrtoul(buf, 0, &val); ++ if (ret) ++ return ret; ++ if (val > 0x3f) + return -EINVAL; + val = (val << 12) | (sysreg_read(PCCR) & 0xfffc0fff); + sysreg_write(PCCR, val); +@@ -61,11 +63,11 @@ + const char *buf, size_t count) + { + unsigned long val; +- char *endp; ++ int ret; + +- val = simple_strtoul(buf, &endp, 0); +- if (endp == buf) +- return -EINVAL; ++ ret = kstrtoul(buf, 0, &val); ++ if (ret) ++ return ret; + sysreg_write(PCNT0, val); + + return count; +@@ -84,10 +86,12 @@ + size_t count) + { + unsigned long val; +- char *endp; ++ int ret; + +- val = simple_strtoul(buf, &endp, 0); +- if (endp == buf || val > 0x3f) ++ ret = kstrtoul(buf, 0, &val); ++ if (ret) ++ return ret; ++ if (val > 0x3f) + return -EINVAL; + val = (val << 18) | (sysreg_read(PCCR) & 0xff03ffff); + sysreg_write(PCCR, val); +@@ -106,11 +110,11 @@ + size_t count) + { + unsigned long val; +- char *endp; ++ int ret; + +- val = simple_strtoul(buf, &endp, 0); +- if (endp == buf) +- return -EINVAL; ++ ret = kstrtoul(buf, 0, &val); ++ if (ret) ++ return ret; + sysreg_write(PCNT1, val); + + return count; +@@ -129,11 +133,11 @@ + size_t count) + { + unsigned long val; +- char *endp; ++ int ret; + +- val = simple_strtoul(buf, &endp, 0); +- if (endp == buf) +- return -EINVAL; ++ ret = kstrtoul(buf, 0, &val); ++ if (ret) ++ return ret; + sysreg_write(PCCNT, val); + + return count; +@@ -152,11 +156,11 @@ + size_t count) + { + unsigned long pccr, val; +- char *endp; ++ int ret; + +- val = simple_strtoul(buf, &endp, 0); +- if (endp == buf) +- return -EINVAL; ++ ret = kstrtoul(buf, 0, &val); ++ if (ret) ++ return ret; + if (val) + val = 1; + +diff -Nur linux-3.14.40.orig/arch/blackfin/include/asm/ftrace.h linux-3.14.40/arch/blackfin/include/asm/ftrace.h +--- linux-3.14.40.orig/arch/blackfin/include/asm/ftrace.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/blackfin/include/asm/ftrace.h 2015-05-01 14:57:58.291427001 -0500 +@@ -66,16 +66,7 @@ + + #endif /* CONFIG_FRAME_POINTER */ + +-#define HAVE_ARCH_CALLER_ADDR +- +-/* inline function or macro may lead to unexpected result */ +-#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) +-#define CALLER_ADDR1 ((unsigned long)return_address(1)) +-#define CALLER_ADDR2 ((unsigned long)return_address(2)) +-#define CALLER_ADDR3 ((unsigned long)return_address(3)) +-#define CALLER_ADDR4 ((unsigned long)return_address(4)) +-#define CALLER_ADDR5 ((unsigned long)return_address(5)) +-#define CALLER_ADDR6 ((unsigned long)return_address(6)) ++#define ftrace_return_address(n) return_address(n) + + #endif /* __ASSEMBLY__ */ + +diff -Nur linux-3.14.40.orig/arch/hexagon/include/asm/elf.h linux-3.14.40/arch/hexagon/include/asm/elf.h +--- linux-3.14.40.orig/arch/hexagon/include/asm/elf.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/hexagon/include/asm/elf.h 2015-05-01 14:57:58.299427001 -0500 +@@ -1,7 +1,7 @@ + /* + * ELF definitions for the Hexagon architecture + * +- * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2010-2013, The Linux Foundation. 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 and +diff -Nur linux-3.14.40.orig/arch/parisc/include/asm/ftrace.h linux-3.14.40/arch/parisc/include/asm/ftrace.h +--- linux-3.14.40.orig/arch/parisc/include/asm/ftrace.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/parisc/include/asm/ftrace.h 2015-05-01 14:57:58.299427001 -0500 +@@ -24,15 +24,7 @@ + + extern unsigned long return_address(unsigned int); + +-#define HAVE_ARCH_CALLER_ADDR +- +-#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) +-#define CALLER_ADDR1 return_address(1) +-#define CALLER_ADDR2 return_address(2) +-#define CALLER_ADDR3 return_address(3) +-#define CALLER_ADDR4 return_address(4) +-#define CALLER_ADDR5 return_address(5) +-#define CALLER_ADDR6 return_address(6) ++#define ftrace_return_address(n) return_address(n) + + #endif /* __ASSEMBLY__ */ + +diff -Nur linux-3.14.40.orig/arch/s390/include/asm/cio.h linux-3.14.40/arch/s390/include/asm/cio.h +--- linux-3.14.40.orig/arch/s390/include/asm/cio.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/s390/include/asm/cio.h 2015-05-01 14:57:58.311427001 -0500 +@@ -199,7 +199,7 @@ + /** + * struct irb - interruption response block + * @scsw: subchannel status word +- * @esw: extened status word ++ * @esw: extended status word + * @ecw: extended control word + * + * The irb that is handed to the device driver when an interrupt occurs. For +diff -Nur linux-3.14.40.orig/arch/sh/include/asm/ftrace.h linux-3.14.40/arch/sh/include/asm/ftrace.h +--- linux-3.14.40.orig/arch/sh/include/asm/ftrace.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/sh/include/asm/ftrace.h 2015-05-01 14:57:58.339427001 -0500 +@@ -40,15 +40,7 @@ + /* arch/sh/kernel/return_address.c */ + extern void *return_address(unsigned int); + +-#define HAVE_ARCH_CALLER_ADDR +- +-#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) +-#define CALLER_ADDR1 ((unsigned long)return_address(1)) +-#define CALLER_ADDR2 ((unsigned long)return_address(2)) +-#define CALLER_ADDR3 ((unsigned long)return_address(3)) +-#define CALLER_ADDR4 ((unsigned long)return_address(4)) +-#define CALLER_ADDR5 ((unsigned long)return_address(5)) +-#define CALLER_ADDR6 ((unsigned long)return_address(6)) ++#define ftrace_return_address(n) return_address(n) + + #endif /* __ASSEMBLY__ */ + +diff -Nur linux-3.14.40.orig/arch/x86/kernel/setup.c linux-3.14.40/arch/x86/kernel/setup.c +--- linux-3.14.40.orig/arch/x86/kernel/setup.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/arch/x86/kernel/setup.c 2015-05-01 14:57:58.351427001 -0500 +@@ -1120,7 +1120,7 @@ + setup_real_mode(); + + memblock_set_current_limit(get_max_mapped()); +- dma_contiguous_reserve(0); ++ dma_contiguous_reserve(max_pfn_mapped << PAGE_SHIFT); + + /* + * NOTE: On x86-32, only from this point on, fixmaps are ready for use. +diff -Nur linux-3.14.40.orig/block/bfq-cgroup.c linux-3.14.40/block/bfq-cgroup.c +--- linux-3.14.40.orig/block/bfq-cgroup.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/block/bfq-cgroup.c 2015-05-01 14:57:58.351427001 -0500 +@@ -0,0 +1,932 @@ ++/* ++ * BFQ: CGROUPS support. ++ * ++ * Based on ideas and code from CFQ: ++ * Copyright (C) 2003 Jens Axboe ++ * ++ * Copyright (C) 2008 Fabio Checconi ++ * Paolo Valente ++ * ++ * Copyright (C) 2010 Paolo Valente ++ * ++ * Licensed under the GPL-2 as detailed in the accompanying COPYING.BFQ ++ * file. ++ */ ++ ++#ifdef CONFIG_CGROUP_BFQIO ++ ++static DEFINE_MUTEX(bfqio_mutex); ++ ++static bool bfqio_is_removed(struct bfqio_cgroup *bgrp) ++{ ++ return bgrp ? !bgrp->online : false; ++} ++ ++static struct bfqio_cgroup bfqio_root_cgroup = { ++ .weight = BFQ_DEFAULT_GRP_WEIGHT, ++ .ioprio = BFQ_DEFAULT_GRP_IOPRIO, ++ .ioprio_class = BFQ_DEFAULT_GRP_CLASS, ++}; ++ ++static inline void bfq_init_entity(struct bfq_entity *entity, ++ struct bfq_group *bfqg) ++{ ++ entity->weight = entity->new_weight; ++ entity->orig_weight = entity->new_weight; ++ entity->ioprio = entity->new_ioprio; ++ entity->ioprio_class = entity->new_ioprio_class; ++ entity->parent = bfqg->my_entity; ++ entity->sched_data = &bfqg->sched_data; ++} ++ ++static struct bfqio_cgroup *css_to_bfqio(struct cgroup_subsys_state *css) ++{ ++ return css ? container_of(css, struct bfqio_cgroup, css) : NULL; ++} ++ ++/* ++ * Search the bfq_group for bfqd into the hash table (by now only a list) ++ * of bgrp. Must be called under rcu_read_lock(). ++ */ ++static struct bfq_group *bfqio_lookup_group(struct bfqio_cgroup *bgrp, ++ struct bfq_data *bfqd) ++{ ++ struct bfq_group *bfqg; ++ void *key; ++ ++ hlist_for_each_entry_rcu(bfqg, &bgrp->group_data, group_node) { ++ key = rcu_dereference(bfqg->bfqd); ++ if (key == bfqd) ++ return bfqg; ++ } ++ ++ return NULL; ++} ++ ++static inline void bfq_group_init_entity(struct bfqio_cgroup *bgrp, ++ struct bfq_group *bfqg) ++{ ++ struct bfq_entity *entity = &bfqg->entity; ++ ++ /* ++ * If the weight of the entity has never been set via the sysfs ++ * interface, then bgrp->weight == 0. In this case we initialize ++ * the weight from the current ioprio value. Otherwise, the group ++ * weight, if set, has priority over the ioprio value. ++ */ ++ if (bgrp->weight == 0) { ++ entity->new_weight = bfq_ioprio_to_weight(bgrp->ioprio); ++ entity->new_ioprio = bgrp->ioprio; ++ } else { ++ entity->new_weight = bgrp->weight; ++ entity->new_ioprio = bfq_weight_to_ioprio(bgrp->weight); ++ } ++ entity->orig_weight = entity->weight = entity->new_weight; ++ entity->ioprio = entity->new_ioprio; ++ entity->ioprio_class = entity->new_ioprio_class = bgrp->ioprio_class; ++ entity->my_sched_data = &bfqg->sched_data; ++ bfqg->active_entities = 0; ++} ++ ++static inline void bfq_group_set_parent(struct bfq_group *bfqg, ++ struct bfq_group *parent) ++{ ++ struct bfq_entity *entity; ++ ++ BUG_ON(parent == NULL); ++ BUG_ON(bfqg == NULL); ++ ++ entity = &bfqg->entity; ++ entity->parent = parent->my_entity; ++ entity->sched_data = &parent->sched_data; ++} ++ ++/** ++ * bfq_group_chain_alloc - allocate a chain of groups. ++ * @bfqd: queue descriptor. ++ * @css: the leaf cgroup_subsys_state this chain starts from. ++ * ++ * Allocate a chain of groups starting from the one belonging to ++ * @cgroup up to the root cgroup. Stop if a cgroup on the chain ++ * to the root has already an allocated group on @bfqd. ++ */ ++static struct bfq_group *bfq_group_chain_alloc(struct bfq_data *bfqd, ++ struct cgroup_subsys_state *css) ++{ ++ struct bfqio_cgroup *bgrp; ++ struct bfq_group *bfqg, *prev = NULL, *leaf = NULL; ++ ++ for (; css != NULL; css = css->parent) { ++ bgrp = css_to_bfqio(css); ++ ++ bfqg = bfqio_lookup_group(bgrp, bfqd); ++ if (bfqg != NULL) { ++ /* ++ * All the cgroups in the path from there to the ++ * root must have a bfq_group for bfqd, so we don't ++ * need any more allocations. ++ */ ++ break; ++ } ++ ++ bfqg = kzalloc(sizeof(*bfqg), GFP_ATOMIC); ++ if (bfqg == NULL) ++ goto cleanup; ++ ++ bfq_group_init_entity(bgrp, bfqg); ++ bfqg->my_entity = &bfqg->entity; ++ ++ if (leaf == NULL) { ++ leaf = bfqg; ++ prev = leaf; ++ } else { ++ bfq_group_set_parent(prev, bfqg); ++ /* ++ * Build a list of allocated nodes using the bfqd ++ * filed, that is still unused and will be ++ * initialized only after the node will be ++ * connected. ++ */ ++ prev->bfqd = bfqg; ++ prev = bfqg; ++ } ++ } ++ ++ return leaf; ++ ++cleanup: ++ while (leaf != NULL) { ++ prev = leaf; ++ leaf = leaf->bfqd; ++ kfree(prev); ++ } ++ ++ return NULL; ++} ++ ++/** ++ * bfq_group_chain_link - link an allocated group chain to a cgroup ++ * hierarchy. ++ * @bfqd: the queue descriptor. ++ * @css: the leaf cgroup_subsys_state to start from. ++ * @leaf: the leaf group (to be associated to @cgroup). ++ * ++ * Try to link a chain of groups to a cgroup hierarchy, connecting the ++ * nodes bottom-up, so we can be sure that when we find a cgroup in the ++ * hierarchy that already as a group associated to @bfqd all the nodes ++ * in the path to the root cgroup have one too. ++ * ++ * On locking: the queue lock protects the hierarchy (there is a hierarchy ++ * per device) while the bfqio_cgroup lock protects the list of groups ++ * belonging to the same cgroup. ++ */ ++static void bfq_group_chain_link(struct bfq_data *bfqd, ++ struct cgroup_subsys_state *css, ++ struct bfq_group *leaf) ++{ ++ struct bfqio_cgroup *bgrp; ++ struct bfq_group *bfqg, *next, *prev = NULL; ++ unsigned long flags; ++ ++ assert_spin_locked(bfqd->queue->queue_lock); ++ ++ for (; css != NULL && leaf != NULL; css = css->parent) { ++ bgrp = css_to_bfqio(css); ++ next = leaf->bfqd; ++ ++ bfqg = bfqio_lookup_group(bgrp, bfqd); ++ BUG_ON(bfqg != NULL); ++ ++ spin_lock_irqsave(&bgrp->lock, flags); ++ ++ rcu_assign_pointer(leaf->bfqd, bfqd); ++ hlist_add_head_rcu(&leaf->group_node, &bgrp->group_data); ++ hlist_add_head(&leaf->bfqd_node, &bfqd->group_list); ++ ++ spin_unlock_irqrestore(&bgrp->lock, flags); ++ ++ prev = leaf; ++ leaf = next; ++ } ++ ++ BUG_ON(css == NULL && leaf != NULL); ++ if (css != NULL && prev != NULL) { ++ bgrp = css_to_bfqio(css); ++ bfqg = bfqio_lookup_group(bgrp, bfqd); ++ bfq_group_set_parent(prev, bfqg); ++ } ++} ++ ++/** ++ * bfq_find_alloc_group - return the group associated to @bfqd in @cgroup. ++ * @bfqd: queue descriptor. ++ * @cgroup: cgroup being searched for. ++ * ++ * Return a group associated to @bfqd in @cgroup, allocating one if ++ * necessary. When a group is returned all the cgroups in the path ++ * to the root have a group associated to @bfqd. ++ * ++ * If the allocation fails, return the root group: this breaks guarantees ++ * but is a safe fallback. If this loss becomes a problem it can be ++ * mitigated using the equivalent weight (given by the product of the ++ * weights of the groups in the path from @group to the root) in the ++ * root scheduler. ++ * ++ * We allocate all the missing nodes in the path from the leaf cgroup ++ * to the root and we connect the nodes only after all the allocations ++ * have been successful. ++ */ ++static struct bfq_group *bfq_find_alloc_group(struct bfq_data *bfqd, ++ struct cgroup_subsys_state *css) ++{ ++ struct bfqio_cgroup *bgrp = css_to_bfqio(css); ++ struct bfq_group *bfqg; ++ ++ bfqg = bfqio_lookup_group(bgrp, bfqd); ++ if (bfqg != NULL) ++ return bfqg; ++ ++ bfqg = bfq_group_chain_alloc(bfqd, css); ++ if (bfqg != NULL) ++ bfq_group_chain_link(bfqd, css, bfqg); ++ else ++ bfqg = bfqd->root_group; ++ ++ return bfqg; ++} ++ ++/** ++ * bfq_bfqq_move - migrate @bfqq to @bfqg. ++ * @bfqd: queue descriptor. ++ * @bfqq: the queue to move. ++ * @entity: @bfqq's entity. ++ * @bfqg: the group to move to. ++ * ++ * Move @bfqq to @bfqg, deactivating it from its old group and reactivating ++ * it on the new one. Avoid putting the entity on the old group idle tree. ++ * ++ * Must be called under the queue lock; the cgroup owning @bfqg must ++ * not disappear (by now this just means that we are called under ++ * rcu_read_lock()). ++ */ ++static void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq, ++ struct bfq_entity *entity, struct bfq_group *bfqg) ++{ ++ int busy, resume; ++ ++ busy = bfq_bfqq_busy(bfqq); ++ resume = !RB_EMPTY_ROOT(&bfqq->sort_list); ++ ++ BUG_ON(resume && !entity->on_st); ++ BUG_ON(busy && !resume && entity->on_st && ++ bfqq != bfqd->in_service_queue); ++ ++ if (busy) { ++ BUG_ON(atomic_read(&bfqq->ref) < 2); ++ ++ if (!resume) ++ bfq_del_bfqq_busy(bfqd, bfqq, 0); ++ else ++ bfq_deactivate_bfqq(bfqd, bfqq, 0); ++ } else if (entity->on_st) ++ bfq_put_idle_entity(bfq_entity_service_tree(entity), entity); ++ ++ /* ++ * Here we use a reference to bfqg. We don't need a refcounter ++ * as the cgroup reference will not be dropped, so that its ++ * destroy() callback will not be invoked. ++ */ ++ entity->parent = bfqg->my_entity; ++ entity->sched_data = &bfqg->sched_data; ++ ++ if (busy && resume) ++ bfq_activate_bfqq(bfqd, bfqq); ++ ++ if (bfqd->in_service_queue == NULL && !bfqd->rq_in_driver) ++ bfq_schedule_dispatch(bfqd); ++} ++ ++/** ++ * __bfq_bic_change_cgroup - move @bic to @cgroup. ++ * @bfqd: the queue descriptor. ++ * @bic: the bic to move. ++ * @cgroup: the cgroup to move to. ++ * ++ * Move bic to cgroup, assuming that bfqd->queue is locked; the caller ++ * has to make sure that the reference to cgroup is valid across the call. ++ * ++ * NOTE: an alternative approach might have been to store the current ++ * cgroup in bfqq and getting a reference to it, reducing the lookup ++ * time here, at the price of slightly more complex code. ++ */ ++static struct bfq_group *__bfq_bic_change_cgroup(struct bfq_data *bfqd, ++ struct bfq_io_cq *bic, ++ struct cgroup_subsys_state *css) ++{ ++ struct bfq_queue *async_bfqq = bic_to_bfqq(bic, 0); ++ struct bfq_queue *sync_bfqq = bic_to_bfqq(bic, 1); ++ struct bfq_entity *entity; ++ struct bfq_group *bfqg; ++ struct bfqio_cgroup *bgrp; ++ ++ bgrp = css_to_bfqio(css); ++ ++ bfqg = bfq_find_alloc_group(bfqd, css); ++ if (async_bfqq != NULL) { ++ entity = &async_bfqq->entity; ++ ++ if (entity->sched_data != &bfqg->sched_data) { ++ bic_set_bfqq(bic, NULL, 0); ++ bfq_log_bfqq(bfqd, async_bfqq, ++ "bic_change_group: %p %d", ++ async_bfqq, atomic_read(&async_bfqq->ref)); ++ bfq_put_queue(async_bfqq); ++ } ++ } ++ ++ if (sync_bfqq != NULL) { ++ entity = &sync_bfqq->entity; ++ if (entity->sched_data != &bfqg->sched_data) ++ bfq_bfqq_move(bfqd, sync_bfqq, entity, bfqg); ++ } ++ ++ return bfqg; ++} ++ ++/** ++ * bfq_bic_change_cgroup - move @bic to @cgroup. ++ * @bic: the bic being migrated. ++ * @cgroup: the destination cgroup. ++ * ++ * When the task owning @bic is moved to @cgroup, @bic is immediately ++ * moved into its new parent group. ++ */ ++static void bfq_bic_change_cgroup(struct bfq_io_cq *bic, ++ struct cgroup_subsys_state *css) ++{ ++ struct bfq_data *bfqd; ++ unsigned long uninitialized_var(flags); ++ ++ bfqd = bfq_get_bfqd_locked(&(bic->icq.q->elevator->elevator_data), ++ &flags); ++ if (bfqd != NULL) { ++ __bfq_bic_change_cgroup(bfqd, bic, css); ++ bfq_put_bfqd_unlock(bfqd, &flags); ++ } ++} ++ ++/** ++ * bfq_bic_update_cgroup - update the cgroup of @bic. ++ * @bic: the @bic to update. ++ * ++ * Make sure that @bic is enqueued in the cgroup of the current task. ++ * We need this in addition to moving bics during the cgroup attach ++ * phase because the task owning @bic could be at its first disk ++ * access or we may end up in the root cgroup as the result of a ++ * memory allocation failure and here we try to move to the right ++ * group. ++ * ++ * Must be called under the queue lock. It is safe to use the returned ++ * value even after the rcu_read_unlock() as the migration/destruction ++ * paths act under the queue lock too. IOW it is impossible to race with ++ * group migration/destruction and end up with an invalid group as: ++ * a) here cgroup has not yet been destroyed, nor its destroy callback ++ * has started execution, as current holds a reference to it, ++ * b) if it is destroyed after rcu_read_unlock() [after current is ++ * migrated to a different cgroup] its attach() callback will have ++ * taken care of remove all the references to the old cgroup data. ++ */ ++static struct bfq_group *bfq_bic_update_cgroup(struct bfq_io_cq *bic) ++{ ++ struct bfq_data *bfqd = bic_to_bfqd(bic); ++ struct bfq_group *bfqg; ++ struct cgroup_subsys_state *css; ++ ++ BUG_ON(bfqd == NULL); ++ ++ rcu_read_lock(); ++ css = task_css(current, bfqio_subsys_id); ++ bfqg = __bfq_bic_change_cgroup(bfqd, bic, css); ++ rcu_read_unlock(); ++ ++ return bfqg; ++} ++ ++/** ++ * bfq_flush_idle_tree - deactivate any entity on the idle tree of @st. ++ * @st: the service tree being flushed. ++ */ ++static inline void bfq_flush_idle_tree(struct bfq_service_tree *st) ++{ ++ struct bfq_entity *entity = st->first_idle; ++ ++ for (; entity != NULL; entity = st->first_idle) ++ __bfq_deactivate_entity(entity, 0); ++} ++ ++/** ++ * bfq_reparent_leaf_entity - move leaf entity to the root_group. ++ * @bfqd: the device data structure with the root group. ++ * @entity: the entity to move. ++ */ ++static inline void bfq_reparent_leaf_entity(struct bfq_data *bfqd, ++ struct bfq_entity *entity) ++{ ++ struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); ++ ++ BUG_ON(bfqq == NULL); ++ bfq_bfqq_move(bfqd, bfqq, entity, bfqd->root_group); ++ return; ++} ++ ++/** ++ * bfq_reparent_active_entities - move to the root group all active ++ * entities. ++ * @bfqd: the device data structure with the root group. ++ * @bfqg: the group to move from. ++ * @st: the service tree with the entities. ++ * ++ * Needs queue_lock to be taken and reference to be valid over the call. ++ */ ++static inline void bfq_reparent_active_entities(struct bfq_data *bfqd, ++ struct bfq_group *bfqg, ++ struct bfq_service_tree *st) ++{ ++ struct rb_root *active = &st->active; ++ struct bfq_entity *entity = NULL; ++ ++ if (!RB_EMPTY_ROOT(&st->active)) ++ entity = bfq_entity_of(rb_first(active)); ++ ++ for (; entity != NULL; entity = bfq_entity_of(rb_first(active))) ++ bfq_reparent_leaf_entity(bfqd, entity); ++ ++ if (bfqg->sched_data.in_service_entity != NULL) ++ bfq_reparent_leaf_entity(bfqd, ++ bfqg->sched_data.in_service_entity); ++ ++ return; ++} ++ ++/** ++ * bfq_destroy_group - destroy @bfqg. ++ * @bgrp: the bfqio_cgroup containing @bfqg. ++ * @bfqg: the group being destroyed. ++ * ++ * Destroy @bfqg, making sure that it is not referenced from its parent. ++ */ ++static void bfq_destroy_group(struct bfqio_cgroup *bgrp, struct bfq_group *bfqg) ++{ ++ struct bfq_data *bfqd; ++ struct bfq_service_tree *st; ++ struct bfq_entity *entity = bfqg->my_entity; ++ unsigned long uninitialized_var(flags); ++ int i; ++ ++ hlist_del(&bfqg->group_node); ++ ++ /* ++ * Empty all service_trees belonging to this group before ++ * deactivating the group itself. ++ */ ++ for (i = 0; i < BFQ_IOPRIO_CLASSES; i++) { ++ st = bfqg->sched_data.service_tree + i; ++ ++ /* ++ * The idle tree may still contain bfq_queues belonging ++ * to exited task because they never migrated to a different ++ * cgroup from the one being destroyed now. No one else ++ * can access them so it's safe to act without any lock. ++ */ ++ bfq_flush_idle_tree(st); ++ ++ /* ++ * It may happen that some queues are still active ++ * (busy) upon group destruction (if the corresponding ++ * processes have been forced to terminate). We move ++ * all the leaf entities corresponding to these queues ++ * to the root_group. ++ * Also, it may happen that the group has an entity ++ * in service, which is disconnected from the active ++ * tree: it must be moved, too. ++ * There is no need to put the sync queues, as the ++ * scheduler has taken no reference. ++ */ ++ bfqd = bfq_get_bfqd_locked(&bfqg->bfqd, &flags); ++ if (bfqd != NULL) { ++ bfq_reparent_active_entities(bfqd, bfqg, st); ++ bfq_put_bfqd_unlock(bfqd, &flags); ++ } ++ BUG_ON(!RB_EMPTY_ROOT(&st->active)); ++ BUG_ON(!RB_EMPTY_ROOT(&st->idle)); ++ } ++ BUG_ON(bfqg->sched_data.next_in_service != NULL); ++ BUG_ON(bfqg->sched_data.in_service_entity != NULL); ++ ++ /* ++ * We may race with device destruction, take extra care when ++ * dereferencing bfqg->bfqd. ++ */ ++ bfqd = bfq_get_bfqd_locked(&bfqg->bfqd, &flags); ++ if (bfqd != NULL) { ++ hlist_del(&bfqg->bfqd_node); ++ __bfq_deactivate_entity(entity, 0); ++ bfq_put_async_queues(bfqd, bfqg); ++ bfq_put_bfqd_unlock(bfqd, &flags); ++ } ++ BUG_ON(entity->tree != NULL); ++ ++ /* ++ * No need to defer the kfree() to the end of the RCU grace ++ * period: we are called from the destroy() callback of our ++ * cgroup, so we can be sure that no one is a) still using ++ * this cgroup or b) doing lookups in it. ++ */ ++ kfree(bfqg); ++} ++ ++static void bfq_end_wr_async(struct bfq_data *bfqd) ++{ ++ struct hlist_node *tmp; ++ struct bfq_group *bfqg; ++ ++ hlist_for_each_entry_safe(bfqg, tmp, &bfqd->group_list, bfqd_node) ++ bfq_end_wr_async_queues(bfqd, bfqg); ++ bfq_end_wr_async_queues(bfqd, bfqd->root_group); ++} ++ ++/** ++ * bfq_disconnect_groups - disconnect @bfqd from all its groups. ++ * @bfqd: the device descriptor being exited. ++ * ++ * When the device exits we just make sure that no lookup can return ++ * the now unused group structures. They will be deallocated on cgroup ++ * destruction. ++ */ ++static void bfq_disconnect_groups(struct bfq_data *bfqd) ++{ ++ struct hlist_node *tmp; ++ struct bfq_group *bfqg; ++ ++ bfq_log(bfqd, "disconnect_groups beginning"); ++ hlist_for_each_entry_safe(bfqg, tmp, &bfqd->group_list, bfqd_node) { ++ hlist_del(&bfqg->bfqd_node); ++ ++ __bfq_deactivate_entity(bfqg->my_entity, 0); ++ ++ /* ++ * Don't remove from the group hash, just set an ++ * invalid key. No lookups can race with the ++ * assignment as bfqd is being destroyed; this ++ * implies also that new elements cannot be added ++ * to the list. ++ */ ++ rcu_assign_pointer(bfqg->bfqd, NULL); ++ ++ bfq_log(bfqd, "disconnect_groups: put async for group %p", ++ bfqg); ++ bfq_put_async_queues(bfqd, bfqg); ++ } ++} ++ ++static inline void bfq_free_root_group(struct bfq_data *bfqd) ++{ ++ struct bfqio_cgroup *bgrp = &bfqio_root_cgroup; ++ struct bfq_group *bfqg = bfqd->root_group; ++ ++ bfq_put_async_queues(bfqd, bfqg); ++ ++ spin_lock_irq(&bgrp->lock); ++ hlist_del_rcu(&bfqg->group_node); ++ spin_unlock_irq(&bgrp->lock); ++ ++ /* ++ * No need to synchronize_rcu() here: since the device is gone ++ * there cannot be any read-side access to its root_group. ++ */ ++ kfree(bfqg); ++} ++ ++static struct bfq_group *bfq_alloc_root_group(struct bfq_data *bfqd, int node) ++{ ++ struct bfq_group *bfqg; ++ struct bfqio_cgroup *bgrp; ++ int i; ++ ++ bfqg = kzalloc_node(sizeof(*bfqg), GFP_KERNEL, node); ++ if (bfqg == NULL) ++ return NULL; ++ ++ bfqg->entity.parent = NULL; ++ for (i = 0; i < BFQ_IOPRIO_CLASSES; i++) ++ bfqg->sched_data.service_tree[i] = BFQ_SERVICE_TREE_INIT; ++ ++ bgrp = &bfqio_root_cgroup; ++ spin_lock_irq(&bgrp->lock); ++ rcu_assign_pointer(bfqg->bfqd, bfqd); ++ hlist_add_head_rcu(&bfqg->group_node, &bgrp->group_data); ++ spin_unlock_irq(&bgrp->lock); ++ ++ return bfqg; ++} ++ ++#define SHOW_FUNCTION(__VAR) \ ++static u64 bfqio_cgroup_##__VAR##_read(struct cgroup_subsys_state *css, \ ++ struct cftype *cftype) \ ++{ \ ++ struct bfqio_cgroup *bgrp = css_to_bfqio(css); \ ++ u64 ret = -ENODEV; \ ++ \ ++ mutex_lock(&bfqio_mutex); \ ++ if (bfqio_is_removed(bgrp)) \ ++ goto out_unlock; \ ++ \ ++ spin_lock_irq(&bgrp->lock); \ ++ ret = bgrp->__VAR; \ ++ spin_unlock_irq(&bgrp->lock); \ ++ \ ++out_unlock: \ ++ mutex_unlock(&bfqio_mutex); \ ++ return ret; \ ++} ++ ++SHOW_FUNCTION(weight); ++SHOW_FUNCTION(ioprio); ++SHOW_FUNCTION(ioprio_class); ++#undef SHOW_FUNCTION ++ ++#define STORE_FUNCTION(__VAR, __MIN, __MAX) \ ++static int bfqio_cgroup_##__VAR##_write(struct cgroup_subsys_state *css,\ ++ struct cftype *cftype, \ ++ u64 val) \ ++{ \ ++ struct bfqio_cgroup *bgrp = css_to_bfqio(css); \ ++ struct bfq_group *bfqg; \ ++ int ret = -EINVAL; \ ++ \ ++ if (val < (__MIN) || val > (__MAX)) \ ++ return ret; \ ++ \ ++ ret = -ENODEV; \ ++ mutex_lock(&bfqio_mutex); \ ++ if (bfqio_is_removed(bgrp)) \ ++ goto out_unlock; \ ++ ret = 0; \ ++ \ ++ spin_lock_irq(&bgrp->lock); \ ++ bgrp->__VAR = (unsigned short)val; \ ++ hlist_for_each_entry(bfqg, &bgrp->group_data, group_node) { \ ++ /* \ ++ * Setting the ioprio_changed flag of the entity \ ++ * to 1 with new_##__VAR == ##__VAR would re-set \ ++ * the value of the weight to its ioprio mapping. \ ++ * Set the flag only if necessary. \ ++ */ \ ++ if ((unsigned short)val != bfqg->entity.new_##__VAR) { \ ++ bfqg->entity.new_##__VAR = (unsigned short)val; \ ++ /* \ ++ * Make sure that the above new value has been \ ++ * stored in bfqg->entity.new_##__VAR before \ ++ * setting the ioprio_changed flag. In fact, \ ++ * this flag may be read asynchronously (in \ ++ * critical sections protected by a different \ ++ * lock than that held here), and finding this \ ++ * flag set may cause the execution of the code \ ++ * for updating parameters whose value may \ ++ * depend also on bfqg->entity.new_##__VAR (in \ ++ * __bfq_entity_update_weight_prio). \ ++ * This barrier makes sure that the new value \ ++ * of bfqg->entity.new_##__VAR is correctly \ ++ * seen in that code. \ ++ */ \ ++ smp_wmb(); \ ++ bfqg->entity.ioprio_changed = 1; \ ++ } \ ++ } \ ++ spin_unlock_irq(&bgrp->lock); \ ++ \ ++out_unlock: \ ++ mutex_unlock(&bfqio_mutex); \ ++ return ret; \ ++} ++ ++STORE_FUNCTION(weight, BFQ_MIN_WEIGHT, BFQ_MAX_WEIGHT); ++STORE_FUNCTION(ioprio, 0, IOPRIO_BE_NR - 1); ++STORE_FUNCTION(ioprio_class, IOPRIO_CLASS_RT, IOPRIO_CLASS_IDLE); ++#undef STORE_FUNCTION ++ ++static struct cftype bfqio_files[] = { ++ { ++ .name = "weight", ++ .read_u64 = bfqio_cgroup_weight_read, ++ .write_u64 = bfqio_cgroup_weight_write, ++ }, ++ { ++ .name = "ioprio", ++ .read_u64 = bfqio_cgroup_ioprio_read, ++ .write_u64 = bfqio_cgroup_ioprio_write, ++ }, ++ { ++ .name = "ioprio_class", ++ .read_u64 = bfqio_cgroup_ioprio_class_read, ++ .write_u64 = bfqio_cgroup_ioprio_class_write, ++ }, ++ { }, /* terminate */ ++}; ++ ++static struct cgroup_subsys_state *bfqio_create(struct cgroup_subsys_state ++ *parent_css) ++{ ++ struct bfqio_cgroup *bgrp; ++ ++ if (parent_css != NULL) { ++ bgrp = kzalloc(sizeof(*bgrp), GFP_KERNEL); ++ if (bgrp == NULL) ++ return ERR_PTR(-ENOMEM); ++ } else ++ bgrp = &bfqio_root_cgroup; ++ ++ spin_lock_init(&bgrp->lock); ++ INIT_HLIST_HEAD(&bgrp->group_data); ++ bgrp->ioprio = BFQ_DEFAULT_GRP_IOPRIO; ++ bgrp->ioprio_class = BFQ_DEFAULT_GRP_CLASS; ++ ++ return &bgrp->css; ++} ++ ++/* ++ * We cannot support shared io contexts, as we have no means to support ++ * two tasks with the same ioc in two different groups without major rework ++ * of the main bic/bfqq data structures. By now we allow a task to change ++ * its cgroup only if it's the only owner of its ioc; the drawback of this ++ * behavior is that a group containing a task that forked using CLONE_IO ++ * will not be destroyed until the tasks sharing the ioc die. ++ */ ++static int bfqio_can_attach(struct cgroup_subsys_state *css, ++ struct cgroup_taskset *tset) ++{ ++ struct task_struct *task; ++ struct io_context *ioc; ++ int ret = 0; ++ ++ cgroup_taskset_for_each(task, css, tset) { ++ /* ++ * task_lock() is needed to avoid races with ++ * exit_io_context() ++ */ ++ task_lock(task); ++ ioc = task->io_context; ++ if (ioc != NULL && atomic_read(&ioc->nr_tasks) > 1) ++ /* ++ * ioc == NULL means that the task is either too ++ * young or exiting: if it has still no ioc the ++ * ioc can't be shared, if the task is exiting the ++ * attach will fail anyway, no matter what we ++ * return here. ++ */ ++ ret = -EINVAL; ++ task_unlock(task); ++ if (ret) ++ break; ++ } ++ ++ return ret; ++} ++ ++static void bfqio_attach(struct cgroup_subsys_state *css, ++ struct cgroup_taskset *tset) ++{ ++ struct task_struct *task; ++ struct io_context *ioc; ++ struct io_cq *icq; ++ ++ /* ++ * IMPORTANT NOTE: The move of more than one process at a time to a ++ * new group has not yet been tested. ++ */ ++ cgroup_taskset_for_each(task, css, tset) { ++ ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE); ++ if (ioc) { ++ /* ++ * Handle cgroup change here. ++ */ ++ rcu_read_lock(); ++ hlist_for_each_entry_rcu(icq, &ioc->icq_list, ioc_node) ++ if (!strncmp( ++ icq->q->elevator->type->elevator_name, ++ "bfq", ELV_NAME_MAX)) ++ bfq_bic_change_cgroup(icq_to_bic(icq), ++ css); ++ rcu_read_unlock(); ++ put_io_context(ioc); ++ } ++ } ++} ++ ++static void bfqio_destroy(struct cgroup_subsys_state *css) ++{ ++ struct bfqio_cgroup *bgrp = css_to_bfqio(css); ++ struct hlist_node *tmp; ++ struct bfq_group *bfqg; ++ ++ /* ++ * Since we are destroying the cgroup, there are no more tasks ++ * referencing it, and all the RCU grace periods that may have ++ * referenced it are ended (as the destruction of the parent ++ * cgroup is RCU-safe); bgrp->group_data will not be accessed by ++ * anything else and we don't need any synchronization. ++ */ ++ hlist_for_each_entry_safe(bfqg, tmp, &bgrp->group_data, group_node) ++ bfq_destroy_group(bgrp, bfqg); ++ ++ BUG_ON(!hlist_empty(&bgrp->group_data)); ++ ++ kfree(bgrp); ++} ++ ++static int bfqio_css_online(struct cgroup_subsys_state *css) ++{ ++ struct bfqio_cgroup *bgrp = css_to_bfqio(css); ++ ++ mutex_lock(&bfqio_mutex); ++ bgrp->online = true; ++ mutex_unlock(&bfqio_mutex); ++ ++ return 0; ++} ++ ++static void bfqio_css_offline(struct cgroup_subsys_state *css) ++{ ++ struct bfqio_cgroup *bgrp = css_to_bfqio(css); ++ ++ mutex_lock(&bfqio_mutex); ++ bgrp->online = false; ++ mutex_unlock(&bfqio_mutex); ++} ++ ++struct cgroup_subsys bfqio_subsys = { ++ .name = "bfqio", ++ .css_alloc = bfqio_create, ++ .css_online = bfqio_css_online, ++ .css_offline = bfqio_css_offline, ++ .can_attach = bfqio_can_attach, ++ .attach = bfqio_attach, ++ .css_free = bfqio_destroy, ++ .subsys_id = bfqio_subsys_id, ++ .base_cftypes = bfqio_files, ++}; ++#else ++static inline void bfq_init_entity(struct bfq_entity *entity, ++ struct bfq_group *bfqg) ++{ ++ entity->weight = entity->new_weight; ++ entity->orig_weight = entity->new_weight; ++ entity->ioprio = entity->new_ioprio; ++ entity->ioprio_class = entity->new_ioprio_class; ++ entity->sched_data = &bfqg->sched_data; ++} ++ ++static inline struct bfq_group * ++bfq_bic_update_cgroup(struct bfq_io_cq *bic) ++{ ++ struct bfq_data *bfqd = bic_to_bfqd(bic); ++ return bfqd->root_group; ++} ++ ++static inline void bfq_bfqq_move(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq, ++ struct bfq_entity *entity, ++ struct bfq_group *bfqg) ++{ ++} ++ ++static void bfq_end_wr_async(struct bfq_data *bfqd) ++{ ++ bfq_end_wr_async_queues(bfqd, bfqd->root_group); ++} ++ ++static inline void bfq_disconnect_groups(struct bfq_data *bfqd) ++{ ++ bfq_put_async_queues(bfqd, bfqd->root_group); ++} ++ ++static inline void bfq_free_root_group(struct bfq_data *bfqd) ++{ ++ kfree(bfqd->root_group); ++} ++ ++static struct bfq_group *bfq_alloc_root_group(struct bfq_data *bfqd, int node) ++{ ++ struct bfq_group *bfqg; ++ int i; ++ ++ bfqg = kmalloc_node(sizeof(*bfqg), GFP_KERNEL | __GFP_ZERO, node); ++ if (bfqg == NULL) ++ return NULL; ++ ++ for (i = 0; i < BFQ_IOPRIO_CLASSES; i++) ++ bfqg->sched_data.service_tree[i] = BFQ_SERVICE_TREE_INIT; ++ ++ return bfqg; ++} ++#endif +diff -Nur linux-3.14.40.orig/block/bfq.h linux-3.14.40/block/bfq.h +--- linux-3.14.40.orig/block/bfq.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/block/bfq.h 2015-05-01 14:57:58.351427001 -0500 +@@ -0,0 +1,770 @@ ++/* ++ * BFQ-v7r5 for 3.14.0: data structures and common functions prototypes. ++ * ++ * Based on ideas and code from CFQ: ++ * Copyright (C) 2003 Jens Axboe ++ * ++ * Copyright (C) 2008 Fabio Checconi ++ * Paolo Valente ++ * ++ * Copyright (C) 2010 Paolo Valente ++ */ ++ ++#ifndef _BFQ_H ++#define _BFQ_H ++ ++#include ++#include ++#include ++#include ++ ++#define BFQ_IOPRIO_CLASSES 3 ++#define BFQ_CL_IDLE_TIMEOUT (HZ/5) ++ ++#define BFQ_MIN_WEIGHT 1 ++#define BFQ_MAX_WEIGHT 1000 ++ ++#define BFQ_DEFAULT_GRP_WEIGHT 10 ++#define BFQ_DEFAULT_GRP_IOPRIO 0 ++#define BFQ_DEFAULT_GRP_CLASS IOPRIO_CLASS_BE ++ ++struct bfq_entity; ++ ++/** ++ * struct bfq_service_tree - per ioprio_class service tree. ++ * @active: tree for active entities (i.e., those backlogged). ++ * @idle: tree for idle entities (i.e., those not backlogged, with V <= F_i). ++ * @first_idle: idle entity with minimum F_i. ++ * @last_idle: idle entity with maximum F_i. ++ * @vtime: scheduler virtual time. ++ * @wsum: scheduler weight sum; active and idle entities contribute to it. ++ * ++ * Each service tree represents a B-WF2Q+ scheduler on its own. Each ++ * ioprio_class has its own independent scheduler, and so its own ++ * bfq_service_tree. All the fields are protected by the queue lock ++ * of the containing bfqd. ++ */ ++struct bfq_service_tree { ++ struct rb_root active; ++ struct rb_root idle; ++ ++ struct bfq_entity *first_idle; ++ struct bfq_entity *last_idle; ++ ++ u64 vtime; ++ unsigned long wsum; ++}; ++ ++/** ++ * struct bfq_sched_data - multi-class scheduler. ++ * @in_service_entity: entity in service. ++ * @next_in_service: head-of-the-line entity in the scheduler. ++ * @service_tree: array of service trees, one per ioprio_class. ++ * ++ * bfq_sched_data is the basic scheduler queue. It supports three ++ * ioprio_classes, and can be used either as a toplevel queue or as ++ * an intermediate queue on a hierarchical setup. ++ * @next_in_service points to the active entity of the sched_data ++ * service trees that will be scheduled next. ++ * ++ * The supported ioprio_classes are the same as in CFQ, in descending ++ * priority order, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE. ++ * Requests from higher priority queues are served before all the ++ * requests from lower priority queues; among requests of the same ++ * queue requests are served according to B-WF2Q+. ++ * All the fields are protected by the queue lock of the containing bfqd. ++ */ ++struct bfq_sched_data { ++ struct bfq_entity *in_service_entity; ++ struct bfq_entity *next_in_service; ++ struct bfq_service_tree service_tree[BFQ_IOPRIO_CLASSES]; ++}; ++ ++/** ++ * struct bfq_weight_counter - counter of the number of all active entities ++ * with a given weight. ++ * @weight: weight of the entities that this counter refers to. ++ * @num_active: number of active entities with this weight. ++ * @weights_node: weights tree member (see bfq_data's @queue_weights_tree ++ * and @group_weights_tree). ++ */ ++struct bfq_weight_counter { ++ short int weight; ++ unsigned int num_active; ++ struct rb_node weights_node; ++}; ++ ++/** ++ * struct bfq_entity - schedulable entity. ++ * @rb_node: service_tree member. ++ * @weight_counter: pointer to the weight counter associated with this entity. ++ * @on_st: flag, true if the entity is on a tree (either the active or ++ * the idle one of its service_tree). ++ * @finish: B-WF2Q+ finish timestamp (aka F_i). ++ * @start: B-WF2Q+ start timestamp (aka S_i). ++ * @tree: tree the entity is enqueued into; %NULL if not on a tree. ++ * @min_start: minimum start time of the (active) subtree rooted at ++ * this entity; used for O(log N) lookups into active trees. ++ * @service: service received during the last round of service. ++ * @budget: budget used to calculate F_i; F_i = S_i + @budget / @weight. ++ * @weight: weight of the queue ++ * @parent: parent entity, for hierarchical scheduling. ++ * @my_sched_data: for non-leaf nodes in the cgroup hierarchy, the ++ * associated scheduler queue, %NULL on leaf nodes. ++ * @sched_data: the scheduler queue this entity belongs to. ++ * @ioprio: the ioprio in use. ++ * @new_weight: when a weight change is requested, the new weight value. ++ * @orig_weight: original weight, used to implement weight boosting ++ * @new_ioprio: when an ioprio change is requested, the new ioprio value. ++ * @ioprio_class: the ioprio_class in use. ++ * @new_ioprio_class: when an ioprio_class change is requested, the new ++ * ioprio_class value. ++ * @ioprio_changed: flag, true when the user requested a weight, ioprio or ++ * ioprio_class change. ++ * ++ * A bfq_entity is used to represent either a bfq_queue (leaf node in the ++ * cgroup hierarchy) or a bfq_group into the upper level scheduler. Each ++ * entity belongs to the sched_data of the parent group in the cgroup ++ * hierarchy. Non-leaf entities have also their own sched_data, stored ++ * in @my_sched_data. ++ * ++ * Each entity stores independently its priority values; this would ++ * allow different weights on different devices, but this ++ * functionality is not exported to userspace by now. Priorities and ++ * weights are updated lazily, first storing the new values into the ++ * new_* fields, then setting the @ioprio_changed flag. As soon as ++ * there is a transition in the entity state that allows the priority ++ * update to take place the effective and the requested priority ++ * values are synchronized. ++ * ++ * Unless cgroups are used, the weight value is calculated from the ++ * ioprio to export the same interface as CFQ. When dealing with ++ * ``well-behaved'' queues (i.e., queues that do not spend too much ++ * time to consume their budget and have true sequential behavior, and ++ * when there are no external factors breaking anticipation) the ++ * relative weights at each level of the cgroups hierarchy should be ++ * guaranteed. All the fields are protected by the queue lock of the ++ * containing bfqd. ++ */ ++struct bfq_entity { ++ struct rb_node rb_node; ++ struct bfq_weight_counter *weight_counter; ++ ++ int on_st; ++ ++ u64 finish; ++ u64 start; ++ ++ struct rb_root *tree; ++ ++ u64 min_start; ++ ++ unsigned long service, budget; ++ unsigned short weight, new_weight; ++ unsigned short orig_weight; ++ ++ struct bfq_entity *parent; ++ ++ struct bfq_sched_data *my_sched_data; ++ struct bfq_sched_data *sched_data; ++ ++ unsigned short ioprio, new_ioprio; ++ unsigned short ioprio_class, new_ioprio_class; ++ ++ int ioprio_changed; ++}; ++ ++struct bfq_group; ++ ++/** ++ * struct bfq_queue - leaf schedulable entity. ++ * @ref: reference counter. ++ * @bfqd: parent bfq_data. ++ * @new_bfqq: shared bfq_queue if queue is cooperating with ++ * one or more other queues. ++ * @pos_node: request-position tree member (see bfq_data's @rq_pos_tree). ++ * @pos_root: request-position tree root (see bfq_data's @rq_pos_tree). ++ * @sort_list: sorted list of pending requests. ++ * @next_rq: if fifo isn't expired, next request to serve. ++ * @queued: nr of requests queued in @sort_list. ++ * @allocated: currently allocated requests. ++ * @meta_pending: pending metadata requests. ++ * @fifo: fifo list of requests in sort_list. ++ * @entity: entity representing this queue in the scheduler. ++ * @max_budget: maximum budget allowed from the feedback mechanism. ++ * @budget_timeout: budget expiration (in jiffies). ++ * @dispatched: number of requests on the dispatch list or inside driver. ++ * @flags: status flags. ++ * @bfqq_list: node for active/idle bfqq list inside our bfqd. ++ * @seek_samples: number of seeks sampled ++ * @seek_total: sum of the distances of the seeks sampled ++ * @seek_mean: mean seek distance ++ * @last_request_pos: position of the last request enqueued ++ * @requests_within_timer: number of consecutive pairs of request completion ++ * and arrival, such that the queue becomes idle ++ * after the completion, but the next request arrives ++ * within an idle time slice; used only if the queue's ++ * IO_bound has been cleared. ++ * @pid: pid of the process owning the queue, used for logging purposes. ++ * @last_wr_start_finish: start time of the current weight-raising period if ++ * the @bfq-queue is being weight-raised, otherwise ++ * finish time of the last weight-raising period ++ * @wr_cur_max_time: current max raising time for this queue ++ * @soft_rt_next_start: minimum time instant such that, only if a new ++ * request is enqueued after this time instant in an ++ * idle @bfq_queue with no outstanding requests, then ++ * the task associated with the queue it is deemed as ++ * soft real-time (see the comments to the function ++ * bfq_bfqq_softrt_next_start()) ++ * @last_idle_bklogged: time of the last transition of the @bfq_queue from ++ * idle to backlogged ++ * @service_from_backlogged: cumulative service received from the @bfq_queue ++ * since the last transition from idle to ++ * backlogged ++ * @bic: pointer to the bfq_io_cq owning the bfq_queue, set to %NULL if the ++ * queue is shared ++ * ++ * A bfq_queue is a leaf request queue; it can be associated with an ++ * io_context or more, if it is async or shared between cooperating ++ * processes. @cgroup holds a reference to the cgroup, to be sure that it ++ * does not disappear while a bfqq still references it (mostly to avoid ++ * races between request issuing and task migration followed by cgroup ++ * destruction). ++ * All the fields are protected by the queue lock of the containing bfqd. ++ */ ++struct bfq_queue { ++ atomic_t ref; ++ struct bfq_data *bfqd; ++ ++ /* fields for cooperating queues handling */ ++ struct bfq_queue *new_bfqq; ++ struct rb_node pos_node; ++ struct rb_root *pos_root; ++ ++ struct rb_root sort_list; ++ struct request *next_rq; ++ int queued[2]; ++ int allocated[2]; ++ int meta_pending; ++ struct list_head fifo; ++ ++ struct bfq_entity entity; ++ ++ unsigned long max_budget; ++ unsigned long budget_timeout; ++ ++ int dispatched; ++ ++ unsigned int flags; ++ ++ struct list_head bfqq_list; ++ ++ unsigned int seek_samples; ++ u64 seek_total; ++ sector_t seek_mean; ++ sector_t last_request_pos; ++ ++ unsigned int requests_within_timer; ++ ++ pid_t pid; ++ struct bfq_io_cq *bic; ++ ++ /* weight-raising fields */ ++ unsigned long wr_cur_max_time; ++ unsigned long soft_rt_next_start; ++ unsigned long last_wr_start_finish; ++ unsigned int wr_coeff; ++ unsigned long last_idle_bklogged; ++ unsigned long service_from_backlogged; ++}; ++ ++/** ++ * struct bfq_ttime - per process thinktime stats. ++ * @ttime_total: total process thinktime ++ * @ttime_samples: number of thinktime samples ++ * @ttime_mean: average process thinktime ++ */ ++struct bfq_ttime { ++ unsigned long last_end_request; ++ ++ unsigned long ttime_total; ++ unsigned long ttime_samples; ++ unsigned long ttime_mean; ++}; ++ ++/** ++ * struct bfq_io_cq - per (request_queue, io_context) structure. ++ * @icq: associated io_cq structure ++ * @bfqq: array of two process queues, the sync and the async ++ * @ttime: associated @bfq_ttime struct ++ * @wr_time_left: snapshot of the time left before weight raising ends ++ * for the sync queue associated to this process; this ++ * snapshot is taken to remember this value while the weight ++ * raising is suspended because the queue is merged with a ++ * shared queue, and is used to set @raising_cur_max_time ++ * when the queue is split from the shared queue and its ++ * weight is raised again ++ * @saved_idle_window: same purpose as the previous field for the idle ++ * window ++ * @saved_IO_bound: same purpose as the previous two fields for the I/O ++ * bound classification of a queue ++ * @cooperations: counter of consecutive successful queue merges underwent ++ * by any of the process' @bfq_queues ++ * @failed_cooperations: counter of consecutive failed queue merges of any ++ * of the process' @bfq_queues ++ */ ++struct bfq_io_cq { ++ struct io_cq icq; /* must be the first member */ ++ struct bfq_queue *bfqq[2]; ++ struct bfq_ttime ttime; ++ int ioprio; ++ ++ unsigned int wr_time_left; ++ unsigned int saved_idle_window; ++ unsigned int saved_IO_bound; ++ ++ unsigned int cooperations; ++ unsigned int failed_cooperations; ++}; ++ ++enum bfq_device_speed { ++ BFQ_BFQD_FAST, ++ BFQ_BFQD_SLOW, ++}; ++ ++/** ++ * struct bfq_data - per device data structure. ++ * @queue: request queue for the managed device. ++ * @root_group: root bfq_group for the device. ++ * @rq_pos_tree: rbtree sorted by next_request position, used when ++ * determining if two or more queues have interleaving ++ * requests (see bfq_close_cooperator()). ++ * @active_numerous_groups: number of bfq_groups containing more than one ++ * active @bfq_entity. ++ * @queue_weights_tree: rbtree of weight counters of @bfq_queues, sorted by ++ * weight. Used to keep track of whether all @bfq_queues ++ * have the same weight. The tree contains one counter ++ * for each distinct weight associated to some active ++ * and not weight-raised @bfq_queue (see the comments to ++ * the functions bfq_weights_tree_[add|remove] for ++ * further details). ++ * @group_weights_tree: rbtree of non-queue @bfq_entity weight counters, sorted ++ * by weight. Used to keep track of whether all ++ * @bfq_groups have the same weight. The tree contains ++ * one counter for each distinct weight associated to ++ * some active @bfq_group (see the comments to the ++ * functions bfq_weights_tree_[add|remove] for further ++ * details). ++ * @busy_queues: number of bfq_queues containing requests (including the ++ * queue in service, even if it is idling). ++ * @busy_in_flight_queues: number of @bfq_queues containing pending or ++ * in-flight requests, plus the @bfq_queue in ++ * service, even if idle but waiting for the ++ * possible arrival of its next sync request. This ++ * field is updated only if the device is rotational, ++ * but used only if the device is also NCQ-capable. ++ * The reason why the field is updated also for non- ++ * NCQ-capable rotational devices is related to the ++ * fact that the value of @hw_tag may be set also ++ * later than when busy_in_flight_queues may need to ++ * be incremented for the first time(s). Taking also ++ * this possibility into account, to avoid unbalanced ++ * increments/decrements, would imply more overhead ++ * than just updating busy_in_flight_queues ++ * regardless of the value of @hw_tag. ++ * @const_seeky_busy_in_flight_queues: number of constantly-seeky @bfq_queues ++ * (that is, seeky queues that expired ++ * for budget timeout at least once) ++ * containing pending or in-flight ++ * requests, including the in-service ++ * @bfq_queue if constantly seeky. This ++ * field is updated only if the device ++ * is rotational, but used only if the ++ * device is also NCQ-capable (see the ++ * comments to @busy_in_flight_queues). ++ * @wr_busy_queues: number of weight-raised busy @bfq_queues. ++ * @queued: number of queued requests. ++ * @rq_in_driver: number of requests dispatched and waiting for completion. ++ * @sync_flight: number of sync requests in the driver. ++ * @max_rq_in_driver: max number of reqs in driver in the last ++ * @hw_tag_samples completed requests. ++ * @hw_tag_samples: nr of samples used to calculate hw_tag. ++ * @hw_tag: flag set to one if the driver is showing a queueing behavior. ++ * @budgets_assigned: number of budgets assigned. ++ * @idle_slice_timer: timer set when idling for the next sequential request ++ * from the queue in service. ++ * @unplug_work: delayed work to restart dispatching on the request queue. ++ * @in_service_queue: bfq_queue in service. ++ * @in_service_bic: bfq_io_cq (bic) associated with the @in_service_queue. ++ * @last_position: on-disk position of the last served request. ++ * @last_budget_start: beginning of the last budget. ++ * @last_idling_start: beginning of the last idle slice. ++ * @peak_rate: peak transfer rate observed for a budget. ++ * @peak_rate_samples: number of samples used to calculate @peak_rate. ++ * @bfq_max_budget: maximum budget allotted to a bfq_queue before ++ * rescheduling. ++ * @group_list: list of all the bfq_groups active on the device. ++ * @active_list: list of all the bfq_queues active on the device. ++ * @idle_list: list of all the bfq_queues idle on the device. ++ * @bfq_quantum: max number of requests dispatched per dispatch round. ++ * @bfq_fifo_expire: timeout for async/sync requests; when it expires ++ * requests are served in fifo order. ++ * @bfq_back_penalty: weight of backward seeks wrt forward ones. ++ * @bfq_back_max: maximum allowed backward seek. ++ * @bfq_slice_idle: maximum idling time. ++ * @bfq_user_max_budget: user-configured max budget value ++ * (0 for auto-tuning). ++ * @bfq_max_budget_async_rq: maximum budget (in nr of requests) allotted to ++ * async queues. ++ * @bfq_timeout: timeout for bfq_queues to consume their budget; used to ++ * to prevent seeky queues to impose long latencies to well ++ * behaved ones (this also implies that seeky queues cannot ++ * receive guarantees in the service domain; after a timeout ++ * they are charged for the whole allocated budget, to try ++ * to preserve a behavior reasonably fair among them, but ++ * without service-domain guarantees). ++ * @bfq_coop_thresh: number of queue merges after which a @bfq_queue is ++ * no more granted any weight-raising. ++ * @bfq_failed_cooperations: number of consecutive failed cooperation ++ * chances after which weight-raising is restored ++ * to a queue subject to more than bfq_coop_thresh ++ * queue merges. ++ * @bfq_requests_within_timer: number of consecutive requests that must be ++ * issued within the idle time slice to set ++ * again idling to a queue which was marked as ++ * non-I/O-bound (see the definition of the ++ * IO_bound flag for further details). ++ * @bfq_wr_coeff: Maximum factor by which the weight of a weight-raised ++ * queue is multiplied ++ * @bfq_wr_max_time: maximum duration of a weight-raising period (jiffies) ++ * @bfq_wr_rt_max_time: maximum duration for soft real-time processes ++ * @bfq_wr_min_idle_time: minimum idle period after which weight-raising ++ * may be reactivated for a queue (in jiffies) ++ * @bfq_wr_min_inter_arr_async: minimum period between request arrivals ++ * after which weight-raising may be ++ * reactivated for an already busy queue ++ * (in jiffies) ++ * @bfq_wr_max_softrt_rate: max service-rate for a soft real-time queue, ++ * sectors per seconds ++ * @RT_prod: cached value of the product R*T used for computing the maximum ++ * duration of the weight raising automatically ++ * @device_speed: device-speed class for the low-latency heuristic ++ * @oom_bfqq: fallback dummy bfqq for extreme OOM conditions ++ * ++ * All the fields are protected by the @queue lock. ++ */ ++struct bfq_data { ++ struct request_queue *queue; ++ ++ struct bfq_group *root_group; ++ struct rb_root rq_pos_tree; ++ ++#ifdef CONFIG_CGROUP_BFQIO ++ int active_numerous_groups; ++#endif ++ ++ struct rb_root queue_weights_tree; ++ struct rb_root group_weights_tree; ++ ++ int busy_queues; ++ int busy_in_flight_queues; ++ int const_seeky_busy_in_flight_queues; ++ int wr_busy_queues; ++ int queued; ++ int rq_in_driver; ++ int sync_flight; ++ ++ int max_rq_in_driver; ++ int hw_tag_samples; ++ int hw_tag; ++ ++ int budgets_assigned; ++ ++ struct timer_list idle_slice_timer; ++ struct work_struct unplug_work; ++ ++ struct bfq_queue *in_service_queue; ++ struct bfq_io_cq *in_service_bic; ++ ++ sector_t last_position; ++ ++ ktime_t last_budget_start; ++ ktime_t last_idling_start; ++ int peak_rate_samples; ++ u64 peak_rate; ++ unsigned long bfq_max_budget; ++ ++ struct hlist_head group_list; ++ struct list_head active_list; ++ struct list_head idle_list; ++ ++ unsigned int bfq_quantum; ++ unsigned int bfq_fifo_expire[2]; ++ unsigned int bfq_back_penalty; ++ unsigned int bfq_back_max; ++ unsigned int bfq_slice_idle; ++ u64 bfq_class_idle_last_service; ++ ++ unsigned int bfq_user_max_budget; ++ unsigned int bfq_max_budget_async_rq; ++ unsigned int bfq_timeout[2]; ++ ++ unsigned int bfq_coop_thresh; ++ unsigned int bfq_failed_cooperations; ++ unsigned int bfq_requests_within_timer; ++ ++ bool low_latency; ++ ++ /* parameters of the low_latency heuristics */ ++ unsigned int bfq_wr_coeff; ++ unsigned int bfq_wr_max_time; ++ unsigned int bfq_wr_rt_max_time; ++ unsigned int bfq_wr_min_idle_time; ++ unsigned long bfq_wr_min_inter_arr_async; ++ unsigned int bfq_wr_max_softrt_rate; ++ u64 RT_prod; ++ enum bfq_device_speed device_speed; ++ ++ struct bfq_queue oom_bfqq; ++}; ++ ++enum bfqq_state_flags { ++ BFQ_BFQQ_FLAG_busy = 0, /* has requests or is in service */ ++ BFQ_BFQQ_FLAG_wait_request, /* waiting for a request */ ++ BFQ_BFQQ_FLAG_must_alloc, /* must be allowed rq alloc */ ++ BFQ_BFQQ_FLAG_fifo_expire, /* FIFO checked in this slice */ ++ BFQ_BFQQ_FLAG_idle_window, /* slice idling enabled */ ++ BFQ_BFQQ_FLAG_prio_changed, /* task priority has changed */ ++ BFQ_BFQQ_FLAG_sync, /* synchronous queue */ ++ BFQ_BFQQ_FLAG_budget_new, /* no completion with this budget */ ++ BFQ_BFQQ_FLAG_IO_bound, /* ++ * bfqq has timed-out at least once ++ * having consumed at most 2/10 of ++ * its budget ++ */ ++ BFQ_BFQQ_FLAG_constantly_seeky, /* ++ * bfqq has proved to be slow and ++ * seeky until budget timeout ++ */ ++ BFQ_BFQQ_FLAG_softrt_update, /* ++ * may need softrt-next-start ++ * update ++ */ ++ BFQ_BFQQ_FLAG_coop, /* bfqq is shared */ ++ BFQ_BFQQ_FLAG_split_coop, /* shared bfqq will be split */ ++ BFQ_BFQQ_FLAG_just_split, /* queue has just been split */ ++}; ++ ++#define BFQ_BFQQ_FNS(name) \ ++static inline void bfq_mark_bfqq_##name(struct bfq_queue *bfqq) \ ++{ \ ++ (bfqq)->flags |= (1 << BFQ_BFQQ_FLAG_##name); \ ++} \ ++static inline void bfq_clear_bfqq_##name(struct bfq_queue *bfqq) \ ++{ \ ++ (bfqq)->flags &= ~(1 << BFQ_BFQQ_FLAG_##name); \ ++} \ ++static inline int bfq_bfqq_##name(const struct bfq_queue *bfqq) \ ++{ \ ++ return ((bfqq)->flags & (1 << BFQ_BFQQ_FLAG_##name)) != 0; \ ++} ++ ++BFQ_BFQQ_FNS(busy); ++BFQ_BFQQ_FNS(wait_request); ++BFQ_BFQQ_FNS(must_alloc); ++BFQ_BFQQ_FNS(fifo_expire); ++BFQ_BFQQ_FNS(idle_window); ++BFQ_BFQQ_FNS(prio_changed); ++BFQ_BFQQ_FNS(sync); ++BFQ_BFQQ_FNS(budget_new); ++BFQ_BFQQ_FNS(IO_bound); ++BFQ_BFQQ_FNS(constantly_seeky); ++BFQ_BFQQ_FNS(coop); ++BFQ_BFQQ_FNS(split_coop); ++BFQ_BFQQ_FNS(just_split); ++BFQ_BFQQ_FNS(softrt_update); ++#undef BFQ_BFQQ_FNS ++ ++/* Logging facilities. */ ++#define bfq_log_bfqq(bfqd, bfqq, fmt, args...) \ ++ blk_add_trace_msg((bfqd)->queue, "bfq%d " fmt, (bfqq)->pid, ##args) ++ ++#define bfq_log(bfqd, fmt, args...) \ ++ blk_add_trace_msg((bfqd)->queue, "bfq " fmt, ##args) ++ ++/* Expiration reasons. */ ++enum bfqq_expiration { ++ BFQ_BFQQ_TOO_IDLE = 0, /* ++ * queue has been idling for ++ * too long ++ */ ++ BFQ_BFQQ_BUDGET_TIMEOUT, /* budget took too long to be used */ ++ BFQ_BFQQ_BUDGET_EXHAUSTED, /* budget consumed */ ++ BFQ_BFQQ_NO_MORE_REQUESTS, /* the queue has no more requests */ ++}; ++ ++#ifdef CONFIG_CGROUP_BFQIO ++/** ++ * struct bfq_group - per (device, cgroup) data structure. ++ * @entity: schedulable entity to insert into the parent group sched_data. ++ * @sched_data: own sched_data, to contain child entities (they may be ++ * both bfq_queues and bfq_groups). ++ * @group_node: node to be inserted into the bfqio_cgroup->group_data ++ * list of the containing cgroup's bfqio_cgroup. ++ * @bfqd_node: node to be inserted into the @bfqd->group_list list ++ * of the groups active on the same device; used for cleanup. ++ * @bfqd: the bfq_data for the device this group acts upon. ++ * @async_bfqq: array of async queues for all the tasks belonging to ++ * the group, one queue per ioprio value per ioprio_class, ++ * except for the idle class that has only one queue. ++ * @async_idle_bfqq: async queue for the idle class (ioprio is ignored). ++ * @my_entity: pointer to @entity, %NULL for the toplevel group; used ++ * to avoid too many special cases during group creation/ ++ * migration. ++ * @active_entities: number of active entities belonging to the group; ++ * unused for the root group. Used to know whether there ++ * are groups with more than one active @bfq_entity ++ * (see the comments to the function ++ * bfq_bfqq_must_not_expire()). ++ * ++ * Each (device, cgroup) pair has its own bfq_group, i.e., for each cgroup ++ * there is a set of bfq_groups, each one collecting the lower-level ++ * entities belonging to the group that are acting on the same device. ++ * ++ * Locking works as follows: ++ * o @group_node is protected by the bfqio_cgroup lock, and is accessed ++ * via RCU from its readers. ++ * o @bfqd is protected by the queue lock, RCU is used to access it ++ * from the readers. ++ * o All the other fields are protected by the @bfqd queue lock. ++ */ ++struct bfq_group { ++ struct bfq_entity entity; ++ struct bfq_sched_data sched_data; ++ ++ struct hlist_node group_node; ++ struct hlist_node bfqd_node; ++ ++ void *bfqd; ++ ++ struct bfq_queue *async_bfqq[2][IOPRIO_BE_NR]; ++ struct bfq_queue *async_idle_bfqq; ++ ++ struct bfq_entity *my_entity; ++ ++ int active_entities; ++}; ++ ++/** ++ * struct bfqio_cgroup - bfq cgroup data structure. ++ * @css: subsystem state for bfq in the containing cgroup. ++ * @online: flag marked when the subsystem is inserted. ++ * @weight: cgroup weight. ++ * @ioprio: cgroup ioprio. ++ * @ioprio_class: cgroup ioprio_class. ++ * @lock: spinlock that protects @ioprio, @ioprio_class and @group_data. ++ * @group_data: list containing the bfq_group belonging to this cgroup. ++ * ++ * @group_data is accessed using RCU, with @lock protecting the updates, ++ * @ioprio and @ioprio_class are protected by @lock. ++ */ ++struct bfqio_cgroup { ++ struct cgroup_subsys_state css; ++ bool online; ++ ++ unsigned short weight, ioprio, ioprio_class; ++ ++ spinlock_t lock; ++ struct hlist_head group_data; ++}; ++#else ++struct bfq_group { ++ struct bfq_sched_data sched_data; ++ ++ struct bfq_queue *async_bfqq[2][IOPRIO_BE_NR]; ++ struct bfq_queue *async_idle_bfqq; ++}; ++#endif ++ ++static inline struct bfq_service_tree * ++bfq_entity_service_tree(struct bfq_entity *entity) ++{ ++ struct bfq_sched_data *sched_data = entity->sched_data; ++ unsigned int idx = entity->ioprio_class - 1; ++ ++ BUG_ON(idx >= BFQ_IOPRIO_CLASSES); ++ BUG_ON(sched_data == NULL); ++ ++ return sched_data->service_tree + idx; ++} ++ ++static inline struct bfq_queue *bic_to_bfqq(struct bfq_io_cq *bic, ++ int is_sync) ++{ ++ return bic->bfqq[!!is_sync]; ++} ++ ++static inline void bic_set_bfqq(struct bfq_io_cq *bic, ++ struct bfq_queue *bfqq, int is_sync) ++{ ++ bic->bfqq[!!is_sync] = bfqq; ++} ++ ++static inline struct bfq_data *bic_to_bfqd(struct bfq_io_cq *bic) ++{ ++ return bic->icq.q->elevator->elevator_data; ++} ++ ++/** ++ * bfq_get_bfqd_locked - get a lock to a bfqd using a RCU protected pointer. ++ * @ptr: a pointer to a bfqd. ++ * @flags: storage for the flags to be saved. ++ * ++ * This function allows bfqg->bfqd to be protected by the ++ * queue lock of the bfqd they reference; the pointer is dereferenced ++ * under RCU, so the storage for bfqd is assured to be safe as long ++ * as the RCU read side critical section does not end. After the ++ * bfqd->queue->queue_lock is taken the pointer is rechecked, to be ++ * sure that no other writer accessed it. If we raced with a writer, ++ * the function returns NULL, with the queue unlocked, otherwise it ++ * returns the dereferenced pointer, with the queue locked. ++ */ ++static inline struct bfq_data *bfq_get_bfqd_locked(void **ptr, ++ unsigned long *flags) ++{ ++ struct bfq_data *bfqd; ++ ++ rcu_read_lock(); ++ bfqd = rcu_dereference(*(struct bfq_data **)ptr); ++ ++ if (bfqd != NULL) { ++ spin_lock_irqsave(bfqd->queue->queue_lock, *flags); ++ if (*ptr == bfqd) ++ goto out; ++ spin_unlock_irqrestore(bfqd->queue->queue_lock, *flags); ++ } ++ ++ bfqd = NULL; ++out: ++ rcu_read_unlock(); ++ return bfqd; ++} ++ ++static inline void bfq_put_bfqd_unlock(struct bfq_data *bfqd, ++ unsigned long *flags) ++{ ++ spin_unlock_irqrestore(bfqd->queue->queue_lock, *flags); ++} ++ ++static void bfq_changed_ioprio(struct bfq_io_cq *bic); ++static void bfq_put_queue(struct bfq_queue *bfqq); ++static void bfq_dispatch_insert(struct request_queue *q, struct request *rq); ++static struct bfq_queue *bfq_get_queue(struct bfq_data *bfqd, ++ struct bfq_group *bfqg, int is_sync, ++ struct bfq_io_cq *bic, gfp_t gfp_mask); ++static void bfq_end_wr_async_queues(struct bfq_data *bfqd, ++ struct bfq_group *bfqg); ++static void bfq_put_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg); ++static void bfq_exit_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq); ++ ++#endif /* _BFQ_H */ +diff -Nur linux-3.14.40.orig/block/bfq-ioc.c linux-3.14.40/block/bfq-ioc.c +--- linux-3.14.40.orig/block/bfq-ioc.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/block/bfq-ioc.c 2015-05-01 14:57:58.351427001 -0500 +@@ -0,0 +1,36 @@ ++/* ++ * BFQ: I/O context handling. ++ * ++ * Based on ideas and code from CFQ: ++ * Copyright (C) 2003 Jens Axboe ++ * ++ * Copyright (C) 2008 Fabio Checconi ++ * Paolo Valente ++ * ++ * Copyright (C) 2010 Paolo Valente ++ */ ++ ++/** ++ * icq_to_bic - convert iocontext queue structure to bfq_io_cq. ++ * @icq: the iocontext queue. ++ */ ++static inline struct bfq_io_cq *icq_to_bic(struct io_cq *icq) ++{ ++ /* bic->icq is the first member, %NULL will convert to %NULL */ ++ return container_of(icq, struct bfq_io_cq, icq); ++} ++ ++/** ++ * bfq_bic_lookup - search into @ioc a bic associated to @bfqd. ++ * @bfqd: the lookup key. ++ * @ioc: the io_context of the process doing I/O. ++ * ++ * Queue lock must be held. ++ */ ++static inline struct bfq_io_cq *bfq_bic_lookup(struct bfq_data *bfqd, ++ struct io_context *ioc) ++{ ++ if (ioc) ++ return icq_to_bic(ioc_lookup_icq(ioc, bfqd->queue)); ++ return NULL; ++} +diff -Nur linux-3.14.40.orig/block/bfq-iosched.c linux-3.14.40/block/bfq-iosched.c +--- linux-3.14.40.orig/block/bfq-iosched.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/block/bfq-iosched.c 2015-05-01 14:57:58.355427001 -0500 +@@ -0,0 +1,3919 @@ ++/* ++ * Budget Fair Queueing (BFQ) disk scheduler. ++ * ++ * Based on ideas and code from CFQ: ++ * Copyright (C) 2003 Jens Axboe ++ * ++ * Copyright (C) 2008 Fabio Checconi ++ * Paolo Valente ++ * ++ * Copyright (C) 2010 Paolo Valente ++ * ++ * Licensed under the GPL-2 as detailed in the accompanying COPYING.BFQ ++ * file. ++ * ++ * BFQ is a proportional-share storage-I/O scheduling algorithm based on ++ * the slice-by-slice service scheme of CFQ. But BFQ assigns budgets, ++ * measured in number of sectors, to processes instead of time slices. The ++ * device is not granted to the in-service process for a given time slice, ++ * but until it has exhausted its assigned budget. This change from the time ++ * to the service domain allows BFQ to distribute the device throughput ++ * among processes as desired, without any distortion due to ZBR, workload ++ * fluctuations or other factors. BFQ uses an ad hoc internal scheduler, ++ * called B-WF2Q+, to schedule processes according to their budgets. More ++ * precisely, BFQ schedules queues associated to processes. Thanks to the ++ * accurate policy of B-WF2Q+, BFQ can afford to assign high budgets to ++ * I/O-bound processes issuing sequential requests (to boost the ++ * throughput), and yet guarantee a low latency to interactive and soft ++ * real-time applications. ++ * ++ * BFQ is described in [1], where also a reference to the initial, more ++ * theoretical paper on BFQ can be found. The interested reader can find ++ * in the latter paper full details on the main algorithm, as well as ++ * formulas of the guarantees and formal proofs of all the properties. ++ * With respect to the version of BFQ presented in these papers, this ++ * implementation adds a few more heuristics, such as the one that ++ * guarantees a low latency to soft real-time applications, and a ++ * hierarchical extension based on H-WF2Q+. ++ * ++ * B-WF2Q+ is based on WF2Q+, that is described in [2], together with ++ * H-WF2Q+, while the augmented tree used to implement B-WF2Q+ with O(log N) ++ * complexity derives from the one introduced with EEVDF in [3]. ++ * ++ * [1] P. Valente and M. Andreolini, ``Improving Application Responsiveness ++ * with the BFQ Disk I/O Scheduler'', ++ * Proceedings of the 5th Annual International Systems and Storage ++ * Conference (SYSTOR '12), June 2012. ++ * ++ * http://algogroup.unimo.it/people/paolo/disk_sched/bf1-v1-suite-results.pdf ++ * ++ * [2] Jon C.R. Bennett and H. Zhang, ``Hierarchical Packet Fair Queueing ++ * Algorithms,'' IEEE/ACM Transactions on Networking, 5(5):675-689, ++ * Oct 1997. ++ * ++ * http://www.cs.cmu.edu/~hzhang/papers/TON-97-Oct.ps.gz ++ * ++ * [3] I. Stoica and H. Abdel-Wahab, ``Earliest Eligible Virtual Deadline ++ * First: A Flexible and Accurate Mechanism for Proportional Share ++ * Resource Allocation,'' technical report. ++ * ++ * http://www.cs.berkeley.edu/~istoica/papers/eevdf-tr-95.pdf ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "bfq.h" ++#include "blk.h" ++ ++/* Max number of dispatches in one round of service. */ ++static const int bfq_quantum = 4; ++ ++/* Expiration time of sync (0) and async (1) requests, in jiffies. */ ++static const int bfq_fifo_expire[2] = { HZ / 4, HZ / 8 }; ++ ++/* Maximum backwards seek, in KiB. */ ++static const int bfq_back_max = 16 * 1024; ++ ++/* Penalty of a backwards seek, in number of sectors. */ ++static const int bfq_back_penalty = 2; ++ ++/* Idling period duration, in jiffies. */ ++static int bfq_slice_idle = HZ / 125; ++ ++/* Default maximum budget values, in sectors and number of requests. */ ++static const int bfq_default_max_budget = 16 * 1024; ++static const int bfq_max_budget_async_rq = 4; ++ ++/* ++ * Async to sync throughput distribution is controlled as follows: ++ * when an async request is served, the entity is charged the number ++ * of sectors of the request, multiplied by the factor below ++ */ ++static const int bfq_async_charge_factor = 10; ++ ++/* Default timeout values, in jiffies, approximating CFQ defaults. */ ++static const int bfq_timeout_sync = HZ / 8; ++static int bfq_timeout_async = HZ / 25; ++ ++struct kmem_cache *bfq_pool; ++ ++/* Below this threshold (in ms), we consider thinktime immediate. */ ++#define BFQ_MIN_TT 2 ++ ++/* hw_tag detection: parallel requests threshold and min samples needed. */ ++#define BFQ_HW_QUEUE_THRESHOLD 4 ++#define BFQ_HW_QUEUE_SAMPLES 32 ++ ++#define BFQQ_SEEK_THR (sector_t)(8 * 1024) ++#define BFQQ_SEEKY(bfqq) ((bfqq)->seek_mean > BFQQ_SEEK_THR) ++ ++/* Min samples used for peak rate estimation (for autotuning). */ ++#define BFQ_PEAK_RATE_SAMPLES 32 ++ ++/* Shift used for peak rate fixed precision calculations. */ ++#define BFQ_RATE_SHIFT 16 ++ ++/* ++ * By default, BFQ computes the duration of the weight raising for ++ * interactive applications automatically, using the following formula: ++ * duration = (R / r) * T, where r is the peak rate of the device, and ++ * R and T are two reference parameters. ++ * In particular, R is the peak rate of the reference device (see below), ++ * and T is a reference time: given the systems that are likely to be ++ * installed on the reference device according to its speed class, T is ++ * about the maximum time needed, under BFQ and while reading two files in ++ * parallel, to load typical large applications on these systems. ++ * In practice, the slower/faster the device at hand is, the more/less it ++ * takes to load applications with respect to the reference device. ++ * Accordingly, the longer/shorter BFQ grants weight raising to interactive ++ * applications. ++ * ++ * BFQ uses four different reference pairs (R, T), depending on: ++ * . whether the device is rotational or non-rotational; ++ * . whether the device is slow, such as old or portable HDDs, as well as ++ * SD cards, or fast, such as newer HDDs and SSDs. ++ * ++ * The device's speed class is dynamically (re)detected in ++ * bfq_update_peak_rate() every time the estimated peak rate is updated. ++ * ++ * In the following definitions, R_slow[0]/R_fast[0] and T_slow[0]/T_fast[0] ++ * are the reference values for a slow/fast rotational device, whereas ++ * R_slow[1]/R_fast[1] and T_slow[1]/T_fast[1] are the reference values for ++ * a slow/fast non-rotational device. Finally, device_speed_thresh are the ++ * thresholds used to switch between speed classes. ++ * Both the reference peak rates and the thresholds are measured in ++ * sectors/usec, left-shifted by BFQ_RATE_SHIFT. ++ */ ++static int R_slow[2] = {1536, 10752}; ++static int R_fast[2] = {17415, 34791}; ++/* ++ * To improve readability, a conversion function is used to initialize the ++ * following arrays, which entails that they can be initialized only in a ++ * function. ++ */ ++static int T_slow[2]; ++static int T_fast[2]; ++static int device_speed_thresh[2]; ++ ++#define BFQ_SERVICE_TREE_INIT ((struct bfq_service_tree) \ ++ { RB_ROOT, RB_ROOT, NULL, NULL, 0, 0 }) ++ ++#define RQ_BIC(rq) ((struct bfq_io_cq *) (rq)->elv.priv[0]) ++#define RQ_BFQQ(rq) ((rq)->elv.priv[1]) ++ ++static inline void bfq_schedule_dispatch(struct bfq_data *bfqd); ++ ++#include "bfq-ioc.c" ++#include "bfq-sched.c" ++#include "bfq-cgroup.c" ++ ++#define bfq_class_idle(bfqq) ((bfqq)->entity.ioprio_class ==\ ++ IOPRIO_CLASS_IDLE) ++#define bfq_class_rt(bfqq) ((bfqq)->entity.ioprio_class ==\ ++ IOPRIO_CLASS_RT) ++ ++#define bfq_sample_valid(samples) ((samples) > 80) ++ ++/* ++ * We regard a request as SYNC, if either it's a read or has the SYNC bit ++ * set (in which case it could also be a direct WRITE). ++ */ ++static inline int bfq_bio_sync(struct bio *bio) ++{ ++ if (bio_data_dir(bio) == READ || (bio->bi_rw & REQ_SYNC)) ++ return 1; ++ ++ return 0; ++} ++ ++/* ++ * Scheduler run of queue, if there are requests pending and no one in the ++ * driver that will restart queueing. ++ */ ++static inline void bfq_schedule_dispatch(struct bfq_data *bfqd) ++{ ++ if (bfqd->queued != 0) { ++ bfq_log(bfqd, "schedule dispatch"); ++ kblockd_schedule_work(bfqd->queue, &bfqd->unplug_work); ++ } ++} ++ ++/* ++ * Lifted from AS - choose which of rq1 and rq2 that is best served now. ++ * We choose the request that is closesr to the head right now. Distance ++ * behind the head is penalized and only allowed to a certain extent. ++ */ ++static struct request *bfq_choose_req(struct bfq_data *bfqd, ++ struct request *rq1, ++ struct request *rq2, ++ sector_t last) ++{ ++ sector_t s1, s2, d1 = 0, d2 = 0; ++ unsigned long back_max; ++#define BFQ_RQ1_WRAP 0x01 /* request 1 wraps */ ++#define BFQ_RQ2_WRAP 0x02 /* request 2 wraps */ ++ unsigned wrap = 0; /* bit mask: requests behind the disk head? */ ++ ++ if (rq1 == NULL || rq1 == rq2) ++ return rq2; ++ if (rq2 == NULL) ++ return rq1; ++ ++ if (rq_is_sync(rq1) && !rq_is_sync(rq2)) ++ return rq1; ++ else if (rq_is_sync(rq2) && !rq_is_sync(rq1)) ++ return rq2; ++ if ((rq1->cmd_flags & REQ_META) && !(rq2->cmd_flags & REQ_META)) ++ return rq1; ++ else if ((rq2->cmd_flags & REQ_META) && !(rq1->cmd_flags & REQ_META)) ++ return rq2; ++ ++ s1 = blk_rq_pos(rq1); ++ s2 = blk_rq_pos(rq2); ++ ++ /* ++ * By definition, 1KiB is 2 sectors. ++ */ ++ back_max = bfqd->bfq_back_max * 2; ++ ++ /* ++ * Strict one way elevator _except_ in the case where we allow ++ * short backward seeks which are biased as twice the cost of a ++ * similar forward seek. ++ */ ++ if (s1 >= last) ++ d1 = s1 - last; ++ else if (s1 + back_max >= last) ++ d1 = (last - s1) * bfqd->bfq_back_penalty; ++ else ++ wrap |= BFQ_RQ1_WRAP; ++ ++ if (s2 >= last) ++ d2 = s2 - last; ++ else if (s2 + back_max >= last) ++ d2 = (last - s2) * bfqd->bfq_back_penalty; ++ else ++ wrap |= BFQ_RQ2_WRAP; ++ ++ /* Found required data */ ++ ++ /* ++ * By doing switch() on the bit mask "wrap" we avoid having to ++ * check two variables for all permutations: --> faster! ++ */ ++ switch (wrap) { ++ case 0: /* common case for CFQ: rq1 and rq2 not wrapped */ ++ if (d1 < d2) ++ return rq1; ++ else if (d2 < d1) ++ return rq2; ++ else { ++ if (s1 >= s2) ++ return rq1; ++ else ++ return rq2; ++ } ++ ++ case BFQ_RQ2_WRAP: ++ return rq1; ++ case BFQ_RQ1_WRAP: ++ return rq2; ++ case (BFQ_RQ1_WRAP|BFQ_RQ2_WRAP): /* both rqs wrapped */ ++ default: ++ /* ++ * Since both rqs are wrapped, ++ * start with the one that's further behind head ++ * (--> only *one* back seek required), ++ * since back seek takes more time than forward. ++ */ ++ if (s1 <= s2) ++ return rq1; ++ else ++ return rq2; ++ } ++} ++ ++static struct bfq_queue * ++bfq_rq_pos_tree_lookup(struct bfq_data *bfqd, struct rb_root *root, ++ sector_t sector, struct rb_node **ret_parent, ++ struct rb_node ***rb_link) ++{ ++ struct rb_node **p, *parent; ++ struct bfq_queue *bfqq = NULL; ++ ++ parent = NULL; ++ p = &root->rb_node; ++ while (*p) { ++ struct rb_node **n; ++ ++ parent = *p; ++ bfqq = rb_entry(parent, struct bfq_queue, pos_node); ++ ++ /* ++ * Sort strictly based on sector. Smallest to the left, ++ * largest to the right. ++ */ ++ if (sector > blk_rq_pos(bfqq->next_rq)) ++ n = &(*p)->rb_right; ++ else if (sector < blk_rq_pos(bfqq->next_rq)) ++ n = &(*p)->rb_left; ++ else ++ break; ++ p = n; ++ bfqq = NULL; ++ } ++ ++ *ret_parent = parent; ++ if (rb_link) ++ *rb_link = p; ++ ++ bfq_log(bfqd, "rq_pos_tree_lookup %llu: returning %d", ++ (long long unsigned)sector, ++ bfqq != NULL ? bfqq->pid : 0); ++ ++ return bfqq; ++} ++ ++static void bfq_rq_pos_tree_add(struct bfq_data *bfqd, struct bfq_queue *bfqq) ++{ ++ struct rb_node **p, *parent; ++ struct bfq_queue *__bfqq; ++ ++ if (bfqq->pos_root != NULL) { ++ rb_erase(&bfqq->pos_node, bfqq->pos_root); ++ bfqq->pos_root = NULL; ++ } ++ ++ if (bfq_class_idle(bfqq)) ++ return; ++ if (!bfqq->next_rq) ++ return; ++ ++ bfqq->pos_root = &bfqd->rq_pos_tree; ++ __bfqq = bfq_rq_pos_tree_lookup(bfqd, bfqq->pos_root, ++ blk_rq_pos(bfqq->next_rq), &parent, &p); ++ if (__bfqq == NULL) { ++ rb_link_node(&bfqq->pos_node, parent, p); ++ rb_insert_color(&bfqq->pos_node, bfqq->pos_root); ++ } else ++ bfqq->pos_root = NULL; ++} ++ ++/* ++ * Tell whether there are active queues or groups with differentiated weights. ++ */ ++static inline bool bfq_differentiated_weights(struct bfq_data *bfqd) ++{ ++ BUG_ON(!bfqd->hw_tag); ++ /* ++ * For weights to differ, at least one of the trees must contain ++ * at least two nodes. ++ */ ++ return (!RB_EMPTY_ROOT(&bfqd->queue_weights_tree) && ++ (bfqd->queue_weights_tree.rb_node->rb_left || ++ bfqd->queue_weights_tree.rb_node->rb_right) ++#ifdef CONFIG_CGROUP_BFQIO ++ ) || ++ (!RB_EMPTY_ROOT(&bfqd->group_weights_tree) && ++ (bfqd->group_weights_tree.rb_node->rb_left || ++ bfqd->group_weights_tree.rb_node->rb_right) ++#endif ++ ); ++} ++ ++/* ++ * If the weight-counter tree passed as input contains no counter for ++ * the weight of the input entity, then add that counter; otherwise just ++ * increment the existing counter. ++ * ++ * Note that weight-counter trees contain few nodes in mostly symmetric ++ * scenarios. For example, if all queues have the same weight, then the ++ * weight-counter tree for the queues may contain at most one node. ++ * This holds even if low_latency is on, because weight-raised queues ++ * are not inserted in the tree. ++ * In most scenarios, the rate at which nodes are created/destroyed ++ * should be low too. ++ */ ++static void bfq_weights_tree_add(struct bfq_data *bfqd, ++ struct bfq_entity *entity, ++ struct rb_root *root) ++{ ++ struct rb_node **new = &(root->rb_node), *parent = NULL; ++ ++ /* ++ * Do not insert if: ++ * - the device does not support queueing; ++ * - the entity is already associated with a counter, which happens if: ++ * 1) the entity is associated with a queue, 2) a request arrival ++ * has caused the queue to become both non-weight-raised, and hence ++ * change its weight, and backlogged; in this respect, each ++ * of the two events causes an invocation of this function, ++ * 3) this is the invocation of this function caused by the second ++ * event. This second invocation is actually useless, and we handle ++ * this fact by exiting immediately. More efficient or clearer ++ * solutions might possibly be adopted. ++ */ ++ if (!bfqd->hw_tag || entity->weight_counter) ++ return; ++ ++ while (*new) { ++ struct bfq_weight_counter *__counter = container_of(*new, ++ struct bfq_weight_counter, ++ weights_node); ++ parent = *new; ++ ++ if (entity->weight == __counter->weight) { ++ entity->weight_counter = __counter; ++ goto inc_counter; ++ } ++ if (entity->weight < __counter->weight) ++ new = &((*new)->rb_left); ++ else ++ new = &((*new)->rb_right); ++ } ++ ++ entity->weight_counter = kzalloc(sizeof(struct bfq_weight_counter), ++ GFP_ATOMIC); ++ entity->weight_counter->weight = entity->weight; ++ rb_link_node(&entity->weight_counter->weights_node, parent, new); ++ rb_insert_color(&entity->weight_counter->weights_node, root); ++ ++inc_counter: ++ entity->weight_counter->num_active++; ++} ++ ++/* ++ * Decrement the weight counter associated with the entity, and, if the ++ * counter reaches 0, remove the counter from the tree. ++ * See the comments to the function bfq_weights_tree_add() for considerations ++ * about overhead. ++ */ ++static void bfq_weights_tree_remove(struct bfq_data *bfqd, ++ struct bfq_entity *entity, ++ struct rb_root *root) ++{ ++ /* ++ * Check whether the entity is actually associated with a counter. ++ * In fact, the device may not be considered NCQ-capable for a while, ++ * which implies that no insertion in the weight trees is performed, ++ * after which the device may start to be deemed NCQ-capable, and hence ++ * this function may start to be invoked. This may cause the function ++ * to be invoked for entities that are not associated with any counter. ++ */ ++ if (!entity->weight_counter) ++ return; ++ ++ BUG_ON(RB_EMPTY_ROOT(root)); ++ BUG_ON(entity->weight_counter->weight != entity->weight); ++ ++ BUG_ON(!entity->weight_counter->num_active); ++ entity->weight_counter->num_active--; ++ if (entity->weight_counter->num_active > 0) ++ goto reset_entity_pointer; ++ ++ rb_erase(&entity->weight_counter->weights_node, root); ++ kfree(entity->weight_counter); ++ ++reset_entity_pointer: ++ entity->weight_counter = NULL; ++} ++ ++static struct request *bfq_find_next_rq(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq, ++ struct request *last) ++{ ++ struct rb_node *rbnext = rb_next(&last->rb_node); ++ struct rb_node *rbprev = rb_prev(&last->rb_node); ++ struct request *next = NULL, *prev = NULL; ++ ++ BUG_ON(RB_EMPTY_NODE(&last->rb_node)); ++ ++ if (rbprev != NULL) ++ prev = rb_entry_rq(rbprev); ++ ++ if (rbnext != NULL) ++ next = rb_entry_rq(rbnext); ++ else { ++ rbnext = rb_first(&bfqq->sort_list); ++ if (rbnext && rbnext != &last->rb_node) ++ next = rb_entry_rq(rbnext); ++ } ++ ++ return bfq_choose_req(bfqd, next, prev, blk_rq_pos(last)); ++} ++ ++/* see the definition of bfq_async_charge_factor for details */ ++static inline unsigned long bfq_serv_to_charge(struct request *rq, ++ struct bfq_queue *bfqq) ++{ ++ return blk_rq_sectors(rq) * ++ (1 + ((!bfq_bfqq_sync(bfqq)) * (bfqq->wr_coeff == 1) * ++ bfq_async_charge_factor)); ++} ++ ++/** ++ * bfq_updated_next_req - update the queue after a new next_rq selection. ++ * @bfqd: the device data the queue belongs to. ++ * @bfqq: the queue to update. ++ * ++ * If the first request of a queue changes we make sure that the queue ++ * has enough budget to serve at least its first request (if the ++ * request has grown). We do this because if the queue has not enough ++ * budget for its first request, it has to go through two dispatch ++ * rounds to actually get it dispatched. ++ */ ++static void bfq_updated_next_req(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq) ++{ ++ struct bfq_entity *entity = &bfqq->entity; ++ struct bfq_service_tree *st = bfq_entity_service_tree(entity); ++ struct request *next_rq = bfqq->next_rq; ++ unsigned long new_budget; ++ ++ if (next_rq == NULL) ++ return; ++ ++ if (bfqq == bfqd->in_service_queue) ++ /* ++ * In order not to break guarantees, budgets cannot be ++ * changed after an entity has been selected. ++ */ ++ return; ++ ++ BUG_ON(entity->tree != &st->active); ++ BUG_ON(entity == entity->sched_data->in_service_entity); ++ ++ new_budget = max_t(unsigned long, bfqq->max_budget, ++ bfq_serv_to_charge(next_rq, bfqq)); ++ if (entity->budget != new_budget) { ++ entity->budget = new_budget; ++ bfq_log_bfqq(bfqd, bfqq, "updated next rq: new budget %lu", ++ new_budget); ++ bfq_activate_bfqq(bfqd, bfqq); ++ } ++} ++ ++static inline unsigned int bfq_wr_duration(struct bfq_data *bfqd) ++{ ++ u64 dur; ++ ++ if (bfqd->bfq_wr_max_time > 0) ++ return bfqd->bfq_wr_max_time; ++ ++ dur = bfqd->RT_prod; ++ do_div(dur, bfqd->peak_rate); ++ ++ return dur; ++} ++ ++static inline unsigned ++bfq_bfqq_cooperations(struct bfq_queue *bfqq) ++{ ++ return bfqq->bic ? bfqq->bic->cooperations : 0; ++} ++ ++static inline void ++bfq_bfqq_resume_state(struct bfq_queue *bfqq, struct bfq_io_cq *bic) ++{ ++ if (bic->saved_idle_window) ++ bfq_mark_bfqq_idle_window(bfqq); ++ else ++ bfq_clear_bfqq_idle_window(bfqq); ++ if (bic->saved_IO_bound) ++ bfq_mark_bfqq_IO_bound(bfqq); ++ else ++ bfq_clear_bfqq_IO_bound(bfqq); ++ if (bic->wr_time_left && bfqq->bfqd->low_latency && ++ bic->cooperations < bfqq->bfqd->bfq_coop_thresh) { ++ /* ++ * Start a weight raising period with the duration given by ++ * the raising_time_left snapshot. ++ */ ++ if (bfq_bfqq_busy(bfqq)) ++ bfqq->bfqd->wr_busy_queues++; ++ bfqq->wr_coeff = bfqq->bfqd->bfq_wr_coeff; ++ bfqq->wr_cur_max_time = bic->wr_time_left; ++ bfqq->last_wr_start_finish = jiffies; ++ bfqq->entity.ioprio_changed = 1; ++ } ++ /* ++ * Clear wr_time_left to prevent bfq_bfqq_save_state() from ++ * getting confused about the queue's need of a weight-raising ++ * period. ++ */ ++ bic->wr_time_left = 0; ++} ++ ++/* ++ * Must be called with the queue_lock held. ++ */ ++static int bfqq_process_refs(struct bfq_queue *bfqq) ++{ ++ int process_refs, io_refs; ++ ++ io_refs = bfqq->allocated[READ] + bfqq->allocated[WRITE]; ++ process_refs = atomic_read(&bfqq->ref) - io_refs - bfqq->entity.on_st; ++ BUG_ON(process_refs < 0); ++ return process_refs; ++} ++ ++static void bfq_add_request(struct request *rq) ++{ ++ struct bfq_queue *bfqq = RQ_BFQQ(rq); ++ struct bfq_entity *entity = &bfqq->entity; ++ struct bfq_data *bfqd = bfqq->bfqd; ++ struct request *next_rq, *prev; ++ unsigned long old_wr_coeff = bfqq->wr_coeff; ++ int idle_for_long_time = 0; ++ ++ bfq_log_bfqq(bfqd, bfqq, "add_request %d", rq_is_sync(rq)); ++ bfqq->queued[rq_is_sync(rq)]++; ++ bfqd->queued++; ++ ++ elv_rb_add(&bfqq->sort_list, rq); ++ ++ /* ++ * Check if this request is a better next-serve candidate. ++ */ ++ prev = bfqq->next_rq; ++ next_rq = bfq_choose_req(bfqd, bfqq->next_rq, rq, bfqd->last_position); ++ BUG_ON(next_rq == NULL); ++ bfqq->next_rq = next_rq; ++ ++ /* ++ * Adjust priority tree position, if next_rq changes. ++ */ ++ if (prev != bfqq->next_rq) ++ bfq_rq_pos_tree_add(bfqd, bfqq); ++ ++ if (!bfq_bfqq_busy(bfqq)) { ++ int soft_rt = bfqd->bfq_wr_max_softrt_rate > 0 && ++ bfq_bfqq_cooperations(bfqq) < bfqd->bfq_coop_thresh && ++ time_is_before_jiffies(bfqq->soft_rt_next_start); ++ idle_for_long_time = bfq_bfqq_cooperations(bfqq) < ++ bfqd->bfq_coop_thresh && ++ time_is_before_jiffies( ++ bfqq->budget_timeout + ++ bfqd->bfq_wr_min_idle_time); ++ entity->budget = max_t(unsigned long, bfqq->max_budget, ++ bfq_serv_to_charge(next_rq, bfqq)); ++ ++ if (!bfq_bfqq_IO_bound(bfqq)) { ++ if (time_before(jiffies, ++ RQ_BIC(rq)->ttime.last_end_request + ++ bfqd->bfq_slice_idle)) { ++ bfqq->requests_within_timer++; ++ if (bfqq->requests_within_timer >= ++ bfqd->bfq_requests_within_timer) ++ bfq_mark_bfqq_IO_bound(bfqq); ++ } else ++ bfqq->requests_within_timer = 0; ++ } ++ ++ if (!bfqd->low_latency) ++ goto add_bfqq_busy; ++ ++ if (bfq_bfqq_just_split(bfqq)) ++ goto set_ioprio_changed; ++ ++ /* ++ * If the queue: ++ * - is not being boosted, ++ * - has been idle for enough time, ++ * - is not a sync queue or is linked to a bfq_io_cq (it is ++ * shared "for its nature" or it is not shared and its ++ * requests have not been redirected to a shared queue) ++ * start a weight-raising period. ++ */ ++ if (old_wr_coeff == 1 && (idle_for_long_time || soft_rt) && ++ (!bfq_bfqq_sync(bfqq) || bfqq->bic != NULL)) { ++ bfqq->wr_coeff = bfqd->bfq_wr_coeff; ++ if (idle_for_long_time) ++ bfqq->wr_cur_max_time = bfq_wr_duration(bfqd); ++ else ++ bfqq->wr_cur_max_time = ++ bfqd->bfq_wr_rt_max_time; ++ bfq_log_bfqq(bfqd, bfqq, ++ "wrais starting at %lu, rais_max_time %u", ++ jiffies, ++ jiffies_to_msecs(bfqq->wr_cur_max_time)); ++ } else if (old_wr_coeff > 1) { ++ if (idle_for_long_time) ++ bfqq->wr_cur_max_time = bfq_wr_duration(bfqd); ++ else if (bfq_bfqq_cooperations(bfqq) >= ++ bfqd->bfq_coop_thresh || ++ (bfqq->wr_cur_max_time == ++ bfqd->bfq_wr_rt_max_time && ++ !soft_rt)) { ++ bfqq->wr_coeff = 1; ++ bfq_log_bfqq(bfqd, bfqq, ++ "wrais ending at %lu, rais_max_time %u", ++ jiffies, ++ jiffies_to_msecs(bfqq-> ++ wr_cur_max_time)); ++ } else if (time_before( ++ bfqq->last_wr_start_finish + ++ bfqq->wr_cur_max_time, ++ jiffies + ++ bfqd->bfq_wr_rt_max_time) && ++ soft_rt) { ++ /* ++ * ++ * The remaining weight-raising time is lower ++ * than bfqd->bfq_wr_rt_max_time, which means ++ * that the application is enjoying weight ++ * raising either because deemed soft-rt in ++ * the near past, or because deemed interactive ++ * a long ago. ++ * In both cases, resetting now the current ++ * remaining weight-raising time for the ++ * application to the weight-raising duration ++ * for soft rt applications would not cause any ++ * latency increase for the application (as the ++ * new duration would be higher than the ++ * remaining time). ++ * ++ * In addition, the application is now meeting ++ * the requirements for being deemed soft rt. ++ * In the end we can correctly and safely ++ * (re)charge the weight-raising duration for ++ * the application with the weight-raising ++ * duration for soft rt applications. ++ * ++ * In particular, doing this recharge now, i.e., ++ * before the weight-raising period for the ++ * application finishes, reduces the probability ++ * of the following negative scenario: ++ * 1) the weight of a soft rt application is ++ * raised at startup (as for any newly ++ * created application), ++ * 2) since the application is not interactive, ++ * at a certain time weight-raising is ++ * stopped for the application, ++ * 3) at that time the application happens to ++ * still have pending requests, and hence ++ * is destined to not have a chance to be ++ * deemed soft rt before these requests are ++ * completed (see the comments to the ++ * function bfq_bfqq_softrt_next_start() ++ * for details on soft rt detection), ++ * 4) these pending requests experience a high ++ * latency because the application is not ++ * weight-raised while they are pending. ++ */ ++ bfqq->last_wr_start_finish = jiffies; ++ bfqq->wr_cur_max_time = ++ bfqd->bfq_wr_rt_max_time; ++ } ++ } ++set_ioprio_changed: ++ if (old_wr_coeff != bfqq->wr_coeff) ++ entity->ioprio_changed = 1; ++add_bfqq_busy: ++ bfqq->last_idle_bklogged = jiffies; ++ bfqq->service_from_backlogged = 0; ++ bfq_clear_bfqq_softrt_update(bfqq); ++ bfq_add_bfqq_busy(bfqd, bfqq); ++ } else { ++ if (bfqd->low_latency && old_wr_coeff == 1 && !rq_is_sync(rq) && ++ time_is_before_jiffies( ++ bfqq->last_wr_start_finish + ++ bfqd->bfq_wr_min_inter_arr_async)) { ++ bfqq->wr_coeff = bfqd->bfq_wr_coeff; ++ bfqq->wr_cur_max_time = bfq_wr_duration(bfqd); ++ ++ bfqd->wr_busy_queues++; ++ entity->ioprio_changed = 1; ++ bfq_log_bfqq(bfqd, bfqq, ++ "non-idle wrais starting at %lu, rais_max_time %u", ++ jiffies, ++ jiffies_to_msecs(bfqq->wr_cur_max_time)); ++ } ++ if (prev != bfqq->next_rq) ++ bfq_updated_next_req(bfqd, bfqq); ++ } ++ ++ if (bfqd->low_latency && ++ (old_wr_coeff == 1 || bfqq->wr_coeff == 1 || ++ idle_for_long_time)) ++ bfqq->last_wr_start_finish = jiffies; ++} ++ ++static struct request *bfq_find_rq_fmerge(struct bfq_data *bfqd, ++ struct bio *bio) ++{ ++ struct task_struct *tsk = current; ++ struct bfq_io_cq *bic; ++ struct bfq_queue *bfqq; ++ ++ bic = bfq_bic_lookup(bfqd, tsk->io_context); ++ if (bic == NULL) ++ return NULL; ++ ++ bfqq = bic_to_bfqq(bic, bfq_bio_sync(bio)); ++ if (bfqq != NULL) ++ return elv_rb_find(&bfqq->sort_list, bio_end_sector(bio)); ++ ++ return NULL; ++} ++ ++static void bfq_activate_request(struct request_queue *q, struct request *rq) ++{ ++ struct bfq_data *bfqd = q->elevator->elevator_data; ++ ++ bfqd->rq_in_driver++; ++ bfqd->last_position = blk_rq_pos(rq) + blk_rq_sectors(rq); ++ bfq_log(bfqd, "activate_request: new bfqd->last_position %llu", ++ (long long unsigned)bfqd->last_position); ++} ++ ++static inline void bfq_deactivate_request(struct request_queue *q, ++ struct request *rq) ++{ ++ struct bfq_data *bfqd = q->elevator->elevator_data; ++ ++ BUG_ON(bfqd->rq_in_driver == 0); ++ bfqd->rq_in_driver--; ++} ++ ++static void bfq_remove_request(struct request *rq) ++{ ++ struct bfq_queue *bfqq = RQ_BFQQ(rq); ++ struct bfq_data *bfqd = bfqq->bfqd; ++ const int sync = rq_is_sync(rq); ++ ++ if (bfqq->next_rq == rq) { ++ bfqq->next_rq = bfq_find_next_rq(bfqd, bfqq, rq); ++ bfq_updated_next_req(bfqd, bfqq); ++ } ++ ++ list_del_init(&rq->queuelist); ++ BUG_ON(bfqq->queued[sync] == 0); ++ bfqq->queued[sync]--; ++ bfqd->queued--; ++ elv_rb_del(&bfqq->sort_list, rq); ++ ++ if (RB_EMPTY_ROOT(&bfqq->sort_list)) { ++ if (bfq_bfqq_busy(bfqq) && bfqq != bfqd->in_service_queue) ++ bfq_del_bfqq_busy(bfqd, bfqq, 1); ++ /* ++ * Remove queue from request-position tree as it is empty. ++ */ ++ if (bfqq->pos_root != NULL) { ++ rb_erase(&bfqq->pos_node, bfqq->pos_root); ++ bfqq->pos_root = NULL; ++ } ++ } ++ ++ if (rq->cmd_flags & REQ_META) { ++ BUG_ON(bfqq->meta_pending == 0); ++ bfqq->meta_pending--; ++ } ++} ++ ++static int bfq_merge(struct request_queue *q, struct request **req, ++ struct bio *bio) ++{ ++ struct bfq_data *bfqd = q->elevator->elevator_data; ++ struct request *__rq; ++ ++ __rq = bfq_find_rq_fmerge(bfqd, bio); ++ if (__rq != NULL && elv_rq_merge_ok(__rq, bio)) { ++ *req = __rq; ++ return ELEVATOR_FRONT_MERGE; ++ } ++ ++ return ELEVATOR_NO_MERGE; ++} ++ ++static void bfq_merged_request(struct request_queue *q, struct request *req, ++ int type) ++{ ++ if (type == ELEVATOR_FRONT_MERGE && ++ rb_prev(&req->rb_node) && ++ blk_rq_pos(req) < ++ blk_rq_pos(container_of(rb_prev(&req->rb_node), ++ struct request, rb_node))) { ++ struct bfq_queue *bfqq = RQ_BFQQ(req); ++ struct bfq_data *bfqd = bfqq->bfqd; ++ struct request *prev, *next_rq; ++ ++ /* Reposition request in its sort_list */ ++ elv_rb_del(&bfqq->sort_list, req); ++ elv_rb_add(&bfqq->sort_list, req); ++ /* Choose next request to be served for bfqq */ ++ prev = bfqq->next_rq; ++ next_rq = bfq_choose_req(bfqd, bfqq->next_rq, req, ++ bfqd->last_position); ++ BUG_ON(next_rq == NULL); ++ bfqq->next_rq = next_rq; ++ /* ++ * If next_rq changes, update both the queue's budget to ++ * fit the new request and the queue's position in its ++ * rq_pos_tree. ++ */ ++ if (prev != bfqq->next_rq) { ++ bfq_updated_next_req(bfqd, bfqq); ++ bfq_rq_pos_tree_add(bfqd, bfqq); ++ } ++ } ++} ++ ++static void bfq_merged_requests(struct request_queue *q, struct request *rq, ++ struct request *next) ++{ ++ struct bfq_queue *bfqq = RQ_BFQQ(rq); ++ ++ /* ++ * Reposition in fifo if next is older than rq. ++ */ ++ if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist) && ++ time_before(rq_fifo_time(next), rq_fifo_time(rq))) { ++ list_move(&rq->queuelist, &next->queuelist); ++ rq_set_fifo_time(rq, rq_fifo_time(next)); ++ } ++ ++ if (bfqq->next_rq == next) ++ bfqq->next_rq = rq; ++ ++ bfq_remove_request(next); ++} ++ ++/* Must be called with bfqq != NULL */ ++static inline void bfq_bfqq_end_wr(struct bfq_queue *bfqq) ++{ ++ BUG_ON(bfqq == NULL); ++ if (bfq_bfqq_busy(bfqq)) ++ bfqq->bfqd->wr_busy_queues--; ++ bfqq->wr_coeff = 1; ++ bfqq->wr_cur_max_time = 0; ++ /* Trigger a weight change on the next activation of the queue */ ++ bfqq->entity.ioprio_changed = 1; ++} ++ ++static void bfq_end_wr_async_queues(struct bfq_data *bfqd, ++ struct bfq_group *bfqg) ++{ ++ int i, j; ++ ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < IOPRIO_BE_NR; j++) ++ if (bfqg->async_bfqq[i][j] != NULL) ++ bfq_bfqq_end_wr(bfqg->async_bfqq[i][j]); ++ if (bfqg->async_idle_bfqq != NULL) ++ bfq_bfqq_end_wr(bfqg->async_idle_bfqq); ++} ++ ++static void bfq_end_wr(struct bfq_data *bfqd) ++{ ++ struct bfq_queue *bfqq; ++ ++ spin_lock_irq(bfqd->queue->queue_lock); ++ ++ list_for_each_entry(bfqq, &bfqd->active_list, bfqq_list) ++ bfq_bfqq_end_wr(bfqq); ++ list_for_each_entry(bfqq, &bfqd->idle_list, bfqq_list) ++ bfq_bfqq_end_wr(bfqq); ++ bfq_end_wr_async(bfqd); ++ ++ spin_unlock_irq(bfqd->queue->queue_lock); ++} ++ ++static inline sector_t bfq_io_struct_pos(void *io_struct, bool request) ++{ ++ if (request) ++ return blk_rq_pos(io_struct); ++ else ++ return ((struct bio *)io_struct)->bi_iter.bi_sector; ++} ++ ++static inline sector_t bfq_dist_from(sector_t pos1, ++ sector_t pos2) ++{ ++ if (pos1 >= pos2) ++ return pos1 - pos2; ++ else ++ return pos2 - pos1; ++} ++ ++static inline int bfq_rq_close_to_sector(void *io_struct, bool request, ++ sector_t sector) ++{ ++ return bfq_dist_from(bfq_io_struct_pos(io_struct, request), sector) <= ++ BFQQ_SEEK_THR; ++} ++ ++static struct bfq_queue *bfqq_close(struct bfq_data *bfqd, sector_t sector) ++{ ++ struct rb_root *root = &bfqd->rq_pos_tree; ++ struct rb_node *parent, *node; ++ struct bfq_queue *__bfqq; ++ ++ if (RB_EMPTY_ROOT(root)) ++ return NULL; ++ ++ /* ++ * First, if we find a request starting at the end of the last ++ * request, choose it. ++ */ ++ __bfqq = bfq_rq_pos_tree_lookup(bfqd, root, sector, &parent, NULL); ++ if (__bfqq != NULL) ++ return __bfqq; ++ ++ /* ++ * If the exact sector wasn't found, the parent of the NULL leaf ++ * will contain the closest sector (rq_pos_tree sorted by ++ * next_request position). ++ */ ++ __bfqq = rb_entry(parent, struct bfq_queue, pos_node); ++ if (bfq_rq_close_to_sector(__bfqq->next_rq, true, sector)) ++ return __bfqq; ++ ++ if (blk_rq_pos(__bfqq->next_rq) < sector) ++ node = rb_next(&__bfqq->pos_node); ++ else ++ node = rb_prev(&__bfqq->pos_node); ++ if (node == NULL) ++ return NULL; ++ ++ __bfqq = rb_entry(node, struct bfq_queue, pos_node); ++ if (bfq_rq_close_to_sector(__bfqq->next_rq, true, sector)) ++ return __bfqq; ++ ++ return NULL; ++} ++ ++/* ++ * bfqd - obvious ++ * cur_bfqq - passed in so that we don't decide that the current queue ++ * is closely cooperating with itself ++ * sector - used as a reference point to search for a close queue ++ */ ++static struct bfq_queue *bfq_close_cooperator(struct bfq_data *bfqd, ++ struct bfq_queue *cur_bfqq, ++ sector_t sector) ++{ ++ struct bfq_queue *bfqq; ++ ++ if (bfq_class_idle(cur_bfqq)) ++ return NULL; ++ if (!bfq_bfqq_sync(cur_bfqq)) ++ return NULL; ++ if (BFQQ_SEEKY(cur_bfqq)) ++ return NULL; ++ ++ /* If device has only one backlogged bfq_queue, don't search. */ ++ if (bfqd->busy_queues == 1) ++ return NULL; ++ ++ /* ++ * We should notice if some of the queues are cooperating, e.g. ++ * working closely on the same area of the disk. In that case, ++ * we can group them together and don't waste time idling. ++ */ ++ bfqq = bfqq_close(bfqd, sector); ++ if (bfqq == NULL || bfqq == cur_bfqq) ++ return NULL; ++ ++ /* ++ * Do not merge queues from different bfq_groups. ++ */ ++ if (bfqq->entity.parent != cur_bfqq->entity.parent) ++ return NULL; ++ ++ /* ++ * It only makes sense to merge sync queues. ++ */ ++ if (!bfq_bfqq_sync(bfqq)) ++ return NULL; ++ if (BFQQ_SEEKY(bfqq)) ++ return NULL; ++ ++ /* ++ * Do not merge queues of different priority classes. ++ */ ++ if (bfq_class_rt(bfqq) != bfq_class_rt(cur_bfqq)) ++ return NULL; ++ ++ return bfqq; ++} ++ ++static struct bfq_queue * ++bfq_setup_merge(struct bfq_queue *bfqq, struct bfq_queue *new_bfqq) ++{ ++ int process_refs, new_process_refs; ++ struct bfq_queue *__bfqq; ++ ++ /* ++ * If there are no process references on the new_bfqq, then it is ++ * unsafe to follow the ->new_bfqq chain as other bfqq's in the chain ++ * may have dropped their last reference (not just their last process ++ * reference). ++ */ ++ if (!bfqq_process_refs(new_bfqq)) ++ return NULL; ++ ++ /* Avoid a circular list and skip interim queue merges. */ ++ while ((__bfqq = new_bfqq->new_bfqq)) { ++ if (__bfqq == bfqq) ++ return NULL; ++ new_bfqq = __bfqq; ++ } ++ ++ process_refs = bfqq_process_refs(bfqq); ++ new_process_refs = bfqq_process_refs(new_bfqq); ++ /* ++ * If the process for the bfqq has gone away, there is no ++ * sense in merging the queues. ++ */ ++ if (process_refs == 0 || new_process_refs == 0) ++ return NULL; ++ ++ bfq_log_bfqq(bfqq->bfqd, bfqq, "scheduling merge with queue %d", ++ new_bfqq->pid); ++ ++ /* ++ * Merging is just a redirection: the requests of the process ++ * owning one of the two queues are redirected to the other queue. ++ * The latter queue, in its turn, is set as shared if this is the ++ * first time that the requests of some process are redirected to ++ * it. ++ * ++ * We redirect bfqq to new_bfqq and not the opposite, because we ++ * are in the context of the process owning bfqq, hence we have ++ * the io_cq of this process. So we can immediately configure this ++ * io_cq to redirect the requests of the process to new_bfqq. ++ * ++ * NOTE, even if new_bfqq coincides with the in-service queue, the ++ * io_cq of new_bfqq is not available, because, if the in-service ++ * queue is shared, bfqd->in_service_bic may not point to the ++ * io_cq of the in-service queue. ++ * Redirecting the requests of the process owning bfqq to the ++ * currently in-service queue is in any case the best option, as ++ * we feed the in-service queue with new requests close to the ++ * last request served and, by doing so, hopefully increase the ++ * throughput. ++ */ ++ bfqq->new_bfqq = new_bfqq; ++ atomic_add(process_refs, &new_bfqq->ref); ++ return new_bfqq; ++} ++ ++/* ++ * Attempt to schedule a merge of bfqq with the currently in-service queue ++ * or with a close queue among the scheduled queues. ++ * Return NULL if no merge was scheduled, a pointer to the shared bfq_queue ++ * structure otherwise. ++ */ ++static struct bfq_queue * ++bfq_setup_cooperator(struct bfq_data *bfqd, struct bfq_queue *bfqq, ++ void *io_struct, bool request) ++{ ++ struct bfq_queue *in_service_bfqq, *new_bfqq; ++ ++ if (bfqq->new_bfqq) ++ return bfqq->new_bfqq; ++ ++ if (!io_struct) ++ return NULL; ++ ++ in_service_bfqq = bfqd->in_service_queue; ++ ++ if (in_service_bfqq == NULL || in_service_bfqq == bfqq || ++ !bfqd->in_service_bic) ++ goto check_scheduled; ++ ++ if (bfq_class_idle(in_service_bfqq) || bfq_class_idle(bfqq)) ++ goto check_scheduled; ++ ++ if (bfq_class_rt(in_service_bfqq) != bfq_class_rt(bfqq)) ++ goto check_scheduled; ++ ++ if (in_service_bfqq->entity.parent != bfqq->entity.parent) ++ goto check_scheduled; ++ ++ if (bfq_rq_close_to_sector(io_struct, request, bfqd->last_position) && ++ bfq_bfqq_sync(in_service_bfqq) && bfq_bfqq_sync(bfqq)) { ++ new_bfqq = bfq_setup_merge(bfqq, in_service_bfqq); ++ if (new_bfqq != NULL) ++ return new_bfqq; /* Merge with in-service queue */ ++ } ++ ++ /* ++ * Check whether there is a cooperator among currently scheduled ++ * queues. The only thing we need is that the bio/request is not ++ * NULL, as we need it to establish whether a cooperator exists. ++ */ ++check_scheduled: ++ new_bfqq = bfq_close_cooperator(bfqd, bfqq, ++ bfq_io_struct_pos(io_struct, request)); ++ if (new_bfqq) ++ return bfq_setup_merge(bfqq, new_bfqq); ++ ++ return NULL; ++} ++ ++static inline void ++bfq_bfqq_save_state(struct bfq_queue *bfqq) ++{ ++ /* ++ * If bfqq->bic == NULL, the queue is already shared or its requests ++ * have already been redirected to a shared queue; both idle window ++ * and weight raising state have already been saved. Do nothing. ++ */ ++ if (bfqq->bic == NULL) ++ return; ++ if (bfqq->bic->wr_time_left) ++ /* ++ * This is the queue of a just-started process, and would ++ * deserve weight raising: we set wr_time_left to the full ++ * weight-raising duration to trigger weight-raising when ++ * and if the queue is split and the first request of the ++ * queue is enqueued. ++ */ ++ bfqq->bic->wr_time_left = bfq_wr_duration(bfqq->bfqd); ++ else if (bfqq->wr_coeff > 1) { ++ unsigned long wr_duration = ++ jiffies - bfqq->last_wr_start_finish; ++ /* ++ * It may happen that a queue's weight raising period lasts ++ * longer than its wr_cur_max_time, as weight raising is ++ * handled only when a request is enqueued or dispatched (it ++ * does not use any timer). If the weight raising period is ++ * about to end, don't save it. ++ */ ++ if (bfqq->wr_cur_max_time <= wr_duration) ++ bfqq->bic->wr_time_left = 0; ++ else ++ bfqq->bic->wr_time_left = ++ bfqq->wr_cur_max_time - wr_duration; ++ /* ++ * The bfq_queue is becoming shared or the requests of the ++ * process owning the queue are being redirected to a shared ++ * queue. Stop the weight raising period of the queue, as in ++ * both cases it should not be owned by an interactive or ++ * soft real-time application. ++ */ ++ bfq_bfqq_end_wr(bfqq); ++ } else ++ bfqq->bic->wr_time_left = 0; ++ bfqq->bic->saved_idle_window = bfq_bfqq_idle_window(bfqq); ++ bfqq->bic->saved_IO_bound = bfq_bfqq_IO_bound(bfqq); ++ bfqq->bic->cooperations++; ++ bfqq->bic->failed_cooperations = 0; ++} ++ ++static inline void ++bfq_get_bic_reference(struct bfq_queue *bfqq) ++{ ++ /* ++ * If bfqq->bic has a non-NULL value, the bic to which it belongs ++ * is about to begin using a shared bfq_queue. ++ */ ++ if (bfqq->bic) ++ atomic_long_inc(&bfqq->bic->icq.ioc->refcount); ++} ++ ++static void ++bfq_merge_bfqqs(struct bfq_data *bfqd, struct bfq_io_cq *bic, ++ struct bfq_queue *bfqq, struct bfq_queue *new_bfqq) ++{ ++ bfq_log_bfqq(bfqd, bfqq, "merging with queue %lu", ++ (long unsigned)new_bfqq->pid); ++ /* Save weight raising and idle window of the merged queues */ ++ bfq_bfqq_save_state(bfqq); ++ bfq_bfqq_save_state(new_bfqq); ++ if (bfq_bfqq_IO_bound(bfqq)) ++ bfq_mark_bfqq_IO_bound(new_bfqq); ++ bfq_clear_bfqq_IO_bound(bfqq); ++ /* ++ * Grab a reference to the bic, to prevent it from being destroyed ++ * before being possibly touched by a bfq_split_bfqq(). ++ */ ++ bfq_get_bic_reference(bfqq); ++ bfq_get_bic_reference(new_bfqq); ++ /* ++ * Merge queues (that is, let bic redirect its requests to new_bfqq) ++ */ ++ bic_set_bfqq(bic, new_bfqq, 1); ++ bfq_mark_bfqq_coop(new_bfqq); ++ /* ++ * new_bfqq now belongs to at least two bics (it is a shared queue): ++ * set new_bfqq->bic to NULL. bfqq either: ++ * - does not belong to any bic any more, and hence bfqq->bic must ++ * be set to NULL, or ++ * - is a queue whose owning bics have already been redirected to a ++ * different queue, hence the queue is destined to not belong to ++ * any bic soon and bfqq->bic is already NULL (therefore the next ++ * assignment causes no harm). ++ */ ++ new_bfqq->bic = NULL; ++ bfqq->bic = NULL; ++ bfq_put_queue(bfqq); ++} ++ ++static inline void bfq_bfqq_increase_failed_cooperations(struct bfq_queue *bfqq) ++{ ++ struct bfq_io_cq *bic = bfqq->bic; ++ struct bfq_data *bfqd = bfqq->bfqd; ++ ++ if (bic && bfq_bfqq_cooperations(bfqq) >= bfqd->bfq_coop_thresh) { ++ bic->failed_cooperations++; ++ if (bic->failed_cooperations >= bfqd->bfq_failed_cooperations) ++ bic->cooperations = 0; ++ } ++} ++ ++static int bfq_allow_merge(struct request_queue *q, struct request *rq, ++ struct bio *bio) ++{ ++ struct bfq_data *bfqd = q->elevator->elevator_data; ++ struct bfq_io_cq *bic; ++ struct bfq_queue *bfqq, *new_bfqq; ++ ++ /* ++ * Disallow merge of a sync bio into an async request. ++ */ ++ if (bfq_bio_sync(bio) && !rq_is_sync(rq)) ++ return 0; ++ ++ /* ++ * Lookup the bfqq that this bio will be queued with. Allow ++ * merge only if rq is queued there. ++ * Queue lock is held here. ++ */ ++ bic = bfq_bic_lookup(bfqd, current->io_context); ++ if (bic == NULL) ++ return 0; ++ ++ bfqq = bic_to_bfqq(bic, bfq_bio_sync(bio)); ++ /* ++ * We take advantage of this function to perform an early merge ++ * of the queues of possible cooperating processes. ++ */ ++ if (bfqq != NULL) { ++ new_bfqq = bfq_setup_cooperator(bfqd, bfqq, bio, false); ++ if (new_bfqq != NULL) { ++ bfq_merge_bfqqs(bfqd, bic, bfqq, new_bfqq); ++ /* ++ * If we get here, the bio will be queued in the ++ * shared queue, i.e., new_bfqq, so use new_bfqq ++ * to decide whether bio and rq can be merged. ++ */ ++ bfqq = new_bfqq; ++ } else ++ bfq_bfqq_increase_failed_cooperations(bfqq); ++ } ++ ++ return bfqq == RQ_BFQQ(rq); ++} ++ ++static void __bfq_set_in_service_queue(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq) ++{ ++ if (bfqq != NULL) { ++ bfq_mark_bfqq_must_alloc(bfqq); ++ bfq_mark_bfqq_budget_new(bfqq); ++ bfq_clear_bfqq_fifo_expire(bfqq); ++ ++ bfqd->budgets_assigned = (bfqd->budgets_assigned*7 + 256) / 8; ++ ++ bfq_log_bfqq(bfqd, bfqq, ++ "set_in_service_queue, cur-budget = %lu", ++ bfqq->entity.budget); ++ } ++ ++ bfqd->in_service_queue = bfqq; ++} ++ ++/* ++ * Get and set a new queue for service. ++ */ ++static struct bfq_queue *bfq_set_in_service_queue(struct bfq_data *bfqd) ++{ ++ struct bfq_queue *bfqq = bfq_get_next_queue(bfqd); ++ ++ __bfq_set_in_service_queue(bfqd, bfqq); ++ return bfqq; ++} ++ ++/* ++ * If enough samples have been computed, return the current max budget ++ * stored in bfqd, which is dynamically updated according to the ++ * estimated disk peak rate; otherwise return the default max budget ++ */ ++static inline unsigned long bfq_max_budget(struct bfq_data *bfqd) ++{ ++ if (bfqd->budgets_assigned < 194) ++ return bfq_default_max_budget; ++ else ++ return bfqd->bfq_max_budget; ++} ++ ++/* ++ * Return min budget, which is a fraction of the current or default ++ * max budget (trying with 1/32) ++ */ ++static inline unsigned long bfq_min_budget(struct bfq_data *bfqd) ++{ ++ if (bfqd->budgets_assigned < 194) ++ return bfq_default_max_budget / 32; ++ else ++ return bfqd->bfq_max_budget / 32; ++} ++ ++static void bfq_arm_slice_timer(struct bfq_data *bfqd) ++{ ++ struct bfq_queue *bfqq = bfqd->in_service_queue; ++ struct bfq_io_cq *bic; ++ unsigned long sl; ++ ++ BUG_ON(!RB_EMPTY_ROOT(&bfqq->sort_list)); ++ ++ /* Processes have exited, don't wait. */ ++ bic = bfqd->in_service_bic; ++ if (bic == NULL || atomic_read(&bic->icq.ioc->active_ref) == 0) ++ return; ++ ++ bfq_mark_bfqq_wait_request(bfqq); ++ ++ /* ++ * We don't want to idle for seeks, but we do want to allow ++ * fair distribution of slice time for a process doing back-to-back ++ * seeks. So allow a little bit of time for him to submit a new rq. ++ * ++ * To prevent processes with (partly) seeky workloads from ++ * being too ill-treated, grant them a small fraction of the ++ * assigned budget before reducing the waiting time to ++ * BFQ_MIN_TT. This happened to help reduce latency. ++ */ ++ sl = bfqd->bfq_slice_idle; ++ /* ++ * Unless the queue is being weight-raised, grant only minimum idle ++ * time if the queue either has been seeky for long enough or has ++ * already proved to be constantly seeky. ++ */ ++ if (bfq_sample_valid(bfqq->seek_samples) && ++ ((BFQQ_SEEKY(bfqq) && bfqq->entity.service > ++ bfq_max_budget(bfqq->bfqd) / 8) || ++ bfq_bfqq_constantly_seeky(bfqq)) && bfqq->wr_coeff == 1) ++ sl = min(sl, msecs_to_jiffies(BFQ_MIN_TT)); ++ else if (bfqq->wr_coeff > 1) ++ sl = sl * 3; ++ bfqd->last_idling_start = ktime_get(); ++ mod_timer(&bfqd->idle_slice_timer, jiffies + sl); ++ bfq_log(bfqd, "arm idle: %u/%u ms", ++ jiffies_to_msecs(sl), jiffies_to_msecs(bfqd->bfq_slice_idle)); ++} ++ ++/* ++ * Set the maximum time for the in-service queue to consume its ++ * budget. This prevents seeky processes from lowering the disk ++ * throughput (always guaranteed with a time slice scheme as in CFQ). ++ */ ++static void bfq_set_budget_timeout(struct bfq_data *bfqd) ++{ ++ struct bfq_queue *bfqq = bfqd->in_service_queue; ++ unsigned int timeout_coeff; ++ if (bfqq->wr_cur_max_time == bfqd->bfq_wr_rt_max_time) ++ timeout_coeff = 1; ++ else ++ timeout_coeff = bfqq->entity.weight / bfqq->entity.orig_weight; ++ ++ bfqd->last_budget_start = ktime_get(); ++ ++ bfq_clear_bfqq_budget_new(bfqq); ++ bfqq->budget_timeout = jiffies + ++ bfqd->bfq_timeout[bfq_bfqq_sync(bfqq)] * timeout_coeff; ++ ++ bfq_log_bfqq(bfqd, bfqq, "set budget_timeout %u", ++ jiffies_to_msecs(bfqd->bfq_timeout[bfq_bfqq_sync(bfqq)] * ++ timeout_coeff)); ++} ++ ++/* ++ * Move request from internal lists to the request queue dispatch list. ++ */ ++static void bfq_dispatch_insert(struct request_queue *q, struct request *rq) ++{ ++ struct bfq_data *bfqd = q->elevator->elevator_data; ++ struct bfq_queue *bfqq = RQ_BFQQ(rq); ++ ++ /* ++ * For consistency, the next instruction should have been executed ++ * after removing the request from the queue and dispatching it. ++ * We execute instead this instruction before bfq_remove_request() ++ * (and hence introduce a temporary inconsistency), for efficiency. ++ * In fact, in a forced_dispatch, this prevents two counters related ++ * to bfqq->dispatched to risk to be uselessly decremented if bfqq ++ * is not in service, and then to be incremented again after ++ * incrementing bfqq->dispatched. ++ */ ++ bfqq->dispatched++; ++ bfq_remove_request(rq); ++ elv_dispatch_sort(q, rq); ++ ++ if (bfq_bfqq_sync(bfqq)) ++ bfqd->sync_flight++; ++} ++ ++/* ++ * Return expired entry, or NULL to just start from scratch in rbtree. ++ */ ++static struct request *bfq_check_fifo(struct bfq_queue *bfqq) ++{ ++ struct request *rq = NULL; ++ ++ if (bfq_bfqq_fifo_expire(bfqq)) ++ return NULL; ++ ++ bfq_mark_bfqq_fifo_expire(bfqq); ++ ++ if (list_empty(&bfqq->fifo)) ++ return NULL; ++ ++ rq = rq_entry_fifo(bfqq->fifo.next); ++ ++ if (time_before(jiffies, rq_fifo_time(rq))) ++ return NULL; ++ ++ return rq; ++} ++ ++static inline unsigned long bfq_bfqq_budget_left(struct bfq_queue *bfqq) ++{ ++ struct bfq_entity *entity = &bfqq->entity; ++ return entity->budget - entity->service; ++} ++ ++static void __bfq_bfqq_expire(struct bfq_data *bfqd, struct bfq_queue *bfqq) ++{ ++ BUG_ON(bfqq != bfqd->in_service_queue); ++ ++ __bfq_bfqd_reset_in_service(bfqd); ++ ++ /* ++ * If this bfqq is shared between multiple processes, check ++ * to make sure that those processes are still issuing I/Os ++ * within the mean seek distance. If not, it may be time to ++ * break the queues apart again. ++ */ ++ if (bfq_bfqq_coop(bfqq) && BFQQ_SEEKY(bfqq)) ++ bfq_mark_bfqq_split_coop(bfqq); ++ ++ if (RB_EMPTY_ROOT(&bfqq->sort_list)) { ++ /* ++ * Overloading budget_timeout field to store the time ++ * at which the queue remains with no backlog; used by ++ * the weight-raising mechanism. ++ */ ++ bfqq->budget_timeout = jiffies; ++ bfq_del_bfqq_busy(bfqd, bfqq, 1); ++ } else { ++ bfq_activate_bfqq(bfqd, bfqq); ++ /* ++ * Resort priority tree of potential close cooperators. ++ */ ++ bfq_rq_pos_tree_add(bfqd, bfqq); ++ } ++} ++ ++/** ++ * __bfq_bfqq_recalc_budget - try to adapt the budget to the @bfqq behavior. ++ * @bfqd: device data. ++ * @bfqq: queue to update. ++ * @reason: reason for expiration. ++ * ++ * Handle the feedback on @bfqq budget. See the body for detailed ++ * comments. ++ */ ++static void __bfq_bfqq_recalc_budget(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq, ++ enum bfqq_expiration reason) ++{ ++ struct request *next_rq; ++ unsigned long budget, min_budget; ++ ++ budget = bfqq->max_budget; ++ min_budget = bfq_min_budget(bfqd); ++ ++ BUG_ON(bfqq != bfqd->in_service_queue); ++ ++ bfq_log_bfqq(bfqd, bfqq, "recalc_budg: last budg %lu, budg left %lu", ++ bfqq->entity.budget, bfq_bfqq_budget_left(bfqq)); ++ bfq_log_bfqq(bfqd, bfqq, "recalc_budg: last max_budg %lu, min budg %lu", ++ budget, bfq_min_budget(bfqd)); ++ bfq_log_bfqq(bfqd, bfqq, "recalc_budg: sync %d, seeky %d", ++ bfq_bfqq_sync(bfqq), BFQQ_SEEKY(bfqd->in_service_queue)); ++ ++ if (bfq_bfqq_sync(bfqq)) { ++ switch (reason) { ++ /* ++ * Caveat: in all the following cases we trade latency ++ * for throughput. ++ */ ++ case BFQ_BFQQ_TOO_IDLE: ++ /* ++ * This is the only case where we may reduce ++ * the budget: if there is no request of the ++ * process still waiting for completion, then ++ * we assume (tentatively) that the timer has ++ * expired because the batch of requests of ++ * the process could have been served with a ++ * smaller budget. Hence, betting that ++ * process will behave in the same way when it ++ * becomes backlogged again, we reduce its ++ * next budget. As long as we guess right, ++ * this budget cut reduces the latency ++ * experienced by the process. ++ * ++ * However, if there are still outstanding ++ * requests, then the process may have not yet ++ * issued its next request just because it is ++ * still waiting for the completion of some of ++ * the still outstanding ones. So in this ++ * subcase we do not reduce its budget, on the ++ * contrary we increase it to possibly boost ++ * the throughput, as discussed in the ++ * comments to the BUDGET_TIMEOUT case. ++ */ ++ if (bfqq->dispatched > 0) /* still outstanding reqs */ ++ budget = min(budget * 2, bfqd->bfq_max_budget); ++ else { ++ if (budget > 5 * min_budget) ++ budget -= 4 * min_budget; ++ else ++ budget = min_budget; ++ } ++ break; ++ case BFQ_BFQQ_BUDGET_TIMEOUT: ++ /* ++ * We double the budget here because: 1) it ++ * gives the chance to boost the throughput if ++ * this is not a seeky process (which may have ++ * bumped into this timeout because of, e.g., ++ * ZBR), 2) together with charge_full_budget ++ * it helps give seeky processes higher ++ * timestamps, and hence be served less ++ * frequently. ++ */ ++ budget = min(budget * 2, bfqd->bfq_max_budget); ++ break; ++ case BFQ_BFQQ_BUDGET_EXHAUSTED: ++ /* ++ * The process still has backlog, and did not ++ * let either the budget timeout or the disk ++ * idling timeout expire. Hence it is not ++ * seeky, has a short thinktime and may be ++ * happy with a higher budget too. So ++ * definitely increase the budget of this good ++ * candidate to boost the disk throughput. ++ */ ++ budget = min(budget * 4, bfqd->bfq_max_budget); ++ break; ++ case BFQ_BFQQ_NO_MORE_REQUESTS: ++ /* ++ * Leave the budget unchanged. ++ */ ++ default: ++ return; ++ } ++ } else /* async queue */ ++ /* async queues get always the maximum possible budget ++ * (their ability to dispatch is limited by ++ * @bfqd->bfq_max_budget_async_rq). ++ */ ++ budget = bfqd->bfq_max_budget; ++ ++ bfqq->max_budget = budget; ++ ++ if (bfqd->budgets_assigned >= 194 && bfqd->bfq_user_max_budget == 0 && ++ bfqq->max_budget > bfqd->bfq_max_budget) ++ bfqq->max_budget = bfqd->bfq_max_budget; ++ ++ /* ++ * Make sure that we have enough budget for the next request. ++ * Since the finish time of the bfqq must be kept in sync with ++ * the budget, be sure to call __bfq_bfqq_expire() after the ++ * update. ++ */ ++ next_rq = bfqq->next_rq; ++ if (next_rq != NULL) ++ bfqq->entity.budget = max_t(unsigned long, bfqq->max_budget, ++ bfq_serv_to_charge(next_rq, bfqq)); ++ else ++ bfqq->entity.budget = bfqq->max_budget; ++ ++ bfq_log_bfqq(bfqd, bfqq, "head sect: %u, new budget %lu", ++ next_rq != NULL ? blk_rq_sectors(next_rq) : 0, ++ bfqq->entity.budget); ++} ++ ++static unsigned long bfq_calc_max_budget(u64 peak_rate, u64 timeout) ++{ ++ unsigned long max_budget; ++ ++ /* ++ * The max_budget calculated when autotuning is equal to the ++ * amount of sectors transfered in timeout_sync at the ++ * estimated peak rate. ++ */ ++ max_budget = (unsigned long)(peak_rate * 1000 * ++ timeout >> BFQ_RATE_SHIFT); ++ ++ return max_budget; ++} ++ ++/* ++ * In addition to updating the peak rate, checks whether the process ++ * is "slow", and returns 1 if so. This slow flag is used, in addition ++ * to the budget timeout, to reduce the amount of service provided to ++ * seeky processes, and hence reduce their chances to lower the ++ * throughput. See the code for more details. ++ */ ++static int bfq_update_peak_rate(struct bfq_data *bfqd, struct bfq_queue *bfqq, ++ int compensate, enum bfqq_expiration reason) ++{ ++ u64 bw, usecs, expected, timeout; ++ ktime_t delta; ++ int update = 0; ++ ++ if (!bfq_bfqq_sync(bfqq) || bfq_bfqq_budget_new(bfqq)) ++ return 0; ++ ++ if (compensate) ++ delta = bfqd->last_idling_start; ++ else ++ delta = ktime_get(); ++ delta = ktime_sub(delta, bfqd->last_budget_start); ++ usecs = ktime_to_us(delta); ++ ++ /* Don't trust short/unrealistic values. */ ++ if (usecs < 100 || usecs >= LONG_MAX) ++ return 0; ++ ++ /* ++ * Calculate the bandwidth for the last slice. We use a 64 bit ++ * value to store the peak rate, in sectors per usec in fixed ++ * point math. We do so to have enough precision in the estimate ++ * and to avoid overflows. ++ */ ++ bw = (u64)bfqq->entity.service << BFQ_RATE_SHIFT; ++ do_div(bw, (unsigned long)usecs); ++ ++ timeout = jiffies_to_msecs(bfqd->bfq_timeout[BLK_RW_SYNC]); ++ ++ /* ++ * Use only long (> 20ms) intervals to filter out spikes for ++ * the peak rate estimation. ++ */ ++ if (usecs > 20000) { ++ if (bw > bfqd->peak_rate || ++ (!BFQQ_SEEKY(bfqq) && ++ reason == BFQ_BFQQ_BUDGET_TIMEOUT)) { ++ bfq_log(bfqd, "measured bw =%llu", bw); ++ /* ++ * To smooth oscillations use a low-pass filter with ++ * alpha=7/8, i.e., ++ * new_rate = (7/8) * old_rate + (1/8) * bw ++ */ ++ do_div(bw, 8); ++ if (bw == 0) ++ return 0; ++ bfqd->peak_rate *= 7; ++ do_div(bfqd->peak_rate, 8); ++ bfqd->peak_rate += bw; ++ update = 1; ++ bfq_log(bfqd, "new peak_rate=%llu", bfqd->peak_rate); ++ } ++ ++ update |= bfqd->peak_rate_samples == BFQ_PEAK_RATE_SAMPLES - 1; ++ ++ if (bfqd->peak_rate_samples < BFQ_PEAK_RATE_SAMPLES) ++ bfqd->peak_rate_samples++; ++ ++ if (bfqd->peak_rate_samples == BFQ_PEAK_RATE_SAMPLES && ++ update) { ++ int dev_type = blk_queue_nonrot(bfqd->queue); ++ if (bfqd->bfq_user_max_budget == 0) { ++ bfqd->bfq_max_budget = ++ bfq_calc_max_budget(bfqd->peak_rate, ++ timeout); ++ bfq_log(bfqd, "new max_budget=%lu", ++ bfqd->bfq_max_budget); ++ } ++ if (bfqd->device_speed == BFQ_BFQD_FAST && ++ bfqd->peak_rate < device_speed_thresh[dev_type]) { ++ bfqd->device_speed = BFQ_BFQD_SLOW; ++ bfqd->RT_prod = R_slow[dev_type] * ++ T_slow[dev_type]; ++ } else if (bfqd->device_speed == BFQ_BFQD_SLOW && ++ bfqd->peak_rate > device_speed_thresh[dev_type]) { ++ bfqd->device_speed = BFQ_BFQD_FAST; ++ bfqd->RT_prod = R_fast[dev_type] * ++ T_fast[dev_type]; ++ } ++ } ++ } ++ ++ /* ++ * If the process has been served for a too short time ++ * interval to let its possible sequential accesses prevail on ++ * the initial seek time needed to move the disk head on the ++ * first sector it requested, then give the process a chance ++ * and for the moment return false. ++ */ ++ if (bfqq->entity.budget <= bfq_max_budget(bfqd) / 8) ++ return 0; ++ ++ /* ++ * A process is considered ``slow'' (i.e., seeky, so that we ++ * cannot treat it fairly in the service domain, as it would ++ * slow down too much the other processes) if, when a slice ++ * ends for whatever reason, it has received service at a ++ * rate that would not be high enough to complete the budget ++ * before the budget timeout expiration. ++ */ ++ expected = bw * 1000 * timeout >> BFQ_RATE_SHIFT; ++ ++ /* ++ * Caveat: processes doing IO in the slower disk zones will ++ * tend to be slow(er) even if not seeky. And the estimated ++ * peak rate will actually be an average over the disk ++ * surface. Hence, to not be too harsh with unlucky processes, ++ * we keep a budget/3 margin of safety before declaring a ++ * process slow. ++ */ ++ return expected > (4 * bfqq->entity.budget) / 3; ++} ++ ++/* ++ * To be deemed as soft real-time, an application must meet two ++ * requirements. First, the application must not require an average ++ * bandwidth higher than the approximate bandwidth required to playback or ++ * record a compressed high-definition video. ++ * The next function is invoked on the completion of the last request of a ++ * batch, to compute the next-start time instant, soft_rt_next_start, such ++ * that, if the next request of the application does not arrive before ++ * soft_rt_next_start, then the above requirement on the bandwidth is met. ++ * ++ * The second requirement is that the request pattern of the application is ++ * isochronous, i.e., that, after issuing a request or a batch of requests, ++ * the application stops issuing new requests until all its pending requests ++ * have been completed. After that, the application may issue a new batch, ++ * and so on. ++ * For this reason the next function is invoked to compute ++ * soft_rt_next_start only for applications that meet this requirement, ++ * whereas soft_rt_next_start is set to infinity for applications that do ++ * not. ++ * ++ * Unfortunately, even a greedy application may happen to behave in an ++ * isochronous way if the CPU load is high. In fact, the application may ++ * stop issuing requests while the CPUs are busy serving other processes, ++ * then restart, then stop again for a while, and so on. In addition, if ++ * the disk achieves a low enough throughput with the request pattern ++ * issued by the application (e.g., because the request pattern is random ++ * and/or the device is slow), then the application may meet the above ++ * bandwidth requirement too. To prevent such a greedy application to be ++ * deemed as soft real-time, a further rule is used in the computation of ++ * soft_rt_next_start: soft_rt_next_start must be higher than the current ++ * time plus the maximum time for which the arrival of a request is waited ++ * for when a sync queue becomes idle, namely bfqd->bfq_slice_idle. ++ * This filters out greedy applications, as the latter issue instead their ++ * next request as soon as possible after the last one has been completed ++ * (in contrast, when a batch of requests is completed, a soft real-time ++ * application spends some time processing data). ++ * ++ * Unfortunately, the last filter may easily generate false positives if ++ * only bfqd->bfq_slice_idle is used as a reference time interval and one ++ * or both the following cases occur: ++ * 1) HZ is so low that the duration of a jiffy is comparable to or higher ++ * than bfqd->bfq_slice_idle. This happens, e.g., on slow devices with ++ * HZ=100. ++ * 2) jiffies, instead of increasing at a constant rate, may stop increasing ++ * for a while, then suddenly 'jump' by several units to recover the lost ++ * increments. This seems to happen, e.g., inside virtual machines. ++ * To address this issue, we do not use as a reference time interval just ++ * bfqd->bfq_slice_idle, but bfqd->bfq_slice_idle plus a few jiffies. In ++ * particular we add the minimum number of jiffies for which the filter ++ * seems to be quite precise also in embedded systems and KVM/QEMU virtual ++ * machines. ++ */ ++static inline unsigned long bfq_bfqq_softrt_next_start(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq) ++{ ++ return max(bfqq->last_idle_bklogged + ++ HZ * bfqq->service_from_backlogged / ++ bfqd->bfq_wr_max_softrt_rate, ++ jiffies + bfqq->bfqd->bfq_slice_idle + 4); ++} ++ ++/* ++ * Return the largest-possible time instant such that, for as long as possible, ++ * the current time will be lower than this time instant according to the macro ++ * time_is_before_jiffies(). ++ */ ++static inline unsigned long bfq_infinity_from_now(unsigned long now) ++{ ++ return now + ULONG_MAX / 2; ++} ++ ++/** ++ * bfq_bfqq_expire - expire a queue. ++ * @bfqd: device owning the queue. ++ * @bfqq: the queue to expire. ++ * @compensate: if true, compensate for the time spent idling. ++ * @reason: the reason causing the expiration. ++ * ++ * ++ * If the process associated to the queue is slow (i.e., seeky), or in ++ * case of budget timeout, or, finally, if it is async, we ++ * artificially charge it an entire budget (independently of the ++ * actual service it received). As a consequence, the queue will get ++ * higher timestamps than the correct ones upon reactivation, and ++ * hence it will be rescheduled as if it had received more service ++ * than what it actually received. In the end, this class of processes ++ * will receive less service in proportion to how slowly they consume ++ * their budgets (and hence how seriously they tend to lower the ++ * throughput). ++ * ++ * In contrast, when a queue expires because it has been idling for ++ * too much or because it exhausted its budget, we do not touch the ++ * amount of service it has received. Hence when the queue will be ++ * reactivated and its timestamps updated, the latter will be in sync ++ * with the actual service received by the queue until expiration. ++ * ++ * Charging a full budget to the first type of queues and the exact ++ * service to the others has the effect of using the WF2Q+ policy to ++ * schedule the former on a timeslice basis, without violating the ++ * service domain guarantees of the latter. ++ */ ++static void bfq_bfqq_expire(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq, ++ int compensate, ++ enum bfqq_expiration reason) ++{ ++ int slow; ++ BUG_ON(bfqq != bfqd->in_service_queue); ++ ++ /* Update disk peak rate for autotuning and check whether the ++ * process is slow (see bfq_update_peak_rate). ++ */ ++ slow = bfq_update_peak_rate(bfqd, bfqq, compensate, reason); ++ ++ /* ++ * As above explained, 'punish' slow (i.e., seeky), timed-out ++ * and async queues, to favor sequential sync workloads. ++ * ++ * Processes doing I/O in the slower disk zones will tend to be ++ * slow(er) even if not seeky. Hence, since the estimated peak ++ * rate is actually an average over the disk surface, these ++ * processes may timeout just for bad luck. To avoid punishing ++ * them we do not charge a full budget to a process that ++ * succeeded in consuming at least 2/3 of its budget. ++ */ ++ if (slow || (reason == BFQ_BFQQ_BUDGET_TIMEOUT && ++ bfq_bfqq_budget_left(bfqq) >= bfqq->entity.budget / 3)) ++ bfq_bfqq_charge_full_budget(bfqq); ++ ++ bfqq->service_from_backlogged += bfqq->entity.service; ++ ++ if (BFQQ_SEEKY(bfqq) && reason == BFQ_BFQQ_BUDGET_TIMEOUT && ++ !bfq_bfqq_constantly_seeky(bfqq)) { ++ bfq_mark_bfqq_constantly_seeky(bfqq); ++ if (!blk_queue_nonrot(bfqd->queue)) ++ bfqd->const_seeky_busy_in_flight_queues++; ++ } ++ ++ if (reason == BFQ_BFQQ_TOO_IDLE && ++ bfqq->entity.service <= 2 * bfqq->entity.budget / 10 ) ++ bfq_clear_bfqq_IO_bound(bfqq); ++ ++ if (bfqd->low_latency && bfqq->wr_coeff == 1) ++ bfqq->last_wr_start_finish = jiffies; ++ ++ if (bfqd->low_latency && bfqd->bfq_wr_max_softrt_rate > 0 && ++ RB_EMPTY_ROOT(&bfqq->sort_list)) { ++ /* ++ * If we get here, and there are no outstanding requests, ++ * then the request pattern is isochronous (see the comments ++ * to the function bfq_bfqq_softrt_next_start()). Hence we ++ * can compute soft_rt_next_start. If, instead, the queue ++ * still has outstanding requests, then we have to wait ++ * for the completion of all the outstanding requests to ++ * discover whether the request pattern is actually ++ * isochronous. ++ */ ++ if (bfqq->dispatched == 0) ++ bfqq->soft_rt_next_start = ++ bfq_bfqq_softrt_next_start(bfqd, bfqq); ++ else { ++ /* ++ * The application is still waiting for the ++ * completion of one or more requests: ++ * prevent it from possibly being incorrectly ++ * deemed as soft real-time by setting its ++ * soft_rt_next_start to infinity. In fact, ++ * without this assignment, the application ++ * would be incorrectly deemed as soft ++ * real-time if: ++ * 1) it issued a new request before the ++ * completion of all its in-flight ++ * requests, and ++ * 2) at that time, its soft_rt_next_start ++ * happened to be in the past. ++ */ ++ bfqq->soft_rt_next_start = ++ bfq_infinity_from_now(jiffies); ++ /* ++ * Schedule an update of soft_rt_next_start to when ++ * the task may be discovered to be isochronous. ++ */ ++ bfq_mark_bfqq_softrt_update(bfqq); ++ } ++ } ++ ++ bfq_log_bfqq(bfqd, bfqq, ++ "expire (%d, slow %d, num_disp %d, idle_win %d)", reason, ++ slow, bfqq->dispatched, bfq_bfqq_idle_window(bfqq)); ++ ++ /* ++ * Increase, decrease or leave budget unchanged according to ++ * reason. ++ */ ++ __bfq_bfqq_recalc_budget(bfqd, bfqq, reason); ++ __bfq_bfqq_expire(bfqd, bfqq); ++} ++ ++/* ++ * Budget timeout is not implemented through a dedicated timer, but ++ * just checked on request arrivals and completions, as well as on ++ * idle timer expirations. ++ */ ++static int bfq_bfqq_budget_timeout(struct bfq_queue *bfqq) ++{ ++ if (bfq_bfqq_budget_new(bfqq) || ++ time_before(jiffies, bfqq->budget_timeout)) ++ return 0; ++ return 1; ++} ++ ++/* ++ * If we expire a queue that is waiting for the arrival of a new ++ * request, we may prevent the fictitious timestamp back-shifting that ++ * allows the guarantees of the queue to be preserved (see [1] for ++ * this tricky aspect). Hence we return true only if this condition ++ * does not hold, or if the queue is slow enough to deserve only to be ++ * kicked off for preserving a high throughput. ++*/ ++static inline int bfq_may_expire_for_budg_timeout(struct bfq_queue *bfqq) ++{ ++ bfq_log_bfqq(bfqq->bfqd, bfqq, ++ "may_budget_timeout: wait_request %d left %d timeout %d", ++ bfq_bfqq_wait_request(bfqq), ++ bfq_bfqq_budget_left(bfqq) >= bfqq->entity.budget / 3, ++ bfq_bfqq_budget_timeout(bfqq)); ++ ++ return (!bfq_bfqq_wait_request(bfqq) || ++ bfq_bfqq_budget_left(bfqq) >= bfqq->entity.budget / 3) ++ && ++ bfq_bfqq_budget_timeout(bfqq); ++} ++ ++/* ++ * Device idling is allowed only for the queues for which this function ++ * returns true. For this reason, the return value of this function plays a ++ * critical role for both throughput boosting and service guarantees. The ++ * return value is computed through a logical expression. In this rather ++ * long comment, we try to briefly describe all the details and motivations ++ * behind the components of this logical expression. ++ * ++ * First, the expression may be true only for sync queues. Besides, if ++ * bfqq is also being weight-raised, then the expression always evaluates ++ * to true, as device idling is instrumental for preserving low-latency ++ * guarantees (see [1]). Otherwise, the expression evaluates to true only ++ * if bfqq has a non-null idle window and at least one of the following ++ * two conditions holds. The first condition is that the device is not ++ * performing NCQ, because idling the device most certainly boosts the ++ * throughput if this condition holds and bfqq has been granted a non-null ++ * idle window. The second compound condition is made of the logical AND of ++ * two components. ++ * ++ * The first component is true only if there is no weight-raised busy ++ * queue. This guarantees that the device is not idled for a sync non- ++ * weight-raised queue when there are busy weight-raised queues. The former ++ * is then expired immediately if empty. Combined with the timestamping ++ * rules of BFQ (see [1] for details), this causes sync non-weight-raised ++ * queues to get a lower number of requests served, and hence to ask for a ++ * lower number of requests from the request pool, before the busy weight- ++ * raised queues get served again. ++ * ++ * This is beneficial for the processes associated with weight-raised ++ * queues, when the request pool is saturated (e.g., in the presence of ++ * write hogs). In fact, if the processes associated with the other queues ++ * ask for requests at a lower rate, then weight-raised processes have a ++ * higher probability to get a request from the pool immediately (or at ++ * least soon) when they need one. Hence they have a higher probability to ++ * actually get a fraction of the disk throughput proportional to their ++ * high weight. This is especially true with NCQ-capable drives, which ++ * enqueue several requests in advance and further reorder internally- ++ * queued requests. ++ * ++ * In the end, mistreating non-weight-raised queues when there are busy ++ * weight-raised queues seems to mitigate starvation problems in the ++ * presence of heavy write workloads and NCQ, and hence to guarantee a ++ * higher application and system responsiveness in these hostile scenarios. ++ * ++ * If the first component of the compound condition is instead true, i.e., ++ * there is no weight-raised busy queue, then the second component of the ++ * compound condition takes into account service-guarantee and throughput ++ * issues related to NCQ (recall that the compound condition is evaluated ++ * only if the device is detected as supporting NCQ). ++ * ++ * As for service guarantees, allowing the drive to enqueue more than one ++ * request at a time, and hence delegating de facto final scheduling ++ * decisions to the drive's internal scheduler, causes loss of control on ++ * the actual request service order. In this respect, when the drive is ++ * allowed to enqueue more than one request at a time, the service ++ * distribution enforced by the drive's internal scheduler is likely to ++ * coincide with the desired device-throughput distribution only in the ++ * following, perfectly symmetric, scenario: ++ * 1) all active queues have the same weight, ++ * 2) all active groups at the same level in the groups tree have the same ++ * weight, ++ * 3) all active groups at the same level in the groups tree have the same ++ * number of children. ++ * ++ * Even in such a scenario, sequential I/O may still receive a preferential ++ * treatment, but this is not likely to be a big issue with flash-based ++ * devices, because of their non-dramatic loss of throughput with random ++ * I/O. Things do differ with HDDs, for which additional care is taken, as ++ * explained after completing the discussion for flash-based devices. ++ * ++ * Unfortunately, keeping the necessary state for evaluating exactly the ++ * above symmetry conditions would be quite complex and time-consuming. ++ * Therefore BFQ evaluates instead the following stronger sub-conditions, ++ * for which it is much easier to maintain the needed state: ++ * 1) all active queues have the same weight, ++ * 2) all active groups have the same weight, ++ * 3) all active groups have at most one active child each. ++ * In particular, the last two conditions are always true if hierarchical ++ * support and the cgroups interface are not enabled, hence no state needs ++ * to be maintained in this case. ++ * ++ * According to the above considerations, the second component of the ++ * compound condition evaluates to true if any of the above symmetry ++ * sub-condition does not hold, or the device is not flash-based. Therefore, ++ * if also the first component is true, then idling is allowed for a sync ++ * queue. These are the only sub-conditions considered if the device is ++ * flash-based, as, for such a device, it is sensible to force idling only ++ * for service-guarantee issues. In fact, as for throughput, idling ++ * NCQ-capable flash-based devices would not boost the throughput even ++ * with sequential I/O; rather it would lower the throughput in proportion ++ * to how fast the device is. In the end, (only) if all the three ++ * sub-conditions hold and the device is flash-based, the compound ++ * condition evaluates to false and therefore no idling is performed. ++ * ++ * As already said, things change with a rotational device, where idling ++ * boosts the throughput with sequential I/O (even with NCQ). Hence, for ++ * such a device the second component of the compound condition evaluates ++ * to true also if the following additional sub-condition does not hold: ++ * the queue is constantly seeky. Unfortunately, this different behavior ++ * with respect to flash-based devices causes an additional asymmetry: if ++ * some sync queues enjoy idling and some other sync queues do not, then ++ * the latter get a low share of the device throughput, simply because the ++ * former get many requests served after being set as in service, whereas ++ * the latter do not. As a consequence, to guarantee the desired throughput ++ * distribution, on HDDs the compound expression evaluates to true (and ++ * hence device idling is performed) also if the following last symmetry ++ * condition does not hold: no other queue is benefiting from idling. Also ++ * this last condition is actually replaced with a simpler-to-maintain and ++ * stronger condition: there is no busy queue which is not constantly seeky ++ * (and hence may also benefit from idling). ++ * ++ * To sum up, when all the required symmetry and throughput-boosting ++ * sub-conditions hold, the second component of the compound condition ++ * evaluates to false, and hence no idling is performed. This helps to ++ * keep the drives' internal queues full on NCQ-capable devices, and hence ++ * to boost the throughput, without causing 'almost' any loss of service ++ * guarantees. The 'almost' follows from the fact that, if the internal ++ * queue of one such device is filled while all the sub-conditions hold, ++ * but at some point in time some sub-condition stops to hold, then it may ++ * become impossible to let requests be served in the new desired order ++ * until all the requests already queued in the device have been served. ++ */ ++static inline bool bfq_bfqq_must_not_expire(struct bfq_queue *bfqq) ++{ ++ struct bfq_data *bfqd = bfqq->bfqd; ++#ifdef CONFIG_CGROUP_BFQIO ++#define symmetric_scenario (!bfqd->active_numerous_groups && \ ++ !bfq_differentiated_weights(bfqd)) ++#else ++#define symmetric_scenario (!bfq_differentiated_weights(bfqd)) ++#endif ++#define cond_for_seeky_on_ncq_hdd (bfq_bfqq_constantly_seeky(bfqq) && \ ++ bfqd->busy_in_flight_queues == \ ++ bfqd->const_seeky_busy_in_flight_queues) ++/* ++ * Condition for expiring a non-weight-raised queue (and hence not idling ++ * the device). ++ */ ++#define cond_for_expiring_non_wr (bfqd->hw_tag && \ ++ (bfqd->wr_busy_queues > 0 || \ ++ (symmetric_scenario && \ ++ (blk_queue_nonrot(bfqd->queue) || \ ++ cond_for_seeky_on_ncq_hdd)))) ++ ++ return bfq_bfqq_sync(bfqq) && ++ (bfq_bfqq_IO_bound(bfqq) || bfqq->wr_coeff > 1) && ++ (bfqq->wr_coeff > 1 || ++ (bfq_bfqq_idle_window(bfqq) && ++ !cond_for_expiring_non_wr) ++ ); ++} ++ ++/* ++ * If the in-service queue is empty but sync, and the function ++ * bfq_bfqq_must_not_expire returns true, then: ++ * 1) the queue must remain in service and cannot be expired, and ++ * 2) the disk must be idled to wait for the possible arrival of a new ++ * request for the queue. ++ * See the comments to the function bfq_bfqq_must_not_expire for the reasons ++ * why performing device idling is the best choice to boost the throughput ++ * and preserve service guarantees when bfq_bfqq_must_not_expire itself ++ * returns true. ++ */ ++static inline bool bfq_bfqq_must_idle(struct bfq_queue *bfqq) ++{ ++ struct bfq_data *bfqd = bfqq->bfqd; ++ ++ return RB_EMPTY_ROOT(&bfqq->sort_list) && bfqd->bfq_slice_idle != 0 && ++ bfq_bfqq_must_not_expire(bfqq); ++} ++ ++/* ++ * Select a queue for service. If we have a current queue in service, ++ * check whether to continue servicing it, or retrieve and set a new one. ++ */ ++static struct bfq_queue *bfq_select_queue(struct bfq_data *bfqd) ++{ ++ struct bfq_queue *bfqq; ++ struct request *next_rq; ++ enum bfqq_expiration reason = BFQ_BFQQ_BUDGET_TIMEOUT; ++ ++ bfqq = bfqd->in_service_queue; ++ if (bfqq == NULL) ++ goto new_queue; ++ ++ bfq_log_bfqq(bfqd, bfqq, "select_queue: already in-service queue"); ++ ++ if (bfq_may_expire_for_budg_timeout(bfqq) && ++ !timer_pending(&bfqd->idle_slice_timer) && ++ !bfq_bfqq_must_idle(bfqq)) ++ goto expire; ++ ++ next_rq = bfqq->next_rq; ++ /* ++ * If bfqq has requests queued and it has enough budget left to ++ * serve them, keep the queue, otherwise expire it. ++ */ ++ if (next_rq != NULL) { ++ if (bfq_serv_to_charge(next_rq, bfqq) > ++ bfq_bfqq_budget_left(bfqq)) { ++ reason = BFQ_BFQQ_BUDGET_EXHAUSTED; ++ goto expire; ++ } else { ++ /* ++ * The idle timer may be pending because we may ++ * not disable disk idling even when a new request ++ * arrives. ++ */ ++ if (timer_pending(&bfqd->idle_slice_timer)) { ++ /* ++ * If we get here: 1) at least a new request ++ * has arrived but we have not disabled the ++ * timer because the request was too small, ++ * 2) then the block layer has unplugged ++ * the device, causing the dispatch to be ++ * invoked. ++ * ++ * Since the device is unplugged, now the ++ * requests are probably large enough to ++ * provide a reasonable throughput. ++ * So we disable idling. ++ */ ++ bfq_clear_bfqq_wait_request(bfqq); ++ del_timer(&bfqd->idle_slice_timer); ++ } ++ goto keep_queue; ++ } ++ } ++ ++ /* ++ * No requests pending. If the in-service queue still has requests ++ * in flight (possibly waiting for a completion) or is idling for a ++ * new request, then keep it. ++ */ ++ if (timer_pending(&bfqd->idle_slice_timer) || ++ (bfqq->dispatched != 0 && bfq_bfqq_must_not_expire(bfqq))) { ++ bfqq = NULL; ++ goto keep_queue; ++ } ++ ++ reason = BFQ_BFQQ_NO_MORE_REQUESTS; ++expire: ++ bfq_bfqq_expire(bfqd, bfqq, 0, reason); ++new_queue: ++ bfqq = bfq_set_in_service_queue(bfqd); ++ bfq_log(bfqd, "select_queue: new queue %d returned", ++ bfqq != NULL ? bfqq->pid : 0); ++keep_queue: ++ return bfqq; ++} ++ ++static void bfq_update_wr_data(struct bfq_data *bfqd, struct bfq_queue *bfqq) ++{ ++ struct bfq_entity *entity = &bfqq->entity; ++ if (bfqq->wr_coeff > 1) { /* queue is being weight-raised */ ++ bfq_log_bfqq(bfqd, bfqq, ++ "raising period dur %u/%u msec, old coeff %u, w %d(%d)", ++ jiffies_to_msecs(jiffies - bfqq->last_wr_start_finish), ++ jiffies_to_msecs(bfqq->wr_cur_max_time), ++ bfqq->wr_coeff, ++ bfqq->entity.weight, bfqq->entity.orig_weight); ++ ++ BUG_ON(bfqq != bfqd->in_service_queue && entity->weight != ++ entity->orig_weight * bfqq->wr_coeff); ++ if (entity->ioprio_changed) ++ bfq_log_bfqq(bfqd, bfqq, "WARN: pending prio change"); ++ ++ /* ++ * If too much time has elapsed from the beginning ++ * of this weight-raising period, or the queue has ++ * exceeded the acceptable number of cooperations, ++ * stop it. ++ */ ++ if (bfq_bfqq_cooperations(bfqq) >= bfqd->bfq_coop_thresh || ++ time_is_before_jiffies(bfqq->last_wr_start_finish + ++ bfqq->wr_cur_max_time)) { ++ bfqq->last_wr_start_finish = jiffies; ++ bfq_log_bfqq(bfqd, bfqq, ++ "wrais ending at %lu, rais_max_time %u", ++ bfqq->last_wr_start_finish, ++ jiffies_to_msecs(bfqq->wr_cur_max_time)); ++ bfq_bfqq_end_wr(bfqq); ++ } ++ } ++ /* Update weight both if it must be raised and if it must be lowered */ ++ if ((entity->weight > entity->orig_weight) != (bfqq->wr_coeff > 1)) ++ __bfq_entity_update_weight_prio( ++ bfq_entity_service_tree(entity), ++ entity); ++} ++ ++/* ++ * Dispatch one request from bfqq, moving it to the request queue ++ * dispatch list. ++ */ ++static int bfq_dispatch_request(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq) ++{ ++ int dispatched = 0; ++ struct request *rq; ++ unsigned long service_to_charge; ++ ++ BUG_ON(RB_EMPTY_ROOT(&bfqq->sort_list)); ++ ++ /* Follow expired path, else get first next available. */ ++ rq = bfq_check_fifo(bfqq); ++ if (rq == NULL) ++ rq = bfqq->next_rq; ++ service_to_charge = bfq_serv_to_charge(rq, bfqq); ++ ++ if (service_to_charge > bfq_bfqq_budget_left(bfqq)) { ++ /* ++ * This may happen if the next rq is chosen in fifo order ++ * instead of sector order. The budget is properly ++ * dimensioned to be always sufficient to serve the next ++ * request only if it is chosen in sector order. The reason ++ * is that it would be quite inefficient and little useful ++ * to always make sure that the budget is large enough to ++ * serve even the possible next rq in fifo order. ++ * In fact, requests are seldom served in fifo order. ++ * ++ * Expire the queue for budget exhaustion, and make sure ++ * that the next act_budget is enough to serve the next ++ * request, even if it comes from the fifo expired path. ++ */ ++ bfqq->next_rq = rq; ++ /* ++ * Since this dispatch is failed, make sure that ++ * a new one will be performed ++ */ ++ if (!bfqd->rq_in_driver) ++ bfq_schedule_dispatch(bfqd); ++ goto expire; ++ } ++ ++ /* Finally, insert request into driver dispatch list. */ ++ bfq_bfqq_served(bfqq, service_to_charge); ++ bfq_dispatch_insert(bfqd->queue, rq); ++ ++ bfq_update_wr_data(bfqd, bfqq); ++ ++ bfq_log_bfqq(bfqd, bfqq, ++ "dispatched %u sec req (%llu), budg left %lu", ++ blk_rq_sectors(rq), ++ (long long unsigned)blk_rq_pos(rq), ++ bfq_bfqq_budget_left(bfqq)); ++ ++ dispatched++; ++ ++ if (bfqd->in_service_bic == NULL) { ++ atomic_long_inc(&RQ_BIC(rq)->icq.ioc->refcount); ++ bfqd->in_service_bic = RQ_BIC(rq); ++ } ++ ++ if (bfqd->busy_queues > 1 && ((!bfq_bfqq_sync(bfqq) && ++ dispatched >= bfqd->bfq_max_budget_async_rq) || ++ bfq_class_idle(bfqq))) ++ goto expire; ++ ++ return dispatched; ++ ++expire: ++ bfq_bfqq_expire(bfqd, bfqq, 0, BFQ_BFQQ_BUDGET_EXHAUSTED); ++ return dispatched; ++} ++ ++static int __bfq_forced_dispatch_bfqq(struct bfq_queue *bfqq) ++{ ++ int dispatched = 0; ++ ++ while (bfqq->next_rq != NULL) { ++ bfq_dispatch_insert(bfqq->bfqd->queue, bfqq->next_rq); ++ dispatched++; ++ } ++ ++ BUG_ON(!list_empty(&bfqq->fifo)); ++ return dispatched; ++} ++ ++/* ++ * Drain our current requests. ++ * Used for barriers and when switching io schedulers on-the-fly. ++ */ ++static int bfq_forced_dispatch(struct bfq_data *bfqd) ++{ ++ struct bfq_queue *bfqq, *n; ++ struct bfq_service_tree *st; ++ int dispatched = 0; ++ ++ bfqq = bfqd->in_service_queue; ++ if (bfqq != NULL) ++ __bfq_bfqq_expire(bfqd, bfqq); ++ ++ /* ++ * Loop through classes, and be careful to leave the scheduler ++ * in a consistent state, as feedback mechanisms and vtime ++ * updates cannot be disabled during the process. ++ */ ++ list_for_each_entry_safe(bfqq, n, &bfqd->active_list, bfqq_list) { ++ st = bfq_entity_service_tree(&bfqq->entity); ++ ++ dispatched += __bfq_forced_dispatch_bfqq(bfqq); ++ bfqq->max_budget = bfq_max_budget(bfqd); ++ ++ bfq_forget_idle(st); ++ } ++ ++ BUG_ON(bfqd->busy_queues != 0); ++ ++ return dispatched; ++} ++ ++static int bfq_dispatch_requests(struct request_queue *q, int force) ++{ ++ struct bfq_data *bfqd = q->elevator->elevator_data; ++ struct bfq_queue *bfqq; ++ int max_dispatch; ++ ++ bfq_log(bfqd, "dispatch requests: %d busy queues", bfqd->busy_queues); ++ if (bfqd->busy_queues == 0) ++ return 0; ++ ++ if (unlikely(force)) ++ return bfq_forced_dispatch(bfqd); ++ ++ bfqq = bfq_select_queue(bfqd); ++ if (bfqq == NULL) ++ return 0; ++ ++ max_dispatch = bfqd->bfq_quantum; ++ if (bfq_class_idle(bfqq)) ++ max_dispatch = 1; ++ ++ if (!bfq_bfqq_sync(bfqq)) ++ max_dispatch = bfqd->bfq_max_budget_async_rq; ++ ++ if (bfqq->dispatched >= max_dispatch) { ++ if (bfqd->busy_queues > 1) ++ return 0; ++ if (bfqq->dispatched >= 4 * max_dispatch) ++ return 0; ++ } ++ ++ if (bfqd->sync_flight != 0 && !bfq_bfqq_sync(bfqq)) ++ return 0; ++ ++ bfq_clear_bfqq_wait_request(bfqq); ++ BUG_ON(timer_pending(&bfqd->idle_slice_timer)); ++ ++ if (!bfq_dispatch_request(bfqd, bfqq)) ++ return 0; ++ ++ bfq_log_bfqq(bfqd, bfqq, "dispatched one request of %d (max_disp %d)", ++ bfqq->pid, max_dispatch); ++ ++ return 1; ++} ++ ++/* ++ * Task holds one reference to the queue, dropped when task exits. Each rq ++ * in-flight on this queue also holds a reference, dropped when rq is freed. ++ * ++ * Queue lock must be held here. ++ */ ++static void bfq_put_queue(struct bfq_queue *bfqq) ++{ ++ struct bfq_data *bfqd = bfqq->bfqd; ++ ++ BUG_ON(atomic_read(&bfqq->ref) <= 0); ++ ++ bfq_log_bfqq(bfqd, bfqq, "put_queue: %p %d", bfqq, ++ atomic_read(&bfqq->ref)); ++ if (!atomic_dec_and_test(&bfqq->ref)) ++ return; ++ ++ BUG_ON(rb_first(&bfqq->sort_list) != NULL); ++ BUG_ON(bfqq->allocated[READ] + bfqq->allocated[WRITE] != 0); ++ BUG_ON(bfqq->entity.tree != NULL); ++ BUG_ON(bfq_bfqq_busy(bfqq)); ++ BUG_ON(bfqd->in_service_queue == bfqq); ++ ++ bfq_log_bfqq(bfqd, bfqq, "put_queue: %p freed", bfqq); ++ ++ kmem_cache_free(bfq_pool, bfqq); ++} ++ ++static void bfq_put_cooperator(struct bfq_queue *bfqq) ++{ ++ struct bfq_queue *__bfqq, *next; ++ ++ /* ++ * If this queue was scheduled to merge with another queue, be ++ * sure to drop the reference taken on that queue (and others in ++ * the merge chain). See bfq_setup_merge and bfq_merge_bfqqs. ++ */ ++ __bfqq = bfqq->new_bfqq; ++ while (__bfqq) { ++ if (__bfqq == bfqq) ++ break; ++ next = __bfqq->new_bfqq; ++ bfq_put_queue(__bfqq); ++ __bfqq = next; ++ } ++} ++ ++static void bfq_exit_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq) ++{ ++ if (bfqq == bfqd->in_service_queue) { ++ __bfq_bfqq_expire(bfqd, bfqq); ++ bfq_schedule_dispatch(bfqd); ++ } ++ ++ bfq_log_bfqq(bfqd, bfqq, "exit_bfqq: %p, %d", bfqq, ++ atomic_read(&bfqq->ref)); ++ ++ bfq_put_cooperator(bfqq); ++ ++ bfq_put_queue(bfqq); ++} ++ ++static inline void bfq_init_icq(struct io_cq *icq) ++{ ++ struct bfq_io_cq *bic = icq_to_bic(icq); ++ ++ bic->ttime.last_end_request = jiffies; ++ /* ++ * A newly created bic indicates that the process has just ++ * started doing I/O, and is probably mapping into memory its ++ * executable and libraries: it definitely needs weight raising. ++ * There is however the possibility that the process performs, ++ * for a while, I/O close to some other process. EQM intercepts ++ * this behavior and may merge the queue corresponding to the ++ * process with some other queue, BEFORE the weight of the queue ++ * is raised. Merged queues are not weight-raised (they are assumed ++ * to belong to processes that benefit only from high throughput). ++ * If the merge is basically the consequence of an accident, then ++ * the queue will be split soon and will get back its old weight. ++ * It is then important to write down somewhere that this queue ++ * does need weight raising, even if it did not make it to get its ++ * weight raised before being merged. To this purpose, we overload ++ * the field raising_time_left and assign 1 to it, to mark the queue ++ * as needing weight raising. ++ */ ++ bic->wr_time_left = 1; ++} ++ ++static void bfq_exit_icq(struct io_cq *icq) ++{ ++ struct bfq_io_cq *bic = icq_to_bic(icq); ++ struct bfq_data *bfqd = bic_to_bfqd(bic); ++ ++ if (bic->bfqq[BLK_RW_ASYNC]) { ++ bfq_exit_bfqq(bfqd, bic->bfqq[BLK_RW_ASYNC]); ++ bic->bfqq[BLK_RW_ASYNC] = NULL; ++ } ++ ++ if (bic->bfqq[BLK_RW_SYNC]) { ++ /* ++ * If the bic is using a shared queue, put the reference ++ * taken on the io_context when the bic started using a ++ * shared bfq_queue. ++ */ ++ if (bfq_bfqq_coop(bic->bfqq[BLK_RW_SYNC])) ++ put_io_context(icq->ioc); ++ bfq_exit_bfqq(bfqd, bic->bfqq[BLK_RW_SYNC]); ++ bic->bfqq[BLK_RW_SYNC] = NULL; ++ } ++} ++ ++/* ++ * Update the entity prio values; note that the new values will not ++ * be used until the next (re)activation. ++ */ ++static void bfq_init_prio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic) ++{ ++ struct task_struct *tsk = current; ++ int ioprio_class; ++ ++ if (!bfq_bfqq_prio_changed(bfqq)) ++ return; ++ ++ ioprio_class = IOPRIO_PRIO_CLASS(bic->ioprio); ++ switch (ioprio_class) { ++ default: ++ dev_err(bfqq->bfqd->queue->backing_dev_info.dev, ++ "bfq: bad prio %x\n", ioprio_class); ++ case IOPRIO_CLASS_NONE: ++ /* ++ * No prio set, inherit CPU scheduling settings. ++ */ ++ bfqq->entity.new_ioprio = task_nice_ioprio(tsk); ++ bfqq->entity.new_ioprio_class = task_nice_ioclass(tsk); ++ break; ++ case IOPRIO_CLASS_RT: ++ bfqq->entity.new_ioprio = IOPRIO_PRIO_DATA(bic->ioprio); ++ bfqq->entity.new_ioprio_class = IOPRIO_CLASS_RT; ++ break; ++ case IOPRIO_CLASS_BE: ++ bfqq->entity.new_ioprio = IOPRIO_PRIO_DATA(bic->ioprio); ++ bfqq->entity.new_ioprio_class = IOPRIO_CLASS_BE; ++ break; ++ case IOPRIO_CLASS_IDLE: ++ bfqq->entity.new_ioprio_class = IOPRIO_CLASS_IDLE; ++ bfqq->entity.new_ioprio = 7; ++ bfq_clear_bfqq_idle_window(bfqq); ++ break; ++ } ++ ++ bfqq->entity.ioprio_changed = 1; ++ ++ bfq_clear_bfqq_prio_changed(bfqq); ++} ++ ++static void bfq_changed_ioprio(struct bfq_io_cq *bic) ++{ ++ struct bfq_data *bfqd; ++ struct bfq_queue *bfqq, *new_bfqq; ++ struct bfq_group *bfqg; ++ unsigned long uninitialized_var(flags); ++ int ioprio = bic->icq.ioc->ioprio; ++ ++ bfqd = bfq_get_bfqd_locked(&(bic->icq.q->elevator->elevator_data), ++ &flags); ++ /* ++ * This condition may trigger on a newly created bic, be sure to ++ * drop the lock before returning. ++ */ ++ if (unlikely(bfqd == NULL) || likely(bic->ioprio == ioprio)) ++ goto out; ++ ++ bfqq = bic->bfqq[BLK_RW_ASYNC]; ++ if (bfqq != NULL) { ++ bfqg = container_of(bfqq->entity.sched_data, struct bfq_group, ++ sched_data); ++ new_bfqq = bfq_get_queue(bfqd, bfqg, BLK_RW_ASYNC, bic, ++ GFP_ATOMIC); ++ if (new_bfqq != NULL) { ++ bic->bfqq[BLK_RW_ASYNC] = new_bfqq; ++ bfq_log_bfqq(bfqd, bfqq, ++ "changed_ioprio: bfqq %p %d", ++ bfqq, atomic_read(&bfqq->ref)); ++ bfq_put_queue(bfqq); ++ } ++ } ++ ++ bfqq = bic->bfqq[BLK_RW_SYNC]; ++ if (bfqq != NULL) ++ bfq_mark_bfqq_prio_changed(bfqq); ++ ++ bic->ioprio = ioprio; ++ ++out: ++ bfq_put_bfqd_unlock(bfqd, &flags); ++} ++ ++static void bfq_init_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq, ++ pid_t pid, int is_sync) ++{ ++ RB_CLEAR_NODE(&bfqq->entity.rb_node); ++ INIT_LIST_HEAD(&bfqq->fifo); ++ ++ atomic_set(&bfqq->ref, 0); ++ bfqq->bfqd = bfqd; ++ ++ bfq_mark_bfqq_prio_changed(bfqq); ++ ++ if (is_sync) { ++ if (!bfq_class_idle(bfqq)) ++ bfq_mark_bfqq_idle_window(bfqq); ++ bfq_mark_bfqq_sync(bfqq); ++ } ++ bfq_mark_bfqq_IO_bound(bfqq); ++ ++ /* Tentative initial value to trade off between thr and lat */ ++ bfqq->max_budget = (2 * bfq_max_budget(bfqd)) / 3; ++ bfqq->pid = pid; ++ ++ bfqq->wr_coeff = 1; ++ bfqq->last_wr_start_finish = 0; ++ /* ++ * Set to the value for which bfqq will not be deemed as ++ * soft rt when it becomes backlogged. ++ */ ++ bfqq->soft_rt_next_start = bfq_infinity_from_now(jiffies); ++} ++ ++static struct bfq_queue *bfq_find_alloc_queue(struct bfq_data *bfqd, ++ struct bfq_group *bfqg, ++ int is_sync, ++ struct bfq_io_cq *bic, ++ gfp_t gfp_mask) ++{ ++ struct bfq_queue *bfqq, *new_bfqq = NULL; ++ ++retry: ++ /* bic always exists here */ ++ bfqq = bic_to_bfqq(bic, is_sync); ++ ++ /* ++ * Always try a new alloc if we fall back to the OOM bfqq ++ * originally, since it should just be a temporary situation. ++ */ ++ if (bfqq == NULL || bfqq == &bfqd->oom_bfqq) { ++ bfqq = NULL; ++ if (new_bfqq != NULL) { ++ bfqq = new_bfqq; ++ new_bfqq = NULL; ++ } else if (gfp_mask & __GFP_WAIT) { ++ spin_unlock_irq(bfqd->queue->queue_lock); ++ new_bfqq = kmem_cache_alloc_node(bfq_pool, ++ gfp_mask | __GFP_ZERO, ++ bfqd->queue->node); ++ spin_lock_irq(bfqd->queue->queue_lock); ++ if (new_bfqq != NULL) ++ goto retry; ++ } else { ++ bfqq = kmem_cache_alloc_node(bfq_pool, ++ gfp_mask | __GFP_ZERO, ++ bfqd->queue->node); ++ } ++ ++ if (bfqq != NULL) { ++ bfq_init_bfqq(bfqd, bfqq, current->pid, is_sync); ++ bfq_log_bfqq(bfqd, bfqq, "allocated"); ++ } else { ++ bfqq = &bfqd->oom_bfqq; ++ bfq_log_bfqq(bfqd, bfqq, "using oom bfqq"); ++ } ++ ++ bfq_init_prio_data(bfqq, bic); ++ bfq_init_entity(&bfqq->entity, bfqg); ++ } ++ ++ if (new_bfqq != NULL) ++ kmem_cache_free(bfq_pool, new_bfqq); ++ ++ return bfqq; ++} ++ ++static struct bfq_queue **bfq_async_queue_prio(struct bfq_data *bfqd, ++ struct bfq_group *bfqg, ++ int ioprio_class, int ioprio) ++{ ++ switch (ioprio_class) { ++ case IOPRIO_CLASS_RT: ++ return &bfqg->async_bfqq[0][ioprio]; ++ case IOPRIO_CLASS_NONE: ++ ioprio = IOPRIO_NORM; ++ /* fall through */ ++ case IOPRIO_CLASS_BE: ++ return &bfqg->async_bfqq[1][ioprio]; ++ case IOPRIO_CLASS_IDLE: ++ return &bfqg->async_idle_bfqq; ++ default: ++ BUG(); ++ } ++} ++ ++static struct bfq_queue *bfq_get_queue(struct bfq_data *bfqd, ++ struct bfq_group *bfqg, int is_sync, ++ struct bfq_io_cq *bic, gfp_t gfp_mask) ++{ ++ const int ioprio = IOPRIO_PRIO_DATA(bic->ioprio); ++ const int ioprio_class = IOPRIO_PRIO_CLASS(bic->ioprio); ++ struct bfq_queue **async_bfqq = NULL; ++ struct bfq_queue *bfqq = NULL; ++ ++ if (!is_sync) { ++ async_bfqq = bfq_async_queue_prio(bfqd, bfqg, ioprio_class, ++ ioprio); ++ bfqq = *async_bfqq; ++ } ++ ++ if (bfqq == NULL) ++ bfqq = bfq_find_alloc_queue(bfqd, bfqg, is_sync, bic, gfp_mask); ++ ++ /* ++ * Pin the queue now that it's allocated, scheduler exit will ++ * prune it. ++ */ ++ if (!is_sync && *async_bfqq == NULL) { ++ atomic_inc(&bfqq->ref); ++ bfq_log_bfqq(bfqd, bfqq, "get_queue, bfqq not in async: %p, %d", ++ bfqq, atomic_read(&bfqq->ref)); ++ *async_bfqq = bfqq; ++ } ++ ++ atomic_inc(&bfqq->ref); ++ bfq_log_bfqq(bfqd, bfqq, "get_queue, at end: %p, %d", bfqq, ++ atomic_read(&bfqq->ref)); ++ return bfqq; ++} ++ ++static void bfq_update_io_thinktime(struct bfq_data *bfqd, ++ struct bfq_io_cq *bic) ++{ ++ unsigned long elapsed = jiffies - bic->ttime.last_end_request; ++ unsigned long ttime = min(elapsed, 2UL * bfqd->bfq_slice_idle); ++ ++ bic->ttime.ttime_samples = (7*bic->ttime.ttime_samples + 256) / 8; ++ bic->ttime.ttime_total = (7*bic->ttime.ttime_total + 256*ttime) / 8; ++ bic->ttime.ttime_mean = (bic->ttime.ttime_total + 128) / ++ bic->ttime.ttime_samples; ++} ++ ++static void bfq_update_io_seektime(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq, ++ struct request *rq) ++{ ++ sector_t sdist; ++ u64 total; ++ ++ if (bfqq->last_request_pos < blk_rq_pos(rq)) ++ sdist = blk_rq_pos(rq) - bfqq->last_request_pos; ++ else ++ sdist = bfqq->last_request_pos - blk_rq_pos(rq); ++ ++ /* ++ * Don't allow the seek distance to get too large from the ++ * odd fragment, pagein, etc. ++ */ ++ if (bfqq->seek_samples == 0) /* first request, not really a seek */ ++ sdist = 0; ++ else if (bfqq->seek_samples <= 60) /* second & third seek */ ++ sdist = min(sdist, (bfqq->seek_mean * 4) + 2*1024*1024); ++ else ++ sdist = min(sdist, (bfqq->seek_mean * 4) + 2*1024*64); ++ ++ bfqq->seek_samples = (7*bfqq->seek_samples + 256) / 8; ++ bfqq->seek_total = (7*bfqq->seek_total + (u64)256*sdist) / 8; ++ total = bfqq->seek_total + (bfqq->seek_samples/2); ++ do_div(total, bfqq->seek_samples); ++ bfqq->seek_mean = (sector_t)total; ++ ++ bfq_log_bfqq(bfqd, bfqq, "dist=%llu mean=%llu", (u64)sdist, ++ (u64)bfqq->seek_mean); ++} ++ ++/* ++ * Disable idle window if the process thinks too long or seeks so much that ++ * it doesn't matter. ++ */ ++static void bfq_update_idle_window(struct bfq_data *bfqd, ++ struct bfq_queue *bfqq, ++ struct bfq_io_cq *bic) ++{ ++ int enable_idle; ++ ++ /* Don't idle for async or idle io prio class. */ ++ if (!bfq_bfqq_sync(bfqq) || bfq_class_idle(bfqq)) ++ return; ++ ++ /* Idle window just restored, statistics are meaningless. */ ++ if (bfq_bfqq_just_split(bfqq)) ++ return; ++ ++ enable_idle = bfq_bfqq_idle_window(bfqq); ++ ++ if (atomic_read(&bic->icq.ioc->active_ref) == 0 || ++ bfqd->bfq_slice_idle == 0 || ++ (bfqd->hw_tag && BFQQ_SEEKY(bfqq) && ++ bfqq->wr_coeff == 1)) ++ enable_idle = 0; ++ else if (bfq_sample_valid(bic->ttime.ttime_samples)) { ++ if (bic->ttime.ttime_mean > bfqd->bfq_slice_idle && ++ bfqq->wr_coeff == 1) ++ enable_idle = 0; ++ else ++ enable_idle = 1; ++ } ++ bfq_log_bfqq(bfqd, bfqq, "update_idle_window: enable_idle %d", ++ enable_idle); ++ ++ if (enable_idle) ++ bfq_mark_bfqq_idle_window(bfqq); ++ else ++ bfq_clear_bfqq_idle_window(bfqq); ++} ++ ++/* ++ * Called when a new fs request (rq) is added to bfqq. Check if there's ++ * something we should do about it. ++ */ ++static void bfq_rq_enqueued(struct bfq_data *bfqd, struct bfq_queue *bfqq, ++ struct request *rq) ++{ ++ struct bfq_io_cq *bic = RQ_BIC(rq); ++ ++ if (rq->cmd_flags & REQ_META) ++ bfqq->meta_pending++; ++ ++ bfq_update_io_thinktime(bfqd, bic); ++ bfq_update_io_seektime(bfqd, bfqq, rq); ++ if (!BFQQ_SEEKY(bfqq) && bfq_bfqq_constantly_seeky(bfqq)) { ++ bfq_clear_bfqq_constantly_seeky(bfqq); ++ if (!blk_queue_nonrot(bfqd->queue)) { ++ BUG_ON(!bfqd->const_seeky_busy_in_flight_queues); ++ bfqd->const_seeky_busy_in_flight_queues--; ++ } ++ } ++ if (bfqq->entity.service > bfq_max_budget(bfqd) / 8 || ++ !BFQQ_SEEKY(bfqq)) ++ bfq_update_idle_window(bfqd, bfqq, bic); ++ bfq_clear_bfqq_just_split(bfqq); ++ ++ bfq_log_bfqq(bfqd, bfqq, ++ "rq_enqueued: idle_window=%d (seeky %d, mean %llu)", ++ bfq_bfqq_idle_window(bfqq), BFQQ_SEEKY(bfqq), ++ (long long unsigned)bfqq->seek_mean); ++ ++ bfqq->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq); ++ ++ if (bfqq == bfqd->in_service_queue && bfq_bfqq_wait_request(bfqq)) { ++ int small_req = bfqq->queued[rq_is_sync(rq)] == 1 && ++ blk_rq_sectors(rq) < 32; ++ int budget_timeout = bfq_bfqq_budget_timeout(bfqq); ++ ++ /* ++ * There is just this request queued: if the request ++ * is small and the queue is not to be expired, then ++ * just exit. ++ * ++ * In this way, if the disk is being idled to wait for ++ * a new request from the in-service queue, we avoid ++ * unplugging the device and committing the disk to serve ++ * just a small request. On the contrary, we wait for ++ * the block layer to decide when to unplug the device: ++ * hopefully, new requests will be merged to this one ++ * quickly, then the device will be unplugged and ++ * larger requests will be dispatched. ++ */ ++ if (small_req && !budget_timeout) ++ return; ++ ++ /* ++ * A large enough request arrived, or the queue is to ++ * be expired: in both cases disk idling is to be ++ * stopped, so clear wait_request flag and reset ++ * timer. ++ */ ++ bfq_clear_bfqq_wait_request(bfqq); ++ del_timer(&bfqd->idle_slice_timer); ++ ++ /* ++ * The queue is not empty, because a new request just ++ * arrived. Hence we can safely expire the queue, in ++ * case of budget timeout, without risking that the ++ * timestamps of the queue are not updated correctly. ++ * See [1] for more details. ++ */ ++ if (budget_timeout) ++ bfq_bfqq_expire(bfqd, bfqq, 0, BFQ_BFQQ_BUDGET_TIMEOUT); ++ ++ /* ++ * Let the request rip immediately, or let a new queue be ++ * selected if bfqq has just been expired. ++ */ ++ __blk_run_queue(bfqd->queue); ++ } ++} ++ ++static void bfq_insert_request(struct request_queue *q, struct request *rq) ++{ ++ struct bfq_data *bfqd = q->elevator->elevator_data; ++ struct bfq_queue *bfqq = RQ_BFQQ(rq), *new_bfqq; ++ ++ assert_spin_locked(bfqd->queue->queue_lock); ++ ++ /* ++ * An unplug may trigger a requeue of a request from the device ++ * driver: make sure we are in process context while trying to ++ * merge two bfq_queues. ++ */ ++ if (!in_interrupt()) { ++ new_bfqq = bfq_setup_cooperator(bfqd, bfqq, rq, true); ++ if (new_bfqq != NULL) { ++ if (bic_to_bfqq(RQ_BIC(rq), 1) != bfqq) ++ new_bfqq = bic_to_bfqq(RQ_BIC(rq), 1); ++ /* ++ * Release the request's reference to the old bfqq ++ * and make sure one is taken to the shared queue. ++ */ ++ new_bfqq->allocated[rq_data_dir(rq)]++; ++ bfqq->allocated[rq_data_dir(rq)]--; ++ atomic_inc(&new_bfqq->ref); ++ bfq_put_queue(bfqq); ++ if (bic_to_bfqq(RQ_BIC(rq), 1) == bfqq) ++ bfq_merge_bfqqs(bfqd, RQ_BIC(rq), ++ bfqq, new_bfqq); ++ rq->elv.priv[1] = new_bfqq; ++ bfqq = new_bfqq; ++ } else ++ bfq_bfqq_increase_failed_cooperations(bfqq); ++ } ++ ++ bfq_init_prio_data(bfqq, RQ_BIC(rq)); ++ ++ bfq_add_request(rq); ++ ++ /* ++ * Here a newly-created bfq_queue has already started a weight-raising ++ * period: clear raising_time_left to prevent bfq_bfqq_save_state() ++ * from assigning it a full weight-raising period. See the detailed ++ * comments about this field in bfq_init_icq(). ++ */ ++ if (bfqq->bic != NULL) ++ bfqq->bic->wr_time_left = 0; ++ rq_set_fifo_time(rq, jiffies + bfqd->bfq_fifo_expire[rq_is_sync(rq)]); ++ list_add_tail(&rq->queuelist, &bfqq->fifo); ++ ++ bfq_rq_enqueued(bfqd, bfqq, rq); ++} ++ ++static void bfq_update_hw_tag(struct bfq_data *bfqd) ++{ ++ bfqd->max_rq_in_driver = max(bfqd->max_rq_in_driver, ++ bfqd->rq_in_driver); ++ ++ if (bfqd->hw_tag == 1) ++ return; ++ ++ /* ++ * This sample is valid if the number of outstanding requests ++ * is large enough to allow a queueing behavior. Note that the ++ * sum is not exact, as it's not taking into account deactivated ++ * requests. ++ */ ++ if (bfqd->rq_in_driver + bfqd->queued < BFQ_HW_QUEUE_THRESHOLD) ++ return; ++ ++ if (bfqd->hw_tag_samples++ < BFQ_HW_QUEUE_SAMPLES) ++ return; ++ ++ bfqd->hw_tag = bfqd->max_rq_in_driver > BFQ_HW_QUEUE_THRESHOLD; ++ bfqd->max_rq_in_driver = 0; ++ bfqd->hw_tag_samples = 0; ++} ++ ++static void bfq_completed_request(struct request_queue *q, struct request *rq) ++{ ++ struct bfq_queue *bfqq = RQ_BFQQ(rq); ++ struct bfq_data *bfqd = bfqq->bfqd; ++ bool sync = bfq_bfqq_sync(bfqq); ++ ++ bfq_log_bfqq(bfqd, bfqq, "completed one req with %u sects left (%d)", ++ blk_rq_sectors(rq), sync); ++ ++ bfq_update_hw_tag(bfqd); ++ ++ BUG_ON(!bfqd->rq_in_driver); ++ BUG_ON(!bfqq->dispatched); ++ bfqd->rq_in_driver--; ++ bfqq->dispatched--; ++ ++ if (!bfqq->dispatched && !bfq_bfqq_busy(bfqq)) { ++ bfq_weights_tree_remove(bfqd, &bfqq->entity, ++ &bfqd->queue_weights_tree); ++ if (!blk_queue_nonrot(bfqd->queue)) { ++ BUG_ON(!bfqd->busy_in_flight_queues); ++ bfqd->busy_in_flight_queues--; ++ if (bfq_bfqq_constantly_seeky(bfqq)) { ++ BUG_ON(!bfqd-> ++ const_seeky_busy_in_flight_queues); ++ bfqd->const_seeky_busy_in_flight_queues--; ++ } ++ } ++ } ++ ++ if (sync) { ++ bfqd->sync_flight--; ++ RQ_BIC(rq)->ttime.last_end_request = jiffies; ++ } ++ ++ /* ++ * If we are waiting to discover whether the request pattern of the ++ * task associated with the queue is actually isochronous, and ++ * both requisites for this condition to hold are satisfied, then ++ * compute soft_rt_next_start (see the comments to the function ++ * bfq_bfqq_softrt_next_start()). ++ */ ++ if (bfq_bfqq_softrt_update(bfqq) && bfqq->dispatched == 0 && ++ RB_EMPTY_ROOT(&bfqq->sort_list)) ++ bfqq->soft_rt_next_start = ++ bfq_bfqq_softrt_next_start(bfqd, bfqq); ++ ++ /* ++ * If this is the in-service queue, check if it needs to be expired, ++ * or if we want to idle in case it has no pending requests. ++ */ ++ if (bfqd->in_service_queue == bfqq) { ++ if (bfq_bfqq_budget_new(bfqq)) ++ bfq_set_budget_timeout(bfqd); ++ ++ if (bfq_bfqq_must_idle(bfqq)) { ++ bfq_arm_slice_timer(bfqd); ++ goto out; ++ } else if (bfq_may_expire_for_budg_timeout(bfqq)) ++ bfq_bfqq_expire(bfqd, bfqq, 0, BFQ_BFQQ_BUDGET_TIMEOUT); ++ else if (RB_EMPTY_ROOT(&bfqq->sort_list) && ++ (bfqq->dispatched == 0 || ++ !bfq_bfqq_must_not_expire(bfqq))) ++ bfq_bfqq_expire(bfqd, bfqq, 0, ++ BFQ_BFQQ_NO_MORE_REQUESTS); ++ } ++ ++ if (!bfqd->rq_in_driver) ++ bfq_schedule_dispatch(bfqd); ++ ++out: ++ return; ++} ++ ++static inline int __bfq_may_queue(struct bfq_queue *bfqq) ++{ ++ if (bfq_bfqq_wait_request(bfqq) && bfq_bfqq_must_alloc(bfqq)) { ++ bfq_clear_bfqq_must_alloc(bfqq); ++ return ELV_MQUEUE_MUST; ++ } ++ ++ return ELV_MQUEUE_MAY; ++} ++ ++static int bfq_may_queue(struct request_queue *q, int rw) ++{ ++ struct bfq_data *bfqd = q->elevator->elevator_data; ++ struct task_struct *tsk = current; ++ struct bfq_io_cq *bic; ++ struct bfq_queue *bfqq; ++ ++ /* ++ * Don't force setup of a queue from here, as a call to may_queue ++ * does not necessarily imply that a request actually will be ++ * queued. So just lookup a possibly existing queue, or return ++ * 'may queue' if that fails. ++ */ ++ bic = bfq_bic_lookup(bfqd, tsk->io_context); ++ if (bic == NULL) ++ return ELV_MQUEUE_MAY; ++ ++ bfqq = bic_to_bfqq(bic, rw_is_sync(rw)); ++ if (bfqq != NULL) { ++ bfq_init_prio_data(bfqq, bic); ++ ++ return __bfq_may_queue(bfqq); ++ } ++ ++ return ELV_MQUEUE_MAY; ++} ++ ++/* ++ * Queue lock held here. ++ */ ++static void bfq_put_request(struct request *rq) ++{ ++ struct bfq_queue *bfqq = RQ_BFQQ(rq); ++ ++ if (bfqq != NULL) { ++ const int rw = rq_data_dir(rq); ++ ++ BUG_ON(!bfqq->allocated[rw]); ++ bfqq->allocated[rw]--; ++ ++ rq->elv.priv[0] = NULL; ++ rq->elv.priv[1] = NULL; ++ ++ bfq_log_bfqq(bfqq->bfqd, bfqq, "put_request %p, %d", ++ bfqq, atomic_read(&bfqq->ref)); ++ bfq_put_queue(bfqq); ++ } ++} ++ ++/* ++ * Returns NULL if a new bfqq should be allocated, or the old bfqq if this ++ * was the last process referring to said bfqq. ++ */ ++static struct bfq_queue * ++bfq_split_bfqq(struct bfq_io_cq *bic, struct bfq_queue *bfqq) ++{ ++ bfq_log_bfqq(bfqq->bfqd, bfqq, "splitting queue"); ++ ++ put_io_context(bic->icq.ioc); ++ ++ if (bfqq_process_refs(bfqq) == 1) { ++ bfqq->pid = current->pid; ++ bfq_clear_bfqq_coop(bfqq); ++ bfq_clear_bfqq_split_coop(bfqq); ++ return bfqq; ++ } ++ ++ bic_set_bfqq(bic, NULL, 1); ++ ++ bfq_put_cooperator(bfqq); ++ ++ bfq_put_queue(bfqq); ++ return NULL; ++} ++ ++/* ++ * Allocate bfq data structures associated with this request. ++ */ ++static int bfq_set_request(struct request_queue *q, struct request *rq, ++ struct bio *bio, gfp_t gfp_mask) ++{ ++ struct bfq_data *bfqd = q->elevator->elevator_data; ++ struct bfq_io_cq *bic = icq_to_bic(rq->elv.icq); ++ const int rw = rq_data_dir(rq); ++ const int is_sync = rq_is_sync(rq); ++ struct bfq_queue *bfqq; ++ struct bfq_group *bfqg; ++ unsigned long flags; ++ bool split = false; ++ ++ might_sleep_if(gfp_mask & __GFP_WAIT); ++ ++ bfq_changed_ioprio(bic); ++ ++ spin_lock_irqsave(q->queue_lock, flags); ++ ++ if (bic == NULL) ++ goto queue_fail; ++ ++ bfqg = bfq_bic_update_cgroup(bic); ++ ++new_queue: ++ bfqq = bic_to_bfqq(bic, is_sync); ++ if (bfqq == NULL || bfqq == &bfqd->oom_bfqq) { ++ bfqq = bfq_get_queue(bfqd, bfqg, is_sync, bic, gfp_mask); ++ bic_set_bfqq(bic, bfqq, is_sync); ++ } else { ++ /* If the queue was seeky for too long, break it apart. */ ++ if (bfq_bfqq_coop(bfqq) && bfq_bfqq_split_coop(bfqq)) { ++ bfq_log_bfqq(bfqd, bfqq, "breaking apart bfqq"); ++ bfqq = bfq_split_bfqq(bic, bfqq); ++ split = true; ++ if (!bfqq) ++ goto new_queue; ++ } ++ } ++ ++ bfqq->allocated[rw]++; ++ atomic_inc(&bfqq->ref); ++ bfq_log_bfqq(bfqd, bfqq, "set_request: bfqq %p, %d", bfqq, ++ atomic_read(&bfqq->ref)); ++ ++ rq->elv.priv[0] = bic; ++ rq->elv.priv[1] = bfqq; ++ ++ /* ++ * If a bfq_queue has only one process reference, it is owned ++ * by only one bfq_io_cq: we can set the bic field of the ++ * bfq_queue to the address of that structure. Also, if the ++ * queue has just been split, mark a flag so that the ++ * information is available to the other scheduler hooks. ++ */ ++ if (bfqq_process_refs(bfqq) == 1) { ++ bfqq->bic = bic; ++ if (split) { ++ bfq_mark_bfqq_just_split(bfqq); ++ /* ++ * If the queue has just been split from a shared ++ * queue, restore the idle window and the possible ++ * weight raising period. ++ */ ++ bfq_bfqq_resume_state(bfqq, bic); ++ } ++ } ++ ++ spin_unlock_irqrestore(q->queue_lock, flags); ++ ++ return 0; ++ ++queue_fail: ++ bfq_schedule_dispatch(bfqd); ++ spin_unlock_irqrestore(q->queue_lock, flags); ++ ++ return 1; ++} ++ ++static void bfq_kick_queue(struct work_struct *work) ++{ ++ struct bfq_data *bfqd = ++ container_of(work, struct bfq_data, unplug_work); ++ struct request_queue *q = bfqd->queue; ++ ++ spin_lock_irq(q->queue_lock); ++ __blk_run_queue(q); ++ spin_unlock_irq(q->queue_lock); ++} ++ ++/* ++ * Handler of the expiration of the timer running if the in-service queue ++ * is idling inside its time slice. ++ */ ++static void bfq_idle_slice_timer(unsigned long data) ++{ ++ struct bfq_data *bfqd = (struct bfq_data *)data; ++ struct bfq_queue *bfqq; ++ unsigned long flags; ++ enum bfqq_expiration reason; ++ ++ spin_lock_irqsave(bfqd->queue->queue_lock, flags); ++ ++ bfqq = bfqd->in_service_queue; ++ /* ++ * Theoretical race here: the in-service queue can be NULL or ++ * different from the queue that was idling if the timer handler ++ * spins on the queue_lock and a new request arrives for the ++ * current queue and there is a full dispatch cycle that changes ++ * the in-service queue. This can hardly happen, but in the worst ++ * case we just expire a queue too early. ++ */ ++ if (bfqq != NULL) { ++ bfq_log_bfqq(bfqd, bfqq, "slice_timer expired"); ++ if (bfq_bfqq_budget_timeout(bfqq)) ++ /* ++ * Also here the queue can be safely expired ++ * for budget timeout without wasting ++ * guarantees ++ */ ++ reason = BFQ_BFQQ_BUDGET_TIMEOUT; ++ else if (bfqq->queued[0] == 0 && bfqq->queued[1] == 0) ++ /* ++ * The queue may not be empty upon timer expiration, ++ * because we may not disable the timer when the ++ * first request of the in-service queue arrives ++ * during disk idling. ++ */ ++ reason = BFQ_BFQQ_TOO_IDLE; ++ else ++ goto schedule_dispatch; ++ ++ bfq_bfqq_expire(bfqd, bfqq, 1, reason); ++ } ++ ++schedule_dispatch: ++ bfq_schedule_dispatch(bfqd); ++ ++ spin_unlock_irqrestore(bfqd->queue->queue_lock, flags); ++} ++ ++static void bfq_shutdown_timer_wq(struct bfq_data *bfqd) ++{ ++ del_timer_sync(&bfqd->idle_slice_timer); ++ cancel_work_sync(&bfqd->unplug_work); ++} ++ ++static inline void __bfq_put_async_bfqq(struct bfq_data *bfqd, ++ struct bfq_queue **bfqq_ptr) ++{ ++ struct bfq_group *root_group = bfqd->root_group; ++ struct bfq_queue *bfqq = *bfqq_ptr; ++ ++ bfq_log(bfqd, "put_async_bfqq: %p", bfqq); ++ if (bfqq != NULL) { ++ bfq_bfqq_move(bfqd, bfqq, &bfqq->entity, root_group); ++ bfq_log_bfqq(bfqd, bfqq, "put_async_bfqq: putting %p, %d", ++ bfqq, atomic_read(&bfqq->ref)); ++ bfq_put_queue(bfqq); ++ *bfqq_ptr = NULL; ++ } ++} ++ ++/* ++ * Release all the bfqg references to its async queues. If we are ++ * deallocating the group these queues may still contain requests, so ++ * we reparent them to the root cgroup (i.e., the only one that will ++ * exist for sure until all the requests on a device are gone). ++ */ ++static void bfq_put_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg) ++{ ++ int i, j; ++ ++ for (i = 0; i < 2; i++) ++ for (j = 0; j < IOPRIO_BE_NR; j++) ++ __bfq_put_async_bfqq(bfqd, &bfqg->async_bfqq[i][j]); ++ ++ __bfq_put_async_bfqq(bfqd, &bfqg->async_idle_bfqq); ++} ++ ++static void bfq_exit_queue(struct elevator_queue *e) ++{ ++ struct bfq_data *bfqd = e->elevator_data; ++ struct request_queue *q = bfqd->queue; ++ struct bfq_queue *bfqq, *n; ++ ++ bfq_shutdown_timer_wq(bfqd); ++ ++ spin_lock_irq(q->queue_lock); ++ ++ BUG_ON(bfqd->in_service_queue != NULL); ++ list_for_each_entry_safe(bfqq, n, &bfqd->idle_list, bfqq_list) ++ bfq_deactivate_bfqq(bfqd, bfqq, 0); ++ ++ bfq_disconnect_groups(bfqd); ++ spin_unlock_irq(q->queue_lock); ++ ++ bfq_shutdown_timer_wq(bfqd); ++ ++ synchronize_rcu(); ++ ++ BUG_ON(timer_pending(&bfqd->idle_slice_timer)); ++ ++ bfq_free_root_group(bfqd); ++ kfree(bfqd); ++} ++ ++static int bfq_init_queue(struct request_queue *q, struct elevator_type *e) ++{ ++ struct bfq_group *bfqg; ++ struct bfq_data *bfqd; ++ struct elevator_queue *eq; ++ ++ eq = elevator_alloc(q, e); ++ if (eq == NULL) ++ return -ENOMEM; ++ ++ bfqd = kzalloc_node(sizeof(*bfqd), GFP_KERNEL, q->node); ++ if (bfqd == NULL) { ++ kobject_put(&eq->kobj); ++ return -ENOMEM; ++ } ++ eq->elevator_data = bfqd; ++ ++ /* ++ * Our fallback bfqq if bfq_find_alloc_queue() runs into OOM issues. ++ * Grab a permanent reference to it, so that the normal code flow ++ * will not attempt to free it. ++ */ ++ bfq_init_bfqq(bfqd, &bfqd->oom_bfqq, 1, 0); ++ atomic_inc(&bfqd->oom_bfqq.ref); ++ ++ bfqd->queue = q; ++ ++ spin_lock_irq(q->queue_lock); ++ q->elevator = eq; ++ spin_unlock_irq(q->queue_lock); ++ ++ bfqg = bfq_alloc_root_group(bfqd, q->node); ++ if (bfqg == NULL) { ++ kfree(bfqd); ++ kobject_put(&eq->kobj); ++ return -ENOMEM; ++ } ++ ++ bfqd->root_group = bfqg; ++#ifdef CONFIG_CGROUP_BFQIO ++ bfqd->active_numerous_groups = 0; ++#endif ++ ++ init_timer(&bfqd->idle_slice_timer); ++ bfqd->idle_slice_timer.function = bfq_idle_slice_timer; ++ bfqd->idle_slice_timer.data = (unsigned long)bfqd; ++ ++ bfqd->rq_pos_tree = RB_ROOT; ++ bfqd->queue_weights_tree = RB_ROOT; ++ bfqd->group_weights_tree = RB_ROOT; ++ ++ INIT_WORK(&bfqd->unplug_work, bfq_kick_queue); ++ ++ INIT_LIST_HEAD(&bfqd->active_list); ++ INIT_LIST_HEAD(&bfqd->idle_list); ++ ++ bfqd->hw_tag = -1; ++ ++ bfqd->bfq_max_budget = bfq_default_max_budget; ++ ++ bfqd->bfq_quantum = bfq_quantum; ++ bfqd->bfq_fifo_expire[0] = bfq_fifo_expire[0]; ++ bfqd->bfq_fifo_expire[1] = bfq_fifo_expire[1]; ++ bfqd->bfq_back_max = bfq_back_max; ++ bfqd->bfq_back_penalty = bfq_back_penalty; ++ bfqd->bfq_slice_idle = bfq_slice_idle; ++ bfqd->bfq_class_idle_last_service = 0; ++ bfqd->bfq_max_budget_async_rq = bfq_max_budget_async_rq; ++ bfqd->bfq_timeout[BLK_RW_ASYNC] = bfq_timeout_async; ++ bfqd->bfq_timeout[BLK_RW_SYNC] = bfq_timeout_sync; ++ ++ bfqd->bfq_coop_thresh = 2; ++ bfqd->bfq_failed_cooperations = 7000; ++ bfqd->bfq_requests_within_timer = 120; ++ ++ bfqd->low_latency = true; ++ ++ bfqd->bfq_wr_coeff = 20; ++ bfqd->bfq_wr_rt_max_time = msecs_to_jiffies(300); ++ bfqd->bfq_wr_max_time = 0; ++ bfqd->bfq_wr_min_idle_time = msecs_to_jiffies(2000); ++ bfqd->bfq_wr_min_inter_arr_async = msecs_to_jiffies(500); ++ bfqd->bfq_wr_max_softrt_rate = 7000; /* ++ * Approximate rate required ++ * to playback or record a ++ * high-definition compressed ++ * video. ++ */ ++ bfqd->wr_busy_queues = 0; ++ bfqd->busy_in_flight_queues = 0; ++ bfqd->const_seeky_busy_in_flight_queues = 0; ++ ++ /* ++ * Begin by assuming, optimistically, that the device peak rate is ++ * equal to the highest reference rate. ++ */ ++ bfqd->RT_prod = R_fast[blk_queue_nonrot(bfqd->queue)] * ++ T_fast[blk_queue_nonrot(bfqd->queue)]; ++ bfqd->peak_rate = R_fast[blk_queue_nonrot(bfqd->queue)]; ++ bfqd->device_speed = BFQ_BFQD_FAST; ++ ++ return 0; ++} ++ ++static void bfq_slab_kill(void) ++{ ++ if (bfq_pool != NULL) ++ kmem_cache_destroy(bfq_pool); ++} ++ ++static int __init bfq_slab_setup(void) ++{ ++ bfq_pool = KMEM_CACHE(bfq_queue, 0); ++ if (bfq_pool == NULL) ++ return -ENOMEM; ++ return 0; ++} ++ ++static ssize_t bfq_var_show(unsigned int var, char *page) ++{ ++ return sprintf(page, "%d\n", var); ++} ++ ++static ssize_t bfq_var_store(unsigned long *var, const char *page, ++ size_t count) ++{ ++ unsigned long new_val; ++ int ret = kstrtoul(page, 10, &new_val); ++ ++ if (ret == 0) ++ *var = new_val; ++ ++ return count; ++} ++ ++static ssize_t bfq_wr_max_time_show(struct elevator_queue *e, char *page) ++{ ++ struct bfq_data *bfqd = e->elevator_data; ++ return sprintf(page, "%d\n", bfqd->bfq_wr_max_time > 0 ? ++ jiffies_to_msecs(bfqd->bfq_wr_max_time) : ++ jiffies_to_msecs(bfq_wr_duration(bfqd))); ++} ++ ++static ssize_t bfq_weights_show(struct elevator_queue *e, char *page) ++{ ++ struct bfq_queue *bfqq; ++ struct bfq_data *bfqd = e->elevator_data; ++ ssize_t num_char = 0; ++ ++ num_char += sprintf(page + num_char, "Tot reqs queued %d\n\n", ++ bfqd->queued); ++ ++ spin_lock_irq(bfqd->queue->queue_lock); ++ ++ num_char += sprintf(page + num_char, "Active:\n"); ++ list_for_each_entry(bfqq, &bfqd->active_list, bfqq_list) { ++ num_char += sprintf(page + num_char, ++ "pid%d: weight %hu, nr_queued %d %d, dur %d/%u\n", ++ bfqq->pid, ++ bfqq->entity.weight, ++ bfqq->queued[0], ++ bfqq->queued[1], ++ jiffies_to_msecs(jiffies - bfqq->last_wr_start_finish), ++ jiffies_to_msecs(bfqq->wr_cur_max_time)); ++ } ++ ++ num_char += sprintf(page + num_char, "Idle:\n"); ++ list_for_each_entry(bfqq, &bfqd->idle_list, bfqq_list) { ++ num_char += sprintf(page + num_char, ++ "pid%d: weight %hu, dur %d/%u\n", ++ bfqq->pid, ++ bfqq->entity.weight, ++ jiffies_to_msecs(jiffies - ++ bfqq->last_wr_start_finish), ++ jiffies_to_msecs(bfqq->wr_cur_max_time)); ++ } ++ ++ spin_unlock_irq(bfqd->queue->queue_lock); ++ ++ return num_char; ++} ++ ++#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ ++static ssize_t __FUNC(struct elevator_queue *e, char *page) \ ++{ \ ++ struct bfq_data *bfqd = e->elevator_data; \ ++ unsigned int __data = __VAR; \ ++ if (__CONV) \ ++ __data = jiffies_to_msecs(__data); \ ++ return bfq_var_show(__data, (page)); \ ++} ++SHOW_FUNCTION(bfq_quantum_show, bfqd->bfq_quantum, 0); ++SHOW_FUNCTION(bfq_fifo_expire_sync_show, bfqd->bfq_fifo_expire[1], 1); ++SHOW_FUNCTION(bfq_fifo_expire_async_show, bfqd->bfq_fifo_expire[0], 1); ++SHOW_FUNCTION(bfq_back_seek_max_show, bfqd->bfq_back_max, 0); ++SHOW_FUNCTION(bfq_back_seek_penalty_show, bfqd->bfq_back_penalty, 0); ++SHOW_FUNCTION(bfq_slice_idle_show, bfqd->bfq_slice_idle, 1); ++SHOW_FUNCTION(bfq_max_budget_show, bfqd->bfq_user_max_budget, 0); ++SHOW_FUNCTION(bfq_max_budget_async_rq_show, ++ bfqd->bfq_max_budget_async_rq, 0); ++SHOW_FUNCTION(bfq_timeout_sync_show, bfqd->bfq_timeout[BLK_RW_SYNC], 1); ++SHOW_FUNCTION(bfq_timeout_async_show, bfqd->bfq_timeout[BLK_RW_ASYNC], 1); ++SHOW_FUNCTION(bfq_low_latency_show, bfqd->low_latency, 0); ++SHOW_FUNCTION(bfq_wr_coeff_show, bfqd->bfq_wr_coeff, 0); ++SHOW_FUNCTION(bfq_wr_rt_max_time_show, bfqd->bfq_wr_rt_max_time, 1); ++SHOW_FUNCTION(bfq_wr_min_idle_time_show, bfqd->bfq_wr_min_idle_time, 1); ++SHOW_FUNCTION(bfq_wr_min_inter_arr_async_show, bfqd->bfq_wr_min_inter_arr_async, ++ 1); ++SHOW_FUNCTION(bfq_wr_max_softrt_rate_show, bfqd->bfq_wr_max_softrt_rate, 0); ++#undef SHOW_FUNCTION ++ ++#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ ++static ssize_t \ ++__FUNC(struct elevator_queue *e, const char *page, size_t count) \ ++{ \ ++ struct bfq_data *bfqd = e->elevator_data; \ ++ unsigned long uninitialized_var(__data); \ ++ int ret = bfq_var_store(&__data, (page), count); \ ++ if (__data < (MIN)) \ ++ __data = (MIN); \ ++ else if (__data > (MAX)) \ ++ __data = (MAX); \ ++ if (__CONV) \ ++ *(__PTR) = msecs_to_jiffies(__data); \ ++ else \ ++ *(__PTR) = __data; \ ++ return ret; \ ++} ++STORE_FUNCTION(bfq_quantum_store, &bfqd->bfq_quantum, 1, INT_MAX, 0); ++STORE_FUNCTION(bfq_fifo_expire_sync_store, &bfqd->bfq_fifo_expire[1], 1, ++ INT_MAX, 1); ++STORE_FUNCTION(bfq_fifo_expire_async_store, &bfqd->bfq_fifo_expire[0], 1, ++ INT_MAX, 1); ++STORE_FUNCTION(bfq_back_seek_max_store, &bfqd->bfq_back_max, 0, INT_MAX, 0); ++STORE_FUNCTION(bfq_back_seek_penalty_store, &bfqd->bfq_back_penalty, 1, ++ INT_MAX, 0); ++STORE_FUNCTION(bfq_slice_idle_store, &bfqd->bfq_slice_idle, 0, INT_MAX, 1); ++STORE_FUNCTION(bfq_max_budget_async_rq_store, &bfqd->bfq_max_budget_async_rq, ++ 1, INT_MAX, 0); ++STORE_FUNCTION(bfq_timeout_async_store, &bfqd->bfq_timeout[BLK_RW_ASYNC], 0, ++ INT_MAX, 1); ++STORE_FUNCTION(bfq_wr_coeff_store, &bfqd->bfq_wr_coeff, 1, INT_MAX, 0); ++STORE_FUNCTION(bfq_wr_max_time_store, &bfqd->bfq_wr_max_time, 0, INT_MAX, 1); ++STORE_FUNCTION(bfq_wr_rt_max_time_store, &bfqd->bfq_wr_rt_max_time, 0, INT_MAX, ++ 1); ++STORE_FUNCTION(bfq_wr_min_idle_time_store, &bfqd->bfq_wr_min_idle_time, 0, ++ INT_MAX, 1); ++STORE_FUNCTION(bfq_wr_min_inter_arr_async_store, ++ &bfqd->bfq_wr_min_inter_arr_async, 0, INT_MAX, 1); ++STORE_FUNCTION(bfq_wr_max_softrt_rate_store, &bfqd->bfq_wr_max_softrt_rate, 0, ++ INT_MAX, 0); ++#undef STORE_FUNCTION ++ ++/* do nothing for the moment */ ++static ssize_t bfq_weights_store(struct elevator_queue *e, ++ const char *page, size_t count) ++{ ++ return count; ++} ++ ++static inline unsigned long bfq_estimated_max_budget(struct bfq_data *bfqd) ++{ ++ u64 timeout = jiffies_to_msecs(bfqd->bfq_timeout[BLK_RW_SYNC]); ++ ++ if (bfqd->peak_rate_samples >= BFQ_PEAK_RATE_SAMPLES) ++ return bfq_calc_max_budget(bfqd->peak_rate, timeout); ++ else ++ return bfq_default_max_budget; ++} ++ ++static ssize_t bfq_max_budget_store(struct elevator_queue *e, ++ const char *page, size_t count) ++{ ++ struct bfq_data *bfqd = e->elevator_data; ++ unsigned long uninitialized_var(__data); ++ int ret = bfq_var_store(&__data, (page), count); ++ ++ if (__data == 0) ++ bfqd->bfq_max_budget = bfq_estimated_max_budget(bfqd); ++ else { ++ if (__data > INT_MAX) ++ __data = INT_MAX; ++ bfqd->bfq_max_budget = __data; ++ } ++ ++ bfqd->bfq_user_max_budget = __data; ++ ++ return ret; ++} ++ ++static ssize_t bfq_timeout_sync_store(struct elevator_queue *e, ++ const char *page, size_t count) ++{ ++ struct bfq_data *bfqd = e->elevator_data; ++ unsigned long uninitialized_var(__data); ++ int ret = bfq_var_store(&__data, (page), count); ++ ++ if (__data < 1) ++ __data = 1; ++ else if (__data > INT_MAX) ++ __data = INT_MAX; ++ ++ bfqd->bfq_timeout[BLK_RW_SYNC] = msecs_to_jiffies(__data); ++ if (bfqd->bfq_user_max_budget == 0) ++ bfqd->bfq_max_budget = bfq_estimated_max_budget(bfqd); ++ ++ return ret; ++} ++ ++static ssize_t bfq_low_latency_store(struct elevator_queue *e, ++ const char *page, size_t count) ++{ ++ struct bfq_data *bfqd = e->elevator_data; ++ unsigned long uninitialized_var(__data); ++ int ret = bfq_var_store(&__data, (page), count); ++ ++ if (__data > 1) ++ __data = 1; ++ if (__data == 0 && bfqd->low_latency != 0) ++ bfq_end_wr(bfqd); ++ bfqd->low_latency = __data; ++ ++ return ret; ++} ++ ++#define BFQ_ATTR(name) \ ++ __ATTR(name, S_IRUGO|S_IWUSR, bfq_##name##_show, bfq_##name##_store) ++ ++static struct elv_fs_entry bfq_attrs[] = { ++ BFQ_ATTR(quantum), ++ BFQ_ATTR(fifo_expire_sync), ++ BFQ_ATTR(fifo_expire_async), ++ BFQ_ATTR(back_seek_max), ++ BFQ_ATTR(back_seek_penalty), ++ BFQ_ATTR(slice_idle), ++ BFQ_ATTR(max_budget), ++ BFQ_ATTR(max_budget_async_rq), ++ BFQ_ATTR(timeout_sync), ++ BFQ_ATTR(timeout_async), ++ BFQ_ATTR(low_latency), ++ BFQ_ATTR(wr_coeff), ++ BFQ_ATTR(wr_max_time), ++ BFQ_ATTR(wr_rt_max_time), ++ BFQ_ATTR(wr_min_idle_time), ++ BFQ_ATTR(wr_min_inter_arr_async), ++ BFQ_ATTR(wr_max_softrt_rate), ++ BFQ_ATTR(weights), ++ __ATTR_NULL ++}; ++ ++static struct elevator_type iosched_bfq = { ++ .ops = { ++ .elevator_merge_fn = bfq_merge, ++ .elevator_merged_fn = bfq_merged_request, ++ .elevator_merge_req_fn = bfq_merged_requests, ++ .elevator_allow_merge_fn = bfq_allow_merge, ++ .elevator_dispatch_fn = bfq_dispatch_requests, ++ .elevator_add_req_fn = bfq_insert_request, ++ .elevator_activate_req_fn = bfq_activate_request, ++ .elevator_deactivate_req_fn = bfq_deactivate_request, ++ .elevator_completed_req_fn = bfq_completed_request, ++ .elevator_former_req_fn = elv_rb_former_request, ++ .elevator_latter_req_fn = elv_rb_latter_request, ++ .elevator_init_icq_fn = bfq_init_icq, ++ .elevator_exit_icq_fn = bfq_exit_icq, ++ .elevator_set_req_fn = bfq_set_request, ++ .elevator_put_req_fn = bfq_put_request, ++ .elevator_may_queue_fn = bfq_may_queue, ++ .elevator_init_fn = bfq_init_queue, ++ .elevator_exit_fn = bfq_exit_queue, ++ }, ++ .icq_size = sizeof(struct bfq_io_cq), ++ .icq_align = __alignof__(struct bfq_io_cq), ++ .elevator_attrs = bfq_attrs, ++ .elevator_name = "bfq", ++ .elevator_owner = THIS_MODULE, ++}; ++ ++static int __init bfq_init(void) ++{ ++ /* ++ * Can be 0 on HZ < 1000 setups. ++ */ ++ if (bfq_slice_idle == 0) ++ bfq_slice_idle = 1; ++ ++ if (bfq_timeout_async == 0) ++ bfq_timeout_async = 1; ++ ++ if (bfq_slab_setup()) ++ return -ENOMEM; ++ ++ /* ++ * Times to load large popular applications for the typical systems ++ * installed on the reference devices (see the comments before the ++ * definitions of the two arrays). ++ */ ++ T_slow[0] = msecs_to_jiffies(2600); ++ T_slow[1] = msecs_to_jiffies(1000); ++ T_fast[0] = msecs_to_jiffies(5500); ++ T_fast[1] = msecs_to_jiffies(2000); ++ ++ /* ++ * Thresholds that determine the switch between speed classes (see ++ * the comments before the definition of the array). ++ */ ++ device_speed_thresh[0] = (R_fast[0] + R_slow[0]) / 2; ++ device_speed_thresh[1] = (R_fast[1] + R_slow[1]) / 2; ++ ++ elv_register(&iosched_bfq); ++ pr_info("BFQ I/O-scheduler version: v7r5"); ++ ++ return 0; ++} ++ ++static void __exit bfq_exit(void) ++{ ++ elv_unregister(&iosched_bfq); ++ bfq_slab_kill(); ++} ++ ++module_init(bfq_init); ++module_exit(bfq_exit); ++ ++MODULE_AUTHOR("Fabio Checconi, Paolo Valente"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.40.orig/block/bfq-sched.c linux-3.14.40/block/bfq-sched.c +--- linux-3.14.40.orig/block/bfq-sched.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/block/bfq-sched.c 2015-05-01 14:57:58.355427001 -0500 +@@ -0,0 +1,1179 @@ ++/* ++ * BFQ: Hierarchical B-WF2Q+ scheduler. ++ * ++ * Based on ideas and code from CFQ: ++ * Copyright (C) 2003 Jens Axboe ++ * ++ * Copyright (C) 2008 Fabio Checconi ++ * Paolo Valente ++ * ++ * Copyright (C) 2010 Paolo Valente ++ */ ++ ++#ifdef CONFIG_CGROUP_BFQIO ++#define for_each_entity(entity) \ ++ for (; entity != NULL; entity = entity->parent) ++ ++#define for_each_entity_safe(entity, parent) \ ++ for (; entity && ({ parent = entity->parent; 1; }); entity = parent) ++ ++static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd, ++ int extract, ++ struct bfq_data *bfqd); ++ ++static inline void bfq_update_budget(struct bfq_entity *next_in_service) ++{ ++ struct bfq_entity *bfqg_entity; ++ struct bfq_group *bfqg; ++ struct bfq_sched_data *group_sd; ++ ++ BUG_ON(next_in_service == NULL); ++ ++ group_sd = next_in_service->sched_data; ++ ++ bfqg = container_of(group_sd, struct bfq_group, sched_data); ++ /* ++ * bfq_group's my_entity field is not NULL only if the group ++ * is not the root group. We must not touch the root entity ++ * as it must never become an in-service entity. ++ */ ++ bfqg_entity = bfqg->my_entity; ++ if (bfqg_entity != NULL) ++ bfqg_entity->budget = next_in_service->budget; ++} ++ ++static int bfq_update_next_in_service(struct bfq_sched_data *sd) ++{ ++ struct bfq_entity *next_in_service; ++ ++ if (sd->in_service_entity != NULL) ++ /* will update/requeue at the end of service */ ++ return 0; ++ ++ /* ++ * NOTE: this can be improved in many ways, such as returning ++ * 1 (and thus propagating upwards the update) only when the ++ * budget changes, or caching the bfqq that will be scheduled ++ * next from this subtree. By now we worry more about ++ * correctness than about performance... ++ */ ++ next_in_service = bfq_lookup_next_entity(sd, 0, NULL); ++ sd->next_in_service = next_in_service; ++ ++ if (next_in_service != NULL) ++ bfq_update_budget(next_in_service); ++ ++ return 1; ++} ++ ++static inline void bfq_check_next_in_service(struct bfq_sched_data *sd, ++ struct bfq_entity *entity) ++{ ++ BUG_ON(sd->next_in_service != entity); ++} ++#else ++#define for_each_entity(entity) \ ++ for (; entity != NULL; entity = NULL) ++ ++#define for_each_entity_safe(entity, parent) \ ++ for (parent = NULL; entity != NULL; entity = parent) ++ ++static inline int bfq_update_next_in_service(struct bfq_sched_data *sd) ++{ ++ return 0; ++} ++ ++static inline void bfq_check_next_in_service(struct bfq_sched_data *sd, ++ struct bfq_entity *entity) ++{ ++} ++ ++static inline void bfq_update_budget(struct bfq_entity *next_in_service) ++{ ++} ++#endif ++ ++/* ++ * Shift for timestamp calculations. This actually limits the maximum ++ * service allowed in one timestamp delta (small shift values increase it), ++ * the maximum total weight that can be used for the queues in the system ++ * (big shift values increase it), and the period of virtual time ++ * wraparounds. ++ */ ++#define WFQ_SERVICE_SHIFT 22 ++ ++/** ++ * bfq_gt - compare two timestamps. ++ * @a: first ts. ++ * @b: second ts. ++ * ++ * Return @a > @b, dealing with wrapping correctly. ++ */ ++static inline int bfq_gt(u64 a, u64 b) ++{ ++ return (s64)(a - b) > 0; ++} ++ ++static inline struct bfq_queue *bfq_entity_to_bfqq(struct bfq_entity *entity) ++{ ++ struct bfq_queue *bfqq = NULL; ++ ++ BUG_ON(entity == NULL); ++ ++ if (entity->my_sched_data == NULL) ++ bfqq = container_of(entity, struct bfq_queue, entity); ++ ++ return bfqq; ++} ++ ++ ++/** ++ * bfq_delta - map service into the virtual time domain. ++ * @service: amount of service. ++ * @weight: scale factor (weight of an entity or weight sum). ++ */ ++static inline u64 bfq_delta(unsigned long service, ++ unsigned long weight) ++{ ++ u64 d = (u64)service << WFQ_SERVICE_SHIFT; ++ ++ do_div(d, weight); ++ return d; ++} ++ ++/** ++ * bfq_calc_finish - assign the finish time to an entity. ++ * @entity: the entity to act upon. ++ * @service: the service to be charged to the entity. ++ */ ++static inline void bfq_calc_finish(struct bfq_entity *entity, ++ unsigned long service) ++{ ++ struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); ++ ++ BUG_ON(entity->weight == 0); ++ ++ entity->finish = entity->start + ++ bfq_delta(service, entity->weight); ++ ++ if (bfqq != NULL) { ++ bfq_log_bfqq(bfqq->bfqd, bfqq, ++ "calc_finish: serv %lu, w %d", ++ service, entity->weight); ++ bfq_log_bfqq(bfqq->bfqd, bfqq, ++ "calc_finish: start %llu, finish %llu, delta %llu", ++ entity->start, entity->finish, ++ bfq_delta(service, entity->weight)); ++ } ++} ++ ++/** ++ * bfq_entity_of - get an entity from a node. ++ * @node: the node field of the entity. ++ * ++ * Convert a node pointer to the relative entity. This is used only ++ * to simplify the logic of some functions and not as the generic ++ * conversion mechanism because, e.g., in the tree walking functions, ++ * the check for a %NULL value would be redundant. ++ */ ++static inline struct bfq_entity *bfq_entity_of(struct rb_node *node) ++{ ++ struct bfq_entity *entity = NULL; ++ ++ if (node != NULL) ++ entity = rb_entry(node, struct bfq_entity, rb_node); ++ ++ return entity; ++} ++ ++/** ++ * bfq_extract - remove an entity from a tree. ++ * @root: the tree root. ++ * @entity: the entity to remove. ++ */ ++static inline void bfq_extract(struct rb_root *root, ++ struct bfq_entity *entity) ++{ ++ BUG_ON(entity->tree != root); ++ ++ entity->tree = NULL; ++ rb_erase(&entity->rb_node, root); ++} ++ ++/** ++ * bfq_idle_extract - extract an entity from the idle tree. ++ * @st: the service tree of the owning @entity. ++ * @entity: the entity being removed. ++ */ ++static void bfq_idle_extract(struct bfq_service_tree *st, ++ struct bfq_entity *entity) ++{ ++ struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); ++ struct rb_node *next; ++ ++ BUG_ON(entity->tree != &st->idle); ++ ++ if (entity == st->first_idle) { ++ next = rb_next(&entity->rb_node); ++ st->first_idle = bfq_entity_of(next); ++ } ++ ++ if (entity == st->last_idle) { ++ next = rb_prev(&entity->rb_node); ++ st->last_idle = bfq_entity_of(next); ++ } ++ ++ bfq_extract(&st->idle, entity); ++ ++ if (bfqq != NULL) ++ list_del(&bfqq->bfqq_list); ++} ++ ++/** ++ * bfq_insert - generic tree insertion. ++ * @root: tree root. ++ * @entity: entity to insert. ++ * ++ * This is used for the idle and the active tree, since they are both ++ * ordered by finish time. ++ */ ++static void bfq_insert(struct rb_root *root, struct bfq_entity *entity) ++{ ++ struct bfq_entity *entry; ++ struct rb_node **node = &root->rb_node; ++ struct rb_node *parent = NULL; ++ ++ BUG_ON(entity->tree != NULL); ++ ++ while (*node != NULL) { ++ parent = *node; ++ entry = rb_entry(parent, struct bfq_entity, rb_node); ++ ++ if (bfq_gt(entry->finish, entity->finish)) ++ node = &parent->rb_left; ++ else ++ node = &parent->rb_right; ++ } ++ ++ rb_link_node(&entity->rb_node, parent, node); ++ rb_insert_color(&entity->rb_node, root); ++ ++ entity->tree = root; ++} ++ ++/** ++ * bfq_update_min - update the min_start field of a entity. ++ * @entity: the entity to update. ++ * @node: one of its children. ++ * ++ * This function is called when @entity may store an invalid value for ++ * min_start due to updates to the active tree. The function assumes ++ * that the subtree rooted at @node (which may be its left or its right ++ * child) has a valid min_start value. ++ */ ++static inline void bfq_update_min(struct bfq_entity *entity, ++ struct rb_node *node) ++{ ++ struct bfq_entity *child; ++ ++ if (node != NULL) { ++ child = rb_entry(node, struct bfq_entity, rb_node); ++ if (bfq_gt(entity->min_start, child->min_start)) ++ entity->min_start = child->min_start; ++ } ++} ++ ++/** ++ * bfq_update_active_node - recalculate min_start. ++ * @node: the node to update. ++ * ++ * @node may have changed position or one of its children may have moved, ++ * this function updates its min_start value. The left and right subtrees ++ * are assumed to hold a correct min_start value. ++ */ ++static inline void bfq_update_active_node(struct rb_node *node) ++{ ++ struct bfq_entity *entity = rb_entry(node, struct bfq_entity, rb_node); ++ ++ entity->min_start = entity->start; ++ bfq_update_min(entity, node->rb_right); ++ bfq_update_min(entity, node->rb_left); ++} ++ ++/** ++ * bfq_update_active_tree - update min_start for the whole active tree. ++ * @node: the starting node. ++ * ++ * @node must be the deepest modified node after an update. This function ++ * updates its min_start using the values held by its children, assuming ++ * that they did not change, and then updates all the nodes that may have ++ * changed in the path to the root. The only nodes that may have changed ++ * are the ones in the path or their siblings. ++ */ ++static void bfq_update_active_tree(struct rb_node *node) ++{ ++ struct rb_node *parent; ++ ++up: ++ bfq_update_active_node(node); ++ ++ parent = rb_parent(node); ++ if (parent == NULL) ++ return; ++ ++ if (node == parent->rb_left && parent->rb_right != NULL) ++ bfq_update_active_node(parent->rb_right); ++ else if (parent->rb_left != NULL) ++ bfq_update_active_node(parent->rb_left); ++ ++ node = parent; ++ goto up; ++} ++ ++static void bfq_weights_tree_add(struct bfq_data *bfqd, ++ struct bfq_entity *entity, ++ struct rb_root *root); ++ ++static void bfq_weights_tree_remove(struct bfq_data *bfqd, ++ struct bfq_entity *entity, ++ struct rb_root *root); ++ ++ ++/** ++ * bfq_active_insert - insert an entity in the active tree of its ++ * group/device. ++ * @st: the service tree of the entity. ++ * @entity: the entity being inserted. ++ * ++ * The active tree is ordered by finish time, but an extra key is kept ++ * per each node, containing the minimum value for the start times of ++ * its children (and the node itself), so it's possible to search for ++ * the eligible node with the lowest finish time in logarithmic time. ++ */ ++static void bfq_active_insert(struct bfq_service_tree *st, ++ struct bfq_entity *entity) ++{ ++ struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); ++ struct rb_node *node = &entity->rb_node; ++#ifdef CONFIG_CGROUP_BFQIO ++ struct bfq_sched_data *sd = NULL; ++ struct bfq_group *bfqg = NULL; ++ struct bfq_data *bfqd = NULL; ++#endif ++ ++ bfq_insert(&st->active, entity); ++ ++ if (node->rb_left != NULL) ++ node = node->rb_left; ++ else if (node->rb_right != NULL) ++ node = node->rb_right; ++ ++ bfq_update_active_tree(node); ++ ++#ifdef CONFIG_CGROUP_BFQIO ++ sd = entity->sched_data; ++ bfqg = container_of(sd, struct bfq_group, sched_data); ++ BUG_ON(!bfqg); ++ bfqd = (struct bfq_data *)bfqg->bfqd; ++#endif ++ if (bfqq != NULL) ++ list_add(&bfqq->bfqq_list, &bfqq->bfqd->active_list); ++#ifdef CONFIG_CGROUP_BFQIO ++ else { /* bfq_group */ ++ BUG_ON(!bfqd); ++ bfq_weights_tree_add(bfqd, entity, &bfqd->group_weights_tree); ++ } ++ if (bfqg != bfqd->root_group) { ++ BUG_ON(!bfqg); ++ BUG_ON(!bfqd); ++ bfqg->active_entities++; ++ if (bfqg->active_entities == 2) ++ bfqd->active_numerous_groups++; ++ } ++#endif ++} ++ ++/** ++ * bfq_ioprio_to_weight - calc a weight from an ioprio. ++ * @ioprio: the ioprio value to convert. ++ */ ++static inline unsigned short bfq_ioprio_to_weight(int ioprio) ++{ ++ BUG_ON(ioprio < 0 || ioprio >= IOPRIO_BE_NR); ++ return IOPRIO_BE_NR - ioprio; ++} ++ ++/** ++ * bfq_weight_to_ioprio - calc an ioprio from a weight. ++ * @weight: the weight value to convert. ++ * ++ * To preserve as mush as possible the old only-ioprio user interface, ++ * 0 is used as an escape ioprio value for weights (numerically) equal or ++ * larger than IOPRIO_BE_NR ++ */ ++static inline unsigned short bfq_weight_to_ioprio(int weight) ++{ ++ BUG_ON(weight < BFQ_MIN_WEIGHT || weight > BFQ_MAX_WEIGHT); ++ return IOPRIO_BE_NR - weight < 0 ? 0 : IOPRIO_BE_NR - weight; ++} ++ ++static inline void bfq_get_entity(struct bfq_entity *entity) ++{ ++ struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); ++ ++ if (bfqq != NULL) { ++ atomic_inc(&bfqq->ref); ++ bfq_log_bfqq(bfqq->bfqd, bfqq, "get_entity: %p %d", ++ bfqq, atomic_read(&bfqq->ref)); ++ } ++} ++ ++/** ++ * bfq_find_deepest - find the deepest node that an extraction can modify. ++ * @node: the node being removed. ++ * ++ * Do the first step of an extraction in an rb tree, looking for the ++ * node that will replace @node, and returning the deepest node that ++ * the following modifications to the tree can touch. If @node is the ++ * last node in the tree return %NULL. ++ */ ++static struct rb_node *bfq_find_deepest(struct rb_node *node) ++{ ++ struct rb_node *deepest; ++ ++ if (node->rb_right == NULL && node->rb_left == NULL) ++ deepest = rb_parent(node); ++ else if (node->rb_right == NULL) ++ deepest = node->rb_left; ++ else if (node->rb_left == NULL) ++ deepest = node->rb_right; ++ else { ++ deepest = rb_next(node); ++ if (deepest->rb_right != NULL) ++ deepest = deepest->rb_right; ++ else if (rb_parent(deepest) != node) ++ deepest = rb_parent(deepest); ++ } ++ ++ return deepest; ++} ++ ++/** ++ * bfq_active_extract - remove an entity from the active tree. ++ * @st: the service_tree containing the tree. ++ * @entity: the entity being removed. ++ */ ++static void bfq_active_extract(struct bfq_service_tree *st, ++ struct bfq_entity *entity) ++{ ++ struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); ++ struct rb_node *node; ++#ifdef CONFIG_CGROUP_BFQIO ++ struct bfq_sched_data *sd = NULL; ++ struct bfq_group *bfqg = NULL; ++ struct bfq_data *bfqd = NULL; ++#endif ++ ++ node = bfq_find_deepest(&entity->rb_node); ++ bfq_extract(&st->active, entity); ++ ++ if (node != NULL) ++ bfq_update_active_tree(node); ++ ++#ifdef CONFIG_CGROUP_BFQIO ++ sd = entity->sched_data; ++ bfqg = container_of(sd, struct bfq_group, sched_data); ++ BUG_ON(!bfqg); ++ bfqd = (struct bfq_data *)bfqg->bfqd; ++#endif ++ if (bfqq != NULL) ++ list_del(&bfqq->bfqq_list); ++#ifdef CONFIG_CGROUP_BFQIO ++ else { /* bfq_group */ ++ BUG_ON(!bfqd); ++ bfq_weights_tree_remove(bfqd, entity, ++ &bfqd->group_weights_tree); ++ } ++ if (bfqg != bfqd->root_group) { ++ BUG_ON(!bfqg); ++ BUG_ON(!bfqd); ++ BUG_ON(!bfqg->active_entities); ++ bfqg->active_entities--; ++ if (bfqg->active_entities == 1) { ++ BUG_ON(!bfqd->active_numerous_groups); ++ bfqd->active_numerous_groups--; ++ } ++ } ++#endif ++} ++ ++/** ++ * bfq_idle_insert - insert an entity into the idle tree. ++ * @st: the service tree containing the tree. ++ * @entity: the entity to insert. ++ */ ++static void bfq_idle_insert(struct bfq_service_tree *st, ++ struct bfq_entity *entity) ++{ ++ struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); ++ struct bfq_entity *first_idle = st->first_idle; ++ struct bfq_entity *last_idle = st->last_idle; ++ ++ if (first_idle == NULL || bfq_gt(first_idle->finish, entity->finish)) ++ st->first_idle = entity; ++ if (last_idle == NULL || bfq_gt(entity->finish, last_idle->finish)) ++ st->last_idle = entity; ++ ++ bfq_insert(&st->idle, entity); ++ ++ if (bfqq != NULL) ++ list_add(&bfqq->bfqq_list, &bfqq->bfqd->idle_list); ++} ++ ++/** ++ * bfq_forget_entity - remove an entity from the wfq trees. ++ * @st: the service tree. ++ * @entity: the entity being removed. ++ * ++ * Update the device status and forget everything about @entity, putting ++ * the device reference to it, if it is a queue. Entities belonging to ++ * groups are not refcounted. ++ */ ++static void bfq_forget_entity(struct bfq_service_tree *st, ++ struct bfq_entity *entity) ++{ ++ struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); ++ struct bfq_sched_data *sd; ++ ++ BUG_ON(!entity->on_st); ++ ++ entity->on_st = 0; ++ st->wsum -= entity->weight; ++ if (bfqq != NULL) { ++ sd = entity->sched_data; ++ bfq_log_bfqq(bfqq->bfqd, bfqq, "forget_entity: %p %d", ++ bfqq, atomic_read(&bfqq->ref)); ++ bfq_put_queue(bfqq); ++ } ++} ++ ++/** ++ * bfq_put_idle_entity - release the idle tree ref of an entity. ++ * @st: service tree for the entity. ++ * @entity: the entity being released. ++ */ ++static void bfq_put_idle_entity(struct bfq_service_tree *st, ++ struct bfq_entity *entity) ++{ ++ bfq_idle_extract(st, entity); ++ bfq_forget_entity(st, entity); ++} ++ ++/** ++ * bfq_forget_idle - update the idle tree if necessary. ++ * @st: the service tree to act upon. ++ * ++ * To preserve the global O(log N) complexity we only remove one entry here; ++ * as the idle tree will not grow indefinitely this can be done safely. ++ */ ++static void bfq_forget_idle(struct bfq_service_tree *st) ++{ ++ struct bfq_entity *first_idle = st->first_idle; ++ struct bfq_entity *last_idle = st->last_idle; ++ ++ if (RB_EMPTY_ROOT(&st->active) && last_idle != NULL && ++ !bfq_gt(last_idle->finish, st->vtime)) { ++ /* ++ * Forget the whole idle tree, increasing the vtime past ++ * the last finish time of idle entities. ++ */ ++ st->vtime = last_idle->finish; ++ } ++ ++ if (first_idle != NULL && !bfq_gt(first_idle->finish, st->vtime)) ++ bfq_put_idle_entity(st, first_idle); ++} ++ ++static struct bfq_service_tree * ++__bfq_entity_update_weight_prio(struct bfq_service_tree *old_st, ++ struct bfq_entity *entity) ++{ ++ struct bfq_service_tree *new_st = old_st; ++ ++ if (entity->ioprio_changed) { ++ struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity); ++ unsigned short prev_weight, new_weight; ++ struct bfq_data *bfqd = NULL; ++ struct rb_root *root; ++#ifdef CONFIG_CGROUP_BFQIO ++ struct bfq_sched_data *sd; ++ struct bfq_group *bfqg; ++#endif ++ ++ if (bfqq != NULL) ++ bfqd = bfqq->bfqd; ++#ifdef CONFIG_CGROUP_BFQIO ++ else { ++ sd = entity->my_sched_data; ++ bfqg = container_of(sd, struct bfq_group, sched_data); ++ BUG_ON(!bfqg); ++ bfqd = (struct bfq_data *)bfqg->bfqd; ++ BUG_ON(!bfqd); ++ } ++#endif ++ ++ BUG_ON(old_st->wsum < entity->weight); ++ old_st->wsum -= entity->weight; ++ ++ if (entity->new_weight != entity->orig_weight) { ++ entity->orig_weight = entity->new_weight; ++ entity->ioprio = ++ bfq_weight_to_ioprio(entity->orig_weight); ++ } else if (entity->new_ioprio != entity->ioprio) { ++ entity->ioprio = entity->new_ioprio; ++ entity->orig_weight = ++ bfq_ioprio_to_weight(entity->ioprio); ++ } else ++ entity->new_weight = entity->orig_weight = ++ bfq_ioprio_to_weight(entity->ioprio); ++ ++ entity->ioprio_class = entity->new_ioprio_class; ++ entity->ioprio_changed = 0; ++ ++ /* ++ * NOTE: here we may be changing the weight too early, ++ * this will cause unfairness. The correct approach ++ * would have required additional complexity to defer ++ * weight changes to the proper time instants (i.e., ++ * when entity->finish <= old_st->vtime). ++ */ ++ new_st = bfq_entity_service_tree(entity); ++ ++ prev_weight = entity->weight; ++ new_weight = entity->orig_weight * ++ (bfqq != NULL ? bfqq->wr_coeff : 1); ++ /* ++ * If the weight of the entity changes, remove the entity ++ * from its old weight counter (if there is a counter ++ * associated with the entity), and add it to the counter ++ * associated with its new weight. ++ */ ++ if (prev_weight != new_weight) { ++ root = bfqq ? &bfqd->queue_weights_tree : ++ &bfqd->group_weights_tree; ++ bfq_weights_tree_remove(bfqd, entity, root); ++ } ++ entity->weight = new_weight; ++ /* ++ * Add the entity to its weights tree only if it is ++ * not associated with a weight-raised queue. ++ */ ++ if (prev_weight != new_weight && ++ (bfqq ? bfqq->wr_coeff == 1 : 1)) ++ /* If we get here, root has been initialized. */ ++ bfq_weights_tree_add(bfqd, entity, root); ++ ++ new_st->wsum += entity->weight; ++ ++ if (new_st != old_st) ++ entity->start = new_st->vtime; ++ } ++ ++ return new_st; ++} ++ ++/** ++ * bfq_bfqq_served - update the scheduler status after selection for ++ * service. ++ * @bfqq: the queue being served. ++ * @served: bytes to transfer. ++ * ++ * NOTE: this can be optimized, as the timestamps of upper level entities ++ * are synchronized every time a new bfqq is selected for service. By now, ++ * we keep it to better check consistency. ++ */ ++static void bfq_bfqq_served(struct bfq_queue *bfqq, unsigned long served) ++{ ++ struct bfq_entity *entity = &bfqq->entity; ++ struct bfq_service_tree *st; ++ ++ for_each_entity(entity) { ++ st = bfq_entity_service_tree(entity); ++ ++ entity->service += served; ++ BUG_ON(entity->service > entity->budget); ++ BUG_ON(st->wsum == 0); ++ ++ st->vtime += bfq_delta(served, st->wsum); ++ bfq_forget_idle(st); ++ } ++ bfq_log_bfqq(bfqq->bfqd, bfqq, "bfqq_served %lu secs", served); ++} ++ ++/** ++ * bfq_bfqq_charge_full_budget - set the service to the entity budget. ++ * @bfqq: the queue that needs a service update. ++ * ++ * When it's not possible to be fair in the service domain, because ++ * a queue is not consuming its budget fast enough (the meaning of ++ * fast depends on the timeout parameter), we charge it a full ++ * budget. In this way we should obtain a sort of time-domain ++ * fairness among all the seeky/slow queues. ++ */ ++static inline void bfq_bfqq_charge_full_budget(struct bfq_queue *bfqq) ++{ ++ struct bfq_entity *entity = &bfqq->entity; ++ ++ bfq_log_bfqq(bfqq->bfqd, bfqq, "charge_full_budget"); ++ ++ bfq_bfqq_served(bfqq, entity->budget - entity->service); ++} ++ ++/** ++ * __bfq_activate_entity - activate an entity. ++ * @entity: the entity being activated. ++ * ++ * Called whenever an entity is activated, i.e., it is not active and one ++ * of its children receives a new request, or has to be reactivated due to ++ * budget exhaustion. It uses the current budget of the entity (and the ++ * service received if @entity is active) of the queue to calculate its ++ * timestamps. ++ */ ++static void __bfq_activate_entity(struct bfq_entity *entity) ++{ ++ struct bfq_sched_data *sd = entity->sched_data; ++ struct bfq_service_tree *st = bfq_entity_service_tree(entity); ++ ++ if (entity == sd->in_service_entity) { ++ BUG_ON(entity->tree != NULL); ++ /* ++ * If we are requeueing the current entity we have ++ * to take care of not charging to it service it has ++ * not received. ++ */ ++ bfq_calc_finish(entity, entity->service); ++ entity->start = entity->finish; ++ sd->in_service_entity = NULL; ++ } else if (entity->tree == &st->active) { ++ /* ++ * Requeueing an entity due to a change of some ++ * next_in_service entity below it. We reuse the ++ * old start time. ++ */ ++ bfq_active_extract(st, entity); ++ } else if (entity->tree == &st->idle) { ++ /* ++ * Must be on the idle tree, bfq_idle_extract() will ++ * check for that. ++ */ ++ bfq_idle_extract(st, entity); ++ entity->start = bfq_gt(st->vtime, entity->finish) ? ++ st->vtime : entity->finish; ++ } else { ++ /* ++ * The finish time of the entity may be invalid, and ++ * it is in the past for sure, otherwise the queue ++ * would have been on the idle tree. ++ */ ++ entity->start = st->vtime; ++ st->wsum += entity->weight; ++ bfq_get_entity(entity); ++ ++ BUG_ON(entity->on_st); ++ entity->on_st = 1; ++ } ++ ++ st = __bfq_entity_update_weight_prio(st, entity); ++ bfq_calc_finish(entity, entity->budget); ++ bfq_active_insert(st, entity); ++} ++ ++/** ++ * bfq_activate_entity - activate an entity and its ancestors if necessary. ++ * @entity: the entity to activate. ++ * ++ * Activate @entity and all the entities on the path from it to the root. ++ */ ++static void bfq_activate_entity(struct bfq_entity *entity) ++{ ++ struct bfq_sched_data *sd; ++ ++ for_each_entity(entity) { ++ __bfq_activate_entity(entity); ++ ++ sd = entity->sched_data; ++ if (!bfq_update_next_in_service(sd)) ++ /* ++ * No need to propagate the activation to the ++ * upper entities, as they will be updated when ++ * the in-service entity is rescheduled. ++ */ ++ break; ++ } ++} ++ ++/** ++ * __bfq_deactivate_entity - deactivate an entity from its service tree. ++ * @entity: the entity to deactivate. ++ * @requeue: if false, the entity will not be put into the idle tree. ++ * ++ * Deactivate an entity, independently from its previous state. If the ++ * entity was not on a service tree just return, otherwise if it is on ++ * any scheduler tree, extract it from that tree, and if necessary ++ * and if the caller did not specify @requeue, put it on the idle tree. ++ * ++ * Return %1 if the caller should update the entity hierarchy, i.e., ++ * if the entity was in service or if it was the next_in_service for ++ * its sched_data; return %0 otherwise. ++ */ ++static int __bfq_deactivate_entity(struct bfq_entity *entity, int requeue) ++{ ++ struct bfq_sched_data *sd = entity->sched_data; ++ struct bfq_service_tree *st = bfq_entity_service_tree(entity); ++ int was_in_service = entity == sd->in_service_entity; ++ int ret = 0; ++ ++ if (!entity->on_st) ++ return 0; ++ ++ BUG_ON(was_in_service && entity->tree != NULL); ++ ++ if (was_in_service) { ++ bfq_calc_finish(entity, entity->service); ++ sd->in_service_entity = NULL; ++ } else if (entity->tree == &st->active) ++ bfq_active_extract(st, entity); ++ else if (entity->tree == &st->idle) ++ bfq_idle_extract(st, entity); ++ else if (entity->tree != NULL) ++ BUG(); ++ ++ if (was_in_service || sd->next_in_service == entity) ++ ret = bfq_update_next_in_service(sd); ++ ++ if (!requeue || !bfq_gt(entity->finish, st->vtime)) ++ bfq_forget_entity(st, entity); ++ else ++ bfq_idle_insert(st, entity); ++ ++ BUG_ON(sd->in_service_entity == entity); ++ BUG_ON(sd->next_in_service == entity); ++ ++ return ret; ++} ++ ++/** ++ * bfq_deactivate_entity - deactivate an entity. ++ * @entity: the entity to deactivate. ++ * @requeue: true if the entity can be put on the idle tree ++ */ ++static void bfq_deactivate_entity(struct bfq_entity *entity, int requeue) ++{ ++ struct bfq_sched_data *sd; ++ struct bfq_entity *parent; ++ ++ for_each_entity_safe(entity, parent) { ++ sd = entity->sched_data; ++ ++ if (!__bfq_deactivate_entity(entity, requeue)) ++ /* ++ * The parent entity is still backlogged, and ++ * we don't need to update it as it is still ++ * in service. ++ */ ++ break; ++ ++ if (sd->next_in_service != NULL) ++ /* ++ * The parent entity is still backlogged and ++ * the budgets on the path towards the root ++ * need to be updated. ++ */ ++ goto update; ++ ++ /* ++ * If we reach there the parent is no more backlogged and ++ * we want to propagate the dequeue upwards. ++ */ ++ requeue = 1; ++ } ++ ++ return; ++ ++update: ++ entity = parent; ++ for_each_entity(entity) { ++ __bfq_activate_entity(entity); ++ ++ sd = entity->sched_data; ++ if (!bfq_update_next_in_service(sd)) ++ break; ++ } ++} ++ ++/** ++ * bfq_update_vtime - update vtime if necessary. ++ * @st: the service tree to act upon. ++ * ++ * If necessary update the service tree vtime to have at least one ++ * eligible entity, skipping to its start time. Assumes that the ++ * active tree of the device is not empty. ++ * ++ * NOTE: this hierarchical implementation updates vtimes quite often, ++ * we may end up with reactivated processes getting timestamps after a ++ * vtime skip done because we needed a ->first_active entity on some ++ * intermediate node. ++ */ ++static void bfq_update_vtime(struct bfq_service_tree *st) ++{ ++ struct bfq_entity *entry; ++ struct rb_node *node = st->active.rb_node; ++ ++ entry = rb_entry(node, struct bfq_entity, rb_node); ++ if (bfq_gt(entry->min_start, st->vtime)) { ++ st->vtime = entry->min_start; ++ bfq_forget_idle(st); ++ } ++} ++ ++/** ++ * bfq_first_active_entity - find the eligible entity with ++ * the smallest finish time ++ * @st: the service tree to select from. ++ * ++ * This function searches the first schedulable entity, starting from the ++ * root of the tree and going on the left every time on this side there is ++ * a subtree with at least one eligible (start >= vtime) entity. The path on ++ * the right is followed only if a) the left subtree contains no eligible ++ * entities and b) no eligible entity has been found yet. ++ */ ++static struct bfq_entity *bfq_first_active_entity(struct bfq_service_tree *st) ++{ ++ struct bfq_entity *entry, *first = NULL; ++ struct rb_node *node = st->active.rb_node; ++ ++ while (node != NULL) { ++ entry = rb_entry(node, struct bfq_entity, rb_node); ++left: ++ if (!bfq_gt(entry->start, st->vtime)) ++ first = entry; ++ ++ BUG_ON(bfq_gt(entry->min_start, st->vtime)); ++ ++ if (node->rb_left != NULL) { ++ entry = rb_entry(node->rb_left, ++ struct bfq_entity, rb_node); ++ if (!bfq_gt(entry->min_start, st->vtime)) { ++ node = node->rb_left; ++ goto left; ++ } ++ } ++ if (first != NULL) ++ break; ++ node = node->rb_right; ++ } ++ ++ BUG_ON(first == NULL && !RB_EMPTY_ROOT(&st->active)); ++ return first; ++} ++ ++/** ++ * __bfq_lookup_next_entity - return the first eligible entity in @st. ++ * @st: the service tree. ++ * ++ * Update the virtual time in @st and return the first eligible entity ++ * it contains. ++ */ ++static struct bfq_entity *__bfq_lookup_next_entity(struct bfq_service_tree *st, ++ bool force) ++{ ++ struct bfq_entity *entity, *new_next_in_service = NULL; ++ ++ if (RB_EMPTY_ROOT(&st->active)) ++ return NULL; ++ ++ bfq_update_vtime(st); ++ entity = bfq_first_active_entity(st); ++ BUG_ON(bfq_gt(entity->start, st->vtime)); ++ ++ /* ++ * If the chosen entity does not match with the sched_data's ++ * next_in_service and we are forcedly serving the IDLE priority ++ * class tree, bubble up budget update. ++ */ ++ if (unlikely(force && entity != entity->sched_data->next_in_service)) { ++ new_next_in_service = entity; ++ for_each_entity(new_next_in_service) ++ bfq_update_budget(new_next_in_service); ++ } ++ ++ return entity; ++} ++ ++/** ++ * bfq_lookup_next_entity - return the first eligible entity in @sd. ++ * @sd: the sched_data. ++ * @extract: if true the returned entity will be also extracted from @sd. ++ * ++ * NOTE: since we cache the next_in_service entity at each level of the ++ * hierarchy, the complexity of the lookup can be decreased with ++ * absolutely no effort just returning the cached next_in_service value; ++ * we prefer to do full lookups to test the consistency of * the data ++ * structures. ++ */ ++static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd, ++ int extract, ++ struct bfq_data *bfqd) ++{ ++ struct bfq_service_tree *st = sd->service_tree; ++ struct bfq_entity *entity; ++ int i = 0; ++ ++ BUG_ON(sd->in_service_entity != NULL); ++ ++ if (bfqd != NULL && ++ jiffies - bfqd->bfq_class_idle_last_service > BFQ_CL_IDLE_TIMEOUT) { ++ entity = __bfq_lookup_next_entity(st + BFQ_IOPRIO_CLASSES - 1, ++ true); ++ if (entity != NULL) { ++ i = BFQ_IOPRIO_CLASSES - 1; ++ bfqd->bfq_class_idle_last_service = jiffies; ++ sd->next_in_service = entity; ++ } ++ } ++ for (; i < BFQ_IOPRIO_CLASSES; i++) { ++ entity = __bfq_lookup_next_entity(st + i, false); ++ if (entity != NULL) { ++ if (extract) { ++ bfq_check_next_in_service(sd, entity); ++ bfq_active_extract(st + i, entity); ++ sd->in_service_entity = entity; ++ sd->next_in_service = NULL; ++ } ++ break; ++ } ++ } ++ ++ return entity; ++} ++ ++/* ++ * Get next queue for service. ++ */ ++static struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd) ++{ ++ struct bfq_entity *entity = NULL; ++ struct bfq_sched_data *sd; ++ struct bfq_queue *bfqq; ++ ++ BUG_ON(bfqd->in_service_queue != NULL); ++ ++ if (bfqd->busy_queues == 0) ++ return NULL; ++ ++ sd = &bfqd->root_group->sched_data; ++ for (; sd != NULL; sd = entity->my_sched_data) { ++ entity = bfq_lookup_next_entity(sd, 1, bfqd); ++ BUG_ON(entity == NULL); ++ entity->service = 0; ++ } ++ ++ bfqq = bfq_entity_to_bfqq(entity); ++ BUG_ON(bfqq == NULL); ++ ++ return bfqq; ++} ++ ++static void __bfq_bfqd_reset_in_service(struct bfq_data *bfqd) ++{ ++ if (bfqd->in_service_bic != NULL) { ++ put_io_context(bfqd->in_service_bic->icq.ioc); ++ bfqd->in_service_bic = NULL; ++ } ++ ++ bfqd->in_service_queue = NULL; ++ del_timer(&bfqd->idle_slice_timer); ++} ++ ++static void bfq_deactivate_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq, ++ int requeue) ++{ ++ struct bfq_entity *entity = &bfqq->entity; ++ ++ if (bfqq == bfqd->in_service_queue) ++ __bfq_bfqd_reset_in_service(bfqd); ++ ++ bfq_deactivate_entity(entity, requeue); ++} ++ ++static void bfq_activate_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq) ++{ ++ struct bfq_entity *entity = &bfqq->entity; ++ ++ bfq_activate_entity(entity); ++} ++ ++/* ++ * Called when the bfqq no longer has requests pending, remove it from ++ * the service tree. ++ */ ++static void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq, ++ int requeue) ++{ ++ BUG_ON(!bfq_bfqq_busy(bfqq)); ++ BUG_ON(!RB_EMPTY_ROOT(&bfqq->sort_list)); ++ ++ bfq_log_bfqq(bfqd, bfqq, "del from busy"); ++ ++ bfq_clear_bfqq_busy(bfqq); ++ ++ BUG_ON(bfqd->busy_queues == 0); ++ bfqd->busy_queues--; ++ ++ if (!bfqq->dispatched) { ++ bfq_weights_tree_remove(bfqd, &bfqq->entity, ++ &bfqd->queue_weights_tree); ++ if (!blk_queue_nonrot(bfqd->queue)) { ++ BUG_ON(!bfqd->busy_in_flight_queues); ++ bfqd->busy_in_flight_queues--; ++ if (bfq_bfqq_constantly_seeky(bfqq)) { ++ BUG_ON(!bfqd-> ++ const_seeky_busy_in_flight_queues); ++ bfqd->const_seeky_busy_in_flight_queues--; ++ } ++ } ++ } ++ if (bfqq->wr_coeff > 1) ++ bfqd->wr_busy_queues--; ++ ++ bfq_deactivate_bfqq(bfqd, bfqq, requeue); ++} ++ ++/* ++ * Called when an inactive queue receives a new request. ++ */ ++static void bfq_add_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq) ++{ ++ BUG_ON(bfq_bfqq_busy(bfqq)); ++ BUG_ON(bfqq == bfqd->in_service_queue); ++ ++ bfq_log_bfqq(bfqd, bfqq, "add to busy"); ++ ++ bfq_activate_bfqq(bfqd, bfqq); ++ ++ bfq_mark_bfqq_busy(bfqq); ++ bfqd->busy_queues++; ++ ++ if (!bfqq->dispatched) { ++ if (bfqq->wr_coeff == 1) ++ bfq_weights_tree_add(bfqd, &bfqq->entity, ++ &bfqd->queue_weights_tree); ++ if (!blk_queue_nonrot(bfqd->queue)) { ++ bfqd->busy_in_flight_queues++; ++ if (bfq_bfqq_constantly_seeky(bfqq)) ++ bfqd->const_seeky_busy_in_flight_queues++; ++ } ++ } ++ if (bfqq->wr_coeff > 1) ++ bfqd->wr_busy_queues++; ++} +diff -Nur linux-3.14.40.orig/block/blk-core.c linux-3.14.40/block/blk-core.c +--- linux-3.14.40.orig/block/blk-core.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/block/blk-core.c 2015-05-01 14:57:58.359427001 -0500 +@@ -1928,7 +1928,7 @@ + * in some cases below, so export this function. + * Request stacking drivers like request-based dm may change the queue + * limits while requests are in the queue (e.g. dm's table swapping). +- * Such request stacking drivers should check those requests agaist ++ * Such request stacking drivers should check those requests against + * the new queue limits again when they dispatch those requests, + * although such checkings are also done against the old queue limits + * when submitting requests. +diff -Nur linux-3.14.40.orig/block/blk-map.c linux-3.14.40/block/blk-map.c +--- linux-3.14.40.orig/block/blk-map.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/block/blk-map.c 2015-05-01 14:57:58.367427001 -0500 +@@ -285,7 +285,7 @@ + * + * Description: + * Data will be mapped directly if possible. Otherwise a bounce +- * buffer is used. Can be called multple times to append multple ++ * buffer is used. Can be called multiple times to append multiple + * buffers. + */ + int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, +diff -Nur linux-3.14.40.orig/block/Kconfig.iosched linux-3.14.40/block/Kconfig.iosched +--- linux-3.14.40.orig/block/Kconfig.iosched 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/block/Kconfig.iosched 2015-05-01 14:57:58.367427001 -0500 +@@ -39,6 +39,27 @@ + ---help--- + Enable group IO scheduling in CFQ. + ++config IOSCHED_BFQ ++ tristate "BFQ I/O scheduler" ++ default n ++ ---help--- ++ The BFQ I/O scheduler tries to distribute bandwidth among ++ all processes according to their weights. ++ It aims at distributing the bandwidth as desired, independently of ++ the disk parameters and with any workload. It also tries to ++ guarantee low latency to interactive and soft real-time ++ applications. If compiled built-in (saying Y here), BFQ can ++ be configured to support hierarchical scheduling. ++ ++config CGROUP_BFQIO ++ bool "BFQ hierarchical scheduling support" ++ depends on CGROUPS && IOSCHED_BFQ=y ++ default n ++ ---help--- ++ Enable hierarchical scheduling in BFQ, using the cgroups ++ filesystem interface. The name of the subsystem will be ++ bfqio. ++ + choice + prompt "Default I/O scheduler" + default DEFAULT_CFQ +@@ -52,6 +73,16 @@ + config DEFAULT_CFQ + bool "CFQ" if IOSCHED_CFQ=y + ++ config DEFAULT_BFQ ++ bool "BFQ" if IOSCHED_BFQ=y ++ help ++ Selects BFQ as the default I/O scheduler which will be ++ used by default for all block devices. ++ The BFQ I/O scheduler aims at distributing the bandwidth ++ as desired, independently of the disk parameters and with ++ any workload. It also tries to guarantee low latency to ++ interactive and soft real-time applications. ++ + config DEFAULT_NOOP + bool "No-op" + +@@ -61,6 +92,7 @@ + string + default "deadline" if DEFAULT_DEADLINE + default "cfq" if DEFAULT_CFQ ++ default "bfq" if DEFAULT_BFQ + default "noop" if DEFAULT_NOOP + + endmenu +diff -Nur linux-3.14.40.orig/block/Makefile linux-3.14.40/block/Makefile +--- linux-3.14.40.orig/block/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/block/Makefile 2015-05-01 14:57:58.367427001 -0500 +@@ -16,6 +16,7 @@ + obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o + obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o + obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o ++obj-$(CONFIG_IOSCHED_BFQ) += bfq-iosched.o + + obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o + obj-$(CONFIG_BLK_DEV_INTEGRITY) += blk-integrity.o +diff -Nur linux-3.14.40.orig/crypto/blkcipher.c linux-3.14.40/crypto/blkcipher.c +--- linux-3.14.40.orig/crypto/blkcipher.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/crypto/blkcipher.c 2015-05-01 14:57:58.383427001 -0500 +@@ -70,14 +70,12 @@ + return max(start, end_page); + } + +-static inline unsigned int blkcipher_done_slow(struct crypto_blkcipher *tfm, +- struct blkcipher_walk *walk, ++static inline unsigned int blkcipher_done_slow(struct blkcipher_walk *walk, + unsigned int bsize) + { + u8 *addr; +- unsigned int alignmask = crypto_blkcipher_alignmask(tfm); + +- addr = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1); ++ addr = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1); + addr = blkcipher_get_spot(addr, bsize); + scatterwalk_copychunks(addr, &walk->out, bsize, 1); + return bsize; +@@ -105,7 +103,6 @@ + int blkcipher_walk_done(struct blkcipher_desc *desc, + struct blkcipher_walk *walk, int err) + { +- struct crypto_blkcipher *tfm = desc->tfm; + unsigned int nbytes = 0; + + if (likely(err >= 0)) { +@@ -117,7 +114,7 @@ + err = -EINVAL; + goto err; + } else +- n = blkcipher_done_slow(tfm, walk, n); ++ n = blkcipher_done_slow(walk, n); + + nbytes = walk->total - n; + err = 0; +@@ -136,7 +133,7 @@ + } + + if (walk->iv != desc->info) +- memcpy(desc->info, walk->iv, crypto_blkcipher_ivsize(tfm)); ++ memcpy(desc->info, walk->iv, walk->ivsize); + if (walk->buffer != walk->page) + kfree(walk->buffer); + if (walk->page) +@@ -226,22 +223,20 @@ + static int blkcipher_walk_next(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) + { +- struct crypto_blkcipher *tfm = desc->tfm; +- unsigned int alignmask = crypto_blkcipher_alignmask(tfm); + unsigned int bsize; + unsigned int n; + int err; + + n = walk->total; +- if (unlikely(n < crypto_blkcipher_blocksize(tfm))) { ++ if (unlikely(n < walk->cipher_blocksize)) { + desc->flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; + return blkcipher_walk_done(desc, walk, -EINVAL); + } + + walk->flags &= ~(BLKCIPHER_WALK_SLOW | BLKCIPHER_WALK_COPY | + BLKCIPHER_WALK_DIFF); +- if (!scatterwalk_aligned(&walk->in, alignmask) || +- !scatterwalk_aligned(&walk->out, alignmask)) { ++ if (!scatterwalk_aligned(&walk->in, walk->alignmask) || ++ !scatterwalk_aligned(&walk->out, walk->alignmask)) { + walk->flags |= BLKCIPHER_WALK_COPY; + if (!walk->page) { + walk->page = (void *)__get_free_page(GFP_ATOMIC); +@@ -250,12 +245,12 @@ + } + } + +- bsize = min(walk->blocksize, n); ++ bsize = min(walk->walk_blocksize, n); + n = scatterwalk_clamp(&walk->in, n); + n = scatterwalk_clamp(&walk->out, n); + + if (unlikely(n < bsize)) { +- err = blkcipher_next_slow(desc, walk, bsize, alignmask); ++ err = blkcipher_next_slow(desc, walk, bsize, walk->alignmask); + goto set_phys_lowmem; + } + +@@ -277,28 +272,26 @@ + return err; + } + +-static inline int blkcipher_copy_iv(struct blkcipher_walk *walk, +- struct crypto_blkcipher *tfm, +- unsigned int alignmask) +-{ +- unsigned bs = walk->blocksize; +- unsigned int ivsize = crypto_blkcipher_ivsize(tfm); +- unsigned aligned_bs = ALIGN(bs, alignmask + 1); +- unsigned int size = aligned_bs * 2 + ivsize + max(aligned_bs, ivsize) - +- (alignmask + 1); ++static inline int blkcipher_copy_iv(struct blkcipher_walk *walk) ++{ ++ unsigned bs = walk->walk_blocksize; ++ unsigned aligned_bs = ALIGN(bs, walk->alignmask + 1); ++ unsigned int size = aligned_bs * 2 + ++ walk->ivsize + max(aligned_bs, walk->ivsize) - ++ (walk->alignmask + 1); + u8 *iv; + +- size += alignmask & ~(crypto_tfm_ctx_alignment() - 1); ++ size += walk->alignmask & ~(crypto_tfm_ctx_alignment() - 1); + walk->buffer = kmalloc(size, GFP_ATOMIC); + if (!walk->buffer) + return -ENOMEM; + +- iv = (u8 *)ALIGN((unsigned long)walk->buffer, alignmask + 1); ++ iv = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1); + iv = blkcipher_get_spot(iv, bs) + aligned_bs; + iv = blkcipher_get_spot(iv, bs) + aligned_bs; +- iv = blkcipher_get_spot(iv, ivsize); ++ iv = blkcipher_get_spot(iv, walk->ivsize); + +- walk->iv = memcpy(iv, walk->iv, ivsize); ++ walk->iv = memcpy(iv, walk->iv, walk->ivsize); + return 0; + } + +@@ -306,7 +299,10 @@ + struct blkcipher_walk *walk) + { + walk->flags &= ~BLKCIPHER_WALK_PHYS; +- walk->blocksize = crypto_blkcipher_blocksize(desc->tfm); ++ walk->walk_blocksize = crypto_blkcipher_blocksize(desc->tfm); ++ walk->cipher_blocksize = walk->walk_blocksize; ++ walk->ivsize = crypto_blkcipher_ivsize(desc->tfm); ++ walk->alignmask = crypto_blkcipher_alignmask(desc->tfm); + return blkcipher_walk_first(desc, walk); + } + EXPORT_SYMBOL_GPL(blkcipher_walk_virt); +@@ -315,7 +311,10 @@ + struct blkcipher_walk *walk) + { + walk->flags |= BLKCIPHER_WALK_PHYS; +- walk->blocksize = crypto_blkcipher_blocksize(desc->tfm); ++ walk->walk_blocksize = crypto_blkcipher_blocksize(desc->tfm); ++ walk->cipher_blocksize = walk->walk_blocksize; ++ walk->ivsize = crypto_blkcipher_ivsize(desc->tfm); ++ walk->alignmask = crypto_blkcipher_alignmask(desc->tfm); + return blkcipher_walk_first(desc, walk); + } + EXPORT_SYMBOL_GPL(blkcipher_walk_phys); +@@ -323,9 +322,6 @@ + static int blkcipher_walk_first(struct blkcipher_desc *desc, + struct blkcipher_walk *walk) + { +- struct crypto_blkcipher *tfm = desc->tfm; +- unsigned int alignmask = crypto_blkcipher_alignmask(tfm); +- + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + +@@ -335,8 +331,8 @@ + + walk->buffer = NULL; + walk->iv = desc->info; +- if (unlikely(((unsigned long)walk->iv & alignmask))) { +- int err = blkcipher_copy_iv(walk, tfm, alignmask); ++ if (unlikely(((unsigned long)walk->iv & walk->alignmask))) { ++ int err = blkcipher_copy_iv(walk); + if (err) + return err; + } +@@ -353,11 +349,28 @@ + unsigned int blocksize) + { + walk->flags &= ~BLKCIPHER_WALK_PHYS; +- walk->blocksize = blocksize; ++ walk->walk_blocksize = blocksize; ++ walk->cipher_blocksize = crypto_blkcipher_blocksize(desc->tfm); ++ walk->ivsize = crypto_blkcipher_ivsize(desc->tfm); ++ walk->alignmask = crypto_blkcipher_alignmask(desc->tfm); + return blkcipher_walk_first(desc, walk); + } + EXPORT_SYMBOL_GPL(blkcipher_walk_virt_block); + ++int blkcipher_aead_walk_virt_block(struct blkcipher_desc *desc, ++ struct blkcipher_walk *walk, ++ struct crypto_aead *tfm, ++ unsigned int blocksize) ++{ ++ walk->flags &= ~BLKCIPHER_WALK_PHYS; ++ walk->walk_blocksize = blocksize; ++ walk->cipher_blocksize = crypto_aead_blocksize(tfm); ++ walk->ivsize = crypto_aead_ivsize(tfm); ++ walk->alignmask = crypto_aead_alignmask(tfm); ++ return blkcipher_walk_first(desc, walk); ++} ++EXPORT_SYMBOL_GPL(blkcipher_aead_walk_virt_block); ++ + static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) + { +diff -Nur linux-3.14.40.orig/crypto/tcrypt.c linux-3.14.40/crypto/tcrypt.c +--- linux-3.14.40.orig/crypto/tcrypt.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/crypto/tcrypt.c 2015-05-01 14:57:58.395427001 -0500 +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include "tcrypt.h" + #include "internal.h" + +@@ -447,6 +448,7 @@ + goto out; + } + ++ schedule(); + printk("test %u (%d bit key, %d byte blocks): ", i, + *keysize * 8, *b_size); + +@@ -713,6 +715,7 @@ + if (speed[i].klen) + crypto_hash_setkey(tfm, tvmem[0], speed[i].klen); + ++ schedule(); + printk(KERN_INFO "test%3u " + "(%5u byte blocks,%5u bytes per update,%4u updates): ", + i, speed[i].blen, speed[i].plen, speed[i].blen / speed[i].plen); +@@ -953,6 +956,7 @@ + break; + } + ++ schedule(); + pr_info("test%3u " + "(%5u byte blocks,%5u bytes per update,%4u updates): ", + i, speed[i].blen, speed[i].plen, speed[i].blen / speed[i].plen); +@@ -1118,6 +1122,7 @@ + goto out_free_req; + } + ++ schedule(); + pr_info("test %u (%d bit key, %d byte blocks): ", i, + *keysize * 8, *b_size); + +@@ -1199,6 +1204,7 @@ + printk("alg %s ", *name); + printk(crypto_has_alg(*name, 0, 0) ? + "found\n" : "not found\n"); ++ schedule(); + name++; + } + } +diff -Nur linux-3.14.40.orig/Documentation/ABI/testing/sysfs-class-net-statistics linux-3.14.40/Documentation/ABI/testing/sysfs-class-net-statistics +--- linux-3.14.40.orig/Documentation/ABI/testing/sysfs-class-net-statistics 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/ABI/testing/sysfs-class-net-statistics 2015-05-01 14:57:58.395427001 -0500 +@@ -0,0 +1,201 @@ ++What: /sys/class//statistics/collisions ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of collisions seen by this network device. ++ This value might not be relevant with all MAC layers. ++ ++What: /sys/class//statistics/multicast ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of multicast packets received by this ++ network device. ++ ++What: /sys/class//statistics/rx_bytes ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of bytes received by this network device. ++ See the network driver for the exact meaning of when this ++ value is incremented. ++ ++What: /sys/class//statistics/rx_compressed ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of compressed packets received by this ++ network device. This value might only be relevant for interfaces ++ that support packet compression (e.g: PPP). ++ ++What: /sys/class//statistics/rx_crc_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of packets received with a CRC (FCS) error ++ by this network device. Note that the specific meaning might ++ depend on the MAC layer used by the interface. ++ ++What: /sys/class//statistics/rx_dropped ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of packets received by the network device ++ but dropped, that are not forwarded to the upper layers for ++ packet processing. See the network driver for the exact ++ meaning of this value. ++ ++What: /sys/class//statistics/rx_fifo_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of receive FIFO errors seen by this ++ network device. See the network driver for the exact ++ meaning of this value. ++ ++What: /sys/class//statistics/rx_frame_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of received frames with error, such as ++ alignment errors. Note that the specific meaning depends on ++ on the MAC layer protocol used. See the network driver for ++ the exact meaning of this value. ++ ++What: /sys/class//statistics/rx_length_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of received error packet with a length ++ error, oversized or undersized. See the network driver for the ++ exact meaning of this value. ++ ++What: /sys/class//statistics/rx_missed_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of received packets that have been missed ++ due to lack of capacity in the receive side. See the network ++ driver for the exact meaning of this value. ++ ++What: /sys/class//statistics/rx_over_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of received packets that are oversized ++ compared to what the network device is configured to accept ++ (e.g: larger than MTU). See the network driver for the exact ++ meaning of this value. ++ ++What: /sys/class//statistics/rx_packets ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the total number of good packets received by this ++ network device. ++ ++What: /sys/class//statistics/tx_aborted_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of packets that have been aborted ++ during transmission by a network device (e.g: because of ++ a medium collision). See the network driver for the exact ++ meaning of this value. ++ ++What: /sys/class//statistics/tx_bytes ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of bytes transmitted by a network ++ device. See the network driver for the exact meaning of this ++ value, in particular whether this accounts for all successfully ++ transmitted packets or all packets that have been queued for ++ transmission. ++ ++What: /sys/class//statistics/tx_carrier_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of packets that could not be transmitted ++ because of carrier errors (e.g: physical link down). See the ++ network driver for the exact meaning of this value. ++ ++What: /sys/class//statistics/tx_compressed ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of transmitted compressed packets. Note ++ this might only be relevant for devices that support ++ compression (e.g: PPP). ++ ++What: /sys/class//statistics/tx_dropped ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of packets dropped during transmission. ++ See the driver for the exact reasons as to why the packets were ++ dropped. ++ ++What: /sys/class//statistics/tx_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of packets in error during transmission by ++ a network device. See the driver for the exact reasons as to ++ why the packets were dropped. ++ ++What: /sys/class//statistics/tx_fifo_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of packets having caused a transmit ++ FIFO error. See the driver for the exact reasons as to why the ++ packets were dropped. ++ ++What: /sys/class//statistics/tx_heartbeat_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of packets transmitted that have been ++ reported as heartbeat errors. See the driver for the exact ++ reasons as to why the packets were dropped. ++ ++What: /sys/class//statistics/tx_packets ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of packets transmitted by a network ++ device. See the driver for whether this reports the number of all ++ attempted or successful transmissions. ++ ++What: /sys/class//statistics/tx_window_errors ++Date: April 2005 ++KernelVersion: 2.6.12 ++Contact: netdev@vger.kernel.org ++Description: ++ Indicates the number of packets not successfully transmitted ++ due to a window collision. The specific meaning depends on the ++ MAC layer used. On Ethernet this is usually used to report ++ late collisions errors. +diff -Nur linux-3.14.40.orig/Documentation/arm64/booting.txt linux-3.14.40/Documentation/arm64/booting.txt +--- linux-3.14.40.orig/Documentation/arm64/booting.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/arm64/booting.txt 2015-05-01 14:57:58.407427001 -0500 +@@ -111,8 +111,14 @@ + - Caches, MMUs + The MMU must be off. + Instruction cache may be on or off. +- Data cache must be off and invalidated. +- External caches (if present) must be configured and disabled. ++ The address range corresponding to the loaded kernel image must be ++ cleaned to the PoC. In the presence of a system cache or other ++ coherent masters with caches enabled, this will typically require ++ cache maintenance by VA rather than set/way operations. ++ System caches which respect the architected cache maintenance by VA ++ operations must be configured and may be enabled. ++ System caches which do not respect architected cache maintenance by VA ++ operations (not recommended) must be configured and disabled. + + - Architected timers + CNTFRQ must be programmed with the timer frequency and CNTVOFF must +diff -Nur linux-3.14.40.orig/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt linux-3.14.40/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/arm/imx/busfreq-imx6.txt 2015-05-01 14:57:58.419427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/arm/imx/gpc.txt linux-3.14.40/Documentation/devicetree/bindings/arm/imx/gpc.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/arm/imx/gpc.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/arm/imx/gpc.txt 2015-05-01 14:57:58.419427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/arm/pmu.txt linux-3.14.40/Documentation/devicetree/bindings/arm/pmu.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/arm/pmu.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/devicetree/bindings/arm/pmu.txt 2015-05-01 14:57:58.435427001 -0500 +@@ -17,6 +17,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.14.40.orig/Documentation/devicetree/bindings/ata/ahci-platform.txt linux-3.14.40/Documentation/devicetree/bindings/ata/ahci-platform.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/ata/ahci-platform.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/devicetree/bindings/ata/ahci-platform.txt 2015-05-01 14:57:58.443427001 -0500 +@@ -4,12 +4,19 @@ + Each SATA controller should have its own node. + + Required properties: +-- compatible : compatible list, contains "snps,spear-ahci" ++- compatible : compatible list, contains "snps,spear-ahci", ++ "fsl,imx53-ahci" or "fsl,imx6q-ahci" + - interrupts : + - reg : + + Optional properties: + - dma-coherent : Present if dma operations are coherent ++- clocks : a list of phandle + clock specifier pairs ++- target-supply : regulator for SATA target power ++ ++"fsl,imx53-ahci", "fsl,imx6q-ahci" required properties: ++- clocks : must contain the sata, sata_ref and ahb clocks ++- clock-names : must contain "ahb" for the ahb clock + + Example: + sata@ffe08000 { +diff -Nur linux-3.14.40.orig/Documentation/devicetree/bindings/clock/imx6q-clock.txt linux-3.14.40/Documentation/devicetree/bindings/clock/imx6q-clock.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/clock/imx6q-clock.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/devicetree/bindings/clock/imx6q-clock.txt 2015-05-01 14:57:58.451427001 -0500 +@@ -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 +@@ -220,6 +218,20 @@ + lvds2_sel 205 + lvds1_gate 206 + lvds2_gate 207 ++ gpt_3m 208 ++ video_27m 209 ++ ldb_di0_div_7 210 ++ ldb_di1_div_7 211 ++ ldb_di0_div_sel 212 ++ ldb_di1_div_sel 213 ++ caam_mem 214 ++ caam_aclk 215 ++ caam_ipg 216 ++ epit1 217 ++ epit2 218 ++ tzasc2 219 ++ lvds1_in 220 ++ lvds1_out 221 + + Examples: + +diff -Nur linux-3.14.40.orig/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt linux-3.14.40/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt 2015-05-01 14:57:58.455427001 -0500 +@@ -47,6 +47,7 @@ + 20 ASRC + 21 ESAI + 22 SSI Dual FIFO (needs firmware ver >= 2) ++ 23 HDMI Audio + + The third cell specifies the transfer priority as below. + +diff -Nur linux-3.14.40.orig/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt linux-3.14.40/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/fb/fsl_ipuv3_fb.txt 2015-05-01 14:57:58.455427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/leds/leds-pwm.txt linux-3.14.40/Documentation/devicetree/bindings/leds/leds-pwm.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/leds/leds-pwm.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/devicetree/bindings/leds/leds-pwm.txt 2015-05-01 14:57:58.459427001 -0500 +@@ -13,6 +13,8 @@ + For the pwms and pwm-names property please refer to: + Documentation/devicetree/bindings/pwm/pwm.txt + - max-brightness : Maximum brightness possible 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.14.40.orig/Documentation/devicetree/bindings/mailbox/mailbox.txt linux-3.14.40/Documentation/devicetree/bindings/mailbox/mailbox.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/mailbox/mailbox.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/mailbox/mailbox.txt 2015-05-01 14:57:58.459427001 -0500 +@@ -0,0 +1,33 @@ ++* Generic Mailbox Controller and client driver bindings ++ ++Generic binding to provide a way for Mailbox controller drivers to ++assign appropriate mailbox channel to client drivers. ++ ++* Mailbox Controller ++ ++Required property: ++- #mbox-cells: Must be at least 1. Number of cells in a mailbox ++ specifier. ++ ++Example: ++ mailbox: mailbox { ++ ... ++ #mbox-cells = <1>; ++ }; ++ ++ ++* Mailbox Client ++ ++Required property: ++- mbox: List of phandle and mailbox channel specifier. ++ ++- mbox-names: List of identifier strings for each mailbox channel ++ required by the client. ++ ++Example: ++ pwr_cntrl: power { ++ ... ++ mbox-names = "pwr-ctrl", "rpc"; ++ mbox = <&mailbox 0 ++ &mailbox 1>; ++ }; +diff -Nur linux-3.14.40.orig/Documentation/devicetree/bindings/mlb/mlb150.txt linux-3.14.40/Documentation/devicetree/bindings/mlb/mlb150.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/mlb/mlb150.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/mlb/mlb150.txt 2015-05-01 14:57:58.463427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/mmc/mmc.txt linux-3.14.40/Documentation/devicetree/bindings/mmc/mmc.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/mmc/mmc.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/devicetree/bindings/mmc/mmc.txt 2015-05-01 14:57:58.471427001 -0500 +@@ -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. +@@ -30,6 +32,15 @@ + - cap-sdio-irq: enable SDIO IRQ signalling on this interface + - full-pwr-cycle: full power cycle of the card is supported + ++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.14.40.orig/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt linux-3.14.40/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt 2015-05-01 14:57:58.479427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/reset/gpio-reset.txt linux-3.14.40/Documentation/devicetree/bindings/reset/gpio-reset.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/reset/gpio-reset.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/reset/gpio-reset.txt 2015-05-01 14:57:58.479427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/sound/cs42888.txt linux-3.14.40/Documentation/devicetree/bindings/sound/cs42888.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/sound/cs42888.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/sound/cs42888.txt 2015-05-01 14:57:58.479427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/sound/fsl-asrc-p2p.txt linux-3.14.40/Documentation/devicetree/bindings/sound/fsl-asrc-p2p.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/sound/fsl-asrc-p2p.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/sound/fsl-asrc-p2p.txt 2015-05-01 14:57:58.479427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt linux-3.14.40/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/sound/imx-audio-cs42888.txt 2015-05-01 14:57:58.479427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt linux-3.14.40/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt 2015-05-01 14:57:58.479427001 -0500 +@@ -24,6 +24,12 @@ + 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 { +@@ -43,4 +49,6 @@ + "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.14.40.orig/Documentation/devicetree/bindings/sound/wm8962.txt linux-3.14.40/Documentation/devicetree/bindings/sound/wm8962.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/sound/wm8962.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/devicetree/bindings/sound/wm8962.txt 2015-05-01 14:57:58.479427001 -0500 +@@ -13,6 +13,14 @@ + 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. + +diff -Nur linux-3.14.40.orig/Documentation/devicetree/bindings/usb/mxs-phy.txt linux-3.14.40/Documentation/devicetree/bindings/usb/mxs-phy.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/usb/mxs-phy.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/devicetree/bindings/usb/mxs-phy.txt 2015-05-01 14:57:58.487427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/video/fsl,csi-v4l2-capture.txt linux-3.14.40/Documentation/devicetree/bindings/video/fsl,csi-v4l2-capture.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/video/fsl,csi-v4l2-capture.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/video/fsl,csi-v4l2-capture.txt 2015-05-01 14:57:58.487427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/video/fsl,mipi-csi2.txt linux-3.14.40/Documentation/devicetree/bindings/video/fsl,mipi-csi2.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/video/fsl,mipi-csi2.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/video/fsl,mipi-csi2.txt 2015-05-01 14:57:58.487427001 -0500 +@@ -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>, <&clks 204>; ++ clock-names = "dphy_clk", "pixel_clk", "cfg_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.14.40.orig/Documentation/devicetree/bindings/video/fsl,pxp.txt linux-3.14.40/Documentation/devicetree/bindings/video/fsl,pxp.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/video/fsl,pxp.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/video/fsl,pxp.txt 2015-05-01 14:57:58.487427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/video/fsl,v4l2-capture.txt linux-3.14.40/Documentation/devicetree/bindings/video/fsl,v4l2-capture.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/video/fsl,v4l2-capture.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/video/fsl,v4l2-capture.txt 2015-05-01 14:57:58.487427001 -0500 +@@ -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.14.40.orig/Documentation/devicetree/bindings/video/mxc_hdmi_video.txt linux-3.14.40/Documentation/devicetree/bindings/video/mxc_hdmi_video.txt +--- linux-3.14.40.orig/Documentation/devicetree/bindings/video/mxc_hdmi_video.txt 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/Documentation/devicetree/bindings/video/mxc_hdmi_video.txt 2015-05-01 14:57:58.491427001 -0500 +@@ -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.14.40.orig/Documentation/filesystems/hfsplus.txt linux-3.14.40/Documentation/filesystems/hfsplus.txt +--- linux-3.14.40.orig/Documentation/filesystems/hfsplus.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/filesystems/hfsplus.txt 2015-05-01 14:57:58.499427001 -0500 +@@ -56,4 +56,4 @@ + + kernel source: + +-Apple Technote 1150 http://developer.apple.com/technotes/tn/tn1150.html ++Apple Technote 1150 https://developer.apple.com/legacy/library/technotes/tn/tn1150.html +diff -Nur linux-3.14.40.orig/Documentation/kernel-parameters.txt linux-3.14.40/Documentation/kernel-parameters.txt +--- linux-3.14.40.orig/Documentation/kernel-parameters.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/kernel-parameters.txt 2015-05-01 14:57:58.511427001 -0500 +@@ -603,8 +603,11 @@ + Also note the kernel might malfunction if you disable + some critical bits. + +- cma=nn[MG] [ARM,KNL] +- Sets the size of kernel global memory area for contiguous ++ cma=nn[MG]@[start[MG][-end[MG]]] ++ [ARM,X86,KNL] ++ Sets the size of kernel global memory area for ++ contiguous memory allocations and optionally the ++ placement constraint by the physical address range of + memory allocations. For more information, see + include/linux/dma-contiguous.h + +diff -Nur linux-3.14.40.orig/Documentation/networking/gianfar.txt linux-3.14.40/Documentation/networking/gianfar.txt +--- linux-3.14.40.orig/Documentation/networking/gianfar.txt 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/Documentation/networking/gianfar.txt 2015-05-01 14:57:58.523427001 -0500 +@@ -1,38 +1,8 @@ + The Gianfar Ethernet Driver +-Sysfs File description + + Author: Andy Fleming + Updated: 2005-07-28 + +-SYSFS +- +-Several of the features of the gianfar driver are controlled +-through sysfs files. These are: +- +-bd_stash: +-To stash RX Buffer Descriptors in the L2, echo 'on' or '1' to +-bd_stash, echo 'off' or '0' to disable +- +-rx_stash_len: +-To stash the first n bytes of the packet in L2, echo the number +-of bytes to buf_stash_len. echo 0 to disable. +- +-WARNING: You could really screw these up if you set them too low or high! +-fifo_threshold: +-To change the number of bytes the controller needs in the +-fifo before it starts transmission, echo the number of bytes to +-fifo_thresh. Range should be 0-511. +- +-fifo_starve: +-When the FIFO has less than this many bytes during a transmit, it +-enters starve mode, and increases the priority of TX memory +-transactions. To change, echo the number of bytes to +-fifo_starve. Range should be 0-511. +- +-fifo_starve_off: +-Once in starve mode, the FIFO remains there until it has this +-many bytes. To change, echo the number of bytes to +-fifo_starve_off. Range should be 0-511. + + CHECKSUM OFFLOADING + +diff -Nur linux-3.14.40.orig/drivers/ata/acard-ahci.c linux-3.14.40/drivers/ata/acard-ahci.c +--- linux-3.14.40.orig/drivers/ata/acard-ahci.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/acard-ahci.c 2015-05-01 14:57:58.539427001 -0500 +@@ -36,7 +36,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/ahci.c linux-3.14.40/drivers/ata/ahci.c +--- linux-3.14.40.orig/drivers/ata/ahci.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/ahci.c 2015-05-01 14:57:58.551427001 -0500 +@@ -35,7 +35,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -610,6 +609,7 @@ + unsigned long deadline) + { + struct ata_port *ap = link->ap; ++ struct ahci_host_priv *hpriv = ap->host->private_data; + bool online; + int rc; + +@@ -620,7 +620,7 @@ + rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), + deadline, &online, NULL); + +- ahci_start_engine(ap); ++ hpriv->start_engine(ap); + + DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class); + +@@ -635,6 +635,7 @@ + { + struct ata_port *ap = link->ap; + struct ahci_port_priv *pp = ap->private_data; ++ struct ahci_host_priv *hpriv = ap->host->private_data; + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + struct ata_taskfile tf; + bool online; +@@ -650,7 +651,7 @@ + rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context), + deadline, &online, NULL); + +- ahci_start_engine(ap); ++ hpriv->start_engine(ap); + + /* The pseudo configuration device on SIMG4726 attached to + * ASUS P5W-DH Deluxe doesn't send signature FIS after +@@ -1146,6 +1147,17 @@ + return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff); + } + ++static bool ahci_broken_devslp(struct pci_dev *pdev) ++{ ++ /* device with broken DEVSLP but still showing SDS capability */ ++ static const struct pci_device_id ids[] = { ++ { PCI_VDEVICE(INTEL, 0x0f23)}, /* Valleyview SoC */ ++ {} ++ }; ++ ++ return pci_match_id(ids, pdev); ++} ++ + #ifdef CONFIG_ATA_ACPI + static void ahci_gtf_filter_workaround(struct ata_host *host) + { +@@ -1397,6 +1409,10 @@ + + hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar]; + ++ /* must set flag prior to save config in order to take effect */ ++ if (ahci_broken_devslp(pdev)) ++ hpriv->flags |= AHCI_HFLAG_NO_DEVSLP; ++ + /* save initial config */ + ahci_pci_save_initial_config(pdev, hpriv); + +diff -Nur linux-3.14.40.orig/drivers/ata/ahci.h linux-3.14.40/drivers/ata/ahci.h +--- linux-3.14.40.orig/drivers/ata/ahci.h 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/ahci.h 2015-05-01 14:57:58.571427001 -0500 +@@ -37,6 +37,8 @@ + + #include + #include ++#include ++#include + + /* Enclosure Management Control */ + #define EM_CTRL_MSG_TYPE 0x000f0000 +@@ -51,6 +53,7 @@ + + enum { + AHCI_MAX_PORTS = 32, ++ AHCI_MAX_CLKS = 3, + AHCI_MAX_SG = 168, /* hardware max is 64K */ + AHCI_DMA_BOUNDARY = 0xffffffff, + AHCI_MAX_CMDS = 32, +@@ -233,6 +236,8 @@ + port start (wait until + error-handling stage) */ + AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */ ++ AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */ ++ AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */ + + /* ap->flags bits */ + +@@ -322,8 +327,17 @@ + u32 em_loc; /* enclosure management location */ + u32 em_buf_sz; /* EM buffer size in byte */ + u32 em_msg_type; /* EM message type */ +- struct clk *clk; /* Only for platforms supporting clk */ ++ bool got_runtime_pm; /* Did we do pm_runtime_get? */ ++ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ ++ struct regulator *target_pwr; /* Optional */ ++ struct phy *phy; /* If platform uses phy */ + void *plat_data; /* Other platform data */ ++ /* ++ * Optional ahci_start_engine override, if not set this gets set to the ++ * default ahci_start_engine during ahci_save_initial_config, this can ++ * be overridden anytime before the host is activated. ++ */ ++ void (*start_engine)(struct ata_port *ap); + }; + + extern int ahci_ignore_sss; +diff -Nur linux-3.14.40.orig/drivers/ata/ahci_imx.c linux-3.14.40/drivers/ata/ahci_imx.c +--- linux-3.14.40.orig/drivers/ata/ahci_imx.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/ahci_imx.c 2015-05-01 14:57:58.571427001 -0500 +@@ -26,12 +26,29 @@ + #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 */ ++ /* Timer 1-ms Register */ ++ IMX_TIMER1MS = 0x00e0, ++ /* Port0 PHY Control Register */ ++ IMX_P0PHYCR = 0x0178, ++ IMX_P0PHYCR_TEST_PDDQ = 1 << 20, ++ IMX_P0PHYCR_CR_READ = 1 << 19, ++ IMX_P0PHYCR_CR_WRITE = 1 << 18, ++ IMX_P0PHYCR_CR_CAP_DATA = 1 << 17, ++ IMX_P0PHYCR_CR_CAP_ADDR = 1 << 16, ++ /* Port0 PHY Status Register */ ++ IMX_P0PHYSR = 0x017c, ++ IMX_P0PHYSR_CR_ACK = 1 << 18, ++ IMX_P0PHYSR_CR_DATA_OUT = 0xffff << 0, ++ /* Lane0 Output Status Register */ ++ IMX_LANE0_OUT_STAT = 0x2003, ++ IMX_LANE0_OUT_STAT_RX_PLL_STATE = 1 << 1, ++ /* Clock Reset Register */ ++ IMX_CLOCK_RESET = 0x7f3f, ++ IMX_CLOCK_RESET_RESET = 1 << 0, + }; + + enum ahci_imx_type { +@@ -42,62 +59,230 @@ + struct imx_ahci_priv { + struct platform_device *ahci_pdev; + enum ahci_imx_type type; +- +- /* i.MX53 clock */ +- struct clk *sata_gate_clk; +- /* Common clock */ +- struct clk *sata_ref_clk; + struct clk *ahb_clk; +- + struct regmap *gpr; + bool no_device; + bool first_time; ++ u32 phy_params; + }; + + 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 int imx_sata_clock_enable(struct device *dev) ++static void ahci_imx_host_stop(struct ata_host *host); ++ ++static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert) ++{ ++ int timeout = 10; ++ u32 crval; ++ u32 srval; ++ ++ /* Assert or deassert the bit */ ++ crval = readl(mmio + IMX_P0PHYCR); ++ if (assert) ++ crval |= bit; ++ else ++ crval &= ~bit; ++ writel(crval, mmio + IMX_P0PHYCR); ++ ++ /* Wait for the cr_ack signal */ ++ do { ++ srval = readl(mmio + IMX_P0PHYSR); ++ if ((assert ? srval : ~srval) & IMX_P0PHYSR_CR_ACK) ++ break; ++ usleep_range(100, 200); ++ } while (--timeout); ++ ++ return timeout ? 0 : -ETIMEDOUT; ++} ++ ++static int imx_phy_reg_addressing(u16 addr, void __iomem *mmio) + { +- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); ++ u32 crval = addr; + int ret; + +- if (imxpriv->type == AHCI_IMX53) { +- ret = clk_prepare_enable(imxpriv->sata_gate_clk); +- if (ret < 0) { +- dev_err(dev, "prepare-enable sata_gate clock err:%d\n", +- ret); +- return ret; +- } ++ /* Supply the address on cr_data_in */ ++ writel(crval, mmio + IMX_P0PHYCR); ++ ++ /* Assert the cr_cap_addr signal */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, true); ++ if (ret) ++ return ret; ++ ++ /* Deassert cr_cap_addr */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_ADDR, false); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int imx_phy_reg_write(u16 val, void __iomem *mmio) ++{ ++ u32 crval = val; ++ int ret; ++ ++ /* Supply the data on cr_data_in */ ++ writel(crval, mmio + IMX_P0PHYCR); ++ ++ /* Assert the cr_cap_data signal */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, true); ++ if (ret) ++ return ret; ++ ++ /* Deassert cr_cap_data */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_CAP_DATA, false); ++ if (ret) ++ return ret; ++ ++ if (val & IMX_CLOCK_RESET_RESET) { ++ /* ++ * In case we're resetting the phy, it's unable to acknowledge, ++ * so we return immediately here. ++ */ ++ crval |= IMX_P0PHYCR_CR_WRITE; ++ writel(crval, mmio + IMX_P0PHYCR); ++ goto out; + } + +- ret = clk_prepare_enable(imxpriv->sata_ref_clk); +- if (ret < 0) { +- dev_err(dev, "prepare-enable sata_ref clock err:%d\n", +- ret); +- goto clk_err; ++ /* Assert the cr_write signal */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, true); ++ if (ret) ++ return ret; ++ ++ /* Deassert cr_write */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_WRITE, false); ++ if (ret) ++ return ret; ++ ++out: ++ return 0; ++} ++ ++static int imx_phy_reg_read(u16 *val, void __iomem *mmio) ++{ ++ int ret; ++ ++ /* Assert the cr_read signal */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, true); ++ if (ret) ++ return ret; ++ ++ /* Capture the data from cr_data_out[] */ ++ *val = readl(mmio + IMX_P0PHYSR) & IMX_P0PHYSR_CR_DATA_OUT; ++ ++ /* Deassert cr_read */ ++ ret = imx_phy_crbit_assert(mmio, IMX_P0PHYCR_CR_READ, false); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int imx_sata_phy_reset(struct ahci_host_priv *hpriv) ++{ ++ void __iomem *mmio = hpriv->mmio; ++ int timeout = 10; ++ u16 val; ++ int ret; ++ ++ /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */ ++ ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio); ++ if (ret) ++ return ret; ++ ret = imx_phy_reg_write(IMX_CLOCK_RESET_RESET, mmio); ++ if (ret) ++ return ret; ++ ++ /* Wait for PHY RX_PLL to be stable */ ++ do { ++ usleep_range(100, 200); ++ ret = imx_phy_reg_addressing(IMX_LANE0_OUT_STAT, mmio); ++ if (ret) ++ return ret; ++ ret = imx_phy_reg_read(&val, mmio); ++ if (ret) ++ return ret; ++ if (val & IMX_LANE0_OUT_STAT_RX_PLL_STATE) ++ break; ++ } while (--timeout); ++ ++ return timeout ? 0 : -ETIMEDOUT; ++} ++ ++static int imx_sata_enable(struct ahci_host_priv *hpriv) ++{ ++ struct imx_ahci_priv *imxpriv = hpriv->plat_data; ++ struct device *dev = &imxpriv->ahci_pdev->dev; ++ int ret; ++ ++ if (imxpriv->no_device) ++ return 0; ++ ++ if (hpriv->target_pwr) { ++ ret = regulator_enable(hpriv->target_pwr); ++ if (ret) ++ return ret; + } + ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ ret = ahci_platform_enable_clks(hpriv); ++ if (ret < 0) ++ goto disable_regulator; ++ + if (imxpriv->type == AHCI_IMX6Q) { ++ /* ++ * set PHY Paremeters, two steps to configure the GPR13, ++ * one write for rest of parameters, mask of first write ++ * is 0x07ffffff, and the other one write for setting ++ * the mpll_clk_en. ++ */ ++ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, ++ 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_MPLL_CLK_EN | ++ IMX6Q_GPR13_SATA_TX_EDGE_RATE, ++ imxpriv->phy_params); + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, + IMX6Q_GPR13_SATA_MPLL_CLK_EN, + IMX6Q_GPR13_SATA_MPLL_CLK_EN); ++ ++ usleep_range(100, 200); ++ ++ ret = imx_sata_phy_reset(hpriv); ++ if (ret) { ++ dev_err(dev, "failed to reset phy: %d\n", ret); ++ goto disable_regulator; ++ } + } + + usleep_range(1000, 2000); + + return 0; + +-clk_err: +- if (imxpriv->type == AHCI_IMX53) +- clk_disable_unprepare(imxpriv->sata_gate_clk); ++disable_regulator: ++ release_bus_freq(BUS_FREQ_HIGH); ++ ++ if (hpriv->target_pwr) ++ regulator_disable(hpriv->target_pwr); ++ + return ret; + } + +-static void imx_sata_clock_disable(struct device *dev) ++static void imx_sata_disable(struct ahci_host_priv *hpriv) + { +- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); ++ struct imx_ahci_priv *imxpriv = hpriv->plat_data; ++ ++ if (imxpriv->no_device) ++ return; + + if (imxpriv->type == AHCI_IMX6Q) { + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, +@@ -105,10 +290,12 @@ + !IMX6Q_GPR13_SATA_MPLL_CLK_EN); + } + +- clk_disable_unprepare(imxpriv->sata_ref_clk); ++ ahci_platform_disable_clks(hpriv); + +- if (imxpriv->type == AHCI_IMX53) +- clk_disable_unprepare(imxpriv->sata_gate_clk); ++ release_bus_freq(BUS_FREQ_HIGH); ++ ++ if (hpriv->target_pwr) ++ regulator_disable(hpriv->target_pwr); + } + + static void ahci_imx_error_handler(struct ata_port *ap) +@@ -118,7 +305,7 @@ + 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); ++ struct imx_ahci_priv *imxpriv = hpriv->plat_data; + + ahci_error_handler(ap); + +@@ -134,17 +321,23 @@ + * 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); +- imx_sata_clock_disable(ap->dev); ++ reg_val = readl(mmio + IMX_P0PHYCR); ++ writel(reg_val | IMX_P0PHYCR_TEST_PDDQ, mmio + IMX_P0PHYCR); ++ imx_sata_disable(hpriv); + 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 int ahci_imx_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) + { + struct ata_port *ap = link->ap; +- struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent); ++ struct ata_host *host = dev_get_drvdata(ap->dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ struct imx_ahci_priv *imxpriv = hpriv->plat_data; + int ret = -EIO; + + if (imxpriv->type == AHCI_IMX53) +@@ -156,7 +349,8 @@ + } + + static struct ata_port_operations ahci_imx_ops = { +- .inherits = &ahci_platform_ops, ++ .inherits = &ahci_ops, ++ .host_stop = ahci_imx_host_stop, + .error_handler = ahci_imx_error_handler, + .softreset = ahci_imx_softreset, + }; +@@ -168,234 +362,306 @@ + .port_ops = &ahci_imx_ops, + }; + +-static int imx_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); +- +- ret = imx_sata_clock_enable(dev); +- if (ret < 0) +- return ret; ++static const struct of_device_id imx_ahci_of_match[] = { ++ { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 }, ++ { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, imx_ahci_of_match); + +- /* +- * 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); +- } ++struct reg_value { ++ u32 of_value; ++ u32 reg_value; ++}; + +- reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; +- writel(reg_val, mmio + HOST_TIMER1MS); ++struct reg_property { ++ const char *name; ++ const struct reg_value *values; ++ size_t num_values; ++ u32 def_value; ++ u32 set_value; ++}; + +- return 0; +-} ++static const struct reg_value gpr13_tx_level[] = { ++ { 937, IMX6Q_GPR13_SATA_TX_LVL_0_937_V }, ++ { 947, IMX6Q_GPR13_SATA_TX_LVL_0_947_V }, ++ { 957, IMX6Q_GPR13_SATA_TX_LVL_0_957_V }, ++ { 966, IMX6Q_GPR13_SATA_TX_LVL_0_966_V }, ++ { 976, IMX6Q_GPR13_SATA_TX_LVL_0_976_V }, ++ { 986, IMX6Q_GPR13_SATA_TX_LVL_0_986_V }, ++ { 996, IMX6Q_GPR13_SATA_TX_LVL_0_996_V }, ++ { 1005, IMX6Q_GPR13_SATA_TX_LVL_1_005_V }, ++ { 1015, IMX6Q_GPR13_SATA_TX_LVL_1_015_V }, ++ { 1025, IMX6Q_GPR13_SATA_TX_LVL_1_025_V }, ++ { 1035, IMX6Q_GPR13_SATA_TX_LVL_1_035_V }, ++ { 1045, IMX6Q_GPR13_SATA_TX_LVL_1_045_V }, ++ { 1054, IMX6Q_GPR13_SATA_TX_LVL_1_054_V }, ++ { 1064, IMX6Q_GPR13_SATA_TX_LVL_1_064_V }, ++ { 1074, IMX6Q_GPR13_SATA_TX_LVL_1_074_V }, ++ { 1084, IMX6Q_GPR13_SATA_TX_LVL_1_084_V }, ++ { 1094, IMX6Q_GPR13_SATA_TX_LVL_1_094_V }, ++ { 1104, IMX6Q_GPR13_SATA_TX_LVL_1_104_V }, ++ { 1113, IMX6Q_GPR13_SATA_TX_LVL_1_113_V }, ++ { 1123, IMX6Q_GPR13_SATA_TX_LVL_1_123_V }, ++ { 1133, IMX6Q_GPR13_SATA_TX_LVL_1_133_V }, ++ { 1143, IMX6Q_GPR13_SATA_TX_LVL_1_143_V }, ++ { 1152, IMX6Q_GPR13_SATA_TX_LVL_1_152_V }, ++ { 1162, IMX6Q_GPR13_SATA_TX_LVL_1_162_V }, ++ { 1172, IMX6Q_GPR13_SATA_TX_LVL_1_172_V }, ++ { 1182, IMX6Q_GPR13_SATA_TX_LVL_1_182_V }, ++ { 1191, IMX6Q_GPR13_SATA_TX_LVL_1_191_V }, ++ { 1201, IMX6Q_GPR13_SATA_TX_LVL_1_201_V }, ++ { 1211, IMX6Q_GPR13_SATA_TX_LVL_1_211_V }, ++ { 1221, IMX6Q_GPR13_SATA_TX_LVL_1_221_V }, ++ { 1230, IMX6Q_GPR13_SATA_TX_LVL_1_230_V }, ++ { 1240, IMX6Q_GPR13_SATA_TX_LVL_1_240_V } ++}; + +-static void imx_sata_exit(struct device *dev) +-{ +- imx_sata_clock_disable(dev); +-} ++static const struct reg_value gpr13_tx_boost[] = { ++ { 0, IMX6Q_GPR13_SATA_TX_BOOST_0_00_DB }, ++ { 370, IMX6Q_GPR13_SATA_TX_BOOST_0_37_DB }, ++ { 740, IMX6Q_GPR13_SATA_TX_BOOST_0_74_DB }, ++ { 1110, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB }, ++ { 1480, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB }, ++ { 1850, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB }, ++ { 2220, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB }, ++ { 2590, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB }, ++ { 2960, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB }, ++ { 3330, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB }, ++ { 3700, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB }, ++ { 4070, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB }, ++ { 4440, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB }, ++ { 4810, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB }, ++ { 5280, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB }, ++ { 5750, IMX6Q_GPR13_SATA_TX_BOOST_5_75_DB } ++}; + +-static int imx_ahci_suspend(struct device *dev) +-{ +- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); ++static const struct reg_value gpr13_tx_atten[] = { ++ { 8, IMX6Q_GPR13_SATA_TX_ATTEN_8_16 }, ++ { 9, IMX6Q_GPR13_SATA_TX_ATTEN_9_16 }, ++ { 10, IMX6Q_GPR13_SATA_TX_ATTEN_10_16 }, ++ { 12, IMX6Q_GPR13_SATA_TX_ATTEN_12_16 }, ++ { 14, IMX6Q_GPR13_SATA_TX_ATTEN_14_16 }, ++ { 16, IMX6Q_GPR13_SATA_TX_ATTEN_16_16 }, ++}; + +- /* +- * 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) +- imx_sata_clock_disable(dev); ++static const struct reg_value gpr13_rx_eq[] = { ++ { 500, IMX6Q_GPR13_SATA_RX_EQ_VAL_0_5_DB }, ++ { 1000, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_0_DB }, ++ { 1500, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_5_DB }, ++ { 2000, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_0_DB }, ++ { 2500, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_5_DB }, ++ { 3000, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB }, ++ { 3500, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_5_DB }, ++ { 4000, IMX6Q_GPR13_SATA_RX_EQ_VAL_4_0_DB }, ++}; + +- return 0; +-} ++static const struct reg_property gpr13_props[] = { ++ { ++ .name = "fsl,transmit-level-mV", ++ .values = gpr13_tx_level, ++ .num_values = ARRAY_SIZE(gpr13_tx_level), ++ .def_value = IMX6Q_GPR13_SATA_TX_LVL_1_025_V, ++ }, { ++ .name = "fsl,transmit-boost-mdB", ++ .values = gpr13_tx_boost, ++ .num_values = ARRAY_SIZE(gpr13_tx_boost), ++ .def_value = IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB, ++ }, { ++ .name = "fsl,transmit-atten-16ths", ++ .values = gpr13_tx_atten, ++ .num_values = ARRAY_SIZE(gpr13_tx_atten), ++ .def_value = IMX6Q_GPR13_SATA_TX_ATTEN_9_16, ++ }, { ++ .name = "fsl,receive-eq-mdB", ++ .values = gpr13_rx_eq, ++ .num_values = ARRAY_SIZE(gpr13_rx_eq), ++ .def_value = IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB, ++ }, { ++ .name = "fsl,no-spread-spectrum", ++ .def_value = IMX6Q_GPR13_SATA_MPLL_SS_EN, ++ .set_value = 0, ++ }, ++}; + +-static int imx_ahci_resume(struct device *dev) ++static u32 imx_ahci_parse_props(struct device *dev, ++ const struct reg_property *prop, size_t num) + { +- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); +- int ret = 0; +- +- if (!imxpriv->no_device) +- ret = imx_sata_clock_enable(dev); ++ struct device_node *np = dev->of_node; ++ u32 reg_value = 0; ++ int i, j; ++ ++ for (i = 0; i < num; i++, prop++) { ++ u32 of_val; ++ ++ if (prop->num_values == 0) { ++ if (of_property_read_bool(np, prop->name)) ++ reg_value |= prop->set_value; ++ else ++ reg_value |= prop->def_value; ++ continue; ++ } + +- return ret; +-} ++ if (of_property_read_u32(np, prop->name, &of_val)) { ++ dev_info(dev, "%s not specified, using %08x\n", ++ prop->name, prop->def_value); ++ reg_value |= prop->def_value; ++ continue; ++ } + +-static struct ahci_platform_data imx_sata_pdata = { +- .init = imx_sata_init, +- .exit = imx_sata_exit, +- .ata_port_info = &ahci_imx_port_info, +- .suspend = imx_ahci_suspend, +- .resume = imx_ahci_resume, ++ for (j = 0; j < prop->num_values; j++) { ++ if (prop->values[j].of_value == of_val) { ++ dev_info(dev, "%s value %u, using %08x\n", ++ prop->name, of_val, prop->values[j].reg_value); ++ reg_value |= prop->values[j].reg_value; ++ break; ++ } ++ } + +-}; ++ if (j == prop->num_values) { ++ dev_err(dev, "DT property %s is not a valid value\n", ++ prop->name); ++ reg_value |= prop->def_value; ++ } ++ } + +-static const struct of_device_id imx_ahci_of_match[] = { +- { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 }, +- { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q }, +- {}, +-}; +-MODULE_DEVICE_TABLE(of, imx_ahci_of_match); ++ return reg_value; ++} + + 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; +- enum ahci_imx_type type; +- const struct ahci_platform_data *pdata = NULL; ++ struct ahci_host_priv *hpriv; + struct imx_ahci_priv *imxpriv; +- struct device *ahci_dev; +- struct platform_device *ahci_pdev; ++ unsigned int reg_val; + int ret; + + of_id = of_match_device(imx_ahci_of_match, dev); + if (!of_id) + return -EINVAL; + +- type = (enum ahci_imx_type)of_id->data; +- pdata = &imx_sata_pdata; +- + imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL); +- if (!imxpriv) { +- dev_err(dev, "can't alloc ahci_host_priv\n"); ++ if (!imxpriv) + return -ENOMEM; +- } +- +- ahci_pdev = platform_device_alloc("ahci", -1); +- if (!ahci_pdev) +- return -ENODEV; +- +- ahci_dev = &ahci_pdev->dev; +- ahci_dev->parent = dev; + ++ imxpriv->ahci_pdev = pdev; + imxpriv->no_device = false; + imxpriv->first_time = true; +- imxpriv->type = type; +- ++ imxpriv->type = (enum ahci_imx_type)of_id->data; + 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; +- } +- +- if (type == AHCI_IMX53) { +- imxpriv->sata_gate_clk = devm_clk_get(dev, "sata_gate"); +- if (IS_ERR(imxpriv->sata_gate_clk)) { +- dev_err(dev, "can't get sata_gate clock.\n"); +- ret = PTR_ERR(imxpriv->sata_gate_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; ++ return PTR_ERR(imxpriv->ahb_clk); + } + +- imxpriv->ahci_pdev = ahci_pdev; +- platform_set_drvdata(pdev, imxpriv); +- +- 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; ++ if (imxpriv->type == AHCI_IMX6Q) { ++ u32 reg_value; + +- if (type == AHCI_IMX6Q) { + 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"); +- ret = PTR_ERR(imxpriv->gpr); +- goto err_out; ++ return PTR_ERR(imxpriv->gpr); + } + +- /* +- * Set PHY Paremeters, two steps to configure the GPR13, +- * one write for rest of parameters, mask of first write +- * is 0x07fffffe, and the other one write for setting +- * the mpll_clk_en happens in imx_sata_clock_enable(). +- */ +- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, +- 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_MPLL_CLK_EN | +- IMX6Q_GPR13_SATA_TX_EDGE_RATE, +- IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB | ++ reg_value = imx_ahci_parse_props(dev, gpr13_props, ++ ARRAY_SIZE(gpr13_props)); ++ ++ imxpriv->phy_params = + 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 | +- IMX6Q_GPR13_SATA_TX_ATTEN_9_16 | +- IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB | +- IMX6Q_GPR13_SATA_TX_LVL_1_025_V); ++ reg_value; + } + +- ret = platform_device_add_resources(ahci_pdev, res, 2); ++ hpriv = ahci_platform_get_resources(pdev); ++ if (IS_ERR(hpriv)) ++ return PTR_ERR(hpriv); ++ ++ hpriv->plat_data = imxpriv; ++ ++ ret = imx_sata_enable(hpriv); + if (ret) +- goto err_out; ++ return ret; + +- ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata)); ++ /* ++ * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, ++ * and IP vendor specific register IMX_TIMER1MS. ++ * Configure CAP_SSS (support stagered spin up). ++ * Implement the port0. ++ * Get the ahb clock rate, and configure the TIMER1MS register. ++ */ ++ reg_val = readl(hpriv->mmio + HOST_CAP); ++ if (!(reg_val & HOST_CAP_SSS)) { ++ reg_val |= HOST_CAP_SSS; ++ writel(reg_val, hpriv->mmio + HOST_CAP); ++ } ++ reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL); ++ if (!(reg_val & 0x1)) { ++ reg_val |= 0x1; ++ writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL); ++ } ++ ++ reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000; ++ writel(reg_val, hpriv->mmio + IMX_TIMER1MS); ++ ++ ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, ++ 0, 0, 0); + if (ret) +- goto err_out; ++ imx_sata_disable(hpriv); ++ ++ return ret; ++} + +- ret = platform_device_add(ahci_pdev); +- if (ret) { +-err_out: +- platform_device_put(ahci_pdev); ++static void ahci_imx_host_stop(struct ata_host *host) ++{ ++ struct ahci_host_priv *hpriv = host->private_data; ++ ++ imx_sata_disable(hpriv); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int imx_ahci_suspend(struct device *dev) ++{ ++ struct ata_host *host = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ int ret; ++ ++ ret = ahci_platform_suspend_host(dev); ++ if (ret) + return ret; +- } ++ ++ imx_sata_disable(hpriv); + + return 0; + } + +-static int imx_ahci_remove(struct platform_device *pdev) ++static int imx_ahci_resume(struct device *dev) + { +- struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev); +- struct platform_device *ahci_pdev = imxpriv->ahci_pdev; ++ struct ata_host *host = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ int ret; + +- platform_device_unregister(ahci_pdev); +- return 0; ++ ret = imx_sata_enable(hpriv); ++ if (ret) ++ return ret; ++ ++ return ahci_platform_resume_host(dev); + } ++#endif ++ ++static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume); + + static struct platform_driver imx_ahci_driver = { + .probe = imx_ahci_probe, +- .remove = imx_ahci_remove, ++ .remove = ata_platform_remove_one, + .driver = { + .name = "ahci-imx", + .owner = THIS_MODULE, + .of_match_table = imx_ahci_of_match, ++ .pm = &ahci_imx_pm_ops, + }, + }; + module_platform_driver(imx_ahci_driver); +diff -Nur linux-3.14.40.orig/drivers/ata/ahci_platform.c linux-3.14.40/drivers/ata/ahci_platform.c +--- linux-3.14.40.orig/drivers/ata/ahci_platform.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/ahci_platform.c 2015-05-01 14:57:58.583427001 -0500 +@@ -12,135 +12,36 @@ + * any later version. + */ + +-#include + #include +-#include + #include + #include +-#include +-#include + #include + #include + #include + #include + #include "ahci.h" + +-static void ahci_host_stop(struct ata_host *host); +- +-enum ahci_type { +- AHCI, /* standard platform ahci */ +- IMX53_AHCI, /* ahci on i.mx53 */ +- STRICT_AHCI, /* delayed DMA engine start */ +-}; +- +-static struct platform_device_id ahci_devtype[] = { +- { +- .name = "ahci", +- .driver_data = AHCI, +- }, { +- .name = "imx53-ahci", +- .driver_data = IMX53_AHCI, +- }, { +- .name = "strict-ahci", +- .driver_data = STRICT_AHCI, +- }, { +- /* sentinel */ +- } +-}; +-MODULE_DEVICE_TABLE(platform, ahci_devtype); +- +-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, +- .host_stop = ahci_host_stop, +-}; +- +-static const struct ata_port_info ahci_port_info[] = { +- /* by features */ +- [AHCI] = { +- .flags = AHCI_FLAG_COMMON, +- .pio_mask = ATA_PIO4, +- .udma_mask = ATA_UDMA6, +- .port_ops = &ahci_platform_ops, +- }, +- [IMX53_AHCI] = { +- .flags = AHCI_FLAG_COMMON, +- .pio_mask = ATA_PIO4, +- .udma_mask = ATA_UDMA6, +- .port_ops = &ahci_platform_retry_srst_ops, +- }, +- [STRICT_AHCI] = { +- AHCI_HFLAGS (AHCI_HFLAG_DELAY_ENGINE), +- .flags = AHCI_FLAG_COMMON, +- .pio_mask = ATA_PIO4, +- .udma_mask = ATA_UDMA6, +- .port_ops = &ahci_platform_ops, +- }, +-}; +- +-static struct scsi_host_template ahci_platform_sht = { +- AHCI_SHT("ahci_platform"), ++static const struct ata_port_info ahci_port_info = { ++ .flags = AHCI_FLAG_COMMON, ++ .pio_mask = ATA_PIO4, ++ .udma_mask = ATA_UDMA6, ++ .port_ops = &ahci_platform_ops, + }; + + static int ahci_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + struct ahci_platform_data *pdata = dev_get_platdata(dev); +- const struct platform_device_id *id = platform_get_device_id(pdev); +- struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0]; +- const struct ata_port_info *ppi[] = { &pi, NULL }; + struct ahci_host_priv *hpriv; +- struct ata_host *host; +- struct resource *mem; +- int irq; +- int n_ports; +- int i; + int rc; + +- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!mem) { +- dev_err(dev, "no mmio space\n"); +- return -EINVAL; +- } +- +- irq = platform_get_irq(pdev, 0); +- if (irq <= 0) { +- dev_err(dev, "no irq\n"); +- return -EINVAL; +- } +- +- if (pdata && pdata->ata_port_info) +- pi = *pdata->ata_port_info; +- +- hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); +- if (!hpriv) { +- dev_err(dev, "can't alloc ahci_host_priv\n"); +- return -ENOMEM; +- } +- +- hpriv->flags |= (unsigned long)pi.private_data; ++ hpriv = ahci_platform_get_resources(pdev); ++ if (IS_ERR(hpriv)) ++ return PTR_ERR(hpriv); + +- hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem)); +- if (!hpriv->mmio) { +- dev_err(dev, "can't map %pR\n", mem); +- return -ENOMEM; +- } +- +- hpriv->clk = clk_get(dev, NULL); +- if (IS_ERR(hpriv->clk)) { +- dev_err(dev, "can't get clock\n"); +- } else { +- rc = clk_prepare_enable(hpriv->clk); +- if (rc) { +- dev_err(dev, "clock prepare enable failed"); +- goto free_clk; +- } +- } ++ rc = ahci_platform_enable_resources(hpriv); ++ if (rc) ++ return rc; + + /* + * Some platforms might need to prepare for mmio region access, +@@ -151,69 +52,10 @@ + if (pdata && pdata->init) { + rc = pdata->init(dev, hpriv->mmio); + if (rc) +- goto disable_unprepare_clk; +- } +- +- ahci_save_initial_config(dev, hpriv, +- pdata ? pdata->force_port_map : 0, +- pdata ? pdata->mask_port_map : 0); +- +- /* prepare host */ +- if (hpriv->cap & HOST_CAP_NCQ) +- pi.flags |= ATA_FLAG_NCQ; +- +- if (hpriv->cap & HOST_CAP_PMP) +- pi.flags |= ATA_FLAG_PMP; +- +- ahci_set_em_messages(hpriv, &pi); +- +- /* CAP.NP sometimes indicate the index of the last enabled +- * port, at other times, that of the last possible port, so +- * determining the maximum port number requires looking at +- * both CAP.NP and port_map. +- */ +- n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); +- +- host = ata_host_alloc_pinfo(dev, ppi, n_ports); +- if (!host) { +- rc = -ENOMEM; +- goto pdata_exit; ++ goto disable_resources; + } + +- host->private_data = hpriv; +- +- if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) +- host->flags |= ATA_HOST_PARALLEL_SCAN; +- else +- dev_info(dev, "SSS flag set, parallel bus scan disabled\n"); +- +- if (pi.flags & ATA_FLAG_EM) +- ahci_reset_em(host); +- +- for (i = 0; i < host->n_ports; i++) { +- struct ata_port *ap = host->ports[i]; +- +- ata_port_desc(ap, "mmio %pR", mem); +- ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); +- +- /* set enclosure management message type */ +- if (ap->flags & ATA_FLAG_EM) +- ap->em_message_type = hpriv->em_msg_type; +- +- /* disabled/not-implemented port */ +- if (!(hpriv->port_map & (1 << i))) +- ap->ops = &ata_dummy_port_ops; +- } +- +- rc = ahci_reset_controller(host); +- if (rc) +- goto pdata_exit; +- +- ahci_init_controller(host); +- ahci_print_info(host, "platform"); +- +- rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, +- &ahci_platform_sht); ++ rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info, 0, 0, 0); + if (rc) + goto pdata_exit; + +@@ -221,115 +63,19 @@ + pdata_exit: + if (pdata && pdata->exit) + pdata->exit(dev); +-disable_unprepare_clk: +- if (!IS_ERR(hpriv->clk)) +- clk_disable_unprepare(hpriv->clk); +-free_clk: +- if (!IS_ERR(hpriv->clk)) +- clk_put(hpriv->clk); +- return rc; +-} +- +-static void ahci_host_stop(struct ata_host *host) +-{ +- struct device *dev = host->dev; +- struct ahci_platform_data *pdata = dev_get_platdata(dev); +- struct ahci_host_priv *hpriv = host->private_data; +- +- if (pdata && pdata->exit) +- pdata->exit(dev); +- +- if (!IS_ERR(hpriv->clk)) { +- clk_disable_unprepare(hpriv->clk); +- clk_put(hpriv->clk); +- } +-} +- +-#ifdef CONFIG_PM_SLEEP +-static int ahci_suspend(struct device *dev) +-{ +- struct ahci_platform_data *pdata = dev_get_platdata(dev); +- struct ata_host *host = dev_get_drvdata(dev); +- struct ahci_host_priv *hpriv = host->private_data; +- void __iomem *mmio = hpriv->mmio; +- u32 ctl; +- int rc; +- +- if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { +- dev_err(dev, "firmware update required for suspend/resume\n"); +- return -EIO; +- } +- +- /* +- * AHCI spec rev1.1 section 8.3.3: +- * Software must disable interrupts prior to requesting a +- * transition of the HBA to D3 state. +- */ +- ctl = readl(mmio + HOST_CTL); +- ctl &= ~HOST_IRQ_EN; +- writel(ctl, mmio + HOST_CTL); +- readl(mmio + HOST_CTL); /* flush */ +- +- rc = ata_host_suspend(host, PMSG_SUSPEND); +- if (rc) +- return rc; +- +- if (pdata && pdata->suspend) +- return pdata->suspend(dev); +- +- if (!IS_ERR(hpriv->clk)) +- clk_disable_unprepare(hpriv->clk); +- +- return 0; +-} +- +-static int ahci_resume(struct device *dev) +-{ +- struct ahci_platform_data *pdata = dev_get_platdata(dev); +- struct ata_host *host = dev_get_drvdata(dev); +- struct ahci_host_priv *hpriv = host->private_data; +- int rc; +- +- if (!IS_ERR(hpriv->clk)) { +- rc = clk_prepare_enable(hpriv->clk); +- if (rc) { +- dev_err(dev, "clock prepare enable failed"); +- return rc; +- } +- } +- +- if (pdata && pdata->resume) { +- rc = pdata->resume(dev); +- if (rc) +- goto disable_unprepare_clk; +- } +- +- if (dev->power.power_state.event == PM_EVENT_SUSPEND) { +- rc = ahci_reset_controller(host); +- if (rc) +- goto disable_unprepare_clk; +- +- ahci_init_controller(host); +- } +- +- ata_host_resume(host); +- +- return 0; +- +-disable_unprepare_clk: +- if (!IS_ERR(hpriv->clk)) +- clk_disable_unprepare(hpriv->clk); +- ++disable_resources: ++ ahci_platform_disable_resources(hpriv); + return rc; + } +-#endif + +-static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume); ++static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend, ++ ahci_platform_resume); + + static const struct of_device_id ahci_of_match[] = { + { .compatible = "snps,spear-ahci", }, + { .compatible = "snps,exynos5440-ahci", }, + { .compatible = "ibm,476gtr-ahci", }, ++ { .compatible = "snps,dwc-ahci", }, + {}, + }; + MODULE_DEVICE_TABLE(of, ahci_of_match); +@@ -343,7 +89,6 @@ + .of_match_table = ahci_of_match, + .pm = &ahci_pm_ops, + }, +- .id_table = ahci_devtype, + }; + module_platform_driver(ahci_driver); + +diff -Nur linux-3.14.40.orig/drivers/ata/ata_generic.c linux-3.14.40/drivers/ata/ata_generic.c +--- linux-3.14.40.orig/drivers/ata/ata_generic.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/ata_generic.c 2015-05-01 14:57:58.583427001 -0500 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/Kconfig linux-3.14.40/drivers/ata/Kconfig +--- linux-3.14.40.orig/drivers/ata/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/Kconfig 2015-05-01 14:57:58.655427001 -0500 +@@ -99,7 +99,7 @@ + + config AHCI_IMX + tristate "Freescale i.MX AHCI SATA support" +- depends on SATA_AHCI_PLATFORM && MFD_SYSCON ++ depends on MFD_SYSCON + help + This option enables support for the Freescale i.MX SoC's + onboard AHCI SATA. +diff -Nur linux-3.14.40.orig/drivers/ata/libahci.c linux-3.14.40/drivers/ata/libahci.c +--- linux-3.14.40.orig/drivers/ata/libahci.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/libahci.c 2015-05-01 14:57:58.683427001 -0500 +@@ -35,7 +35,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -394,6 +393,9 @@ + * + * If inconsistent, config values are fixed up by this function. + * ++ * If it is not set already this function sets hpriv->start_engine to ++ * ahci_start_engine. ++ * + * LOCKING: + * None. + */ +@@ -450,11 +452,23 @@ + cap &= ~HOST_CAP_SNTF; + } + ++ if ((cap2 & HOST_CAP2_SDS) && (hpriv->flags & AHCI_HFLAG_NO_DEVSLP)) { ++ dev_info(dev, ++ "controller can't do DEVSLP, turning off\n"); ++ cap2 &= ~HOST_CAP2_SDS; ++ cap2 &= ~HOST_CAP2_SADM; ++ } ++ + if (!(cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_YES_FBS)) { + dev_info(dev, "controller can do FBS, turning on CAP_FBS\n"); + cap |= HOST_CAP_FBS; + } + ++ if ((cap & HOST_CAP_FBS) && (hpriv->flags & AHCI_HFLAG_NO_FBS)) { ++ dev_info(dev, "controller can't do FBS, turning off CAP_FBS\n"); ++ cap &= ~HOST_CAP_FBS; ++ } ++ + if (force_port_map && port_map != force_port_map) { + dev_info(dev, "forcing port_map 0x%x -> 0x%x\n", + port_map, force_port_map); +@@ -500,6 +514,9 @@ + hpriv->cap = cap; + hpriv->cap2 = cap2; + hpriv->port_map = port_map; ++ ++ if (!hpriv->start_engine) ++ hpriv->start_engine = ahci_start_engine; + } + EXPORT_SYMBOL_GPL(ahci_save_initial_config); + +@@ -766,7 +783,7 @@ + + /* enable DMA */ + if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE)) +- ahci_start_engine(ap); ++ hpriv->start_engine(ap); + + /* turn on LEDs */ + if (ap->flags & ATA_FLAG_EM) { +@@ -1234,7 +1251,7 @@ + + /* restart engine */ + out_restart: +- ahci_start_engine(ap); ++ hpriv->start_engine(ap); + return rc; + } + EXPORT_SYMBOL_GPL(ahci_kick_engine); +@@ -1426,6 +1443,7 @@ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + struct ata_port *ap = link->ap; + struct ahci_port_priv *pp = ap->private_data; ++ struct ahci_host_priv *hpriv = ap->host->private_data; + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + struct ata_taskfile tf; + bool online; +@@ -1443,7 +1461,7 @@ + rc = sata_link_hardreset(link, timing, deadline, &online, + ahci_check_ready); + +- ahci_start_engine(ap); ++ hpriv->start_engine(ap); + + if (online) + *class = ahci_dev_classify(ap); +@@ -2007,10 +2025,12 @@ + + void ahci_error_handler(struct ata_port *ap) + { ++ struct ahci_host_priv *hpriv = ap->host->private_data; ++ + if (!(ap->pflags & ATA_PFLAG_FROZEN)) { + /* restart engine */ + ahci_stop_engine(ap); +- ahci_start_engine(ap); ++ hpriv->start_engine(ap); + } + + sata_pmp_error_handler(ap); +@@ -2031,6 +2051,7 @@ + + static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) + { ++ struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *port_mmio = ahci_port_base(ap); + struct ata_device *dev = ap->link.device; + u32 devslp, dm, dito, mdat, deto; +@@ -2094,7 +2115,7 @@ + PORT_DEVSLP_ADSE); + writel(devslp, port_mmio + PORT_DEVSLP); + +- ahci_start_engine(ap); ++ hpriv->start_engine(ap); + + /* enable device sleep feature for the drive */ + err_mask = ata_dev_set_feature(dev, +@@ -2106,6 +2127,7 @@ + + static void ahci_enable_fbs(struct ata_port *ap) + { ++ struct ahci_host_priv *hpriv = ap->host->private_data; + struct ahci_port_priv *pp = ap->private_data; + void __iomem *port_mmio = ahci_port_base(ap); + u32 fbs; +@@ -2134,11 +2156,12 @@ + } else + dev_err(ap->host->dev, "Failed to enable FBS\n"); + +- ahci_start_engine(ap); ++ hpriv->start_engine(ap); + } + + static void ahci_disable_fbs(struct ata_port *ap) + { ++ struct ahci_host_priv *hpriv = ap->host->private_data; + struct ahci_port_priv *pp = ap->private_data; + void __iomem *port_mmio = ahci_port_base(ap); + u32 fbs; +@@ -2166,7 +2189,7 @@ + pp->fbs_enabled = false; + } + +- ahci_start_engine(ap); ++ hpriv->start_engine(ap); + } + + static void ahci_pmp_attach(struct ata_port *ap) +diff -Nur linux-3.14.40.orig/drivers/ata/libahci_platform.c linux-3.14.40/drivers/ata/libahci_platform.c +--- linux-3.14.40.orig/drivers/ata/libahci_platform.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/ata/libahci_platform.c 2015-05-01 14:57:58.683427001 -0500 +@@ -0,0 +1,544 @@ ++/* ++ * AHCI SATA platform library ++ * ++ * Copyright 2004-2005 Red Hat, Inc. ++ * Jeff Garzik ++ * Copyright 2010 MontaVista Software, LLC. ++ * Anton Vorontsov ++ * ++ * 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, or (at your option) ++ * any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ahci.h" ++ ++static void ahci_host_stop(struct ata_host *host); ++ ++struct ata_port_operations ahci_platform_ops = { ++ .inherits = &ahci_ops, ++ .host_stop = ahci_host_stop, ++}; ++EXPORT_SYMBOL_GPL(ahci_platform_ops); ++ ++static struct scsi_host_template ahci_platform_sht = { ++ AHCI_SHT("ahci_platform"), ++}; ++ ++/** ++ * ahci_platform_enable_clks - Enable platform clocks ++ * @hpriv: host private area to store config values ++ * ++ * This function enables all the clks found in hpriv->clks, starting at ++ * index 0. If any clk fails to enable it disables all the clks already ++ * enabled in reverse order, and then returns an error. ++ * ++ * RETURNS: ++ * 0 on success otherwise a negative error code ++ */ ++int ahci_platform_enable_clks(struct ahci_host_priv *hpriv) ++{ ++ int c, rc; ++ ++ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) { ++ rc = clk_prepare_enable(hpriv->clks[c]); ++ if (rc) ++ goto disable_unprepare_clk; ++ } ++ return 0; ++ ++disable_unprepare_clk: ++ while (--c >= 0) ++ clk_disable_unprepare(hpriv->clks[c]); ++ return rc; ++} ++EXPORT_SYMBOL_GPL(ahci_platform_enable_clks); ++ ++/** ++ * ahci_platform_disable_clks - Disable platform clocks ++ * @hpriv: host private area to store config values ++ * ++ * This function disables all the clks found in hpriv->clks, in reverse ++ * order of ahci_platform_enable_clks (starting at the end of the array). ++ */ ++void ahci_platform_disable_clks(struct ahci_host_priv *hpriv) ++{ ++ int c; ++ ++ for (c = AHCI_MAX_CLKS - 1; c >= 0; c--) ++ if (hpriv->clks[c]) ++ clk_disable_unprepare(hpriv->clks[c]); ++} ++EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); ++ ++/** ++ * ahci_platform_enable_resources - Enable platform resources ++ * @hpriv: host private area to store config values ++ * ++ * This function enables all ahci_platform managed resources in the ++ * following order: ++ * 1) Regulator ++ * 2) Clocks (through ahci_platform_enable_clks) ++ * 3) Phy ++ * ++ * If resource enabling fails at any point the previous enabled resources ++ * are disabled in reverse order. ++ * ++ * RETURNS: ++ * 0 on success otherwise a negative error code ++ */ ++int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) ++{ ++ int rc; ++ ++ if (hpriv->target_pwr) { ++ rc = regulator_enable(hpriv->target_pwr); ++ if (rc) ++ return rc; ++ } ++ ++ rc = ahci_platform_enable_clks(hpriv); ++ if (rc) ++ goto disable_regulator; ++ ++ if (hpriv->phy) { ++ rc = phy_init(hpriv->phy); ++ if (rc) ++ goto disable_clks; ++ ++ rc = phy_power_on(hpriv->phy); ++ if (rc) { ++ phy_exit(hpriv->phy); ++ goto disable_clks; ++ } ++ } ++ ++ return 0; ++ ++disable_clks: ++ ahci_platform_disable_clks(hpriv); ++ ++disable_regulator: ++ if (hpriv->target_pwr) ++ regulator_disable(hpriv->target_pwr); ++ return rc; ++} ++EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); ++ ++/** ++ * ahci_platform_disable_resources - Disable platform resources ++ * @hpriv: host private area to store config values ++ * ++ * This function disables all ahci_platform managed resources in the ++ * following order: ++ * 1) Phy ++ * 2) Clocks (through ahci_platform_disable_clks) ++ * 3) Regulator ++ */ ++void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) ++{ ++ if (hpriv->phy) { ++ phy_power_off(hpriv->phy); ++ phy_exit(hpriv->phy); ++ } ++ ++ ahci_platform_disable_clks(hpriv); ++ ++ if (hpriv->target_pwr) ++ regulator_disable(hpriv->target_pwr); ++} ++EXPORT_SYMBOL_GPL(ahci_platform_disable_resources); ++ ++static void ahci_platform_put_resources(struct device *dev, void *res) ++{ ++ struct ahci_host_priv *hpriv = res; ++ int c; ++ ++ if (hpriv->got_runtime_pm) { ++ pm_runtime_put_sync(dev); ++ pm_runtime_disable(dev); ++ } ++ ++ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) ++ clk_put(hpriv->clks[c]); ++} ++ ++/** ++ * ahci_platform_get_resources - Get platform resources ++ * @pdev: platform device to get resources for ++ * ++ * This function allocates an ahci_host_priv struct, and gets the following ++ * resources, storing a reference to them inside the returned struct: ++ * ++ * 1) mmio registers (IORESOURCE_MEM 0, mandatory) ++ * 2) regulator for controlling the targets power (optional) ++ * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, ++ * or for non devicetree enabled platforms a single clock ++ * 4) phy (optional) ++ * ++ * RETURNS: ++ * The allocated ahci_host_priv on success, otherwise an ERR_PTR value ++ */ ++struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ahci_host_priv *hpriv; ++ struct clk *clk; ++ int i, rc = -ENOMEM; ++ ++ if (!devres_open_group(dev, NULL, GFP_KERNEL)) ++ return ERR_PTR(-ENOMEM); ++ ++ hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv), ++ GFP_KERNEL); ++ if (!hpriv) ++ goto err_out; ++ ++ devres_add(dev, hpriv); ++ ++ hpriv->mmio = devm_ioremap_resource(dev, ++ platform_get_resource(pdev, IORESOURCE_MEM, 0)); ++ if (IS_ERR(hpriv->mmio)) { ++ dev_err(dev, "no mmio space\n"); ++ rc = PTR_ERR(hpriv->mmio); ++ goto err_out; ++ } ++ ++ hpriv->target_pwr = devm_regulator_get_optional(dev, "target"); ++ if (IS_ERR(hpriv->target_pwr)) { ++ rc = PTR_ERR(hpriv->target_pwr); ++ if (rc == -EPROBE_DEFER) ++ goto err_out; ++ hpriv->target_pwr = NULL; ++ } ++ ++ for (i = 0; i < AHCI_MAX_CLKS; i++) { ++ /* ++ * For now we must use clk_get(dev, NULL) for the first clock, ++ * because some platforms (da850, spear13xx) are not yet ++ * converted to use devicetree for clocks. For new platforms ++ * this is equivalent to of_clk_get(dev->of_node, 0). ++ */ ++ if (i == 0) ++ clk = clk_get(dev, NULL); ++ else ++ clk = of_clk_get(dev->of_node, i); ++ ++ if (IS_ERR(clk)) { ++ rc = PTR_ERR(clk); ++ if (rc == -EPROBE_DEFER) ++ goto err_out; ++ break; ++ } ++ hpriv->clks[i] = clk; ++ } ++ ++ hpriv->phy = devm_phy_get(dev, "sata-phy"); ++ if (IS_ERR(hpriv->phy)) { ++ rc = PTR_ERR(hpriv->phy); ++ switch (rc) { ++ case -ENODEV: ++ case -ENOSYS: ++ /* continue normally */ ++ hpriv->phy = NULL; ++ break; ++ ++ case -EPROBE_DEFER: ++ goto err_out; ++ ++ default: ++ dev_err(dev, "couldn't get sata-phy\n"); ++ goto err_out; ++ } ++ } ++ ++ pm_runtime_enable(dev); ++ pm_runtime_get_sync(dev); ++ hpriv->got_runtime_pm = true; ++ ++ devres_remove_group(dev, NULL); ++ return hpriv; ++ ++err_out: ++ devres_release_group(dev, NULL); ++ return ERR_PTR(rc); ++} ++EXPORT_SYMBOL_GPL(ahci_platform_get_resources); ++ ++/** ++ * ahci_platform_init_host - Bring up an ahci-platform host ++ * @pdev: platform device pointer for the host ++ * @hpriv: ahci-host private data for the host ++ * @pi_template: template for the ata_port_info to use ++ * @host_flags: ahci host flags used in ahci_host_priv ++ * @force_port_map: param passed to ahci_save_initial_config ++ * @mask_port_map: param passed to ahci_save_initial_config ++ * ++ * This function does all the usual steps needed to bring up an ++ * ahci-platform host, note any necessary resources (ie clks, phy, etc.) ++ * must be initialized / enabled before calling this. ++ * ++ * RETURNS: ++ * 0 on success otherwise a negative error code ++ */ ++int ahci_platform_init_host(struct platform_device *pdev, ++ struct ahci_host_priv *hpriv, ++ const struct ata_port_info *pi_template, ++ unsigned long host_flags, ++ unsigned int force_port_map, ++ unsigned int mask_port_map) ++{ ++ struct device *dev = &pdev->dev; ++ struct ata_port_info pi = *pi_template; ++ const struct ata_port_info *ppi[] = { &pi, NULL }; ++ struct ata_host *host; ++ int i, irq, n_ports, rc; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq <= 0) { ++ dev_err(dev, "no irq\n"); ++ return -EINVAL; ++ } ++ ++ /* prepare host */ ++ pi.private_data = (void *)host_flags; ++ hpriv->flags |= host_flags; ++ ++ ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map); ++ ++ if (hpriv->cap & HOST_CAP_NCQ) ++ pi.flags |= ATA_FLAG_NCQ; ++ ++ if (hpriv->cap & HOST_CAP_PMP) ++ pi.flags |= ATA_FLAG_PMP; ++ ++ ahci_set_em_messages(hpriv, &pi); ++ ++ /* CAP.NP sometimes indicate the index of the last enabled ++ * port, at other times, that of the last possible port, so ++ * determining the maximum port number requires looking at ++ * both CAP.NP and port_map. ++ */ ++ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); ++ ++ host = ata_host_alloc_pinfo(dev, ppi, n_ports); ++ if (!host) ++ return -ENOMEM; ++ ++ host->private_data = hpriv; ++ ++ if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) ++ host->flags |= ATA_HOST_PARALLEL_SCAN; ++ else ++ dev_info(dev, "SSS flag set, parallel bus scan disabled\n"); ++ ++ if (pi.flags & ATA_FLAG_EM) ++ ahci_reset_em(host); ++ ++ for (i = 0; i < host->n_ports; i++) { ++ struct ata_port *ap = host->ports[i]; ++ ++ ata_port_desc(ap, "mmio %pR", ++ platform_get_resource(pdev, IORESOURCE_MEM, 0)); ++ ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); ++ ++ /* set enclosure management message type */ ++ if (ap->flags & ATA_FLAG_EM) ++ ap->em_message_type = hpriv->em_msg_type; ++ ++ /* disabled/not-implemented port */ ++ if (!(hpriv->port_map & (1 << i))) ++ ap->ops = &ata_dummy_port_ops; ++ } ++ ++ rc = ahci_reset_controller(host); ++ if (rc) ++ return rc; ++ ++ ahci_init_controller(host); ++ ahci_print_info(host, "platform"); ++ ++ return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, ++ &ahci_platform_sht); ++} ++EXPORT_SYMBOL_GPL(ahci_platform_init_host); ++ ++static void ahci_host_stop(struct ata_host *host) ++{ ++ struct device *dev = host->dev; ++ struct ahci_platform_data *pdata = dev_get_platdata(dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ ++ if (pdata && pdata->exit) ++ pdata->exit(dev); ++ ++ ahci_platform_disable_resources(hpriv); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++/** ++ * ahci_platform_suspend_host - Suspend an ahci-platform host ++ * @dev: device pointer for the host ++ * ++ * This function does all the usual steps needed to suspend an ++ * ahci-platform host, note any necessary resources (ie clks, phy, etc.) ++ * must be disabled after calling this. ++ * ++ * RETURNS: ++ * 0 on success otherwise a negative error code ++ */ ++int ahci_platform_suspend_host(struct device *dev) ++{ ++ struct ata_host *host = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ void __iomem *mmio = hpriv->mmio; ++ u32 ctl; ++ ++ if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { ++ dev_err(dev, "firmware update required for suspend/resume\n"); ++ return -EIO; ++ } ++ ++ /* ++ * AHCI spec rev1.1 section 8.3.3: ++ * Software must disable interrupts prior to requesting a ++ * transition of the HBA to D3 state. ++ */ ++ ctl = readl(mmio + HOST_CTL); ++ ctl &= ~HOST_IRQ_EN; ++ writel(ctl, mmio + HOST_CTL); ++ readl(mmio + HOST_CTL); /* flush */ ++ ++ return ata_host_suspend(host, PMSG_SUSPEND); ++} ++EXPORT_SYMBOL_GPL(ahci_platform_suspend_host); ++ ++/** ++ * ahci_platform_resume_host - Resume an ahci-platform host ++ * @dev: device pointer for the host ++ * ++ * This function does all the usual steps needed to resume an ahci-platform ++ * host, note any necessary resources (ie clks, phy, etc.) must be ++ * initialized / enabled before calling this. ++ * ++ * RETURNS: ++ * 0 on success otherwise a negative error code ++ */ ++int ahci_platform_resume_host(struct device *dev) ++{ ++ struct ata_host *host = dev_get_drvdata(dev); ++ int rc; ++ ++ if (dev->power.power_state.event == PM_EVENT_SUSPEND) { ++ rc = ahci_reset_controller(host); ++ if (rc) ++ return rc; ++ ++ ahci_init_controller(host); ++ } ++ ++ ata_host_resume(host); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ahci_platform_resume_host); ++ ++/** ++ * ahci_platform_suspend - Suspend an ahci-platform device ++ * @dev: the platform device to suspend ++ * ++ * This function suspends the host associated with the device, followed by ++ * disabling all the resources of the device. ++ * ++ * RETURNS: ++ * 0 on success otherwise a negative error code ++ */ ++int ahci_platform_suspend(struct device *dev) ++{ ++ struct ahci_platform_data *pdata = dev_get_platdata(dev); ++ struct ata_host *host = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ int rc; ++ ++ rc = ahci_platform_suspend_host(dev); ++ if (rc) ++ return rc; ++ ++ if (pdata && pdata->suspend) { ++ rc = pdata->suspend(dev); ++ if (rc) ++ goto resume_host; ++ } ++ ++ ahci_platform_disable_resources(hpriv); ++ ++ return 0; ++ ++resume_host: ++ ahci_platform_resume_host(dev); ++ return rc; ++} ++EXPORT_SYMBOL_GPL(ahci_platform_suspend); ++ ++/** ++ * ahci_platform_resume - Resume an ahci-platform device ++ * @dev: the platform device to resume ++ * ++ * This function enables all the resources of the device followed by ++ * resuming the host associated with the device. ++ * ++ * RETURNS: ++ * 0 on success otherwise a negative error code ++ */ ++int ahci_platform_resume(struct device *dev) ++{ ++ struct ahci_platform_data *pdata = dev_get_platdata(dev); ++ struct ata_host *host = dev_get_drvdata(dev); ++ struct ahci_host_priv *hpriv = host->private_data; ++ int rc; ++ ++ rc = ahci_platform_enable_resources(hpriv); ++ if (rc) ++ return rc; ++ ++ if (pdata && pdata->resume) { ++ rc = pdata->resume(dev); ++ if (rc) ++ goto disable_resources; ++ } ++ ++ rc = ahci_platform_resume_host(dev); ++ if (rc) ++ goto disable_resources; ++ ++ /* We resumed so update PM runtime state */ ++ pm_runtime_disable(dev); ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ ++ return 0; ++ ++disable_resources: ++ ahci_platform_disable_resources(hpriv); ++ ++ return rc; ++} ++EXPORT_SYMBOL_GPL(ahci_platform_resume); ++#endif ++ ++MODULE_DESCRIPTION("AHCI SATA platform library"); ++MODULE_AUTHOR("Anton Vorontsov "); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.40.orig/drivers/ata/libata-core.c linux-3.14.40/drivers/ata/libata-core.c +--- linux-3.14.40.orig/drivers/ata/libata-core.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/libata-core.c 2015-05-01 14:57:58.703427001 -0500 +@@ -1524,7 +1524,7 @@ + * @dev: Device to which the command is sent + * @tf: Taskfile registers for the command and the result + * @cdb: CDB for packet command +- * @dma_dir: Data tranfer direction of the command ++ * @dma_dir: Data transfer direction of the command + * @sgl: sg list for the data buffer of the command + * @n_elem: Number of sg entries + * @timeout: Timeout in msecs (0 for default) +@@ -1712,7 +1712,7 @@ + * @dev: Device to which the command is sent + * @tf: Taskfile registers for the command and the result + * @cdb: CDB for packet command +- * @dma_dir: Data tranfer direction of the command ++ * @dma_dir: Data transfer direction of the command + * @buf: Data buffer of the command + * @buflen: Length of data buffer + * @timeout: Timeout in msecs (0 for default) +diff -Nur linux-3.14.40.orig/drivers/ata/Makefile linux-3.14.40/drivers/ata/Makefile +--- linux-3.14.40.orig/drivers/ata/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/Makefile 2015-05-01 14:57:58.703427001 -0500 +@@ -4,13 +4,13 @@ + # non-SFF interface + obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o + obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o +-obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o ++obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o + obj-$(CONFIG_SATA_FSL) += sata_fsl.o + obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o + 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 ++obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o + + # SFF w/ custom DMA + obj-$(CONFIG_PDC_ADMA) += pdc_adma.o +diff -Nur linux-3.14.40.orig/drivers/ata/pata_acpi.c linux-3.14.40/drivers/ata/pata_acpi.c +--- linux-3.14.40.orig/drivers/ata/pata_acpi.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_acpi.c 2015-05-01 14:57:58.703427001 -0500 +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_amd.c linux-3.14.40/drivers/ata/pata_amd.c +--- linux-3.14.40.orig/drivers/ata/pata_amd.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_amd.c 2015-05-01 14:57:58.703427001 -0500 +@@ -17,7 +17,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_artop.c linux-3.14.40/drivers/ata/pata_artop.c +--- linux-3.14.40.orig/drivers/ata/pata_artop.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_artop.c 2015-05-01 14:57:58.703427001 -0500 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_at91.c linux-3.14.40/drivers/ata/pata_at91.c +--- linux-3.14.40.orig/drivers/ata/pata_at91.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_at91.c 2015-05-01 14:57:58.703427001 -0500 +@@ -18,7 +18,6 @@ + + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_atiixp.c linux-3.14.40/drivers/ata/pata_atiixp.c +--- linux-3.14.40.orig/drivers/ata/pata_atiixp.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_atiixp.c 2015-05-01 14:57:58.707427001 -0500 +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_atp867x.c linux-3.14.40/drivers/ata/pata_atp867x.c +--- linux-3.14.40.orig/drivers/ata/pata_atp867x.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_atp867x.c 2015-05-01 14:57:58.707427001 -0500 +@@ -29,7 +29,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_cmd640.c linux-3.14.40/drivers/ata/pata_cmd640.c +--- linux-3.14.40.orig/drivers/ata/pata_cmd640.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_cmd640.c 2015-05-01 14:57:58.707427001 -0500 +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_cmd64x.c linux-3.14.40/drivers/ata/pata_cmd64x.c +--- linux-3.14.40.orig/drivers/ata/pata_cmd64x.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_cmd64x.c 2015-05-01 14:57:58.707427001 -0500 +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_cs5520.c linux-3.14.40/drivers/ata/pata_cs5520.c +--- linux-3.14.40.orig/drivers/ata/pata_cs5520.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_cs5520.c 2015-05-01 14:57:58.707427001 -0500 +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_cs5530.c linux-3.14.40/drivers/ata/pata_cs5530.c +--- linux-3.14.40.orig/drivers/ata/pata_cs5530.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_cs5530.c 2015-05-01 14:57:58.707427001 -0500 +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_cs5535.c linux-3.14.40/drivers/ata/pata_cs5535.c +--- linux-3.14.40.orig/drivers/ata/pata_cs5535.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_cs5535.c 2015-05-01 14:57:58.707427001 -0500 +@@ -31,7 +31,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_cs5536.c linux-3.14.40/drivers/ata/pata_cs5536.c +--- linux-3.14.40.orig/drivers/ata/pata_cs5536.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_cs5536.c 2015-05-01 14:57:58.707427001 -0500 +@@ -33,7 +33,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_cypress.c linux-3.14.40/drivers/ata/pata_cypress.c +--- linux-3.14.40.orig/drivers/ata/pata_cypress.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_cypress.c 2015-05-01 14:57:58.707427001 -0500 +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_efar.c linux-3.14.40/drivers/ata/pata_efar.c +--- linux-3.14.40.orig/drivers/ata/pata_efar.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_efar.c 2015-05-01 14:57:58.707427001 -0500 +@@ -14,7 +14,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_ep93xx.c linux-3.14.40/drivers/ata/pata_ep93xx.c +--- linux-3.14.40.orig/drivers/ata/pata_ep93xx.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_ep93xx.c 2015-05-01 14:57:58.711427001 -0500 +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_hpt366.c linux-3.14.40/drivers/ata/pata_hpt366.c +--- linux-3.14.40.orig/drivers/ata/pata_hpt366.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_hpt366.c 2015-05-01 14:57:58.711427001 -0500 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_hpt37x.c linux-3.14.40/drivers/ata/pata_hpt37x.c +--- linux-3.14.40.orig/drivers/ata/pata_hpt37x.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_hpt37x.c 2015-05-01 14:57:58.735427001 -0500 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_hpt3x2n.c linux-3.14.40/drivers/ata/pata_hpt3x2n.c +--- linux-3.14.40.orig/drivers/ata/pata_hpt3x2n.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_hpt3x2n.c 2015-05-01 14:57:58.739427001 -0500 +@@ -20,7 +20,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_hpt3x3.c linux-3.14.40/drivers/ata/pata_hpt3x3.c +--- linux-3.14.40.orig/drivers/ata/pata_hpt3x3.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_hpt3x3.c 2015-05-01 14:57:58.739427001 -0500 +@@ -16,7 +16,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_imx.c linux-3.14.40/drivers/ata/pata_imx.c +--- linux-3.14.40.orig/drivers/ata/pata_imx.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_imx.c 2015-05-01 14:57:58.739427001 -0500 +@@ -15,7 +15,6 @@ + */ + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_it8213.c linux-3.14.40/drivers/ata/pata_it8213.c +--- linux-3.14.40.orig/drivers/ata/pata_it8213.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_it8213.c 2015-05-01 14:57:58.767427001 -0500 +@@ -10,7 +10,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_it821x.c linux-3.14.40/drivers/ata/pata_it821x.c +--- linux-3.14.40.orig/drivers/ata/pata_it821x.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_it821x.c 2015-05-01 14:57:58.767427001 -0500 +@@ -72,7 +72,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_jmicron.c linux-3.14.40/drivers/ata/pata_jmicron.c +--- linux-3.14.40.orig/drivers/ata/pata_jmicron.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_jmicron.c 2015-05-01 14:57:58.767427001 -0500 +@@ -10,7 +10,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_marvell.c linux-3.14.40/drivers/ata/pata_marvell.c +--- linux-3.14.40.orig/drivers/ata/pata_marvell.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_marvell.c 2015-05-01 14:57:58.767427001 -0500 +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_mpiix.c linux-3.14.40/drivers/ata/pata_mpiix.c +--- linux-3.14.40.orig/drivers/ata/pata_mpiix.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_mpiix.c 2015-05-01 14:57:58.767427001 -0500 +@@ -28,7 +28,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_netcell.c linux-3.14.40/drivers/ata/pata_netcell.c +--- linux-3.14.40.orig/drivers/ata/pata_netcell.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_netcell.c 2015-05-01 14:57:58.767427001 -0500 +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_ninja32.c linux-3.14.40/drivers/ata/pata_ninja32.c +--- linux-3.14.40.orig/drivers/ata/pata_ninja32.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_ninja32.c 2015-05-01 14:57:58.767427001 -0500 +@@ -37,7 +37,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_ns87410.c linux-3.14.40/drivers/ata/pata_ns87410.c +--- linux-3.14.40.orig/drivers/ata/pata_ns87410.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_ns87410.c 2015-05-01 14:57:58.771427001 -0500 +@@ -20,7 +20,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_ns87415.c linux-3.14.40/drivers/ata/pata_ns87415.c +--- linux-3.14.40.orig/drivers/ata/pata_ns87415.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_ns87415.c 2015-05-01 14:57:58.771427001 -0500 +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_oldpiix.c linux-3.14.40/drivers/ata/pata_oldpiix.c +--- linux-3.14.40.orig/drivers/ata/pata_oldpiix.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_oldpiix.c 2015-05-01 14:57:58.771427001 -0500 +@@ -16,7 +16,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_opti.c linux-3.14.40/drivers/ata/pata_opti.c +--- linux-3.14.40.orig/drivers/ata/pata_opti.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_opti.c 2015-05-01 14:57:58.771427001 -0500 +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_optidma.c linux-3.14.40/drivers/ata/pata_optidma.c +--- linux-3.14.40.orig/drivers/ata/pata_optidma.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_optidma.c 2015-05-01 14:57:58.771427001 -0500 +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_pcmcia.c linux-3.14.40/drivers/ata/pata_pcmcia.c +--- linux-3.14.40.orig/drivers/ata/pata_pcmcia.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_pcmcia.c 2015-05-01 14:57:58.771427001 -0500 +@@ -26,7 +26,6 @@ + + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_pdc2027x.c linux-3.14.40/drivers/ata/pata_pdc2027x.c +--- linux-3.14.40.orig/drivers/ata/pata_pdc2027x.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_pdc2027x.c 2015-05-01 14:57:58.771427001 -0500 +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_pdc202xx_old.c linux-3.14.40/drivers/ata/pata_pdc202xx_old.c +--- linux-3.14.40.orig/drivers/ata/pata_pdc202xx_old.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_pdc202xx_old.c 2015-05-01 14:57:58.771427001 -0500 +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_piccolo.c linux-3.14.40/drivers/ata/pata_piccolo.c +--- linux-3.14.40.orig/drivers/ata/pata_piccolo.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_piccolo.c 2015-05-01 14:57:58.771427001 -0500 +@@ -18,7 +18,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_platform.c linux-3.14.40/drivers/ata/pata_platform.c +--- linux-3.14.40.orig/drivers/ata/pata_platform.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_platform.c 2015-05-01 14:57:58.771427001 -0500 +@@ -13,7 +13,6 @@ + */ + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_pxa.c linux-3.14.40/drivers/ata/pata_pxa.c +--- linux-3.14.40.orig/drivers/ata/pata_pxa.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_pxa.c 2015-05-01 14:57:58.771427001 -0500 +@@ -20,7 +20,6 @@ + + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_radisys.c linux-3.14.40/drivers/ata/pata_radisys.c +--- linux-3.14.40.orig/drivers/ata/pata_radisys.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_radisys.c 2015-05-01 14:57:58.775427001 -0500 +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_rdc.c linux-3.14.40/drivers/ata/pata_rdc.c +--- linux-3.14.40.orig/drivers/ata/pata_rdc.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_rdc.c 2015-05-01 14:57:58.775427001 -0500 +@@ -24,7 +24,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_rz1000.c linux-3.14.40/drivers/ata/pata_rz1000.c +--- linux-3.14.40.orig/drivers/ata/pata_rz1000.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_rz1000.c 2015-05-01 14:57:58.775427001 -0500 +@@ -14,7 +14,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_sc1200.c linux-3.14.40/drivers/ata/pata_sc1200.c +--- linux-3.14.40.orig/drivers/ata/pata_sc1200.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_sc1200.c 2015-05-01 14:57:58.775427001 -0500 +@@ -32,7 +32,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_scc.c linux-3.14.40/drivers/ata/pata_scc.c +--- linux-3.14.40.orig/drivers/ata/pata_scc.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_scc.c 2015-05-01 14:57:58.775427001 -0500 +@@ -35,7 +35,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_sch.c linux-3.14.40/drivers/ata/pata_sch.c +--- linux-3.14.40.orig/drivers/ata/pata_sch.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_sch.c 2015-05-01 14:57:58.775427001 -0500 +@@ -27,7 +27,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_serverworks.c linux-3.14.40/drivers/ata/pata_serverworks.c +--- linux-3.14.40.orig/drivers/ata/pata_serverworks.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_serverworks.c 2015-05-01 14:57:58.775427001 -0500 +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_sil680.c linux-3.14.40/drivers/ata/pata_sil680.c +--- linux-3.14.40.orig/drivers/ata/pata_sil680.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_sil680.c 2015-05-01 14:57:58.775427001 -0500 +@@ -25,7 +25,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_sis.c linux-3.14.40/drivers/ata/pata_sis.c +--- linux-3.14.40.orig/drivers/ata/pata_sis.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_sis.c 2015-05-01 14:57:58.775427001 -0500 +@@ -26,7 +26,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_sl82c105.c linux-3.14.40/drivers/ata/pata_sl82c105.c +--- linux-3.14.40.orig/drivers/ata/pata_sl82c105.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_sl82c105.c 2015-05-01 14:57:58.775427001 -0500 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_triflex.c linux-3.14.40/drivers/ata/pata_triflex.c +--- linux-3.14.40.orig/drivers/ata/pata_triflex.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_triflex.c 2015-05-01 14:57:58.779427001 -0500 +@@ -36,7 +36,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pata_via.c linux-3.14.40/drivers/ata/pata_via.c +--- linux-3.14.40.orig/drivers/ata/pata_via.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pata_via.c 2015-05-01 14:57:58.779427001 -0500 +@@ -55,7 +55,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/pdc_adma.c linux-3.14.40/drivers/ata/pdc_adma.c +--- linux-3.14.40.orig/drivers/ata/pdc_adma.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/pdc_adma.c 2015-05-01 14:57:58.779427001 -0500 +@@ -36,7 +36,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/sata_dwc_460ex.c linux-3.14.40/drivers/ata/sata_dwc_460ex.c +--- linux-3.14.40.orig/drivers/ata/sata_dwc_460ex.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_dwc_460ex.c 2015-05-01 14:57:58.779427001 -0500 +@@ -29,7 +29,6 @@ + + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/sata_highbank.c linux-3.14.40/drivers/ata/sata_highbank.c +--- linux-3.14.40.orig/drivers/ata/sata_highbank.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_highbank.c 2015-05-01 14:57:58.779427001 -0500 +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -403,6 +402,7 @@ + static const unsigned long timing[] = { 5, 100, 500}; + struct ata_port *ap = link->ap; + struct ahci_port_priv *pp = ap->private_data; ++ struct ahci_host_priv *hpriv = ap->host->private_data; + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; + struct ata_taskfile tf; + bool online; +@@ -431,7 +431,7 @@ + break; + } while (!online && retry--); + +- ahci_start_engine(ap); ++ hpriv->start_engine(ap); + + if (online) + *class = ahci_dev_classify(ap); +diff -Nur linux-3.14.40.orig/drivers/ata/sata_nv.c linux-3.14.40/drivers/ata/sata_nv.c +--- linux-3.14.40.orig/drivers/ata/sata_nv.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_nv.c 2015-05-01 14:57:58.779427001 -0500 +@@ -40,7 +40,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/sata_promise.c linux-3.14.40/drivers/ata/sata_promise.c +--- linux-3.14.40.orig/drivers/ata/sata_promise.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_promise.c 2015-05-01 14:57:58.783427001 -0500 +@@ -35,7 +35,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/sata_qstor.c linux-3.14.40/drivers/ata/sata_qstor.c +--- linux-3.14.40.orig/drivers/ata/sata_qstor.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_qstor.c 2015-05-01 14:57:58.783427001 -0500 +@@ -31,7 +31,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/sata_sil.c linux-3.14.40/drivers/ata/sata_sil.c +--- linux-3.14.40.orig/drivers/ata/sata_sil.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_sil.c 2015-05-01 14:57:58.783427001 -0500 +@@ -37,7 +37,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/sata_sis.c linux-3.14.40/drivers/ata/sata_sis.c +--- linux-3.14.40.orig/drivers/ata/sata_sis.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_sis.c 2015-05-01 14:57:58.783427001 -0500 +@@ -33,7 +33,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/sata_svw.c linux-3.14.40/drivers/ata/sata_svw.c +--- linux-3.14.40.orig/drivers/ata/sata_svw.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_svw.c 2015-05-01 14:57:58.783427001 -0500 +@@ -39,7 +39,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/sata_sx4.c linux-3.14.40/drivers/ata/sata_sx4.c +--- linux-3.14.40.orig/drivers/ata/sata_sx4.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_sx4.c 2015-05-01 14:57:58.783427001 -0500 +@@ -82,7 +82,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/sata_uli.c linux-3.14.40/drivers/ata/sata_uli.c +--- linux-3.14.40.orig/drivers/ata/sata_uli.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_uli.c 2015-05-01 14:57:58.783427001 -0500 +@@ -28,7 +28,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/sata_via.c linux-3.14.40/drivers/ata/sata_via.c +--- linux-3.14.40.orig/drivers/ata/sata_via.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_via.c 2015-05-01 14:57:58.783427001 -0500 +@@ -36,7 +36,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/ata/sata_vsc.c linux-3.14.40/drivers/ata/sata_vsc.c +--- linux-3.14.40.orig/drivers/ata/sata_vsc.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/ata/sata_vsc.c 2015-05-01 14:57:58.787427001 -0500 +@@ -37,7 +37,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff -Nur linux-3.14.40.orig/drivers/base/bus.c linux-3.14.40/drivers/base/bus.c +--- linux-3.14.40.orig/drivers/base/bus.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/base/bus.c 2015-05-01 14:57:58.803427001 -0500 +@@ -1220,7 +1220,7 @@ + * with the name of the subsystem. The root device can carry subsystem- + * wide attributes. All registered devices are below this single root + * device and are named after the subsystem with a simple enumeration +- * number appended. The registered devices are not explicitely named; ++ * number appended. The registered devices are not explicitly named; + * only 'id' in the device needs to be set. + * + * Do not use this interface for anything new, it exists for compatibility +diff -Nur linux-3.14.40.orig/drivers/base/cpu.c linux-3.14.40/drivers/base/cpu.c +--- linux-3.14.40.orig/drivers/base/cpu.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/base/cpu.c 2015-05-01 14:57:58.811427001 -0500 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #include "base.h" + +@@ -286,6 +287,45 @@ + */ + } + ++#ifdef CONFIG_HAVE_CPU_AUTOPROBE ++#ifdef CONFIG_GENERIC_CPU_AUTOPROBE ++static ssize_t print_cpu_modalias(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ ssize_t n; ++ u32 i; ++ ++ n = sprintf(buf, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:", ++ CPU_FEATURE_TYPEVAL); ++ ++ for (i = 0; i < MAX_CPU_FEATURES; i++) ++ if (cpu_have_feature(i)) { ++ if (PAGE_SIZE < n + sizeof(",XXXX\n")) { ++ WARN(1, "CPU features overflow page\n"); ++ break; ++ } ++ n += sprintf(&buf[n], ",%04X", i); ++ } ++ buf[n++] = '\n'; ++ return n; ++} ++#else ++#define print_cpu_modalias arch_print_cpu_modalias ++#endif ++ ++static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env) ++{ ++ char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); ++ if (buf) { ++ print_cpu_modalias(NULL, NULL, buf); ++ add_uevent_var(env, "MODALIAS=%s", buf); ++ kfree(buf); ++ } ++ return 0; ++} ++#endif ++ + /* + * register_cpu - Setup a sysfs device for a CPU. + * @cpu - cpu->hotpluggable field set to 1 will generate a control file in +@@ -306,8 +346,8 @@ + cpu->dev.offline_disabled = !cpu->hotpluggable; + cpu->dev.offline = !cpu_online(num); + cpu->dev.of_node = of_get_cpu_node(num, NULL); +-#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE +- cpu->dev.bus->uevent = arch_cpu_uevent; ++#ifdef CONFIG_HAVE_CPU_AUTOPROBE ++ cpu->dev.bus->uevent = cpu_uevent; + #endif + cpu->dev.groups = common_cpu_attr_groups; + if (cpu->hotpluggable) +@@ -330,8 +370,8 @@ + } + EXPORT_SYMBOL_GPL(get_cpu_device); + +-#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE +-static DEVICE_ATTR(modalias, 0444, arch_print_cpu_modalias, NULL); ++#ifdef CONFIG_HAVE_CPU_AUTOPROBE ++static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL); + #endif + + static struct attribute *cpu_root_attrs[] = { +@@ -344,7 +384,7 @@ + &cpu_attrs[2].attr.attr, + &dev_attr_kernel_max.attr, + &dev_attr_offline.attr, +-#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE ++#ifdef CONFIG_HAVE_CPU_AUTOPROBE + &dev_attr_modalias.attr, + #endif + NULL +diff -Nur linux-3.14.40.orig/drivers/base/dma-buf.c linux-3.14.40/drivers/base/dma-buf.c +--- linux-3.14.40.orig/drivers/base/dma-buf.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/base/dma-buf.c 2015-05-01 14:57:58.811427001 -0500 +@@ -251,9 +251,8 @@ + * @dmabuf: [in] buffer to attach device to. + * @dev: [in] device to be attached. + * +- * Returns struct dma_buf_attachment * for this attachment; may return negative +- * error codes. +- * ++ * Returns struct dma_buf_attachment * for this attachment; returns ERR_PTR on ++ * error. + */ + struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, + struct device *dev) +@@ -319,9 +318,8 @@ + * @attach: [in] attachment whose scatterlist is to be returned + * @direction: [in] direction of DMA transfer + * +- * Returns sg_table containing the scatterlist to be returned; may return NULL +- * or ERR_PTR. +- * ++ * Returns sg_table containing the scatterlist to be returned; returns ERR_PTR ++ * on error. + */ + struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, + enum dma_data_direction direction) +@@ -334,6 +332,8 @@ + return ERR_PTR(-EINVAL); + + sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction); ++ if (!sg_table) ++ sg_table = ERR_PTR(-ENOMEM); + + return sg_table; + } +@@ -544,6 +544,8 @@ + * These calls are optional in drivers. The intended use for them + * is for mapping objects linear in kernel space for high use objects. + * Please attempt to use kmap/kunmap before thinking about these interfaces. ++ * ++ * Returns NULL on error. + */ + void *dma_buf_vmap(struct dma_buf *dmabuf) + { +@@ -566,7 +568,9 @@ + BUG_ON(dmabuf->vmap_ptr); + + ptr = dmabuf->ops->vmap(dmabuf); +- if (IS_ERR_OR_NULL(ptr)) ++ if (WARN_ON_ONCE(IS_ERR(ptr))) ++ ptr = NULL; ++ if (!ptr) + goto out_unlock; + + dmabuf->vmap_ptr = ptr; +diff -Nur linux-3.14.40.orig/drivers/base/dma-contiguous.c linux-3.14.40/drivers/base/dma-contiguous.c +--- linux-3.14.40.orig/drivers/base/dma-contiguous.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/base/dma-contiguous.c 2015-05-01 14:57:58.815427001 -0500 +@@ -24,22 +24,9 @@ + + #include + #include +-#include +-#include +-#include + #include +-#include +-#include +-#include + #include +- +-struct cma { +- unsigned long base_pfn; +- unsigned long count; +- unsigned long *bitmap; +-}; +- +-struct cma *dma_contiguous_default_area; ++#include + + #ifdef CONFIG_CMA_SIZE_MBYTES + #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES +@@ -47,6 +34,8 @@ + #define CMA_SIZE_MBYTES 0 + #endif + ++struct cma *dma_contiguous_default_area; ++ + /* + * Default global CMA area size can be defined in kernel's .config. + * This is useful mainly for distro maintainers to create a kernel +@@ -59,11 +48,22 @@ + */ + static const phys_addr_t size_bytes = CMA_SIZE_MBYTES * SZ_1M; + static phys_addr_t size_cmdline = -1; ++static phys_addr_t base_cmdline; ++static phys_addr_t limit_cmdline; + + static int __init early_cma(char *p) + { + pr_debug("%s(%s)\n", __func__, p); + size_cmdline = memparse(p, &p); ++ if (*p != '@') ++ return 0; ++ base_cmdline = memparse(p + 1, &p); ++ if (*p != '-') { ++ limit_cmdline = base_cmdline + size_cmdline; ++ return 0; ++ } ++ limit_cmdline = memparse(p + 1, &p); ++ + return 0; + } + early_param("cma", early_cma); +@@ -107,11 +107,18 @@ + void __init dma_contiguous_reserve(phys_addr_t limit) + { + phys_addr_t selected_size = 0; ++ phys_addr_t selected_base = 0; ++ phys_addr_t selected_limit = limit; ++ bool fixed = false; + + pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit); + + if (size_cmdline != -1) { + selected_size = size_cmdline; ++ selected_base = base_cmdline; ++ selected_limit = min_not_zero(limit_cmdline, limit); ++ if (base_cmdline + size_cmdline == limit_cmdline) ++ fixed = true; + } else { + #ifdef CONFIG_CMA_SIZE_SEL_MBYTES + selected_size = size_bytes; +@@ -128,68 +135,12 @@ + pr_debug("%s: reserving %ld MiB for global area\n", __func__, + (unsigned long)selected_size / SZ_1M); + +- dma_contiguous_reserve_area(selected_size, 0, limit, +- &dma_contiguous_default_area); +- } +-}; +- +-static DEFINE_MUTEX(cma_mutex); +- +-static int __init cma_activate_area(struct cma *cma) +-{ +- int bitmap_size = BITS_TO_LONGS(cma->count) * sizeof(long); +- unsigned long base_pfn = cma->base_pfn, pfn = base_pfn; +- unsigned i = cma->count >> pageblock_order; +- struct zone *zone; +- +- cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL); +- +- if (!cma->bitmap) +- return -ENOMEM; +- +- WARN_ON_ONCE(!pfn_valid(pfn)); +- zone = page_zone(pfn_to_page(pfn)); +- +- do { +- unsigned j; +- base_pfn = pfn; +- for (j = pageblock_nr_pages; j; --j, pfn++) { +- WARN_ON_ONCE(!pfn_valid(pfn)); +- /* +- * alloc_contig_range requires the pfn range +- * specified to be in the same zone. Make this +- * simple by forcing the entire CMA resv range +- * to be in the same zone. +- */ +- if (page_zone(pfn_to_page(pfn)) != zone) +- goto err; +- } +- init_cma_reserved_pageblock(pfn_to_page(base_pfn)); +- } while (--i); +- +- return 0; +- +-err: +- kfree(cma->bitmap); +- return -EINVAL; +-} +- +-static struct cma cma_areas[MAX_CMA_AREAS]; +-static unsigned cma_area_count; +- +-static int __init cma_init_reserved_areas(void) +-{ +- int i; +- +- for (i = 0; i < cma_area_count; i++) { +- int ret = cma_activate_area(&cma_areas[i]); +- if (ret) +- return ret; ++ dma_contiguous_reserve_area(selected_size, selected_base, ++ selected_limit, ++ &dma_contiguous_default_area, ++ fixed); + } +- +- return 0; + } +-core_initcall(cma_init_reserved_areas); + + /** + * dma_contiguous_reserve_area() - reserve custom contiguous area +@@ -197,78 +148,32 @@ + * @base: Base address of the reserved area optional, use 0 for any + * @limit: End address of the reserved memory (optional, 0 for any). + * @res_cma: Pointer to store the created cma region. ++ * @fixed: hint about where to place the reserved area + * + * This function reserves memory from early allocator. It should be + * called by arch specific code once the early allocator (memblock or bootmem) + * has been activated and all other subsystems have already allocated/reserved + * memory. This function allows to create custom reserved areas for specific + * devices. ++ * ++ * If @fixed is true, reserve contiguous area at exactly @base. If false, ++ * reserve in range from @base to @limit. + */ + int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, +- phys_addr_t limit, struct cma **res_cma) ++ phys_addr_t limit, struct cma **res_cma, ++ bool fixed) + { +- struct cma *cma = &cma_areas[cma_area_count]; +- phys_addr_t alignment; +- int ret = 0; +- +- pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__, +- (unsigned long)size, (unsigned long)base, +- (unsigned long)limit); +- +- /* Sanity checks */ +- if (cma_area_count == ARRAY_SIZE(cma_areas)) { +- pr_err("Not enough slots for CMA reserved regions!\n"); +- return -ENOSPC; +- } +- +- if (!size) +- return -EINVAL; +- +- /* Sanitise input arguments */ +- alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order); +- base = ALIGN(base, alignment); +- size = ALIGN(size, alignment); +- limit &= ~(alignment - 1); +- +- /* Reserve memory */ +- if (base) { +- if (memblock_is_region_reserved(base, size) || +- memblock_reserve(base, size) < 0) { +- ret = -EBUSY; +- goto err; +- } +- } else { +- /* +- * Use __memblock_alloc_base() since +- * memblock_alloc_base() panic()s. +- */ +- phys_addr_t addr = __memblock_alloc_base(size, alignment, limit); +- if (!addr) { +- ret = -ENOMEM; +- goto err; +- } else { +- base = addr; +- } +- } +- +- /* +- * Each reserved area must be initialised later, when more kernel +- * subsystems (like slab allocator) are available. +- */ +- cma->base_pfn = PFN_DOWN(base); +- cma->count = size >> PAGE_SHIFT; +- *res_cma = cma; +- cma_area_count++; ++ int ret; + +- pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M, +- (unsigned long)base); ++ ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed, res_cma); ++ if (ret) ++ return ret; + + /* Architecture specific contiguous memory fixup. */ +- dma_contiguous_early_fixup(base, size); ++ dma_contiguous_early_fixup(cma_get_base(*res_cma), ++ cma_get_size(*res_cma)); ++ + return 0; +-err: +- pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M); +- return ret; + } + + /** +@@ -279,57 +184,16 @@ + * + * This function allocates memory buffer for specified device. It uses + * device specific contiguous memory area if available or the default +- * global one. Requires architecture specific get_dev_cma_area() helper ++ * global one. Requires architecture specific dev_get_cma_area() helper + * function. + */ + struct page *dma_alloc_from_contiguous(struct device *dev, int count, + unsigned int align) + { +- unsigned long mask, pfn, pageno, start = 0; +- struct cma *cma = dev_get_cma_area(dev); +- struct page *page = NULL; +- int ret; +- +- if (!cma || !cma->count) +- return NULL; +- + if (align > CONFIG_CMA_ALIGNMENT) + align = CONFIG_CMA_ALIGNMENT; + +- pr_debug("%s(cma %p, count %d, align %d)\n", __func__, (void *)cma, +- count, align); +- +- if (!count) +- return NULL; +- +- mask = (1 << align) - 1; +- +- mutex_lock(&cma_mutex); +- +- for (;;) { +- pageno = bitmap_find_next_zero_area(cma->bitmap, cma->count, +- start, count, mask); +- if (pageno >= cma->count) +- break; +- +- pfn = cma->base_pfn + pageno; +- ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA); +- if (ret == 0) { +- bitmap_set(cma->bitmap, pageno, count); +- page = pfn_to_page(pfn); +- break; +- } else if (ret != -EBUSY) { +- break; +- } +- pr_debug("%s(): memory range at %p is busy, retrying\n", +- __func__, pfn_to_page(pfn)); +- /* try again with a bit different memory target */ +- start = pageno + mask + 1; +- } +- +- mutex_unlock(&cma_mutex); +- pr_debug("%s(): returned %p\n", __func__, page); +- return page; ++ return cma_alloc(dev_get_cma_area(dev), count, align); + } + + /** +@@ -345,25 +209,5 @@ + bool dma_release_from_contiguous(struct device *dev, struct page *pages, + int count) + { +- struct cma *cma = dev_get_cma_area(dev); +- unsigned long pfn; +- +- if (!cma || !pages) +- return false; +- +- pr_debug("%s(page %p)\n", __func__, (void *)pages); +- +- pfn = page_to_pfn(pages); +- +- if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count) +- return false; +- +- VM_BUG_ON(pfn + count > cma->base_pfn + cma->count); +- +- mutex_lock(&cma_mutex); +- bitmap_clear(cma->bitmap, pfn - cma->base_pfn, count); +- free_contig_range(pfn, count); +- mutex_unlock(&cma_mutex); +- +- return true; ++ return cma_release(dev_get_cma_area(dev), pages, count); + } +diff -Nur linux-3.14.40.orig/drivers/base/Kconfig linux-3.14.40/drivers/base/Kconfig +--- linux-3.14.40.orig/drivers/base/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/base/Kconfig 2015-05-01 14:57:58.815427001 -0500 +@@ -185,6 +185,14 @@ + bool + default n + ++config HAVE_CPU_AUTOPROBE ++ def_bool ARCH_HAS_CPU_AUTOPROBE ++ ++config GENERIC_CPU_AUTOPROBE ++ bool ++ depends on !ARCH_HAS_CPU_AUTOPROBE ++ select HAVE_CPU_AUTOPROBE ++ + config SOC_BUS + bool + +@@ -266,16 +274,6 @@ + + If unsure, leave the default value "8". + +-config CMA_AREAS +- int "Maximum count of the CMA device-private areas" +- default 7 +- help +- CMA allows to create CMA areas for particular devices. This parameter +- sets the maximum number of such device private CMA areas in the +- system. +- +- If unsure, leave the default value "7". +- + endif + + endmenu +diff -Nur linux-3.14.40.orig/drivers/bus/arm-cci.c linux-3.14.40/drivers/bus/arm-cci.c +--- linux-3.14.40.orig/drivers/bus/arm-cci.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/bus/arm-cci.c 2015-05-01 14:57:58.815427001 -0500 +@@ -26,6 +26,7 @@ + + #include + #include ++#include + #include + #include + +@@ -544,6 +545,7 @@ + + cci_pmu->plat_device = pdev; + cci_pmu->num_events = pmu_get_max_counters(); ++ cpumask_setall(&cci_pmu->valid_cpus); + + return armpmu_register(cci_pmu, -1); + } +@@ -969,6 +971,11 @@ + const char *match_str; + bool is_ace; + ++ if (psci_probe() == 0) { ++ pr_debug("psci found. Aborting cci probe\n"); ++ return -ENODEV; ++ } ++ + np = of_find_matching_node(NULL, arm_cci_matches); + if (!np) + return -ENODEV; +diff -Nur linux-3.14.40.orig/drivers/char/fsl_otp.c linux-3.14.40/drivers/char/fsl_otp.c +--- linux-3.14.40.orig/drivers/char/fsl_otp.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/char/fsl_otp.c 2015-05-01 14:57:58.815427001 -0500 +@@ -0,0 +1,316 @@ ++/* ++ * 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 ++#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; ++} ++ ++int fsl_otp_readl(unsigned long offset, u32 *value) ++{ ++ int ret = 0; ++ ++ ret = clk_prepare_enable(otp_clk); ++ if (ret) ++ return ret; ++ ++ mutex_lock(&otp_mutex); ++ ++ set_otp_timing(); ++ ret = otp_wait_busy(0); ++ if (ret) ++ goto out; ++ ++ *value = __raw_readl(otp_base + offset); ++ ++out: ++ mutex_unlock(&otp_mutex); ++ clk_disable_unprepare(otp_clk); ++ return ret; ++} ++EXPORT_SYMBOL(fsl_otp_readl); ++ ++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 = fsl_otp_readl(HW_OCOTP_CUST_N(index), &value); ++ ++ return ret ? 0 : sprintf(buf, "0x%x\n", value); ++} ++ ++#ifdef CONFIG_FSL_OTP_WRITE_ENABLE ++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; ++} ++#endif ++ ++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]; ++#ifdef CONFIG_FSL_OTP_WRITE_ENABLE ++ otp_kattr[i].attr.mode = 0600; ++ otp_kattr[i].store = fsl_otp_store; ++#else ++ otp_kattr[i].attr.mode = 0400; ++#endif ++ otp_kattr[i].show = fsl_otp_show; ++ 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.14.40.orig/drivers/char/Kconfig linux-3.14.40/drivers/char/Kconfig +--- linux-3.14.40.orig/drivers/char/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/char/Kconfig 2015-05-01 14:57:58.823427001 -0500 +@@ -82,6 +82,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.14.40.orig/drivers/char/Makefile linux-3.14.40/drivers/char/Makefile +--- linux-3.14.40.orig/drivers/char/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/char/Makefile 2015-05-01 14:57:58.839427001 -0500 +@@ -16,6 +16,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.14.40.orig/drivers/clk/clk.c linux-3.14.40/drivers/clk/clk.c +--- linux-3.14.40.orig/drivers/clk/clk.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/clk/clk.c 2015-05-01 14:57:58.851427001 -0500 +@@ -1707,6 +1707,7 @@ + */ + int clk_set_parent(struct clk *clk, struct clk *parent) + { ++ struct clk *child; + int ret = 0; + int p_index = 0; + unsigned long p_rate = 0; +@@ -1733,6 +1734,18 @@ + goto out; + } + ++ /* check two consecutive basic mux clocks */ ++ if (clk->flags & CLK_IS_BASIC_MUX) { ++ hlist_for_each_entry(child, &clk->children, child_node) { ++ if (child->flags & CLK_IS_BASIC_MUX) { ++ pr_err("%s: failed to switch parent of %s due to child mux %s\n", ++ __func__, clk->name, child->name); ++ ret = -EBUSY; ++ goto out; ++ } ++ } ++ } ++ + /* try finding the new parent index */ + if (parent) { + p_index = clk_fetch_parent_index(clk, parent); +diff -Nur linux-3.14.40.orig/drivers/clk/clk-mux.c linux-3.14.40/drivers/clk/clk-mux.c +--- linux-3.14.40.orig/drivers/clk/clk-mux.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/clk/clk-mux.c 2015-05-01 14:57:58.863427001 -0500 +@@ -143,7 +143,7 @@ + init.ops = &clk_mux_ro_ops; + else + init.ops = &clk_mux_ops; +- init.flags = flags | CLK_IS_BASIC; ++ init.flags = flags | CLK_IS_BASIC | CLK_IS_BASIC_MUX; + init.parent_names = parent_names; + init.num_parents = num_parents; + +diff -Nur linux-3.14.40.orig/drivers/cpufreq/cpufreq_interactive.c linux-3.14.40/drivers/cpufreq/cpufreq_interactive.c +--- linux-3.14.40.orig/drivers/cpufreq/cpufreq_interactive.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/cpufreq/cpufreq_interactive.c 2015-05-01 14:57:58.863427001 -0500 +@@ -0,0 +1,1349 @@ ++/* ++ * drivers/cpufreq/cpufreq_interactive.c ++ * ++ * Copyright (C) 2010 Google, 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 ++ ++#define CREATE_TRACE_POINTS ++#include ++ ++struct cpufreq_interactive_cpuinfo { ++ struct timer_list cpu_timer; ++ struct timer_list cpu_slack_timer; ++ spinlock_t load_lock; /* protects the next 4 fields */ ++ u64 time_in_idle; ++ u64 time_in_idle_timestamp; ++ u64 cputime_speedadj; ++ u64 cputime_speedadj_timestamp; ++ struct cpufreq_policy *policy; ++ struct cpufreq_frequency_table *freq_table; ++ unsigned int target_freq; ++ unsigned int floor_freq; ++ u64 floor_validate_time; ++ u64 hispeed_validate_time; ++ struct rw_semaphore enable_sem; ++ int governor_enabled; ++}; ++ ++static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo); ++ ++/* realtime thread handles frequency scaling */ ++static struct task_struct *speedchange_task; ++static cpumask_t speedchange_cpumask; ++static spinlock_t speedchange_cpumask_lock; ++static struct mutex gov_lock; ++ ++/* Target load. Lower values result in higher CPU speeds. */ ++#define DEFAULT_TARGET_LOAD 90 ++static unsigned int default_target_loads[] = {DEFAULT_TARGET_LOAD}; ++ ++#define DEFAULT_TIMER_RATE (20 * USEC_PER_MSEC) ++#define DEFAULT_ABOVE_HISPEED_DELAY DEFAULT_TIMER_RATE ++static unsigned int default_above_hispeed_delay[] = { ++ DEFAULT_ABOVE_HISPEED_DELAY }; ++ ++struct cpufreq_interactive_tunables { ++ int usage_count; ++ /* Hi speed to bump to from lo speed when load burst (default max) */ ++ unsigned int hispeed_freq; ++ /* Go to hi speed when CPU load at or above this value. */ ++#define DEFAULT_GO_HISPEED_LOAD 99 ++ unsigned long go_hispeed_load; ++ /* Target load. Lower values result in higher CPU speeds. */ ++ spinlock_t target_loads_lock; ++ unsigned int *target_loads; ++ int ntarget_loads; ++ /* ++ * The minimum amount of time to spend at a frequency before we can ramp ++ * down. ++ */ ++#define DEFAULT_MIN_SAMPLE_TIME (80 * USEC_PER_MSEC) ++ unsigned long min_sample_time; ++ /* ++ * The sample rate of the timer used to increase frequency ++ */ ++ unsigned long timer_rate; ++ /* ++ * Wait this long before raising speed above hispeed, by default a ++ * single timer interval. ++ */ ++ spinlock_t above_hispeed_delay_lock; ++ unsigned int *above_hispeed_delay; ++ int nabove_hispeed_delay; ++ /* Non-zero means indefinite speed boost active */ ++ int boost_val; ++ /* Duration of a boot pulse in usecs */ ++ int boostpulse_duration_val; ++ /* End time of boost pulse in ktime converted to usecs */ ++ u64 boostpulse_endtime; ++ /* ++ * Max additional time to wait in idle, beyond timer_rate, at speeds ++ * above minimum before wakeup to reduce speed, or -1 if unnecessary. ++ */ ++#define DEFAULT_TIMER_SLACK (4 * DEFAULT_TIMER_RATE) ++ int timer_slack_val; ++ bool io_is_busy; ++}; ++ ++/* For cases where we have single governor instance for system */ ++struct cpufreq_interactive_tunables *common_tunables; ++ ++static struct attribute_group *get_sysfs_attr(void); ++ ++static void cpufreq_interactive_timer_resched( ++ struct cpufreq_interactive_cpuinfo *pcpu) ++{ ++ struct cpufreq_interactive_tunables *tunables = ++ pcpu->policy->governor_data; ++ unsigned long expires; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pcpu->load_lock, flags); ++ pcpu->time_in_idle = ++ get_cpu_idle_time(smp_processor_id(), ++ &pcpu->time_in_idle_timestamp, ++ tunables->io_is_busy); ++ pcpu->cputime_speedadj = 0; ++ pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp; ++ expires = jiffies + usecs_to_jiffies(tunables->timer_rate); ++ mod_timer_pinned(&pcpu->cpu_timer, expires); ++ ++ if (tunables->timer_slack_val >= 0 && ++ pcpu->target_freq > pcpu->policy->min) { ++ expires += usecs_to_jiffies(tunables->timer_slack_val); ++ mod_timer_pinned(&pcpu->cpu_slack_timer, expires); ++ } ++ ++ spin_unlock_irqrestore(&pcpu->load_lock, flags); ++} ++ ++/* The caller shall take enable_sem write semaphore to avoid any timer race. ++ * The cpu_timer and cpu_slack_timer must be deactivated when calling this ++ * function. ++ */ ++static void cpufreq_interactive_timer_start( ++ struct cpufreq_interactive_tunables *tunables, int cpu) ++{ ++ struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu); ++ unsigned long expires = jiffies + ++ usecs_to_jiffies(tunables->timer_rate); ++ unsigned long flags; ++ ++ pcpu->cpu_timer.expires = expires; ++ add_timer_on(&pcpu->cpu_timer, cpu); ++ if (tunables->timer_slack_val >= 0 && ++ pcpu->target_freq > pcpu->policy->min) { ++ expires += usecs_to_jiffies(tunables->timer_slack_val); ++ pcpu->cpu_slack_timer.expires = expires; ++ add_timer_on(&pcpu->cpu_slack_timer, cpu); ++ } ++ ++ spin_lock_irqsave(&pcpu->load_lock, flags); ++ pcpu->time_in_idle = ++ get_cpu_idle_time(cpu, &pcpu->time_in_idle_timestamp, ++ tunables->io_is_busy); ++ pcpu->cputime_speedadj = 0; ++ pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp; ++ spin_unlock_irqrestore(&pcpu->load_lock, flags); ++} ++ ++static unsigned int freq_to_above_hispeed_delay( ++ struct cpufreq_interactive_tunables *tunables, ++ unsigned int freq) ++{ ++ int i; ++ unsigned int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags); ++ ++ for (i = 0; i < tunables->nabove_hispeed_delay - 1 && ++ freq >= tunables->above_hispeed_delay[i+1]; i += 2) ++ ; ++ ++ ret = tunables->above_hispeed_delay[i]; ++ spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags); ++ return ret; ++} ++ ++static unsigned int freq_to_targetload( ++ struct cpufreq_interactive_tunables *tunables, unsigned int freq) ++{ ++ int i; ++ unsigned int ret; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tunables->target_loads_lock, flags); ++ ++ for (i = 0; i < tunables->ntarget_loads - 1 && ++ freq >= tunables->target_loads[i+1]; i += 2) ++ ; ++ ++ ret = tunables->target_loads[i]; ++ spin_unlock_irqrestore(&tunables->target_loads_lock, flags); ++ return ret; ++} ++ ++/* ++ * If increasing frequencies never map to a lower target load then ++ * choose_freq() will find the minimum frequency that does not exceed its ++ * target load given the current load. ++ */ ++static unsigned int choose_freq(struct cpufreq_interactive_cpuinfo *pcpu, ++ unsigned int loadadjfreq) ++{ ++ unsigned int freq = pcpu->policy->cur; ++ unsigned int prevfreq, freqmin, freqmax; ++ unsigned int tl; ++ int index; ++ ++ freqmin = 0; ++ freqmax = UINT_MAX; ++ ++ do { ++ prevfreq = freq; ++ tl = freq_to_targetload(pcpu->policy->governor_data, freq); ++ ++ /* ++ * Find the lowest frequency where the computed load is less ++ * than or equal to the target load. ++ */ ++ ++ if (cpufreq_frequency_table_target( ++ pcpu->policy, pcpu->freq_table, loadadjfreq / tl, ++ CPUFREQ_RELATION_L, &index)) ++ break; ++ freq = pcpu->freq_table[index].frequency; ++ ++ if (freq > prevfreq) { ++ /* The previous frequency is too low. */ ++ freqmin = prevfreq; ++ ++ if (freq >= freqmax) { ++ /* ++ * Find the highest frequency that is less ++ * than freqmax. ++ */ ++ if (cpufreq_frequency_table_target( ++ pcpu->policy, pcpu->freq_table, ++ freqmax - 1, CPUFREQ_RELATION_H, ++ &index)) ++ break; ++ freq = pcpu->freq_table[index].frequency; ++ ++ if (freq == freqmin) { ++ /* ++ * The first frequency below freqmax ++ * has already been found to be too ++ * low. freqmax is the lowest speed ++ * we found that is fast enough. ++ */ ++ freq = freqmax; ++ break; ++ } ++ } ++ } else if (freq < prevfreq) { ++ /* The previous frequency is high enough. */ ++ freqmax = prevfreq; ++ ++ if (freq <= freqmin) { ++ /* ++ * Find the lowest frequency that is higher ++ * than freqmin. ++ */ ++ if (cpufreq_frequency_table_target( ++ pcpu->policy, pcpu->freq_table, ++ freqmin + 1, CPUFREQ_RELATION_L, ++ &index)) ++ break; ++ freq = pcpu->freq_table[index].frequency; ++ ++ /* ++ * If freqmax is the first frequency above ++ * freqmin then we have already found that ++ * this speed is fast enough. ++ */ ++ if (freq == freqmax) ++ break; ++ } ++ } ++ ++ /* If same frequency chosen as previous then done. */ ++ } while (freq != prevfreq); ++ ++ return freq; ++} ++ ++static u64 update_load(int cpu) ++{ ++ struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu); ++ struct cpufreq_interactive_tunables *tunables = ++ pcpu->policy->governor_data; ++ u64 now; ++ u64 now_idle; ++ unsigned int delta_idle; ++ unsigned int delta_time; ++ u64 active_time; ++ ++ now_idle = get_cpu_idle_time(cpu, &now, tunables->io_is_busy); ++ delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle); ++ delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp); ++ ++ if (delta_time <= delta_idle) ++ active_time = 0; ++ else ++ active_time = delta_time - delta_idle; ++ ++ pcpu->cputime_speedadj += active_time * pcpu->policy->cur; ++ ++ pcpu->time_in_idle = now_idle; ++ pcpu->time_in_idle_timestamp = now; ++ return now; ++} ++ ++static void cpufreq_interactive_timer(unsigned long data) ++{ ++ u64 now; ++ unsigned int delta_time; ++ u64 cputime_speedadj; ++ int cpu_load; ++ struct cpufreq_interactive_cpuinfo *pcpu = ++ &per_cpu(cpuinfo, data); ++ struct cpufreq_interactive_tunables *tunables = ++ pcpu->policy->governor_data; ++ unsigned int new_freq; ++ unsigned int loadadjfreq; ++ unsigned int index; ++ unsigned long flags; ++ bool boosted; ++ ++ if (!down_read_trylock(&pcpu->enable_sem)) ++ return; ++ if (!pcpu->governor_enabled) ++ goto exit; ++ ++ spin_lock_irqsave(&pcpu->load_lock, flags); ++ now = update_load(data); ++ delta_time = (unsigned int)(now - pcpu->cputime_speedadj_timestamp); ++ cputime_speedadj = pcpu->cputime_speedadj; ++ spin_unlock_irqrestore(&pcpu->load_lock, flags); ++ ++ if (WARN_ON_ONCE(!delta_time)) ++ goto rearm; ++ ++ do_div(cputime_speedadj, delta_time); ++ loadadjfreq = (unsigned int)cputime_speedadj * 100; ++ cpu_load = loadadjfreq / pcpu->target_freq; ++ boosted = tunables->boost_val || now < tunables->boostpulse_endtime; ++ ++ if (cpu_load >= tunables->go_hispeed_load || boosted) { ++ if (pcpu->target_freq < tunables->hispeed_freq) { ++ new_freq = tunables->hispeed_freq; ++ } else { ++ new_freq = choose_freq(pcpu, loadadjfreq); ++ ++ if (new_freq < tunables->hispeed_freq) ++ new_freq = tunables->hispeed_freq; ++ } ++ } else { ++ new_freq = choose_freq(pcpu, loadadjfreq); ++ } ++ ++ if (pcpu->target_freq >= tunables->hispeed_freq && ++ new_freq > pcpu->target_freq && ++ now - pcpu->hispeed_validate_time < ++ freq_to_above_hispeed_delay(tunables, pcpu->target_freq)) { ++ trace_cpufreq_interactive_notyet( ++ data, cpu_load, pcpu->target_freq, ++ pcpu->policy->cur, new_freq); ++ goto rearm; ++ } ++ ++ pcpu->hispeed_validate_time = now; ++ ++ if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table, ++ new_freq, CPUFREQ_RELATION_L, ++ &index)) ++ goto rearm; ++ ++ new_freq = pcpu->freq_table[index].frequency; ++ ++ /* ++ * Do not scale below floor_freq unless we have been at or above the ++ * floor frequency for the minimum sample time since last validated. ++ */ ++ if (new_freq < pcpu->floor_freq) { ++ if (now - pcpu->floor_validate_time < ++ tunables->min_sample_time) { ++ trace_cpufreq_interactive_notyet( ++ data, cpu_load, pcpu->target_freq, ++ pcpu->policy->cur, new_freq); ++ goto rearm; ++ } ++ } ++ ++ /* ++ * Update the timestamp for checking whether speed has been held at ++ * or above the selected frequency for a minimum of min_sample_time, ++ * if not boosted to hispeed_freq. If boosted to hispeed_freq then we ++ * allow the speed to drop as soon as the boostpulse duration expires ++ * (or the indefinite boost is turned off). ++ */ ++ ++ if (!boosted || new_freq > tunables->hispeed_freq) { ++ pcpu->floor_freq = new_freq; ++ pcpu->floor_validate_time = now; ++ } ++ ++ if (pcpu->target_freq == new_freq) { ++ trace_cpufreq_interactive_already( ++ data, cpu_load, pcpu->target_freq, ++ pcpu->policy->cur, new_freq); ++ goto rearm_if_notmax; ++ } ++ ++ trace_cpufreq_interactive_target(data, cpu_load, pcpu->target_freq, ++ pcpu->policy->cur, new_freq); ++ ++ pcpu->target_freq = new_freq; ++ spin_lock_irqsave(&speedchange_cpumask_lock, flags); ++ cpumask_set_cpu(data, &speedchange_cpumask); ++ spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); ++ wake_up_process(speedchange_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)) ++ cpufreq_interactive_timer_resched(pcpu); ++ ++exit: ++ up_read(&pcpu->enable_sem); ++ return; ++} ++ ++static void cpufreq_interactive_idle_start(void) ++{ ++ struct cpufreq_interactive_cpuinfo *pcpu = ++ &per_cpu(cpuinfo, smp_processor_id()); ++ int pending; ++ ++ if (!down_read_trylock(&pcpu->enable_sem)) ++ return; ++ if (!pcpu->governor_enabled) { ++ up_read(&pcpu->enable_sem); ++ return; ++ } ++ ++ pending = timer_pending(&pcpu->cpu_timer); ++ ++ if (pcpu->target_freq != pcpu->policy->min) { ++ /* ++ * 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) ++ cpufreq_interactive_timer_resched(pcpu); ++ } ++ ++ up_read(&pcpu->enable_sem); ++} ++ ++static void cpufreq_interactive_idle_end(void) ++{ ++ struct cpufreq_interactive_cpuinfo *pcpu = ++ &per_cpu(cpuinfo, smp_processor_id()); ++ ++ if (!down_read_trylock(&pcpu->enable_sem)) ++ return; ++ if (!pcpu->governor_enabled) { ++ up_read(&pcpu->enable_sem); ++ return; ++ } ++ ++ /* Arm the timer for 1-2 ticks later if not already. */ ++ if (!timer_pending(&pcpu->cpu_timer)) { ++ cpufreq_interactive_timer_resched(pcpu); ++ } else if (time_after_eq(jiffies, pcpu->cpu_timer.expires)) { ++ del_timer(&pcpu->cpu_timer); ++ del_timer(&pcpu->cpu_slack_timer); ++ cpufreq_interactive_timer(smp_processor_id()); ++ } ++ ++ up_read(&pcpu->enable_sem); ++} ++ ++static int cpufreq_interactive_speedchange_task(void *data) ++{ ++ unsigned int cpu; ++ cpumask_t tmp_mask; ++ unsigned long flags; ++ struct cpufreq_interactive_cpuinfo *pcpu; ++ ++ while (1) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ spin_lock_irqsave(&speedchange_cpumask_lock, flags); ++ ++ if (cpumask_empty(&speedchange_cpumask)) { ++ spin_unlock_irqrestore(&speedchange_cpumask_lock, ++ flags); ++ schedule(); ++ ++ if (kthread_should_stop()) ++ break; ++ ++ spin_lock_irqsave(&speedchange_cpumask_lock, flags); ++ } ++ ++ set_current_state(TASK_RUNNING); ++ tmp_mask = speedchange_cpumask; ++ cpumask_clear(&speedchange_cpumask); ++ spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); ++ ++ for_each_cpu(cpu, &tmp_mask) { ++ unsigned int j; ++ unsigned int max_freq = 0; ++ ++ pcpu = &per_cpu(cpuinfo, cpu); ++ if (!down_read_trylock(&pcpu->enable_sem)) ++ continue; ++ if (!pcpu->governor_enabled) { ++ up_read(&pcpu->enable_sem); ++ continue; ++ } ++ ++ for_each_cpu(j, pcpu->policy->cpus) { ++ 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); ++ trace_cpufreq_interactive_setspeed(cpu, ++ pcpu->target_freq, ++ pcpu->policy->cur); ++ ++ up_read(&pcpu->enable_sem); ++ } ++ } ++ ++ return 0; ++} ++ ++static void cpufreq_interactive_boost(void) ++{ ++ int i; ++ int anyboost = 0; ++ unsigned long flags; ++ struct cpufreq_interactive_cpuinfo *pcpu; ++ struct cpufreq_interactive_tunables *tunables; ++ ++ spin_lock_irqsave(&speedchange_cpumask_lock, flags); ++ ++ for_each_online_cpu(i) { ++ pcpu = &per_cpu(cpuinfo, i); ++ tunables = pcpu->policy->governor_data; ++ ++ if (pcpu->target_freq < tunables->hispeed_freq) { ++ pcpu->target_freq = tunables->hispeed_freq; ++ cpumask_set_cpu(i, &speedchange_cpumask); ++ pcpu->hispeed_validate_time = ++ ktime_to_us(ktime_get()); ++ anyboost = 1; ++ } ++ ++ /* ++ * Set floor freq and (re)start timer for when last ++ * validated. ++ */ ++ ++ pcpu->floor_freq = tunables->hispeed_freq; ++ pcpu->floor_validate_time = ktime_to_us(ktime_get()); ++ } ++ ++ spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); ++ ++ if (anyboost) ++ wake_up_process(speedchange_task); ++} ++ ++static int cpufreq_interactive_notifier( ++ struct notifier_block *nb, unsigned long val, void *data) ++{ ++ struct cpufreq_freqs *freq = data; ++ struct cpufreq_interactive_cpuinfo *pcpu; ++ int cpu; ++ unsigned long flags; ++ ++ if (val == CPUFREQ_POSTCHANGE) { ++ pcpu = &per_cpu(cpuinfo, freq->cpu); ++ if (!down_read_trylock(&pcpu->enable_sem)) ++ return 0; ++ if (!pcpu->governor_enabled) { ++ up_read(&pcpu->enable_sem); ++ return 0; ++ } ++ ++ for_each_cpu(cpu, pcpu->policy->cpus) { ++ struct cpufreq_interactive_cpuinfo *pjcpu = ++ &per_cpu(cpuinfo, cpu); ++ if (cpu != freq->cpu) { ++ if (!down_read_trylock(&pjcpu->enable_sem)) ++ continue; ++ if (!pjcpu->governor_enabled) { ++ up_read(&pjcpu->enable_sem); ++ continue; ++ } ++ } ++ spin_lock_irqsave(&pjcpu->load_lock, flags); ++ update_load(cpu); ++ spin_unlock_irqrestore(&pjcpu->load_lock, flags); ++ if (cpu != freq->cpu) ++ up_read(&pjcpu->enable_sem); ++ } ++ ++ up_read(&pcpu->enable_sem); ++ } ++ return 0; ++} ++ ++static struct notifier_block cpufreq_notifier_block = { ++ .notifier_call = cpufreq_interactive_notifier, ++}; ++ ++static unsigned int *get_tokenized_data(const char *buf, int *num_tokens) ++{ ++ const char *cp; ++ int i; ++ int ntokens = 1; ++ unsigned int *tokenized_data; ++ int err = -EINVAL; ++ ++ cp = buf; ++ while ((cp = strpbrk(cp + 1, " :"))) ++ ntokens++; ++ ++ if (!(ntokens & 0x1)) ++ goto err; ++ ++ tokenized_data = kmalloc(ntokens * sizeof(unsigned int), GFP_KERNEL); ++ if (!tokenized_data) { ++ err = -ENOMEM; ++ goto err; ++ } ++ ++ cp = buf; ++ i = 0; ++ while (i < ntokens) { ++ if (sscanf(cp, "%u", &tokenized_data[i++]) != 1) ++ goto err_kfree; ++ ++ cp = strpbrk(cp, " :"); ++ if (!cp) ++ break; ++ cp++; ++ } ++ ++ if (i != ntokens) ++ goto err_kfree; ++ ++ *num_tokens = ntokens; ++ return tokenized_data; ++ ++err_kfree: ++ kfree(tokenized_data); ++err: ++ return ERR_PTR(err); ++} ++ ++static ssize_t show_target_loads( ++ struct cpufreq_interactive_tunables *tunables, ++ char *buf) ++{ ++ int i; ++ ssize_t ret = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tunables->target_loads_lock, flags); ++ ++ for (i = 0; i < tunables->ntarget_loads; i++) ++ ret += sprintf(buf + ret, "%u%s", tunables->target_loads[i], ++ i & 0x1 ? ":" : " "); ++ ++ sprintf(buf + ret - 1, "\n"); ++ spin_unlock_irqrestore(&tunables->target_loads_lock, flags); ++ return ret; ++} ++ ++static ssize_t store_target_loads( ++ struct cpufreq_interactive_tunables *tunables, ++ const char *buf, size_t count) ++{ ++ int ntokens; ++ unsigned int *new_target_loads = NULL; ++ unsigned long flags; ++ ++ new_target_loads = get_tokenized_data(buf, &ntokens); ++ if (IS_ERR(new_target_loads)) ++ return PTR_RET(new_target_loads); ++ ++ spin_lock_irqsave(&tunables->target_loads_lock, flags); ++ if (tunables->target_loads != default_target_loads) ++ kfree(tunables->target_loads); ++ tunables->target_loads = new_target_loads; ++ tunables->ntarget_loads = ntokens; ++ spin_unlock_irqrestore(&tunables->target_loads_lock, flags); ++ return count; ++} ++ ++static ssize_t show_above_hispeed_delay( ++ struct cpufreq_interactive_tunables *tunables, char *buf) ++{ ++ int i; ++ ssize_t ret = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags); ++ ++ for (i = 0; i < tunables->nabove_hispeed_delay; i++) ++ ret += sprintf(buf + ret, "%u%s", ++ tunables->above_hispeed_delay[i], ++ i & 0x1 ? ":" : " "); ++ ++ sprintf(buf + ret - 1, "\n"); ++ spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags); ++ return ret; ++} ++ ++static ssize_t store_above_hispeed_delay( ++ struct cpufreq_interactive_tunables *tunables, ++ const char *buf, size_t count) ++{ ++ int ntokens; ++ unsigned int *new_above_hispeed_delay = NULL; ++ unsigned long flags; ++ ++ new_above_hispeed_delay = get_tokenized_data(buf, &ntokens); ++ if (IS_ERR(new_above_hispeed_delay)) ++ return PTR_RET(new_above_hispeed_delay); ++ ++ spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags); ++ if (tunables->above_hispeed_delay != default_above_hispeed_delay) ++ kfree(tunables->above_hispeed_delay); ++ tunables->above_hispeed_delay = new_above_hispeed_delay; ++ tunables->nabove_hispeed_delay = ntokens; ++ spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags); ++ return count; ++ ++} ++ ++static ssize_t show_hispeed_freq(struct cpufreq_interactive_tunables *tunables, ++ char *buf) ++{ ++ return sprintf(buf, "%u\n", tunables->hispeed_freq); ++} ++ ++static ssize_t store_hispeed_freq(struct cpufreq_interactive_tunables *tunables, ++ const char *buf, size_t count) ++{ ++ int ret; ++ long unsigned int val; ++ ++ ret = strict_strtoul(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ tunables->hispeed_freq = val; ++ return count; ++} ++ ++static ssize_t show_go_hispeed_load(struct cpufreq_interactive_tunables ++ *tunables, char *buf) ++{ ++ return sprintf(buf, "%lu\n", tunables->go_hispeed_load); ++} ++ ++static ssize_t store_go_hispeed_load(struct cpufreq_interactive_tunables ++ *tunables, const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = strict_strtoul(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ tunables->go_hispeed_load = val; ++ return count; ++} ++ ++static ssize_t show_min_sample_time(struct cpufreq_interactive_tunables ++ *tunables, char *buf) ++{ ++ return sprintf(buf, "%lu\n", tunables->min_sample_time); ++} ++ ++static ssize_t store_min_sample_time(struct cpufreq_interactive_tunables ++ *tunables, const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = strict_strtoul(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ tunables->min_sample_time = val; ++ return count; ++} ++ ++static ssize_t show_timer_rate(struct cpufreq_interactive_tunables *tunables, ++ char *buf) ++{ ++ return sprintf(buf, "%lu\n", tunables->timer_rate); ++} ++ ++static ssize_t store_timer_rate(struct cpufreq_interactive_tunables *tunables, ++ const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = strict_strtoul(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ tunables->timer_rate = val; ++ return count; ++} ++ ++static ssize_t show_timer_slack(struct cpufreq_interactive_tunables *tunables, ++ char *buf) ++{ ++ return sprintf(buf, "%d\n", tunables->timer_slack_val); ++} ++ ++static ssize_t store_timer_slack(struct cpufreq_interactive_tunables *tunables, ++ const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = kstrtol(buf, 10, &val); ++ if (ret < 0) ++ return ret; ++ ++ tunables->timer_slack_val = val; ++ return count; ++} ++ ++static ssize_t show_boost(struct cpufreq_interactive_tunables *tunables, ++ char *buf) ++{ ++ return sprintf(buf, "%d\n", tunables->boost_val); ++} ++ ++static ssize_t store_boost(struct cpufreq_interactive_tunables *tunables, ++ const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = kstrtoul(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ ++ tunables->boost_val = val; ++ ++ if (tunables->boost_val) { ++ trace_cpufreq_interactive_boost("on"); ++ cpufreq_interactive_boost(); ++ } else { ++ trace_cpufreq_interactive_unboost("off"); ++ } ++ ++ return count; ++} ++ ++static ssize_t store_boostpulse(struct cpufreq_interactive_tunables *tunables, ++ const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = kstrtoul(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ ++ tunables->boostpulse_endtime = ktime_to_us(ktime_get()) + ++ tunables->boostpulse_duration_val; ++ trace_cpufreq_interactive_boost("pulse"); ++ cpufreq_interactive_boost(); ++ return count; ++} ++ ++static ssize_t show_boostpulse_duration(struct cpufreq_interactive_tunables ++ *tunables, char *buf) ++{ ++ return sprintf(buf, "%d\n", tunables->boostpulse_duration_val); ++} ++ ++static ssize_t store_boostpulse_duration(struct cpufreq_interactive_tunables ++ *tunables, const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = kstrtoul(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ ++ tunables->boostpulse_duration_val = val; ++ return count; ++} ++ ++static ssize_t show_io_is_busy(struct cpufreq_interactive_tunables *tunables, ++ char *buf) ++{ ++ return sprintf(buf, "%u\n", tunables->io_is_busy); ++} ++ ++static ssize_t store_io_is_busy(struct cpufreq_interactive_tunables *tunables, ++ const char *buf, size_t count) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = kstrtoul(buf, 0, &val); ++ if (ret < 0) ++ return ret; ++ tunables->io_is_busy = val; ++ return count; ++} ++ ++/* ++ * Create show/store routines ++ * - sys: One governor instance for complete SYSTEM ++ * - pol: One governor instance per struct cpufreq_policy ++ */ ++#define show_gov_pol_sys(file_name) \ ++static ssize_t show_##file_name##_gov_sys \ ++(struct kobject *kobj, struct attribute *attr, char *buf) \ ++{ \ ++ return show_##file_name(common_tunables, buf); \ ++} \ ++ \ ++static ssize_t show_##file_name##_gov_pol \ ++(struct cpufreq_policy *policy, char *buf) \ ++{ \ ++ return show_##file_name(policy->governor_data, buf); \ ++} ++ ++#define store_gov_pol_sys(file_name) \ ++static ssize_t store_##file_name##_gov_sys \ ++(struct kobject *kobj, struct attribute *attr, const char *buf, \ ++ size_t count) \ ++{ \ ++ return store_##file_name(common_tunables, buf, count); \ ++} \ ++ \ ++static ssize_t store_##file_name##_gov_pol \ ++(struct cpufreq_policy *policy, const char *buf, size_t count) \ ++{ \ ++ return store_##file_name(policy->governor_data, buf, count); \ ++} ++ ++#define show_store_gov_pol_sys(file_name) \ ++show_gov_pol_sys(file_name); \ ++store_gov_pol_sys(file_name) ++ ++show_store_gov_pol_sys(target_loads); ++show_store_gov_pol_sys(above_hispeed_delay); ++show_store_gov_pol_sys(hispeed_freq); ++show_store_gov_pol_sys(go_hispeed_load); ++show_store_gov_pol_sys(min_sample_time); ++show_store_gov_pol_sys(timer_rate); ++show_store_gov_pol_sys(timer_slack); ++show_store_gov_pol_sys(boost); ++store_gov_pol_sys(boostpulse); ++show_store_gov_pol_sys(boostpulse_duration); ++show_store_gov_pol_sys(io_is_busy); ++ ++#define gov_sys_attr_rw(_name) \ ++static struct global_attr _name##_gov_sys = \ ++__ATTR(_name, 0644, show_##_name##_gov_sys, store_##_name##_gov_sys) ++ ++#define gov_pol_attr_rw(_name) \ ++static struct freq_attr _name##_gov_pol = \ ++__ATTR(_name, 0644, show_##_name##_gov_pol, store_##_name##_gov_pol) ++ ++#define gov_sys_pol_attr_rw(_name) \ ++ gov_sys_attr_rw(_name); \ ++ gov_pol_attr_rw(_name) ++ ++gov_sys_pol_attr_rw(target_loads); ++gov_sys_pol_attr_rw(above_hispeed_delay); ++gov_sys_pol_attr_rw(hispeed_freq); ++gov_sys_pol_attr_rw(go_hispeed_load); ++gov_sys_pol_attr_rw(min_sample_time); ++gov_sys_pol_attr_rw(timer_rate); ++gov_sys_pol_attr_rw(timer_slack); ++gov_sys_pol_attr_rw(boost); ++gov_sys_pol_attr_rw(boostpulse_duration); ++gov_sys_pol_attr_rw(io_is_busy); ++ ++static struct global_attr boostpulse_gov_sys = ++ __ATTR(boostpulse, 0200, NULL, store_boostpulse_gov_sys); ++ ++static struct freq_attr boostpulse_gov_pol = ++ __ATTR(boostpulse, 0200, NULL, store_boostpulse_gov_pol); ++ ++/* One Governor instance for entire system */ ++static struct attribute *interactive_attributes_gov_sys[] = { ++ &target_loads_gov_sys.attr, ++ &above_hispeed_delay_gov_sys.attr, ++ &hispeed_freq_gov_sys.attr, ++ &go_hispeed_load_gov_sys.attr, ++ &min_sample_time_gov_sys.attr, ++ &timer_rate_gov_sys.attr, ++ &timer_slack_gov_sys.attr, ++ &boost_gov_sys.attr, ++ &boostpulse_gov_sys.attr, ++ &boostpulse_duration_gov_sys.attr, ++ &io_is_busy_gov_sys.attr, ++ NULL, ++}; ++ ++static struct attribute_group interactive_attr_group_gov_sys = { ++ .attrs = interactive_attributes_gov_sys, ++ .name = "interactive", ++}; ++ ++/* Per policy governor instance */ ++static struct attribute *interactive_attributes_gov_pol[] = { ++ &target_loads_gov_pol.attr, ++ &above_hispeed_delay_gov_pol.attr, ++ &hispeed_freq_gov_pol.attr, ++ &go_hispeed_load_gov_pol.attr, ++ &min_sample_time_gov_pol.attr, ++ &timer_rate_gov_pol.attr, ++ &timer_slack_gov_pol.attr, ++ &boost_gov_pol.attr, ++ &boostpulse_gov_pol.attr, ++ &boostpulse_duration_gov_pol.attr, ++ &io_is_busy_gov_pol.attr, ++ NULL, ++}; ++ ++static struct attribute_group interactive_attr_group_gov_pol = { ++ .attrs = interactive_attributes_gov_pol, ++ .name = "interactive", ++}; ++ ++static struct attribute_group *get_sysfs_attr(void) ++{ ++ if (have_governor_per_policy()) ++ return &interactive_attr_group_gov_pol; ++ else ++ return &interactive_attr_group_gov_sys; ++} ++ ++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 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; ++ struct cpufreq_interactive_tunables *tunables; ++ ++ if (have_governor_per_policy()) ++ tunables = policy->governor_data; ++ else ++ tunables = common_tunables; ++ ++ WARN_ON(!tunables && (event != CPUFREQ_GOV_POLICY_INIT)); ++ ++ switch (event) { ++ case CPUFREQ_GOV_POLICY_INIT: ++ if (have_governor_per_policy()) { ++ WARN_ON(tunables); ++ } else if (tunables) { ++ tunables->usage_count++; ++ policy->governor_data = tunables; ++ return 0; ++ } ++ ++ tunables = kzalloc(sizeof(*tunables), GFP_KERNEL); ++ if (!tunables) { ++ pr_err("%s: POLICY_INIT: kzalloc failed\n", __func__); ++ return -ENOMEM; ++ } ++ ++ tunables->usage_count = 1; ++ tunables->above_hispeed_delay = default_above_hispeed_delay; ++ tunables->nabove_hispeed_delay = ++ ARRAY_SIZE(default_above_hispeed_delay); ++ tunables->go_hispeed_load = DEFAULT_GO_HISPEED_LOAD; ++ tunables->target_loads = default_target_loads; ++ tunables->ntarget_loads = ARRAY_SIZE(default_target_loads); ++ tunables->min_sample_time = DEFAULT_MIN_SAMPLE_TIME; ++ tunables->timer_rate = DEFAULT_TIMER_RATE; ++ tunables->boostpulse_duration_val = DEFAULT_MIN_SAMPLE_TIME; ++ tunables->timer_slack_val = DEFAULT_TIMER_SLACK; ++ ++ spin_lock_init(&tunables->target_loads_lock); ++ spin_lock_init(&tunables->above_hispeed_delay_lock); ++ ++ policy->governor_data = tunables; ++ if (!have_governor_per_policy()) { ++ common_tunables = tunables; ++ WARN_ON(cpufreq_get_global_kobject()); ++ } ++ ++ rc = sysfs_create_group(get_governor_parent_kobj(policy), ++ get_sysfs_attr()); ++ if (rc) { ++ kfree(tunables); ++ policy->governor_data = NULL; ++ if (!have_governor_per_policy()) ++ common_tunables = NULL; ++ return rc; ++ } ++ ++ if (!policy->governor->initialized) { ++ idle_notifier_register(&cpufreq_interactive_idle_nb); ++ cpufreq_register_notifier(&cpufreq_notifier_block, ++ CPUFREQ_TRANSITION_NOTIFIER); ++ } ++ ++ break; ++ ++ case CPUFREQ_GOV_POLICY_EXIT: ++ if (!--tunables->usage_count) { ++ sysfs_remove_group(get_governor_parent_kobj(policy), ++ get_sysfs_attr()); ++ ++ if (!have_governor_per_policy()) ++ cpufreq_put_global_kobject(); ++ ++ if (policy->governor->initialized == 1) { ++ cpufreq_unregister_notifier(&cpufreq_notifier_block, ++ CPUFREQ_TRANSITION_NOTIFIER); ++ idle_notifier_unregister(&cpufreq_interactive_idle_nb); ++ } ++ ++ kfree(tunables); ++ common_tunables = NULL; ++ } ++ ++ policy->governor_data = NULL; ++ break; ++ ++ case CPUFREQ_GOV_START: ++ mutex_lock(&gov_lock); ++ ++ freq_table = cpufreq_frequency_get_table(policy->cpu); ++ if (!tunables->hispeed_freq) ++ tunables->hispeed_freq = policy->max; ++ ++ for_each_cpu(j, policy->cpus) { ++ pcpu = &per_cpu(cpuinfo, j); ++ pcpu->policy = policy; ++ pcpu->target_freq = policy->cur; ++ pcpu->freq_table = freq_table; ++ pcpu->floor_freq = pcpu->target_freq; ++ pcpu->floor_validate_time = ++ ktime_to_us(ktime_get()); ++ pcpu->hispeed_validate_time = ++ pcpu->floor_validate_time; ++ down_write(&pcpu->enable_sem); ++ del_timer_sync(&pcpu->cpu_timer); ++ del_timer_sync(&pcpu->cpu_slack_timer); ++ cpufreq_interactive_timer_start(tunables, j); ++ pcpu->governor_enabled = 1; ++ up_write(&pcpu->enable_sem); ++ } ++ ++ mutex_unlock(&gov_lock); ++ break; ++ ++ case CPUFREQ_GOV_STOP: ++ mutex_lock(&gov_lock); ++ for_each_cpu(j, policy->cpus) { ++ pcpu = &per_cpu(cpuinfo, j); ++ down_write(&pcpu->enable_sem); ++ pcpu->governor_enabled = 0; ++ del_timer_sync(&pcpu->cpu_timer); ++ del_timer_sync(&pcpu->cpu_slack_timer); ++ up_write(&pcpu->enable_sem); ++ } ++ ++ mutex_unlock(&gov_lock); ++ 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); ++ for_each_cpu(j, policy->cpus) { ++ pcpu = &per_cpu(cpuinfo, j); ++ ++ /* hold write semaphore to avoid race */ ++ down_write(&pcpu->enable_sem); ++ if (pcpu->governor_enabled == 0) { ++ up_write(&pcpu->enable_sem); ++ continue; ++ } ++ ++ /* update target_freq firstly */ ++ if (policy->max < pcpu->target_freq) ++ pcpu->target_freq = policy->max; ++ else if (policy->min > pcpu->target_freq) ++ pcpu->target_freq = policy->min; ++ ++ /* Reschedule timer. ++ * Delete the timers, else the timer callback may ++ * return without re-arm the timer when failed ++ * acquire the semaphore. This race may cause timer ++ * stopped unexpectedly. ++ */ ++ del_timer_sync(&pcpu->cpu_timer); ++ del_timer_sync(&pcpu->cpu_slack_timer); ++ cpufreq_interactive_timer_start(tunables, j); ++ up_write(&pcpu->enable_sem); ++ } ++ break; ++ } ++ return 0; ++} ++ ++#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_nop_timer(unsigned long data) ++{ ++} ++ ++static int __init cpufreq_interactive_init(void) ++{ ++ unsigned int i; ++ struct cpufreq_interactive_cpuinfo *pcpu; ++ struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; ++ ++ /* Initalize per-cpu timers */ ++ for_each_possible_cpu(i) { ++ pcpu = &per_cpu(cpuinfo, i); ++ init_timer_deferrable(&pcpu->cpu_timer); ++ pcpu->cpu_timer.function = cpufreq_interactive_timer; ++ pcpu->cpu_timer.data = i; ++ init_timer(&pcpu->cpu_slack_timer); ++ pcpu->cpu_slack_timer.function = cpufreq_interactive_nop_timer; ++ spin_lock_init(&pcpu->load_lock); ++ init_rwsem(&pcpu->enable_sem); ++ } ++ ++ spin_lock_init(&speedchange_cpumask_lock); ++ mutex_init(&gov_lock); ++ speedchange_task = ++ kthread_create(cpufreq_interactive_speedchange_task, NULL, ++ "cfinteractive"); ++ if (IS_ERR(speedchange_task)) ++ return PTR_ERR(speedchange_task); ++ ++ sched_setscheduler_nocheck(speedchange_task, SCHED_FIFO, ¶m); ++ get_task_struct(speedchange_task); ++ ++ /* NB: wake up so the thread does not look hung to the freezer */ ++ wake_up_process(speedchange_task); ++ ++ return cpufreq_register_governor(&cpufreq_gov_interactive); ++} ++ ++#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE ++fs_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(speedchange_task); ++ put_task_struct(speedchange_task); ++} ++ ++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.14.40.orig/drivers/cpufreq/highbank-cpufreq.c linux-3.14.40/drivers/cpufreq/highbank-cpufreq.c +--- linux-3.14.40.orig/drivers/cpufreq/highbank-cpufreq.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/cpufreq/highbank-cpufreq.c 2015-05-01 14:57:58.895427001 -0500 +@@ -19,7 +19,7 @@ + #include + #include + #include +-#include ++#include + #include + + #define HB_CPUFREQ_CHANGE_NOTE 0x80000001 +diff -Nur linux-3.14.40.orig/drivers/cpufreq/imx6-cpufreq.c linux-3.14.40/drivers/cpufreq/imx6-cpufreq.c +--- linux-3.14.40.orig/drivers/cpufreq/imx6-cpufreq.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/cpufreq/imx6-cpufreq.c 2015-05-01 14:57:58.895427001 -0500 +@@ -0,0 +1,393 @@ ++/* ++ * 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 ++ ++#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 struct mutex set_cpufreq_lock; ++ ++static u32 *imx6_soc_volt; ++static u32 soc_opp_count; ++ ++static int imx6_set_target(struct cpufreq_policy *policy, unsigned int index) ++{ ++ struct dev_pm_opp *opp; ++ unsigned long freq_hz, volt, volt_old; ++ unsigned int old_freq, new_freq; ++ int ret; ++ ++ mutex_lock(&set_cpufreq_lock); ++ ++ new_freq = freq_table[index].frequency; ++ freq_hz = new_freq * 1000; ++ old_freq = clk_get_rate(arm_clk) / 1000; ++ ++ rcu_read_lock(); ++ opp = dev_pm_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); ++ ret = PTR_ERR(opp); ++ goto unlock; ++ } ++ ++ volt = dev_pm_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", ++ old_freq / 1000, volt_old / 1000, ++ new_freq / 1000, volt / 1000); ++ ++ /* ++ * CPU freq is increasing, so need to ensure ++ * that bus frequency is increased too. ++ */ ++ if (old_freq == freq_table[0].frequency) ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ /* scaling up? scale voltage before frequency */ ++ if (new_freq > old_freq) { ++ if (regulator_is_enabled(pu_reg)) { ++ ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); ++ if (ret) { ++ dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret); ++ goto unlock; ++ } ++ } ++ ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); ++ if (ret) { ++ dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret); ++ goto unlock; ++ } ++ ret = regulator_set_voltage_tol(arm_reg, volt, 0); ++ if (ret) { ++ dev_err(cpu_dev, ++ "failed to scale vddarm up: %d\n", ret); ++ goto unlock; ++ } ++ } ++ ++ /* ++ * 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, new_freq * 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, new_freq * 1000); ++ if (ret) { ++ dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); ++ regulator_set_voltage_tol(arm_reg, volt_old, 0); ++ goto unlock; ++ } ++ ++ /* scaling down? scale voltage after frequency */ ++ if (new_freq < old_freq) { ++ ret = regulator_set_voltage_tol(arm_reg, volt, 0); ++ if (ret) { ++ dev_warn(cpu_dev, ++ "failed to scale vddarm down: %d\n", ret); ++ ret = 0; ++ } ++ ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); ++ if (ret) { ++ dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret); ++ ret = 0; ++ } ++ if (regulator_is_enabled(pu_reg)) { ++ ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); ++ if (ret) { ++ dev_warn(cpu_dev, "failed to scale vddpu down: %d\n", ret); ++ ret = 0; ++ } ++ } ++ } ++ ++ if (policy->cur == freq_table[0].frequency) ++ release_bus_freq(BUS_FREQ_HIGH); ++ ++unlock: ++ mutex_unlock(&set_cpufreq_lock); ++ return ret; ++} ++ ++static int imx6_cpufreq_init(struct cpufreq_policy *policy) ++{ ++ policy->clk = arm_clk; ++ ++ if (policy->cur > freq_table[0].frequency) ++ request_bus_freq(BUS_FREQ_HIGH); ++ ++ return cpufreq_generic_init(policy, freq_table, transition_latency); ++} ++ ++static struct cpufreq_driver imx6_cpufreq_driver = { ++ .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, ++ .verify = cpufreq_generic_frequency_table_verify, ++ .target_index = imx6_set_target, ++ .get = cpufreq_generic_get, ++ .init = imx6_cpufreq_init, ++ .exit = cpufreq_generic_exit, ++ .name = "imx6-cpufreq", ++ .attr = cpufreq_generic_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 dev_pm_opp *opp; ++ unsigned long min_volt, max_volt; ++ int num, ret; ++ const struct property *prop; ++ const __be32 *val; ++ u32 nr, i, j; ++ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ pr_err("failed to get cpu0 device\n"); ++ return -ENODEV; ++ } ++ ++ np = of_node_get(cpu_dev->of_node); ++ if (!np) { ++ dev_err(cpu_dev, "failed to find cpu0 node\n"); ++ return -ENOENT; ++ } ++ ++ 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. ++ * Just, incase the platform did not supply the OPP ++ * table, it will try to get it. ++ */ ++ num = dev_pm_opp_get_opp_count(cpu_dev); ++ if (num < 0) { ++ ret = of_init_opp_table(cpu_dev); ++ if (ret < 0) { ++ dev_err(cpu_dev, "failed to init OPP table: %d\n", ret); ++ goto put_node; ++ } ++ ++ num = dev_pm_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 = dev_pm_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; ++ } ++ ++ /* Make imx6_soc_volt array's size same as arm opp number */ ++ imx6_soc_volt = devm_kzalloc(cpu_dev, sizeof(*imx6_soc_volt) * num, GFP_KERNEL); ++ if (imx6_soc_volt == NULL) { ++ ret = -ENOMEM; ++ goto free_freq_table; ++ } ++ ++ prop = of_find_property(np, "fsl,soc-operating-points", NULL); ++ if (!prop || !prop->value) ++ goto soc_opp_out; ++ ++ /* ++ * Each OPP is a set of tuples consisting of frequency and ++ * voltage like . ++ */ ++ nr = prop->length / sizeof(u32); ++ if (nr % 2 || (nr / 2) < num) ++ goto soc_opp_out; ++ ++ for (j = 0; j < num; j++) { ++ 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 (freq_table[j].frequency == freq) { ++ imx6_soc_volt[soc_opp_count++] = volt; ++ break; ++ } ++ } ++ } ++ ++soc_opp_out: ++ /* use fixed soc opp volt if no valid soc opp info found in dtb */ ++ if (soc_opp_count != num) { ++ dev_warn(cpu_dev, "can NOT find valid fsl,soc-operating-points property in dtb, use default value!\n"); ++ for (j = 0; j < num; j++) ++ imx6_soc_volt[j] = PU_SOC_VOLTAGE_NORMAL; ++ if (freq_table[num - 1].frequency * 1000 == FREQ_1P2_GHZ) ++ imx6_soc_volt[num - 1] = PU_SOC_VOLTAGE_HIGH; ++ } ++ ++ 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, imx6_soc_volt[0], imx6_soc_volt[num - 1]); ++ if (ret > 0) ++ transition_latency += ret * 1000; ++ ret = regulator_set_voltage_time(pu_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]); ++ 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 = dev_pm_opp_find_freq_exact(cpu_dev, ++ freq_table[0].frequency * 1000, true); ++ min_volt = dev_pm_opp_get_voltage(opp); ++ opp = dev_pm_opp_find_freq_exact(cpu_dev, ++ freq_table[--num].frequency * 1000, true); ++ max_volt = dev_pm_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: ++ dev_pm_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); ++ dev_pm_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.MX6Q cpufreq driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.40.orig/drivers/cpufreq/imx6q-cpufreq.c linux-3.14.40/drivers/cpufreq/imx6q-cpufreq.c +--- linux-3.14.40.orig/drivers/cpufreq/imx6q-cpufreq.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/cpufreq/imx6q-cpufreq.c 1969-12-31 18:00:00.000000000 -0600 +@@ -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 +-#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 u32 *imx6_soc_volt; +-static u32 soc_opp_count; +- +-static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) +-{ +- struct dev_pm_opp *opp; +- unsigned long freq_hz, volt, volt_old; +- unsigned int old_freq, new_freq; +- int ret; +- +- new_freq = freq_table[index].frequency; +- freq_hz = new_freq * 1000; +- old_freq = clk_get_rate(arm_clk) / 1000; +- +- rcu_read_lock(); +- opp = dev_pm_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 = dev_pm_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", +- old_freq / 1000, volt_old / 1000, +- new_freq / 1000, volt / 1000); +- +- /* scaling up? scale voltage before frequency */ +- if (new_freq > old_freq) { +- ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); +- if (ret) { +- dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret); +- return ret; +- } +- ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); +- if (ret) { +- dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret); +- return ret; +- } +- 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; +- } +- } +- +- /* +- * 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, new_freq * 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, new_freq * 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 (new_freq < old_freq) { +- ret = regulator_set_voltage_tol(arm_reg, volt, 0); +- if (ret) { +- dev_warn(cpu_dev, +- "failed to scale vddarm down: %d\n", ret); +- ret = 0; +- } +- ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0); +- if (ret) { +- dev_warn(cpu_dev, "failed to scale vddsoc down: %d\n", ret); +- ret = 0; +- } +- ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0); +- if (ret) { +- dev_warn(cpu_dev, "failed to scale vddpu down: %d\n", ret); +- ret = 0; +- } +- } +- +- return 0; +-} +- +-static int imx6q_cpufreq_init(struct cpufreq_policy *policy) +-{ +- policy->clk = arm_clk; +- return cpufreq_generic_init(policy, freq_table, transition_latency); +-} +- +-static struct cpufreq_driver imx6q_cpufreq_driver = { +- .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, +- .verify = cpufreq_generic_frequency_table_verify, +- .target_index = imx6q_set_target, +- .get = cpufreq_generic_get, +- .init = imx6q_cpufreq_init, +- .exit = cpufreq_generic_exit, +- .name = "imx6q-cpufreq", +- .attr = cpufreq_generic_attr, +-}; +- +-static int imx6q_cpufreq_probe(struct platform_device *pdev) +-{ +- struct device_node *np; +- struct dev_pm_opp *opp; +- unsigned long min_volt, max_volt; +- int num, ret; +- const struct property *prop; +- const __be32 *val; +- u32 nr, i, j; +- +- cpu_dev = get_cpu_device(0); +- if (!cpu_dev) { +- pr_err("failed to get cpu0 device\n"); +- return -ENODEV; +- } +- +- np = of_node_get(cpu_dev->of_node); +- if (!np) { +- dev_err(cpu_dev, "failed to find cpu0 node\n"); +- return -ENOENT; +- } +- +- 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. +- * Just, incase the platform did not supply the OPP +- * table, it will try to get it. +- */ +- num = dev_pm_opp_get_opp_count(cpu_dev); +- if (num < 0) { +- ret = of_init_opp_table(cpu_dev); +- if (ret < 0) { +- dev_err(cpu_dev, "failed to init OPP table: %d\n", ret); +- goto put_node; +- } +- +- num = dev_pm_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 = dev_pm_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; +- } +- +- /* Make imx6_soc_volt array's size same as arm opp number */ +- imx6_soc_volt = devm_kzalloc(cpu_dev, sizeof(*imx6_soc_volt) * num, GFP_KERNEL); +- if (imx6_soc_volt == NULL) { +- ret = -ENOMEM; +- goto free_freq_table; +- } +- +- prop = of_find_property(np, "fsl,soc-operating-points", NULL); +- if (!prop || !prop->value) +- goto soc_opp_out; +- +- /* +- * Each OPP is a set of tuples consisting of frequency and +- * voltage like . +- */ +- nr = prop->length / sizeof(u32); +- if (nr % 2 || (nr / 2) < num) +- goto soc_opp_out; +- +- for (j = 0; j < num; j++) { +- 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 (freq_table[j].frequency == freq) { +- imx6_soc_volt[soc_opp_count++] = volt; +- break; +- } +- } +- } +- +-soc_opp_out: +- /* use fixed soc opp volt if no valid soc opp info found in dtb */ +- if (soc_opp_count != num) { +- dev_warn(cpu_dev, "can NOT find valid fsl,soc-operating-points property in dtb, use default value!\n"); +- for (j = 0; j < num; j++) +- imx6_soc_volt[j] = PU_SOC_VOLTAGE_NORMAL; +- if (freq_table[num - 1].frequency * 1000 == FREQ_1P2_GHZ) +- imx6_soc_volt[num - 1] = PU_SOC_VOLTAGE_HIGH; +- } +- +- 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, imx6_soc_volt[0], imx6_soc_volt[num - 1]); +- if (ret > 0) +- transition_latency += ret * 1000; +- ret = regulator_set_voltage_time(pu_reg, imx6_soc_volt[0], imx6_soc_volt[num - 1]); +- 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 = dev_pm_opp_find_freq_exact(cpu_dev, +- freq_table[0].frequency * 1000, true); +- min_volt = dev_pm_opp_get_voltage(opp); +- opp = dev_pm_opp_find_freq_exact(cpu_dev, +- freq_table[--num].frequency * 1000, true); +- max_volt = dev_pm_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; +- +- 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: +- dev_pm_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); +- dev_pm_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.14.40.orig/drivers/cpufreq/Kconfig linux-3.14.40/drivers/cpufreq/Kconfig +--- linux-3.14.40.orig/drivers/cpufreq/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/cpufreq/Kconfig 2015-05-01 14:57:58.895427001 -0500 +@@ -91,6 +91,15 @@ + 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 ++ 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. ++ + config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE + bool "conservative" + select CPU_FREQ_GOV_CONSERVATIVE +@@ -157,6 +166,24 @@ + + For details, take a look at linux/Documentation/cpu-freq. + ++ If in doubt, say N. ++ ++config CPU_FREQ_GOV_INTERACTIVE ++ tristate "'interactive' cpufreq policy governor" ++ default n ++ 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 CPU_FREQ_GOV_CONSERVATIVE +diff -Nur linux-3.14.40.orig/drivers/cpufreq/Kconfig.arm linux-3.14.40/drivers/cpufreq/Kconfig.arm +--- linux-3.14.40.orig/drivers/cpufreq/Kconfig.arm 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/cpufreq/Kconfig.arm 2015-05-01 14:57:58.911427001 -0500 +@@ -4,7 +4,8 @@ + + config ARM_BIG_LITTLE_CPUFREQ + tristate "Generic ARM big LITTLE CPUfreq driver" +- depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK ++ depends on (BIG_LITTLE && ARM_CPU_TOPOLOGY) || (ARM64 && SMP) ++ depends on HAVE_CLK + select PM_OPP + help + This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. +@@ -95,7 +96,7 @@ + + If in doubt, say N. + +-config ARM_IMX6Q_CPUFREQ ++config ARM_IMX6_CPUFREQ + tristate "Freescale i.MX6 cpufreq support" + depends on ARCH_MXC + depends on REGULATOR_ANATOP +diff -Nur linux-3.14.40.orig/drivers/cpufreq/Makefile linux-3.14.40/drivers/cpufreq/Makefile +--- linux-3.14.40.orig/drivers/cpufreq/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/cpufreq/Makefile 2015-05-01 14:57:58.951427001 -0500 +@@ -8,6 +8,7 @@ + obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o + obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o + obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o ++obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o + obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o + obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o + +@@ -55,7 +56,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) += imx6-cpufreq.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.14.40.orig/drivers/crypto/caam/secvio.c linux-3.14.40/drivers/crypto/caam/secvio.c +--- linux-3.14.40.orig/drivers/crypto/caam/secvio.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/crypto/caam/secvio.c 2015-05-01 14:57:58.951427001 -0500 +@@ -0,0 +1,335 @@ ++ ++/* ++ * 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; ++ ++ printk(KERN_ERR "secvio_inten_src = %x\n", secvio_inten_src); ++ ++ 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.14.40.orig/drivers/crypto/caam/secvio.h linux-3.14.40/drivers/crypto/caam/secvio.h +--- linux-3.14.40.orig/drivers/crypto/caam/secvio.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/crypto/caam/secvio.h 2015-05-01 14:57:58.951427001 -0500 +@@ -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.14.40.orig/drivers/crypto/caam/sm.h linux-3.14.40/drivers/crypto/caam/sm.h +--- linux-3.14.40.orig/drivers/crypto/caam/sm.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/crypto/caam/sm.h 2015-05-01 14:57:58.951427001 -0500 +@@ -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.14.40.orig/drivers/crypto/caam/sm_store.c linux-3.14.40/drivers/crypto/caam/sm_store.c +--- linux-3.14.40.orig/drivers/crypto/caam/sm_store.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/crypto/caam/sm_store.c 2015-05-01 14:57:58.951427001 -0500 +@@ -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.14.40.orig/drivers/crypto/caam/sm_test.c linux-3.14.40/drivers/crypto/caam/sm_test.c +--- linux-3.14.40.orig/drivers/crypto/caam/sm_test.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/crypto/caam/sm_test.c 2015-05-01 14:57:58.955427001 -0500 +@@ -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.14.40.orig/drivers/crypto/caam/snvsregs.h linux-3.14.40/drivers/crypto/caam/snvsregs.h +--- linux-3.14.40.orig/drivers/crypto/caam/snvsregs.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/crypto/caam/snvsregs.h 2015-05-01 14:57:58.955427001 -0500 +@@ -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.14.40.orig/drivers/dma/imx-sdma.c linux-3.14.40/drivers/dma/imx-sdma.c +--- linux-3.14.40.orig/drivers/dma/imx-sdma.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/dma/imx-sdma.c 2015-05-01 14:57:58.963427001 -0500 +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -232,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 +253,7 @@ + * @word_size peripheral access size + * @buf_tail ID of the buffer that was processed + * @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; +@@ -255,14 +265,19 @@ + enum dma_slave_buswidth word_size; + unsigned int buf_tail; + unsigned int num_bd; ++ unsigned int period_len; + 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; +@@ -272,8 +287,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 +@@ -325,6 +338,7 @@ + spinlock_t channel_0_lock; + u32 script_number; + struct sdma_script_start_addrs *script_addrs; ++ struct gen_pool *iram_pool; + const struct sdma_driver_data *drvdata; + }; + +@@ -540,12 +554,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); +@@ -562,7 +578,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; + } +@@ -593,6 +612,12 @@ + + static void sdma_handle_channel_loop(struct sdma_channel *sdmac) + { ++ if (sdmac->desc.callback) ++ sdmac->desc.callback(sdmac->desc.callback_param); ++} ++ ++static void sdma_update_channel_loop(struct sdma_channel *sdmac) ++{ + struct sdma_buffer_descriptor *bd; + + /* +@@ -607,15 +632,10 @@ + + if (bd->mode.status & BD_RROR) + sdmac->status = DMA_ERROR; +- else +- sdmac->status = DMA_IN_PROGRESS; + + bd->mode.status |= BD_DONE; + sdmac->buf_tail++; + sdmac->buf_tail %= sdmac->num_bd; +- +- if (sdmac->desc.callback) +- sdmac->desc.callback(sdmac->desc.callback_param); + } + } + +@@ -647,14 +667,31 @@ + 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; + +- 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) +@@ -671,6 +708,9 @@ + int channel = fls(stat) - 1; + struct sdma_channel *sdmac = &sdma->channel[channel]; + ++ if (sdmac->mode & SDMA_MODE_LOOP) ++ sdma_update_channel_loop(sdmac); ++ + tasklet_schedule(&sdmac->tasklet); + + __clear_bit(channel, &stat); +@@ -692,9 +732,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: +@@ -740,8 +783,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: +@@ -758,12 +801,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) +@@ -776,11 +824,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; +@@ -800,11 +851,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; +@@ -829,6 +885,7 @@ + + static int sdma_config_channel(struct sdma_channel *sdmac) + { ++ struct imx_dma_data *data = sdmac->chan.private; + int ret; + + sdma_disable_channel(sdmac); +@@ -837,12 +894,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->drvdata->num_events) + return -EINVAL; + sdma_event_enable(sdmac, sdmac->event_id0); + } ++ if (sdmac->event_id1) { ++ if (sdmac->event_id1 >= sdmac->sdma->drvdata->num_events) ++ return -EINVAL; ++ sdma_event_enable(sdmac, sdmac->event_id1); ++ } + + switch (sdmac->peripheral_type) { + case IMX_DMATYPE_DSP: +@@ -862,19 +926,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 */ + } +@@ -906,10 +1026,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); +@@ -967,7 +1092,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); +@@ -985,6 +1111,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; + } + +@@ -1005,7 +1134,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); +@@ -1026,7 +1158,7 @@ + return NULL; + sdmac->status = DMA_IN_PROGRESS; + +- sdmac->flags = 0; ++ sdmac->mode = SDMA_MODE_NORMAL; + + sdmac->buf_tail = 0; + +@@ -1119,9 +1251,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); + +@@ -1131,13 +1263,35 @@ + sdmac->status = DMA_IN_PROGRESS; + + sdmac->buf_tail = 0; ++ sdmac->period_len = period_len; + +- 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); +@@ -1202,18 +1356,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; +@@ -1227,9 +1394,15 @@ + struct dma_tx_state *txstate) + { + struct sdma_channel *sdmac = to_sdma_chan(chan); ++ u32 residue; ++ ++ if (sdmac->mode & SDMA_MODE_LOOP) ++ residue = (sdmac->num_bd - sdmac->buf_tail) * sdmac->period_len; ++ else ++ residue = sdmac->chn_count - sdmac->chn_real_count; + + dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, +- sdmac->chn_count - sdmac->chn_real_count); ++ residue); + + return sdmac->status; + } +@@ -1285,7 +1458,10 @@ + goto err_firmware; + switch (header->version_major) { + case 1: +- sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; ++ if (header->version_minor > 0) ++ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2; ++ else ++ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; + break; + case 2: + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2; +@@ -1331,7 +1507,7 @@ + + static int __init sdma_init(struct sdma_engine *sdma) + { +- int i, ret; ++ int i, ret, ccbsize; + dma_addr_t ccb_phys; + + clk_enable(sdma->clk_ipg); +@@ -1340,14 +1516,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 + +@@ -1422,9 +1601,10 @@ + if (dma_spec->args_count != 3) + return NULL; + +- data.dma_request = dma_spec->args[0]; ++ 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); + } +@@ -1542,6 +1722,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; +diff -Nur linux-3.14.40.orig/drivers/dma/Kconfig linux-3.14.40/drivers/dma/Kconfig +--- linux-3.14.40.orig/drivers/dma/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/dma/Kconfig 2015-05-01 14:57:58.963427001 -0500 +@@ -137,6 +137,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.14.40.orig/drivers/dma/Makefile linux-3.14.40/drivers/dma/Makefile +--- linux-3.14.40.orig/drivers/dma/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/dma/Makefile 2015-05-01 14:57:58.975427001 -0500 +@@ -18,6 +18,7 @@ + obj-$(CONFIG_DW_DMAC_CORE) += dw/ + 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.14.40.orig/drivers/dma/pxp/Makefile linux-3.14.40/drivers/dma/pxp/Makefile +--- linux-3.14.40.orig/drivers/dma/pxp/Makefile 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/dma/pxp/Makefile 2015-05-01 14:57:58.975427001 -0500 +@@ -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.14.40.orig/drivers/dma/pxp/pxp_device.c linux-3.14.40/drivers/dma/pxp/pxp_device.c +--- linux-3.14.40.orig/drivers/dma/pxp/pxp_device.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/dma/pxp/pxp_device.c 2015-05-01 14:57:58.975427001 -0500 +@@ -0,0 +1,765 @@ ++/* ++ * Copyright (C) 2010-2014 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 ++ ++#define BUFFER_HASH_ORDER 4 ++ ++static struct pxp_buffer_hash bufhash; ++static struct pxp_irq_info irq_info[NR_PXP_VIRT_CHANNEL]; ++ ++static int pxp_ht_create(struct pxp_buffer_hash *hash, int order) ++{ ++ unsigned long i; ++ unsigned long table_size; ++ ++ table_size = 1U << order; ++ ++ hash->order = order; ++ hash->hash_table = kmalloc(sizeof(*hash->hash_table) * table_size, GFP_KERNEL); ++ ++ if (!hash->hash_table) { ++ pr_err("%s: Out of memory for hash table\n", __func__); ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < table_size; i++) ++ INIT_HLIST_HEAD(&hash->hash_table[i]); ++ ++ return 0; ++} ++ ++static int pxp_ht_insert_item(struct pxp_buffer_hash *hash, ++ struct pxp_buf_obj *new) ++{ ++ unsigned long hashkey; ++ struct hlist_head *h_list; ++ ++ hashkey = hash_long(new->offset >> PAGE_SHIFT, hash->order); ++ h_list = &hash->hash_table[hashkey]; ++ ++ spin_lock(&hash->hash_lock); ++ hlist_add_head_rcu(&new->item, h_list); ++ spin_unlock(&hash->hash_lock); ++ ++ return 0; ++} ++ ++static int pxp_ht_remove_item(struct pxp_buffer_hash *hash, ++ struct pxp_buf_obj *obj) ++{ ++ spin_lock(&hash->hash_lock); ++ hlist_del_init_rcu(&obj->item); ++ spin_unlock(&hash->hash_lock); ++ return 0; ++} ++ ++static struct hlist_node *pxp_ht_find_key(struct pxp_buffer_hash *hash, ++ unsigned long key) ++{ ++ struct pxp_buf_obj *entry; ++ struct hlist_head *h_list; ++ unsigned long hashkey; ++ ++ hashkey = hash_long(key, hash->order); ++ h_list = &hash->hash_table[hashkey]; ++ ++ hlist_for_each_entry_rcu(entry, h_list, item) { ++ if (entry->offset >> PAGE_SHIFT == key) ++ return &entry->item; ++ } ++ ++ return NULL; ++} ++ ++static void pxp_ht_destroy(struct pxp_buffer_hash *hash) ++{ ++ kfree(hash->hash_table); ++ hash->hash_table = NULL; ++} ++ ++static int pxp_buffer_handle_create(struct pxp_file *file_priv, ++ struct pxp_buf_obj *obj, ++ uint32_t *handlep) ++{ ++ int ret; ++ ++ idr_preload(GFP_KERNEL); ++ spin_lock(&file_priv->buffer_lock); ++ ++ ret = idr_alloc(&file_priv->buffer_idr, obj, 1, 0, GFP_NOWAIT); ++ ++ spin_unlock(&file_priv->buffer_lock); ++ idr_preload_end(); ++ ++ if (ret < 0) ++ return ret; ++ ++ *handlep = ret; ++ ++ return 0; ++} ++ ++static struct pxp_buf_obj * ++pxp_buffer_object_lookup(struct pxp_file *file_priv, ++ uint32_t handle) ++{ ++ struct pxp_buf_obj *obj; ++ ++ spin_lock(&file_priv->buffer_lock); ++ ++ obj = idr_find(&file_priv->buffer_idr, handle); ++ if (!obj) { ++ spin_unlock(&file_priv->buffer_lock); ++ return NULL; ++ } ++ ++ spin_unlock(&file_priv->buffer_lock); ++ ++ return obj; ++} ++ ++static int pxp_buffer_handle_delete(struct pxp_file *file_priv, ++ uint32_t handle) ++{ ++ struct pxp_buf_obj *obj; ++ ++ spin_lock(&file_priv->buffer_lock); ++ ++ obj = idr_find(&file_priv->buffer_idr, handle); ++ if (!obj) { ++ spin_unlock(&file_priv->buffer_lock); ++ return -EINVAL; ++ } ++ ++ idr_remove(&file_priv->buffer_idr, handle); ++ spin_unlock(&file_priv->buffer_lock); ++ ++ return 0; ++} ++ ++static int pxp_channel_handle_create(struct pxp_file *file_priv, ++ struct pxp_chan_obj *obj, ++ uint32_t *handlep) ++{ ++ int ret; ++ ++ idr_preload(GFP_KERNEL); ++ spin_lock(&file_priv->channel_lock); ++ ++ ret = idr_alloc(&file_priv->channel_idr, obj, 0, 0, GFP_NOWAIT); ++ ++ spin_unlock(&file_priv->channel_lock); ++ idr_preload_end(); ++ ++ if (ret < 0) ++ return ret; ++ ++ *handlep = ret; ++ ++ return 0; ++} ++ ++static struct pxp_chan_obj * ++pxp_channel_object_lookup(struct pxp_file *file_priv, ++ uint32_t handle) ++{ ++ struct pxp_chan_obj *obj; ++ ++ spin_lock(&file_priv->channel_lock); ++ ++ obj = idr_find(&file_priv->channel_idr, handle); ++ if (!obj) { ++ spin_unlock(&file_priv->channel_lock); ++ return NULL; ++ } ++ ++ spin_unlock(&file_priv->channel_lock); ++ ++ return obj; ++} ++ ++static int pxp_channel_handle_delete(struct pxp_file *file_priv, ++ uint32_t handle) ++{ ++ struct pxp_chan_obj *obj; ++ ++ spin_lock(&file_priv->channel_lock); ++ ++ obj = idr_find(&file_priv->channel_idr, handle); ++ if (!obj) { ++ spin_unlock(&file_priv->channel_lock); ++ return -EINVAL; ++ } ++ ++ idr_remove(&file_priv->channel_idr, handle); ++ spin_unlock(&file_priv->channel_lock); ++ ++ return 0; ++} ++ ++static int pxp_alloc_dma_buffer(struct pxp_buf_obj *obj) ++{ ++ obj->virtual = dma_alloc_coherent(NULL, PAGE_ALIGN(obj->size), ++ (dma_addr_t *) (&obj->offset), ++ GFP_DMA | GFP_KERNEL); ++ pr_debug("[ALLOC] mem alloc phys_addr = 0x%lx\n", obj->offset); ++ ++ if (obj->virtual == NULL) { ++ printk(KERN_ERR "Physical memory allocation error!\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static void pxp_free_dma_buffer(struct pxp_buf_obj *obj) ++{ ++ if (obj->virtual != NULL) { ++ dma_free_coherent(0, PAGE_ALIGN(obj->size), ++ obj->virtual, (dma_addr_t)obj->offset); ++ } ++} ++ ++static int ++pxp_buffer_object_free(int id, void *ptr, void *data) ++{ ++ struct pxp_file *file_priv = data; ++ struct pxp_buf_obj *obj = ptr; ++ int ret; ++ ++ ret = pxp_buffer_handle_delete(file_priv, obj->handle); ++ if (ret < 0) ++ return ret; ++ ++ pxp_ht_remove_item(&bufhash, obj); ++ pxp_free_dma_buffer(obj); ++ kfree(obj); ++ ++ return 0; ++} ++ ++static int ++pxp_channel_object_free(int id, void *ptr, void *data) ++{ ++ struct pxp_file *file_priv = data; ++ struct pxp_chan_obj *obj = ptr; ++ int chan_id; ++ ++ chan_id = obj->chan->chan_id; ++ wait_event(irq_info[chan_id].waitq, ++ atomic_read(&irq_info[chan_id].irq_pending) == 0); ++ ++ pxp_channel_handle_delete(file_priv, obj->handle); ++ dma_release_channel(obj->chan); ++ kfree(obj); ++ ++ return 0; ++} ++ ++static void pxp_free_buffers(struct pxp_file *file_priv) ++{ ++ idr_for_each(&file_priv->buffer_idr, ++ &pxp_buffer_object_free, file_priv); ++ idr_destroy(&file_priv->buffer_idr); ++} ++ ++static void pxp_free_channels(struct pxp_file *file_priv) ++{ ++ idr_for_each(&file_priv->channel_idr, ++ &pxp_channel_object_free, file_priv); ++ idr_destroy(&file_priv->channel_idr); ++} ++ ++/* 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); ++ ++ atomic_dec(&irq_info[chan_id].irq_pending); ++ irq_info[chan_id].hist_status = tx_desc->hist_status; ++ ++ wake_up(&(irq_info[chan_id].waitq)); ++} ++ ++static int pxp_ioc_config_chan(struct pxp_file *priv, unsigned long arg) ++{ ++ struct scatterlist sg[3]; ++ struct pxp_tx_desc *desc; ++ struct dma_async_tx_descriptor *txd; ++ struct pxp_config_data pxp_conf; ++ dma_cookie_t cookie; ++ int handle, chan_id; ++ int i, length, ret; ++ struct dma_chan *chan; ++ struct pxp_chan_obj *obj; ++ ++ ret = copy_from_user(&pxp_conf, ++ (struct pxp_config_data *)arg, ++ sizeof(struct pxp_config_data)); ++ if (ret) ++ return -EFAULT; ++ ++ handle = pxp_conf.handle; ++ obj = pxp_channel_object_lookup(priv, handle); ++ if (!obj) ++ return -EINVAL; ++ chan = obj->chan; ++ chan_id = chan->chan_id; ++ ++ sg_init_table(sg, 3); ++ ++ txd = chan->device->device_prep_slave_sg(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; ++ } ++ ++ atomic_inc(&irq_info[chan_id].irq_pending); ++ ++ return 0; ++} ++ ++static int pxp_device_open(struct inode *inode, struct file *filp) ++{ ++ struct pxp_file *priv; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ ++ if (!priv) ++ return -ENOMEM; ++ ++ filp->private_data = priv; ++ priv->filp = filp; ++ ++ idr_init(&priv->buffer_idr); ++ spin_lock_init(&priv->buffer_lock); ++ ++ idr_init(&priv->channel_idr); ++ spin_lock_init(&priv->channel_lock); ++ ++ return 0; ++} ++ ++static int pxp_device_release(struct inode *inode, struct file *filp) ++{ ++ struct pxp_file *priv = filp->private_data; ++ ++ if (priv) { ++ pxp_free_channels(priv); ++ pxp_free_buffers(priv); ++ kfree(priv); ++ filp->private_data = NULL; ++ } ++ ++ return 0; ++} ++ ++static int pxp_device_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int request_size; ++ struct hlist_node *node; ++ struct pxp_buf_obj *obj; ++ ++ request_size = vma->vm_end - vma->vm_start; ++ ++ pr_debug("start=0x%x, pgoff=0x%x, size=0x%x\n", ++ (unsigned int)(vma->vm_start), (unsigned int)(vma->vm_pgoff), ++ request_size); ++ ++ node = pxp_ht_find_key(&bufhash, vma->vm_pgoff); ++ if (!node) ++ return -EINVAL; ++ ++ obj = list_entry(node, struct pxp_buf_obj, item); ++ if (obj->offset + (obj->size >> PAGE_SHIFT) < ++ (vma->vm_pgoff + vma_pages(vma))) ++ return -ENOMEM; ++ ++ switch (obj->mem_type) { ++ case MEMORY_TYPE_UNCACHED: ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ break; ++ case MEMORY_TYPE_WC: ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++ break; ++ case MEMORY_TYPE_CACHED: ++ break; ++ default: ++ pr_err("%s: invalid memory type!\n", __func__); ++ return -EINVAL; ++ } ++ ++ 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; ++ struct pxp_file *file_priv = filp->private_data; ++ ++ switch (cmd) { ++ case PXP_IOC_GET_CHAN: ++ { ++ int ret; ++ struct dma_chan *chan = NULL; ++ dma_cap_mask_t mask; ++ struct pxp_chan_obj *obj = NULL; ++ ++ pr_debug("drv: PXP_IOC_GET_CHAN Line %d\n", __LINE__); ++ ++ 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("Unsccessfully received channel!\n"); ++ return -EBUSY; ++ } ++ ++ pr_debug("Successfully received channel." ++ "chan_id %d\n", chan->chan_id); ++ ++ obj = kzalloc(sizeof(*obj), GFP_KERNEL); ++ if (!obj) { ++ dma_release_channel(chan); ++ return -ENOMEM; ++ } ++ obj->chan = chan; ++ ++ ret = pxp_channel_handle_create(file_priv, obj, ++ &obj->handle); ++ if (ret) { ++ dma_release_channel(chan); ++ kfree(obj); ++ return ret; ++ } ++ ++ init_waitqueue_head(&(irq_info[chan->chan_id].waitq)); ++ if (put_user(obj->handle, (u32 __user *) arg)) { ++ pxp_channel_handle_delete(file_priv, obj->handle); ++ dma_release_channel(chan); ++ kfree(obj); ++ return -EFAULT; ++ } ++ ++ break; ++ } ++ case PXP_IOC_PUT_CHAN: ++ { ++ int handle; ++ struct pxp_chan_obj *obj; ++ ++ if (get_user(handle, (u32 __user *) arg)) ++ return -EFAULT; ++ ++ pr_debug("%d release handle %d\n", __LINE__, handle); ++ ++ obj = pxp_channel_object_lookup(file_priv, handle); ++ if (!obj) ++ return -EINVAL; ++ ++ pxp_channel_handle_delete(file_priv, obj->handle); ++ dma_release_channel(obj->chan); ++ kfree(obj); ++ ++ break; ++ } ++ case PXP_IOC_CONFIG_CHAN: ++ { ++ int ret; ++ ++ ret = pxp_ioc_config_chan(file_priv, arg); ++ if (ret) ++ return ret; ++ ++ break; ++ } ++ case PXP_IOC_START_CHAN: ++ { ++ int handle; ++ struct pxp_chan_obj *obj = NULL; ++ ++ if (get_user(handle, (u32 __user *) arg)) ++ return -EFAULT; ++ ++ obj = pxp_channel_object_lookup(file_priv, handle); ++ if (!obj) ++ return -EINVAL; ++ ++ dma_async_issue_pending(obj->chan); ++ ++ break; ++ } ++ case PXP_IOC_GET_PHYMEM: ++ { ++ struct pxp_mem_desc buffer; ++ struct pxp_buf_obj *obj; ++ ++ ret = copy_from_user(&buffer, ++ (struct pxp_mem_desc *)arg, ++ sizeof(struct pxp_mem_desc)); ++ if (ret) ++ return -EFAULT; ++ ++ pr_debug("[ALLOC] mem alloc size = 0x%x\n", ++ buffer.size); ++ ++ obj = kzalloc(sizeof(*obj), GFP_KERNEL); ++ if (!obj) ++ return -ENOMEM; ++ obj->size = buffer.size; ++ obj->mem_type = buffer.mtype; ++ ++ ret = pxp_alloc_dma_buffer(obj); ++ if (ret == -1) { ++ printk(KERN_ERR ++ "Physical memory allocation error!\n"); ++ kfree(obj); ++ return ret; ++ } ++ ++ ret = pxp_buffer_handle_create(file_priv, obj, &obj->handle); ++ if (ret) { ++ pxp_free_dma_buffer(obj); ++ kfree(obj); ++ return ret; ++ } ++ buffer.handle = obj->handle; ++ buffer.phys_addr = obj->offset; ++ ++ ret = copy_to_user((void __user *)arg, &buffer, ++ sizeof(struct pxp_mem_desc)); ++ if (ret) { ++ pxp_buffer_handle_delete(file_priv, buffer.handle); ++ pxp_free_dma_buffer(obj); ++ kfree(obj); ++ return -EFAULT; ++ } ++ ++ pxp_ht_insert_item(&bufhash, obj); ++ ++ break; ++ } ++ case PXP_IOC_PUT_PHYMEM: ++ { ++ struct pxp_mem_desc pxp_mem; ++ struct pxp_buf_obj *obj; ++ ++ ret = copy_from_user(&pxp_mem, ++ (struct pxp_mem_desc *)arg, ++ sizeof(struct pxp_mem_desc)); ++ if (ret) ++ return -EACCES; ++ ++ obj = pxp_buffer_object_lookup(file_priv, pxp_mem.handle); ++ if (!obj) ++ return -EINVAL; ++ ++ ret = pxp_buffer_handle_delete(file_priv, obj->handle); ++ if (ret) ++ return ret; ++ ++ pxp_ht_remove_item(&bufhash, obj); ++ pxp_free_dma_buffer(obj); ++ kfree(obj); ++ ++ break; ++ } ++ case PXP_IOC_FLUSH_PHYMEM: ++ { ++ int ret; ++ struct pxp_mem_flush flush; ++ struct pxp_buf_obj *obj; ++ ++ ret = copy_from_user(&flush, ++ (struct pxp_mem_flush *)arg, ++ sizeof(struct pxp_mem_flush)); ++ if (ret) ++ return -EACCES; ++ ++ obj = pxp_buffer_object_lookup(file_priv, flush.handle); ++ if (!obj) ++ return -EINVAL; ++ ++ switch (flush.type) { ++ case CACHE_CLEAN: ++ dma_sync_single_for_device(NULL, obj->offset, ++ obj->size, DMA_TO_DEVICE); ++ break; ++ case CACHE_INVALIDATE: ++ dma_sync_single_for_device(NULL, obj->offset, ++ obj->size, DMA_FROM_DEVICE); ++ break; ++ case CACHE_FLUSH: ++ dma_sync_single_for_device(NULL, obj->offset, ++ obj->size, DMA_TO_DEVICE); ++ dma_sync_single_for_device(NULL, obj->offset, ++ obj->size, DMA_FROM_DEVICE); ++ break; ++ default: ++ pr_err("%s: invalid cache flush type\n", __func__); ++ return -EINVAL; ++ } ++ ++ break; ++ } ++ case PXP_IOC_WAIT4CMPLT: ++ { ++ struct pxp_chan_handle chan_handle; ++ int ret, chan_id, handle; ++ struct pxp_chan_obj *obj = NULL; ++ ++ ret = copy_from_user(&chan_handle, ++ (struct pxp_chan_handle *)arg, ++ sizeof(struct pxp_chan_handle)); ++ if (ret) ++ return -EFAULT; ++ ++ handle = chan_handle.handle; ++ obj = pxp_channel_object_lookup(file_priv, handle); ++ if (!obj) ++ return -EINVAL; ++ chan_id = obj->chan->chan_id; ++ ++ ret = wait_event_interruptible ++ (irq_info[chan_id].waitq, ++ (atomic_read(&irq_info[chan_id].irq_pending) == 0)); ++ if (ret < 0) { ++ printk(KERN_WARNING ++ "WAIT4CMPLT: signal received.\n"); ++ return -ERESTARTSYS; ++ } ++ ++ 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; ++ ++ ret = pxp_ht_create(&bufhash, BUFFER_HASH_ORDER); ++ if (ret) ++ return ret; ++ spin_lock_init(&(bufhash.hash_lock)); ++ ++ pr_debug("PxP_Device registered Successfully\n"); ++ return 0; ++} ++ ++void unregister_pxp_device(void) ++{ ++ pxp_ht_destroy(&bufhash); ++ misc_deregister(&pxp_device_miscdev); ++} +diff -Nur linux-3.14.40.orig/drivers/dma/pxp/pxp_dma_v2.c linux-3.14.40/drivers/dma/pxp/pxp_dma_v2.c +--- linux-3.14.40.orig/drivers/dma/pxp/pxp_dma_v2.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/dma/pxp/pxp_dma_v2.c 2015-05-01 14:57:58.975427001 -0500 +@@ -0,0 +1,1854 @@ ++/* ++ * 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 "regs-pxp_v2.h" ++ ++#define PXP_DOWNSCALE_THRESHOLD 0x4000 ++ ++static LIST_HEAD(head); ++static int timeout_in_ms = 600; ++static unsigned int block_size; ++static struct kmem_cache *tx_desc_cache; ++ ++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; ++ ++ /* for pxp config dispatch asynchronously*/ ++ struct task_struct *dispatch; ++ wait_queue_head_t thread_waitq; ++ struct completion complete; ++}; ++ ++#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; ++ if (s0_params->pixel_fmt == PXP_PIX_FMT_YVU420P) { ++ __raw_writel(V1, pxp->base + HW_PXP_PS_UBUF); ++ __raw_writel(U1, pxp->base + HW_PXP_PS_VBUF); ++ } else { ++ __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; ++ } ++ ++ 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); ++ ++ 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_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; ++ ++ /* S0 */ ++ desc = list_first_entry(&head, struct pxp_tx_desc, list); ++ 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; ++ struct pxp_tx_desc *desc = NULL; ++ ++ spin_lock_irqsave(&pxp->lock, flags); ++ ++ desc = list_entry(head.next, struct pxp_tx_desc, list); ++ pxp_chan = to_pxp_channel(desc->txd.chan); ++ ++ __pxpdma_dostart(pxp_chan); ++ ++ /* 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 pxps *pxp) ++{ ++ unsigned long flags; ++ struct pxp_tx_desc *desc = NULL; ++ ++ do { ++ desc = pxpdma_first_queued(pxp_chan); ++ spin_lock_irqsave(&pxp->lock, flags); ++ list_move_tail(&desc->list, &head); ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ } 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; ++ ++ dev_dbg(&pxp_chan->dma_chan.dev->device, "received TX\n"); ++ ++ /* pxp_chan->lock can be taken under ichan->lock, but not v.v. */ ++ spin_lock(&pxp_chan->lock); ++ ++ 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; ++ ++ /* Here we add the tx descriptor to our PxP task queue. */ ++ list_add_tail(&desc->list, &pxp_chan->queue); ++ ++ spin_unlock(&pxp_chan->lock); ++ ++ dev_dbg(&pxp_chan->dma_chan.dev->device, "done TX\n"); ++ ++ return cookie; ++} ++ ++/** ++ * 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) ++{ ++ int ret = 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. ++ */ ++ ++ INIT_LIST_HEAD(&pxp_chan->queue); ++ ++ 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; ++ struct pxp_tx_desc *child, *_child; ++ 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; ++ } ++ ++ /* Get descriptor and call callback */ ++ desc = list_entry(head.next, struct pxp_tx_desc, list); ++ pxp_chan = to_pxp_channel(desc->txd.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_for_each_entry_safe(child, _child, &desc->tx_list, list) { ++ list_del_init(&child->list); ++ kmem_cache_free(tx_desc_cache, (void *)child); ++ } ++ list_del_init(&desc->list); ++ kmem_cache_free(tx_desc_cache, (void *)desc); ++ ++ complete(&pxp->complete); ++ 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; ++} ++ ++/* allocate/free dma tx descriptor dynamically*/ ++static struct pxp_tx_desc *pxpdma_desc_alloc(struct pxp_channel *pxp_chan) ++{ ++ struct pxp_tx_desc *desc = NULL; ++ struct dma_async_tx_descriptor *txd = NULL; ++ ++ desc = kmem_cache_alloc(tx_desc_cache, GFP_KERNEL | __GFP_ZERO); ++ if (desc == NULL) ++ return NULL; ++ ++ INIT_LIST_HEAD(&desc->list); ++ INIT_LIST_HEAD(&desc->tx_list); ++ txd = &desc->txd; ++ dma_async_tx_descriptor_init(txd, &pxp_chan->dma_chan); ++ txd->tx_submit = pxp_tx_submit; ++ ++ return desc; ++} ++ ++/* 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; ++ 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; ++ ++ for_each_sg(sgl, sg, sg_len, i) { ++ desc = pxpdma_desc_alloc(pxp_chan); ++ if (!desc) { ++ dev_err(chan->device->dev, "no enough memory to allocate tx descriptor\n"); ++ 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; ++ } ++ ++ 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); ++ ++ spin_lock(&pxp_chan->lock); ++ ++ if (list_empty(&pxp_chan->queue)) { ++ spin_unlock(&pxp_chan->lock); ++ return; ++ } ++ ++ pxpdma_dequeue(pxp_chan, pxp); ++ pxp_chan->status = PXP_CHANNEL_READY; ++ ++ spin_unlock(&pxp_chan->lock); ++ ++ pxp_clk_enable(pxp); ++ wake_up_interruptible(&pxp->thread_waitq); ++} ++ ++static void __pxp_terminate_all(struct dma_chan *chan) ++{ ++ struct pxp_channel *pxp_chan = to_pxp_channel(chan); ++ ++ 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; ++ ++ spin_lock(&pxp_chan->lock); ++ __pxp_terminate_all(chan); ++ spin_unlock(&pxp_chan->lock); ++ ++ 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); ++ ++ spin_lock(&pxp_chan->lock); ++ ++ __pxp_terminate_all(chan); ++ ++ pxp_chan->status = PXP_CHANNEL_FREE; ++ ++ spin_unlock(&pxp_chan->lock); ++} ++ ++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_COMPLETE; ++} ++ ++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); ++ ++ /* 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 has_pending_task(struct pxps *pxp, struct pxp_channel *task) ++{ ++ int found; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&pxp->lock, flags); ++ found = !list_empty(&head); ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ ++ return found; ++} ++ ++static int pxp_dispatch_thread(void *argv) ++{ ++ struct pxps *pxp = (struct pxps *)argv; ++ struct pxp_channel *pending = NULL; ++ unsigned long flags; ++ ++ while (!kthread_should_stop()) { ++ int ret; ++ ret = wait_event_interruptible(pxp->thread_waitq, ++ has_pending_task(pxp, pending)); ++ if (signal_pending(current)) ++ continue; ++ ++ if (kthread_should_stop()) ++ break; ++ ++ spin_lock_irqsave(&pxp->lock, flags); ++ pxp->pxp_ongoing = 1; ++ spin_unlock_irqrestore(&pxp->lock, flags); ++ init_completion(&pxp->complete); ++ pxpdma_dostart_work(pxp); ++ ret = wait_for_completion_timeout(&pxp->complete, 2 * HZ); ++ if (ret == 0) { ++ printk(KERN_EMERG "%s: task is timeout\n\n", __func__); ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++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); ++ ++ 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; ++ ++ /* allocate a kernel thread to dispatch pxp conf */ ++ pxp->dispatch = kthread_run(pxp_dispatch_thread, pxp, "pxp_dispatch"); ++ if (IS_ERR(pxp->dispatch)) { ++ err = PTR_ERR(pxp->dispatch); ++ goto exit; ++ } ++ init_waitqueue_head(&pxp->thread_waitq); ++ tx_desc_cache = kmem_cache_create("tx_desc", sizeof(struct pxp_tx_desc), ++ 0, SLAB_HWCACHE_ALIGN, NULL); ++ if (!tx_desc_cache) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ register_pxp_device(); ++ ++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(); ++ kmem_cache_destroy(tx_desc_cache); ++ kthread_stop(pxp->dispatch); ++ 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 ++static int pxp_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct pxps *pxp = platform_get_drvdata(pdev); ++ ++ 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 platform_device *pdev) ++{ ++ struct pxps *pxp = platform_get_drvdata(pdev); ++ ++ 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 ++ ++static struct platform_driver pxp_driver = { ++ .driver = { ++ .name = "imx-pxp", ++ .of_match_table = of_match_ptr(imx_pxpdma_dt_ids), ++ }, ++ .probe = pxp_probe, ++ .remove = pxp_remove, ++ .suspend = pxp_suspend, ++ .resume = pxp_resume, ++}; ++ ++module_platform_driver(pxp_driver); ++ ++ ++MODULE_DESCRIPTION("i.MX PxP driver"); ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.14.40.orig/drivers/dma/pxp/regs-pxp_v2.h linux-3.14.40/drivers/dma/pxp/regs-pxp_v2.h +--- linux-3.14.40.orig/drivers/dma/pxp/regs-pxp_v2.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/dma/pxp/regs-pxp_v2.h 2015-05-01 14:57:58.975427001 -0500 +@@ -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.14.40.orig/drivers/gpio/gpio-pca953x.c linux-3.14.40/drivers/gpio/gpio-pca953x.c +--- linux-3.14.40.orig/drivers/gpio/gpio-pca953x.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/gpio/gpio-pca953x.c 2015-05-01 14:57:58.999427001 -0500 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #ifdef CONFIG_OF_GPIO + #include +@@ -741,6 +742,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.14.40.orig/drivers/gpu/drm/drm_crtc_helper.c linux-3.14.40/drivers/gpu/drm/drm_crtc_helper.c +--- linux-3.14.40.orig/drivers/gpu/drm/drm_crtc_helper.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/gpu/drm/drm_crtc_helper.c 2015-05-01 14:57:59.031427001 -0500 +@@ -564,7 +564,7 @@ + * Caller must hold mode config lock. + * + * Setup a new configuration, provided by the upper layers (either an ioctl call +- * from userspace or internally e.g. from the fbdev suppport code) in @set, and ++ * from userspace or internally e.g. from the fbdev support code) in @set, and + * enable it. This is the main helper functions for drivers that implement + * kernel mode setting with the crtc helper functions and the assorted + * ->prepare(), ->modeset() and ->commit() helper callbacks. +diff -Nur linux-3.14.40.orig/drivers/gpu/drm/drm_prime.c linux-3.14.40/drivers/gpu/drm/drm_prime.c +--- linux-3.14.40.orig/drivers/gpu/drm/drm_prime.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/gpu/drm/drm_prime.c 2015-05-01 14:57:59.039427001 -0500 +@@ -471,7 +471,7 @@ + get_dma_buf(dma_buf); + + sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); +- if (IS_ERR_OR_NULL(sgt)) { ++ if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + goto fail_detach; + } +diff -Nur linux-3.14.40.orig/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c linux-3.14.40/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c +--- linux-3.14.40.orig/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c 2015-05-01 14:57:59.051427001 -0500 +@@ -224,7 +224,7 @@ + get_dma_buf(dma_buf); + + sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); +- if (IS_ERR_OR_NULL(sgt)) { ++ if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + goto err_buf_detach; + } +diff -Nur linux-3.14.40.orig/drivers/gpu/drm/Kconfig linux-3.14.40/drivers/gpu/drm/Kconfig +--- linux-3.14.40.orig/drivers/gpu/drm/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/gpu/drm/Kconfig 2015-05-01 14:57:59.059427001 -0500 +@@ -166,6 +166,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.14.40.orig/drivers/gpu/drm/Makefile linux-3.14.40/drivers/gpu/drm/Makefile +--- linux-3.14.40.orig/drivers/gpu/drm/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/gpu/drm/Makefile 2015-05-01 14:57:59.067427001 -0500 +@@ -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. +@@ -35,6 +56,7 @@ + obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.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.14.40.orig/drivers/gpu/drm/vivante/Makefile linux-3.14.40/drivers/gpu/drm/vivante/Makefile +--- linux-3.14.40.orig/drivers/gpu/drm/vivante/Makefile 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/gpu/drm/vivante/Makefile 2015-05-01 14:57:59.067427001 -0500 +@@ -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.14.40.orig/drivers/gpu/drm/vivante/vivante_drv.c linux-3.14.40/drivers/gpu/drm/vivante/vivante_drv.c +--- linux-3.14.40.orig/drivers/gpu/drm/vivante/vivante_drv.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/gpu/drm/vivante/vivante_drv.c 2015-05-01 14:57:59.067427001 -0500 +@@ -0,0 +1,108 @@ ++/**************************************************************************** ++* ++* 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, ++ .llseek = noop_llseek, ++}; ++ ++static struct drm_driver driver = { ++ .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) { ++ 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.14.40.orig/drivers/gpu/drm/vivante/vivante_drv.h linux-3.14.40/drivers/gpu/drm/vivante/vivante_drv.h +--- linux-3.14.40.orig/drivers/gpu/drm/vivante/vivante_drv.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/gpu/drm/vivante/vivante_drv.h 2015-05-01 14:57:59.067427001 -0500 +@@ -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.14.40.orig/drivers/hwmon/Kconfig linux-3.14.40/drivers/hwmon/Kconfig +--- linux-3.14.40.orig/drivers/hwmon/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/hwmon/Kconfig 2015-05-01 14:57:59.075427001 -0500 +@@ -1584,4 +1584,19 @@ + + 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 ++ depends on INPUT_POLLDEV ++ default y ++ + endif # HWMON +diff -Nur linux-3.14.40.orig/drivers/hwmon/mag3110.c linux-3.14.40/drivers/hwmon/mag3110.c +--- linux-3.14.40.orig/drivers/hwmon/mag3110.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/hwmon/mag3110.c 2015-05-01 14:57:59.075427001 -0500 +@@ -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.14.40.orig/drivers/hwmon/Makefile linux-3.14.40/drivers/hwmon/Makefile +--- linux-3.14.40.orig/drivers/hwmon/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/hwmon/Makefile 2015-05-01 14:57:59.087427001 -0500 +@@ -142,6 +142,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.14.40.orig/drivers/hwmon/mxc_mma8451.c linux-3.14.40/drivers/hwmon/mxc_mma8451.c +--- linux-3.14.40.orig/drivers/hwmon/mxc_mma8451.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/hwmon/mxc_mma8451.c 2015-05-01 14:57:59.087427001 -0500 +@@ -0,0 +1,598 @@ ++/* ++ * 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.active = MMA_STANDBY; ++ ++ result = i2c_smbus_write_byte_data(client, MMA8451_XYZ_DATA_CFG, ++ mode); ++ if (result < 0) ++ goto out; ++ mdelay(MODE_CHANGE_DELAY_MS); ++ mma_status.mode = mode; ++ ++ 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 ssize_t mma8451_scalemode_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ int mode = 0; ++ mutex_lock(&mma8451_lock); ++ mode = (int)mma_status.mode; ++ mutex_unlock(&mma8451_lock); ++ ++ return sprintf(buf, "%d\n", mode); ++} ++ ++static ssize_t mma8451_scalemode_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned long mode; ++ int ret, active_save; ++ struct i2c_client *client = mma8451_i2c_client; ++ ++ ret = strict_strtoul(buf, 10, &mode); ++ if (ret) { ++ dev_err(dev, "string transform error\n"); ++ goto out; ++ } ++ ++ if (mode > MODE_8G) { ++ dev_warn(dev, "not supported mode\n"); ++ ret = count; ++ goto out; ++ } ++ ++ mutex_lock(&mma8451_lock); ++ if (mode == mma_status.mode) { ++ ret = count; ++ goto out_unlock; ++ } ++ ++ active_save = mma_status.active; ++ ret = mma8451_change_mode(client, mode); ++ if (ret) ++ goto out_unlock; ++ ++ if (active_save == MMA_ACTIVED) { ++ ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, 1); ++ ++ if (ret) ++ goto out_unlock; ++ mma_status.active = active_save; ++ } ++ ++out_unlock: ++ mutex_unlock(&mma8451_lock); ++out: ++ return ret; ++} ++ ++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 DEVICE_ATTR(scalemode, S_IWUSR | S_IRUGO, ++ mma8451_scalemode_show, mma8451_scalemode_store); ++ ++static struct attribute *mma8451_attributes[] = { ++ &dev_attr_enable.attr, ++ &dev_attr_position.attr, ++ &dev_attr_scalemode.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.14.40.orig/drivers/i2c/busses/i2c-imx.c linux-3.14.40/drivers/i2c/busses/i2c-imx.c +--- linux-3.14.40.orig/drivers/i2c/busses/i2c-imx.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/i2c/busses/i2c-imx.c 2015-05-01 14:57:59.091427001 -0500 +@@ -184,6 +184,9 @@ + int stopped; + unsigned int ifdr; /* IMX_I2C_IFDR */ + const struct imx_i2c_hwdata *hwdata; ++ ++ unsigned int cur_clk; ++ unsigned int bitrate; + }; + + static const struct imx_i2c_hwdata imx1_i2c_hwdata = { +@@ -305,6 +308,51 @@ + return 0; + } + ++static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) ++{ ++ struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; ++ unsigned ndivs = i2c_imx->hwdata->ndivs; ++ 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].div) ++ i = 0; ++ else if (div > i2c_clk_div[ndivs - 1].div) ++ i = ndivs - 1; ++ else ++ for (i = 0; i2c_clk_div[i].div < div; i++) ++ ; ++ ++ /* Store divider value */ ++ i2c_imx->ifdr = imx_i2c_clk_div[i].val; ++ ++ /* ++ * 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].div ++ + (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].val, i2c_clk_div[i].div); ++#endif ++} ++ + static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) + { + unsigned int temp = 0; +@@ -312,6 +360,7 @@ + + dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); + ++ i2c_imx_set_clk(i2c_imx); + result = clk_prepare_enable(i2c_imx->clk); + if (result) + return result; +@@ -367,45 +416,6 @@ + clk_disable_unprepare(i2c_imx->clk); + } + +-static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, +- unsigned int rate) +-{ +- struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; +- 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].div) +- i = 0; +- else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div) +- i = i2c_imx->hwdata->ndivs - 1; +- else +- for (i = 0; i2c_clk_div[i].div < div; i++); +- +- /* Store divider value */ +- i2c_imx->ifdr = i2c_clk_div[i].val; +- +- /* +- * 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].div +- + (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].val, i2c_clk_div[i].div); +-#endif +-} +- + static irqreturn_t i2c_imx_isr(int irq, void *dev_id) + { + struct imx_i2c_struct *i2c_imx = dev_id; +@@ -600,7 +610,6 @@ + struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev); + void __iomem *base; + int irq, ret; +- u32 bitrate; + + dev_dbg(&pdev->dev, "<%s>\n", __func__); + +@@ -664,12 +673,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 */ + imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, +diff -Nur linux-3.14.40.orig/drivers/input/keyboard/gpio_keys.c linux-3.14.40/drivers/input/keyboard/gpio_keys.c +--- linux-3.14.40.orig/drivers/input/keyboard/gpio_keys.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/input/keyboard/gpio_keys.c 2015-05-01 14:57:59.099427001 -0500 +@@ -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 +@@ -473,6 +474,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.14.40.orig/drivers/input/keyboard/imx_keypad.c linux-3.14.40/drivers/input/keyboard/imx_keypad.c +--- linux-3.14.40.orig/drivers/input/keyboard/imx_keypad.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/input/keyboard/imx_keypad.c 2015-05-01 14:57:59.099427001 -0500 +@@ -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 +@@ -548,6 +549,8 @@ + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(kbd->irq); ++ else ++ pinctrl_pm_select_sleep_state(dev); + + return 0; + } +@@ -561,6 +564,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.14.40.orig/drivers/input/misc/mma8450.c linux-3.14.40/drivers/input/misc/mma8450.c +--- linux-3.14.40.orig/drivers/input/misc/mma8450.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/input/misc/mma8450.c 2015-05-01 14:57:59.107427001 -0500 +@@ -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 +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #define MMA8450_DRV_NAME "mma8450" + +@@ -51,11 +52,22 @@ + + #define MMA8450_CTRL_REG1 0x38 + #define MMA8450_CTRL_REG2 0x39 ++#define MMA8450_ID 0xC6 ++#define MMA8450_WHO_AM_I 0x0F ++ ++enum { ++ MODE_STANDBY = 0, ++ MODE_2G, ++ MODE_4G, ++ MODE_8G, ++}; + + /* mma8450 status */ + struct mma8450 { + struct i2c_client *client; + struct input_polled_dev *idev; ++ struct mutex mma8450_lock; ++ u8 mode; + }; + + static int mma8450_read(struct mma8450 *m, unsigned off) +@@ -112,16 +124,19 @@ + int ret; + u8 buf[6]; + +- ret = mma8450_read(m, MMA8450_STATUS); +- if (ret < 0) +- return; ++ mutex_lock(&m->mma8450_lock); + +- if (!(ret & MMA8450_STATUS_ZXYDR)) ++ ret = mma8450_read(m, MMA8450_STATUS); ++ if (ret < 0 || !(ret & MMA8450_STATUS_ZXYDR)) { ++ mutex_unlock(&m->mma8450_lock); + return; ++ } + + ret = mma8450_read_block(m, MMA8450_OUT_X_LSB, buf, sizeof(buf)); +- if (ret < 0) ++ if (ret < 0) { ++ mutex_unlock(&m->mma8450_lock); + return; ++ } + + x = ((int)(s8)buf[1] << 4) | (buf[0] & 0xf); + y = ((int)(s8)buf[3] << 4) | (buf[2] & 0xf); +@@ -131,10 +146,12 @@ + input_report_abs(dev->input, ABS_Y, y); + input_report_abs(dev->input, ABS_Z, z); + input_sync(dev->input); ++ ++ mutex_unlock(&m->mma8450_lock); + } + + /* Initialize the MMA8450 chip */ +-static void mma8450_open(struct input_polled_dev *dev) ++static s32 mma8450_open(struct input_polled_dev *dev) + { + struct mma8450 *m = dev->private; + int err; +@@ -142,18 +159,20 @@ + /* enable all events from X/Y/Z, no FIFO */ + err = mma8450_write(m, MMA8450_XYZ_DATA_CFG, 0x07); + if (err) +- return; ++ return err; + + /* + * Sleep mode poll rate - 50Hz + * System output data rate - 400Hz +- * Full scale selection - Active, +/- 2G ++ * Standby mode + */ +- err = mma8450_write(m, MMA8450_CTRL_REG1, 0x01); +- if (err < 0) +- return; +- ++ err = mma8450_write(m, MMA8450_CTRL_REG1, MODE_STANDBY); ++ if (err) ++ return err; ++ m->mode = MODE_STANDBY; + msleep(MODE_CHANGE_DELAY_MS); ++ ++ return 0; + } + + static void mma8450_close(struct input_polled_dev *dev) +@@ -164,6 +183,76 @@ + mma8450_write(m, MMA8450_CTRL_REG2, 0x01); + } + ++static ssize_t mma8450_scalemode_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ int mode = 0; ++ struct mma8450 *m; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ m = i2c_get_clientdata(client); ++ ++ mutex_lock(&m->mma8450_lock); ++ mode = (int)m->mode; ++ mutex_unlock(&m->mma8450_lock); ++ ++ return sprintf(buf, "%d\n", mode); ++} ++ ++static ssize_t mma8450_scalemode_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned long mode; ++ int ret; ++ struct mma8450 *m = NULL; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ ret = strict_strtoul(buf, 10, &mode); ++ if (ret) { ++ dev_err(dev, "string transform error\n"); ++ return ret; ++ } ++ ++ if (mode > MODE_8G) { ++ dev_warn(dev, "not supported mode %d\n", (int)mode); ++ return count; ++ } ++ ++ m = i2c_get_clientdata(client); ++ ++ mutex_lock(&m->mma8450_lock); ++ if (mode == m->mode) { ++ mutex_unlock(&m->mma8450_lock); ++ return count; ++ } ++ ++ ret = mma8450_write(m, MMA8450_CTRL_REG1, mode); ++ if (ret < 0) { ++ mutex_unlock(&m->mma8450_lock); ++ return ret; ++ } ++ ++ msleep(MODE_CHANGE_DELAY_MS); ++ m->mode = (u8)mode; ++ mutex_unlock(&m->mma8450_lock); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(scalemode, S_IWUSR | S_IRUGO, ++ mma8450_scalemode_show, mma8450_scalemode_store); ++ ++static struct attribute *mma8450_attributes[] = { ++ &dev_attr_scalemode.attr, ++ NULL ++}; ++ ++static const struct attribute_group mma8450_attr_group = { ++ .attrs = mma8450_attributes, ++}; ++ + /* + * I2C init/probing/exit functions + */ +@@ -172,7 +261,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(); +@@ -183,6 +290,7 @@ + + m->client = c; + m->idev = idev; ++ i2c_set_clientdata(c, m); + + idev->private = m; + idev->input->name = MMA8450_DRV_NAME; +@@ -190,8 +298,6 @@ + idev->poll = mma8450_poll; + idev->poll_interval = POLL_INTERVAL; + idev->poll_interval_max = POLL_INTERVAL_MAX; +- idev->open = mma8450_open; +- idev->close = mma8450_close; + + __set_bit(EV_ABS, idev->input->evbit); + input_set_abs_params(idev->input, ABS_X, -2048, 2047, 32, 32); +@@ -206,11 +312,32 @@ + + i2c_set_clientdata(c, m); + ++ mutex_init(&m->mma8450_lock); ++ ++ err = mma8450_open(idev); ++ if (err) { ++ dev_err(&c->dev, "failed to initialize mma8450\n"); ++ goto err_unreg_dev; ++ } ++ ++ err = sysfs_create_group(&c->dev.kobj, &mma8450_attr_group); ++ if (err) { ++ dev_err(&c->dev, "create device file failed!\n"); ++ err = -EINVAL; ++ goto err_close; ++ } ++ + return 0; + ++err_close: ++ mma8450_close(idev); ++err_unreg_dev: ++ mutex_destroy(&m->mma8450_lock); ++ input_unregister_polled_device(idev); + err_free_mem: + input_free_polled_device(idev); + kfree(m); ++err_out: + return err; + } + +@@ -219,6 +346,9 @@ + struct mma8450 *m = i2c_get_clientdata(c); + struct input_polled_dev *idev = m->idev; + ++ sysfs_remove_group(&c->dev.kobj, &mma8450_attr_group); ++ mma8450_close(idev); ++ mutex_destroy(&m->mma8450_lock); + input_unregister_polled_device(idev); + input_free_polled_device(idev); + kfree(m); +diff -Nur linux-3.14.40.orig/drivers/input/sparse-keymap.c linux-3.14.40/drivers/input/sparse-keymap.c +--- linux-3.14.40.orig/drivers/input/sparse-keymap.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/input/sparse-keymap.c 2015-05-01 14:57:59.115427001 -0500 +@@ -236,7 +236,7 @@ + * in an input device that was set up by sparse_keymap_setup(). + * NOTE: It is safe to cal this function while input device is + * still registered (however the drivers should care not to try to +- * use freed keymap and thus have to shut off interrups/polling ++ * use freed keymap and thus have to shut off interrupts/polling + * before freeing the keymap). + */ + void sparse_keymap_free(struct input_dev *dev) +diff -Nur linux-3.14.40.orig/drivers/Kconfig linux-3.14.40/drivers/Kconfig +--- linux-3.14.40.orig/drivers/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/Kconfig 2015-05-01 14:57:59.147427001 -0500 +@@ -96,6 +96,8 @@ + + source "drivers/memstick/Kconfig" + ++source "drivers/mxc/Kconfig" ++ + source "drivers/leds/Kconfig" + + source "drivers/accessibility/Kconfig" +diff -Nur linux-3.14.40.orig/drivers/leds/leds-gpio.c linux-3.14.40/drivers/leds/leds-gpio.c +--- linux-3.14.40.orig/drivers/leds/leds-gpio.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/leds/leds-gpio.c 2015-05-01 14:57:59.163427001 -0500 +@@ -3,7 +3,7 @@ + * + * Copyright (C) 2007 8D Technologies inc. + * Raphael Assenat +- * Copyright (C) 2008 Freescale Semiconductor, Inc. ++ * Copyright (C) 2008, 2014 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 +@@ -203,6 +203,8 @@ + else + led.default_state = LEDS_GPIO_DEFSTATE_OFF; + } ++ if (of_get_property(child, "retain-state-suspended", NULL)) ++ led.retain_state_suspended = 1; + + ret = create_gpio_led(&led, &priv->leds[priv->num_leds++], + &pdev->dev, NULL); +diff -Nur linux-3.14.40.orig/drivers/leds/leds-pwm.c linux-3.14.40/drivers/leds/leds-pwm.c +--- linux-3.14.40.orig/drivers/leds/leds-pwm.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/leds/leds-pwm.c 2015-05-01 14:57:59.167427001 -0500 +@@ -70,6 +70,10 @@ + + duty *= brightness; + do_div(duty, max); ++ ++ if (led_dat->active_low) ++ duty = led_dat->period - duty; ++ + led_dat->duty = duty; + + if (led_dat->can_sleep) +@@ -93,55 +97,75 @@ + } + } + +-static int led_pwm_create_of(struct platform_device *pdev, +- struct led_pwm_priv *priv) ++static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, ++ struct led_pwm *led, struct device_node *child) + { +- struct device_node *child; ++ struct led_pwm_data *led_data = &priv->leds[priv->num_leds]; + int ret; + +- for_each_child_of_node(pdev->dev.of_node, child) { +- struct led_pwm_data *led_dat = &priv->leds[priv->num_leds]; ++ led_data->active_low = led->active_low; ++ led_data->period = led->pwm_period_ns; ++ led_data->cdev.name = led->name; ++ led_data->cdev.default_trigger = led->default_trigger; ++ led_data->cdev.brightness_set = led_pwm_set; ++ led_data->cdev.brightness = LED_OFF; ++ led_data->cdev.max_brightness = led->max_brightness; ++ led_data->cdev.flags = LED_CORE_SUSPENDRESUME; ++ ++ if (child) ++ led_data->pwm = devm_of_pwm_get(dev, child, NULL); ++ else ++ led_data->pwm = devm_pwm_get(dev, led->name); ++ if (IS_ERR(led_data->pwm)) { ++ ret = PTR_ERR(led_data->pwm); ++ dev_err(dev, "unable to request PWM for %s: %d\n", ++ led->name, ret); ++ return ret; ++ } + +- led_dat->cdev.name = of_get_property(child, "label", +- NULL) ? : child->name; ++ if (child) ++ led_data->period = pwm_get_period(led_data->pwm); + +- led_dat->pwm = devm_of_pwm_get(&pdev->dev, child, NULL); +- if (IS_ERR(led_dat->pwm)) { +- dev_err(&pdev->dev, "unable to request PWM for %s\n", +- led_dat->cdev.name); +- ret = PTR_ERR(led_dat->pwm); +- goto err; +- } +- /* Get the period from PWM core when n*/ +- led_dat->period = pwm_get_period(led_dat->pwm); ++ led_data->can_sleep = pwm_can_sleep(led_data->pwm); ++ if (led_data->can_sleep) ++ INIT_WORK(&led_data->work, led_pwm_work); + +- led_dat->cdev.default_trigger = of_get_property(child, ++ ret = led_classdev_register(dev, &led_data->cdev); ++ if (ret == 0) { ++ priv->num_leds++; ++ } else { ++ dev_err(dev, "failed to register PWM led for %s: %d\n", ++ led->name, ret); ++ } ++ ++ return ret; ++} ++ ++static int led_pwm_create_of(struct device *dev, struct led_pwm_priv *priv) ++{ ++ struct device_node *child; ++ struct led_pwm led; ++ int ret = 0; ++ ++ memset(&led, 0, sizeof(led)); ++ ++ for_each_child_of_node(dev->of_node, child) { ++ led.name = of_get_property(child, "label", NULL) ? : ++ child->name; ++ ++ led.default_trigger = of_get_property(child, + "linux,default-trigger", NULL); ++ led.active_low = of_property_read_bool(child, "active-low"); + of_property_read_u32(child, "max-brightness", +- &led_dat->cdev.max_brightness); ++ &led.max_brightness); + +- led_dat->cdev.brightness_set = led_pwm_set; +- led_dat->cdev.brightness = LED_OFF; +- led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; +- +- led_dat->can_sleep = pwm_can_sleep(led_dat->pwm); +- if (led_dat->can_sleep) +- INIT_WORK(&led_dat->work, led_pwm_work); +- +- ret = led_classdev_register(&pdev->dev, &led_dat->cdev); +- if (ret < 0) { +- dev_err(&pdev->dev, "failed to register for %s\n", +- led_dat->cdev.name); ++ ret = led_pwm_add(dev, priv, &led, child); ++ if (ret) { + of_node_put(child); +- goto err; ++ break; + } +- priv->num_leds++; + } + +- return 0; +-err: +- led_pwm_cleanup(priv); +- + return ret; + } + +@@ -167,51 +191,23 @@ + + if (pdata) { + for (i = 0; i < count; i++) { +- struct led_pwm *cur_led = &pdata->leds[i]; +- struct led_pwm_data *led_dat = &priv->leds[i]; +- +- led_dat->pwm = devm_pwm_get(&pdev->dev, cur_led->name); +- if (IS_ERR(led_dat->pwm)) { +- ret = PTR_ERR(led_dat->pwm); +- dev_err(&pdev->dev, +- "unable to request PWM for %s\n", +- cur_led->name); +- goto err; +- } +- +- led_dat->cdev.name = cur_led->name; +- led_dat->cdev.default_trigger = cur_led->default_trigger; +- led_dat->active_low = cur_led->active_low; +- led_dat->period = cur_led->pwm_period_ns; +- led_dat->cdev.brightness_set = led_pwm_set; +- led_dat->cdev.brightness = LED_OFF; +- led_dat->cdev.max_brightness = cur_led->max_brightness; +- led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; +- +- led_dat->can_sleep = pwm_can_sleep(led_dat->pwm); +- if (led_dat->can_sleep) +- INIT_WORK(&led_dat->work, led_pwm_work); +- +- ret = led_classdev_register(&pdev->dev, &led_dat->cdev); +- if (ret < 0) +- goto err; ++ ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i], ++ NULL); ++ if (ret) ++ break; + } +- priv->num_leds = count; + } else { +- ret = led_pwm_create_of(pdev, priv); +- if (ret) +- return ret; ++ ret = led_pwm_create_of(&pdev->dev, priv); ++ } ++ ++ if (ret) { ++ led_pwm_cleanup(priv); ++ return ret; + } + + platform_set_drvdata(pdev, priv); + + return 0; +- +-err: +- priv->num_leds = i; +- led_pwm_cleanup(priv); +- +- return ret; + } + + static int led_pwm_remove(struct platform_device *pdev) +diff -Nur linux-3.14.40.orig/drivers/mailbox/mailbox.c linux-3.14.40/drivers/mailbox/mailbox.c +--- linux-3.14.40.orig/drivers/mailbox/mailbox.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/mailbox/mailbox.c 2015-05-01 14:57:59.167427001 -0500 +@@ -0,0 +1,488 @@ ++/* ++ * Mailbox: Common code for Mailbox controllers and users ++ * ++ * Copyright (C) 2014 Linaro Ltd. ++ * Author: Jassi Brar ++ * ++ * This program is free software; you can 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 ++ ++#define TXDONE_BY_IRQ (1 << 0) /* controller has remote RTR irq */ ++#define TXDONE_BY_POLL (1 << 1) /* controller can read status of last TX */ ++#define TXDONE_BY_ACK (1 << 2) /* S/W ACK recevied by Client ticks the TX */ ++ ++static LIST_HEAD(mbox_cons); ++static DEFINE_MUTEX(con_mutex); ++ ++static int _add_to_rbuf(struct mbox_chan *chan, void *mssg) ++{ ++ int idx; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&chan->lock, flags); ++ ++ /* See if there is any space left */ ++ if (chan->msg_count == MBOX_TX_QUEUE_LEN) { ++ spin_unlock_irqrestore(&chan->lock, flags); ++ return -ENOMEM; ++ } ++ ++ idx = chan->msg_free; ++ chan->msg_data[idx] = mssg; ++ chan->msg_count++; ++ ++ if (idx == MBOX_TX_QUEUE_LEN - 1) ++ chan->msg_free = 0; ++ else ++ chan->msg_free++; ++ ++ spin_unlock_irqrestore(&chan->lock, flags); ++ ++ return idx; ++} ++ ++static void _msg_submit(struct mbox_chan *chan) ++{ ++ unsigned count, idx; ++ unsigned long flags; ++ void *data; ++ int err; ++ ++ spin_lock_irqsave(&chan->lock, flags); ++ ++ if (!chan->msg_count || chan->active_req) { ++ spin_unlock_irqrestore(&chan->lock, flags); ++ return; ++ } ++ ++ count = chan->msg_count; ++ idx = chan->msg_free; ++ if (idx >= count) ++ idx -= count; ++ else ++ idx += MBOX_TX_QUEUE_LEN - count; ++ ++ data = chan->msg_data[idx]; ++ ++ /* Try to submit a message to the MBOX controller */ ++ err = chan->mbox->ops->send_data(chan, data); ++ if (!err) { ++ chan->active_req = data; ++ chan->msg_count--; ++ } ++ ++ spin_unlock_irqrestore(&chan->lock, flags); ++} ++ ++static void tx_tick(struct mbox_chan *chan, int r) ++{ ++ unsigned long flags; ++ void *mssg; ++ ++ spin_lock_irqsave(&chan->lock, flags); ++ mssg = chan->active_req; ++ chan->active_req = NULL; ++ spin_unlock_irqrestore(&chan->lock, flags); ++ ++ /* Submit next message */ ++ _msg_submit(chan); ++ ++ /* Notify the client */ ++ if (chan->cl->tx_block) ++ complete(&chan->tx_complete); ++ else if (mssg && chan->cl->tx_done) ++ chan->cl->tx_done(chan->cl, mssg, r); ++} ++ ++static void poll_txdone(unsigned long data) ++{ ++ struct mbox_controller *mbox = (struct mbox_controller *)data; ++ bool txdone, resched = false; ++ int i; ++ ++ for (i = 0; i < mbox->num_chans; i++) { ++ struct mbox_chan *chan = &mbox->chans[i]; ++ ++ if (chan->active_req && chan->cl) { ++ resched = true; ++ txdone = chan->mbox->ops->last_tx_done(chan); ++ if (txdone) ++ tx_tick(chan, 0); ++ } ++ } ++ ++ if (resched) ++ mod_timer(&mbox->poll, ++ jiffies + msecs_to_jiffies(mbox->period)); ++} ++ ++/** ++ * mbox_chan_received_data - A way for controller driver to push data ++ * received from remote to the upper layer. ++ * @chan: Pointer to the mailbox channel on which RX happened. ++ * @data: Client specific message typecasted as void * ++ * ++ * After startup and before shutdown any data received on the chan ++ * is passed on to the API via atomic mbox_chan_received_data(). ++ * The controller should ACK the RX only after this call returns. ++ */ ++void mbox_chan_received_data(struct mbox_chan *chan, void *mssg) ++{ ++ /* No buffering the received data */ ++ if (chan->cl->rx_callback) ++ chan->cl->rx_callback(chan->cl, mssg); ++} ++EXPORT_SYMBOL_GPL(mbox_chan_received_data); ++ ++/** ++ * mbox_chan_txdone - A way for controller driver to notify the ++ * framework that the last TX has completed. ++ * @chan: Pointer to the mailbox chan on which TX happened. ++ * @r: Status of last TX - OK or ERROR ++ * ++ * The controller that has IRQ for TX ACK calls this atomic API ++ * to tick the TX state machine. It works only if txdone_irq ++ * is set by the controller. ++ */ ++void mbox_chan_txdone(struct mbox_chan *chan, int r) ++{ ++ if (unlikely(!(chan->txdone_method & TXDONE_BY_IRQ))) { ++ pr_err("Controller can't run the TX ticker\n"); ++ return; ++ } ++ ++ tx_tick(chan, r); ++} ++EXPORT_SYMBOL_GPL(mbox_chan_txdone); ++ ++/** ++ * mbox_client_txdone - The way for a client to run the TX state machine. ++ * @chan: Mailbox channel assigned to this client. ++ * @r: Success status of last transmission. ++ * ++ * The client/protocol had received some 'ACK' packet and it notifies ++ * the API that the last packet was sent successfully. This only works ++ * if the controller can't sense TX-Done. ++ */ ++void mbox_client_txdone(struct mbox_chan *chan, int r) ++{ ++ if (unlikely(!(chan->txdone_method & TXDONE_BY_ACK))) { ++ pr_err("Client can't run the TX ticker\n"); ++ return; ++ } ++ ++ tx_tick(chan, r); ++} ++EXPORT_SYMBOL_GPL(mbox_client_txdone); ++ ++/** ++ * mbox_client_peek_data - A way for client driver to pull data ++ * received from remote by the controller. ++ * @chan: Mailbox channel assigned to this client. ++ * ++ * A poke to controller driver for any received data. ++ * The data is actually passed onto client via the ++ * mbox_chan_received_data() ++ * The call can be made from atomic context, so the controller's ++ * implementation of peek_data() must not sleep. ++ * ++ * Return: True, if controller has, and is going to push after this, ++ * some data. ++ * False, if controller doesn't have any data to be read. ++ */ ++bool mbox_client_peek_data(struct mbox_chan *chan) ++{ ++ if (chan->mbox->ops->peek_data) ++ return chan->mbox->ops->peek_data(chan); ++ ++ return false; ++} ++EXPORT_SYMBOL_GPL(mbox_client_peek_data); ++ ++/** ++ * mbox_send_message - For client to submit a message to be ++ * sent to the remote. ++ * @chan: Mailbox channel assigned to this client. ++ * @mssg: Client specific message typecasted. ++ * ++ * For client to submit data to the controller destined for a remote ++ * processor. If the client had set 'tx_block', the call will return ++ * either when the remote receives the data or when 'tx_tout' millisecs ++ * run out. ++ * In non-blocking mode, the requests are buffered by the API and a ++ * non-negative token is returned for each queued request. If the request ++ * is not queued, a negative token is returned. Upon failure or successful ++ * TX, the API calls 'tx_done' from atomic context, from which the client ++ * could submit yet another request. ++ * In blocking mode, 'tx_done' is not called, effectively making the ++ * queue length 1. ++ * The pointer to message should be preserved until it is sent ++ * over the chan, i.e, tx_done() is made. ++ * This function could be called from atomic context as it simply ++ * queues the data and returns a token against the request. ++ * ++ * Return: Non-negative integer for successful submission (non-blocking mode) ++ * or transmission over chan (blocking mode). ++ * Negative value denotes failure. ++ */ ++int mbox_send_message(struct mbox_chan *chan, void *mssg) ++{ ++ int t; ++ ++ if (!chan || !chan->cl) ++ return -EINVAL; ++ ++ t = _add_to_rbuf(chan, mssg); ++ if (t < 0) { ++ pr_err("Try increasing MBOX_TX_QUEUE_LEN\n"); ++ return t; ++ } ++ ++ _msg_submit(chan); ++ ++ reinit_completion(&chan->tx_complete); ++ ++ if (chan->txdone_method == TXDONE_BY_POLL) ++ poll_txdone((unsigned long)chan->mbox); ++ ++ if (chan->cl->tx_block && chan->active_req) { ++ unsigned long wait; ++ int ret; ++ ++ if (!chan->cl->tx_tout) /* wait for ever */ ++ wait = msecs_to_jiffies(3600000); ++ else ++ wait = msecs_to_jiffies(chan->cl->tx_tout); ++ ++ ret = wait_for_completion_timeout(&chan->tx_complete, wait); ++ if (ret == 0) { ++ t = -EIO; ++ tx_tick(chan, -EIO); ++ } ++ } ++ ++ return t; ++} ++EXPORT_SYMBOL_GPL(mbox_send_message); ++ ++/** ++ * mbox_request_channel - Request a mailbox channel. ++ * @cl: Identity of the client requesting the channel. ++ * ++ * The Client specifies its requirements and capabilities while asking for ++ * a mailbox channel. It can't be called from atomic context. ++ * The channel is exclusively allocated and can't be used by another ++ * client before the owner calls mbox_free_channel. ++ * After assignment, any packet received on this channel will be ++ * handed over to the client via the 'rx_callback'. ++ * The framework holds reference to the client, so the mbox_client ++ * structure shouldn't be modified until the mbox_free_channel returns. ++ * ++ * Return: Pointer to the channel assigned to the client if successful. ++ * ERR_PTR for request failure. ++ */ ++struct mbox_chan *mbox_request_channel(struct mbox_client *cl) ++{ ++ struct device *dev = cl->dev; ++ struct mbox_controller *mbox; ++ struct of_phandle_args spec; ++ struct mbox_chan *chan; ++ unsigned long flags; ++ int count, i, ret; ++ ++ if (!dev || !dev->of_node) { ++ pr_err("%s: No owner device node\n", __func__); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ count = of_property_count_strings(dev->of_node, "mbox-names"); ++ if (count < 0) { ++ pr_err("%s: mbox-names property of node '%s' missing\n", ++ __func__, dev->of_node->full_name); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ mutex_lock(&con_mutex); ++ ++ ret = -ENODEV; ++ for (i = 0; i < count; i++) { ++ const char *s; ++ ++ if (of_property_read_string_index(dev->of_node, ++ "mbox-names", i, &s)) ++ continue; ++ ++ if (strcmp(cl->chan_name, s)) ++ continue; ++ ++ if (of_parse_phandle_with_args(dev->of_node, ++ "mbox", "#mbox-cells", i, &spec)) ++ continue; ++ ++ chan = NULL; ++ list_for_each_entry(mbox, &mbox_cons, node) ++ if (mbox->dev->of_node == spec.np) { ++ chan = mbox->of_xlate(mbox, &spec); ++ break; ++ } ++ ++ of_node_put(spec.np); ++ ++ if (!chan) ++ continue; ++ ++ ret = -EBUSY; ++ if (!chan->cl && try_module_get(mbox->dev->driver->owner)) ++ break; ++ } ++ ++ if (i == count) { ++ mutex_unlock(&con_mutex); ++ return ERR_PTR(ret); ++ } ++ ++ spin_lock_irqsave(&chan->lock, flags); ++ chan->msg_free = 0; ++ chan->msg_count = 0; ++ chan->active_req = NULL; ++ chan->cl = cl; ++ init_completion(&chan->tx_complete); ++ ++ if (chan->txdone_method == TXDONE_BY_POLL ++ && cl->knows_txdone) ++ chan->txdone_method |= TXDONE_BY_ACK; ++ spin_unlock_irqrestore(&chan->lock, flags); ++ ++ ret = chan->mbox->ops->startup(chan); ++ if (ret) { ++ pr_err("Unable to startup the chan (%d)\n", ret); ++ mbox_free_channel(chan); ++ chan = ERR_PTR(ret); ++ } ++ ++ mutex_unlock(&con_mutex); ++ return chan; ++} ++EXPORT_SYMBOL_GPL(mbox_request_channel); ++ ++/** ++ * mbox_free_channel - The client relinquishes control of a mailbox ++ * channel by this call. ++ * @chan: The mailbox channel to be freed. ++ */ ++void mbox_free_channel(struct mbox_chan *chan) ++{ ++ unsigned long flags; ++ ++ if (!chan || !chan->cl) ++ return; ++ ++ chan->mbox->ops->shutdown(chan); ++ ++ /* The queued TX requests are simply aborted, no callbacks are made */ ++ spin_lock_irqsave(&chan->lock, flags); ++ chan->cl = NULL; ++ chan->active_req = NULL; ++ if (chan->txdone_method == (TXDONE_BY_POLL | TXDONE_BY_ACK)) ++ chan->txdone_method = TXDONE_BY_POLL; ++ ++ module_put(chan->mbox->dev->driver->owner); ++ spin_unlock_irqrestore(&chan->lock, flags); ++} ++EXPORT_SYMBOL_GPL(mbox_free_channel); ++ ++static struct mbox_chan * ++of_mbox_index_xlate(struct mbox_controller *mbox, ++ const struct of_phandle_args *sp) ++{ ++ int ind = sp->args[0]; ++ ++ if (ind >= mbox->num_chans) ++ return NULL; ++ ++ return &mbox->chans[ind]; ++} ++ ++/** ++ * mbox_controller_register - Register the mailbox controller ++ * @mbox: Pointer to the mailbox controller. ++ * ++ * The controller driver registers its communication chans ++ */ ++int mbox_controller_register(struct mbox_controller *mbox) ++{ ++ int i, txdone; ++ ++ /* Sanity check */ ++ if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) ++ return -EINVAL; ++ ++ if (mbox->txdone_irq) ++ txdone = TXDONE_BY_IRQ; ++ else if (mbox->txdone_poll) ++ txdone = TXDONE_BY_POLL; ++ else /* It has to be ACK then */ ++ txdone = TXDONE_BY_ACK; ++ ++ if (txdone == TXDONE_BY_POLL) { ++ mbox->poll.function = &poll_txdone; ++ mbox->poll.data = (unsigned long)mbox; ++ init_timer(&mbox->poll); ++ } ++ ++ for (i = 0; i < mbox->num_chans; i++) { ++ struct mbox_chan *chan = &mbox->chans[i]; ++ chan->cl = NULL; ++ chan->mbox = mbox; ++ chan->txdone_method = txdone; ++ spin_lock_init(&chan->lock); ++ } ++ ++ if (!mbox->of_xlate) ++ mbox->of_xlate = of_mbox_index_xlate; ++ ++ mutex_lock(&con_mutex); ++ list_add_tail(&mbox->node, &mbox_cons); ++ mutex_unlock(&con_mutex); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(mbox_controller_register); ++ ++/** ++ * mbox_controller_unregister - UnRegister the mailbox controller ++ * @mbox: Pointer to the mailbox controller. ++ */ ++void mbox_controller_unregister(struct mbox_controller *mbox) ++{ ++ int i; ++ ++ if (!mbox) ++ return; ++ ++ mutex_lock(&con_mutex); ++ ++ list_del(&mbox->node); ++ ++ for (i = 0; i < mbox->num_chans; i++) ++ mbox_free_channel(&mbox->chans[i]); ++ ++ if (mbox->txdone_poll) ++ del_timer_sync(&mbox->poll); ++ ++ mutex_unlock(&con_mutex); ++} ++EXPORT_SYMBOL_GPL(mbox_controller_unregister); +diff -Nur linux-3.14.40.orig/drivers/mailbox/Makefile linux-3.14.40/drivers/mailbox/Makefile +--- linux-3.14.40.orig/drivers/mailbox/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/mailbox/Makefile 2015-05-01 14:57:59.179427001 -0500 +@@ -1,3 +1,7 @@ ++# Generic MAILBOX API ++ ++obj-$(CONFIG_MAILBOX) += mailbox.o ++ + obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o + + obj-$(CONFIG_OMAP_MBOX) += omap-mailbox.o +diff -Nur linux-3.14.40.orig/drivers/mailbox/pl320-ipc.c linux-3.14.40/drivers/mailbox/pl320-ipc.c +--- linux-3.14.40.orig/drivers/mailbox/pl320-ipc.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/mailbox/pl320-ipc.c 2015-05-01 14:57:59.179427001 -0500 +@@ -26,7 +26,7 @@ + #include + #include + +-#include ++#include + + #define IPCMxSOURCE(m) ((m) * 0x40) + #define IPCMxDSET(m) (((m) * 0x40) + 0x004) +diff -Nur linux-3.14.40.orig/drivers/Makefile linux-3.14.40/drivers/Makefile +--- linux-3.14.40.orig/drivers/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/Makefile 2015-05-01 14:57:59.203427001 -0500 +@@ -111,6 +111,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/ +diff -Nur linux-3.14.40.orig/drivers/media/platform/Kconfig linux-3.14.40/drivers/media/platform/Kconfig +--- linux-3.14.40.orig/drivers/media/platform/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/media/platform/Kconfig 2015-05-01 14:57:59.211427001 -0500 +@@ -115,6 +115,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.14.40.orig/drivers/media/platform/Makefile linux-3.14.40/drivers/media/platform/Makefile +--- linux-3.14.40.orig/drivers/media/platform/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/media/platform/Makefile 2015-05-01 14:57:59.227427001 -0500 +@@ -51,4 +51,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.14.40.orig/drivers/media/platform/mxc/capture/adv7180.c linux-3.14.40/drivers/media/platform/mxc/capture/adv7180.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/adv7180.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/adv7180.c 2015-05-01 14:57:59.227427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/capture/csi_v4l2_capture.c linux-3.14.40/drivers/media/platform/mxc/capture/csi_v4l2_capture.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/csi_v4l2_capture.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/csi_v4l2_capture.c 2015-05-01 14:57:59.255427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/capture/fsl_csi.c linux-3.14.40/drivers/media/platform/mxc/capture/fsl_csi.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/fsl_csi.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/fsl_csi.c 2015-05-01 14:57:59.255427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/capture/fsl_csi.h linux-3.14.40/drivers/media/platform/mxc/capture/fsl_csi.h +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/fsl_csi.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/fsl_csi.h 2015-05-01 14:57:59.255427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c linux-3.14.40/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c 2015-05-01 14:57:59.255427001 -0500 +@@ -0,0 +1,546 @@ ++ ++/* ++ * Copyright 2004-2014 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; ++ } ++ } ++#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); ++ } ++ } ++#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.14.40.orig/drivers/media/platform/mxc/capture/ipu_csi_enc.c linux-3.14.40/drivers/media/platform/mxc/capture/ipu_csi_enc.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/ipu_csi_enc.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/ipu_csi_enc.c 2015-05-01 14:57:59.259427001 -0500 +@@ -0,0 +1,418 @@ ++/* ++ * Copyright 2009-2014 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; ++ } ++ } ++#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); ++ } ++ } ++#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.14.40.orig/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c linux-3.14.40/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c 2015-05-01 14:57:59.259427001 -0500 +@@ -0,0 +1,634 @@ ++/* ++ * Copyright 2004-2014 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; ++ } ++ } ++#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); ++ } ++ } ++#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.14.40.orig/drivers/media/platform/mxc/capture/ipu_prp_enc.c linux-3.14.40/drivers/media/platform/mxc/capture/ipu_prp_enc.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/ipu_prp_enc.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/ipu_prp_enc.c 2015-05-01 14:57:59.259427001 -0500 +@@ -0,0 +1,595 @@ ++/* ++ * Copyright 2004-2014 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; ++ } ++ } ++#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); ++ } ++ } ++#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.14.40.orig/drivers/media/platform/mxc/capture/ipu_prp_sw.h linux-3.14.40/drivers/media/platform/mxc/capture/ipu_prp_sw.h +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/ipu_prp_sw.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/ipu_prp_sw.h 2015-05-01 14:57:59.259427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c linux-3.14.40/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c 2015-05-01 14:57:59.259427001 -0500 +@@ -0,0 +1,521 @@ ++/* ++ * Copyright 2004-2014 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; ++ } ++ } ++#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); ++ } ++ } ++#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.14.40.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c linux-3.14.40/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c 2015-05-01 14:57:59.259427001 -0500 +@@ -0,0 +1,582 @@ ++/* ++ * Copyright 2004-2014 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; ++ } ++ } ++#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); ++ } ++ } ++#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.14.40.orig/drivers/media/platform/mxc/capture/ipu_still.c linux-3.14.40/drivers/media/platform/mxc/capture/ipu_still.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/ipu_still.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/ipu_still.c 2015-05-01 14:57:59.259427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/capture/Kconfig linux-3.14.40/drivers/media/platform/mxc/capture/Kconfig +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/Kconfig 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/Kconfig 2015-05-01 14:57:59.259427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/capture/Makefile linux-3.14.40/drivers/media/platform/mxc/capture/Makefile +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/Makefile 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/Makefile 2015-05-01 14:57:59.259427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c linux-3.14.40/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c 2015-05-01 14:57:59.263427001 -0500 +@@ -0,0 +1,3102 @@ ++/* ++ * Copyright 2004-2014 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; ++ ++ 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; ++ 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) ++{ ++ pr_debug("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.14.40.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h linux-3.14.40/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h 2015-05-01 14:57:59.263427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/capture/ov5640.c linux-3.14.40/drivers/media/platform/mxc/capture/ov5640.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/ov5640.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/ov5640.c 2015-05-01 14:57:59.263427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/capture/ov5640_mipi.c linux-3.14.40/drivers/media/platform/mxc/capture/ov5640_mipi.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/ov5640_mipi.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/ov5640_mipi.c 2015-05-01 14:57:59.267427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/capture/ov5642.c linux-3.14.40/drivers/media/platform/mxc/capture/ov5642.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/capture/ov5642.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/capture/ov5642.c 2015-05-01 14:57:59.267427001 -0500 +@@ -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.14.40.orig/drivers/media/platform/mxc/output/Kconfig linux-3.14.40/drivers/media/platform/mxc/output/Kconfig +--- linux-3.14.40.orig/drivers/media/platform/mxc/output/Kconfig 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/output/Kconfig 2015-05-01 14:57:59.267427001 -0500 +@@ -0,0 +1,5 @@ ++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. +diff -Nur linux-3.14.40.orig/drivers/media/platform/mxc/output/Makefile linux-3.14.40/drivers/media/platform/mxc/output/Makefile +--- linux-3.14.40.orig/drivers/media/platform/mxc/output/Makefile 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/output/Makefile 2015-05-01 14:57:59.267427001 -0500 +@@ -0,0 +1 @@ ++obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT) += mxc_vout.o +diff -Nur linux-3.14.40.orig/drivers/media/platform/mxc/output/mxc_vout.c linux-3.14.40/drivers/media/platform/mxc/output/mxc_vout.c +--- linux-3.14.40.orig/drivers/media/platform/mxc/output/mxc_vout.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/media/platform/mxc/output/mxc_vout.c 2015-05-01 14:57:59.271427001 -0500 +@@ -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.14.40.orig/drivers/media/v4l2-core/videobuf2-dma-contig.c linux-3.14.40/drivers/media/v4l2-core/videobuf2-dma-contig.c +--- linux-3.14.40.orig/drivers/media/v4l2-core/videobuf2-dma-contig.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/media/v4l2-core/videobuf2-dma-contig.c 2015-05-01 14:57:59.295427001 -0500 +@@ -719,7 +719,7 @@ + + /* get the associated scatterlist for this buffer */ + sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir); +- if (IS_ERR_OR_NULL(sgt)) { ++ if (IS_ERR(sgt)) { + pr_err("Error getting dmabuf scatterlist\n"); + return -EINVAL; + } +diff -Nur linux-3.14.40.orig/drivers/media/v4l2-core/videobuf-dma-contig.c linux-3.14.40/drivers/media/v4l2-core/videobuf-dma-contig.c +--- linux-3.14.40.orig/drivers/media/v4l2-core/videobuf-dma-contig.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/media/v4l2-core/videobuf-dma-contig.c 2015-05-01 14:57:59.295427001 -0500 +@@ -304,7 +304,7 @@ + + /* Try to remap memory */ + size = vma->vm_end - vma->vm_start; +- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + retval = vm_iomap_memory(vma, vma->vm_start, size); + if (retval) { + dev_err(q->dev, "mmap: remap failed with error %d. ", +diff -Nur linux-3.14.40.orig/drivers/mfd/ab8500-core.c linux-3.14.40/drivers/mfd/ab8500-core.c +--- linux-3.14.40.orig/drivers/mfd/ab8500-core.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/mfd/ab8500-core.c 2015-05-01 14:57:59.315427001 -0500 +@@ -592,7 +592,7 @@ + + /* If ->irq_base is zero this will give a linear mapping */ + ab8500->domain = irq_domain_add_simple(NULL, +- num_irqs, ab8500->irq_base, ++ num_irqs, 0, + &ab8500_irq_ops, ab8500); + + if (!ab8500->domain) { +@@ -1583,14 +1583,13 @@ + if (!ab8500) + return -ENOMEM; + +- if (plat) +- ab8500->irq_base = plat->irq_base; +- + ab8500->dev = &pdev->dev; + + resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); +- if (!resource) ++ if (!resource) { ++ dev_err(&pdev->dev, "no IRQ resource\n"); + return -ENODEV; ++ } + + ab8500->irq = resource->start; + +@@ -1612,8 +1611,10 @@ + else { + ret = get_register_interruptible(ab8500, AB8500_MISC, + AB8500_IC_NAME_REG, &value); +- if (ret < 0) ++ if (ret < 0) { ++ dev_err(&pdev->dev, "could not probe HW\n"); + return ret; ++ } + + ab8500->version = value; + } +@@ -1759,30 +1760,30 @@ + if (is_ab9540(ab8500)) + ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, + ARRAY_SIZE(ab9540_devs), NULL, +- ab8500->irq_base, ab8500->domain); ++ 0, ab8500->domain); + else if (is_ab8540(ab8500)) { + ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs, + ARRAY_SIZE(ab8540_devs), NULL, +- ab8500->irq_base, NULL); ++ 0, ab8500->domain); + if (ret) + return ret; + + if (is_ab8540_1p2_or_earlier(ab8500)) + ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs, + ARRAY_SIZE(ab8540_cut1_devs), NULL, +- ab8500->irq_base, NULL); ++ 0, ab8500->domain); + else /* ab8540 >= cut2 */ + ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs, + ARRAY_SIZE(ab8540_cut2_devs), NULL, +- ab8500->irq_base, NULL); ++ 0, ab8500->domain); + } else if (is_ab8505(ab8500)) + ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs, + ARRAY_SIZE(ab8505_devs), NULL, +- ab8500->irq_base, ab8500->domain); ++ 0, ab8500->domain); + else + ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, + ARRAY_SIZE(ab8500_devs), NULL, +- ab8500->irq_base, ab8500->domain); ++ 0, ab8500->domain); + if (ret) + return ret; + +@@ -1790,7 +1791,7 @@ + /* Add battery management devices */ + ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, + ARRAY_SIZE(ab8500_bm_devs), NULL, +- ab8500->irq_base, ab8500->domain); ++ 0, ab8500->domain); + if (ret) + dev_err(ab8500->dev, "error adding bm devices\n"); + } +diff -Nur linux-3.14.40.orig/drivers/mfd/db8500-prcmu.c linux-3.14.40/drivers/mfd/db8500-prcmu.c +--- linux-3.14.40.orig/drivers/mfd/db8500-prcmu.c 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/mfd/db8500-prcmu.c 2015-05-01 14:57:59.323427001 -0500 +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2678,16 +2679,12 @@ + .xlate = irq_domain_xlate_twocell, + }; + +-static int db8500_irq_init(struct device_node *np, int irq_base) ++static int db8500_irq_init(struct device_node *np) + { + int i; + +- /* In the device tree case, just take some IRQs */ +- if (np) +- irq_base = 0; +- + db8500_irq_domain = irq_domain_add_simple( +- np, NUM_PRCMU_WAKEUPS, irq_base, ++ np, NUM_PRCMU_WAKEUPS, 0, + &db8500_irq_ops, NULL); + + if (!db8500_irq_domain) { +@@ -3114,10 +3111,10 @@ + } + + static int db8500_prcmu_register_ab8500(struct device *parent, +- struct ab8500_platform_data *pdata, +- int irq) ++ struct ab8500_platform_data *pdata) + { +- struct resource ab8500_resource = DEFINE_RES_IRQ(irq); ++ struct device_node *np; ++ struct resource ab8500_resource; + struct mfd_cell ab8500_cell = { + .name = "ab8500-core", + .of_compatible = "stericsson,ab8500", +@@ -3128,6 +3125,20 @@ + .num_resources = 1, + }; + ++ if (!parent->of_node) ++ return -ENODEV; ++ ++ /* Look up the device node, sneak the IRQ out of it */ ++ for_each_child_of_node(parent->of_node, np) { ++ if (of_device_is_compatible(np, ab8500_cell.of_compatible)) ++ break; ++ } ++ if (!np) { ++ dev_info(parent, "could not find AB8500 node in the device tree\n"); ++ return -ENODEV; ++ } ++ of_irq_to_resource_table(np, &ab8500_resource, 1); ++ + return mfd_add_devices(parent, 0, &ab8500_cell, 1, NULL, 0, NULL); + } + +@@ -3180,7 +3191,7 @@ + goto no_irq_return; + } + +- db8500_irq_init(np, pdata->irq_base); ++ db8500_irq_init(np); + + prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); + +@@ -3205,8 +3216,7 @@ + } + } + +- err = db8500_prcmu_register_ab8500(&pdev->dev, pdata->ab_platdata, +- pdata->ab_irq); ++ err = db8500_prcmu_register_ab8500(&pdev->dev, pdata->ab_platdata); + if (err) { + mfd_remove_devices(&pdev->dev); + pr_err("prcmu: Failed to add ab8500 subdevice\n"); +diff -Nur linux-3.14.40.orig/drivers/mfd/Kconfig linux-3.14.40/drivers/mfd/Kconfig +--- linux-3.14.40.orig/drivers/mfd/Kconfig 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/mfd/Kconfig 2015-05-01 14:57:59.331427001 -0500 +@@ -163,6 +163,14 @@ + Additional drivers must be enabled in order to use the functionality + of the device. + ++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_MC13XXX + tristate + depends on (SPI_MASTER || I2C) +@@ -1226,3 +1234,4 @@ + help + Platform configuration infrastructure for the ARM Ltd. + Versatile Express. ++ +diff -Nur linux-3.14.40.orig/drivers/mfd/Makefile linux-3.14.40/drivers/mfd/Makefile +--- linux-3.14.40.orig/drivers/mfd/Makefile 2015-04-29 03:32:58.000000000 -0500 ++++ linux-3.14.40/drivers/mfd/Makefile 2015-05-01 14:57:59.351427001 -0500 +@@ -166,3 +166,4 @@ + obj-$(CONFIG_MFD_AS3711) += as3711.o + obj-$(CONFIG_MFD_AS3722) += as3722.o + obj-$(CONFIG_MFD_STW481X) += stw481x.o ++obj-$(CONFIG_MFD_MXC_HDMI) += mxc-hdmi-core.o +diff -Nur linux-3.14.40.orig/drivers/mfd/mxc-hdmi-core.c linux-3.14.40/drivers/mfd/mxc-hdmi-core.c +--- linux-3.14.40.orig/drivers/mfd/mxc-hdmi-core.c 1969-12-31 18:00:00.000000000 -0600 ++++ linux-3.14.40/drivers/mfd/mxc-hdmi-core.c 2015-05-01 14:57:59.351427001 -0500 +@@ -0,0 +1,798 @@ ++/* ++ * Copyright (C) 2011-2014 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