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